Bug 1000100 - Baseline postbarrier tidyup r=jandem
authorJon Coppeard <jcoppeard@mozilla.com>
Thu, 01 May 2014 11:34:48 +0100
changeset 181557 7dc742da42106567618c91c0b2b4886e1135c572
parent 181556 7210c4f043a59d153706e443aea8df83ea87e72d
child 181558 d4b2e930ecd52c6be982783ee83a7b0fc68a5918
child 181564 51bc58066ac9fd0897374dbcea763a43303bfc18
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
reviewersjandem
bugs1000100
milestone32.0a1
Bug 1000100 - Baseline postbarrier tidyup r=jandem
js/src/jit/BaselineCompiler.cpp
js/src/jit/BaselineIC.cpp
js/src/jit/CodeGenerator.cpp
js/src/jit/arm/MacroAssembler-arm.cpp
js/src/jit/arm/MacroAssembler-arm.h
js/src/jit/x64/MacroAssembler-x64.cpp
js/src/jit/x64/MacroAssembler-x64.h
js/src/jit/x86/MacroAssembler-x86.cpp
js/src/jit/x86/MacroAssembler-x86.h
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -403,43 +403,47 @@ BaselineCompiler::emitEpilogue()
 
     masm.ret();
     return true;
 }
 
 #ifdef JSGC_GENERATIONAL
 // On input:
 //  R2.scratchReg() contains object being written to.
-//  Otherwise, baseline stack will be synced, so all other registers are usable as scratch.
+//  Called with the baseline stack synced, except for R0 which is preserved.
+//  All other registers are usable as scratch.
 // This calls:
 //    void PostWriteBarrier(JSRuntime *rt, JSObject *obj);
 bool
 BaselineCompiler::emitOutOfLinePostBarrierSlot()
 {
     masm.bind(&postBarrierSlot_);
 
     Register objReg = R2.scratchReg();
     GeneralRegisterSet regs(GeneralRegisterSet::All());
+    regs.take(R0);
     regs.take(objReg);
     regs.take(BaselineFrameReg);
     Register scratch = regs.takeAny();
 #if defined(JS_CODEGEN_ARM)
     // On ARM, save the link register before calling.  It contains the return
     // address.  The |masm.ret()| later will pop this into |pc| to return.
     masm.push(lr);
 #elif defined(JS_CODEGEN_MIPS)
     masm.push(ra);
 #endif
+    masm.pushValue(R0);
 
     masm.setupUnalignedABICall(2, scratch);
     masm.movePtr(ImmPtr(cx->runtime()), scratch);
     masm.passABIArg(scratch);
     masm.passABIArg(objReg);
     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, PostWriteBarrier));
 
+    masm.popValue(R0);
     masm.ret();
     return true;
 }
 #endif // JSGC_GENERATIONAL
 
 bool
 BaselineCompiler::emitIC(ICStub *stub, ICEntry::Kind kind)
 {
@@ -2091,26 +2095,25 @@ BaselineCompiler::emit_JSOP_SETALIASEDVA
 
     getScopeCoordinateObject(objReg);
     Address address = getScopeCoordinateAddressFromObject(objReg, R1.scratchReg());
     masm.patchableCallPreBarrier(address, MIRType_Value);
     masm.storeValue(R0, address);
     frame.push(R0);
 
 #ifdef JSGC_GENERATIONAL
-    // Fully sync the stack if post-barrier is needed.
+    // Only R0 is live at this point.
     // Scope coordinate object is already in R2.scratchReg().
-    frame.syncStack(0);
     Register temp = R1.scratchReg();
 
     Label skipBarrier;
-    masm.branchTestObject(Assembler::NotEqual, R0, &skipBarrier);
-    masm.branchPtrInNurseryRange(objReg, temp, &skipBarrier);
-
-    masm.call(&postBarrierSlot_);
+    masm.branchPtrInNurseryRange(Assembler::Equal, objReg, temp, &skipBarrier);
+    masm.branchValueIsNurseryObject(Assembler::NotEqual, R0, temp, &skipBarrier);
+
+    masm.call(&postBarrierSlot_); // Won't clobber R0
 
     masm.bind(&skipBarrier);
 #endif
 
     return true;
 }
 
 bool
@@ -2456,29 +2459,32 @@ BaselineCompiler::emitFormalArgAccess(ui
 
     // Load/store the argument.
     Address argAddr(reg, ArgumentsData::offsetOfArgs() + arg * sizeof(Value));
     if (get) {
         masm.loadValue(argAddr, R0);
         frame.push(R0);
     } else {
         masm.patchableCallPreBarrier(argAddr, MIRType_Value);
-        storeValue(frame.peek(-1), argAddr, R0);
+        masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
+        masm.storeValue(R0, argAddr);
 
 #ifdef JSGC_GENERATIONAL
-        // Fully sync the stack if post-barrier is needed.
-        frame.syncStack(0);
+        MOZ_ASSERT(frame.numUnsyncedSlots() == 0);
+
         Register temp = R1.scratchReg();
 
         // Reload the arguments object
         Register reg = R2.scratchReg();
         masm.loadPtr(Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfArgsObj()), reg);
 
         Label skipBarrier;
-        masm.branchPtrInNurseryRange(reg, temp, &skipBarrier);
+
+        masm.branchPtrInNurseryRange(Assembler::Equal, reg, temp, &skipBarrier);
+        masm.branchValueIsNurseryObject(Assembler::NotEqual, R0, temp, &skipBarrier);
 
         masm.call(&postBarrierSlot_);
 
         masm.bind(&skipBarrier);
 #endif
     }
 
     masm.bind(&done);
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -729,26 +729,19 @@ ICStubCompiler::emitProfilingUpdate(Macr
     emitProfilingUpdate(masm, regs.takeAny(), regs.takeAny(), stubPcOffset);
 }
 
 #ifdef JSGC_GENERATIONAL
 inline bool
 ICStubCompiler::emitPostWriteBarrierSlot(MacroAssembler &masm, Register obj, ValueOperand val,
                                          Register scratch, GeneralRegisterSet saveRegs)
 {
-    Nursery &nursery = cx->runtime()->gc.nursery;
-
     Label skipBarrier;
-    masm.branchTestObject(Assembler::NotEqual, val, &skipBarrier);
-
-    masm.branchPtrInNurseryRange(obj, scratch, &skipBarrier);
-
-    Register valReg = masm.extractObject(val, scratch);
-    masm.branchPtr(Assembler::Below, valReg, ImmWord(nursery.start()), &skipBarrier);
-    masm.branchPtr(Assembler::AboveOrEqual, valReg, ImmWord(nursery.heapEnd()), &skipBarrier);
+    masm.branchPtrInNurseryRange(Assembler::Equal, obj, scratch, &skipBarrier);
+    masm.branchValueIsNurseryObject(Assembler::NotEqual, val, scratch, &skipBarrier);
 
     // void PostWriteBarrier(JSRuntime *rt, JSObject *obj);
 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
     saveRegs.add(BaselineTailCallReg);
 #endif
     saveRegs = GeneralRegisterSet::Intersect(saveRegs, GeneralRegisterSet::Volatile());
     masm.PushRegsInMask(saveRegs);
     masm.setupUnalignedABICall(2, scratch);
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -1870,20 +1870,21 @@ CodeGenerator::visitPostWriteBarrierO(LP
     Register temp = ToTempRegisterOrInvalid(lir->temp());
 
     if (lir->object()->isConstant()) {
 #ifdef DEBUG
         const Nursery &nursery = GetIonContext()->runtime->gcNursery();
         JS_ASSERT(!nursery.isInside(&lir->object()->toConstant()->toObject()));
 #endif
     } else {
-        masm.branchPtrInNurseryRange(ToRegister(lir->object()), temp, ool->rejoin());
-    }
-
-    masm.branchPtrInNurseryRange(ToRegister(lir->value()), temp, ool->entry());
+        masm.branchPtrInNurseryRange(Assembler::Equal, ToRegister(lir->object()), temp,
+                                     ool->rejoin());
+    }
+
+    masm.branchPtrInNurseryRange(Assembler::Equal, ToRegister(lir->value()), temp, ool->entry());
 
     masm.bind(ool->rejoin());
 #endif
     return true;
 }
 
 bool
 CodeGenerator::visitPostWriteBarrierV(LPostWriteBarrierV *lir)
@@ -1896,21 +1897,22 @@ CodeGenerator::visitPostWriteBarrierV(LP
     Register temp = ToTempRegisterOrInvalid(lir->temp());
 
     if (lir->object()->isConstant()) {
 #ifdef DEBUG
         const Nursery &nursery = GetIonContext()->runtime->gcNursery();
         JS_ASSERT(!nursery.isInside(&lir->object()->toConstant()->toObject()));
 #endif
     } else {
-        masm.branchPtrInNurseryRange(ToRegister(lir->object()), temp, ool->rejoin());
+        masm.branchPtrInNurseryRange(Assembler::Equal, ToRegister(lir->object()), temp,
+                                     ool->rejoin());
     }
 
     ValueOperand value = ToValue(lir, LPostWriteBarrierV::Input);
-    masm.branchValueIsNurseryObject(value, temp, ool->entry());
+    masm.branchValueIsNurseryObject(Assembler::Equal, value, temp, ool->entry());
 
     masm.bind(ool->rejoin());
 #endif
     return true;
 }
 
 bool
 CodeGenerator::visitCallNative(LCallNative *call)
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -4345,33 +4345,39 @@ MacroAssemblerARMCompat::jumpWithPatch(R
     // pool entry that the instruction loads from.
     CodeOffsetJump ret(bo.getOffset(), pe.encode());
     return ret;
 }
 
 #ifdef JSGC_GENERATIONAL
 
 void
-MacroAssemblerARMCompat::branchPtrInNurseryRange(Register ptr, Register temp, Label *label)
-{
+MacroAssemblerARMCompat::branchPtrInNurseryRange(Condition cond, Register ptr, Register temp,
+                                                 Label *label)
+{
+    JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
     JS_ASSERT(ptr != temp);
     JS_ASSERT(ptr != secondScratchReg_);
 
     const Nursery &nursery = GetIonContext()->runtime->gcNursery();
     uintptr_t startChunk = nursery.start() >> Nursery::ChunkShift;
 
     ma_mov(Imm32(startChunk), secondScratchReg_);
     as_rsb(secondScratchReg_, secondScratchReg_, lsr(ptr, Nursery::ChunkShift));
-    branch32(Assembler::Below, secondScratchReg_, Imm32(Nursery::NumNurseryChunks), label);
-}
-
-void
-MacroAssemblerARMCompat::branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label)
-{
+    branch32(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual,
+              secondScratchReg_, Imm32(Nursery::NumNurseryChunks), label);
+}
+
+void
+MacroAssemblerARMCompat::branchValueIsNurseryObject(Condition cond, ValueOperand value,
+                                                    Register temp, Label *label)
+{
+    JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
+
     Label done;
 
-    branchTestObject(Assembler::NotEqual, value, &done);
-    branchPtrInNurseryRange(value.payloadReg(), temp, label);
+    branchTestObject(Assembler::NotEqual, value, cond == Assembler::Equal ? &done : label);
+    branchPtrInNurseryRange(cond, value.payloadReg(), temp, label);
 
     bind(&done);
 }
 
 #endif
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -1594,18 +1594,18 @@ class MacroAssemblerARMCompat : public M
         return as_cmp(bounded, Imm8(0));
     }
 
     void moveFloat32(FloatRegister src, FloatRegister dest) {
         as_vmov(VFPRegister(src).singleOverlay(), VFPRegister(dest).singleOverlay());
     }
 
 #ifdef JSGC_GENERATIONAL
-    void branchPtrInNurseryRange(Register ptr, Register temp, Label *label);
-    void branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label);
+    void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label *label);
+    void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label *label);
 #endif
 };
 
 typedef MacroAssemblerARMCompat MacroAssemblerSpecific;
 
 } // namespace jit
 } // namespace js
 
--- a/js/src/jit/x64/MacroAssembler-x64.cpp
+++ b/js/src/jit/x64/MacroAssembler-x64.cpp
@@ -365,32 +365,38 @@ MacroAssemblerX64::handleFailureWithHand
     loadPtr(Address(esp, offsetof(ResumeFromException, bailoutInfo)), r9);
     mov(ImmWord(BAILOUT_RETURN_OK), rax);
     jmp(Operand(rsp, offsetof(ResumeFromException, target)));
 }
 
 #ifdef JSGC_GENERATIONAL
 
 void
-MacroAssemblerX64::branchPtrInNurseryRange(Register ptr, Register temp, Label *label)
+MacroAssemblerX64::branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label *label)
 {
+    JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
     JS_ASSERT(ptr != temp);
     JS_ASSERT(ptr != ScratchReg);
 
     const Nursery &nursery = GetIonContext()->runtime->gcNursery();
     movePtr(ImmWord(-ptrdiff_t(nursery.start())), ScratchReg);
     addPtr(ptr, ScratchReg);
-    branchPtr(Assembler::Below, ScratchReg, Imm32(Nursery::NurserySize), label);
+    branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual,
+              ScratchReg, Imm32(Nursery::NurserySize), label);
 }
 
 void
-MacroAssemblerX64::branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label)
+MacroAssemblerX64::branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp,
+                                              Label *label)
 {
+    JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
+
     // 'Value' representing the start of the nursery tagged as a JSObject
     const Nursery &nursery = GetIonContext()->runtime->gcNursery();
     Value start = ObjectValue(*reinterpret_cast<JSObject *>(nursery.start()));
 
     movePtr(ImmWord(-ptrdiff_t(start.asRawBits())), ScratchReg);
     addPtr(value.valueReg(), ScratchReg);
-    branchPtr(Assembler::Below, ScratchReg, Imm32(Nursery::NurserySize), label);
+    branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual,
+              ScratchReg, Imm32(Nursery::NurserySize), label);
 }
 
 #endif
--- a/js/src/jit/x64/MacroAssembler-x64.h
+++ b/js/src/jit/x64/MacroAssembler-x64.h
@@ -1329,18 +1329,18 @@ class MacroAssemblerX64 : public MacroAs
         ((int32_t *)nextInsn)[-1] = target - nextInsn;
     }
     void memIntToValue(Address Source, Address Dest) {
         load32(Source, ScratchReg);
         storeValue(JSVAL_TYPE_INT32, ScratchReg, Dest);
     }
 
 #ifdef JSGC_GENERATIONAL
-    void branchPtrInNurseryRange(Register ptr, Register temp, Label *label);
-    void branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label);
+    void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label *label);
+    void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label *label);
 #endif
 };
 
 typedef MacroAssemblerX64 MacroAssemblerSpecific;
 
 } // namespace jit
 } // namespace js
 
--- a/js/src/jit/x86/MacroAssembler-x86.cpp
+++ b/js/src/jit/x86/MacroAssembler-x86.cpp
@@ -385,31 +385,37 @@ MacroAssemblerX86::branchTestValue(Condi
         cmpl(value.typeReg(), Imm32(jv.s.tag));
         j(NotEqual, label);
     }
 }
 
 #ifdef JSGC_GENERATIONAL
 
 void
-MacroAssemblerX86::branchPtrInNurseryRange(Register ptr, Register temp, Label *label)
+MacroAssemblerX86::branchPtrInNurseryRange(Condition cond, Register ptr, Register temp,
+                                           Label *label)
 {
+    JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
     JS_ASSERT(ptr != temp);
     JS_ASSERT(temp != InvalidReg);  // A temp register is required for x86.
 
     const Nursery &nursery = GetIonContext()->runtime->gcNursery();
     movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp);
     addPtr(ptr, temp);
-    branchPtr(Assembler::Below, temp, Imm32(Nursery::NurserySize), label);
+    branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual,
+              temp, Imm32(Nursery::NurserySize), label);
 }
 
 void
-MacroAssemblerX86::branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label)
+MacroAssemblerX86::branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp,
+                                              Label *label)
 {
+    JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
+
     Label done;
 
-    branchTestObject(Assembler::NotEqual, value, &done);
-    branchPtrInNurseryRange(value.payloadReg(), temp, label);
+    branchTestObject(Assembler::NotEqual, value, cond == Assembler::Equal ? &done : label);
+    branchPtrInNurseryRange(cond, value.payloadReg(), temp, label);
 
     bind(&done);
 }
 
 #endif
--- a/js/src/jit/x86/MacroAssembler-x86.h
+++ b/js/src/jit/x86/MacroAssembler-x86.h
@@ -1119,18 +1119,18 @@ class MacroAssemblerX86 : public MacroAs
 
     // Save an exit frame to the thread data of the current thread, given a
     // register that holds a PerThreadData *.
     void linkParallelExitFrame(const Register &pt) {
         movl(StackPointer, Operand(pt, offsetof(PerThreadData, jitTop)));
     }
 
 #ifdef JSGC_GENERATIONAL
-    void branchPtrInNurseryRange(Register ptr, Register temp, Label *label);
-    void branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label);
+    void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label *label);
+    void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label *label);
 #endif
 };
 
 typedef MacroAssemblerX86 MacroAssemblerSpecific;
 
 } // namespace jit
 } // namespace js