[INFER] Don't check for invariant copy preservation in stack entries popped by REJOIN_NONE calls, bug 684943. r=dvander
authorBrian Hackett <bhackett1024@gmail.com>
Tue, 06 Sep 2011 22:46:01 -0700
changeset 78361 6a8947bcc821f3d7d0859757878f42f88fc74ba5
parent 78360 c2726640029ff54f418ba361e6f330fc37bcc650
child 78362 50d4f6fa00ced827a04e199d77814fcfe25faf5d
push id78
push userclegnitto@mozilla.com
push dateFri, 16 Dec 2011 17:32:24 +0000
treeherdermozilla-release@79d24e644fdd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdvander
bugs684943
milestone9.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
[INFER] Don't check for invariant copy preservation in stack entries popped by REJOIN_NONE calls, bug 684943. r=dvander
js/src/jit-test/tests/jaeger/bug684943.js
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/FastOps.cpp
js/src/methodjit/FrameState.cpp
js/src/methodjit/FrameState.h
js/src/methodjit/LoopState.cpp
js/src/methodjit/LoopState.h
js/src/methodjit/StubCompiler.cpp
js/src/methodjit/StubCompiler.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/bug684943.js
@@ -0,0 +1,7 @@
+
+function foo(x) {
+  for (var i = 0; i < 100; i++) {
+    x.f === i;
+  }
+}
+foo({f:"three"});
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -4051,27 +4051,27 @@ mjit::Compiler::inlineScriptedFunction(u
  */
 void
 mjit::Compiler::addCallSite(const InternalCallSite &site)
 {
     callSites.append(site);
 }
 
 void
-mjit::Compiler::inlineStubCall(void *stub, RejoinState rejoin)
+mjit::Compiler::inlineStubCall(void *stub, RejoinState rejoin, Uses uses)
 {
     DataLabelPtr inlinePatch;
     Call cl = emitStubCall(stub, &inlinePatch);
     InternalCallSite site(masm.callReturnOffset(cl), a->inlineIndex, PC,
                           rejoin, false);
     site.inlinePatch = inlinePatch;
     if (loop && loop->generatingInvariants()) {
         Jump j = masm.jump();
         Label l = masm.label();
-        loop->addInvariantCall(j, l, false, false, callSites.length());
+        loop->addInvariantCall(j, l, false, false, callSites.length(), uses);
     }
     addCallSite(site);
 }
 
 bool
 mjit::Compiler::compareTwoValues(JSContext *cx, JSOp op, const Value &lhs, const Value &rhs)
 {
     JS_ASSERT(lhs.isPrimitive());
--- a/js/src/methodjit/Compiler.h
+++ b/js/src/methodjit/Compiler.h
@@ -483,17 +483,17 @@ class Compiler : public BaseCompiler
 
     CompileStatus compile();
 
     Label getLabel() { return masm.label(); }
     bool knownJump(jsbytecode *pc);
     Label labelOf(jsbytecode *target, uint32 inlineIndex);
     void addCallSite(const InternalCallSite &callSite);
     void addReturnSite();
-    void inlineStubCall(void *stub, RejoinState rejoin);
+    void inlineStubCall(void *stub, RejoinState rejoin, Uses uses);
 
     bool debugMode() { return debugMode_; }
     bool inlining() { return inlining_; }
     bool constructing() { return isConstructing; }
 
     jsbytecode *outerPC() {
         if (a == outer)
             return PC;
@@ -773,24 +773,28 @@ class Compiler : public BaseCompiler
 
     void prepareStubCall(Uses uses);
     Call emitStubCall(void *ptr, DataLabelPtr *pinline);
 };
 
 // Given a stub call, emits the call into the inline assembly path. rejoin
 // indicates how to rejoin should this call trigger expansion/discarding.
 #define INLINE_STUBCALL(stub, rejoin)                                       \
-    inlineStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), rejoin)
+    inlineStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), rejoin, Uses(0))
+#define INLINE_STUBCALL_USES(stub, rejoin, uses)                            \
+    inlineStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), rejoin, uses)
 
 // Given a stub call, emits the call into the out-of-line assembly path.
 // Unlike the INLINE_STUBCALL variant, this returns the Call offset.
 #define OOL_STUBCALL(stub, rejoin)                                          \
-    stubcc.emitStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), rejoin)
+    stubcc.emitStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), rejoin, Uses(0))
+#define OOL_STUBCALL_USES(stub, rejoin, uses)                               \
+    stubcc.emitStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), rejoin, uses)
 
 // Same as OOL_STUBCALL, but specifies a slot depth.
 #define OOL_STUBCALL_LOCAL_SLOTS(stub, rejoin, slots)                       \
-    stubcc.emitStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), rejoin, (slots))
+    stubcc.emitStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), rejoin, Uses(0), (slots))
 
 } /* namespace js */
 } /* namespace mjit */
 
 #endif
 
--- a/js/src/methodjit/FastOps.cpp
+++ b/js/src/methodjit/FastOps.cpp
@@ -629,17 +629,17 @@ mjit::Compiler::jsop_not()
             frame.pop();
             frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, reg);
             break;
           }
 
           default:
           {
             prepareStubCall(Uses(1));
-            INLINE_STUBCALL(stubs::ValueToBoolean, REJOIN_NONE);
+            INLINE_STUBCALL_USES(stubs::ValueToBoolean, REJOIN_NONE, Uses(1));
 
             RegisterID reg = Registers::ReturnReg;
             frame.takeReg(reg);
             masm.xor32(Imm32(1), reg);
 
             frame.pop();
             frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, reg);
             break;
@@ -2339,19 +2339,19 @@ mjit::Compiler::jsop_stricteq(JSOp op)
     }
 
     /* Is it impossible that both Values are ints? */
     if ((lhs->isTypeKnown() && lhs->isNotType(JSVAL_TYPE_INT32)) ||
         (rhs->isTypeKnown() && rhs->isNotType(JSVAL_TYPE_INT32))) {
         prepareStubCall(Uses(2));
 
         if (op == JSOP_STRICTEQ)
-            INLINE_STUBCALL(stubs::StrictEq, REJOIN_NONE);
+            INLINE_STUBCALL_USES(stubs::StrictEq, REJOIN_NONE, Uses(2));
         else
-            INLINE_STUBCALL(stubs::StrictNe, REJOIN_NONE);
+            INLINE_STUBCALL_USES(stubs::StrictNe, REJOIN_NONE, Uses(2));
 
         frame.popn(2);
         frame.pushSynced(JSVAL_TYPE_BOOLEAN);
         return;
     }
 
 #if !defined JS_CPU_ARM && !defined JS_CPU_SPARC
     /* Try an integer fast-path. */
@@ -2393,34 +2393,34 @@ mjit::Compiler::jsop_stricteq(JSOp op)
         masm.set32(cond, testReg, otherReg, resultReg);
     }
 
     frame.unpinReg(testReg);
 
     if (needStub) {
         stubcc.leave();
         if (op == JSOP_STRICTEQ)
-            OOL_STUBCALL(stubs::StrictEq, REJOIN_NONE);
+            OOL_STUBCALL_USES(stubs::StrictEq, REJOIN_NONE, Uses(2));
         else
-            OOL_STUBCALL(stubs::StrictNe, REJOIN_NONE);
+            OOL_STUBCALL_USES(stubs::StrictNe, REJOIN_NONE, Uses(2));
     }
 
     frame.popn(2);
     frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, resultReg);
 
     if (needStub)
         stubcc.rejoin(Changes(1));
 #else
     /* TODO: Port set32() logic to ARM. */
     prepareStubCall(Uses(2));
 
     if (op == JSOP_STRICTEQ)
-        INLINE_STUBCALL(stubs::StrictEq, REJOIN_NONE);
+        INLINE_STUBCALL_USES(stubs::StrictEq, REJOIN_NONE, Uses(2));
     else
-        INLINE_STUBCALL(stubs::StrictNe, REJOIN_NONE);
+        INLINE_STUBCALL_USES(stubs::StrictNe, REJOIN_NONE, Uses(2));
 
     frame.popn(2);
     frame.pushSynced(JSVAL_TYPE_BOOLEAN);
     return;
 #endif
 }
 
 void
--- a/js/src/methodjit/FrameState.cpp
+++ b/js/src/methodjit/FrameState.cpp
@@ -2875,28 +2875,28 @@ FrameState::clearTemporaries()
         forgetAllRegs(fe);
         fe->resetSynced();
     }
 
     temporariesTop = temporaries;
 }
 
 Vector<TemporaryCopy> *
-FrameState::getTemporaryCopies()
+FrameState::getTemporaryCopies(Uses uses)
 {
     /* :XXX: handle OOM */
     Vector<TemporaryCopy> *res = NULL;
 
     for (FrameEntry *fe = temporaries; fe < temporariesTop; fe++) {
         if (!fe->isTracked())
             continue;
         if (fe->isCopied()) {
             for (uint32 i = fe->trackerIndex() + 1; i < tracker.nentries; i++) {
                 FrameEntry *nfe = tracker[i];
-                if (!deadEntry(nfe) && nfe->isCopy() && nfe->copyOf() == fe) {
+                if (!deadEntry(nfe, uses.nuses) && nfe->isCopy() && nfe->copyOf() == fe) {
                     if (!res)
                         res = cx->new_< Vector<TemporaryCopy> >(cx);
                     res->append(TemporaryCopy(addressOf(nfe), addressOf(fe)));
                 }
             }
         }
     }
 
--- a/js/src/methodjit/FrameState.h
+++ b/js/src/methodjit/FrameState.h
@@ -942,18 +942,21 @@ class FrameState
 
     /* Maximum number of analysis temporaries the FrameState can track. */
     static const uint32 TEMPORARY_LIMIT = 10;
 
     uint32 allocTemporary();  /* -1 if limit reached. */
     void clearTemporaries();
     inline FrameEntry *getTemporary(uint32 which);
 
-    /* Return NULL or a new vector with all current copies of temporaries. */
-    Vector<TemporaryCopy> *getTemporaryCopies();
+    /*
+     * Return NULL or a new vector with all current copies of temporaries,
+     * excluding those about to be popped per 'uses'.
+     */
+    Vector<TemporaryCopy> *getTemporaryCopies(Uses uses);
 
     inline void syncAndForgetFe(FrameEntry *fe, bool markSynced = false);
     inline void forgetLoopReg(FrameEntry *fe);
 
     /*
      * Get an address for the specified name access in another script.
      * The compiler owns the result's base register.
      */
--- a/js/src/methodjit/LoopState.cpp
+++ b/js/src/methodjit/LoopState.cpp
@@ -190,25 +190,25 @@ LoopState::addJoin(unsigned index, bool 
 {
     StubJoin r;
     r.index = index;
     r.script = script;
     loopJoins.append(r);
 }
 
 void
-LoopState::addInvariantCall(Jump jump, Label label, bool ool, bool entry, unsigned patchIndex)
+LoopState::addInvariantCall(Jump jump, Label label, bool ool, bool entry, unsigned patchIndex, Uses uses)
 {
     RestoreInvariantCall call;
     call.jump = jump;
     call.label = label;
     call.ool = ool;
     call.entry = entry;
     call.patchIndex = patchIndex;
-    call.temporaryCopies = frame.getTemporaryCopies();
+    call.temporaryCopies = frame.getTemporaryCopies(uses);
 
     restoreInvariantCalls.append(call);
 }
 
 void
 LoopState::flushLoop(StubCompiler &stubcc)
 {
     clearLoopRegisters();
--- a/js/src/methodjit/LoopState.h
+++ b/js/src/methodjit/LoopState.h
@@ -248,17 +248,17 @@ class LoopState : public MacroAssemblerT
     {
         if (uint32(pc - outerScript->code) == lifetime->entry && lifetime->entry != lifetime->head)
             reachedEntryPoint = true;
     }
 
     bool generatingInvariants() { return !skipAnalysis; }
 
     /* Add a call with trailing jump/label, after which invariants need to be restored. */
-    void addInvariantCall(Jump jump, Label label, bool ool, bool entry, unsigned patchIndex);
+    void addInvariantCall(Jump jump, Label label, bool ool, bool entry, unsigned patchIndex, Uses uses);
 
     uint32 headOffset() { return lifetime->head; }
     uint32 getLoopRegs() { return loopRegs.freeMask; }
 
     Jump entryJump() { return entry; }
     uint32 entryOffset() { return lifetime->entry; }
     uint32 backedgeOffset() { return lifetime->backedge; }
 
--- a/js/src/methodjit/StubCompiler.cpp
+++ b/js/src/methodjit/StubCompiler.cpp
@@ -165,23 +165,23 @@ StubCompiler::linkRejoin(Jump j)
 }
 
 typedef JSC::MacroAssembler::RegisterID RegisterID;
 typedef JSC::MacroAssembler::ImmPtr ImmPtr;
 typedef JSC::MacroAssembler::Imm32 Imm32;
 typedef JSC::MacroAssembler::DataLabelPtr DataLabelPtr;
 
 JSC::MacroAssembler::Call
-StubCompiler::emitStubCall(void *ptr, RejoinState rejoin)
+StubCompiler::emitStubCall(void *ptr, RejoinState rejoin, Uses uses)
 {
-    return emitStubCall(ptr, rejoin, frame.totalDepth());
+    return emitStubCall(ptr, rejoin, uses, frame.totalDepth());
 }
 
 JSC::MacroAssembler::Call
-StubCompiler::emitStubCall(void *ptr, RejoinState rejoin, int32 slots)
+StubCompiler::emitStubCall(void *ptr, RejoinState rejoin, Uses uses, int32 slots)
 {
     JaegerSpew(JSpew_Insns, " ---- BEGIN SLOW CALL CODE ---- \n");
     masm.bumpStubCounter(cc.script, cc.PC, Registers::tempCallReg());
     DataLabelPtr inlinePatch;
     Call cl = masm.fallibleVMCall(cx->typeInferenceEnabled(),
                                   ptr, cc.outerPC(), &inlinePatch, slots);
     JaegerSpew(JSpew_Insns, " ---- END SLOW CALL CODE ---- \n");
 
@@ -194,17 +194,17 @@ StubCompiler::emitStubCall(void *ptr, Re
     /* Add a hook for restoring loop invariants if necessary. */
     if (cc.loop && cc.loop->generatingInvariants()) {
         site.loopJumpLabel = masm.label();
         Jump j = masm.jump();
         Label l = masm.label();
         /* MissedBoundsCheck* are not actually called, so f.regs need to be written before InvariantFailure. */
         bool entry = (ptr == JS_FUNC_TO_DATA_PTR(void *, stubs::MissedBoundsCheckEntry))
                   || (ptr == JS_FUNC_TO_DATA_PTR(void *, stubs::MissedBoundsCheckHead));
-        cc.loop->addInvariantCall(j, l, true, entry, cc.callSites.length());
+        cc.loop->addInvariantCall(j, l, true, entry, cc.callSites.length(), uses);
     }
 
     cc.addCallSite(site);
     return cl;
 }
 
 void
 StubCompiler::fixCrossJumps(uint8 *ncode, size_t offset, size_t total)
--- a/js/src/methodjit/StubCompiler.h
+++ b/js/src/methodjit/StubCompiler.h
@@ -132,18 +132,18 @@ class StubCompiler
     void rejoin(Changes changes);
     void linkRejoin(Jump j);
 
     /* Finish all native code patching. */
     void fixCrossJumps(uint8 *ncode, size_t offset, size_t total);
     bool jumpInScript(Jump j, jsbytecode *target);
     unsigned crossJump(Jump j, Label l);
 
-    Call emitStubCall(void *ptr, RejoinState rejoin);
-    Call emitStubCall(void *ptr, RejoinState rejoin, int32 slots);
+    Call emitStubCall(void *ptr, RejoinState rejoin, Uses uses);
+    Call emitStubCall(void *ptr, RejoinState rejoin, Uses uses, int32 slots);
 
     void patchJoin(unsigned i, bool script, Assembler::Address address, AnyRegisterID reg);
 };
 
 } /* namepsace mjit */
 } /* namespace js */
 
 #endif /* jsstub_compiler_h__ */