Update inlineCallCount with the total call stack height, which is the sum of rp_adj and any adjustments nested trees added. Also make sure to read all stack adjustment information from the tree we exit on, not the tree we entered (might be different in case of nesting.)
authorAndreas Gal <gal@mozilla.com>
Wed, 13 Aug 2008 19:09:05 -0700
changeset 18159 df0ca7630874415cb040fe8af267e478ab509202
parent 18158 57bfefe8dfc3f66251a0b52fa9c719a8c8296cd8
child 18160 78655198504628022c167e2ec057806a99c4e54c
child 18162 5375ca6c1cfc9a0a71025b1bf0e544ce98129962
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone1.9.1a2pre
Update inlineCallCount with the total call stack height, which is the sum of rp_adj and any adjustments nested trees added. Also make sure to read all stack adjustment information from the tree we exit on, not the tree we entered (might be different in case of nesting.)
js/src/jstracer.cpp
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -1371,26 +1371,26 @@ TraceRecorder::emitTreeCall(Fragment* in
     LIns* args[] = { lir->insImmPtr(inner), lirbuf->state }; /* reverse order */
     LIns* ret = lir->insCall(F_CallTree, args);
     /* Make a note that we now depend on that tree. */
     ti->dependentTrees.addUnique(fragment);
     /* Read back all registers, in case the called tree changed any of them. */
     SideExit* exit = lr->exit;
     import(ti, inner_sp, exit->numGlobalSlots, exit->calldepth, 
            exit->typeMap, exit->typeMap + exit->numGlobalSlots);
+    /* Store the guard pointer in case we exit on an unexpected guard */
+    lir->insStorei(lir->insImmPtr(lr), lirbuf->state, offsetof(InterpState, nestedExit));
+    /* Guard that we come out of the inner tree along the same side exit we came out when
+       we called the inner tree at recording time. */
+    guard(true, lir->ins2(LIR_eq, ret, lir->insImmPtr(lr)), NESTED_EXIT);
     /* Restore sp and rp to their original values (we still have them in a register). */
     if (callDepth > 0) {
         lir->insStorei(lirbuf->sp, lirbuf->state, offsetof(InterpState, sp));
         lir->insStorei(lirbuf->rp, lirbuf->state, offsetof(InterpState, rp));
     }
-    /* Store the guard pointer in case we exit on an unexpected guard */
-    lir->insStorei(lir->insImmPtr(lr), lirbuf->state, offsetof(InterpState, nestedExit));
-    /* Guard that we come out of the inner tree along the same side exit we came out when
-       we called the inner tree at recording time. */
-    guard(true, lir->ins2(LIR_eq, ret, lir->insImmPtr(lr)), NESTED_EXIT);
 }
 
 int
 nanojit::StackFilter::getTop(LInsp guard)
 {
     if (sp == frag->lirbuf->sp)
         return guard->exit()->sp_adj + sizeof(double);
     JS_ASSERT(sp == frag->lirbuf->rp);
@@ -1744,17 +1744,16 @@ js_ExecuteTree(JSContext* cx, Fragment* 
             js_TrashTree(cx, f);
         }
         return NULL;
     }
     
     ti->mismatchCount = 0;
 
     double* entry_sp = &stack[ti->nativeStackBase/sizeof(double)];
-    //FrameInfo* callstack = (FrameInfo*) alloca(ti->maxCallDepth * sizeof(FrameInfo));
     FrameInfo* callstack = (FrameInfo*) alloca(MAX_CALL_STACK_ENTRIES * sizeof(FrameInfo));
     
     InterpState state;
     state.sp = (void*)entry_sp;
     state.eos = ((double*)state.sp) + MAX_NATIVE_STACK_SLOTS;
     state.rp = callstack;
     state.eor = callstack + MAX_CALL_STACK_ENTRIES;
     state.gp = global;
@@ -1772,32 +1771,35 @@ js_ExecuteTree(JSContext* cx, Fragment* 
     cx->gcDontBlock = JS_FALSE;
 
     /* If we bail out on a nested exit, the compiled code returns the outermost nesting
        guard but what we are really interested in is the innermost guard that we hit
        instead of the guard we were expecting there. */
     if (lr->exit->exitType == NESTED_EXIT)
         lr = state.nestedExit;
 
-    /* As long we are not dealing with nested trees, the call stack should have exactly
-       as many entries as the side-exit predicts. When synthesizing frames however we
-       have to use the actual call stack depth instead of trusting the side exit since
-       its only the innermost side exit, which might not know about the outer call stack. */
-    JS_ASSERT((lr->exit->exitType == NESTED_EXIT) ||
-              ((((FrameInfo*)state.rp) - callstack) == lr->exit->calldepth));
-    for (int32 i = 0; i < (((FrameInfo*)state.rp) - callstack); ++i)
+    /* sp_adj and ip_adj are relative to the tree we exit out of, not the tree we 
+       entered into (which might be different in the presence of nested trees). */
+    ti = (TreeInfo*)lr->from->root->vmprivate;
+    
+    /* While executing a tree we don't update state->rp, but we do so when we call another
+       tree. So the total call stack height is the sum of the statically calculated 
+       calldepth in the side exit (relative to the tree entry), and the difference between
+       rp and the bottom of the call stack we setup for the call. */
+    int calldepth = (((FrameInfo*)state.rp) - callstack) + lr->exit->calldepth;
+
+    for (int32 i = 0; i < calldepth; ++i)
         js_SynthesizeFrame(cx, callstack[i]);
 
     /* Adjust sp and pc relative to the tree we exited from (not the tree we entered
        into). These are our final values for sp and pc since js_SynthesizeFrame has
        already taken care of all frames in between. */
     SideExit* e = lr->exit;
     JSStackFrame* fp = cx->fp;
-    JS_ASSERT((e->sp_adj / sizeof(double)) + 
-              ((TreeInfo*)lr->from->root->vmprivate)->entryNativeStackSlots >=
+    JS_ASSERT((e->sp_adj / sizeof(double)) + ti->entryNativeStackSlots >=
               nativeStackSlots(cx, lr->calldepth, fp));
     fp->regs->sp += (e->sp_adj / sizeof(double)) + ti->entryNativeStackSlots -
                     nativeStackSlots(cx, lr->calldepth, fp);
     fp->regs->pc = (jsbytecode*)lr->from->root->ip + e->ip_adj;
 
 #if defined(DEBUG) && defined(NANOJIT_IA32)
     printf("leaving trace at %s:%u@%u, exitType=%d, sp=%d, ip=%p, cycles=%llu\n",
            fp->script->filename, js_PCToLineNumber(cx, fp->script, fp->regs->pc),
@@ -1816,17 +1818,18 @@ js_ExecuteTree(JSContext* cx, Fragment* 
     /* write back native stack frame */
     FlushNativeStackFrame(cx, e->calldepth, e->typeMap + e->numGlobalSlots, stack);
     
     AUDIT(sideExitIntoInterpreter);
 
     if (!lr) /* did the tree actually execute? */
         return NULL;
 
-    inlineCallCount += lr->exit->calldepth;
+    /* Adjust inlineCallCount by the total call depth at this point (call stack height). */
+    inlineCallCount += calldepth;
 
     return lr;
 }
 
 bool
 js_LoopEdge(JSContext* cx, jsbytecode* oldpc, uintN& inlineCallCount)
 {
     JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx);