001: /*
002: * Javassist, a Java-bytecode translator toolkit.
003: * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
004: *
005: * The contents of this file are subject to the Mozilla Public License Version
006: * 1.1 (the "License"); you may not use this file except in compliance with
007: * the License. Alternatively, the contents of this file may be used under
008: * the terms of the GNU Lesser General Public License Version 2.1 or later.
009: *
010: * Software distributed under the License is distributed on an "AS IS" basis,
011: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
012: * for the specific language governing rights and limitations under the
013: * License.
014: */
015:
016: package javassist.expr;
017:
018: import javassist.*;
019: import javassist.bytecode.*;
020: import javassist.compiler.*;
021: import javassist.compiler.ast.ASTList;
022:
023: /**
024: * Object creation (<tt>new</tt> expression).
025: */
026: public class NewExpr extends Expr {
027: String newTypeName;
028: int newPos;
029:
030: /**
031: * Undocumented constructor. Do not use; internal-use only.
032: */
033: protected NewExpr(int pos, CodeIterator i, CtClass declaring,
034: MethodInfo m, String type, int np) {
035: super (pos, i, declaring, m);
036: newTypeName = type;
037: newPos = np;
038: }
039:
040: /*
041: * Not used
042: *
043: private int getNameAndType(ConstPool cp) {
044: int pos = currentPos;
045: int c = iterator.byteAt(pos);
046: int index = iterator.u16bitAt(pos + 1);
047:
048: if (c == INVOKEINTERFACE)
049: return cp.getInterfaceMethodrefNameAndType(index);
050: else
051: return cp.getMethodrefNameAndType(index);
052: } */
053:
054: /**
055: * Returns the method or constructor containing the <tt>new</tt>
056: * expression represented by this object.
057: */
058: public CtBehavior where() {
059: return super .where();
060: }
061:
062: /**
063: * Returns the line number of the source line containing the
064: * <tt>new</tt> expression.
065: *
066: * @return -1 if this information is not available.
067: */
068: public int getLineNumber() {
069: return super .getLineNumber();
070: }
071:
072: /**
073: * Returns the source file containing the <tt>new</tt> expression.
074: *
075: * @return null if this information is not available.
076: */
077: public String getFileName() {
078: return super .getFileName();
079: }
080:
081: /**
082: * Returns the class of the created object.
083: */
084: private CtClass getCtClass() throws NotFoundException {
085: return this Class.getClassPool().get(newTypeName);
086: }
087:
088: /**
089: * Returns the class name of the created object.
090: */
091: public String getClassName() {
092: return newTypeName;
093: }
094:
095: /**
096: * Get the signature of the constructor
097: *
098: * The signature is represented by a character string
099: * called method descriptor, which is defined in the JVM specification.
100: *
101: * @see javassist.CtBehavior#getSignature()
102: * @see javassist.bytecode.Descriptor
103: * @return the signature
104: */
105: public String getSignature() {
106: ConstPool constPool = getConstPool();
107: int methodIndex = iterator.u16bitAt(currentPos + 1); // constructor
108: return constPool.getMethodrefType(methodIndex);
109: }
110:
111: /**
112: * Returns the constructor called for creating the object.
113: */
114: public CtConstructor getConstructor() throws NotFoundException {
115: ConstPool cp = getConstPool();
116: int index = iterator.u16bitAt(currentPos + 1);
117: String desc = cp.getMethodrefType(index);
118: return getCtClass().getConstructor(desc);
119: }
120:
121: /**
122: * Returns the list of exceptions that the expression may throw.
123: * This list includes both the exceptions that the try-catch statements
124: * including the expression can catch and the exceptions that
125: * the throws declaration allows the method to throw.
126: */
127: public CtClass[] mayThrow() {
128: return super .mayThrow();
129: }
130:
131: /*
132: * Returns the parameter types of the constructor.
133:
134: public CtClass[] getParameterTypes() throws NotFoundException {
135: ConstPool cp = getConstPool();
136: int index = iterator.u16bitAt(currentPos + 1);
137: String desc = cp.getMethodrefType(index);
138: return Descriptor.getParameterTypes(desc, thisClass.getClassPool());
139: }
140: */
141:
142: private int canReplace() throws CannotCompileException {
143: int op = iterator.byteAt(newPos + 3);
144: if (op == Opcode.DUP)
145: return 4;
146: else if (op == Opcode.DUP_X1
147: && iterator.byteAt(newPos + 4) == Opcode.SWAP)
148: return 5;
149: else if (op == Opcode.INVOKESPECIAL)
150: return 3; // for Eclipse's compiler
151: else
152: throw new CannotCompileException(
153: "sorry, cannot edit NEW followed by no DUP");
154: }
155:
156: /**
157: * Replaces the <tt>new</tt> expression with the bytecode derived from
158: * the given source text.
159: *
160: * <p>$0 is available but the value is null.
161: *
162: * @param statement a Java statement.
163: */
164: public void replace(String statement) throws CannotCompileException {
165: final int bytecodeSize = 3;
166: int pos = newPos;
167:
168: int newIndex = iterator.u16bitAt(pos + 1);
169:
170: /* delete the preceding NEW and DUP (or DUP_X1, SWAP) instructions.
171: */
172: int end = pos + canReplace();
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(this Class);
183: ClassPool cp = this Class.getClassPool();
184: CodeAttribute ca = iterator.get();
185: try {
186: CtClass[] params = Descriptor.getParameterTypes(signature,
187: cp);
188: CtClass newType = cp.get(newTypeName);
189: int paramVar = ca.getMaxLocals();
190: jc.recordParams(newTypeName, params, true, paramVar,
191: withinStatic());
192: int retVar = jc.recordReturnType(newType, true);
193: jc.recordProceed(new ProceedForNew(newType, newIndex,
194: methodIndex));
195:
196: /* Is $_ included in the source code?
197: */
198: checkResultValue(newType, statement);
199:
200: Bytecode bytecode = jc.getBytecode();
201: storeStack(params, true, paramVar, bytecode);
202: jc.recordLocalVariables(ca, pos);
203:
204: bytecode.addConstZero(newType);
205: bytecode.addStore(retVar, newType); // initialize $_
206:
207: jc.compileStmnt(statement);
208: bytecode.addAload(retVar);
209:
210: replace0(pos, bytecode, bytecodeSize);
211: } catch (CompileError e) {
212: throw new CannotCompileException(e);
213: } catch (NotFoundException e) {
214: throw new CannotCompileException(e);
215: } catch (BadBytecode e) {
216: throw new CannotCompileException("broken method");
217: }
218: }
219:
220: static class ProceedForNew implements ProceedHandler {
221: CtClass newType;
222: int newIndex, methodIndex;
223:
224: ProceedForNew(CtClass nt, int ni, int mi) {
225: newType = nt;
226: newIndex = ni;
227: methodIndex = mi;
228: }
229:
230: public void doit(JvstCodeGen gen, Bytecode bytecode,
231: ASTList args) throws CompileError {
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:
240: public void setReturnType(JvstTypeChecker c, ASTList args)
241: throws CompileError {
242: c.atMethodCallCore(newType, MethodInfo.nameInit, args);
243: c.setType(newType);
244: }
245: }
246: }
|