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, that is, 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, for example 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(), that is, 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, that is, 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 /** 077 * Gets the type of the Exception to catch, 'null' for ANY. 078 * 079 * @return the type of the Exception to catch, 'null' for ANY. 080 */ 081 public ObjectType getCatchType() { 082 return catchType; 083 } 084 085 /** 086 * Gets CodeException object. 087 * 088 * This relies on that the instruction list has already been dumped to byte code or that the 'setPositions' methods 089 * has been called for the instruction list. 090 * 091 * @param cp constant pool. 092 * @return the CodeException object. 093 */ 094 public CodeException getCodeException(final ConstantPoolGen cp) { 095 return new CodeException(startPc.getPosition(), endPc.getPosition() + endPc.getInstruction().getLength(), handlerPc.getPosition(), 096 catchType == null ? 0 : cp.addClass(catchType)); 097 } 098 099 /** 100 * Gets the end of handled region (inclusive). 101 * 102 * @return end of handled region (inclusive). 103 */ 104 public InstructionHandle getEndPC() { 105 return endPc; 106 } 107 108 /** 109 * Gets the start of handler. 110 * 111 * @return start of handler. 112 */ 113 public InstructionHandle getHandlerPC() { 114 return handlerPc; 115 } 116 117 /** 118 * Gets the start of handled region (inclusive). 119 * 120 * @return start of handled region (inclusive). 121 */ 122 public InstructionHandle getStartPC() { 123 return startPc; 124 } 125 126 /** 127 * Sets the type of the Exception to catch. Set 'null' for ANY. 128 * 129 * @param catchType the type of the Exception to catch. 130 */ 131 public void setCatchType(final ObjectType catchType) { 132 this.catchType = catchType; 133 } 134 135 /** 136 * Sets end of handler. 137 * 138 * @param endPc End of handled region (inclusive). 139 */ 140 public void setEndPC(final InstructionHandle endPc) { // TODO could be package-protected? 141 BranchInstruction.notifyTarget(this.endPc, endPc, this); 142 this.endPc = endPc; 143 } 144 145 /** 146 * Sets handler code. 147 * 148 * @param handlerPc Start of handler. 149 */ 150 public void setHandlerPC(final InstructionHandle handlerPc) { // TODO could be package-protected? 151 BranchInstruction.notifyTarget(this.handlerPc, handlerPc, this); 152 this.handlerPc = handlerPc; 153 } 154 155 /** 156 * Sets start of handler. 157 * 158 * @param startPc Start of handled region (inclusive). 159 */ 160 public void setStartPC(final InstructionHandle startPc) { // TODO could be package-protected? 161 BranchInstruction.notifyTarget(this.startPc, startPc, this); 162 this.startPc = startPc; 163 } 164 165 @Override 166 public String toString() { 167 return "CodeExceptionGen(" + startPc + ", " + endPc + ", " + handlerPc + ")"; 168 } 169 170 /** 171 * @param oldIh old target, either start or end. 172 * @param newIh new target. 173 */ 174 @Override 175 public void updateTarget(final InstructionHandle oldIh, final InstructionHandle newIh) { 176 boolean targeted = false; 177 if (startPc == oldIh) { 178 targeted = true; 179 setStartPC(newIh); 180 } 181 if (endPc == oldIh) { 182 targeted = true; 183 setEndPC(newIh); 184 } 185 if (handlerPc == oldIh) { 186 targeted = true; 187 setHandlerPC(newIh); 188 } 189 if (!targeted) { 190 throw new ClassGenException("Not targeting " + oldIh + ", but {" + startPc + ", " + endPc + ", " + handlerPc + "}"); 191 } 192 } 193}