/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* $Id: OPcall.java 490 2006-10-01 16:08:04Z metlov $
*
* This file is part of the Java Expressions Library (JEL).
* For more information about JEL visit :
* http://kinetic.ac.donetsk.ua/JEL/
*
* (c) 1998 -- 2007 by Konstantin Metlov(metlov@kinetic.ac.donetsk.ua);
*
* JEL is Distributed under the terms of GNU General Public License.
* This code comes with ABSOLUTELY NO WARRANTY.
* For license details see COPYING file in this directory.
*/
package gnu.jel;
import java.lang.reflect.Member;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import gnu.jel.debug.Debug;
import java.util.Stack;
/**
* A tree node, representing a method call (field/local variable load).
*/
public class OPcall extends OP {
/** Holds method to be executed */
public Member m; // member to eval (null for the local variable access)
/**
* local variable number (in case m=null), number of formal
* parameters of the method to call otherwise. */
public int nplv=0;
/**
* if evaluation of the method will be attempted at compile-time */
private boolean aEval=false;
/**
* Prepares a new method/field call/get operation to be added to the code.
* @param paramOPs stack holding the operands
* @param m method/field to call/get.
* @param aEval indicates if the method call should be attempted
* at the compile time
*/
public OPcall(Stack<OP> paramOPs, Member m, boolean aEval)
throws CompilationException {
this.m=m;
Class[] reqParamTypes=Library.getParameterTypes(m);
nplv=reqParamTypes.length;
int thisIdx=0;
if ((m.getModifiers() & 0x0008) == 0) { // method is not static
thisIdx=-1;
nplv++;
};
this.chi=new OP[nplv];
// convert formal and actual parameter types and "this", if needed
for(int i=reqParamTypes.length-1;i>=thisIdx;i--) {
Class cReq=(i>=0?reqParamTypes[i]:m.getDeclaringClass());
OP cop=(OP)paramOPs.peek();
// add convert type OP
if ((cop.resID==10) || (cop.resType!=cReq))
paramOPs.push(new OPunary(paramOPs,typeID(cReq),cReq,i<0));
chi[i-thisIdx]=(OP)paramOPs.pop();
};
// push & store the result type
resType=Library.getType(m);
resID=typeID(resType);
// System.out.println("MAKING CALL TO "+m.getName()+
// ClassFile.getSignature(m)+" returning "+
// m.getType());
// determine if compile-time evaluation should be attempted
this.aEval=(aEval && // eval only if requested.
((m.getModifiers() & 0x0008)!=0) && // if static
((resID<=7) || (resID==11)) // if can store result
);
};
/**
* Prepares access to the local variable (formal parameter) of method.
* @param lvarn local variable number.
* @param type local variable type.
*/
public OPcall(int lvarn, Class type) {
this.m=null;
this.nplv=lvarn;
resID=typeID(type);
resType=type;
};
/**
* Attempts to evaluate this function.
* @return the OPload, representing the function's result (if it can \
* be evaluated).
* @throws Exception if the function can't be evaluated, or the evaluation
* results in error.
*/
public Object eval() throws Exception {
Object[] params=new Object[chi.length];
boolean[] evaltd=new boolean[chi.length];
Exception exception=null;
for(int i=0;i<chi.length;i++) {
try {
params[i]=chi[i].eval();
evaltd[i]=true;
} catch (Exception exc) {
exception=exc;
evaltd[i]=false;
};
};
Object res=null;
if (exception==null) { // try to evaluate the method
try {
if (!aEval)
throw new Exception();
if (m instanceof Method) res=((Method)m).invoke(null,params);
else if (m instanceof Field) res=((Field)m).get(null);
else throw new Exception();
} catch (Exception exc) {
exception=exc;
};
};
if (exception!=null) {
// didn't eval, replace at least evaluated children
for(int i=0;i<chi.length;i++)
if (evaltd[i])
chi[i]=new OPload(chi[i],params[i]);
throw exception;
};
return res;
};
// compilation code
public void compile(ClassFile cf) {
if (m==null) {
// load the local variable with a given number
// int[][] load={
// //wide shrt 0 1 2 3
// {0x15c4,0x15,0x1a,0x1b,0x1c,0x1d}, // Z
// {0x15c4,0x15,0x1a,0x1b,0x1c,0x1d}, // B
// {0x15c4,0x15,0x1a,0x1b,0x1c,0x1d}, // C
// {0x15c4,0x15,0x1a,0x1b,0x1c,0x1d}, // S
// {0x15c4,0x15,0x1a,0x1b,0x1c,0x1d}, // I
// {0x16c4,0x16,0x1e,0x1f,0x20,0x21}, // J
// {0x17c4,0x17,0x22,0x23,0x24,0x25}, // F
// {0x18c4,0x18,0x26,0x27,0x28,0x29}, // D
// {0x19c4,0x19,0x2a,0x2b,0x2c,0x2d} // L
// };
int lvt=resID-4;
if (lvt<0) lvt=0;
int lvarn_translated=cf.paramsVars[nplv];
if (lvarn_translated<4)
cf.code(0x1a+lvt*4+lvarn_translated);
else if (lvarn_translated<=255)
cf.code(0x15+lvt+(lvarn_translated<<8));
else {
cf.code(((0x15+lvt)<<8)+0xc4);
cf.writeShort(lvarn_translated);
};
} else {
cf.code(0xFB); // labels block;
for(int i=0;i<chi.length;i++) {
chi[i].compile(cf);
cf.code(0xFA); // ensure value in stack
};
cf.code(0xF8); // labels unblock;
for(int i=0;i<chi.length;i++)
cf.noteStk(chi[i].resID,-1);
cf.codeM(m); // call the method / get field
};
cf.noteStk(-1,resID);
};
};