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 22 /** 23 * Method invocation (caller-side expression). 24 */ 25 public class MethodCall extends Expr { 26 /** 27 * Undocumented constructor. Do not use; internal-use only. 28 */ MethodCall(int pos, CodeIterator i, CtClass declaring, MethodInfo m)29 protected MethodCall(int pos, CodeIterator i, CtClass declaring, 30 MethodInfo m) { 31 super(pos, i, declaring, m); 32 } 33 getNameAndType(ConstPool cp)34 private int getNameAndType(ConstPool cp) { 35 int pos = currentPos; 36 int c = iterator.byteAt(pos); 37 int index = iterator.u16bitAt(pos + 1); 38 39 if (c == INVOKEINTERFACE) 40 return cp.getInterfaceMethodrefNameAndType(index); 41 else 42 return cp.getMethodrefNameAndType(index); 43 } 44 45 /** 46 * Returns the method or constructor containing the method-call 47 * expression represented by this object. 48 */ where()49 public CtBehavior where() { return super.where(); } 50 51 /** 52 * Returns the line number of the source line containing the 53 * method call. 54 * 55 * @return -1 if this information is not available. 56 */ getLineNumber()57 public int getLineNumber() { 58 return super.getLineNumber(); 59 } 60 61 /** 62 * Returns the source file containing the method call. 63 * 64 * @return null if this information is not available. 65 */ getFileName()66 public String getFileName() { 67 return super.getFileName(); 68 } 69 70 /** 71 * Returns the class of the target object, 72 * which the method is called on. 73 */ getCtClass()74 protected CtClass getCtClass() throws NotFoundException { 75 return thisClass.getClassPool().get(getClassName()); 76 } 77 78 /** 79 * Returns the class name of the target object, 80 * which the method is called on. 81 */ getClassName()82 public String getClassName() { 83 String cname; 84 85 ConstPool cp = getConstPool(); 86 int pos = currentPos; 87 int c = iterator.byteAt(pos); 88 int index = iterator.u16bitAt(pos + 1); 89 90 if (c == INVOKEINTERFACE) 91 cname = cp.getInterfaceMethodrefClassName(index); 92 else 93 cname = cp.getMethodrefClassName(index); 94 95 if (cname.charAt(0) == '[') 96 cname = Descriptor.toClassName(cname); 97 98 return cname; 99 } 100 101 /** 102 * Returns the name of the called method. 103 */ getMethodName()104 public String getMethodName() { 105 ConstPool cp = getConstPool(); 106 int nt = getNameAndType(cp); 107 return cp.getUtf8Info(cp.getNameAndTypeName(nt)); 108 } 109 110 /** 111 * Returns the called method. 112 */ getMethod()113 public CtMethod getMethod() throws NotFoundException { 114 return getCtClass().getMethod(getMethodName(), getSignature()); 115 } 116 117 /** 118 * Returns the method signature (the parameter types 119 * and the return type). 120 * The method signature is represented by a character string 121 * called method descriptor, which is defined in the JVM specification. 122 * 123 * @see javassist.CtBehavior#getSignature() 124 * @see javassist.bytecode.Descriptor 125 * @since 3.1 126 */ getSignature()127 public String getSignature() { 128 ConstPool cp = getConstPool(); 129 int nt = getNameAndType(cp); 130 return cp.getUtf8Info(cp.getNameAndTypeDescriptor(nt)); 131 } 132 133 /** 134 * Returns the list of exceptions that the expression may throw. 135 * This list includes both the exceptions that the try-catch statements 136 * including the expression can catch and the exceptions that 137 * the throws declaration allows the method to throw. 138 */ mayThrow()139 public CtClass[] mayThrow() { 140 return super.mayThrow(); 141 } 142 143 /** 144 * Returns true if the called method is of a superclass of the current 145 * class. 146 */ isSuper()147 public boolean isSuper() { 148 return iterator.byteAt(currentPos) == INVOKESPECIAL 149 && !where().getDeclaringClass().getName().equals(getClassName()); 150 } 151 152 /* 153 * Returns the parameter types of the called method. 154 155 public CtClass[] getParameterTypes() throws NotFoundException { 156 return Descriptor.getParameterTypes(getMethodDesc(), 157 thisClass.getClassPool()); 158 } 159 */ 160 161 /* 162 * Returns the return type of the called method. 163 164 public CtClass getReturnType() throws NotFoundException { 165 return Descriptor.getReturnType(getMethodDesc(), 166 thisClass.getClassPool()); 167 } 168 */ 169 170 /** 171 * Replaces the method call with the bytecode derived from 172 * the given source text. 173 * 174 * <p>$0 is available even if the called method is static. 175 * 176 * @param statement a Java statement except try-catch. 177 */ replace(String statement)178 public void replace(String statement) throws CannotCompileException { 179 thisClass.getClassFile(); // to call checkModify(). 180 ConstPool constPool = getConstPool(); 181 int pos = currentPos; 182 int index = iterator.u16bitAt(pos + 1); 183 184 String classname, methodname, signature; 185 int opcodeSize; 186 int c = iterator.byteAt(pos); 187 if (c == INVOKEINTERFACE) { 188 opcodeSize = 5; 189 classname = constPool.getInterfaceMethodrefClassName(index); 190 methodname = constPool.getInterfaceMethodrefName(index); 191 signature = constPool.getInterfaceMethodrefType(index); 192 } 193 else if (c == INVOKESTATIC 194 || c == INVOKESPECIAL || c == INVOKEVIRTUAL) { 195 opcodeSize = 3; 196 classname = constPool.getMethodrefClassName(index); 197 methodname = constPool.getMethodrefName(index); 198 signature = constPool.getMethodrefType(index); 199 } 200 else 201 throw new CannotCompileException("not method invocation"); 202 203 Javac jc = new Javac(thisClass); 204 ClassPool cp = thisClass.getClassPool(); 205 CodeAttribute ca = iterator.get(); 206 try { 207 CtClass[] params = Descriptor.getParameterTypes(signature, cp); 208 CtClass retType = Descriptor.getReturnType(signature, cp); 209 int paramVar = ca.getMaxLocals(); 210 jc.recordParams(classname, params, 211 true, paramVar, withinStatic()); 212 int retVar = jc.recordReturnType(retType, true); 213 if (c == INVOKESTATIC) 214 jc.recordStaticProceed(classname, methodname); 215 else if (c == INVOKESPECIAL) 216 jc.recordSpecialProceed(Javac.param0Name, classname, 217 methodname, signature); 218 else 219 jc.recordProceed(Javac.param0Name, methodname); 220 221 /* Is $_ included in the source code? 222 */ 223 checkResultValue(retType, statement); 224 225 Bytecode bytecode = jc.getBytecode(); 226 storeStack(params, c == INVOKESTATIC, paramVar, bytecode); 227 jc.recordLocalVariables(ca, pos); 228 229 if (retType != CtClass.voidType) { 230 bytecode.addConstZero(retType); 231 bytecode.addStore(retVar, retType); // initialize $_ 232 } 233 234 jc.compileStmnt(statement); 235 if (retType != CtClass.voidType) 236 bytecode.addLoad(retVar, retType); 237 238 replace0(pos, bytecode, opcodeSize); 239 } 240 catch (CompileError e) { throw new CannotCompileException(e); } 241 catch (NotFoundException e) { throw new CannotCompileException(e); } 242 catch (BadBytecode e) { 243 throw new CannotCompileException("broken method"); 244 } 245 } 246 } 247