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