@Override
  public Object execute(IRScope s, Object... data) {
    StoreLocalVarPlacementProblem slvp = new StoreLocalVarPlacementProblem();

    // Only run if we are pushing a scope or we are reusing the parents scope.
    if (!s.getFlags().contains(IRFlags.DYNSCOPE_ELIMINATED)
        || s.getFlags().contains(IRFlags.REUSE_PARENT_DYNSCOPE)) {
      // Make sure flags are computed
      s.computeScopeFlags();

      Map<Operand, Operand> varRenameMap = new HashMap<Operand, Operand>();
      // 1. Figure out required stores
      // 2. Add stores
      // 3. Figure out required loads
      // 4. Add loads
      //
      // Order is important since loads in 3. depend on stores in 2.
      slvp.setup(s);
      slvp.compute_MOP_Solution();

      // Add stores, assigning an equivalent tmp-var for each local var
      slvp.addStores(varRenameMap);

      // Once stores have been added, figure out required loads
      LoadLocalVarPlacementProblem llvp = new LoadLocalVarPlacementProblem();
      llvp.setup(s);
      llvp.compute_MOP_Solution();

      // Add loads
      llvp.addLoads(varRenameMap);

      // Rename all local var uses with their tmp-var stand-ins
      for (BasicBlock b : s.getCFG().getBasicBlocks()) {
        for (Instr i : b.getInstrs()) i.renameVars(varRenameMap);
      }

      // Run on all nested closures.
      //
      // In the current implementation, nested scopes are processed independently (unlike Live
      // Variable Analysis)
      for (IRClosure c : s.getClosures()) run(c, false, true);

      // LVA information is no longer valid after this pass
      // FIXME: Grrr ... this seems broken to have to create a new object to invalidate
      (new LiveVariableAnalysis()).invalidate(s);
    }

    s.setDataFlowSolution(StoreLocalVarPlacementProblem.NAME, slvp);

    return slvp;
  }
  @Override
  public Object execute(IRScope scope, Object... data) {
    // IRScriptBody do not get explicit call protocol instructions right now.
    // They dont push/pop a frame and do other special things like run begin/end blocks.
    // So, for now, they go through the runtime stub in IRScriptBody.
    //
    // Add explicit frame and binding push/pop instrs ONLY for methods -- we cannot handle this in
    // closures and evals yet
    // If the scope uses $_ or $~ family of vars, has local load/stores, or if its binding has
    // escaped, we have
    // to allocate a dynamic scope for it and add binding push/pop instructions.
    if (explicitCallProtocolSupported(scope)) {
      StoreLocalVarPlacementProblem slvpp =
          (StoreLocalVarPlacementProblem)
              scope.getDataFlowSolution(StoreLocalVarPlacementProblem.NAME);
      boolean scopeHasLocalVarStores = false;
      boolean bindingHasEscaped = scope.bindingHasEscaped();

      CFG cfg = scope.cfg();

      if (slvpp != null && bindingHasEscaped) {
        scopeHasLocalVarStores = slvpp.scopeHasLocalVarStores();
      } else {
        // We dont require local-var load/stores to have been run.
        // If it is not run, we go conservative and add push/pop binding instrs. everywhere
        scopeHasLocalVarStores = bindingHasEscaped;
      }

      boolean requireFrame = doesItRequireFrame(scope, bindingHasEscaped);
      boolean requireBinding = !scope.getFlags().contains(IRFlags.DYNSCOPE_ELIMINATED);

      if (requireBinding || requireFrame) {
        BasicBlock entryBB = cfg.getEntryBB();
        // Push
        if (requireFrame) entryBB.addInstr(new PushFrameInstr(scope.getName()));
        if (requireBinding) entryBB.addInstr(new PushBindingInstr());

        // SSS FIXME: We are doing this conservatively.
        // Only scopes that have unrescued exceptions need a GEB.
        //
        // Allocate GEB if necessary for popping
        BasicBlock geb = cfg.getGlobalEnsureBB();
        if (geb == null) {
          Variable exc = scope.createTemporaryVariable();
          geb = new BasicBlock(cfg, Label.getGlobalEnsureBlockLabel());
          geb.addInstr(
              new ReceiveJRubyExceptionInstr(exc)); // JRuby Implementation exception handling
          geb.addInstr(new ThrowExceptionInstr(exc));
          cfg.addGlobalEnsureBB(geb);
        }

        // Pop on all scope-exit paths
        for (BasicBlock bb : cfg.getBasicBlocks()) {
          Instr i = null;
          ListIterator<Instr> instrs = bb.getInstrs().listIterator();
          while (instrs.hasNext()) {
            i = instrs.next();
            // Right now, we only support explicit call protocol on methods.
            // So, non-local returns and breaks don't get here.
            // Non-local-returns and breaks are tricky since they almost always
            // throw an exception and we don't multiple pops (once before the
            // return/break, and once when the exception is caught).
            if (!bb.isExitBB() && i instanceof ReturnBase) {
              // Add before the break/return
              instrs.previous();
              if (requireBinding) instrs.add(new PopBindingInstr());
              if (requireFrame) instrs.add(new PopFrameInstr());
              break;
            }
          }

          if (bb.isExitBB() && !bb.isEmpty()) {
            // Last instr could be a return -- so, move iterator one position back
            if (i != null && i instanceof ReturnBase) instrs.previous();
            if (requireBinding) instrs.add(new PopBindingInstr());
            if (requireFrame) instrs.add(new PopFrameInstr());
          }

          if (bb == geb) {
            // Add before throw-exception-instr which would be the last instr
            if (i != null) {
              // Assumption: Last instr should always be a control-transfer instruction
              assert i.getOperation().transfersControl()
                  : "Last instruction of GEB in scope: "
                      + scope
                      + " is "
                      + i
                      + ", not a control-xfer instruction";
              instrs.previous();
            }
            if (requireBinding) instrs.add(new PopBindingInstr());
            if (requireFrame) instrs.add(new PopFrameInstr());
          }
        }
      }

      // This scope has an explicit call protocol flag now
      scope.setExplicitCallProtocolFlag();
    }

    // FIXME: Useless for now
    // Run on all nested closures.
    for (IRClosure c : scope.getClosures()) run(c, false, true);

    // LVA information is no longer valid after the pass
    // FIXME: Grrr ... this seems broken to have to create a new object to invalidate
    (new LiveVariableAnalysis()).invalidate(scope);

    return null;
  }