private void addClosureExitBindingStores( IRExecutionScope s, ListIterator<Instr> instrs, Set<LocalVariable> dirtyVars) { for (Variable v : dirtyVars) { if (v instanceof ClosureLocalVariable) { IRClosure definingScope = ((ClosureLocalVariable) v).definingScope; if ((s != definingScope) && s.nestedInClosure(definingScope)) instrs.add(new StoreToBindingInstr(s, v.getName(), v)); } else { instrs.add(new StoreToBindingInstr(s, v.getName(), v)); } } }
public Variable getRenamedVariable(Variable v) { Variable newVar = this.varRenameMap.get(v); if (newVar == null) { if (inClosureCloneMode) { // when cloning a closure, local vars and temps are not renamed newVar = v.cloneForCloningClosure(this); } else if (inClosureInlineMode) { // when inlining a closure, // - local var depths are reduced by 1 (to move them to the host scope) // - tmp vars are reallocated in the host scope if (v instanceof LocalVariable) { LocalVariable lv = (LocalVariable) v; int depth = lv.getScopeDepth(); newVar = getInlineHostScope().getLocalVariable(lv.getName(), depth > 1 ? depth - 1 : 0); } else { newVar = getInlineHostScope().getNewTemporaryVariable(); } } else { // when inlining a method, local vars and temps have to be renamed newVar = getInlineHostScope().getNewInlineVariable(inlineVarPrefix, v); } this.varRenameMap.put(v, newVar); } else if (inClosureCloneMode && (v instanceof LocalVariable)) { LocalVariable l_v = (LocalVariable) v; LocalVariable l_newVar = (LocalVariable) newVar; if (l_v.getScopeDepth() != l_newVar.getScopeDepth()) newVar = l_newVar.cloneForDepth(l_v.getScopeDepth()); } return newVar; }
@Override public Instr cloneForInlining(InlinerInfo ii) { return new ToAryInstr( (Variable) result.cloneForInlining(ii), array.cloneForInlining(ii), (BooleanLiteral) dontToAryArrays.cloneForInlining(ii)); }
@Override public Object interpret( ThreadContext context, IRubyObject self, IRubyObject[] args, Block block, Object exception, Object[] temp) { result.store(context, self, temp, methodHandle.retrieve(context, self, temp)); return null; }
@Override public Object interpret( ThreadContext context, IRubyObject self, IRubyObject[] args, Block block, Object exception, Object[] temp) { IRubyObject receiver = (IRubyObject) arg1.retrieve(context, self, temp); IRubyObject value = (IRubyObject) arg2.retrieve(context, self, temp); if (value == UndefinedValue.UNDEFINED) { result.store(context, self, temp, receiver); } else if (receiver instanceof RubyArray) { RubyArray testVals = (RubyArray) receiver; for (int i = 0, n = testVals.getLength(); i < n; i++) { IRubyObject excType = (IRubyObject) testVals.eltInternal(i); if (!(excType instanceof RubyModule)) { throw context .getRuntime() .newTypeError("class or module required for rescue clause. Found: " + excType); } IRubyObject eqqVal = excType.callMethod(context, "===", value); if (eqqVal.isTrue()) { result.store(context, self, temp, eqqVal); return null; } } result.store(context, self, temp, context.getRuntime().newBoolean(false)); } else { if (!(receiver instanceof RubyModule)) { throw context .getRuntime() .newTypeError("class or module required for rescue clause. Found: " + receiver); } result.store(context, self, temp, receiver.callMethod(context, "===", value)); } return null; }
@Override public Object interpret( ThreadContext context, IRubyObject self, IRubyObject[] args, Block block, Object exception, Object[] temp) { // ENEBO: This seems like a lot of extra work... result.store( context, self, temp, context .getRuntime() .newBoolean(((IRubyObject) value.retrieve(context, self, temp)).isTrue())); return null; }
public void addStoreAndBindingAllocInstructions(Set<LocalVariable> callsiteDirtyVars) { boolean addAllocateBindingInstructions = false; // SSS: This is going to be useful during JIT -- we are far away from there at this // time BindingStorePlacementProblem bsp = (BindingStorePlacementProblem) _prob; CFG cfg = bsp.getCFG(); IRExecutionScope s = cfg.getScope(); ListIterator<Instr> instrs = _bb.getInstrs().listIterator(); Set<LocalVariable> dirtyVars = new HashSet<LocalVariable>(_inDirtyVars); boolean bindingAllocated = _inBindingAllocated; // If this is the exit BB, we need a binding story on exit only for vars that are both: // // (a) dirty, // (b) live on exit from the closure // condition reqd. because the variable could be dirty but not used outside. // Ex: s=0; a.each { |i| j = i+1; sum += j; }; puts sum // i,j are dirty inside the block, but not used outside boolean amExitBB = (_bb == cfg.getExitBB()); if (amExitBB) { /** * LiveVariablesProblem lvp = * (LiveVariablesProblem)cfg.getDataFlowSolution(DataFlowConstants.LVP_NAME); * java.util.Collection<Variable> liveVars = lvp.getVarsLiveOnEntry(); * System.out.println("\n[In Exit BB] For CFG " + cfg + ":"); System.out.println("\t--> Dirty * vars here : " + java.util.Arrays.toString(dirtyVars.toArray())); System.out.println("\t--> * Vars live on entry: " + (liveVars == null ? "NONE" : * java.util.Arrays.toString(liveVars.toArray()))); liveVars = lvp.getVarsLiveOnExit(); * System.out.println("\t--> Vars live on exit : " + (liveVars == null ? "NONE" : * java.util.Arrays.toString(liveVars.toArray()))); */ LiveVariablesProblem lvp = (LiveVariablesProblem) cfg.getDataFlowSolution(DataFlowConstants.LVP_NAME); if (lvp != null) { java.util.Collection<Variable> liveVars = lvp.getVarsLiveOnExit(); if (liveVars != null) { dirtyVars.retainAll(liveVars); // Intersection with variables live on exit from the scope } else { dirtyVars.clear(); } } } while (instrs.hasNext()) { Instr i = instrs.next(); if (i.operation == Operation.BINDING_LOAD) continue; if (i instanceof CallInstr) { CallInstr call = (CallInstr) i; Operand o = call.getClosureArg(); if ((o != null) && (o instanceof MetaObject)) { CFG cl_cfg = ((IRClosure) ((MetaObject) o).scope).getCFG(); BindingStorePlacementProblem cl_bsp = (BindingStorePlacementProblem) cl_cfg.getDataFlowSolution(bsp.getName()); instrs.previous(); if (addAllocateBindingInstructions) { // Add a binding allocation instruction, if necessary if (!bindingAllocated) { instrs.add(new AllocateBindingInstr(s)); bindingAllocated = true; } } // If the call is an eval, or if the callee can capture this method's binding, // we have to spill all variables. boolean spillAllVars = call.canBeEval() || call.targetRequiresCallersBinding(); // Unless we have to spill everything, spill only those dirty variables that are: // - used in the closure (FIXME: Strictly only those vars that are live at the call site // -- but we dont have this info!) Set<LocalVariable> newDirtyVars = new HashSet<LocalVariable>(dirtyVars); for (Variable v : dirtyVars) { if (spillAllVars || cl_bsp.scopeUsesVariable(v)) { // FIXME: This may not need check for local variable if it is guaranteed to only be // local variables. instrs.add(new StoreToBindingInstr(s, v.getName(), v)); newDirtyVars.remove(v); } // These variables will be spilt inside the closure -- so they will no longer be dirty // after the call site! else if (cl_bsp.scopeDefinesVariable(v)) { newDirtyVars.remove(v); } } dirtyVars = newDirtyVars; instrs.next(); // add stores in the closure ((BindingStorePlacementProblem) cl_cfg.getDataFlowSolution(bsp.getName())) .addStoreAndBindingAllocInstructions(); } // Call has no closure && it requires stores else if (call.targetRequiresCallersBinding()) { instrs.previous(); if (addAllocateBindingInstructions) { if (!bindingAllocated) { instrs.add(new AllocateBindingInstr(s)); bindingAllocated = true; } } for (LocalVariable v : dirtyVars) { instrs.add(new StoreToBindingInstr(s, v.getName(), v)); } instrs.next(); dirtyVars.clear(); } else if (call.canSetDollarVars()) { if (addAllocateBindingInstructions) { if (!bindingAllocated) { instrs.add(new AllocateBindingInstr(s)); bindingAllocated = true; } } } // Add all the remaining dirty local vars into callsiteDirtyVars // These variables would have to be spilled into the binding if this // call raised an exception and exited this scope. if ((callsiteDirtyVars != null) && call.canRaiseException()) callsiteDirtyVars.addAll(dirtyVars); } else if ((i instanceof ClosureReturnInstr) || (i instanceof BREAK_Instr)) { // At closure return and break instructions (both of which are exits from the closure), // we need a binding store on exit only for vars that are both: // // (a) dirty, // (b) live on exit from the closure // condition reqd. because the variable could be dirty but not used outside. // Ex: s=0; a.each { |i| j = i+1; sum += j; }; puts sum // i,j are dirty inside the block, but not used outside // // If this also happens to be exit BB, we would have intersected already earlier -- so no // need to do it again! if (!amExitBB) { /** * LiveVariablesProblem lvp = * (LiveVariablesProblem)cfg.getDataFlowSolution(DataFlowConstants.LVP_NAME); * java.util.Collection<Variable> liveVars = lvp.getVarsLiveOnEntry(); * System.out.println("\n[@Closure Instr<" + i + ">] For CFG " + cfg + ":"); * System.out.println("\t--> Dirty vars here : " + * java.util.Arrays.toString(dirtyVars.toArray())); System.out.println("\t--> Vars live on * entry: " + (liveVars == null ? "NONE" : * java.util.Arrays.toString(liveVars.toArray()))); liveVars = lvp.getVarsLiveOnExit(); * System.out.println("\t--> Vars live on exit : " + (liveVars == null ? "NONE" : * java.util.Arrays.toString(liveVars.toArray()))); */ LiveVariablesProblem lvp = (LiveVariablesProblem) cfg.getDataFlowSolution(DataFlowConstants.LVP_NAME); if (lvp != null) { java.util.Collection<Variable> liveVars = lvp.getVarsLiveOnExit(); if (liveVars != null) { dirtyVars.retainAll( liveVars); // Intersection with variables live on exit from the scope } else { dirtyVars.clear(); } } } instrs.previous(); addClosureExitBindingStores(s, instrs, dirtyVars); instrs.next(); // Nothing is dirty anymore -- everything that needs spilling has been spilt dirtyVars.clear(); } Variable v = i.getResult(); // %self is local to every scope and never crosses scope boundaries and need not be // spilled/refilled if ((v != null) && (v instanceof LocalVariable) && !((LocalVariable) v).isSelf()) { dirtyVars.add((LocalVariable) v); } } // If this is the exit BB, add binding stores for all vars that are still dirty if (amExitBB) addClosureExitBindingStores(s, instrs, dirtyVars); }
public void addLoads() { BindingLoadPlacementProblem blp = (BindingLoadPlacementProblem) _prob; IRExecutionScope s = blp.getCFG().getScope(); List<Instr> instrs = _bb.getInstrs(); ListIterator<Instr> it = instrs.listIterator(instrs.size()); Set<Variable> reqdLoads = new HashSet<Variable>(_inReqdLoads); while (it.hasPrevious()) { Instr i = it.previous(); if (i.operation == Operation.BINDING_STORE) continue; // Right away, clear the variable defined by this instruction -- it doesn't have to be loaded! Variable r = i.getResult(); if (r != null) reqdLoads.remove(r); if (i instanceof CallInstr) { CallInstr call = (CallInstr) i; Operand o = call.getClosureArg(); if ((o != null) && (o instanceof MetaObject)) { CFG cl_cfg = ((IRClosure) ((MetaObject) o).scope).getCFG(); BindingLoadPlacementProblem cl_blp = (BindingLoadPlacementProblem) cl_cfg.getDataFlowSolution(blp.getName()); // Only those variables that are defined in the closure, and are in the required loads set // will need to be loaded from the binding after the call! Set<Variable> newReqdLoads = new HashSet<Variable>(reqdLoads); it.next(); for (Variable v : reqdLoads) { if (cl_blp.scopeDefinesVariable(v)) { it.add(new LoadFromBindingInstr(v, s, v.getName())); it.previous(); newReqdLoads.remove(v); } } it.previous(); reqdLoads = newReqdLoads; // add loads in the closure ((BindingLoadPlacementProblem) cl_cfg.getDataFlowSolution(blp.getName())).addLoads(); } else if (call.requiresBinding()) { it.next(); for (Variable v : reqdLoads) { it.add(new LoadFromBindingInstr(v, s, v.getName())); it.previous(); } it.previous(); reqdLoads.clear(); } } // The variables used as arguments will need to be loaded for (Variable x : i.getUsedVariables()) { if (x instanceof LocalVariable) reqdLoads.add(x); } } // Load first use of variables in closures if ((s instanceof IRClosure) && (_bb == _prob.getCFG().getEntryBB())) { /** * System.out.println("\n[In Entry BB] For CFG " + _prob.getCFG() + ":"); * System.out.println("\t--> Reqd loads : " + java.util.Arrays.toString(reqdLoads.toArray())); */ for (Variable v : reqdLoads) { if (blp.scopeUsesVariable(v)) { it.add(new LoadFromBindingInstr(v, s, v.getName())); } } } }