Bug 798819 - Ensure the EnterJIT thunk exists when using FastInvoke. r=dvander
authorJan de Mooij <jdemooij@mozilla.com>
Sat, 06 Oct 2012 15:39:04 -0700
changeset 109535 3fd916a2c18cdfbaac9f9f2fe31d34f6a46f7d55
parent 109534 416a9b587ba84ed872022a7c87335e1c4b9cb9d9
child 109536 d3afcd4f3cc0f29bdf87e57417a3a85c8c801b51
push id23631
push userphilringnalda@gmail.com
push dateSun, 07 Oct 2012 05:11:15 +0000
treeherdermozilla-central@ecd4c4304219 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdvander
bugs798819
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
Bug 798819 - Ensure the EnterJIT thunk exists when using FastInvoke. r=dvander
js/src/ion/Ion.cpp
js/src/ion/Ion.h
js/src/jit-test/tests/ion/bug798819.js
js/src/jsinterpinlines.h
--- a/js/src/ion/Ion.cpp
+++ b/js/src/ion/Ion.cpp
@@ -181,21 +181,16 @@ IonCompartment::mark(JSTracer *trc, JSCo
 
     bool mustMarkEnterJIT = false;
     for (IonActivationIterator iter(trc->runtime); iter.more(); ++iter) {
         IonActivation *activation = iter.activation();
 
         if (activation->compartment() != compartment)
             continue;
 
-        // Activations may be tied to the Method JIT, in which case enterJIT
-        // is not present on the activation's call stack.
-        if (!activation->entryfp() || activation->entryfp()->callingIntoIon())
-            continue;
-
         // Both OSR and normal function calls depend on the EnterJIT code
         // existing for entrance and exit.
         mustMarkEnterJIT = true;
     }
 
     // These must be available if we could be running JIT code; they are not
     // traced as normal through IonCode or IonScript objects
     if (mustMarkEnterJIT)
@@ -1287,16 +1282,38 @@ ion::CanEnter(JSContext *cx, HandleScrip
         return Method_Error;
 
     if (!script->ion)
         return Method_Skipped;
 
     return Method_Compiled;
 }
 
+MethodStatus
+ion::CanEnterUsingFastInvoke(JSContext *cx, HandleScript script)
+{
+    JS_ASSERT(ion::IsEnabled(cx));
+
+    // Skip if the code is expected to result in a bailout.
+    if (!script->hasIonScript() || script->ion->bailoutExpected())
+        return Method_Skipped;
+
+    if (!cx->compartment->ensureIonCompartmentExists(cx))
+        return Method_Error;
+
+    // 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)
+        return Method_Skipped;
+
+    return Method_Compiled;
+}
+
 static IonExecStatus
 EnterIon(JSContext *cx, StackFrame *fp, void *jitcode)
 {
     JS_CHECK_RECURSION(cx, return IonExec_Error);
     JS_ASSERT(ion::IsEnabled(cx));
     JS_ASSERT(CheckFrame(fp));
     JS_ASSERT(!fp->script()->ion->bailoutExpected());
 
--- a/js/src/ion/Ion.h
+++ b/js/src/ion/Ion.h
@@ -221,16 +221,17 @@ bool InitializeIon();
 // Get and set the current Ion context.
 IonContext *GetIonContext();
 
 bool SetIonContext(IonContext *ctx);
 
 MethodStatus CanEnterAtBranch(JSContext *cx, HandleScript script,
                               StackFrame *fp, jsbytecode *pc);
 MethodStatus CanEnter(JSContext *cx, HandleScript script, StackFrame *fp, bool newType);
+MethodStatus CanEnterUsingFastInvoke(JSContext *cx, HandleScript script);
 
 enum IonExecStatus
 {
     IonExec_Error,
     IonExec_Ok,
     IonExec_Bailout
 };
 
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug798819.js
@@ -0,0 +1,10 @@
+if (!this.gcPreserveCode)
+    gcPreserveCode = function() {};
+this.toString = (function() {
+  x.filter(function() {})
+});
+x = [0, 0, 0, 0, 0, 0, 0];
+gcPreserveCode()
+print(this)
+gc();
+this + ''
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -1026,25 +1026,30 @@ class FastInvokeGuard
         return args_;
     }
 
     bool invoke(JSContext *cx) {
 #ifdef JS_ION
         if (useIon_ && fun_) {
             JS_ASSERT(fun_->script() == script_);
 
-            if (script_->hasIonScript() && !script_->ion->bailoutExpected()) {
+            ion::MethodStatus status = ion::CanEnterUsingFastInvoke(cx, script_);
+            if (status == ion::Method_Error)
+                return false;
+            if (status == ion::Method_Compiled) {
                 ion::IonExecStatus result = ion::FastInvoke(cx, fun_, args_);
                 if (result == ion::IonExec_Error)
                     return false;
 
                 JS_ASSERT(result == ion::IonExec_Ok);
                 return true;
             }
 
+            JS_ASSERT(status == ion::Method_Skipped);
+
             if (script_->canIonCompile()) {
                 // This script is not yet hot. Since calling into Ion is much
                 // faster here, bump the use count a bit to account for this.
                 script_->incUseCount(5);
             }
         }
 #endif