Increase maximum inlining depth from 1 to 2 (bug 729920, r=dvander)
authorJan de Mooij <jdemooij@mozilla.com>
Fri, 24 Feb 2012 10:44:07 +0100
changeset 105932 d85d370124470821649071bcc537fdb96eeed133
parent 105931 7008b902d362bf3a1dd7d75d49ae6ce149cce3f6
child 105933 1a9e91a88a5488d15b39a0530c326fdb1e1ce77b
push id14706
push usereakhgari@mozilla.com
push dateTue, 11 Sep 2012 20:39:52 +0000
treeherdermozilla-inbound@d50bf1edaabe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdvander
bugs729920
milestone13.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Increase maximum inlining depth from 1 to 2 (bug 729920, r=dvander)
js/src/ion/IonBuilder.cpp
js/src/ion/IonBuilder.h
js/src/ion/MIRGraph.h
--- a/js/src/ion/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -57,16 +57,17 @@ using namespace js::ion;
 
 IonBuilder::IonBuilder(JSContext *cx, JSObject *scopeChain, TempAllocator &temp, MIRGraph &graph,
                        TypeOracle *oracle, CompileInfo &info, size_t inliningDepth, uint32 loopDepth)
   : MIRGenerator(cx, temp, graph, info),
     script(info.script()),
     initialScopeChain_(scopeChain),
     loopDepth_(loopDepth),
     callerResumePoint_(NULL),
+    callerBuilder_(NULL),
     oracle(oracle),
     inliningDepth(inliningDepth)
 {
     pc = info.startPC();
 }
 
 bool
 IonBuilder::abort(const char *message, ...)
@@ -168,16 +169,26 @@ IonBuilder::getInliningTarget(uint32 arg
 
     if (fun->getParent() != script->global()) {
         IonSpew(IonSpew_Inlining, "Cannot inline due to scope mismatch");
         return true;
     }
 
     JSScript *inlineScript = fun->script();
 
+    // Allow inlining of recursive calls, but only one level deep.
+    IonBuilder *builder = callerBuilder_;
+    while (builder) {
+        if (builder->script == inlineScript) {
+            IonSpew(IonSpew_Inlining, "Not inlining recursive call");
+            return true;
+        }
+        builder = builder->callerBuilder_;
+    }
+
     bool canInline = oracle->canEnterInlinedScript(inlineScript);
 
     if (!canInline) {
         IonSpew(IonSpew_Inlining, "Cannot inline due to oracle veto");
         return true;
     }
 
     IonSpew(IonSpew_Inlining, "Inlining good to go!");
@@ -276,26 +287,27 @@ IonBuilder::build()
     if (!traverseBytecode())
         return false;
 
     JS_ASSERT(loopDepth_ == 0);
     return true;
 }
 
 bool
-IonBuilder::buildInline(MResumePoint *callerResumePoint, MDefinition *thisDefn,
-                        MDefinitionVector &argv)
+IonBuilder::buildInline(IonBuilder *callerBuilder, MResumePoint *callerResumePoint,
+                        MDefinition *thisDefn, MDefinitionVector &argv)
 {
     current = newBlock(pc);
     if (!current)
         return false;
 
     IonSpew(IonSpew_MIR, "Inlining script %s:%d (%p)",
             script->filename, script->lineno, (void *) script);
 
+    callerBuilder_ = callerBuilder;
     callerResumePoint_ = callerResumePoint;
     MBasicBlock *predecessor = callerResumePoint->block();
     predecessor->end(MGoto::New(current));
     if (!current->addPredecessorWithoutPhis(predecessor))
         return false;
     JS_ASSERT(predecessor->numSuccessors() == 1);
     JS_ASSERT(current->numPredecessors() == 1);
     current->setCallerResumePoint(callerResumePoint);
@@ -2259,20 +2271,20 @@ IonBuilder::jsop_call_inline(uint32 argc
 
     // Arguments are popped right-to-left so we have to fill |args| backwards.
     if (!discardCallArgs(argc, argv, top))
         return false;
 
     MDefinition *thisDefn = argv[0];
 
     // Build the graph.
-    if (!inlineBuilder.buildInline(inlineResumePoint, thisDefn, argv))
+    if (!inlineBuilder.buildInline(this, inlineResumePoint, thisDefn, argv))
         return false;
 
-    MIRGraphExits &exits = inlineBuilder.graph().getExitAccumulator();
+    MIRGraphExits &exits = *inlineBuilder.graph().exitAccumulator();
 
     // Create a |bottom| block for all the callee subgraph exits to jump to.
     JS_ASSERT(*pc == JSOP_CALL);
     jsbytecode *postCall = GetNextPc(pc);
     MBasicBlock *bottom = newBlock(NULL, postCall);
 
     // Link graph exits to |bottom| via MGotos, replacing MReturns.
     Vector<MDefinition *, 8, IonAllocPolicy> retvalDefns;
@@ -2325,24 +2337,26 @@ IonBuilder::jsop_call_inline(uint32 argc
     JS_ASSERT(bottom->stackDepth() == origStackDepth - argc - 1);
 
     current = bottom;
     return true;
 }
 
 class AutoAccumulateExits
 {
-    MIRGraph &graph;
+    MIRGraph &graph_;
+    MIRGraphExits *prev_;
 
   public:
-    AutoAccumulateExits(MIRGraph &graph, MIRGraphExits &exits) : graph(graph) {
-        graph.setExitAccumulator(&exits);
+    AutoAccumulateExits(MIRGraph &graph, MIRGraphExits &exits) : graph_(graph) {
+        prev_ = graph_.exitAccumulator();
+        graph_.setExitAccumulator(&exits);
     }
     ~AutoAccumulateExits() {
-        graph.setExitAccumulator(NULL);
+        graph_.setExitAccumulator(prev_);
     }
 };
 
 bool
 IonBuilder::makeInliningDecision(uint32 argc, InliningData *data)
 {
     JS_ASSERT(data->shouldInline == false);
 
@@ -2372,17 +2386,17 @@ IonBuilder::makeInliningDecision(uint32 
 
 IonBuilder::InliningStatus
 IonBuilder::maybeInline(uint32 argc)
 {
     InliningData data;
     if (!makeInliningDecision(argc, &data))
         return InliningStatus_Error;
 
-    if (!data.shouldInline || inliningDepth >= 1)
+    if (!data.shouldInline || inliningDepth >= 2)
         return InliningStatus_NotInlined;
 
     IonSpew(IonSpew_Inlining, "Recursively building");
     // Compilation information is allocated for the duration of the current tempLifoAlloc
     // lifetime.
     CompileInfo *info = cx->tempLifoAlloc().new_<CompileInfo>(data.callee->script().get(),
                                                               data.callee, (jsbytecode *)NULL);
     if (!info)
--- a/js/src/ion/IonBuilder.h
+++ b/js/src/ion/IonBuilder.h
@@ -186,17 +186,17 @@ class IonBuilder : public MIRGenerator
         { }
     };
 
   public:
     IonBuilder(JSContext *cx, JSObject *scopeChain, TempAllocator &temp, MIRGraph &graph,
                TypeOracle *oracle, CompileInfo &info, size_t inliningDepth = 0, uint32 loopDepth = 0);
 
     bool build();
-    bool buildInline(MResumePoint *callerResumePoint, MDefinition *thisDefn,
+    bool buildInline(IonBuilder *callerBuilder, MResumePoint *callerResumePoint, MDefinition *thisDefn,
                      MDefinitionVector &args);
 
   private:
     bool traverseBytecode();
     ControlStatus snoopControlFlow(JSOp op);
     bool inspectOpcode(JSOp op);
     uint32 readIndex(jsbytecode *pc);
     JSAtom *readAtom(jsbytecode *pc);
@@ -354,16 +354,17 @@ class IonBuilder : public MIRGenerator
     MBasicBlock *current;
     uint32 loopDepth_;
 
     /* Information used for inline-call builders. */
     MResumePoint *callerResumePoint_;
     jsbytecode *callerPC() {
         return callerResumePoint_ ? callerResumePoint_->pc() : NULL;
     }
+    IonBuilder *callerBuilder_;
 
     Vector<CFGState, 8, IonAllocPolicy> cfgStack_;
     Vector<ControlFlowInfo, 4, IonAllocPolicy> loops_;
     Vector<ControlFlowInfo, 0, IonAllocPolicy> switches_;
     TypeOracle *oracle;
     size_t inliningDepth;
 };
 
--- a/js/src/ion/MIRGraph.h
+++ b/js/src/ion/MIRGraph.h
@@ -482,29 +482,29 @@ typedef InlineListIterator<MBasicBlock> 
 typedef InlineListReverseIterator<MBasicBlock> PostorderIterator;
 
 typedef Vector<MBasicBlock *, 1, IonAllocPolicy> MIRGraphExits;
 
 class MIRGraph
 {
     InlineList<MBasicBlock> blocks_;
     TempAllocator &alloc_;
-    MIRGraphExits *exitAccumulator;
+    MIRGraphExits *exitAccumulator_;
     uint32 blockIdGen_;
     uint32 idGen_;
     MBasicBlock *osrBlock_;
     MStart *osrStart_;
 #ifdef DEBUG
     size_t numBlocks_;
 #endif
 
   public:
     MIRGraph(TempAllocator &alloc)
       : alloc_(alloc),
-        exitAccumulator(NULL),
+        exitAccumulator_(NULL),
         blockIdGen_(0),
         idGen_(0),
         osrBlock_(NULL),
         osrStart_(NULL)
 #ifdef DEBUG
         , numBlocks_(0)
 #endif
     { }
@@ -513,29 +513,27 @@ class MIRGraph
     T * allocate(size_t count = 1) {
         return reinterpret_cast<T *>(alloc_.allocate(sizeof(T) * count));
     }
 
     void addBlock(MBasicBlock *block);
     void unmarkBlocks();
 
     void setExitAccumulator(MIRGraphExits *accum) {
-        exitAccumulator = accum;
+        exitAccumulator_ = accum;
     }
-
-    MIRGraphExits &getExitAccumulator() {
-        JS_ASSERT(exitAccumulator);
-        return *exitAccumulator;
+    MIRGraphExits *exitAccumulator() const {
+        return exitAccumulator_;
     }
 
     bool addExit(MBasicBlock *exitBlock) {
-        if (!exitAccumulator)
+        if (!exitAccumulator_)
             return true;
 
-        return exitAccumulator->append(exitBlock);
+        return exitAccumulator_->append(exitBlock);
     }
 
     MBasicBlock *entryBlock() {
         return *blocks_.begin();
     }
 
     void clearBlockList() {
         blocks_.clear();