}
return value;
}
public void addLoads(Map<Operand, Operand> varRenameMap) {
IRScope scope = problem.getScope();
boolean isEvalScript = scope instanceof IREvalScript;
boolean scopeBindingHasEscaped = scope.bindingHasEscaped();
List<Instr> instrs = basicBlock.getInstrs();
ListIterator<Instr> it = instrs.listIterator(instrs.size());
initSolution();
while (it.hasPrevious()) {
Instr i = it.previous();
// Right away, clear the variable defined by this instruction -- it doesn't have to be loaded!
if (i instanceof ResultInstr) reqdLoads.remove(((ResultInstr) i).getResult());
// Process closure accepting instrs specially -- these are the sites of binding loads!
if (i instanceof ClosureAcceptingInstr) {
Operand o = ((ClosureAcceptingInstr)i).getClosureArg();
if (o != null && o instanceof WrappedIRClosure) {
IRClosure cl = ((WrappedIRClosure) o).getClosure();
// 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! Rest can wait ..
it.next();
for (Iterator<LocalVariable> iter = reqdLoads.iterator(); iter.hasNext();) {
LocalVariable v = iter.next();
if (cl.definesLocalVariable(v)) {
it.add(new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
it.previous();
iter.remove();
}
}
it.previous();
}
// In this case, we are going to blindly load everything
if (scopeBindingHasEscaped) {
it.next();
for (LocalVariable v: reqdLoads) {
it.add(new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
it.previous();
}
it.previous();
reqdLoads.clear();
} else {
// All variables not defined in the current scope have to be always loaded
// because of multi-threading scenarios where some other scope
// could update this variable concurrently.
it.next();
for (Iterator<LocalVariable> iter = reqdLoads.iterator(); iter.hasNext();) {
LocalVariable v = iter.next();
if (!scope.definesLocalVariable(v)) {
it.add(new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
it.previous();
iter.remove();
}
}
it.previous();
}
} else if (scopeBindingHasEscaped && (i.getOperation() == Operation.PUT_GLOBAL_VAR)) {
// global-var tracing can execute closures set up in previous trace-var calls
// in which case we would have the 'scopeBindingHasEscaped' flag set to true
it.next();
for (LocalVariable v : reqdLoads) {
it.add(new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
it.previous();
}
it.previous();
reqdLoads.clear();
}
if (i.getOperation() == Operation.BINDING_STORE) {
LocalVariable lv = ((StoreLocalVarInstr)i).getLocalVar();
if (!lv.isSelf()) {
reqdLoads.add(lv);
// SSS FIXME: Why is this reqd again? Document with example
// Make sure there is a replacement var for all local vars
getLocalVarReplacement(lv, scope, varRenameMap);
}
} else {
// The variables used as arguments will need to be loaded
// %self is local to every scope and never crosses scope boundaries and need not be spilled/refilled
for (Variable v : i.getUsedVariables()) {
if (!(v instanceof LocalVariable)) continue;
LocalVariable lv = (LocalVariable)v;
if (!lv.isSelf()) {
reqdLoads.add(lv);
// SSS FIXME: Why is this reqd again? Document with example
// Make sure there is a replacement var for all local vars
getLocalVarReplacement(lv, scope, varRenameMap);
}
}
}
}
// Add loads on entry of a rescue block.
if (basicBlock.isRescueEntry()) {
for (LocalVariable v : reqdLoads) {
it.add(new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
}
}
// Load first use of variables in closures
if (scope instanceof IRClosure && basicBlock.isEntryBB()) {
// System.out.println("\n[In Entry BB] For CFG " + getCFG() + ":");
// System.out.println("\t--> Reqd loads : " + java.util.Arrays.toString(reqdLoads.toArray()));
for (LocalVariable v : reqdLoads) {
if (scope.usesLocalVariable(v) || scope.definesLocalVariable(v)) {
if (isEvalScript || !(v instanceof ClosureLocalVariable) || (scope != ((ClosureLocalVariable)v).definingScope)) {
it.add(new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
}
}
}