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:
022: /**
023: * Method invocation (caller-side expression).
024: */
025: public class MethodCall extends Expr {
026: /**
027: * Undocumented constructor. Do not use; internal-use only.
028: */
029: protected MethodCall(int pos, CodeIterator i, CtClass declaring,
030: MethodInfo m) {
031: super (pos, i, declaring, m);
032: }
033:
034: private int getNameAndType(ConstPool cp) {
035: int pos = currentPos;
036: int c = iterator.byteAt(pos);
037: int index = iterator.u16bitAt(pos + 1);
038:
039: if (c == INVOKEINTERFACE)
040: return cp.getInterfaceMethodrefNameAndType(index);
041: else
042: return cp.getMethodrefNameAndType(index);
043: }
044:
045: /**
046: * Returns the method or constructor containing the method-call
047: * expression represented by this object.
048: */
049: public CtBehavior where() {
050: return super .where();
051: }
052:
053: /**
054: * Returns the line number of the source line containing the
055: * method call.
056: *
057: * @return -1 if this information is not available.
058: */
059: public int getLineNumber() {
060: return super .getLineNumber();
061: }
062:
063: /**
064: * Returns the source file containing the method call.
065: *
066: * @return null if this information is not available.
067: */
068: public String getFileName() {
069: return super .getFileName();
070: }
071:
072: /**
073: * Returns the class of the target object,
074: * which the method is called on.
075: */
076: protected CtClass getCtClass() throws NotFoundException {
077: return this Class.getClassPool().get(getClassName());
078: }
079:
080: /**
081: * Returns the class name of the target object,
082: * which the method is called on.
083: */
084: public String getClassName() {
085: String cname;
086:
087: ConstPool cp = getConstPool();
088: int pos = currentPos;
089: int c = iterator.byteAt(pos);
090: int index = iterator.u16bitAt(pos + 1);
091:
092: if (c == INVOKEINTERFACE)
093: cname = cp.getInterfaceMethodrefClassName(index);
094: else
095: cname = cp.getMethodrefClassName(index);
096:
097: if (cname.charAt(0) == '[')
098: cname = Descriptor.toClassName(cname);
099:
100: return cname;
101: }
102:
103: /**
104: * Returns the name of the called method.
105: */
106: public String getMethodName() {
107: ConstPool cp = getConstPool();
108: int nt = getNameAndType(cp);
109: return cp.getUtf8Info(cp.getNameAndTypeName(nt));
110: }
111:
112: /**
113: * Returns the called method.
114: */
115: public CtMethod getMethod() throws NotFoundException {
116: return getCtClass().getMethod(getMethodName(), getSignature());
117: }
118:
119: /**
120: * Returns the method signature (the parameter types
121: * and the return type).
122: * The method signature is represented by a character string
123: * called method descriptor, which is defined in the JVM specification.
124: *
125: * @see javassist.CtBehavior#getSignature()
126: * @see javassist.bytecode.Descriptor
127: * @since 3.1
128: */
129: public String getSignature() {
130: ConstPool cp = getConstPool();
131: int nt = getNameAndType(cp);
132: return cp.getUtf8Info(cp.getNameAndTypeDescriptor(nt));
133: }
134:
135: /**
136: * Returns the list of exceptions that the expression may throw.
137: * This list includes both the exceptions that the try-catch statements
138: * including the expression can catch and the exceptions that
139: * the throws declaration allows the method to throw.
140: */
141: public CtClass[] mayThrow() {
142: return super .mayThrow();
143: }
144:
145: /**
146: * Returns true if the called method is of a superclass of the current
147: * class.
148: */
149: public boolean isSuper() {
150: return iterator.byteAt(currentPos) == INVOKESPECIAL
151: && !where().getDeclaringClass().getName().equals(
152: getClassName());
153: }
154:
155: /*
156: * Returns the parameter types of the called method.
157:
158: public CtClass[] getParameterTypes() throws NotFoundException {
159: return Descriptor.getParameterTypes(getMethodDesc(),
160: thisClass.getClassPool());
161: }
162: */
163:
164: /*
165: * Returns the return type of the called method.
166:
167: public CtClass getReturnType() throws NotFoundException {
168: return Descriptor.getReturnType(getMethodDesc(),
169: thisClass.getClassPool());
170: }
171: */
172:
173: /**
174: * Replaces the method call with the bytecode derived from
175: * the given source text.
176: *
177: * <p>$0 is available even if the called method is static.
178: *
179: * @param statement a Java statement.
180: */
181: public void replace(String statement) throws CannotCompileException {
182: ConstPool constPool = getConstPool();
183: int pos = currentPos;
184: int index = iterator.u16bitAt(pos + 1);
185:
186: String classname, methodname, signature;
187: int opcodeSize;
188: int c = iterator.byteAt(pos);
189: if (c == INVOKEINTERFACE) {
190: opcodeSize = 5;
191: classname = constPool.getInterfaceMethodrefClassName(index);
192: methodname = constPool.getInterfaceMethodrefName(index);
193: signature = constPool.getInterfaceMethodrefType(index);
194: } else if (c == INVOKESTATIC || c == INVOKESPECIAL
195: || c == INVOKEVIRTUAL) {
196: opcodeSize = 3;
197: classname = constPool.getMethodrefClassName(index);
198: methodname = constPool.getMethodrefName(index);
199: signature = constPool.getMethodrefType(index);
200: } else
201: throw new CannotCompileException("not method invocation");
202:
203: Javac jc = new Javac(this Class);
204: ClassPool cp = this Class.getClassPool();
205: CodeAttribute ca = iterator.get();
206: try {
207: CtClass[] params = Descriptor.getParameterTypes(signature,
208: cp);
209: CtClass retType = Descriptor.getReturnType(signature, cp);
210: int paramVar = ca.getMaxLocals();
211: jc.recordParams(classname, params, true, paramVar,
212: withinStatic());
213: int retVar = jc.recordReturnType(retType, true);
214: if (c == INVOKESTATIC)
215: jc.recordStaticProceed(classname, methodname);
216: else if (c == INVOKESPECIAL)
217: jc.recordSpecialProceed(Javac.param0Name, classname,
218: methodname, signature);
219: else
220: jc.recordProceed(Javac.param0Name, methodname);
221:
222: /* Is $_ included in the source code?
223: */
224: checkResultValue(retType, statement);
225:
226: Bytecode bytecode = jc.getBytecode();
227: storeStack(params, c == INVOKESTATIC, paramVar, bytecode);
228: jc.recordLocalVariables(ca, pos);
229:
230: if (retType != CtClass.voidType) {
231: bytecode.addConstZero(retType);
232: bytecode.addStore(retVar, retType); // initialize $_
233: }
234:
235: jc.compileStmnt(statement);
236: if (retType != CtClass.voidType)
237: bytecode.addLoad(retVar, retType);
238:
239: replace0(pos, bytecode, opcodeSize);
240: } catch (CompileError e) {
241: throw new CannotCompileException(e);
242: } catch (NotFoundException e) {
243: throw new CannotCompileException(e);
244: } catch (BadBytecode e) {
245: throw new CannotCompileException("broken method");
246: }
247: }
248: }
|