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    }