• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999-2007 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  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  */
15 
16 package javassist.expr;
17 
18 import javassist.*;
19 import javassist.bytecode.*;
20 import javassist.compiler.*;
21 import javassist.compiler.ast.ASTList;
22 
23 /**
24  * Object creation (<tt>new</tt> expression).
25  */
26 public class NewExpr extends Expr {
27     String newTypeName;
28     int newPos;
29 
30     /**
31      * Undocumented constructor.  Do not use; internal-use only.
32      */
NewExpr(int pos, CodeIterator i, CtClass declaring, MethodInfo m, String type, int np)33     protected NewExpr(int pos, CodeIterator i, CtClass declaring,
34                       MethodInfo m, String type, int np) {
35         super(pos, i, declaring, m);
36         newTypeName = type;
37         newPos = np;
38     }
39 
40     /*
41      * Not used
42      *
43     private int getNameAndType(ConstPool cp) {
44         int pos = currentPos;
45         int c = iterator.byteAt(pos);
46         int index = iterator.u16bitAt(pos + 1);
47 
48         if (c == INVOKEINTERFACE)
49             return cp.getInterfaceMethodrefNameAndType(index);
50         else
51             return cp.getMethodrefNameAndType(index);
52     } */
53 
54     /**
55      * Returns the method or constructor containing the <tt>new</tt>
56      * expression represented by this object.
57      */
where()58     public CtBehavior where() { return super.where(); }
59 
60     /**
61      * Returns the line number of the source line containing the
62      * <tt>new</tt> expression.
63      *
64      * @return -1       if this information is not available.
65      */
getLineNumber()66     public int getLineNumber() {
67         return super.getLineNumber();
68     }
69 
70     /**
71      * Returns the source file containing the <tt>new</tt> expression.
72      *
73      * @return null     if this information is not available.
74      */
getFileName()75     public String getFileName() {
76         return super.getFileName();
77     }
78 
79     /**
80      * Returns the class of the created object.
81      */
getCtClass()82     private CtClass getCtClass() throws NotFoundException {
83         return thisClass.getClassPool().get(newTypeName);
84     }
85 
86     /**
87      * Returns the class name of the created object.
88      */
getClassName()89     public String getClassName() {
90         return newTypeName;
91     }
92 
93     /**
94      * Get the signature of the constructor
95      *
96      * The signature is represented by a character string
97      * called method descriptor, which is defined in the JVM specification.
98      *
99      * @see javassist.CtBehavior#getSignature()
100      * @see javassist.bytecode.Descriptor
101      * @return the signature
102      */
getSignature()103     public String getSignature() {
104         ConstPool constPool = getConstPool();
105         int methodIndex = iterator.u16bitAt(currentPos + 1);   // constructor
106         return constPool.getMethodrefType(methodIndex);
107     }
108 
109     /**
110      * Returns the constructor called for creating the object.
111      */
getConstructor()112     public CtConstructor getConstructor() throws NotFoundException {
113         ConstPool cp = getConstPool();
114         int index = iterator.u16bitAt(currentPos + 1);
115         String desc = cp.getMethodrefType(index);
116         return getCtClass().getConstructor(desc);
117     }
118 
119     /**
120      * Returns the list of exceptions that the expression may throw.
121      * This list includes both the exceptions that the try-catch statements
122      * including the expression can catch and the exceptions that
123      * the throws declaration allows the method to throw.
124      */
mayThrow()125     public CtClass[] mayThrow() {
126         return super.mayThrow();
127     }
128 
129     /*
130      * Returns the parameter types of the constructor.
131 
132     public CtClass[] getParameterTypes() throws NotFoundException {
133         ConstPool cp = getConstPool();
134         int index = iterator.u16bitAt(currentPos + 1);
135         String desc = cp.getMethodrefType(index);
136         return Descriptor.getParameterTypes(desc, thisClass.getClassPool());
137     }
138     */
139 
canReplace()140     private int canReplace() throws CannotCompileException {
141         int op = iterator.byteAt(newPos + 3);
142         if (op == Opcode.DUP)
143             return 4;
144         else if (op == Opcode.DUP_X1
145                  && iterator.byteAt(newPos + 4) == Opcode.SWAP)
146             return 5;
147         else
148             return 3;   // for Eclipse.  The generated code may include no DUP.
149             // throw new CannotCompileException(
150             //            "sorry, cannot edit NEW followed by no DUP");
151     }
152 
153     /**
154      * Replaces the <tt>new</tt> expression with the bytecode derived from
155      * the given source text.
156      *
157      * <p>$0 is available but the value is null.
158      *
159      * @param statement         a Java statement except try-catch.
160      */
replace(String statement)161     public void replace(String statement) throws CannotCompileException {
162         thisClass.getClassFile();   // to call checkModify().
163 
164         final int bytecodeSize = 3;
165         int pos = newPos;
166 
167         int newIndex = iterator.u16bitAt(pos + 1);
168 
169         /* delete the preceding NEW and DUP (or DUP_X1, SWAP) instructions.
170          */
171         int codeSize = canReplace();
172         int end = pos + codeSize;
173         for (int i = pos; i < end; ++i)
174             iterator.writeByte(NOP, i);
175 
176         ConstPool constPool = getConstPool();
177         pos = currentPos;
178         int methodIndex = iterator.u16bitAt(pos + 1);   // constructor
179 
180         String signature = constPool.getMethodrefType(methodIndex);
181 
182         Javac jc = new Javac(thisClass);
183         ClassPool cp = thisClass.getClassPool();
184         CodeAttribute ca = iterator.get();
185         try {
186             CtClass[] params = Descriptor.getParameterTypes(signature, cp);
187             CtClass newType = cp.get(newTypeName);
188             int paramVar = ca.getMaxLocals();
189             jc.recordParams(newTypeName, params,
190                             true, paramVar, withinStatic());
191             int retVar = jc.recordReturnType(newType, true);
192             jc.recordProceed(new ProceedForNew(newType, newIndex,
193                                                methodIndex));
194 
195             /* Is $_ included in the source code?
196              */
197             checkResultValue(newType, statement);
198 
199             Bytecode bytecode = jc.getBytecode();
200             storeStack(params, true, paramVar, bytecode);
201             jc.recordLocalVariables(ca, pos);
202 
203             bytecode.addConstZero(newType);
204             bytecode.addStore(retVar, newType);     // initialize $_
205 
206             jc.compileStmnt(statement);
207             if (codeSize > 3)   // if the original code includes DUP.
208                 bytecode.addAload(retVar);
209 
210             replace0(pos, bytecode, bytecodeSize);
211         }
212         catch (CompileError e) { throw new CannotCompileException(e); }
213         catch (NotFoundException e) { throw new CannotCompileException(e); }
214         catch (BadBytecode e) {
215             throw new CannotCompileException("broken method");
216         }
217     }
218 
219     static class ProceedForNew implements ProceedHandler {
220         CtClass newType;
221         int newIndex, methodIndex;
222 
ProceedForNew(CtClass nt, int ni, int mi)223         ProceedForNew(CtClass nt, int ni, int mi) {
224             newType = nt;
225             newIndex = ni;
226             methodIndex = mi;
227         }
228 
doit(JvstCodeGen gen, Bytecode bytecode, ASTList args)229         public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args)
230             throws CompileError
231         {
232             bytecode.addOpcode(NEW);
233             bytecode.addIndex(newIndex);
234             bytecode.addOpcode(DUP);
235             gen.atMethodCallCore(newType, MethodInfo.nameInit, args,
236                                  false, true, -1, null);
237             gen.setType(newType);
238         }
239 
setReturnType(JvstTypeChecker c, ASTList args)240         public void setReturnType(JvstTypeChecker c, ASTList args)
241             throws CompileError
242         {
243             c.atMethodCallCore(newType, MethodInfo.nameInit, args);
244             c.setType(newType);
245         }
246     }
247 }
248