BindingStorePlacementProblem cl_bsp = (BindingStorePlacementProblem) cl_cfg.getDataFlowSolution(bsp.getName());
// Add a binding allocation instruction, if necessary
instrs.previous();
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.canCaptureCallersBinding();
// 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<Variable> newDirtyVars = new HashSet<Variable>(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.requiresBinding()) {
instrs.previous();
if (!bindingAllocated) {
instrs.add(new AllocateBindingInstr(s));
bindingAllocated = true;
}
for (Variable v : dirtyVars) {
instrs.add(new StoreToBindingInstr(s, v.getName(), v));
}