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}