• 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 
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