[JAEGER] Fixed bugs when LOCALINC and friends took slow paths (bug 584607, r=sstangl).
authorDavid Anderson <danderson@mozilla.com>
Fri, 06 Aug 2010 18:44:31 -0700
changeset 49509 787e350635450e889d7e593d788fad19ef9f647e
parent 49508 df19134dafb6cf2700c27dfe35f4b93a66322ab9
child 49510 92c4c89c5ba8846ba65e0e3a9396909fd7c8e2a9
push id455
push userdanderson@mozilla.com
push dateSat, 07 Aug 2010 01:44:48 +0000
reviewerssstangl
bugs584607
milestone2.0b3pre
[JAEGER] Fixed bugs when LOCALINC and friends took slow paths (bug 584607, r=sstangl).
js/src/methodjit/FastOps.cpp
js/src/methodjit/FrameState-inl.h
js/src/methodjit/StubCalls.cpp
js/src/methodjit/StubCalls.h
js/src/methodjit/StubCompiler.cpp
--- a/js/src/methodjit/FastOps.cpp
+++ b/js/src/methodjit/FastOps.cpp
@@ -936,17 +936,17 @@ mjit::Compiler::jsop_andor(JSOp op, jsby
     booleanJumpScript(op, target);
 }
 
 void
 mjit::Compiler::jsop_localinc(JSOp op, uint32 slot, bool popped)
 {
     bool post = (op == JSOP_LOCALINC || op == JSOP_LOCALDEC);
     int32 amt = (op == JSOP_INCLOCAL || op == JSOP_LOCALINC) ? 1 : -1;
-    uint32 depth = frame.stackDepth();
+    uint32 ndefs = 1;
 
     frame.pushLocal(slot);
 
     FrameEntry *fe = frame.peek(-1);
 
     if (fe->isConstant() && fe->getValue().isPrimitive()) {
         Value v = fe->getValue();
         double d;
@@ -963,55 +963,69 @@ mjit::Compiler::jsop_localinc(JSOp op, u
         if (popped)
             frame.pop();
         return;
     }
 
     if (post && !popped) {
         frame.dup();
         fe = frame.peek(-1);
+        ndefs++;
     }
 
     if (!fe->isTypeKnown() || fe->getKnownType() != JSVAL_TYPE_INT32) {
         /* :TODO: do something smarter for the known-type-is-bad case. */
         if (fe->isTypeKnown()) {
             Jump j = masm.jump();
-            stubcc.linkExit(j, Uses(0));
+            stubcc.linkExit(j, Uses(ndefs));
         } else {
             Jump intFail = frame.testInt32(Assembler::NotEqual, fe);
-            stubcc.linkExit(intFail, Uses(0));
+            stubcc.linkExit(intFail, Uses(ndefs));
         }
     }
 
-    RegisterID reg = frame.ownRegForData(fe);
-    frame.pop();
+    RegisterID reg = frame.copyDataIntoReg(fe);
 
     Jump ovf;
     if (amt > 0)
         ovf = masm.branchAdd32(Assembler::Overflow, Imm32(1), reg);
     else
         ovf = masm.branchSub32(Assembler::Overflow, Imm32(1), reg);
-    stubcc.linkExit(ovf, Uses(0));
+    stubcc.linkExit(ovf, Uses(ndefs));
 
     /* Note, stub call will push original value again no matter what. */
     stubcc.leave();
-    stubcc.masm.addPtr(Imm32(sizeof(Value) * slot + sizeof(JSStackFrame)),
-                       JSFrameReg,
-                       Registers::ArgReg1);
-    stubcc.vpInc(op, depth);
 
+    stubcc.masm.move(Imm32(slot), Registers::ArgReg1);
+    if (post && !popped) {
+        if (op == JSOP_LOCALINC)
+            stubcc.call(stubs::LocalInc);
+        else
+            stubcc.call(stubs::LocalDec);
+    } else {
+        if (op == JSOP_LOCALINC || op == JSOP_INCLOCAL)
+            stubcc.call(stubs::IncLocal);
+        else
+            stubcc.call(stubs::DecLocal);
+    }
+
+    frame.pop();
     frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
     frame.storeLocal(slot, post || popped, false);
 
-    if (post || popped)
-        frame.pop();
-    else
+    if (popped) {
+        /* No value will be observed. */
+        frame.popn(ndefs);
+    } else {
+        if (post)
+            frame.pop();
         frame.forgetType(frame.peek(-1));
+    }
 
-    stubcc.rejoin(Changes((post || popped) ? 0 : 1));
+    stubcc.rejoin(Changes((post || popped) ? 1 : 0));
 }
 
 void
 mjit::Compiler::jsop_arginc(JSOp op, uint32 slot, bool popped)
 {
     int amt = (js_CodeSpec[op].format & JOF_INC) ? 1 : -1;
     bool post = !!(js_CodeSpec[op].format & JOF_POST);
     uint32 depth = frame.stackDepth();
--- a/js/src/methodjit/FrameState-inl.h
+++ b/js/src/methodjit/FrameState-inl.h
@@ -512,16 +512,19 @@ FrameState::syncData(const FrameEntry *f
     } else {
         masm.storePayload(fe->data.reg(), to);
     }
 }
 
 inline void
 FrameState::forgetType(FrameEntry *fe)
 {
+    if (!fe->isTypeKnown())
+        return;
+
     JS_ASSERT(fe->isTypeKnown() && !fe->type.synced());
     syncType(fe, addressOf(fe), masm);
     fe->type.setMemory();
 }
 
 inline void
 FrameState::learnType(FrameEntry *fe, JSValueType type)
 {
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -789,16 +789,58 @@ stubs::DecVp(VMFrame &f, Value *vp)
 void JS_FASTCALL
 stubs::IncVp(VMFrame &f, Value *vp)
 {
     if (!PreInc<1>(f, vp))
         THROW();
 }
 
 void JS_FASTCALL
+stubs::LocalInc(VMFrame &f, uint32 slot)
+{
+    double d;
+    if (!ValueToNumber(f.cx, f.regs.sp[-2], &d))
+        THROW();
+    f.regs.sp[-2].setNumber(d);
+    f.regs.sp[-1].setNumber(d + 1);
+    f.fp->slots()[slot] = f.regs.sp[-1];
+}
+
+void JS_FASTCALL
+stubs::LocalDec(VMFrame &f, uint32 slot)
+{
+    double d;
+    if (!ValueToNumber(f.cx, f.regs.sp[-2], &d))
+        THROW();
+    f.regs.sp[-2].setNumber(d);
+    f.regs.sp[-1].setNumber(d - 1);
+    f.fp->slots()[slot] = f.regs.sp[-1];
+}
+
+void JS_FASTCALL
+stubs::IncLocal(VMFrame &f, uint32 slot)
+{
+    double d;
+    if (!ValueToNumber(f.cx, f.regs.sp[-1], &d))
+        THROW();
+    f.regs.sp[-1].setNumber(d + 1);
+    f.fp->slots()[slot] = f.regs.sp[-1];
+}
+
+void JS_FASTCALL
+stubs::DecLocal(VMFrame &f, uint32 slot)
+{
+    double d;
+    if (!ValueToNumber(f.cx, f.regs.sp[-1], &d))
+        THROW();
+    f.regs.sp[-1].setNumber(d - 1);
+    f.fp->slots()[slot] = f.regs.sp[-1];
+}
+
+void JS_FASTCALL
 stubs::DefFun(VMFrame &f, uint32 index)
 {
     bool doSet;
     JSObject *pobj, *obj2;
     JSProperty *prop;
     uint32 old;
 
     JSContext *cx = f.cx;
--- a/js/src/methodjit/StubCalls.h
+++ b/js/src/methodjit/StubCalls.h
@@ -123,16 +123,20 @@ void JS_FASTCALL Arguments(VMFrame &f);
 void JS_FASTCALL ArgSub(VMFrame &f, uint32 n);
 void JS_FASTCALL EnterBlock(VMFrame &f, JSObject *obj);
 void JS_FASTCALL LeaveBlock(VMFrame &f);
 
 void JS_FASTCALL VpInc(VMFrame &f, Value *vp);
 void JS_FASTCALL VpDec(VMFrame &f, Value *vp);
 void JS_FASTCALL DecVp(VMFrame &f, Value *vp);
 void JS_FASTCALL IncVp(VMFrame &f, Value *vp);
+void JS_FASTCALL LocalInc(VMFrame &f, uint32 slot);
+void JS_FASTCALL LocalDec(VMFrame &f, uint32 slot);
+void JS_FASTCALL IncLocal(VMFrame &f, uint32 slot);
+void JS_FASTCALL DecLocal(VMFrame &f, uint32 slot);
 
 JSBool JS_FASTCALL LessThan(VMFrame &f);
 JSBool JS_FASTCALL LessEqual(VMFrame &f);
 JSBool JS_FASTCALL GreaterThan(VMFrame &f);
 JSBool JS_FASTCALL GreaterEqual(VMFrame &f);
 JSBool JS_FASTCALL Equal(VMFrame &f);
 JSBool JS_FASTCALL NotEqual(VMFrame &f);
 
--- a/js/src/methodjit/StubCompiler.cpp
+++ b/js/src/methodjit/StubCompiler.cpp
@@ -209,35 +209,31 @@ JSC::MacroAssembler::Call
 StubCompiler::vpInc(JSOp op, uint32 depth)
 {
     uint32 slots = depth + script->nfixed;
 
     VoidVpStub stub = NULL;
     switch (op) {
       case JSOP_GLOBALINC:
       case JSOP_ARGINC:
-      case JSOP_LOCALINC:
         stub = stubs::VpInc;
         break;
 
       case JSOP_GLOBALDEC:
       case JSOP_ARGDEC:
-      case JSOP_LOCALDEC:
         stub = stubs::VpDec;
         break;
 
       case JSOP_INCGLOBAL:
       case JSOP_INCARG:
-      case JSOP_INCLOCAL:
         stub = stubs::IncVp;
         break;
 
       case JSOP_DECGLOBAL:
       case JSOP_DECARG:
-      case JSOP_DECLOCAL:
         stub = stubs::DecVp;
         break;
 
       default:
         JS_NOT_REACHED("unknown incdec op");
         break;
     }