Пример #1
0
  public boolean isNestedInClosure(IRClosure closure) {
    for (IRScope s = this; s != null && !s.isTopLocalVariableScope(); s = s.getLexicalParent()) {
      if (s == closure) return true;
    }

    return false;
  }
Пример #2
0
  /** Returns the top level scope */
  public IRScope getTopLevelScope() {
    IRScope current = this;

    for (; current != null && !current.isScriptScope(); current = current.getLexicalParent()) {}

    return current;
  }
Пример #3
0
  public IRScope getNearestTopLocalVariableScope() {
    IRScope current = this;

    while (current != null && !current.isTopLocalVariableScope()) {
      current = current.getLexicalParent();
    }

    return current;
  }
Пример #4
0
  public IRMethod getNearestMethod() {
    IRScope current = this;

    while (current != null && !(current instanceof IRMethod)) {
      current = current.getLexicalParent();
    }

    return (IRMethod) current;
  }
Пример #5
0
  /**
   * Returns the nearest scope which we can extract a live module from. If this returns null (like
   * for evals), then it means it cannot be statically determined.
   */
  public IRScope getNearestModuleReferencingScope() {
    IRScope current = this;

    while (!(current instanceof IRModuleBody)) {
      // When eval'ing, we dont have a lexical view of what module we are nested in
      // because binding_eval, class_eval, module_eval, instance_eval can switch
      // around the lexical scope for evaluation to be something else.
      if (current == null || current instanceof IREvalScript) return null;

      current = current.getLexicalParent();
    }

    return current;
  }
Пример #6
0
  public IREvalScript(
      IRManager manager,
      IRScope lexicalParent,
      String fileName,
      int lineNumber,
      StaticScope staticScope) {
    super(manager, lexicalParent, fileName, lineNumber, staticScope, "EVAL_");

    int n = 0;
    IRScope s = lexicalParent;
    while (s instanceof IREvalScript) {
      n++;
      s = s.getLexicalParent();
    }

    this.nearestNonEvalScope = s;
    this.nearestNonEvalScopeDepth = n;
    this.nearestNonEvalScope.initEvalScopeVariableAllocator(false);
  }
  public void addDFVar(Variable v) {
    Integer dfv = addDataFlowVar();
    dfVarMap.put(v, dfv);
    varDfVarMap.put(dfv, v);

    if (v instanceof LocalVariable && !v.isSelf()) {
      // System.out.println("Adding df var for " + v + ":" + dfv.id);
      IRScope s = getScope();
      for (int n = ((LocalVariable) v).getScopeDepth(); s != null && n >= 0; n--) {
        if (s instanceof IREvalScript) {
          // If a variable is at the topmost scope of the eval OR crosses an eval boundary,
          // it is going to be marked always live since it could be used by other evals (n = 0)
          // or by enclosing scopes (n > 0)
          alwaysLiveVars.add((LocalVariable) v);
          break;
        }

        s = s.getLexicalParent();
      }
      localVars.add((LocalVariable) v);
    }
  }
Пример #8
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;
    }
  }