[INFER] Block repeated recursive EnterMethodJIT on the same stack frame from loop backedges, bug 657890.
authorBrian Hackett <bhackett1024@gmail.com>
Wed, 18 May 2011 10:12:06 -0700
changeset 75074 bcd868ff18d4e572c9fba427ee714af42046e327
parent 75073 0b30b3263f8d05a111b5f7192beeade8fcd0a713
child 75075 29bd8523ead93a79c69a4ac5749df438c630a9d0
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
bugs657890
milestone6.0a1
[INFER] Block repeated recursive EnterMethodJIT on the same stack frame from loop backedges, bug 657890.
js/src/jit-test/tests/jaeger/bug657890.js
js/src/methodjit/Compiler.cpp
js/src/methodjit/MethodJIT-inl.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/bug657890.js
@@ -0,0 +1,6 @@
+function f() {};
+var x;
+for(var i=0; i<200; i++) {
+    x = f.bind(x, x, 2);
+    gc();
+}
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -7151,17 +7151,17 @@ mjit::Compiler::testBarrier(RegisterID t
     }
 
 #if 0
     /* Stress test. */
     state.jump.setJump(masm.testInt32(Assembler::NotEqual, typeReg));
     return state;
 #endif
 
-    types::TypeSet *types = pushedTypeSet(0);
+    types::TypeSet *types = script->bytecodeTypes(PC);
     types->addFreeze(cx);
 
     /* Cannot have type barriers when the result of the operation is already unknown. */
     JS_ASSERT(!types->unknown());
 
     state.jump = trySingleTypeTest(types, typeReg);
     if (!state.jump.isSet())
         state.jump.setJump(addTypeTest(types, typeReg, dataReg));
--- a/js/src/methodjit/MethodJIT-inl.h
+++ b/js/src/methodjit/MethodJIT-inl.h
@@ -71,24 +71,43 @@ CanMethodJIT(JSContext *cx, JSScript *sc
     {
         return Compile_Skipped;
     }
     if (status == JITScript_None)
         return TryCompile(cx, fp);
     return Compile_Okay;
 }
 
+static inline bool
+RecursiveMethodJIT(JSContext *cx, StackFrame *fp)
+{
+    /*
+     * We can recursively enter the method JIT on a single stack frame by
+     * taking back edges, compiling, getting kicked back into the interpreter
+     * and repeating. Watch for this case here, and finish the frame in the
+     * interpreter. :XXX: should be more robust.
+     */
+    static const unsigned RECURSIVE_METHODJIT_LIMIT = 10;
+    VMFrame *f = cx->compartment->jaegerCompartment->activeFrame();
+    for (unsigned i = 0; i < RECURSIVE_METHODJIT_LIMIT; i++) {
+        if (!f || f->entryfp != fp)
+            return false;
+        f = f->previous;
+    }
+    return true;
+}
+
 /*
  * Called from a backedge in the interpreter to decide if we should transition to the
  * methodjit. If so, we compile the given function.
  */
 static inline CompileStatus
 CanMethodJITAtBranch(JSContext *cx, JSScript *script, StackFrame *fp, jsbytecode *pc)
 {
-    if (!cx->methodJitEnabled)
+    if (!cx->methodJitEnabled || RecursiveMethodJIT(cx, fp))
         return Compile_Abort;
     JITScriptStatus status = script->getJITStatus(fp->isConstructing());
     if (status == JITScript_Invalid)
         return Compile_Abort;
     if (status == JITScript_None &&
         !cx->hasRunOption(JSOPTION_METHODJIT_ALWAYS) &&
         script->incUseCount() <= USES_BEFORE_COMPILE)
     {