/Users/lyon/j4p/src/javassist/expr/NewExpr.java
|
1 /*
2 * Javassist, a Java-bytecode translator toolkit.
3 * Copyright (C) 1999-2003 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.ASTree;
22 import javassist.compiler.ast.ASTList;
23
24 /**
25 * Object creation (<tt>new</tt> expression).
26 */
27 public class NewExpr extends Expr {
28 String newTypeName;
29 int newPos;
30
31 /**
32 * Undocumented constructor. Do not use; internal-use only.
33 */
34 NewExpr(int pos, CodeIterator i, CtClass declaring, MethodInfo m,
35 String type, int np) {
36 super(pos, i, declaring, m);
37 newTypeName = type;
38 newPos = np;
39 }
40
41 private int getNameAndType(ConstPool cp) {
42 String cname;
43 int pos = currentPos;
44 int c = iterator.byteAt(pos);
45 int index = iterator.u16bitAt(pos + 1);
46
47 if (c == INVOKEINTERFACE)
48 return cp.getInterfaceMethodrefNameAndType(index);
49 else
50 return cp.getMethodrefNameAndType(index);
51 }
52
53 /**
54 * Returns the method or constructor containing the <tt>new</tt>
55 * expression represented by this object.
56 */
57 public CtBehavior where() {
58 return super.where();
59 }
60
61 /**
62 * Returns the line number of the source line containing the
63 * <tt>new</tt> expression.
64 *
65 * @return -1 if this information is not available.
66 */
67 public int getLineNumber() {
68 return super.getLineNumber();
69 }
70
71 /**
72 * Returns the source file containing the <tt>new</tt> expression.
73 *
74 * @return null if this information is not available.
75 */
76 public String getFileName() {
77 return super.getFileName();
78 }
79
80 /**
81 * Returns the class of the created object.
82 */
83 private CtClass getCtClass() throws NotFoundException {
84 return thisClass.getClassPool().get(newTypeName);
85 }
86
87 /**
88 * Returns the class name of the created object.
89 */
90 public String getClassName() {
91 return newTypeName;
92 }
93
94 /**
95 * Returns the constructor called for creating the object.
96 */
97 public CtConstructor getConstructor() throws NotFoundException {
98 ConstPool cp = getConstPool();
99 int index = iterator.u16bitAt(currentPos + 1);
100 String desc = cp.getMethodrefType(index);
101 return getCtClass().getConstructor(desc);
102 }
103
104 /**
105 * Returns the list of exceptions that the expression may throw.
106 * This list includes both the exceptions that the try-catch statements
107 * including the expression can catch and the exceptions that
108 * the throws declaration allows the method to throw.
109 */
110 public CtClass[] mayThrow() {
111 return super.mayThrow();
112 }
113
114 /*
115 * Returns the parameter types of the constructor.
116
117 public CtClass[] getParameterTypes() throws NotFoundException {
118 ConstPool cp = getConstPool();
119 int index = iterator.u16bitAt(currentPos + 1);
120 String desc = cp.getMethodrefType(index);
121 return Descriptor.getParameterTypes(desc, thisClass.getClassPool());
122 }
123 */
124
125 private int canReplace() throws CannotCompileException {
126 int op = iterator.byteAt(newPos + 3);
127 if (op == Opcode.DUP)
128 return 4;
129 else if (op == Opcode.DUP_X1
130 && iterator.byteAt(newPos + 4) == Opcode.SWAP)
131 return 5;
132 else
133 throw new CannotCompileException(
134 "sorry, cannot edit NEW followed by no DUP");
135 }
136
137 /**
138 * Replaces the <tt>new</tt> expression with the bytecode derived from
139 * the given source text.
140 *
141 * <p>$0 is available but the value is null.
142 *
143 * @param statement a Java statement.
144 */
145 public void replace(String statement) throws CannotCompileException {
146 final int bytecodeSize = 3;
147 int pos = newPos;
148
149 int newIndex = iterator.u16bitAt(pos + 1);
150
151 /* delete the preceding NEW and DUP (or DUP_X1, SWAP) instructions.
152 */
153 int end = pos + canReplace();
154 for (int i = pos; i < end; ++i)
155 iterator.writeByte(NOP, i);
156
157 ConstPool constPool = getConstPool();
158 pos = currentPos;
159 int methodIndex = iterator.u16bitAt(pos + 1); // constructor
160
161 String signature = constPool.getMethodrefType(methodIndex);
162
163 Javac jc = new Javac(thisClass);
164 ClassPool cp = thisClass.getClassPool();
165 CodeAttribute ca = iterator.get();
166 try {
167 CtClass[] params = Descriptor.getParameterTypes(signature, cp);
168 CtClass newType = cp.get(newTypeName);
169 int paramVar = ca.getMaxLocals();
170 jc.recordParams(newTypeName, params,
171 true, paramVar, withinStatic());
172 int retVar = jc.recordReturnType(newType, true);
173 jc.recordProceed(new ProceedForNew(newType, newIndex,
174 methodIndex));
175
176 /* Is $_ included in the source code?
177 */
178 checkResultValue(newType, statement);
179
180 Bytecode bytecode = jc.getBytecode();
181 storeStack(params, true, paramVar, bytecode);
182 jc.compileStmnt(statement);
183 bytecode.addAload(retVar);
184
185 replace0(pos, bytecode, bytecodeSize);
186 } catch (CompileError e) {
187 throw new CannotCompileException(e);
188 } catch (NotFoundException e) {
189 throw new CannotCompileException(e);
190 } catch (BadBytecode e) {
191 throw new CannotCompileException("broken method");
192 }
193 }
194
195 static class ProceedForNew implements ProceedHandler {
196 CtClass newType;
197 int newIndex, methodIndex;
198
199 ProceedForNew(CtClass nt, int ni, int mi) {
200 newType = nt;
201 newIndex = ni;
202 methodIndex = mi;
203 }
204
205 public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args)
206 throws CompileError {
207 bytecode.addOpcode(NEW);
208 bytecode.addIndex(newIndex);
209 bytecode.addOpcode(DUP);
210 gen.atMethodCall2(newType, MethodInfo.nameInit,
211 args, false, true);
212 gen.setType(newType);
213 }
214 }
215 }
216