Example #1
0
  private void encodeCallBaseInstr(CallBase instr) {
    boolean hasClosure = instr.getClosureArg(null) != null;

    e.encode(instr.getCallType().ordinal());
    e.encode(instr.getMethodAddr().getName());
    e.encode(instr.getReceiver());
    e.encode(calculateArity(instr.getCallArgs(), hasClosure));

    for (Operand arg : instr.getCallArgs()) {
      e.encode(arg);
    }

    if (hasClosure) e.encode(instr.getClosureArg(null));
  }
  public void unbox(Map<Variable, TemporaryLocalVariable> unboxMap) {
    // System.out.println("BB : " + basicBlock + " in " + this.problem.getScope().getName());
    // System.out.println("-- known types on entry:");
    // for (Variable v: inState.types.keySet()) {
    //     if (inState.types.get(v) != Object.class) {
    //         System.out.println(v + "-->" + inState.types.get(v));
    //     }
    // }
    // System.out.print("-- unboxed vars on entry:");
    // for (Variable v: inState.unboxedVars) {
    //     System.out.print(" " + v);
    // }
    // System.out.println("------");
    // System.out.print("-- unboxed vars on exit:");
    // for (Variable v: outState.unboxedVars) {
    //     System.out.print(" " + v);
    // }
    // System.out.println("------");

    // Compute UNION(unboxedVarsIn(all-successors)) - this.unboxedVarsOut
    // All vars in this new set have to be unboxed on exit from this BB
    boolean scopeBindingHasEscaped = problem.getScope().bindingHasEscaped();
    Set<Variable> succUnboxedVars = new HashSet<Variable>();
    CFG cfg = problem.getScope().cfg();

    for (Edge e : cfg.getOutgoingEdges(basicBlock)) {
      BasicBlock b = (BasicBlock) e.getDestination().getData();
      if (b != cfg.getExitBB()) {
        UnboxableOpsAnalysisNode x = (UnboxableOpsAnalysisNode) problem.getFlowGraphNode(b);
        succUnboxedVars.addAll(x.inState.unboxedVars);
      }
    }

    succUnboxedVars.removeAll(outState.unboxedVars);

    // Only worry about vars live on exit from the BB
    LiveVariablesProblem lvp =
        (LiveVariablesProblem) problem.getScope().getDataFlowSolution(DataFlowConstants.LVP_NAME);
    BitSet liveVarsSet = ((LiveVariableNode) lvp.getFlowGraphNode(basicBlock)).getLiveInBitSet();

    // Rescue node, if any
    IRScope scope = this.problem.getScope();
    boolean isClosure = scope instanceof IRClosure;

    List<Instr> newInstrs = new ArrayList<Instr>();
    boolean unboxedLiveVars = false;

    initSolution();

    for (Instr i : basicBlock.getInstrs()) {
      Variable dst = null;
      boolean dirtied = false;
      boolean hitDFBarrier = false;
      // System.out.println("ORIG: " + i);
      if (i.getOperation().transfersControl()) {
        // Add unboxing instrs.
        for (Variable v : succUnboxedVars) {
          if (liveVarsSet.get(lvp.getDFVar(v).getId())) {
            // System.out.println("suv: UNBOXING for " + v);
            newInstrs.add(new UnboxFloatInstr(getUnboxedVar(unboxMap, v), v));
            tmpState.unboxedVars.add(v);
          }
        }
        unboxedLiveVars = true;
      } else {
        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) {
            Operand unboxedSrc =
                src instanceof Variable ? getUnboxedVar(unboxMap, (Variable) src) : src;
            TemporaryLocalVariable unboxedDst = getUnboxedVar(unboxMap, dst);
            newInstrs.add(new CopyInstr(Operation.COPY_UNBOXED, unboxedDst, unboxedSrc));
            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);
                r = getUnboxedOperand(tmpState.unboxedVars, unboxMap, r, newInstrs);
                a = getUnboxedOperand(tmpState.unboxedVars, unboxMap, a, newInstrs);
                TemporaryLocalVariable unboxedDst = getUnboxedVar(unboxMap, dst);
                newInstrs.add(new AluInstr(m.getUnboxedOp(Float.class), unboxedDst, r, 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) {
              // 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.
              hitDFBarrier = true;

              // Fetch the nested unboxing-analysis problem, creating one if necessary
              IRClosure cl = ((WrappedIRClosure) o).getClosure();
              UnboxableOpsAnalysisProblem subProblem =
                  (UnboxableOpsAnalysisProblem) cl.getDataFlowSolution(DataFlowConstants.UNBOXING);
              UnboxableOpsAnalysisNode exitNode =
                  (UnboxableOpsAnalysisNode) subProblem.getExitNode();

              // Compute solution
              subProblem.unbox();

              // 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 {
              // 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.
        boxRequiredVars(
            i, tmpState, unboxMap, dst, hasExceptionsRescued(), hitDFBarrier, newInstrs);
      }
    }

    // Add unboxing instrs.
    if (!unboxedLiveVars) {
      for (Variable v : succUnboxedVars) {
        if (liveVarsSet.get(lvp.getDFVar(v).getId())) {
          // System.out.println("suv: UNBOXING for " + v);
          newInstrs.add(new UnboxFloatInstr(getUnboxedVar(unboxMap, v), v));
        }
      }
    }

    /*
            System.out.println("------");
            for (Instr i : newInstrs) {
                System.out.println("NEW: " + i);
            }
    */

    basicBlock.replaceInstrs(newInstrs);
  }
  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);
    }
  }
Example #4
0
  private static void analyzeProfile() {
    versionCount++;

    // if (inlineCount == 2) return;

    if (codeModificationsCount == 0) numCyclesWithNoModifications++;
    else numCyclesWithNoModifications = 0;

    codeModificationsCount = 0;

    if (numCyclesWithNoModifications < 3) return;

    // We are now good to go -- start analyzing the profile

    // System.out.println("-------------------start analysis-----------------------");

    final HashMap<IRScope, Long> scopeCounts = new HashMap<IRScope, Long>();
    final ArrayList<IRCallSite> callSites = new ArrayList<IRCallSite>();
    HashMap<IRCallSite, Long> callSiteCounts = new HashMap<IRCallSite, Long>();
    // System.out.println("# call sites: " + callProfile.keySet().size());
    long total = 0;
    for (Long id : callProfile.keySet()) {
      Long c;

      CallSiteProfile csp = callProfile.get(id);
      IRCallSite cs = csp.cs;

      if (cs.v != scopeVersionMap.get(cs.s).intValue()) {
        // System.out.println("Skipping callsite: <" + cs.s + "," + cs.v + "> with compiled version:
        // " + scopeVersionMap.get(cs.s));
        continue;
      }

      Set<IRScope> calledScopes = csp.counters.keySet();
      cs.count = 0;
      for (IRScope s : calledScopes) {
        c = scopeCounts.get(s);
        if (c == null) {
          c = new Long(0);
          scopeCounts.put(s, c);
        }

        long x = csp.counters.get(s).count;
        c += x;
        cs.count += x;
      }

      CallBase call = cs.call;
      if (calledScopes.size() == 1 && !call.inliningBlocked()) {
        CallSite runtimeCS = call.getCallSite();
        if (runtimeCS != null && (runtimeCS instanceof CachingCallSite)) {
          CachingCallSite ccs = (CachingCallSite) runtimeCS;
          CacheEntry ce = ccs.getCache();

          if (!(ce.method instanceof InterpretedIRMethod)) {
            // System.out.println("NOT IR-M!");
            continue;
          } else {
            callSites.add(cs);
            cs.tgtM = (InterpretedIRMethod) ce.method;
          }
        }
      }

      total += cs.count;
    }

    Collections.sort(
        callSites,
        new java.util.Comparator<IRCallSite>() {
          @Override
          public int compare(IRCallSite a, IRCallSite b) {
            if (a.count == b.count) return 0;
            return (a.count < b.count) ? 1 : -1;
          }
        });

    // Find top N call sites
    double freq = 0.0;
    int i = 0;
    boolean noInlining = true;
    Set<IRScope> inlinedScopes = new HashSet<IRScope>();
    for (IRCallSite ircs : callSites) {
      double contrib = (ircs.count * 100.0) / total;

      // 1% is arbitrary
      if (contrib < 1.0) break;

      i++;
      freq += contrib;

      // This check is arbitrary
      if (i == 100 || freq > 99.0) break;

      // System.out.println("Considering: " + ircs.call + " with id: " + ircs.call.callSiteId +
      // " in scope " + ircs.s + " with count " + ircs.count + "; contrib " + contrib + "; freq: " +
      // freq);

      // Now inline here!
      CallBase call = ircs.call;

      IRScope hs = ircs.s;
      boolean isHotClosure = hs instanceof IRClosure;
      IRScope hc = isHotClosure ? hs : null;
      hs = isHotClosure ? hs.getLexicalParent() : hs;

      IRScope tgtMethod = ircs.tgtM.getIRMethod();

      Instr[] instrs = tgtMethod.getInstrsForInterpretation();
      // Dont inline large methods -- 500 is arbitrary
      // Can be null if a previously inlined method hasn't been rebuilt
      if ((instrs == null) || instrs.length > 500) {
        // if (instrs == null) System.out.println("no instrs!");
        // else System.out.println("large method with " + instrs.length + " instrs. skipping!");
        continue;
      }

      RubyModule implClass = ircs.tgtM.getImplementationClass();
      int classToken = implClass.getGeneration();
      String n = tgtMethod.getName();
      boolean inlineCall = true;
      if (isHotClosure) {
        Operand clArg = call.getClosureArg(null);
        inlineCall =
            (clArg instanceof WrappedIRClosure) && (((WrappedIRClosure) clArg).getClosure() == hc);
      }

      if (inlineCall) {
        noInlining = false;
        long start = new java.util.Date().getTime();
        hs.inlineMethod(tgtMethod, implClass, classToken, null, call);
        inlinedScopes.add(hs);
        long end = new java.util.Date().getTime();
        // System.out.println("Inlined " + tgtMethod + " in " + hs +
        //     " @ instr " + call + " in time (ms): "
        //     + (end-start) + " # instrs: " + instrs.length);

        inlineCount++;
      } else {
        // System.out.println("--no inlining--");
      }
    }

    for (IRScope x : inlinedScopes) {
      // update version count for 'hs'
      scopeVersionMap.put(x, versionCount);
      // System.out.println("Updating version of " + x + " to " + versionCount);
      // System.out.println("--- pre-inline-instrs ---");
      // System.out.println(x.getCFG().toStringInstrs());
      // System.out.println("--- post-inline-instrs ---");
      // System.out.println(x.getCFG().toStringInstrs());
    }

    // reset
    codeModificationsCount = 0;
    callProfile = new HashMap<Long, CallSiteProfile>();

    // Every 1M thread polls, discard stats by reallocating the thread-poll count map
    if (globalThreadPollCount % 1000000 == 0) {
      globalThreadPollCount = 0;
    }
  }
  public void unbox(Map<Variable, TemporaryLocalVariable> unboxMap) {
    // System.out.println("BB : " + basicBlock + " in " + problem.getScope().getName());
    // System.out.println("-- known types on entry:");
    // for (Variable v: inState.types.keySet()) {
    //     if (inState.types.get(v) != Object.class) {
    //         System.out.println(v + "-->" + inState.types.get(v));
    //     }
    // }
    // System.out.print("-- unboxed vars on entry:");
    // for (Variable v: inState.unboxedVars) {
    //     System.out.print(" " + v);
    // }
    // System.out.println("------");
    // System.out.print("-- unboxed vars on exit:");
    // for (Variable v: outState.unboxedVars) {
    //     System.out.print(" " + v);
    // }
    // System.out.println("------");

    CFG cfg = getCFG();

    // Compute UNION(unboxedVarsIn(all-successors)) - this.unboxedVarsOut
    // All vars in this new set have to be unboxed on exit from this BB
    HashMap<Variable, Class> succUnboxedVars = new HashMap<Variable, Class>();
    for (BasicBlock b : cfg.getOutgoingDestinations(basicBlock)) {
      if (b.isExitBB()) continue;

      Map<Variable, Class> xVars = problem.getFlowGraphNode(b).inState.unboxedVars;
      for (Variable v2 : xVars.keySet()) {
        // VERY IMPORTANT: Pay attention!
        //
        // Technically, the successors of this node may not all agree on what
        // the unboxed type ought to be for 'v2'. For example, one successor might
        // want 'v2' in Fixnum form and other might want it in Float form. If that
        // happens, we have to add unboxing instructions for each of those expected
        // types. However, for now, we are going to punt and assume that our successors
        // agree on unboxed types for 'v2'.
        succUnboxedVars.put(v2, xVars.get(v2));
      }
    }

    // Same caveat as above applies here
    for (Variable v3 : outState.unboxedVars.keySet()) {
      succUnboxedVars.remove(v3);
    }

    // Only worry about vars live on exit from the BB
    LiveVariablesProblem lvp =
        (LiveVariablesProblem) problem.getScope().getDataFlowSolution(DataFlowConstants.LVP_NAME);
    BitSet liveVarsSet = lvp.getFlowGraphNode(basicBlock).getLiveInBitSet();

    List<Instr> newInstrs = new ArrayList<Instr>();
    boolean unboxedLiveVars = false;

    initSolution();

    for (Instr i : basicBlock.getInstrs()) {
      Variable dst = null;
      boolean dirtied = false;
      boolean hitDFBarrier = false;
      // System.out.println("ORIG: " + i);
      if (i.getOperation().transfersControl()) {
        // Add unboxing instrs.
        for (Variable v : succUnboxedVars.keySet()) {
          if (liveVarsSet.get(lvp.getDFVar(v))) {
            unboxVar(tmpState, succUnboxedVars.get(v), unboxMap, v, newInstrs);
          }
        }
        unboxedLiveVars = true;
      } else {
        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 || srcType == Fixnum.class) {
            Operand unboxedSrc =
                src instanceof Variable ? getUnboxedVar(srcType, unboxMap, (Variable) src) : src;
            TemporaryLocalVariable unboxedDst = getUnboxedVar(srcType, unboxMap, dst);
            newInstrs.add(new CopyInstr(Operation.COPY, unboxedDst, unboxedSrc));
            tmpState.unboxedVars.put(dst, srcType);
            dirtied = true;
          }
        } else if (i instanceof ClosureAcceptingInstr) {
          Operand o = ((ClosureAcceptingInstr) i).getClosureArg();
          if (i instanceof CallBase && o == null) {
            CallBase c = (CallBase) i;
            MethAddr m = c.getMethodAddr();
            Operand r = c.getReceiver();
            Operand[] args = c.getCallArgs();
            if (dst != null && 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
              Operation unboxedOp;
              if ((receiverType == Float.class
                      || (receiverType == Fixnum.class && argType == Float.class))
                  && (unboxedOp = m.getUnboxedOp(Float.class)) != null) {
                dirtied = true;

                Class dstType = m.getUnboxedResultType(Float.class);
                setOperandType(tmpState, dst, dstType);
                tmpState.unboxedVars.put(dst, dstType);

                TemporaryLocalVariable unboxedDst = getUnboxedVar(dstType, unboxMap, dst);
                r = unboxOperand(tmpState, Float.class, unboxMap, r, newInstrs);
                a = unboxOperand(tmpState, Float.class, unboxMap, a, newInstrs);
                newInstrs.add(new AluInstr(unboxedOp, unboxedDst, r, a));
              } else if ((receiverType == Float.class
                      || (receiverType == Fixnum.class && argType == Fixnum.class))
                  && (unboxedOp = m.getUnboxedOp(Fixnum.class)) != null) {
                dirtied = true;

                Class dstType = m.getUnboxedResultType(Fixnum.class);
                setOperandType(tmpState, dst, dstType);
                tmpState.unboxedVars.put(dst, dstType);

                TemporaryLocalVariable unboxedDst = getUnboxedVar(dstType, unboxMap, dst);
                r = unboxOperand(tmpState, Fixnum.class, unboxMap, r, newInstrs);
                a = unboxOperand(tmpState, Fixnum.class, unboxMap, a, newInstrs);
                newInstrs.add(new AluInstr(unboxedOp, unboxedDst, r, a));
              } 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) {
              // 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.
              hitDFBarrier = true;

              // Fetch the nested unboxing-analysis problem, creating one if necessary
              IRClosure cl = ((WrappedIRClosure) o).getClosure();
              UnboxableOpsAnalysisProblem subProblem =
                  (UnboxableOpsAnalysisProblem) cl.getDataFlowSolution(DataFlowConstants.UNBOXING);
              UnboxableOpsAnalysisNode exitNode = subProblem.getExitNode();

              // Compute solution
              subProblem.unbox();

              // 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 {
              // 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.unboxedDirtyVars.add(dst);
      } else {
        // Since the instruction didn't run in unboxed form,
        // dirty unboxed vars will have to get boxed here.
        boxRequiredVars(
            i, tmpState, unboxMap, dst, hasExceptionsRescued(), hitDFBarrier, newInstrs);
      }
    }

    // Add unboxing instrs.
    if (!unboxedLiveVars) {
      for (Variable v : succUnboxedVars.keySet()) {
        if (liveVarsSet.get(lvp.getDFVar(v))) {
          unboxVar(tmpState, succUnboxedVars.get(v), unboxMap, v, newInstrs);
        }
      }
    }

    /*
            System.out.println("------");
            for (Instr i : newInstrs) {
                System.out.println("NEW: " + i);
            }
    */

    basicBlock.replaceInstrs(newInstrs);
  }
Example #6
0
  private boolean computeScopeFlags(boolean receivesClosureArg, List<Instr> instrs) {
    for (Instr i : instrs) {
      Operation op = i.getOperation();
      if (op == Operation.RECV_CLOSURE) {
        receivesClosureArg = true;
      } else if (op == Operation.ZSUPER) {
        this.canCaptureCallersBinding = true;
        this.usesZSuper = true;
      } else if (i instanceof CallBase) {
        CallBase call = (CallBase) i;

        if (call.targetRequiresCallersBinding()) this.bindingHasEscaped = true;

        if (call.canBeEval()) {
          this.usesEval = true;

          // If this method receives a closure arg, and this call is an eval that has more than 1
          // argument,
          // it could be using the closure as a binding -- which means it could be using pretty much
          // any
          // variable from the caller's binding!
          if (receivesClosureArg && (call.getCallArgs().length > 1)) {
            this.canCaptureCallersBinding = true;
          }
        }
      } else if (op == Operation.GET_GLOBAL_VAR) {
        GlobalVariable gv = (GlobalVariable) ((GetGlobalVariableInstr) i).getSource();
        String gvName = gv.getName();
        if (gvName.equals("$_")
            || gvName.equals("$~")
            || gvName.equals("$`")
            || gvName.equals("$'")
            || gvName.equals("$+")
            || gvName.equals("$LAST_READ_LINE")
            || gvName.equals("$LAST_MATCH_INFO")
            || gvName.equals("$PREMATCH")
            || gvName.equals("$POSTMATCH")
            || gvName.equals("$LAST_PAREN_MATCH")) {
          this.usesBackrefOrLastline = true;
        }
      } else if (op == Operation.PUT_GLOBAL_VAR) {
        GlobalVariable gv = (GlobalVariable) ((PutGlobalVarInstr) i).getTarget();
        String gvName = gv.getName();
        if (gvName.equals("$_") || gvName.equals("$~")) usesBackrefOrLastline = true;
      } else if (op == Operation.MATCH || op == Operation.MATCH2 || op == Operation.MATCH3) {
        this.usesBackrefOrLastline = true;
      } else if (op == Operation.BREAK) {
        this.hasBreakInstrs = true;
      } else if (i instanceof NonlocalReturnInstr) {
        this.hasNonlocalReturns = true;
      } else if (i instanceof DefineMetaClassInstr) {
        // SSS: Inner-classes are defined with closures and
        // a return in the closure can force a return from this method
        // For now conservatively assume that a scope with inner-classes
        // can receive non-local returns. (Alternatively, have to inspect
        // all lexically nested scopes, not just closures in computeScopeFlags())
        this.canReceiveNonlocalReturns = true;
      }
    }

    return receivesClosureArg;
  }