Bug 776748 - Do not invalidate ionScript when JM is invalidated. r=dvander
☠☠ backed out by 41f66d0e46b3 ☠ ☠
authorNicolas B. Pierron <nicolas.b.pierron@mozilla.com>
Tue, 24 Jul 2012 17:48:47 -0700
changeset 102080 eef915d5a18f
parent 102079 2af804d84437
child 102081 41f66d0e46b3
push id1143
push usernpierron@mozilla.com
push date2012-07-25 00:57 +0000
reviewersdvander
bugs776748
milestone17.0a1
Bug 776748 - Do not invalidate ionScript when JM is invalidated. r=dvander
js/src/ion/Ion.cpp
js/src/jit-test/tests/ion/bug776748.js
--- a/js/src/ion/Ion.cpp
+++ b/js/src/ion/Ion.cpp
@@ -1204,21 +1204,23 @@ InvalidateActivation(FreeOp *fop, uint8 
         if (!script->hasIonScript())
             continue;
 
         if (!invalidateAll && !script->ion->invalidated())
             continue;
 
         // This frame needs to be invalidated. We do the following:
         //
-        // 1. Determine safepoint that corresponds to the current call.
-        // 2. From safepoint, get distance to the OSI-patchable offset.
-        // 3. From the IonScript, determine the distance between the
+        // 1. Increment the reference counter to keep the ionScript alive
+        //    for the invalidation bailout or for the exception handler.
+        // 2. Determine safepoint that corresponds to the current call.
+        // 3. From safepoint, get distance to the OSI-patchable offset.
+        // 4. From the IonScript, determine the distance between the
         //    call-patchable offset and the invalidation epilogue.
-        // 4. Patch the OSI point with a call-relative to the
+        // 5. Patch the OSI point with a call-relative to the
         //    invalidation epilogue.
         //
         // The code generator ensures that there's enough space for us
         // to patch in a call-relative operation at each invalidation
         // point.
         //
         // Note: you can't simplify this mechanism to "just patch the
         // instruction immediately after the call" because things may
@@ -1285,17 +1287,19 @@ ion::Invalidate(FreeOp *fop, const Vecto
     for (size_t i = 0; i < invalid.length(); i++) {
         const types::CompilerOutput &co = invalid[i];
         JS_ASSERT(co.isValid());
         if (co.isIon()) {
             JS_ASSERT(co.script->hasIonScript() && co.out.ion == co.script->ionScript());
             IonSpew(IonSpew_Invalidate, " Invalidate %s:%u, IonScript %p",
                     co.script->filename, co.script->lineno, co.out.ion);
 
-            // Cause the IonScript to be invalidated in InvalidateActivation.
+            // Keep the ion script alive during the invalidation and flag this
+            // ionScript as being invalidated.  This increment is removed by the
+            // loop after the calls to InvalidateActivation.
             co.out.ion->incref();
             anyInvalidation = true;
         }
     }
 
     if (!anyInvalidation) {
         IonSpew(IonSpew_Invalidate, " No IonScript invalidation.");
         return;
@@ -1303,30 +1307,32 @@ ion::Invalidate(FreeOp *fop, const Vecto
 
     for (IonActivationIterator iter(fop->runtime()); iter.more(); ++iter)
         InvalidateActivation(fop, iter.top(), false);
 
     // Drop the references added above. If a script was never active, its
     // IonScript will be immediately destroyed. Otherwise, it will be held live
     // until its last invalidated frame is destroyed.
     for (size_t i = 0; i < invalid.length(); i++) {
-        if (invalid[i].script->hasIonScript()) {
-            JSScript *script = invalid[i].script;
-            IonScript *ionScript = script->ion;
+        const types::CompilerOutput &co = invalid[i];
+        JS_ASSERT(co.isValid());
+        if (co.isIon()) {
+            JSScript *script = co.script;
+            IonScript *ionScript = co.out.ion;
 
             JSCompartment *compartment = script->compartment();
             if (compartment->needsBarrier()) {
                 // We're about to remove edges from the JSScript to gcthings
                 // embedded in the IonScript. Perform one final trace of the
                 // IonScript for the incremental GC, as it must know about
                 // those edges.
                 IonScript::Trace(compartment->barrierTracer(), ionScript);
             }
 
-            script->ion->decref(fop);
+            co.out.ion->decref(fop);
             script->ion = NULL;
         }
     }
 
     // Wait for the scripts to get warm again before doing another compile,
     // unless we are recompiling *because* a script got hot.
     if (resetUses) {
         for (size_t i = 0; i < invalid.length(); i++)
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug776748.js
@@ -0,0 +1,23 @@
+var eCount = 0;
+var funs = [function () {}, function () {}];
+function someElement(a) {
+    ++eCount;
+    var i = (eCount >= 8) ? 1 : 0;
+    return a[i]
+}
+var recursionGuard = 0;
+function recursiveThing() {
+    someElement(funs);
+    if (++recursionGuard % 2) {
+        e1();
+    }
+}
+function e1() {
+    try {} catch (e) {}
+    someElement(funs);
+    recursiveThing()
+}
+recursiveThing()
+gc();
+recursiveThing()
+recursiveThing()