    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 *  Unless required by applicable law or agreed to in writing, software
    012 *  distributed under the License is distributed on an "AS IS" BASIS,
    013 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 *  See the License for the specific language governing permissions and
    015 *  limitations under the License.
    016 *
    017 */
    018package org.apache.bcel.generic;
    019
    020import org.apache.bcel.classfile.CodeException;
    021
    022/**
    023 * This class represents an exception handler, i.e., specifies the region where a handler is active and an instruction
    024 * where the actual handling is done. pool as parameters. Opposed to the JVM specification the end of the handled region
    025 * is set to be inclusive, i.e. all instructions between start and end are protected including the start and end
    026 * instructions (handles) themselves. The end of the region is automatically mapped to be exclusive when calling
    027 * getCodeException(), i.e., there is no difference semantically.
    028 *
    029 * @see MethodGen
    030 * @see CodeException
    031 * @see InstructionHandle
    032 */
    033public final class CodeExceptionGen implements InstructionTargeter, Cloneable {
    034
    035    static final CodeExceptionGen[] EMPTY_ARRAY = {};
    036
    037    private InstructionHandle startPc;
    038    private InstructionHandle endPc;
    039    private InstructionHandle handlerPc;
    040    private ObjectType catchType;
    041
    042    /**
    043     * Add an exception handler, i.e., specify region where a handler is active and an instruction where the actual handling
    044     * is done.
    045     *
    046     * @param startPc Start of handled region (inclusive)
    047     * @param endPc End of handled region (inclusive)
    048     * @param handlerPc Where handling is done
    049     * @param catchType which exception is handled, null for ANY
    050     */
    051    public CodeExceptionGen(final InstructionHandle startPc, final InstructionHandle endPc, final InstructionHandle handlerPc, final ObjectType catchType) {
    052        setStartPC(startPc);
    053        setEndPC(endPc);
    054        setHandlerPC(handlerPc);
    055        this.catchType = catchType;
    056    }
    057
    058    @Override
    059    public Object clone() {
    060        try {
    061            return super.clone();
    062        } catch (final CloneNotSupportedException e) {
    063            throw new Error("Clone Not Supported"); // never happens
    064        }
    065    }
    066
    067    /**
    068     * @return true, if ih is target of this handler
    069     */
    070    @Override
    071    public boolean containsTarget(final InstructionHandle ih) {
    072        return startPc == ih || endPc == ih || handlerPc == ih;
    073    }
    074
    075    /** Gets the type of the Exception to catch, 'null' for ANY. */
    076    public ObjectType getCatchType() {
    077        return catchType;
    078    }
    079
    080    /**
    081     * Get CodeException object.<BR>
    082     *
    083     * This relies on that the instruction list has already been dumped to byte code or that the `setPositions' methods
    084     * has been called for the instruction list.
    085     *
    086     * @param cp constant pool
    087     */
    088    public CodeException getCodeException(final ConstantPoolGen cp) {
    089        return new CodeException(startPc.getPosition(), endPc.getPosition() + endPc.getInstruction().getLength(), handlerPc.getPosition(),
    090            catchType == null ? 0 : cp.addClass(catchType));
    091    }
    092
    093    /**
    094     * @return end of handled region (inclusive)
    095     */
    096    public InstructionHandle getEndPC() {
    097        return endPc;
    098    }
    099
    100    /**
    101     * @return start of handler
    102     */
    103    public InstructionHandle getHandlerPC() {
    104        return handlerPc;
    105    }
    106
    107    /**
    108     * @return start of handled region (inclusive)
    109     */
    110    public InstructionHandle getStartPC() {
    111        return startPc;
    112    }
    113
    114    /** Sets the type of the Exception to catch. Set 'null' for ANY. */
    115    public void setCatchType(final ObjectType catchType) {
    116        this.catchType = catchType;
    117    }
    118
    119    /*
    120     * Set end of handler
    121     *
    122     * @param endPc End of handled region (inclusive)
    123     */
    124    public void setEndPC(final InstructionHandle end_pc) { // TODO could be package-protected?
    125        BranchInstruction.notifyTarget(this.endPc, end_pc, this);
    126        this.endPc = end_pc;
    127    }
    128
    129    /*
    130     * Set handler code
    131     *
    132     * @param handlerPc Start of handler
    133     */
    134    public void setHandlerPC(final InstructionHandle handler_pc) { // TODO could be package-protected?
    135        BranchInstruction.notifyTarget(this.handlerPc, handler_pc, this);
    136        this.handlerPc = handler_pc;
    137    }
    138
    139    /*
    140     * Set start of handler
    141     *
    142     * @param startPc Start of handled region (inclusive)
    143     */
    144    public void setStartPC(final InstructionHandle start_pc) { // TODO could be package-protected?
    145        BranchInstruction.notifyTarget(this.startPc, start_pc, this);
    146        this.startPc = start_pc;
    147    }
    148
    149    @Override
    150    public String toString() {
    151        return "CodeExceptionGen(" + startPc + ", " + endPc + ", " + handlerPc + ")";
    152    }
    153
    154    /**
    155     * @param old_ih old target, either start or end
    156     * @param new_ih new target
    157     */
    158    @Override
    159    public void updateTarget(final InstructionHandle old_ih, final InstructionHandle new_ih) {
    160        boolean targeted = false;
    161        if (startPc == old_ih) {
    162            targeted = true;
    163            setStartPC(new_ih);
    164        }
    165        if (endPc == old_ih) {
    166            targeted = true;
    167            setEndPC(new_ih);
    168        }
    169        if (handlerPc == old_ih) {
    170            targeted = true;
    171            setHandlerPC(new_ih);
    172        }
    173        if (!targeted) {
    174            throw new ClassGenException("Not targeting " + old_ih + ", but {" + startPc + ", " + endPc + ", " + handlerPc + "}");
    175        }
    176    }
    177}