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