package org.rascalmpl.library.experiments.Compiler.RVM.Interpreter; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Stack; import org.rascalmpl.interpreter.Configuration; import org.rascalmpl.interpreter.control_exceptions.Throw; // TODO: remove import: NOT YET: JavaCalls generate a Throw import org.rascalmpl.interpreter.types.RascalType; import org.rascalmpl.library.experiments.Compiler.RVM.Interpreter.Instructions.Opcode; import org.rascalmpl.value.IBool; import org.rascalmpl.value.IConstructor; import org.rascalmpl.value.IInteger; import org.rascalmpl.value.IList; import org.rascalmpl.value.IMap; import org.rascalmpl.value.ISourceLocation; import org.rascalmpl.value.IString; import org.rascalmpl.value.IValue; import org.rascalmpl.value.type.Type; public class RVMInterpreter extends RVMCore { public RVMInterpreter(RVMExecutable rvmExec, RascalExecutionContext rex) { super(rvmExec, rex); Opcode.init(stdout, rex.getProfile()); } Configuration getConfiguration() { return rex.getConfiguration(); } /************************************************************************************/ /* Implementation of abstract methods in RVMCore for RVMInterpreter */ /************************************************************************************/ /* (non-Javadoc) * Implements abstract function for RVM interpreter * @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) */ 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.stack[func.nformals] = kwArgs == null ? new HashMap<String, IValue>() : kwArgs; Object o = interpretRVMProgram(root, cf); if(o instanceof Thrown){ throw (Thrown) o; } return o; } /* (non-Javadoc) * Implements abstract function for RVM interpreter * @see org.rascalmpl.library.experiments.Compiler.RVM.Interpreter.RVMCore#executeRVMFunction(org.rascalmpl.library.experiments.Compiler.RVM.Interpreter.FunctionInstance, org.rascalmpl.value.IValue[]) */ public IValue executeRVMFunction(FunctionInstance func, IValue[] posArgs, Map<String, IValue> kwArgs){ Frame root = new Frame(func.function.scopeId, null, func.env, func.function.maxstack, func.function); 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.args.length-1] = kwArgs; // CHECK Object o = interpretRVMProgram(root, cf); if(o instanceof Thrown){ throw (Thrown) o; } return narrow(o); } /* (non-Javadoc) * Implements abstract function for RVM interpreter * @see org.rascalmpl.library.experiments.Compiler.RVM.Interpreter.RVMCore#executeRVMFunction(org.rascalmpl.library.experiments.Compiler.RVM.Interpreter.OverloadedFunctionInstance, org.rascalmpl.value.IValue[]) */ 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); root.sp = arity; OverloadedFunctionInstanceCall c_ofun_call_next = scopeId == -1 ? new OverloadedFunctionInstanceCall(root, func.getFunctions(), func.getConstructors(), root, null, arity) // changed root to cf : OverloadedFunctionInstanceCall.computeOverloadedFunctionInstanceCall(root, func.getFunctions(), func.getConstructors(), scopeId, null, arity); Frame cf = c_ofun_call_next.nextFrame(functionStore); // Pass the program arguments to func for(int i = 0; i < posArgs.length; i++) { cf.stack[i] = posArgs[i]; } cf.stack[arity - 1] = kwArgs; cf.sp = arity; cf.previousCallFrame = null; // ensure that func will return here Object o = interpretRVMProgram(root, cf, c_ofun_call_next); if(o instanceof Thrown){ throw (Thrown) o; } return narrow(o); } /* (non-Javadoc) * Implements abstract function for RVM interpreter * @see org.rascalmpl.library.experiments.Compiler.RVM.Interpreter.RVMCore#executeRVMFunctionInVisit(org.rascalmpl.library.experiments.Compiler.RVM.Interpreter.Frame) */ public IValue executeRVMFunctionInVisit(Frame root){ Frame cf = root; // Pass the subject argument Object o = interpretRVMProgram(root, cf); if(o instanceof Thrown){ throw (Thrown) o; } return (IValue)o; } /* (non-Javadoc) * Implements abstract function for RVM interpreter * @see org.rascalmpl.library.experiments.Compiler.RVM.Interpreter.RVMCore#executeRVMProgram(java.lang.String, java.lang.String, org.rascalmpl.value.IValue[], java.util.HashMap) */ public IValue executeRVMProgram(String moduleName, String uid_main, IValue[] args, Map<String,IValue> kwArgs) { String oldModuleName = rex.getFullModuleName(); rex.setFullModuleName(moduleName); Function main_function = functionStore[functionMap.get(uid_main)]; if (main_function == null) { throw RascalRuntimeException.noMainFunction(null); //throw new RuntimeException("No main function found"); } Frame root = new Frame(main_function.scopeId, null, main_function.maxstack, main_function); Frame cf = root; //cf.stack[0] = vf.list(args); // pass the program argument to main_function as a IList object cf.stack[0] = kwArgs == null ? new HashMap<String, IValue>() : kwArgs; cf.src = main_function.src; Object o = interpretRVMProgram(root, cf); if(o != null && o instanceof Thrown){ throw (Thrown) o; } IValue res = narrow(o); rex.setFullModuleName(oldModuleName); return res; } /********************************************************************************/ /* Auxiliary functions that implement specific instructions */ /* that are only used by RVM ineterpreter */ /********************************************************************************/ private Object VALUESUBTYPE(Type reqType, Object accu){ return vf.bool(((IValue) accu).getType().isSubtypeOf(reqType)); //return vf.bool(rex.isSubtypeOf(((IValue) accu).getType(), reqType)); } private int APPLY(Object[] stack, int sp, Frame cf, Function fun, int arity, Frame root){ assert arity <= fun.nformals : "APPLY, too many arguments at " + cf.src; assert fun.scopeIn == -1 : "APPLY, illegal scope at " + cf.src; FunctionInstance fun_instance = FunctionInstance.applyPartial(fun, root, this, arity, stack, sp); sp = sp - arity; stack[sp++] = fun_instance; return sp; } private int APPLYDYN(int arity, Frame cf, Object[] stack, int sp){ FunctionInstance fun_instance; Object src = stack[--sp]; if(src instanceof FunctionInstance) { fun_instance = (FunctionInstance) src; assert arity + fun_instance.next <= fun_instance.function.nformals : "APPLYDYN, too many arguments at " + cf.src; fun_instance = fun_instance.applyPartial(arity, stack, sp); } else { throw new CompilerError("Unexpected argument type for APPLYDYN: " + asString(src), cf); } sp = sp - arity; stack[sp++] = fun_instance; return sp; } private Object interpretRVMProgram(Frame root, Frame cf) { return interpretRVMProgram(root, cf, null); } /********************************************************************************/ /* The actual RVM interpreter */ /********************************************************************************/ @SuppressWarnings("unchecked") private Object interpretRVMProgram(final Frame root, Frame cf, OverloadedFunctionInstanceCall c_ofun_call) { Object[] stack = cf.stack; // current stack int sp = cf.function.getNlocals(); // current stack pointer long [] instructions = cf.function.codeblock.getInstructions(); // current instruction sequence int pc = 0; // current program counter int postOp = 0; // postprocessing operator (following main switch) int pos = 0; ArrayList<Frame> stacktrace = new ArrayList<Frame>(); Thrown thrown = null; int arity; long instruction; int op; Object rval; Object accu = null; if(rex.getJVM()){ throw new CompilerError("*** SHOULD NOT BE CALLED IN JVM MODE: interpretRVMProgram: " + cf.toString()); } // Overloading specific Stack<OverloadedFunctionInstanceCall> ocalls = new Stack<OverloadedFunctionInstanceCall>(); if(c_ofun_call != null){ ocalls.push(c_ofun_call); } frameObserver.enter(cf); try { NEXT_INSTRUCTION: while (true) { frameObserver.observeRVM(this, cf, pc, stack, sp, accu); instruction = instructions[pc++]; op = CodeBlock.fetchOp(instruction); INSTRUCTION: switch (op) { case Opcode.OP_PUSHACCU: stack[sp++] = accu; continue NEXT_INSTRUCTION; case Opcode.OP_POPACCU: accu = stack[--sp]; continue NEXT_INSTRUCTION; case Opcode.OP_POP: sp--; continue NEXT_INSTRUCTION; case Opcode.OP_LOADLOC0: // assert 0 < cf.function.nlocals : "LOADLOC0: pos larger that nlocals at " + cf.src; // assert stack[0] != null: "Local variable 0 is null"; accu = stack[0]; //if(a == null){ postOp = Opcode.POSTOP_CHECKUNDEF; break; } continue NEXT_INSTRUCTION; case Opcode.OP_LOADLOC1: // assert 1 < cf.function.nlocals : "LOADLOC1: pos larger that nlocals at " + cf.src; // assert stack[1] != null: "Local variable 1 is null"; accu = stack[1]; //if(accu == null){ postOp = Opcode.POSTOP_CHECKUNDEF; break; } continue NEXT_INSTRUCTION; case Opcode.OP_LOADLOC2: // assert 2 < cf.function.nlocals : "LOADLOC2: pos larger that nlocals at " + cf.src; // assert stack[2] != null: "Local variable 2 is null"; accu = stack[2]; //if(accu == null){ postOp = Opcode.POSTOP_CHECKUNDEF; break; } continue NEXT_INSTRUCTION; case Opcode.OP_LOADLOC3: // assert 3 < cf.function.nlocals : "LOADLOC3: pos larger that nlocals at " + cf.src; // assert stack[3] != null: "Local variable 3 is null"; accu = stack[3]; //if(accu == null){ postOp = Opcode.POSTOP_CHECKUNDEF; break; } continue NEXT_INSTRUCTION; case Opcode.OP_LOADLOC4: // assert 4 < cf.function.nlocals : "LOADLOC4: pos larger that nlocals at " + cf.src; // assert stack[4] != null: "Local variable 4 is null"; accu = stack[4]; //if(accu == null){ postOp = Opcode.POSTOP_CHECKUNDEF; break; } continue NEXT_INSTRUCTION; case Opcode.OP_LOADLOC5: // assert 5 < cf.function.nlocals : "LOADLOC5: pos larger that nlocals at " + cf.src; // assert stack[5] != null: "Local variable 5 is null"; accu = stack[5]; //if(accu == null){ postOp = Opcode.POSTOP_CHECKUNDEF; break; } continue NEXT_INSTRUCTION; case Opcode.OP_LOADLOC6: // assert 6 < cf.function.nlocals : "LOADLOC6: pos larger that nlocals at " + cf.src; // assert stack[6] != null: "Local variable 6 is null"; accu = stack[6]; //if(accu == null){ postOp = Opcode.POSTOP_CHECKUNDEF; break; } continue NEXT_INSTRUCTION; case Opcode.OP_LOADLOC7: // assert 7 < cf.function.nlocals : "LOADLOC7: pos larger that nlocals at " + cf.src; // assert stack[7] != null: "Local variable 7 is null"; accu = stack[7]; //if(accu == null){ postOp = Opcode.POSTOP_CHECKUNDEF; break; } continue NEXT_INSTRUCTION; case Opcode.OP_LOADLOC8: // assert 8 < cf.function.nlocals : "LOADLOC8: pos larger that nlocals at " + cf.src; // assert stack[8] != null: "Local variable 8 is null"; accu = stack[8]; //if(accu == null){ postOp = Opcode.POSTOP_CHECKUNDEF; break; } continue NEXT_INSTRUCTION; case Opcode.OP_LOADLOC9: // assert 9 < cf.function.nlocals : "LOADLOC9: pos larger that nlocals at " + cf.src; // assert stack[9] != null: "Local variable 9 is null"; accu = stack[9]; // if(accu == null){ postOp = Opcode.POSTOP_CHECKUNDEF; break; } continue NEXT_INSTRUCTION; case Opcode.OP_LOADLOC: pos = CodeBlock.fetchArg1(instruction); // assert pos < cf.function.nlocals : "LOADLOC: pos larger that nlocals at " + cf.src; // assert stack[pos] != null: "Local variable " + pos + " is null"; accu = stack[pos]; //if(accu == null){ postOp = Opcode.POSTOP_CHECKUNDEF; break; } continue NEXT_INSTRUCTION; case Opcode.OP_PUSHLOC: pos = CodeBlock.fetchArg1(instruction); // assert pos < cf.function.nlocals : "LOADLOC: pos larger that nlocals at " + cf.src; // assert stack[pos] != null: "Local variable " + pos + " is null"; accu = stack[pos]; //if(accu == null){ postOp = Opcode.POSTOP_CHECKUNDEF; break; } stack[sp++] = accu; continue NEXT_INSTRUCTION; case Opcode.OP_RESETLOCS: IList positions = (IList) cf.function.constantStore[CodeBlock.fetchArg1(instruction)]; for(IValue v : positions){ stack[((IInteger) v).intValue()] = null; } continue NEXT_INSTRUCTION; case Opcode.OP_RESETLOC: stack[CodeBlock.fetchArg1(instruction)] = null; continue NEXT_INSTRUCTION; case Opcode.OP_LOADBOOL: accu = CodeBlock.fetchArg1(instruction) == 1 ? Rascal_TRUE : Rascal_FALSE; continue NEXT_INSTRUCTION; case Opcode.OP_LOADINT: accu = CodeBlock.fetchArg1(instruction); continue NEXT_INSTRUCTION; case Opcode.OP_LOADCON: accu = cf.function.constantStore[CodeBlock.fetchArg1(instruction)]; continue NEXT_INSTRUCTION; case Opcode.OP_PUSHCON: accu = stack[sp++] = cf.function.constantStore[CodeBlock.fetchArg1(instruction)]; continue NEXT_INSTRUCTION; case Opcode.OP_LOADLOCREF: accu = new Reference(stack, CodeBlock.fetchArg1(instruction)); continue NEXT_INSTRUCTION; case Opcode.OP_PUSHLOCREF: stack[sp++] = new Reference(stack, CodeBlock.fetchArg1(instruction)); continue NEXT_INSTRUCTION; case Opcode.OP_PUSHEMPTYKWMAP: // TODO: use unique copy of emptyKeywordMap and delay creation of new copy to assignment // to keyword parameter //stack[sp++] = emptyKeywordMap; stack[sp++] = new HashMap<String,IValue>(); continue NEXT_INSTRUCTION; case Opcode.OP_CALLMUPRIM0: accu = MuPrimitive.values[CodeBlock.fetchArg1(instruction)].execute0(); continue NEXT_INSTRUCTION; case Opcode.OP_PUSHCALLMUPRIM0: stack[sp++] = MuPrimitive.values[CodeBlock.fetchArg1(instruction)].execute0(); continue NEXT_INSTRUCTION; case Opcode.OP_CALLMUPRIM1: accu = MuPrimitive.values[CodeBlock.fetchArg1(instruction)].execute1(accu); continue NEXT_INSTRUCTION; case Opcode.OP_PUSHCALLMUPRIM1: stack[sp++] = MuPrimitive.values[CodeBlock.fetchArg1(instruction)].execute1(accu); continue NEXT_INSTRUCTION; case Opcode.OP_CALLMUPRIM2: accu = MuPrimitive.values[CodeBlock.fetchArg1(instruction)].execute2(stack[sp - 1], accu); sp--; continue NEXT_INSTRUCTION; case Opcode.OP_PUSHCALLMUPRIM2: stack[sp - 1] = MuPrimitive.values[CodeBlock.fetchArg1(instruction)].execute2(stack[sp - 1], accu); continue NEXT_INSTRUCTION; case Opcode.OP_CALLMUPRIMN: sp = MuPrimitive.values[CodeBlock.fetchArg1(instruction)].executeN(stack, sp, CodeBlock.fetchArg2(instruction)); accu = stack[--sp]; continue NEXT_INSTRUCTION; case Opcode.OP_PUSHCALLMUPRIMN: sp = MuPrimitive.values[CodeBlock.fetchArg1(instruction)].executeN(stack, sp, CodeBlock.fetchArg2(instruction)); continue NEXT_INSTRUCTION; case Opcode.OP_JMP: pc = CodeBlock.fetchArg1(instruction); continue NEXT_INSTRUCTION; case Opcode.OP_JMPTRUE: if (((IBool) accu).getValue()) { pc = CodeBlock.fetchArg1(instruction); } continue NEXT_INSTRUCTION; case Opcode.OP_JMPFALSE: if (!((IBool) accu).getValue()) { pc = CodeBlock.fetchArg1(instruction); } continue NEXT_INSTRUCTION; case Opcode.OP_TYPESWITCH: Type t = null; if(accu instanceof IConstructor) { t = ((IConstructor) accu).getConstructorType(); } else { t = ((IValue)accu).getType(); } int labelIndex = ToplevelType.getToplevelTypeAsInt(t); IList labels = (IList) cf.function.constantStore[CodeBlock.fetchArg1(instruction)]; pc = ((IInteger) labels.get(labelIndex)).intValue(); continue NEXT_INSTRUCTION; case Opcode.OP_SWITCH: IMap caseLabels = (IMap) cf.function.constantStore[CodeBlock.fetchArg1(instruction)]; int caseDefault = CodeBlock.fetchArg2(instruction); boolean useConcreteFingerprint = instructions[pc++] == 1; IInteger fp = vf.integer(ToplevelType.getFingerprint((IValue)accu, useConcreteFingerprint)); IInteger x = (IInteger) caseLabels.get(fp); //stdout.println("SWITCH: fp = " + fp + ", val = " + val + ", x = " + x + ", useConcreteFingerprint = " + useConcreteFingerprint); if(x == null){ pc = caseDefault; } else { pc = x.intValue(); } continue NEXT_INSTRUCTION; case Opcode.OP_LOADTYPE: accu = cf.function.typeConstantStore[CodeBlock.fetchArg1(instruction)]; continue NEXT_INSTRUCTION; case Opcode.OP_PUSHTYPE: stack[sp++] = cf.function.typeConstantStore[CodeBlock.fetchArg1(instruction)]; continue NEXT_INSTRUCTION; case Opcode.OP_LOADLOCDEREF: { Reference ref = (Reference) stack[CodeBlock.fetchArg1(instruction)]; accu = ref.stack[ref.pos]; continue NEXT_INSTRUCTION; } case Opcode.OP_PUSHLOCDEREF: { Reference ref = (Reference) stack[CodeBlock.fetchArg1(instruction)]; stack[sp++] = ref.stack[ref.pos]; continue NEXT_INSTRUCTION; } case Opcode.OP_STORELOC: pos = CodeBlock.fetchArg1(instruction); assert pos < cf.function.getNlocals() : "STORELOC: pos larger that nlocals at " + cf.src; stack[pos] = accu; continue NEXT_INSTRUCTION; case Opcode.OP_STORELOCDEREF: Reference ref = (Reference) stack[CodeBlock.fetchArg1(instruction)]; ref.stack[ref.pos] = accu; // TODO: We need to re-consider how to guarantee safe use of both Java objects and IValues continue NEXT_INSTRUCTION; case Opcode.OP_PUSH_ROOT_FUN: // Loads functions that are defined at the root stack[sp++] = new FunctionInstance(functionStore[CodeBlock.fetchArg1(instruction)], root, this); continue NEXT_INSTRUCTION; case Opcode.OP_PUSH_NESTED_FUN: { // Loads nested functions and closures (anonymous nested functions) stack[sp++] = FunctionInstance.computeFunctionInstance(functionStore[CodeBlock.fetchArg1(instruction)], cf, CodeBlock.fetchArg2(instruction), this); continue NEXT_INSTRUCTION; } case Opcode.OP_PUSHOFUN: OverloadedFunction of = overloadedStore[CodeBlock.fetchArg1(instruction)]; 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); continue NEXT_INSTRUCTION; case Opcode.OP_PUSHCONSTR: Type constructor = constructorStore.get(CodeBlock.fetchArg1(instruction)); stack[sp++] = constructor; continue NEXT_INSTRUCTION; case Opcode.OP_LOADVAR: accu = LOADVAR(cf, CodeBlock.fetchArg1(instruction), CodeBlock.fetchArg2(instruction)); // if(accu == null){ // postOp = Opcode.POSTOP_CHECKUNDEF; break; // } continue NEXT_INSTRUCTION; case Opcode.OP_PUSHVAR: sp = PUSHVAR(stack, sp, cf, CodeBlock.fetchArg1(instruction), CodeBlock.fetchArg2(instruction)); // if(accu == null){ // postOp = Opcode.POSTOP_CHECKUNDEF; break; // } // stack[sp++] = accu; continue NEXT_INSTRUCTION; case Opcode.OP_RESETVAR: RESETVAR(cf, CodeBlock.fetchArg1(instruction), CodeBlock.fetchArg2(instruction)); continue NEXT_INSTRUCTION; case Opcode.OP_LOADVARREF: accu = LOADVARREF(cf, CodeBlock.fetchArg1(instruction), CodeBlock.fetchArg2(instruction)); continue NEXT_INSTRUCTION; case Opcode.OP_PUSHVARREF: stack[sp++] = LOADVARREF(cf, CodeBlock.fetchArg1(instruction), CodeBlock.fetchArg2(instruction)); continue NEXT_INSTRUCTION; case Opcode.OP_LOADVARDEREF: accu = LOADVARDEREF(cf, CodeBlock.fetchArg1(instruction), CodeBlock.fetchArg2(instruction)); // if(accu == null){ // postOp = Opcode.POSTOP_CHECKUNDEF; break; // } continue NEXT_INSTRUCTION; case Opcode.OP_PUSHVARDEREF: accu = LOADVARDEREF(cf, CodeBlock.fetchArg1(instruction), CodeBlock.fetchArg2(instruction)); // if(accu == null){ // postOp = Opcode.POSTOP_CHECKUNDEF; break; // } stack[sp++] = accu; continue NEXT_INSTRUCTION; case Opcode.OP_STOREVAR: STOREVAR(cf, CodeBlock.fetchArg1(instruction), CodeBlock.fetchArg2(instruction), accu); continue NEXT_INSTRUCTION; case Opcode.OP_STOREVARDEREF: STOREVARDEREF(cf, CodeBlock.fetchArg1(instruction), CodeBlock.fetchArg2(instruction), accu); continue NEXT_INSTRUCTION; case Opcode.OP_CALLCONSTR: sp = CALLCONSTR(stack, sp, CodeBlock.fetchArg1(instruction), CodeBlock.fetchArg2(instruction)); accu = stack[--sp]; continue NEXT_INSTRUCTION; case Opcode.OP_CALLDYN: case Opcode.OP_CALL: if(!frameObserver.observe(cf)){ return Rascal_FALSE; } // In case of CALLDYN, the stack top value of type 'Type' leads to a constructor call if(op == Opcode.OP_CALLDYN && 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; accu = vf.constructor(constr, args); continue NEXT_INSTRUCTION; } cf.pc = pc; if(op == Opcode.OP_CALLDYN && stack[sp - 1] instanceof FunctionInstance){ FunctionInstance fun_instance = (FunctionInstance) stack[--sp]; arity = CodeBlock.fetchArg1(instruction); // 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; accu = fun_instance; continue NEXT_INSTRUCTION; } cf = cf.getFrame(fun_instance.function, fun_instance.env, fun_instance.args, arity, sp); } else if(op == Opcode.OP_CALL) { Function fun = functionStore[CodeBlock.fetchArg1(instruction)]; arity = CodeBlock.fetchArg2(instruction); // In case of partial parameter binding if(arity < fun.nformals) { FunctionInstance fun_instance = FunctionInstance.applyPartial(fun, root, this, arity, stack, sp); sp = sp - arity; accu = fun_instance; continue NEXT_INSTRUCTION; } cf = cf.getFrame(fun, root, arity, sp); } else { throw new CompilerError("Unexpected argument type for CALLDYN: " + asString(stack[sp - 1]), cf); } frameObserver.enter(cf); instructions = cf.function.codeblock.getInstructions(); stack = cf.stack; sp = cf.sp; pc = cf.pc; //accu = stack[--sp]; // TODO continue NEXT_INSTRUCTION; case Opcode.OP_OCALLDYN: case Opcode.OP_OCALL: Object funcObject = (op == Opcode.OP_OCALLDYN) ? stack[--sp] : null; // Get function arguments from the stack arity = CodeBlock.fetchArg2(instruction); cf.src = (ISourceLocation) cf.function.constantStore[(int) instructions[pc++]]; if(!frameObserver.observe(cf)){ return Rascal_FALSE; } cf.sp = sp; cf.pc = pc; OverloadedFunctionInstanceCall c_ofun_call_next = null; if(op == Opcode.OP_OCALLDYN) { // Get function types to perform a type-based dynamic resolution Type types = cf.function.codeblock.getConstantType(CodeBlock.fetchArg1(instruction)); // Objects of three types may appear on the stack: // 1. FunctionInstance due to closures if(funcObject instanceof FunctionInstance) { FunctionInstance fun_instance = (FunctionInstance) funcObject; cf = cf.getFrame(fun_instance.function, fun_instance.env, arity, sp); instructions = cf.function.codeblock.getInstructions(); stack = cf.stack; sp = cf.sp; pc = cf.pc; frameObserver.enter(cf);; continue NEXT_INSTRUCTION; } // 2. OverloadedFunctionInstance due to named Rascal functions OverloadedFunctionInstance of_instance = (OverloadedFunctionInstance) funcObject; c_ofun_call_next = new OverloadedFunctionInstanceCall(cf, of_instance.getFunctions(), of_instance.getConstructors(), of_instance.env, types, arity); } else { of = overloadedStore[CodeBlock.fetchArg1(instruction)]; Object arg0 = stack[sp - arity]; c_ofun_call_next = of.getScopeIn() == -1 ? new OverloadedFunctionInstanceCall(cf, of.getFunctions(arg0), of.getConstructors(arg0), cf, null, arity) // changed root to cf : OverloadedFunctionInstanceCall.computeOverloadedFunctionInstanceCall(cf, of.getFunctions(arg0), of.getConstructors(arg0), of.getScopeIn(), null, arity); } Frame frame = c_ofun_call_next.nextFrame(functionStore); if(frame != null) { c_ofun_call = c_ofun_call_next; ocalls.push(c_ofun_call); cf = frame; frameObserver.enter(cf); instructions = cf.function.codeblock.getInstructions(); stack = cf.stack; sp = cf.sp; pc = cf.pc; } else { constructor = c_ofun_call_next.nextConstructor(constructorStore); sp = sp - arity; accu = vf.constructor(constructor, c_ofun_call_next.getConstructorArguments(constructor.getArity())); } continue NEXT_INSTRUCTION; case Opcode.OP_CHECKARGTYPEANDCOPY: pos = CodeBlock.fetchArg1(instruction); Type argType = ((IValue) stack[pos]).getType(); Type paramType = cf.function.typeConstantStore[CodeBlock.fetchArg2(instruction)]; int pos2 = (int) instructions[pc++]; if(argType.isSubtypeOf(paramType)){ stack[pos2] = stack[pos]; accu = vf.bool(true); continue NEXT_INSTRUCTION; } if(argType instanceof RascalType){ RascalType atype = (RascalType) argType; RascalType ptype = (RascalType) paramType; if(ptype.isNonterminal() && atype.isSubtypeOfNonTerminal(ptype)){ stack[pos2] = stack[pos]; accu = vf.bool(true); continue NEXT_INSTRUCTION; } } accu = vf.bool(false); //System.out.println("OP_CHECKARGTYPEANDCOPY: " + argType + ", " + paramType + " => false"); continue NEXT_INSTRUCTION; case Opcode.OP_FAILRETURN: assert cf.previousCallFrame == c_ofun_call.cf : "FAILRETURN, incorrect frame at" + cf.src; frame = c_ofun_call.nextFrame(functionStore); if(frame != null) { cf = frame; instructions = cf.function.codeblock.getInstructions(); stack = cf.stack; sp = cf.sp; pc = cf.pc; } else { cf = c_ofun_call.cf; instructions = cf.function.codeblock.getInstructions(); stack = cf.stack; sp = cf.sp; pc = cf.pc; constructor = c_ofun_call.nextConstructor(constructorStore); accu = vf.constructor(constructor, c_ofun_call.getConstructorArguments(constructor.getArity())); ocalls.pop(); c_ofun_call = ocalls.isEmpty() ? null : ocalls.peek(); } continue NEXT_INSTRUCTION; case Opcode.OP_VISIT: boolean direction = ((IBool) cf.function.constantStore[CodeBlock.fetchArg1(instruction)]).getValue(); boolean progress = ((IBool) cf.function.constantStore[CodeBlock.fetchArg2(instruction)]).getValue(); boolean fixedpoint = ((IBool) cf.function.constantStore[(int)instructions[pc++]]).getValue(); boolean rebuild = ((IBool) cf.function.constantStore[(int)instructions[pc++]]).getValue(); sp = VISIT(stack, sp, direction, progress, fixedpoint, rebuild); if(sp > 0){ continue NEXT_INSTRUCTION; } // Fall through to force a function return; sp = -sp; accu = stack[--sp]; op = Opcode.OP_RETURN1; case Opcode.OP_RETURN1: // Overloading specific if(c_ofun_call != null && cf.previousCallFrame == c_ofun_call.cf) { ocalls.pop(); c_ofun_call = ocalls.isEmpty() ? null : ocalls.peek(); } frameObserver.leave(cf, accu); cf = cf.previousCallFrame; if(cf == null) { return accu; } instructions = cf.function.codeblock.getInstructions(); stack = cf.stack; sp = cf.sp; pc = cf.pc; //stack[sp++] = accu; continue NEXT_INSTRUCTION; case Opcode.OP_FILTERRETURN: case Opcode.OP_RETURN0: // Overloading specific if(c_ofun_call != null && cf.previousCallFrame == c_ofun_call.cf) { ocalls.pop(); c_ofun_call = ocalls.isEmpty() ? null : ocalls.peek(); } rval = null; boolean returns = op != Opcode.OP_RETURN0; frameObserver.leave(cf, rval); cf = cf.previousCallFrame; if(cf == null) { return returns ? rval : NOVALUE; } instructions = cf.function.codeblock.getInstructions(); stack = cf.stack; sp = cf.sp; pc = cf.pc; if(returns) { accu = rval; } continue NEXT_INSTRUCTION; case Opcode.OP_CORETURN0: case Opcode.OP_CORETURN1: rval = Rascal_TRUE; if(op == Opcode.OP_CORETURN1) { arity = CodeBlock.fetchArg1(instruction); int[] refs = cf.function.refs; if(arity != refs.length) { throw new CompilerError("Coroutine " + cf.function.name + ": arity of return (" + arity + ") unequal to number of reference parameters (" + refs.length + ")", cf); } for(int i = 0; i < arity; i++) { ref = (Reference) stack[refs[arity - 1 - i]]; ref.stack[ref.pos] = stack[--sp]; } } // if the current frame is the frame of a top active coroutine, // then pop this coroutine from the stack of active coroutines activeCoroutines.pop(); ccf = activeCoroutines.isEmpty() ? null : activeCoroutines.peek().start; frameObserver.leave(cf, rval); cf = cf.previousCallFrame; if(cf == null) { return rval; } instructions = cf.function.codeblock.getInstructions(); stack = cf.stack; sp = cf.sp; pc = cf.pc; accu = rval; continue NEXT_INSTRUCTION; case Opcode.OP_CALLJAVA: String methodName = ((IString) cf.function.constantStore[(int) instructions[pc++]]).getValue(); String className = ((IString) cf.function.constantStore[(int) instructions[pc++]]).getValue(); Type parameterTypes = cf.function.typeConstantStore[(int) instructions[pc++]]; Type keywordTypes = cf.function.typeConstantStore[(int) instructions[pc++]]; int reflect = (int) instructions[pc++]; arity = parameterTypes.getArity(); try { //int sp1 = sp; sp = callJavaMethod(methodName, className, parameterTypes, keywordTypes, reflect, stack, sp); //assert sp == sp1 - arity + 1; } catch (Throw e) { stacktrace.add(cf); thrown = Thrown.getInstance(e.getException(), e.getLocation(), cf); postOp = Opcode.POSTOP_HANDLEEXCEPTION; break INSTRUCTION; } catch (Thrown e){ stacktrace.add(cf); thrown = e; postOp = Opcode.POSTOP_HANDLEEXCEPTION; break INSTRUCTION; } catch (Throwable e){ thrown = Thrown.getInstance(e, cf.src, cf); postOp = Opcode.POSTOP_HANDLEEXCEPTION; break INSTRUCTION; } continue NEXT_INSTRUCTION; case Opcode.OP_CREATE: case Opcode.OP_CREATEDYN: if(op == Opcode.OP_CREATE) { cccf = cf.getCoroutineFrame(functionStore[CodeBlock.fetchArg1(instruction)], root, CodeBlock.fetchArg2(instruction), sp); } else { arity = CodeBlock.fetchArg1(instruction); Object src = stack[--sp]; if(src instanceof FunctionInstance) { // In case of partial parameter binding FunctionInstance fun_instance = (FunctionInstance) src; cccf = cf.getCoroutineFrame(fun_instance, arity, sp); } else { throw new CompilerError("Unexpected argument type for INIT: " + src.getClass() + ", " + src, cf); } } sp = cf.sp; // Instead of suspending a coroutine instance during CREATE, execute it until GUARD; // Let CREATE postpone creation of an actual coroutine instance (delegated to GUARD), // which also implies no stack management of active coroutines until GUARD; cccf.previousCallFrame = cf; cf.sp = sp; cf.pc = pc; instructions = cccf.function.codeblock.getInstructions(); cf = cccf; stack = cf.stack; sp = cf.sp; pc = cf.pc; continue NEXT_INSTRUCTION; case Opcode.OP_GUARD: //rval = stack[sp - 1]; boolean precondition; if(accu instanceof IBool) { precondition = ((IBool) accu).getValue(); // } else if(rval instanceof Boolean) { // precondition = (Boolean) rval; } else { throw new CompilerError("Guard's expression has to be boolean!", cf); } if(cf == cccf) { Coroutine coroutine = null; Frame prev = cf.previousCallFrame; if(precondition) { coroutine = new Coroutine(cccf); coroutine.isInitialized = true; coroutine.suspend(cf); } cccf = null; //--sp; cf.pc = pc; cf.sp = sp; cf = prev; instructions = cf.function.codeblock.getInstructions(); stack = cf.stack; sp = cf.sp; pc = cf.pc; accu = precondition ? coroutine : exhausted; continue NEXT_INSTRUCTION; } if(!precondition) { cf.pc = pc; cf.sp = sp; cf = cf.previousCallFrame; instructions = cf.function.codeblock.getInstructions(); stack = cf.stack; sp = cf.sp; pc = cf.pc; accu = Rascal_FALSE; continue NEXT_INSTRUCTION; } //--sp; continue NEXT_INSTRUCTION; case Opcode.OP_APPLY: sp = APPLY(stack, sp, cf, functionStore[CodeBlock.fetchArg1(instruction)], CodeBlock.fetchArg2(instruction), root); continue NEXT_INSTRUCTION; case Opcode.OP_APPLYDYN: sp = APPLYDYN(CodeBlock.fetchArg1(instruction), cf, stack, sp); continue NEXT_INSTRUCTION; case Opcode.OP_NEXT0: case Opcode.OP_NEXT1: Coroutine coroutine = (Coroutine) accu; if(!coroutine.hasNext()) { if(op == Opcode.OP_NEXT1) { --sp; } accu = Rascal_FALSE; continue NEXT_INSTRUCTION; } // put the coroutine onto the stack of active coroutines activeCoroutines.push(coroutine); ccf = coroutine.start; coroutine.next(cf); instructions = coroutine.frame.function.codeblock.getInstructions(); // Transmit NEXT's arg (if present) to the corresponding YIELD in the coroutine; // but always leave an entry on the stack coroutine.frame.stack[coroutine.frame.sp++] = (op == Opcode.OP_NEXT1) ? stack[--sp] : null; cf.pc = pc; cf.sp = sp; cf = coroutine.frame; stack = cf.stack; sp = cf.sp; pc = cf.pc; continue NEXT_INSTRUCTION; case Opcode.OP_YIELD0: case Opcode.OP_YIELD1: coroutine = activeCoroutines.pop(); ccf = activeCoroutines.isEmpty() ? null : activeCoroutines.peek().start; Frame prev = coroutine.start.previousCallFrame; if(op == Opcode.OP_YIELD1) { arity = CodeBlock.fetchArg1(instruction); int[] refs = cf.function.refs; if(arity != refs.length) { throw new CompilerError("YIELD requires same number of arguments as the number of coroutine's reference parameters; arity: " + arity + "; reference parameter number: " + refs.length, cf); } // Assign the reference parameters of the currently active coroutine instance for(int i = 0; i < arity; i++) { ref = (Reference) stack[refs[arity - 1 - i]]; ref.stack[ref.pos] = stack[--sp]; } } cf.pc = pc; cf.sp = sp; coroutine.suspend(cf); cf = prev; if(op == Opcode.OP_YIELD1 && cf == null) { return Rascal_TRUE; } instructions = cf.function.codeblock.getInstructions(); stack = cf.stack; sp = cf.sp; pc = cf.pc; accu = Rascal_TRUE; // YIELD always returns TRUE to the corresponding NEXT continue NEXT_INSTRUCTION; case Opcode.OP_EXHAUST: if(cf == ccf) { activeCoroutines.pop(); ccf = activeCoroutines.isEmpty() ? null : activeCoroutines.peek().start; } cf = cf.previousCallFrame; if(cf == null) { return Rascal_FALSE; // EXHAUST always returns FALSE, to the corresponding NEXT } instructions = cf.function.codeblock.getInstructions(); stack = cf.stack; sp = cf.sp; pc = cf.pc; accu = Rascal_FALSE; // EXHAUST always returns FALSE, to the corresponding NEXT continue NEXT_INSTRUCTION; case Opcode.OP_CALLPRIMN: arity = CodeBlock.fetchArg2(instruction); cf.src = (ISourceLocation) cf.function.constantStore[(int) instructions[pc++]]; frameObserver.observe(cf); try { sp = RascalPrimitive.values[CodeBlock.fetchArg1(instruction)].executeN(stack, sp, CodeBlock.fetchArg2(instruction), cf, rex); accu = stack[--sp]; } catch (Thrown exception) { thrown = exception; sp = sp - arity; postOp = Opcode.POSTOP_HANDLEEXCEPTION; break INSTRUCTION; } continue NEXT_INSTRUCTION; case Opcode.OP_PUSHCALLPRIMN: arity = CodeBlock.fetchArg2(instruction); cf.src = (ISourceLocation) cf.function.constantStore[(int) instructions[pc++]]; frameObserver.observe(cf); try { sp = RascalPrimitive.values[CodeBlock.fetchArg1(instruction)].executeN(stack, sp, CodeBlock.fetchArg2(instruction), cf, rex); } catch (Thrown exception) { thrown = exception; sp = sp - arity; postOp = Opcode.POSTOP_HANDLEEXCEPTION; break INSTRUCTION; } continue NEXT_INSTRUCTION; case Opcode.OP_CALLPRIM0: cf.src = (ISourceLocation) cf.function.constantStore[(int) instructions[pc++]]; frameObserver.observe(cf); try { accu = RascalPrimitive.values[CodeBlock.fetchArg1(instruction)].execute0(cf, rex); } catch (Thrown exception) { thrown = exception; postOp = Opcode.POSTOP_HANDLEEXCEPTION; break INSTRUCTION; } continue NEXT_INSTRUCTION; case Opcode.OP_PUSHCALLPRIM0: cf.src = (ISourceLocation) cf.function.constantStore[(int) instructions[pc++]]; frameObserver.observe(cf); try { stack[sp++] = RascalPrimitive.values[CodeBlock.fetchArg1(instruction)].execute0(cf, rex); } catch (Thrown exception) { thrown = exception; postOp = Opcode.POSTOP_HANDLEEXCEPTION; break INSTRUCTION; } continue NEXT_INSTRUCTION; case Opcode.OP_CALLPRIM1: cf.src = (ISourceLocation) cf.function.constantStore[(int) instructions[pc++]]; frameObserver.observe(cf); try { accu = RascalPrimitive.values[CodeBlock.fetchArg1(instruction)].execute1(accu, cf, rex); } catch (Thrown exception) { thrown = exception; postOp = Opcode.POSTOP_HANDLEEXCEPTION; break INSTRUCTION; } continue NEXT_INSTRUCTION; case Opcode.OP_PUSHCALLPRIM1: cf.src = (ISourceLocation) cf.function.constantStore[(int) instructions[pc++]]; frameObserver.observe(cf); try { stack[sp++] = RascalPrimitive.values[CodeBlock.fetchArg1(instruction)].execute1(accu, cf, rex); } catch (Thrown exception) { thrown = exception; postOp = Opcode.POSTOP_HANDLEEXCEPTION; break INSTRUCTION; } continue NEXT_INSTRUCTION; case Opcode.OP_CALLPRIM2: cf.src = (ISourceLocation) cf.function.constantStore[(int) instructions[pc++]]; frameObserver.observe(cf); try { accu = RascalPrimitive.values[CodeBlock.fetchArg1(instruction)].execute2(stack[sp - 1], accu, cf, rex); sp--; } catch (Thrown exception) { thrown = exception; sp = sp - 1; postOp = Opcode.POSTOP_HANDLEEXCEPTION; break INSTRUCTION; } continue NEXT_INSTRUCTION; case Opcode.OP_PUSHCALLPRIM2: cf.src = (ISourceLocation) cf.function.constantStore[(int) instructions[pc++]]; frameObserver.observe(cf); try { stack[sp - 1] = RascalPrimitive.values[CodeBlock.fetchArg1(instruction)].execute2(stack[sp - 1], accu, cf, rex); } catch (Thrown exception) { thrown = exception; sp = sp - 1; postOp = Opcode.POSTOP_HANDLEEXCEPTION; break INSTRUCTION; } continue NEXT_INSTRUCTION; case Opcode.OP_UNWRAPTHROWNLOC: { pos = CodeBlock.fetchArg1(instruction); assert pos < cf.function.getNlocals() : "UNWRAPTHROWNLOC: pos larger that nlocals at " + cf.src; stack[pos] = ((Thrown) stack[--sp]).getValue(); continue NEXT_INSTRUCTION; } case Opcode.OP_UNWRAPTHROWNVAR: sp = UNWRAPTHROWNVAR(stack, sp, cf, CodeBlock.fetchArg1(instruction), CodeBlock.fetchArg2(instruction)); continue NEXT_INSTRUCTION; // Some specialized MuPrimitives case Opcode.OP_SUBSCRIPTARRAY: accu = ((Object[]) stack[sp - 1])[((Integer) accu)]; sp--; continue NEXT_INSTRUCTION; case Opcode.OP_SUBSCRIPTLIST: accu = ((IList) stack[sp - 1]).get((Integer) accu); sp--; continue NEXT_INSTRUCTION; case Opcode.OP_LESSINT: accu = vf.bool(((Integer) stack[sp - 1]) < ((Integer) accu)); sp--; continue NEXT_INSTRUCTION; case Opcode.OP_GREATEREQUALINT: accu = vf.bool(((Integer) stack[sp - 1]) >= ((Integer) accu)); sp--; continue NEXT_INSTRUCTION; case Opcode.OP_ADDINT: accu = ((Integer) stack[sp - 1]) + ((Integer) accu); sp--; continue NEXT_INSTRUCTION; case Opcode.OP_SUBTRACTINT: accu = ((Integer) stack[sp - 1]) - ((Integer) accu); sp--; continue NEXT_INSTRUCTION; case Opcode.OP_ANDBOOL: accu = ((IBool) stack[sp - 1]).and((IBool) accu); sp--; continue NEXT_INSTRUCTION; case Opcode.OP_TYPEOF: if(accu instanceof HashSet<?>){ // For the benefit of set matching HashSet<IValue> mset = (HashSet<IValue>) accu; if(mset.isEmpty()){ accu = tf.setType(tf.voidType()); } else { IValue v = mset.iterator().next(); accu = tf.setType(v.getType()); } } else { accu = ((IValue) accu).getType(); } continue NEXT_INSTRUCTION; case Opcode.OP_SUBTYPE: accu = vf.bool(((Type) stack[sp - 1]).isSubtypeOf((Type) accu)); sp--; continue NEXT_INSTRUCTION; case Opcode.OP_VALUESUBTYPE: accu = VALUESUBTYPE(cf.function.typeConstantStore[CodeBlock.fetchArg1(instruction)], accu); continue NEXT_INSTRUCTION; case Opcode.OP_LABEL: throw new CompilerError("LABEL instruction at runtime", cf); case Opcode.OP_HALT: return stack[sp - 1]; case Opcode.OP_PRINTLN: sp = PRINTLN(stack, sp, CodeBlock.fetchArg1(instruction)); continue NEXT_INSTRUCTION; case Opcode.OP_THROW: Object obj = stack[--sp]; thrown = null; cf.src = (ISourceLocation) cf.function.constantStore[CodeBlock.fetchArg1(instruction)]; frameObserver.observe(cf); if(obj instanceof IValue) { //stacktrace = new ArrayList<Frame>(); //stacktrace.add(cf); thrown = Thrown.getInstance((IValue) obj, null, cf); } else { // Then, an object of type 'Thrown' is on top of the stack thrown = (Thrown) obj; } postOp = Opcode.POSTOP_HANDLEEXCEPTION; break INSTRUCTION; case Opcode.OP_LOADLOCKWP: accu = LOADLOCKWP(stack, cf, CodeBlock.fetchArg1(instruction)); continue NEXT_INSTRUCTION; case Opcode.OP_PUSHLOCKWP: stack[sp++] = LOADLOCKWP(stack, cf, CodeBlock.fetchArg1(instruction)); continue NEXT_INSTRUCTION; case Opcode.OP_LOADVARKWP: accu = LOADVARKWP(cf, CodeBlock.fetchArg1(instruction), CodeBlock.fetchArg2(instruction)); continue NEXT_INSTRUCTION; case Opcode.OP_PUSHVARKWP: stack[sp++] = LOADVARKWP(cf, CodeBlock.fetchArg1(instruction), CodeBlock.fetchArg2(instruction)); continue NEXT_INSTRUCTION; case Opcode.OP_STORELOCKWP: STORELOCKWP(stack, cf, CodeBlock.fetchArg1(instruction), accu); continue NEXT_INSTRUCTION; case Opcode.OP_STOREVARKWP: STOREVARKWP(cf, CodeBlock.fetchArg1(instruction), CodeBlock.fetchArg2(instruction), accu); continue NEXT_INSTRUCTION; case Opcode.OP_CHECKMEMO: sp = CHECKMEMO(stack, sp, cf); if(sp > 0){ accu = stack[--sp]; continue NEXT_INSTRUCTION; } sp = - sp; op = Opcode.OP_RETURN1; // Specialized copy of RETURN code // Overloading specific if(c_ofun_call != null && cf.previousCallFrame == c_ofun_call.cf) { ocalls.pop(); c_ofun_call = ocalls.isEmpty() ? null : ocalls.peek(); } rval = stack[sp - 1]; assert sp == cf.function.getNlocals() + 1 : "On return from " + cf.function.name + ": " + (sp - cf.function.getNlocals()) + " spurious stack elements"; // if the current frame is the frame of a top active coroutine, // then pop this coroutine from the stack of active coroutines if(cf == ccf) { activeCoroutines.pop(); ccf = activeCoroutines.isEmpty() ? null : activeCoroutines.peek().start; } if(!frameObserver.leave(cf, rval)){ return Rascal_FALSE; } cf = cf.previousCallFrame; if(cf == null) { return rval; } instructions = cf.function.codeblock.getInstructions(); stack = cf.stack; sp = cf.sp; pc = cf.pc; accu = rval; continue NEXT_INSTRUCTION; default: throw new CompilerError("RVM main loop -- cannot decode instruction", cf); } switch(postOp){ case Opcode.POSTOP_CHECKUNDEF: case Opcode.POSTOP_HANDLEEXCEPTION: // EXCEPTION HANDLING if(postOp == Opcode.POSTOP_CHECKUNDEF) { //stacktrace = new ArrayList<Frame>(); //stacktrace.add(cf); thrown = RascalRuntimeException.uninitializedVariable("name to be provided", cf); } cf.pc = pc; // First, try to find a handler in the current frame function, // given the current instruction index and the value type, // then, if not found, look up the caller function(s) for(Frame f = cf; f != null; f = f.previousCallFrame) { int handler = f.function.getHandler(f.pc - 1, thrown.getValue().getType()); if(handler != -1) { int fromSP = f.function.getFromSP(); if(f != cf) { cf = f; instructions = cf.function.codeblock.getInstructions(); stack = cf.stack; sp = cf.sp; pc = cf.pc; } pc = handler; sp = fromSP; stack[sp++] = thrown; thrown = null; continue NEXT_INSTRUCTION; } if(c_ofun_call != null && f.previousCallFrame == c_ofun_call.cf) { ocalls.pop(); c_ofun_call = ocalls.isEmpty() ? null : ocalls.peek(); } } // If a handler has not been found in the caller functions... // stdout.println("EXCEPTION " + thrown + " at: " + cf.src); // for(Frame f = cf; f != null; f = f.previousCallFrame) { // stdout.println("\t" + f.toString()); // } // stdout.flush(); if(frameObserver.exception(cf, thrown)){ continue NEXT_INSTRUCTION; } else { return thrown; } } } } catch (Thrown e) { throw e; // this is a normal Rascal exception, but we want to handle the next case here exceptionally, which // should not happen normally and hints at a compiler or run-time bug: } catch (Exception e) { stdout.println("EXCEPTION " + e + " at: " + cf.src); for(Frame f = cf; f != null; f = f.previousCallFrame) { stdout.println("\t" + f.toString()); } stdout.flush(); e.printStackTrace(stderr); stderr.flush(); String e2s = (e instanceof CompilerError) ? e.getMessage() : e.toString(); throw new CompilerError(e2s + "; function: " + cf + "; instruction: " + cf.function.codeblock.toString(pc - 1), cf, e); } } }