package org.rascalmpl.library.experiments.Compiler.RVM.Interpreter; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import org.rascalmpl.interpreter.TypeReifier; 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.ISet; import org.rascalmpl.value.ISetWriter; import org.rascalmpl.value.ISourceLocation; import org.rascalmpl.value.IString; import org.rascalmpl.value.ITuple; import org.rascalmpl.value.IValue; import org.rascalmpl.value.IValueFactory; import org.rascalmpl.value.type.Type; import org.rascalmpl.value.type.TypeFactory; import org.rascalmpl.value.type.TypeStore; /** * The RVMLinker takes an RVMProgram (and its imports) and creates a single RVMExecutable for it, with * - all overloaded resolved * - all unused functions removed */ public class RVMLinker { private IValueFactory vf; private TypeFactory tf; // Functions private ArrayList<Function> functionStore; private Map<String, Integer> functionMap; // Constructors private ArrayList<Type> constructorStore; private Map<String, Integer> constructorMap; // Function overloading private Map<String, Integer> resolver; private ArrayList<OverloadedFunction> overloadedStore; private TypeStore typeStore; private final Types types; public RVMLinker(IValueFactory vf, TypeStore typeStore) { this.vf = vf; this.types = new Types(this.vf); this.tf = TypeFactory.getInstance(); this.typeStore = typeStore; } String moduleInit(String moduleName){ return "/#" + moduleName + "_init(list(value());)#0"; } String muModuleInit(String moduleName){ return "/#" + moduleName + "_init"; } private void validateInstructionAdressingLimits(){ int nfs = functionStore.size(); //System.out.println("size functionStore: " + nfs); if(nfs >= CodeBlock.maxArg){ throw new CompilerError("functionStore size " + nfs + " exceeds limit " + CodeBlock.maxArg1); } int ncs = constructorStore.size(); //System.out.println("size constructorStore: " + ncs); if(ncs >= CodeBlock.maxArg){ throw new CompilerError("constructorStore size " + ncs + " exceeds limit " + CodeBlock.maxArg1); } int nov = overloadedStore.size(); //System.out.println("size overloadedStore: " + nov); if(nov >= CodeBlock.maxArg){ throw new CompilerError("overloadedStore size " + nov + " exceeds limit " + CodeBlock.maxArg1); } } private HashSet<String> usedFunctions = new HashSet<>(); private Integer useFunctionName(String fname){ Integer index = functionMap.get(fname); if(index == null){ index = functionStore.size(); functionMap.put(fname, index); functionStore.add(null); //System.out.println("useFunctionName (undef): " + index + " => " + fname); usedFunctions.add(fname); } //System.out.println("useFunctionName: " + index + " => " + fname); return index; } private void declareFunction(Function f){ Integer index = functionMap.get(f.getName()); if(index == null){ index = functionStore.size(); functionMap.put(f.getName(), index); functionStore.add(f); f.funId = index ; } else { functionStore.set(index, f); f.funId = index ; } //System.out.println("declareFunction: " + index + " => " + f.getName()); } private Integer useConstructorName(String cname) { Integer index = constructorMap.get(cname) ; if(index == null) { index = constructorStore.size(); constructorMap.put(cname, index); constructorStore.add(null); } //System.out.println("useConstructorName: " + index + " => " + cname); return index; } public Type loadProduction(IConstructor symbol) { return types.loadProduction(symbol); } private void declareConstructor(String cname, IConstructor symbol) { Type constr = loadProduction(symbol); Integer index = constructorMap.get(cname); if(index == null) { index = constructorStore.size(); constructorMap.put(cname, index); constructorStore.add(constr); } else { constructorStore.set(index, constr); } } private void addResolver(IMap resolver) { for(IValue fuid : resolver) { String of = ((IString) fuid).getValue(); int index = ((IInteger) resolver.get(fuid)).intValue(); this.resolver.put(of, index); } } private void fillOverloadedStore(IList overloadedStore) { for(IValue of : overloadedStore) { ITuple ofTuple = (ITuple) of; String funName = ((IString) ofTuple.get(0)).getValue(); IConstructor funType = (IConstructor) ofTuple.get(1); String scopeIn = ((IString) ofTuple.get(2)).getValue(); IList fuids = (IList) ofTuple.get(3); // function alternatives int[] funs = new int[fuids.length()]; int alt = 0; for(IValue fuid : fuids) { String name = ((IString) fuid).getValue(); //System.out.println("fillOverloadedStore: add function " + name); Integer index = useFunctionName(name); funs[alt++] = index; } fuids = (IList) ofTuple.get(4); // constructor alternatives int[] constrs = new int[fuids.length()]; alt = 0; for(IValue fuid : fuids) { Integer index = useConstructorName(((IString) fuid).getValue()); constrs[alt++] = index; } OverloadedFunction res = new OverloadedFunction(funName, new TypeReifier(vf).symbolToType(funType, vf.mapWriter().done()), funs, constrs, scopeIn); this.overloadedStore.add(res); } } private void validateExecutable(){ int nfun = functionStore.size(); if(nfun != functionMap.size()){ System.err.println("functionStore and functionMap have different size: " + nfun + " vs " + functionMap.size()); } for(String fname : functionMap.keySet()){ int n = functionMap.get(fname); if(functionStore.get(n) == null){ System.err.println("FunctionStore has null entry for: "+ fname + " at index " + n); } } int ncon = constructorStore.size(); if(ncon != constructorMap.size()){ System.err.println("constructorStore and constructorMap have different size: " + ncon + " vs " + constructorMap.size()); } for(String cname : constructorMap.keySet()){ int n = constructorMap.get(cname); if(constructorStore.get(n) == null){ System.err.println("ConstructorStore has null entry for: "+ cname + " at index " + n); } } } private void validateOverloading(){ for(String oname : resolver.keySet()){ int n = resolver.get(oname); if(overloadedStore.get(n) == null){ System.err.println("OverloadedStore has null entry for: "+ oname + " at index " + n); } } } /* * Remove all unused functions from this RVM, given a set of used functions: * - Remove unused functions from functionMap and shift function indices * - The finalize in overloaded functions uses the resulting indexMap to shift and prune * function indices in overloading vectors */ private HashMap<Integer,Integer> removeUnusedFunctions(ISet used){ int newSize = used.size(); ArrayList<Function> newFunctionStore = new ArrayList<Function>(newSize); HashMap<Integer,Integer> functionIndexMap = new HashMap<>(newSize); // Prune and shift functionMap and functionStore int shift = 0; for(int i = 0; i < functionStore.size(); i++){ Function fn = functionStore.get(i); if(!used.contains(vf.string(fn.name))){ functionMap.remove(fn.name); shift++; } else { int ishifted = i - shift; fn.funId = ishifted; functionMap.put(fn.name, ishifted); newFunctionStore.add(fn); functionIndexMap.put(i, ishifted); //System.err.println("Shift " + fn.name + " from " + i + " to " + ishifted); } } functionStore = newFunctionStore; return functionIndexMap; } /* * After collecting the basic use relation for all functions we have * to expand each overlaoded function to all its possible alternatives. * This can only be done in a second pass over the use relation * when all function overloading information is available. */ private ISet expandOverloadedFunctionUses(ISet initial){ ISetWriter w = vf.setWriter(); for(IValue v : initial){ ITuple tup = (ITuple) v; IString left = (IString) tup.get(0); IString right = (IString) tup.get(1); Integer uresolver = resolver.get(right.getValue()); if(uresolver != null){ // right is an overloaded function, replace by its alternatives OverloadedFunction of = overloadedStore.get(uresolver); for (int uuid : of.functions){ Function function = functionStore.get(uuid); if (function == null) { throw new CompilerError("No function for uuid " + uuid + " in store, part of overloaded function:" + of); } w.insert(vf.tuple(left, vf.string(function.name))); } } else { // otherwise, keep original tuple w.insert(tup); } } return w.done(); } private void finalizeInstructions(Map<Integer, Integer> indexMap){ int i = 0; for(String fname : functionMap.keySet()){ if(functionMap.get(fname) == null){ System.out.println("finalizeInstructions, null for function : " + fname); } } for(String fname : functionMap.keySet()) { Function f = functionStore.get(functionMap.get(fname)); if(f == null){ String nameAtIndex = "**unknown**"; for(String fname2 : functionMap.keySet()){ if(functionMap.get(fname2) == i){ nameAtIndex = fname2; break; } } System.out.println("finalizeInstructions, null at index: " + i + ", " + nameAtIndex); } else { //System.out.println("finalizeInstructions: " + f.name); } f.finalize(functionMap, constructorMap, resolver); i++; } for(OverloadedFunction of : overloadedStore) { of.finalize(functionMap, functionStore, indexMap); } } private void addFunctionUses(ISetWriter w, IString fname, ISet uses){ for(IValue use : uses){ w.insert(vf.tuple(fname, use)); } } private void addOverloadedFunctionUses(ISetWriter w, IString fname, ISet uses){ //System.err.println("addOverloadedFunctionUses:" + fname + ", " + uses); for(IValue use : uses){ w.insert(vf.tuple(fname, use)); } } public ISet getErrors(IConstructor program){ ISetWriter w = vf.setWriter(); IConstructor main_module = (IConstructor) program.get("main_module"); ISet messages = (ISet) main_module.get("messages"); for(IValue v : messages){ IConstructor msg = (IConstructor) v; if(msg.getName().equals("error")){ w.insert(msg); } } return w.done(); } public RVMExecutable link(IConstructor program, boolean jvm) throws IOException { ISet errors = getErrors(program); if(errors.size() > 0){ return new RVMExecutable(errors); } boolean eliminateDeadCode = true; functionStore = new ArrayList<Function>(); constructorStore = new ArrayList<Type>(); functionMap = new HashMap<String, Integer>(); constructorMap = new HashMap<String, Integer>(); resolver = new HashMap<String,Integer>(); overloadedStore = new ArrayList<OverloadedFunction>(); IMap imported_module_tags = (IMap) program.get("imported_module_tags"); IConstructor main_module = (IConstructor) program.get("main_module"); IMap moduleTags = imported_module_tags.put(main_module.get("name"), main_module.get("module_tags")); String moduleName = ((IString) main_module.get("name")).getValue(); IList extendedModules = (IList) main_module.get("extends"); HashSet<String> extendedModuleSet = new HashSet<>(); for(IValue v : extendedModules){ extendedModuleSet.add(((IString) v).getValue()); } boolean hasExtends = !extendedModuleSet.isEmpty(); /** Imported types */ IMap imported_types = (IMap) program.get("imported_types"); Iterator<Entry<IValue, IValue>> entries = imported_types.entryIterator(); while(entries.hasNext()) { Entry<IValue, IValue> entry = entries.next(); declareConstructor(((IString) entry.getKey()).getValue(), (IConstructor) entry.getValue()); } /** Overloading resolution */ // Overloading resolution of imported functions IMap imported_overloading_resolvers = (IMap) program.get("imported_overloading_resolvers"); addResolver(imported_overloading_resolvers); IList imported_overloaded_functions = (IList) program.get("imported_overloaded_functions"); fillOverloadedStore(imported_overloaded_functions); // Overloading resolution of functions in main module addResolver((IMap) main_module.get("resolver")); fillOverloadedStore((IList) main_module.get("overloaded_functions")); ISetWriter usesWriter = vf.setWriter(); ISetWriter rootWriter = vf.setWriter(); /** Imported functions */ ArrayList<String> initializers = new ArrayList<String>(); // initializers of imported modules IList imported_declarations = (IList) program.get("imported_declarations"); for(IValue imp : imported_declarations){ IConstructor declaration = (IConstructor) imp; IString iname = (IString) declaration.get("qname"); String name = iname.getValue(); if (declaration.getName().contentEquals("FUNCTION")) { //System.out.println("IMPORTED FUNCTION: " + name); if(name.endsWith("_init(list(value());)#0")){ rootWriter.insert(iname); initializers.add(name); } loadInstructions(name, declaration, false); if(eliminateDeadCode){ addOverloadedFunctionUses(usesWriter, iname, (ISet) declaration.get("usedOverloadedFunctions")); addFunctionUses(usesWriter, iname, (ISet) declaration.get("usedFunctions")); if(name.contains("companion")){ // always preserve generated companion and companion-defaults functions rootWriter.insert(iname); loadInstructions(name, declaration, false); } if(name.contains("closure#")){ // preserve generated closure functions and their enclosing function // (this is an overapproximation and may result in preserving some unused functions) IString scopeIn = (IString) declaration.get("scopeIn"); rootWriter.insert(iname); rootWriter.insert(scopeIn); } if(hasExtends){ int n = name.indexOf("/"); if(n >=0 && extendedModuleSet.contains(name.substring(0, n))){ rootWriter.insert(iname); } } } } if (declaration.getName().contentEquals("COROUTINE")) { loadInstructions(name, declaration, true); if(eliminateDeadCode){ addOverloadedFunctionUses(usesWriter, iname, (ISet) declaration.get("usedOverloadedFunctions")); addFunctionUses(usesWriter, iname, (ISet) declaration.get("usedFunctions")); } } } /** Types from main module */ IMap types = (IMap) main_module.get("types"); entries = types.entryIterator(); while(entries.hasNext()) { Entry<IValue, IValue> entry = entries.next(); declareConstructor(((IString) entry.getKey()).getValue(), (IConstructor) entry.getValue()); } /** Declarations for main module */ String main = "/main()#0"; String mu_main = "/MAIN"; String module_init = moduleInit(moduleName); String mu_module_init = muModuleInit(moduleName); String uid_module_main = ""; String uid_module_init = ""; IList declarations = (IList) main_module.get("declarations"); for (IValue ideclaration : declarations) { IConstructor declaration = (IConstructor) ideclaration; IString iname = (IString) declaration.get("qname"); String name = iname.getValue(); if (declaration.getName().contentEquals("FUNCTION")) { //System.out.println("FUNCTION: " + name); if(name.endsWith(main) || name.endsWith(mu_main)) { uid_module_main = name; // Get main's uid in current module } if(name.endsWith(module_init) || name.endsWith(mu_module_init)) { uid_module_init = name; // Get module_init's uid in current module } loadInstructions(name, declaration, false); if(eliminateDeadCode){ rootWriter.insert(iname); addOverloadedFunctionUses(usesWriter, iname, (ISet) declaration.get("usedOverloadedFunctions")); addFunctionUses(usesWriter, iname, (ISet) declaration.get("usedFunctions")); } } if(declaration.getName().contentEquals("COROUTINE")) { loadInstructions(name, declaration, true); if(eliminateDeadCode){ addOverloadedFunctionUses(usesWriter, iname, (ISet) declaration.get("usedOverloadedFunctions")); addFunctionUses(usesWriter, iname, (ISet) declaration.get("usedFunctions")); } } } HashMap<Integer, Integer> indexMap = null; if(eliminateDeadCode){ ISet uses = expandOverloadedFunctionUses(usesWriter.done()); ISet roots = rootWriter.done(); ISetWriter usedWriter = vf.setWriter(); for(IValue v : roots){ usedWriter.insert(v); } for(IValue v : uses.asRelation().closure()){ ITuple tup = (ITuple) v; if(roots.contains(tup.get(0))){ usedWriter.insert(tup.get(1)); } } ISet used = usedWriter.done(); indexMap = removeUnusedFunctions(used); } /** Finalize & validate */ finalizeInstructions(indexMap); validateInstructionAdressingLimits(); validateExecutable(); validateOverloading(); //System.out.println("Linking: " + (Timing.getCpuTime() - start)/1000000 + " ms"); return new RVMExecutable(((IString) main_module.get("name")).getValue(), moduleTags, (IMap) main_module.get("symbol_definitions"), functionMap, functionStore.toArray(new Function[functionStore.size()]), constructorMap, constructorStore, resolver, overloadedStore.toArray(new OverloadedFunction[overloadedStore.size()]), initializers, uid_module_init, uid_module_main, typeStore, vf, jvm); } /* * Utility function for instruction loading */ // Get Boolean field from an instruction private boolean getBooleanField(IConstructor instruction, String field) { return ((IBool) instruction.get(field)).getValue(); } // Get integer field from an instruction private int getIntField(IConstructor instruction, String field) { return ((IInteger) instruction.get(field)).intValue(); } // Get String field from an instruction private String getStrField(IConstructor instruction, String field) { return ((IString) instruction.get(field)).getValue(); } // Get Location field from an instruction private ISourceLocation getLocField(IConstructor instruction, String field) { return ((ISourceLocation) instruction.get(field)); } private IList getListField(IConstructor instruction, String field) { return ((IList) instruction.get(field)); } /** * Load the instructions of a function in a RVM. * * @param name of the function to be loaded * @param declaration the declaration of that function * @param rvm in which function will be loaded */ private void loadInstructions(String name, IConstructor declaration, boolean isCoroutine){ int continuationPoints = 0 ; Type ftype = isCoroutine ? tf.voidType() : types.symbolToType((IConstructor) declaration.get("ftype")); Type kwType = null; // transitional for boot if(!isCoroutine && declaration.has("kwType")){ kwType = types.symbolToType((IConstructor) declaration.get("kwType")); } String scopeIn = ((IString) declaration.get("scopeIn")).getValue(); // if(scopeIn.equals("")) { // scopeIn = null; // } Integer nlocals = ((IInteger) declaration.get("nlocals")).intValue(); IMap localNames = ((IMap) declaration.get("localNames")); Integer nformals = ((IInteger) declaration.get("nformals")).intValue(); Integer maxstack = ((IInteger) declaration.get("maxStack")).intValue(); IList code = (IList) declaration.get("instructions"); ISourceLocation src = (ISourceLocation) declaration.get("src"); boolean isDefault = false; boolean isTest = false; IMap tags = null; boolean isConcreteArg = false; int abstractFingerprint = 0; int concreteFingerprint = 0; if(!isCoroutine){ isDefault = ((IBool) declaration.get("isDefault")).getValue(); if(declaration.has("isTest")){ // Transitional for boot isTest = ((IBool) declaration.get("isTest")).getValue(); tags = ((IMap) declaration.get("tags")); } else { tags = vf.mapWriter().done(); } isConcreteArg = ((IBool) declaration.get("isConcreteArg")).getValue(); abstractFingerprint = ((IInteger) declaration.get("abstractFingerprint")).intValue(); concreteFingerprint = ((IInteger) declaration.get("concreteFingerprint")).intValue(); } CodeBlock codeblock = new CodeBlock(name, vf); // Loading instructions try { for (int i = 0; i < code.length(); i++) { IConstructor instruction = (IConstructor) code.get(i); String opcode = instruction.getName(); // TODO: let's do this with Java reflection; the names all match up and this code // is brittle to extension and renaming switch (opcode) { case "LOADCON": codeblock.LOADCON(instruction.get("val")); break; case "PUSHCON": codeblock.PUSHCON(instruction.get("val")); break; case "LOADVAR": codeblock.LOADVAR(getStrField(instruction, "fuid"), getIntField(instruction, "pos")); break; case "PUSHVAR": codeblock.PUSHVAR(getStrField(instruction, "fuid"), getIntField(instruction, "pos")); break; case "LOADLOC": codeblock.LOADLOC(getIntField(instruction, "pos")); break; case "PUSHLOC": codeblock.PUSHLOC(getIntField(instruction, "pos")); break; case "STOREVAR": codeblock.STOREVAR(getStrField(instruction, "fuid"), getIntField(instruction, "pos")); break; case "RESETVAR": codeblock.RESETVAR(getStrField(instruction, "fuid"), getIntField(instruction, "pos")); break; case "STORELOC": codeblock.STORELOC(getIntField(instruction, "pos")); break; case "RESETLOC": codeblock.RESETLOC(getIntField(instruction, "pos")); break; case "LABEL": codeblock = codeblock.LABEL(getStrField(instruction, "label")); break; case "CALL": codeblock.CALL(getStrField(instruction, "fuid"), getIntField(instruction, "arity"),++continuationPoints); break; case "CALLDYN": codeblock.CALLDYN( getIntField(instruction, "arity"), ++continuationPoints); break; case "APPLY": codeblock.APPLY(getStrField(instruction, "fuid"), getIntField(instruction, "arity")); break; case "APPLYDYN": codeblock.APPLYDYN(getIntField(instruction, "arity")); break; case "PUSH_ROOT_FUN": codeblock.PUSH_ROOT_FUN(getStrField(instruction, "fuid")); break; case "RETURN0": codeblock.RETURN0(); break; case "RETURN1": codeblock.RETURN1(); break; case "CORETURN0": codeblock.CORETURN0(); break; case "CORETURN1": codeblock.CORETURN1(getIntField(instruction, "arity")); break; case "JMP": codeblock.JMP(getStrField(instruction, "label")); break; case "JMPTRUE": codeblock.JMPTRUE(getStrField(instruction, "label")); break; case "JMPFALSE": codeblock.JMPFALSE(getStrField(instruction, "label")); break; case "HALT": codeblock.HALT(); break; case "CREATE": codeblock.CREATE(getStrField(instruction, "fuid"), getIntField(instruction, "arity")); break; case "CREATEDYN": codeblock.CREATEDYN(getIntField(instruction, "arity")); break; case "NEXT0": codeblock.NEXT0(); break; case "NEXT1": codeblock.NEXT1(); break; case "YIELD0": codeblock.YIELD0(++continuationPoints); break; case "YIELD1": codeblock.YIELD1(getIntField(instruction, "arity"),++continuationPoints); break; case "PRINTLN": codeblock.PRINTLN(getIntField(instruction, "arity")); break; case "POP": codeblock.POP(); break; case "LOADLOCREF": codeblock.LOADLOCREF(getIntField(instruction, "pos")); break; case "PUSHLOCREF": codeblock.PUSHLOCREF(getIntField(instruction, "pos")); break; case "LOADVARREF": codeblock.LOADVARREF(getStrField(instruction, "fuid"), getIntField(instruction, "pos")); break; case "PUSHVARREF": codeblock.PUSHVARREF(getStrField(instruction, "fuid"), getIntField(instruction, "pos")); break; case "LOADLOCDEREF": codeblock.LOADLOCDEREF(getIntField(instruction, "pos")); break; case "PUSHLOCDEREF": codeblock.PUSHLOCDEREF(getIntField(instruction, "pos")); break; case "LOADVARDEREF": codeblock.LOADVARDEREF(getStrField(instruction, "fuid"), getIntField(instruction, "pos")); break; case "PUSHVARDEREF": codeblock.PUSHVARDEREF(getStrField(instruction, "fuid"), getIntField(instruction, "pos")); break; case "STORELOCDEREF": codeblock.STORELOCDEREF(getIntField(instruction, "pos")); break; case "STOREVARDEREF": codeblock.STOREVARDEREF(getStrField(instruction, "fuid"), getIntField(instruction, "pos")); break; case "PUSH_NESTED_FUN": codeblock.PUSHNESTEDFUN(getStrField(instruction, "fuid"), getStrField(instruction, "scopeIn")); break; case "PUSHCONSTR": codeblock.PUSHCONSTR(getStrField(instruction, "fuid")); break; case "CALLCONSTR": codeblock.CALLCONSTR(getStrField(instruction, "fuid"), getIntField(instruction, "arity")/*, getLocField(instruction, "src")*/); break; case "LOADTYPE": codeblock.LOADTYPE(getTypeField(instruction, "type")); break; case "PUSHTYPE": codeblock.PUSHTYPE(getTypeField(instruction, "type")); break; case "LOADBOOL": codeblock.LOADBOOL(getBooleanField(instruction, "bval")); break; case "LOADINT": codeblock.LOADINT(getIntField(instruction, "nval")); break; case "FAILRETURN": codeblock.FAILRETURN(); break; case "PUSHOFUN" : codeblock.PUSHOFUN(getStrField(instruction, "fuid")); break; case "OCALL" : codeblock.OCALL(getStrField(instruction, "fuid"), getIntField(instruction, "arity"), getLocField(instruction, "src")); break; case "OCALLDYN" : codeblock.OCALLDYN(getTypeField(instruction, "types"), getIntField(instruction, "arity"), getLocField(instruction, "src")); break; case "CALLJAVA": codeblock.CALLJAVA(getStrField(instruction, "name"), getStrField(instruction, "class"), getTypeField(instruction, "parameterTypes"), getTypeField(instruction, "keywordTypes"), getIntField(instruction, "reflect")); break; case "THROW": codeblock.THROW(getLocField(instruction, "src")); break; case "TYPESWITCH": codeblock.TYPESWITCH((IList)instruction.get("labels")); break; case "UNWRAPTHROWNLOC": codeblock.UNWRAPTHROWNLOC(getIntField(instruction, "pos")); break; case "FILTERRETURN": codeblock.FILTERRETURN(); break; case "EXHAUST": codeblock.EXHAUST(); break; case "GUARD": codeblock.GUARD(++continuationPoints); break; case "SUBSCRIPTARRAY": codeblock.SUBSCRIPTARRAY(); break; case "SUBSCRIPTLIST": codeblock.SUBSCRIPTLIST(); break; case "LESSINT": codeblock.LESSINT(); break; case "GREATEREQUALINT": codeblock.GREATEREQUALINT(); break; case "ADDINT": codeblock.ADDINT(); break; case "SUBTRACTINT": codeblock.SUBTRACTINT(); break; case "ANDBOOL": codeblock.ANDBOOL(); break; case "TYPEOF": codeblock.TYPEOF(); break; case "SUBTYPE": codeblock.SUBTYPE(); break; case "CHECKARGTYPEANDCOPY": codeblock.CHECKARGTYPEANDCOPY(getIntField(instruction, "pos1"), getTypeField(instruction, "type"), getIntField(instruction, "pos2")); break; case "LOADLOCKWP": codeblock.LOADLOCKWP(getStrField(instruction, "name")); break; case "PUSHLOCKWP": codeblock.PUSHLOCKWP(getStrField(instruction, "name")); break; case "LOADVARKWP": codeblock.LOADVARKWP(getStrField(instruction, "fuid"), getStrField(instruction, "name")); break; case "PUSHVARKWP": codeblock.PUSHVARKWP(getStrField(instruction, "fuid"), getStrField(instruction, "name")); break; case "STORELOCKWP": codeblock.STORELOCKWP(getStrField(instruction, "name")); break; case "STOREVARKWP": codeblock.STOREVARKWP(getStrField(instruction, "fuid"), getStrField(instruction, "name")); break; case "UNWRAPTHROWNVAR": codeblock.UNWRAPTHROWNVAR(getStrField(instruction, "fuid"), getIntField(instruction, "pos")); break; case "SWITCH": codeblock.SWITCH((IMap)instruction.get("caseLabels"), getStrField(instruction, "caseDefault"), getBooleanField(instruction, "useConcreteFingerprint")); break; case "RESETLOCS": codeblock.RESETLOCS(getListField(instruction, "positions")); break; case "VISIT": codeblock.VISIT(getBooleanField(instruction, "direction"), getBooleanField(instruction, "fixedpoint"), getBooleanField(instruction, "progress"), getBooleanField(instruction, "rebuild")); break; case "CHECKMEMO": codeblock.CHECKMEMO(); break; case "PUSHEMPTYKWMAP": codeblock.PUSHEMPTYKWMAP(); break; case "VALUESUBTYPE": codeblock.VALUESUBTYPE(getTypeField(instruction, "type")); break; case "CALLMUPRIM0": codeblock.CALLMUPRIM0(MuPrimitive.valueOf(getStrField(instruction, "name"))); break; case "PUSHCALLMUPRIM0": codeblock.PUSHCALLMUPRIM0(MuPrimitive.valueOf(getStrField(instruction, "name"))); break; case "CALLMUPRIM1": codeblock.CALLMUPRIM1(MuPrimitive.valueOf(getStrField(instruction, "name"))); break; case "PUSHCALLMUPRIM1": codeblock.PUSHCALLMUPRIM1(MuPrimitive.valueOf(getStrField(instruction, "name"))); break; case "CALLMUPRIM2": codeblock.CALLMUPRIM2(MuPrimitive.valueOf(getStrField(instruction, "name"))); break; case "PUSHCALLMUPRIM2": codeblock.PUSHCALLMUPRIM2(MuPrimitive.valueOf(getStrField(instruction, "name"))); break; case "CALLMUPRIMN": codeblock.CALLMUPRIMN(MuPrimitive.valueOf(getStrField(instruction, "name")), getIntField(instruction, "arity")); break; case "PUSHCALLMUPRIMN": codeblock.PUSHCALLMUPRIMN(MuPrimitive.valueOf(getStrField(instruction, "name")), getIntField(instruction, "arity")); break; case "CALLPRIM0": codeblock.CALLPRIM0(RascalPrimitive.valueOf(getStrField(instruction, "name")), getLocField(instruction, "src")); break; case "PUSHCALLPRIM0": codeblock.PUSHCALLPRIM0(RascalPrimitive.valueOf(getStrField(instruction, "name")), getLocField(instruction, "src")); break; case "CALLPRIM1": codeblock.CALLPRIM1(RascalPrimitive.valueOf(getStrField(instruction, "name")), getLocField(instruction, "src")); break; case "PUSHCALLPRIM1": codeblock.PUSHCALLPRIM1(RascalPrimitive.valueOf(getStrField(instruction, "name")), getLocField(instruction, "src")); break; case "CALLPRIM2": codeblock.CALLPRIM2(RascalPrimitive.valueOf(getStrField(instruction, "name")), getLocField(instruction, "src")); break; case "PUSHCALLPRIM2": codeblock.PUSHCALLPRIM2(RascalPrimitive.valueOf(getStrField(instruction, "name")), getLocField(instruction, "src")); break; case "CALLPRIMN": codeblock.CALLPRIMN(RascalPrimitive.valueOf(getStrField(instruction, "name")), getIntField(instruction, "arity"), getLocField(instruction, "src")); break; case "PUSHCALLPRIMN": codeblock.PUSHCALLPRIMN(RascalPrimitive.valueOf(getStrField(instruction, "name")), getIntField(instruction, "arity"), getLocField(instruction, "src")); break; case "POPACCU": codeblock.POPACCU(); break; case "PUSHACCU": codeblock.PUSHACCU(); break; default: throw new CompilerError("In function " + name + ", unknown instruction: " + opcode); } } } catch (Exception e){ throw new CompilerError("In function " + name + " : " + e.getMessage(), e); } Function function = new Function(name, ftype, kwType, scopeIn, nformals, nlocals, isDefault, isTest, tags, localNames, maxstack, isConcreteArg, abstractFingerprint, concreteFingerprint, codeblock, src, continuationPoints); function.attachExceptionTable((IList) declaration.get("exceptions")); if(isCoroutine) { function.isCoroutine = true; IList refList = (IList) declaration.get("refs"); int[] refs = new int[refList.length()]; int i = 0; for(IValue ref : refList) { refs[i++] = ((IInteger) ref).intValue(); } function.refs = refs; } else { boolean isVarArgs = ((IBool) declaration.get("isVarArgs")).getValue(); function.isVarArgs = isVarArgs; } declareFunction(function); } private Type getTypeField(IConstructor instruction, String field) { return types.symbolToType((IConstructor) instruction.get(field)); } }