/*******************************************************************************
* Copyright (c) 2009-2016 CWI
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* * Ferry Rietveld - f.rietveld@hva.nl - HvA
* * Paul Klint - Paul.Klint@cwi.nl - CWI
*******************************************************************************/
package org.rascalmpl.library.experiments.Compiler.RVM.Interpreter;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Map;
import org.rascalmpl.interpreter.control_exceptions.Throw;
import org.rascalmpl.parser.gtd.exception.ParseError;
import org.rascalmpl.value.IBool;
import org.rascalmpl.value.IConstructor;
import org.rascalmpl.value.IInteger;
import org.rascalmpl.value.IList;
import org.rascalmpl.value.ISourceLocation;
import org.rascalmpl.value.IString;
import org.rascalmpl.value.IValue;
import org.rascalmpl.value.type.Type;
import org.rascalmpl.values.ValueFactoryFactory;
public class RVMonJVM extends RVMCore {
/********************************************************************************/
/* RVMonJVM extends RVMCore and is itself extended by the class produced by */
/* BytecodeGenerator. */
/********************************************************************************/
/*
* The following instance variables are only used by executeProgram
*/
public Frame root; // Root frame of a program
Thrown thrown;
// TODO : ccf, cccf and activeCoroutines needed to allow exception handling in coroutines. :(
// Return types of dynRun
static protected final IString NONE = ValueFactoryFactory.getValueFactory().string("$none$");
static protected final IString YIELD = ValueFactoryFactory.getValueFactory().string("$yield$");
static protected final IString FAILRETURN = ValueFactoryFactory.getValueFactory().string("$failreturn$");
static protected final IString PANIC = ValueFactoryFactory.getValueFactory().string("$panic$");
protected Object returnValue = null; // Actual return value of functions
public RVMonJVM(RVMExecutable rvmExec, RascalExecutionContext rex) {
super(rvmExec, rex);
}
/************************************************************************************/
/* Implementation of abstract methods in RVMCore for RVMonJVM */
/************************************************************************************/
/* (non-Javadoc)
* Implements abstract function for RVMonJVM
* @see org.rascalmpl.library.experiments.Compiler.RVM.Interpreter.RVMCore#executeRVMFunction(org.rascalmpl.library.experiments.Compiler.RVM.Interpreter.Function, org.rascalmpl.value.IValue[], java.util.Map)
*/
@Override
public Object executeRVMFunction(Function func, IValue[] posArgs, Map<String,IValue> kwArgs){
// Assumption here is that the function called is not a nested one
// and does not use global variables
Frame root = new Frame(func.scopeId, null, func.maxstack, func);
Frame cf = root;
// Pass the program arguments to main
for(int i = 0; i < posArgs.length; i++){
cf.stack[i] = posArgs[i];
}
cf.stack[func.nformals-1] = kwArgs; // new HashMap<String, IValue>();
cf.sp = func.getNlocals();
//cf.stack[func.nformals] = kwArgs == null ? new HashMap<String, IValue>() : kwArgs;
dynRun(func.funId, cf);
if(returnValue instanceof Thrown){
frameObserver.exception(cf, (Thrown) thrown);
throw (Thrown) returnValue;
}
return returnValue;
}
/* (non-Javadoc)
* Implements abstract function for RVMonJVM
* @see org.rascalmpl.library.experiments.Compiler.RVM.Interpreter.RVMCore#executeRVMFunction(org.rascalmpl.library.experiments.Compiler.RVM.Interpreter.FunctionInstance, org.rascalmpl.value.IValue[])
*/
@Override
public IValue executeRVMFunction(FunctionInstance func, IValue[] posArgs, Map<String, IValue> kwArgs) {
Thrown oldthrown = thrown;
Frame root = new Frame(func.function.scopeId, null, func.env, func.function.maxstack, func.function);
root.sp = func.function.getNlocals();
// Pass the program arguments to main
for (int i = 0; i < posArgs.length; i++) {
root.stack[i] = posArgs[i];
}
root.stack[posArgs.length] = kwArgs;
dynRun(func.function.funId, root);
thrown = oldthrown;
if (returnValue instanceof Thrown) {
frameObserver.exception(root, (Thrown) thrown);
throw (Thrown) returnValue;
}
if(returnValue instanceof IValue){
IValue v = (IValue) returnValue;
Type tp = v.getType();
if(tp.isAbstractData() && tp.getName().equals("RuntimeException")){
Thrown th = Thrown.getInstance(v, null, null);
frameObserver.exception(root, th);
throw th;
}
}
return narrow(returnValue);
}
/* (non-Javadoc)
* Implements abstract function for RVMonJVM
* @see org.rascalmpl.library.experiments.Compiler.RVM.Interpreter.RVMCore#executeRVMFunction(org.rascalmpl.library.experiments.Compiler.RVM.Interpreter.OverloadedFunctionInstance, org.rascalmpl.value.IValue[])
*/
@Override
public IValue executeRVMFunction(OverloadedFunctionInstance func, IValue[] posArgs, Map<String, IValue> kwArgs){
Function firstFunc = functionStore[func.getFunctions()[0]]; // TODO: null?
int arity = posArgs.length + 1;
int scopeId = func.env == null ? 0 : func.env.scopeId;
Frame root = new Frame(scopeId, null, func.env, arity+2, firstFunc);
// Pass the program arguments to func
for(int i = 0; i < posArgs.length; i++) {
root.stack[i] = posArgs[i];
}
root.stack[arity - 1] = kwArgs;
root.sp = arity;
root.previousCallFrame = null;
OverloadedFunctionInstanceCall ofunCall = new OverloadedFunctionInstanceCall(root, func.getFunctions(), func.getConstructors(), func.env, null, arity);
Frame frame = ofunCall.nextFrame(functionStore);
while (frame != null) {
Object rsult = dynRun(frame.function.funId, frame);
if (rsult == NONE) {
return narrow(returnValue); // Alternative matched.
}
frame = ofunCall.nextFrame(functionStore);
}
Type constructor = ofunCall.nextConstructor(constructorStore);
return vf.constructor(constructor, ofunCall.getConstructorArguments(constructor.getArity()));
}
/* (non-Javadoc)
* Implements abstract function for RVMonJVM
* @see org.rascalmpl.library.experiments.Compiler.RVM.Interpreter.RVMCore#executeRVMFunctionInVisit(org.rascalmpl.library.experiments.Compiler.RVM.Interpreter.Frame)
*/
@Override
public IValue executeRVMFunctionInVisit(Frame root){
root.sp = root.function.getNlocals(); // TODO: should be done at frame creation.
dynRun(root.function.funId, root);
if(returnValue instanceof Thrown){
frameObserver.exception(root, (Thrown) thrown);
throw (Thrown) returnValue;
}
return (IValue) returnValue;
}
/* (non-Javadoc)
* Implements abstract function for RVMonJVM
* @see org.rascalmpl.library.experiments.Compiler.RVM.Interpreter.RVMCore#executeRVMProgram(java.lang.String, java.lang.String, org.rascalmpl.value.IValue[], java.util.HashMap)
*/
@Override
public IValue executeRVMProgram(String moduleName, String uid_main, IValue[] posArgs, Map<String,IValue> kwArgs) {
rex.setFullModuleName(moduleName);
Function main_function = functionStore[functionMap.get(uid_main)];
if (main_function == null) {
throw new RuntimeException("PANIC: No function " + uid_main + " found");
}
//Thrown oldthrown = thrown; //<===
dynRun(uid_main, posArgs, kwArgs);
//thrown = oldthrown;
Object o = returnValue;
if (o != null){
if(o instanceof Thrown) {
//TODO: frameObserver.exception(cf, (Thrown) thrown);
throw (Thrown) o;
}
if(o instanceof IValue){
IValue v = (IValue) o;
Type tp = v.getType();
if(tp.isAbstractData() && tp.getName().equals("RuntimeException")){
throw Thrown.getInstance(v, null, null);
}
}
}
return narrow(o);
}
/********************************************************************************************/
/* When the BytecodeGenerator is called with debug == true, calls will be generated to the */
/* following methods that produce a runtime trace similar to that of the RVM interpreter. */
/********************************************************************************************/
static boolean verbose = true; // Turn debug output during JVM execution on/off
private static final int MAXLEN = 80;
public static String abbrev(String sval){
if(sval.length() > MAXLEN){
sval = sval.substring(0, MAXLEN) + " ...";
}
return sval;
}
private static boolean interesting(Frame cf) {
return verbose; // && cf.function.name.contains("extractScopes");
}
private static void printFrameAndStackAndAccu(Frame cf, int sp, Object accu){
System.err.println(cf + ", scope " + cf.scopeId);
// System.err.println("sp: " + sp);
for(int i = 0; i < sp; i++){
if(cf.stack[i] != null){
String isLocal = i < cf.function.getNlocals() ? "*" : " ";
System.err.println("\t" + isLocal + i + ": " + abbrev(asString(cf.stack[i])));
}
}
System.err.println("\tacc: " + abbrev(asString(accu)));
}
public static void debugINSTRUCTION(String insName, Frame cf, int sp, Object accu){
if(interesting(cf)){
printFrameAndStackAndAccu(cf, sp, accu);
System.err.println(insName +"\n");
}
}
public static void debugINSTRUCTION1(String insName, int arg1, Frame cf, int sp, Object accu){
if(interesting(cf)){
printFrameAndStackAndAccu(cf, sp, accu);
System.err.println(insName + " " + arg1 + "\n");
}
}
public static void debugINSTRUCTION2(String insName, String arg1, int arg2, Frame cf, int sp, Object accu){
if(interesting(cf)){
printFrameAndStackAndAccu(cf, sp, accu);
System.err.println(insName + " " + abbrev(arg1) + ", " + arg2 + "\n");
}
}
/********************************************************************************************/
/* Utitities for FrameObservers */
/********************************************************************************************/
public void frameUpdateSrc(Frame cf, int srcIndex){
cf.src = (ISourceLocation) cf.function.constantStore[srcIndex];
}
public void frameObserve(Frame cf, int srcIndex){
cf.src = (ISourceLocation) cf.function.constantStore[srcIndex];
frameObserver.observe(cf);
}
public void frameEnter(Frame cf, int srcIndex){
cf.src = (ISourceLocation) cf.function.constantStore[srcIndex];
frameObserver.enter(cf);
}
public void frameLeave(Frame cf, IValue rval){
frameObserver.leave(cf, rval);
}
public void frameException(Frame cf, Thrown thrown){
frameObserver.exception(cf, thrown);
}
/************************************************************************************************/
/* All following functions are called from generated byte code */
/* - insn* methods completely implement one RVM instruction */
/* - *helper methods are called as part of the inline implementation of one RVM instruction */
/************************************************************************************************/
public Object insnLOADLOCREF(Object[] stack, int pos) {
return new Reference(stack, pos);
}
public int insnPUSHLOCREF(Object[] stack, int sp, int pos) {
stack[sp++] = new Reference(stack, pos);
return sp;
}
public int insnLOADTYPE(Object[] stack, int sp, Frame cf, int arg1) {
stack[sp++] = cf.function.typeConstantStore[arg1];
return sp;
}
public Object insnLOADLOCDEREF(Object[] stack, int pos) {
Reference ref = (Reference) stack[pos];
return ref.stack[ref.pos];
}
public int insnPUSHLOCDEREF(Object[] stack, int sp, int pos) {
Reference ref = (Reference) stack[pos];
stack[sp++] = ref.stack[ref.pos];
return sp;
}
public int insnUNWRAPTHROWNLOC(Object[] stack, int sp, int target) {
stack[target] = ((Thrown) stack[--sp]).getValue();
return sp;
}
public void insnSTORELOCDEREF(Object[] stack, int sp, int pos) {
Reference ref = (Reference) stack[pos];
ref.stack[ref.pos] = stack[sp - 1];
}
public int insnPUSH_ROOT_FUN(Object[] stack, int sp, int fun) {
stack[sp++] = new FunctionInstance(functionStore[fun], root, this);
return sp;
}
public int insnPUSH_NESTED_FUN(Object[] stack, int sp, Frame cf, int fun, int scopeIn) {
stack[sp++] = FunctionInstance.computeFunctionInstance(functionStore[fun], cf, scopeIn, this);
return sp;
}
public int insnPUSHOFUN(Object[] stack, int sp, Frame cf, int ofun) {
OverloadedFunction of = overloadedStore[ofun];
stack[sp++] = of.getScopeIn() == -1 ? new OverloadedFunctionInstance(of.functions, of.constructors, root, functionStore, constructorStore, this)
: OverloadedFunctionInstance.computeOverloadedFunctionInstance(of.functions, of.constructors, cf, of.getScopeIn(), functionStore, constructorStore, this);
return sp;
}
public int insnPUSHCONSTR(Object[] stack, int sp, int construct) {
Type constructor = constructorStore.get(construct);
stack[sp++] = constructor;
return sp;
}
public int insnCALLJAVA(Object[] stack, int sp, Frame cf, int m, int c, int p, int k, int reflect) {
int newsp = sp;
Type parameterTypes = cf.function.typeConstantStore[p];
Type keywordTypes = cf.function.typeConstantStore[k];
Class<?> clazz = cf.function.getJavaClass();
Method method = cf.function.getJavaMethod();
if (method == null || clazz == null) {
String methodName = ((IString) cf.function.constantStore[m]).getValue();
String className = ((IString) cf.function.constantStore[c]).getValue();
clazz = getJavaClass(className);
method = getJavaMethod(clazz, methodName, className, parameterTypes, keywordTypes, reflect);
cf.function.setJavaMetaObjects(clazz, method);
}
try {
newsp = callJavaMethod(clazz, method, parameterTypes, keywordTypes, reflect, stack, sp);
} catch (Throw e) {
//stacktrace.add(cf);
thrown = Thrown.getInstance(e.getException(), e.getLocation(), cf);
throw thrown; // <===
// postOp = Opcode.POSTOP_HANDLEEXCEPTION; break INSTRUCTION;
} catch (Thrown e) {
//stacktrace.add(cf);
thrown = e;
throw thrown; // <===
// postOp = Opcode.POSTOP_HANDLEEXCEPTION; break INSTRUCTION;
} catch (ParseError e){
throw e;
} catch (Exception e) {
e.printStackTrace(stderr);
stderr.flush();
throw new CompilerError("Exception in CALLJAVA: " + clazz.getName() + "." + method.getName() + "; message: " + e.getMessage() + e.getCause(), cf, e);
} catch (Throwable e) {
e.printStackTrace();
throw new CompilerError("Throwable in CALLJAVA: " + clazz.getName() + "." + method.getName() + "; message: " + e.getMessage() + e.getCause(), cf, e);
}
return newsp;
}
public int insnAPPLY(Object[] stack, int sp, int function, int arity) {
FunctionInstance fun_instance;
Function fun = functionStore[function];
assert arity <= fun.nformals;
assert fun.scopeIn == -1;
fun_instance = FunctionInstance.applyPartial(fun, root, this, arity, stack, sp);
sp = sp - arity;
stack[sp++] = fun_instance;
return sp;
}
public int insnAPPLYDYN(Object[] stack, int sp, int arity) {
FunctionInstance fun_instance;
Object src = stack[--sp];
if (src instanceof FunctionInstance) {
fun_instance = (FunctionInstance) src;
assert arity + fun_instance.next <= fun_instance.function.nformals;
fun_instance = fun_instance.applyPartial(arity, stack, sp);
} else {
throw new RuntimeException("Unexpected argument type for APPLYDYN: " + asString(src));
}
sp = sp - arity;
stack[sp++] = fun_instance;
return sp;
}
public Object insnSUBSCRIPTARRAY(Object arg_2, Object arg_1) {
return ((Object[]) arg_2)[((Integer) arg_1)];
}
public Object insnSUBSCRIPTLIST(Object arg_2, Object arg_1) {
return ((IList) arg_2).get((Integer) arg_1);
}
public Object insnLESSINT(Object arg_2, Object arg_1) {
return ((Integer) arg_2) < ((Integer) arg_1) ? Rascal_TRUE : Rascal_FALSE;
}
public Object insnGREATEREQUALINT(Object arg_2, Object arg_1) {
return ((Integer) arg_2) >= ((Integer) arg_1) ? Rascal_TRUE : Rascal_FALSE;
}
public Object insnADDINT(Object arg_2, Object arg_1) {
return ((Integer) arg_2) + ((Integer) arg_1);
}
public Object insnSUBTRACTINT(Object arg_2, Object arg_1) {
return ((Integer) arg_2) - ((Integer) arg_1);
}
public Object insnANDBOOL(Object arg_2, Object arg_1) {
return ((IBool) arg_2).and((IBool) arg_1);
}
public Object insnTYPEOF(Object arg_1) {
if (arg_1 instanceof HashSet<?>) { // For the benefit of set
// matching
@SuppressWarnings("unchecked")
HashSet<IValue> mset = (HashSet<IValue>) arg_1;
if (mset.isEmpty()) {
return tf.setType(tf.voidType());
} else {
IValue v = mset.iterator().next();
return tf.setType(v.getType());
}
} else {
return ((IValue) arg_1).getType();
}
}
public Object insnSUBTYPE(Object arg_2, Object arg_1) {
return vf.bool(((Type) arg_2).isSubtypeOf((Type) arg_1));
}
public Object insnCHECKARGTYPEANDCOPY(Object[] lstack, int lsp, Frame cof, int loc, int type, int toLoc) {
Type argType = ((IValue) lstack[loc]).getType();
Type paramType = cof.function.typeConstantStore[type];
if (argType.isSubtypeOf(paramType)) {
lstack[toLoc] = lstack[loc];
return Rascal_TRUE;
} else {
return Rascal_FALSE;
}
}
public void insnLABEL() {
throw new RuntimeException("label instruction at runtime");
}
public void insnHALT(Object[] stack, int sp) {
stdout.println("Program halted:");
for (int i = 0; i < sp; i++) {
stdout.println(i + ": " + stack[i]);
}
return;
}
/************************************************************************************************/
/* JVM helper methods, called from inline jvm code generated for an RVM instruction */
/************************************************************************************************/
public Object dynRun(final String fname, final IValue[] args, Map<String, IValue> kwArgs) {
int n = functionMap.get(fname);
Function func = functionStore[n];
root = new Frame(func.scopeId, null, func.maxstack, func);
root.stack[0] = vf.list(args); // pass the program argument to
root.stack[1] = kwArgs;
root.sp = func.getNlocals();
return dynRun(n, root);
}
// public Object executeFunction(final String fname, final IValue[] args){
// int n = functionMap.get(fname);
// Function func = functionStore[n];
// root = new Frame(func.scopeId, null, func.maxstack, func);
// for(int i = 0; i < args.length; i++){
// root.stack[i] = args[i];
// }
// root.stack[args.length] = vf.mapWriter().done();
// root.sp = func.getNlocals();
//
// return dynRun(n, root);
// }
public Object dynRun(final int n, final Frame cf) {
System.out.println("Unimplemented Base called !");
return PANIC;
}
public void coreturn0Helper(final Frame cof) {
if (cof == ccf) {
activeCoroutines.pop();
ccf = activeCoroutines.isEmpty() ? null : activeCoroutines.peek().start;
}
returnValue = Rascal_TRUE;
}
public void coreturn1Helper(final Object[] lstack, int sop, final Frame cof, final int arity) {
int[] refs = cof.function.refs;
if (arity != refs.length) {
throw new RuntimeException("Coroutine " + cof.function.name + ": arity of return (" + arity + ") unequal to number of reference parameters (" + refs.length + ")");
}
for (int i = 0; i < arity; i++) {
Reference ref = (Reference) lstack[refs[arity - 1 - i]];
ref.stack[ref.pos] = lstack[--sop];
}
returnValue = Rascal_TRUE;
}
public Object jvmCREATE(final Object[] stack, final int sp, final Frame cf, final int fun, final int arity) {
cccf = cf.getCoroutineFrame(functionStore[fun], root, arity, sp);
cccf.previousCallFrame = cf;
// lcf.sp = modified by getCoroutineFrame.
dynRun(fun, cccf); // Run untill guard, leaves coroutine instance in stack.
return returnValue;
}
public Object jvmCREATEDYN(final Object[] stack, int sp, final Frame cf, final int arity) {
FunctionInstance fun_instance;
Object src = stack[--sp];
if (!(src instanceof FunctionInstance)) {
throw new RuntimeException("Unexpected argument type for CREATEDYN: " + src.getClass() + ", " + src);
}
// In case of partial parameter binding
fun_instance = (FunctionInstance) src;
cccf = cf.getCoroutineFrame(fun_instance, arity, sp);
sp = cf.sp;
cccf.previousCallFrame = cf;
// cf.sp = modified by getCoroutineFrame.
dynRun(fun_instance.function.funId, cccf);
return returnValue;
}
public int typeSwitchHelper(final Object accu) { // stackpointer calc is done in the inline part.
IValue val = (IValue) accu;
Type t = null;
if (val instanceof IConstructor) {
t = ((IConstructor) val).getConstructorType();
} else {
t = val.getType();
}
return ToplevelType.getToplevelTypeAsInt(t);
}
public int switchHelper(final Object accu, final boolean useConcreteFingerprint) {
IValue val = (IValue) accu;
IInteger fp = vf.integer(ToplevelType.getFingerprint(val, useConcreteFingerprint));
int toReturn = fp.intValue();
return toReturn;
}
public boolean guardHelper(final Object accu) {
boolean precondition;
if (accu instanceof IBool) {
precondition = ((IBool) accu).getValue();
} else {
throw new RuntimeException("Guard's expression has to be boolean!");
}
return precondition;
}
public void yield1Helper(final Frame cf, Object[] stack, int sp, final int arity, final int ep) {
// Stores a Rascal_TRUE value into the stack of the NEXT? caller.
// The inline yield1 does the return
Coroutine coroutine = activeCoroutines.pop();
ccf = activeCoroutines.isEmpty() ? null : activeCoroutines.peek().start;
returnValue = Rascal_TRUE;
int[] refs = cf.function.refs;
for (int i = 0; i < arity; i++) {
Reference ref = (Reference) stack[refs[arity - 1 - i]];
ref.stack[ref.pos] = stack[--sp];
}
cf.hotEntryPoint = ep;
cf.sp = sp;
coroutine.frame = cf;
coroutine.suspended = true;
}
public void yield0Helper(final Frame cf, final Object[] stack, final int sp, final int ep) {
// Stores a Rascal_TRUE value into the stack of the NEXT? caller.
// The inline yield0 does the return
Coroutine coroutine = activeCoroutines.pop();
ccf = activeCoroutines.isEmpty() ? null : activeCoroutines.peek().start;
returnValue = Rascal_TRUE;
cf.hotEntryPoint = ep;
cf.sp = sp;
coroutine.frame = cf;
coroutine.suspended = true;
}
public Object callHelper(final Object[] stack, int sp, final Frame cf, final int funid, final int arity, final int ep) {
Frame tmp;
Function fun;
Object rval;
if (cf.hotEntryPoint != ep) {
fun = functionStore[funid];
// In case of partial parameter binding
if (arity < fun.nformals) {
FunctionInstance fun_instance = FunctionInstance.applyPartial(fun, root, this, arity, stack, sp);
sp = sp - arity;
returnValue = fun_instance;
cf.sp = sp;
return NONE;
}
tmp = cf.getFrame(fun, root, arity, sp);
cf.nextFrame = tmp;
} else {
tmp = cf.nextFrame;
fun = tmp.function;
}
tmp.previousCallFrame = cf;
rval = dynRun(fun.funId, tmp); // In a full inline version we can call the
// function directly (name is known).
if (rval == YIELD) {
// drop my stack
cf.hotEntryPoint = ep;
return YIELD; // Will cause the inline call to return YIELD
} else {
cf.hotEntryPoint = 0;
cf.nextFrame = null; // Allow GC to clean
return NONE; // Inline call will continue execution
}
}
public Object jvmNEXT0(final Frame cf, final Object accu) {
Coroutine coroutine = (Coroutine) accu;
if (!coroutine.hasNext()) {
return Rascal_FALSE;
}
// put the coroutine onto the stack of active coroutines
activeCoroutines.push(coroutine);
ccf = coroutine.start;
coroutine.next(cf);
// Push something on the stack of the prev yielding function
coroutine.frame.stack[coroutine.frame.sp++] = null;
coroutine.frame.previousCallFrame = cf;
dynRun(coroutine.entryFrame.function.funId, coroutine.entryFrame);
return returnValue;
}
public Object exhaustHelper(final Object[] stack, final int sp, final Frame cf) {
if (cf == ccf) {
activeCoroutines.pop();
ccf = activeCoroutines.isEmpty() ? null : activeCoroutines.peek().start;
}
returnValue = Rascal_FALSE;
if (cf.previousCallFrame == null) {
return Rascal_FALSE;
}
return NONE;// i.e., signal a failure;
}
public Object jvmOCALL(final Object[] stack, int sp, final Frame cf, final int ofun, final int arity) {
cf.sp = sp;
OverloadedFunctionInstanceCall ofun_call = null;
OverloadedFunction of = overloadedStore[ofun];
Object arg0 = stack[sp - arity];
ofun_call = of.getScopeIn() == -1 ? new OverloadedFunctionInstanceCall(cf, of.getFunctions(arg0), of.getConstructors(arg0), cf, null, arity)
: OverloadedFunctionInstanceCall.computeOverloadedFunctionInstanceCall(cf, of.getFunctions(arg0), of.getConstructors(arg0), of.getScopeIn(), null, arity);
Frame frame = ofun_call.nextFrame(functionStore);
frameObserver.enter(root);
while (frame != null) {
Object rsult = dynRun(frame.function.funId, frame);
if (rsult == NONE) {
frameObserver.leave(root, returnValue);
return returnValue; // Alternative matched.
}
frame = ofun_call.nextFrame(functionStore);
}
Type constructor = ofun_call.nextConstructor(constructorStore);
sp = sp - arity;
cf.sp = sp;
returnValue = vf.constructor(constructor, ofun_call.getConstructorArguments(constructor.getArity()));
//frameObserver.leave(frame, returnValue);
return returnValue;
}
public Object jvmOCALLSingleConstructor(final Object[] stack, int sp, final Frame cf, final int ofun, final int arity) {
cf.sp = sp;
OverloadedFunction of = overloadedStore[ofun];
Type constructor = constructorStore.get(of.getConstructors()[0]);
IValue[] args = new IValue[arity - 1]; // Ignore kw parameters, see OverloadedFunctionInstanceCall.getConstructorArguments
for(int i = 0; i < arity - 1; i++) {
args[i] = (IValue) stack[sp - arity + i];
}
sp = sp - arity;
cf.sp = sp;
returnValue = vf.constructor(constructor, args);
return returnValue;
}
public int jvmOCALLDYN(final Object[] stack, int sp, final Frame cf, final int typesel, final int arity) {
Object funcObject = stack[--sp];
OverloadedFunctionInstanceCall ofunCall = null;
cf.sp = sp;
// Get function types to perform a type-based dynamic
// resolution
Type types = cf.function.codeblock.getConstantType(typesel);
// Objects of two types may appear on the stack:
// 1. FunctionInstance due to closures whom will have no overloading
if (funcObject instanceof FunctionInstance) {
FunctionInstance fun_instance = (FunctionInstance) funcObject;
Frame frame = cf.getFrame(fun_instance.function, fun_instance.env, arity, sp);
frame.previousCallFrame = cf;
dynRun(frame.function.funId, frame);
return cf.sp;
}
// 2. OverloadedFunctionInstance due to named Rascal
// functions
OverloadedFunctionInstance of_instance = (OverloadedFunctionInstance) funcObject;
ofunCall = new OverloadedFunctionInstanceCall(cf, of_instance.getFunctions(), of_instance.getConstructors(), of_instance.env, types, arity);
boolean stackPointerAdjusted = false;
Frame frame = ofunCall.nextFrame(functionStore);
while (frame != null) {
stackPointerAdjusted = true; // See text at OCALL
Object rsult = dynRun(frame.function.funId, frame);
if (rsult == NONE) {
return cf.sp; // Alternative matched.
}
frame = ofunCall.nextFrame(functionStore);
}
Type constructor = ofunCall.nextConstructor(constructorStore);
if (stackPointerAdjusted == false) {
sp = sp - arity;
}
returnValue = vf.constructor(constructor, ofunCall.getConstructorArguments(constructor.getArity()));
cf.sp = sp;
return sp;
}
public Object calldynHelper(final Object[] stack, int sp, final Frame cf, int arity, final int ep) {
Frame tmp;
Object rval;
if (cf.hotEntryPoint != ep) {
if (stack[sp - 1] instanceof Type) {
Type constr = (Type) stack[--sp];
arity = constr.getArity();
IValue[] args = new IValue[arity];
for (int i = arity - 1; i >= 0; i--) {
args[i] = (IValue) stack[sp - arity + i];
}
sp = sp - arity;
returnValue = vf.constructor(constr, args);
cf.sp = sp;
return NONE; // DO not return continue execution
}
if (stack[sp - 1] instanceof FunctionInstance) {
FunctionInstance fun_instance = (FunctionInstance) stack[--sp];
// In case of partial parameter binding
if (fun_instance.next + arity < fun_instance.function.nformals) {
fun_instance = fun_instance.applyPartial(arity, stack, sp);
sp = sp - arity;
returnValue = fun_instance;
cf.sp = sp;
return NONE;
}
tmp = cf.getFrame(fun_instance.function, fun_instance.env, fun_instance.args, arity, sp);
cf.nextFrame = tmp;
} else {
throw new RuntimeException("Unexpected argument type for CALLDYN: " + asString(stack[sp - 1]));
}
} else {
tmp = cf.nextFrame;
}
tmp.previousCallFrame = cf;
rval = dynRun(tmp.function.funId, tmp); // In a inline version we can call the
// function directly.
if (rval == YIELD) {
// Save reentry point
cf.hotEntryPoint = ep;
return YIELD; // Will cause the inline call to return YIELD
} else {
cf.hotEntryPoint = 0;
cf.nextFrame = null; // Allow GC to clean
return NONE; // Inline call will continue execution
}
}
public Thrown thrownHelper(final Frame cf, final Object[] stack, final int sp) {
Object obj = stack[sp];
Thrown thrown = null;
if (obj instanceof IValue) {
thrown = Thrown.getInstance((IValue) obj, null, cf);
} else {
thrown = (Thrown) obj;
}
return thrown;
}
// public static Object anyDeserialize(String s) throws IOException, ClassNotFoundException {
// ByteArrayInputStream bais = new ByteArrayInputStream(DatatypeConverter.parseBase64Binary(s));
// ObjectInputStream ois = new ObjectInputStream(bais);
// Object o = ois.readObject();
// ois.close();
// return o;
// }
}