예제 #1
0
 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;
 }
예제 #2
0
  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);
  }