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