--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -1325,18 +1325,122 @@ js_SynthesizeFrame(JSContext* cx, const
newifp->frame.pcDisabledSave = 0;
#endif
cx->fp->regs = &newifp->callerRegs;
cx->fp = &newifp->frame;
return newifp;
}
-static GuardRecord*
-js_ExecuteTree(JSContext* cx, Fragment* f)
+bool
+js_RecordTree(JSContext* cx, JSTraceMonitor* tm, Fragment* f)
+{
+ AUDIT(recorderStarted);
+ f->calldepth = 0;
+ f->root = f;
+ /* allocate space to store the LIR for this tree */
+ if (!f->lirbuf) {
+ f->lirbuf = new (&gc) LirBuffer(tm->fragmento, builtins);
+#ifdef DEBUG
+ f->lirbuf->names = new (&gc) LirNameMap(&gc, builtins, tm->fragmento->labels);
+#endif
+ }
+ /* create the tree anchor structure */
+ TreeInfo* ti = (TreeInfo*)f->vmprivate;
+ if (!ti) {
+ /* setup the VM-private treeInfo structure for this fragment */
+ ti = new TreeInfo(); // TODO: deallocate when fragment dies
+ f->vmprivate = ti;
+
+ /* determine the native frame layout at the entry point */
+ unsigned entryNativeStackSlots = nativeStackSlots(0/*callDepth*/, cx->fp);
+ ti->entryNativeStackSlots = entryNativeStackSlots;
+ ti->nativeStackBase = (entryNativeStackSlots -
+ (cx->fp->regs->sp - StackBase(cx->fp))) * sizeof(double);
+ ti->maxNativeStackSlots = entryNativeStackSlots;
+ ti->maxCallDepth = 0;
+
+ /* create the list of global properties we want to intern */
+ ti->globalShape = OBJ_SCOPE(JS_GetGlobalForObject(cx, cx->fp->scopeChain))->shape;
+
+ /* remember the coerced type of each active slot in the stack type map */
+ ti->stackTypeMap.setLength(entryNativeStackSlots);
+ uint8* m = ti->stackTypeMap.data();
+ FORALL_SLOTS_IN_PENDING_FRAMES(cx, 0/*callDepth*/,
+ *m++ = getCoercedType(*vp);
+ );
+ }
+ JS_ASSERT(ti->entryNativeStackSlots == nativeStackSlots(0/*callDepth*/, cx->fp));
+
+ /* recording primary trace */
+ return js_StartRecorder(cx, NULL, f, ti->globalSlots.length(),
+ ti->globalTypeMap.data(), ti->stackTypeMap.data());
+}
+
+static bool
+js_AttemptToExtendTree(JSContext* cx, GuardRecord* lr, Fragment* f)
+{
+ JS_ASSERT(lr->from->root == f);
+
+ debug_only(printf("trying to attach another branch to the tree\n");)
+
+ Fragment* c;
+ if (!(c = lr->target)) {
+ c = JS_TRACE_MONITOR(cx).fragmento->createBranch(lr, lr->exit);
+ c->spawnedFrom = lr->guard;
+ c->parent = f;
+ lr->exit->target = c;
+ lr->target = c;
+ c->root = f;
+ }
+
+ if (++c->hits() >= HOTEXIT) {
+ /* start tracing secondary trace from this point */
+ c->lirbuf = f->lirbuf;
+ SideExit* e = lr->exit;
+ unsigned ngslots = e->numGlobalSlots;
+ uint8* globalTypeMap = e->typeMap;
+ uint8* stackTypeMap = globalTypeMap + ngslots;
+ return js_StartRecorder(cx, lr, c, ngslots, globalTypeMap, stackTypeMap);
+ }
+ return false;
+}
+
+bool
+js_ContinueRecording(JSContext* cx, TraceRecorder* r, jsbytecode* oldpc)
+{
+#ifdef JS_THREADSAFE
+ if (OBJ_SCOPE(JS_GetGlobalForObject(cx, cx->fp->scopeChain))->title.ownercx != cx) {
+#ifdef DEBUG
+ printf("Global object not owned by this context.\n");
+#endif
+ return false; /* we stay away from shared global objects */
+ }
+#endif
+ if (r->isLoopHeader(cx)) { /* did we hit the start point? */
+ AUDIT(traceCompleted);
+ r->closeLoop(JS_TRACE_MONITOR(cx).fragmento);
+ js_DeleteRecorder(cx);
+ return false; /* done recording */
+ }
+ if (++r->backEdgeCount >= MAX_XJUMPS) {
+ AUDIT(returnToDifferentLoopHeader);
+ debug_only(printf("loop edge %d -> %d, header %d\n",
+ oldpc - cx->fp->script->code,
+ cx->fp->regs->pc - cx->fp->script->code,
+ (jsbytecode*)r->getFragment()->root->ip - cx->fp->script->code));
+ js_AbortRecording(cx, oldpc, "Loop edge does not return to header");
+ return false; /* done recording */
+ }
+ return true; /* keep recording (attempting to unroll inner loop) */
+}
+
+
+bool
+js_ExecuteTree(JSContext* cx, Fragment* f, uintN& inlineCallCount)
{
AUDIT(traceTriggered);
/* execute previously recorded trace */
TreeInfo* ti = (TreeInfo*)f->vmprivate;
JSObject* globalObj = JS_GetGlobalForObject(cx, cx->fp->scopeChain);
if (OBJ_SCOPE(globalObj)->shape != ti->globalShape) {
AUDIT(globalShapeMismatchAtEntry);
@@ -1407,135 +1511,16 @@ js_ExecuteTree(JSContext* cx, Fragment*
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*)&stack[ti->maxNativeStackSlots] == 0xdeadbeefdeadbeefLL);
JS_ASSERT(*(uint64*)&global[globalFrameSize] == 0xdeadbeefdeadbeefLL);
AUDIT(sideExitIntoInterpreter);
- return lr;
-}
-
-static bool
-js_AttemptToExtendTree(JSContext* cx, GuardRecord* lr, Fragment* f)
-{
- JS_ASSERT(lr->from->root == f);
-
- debug_only(printf("trying to attach another branch to the tree\n");)
-
- Fragment* c;
- if (!(c = lr->target)) {
- c = JS_TRACE_MONITOR(cx).fragmento->createBranch(lr, lr->exit);
- c->spawnedFrom = lr->guard;
- c->parent = f;
- lr->exit->target = c;
- lr->target = c;
- c->root = f;
- }
-
- if (++c->hits() >= HOTEXIT) {
- /* start tracing secondary trace from this point */
- c->lirbuf = f->lirbuf;
- SideExit* e = lr->exit;
- unsigned ngslots = e->numGlobalSlots;
- uint8* globalTypeMap = e->typeMap;
- uint8* stackTypeMap = globalTypeMap + ngslots;
- return js_StartRecorder(cx, lr, c, ngslots, globalTypeMap, stackTypeMap);
- }
- return false;
-}
-
-static bool
-js_ContinueRecording(JSContext* cx, TraceRecorder* r, jsbytecode* oldpc)
-{
-#ifdef JS_THREADSAFE
- if (OBJ_SCOPE(JS_GetGlobalForObject(cx, cx->fp->scopeChain))->title.ownercx != cx) {
-#ifdef DEBUG
- printf("Global object not owned by this context.\n");
-#endif
- return false; /* we stay away from shared global objects */
- }
-#endif
- if (r->isLoopHeader(cx)) { /* did we hit the start point? */
- AUDIT(traceCompleted);
- r->closeLoop(JS_TRACE_MONITOR(cx).fragmento);
- js_DeleteRecorder(cx);
- return false; /* done recording */
- }
- if (++r->backEdgeCount >= MAX_XJUMPS) {
- AUDIT(returnToDifferentLoopHeader);
- debug_only(printf("loop edge %d -> %d, header %d\n",
- oldpc - cx->fp->script->code,
- cx->fp->regs->pc - cx->fp->script->code,
- (jsbytecode*)r->getFragment()->root->ip - cx->fp->script->code));
- js_AbortRecording(cx, oldpc, "Loop edge does not return to header");
- return false; /* done recording */
- }
- return true; /* keep recording (attempting to unroll inner loop) */
-}
-
-bool
-js_LoopEdge(JSContext* cx, jsbytecode* oldpc, uintN& inlineCallCount)
-{
- JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx);
-
- /* is the recorder currently active? */
- if (tm->recorder)
- return js_ContinueRecording(cx, tm->recorder, oldpc);
-
- Fragment* f = tm->fragmento->getLoop(cx->fp->regs->pc);
- if (!f->code()) {
- if (++f->hits() >= HOTLOOP) {
- AUDIT(recorderStarted);
- f->calldepth = 0;
- f->root = f;
- /* allocate space to store the LIR for this tree */
- if (!f->lirbuf) {
- f->lirbuf = new (&gc) LirBuffer(tm->fragmento, builtins);
-#ifdef DEBUG
- f->lirbuf->names = new (&gc) LirNameMap(&gc, builtins, tm->fragmento->labels);
-#endif
- }
- /* create the tree anchor structure */
- TreeInfo* ti = (TreeInfo*)f->vmprivate;
- if (!ti) {
- /* setup the VM-private treeInfo structure for this fragment */
- ti = new TreeInfo(); // TODO: deallocate when fragment dies
- f->vmprivate = ti;
-
- /* determine the native frame layout at the entry point */
- unsigned entryNativeStackSlots = nativeStackSlots(0/*callDepth*/, cx->fp);
- ti->entryNativeStackSlots = entryNativeStackSlots;
- ti->nativeStackBase = (entryNativeStackSlots -
- (cx->fp->regs->sp - StackBase(cx->fp))) * sizeof(double);
- ti->maxNativeStackSlots = entryNativeStackSlots;
- ti->maxCallDepth = 0;
-
- /* create the list of global properties we want to intern */
- ti->globalShape = OBJ_SCOPE(JS_GetGlobalForObject(cx, cx->fp->scopeChain))->shape;
-
- /* remember the coerced type of each active slot in the stack type map */
- ti->stackTypeMap.setLength(entryNativeStackSlots);
- uint8* m = ti->stackTypeMap.data();
- FORALL_SLOTS_IN_PENDING_FRAMES(cx, 0/*callDepth*/,
- *m++ = getCoercedType(*vp);
- );
- }
- JS_ASSERT(ti->entryNativeStackSlots == nativeStackSlots(0/*callDepth*/, cx->fp));
-
- /* recording primary trace */
- return js_StartRecorder(cx, NULL, f, ti->globalSlots.length(),
- ti->globalTypeMap.data(), ti->stackTypeMap.data());
- }
- return false;
- }
-
- GuardRecord* lr = js_ExecuteTree(cx, f);
-
if (!lr) /* did the tree actually execute? */
return false;
inlineCallCount += lr->exit->calldepth;
switch (lr->exit->exitType) {
case BRANCH_EXIT:
/* if its a branch, try to extend the tree */
return js_AttemptToExtendTree(cx, lr, f);
@@ -1545,16 +1530,35 @@ js_LoopEdge(JSContext* cx, jsbytecode* o
default:
JS_ASSERT(lr->exit->exitType == DONT_GROW);
/* We ran out of heap, or an unsupported instruction. Exit for now and re-enter once the
GC ran. */
return false;
}
}
+bool
+js_LoopEdge(JSContext* cx, jsbytecode* oldpc, uintN& inlineCallCount)
+{
+ JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx);
+
+ /* is the recorder currently active? */
+ if (tm->recorder)
+ return js_ContinueRecording(cx, tm->recorder, oldpc);
+
+ Fragment* f = tm->fragmento->getLoop(cx->fp->regs->pc);
+ if (!f->code()) {
+ if (++f->hits() >= HOTLOOP)
+ return js_RecordTree(cx, tm, f);
+ return false;
+ }
+
+ return js_ExecuteTree(cx, f, inlineCallCount);
+}
+
void
js_AbortRecording(JSContext* cx, jsbytecode* abortpc, const char* reason)
{
AUDIT(recorderAborted);
debug_only(if (!abortpc) abortpc = cx->fp->regs->pc;
printf("Abort recording (line %d, pc %d): %s.\n",
js_PCToLineNumber(cx, cx->fp->script, abortpc),
abortpc - cx->fp->script->code, reason);)