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