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}