1/*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5/*
6 * Licensed to the Apache Software Foundation (ASF) under one or more
7 * contributor license agreements.  See the NOTICE file distributed with
8 * this work for additional information regarding copyright ownership.
9 * The ASF licenses this file to You under the Apache License, Version 2.0
10 * (the "License"); you may not use this file except in compliance with
11 * the License.  You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21package com.sun.org.apache.bcel.internal.generic;
22
23import com.sun.org.apache.bcel.internal.classfile.CodeException;
24
25/**
26 * This class represents an exception handler, i.e., specifies the region where
27 * a handler is active and an instruction where the actual handling is done.
28 * pool as parameters. Opposed to the JVM specification the end of the handled
29 * region is set to be inclusive, i.e. all instructions between start and end
30 * are protected including the start and end instructions (handles) themselves.
31 * The end of the region is automatically mapped to be exclusive when calling
32 * getCodeException(), i.e., there is no difference semantically.
33 *
34 * @version $Id: CodeExceptionGen.java 1749603 2016-06-21 20:50:19Z ggregory $
35 * @see MethodGen
36 * @see CodeException
37 * @see InstructionHandle
38 */
39public final class CodeExceptionGen implements InstructionTargeter, Cloneable {
40
41    private InstructionHandle start_pc;
42    private InstructionHandle end_pc;
43    private InstructionHandle handler_pc;
44    private ObjectType catch_type;
45
46    /**
47     * Add an exception handler, i.e., specify region where a handler is active
48     * and an instruction where the actual handling is done.
49     *
50     * @param start_pc Start of handled region (inclusive)
51     * @param end_pc End of handled region (inclusive)
52     * @param handler_pc Where handling is done
53     * @param catch_type which exception is handled, null for ANY
54     */
55    public CodeExceptionGen(final InstructionHandle start_pc, final InstructionHandle end_pc,
56            final InstructionHandle handler_pc, final ObjectType catch_type) {
57        setStartPC(start_pc);
58        setEndPC(end_pc);
59        setHandlerPC(handler_pc);
60        this.catch_type = catch_type;
61    }
62
63    /**
64     * Get CodeException object.<BR>
65     *
66     * This relies on that the instruction list has already been dumped to byte
67     * code or or that the `setPositions' methods has been called for the
68     * instruction list.
69     *
70     * @param cp constant pool
71     */
72    public CodeException getCodeException(final ConstantPoolGen cp) {
73        return new CodeException(start_pc.getPosition(), end_pc.getPosition()
74                + end_pc.getInstruction().getLength(), handler_pc.getPosition(),
75                (catch_type == null) ? 0 : cp.addClass(catch_type));
76    }
77
78
79    /* Set start of handler
80     * @param start_pc Start of handled region (inclusive)
81     */
82    public void setStartPC(final InstructionHandle start_pc) { // TODO could be package-protected?
83        BranchInstruction.notifyTarget(this.start_pc, start_pc, this);
84        this.start_pc = start_pc;
85    }
86
87
88    /* Set end of handler
89     * @param end_pc End of handled region (inclusive)
90     */
91    public void setEndPC(final InstructionHandle end_pc) { // TODO could be package-protected?
92        BranchInstruction.notifyTarget(this.end_pc, end_pc, this);
93        this.end_pc = end_pc;
94    }
95
96
97    /* Set handler code
98     * @param handler_pc Start of handler
99     */
100    public void setHandlerPC(final InstructionHandle handler_pc) { // TODO could be package-protected?
101        BranchInstruction.notifyTarget(this.handler_pc, handler_pc, this);
102        this.handler_pc = handler_pc;
103    }
104
105    /**
106     * @param old_ih old target, either start or end
107     * @param new_ih new target
108     */
109    @Override
110    public void updateTarget(final InstructionHandle old_ih, final InstructionHandle new_ih) {
111        boolean targeted = false;
112        if (start_pc == old_ih) {
113            targeted = true;
114            setStartPC(new_ih);
115        }
116        if (end_pc == old_ih) {
117            targeted = true;
118            setEndPC(new_ih);
119        }
120        if (handler_pc == old_ih) {
121            targeted = true;
122            setHandlerPC(new_ih);
123        }
124        if (!targeted) {
125            throw new ClassGenException("Not targeting " + old_ih + ", but {" + start_pc + ", "
126                    + end_pc + ", " + handler_pc + "}");
127        }
128    }
129
130    /**
131     * @return true, if ih is target of this handler
132     */
133    @Override
134    public boolean containsTarget(final InstructionHandle ih) {
135        return (start_pc == ih) || (end_pc == ih) || (handler_pc == ih);
136    }
137
138    /**
139     * Sets the type of the Exception to catch. Set 'null' for ANY.
140     */
141    public void setCatchType(final 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     */
148    public ObjectType getCatchType() {
149        return catch_type;
150    }
151
152    /**
153     * @return start of handled region (inclusive)
154     */
155    public InstructionHandle getStartPC() {
156        return start_pc;
157    }
158
159    /**
160     * @return end of handled region (inclusive)
161     */
162    public InstructionHandle getEndPC() {
163        return end_pc;
164    }
165
166    /**
167     * @return start of handler
168     */
169    public InstructionHandle getHandlerPC() {
170        return handler_pc;
171    }
172
173    @Override
174    public String toString() {
175        return "CodeExceptionGen(" + start_pc + ", " + end_pc + ", " + handler_pc + ")";
176    }
177
178    @Override
179    public Object clone() {
180        try {
181            return super.clone();
182        } catch (final CloneNotSupportedException e) {
183            throw new Error("Clone Not Supported"); // never happens
184        }
185    }
186}
187