1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License.  Alternatively, the contents of this file may be used under
8  * the terms of the GNU Lesser General Public License Version 2.1 or later,
9  * or the Apache License Version 2.0.
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  */
16 
17 package javassist.expr;
18 
19 import javassist.CannotCompileException;
20 import javassist.CtBehavior;
21 import javassist.CtClass;
22 import javassist.NotFoundException;
23 import javassist.bytecode.Bytecode;
24 import javassist.bytecode.CodeAttribute;
25 import javassist.bytecode.CodeIterator;
26 import javassist.bytecode.ConstPool;
27 import javassist.bytecode.ExceptionTable;
28 import javassist.bytecode.MethodInfo;
29 import javassist.bytecode.Opcode;
30 import javassist.compiler.CompileError;
31 import javassist.compiler.Javac;
32 
33 /**
34  * A <code>catch</code> clause or a <code>finally</code> block.
35  */
36 public class Handler extends Expr {
37     private static String EXCEPTION_NAME = "$1";
38     private ExceptionTable etable;
39     private int index;
40 
41     /**
42      * Undocumented constructor.  Do not use; internal-use only.
43      */
Handler(ExceptionTable et, int nth, CodeIterator it, CtClass declaring, MethodInfo m)44     protected Handler(ExceptionTable et, int nth,
45                       CodeIterator it, CtClass declaring, MethodInfo m) {
46         super(et.handlerPc(nth), it, declaring, m);
47         etable = et;
48         index = nth;
49     }
50 
51     /**
52      * Returns the method or constructor containing the catch clause.
53      */
54     @Override
where()55     public CtBehavior where() { return super.where(); }
56 
57     /**
58      * Returns the source line number of the catch clause.
59      *
60      * @return -1       if this information is not available.
61      */
62     @Override
getLineNumber()63     public int getLineNumber() {
64         return super.getLineNumber();
65     }
66 
67     /**
68      * Returns the source file containing the catch clause.
69      *
70      * @return null     if this information is not available.
71      */
72     @Override
getFileName()73     public String getFileName() {
74         return super.getFileName();
75     }
76 
77     /**
78      * Returns the list of exceptions that the catch clause may throw.
79      */
80     @Override
mayThrow()81     public CtClass[] mayThrow() {
82         return super.mayThrow();
83     }
84 
85     /**
86      * Returns the type handled by the catch clause.
87      * If this is a <code>finally</code> block, <code>null</code> is returned.
88      */
getType()89     public CtClass getType() throws NotFoundException {
90         int type = etable.catchType(index);
91         if (type == 0)
92             return null;
93         ConstPool cp = getConstPool();
94         String name = cp.getClassInfo(type);
95         return thisClass.getClassPool().getCtClass(name);
96     }
97 
98     /**
99      * Returns true if this is a <code>finally</code> block.
100      */
isFinally()101     public boolean isFinally() {
102         return etable.catchType(index) == 0;
103     }
104 
105     /**
106      * This method has not been implemented yet.
107      *
108      * @param statement         a Java statement except try-catch.
109      */
110     @Override
replace(String statement)111     public void replace(String statement) throws CannotCompileException {
112         throw new RuntimeException("not implemented yet");
113     }
114 
115     /**
116      * Inserts bytecode at the beginning of the catch clause.
117      * The caught exception is stored in <code>$1</code>.
118      *
119      * @param src       the source code representing the inserted bytecode.
120      *                  It must be a single statement or block.
121      */
insertBefore(String src)122     public void insertBefore(String src) throws CannotCompileException {
123         edited = true;
124 
125         @SuppressWarnings("unused")
126         ConstPool cp = getConstPool();
127         CodeAttribute ca = iterator.get();
128         Javac jv = new Javac(thisClass);
129         Bytecode b = jv.getBytecode();
130         b.setStackDepth(1);
131         b.setMaxLocals(ca.getMaxLocals());
132 
133         try {
134             CtClass type = getType();
135             int var = jv.recordVariable(type, EXCEPTION_NAME);
136             jv.recordReturnType(type, false);
137             b.addAstore(var);
138             jv.compileStmnt(src);
139             b.addAload(var);
140 
141             int oldHandler = etable.handlerPc(index);
142             b.addOpcode(Opcode.GOTO);
143             b.addIndex(oldHandler - iterator.getCodeLength()
144                        - b.currentPc() + 1);
145 
146             maxStack = b.getMaxStack();
147             maxLocals = b.getMaxLocals();
148 
149             int pos = iterator.append(b.get());
150             iterator.append(b.getExceptionTable(), pos);
151             etable.setHandlerPc(index, pos);
152         }
153         catch (NotFoundException e) {
154             throw new CannotCompileException(e);
155         }
156         catch (CompileError e) {
157             throw new CannotCompileException(e);
158         }
159     }
160 }
161