[INFER] Sync 'this' fe when testing for primitive return in functions which return a value with unknown type, bug 678141.
authorBrian Hackett <bhackett1024@gmail.com>
Fri, 12 Aug 2011 09:18:48 -0700
changeset 76120 409b62513ac6ad4a1c2287376fb59ead21fe7550
parent 76119 0a8195cb7590cc4c803adced8fea4c1f99b34c03
child 76121 07361922fd67f3678cd65f29e9369c54f552a2f7
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
bugs678141
milestone8.0a1
[INFER] Sync 'this' fe when testing for primitive return in functions which return a value with unknown type, bug 678141.
js/src/jit-test/tests/jaeger/bug678141.js
js/src/methodjit/Compiler.cpp
js/src/methodjit/FrameState-inl.h
js/src/methodjit/FrameState.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/bug678141.js
@@ -0,0 +1,10 @@
+
+c = {}.__proto__[1] = 3;
+(function() {
+    function b(a) {
+        return a
+    }
+    for each(let z in [{}]) {
+        print(new b(z))
+    }
+})()
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -779,39 +779,39 @@ mjit::Compiler::generatePrologue()
                                                    StackFrame::OVERFLOW_ARGS |
                                                    StackFrame::HAS_ARGS_OBJ));
             masm.storePtr(ImmPtr((void *) script->function()->nargs),
                           Address(JSFrameReg, StackFrame::offsetOfArgs()));
             hasArgs.linkTo(masm.label(), &masm);
         }
     }
 
+    if (cx->typeInferenceEnabled()) {
+#ifdef DEBUG
+        if (script->hasFunction) {
+            prepareStubCall(Uses(0));
+            INLINE_STUBCALL(stubs::AssertArgumentTypes, REJOIN_NONE);
+        }
+#endif
+        ensureDoubleArguments();
+    }
+
     if (isConstructing) {
         if (!constructThis())
             return Compile_Error;
     }
 
     if (debugMode()) {
         prepareStubCall(Uses(0));
         INLINE_STUBCALL(stubs::ScriptDebugPrologue, REJOIN_RESUME);
     } else if (Probes::callTrackingActive(cx)) {
         prepareStubCall(Uses(0));
         INLINE_STUBCALL(stubs::ScriptProbeOnlyPrologue, REJOIN_RESUME);
     }
 
-    if (cx->typeInferenceEnabled()) {
-#ifdef DEBUG
-        if (script->hasFunction) {
-            prepareStubCall(Uses(0));
-            INLINE_STUBCALL(stubs::AssertArgumentTypes, REJOIN_NONE);
-        }
-#endif
-        ensureDoubleArguments();
-    }
-
     recompileCheckHelper();
 
     if (outerScript->pcCounters) {
         size_t length = ssa.frameLength(ssa.numFrames() - 1);
         pcLengths = (PCLengthEntry *) cx->calloc_(sizeof(pcLengths[0]) * length);
         if (!pcLengths)
             return Compile_Error;
     }
@@ -2943,17 +2943,19 @@ mjit::Compiler::fixPrimitiveReturn(Assem
 
     // If the type is known to be an object, just load the return value as normal.
     if (fe && fe->isTypeKnown() && fe->getKnownType() == JSVAL_TYPE_OBJECT) {
         loadReturnValue(masm, fe);
         return;
     }
 
     // There's a return value, and its type is unknown. Test the type and load
-    // |thisv| if necessary.
+    // |thisv| if necessary. Sync the 'this' entry before doing so, as it may
+    // be stored in registers if we constructed it inline.
+    frame.syncThis();
     loadReturnValue(masm, fe);
     Jump j = masm->testObject(Assembler::Equal, JSReturnReg_Type);
     masm->loadValueAsComponents(thisv, JSReturnReg_Type, JSReturnReg_Data);
     j.linkTo(masm->label(), masm);
 }
 
 // Loads the return value into the scripted ABI register pair, such that JS
 // semantics in constructors are preserved.
--- a/js/src/methodjit/FrameState-inl.h
+++ b/js/src/methodjit/FrameState-inl.h
@@ -1310,34 +1310,37 @@ FrameState::pushThis()
 }
 
 void
 FrameState::learnThisIsObject(bool unsync)
 {
     // If the 'this' object is a copy, this must be an inline frame, in which
     // case we will trigger recompilation if the 'this' entry isn't actually
     // an object (thus, it is OK to modify the backing directly).
-    FrameEntry *fe = a->this_;
-    if (!fe->isTracked())
-        addToTracker(fe);
+    FrameEntry *fe = getThis();
     if (fe->isCopy())
         fe = fe->copyOf();
     learnType(fe, JSVAL_TYPE_OBJECT, unsync);
 }
 
 void
 FrameState::setThis(RegisterID reg)
 {
-    FrameEntry *fe = a->this_;
-    if (!fe->isTracked())
-        addToTracker(fe);
+    FrameEntry *fe = getThis();
     JS_ASSERT(!fe->isCopy());
     learnType(fe, JSVAL_TYPE_OBJECT, reg);
 }
 
+void
+FrameState::syncThis()
+{
+    FrameEntry *fe = getThis();
+    syncFe(fe);
+}
+
 inline void
 FrameState::leaveBlock(uint32 n)
 {
     popn(n);
 }
 
 inline void
 FrameState::enterBlock(uint32 n)
--- a/js/src/methodjit/FrameState.h
+++ b/js/src/methodjit/FrameState.h
@@ -388,16 +388,17 @@ class FrameState
     // Pushes a copy of a slot (formal argument, local variable, or stack slot)
     // onto the operation stack.
     void pushLocal(uint32 n);
     void pushArg(uint32 n);
     void pushCallee();
     void pushThis();
     void pushCopyOf(FrameEntry *fe);
     inline void setThis(RegisterID reg);
+    inline void syncThis();
     inline void learnThisIsObject(bool unsync = true);
 
     inline FrameEntry *getStack(uint32 slot);
     inline FrameEntry *getLocal(uint32 slot);
     inline FrameEntry *getArg(uint32 slot);
     inline FrameEntry *getSlotEntry(uint32 slot);
 
     /*