Ejemplo n.º 1
0
  public void applyTransferFunction(Instr i) {
    // Rescue node, if any
    boolean scopeBindingHasEscaped = problem.getScope().bindingHasEscaped();

    Variable dst = null;
    boolean dirtied = false;
    boolean hitDFBarrier = false;
    if (i instanceof ResultInstr) {
      dst = ((ResultInstr) i).getResult();
    }

    if (i instanceof CopyInstr) {
      // Copies are easy
      Operand src = ((CopyInstr) i).getSource();
      Class srcType = getOperandType(tmpState, src);
      setOperandType(tmpState, dst, srcType);

      // If we have an unboxed type for 'src', we can leave this unboxed.
      //
      // FIXME: However, if 'src' is a constant, this could unnecessarily
      // leave 'src' unboxed and lead to a boxing instruction further down
      // at the use site of 'dst'. This indicates that leaving this unboxed
      // should ideally be done 'on-demand'. This indicates that this could
      // be a backward-flow algo OR that this algo should be run on a
      // dataflow graph / SSA graph.
      if (srcType == Float.class) {
        dirtied = true;
      }
    } else if (i instanceof CallBase) {
      // Process calls specially -- these are what we want to optimize!
      CallBase c = (CallBase) i;
      Operand o = c.getClosureArg(null);
      if (o == null) {
        MethAddr m = c.getMethodAddr();
        Operand r = c.getReceiver();
        Operand[] args = c.getCallArgs();
        if (args.length == 1 && m.resemblesALUOp()) {
          Operand a = args[0];
          Class receiverType = getOperandType(tmpState, r);
          Class argType = getOperandType(tmpState, a);
          // Optimistically assume that call is an ALU op
          if (receiverType == Float.class
              || (receiverType == Fixnum.class && argType == Float.class)) {
            setOperandType(tmpState, dst, Float.class);

            // If 'r' and 'a' are not already in unboxed forms at this point,
            // they will get unboxed after this, because we want to opt. this call
            if (r instanceof Variable) {
              tmpState.unboxedVars.add((Variable) r);
            }
            if (a instanceof Variable) {
              tmpState.unboxedVars.add((Variable) a);
            }
            dirtied = true;
          } else {
            if (receiverType == Fixnum.class && argType == Fixnum.class) {
              setOperandType(tmpState, dst, Fixnum.class);
            } else {
              setOperandType(tmpState, dst, Object.class);
            }

            if (c.targetRequiresCallersBinding()) {
              hitDFBarrier = true;
            }
          }
        } else {
          setOperandType(tmpState, dst, Object.class);
        }
      } else {
        if (o instanceof WrappedIRClosure) {
          // Fetch the nested unboxing-analysis problem, creating one if necessary
          IRClosure cl = ((WrappedIRClosure) o).getClosure();
          UnboxableOpsAnalysisProblem subProblem =
              (UnboxableOpsAnalysisProblem) cl.getDataFlowSolution(DataFlowConstants.UNBOXING);
          if (subProblem == null) {
            subProblem = new UnboxableOpsAnalysisProblem();
            subProblem.setup(cl);
            cl.setDataFlowSolution(DataFlowConstants.UNBOXING, subProblem);
          }

          UnboxableOpsAnalysisNode exitNode = (UnboxableOpsAnalysisNode) subProblem.getExitNode();
          UnboxableOpsAnalysisNode entryNode = (UnboxableOpsAnalysisNode) subProblem.getEntryNode();

          // Init it to MEET(state-on-entry, state-on-exit).
          // The meet is required to account for participation of the closure in a loop.
          // Ex: f = 0.0; n.times { f += 10; }
          entryNode.inState = new UnboxState();
          for (Variable v : tmpState.types.keySet()) {
            if (v instanceof LocalVariable) {
              entryNode.inState.types.put(v, tmpState.types.get(v));
            }
          }
          entryNode.inState.computeMEET(exitNode.outState);

          // Compute solution
          subProblem.compute_MOP_Solution();

          // Update types to MEET(new-state-on-exit, current-state)
          tmpState.computeMEETForTypes(exitNode.outState, true);

          // As for unboxed var state, since binding can escape in
          // arbitrary ways in the general case, assume the worst for now.
          // If we are guaranteed that the closure binding is not used
          // outside the closure itself, we can avoid worst-case behavior
          // and only clear vars that are modified in the closure.
          hitDFBarrier = true;
        } else {
          // Black hole -- cannot analyze
          hitDFBarrier = true;
        }
      }
    } else {
      // We dont know how to optimize this instruction.
      // So, we assume we dont know type of the result.
      // TOP/class --> BOTTOM
      setOperandType(tmpState, dst, Object.class);
    }

    if (dirtied) {
      tmpState.unboxedVars.add(dst);
      tmpState.unboxedDirtyVars.add(dst);
    } else {
      // Since the instruction didn't run in unboxed form,
      // dirty unboxed vars will have to get boxed here.
      updateUnboxedVarsInfo(i, tmpState, dst, hasExceptionsRescued(), hitDFBarrier);
    }
  }