CodeExceptionGen.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  *  Unless required by applicable law or agreed to in writing, software
  12.  *  distributed under the License is distributed on an "AS IS" BASIS,
  13.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  *  See the License for the specific language governing permissions and
  15.  *  limitations under the License.
  16.  */
  17. package org.apache.bcel.generic;

  18. import org.apache.bcel.classfile.CodeException;

  19. /**
  20.  * This class represents an exception handler, i.e., specifies the region where a handler is active and an instruction
  21.  * where the actual handling is done. pool as parameters. Opposed to the JVM specification the end of the handled region
  22.  * is set to be inclusive, i.e. all instructions between start and end are protected including the start and end
  23.  * instructions (handles) themselves. The end of the region is automatically mapped to be exclusive when calling
  24.  * getCodeException(), i.e., there is no difference semantically.
  25.  *
  26.  * @see MethodGen
  27.  * @see CodeException
  28.  * @see InstructionHandle
  29.  */
  30. public final class CodeExceptionGen implements InstructionTargeter, Cloneable {

  31.     static final CodeExceptionGen[] EMPTY_ARRAY = {};

  32.     private InstructionHandle startPc;
  33.     private InstructionHandle endPc;
  34.     private InstructionHandle handlerPc;
  35.     private ObjectType catchType;

  36.     /**
  37.      * Add an exception handler, i.e., specify region where a handler is active and an instruction where the actual handling
  38.      * is done.
  39.      *
  40.      * @param startPc Start of handled region (inclusive)
  41.      * @param endPc End of handled region (inclusive)
  42.      * @param handlerPc Where handling is done
  43.      * @param catchType which exception is handled, null for ANY
  44.      */
  45.     public CodeExceptionGen(final InstructionHandle startPc, final InstructionHandle endPc, final InstructionHandle handlerPc, final ObjectType catchType) {
  46.         setStartPC(startPc);
  47.         setEndPC(endPc);
  48.         setHandlerPC(handlerPc);
  49.         this.catchType = catchType;
  50.     }

  51.     @Override
  52.     public Object clone() {
  53.         try {
  54.             return super.clone();
  55.         } catch (final CloneNotSupportedException e) {
  56.             throw new UnsupportedOperationException("Clone Not Supported", e); // never happens
  57.         }
  58.     }

  59.     /**
  60.      * @return true, if ih is target of this handler
  61.      */
  62.     @Override
  63.     public boolean containsTarget(final InstructionHandle ih) {
  64.         return startPc == ih || endPc == ih || handlerPc == ih;
  65.     }

  66.     /** Gets the type of the Exception to catch, 'null' for ANY. */
  67.     public ObjectType getCatchType() {
  68.         return catchType;
  69.     }

  70.     /**
  71.      * Gets CodeException object.<BR>
  72.      *
  73.      * This relies on that the instruction list has already been dumped to byte code or that the 'setPositions' methods
  74.      * has been called for the instruction list.
  75.      *
  76.      * @param cp constant pool
  77.      */
  78.     public CodeException getCodeException(final ConstantPoolGen cp) {
  79.         return new CodeException(startPc.getPosition(), endPc.getPosition() + endPc.getInstruction().getLength(), handlerPc.getPosition(),
  80.             catchType == null ? 0 : cp.addClass(catchType));
  81.     }

  82.     /**
  83.      * @return end of handled region (inclusive)
  84.      */
  85.     public InstructionHandle getEndPC() {
  86.         return endPc;
  87.     }

  88.     /**
  89.      * @return start of handler
  90.      */
  91.     public InstructionHandle getHandlerPC() {
  92.         return handlerPc;
  93.     }

  94.     /**
  95.      * @return start of handled region (inclusive)
  96.      */
  97.     public InstructionHandle getStartPC() {
  98.         return startPc;
  99.     }

  100.     /** Sets the type of the Exception to catch. Set 'null' for ANY. */
  101.     public void setCatchType(final ObjectType catchType) {
  102.         this.catchType = catchType;
  103.     }

  104.     /*
  105.      * Sets end of handler
  106.      *
  107.      * @param endPc End of handled region (inclusive)
  108.      */
  109.     public void setEndPC(final InstructionHandle endPc) { // TODO could be package-protected?
  110.         BranchInstruction.notifyTarget(this.endPc, endPc, this);
  111.         this.endPc = endPc;
  112.     }

  113.     /*
  114.      * Sets handler code
  115.      *
  116.      * @param handlerPc Start of handler
  117.      */
  118.     public void setHandlerPC(final InstructionHandle handlerPc) { // TODO could be package-protected?
  119.         BranchInstruction.notifyTarget(this.handlerPc, handlerPc, this);
  120.         this.handlerPc = handlerPc;
  121.     }

  122.     /*
  123.      * Sets start of handler
  124.      *
  125.      * @param startPc Start of handled region (inclusive)
  126.      */
  127.     public void setStartPC(final InstructionHandle startPc) { // TODO could be package-protected?
  128.         BranchInstruction.notifyTarget(this.startPc, startPc, this);
  129.         this.startPc = startPc;
  130.     }

  131.     @Override
  132.     public String toString() {
  133.         return "CodeExceptionGen(" + startPc + ", " + endPc + ", " + handlerPc + ")";
  134.     }

  135.     /**
  136.      * @param oldIh old target, either start or end
  137.      * @param newIh new target
  138.      */
  139.     @Override
  140.     public void updateTarget(final InstructionHandle oldIh, final InstructionHandle newIh) {
  141.         boolean targeted = false;
  142.         if (startPc == oldIh) {
  143.             targeted = true;
  144.             setStartPC(newIh);
  145.         }
  146.         if (endPc == oldIh) {
  147.             targeted = true;
  148.             setEndPC(newIh);
  149.         }
  150.         if (handlerPc == oldIh) {
  151.             targeted = true;
  152.             setHandlerPC(newIh);
  153.         }
  154.         if (!targeted) {
  155.             throw new ClassGenException("Not targeting " + oldIh + ", but {" + startPc + ", " + endPc + ", " + handlerPc + "}");
  156.         }
  157.     }
  158. }