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 */ 18 package org.apache.bcel.generic; 19 20 import org.apache.bcel.classfile.CodeException; 21 22 /** 23 * This class represents an exception handler, i.e., specifies the region where 24 * a handler is active and an instruction where the actual handling is done. 25 * pool as parameters. Opposed to the JVM specification the end of the handled 26 * region is set to be inclusive, i.e. all instructions between start and end 27 * are protected including the start and end instructions (handles) themselves. 28 * The end of the region is automatically mapped to be exclusive when calling 29 * getCodeException(), i.e., there is no difference semantically. 30 * 31 * @version $Id$ 32 * @see MethodGen 33 * @see CodeException 34 * @see InstructionHandle 35 */ 36 public final class CodeExceptionGen implements InstructionTargeter, Cloneable { 37 38 private InstructionHandle start_pc; 39 private InstructionHandle end_pc; 40 private InstructionHandle handler_pc; 41 private ObjectType catch_type; 42 43 44 /** 45 * Add an exception handler, i.e., specify region where a handler is active and an 46 * instruction where the actual handling is done. 47 * 48 * @param start_pc Start of handled region (inclusive) 49 * @param end_pc End of handled region (inclusive) 50 * @param handler_pc Where handling is done 51 * @param catch_type which exception is handled, null for ANY 52 */ CodeExceptionGen(final InstructionHandle start_pc, final InstructionHandle end_pc, final InstructionHandle handler_pc, final ObjectType catch_type)53 public CodeExceptionGen(final InstructionHandle start_pc, final InstructionHandle end_pc, 54 final InstructionHandle handler_pc, final ObjectType catch_type) { 55 setStartPC(start_pc); 56 setEndPC(end_pc); 57 setHandlerPC(handler_pc); 58 this.catch_type = catch_type; 59 } 60 61 62 /** 63 * Get CodeException object.<BR> 64 * 65 * This relies on that the instruction list has already been dumped 66 * to byte code or or that the `setPositions' methods has been 67 * called for the instruction list. 68 * 69 * @param cp constant pool 70 */ getCodeException( final ConstantPoolGen cp )71 public CodeException getCodeException( final ConstantPoolGen cp ) { 72 return new CodeException(start_pc.getPosition(), end_pc.getPosition() 73 + end_pc.getInstruction().getLength(), handler_pc.getPosition(), 74 (catch_type == null) ? 0 : cp.addClass(catch_type)); 75 } 76 77 78 /* Set start of handler 79 * @param start_pc Start of handled region (inclusive) 80 */ setStartPC( final InstructionHandle start_pc )81 public void setStartPC( final InstructionHandle start_pc ) { // TODO could be package-protected? 82 BranchInstruction.notifyTarget(this.start_pc, start_pc, this); 83 this.start_pc = start_pc; 84 } 85 86 87 /* Set end of handler 88 * @param end_pc End of handled region (inclusive) 89 */ setEndPC( final InstructionHandle end_pc )90 public void setEndPC( final InstructionHandle end_pc ) { // TODO could be package-protected? 91 BranchInstruction.notifyTarget(this.end_pc, end_pc, this); 92 this.end_pc = end_pc; 93 } 94 95 96 /* Set handler code 97 * @param handler_pc Start of handler 98 */ setHandlerPC( final InstructionHandle handler_pc )99 public void setHandlerPC( final InstructionHandle handler_pc ) { // TODO could be package-protected? 100 BranchInstruction.notifyTarget(this.handler_pc, handler_pc, this); 101 this.handler_pc = handler_pc; 102 } 103 104 105 /** 106 * @param old_ih old target, either start or end 107 * @param new_ih new target 108 */ 109 @Override updateTarget( final InstructionHandle old_ih, final InstructionHandle new_ih )110 public void updateTarget( final InstructionHandle old_ih, final InstructionHandle new_ih ) { 111 boolean targeted = false; 112 if (start_pc == old_ih) { 113 targeted = true; 114 setStartPC(new_ih); 115 } 116 if (end_pc == old_ih) { 117 targeted = true; 118 setEndPC(new_ih); 119 } 120 if (handler_pc == old_ih) { 121 targeted = true; 122 setHandlerPC(new_ih); 123 } 124 if (!targeted) { 125 throw new ClassGenException("Not targeting " + old_ih + ", but {" + start_pc + ", " 126 + end_pc + ", " + handler_pc + "}"); 127 } 128 } 129 130 131 /** 132 * @return true, if ih is target of this handler 133 */ 134 @Override containsTarget( final InstructionHandle ih )135 public boolean containsTarget( final InstructionHandle ih ) { 136 return (start_pc == ih) || (end_pc == ih) || (handler_pc == ih); 137 } 138 139 140 /** Sets the type of the Exception to catch. Set 'null' for ANY. */ setCatchType( final ObjectType catch_type )141 public void setCatchType( final ObjectType catch_type ) { 142 this.catch_type = catch_type; 143 } 144 145 146 /** Gets the type of the Exception to catch, 'null' for ANY. */ getCatchType()147 public ObjectType getCatchType() { 148 return catch_type; 149 } 150 151 152 /** @return start of handled region (inclusive) 153 */ getStartPC()154 public InstructionHandle getStartPC() { 155 return start_pc; 156 } 157 158 159 /** @return end of handled region (inclusive) 160 */ getEndPC()161 public InstructionHandle getEndPC() { 162 return end_pc; 163 } 164 165 166 /** @return start of handler 167 */ getHandlerPC()168 public InstructionHandle getHandlerPC() { 169 return handler_pc; 170 } 171 172 173 @Override toString()174 public String toString() { 175 return "CodeExceptionGen(" + start_pc + ", " + end_pc + ", " + handler_pc + ")"; 176 } 177 178 179 @Override clone()180 public Object clone() { 181 try { 182 return super.clone(); 183 } catch (final CloneNotSupportedException e) { 184 throw new Error("Clone Not Supported"); // never happens 185 } 186 } 187 } 188