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 */
018 package org.apache.bcel.generic;
019
020 import org.apache.bcel.classfile.CodeException;
021
022 /**
023 * This class represents an exception handler, i.e., specifies the region where
024 * a handler is active and an instruction where the actual handling is done.
025 * pool as parameters. Opposed to the JVM specification the end of the handled
026 * region is set to be inclusive, i.e. all instructions between start and end
027 * are protected including the start and end instructions (handles) themselves.
028 * The end of the region is automatically mapped to be exclusive when calling
029 * getCodeException(), i.e., there is no difference semantically.
030 *
031 * @version $Id: CodeExceptionGen.java 1152072 2011-07-29 01:54:05Z dbrosius $
032 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
033 * @see MethodGen
034 * @see CodeException
035 * @see InstructionHandle
036 */
037 public final class CodeExceptionGen implements InstructionTargeter, Cloneable, java.io.Serializable {
038
039 private static final long serialVersionUID = 6548901422158960190L;
040 private InstructionHandle start_pc;
041 private InstructionHandle end_pc;
042 private InstructionHandle handler_pc;
043 private ObjectType catch_type;
044
045
046 /**
047 * Add an exception handler, i.e., specify region where a handler is active and an
048 * instruction where the actual handling is done.
049 *
050 * @param start_pc Start of handled region (inclusive)
051 * @param end_pc End of handled region (inclusive)
052 * @param handler_pc Where handling is done
053 * @param catch_type which exception is handled, null for ANY
054 */
055 public CodeExceptionGen(InstructionHandle start_pc, InstructionHandle end_pc,
056 InstructionHandle handler_pc, ObjectType catch_type) {
057 setStartPC(start_pc);
058 setEndPC(end_pc);
059 setHandlerPC(handler_pc);
060 this.catch_type = catch_type;
061 }
062
063
064 /**
065 * Get CodeException object.<BR>
066 *
067 * This relies on that the instruction list has already been dumped
068 * to byte code or or that the `setPositions' methods has been
069 * called for the instruction list.
070 *
071 * @param cp constant pool
072 */
073 public CodeException getCodeException( ConstantPoolGen cp ) {
074 return new CodeException(start_pc.getPosition(), end_pc.getPosition()
075 + end_pc.getInstruction().getLength(), handler_pc.getPosition(),
076 (catch_type == null) ? 0 : cp.addClass(catch_type));
077 }
078
079
080 /* Set start of handler
081 * @param start_pc Start of handled region (inclusive)
082 */
083 public void setStartPC( InstructionHandle start_pc ) {
084 BranchInstruction.notifyTarget(this.start_pc, start_pc, this);
085 this.start_pc = start_pc;
086 }
087
088
089 /* Set end of handler
090 * @param end_pc End of handled region (inclusive)
091 */
092 public void setEndPC( InstructionHandle end_pc ) {
093 BranchInstruction.notifyTarget(this.end_pc, end_pc, this);
094 this.end_pc = end_pc;
095 }
096
097
098 /* Set handler code
099 * @param handler_pc Start of handler
100 */
101 public void setHandlerPC( InstructionHandle handler_pc ) {
102 BranchInstruction.notifyTarget(this.handler_pc, handler_pc, this);
103 this.handler_pc = handler_pc;
104 }
105
106
107 /**
108 * @param old_ih old target, either start or end
109 * @param new_ih new target
110 */
111 public void updateTarget( InstructionHandle old_ih, InstructionHandle new_ih ) {
112 boolean targeted = false;
113 if (start_pc == old_ih) {
114 targeted = true;
115 setStartPC(new_ih);
116 }
117 if (end_pc == old_ih) {
118 targeted = true;
119 setEndPC(new_ih);
120 }
121 if (handler_pc == old_ih) {
122 targeted = true;
123 setHandlerPC(new_ih);
124 }
125 if (!targeted) {
126 throw new ClassGenException("Not targeting " + old_ih + ", but {" + start_pc + ", "
127 + end_pc + ", " + handler_pc + "}");
128 }
129 }
130
131
132 /**
133 * @return true, if ih is target of this handler
134 */
135 public boolean containsTarget( 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. */
141 public void setCatchType( ObjectType catch_type ) {
142 this.catch_type = catch_type;
143 }
144
145
146 /** Gets the type of the Exception to catch, 'null' for ANY. */
147 public ObjectType getCatchType() {
148 return catch_type;
149 }
150
151
152 /** @return start of handled region (inclusive)
153 */
154 public InstructionHandle getStartPC() {
155 return start_pc;
156 }
157
158
159 /** @return end of handled region (inclusive)
160 */
161 public InstructionHandle getEndPC() {
162 return end_pc;
163 }
164
165
166 /** @return start of handler
167 */
168 public InstructionHandle getHandlerPC() {
169 return handler_pc;
170 }
171
172
173 @Override
174 public String toString() {
175 return "CodeExceptionGen(" + start_pc + ", " + end_pc + ", " + handler_pc + ")";
176 }
177
178
179 @Override
180 public Object clone() {
181 try {
182 return super.clone();
183 } catch (CloneNotSupportedException e) {
184 System.err.println(e);
185 return null;
186 }
187 }
188 }