1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * https://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.bcel.generic;
20
21 import org.apache.bcel.classfile.CodeException;
22
23 /**
24 * This class represents an exception handler, i.e., specifies the region where a handler is active and an instruction
25 * where the actual handling is done. pool as parameters. Opposed to the JVM specification the end of the handled region
26 * is set to be inclusive, i.e. all instructions between start and end are protected including the start and end
27 * instructions (handles) themselves. The end of the region is automatically mapped to be exclusive when calling
28 * getCodeException(), i.e., there is no difference semantically.
29 *
30 * @see MethodGen
31 * @see CodeException
32 * @see InstructionHandle
33 */
34 public final class CodeExceptionGen implements InstructionTargeter, Cloneable {
35
36 static final CodeExceptionGen[] EMPTY_ARRAY = {};
37
38 private InstructionHandle startPc;
39 private InstructionHandle endPc;
40 private InstructionHandle handlerPc;
41 private ObjectType catchType;
42
43 /**
44 * Add an exception handler, i.e., specify region where a handler is active and an instruction where the actual handling
45 * is done.
46 *
47 * @param startPc Start of handled region (inclusive)
48 * @param endPc End of handled region (inclusive)
49 * @param handlerPc Where handling is done
50 * @param catchType which exception is handled, null for ANY
51 */
52 public CodeExceptionGen(final InstructionHandle startPc, final InstructionHandle endPc, final InstructionHandle handlerPc, final ObjectType catchType) {
53 setStartPC(startPc);
54 setEndPC(endPc);
55 setHandlerPC(handlerPc);
56 this.catchType = catchType;
57 }
58
59 @Override
60 public Object clone() {
61 try {
62 return super.clone();
63 } catch (final CloneNotSupportedException e) {
64 throw new UnsupportedOperationException("Clone Not Supported", e); // never happens
65 }
66 }
67
68 /**
69 * @return true, if ih is target of this handler
70 */
71 @Override
72 public boolean containsTarget(final InstructionHandle ih) {
73 return startPc == ih || endPc == ih || handlerPc == ih;
74 }
75
76 /** Gets the type of the Exception to catch, 'null' for ANY. */
77 public ObjectType getCatchType() {
78 return catchType;
79 }
80
81 /**
82 * Gets CodeException object.<BR>
83 *
84 * This relies on that the instruction list has already been dumped to byte code or that the 'setPositions' methods
85 * has been called for the instruction list.
86 *
87 * @param cp constant pool
88 */
89 public CodeException getCodeException(final ConstantPoolGen cp) {
90 return new CodeException(startPc.getPosition(), endPc.getPosition() + endPc.getInstruction().getLength(), handlerPc.getPosition(),
91 catchType == null ? 0 : cp.addClass(catchType));
92 }
93
94 /**
95 * @return end of handled region (inclusive)
96 */
97 public InstructionHandle getEndPC() {
98 return endPc;
99 }
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 }