Invalidate scripts when forbidding compilation (bug 792552, r=jandem).
authorDavid Anderson <danderson@mozilla.com>
Fri, 21 Sep 2012 16:41:23 -0700
changeset 107769 c914225fc39adfa6e9865fea3002a67eca84e211
parent 107768 6fd36867bac751417fce03468cbe2c771810f24c
child 107770 d3319e868a9275aba607378ab8df1399eee9d9a0
push id15211
push userdanderson@mozilla.com
push dateFri, 21 Sep 2012 23:48:59 +0000
treeherdermozilla-inbound@c914225fc39a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs792552
milestone18.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
Invalidate scripts when forbidding compilation (bug 792552, r=jandem).
js/src/ion/Ion.cpp
js/src/ion/Ion.h
js/src/ion/VMFunctions.cpp
js/src/jsfun.cpp
--- a/js/src/ion/Ion.cpp
+++ b/js/src/ion/Ion.cpp
@@ -1042,17 +1042,17 @@ IonCompile(JSContext *cx, JSScript *scri
     return true;
 }
 
 bool
 TestIonCompile(JSContext *cx, JSScript *script, JSFunction *fun, jsbytecode *osrPc, bool constructing)
 {
     if (!IonCompile<TestCompiler>(cx, script, fun, osrPc, constructing)) {
         if (!cx->isExceptionPending())
-            ForbidCompilation(script);
+            ForbidCompilation(cx, script);
         return false;
     }
     return true;
 }
 
 static bool
 CheckFrame(StackFrame *fp)
 {
@@ -1197,26 +1197,26 @@ ion::CanEnterAtBranch(JSContext *cx, Han
         return Method_Skipped;
 
     // Optionally ignore on user request.
     if (!js_IonOptions.osr)
         return Method_Skipped;
 
     // Mark as forbidden if frame can't be handled.
     if (!CheckFrame(fp)) {
-        ForbidCompilation(script);
+        ForbidCompilation(cx, script);
         return Method_CantCompile;
     }
 
     // Attempt compilation. Returns Method_Compiled if already compiled.
     JSFunction *fun = fp->isFunctionFrame() ? fp->fun() : NULL;
     MethodStatus status = Compile<TestCompiler>(cx, script, fun, pc, false);
     if (status != Method_Compiled) {
         if (status == Method_CantCompile)
-            ForbidCompilation(script);
+            ForbidCompilation(cx, script);
         return status;
     }
 
     if (script->ion->osrPc() != pc)
         return Method_Skipped;
 
     // This can GC, so afterward, script->ion is not guaranteed to be valid.
     if (!cx->compartment->ionCompartment()->enterJIT(cx))
@@ -1253,26 +1253,26 @@ ion::CanEnter(JSContext *cx, HandleScrip
         RootedObject obj(cx, js_CreateThisForFunction(cx, callee, newType));
         if (!obj)
             return Method_Skipped;
         fp->functionThis().setObject(*obj);
     }
 
     // Mark as forbidden if frame can't be handled.
     if (!CheckFrame(fp)) {
-        ForbidCompilation(script);
+        ForbidCompilation(cx, script);
         return Method_CantCompile;
     }
 
     // Attempt compilation. Returns Method_Compiled if already compiled.
     JSFunction *fun = fp->isFunctionFrame() ? fp->fun() : NULL;
     MethodStatus status = Compile<TestCompiler>(cx, script, fun, NULL, fp->isConstructing());
     if (status != Method_Compiled) {
         if (status == Method_CantCompile)
-            ForbidCompilation(script);
+            ForbidCompilation(cx, script);
         return status;
     }
 
     // This can GC, so afterward, script->ion is not guaranteed to be valid.
     if (!cx->compartment->ionCompartment()->enterJIT(cx))
         return Method_Error;
 
     if (!script->ion)
@@ -1629,17 +1629,19 @@ ion::Invalidate(JSContext *cx, const Vec
 }
 
 bool
 ion::Invalidate(JSContext *cx, JSScript *script, bool resetUses)
 {
     JS_ASSERT(script->hasIonScript());
 
     Vector<types::RecompileInfo> scripts(cx);
-    scripts.append(script->ionScript()->recompileInfo());
+    if (!scripts.append(script->ionScript()->recompileInfo()))
+        return false;
+
     Invalidate(cx, scripts, resetUses);
     return true;
 }
 
 void
 ion::FinishInvalidation(FreeOp *fop, JSScript *script)
 {
     if (!script->hasIonScript())
@@ -1662,27 +1664,29 @@ ion::FinishInvalidation(FreeOp *fop, JSS
 
 void
 ion::MarkFromIon(JSCompartment *comp, Value *vp)
 {
     gc::MarkValueUnbarriered(comp->barrierTracer(), vp, "write barrier");
 }
 
 void
-ion::ForbidCompilation(JSScript *script)
+ion::ForbidCompilation(JSContext *cx, JSScript *script)
 {
     IonSpew(IonSpew_Abort, "Disabling Ion compilation of script %s:%d",
             script->filename, script->lineno);
 
-    if (script->hasIonScript() && script->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(script->compartment()->barrierTracer(), script->ion);
+    if (script->hasIonScript()) {
+        // It is only safe to modify script->ion if the script is not currently
+        // running, because IonFrameIterator needs to tell what ionScript to
+        // use (either the one on the JSScript, or the one hidden in the
+        // breadcrumbs Invalidation() leaves). Therefore, if invalidation
+        // fails, we cannot disable the script.
+        if (!Invalidate(cx, script, false))
+            return;
     }
 
     script->ion = ION_DISABLED_SCRIPT;
 }
 
 uint32_t
 ion::UsesBeforeIonRecompile(JSScript *script, jsbytecode *pc)
 {
--- a/js/src/ion/Ion.h
+++ b/js/src/ion/Ion.h
@@ -247,16 +247,16 @@ void AttachFinishedCompilations(JSContex
 void FinishOffThreadBuilder(IonBuilder *builder);
 bool TestIonCompile(JSContext *cx, JSScript *script, JSFunction *fun, jsbytecode *osrPc, bool constructing);
 
 static inline bool IsEnabled(JSContext *cx)
 {
     return cx->hasRunOption(JSOPTION_ION) && cx->typeInferenceEnabled();
 }
 
-void ForbidCompilation(JSScript *script);
+void ForbidCompilation(JSContext *cx, JSScript *script);
 uint32_t UsesBeforeIonRecompile(JSScript *script, jsbytecode *pc);
 
 } // namespace ion
 } // namespace js
 
 #endif // jsion_ion_h__
 
--- a/js/src/ion/VMFunctions.cpp
+++ b/js/src/ion/VMFunctions.cpp
@@ -34,24 +34,23 @@ InvokeFunction(JSContext *cx, JSFunction
 
     // In order to prevent massive bouncing between Ion and JM, see if we keep
     // hitting functions that are uncompilable.
     
     if (fun->isInterpreted() && !fun->script()->canIonCompile()) {
         JSScript *script = GetTopIonJSScript(cx);
         if (script->hasIonScript() && ++script->ion->slowCallCount >= js_IonOptions.slowCallLimit) {
             AutoFlushCache afc("InvokeFunction");
-            Invalidate(cx, script, false);
 
-            // Finally, poison the script so we don't try to run it again
-            ForbidCompilation(script);
+            // Poison the script so we don't try to run it again. This will
+            // trigger invalidation.
+            ForbidCompilation(cx, script);
         }
     }
 
-
     // TI will return false for monitorReturnTypes, meaning there is no
     // TypeBarrier or Monitor instruction following this. However, we need to
     // explicitly monitor if the callee has not been analyzed yet. We special
     // case this to avoid the cost of ion::GetPcScript if we must take this
     // path frequently.
     bool needsMonitor = ShouldMonitorReturnType(fun);
 
     // Data in the argument vector is arranged for a JIT -> JIT call.
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -126,17 +126,17 @@ fun_getProperty(JSContext *cx, HandleObj
 
 #ifdef JS_ION
         // If this script hasn't been compiled yet, make sure it will never
         // be compiled. IonMonkey does not guarantee |f.arguments| can be
         // fully recovered, so we try to mitigate observing this behavior by
         // detecting its use early.
         JSScript *script = iter.script();
         if (!script->hasIonScript())
-            ion::ForbidCompilation(script);
+            ion::ForbidCompilation(cx, script);
 #endif
 
         vp.setObject(*argsobj);
         return true;
     }
 
 #ifdef JS_METHODJIT
     if (iter.isScript() && iter.isIon())