private void addClosureExitBindingStores(
     IRExecutionScope s, ListIterator<Instr> instrs, Set<LocalVariable> dirtyVars) {
   for (Variable v : dirtyVars) {
     if (v instanceof ClosureLocalVariable) {
       IRClosure definingScope = ((ClosureLocalVariable) v).definingScope;
       if ((s != definingScope) && s.nestedInClosure(definingScope))
         instrs.add(new StoreToBindingInstr(s, v.getName(), v));
     } else {
       instrs.add(new StoreToBindingInstr(s, v.getName(), v));
     }
   }
 }
Beispiel #2
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;
 }
Beispiel #3
0
 @Override
 public Instr cloneForInlining(InlinerInfo ii) {
   return new ToAryInstr(
       (Variable) result.cloneForInlining(ii),
       array.cloneForInlining(ii),
       (BooleanLiteral) dontToAryArrays.cloneForInlining(ii));
 }
Beispiel #4
0
 @Override
 public Object interpret(
     ThreadContext context,
     IRubyObject self,
     IRubyObject[] args,
     Block block,
     Object exception,
     Object[] temp) {
   result.store(context, self, temp, methodHandle.retrieve(context, self, temp));
   return null;
 }
Beispiel #5
0
  @Override
  public Object interpret(
      ThreadContext context,
      IRubyObject self,
      IRubyObject[] args,
      Block block,
      Object exception,
      Object[] temp) {
    IRubyObject receiver = (IRubyObject) arg1.retrieve(context, self, temp);
    IRubyObject value = (IRubyObject) arg2.retrieve(context, self, temp);

    if (value == UndefinedValue.UNDEFINED) {
      result.store(context, self, temp, receiver);
    } else if (receiver instanceof RubyArray) {
      RubyArray testVals = (RubyArray) receiver;
      for (int i = 0, n = testVals.getLength(); i < n; i++) {
        IRubyObject excType = (IRubyObject) testVals.eltInternal(i);
        if (!(excType instanceof RubyModule)) {
          throw context
              .getRuntime()
              .newTypeError("class or module required for rescue clause. Found: " + excType);
        }
        IRubyObject eqqVal = excType.callMethod(context, "===", value);
        if (eqqVal.isTrue()) {
          result.store(context, self, temp, eqqVal);
          return null;
        }
      }
      result.store(context, self, temp, context.getRuntime().newBoolean(false));
    } else {
      if (!(receiver instanceof RubyModule)) {
        throw context
            .getRuntime()
            .newTypeError("class or module required for rescue clause. Found: " + receiver);
      }
      result.store(context, self, temp, receiver.callMethod(context, "===", value));
    }

    return null;
  }
Beispiel #6
0
 @Override
 public Object interpret(
     ThreadContext context,
     IRubyObject self,
     IRubyObject[] args,
     Block block,
     Object exception,
     Object[] temp) {
   // ENEBO: This seems like a lot of extra work...
   result.store(
       context,
       self,
       temp,
       context
           .getRuntime()
           .newBoolean(((IRubyObject) value.retrieve(context, self, temp)).isTrue()));
   return null;
 }
  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);
  }
  public void addLoads() {
    BindingLoadPlacementProblem blp = (BindingLoadPlacementProblem) _prob;
    IRExecutionScope s = blp.getCFG().getScope();
    List<Instr> instrs = _bb.getInstrs();
    ListIterator<Instr> it = instrs.listIterator(instrs.size());
    Set<Variable> reqdLoads = new HashSet<Variable>(_inReqdLoads);
    while (it.hasPrevious()) {
      Instr i = it.previous();

      if (i.operation == Operation.BINDING_STORE) continue;

      // Right away, clear the variable defined by this instruction -- it doesn't have to be loaded!
      Variable r = i.getResult();

      if (r != null) reqdLoads.remove(r);

      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();
          BindingLoadPlacementProblem cl_blp =
              (BindingLoadPlacementProblem) cl_cfg.getDataFlowSolution(blp.getName());

          // 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!
          Set<Variable> newReqdLoads = new HashSet<Variable>(reqdLoads);
          it.next();
          for (Variable v : reqdLoads) {
            if (cl_blp.scopeDefinesVariable(v)) {
              it.add(new LoadFromBindingInstr(v, s, v.getName()));
              it.previous();
              newReqdLoads.remove(v);
            }
          }
          it.previous();
          reqdLoads = newReqdLoads;

          // add loads in the closure
          ((BindingLoadPlacementProblem) cl_cfg.getDataFlowSolution(blp.getName())).addLoads();
        } else if (call.requiresBinding()) {
          it.next();
          for (Variable v : reqdLoads) {
            it.add(new LoadFromBindingInstr(v, s, v.getName()));
            it.previous();
          }
          it.previous();
          reqdLoads.clear();
        }
      }

      // The variables used as arguments will need to be loaded
      for (Variable x : i.getUsedVariables()) {
        if (x instanceof LocalVariable) reqdLoads.add(x);
      }
    }

    // Load first use of variables in closures
    if ((s instanceof IRClosure) && (_bb == _prob.getCFG().getEntryBB())) {
      /**
       * System.out.println("\n[In Entry BB] For CFG " + _prob.getCFG() + ":");
       * System.out.println("\t--> Reqd loads : " + java.util.Arrays.toString(reqdLoads.toArray()));
       */
      for (Variable v : reqdLoads) {
        if (blp.scopeUsesVariable(v)) {
          it.add(new LoadFromBindingInstr(v, s, v.getName()));
        }
      }
    }
  }