Bug 456370. Flush the fragment cache earlier on global shape mismatch. r=gal
authorBoris Zbarsky <bzbarsky@mit.edu>
Fri, 26 Sep 2008 14:37:49 -0400
changeset 19989 3a02053b2cffd0c06000bcebf3e12ba35be1ac26
parent 19988 ea5a7136bce2e8d4fd41f99358e7233a0ffc65ea
child 19990 b8dcfe8b5efba925ad209faeebc7b49a941ea76a
push id2577
push userbrendan@mozilla.com
push dateWed, 01 Oct 2008 04:35:27 +0000
treeherdermozilla-central@a613924403d6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgal
bugs456370
milestone1.9.1b1pre
Bug 456370. Flush the fragment cache earlier on global shape mismatch. r=gal
js/src/jstracer.cpp
js/src/trace-test.js
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -2195,16 +2195,17 @@ js_SynthesizeFrame(JSContext* cx, const 
 }
 
 bool
 js_RecordTree(JSContext* cx, JSTraceMonitor* tm, Fragment* f)
 {
     /* Make sure the global type map didn't change on us. */
     uint32 globalShape = OBJ_SHAPE(JS_GetGlobalForObject(cx, cx->fp->scopeChain));
     if (tm->globalShape != globalShape) {
+        AUDIT(globalShapeMismatchAtEntry);
         debug_only_v(printf("Global shape mismatch (%u vs. %u) in RecordTree, flushing cache.\n",
                           globalShape, tm->globalShape);)
         js_FlushJITCache(cx);
         return false;
     }
     TypeMap current;
     current.captureGlobalTypes(cx, *tm->globalSlots);
     if (!current.matches(*tm->globalTypeMap)) {
@@ -2649,16 +2650,27 @@ js_MonitorLoopEdge(JSContext* cx, jsbyte
     /* Is the recorder currently active? */
     if (tm->recorder) {
         if (js_RecordLoopEdge(cx, tm->recorder, oldpc, inlineCallCount))
             return true;
         /* recording was aborted, treat like a regular loop edge hit */
     }
     JS_ASSERT(!tm->recorder);
 
+    /* Do an up-front global shape check, since we'll blow away the jit cache
+       on global shape mismatch, wasting all the other work this method does,
+       if we end up in either js_RecordTree or js_ExecuteTree */
+    uint32 globalShape = OBJ_SHAPE(JS_GetGlobalForObject(cx, cx->fp->scopeChain));
+    if (tm->globalShape != globalShape) {
+        debug_only_v(printf("Global shape mismatch (%u vs. %u) in js_MonitorLoopEdge, flushing cache.\n",
+                            globalShape, tm->globalShape);)
+        js_FlushJITCache(cx);
+        // Press on to at least increment a hit count
+    }
+
     /* check if our quick cache has an entry for this ip, otherwise ask fragmento. */
     jsbytecode* pc = cx->fp->regs->pc;
     Fragment* f;
     JSFragmentCacheEntry* cacheEntry = &tm->fcache[jsuword(pc) & JS_FRAGMENT_CACHE_MASK];
     if (cacheEntry->pc == pc) {
         f = cacheEntry->fragment;
     } else {
         f = tm->fragmento->getLoop(pc);
--- a/js/src/trace-test.js
+++ b/js/src/trace-test.js
@@ -1636,11 +1636,45 @@ function regexpLastIndex()
         n += (re.lastIndex > 0) ? 3 : 0;
         re.lastIndex = 0;
     }
     return n;
 }
 regexpLastIndex.expected = 0; // 30;
 test(regexpLastIndex);
 
+function testHOTLOOPCorrectness() {
+    var b = 0;
+    for (var i = 0; i < HOTLOOP; ++i) {
+	++b;
+    }
+    return b;
+}
+testHOTLOOPCorrectness.expected = HOTLOOP;
+testHOTLOOPCorrectness.jitstats = {
+    recorderStarted: 1,
+    recorderAborted: 0,
+    traceTriggered: 0
+};
+// Change the global shape right before doing the test
+this.testHOTLOOPCorrectnessVar = 1;
+test(testHOTLOOPCorrectness);
+
+function testRUNLOOPCorrectness() {
+    var b = 0;
+    for (var i = 0; i < RUNLOOP; ++i) {
+	++b;
+    }
+    return b;
+}
+testRUNLOOPCorrectness.expected = RUNLOOP;
+testRUNLOOPCorrectness.jitstats = {
+    recorderStarted: 1,
+    recorderAborted: 0,
+    traceTriggered: 1
+};
+// Change the global shape right before doing the test
+this.testRUNLOOPCorrectnessVar = 1;
+test(testRUNLOOPCorrectness);
+
 /* Keep these at the end so that we can see the summary after the trace-debug spew. */
 print("\npassed:", passes.length && passes.join(","));
 print("\nFAILED:", fails.length && fails.join(","));