Purge IC caches when verifying barriers (bug 761854, r=billm).
authorDavid Anderson <danderson@mozilla.com>
Wed, 27 Jun 2012 15:38:39 -0700
changeset 106477 c47c09bf5775598666faa7e975525ef539d731bd
parent 106476 62c180773b87fd633d8013f7d77e0e3633d3b0df
child 106478 ddbd42e6704909320cd7f7c181db00da630e67aa
push id23447
push userdanderson@mozilla.com
push dateTue, 11 Sep 2012 17:34:27 +0000
treeherdermozilla-central@fdfaef738a00 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm
bugs761854
milestone16.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Purge IC caches when verifying barriers (bug 761854, r=billm).
js/src/jit-test/tests/ion/bug761854.js
js/src/jscompartment.cpp
js/src/jsgc.cpp
js/src/jsgc.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug761854.js
@@ -0,0 +1,57 @@
+var gTestcases = new Array();
+function TestCase(n, d, e, a) {
+  this.name = n;
+  this.description = d;
+  this.expect = e;
+  this.actual = a;
+  this.passed = getTestCaseResult(e, a);
+  options.stackvalues = [];
+function getTestCaseResult(expected, actual) { }
+}
+var lfcode = new Array();
+lfcode.push("3");
+lfcode.push("var statusitems = [];\
+var actualvalues = [];\
+var expectedvalues = [];\
+actual = '$a$^'.replace(/\\$\\^/, '--');\
+actual = 'ababc'.replace(/abc/, '--');\
+actual = 'ababc'.replace(/abc/g, '--');\
+");
+lfcode.push("\
+var SECTION = \"15.4.4.3-1\";\
+new TestCase( SECTION, \"Array.prototype.join.length\",           1,      Array.prototype.join.length );\
+new TestCase( SECTION, \"delete Array.prototype.join.length\",    false,  delete Array.prototype.join.length );\
+new TestCase( SECTION, \"delete Array.prototype.join.length; Array.prototype.join.length\",    1, eval(\"delete Array.prototype.join.length; Array.prototype.join.length\") );\
+new TestCase(   SECTION, eval(\"var TEST_ARRAY = new Array(); TEST_ARRAY.join()\") );\
+new TestCase(   SECTION, eval(\"var TEST_ARRAY = new Array(); TEST_ARRAY.join(' ')\") );\
+new TestCase(   SECTION, eval(\"var TEST_ARRAY = new Array(null, void 0, true, false, 123, new Object(), new Boolean(true) ); TEST_ARRAY.join('&')\") );\
+new TestCase(   SECTION, eval(\"var TEST_ARRAY = new Array(null, void 0, true, false, 123, new Object(), new Boolean(true) ); TEST_ARRAY.join('')\") );\
+new TestCase(   SECTION, eval(\"var TEST_ARRAY = new Array(null, void 0, true, false, 123, new Object(), new Boolean(true) ); TEST_ARRAY.join(void 0)\") );\
+new TestCase(   SECTION, eval(\"var TEST_ARRAY = new Array(null, void 0, true, false, 123, new Object(), new Boolean(true) ); TEST_ARRAY.join()\") );\
+new TestCase(   SECTION, eval(\"var TEST_ARRAY = new Array(true); TEST_ARRAY.join('\\v')\") );\
+SEPARATOR = \"\\t\";\
+new TestCase( SECTION,TEST_ARRAY.join( SEPARATOR ) );\
+");
+lfcode.push("new TestCase( assertEq,   \"String.prototype.toString()\",        \"\",     String.prototype.toString() );\
+new TestCase( SECTION,   \"(new String()).toString()\",          \"\",     (new String()).toString() );\
+new TestCase( SECTION,   \"(new String(\\\"\\\")).toString()\",      \"\",     (new String(\"\")).toString() );\
+new TestCase( SECTION,   \"(new String( String() )).toString()\",\"\",    (new String(String())).toString() );\
+gczeal(4);\
+new TestCase( SECTION,   \"(new String( 0 )).toString()\",       \"0\",    (new String((1))).toString() );\
+");
+while (true) {
+	var file = lfcode.shift(); if (file == undefined) { break; }
+                loadFile(file);
+}
+function loadFile(lfVarx) {
+	try {
+		if (lfVarx.substr(-3) == ".js") {
+		} else if (!isNaN(lfVarx)) {
+			lfRunTypeId = lfVarx;
+		} else {
+			switch (lfRunTypeId) {
+				default: evaluate(lfVarx);
+			}
+		}
+	} catch (lfVare) {}
+}
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -475,32 +475,17 @@ JSCompartment::discardJitCode(FreeOp *fo
      * purge all caches in the JIT scripts. Even if we are not releasing all
      * JIT code, we still need to release code for scripts which are in the
      * middle of a native or getter stub call, as these stubs will have been
      * redirected to the interpoline.
      */
     mjit::ClearAllFrames(this);
 
     if (isPreservingCode()) {
-        for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
-            JSScript *script = i.get<JSScript>();
-
-            /* Discard JM caches. */
-            for (int constructing = 0; constructing <= 1; constructing++) {
-                for (int barriers = 0; barriers <= 1; barriers++) {
-                    mjit::JITScript *jit = script->getJIT((bool) constructing, (bool) barriers);
-                    if (jit)
-                        jit->purgeCaches();
-                }
-            }
-
-            /* Discard Ion caches. */
-            if (script->hasIonScript())
-                script->ion->purgeCaches();
-        }
+        PurgeJITCaches(this);
     } else {
 # ifdef JS_ION
         /* Only mark OSI points if code is being discarded. */
         ion::InvalidateAll(fop, this);
 # endif
         for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
             JSScript *script = i.get<JSScript>();
             mjit::ReleaseScriptCode(fop, script);
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -4536,16 +4536,17 @@ StartVerifyBarriers(JSRuntime *rt)
 
         node = NextNode(node);
     }
 
     rt->gcVerifyData = trc;
     rt->gcIncrementalState = MARK;
     rt->gcMarker.start(rt);
     for (CompartmentsIter c(rt); !c.done(); c.next()) {
+        PurgeJITCaches(c);
         c->setNeedsBarrier(true);
         c->arenas.prepareForIncrementalGC(rt);
     }
 
     return;
 
 oom:
     rt->gcIncrementalState = NO_INCREMENTAL;
@@ -4621,16 +4622,17 @@ EndVerifyBarriers(JSRuntime *rt)
 
     bool compartmentCreated = false;
 
     /* We need to disable barriers before tracing, which may invoke barriers. */
     for (CompartmentsIter c(rt); !c.done(); c.next()) {
         if (!c->needsBarrier())
             compartmentCreated = true;
 
+        PurgeJITCaches(c);
         c->setNeedsBarrier(false);
     }
 
     /*
      * We need to bump gcNumber so that the methodjit knows that jitcode has
      * been discarded.
      */
     JS_ASSERT(trc->number == rt->gcNumber);
@@ -4819,16 +4821,37 @@ PurgePCCounts(JSContext *cx)
 
     if (!rt->scriptAndCountsVector)
         return;
     JS_ASSERT(!rt->profilingScripts);
 
     ReleaseScriptCounts(rt->defaultFreeOp());
 }
 
+void
+PurgeJITCaches(JSCompartment *c)
+{
+    for (CellIterUnderGC i(c, FINALIZE_SCRIPT); !i.done(); i.next()) {
+        JSScript *script = i.get<JSScript>();
+
+        /* Discard JM caches. */
+        for (int constructing = 0; constructing <= 1; constructing++) {
+            for (int barriers = 0; barriers <= 1; barriers++) {
+                mjit::JITScript *jit = script->getJIT((bool) constructing, (bool) barriers);
+                if (jit)
+                    jit->purgeCaches();
+            }
+        }
+
+        /* Discard Ion caches. */
+        if (script->hasIonScript())
+            script->ion->purgeCaches();
+    }
+}
+
 } /* namespace js */
 
 JS_PUBLIC_API(void)
 JS_IterateCompartments(JSRuntime *rt, void *data,
                        JSIterateCompartmentCallback compartmentCallback)
 {
     JS_ASSERT(!rt->gcRunning);
 
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -1111,11 +1111,14 @@ static inline JSCompartment *
 GetObjectCompartment(JSObject *obj) { return reinterpret_cast<js::gc::Cell *>(obj)->compartment(); }
 
 void
 ReleaseAllJITCode(FreeOp *fop, JSCompartment *c, bool resetUseCounts);
 
 void
 ReleaseAllJITCode(FreeOp *fop, bool resetUseCounts);
 
+void
+PurgeJITCaches(JSCompartment *c);
+
 } /* namespace js */
 
 #endif /* jsgc_h___ */