Factor out most of the remaining code in js_LoopEdge into js_RecordTree and move the code to attach new branches into js_ExecuteTree.
authorAndreas Gal <gal@mozilla.com>
Fri, 01 Aug 2008 22:47:15 -0700
changeset 17939 01677050142d7b44d16efc6c5af4ec6a880022d7
parent 17938 909b44d62e0d2966f0940cec563ecb11f616b61c
child 17940 65a8e14beca4f31a1e369aafebe38451977db554
push id1452
push usershaver@mozilla.com
push dateFri, 22 Aug 2008 00:08:22 +0000
treeherderautoland@d13bb0868596 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone1.9.1a1pre
Factor out most of the remaining code in js_LoopEdge into js_RecordTree and move the code to attach new branches into js_ExecuteTree.
js/src/jstracer.cpp
--- 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);)