--- 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;
@@ -1766,50 +1765,71 @@ js_ExecuteTree(JSContext* cx, Fragment*
uint64 start = rdtsc();
#endif
JS_ASSERT(!cx->gcDontBlock);
cx->gcDontBlock = JS_TRUE;
GuardRecord* lr = u.func(&state, NULL);
cx->gcDontBlock = JS_FALSE;
- for (int32 i = 0; i < lr->calldepth; i++)
+ /* 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;
+
+ /* 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)) + 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=%p, ip=%p, cycles=%llu\n",
+ 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),
fp->regs->pc - fp->script->code,
lr->exit->exitType,
- state.sp, lr->jmp,
+ fp->regs->sp - StackBase(fp), lr->jmp,
(rdtsc() - start));
#endif
- JS_ASSERT(lr->exit->exitType != NESTED_EXIT);
-
+ /* write back interned globals */
FlushNativeGlobalFrame(cx, e->numGlobalSlots, ti->globalSlots.data(), e->typeMap, global);
- FlushNativeStackFrame(cx, e->calldepth, e->typeMap + e->numGlobalSlots, stack);
JS_ASSERT(ti->globalSlots.length() >= e->numGlobalSlots);
JS_ASSERT(globalFrameSize == STOBJ_NSLOTS(globalObj));
JS_ASSERT(*(uint64*)&global[globalFrameSize] == 0xdeadbeefdeadbeefLL);
-
+
+ /* 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);