}
public void addLoads(Map<Operand, Operand> varRenameMap) {
LoadLocalVarPlacementProblem blp = (LoadLocalVarPlacementProblem) problem;
IRScope scope = blp.getScope();
boolean isEvalScript = scope instanceof IREvalScript;
boolean scopeBindingHasEscaped = scope.bindingHasEscaped();
List<Instr> instrs = basicBlock.getInstrs();
ListIterator<Instr> it = instrs.listIterator(instrs.size());
Set<LocalVariable> reqdLoads = new HashSet<LocalVariable>(inRequiredLoads);
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());
if (i instanceof CallBase) {
CallBase call = (CallBase) i;
Operand o = call.getClosureArg(null);
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 ..
//
// Allocate a new hash-set and modify it to get around ConcurrentModificationException on reqdLoads
Set<LocalVariable> newReqdLoads = new HashSet<LocalVariable>(reqdLoads);
it.next();
for (LocalVariable v : reqdLoads) {
if (cl.definesLocalVariable(v)) {
it.add(new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
it.previous();
newReqdLoads.remove(v);
}
}
it.previous();
reqdLoads = newReqdLoads;
}
// In this case, we are going to blindly load everything
if (scopeBindingHasEscaped || call.targetRequiresCallersBinding()) {
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.
//
// Allocate a new hash-set and modify it to get around ConcurrentModificationException on reqdLoads
Set<LocalVariable> newReqdLoads = new HashSet<LocalVariable>(reqdLoads);
it.next();
for (LocalVariable v: reqdLoads) {
if (!scope.definesLocalVariable(v)) {
it.add(new LoadLocalVarInstr(scope, getLocalVarReplacement(v, scope, varRenameMap), v));
it.previous();
newReqdLoads.remove(v);
}
}
it.previous();
reqdLoads = newReqdLoads;
}
} 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 == problem.getScope().cfg().getEntryBB())) {
// System.out.println("\n[In Entry BB] For CFG " + problem.getScope().cfg() + ":");
// 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));
}
}
}