Bug 988950 - Add a macro assembler instruction to check if a pointer is in the nursery r=jandem
authorJon Coppeard <jcoppeard@mozilla.com>
Wed, 23 Apr 2014 13:48:35 +0100
changeset 180113 b72e6cc2357400d932efd7cae75c4766984b06f8
parent 180112 116fabfb50b5b219ea274a52ec6bdc2bb67c99f8
child 180114 13d60930dab2b563e9bdd9564f54775588914bf5
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
reviewersjandem
bugs988950
milestone31.0a1
Bug 988950 - Add a macro assembler instruction to check if a pointer is in the nursery r=jandem
js/src/jit/BaselineCompiler.cpp
js/src/jit/BaselineIC.cpp
js/src/jit/CodeGenerator.cpp
js/src/jit/IonMacroAssembler.cpp
js/src/jit/IonMacroAssembler.h
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -411,17 +411,16 @@ BaselineCompiler::emitEpilogue()
 
     masm.ret();
     return true;
 }
 
 #ifdef JSGC_GENERATIONAL
 // On input:
 //  R2.scratchReg() contains object being written to.
-//  R1.scratchReg() contains slot index being written to.
 //  Otherwise, baseline stack will be synced, so all other registers are usable as scratch.
 // This calls:
 //    void PostWriteBarrier(JSRuntime *rt, JSObject *obj);
 bool
 BaselineCompiler::emitOutOfLinePostBarrierSlot()
 {
     masm.bind(&postBarrierSlot_);
 
@@ -2096,25 +2095,23 @@ BaselineCompiler::emit_JSOP_SETALIASEDVA
     masm.patchableCallPreBarrier(address, MIRType_Value);
     masm.storeValue(R0, address);
     frame.push(R0);
 
 #ifdef JSGC_GENERATIONAL
     // Fully sync the stack if post-barrier is needed.
     // Scope coordinate object is already in R2.scratchReg().
     frame.syncStack(0);
+    Register temp = R1.scratchReg();
 
     Nursery &nursery = cx->runtime()->gcNursery;
     Label skipBarrier;
-    Label isTenured;
     masm.branchTestObject(Assembler::NotEqual, R0, &skipBarrier);
-    masm.branchPtr(Assembler::Below, objReg, ImmWord(nursery.start()), &isTenured);
-    masm.branchPtr(Assembler::Below, objReg, ImmWord(nursery.heapEnd()), &skipBarrier);
-
-    masm.bind(&isTenured);
+    masm.branchPtrInNurseryRange(objReg, temp, &skipBarrier);
+
     masm.call(&postBarrierSlot_);
 
     masm.bind(&skipBarrier);
 #endif
 
     return true;
 }
 
@@ -2414,28 +2411,26 @@ BaselineCompiler::emitFormalArgAccess(ui
         frame.push(R0);
     } else {
         masm.patchableCallPreBarrier(argAddr, MIRType_Value);
         storeValue(frame.peek(-1), argAddr, R0);
 
 #ifdef JSGC_GENERATIONAL
         // Fully sync the stack if post-barrier is needed.
         frame.syncStack(0);
+        Register temp = R1.scratchReg();
 
         // Reload the arguments object
         Register reg = R2.scratchReg();
         masm.loadPtr(Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfArgsObj()), reg);
 
         Nursery &nursery = cx->runtime()->gcNursery;
         Label skipBarrier;
-        Label isTenured;
-        masm.branchPtr(Assembler::Below, reg, ImmWord(nursery.start()), &isTenured);
-        masm.branchPtr(Assembler::Below, reg, ImmWord(nursery.heapEnd()), &skipBarrier);
-
-        masm.bind(&isTenured);
+        masm.branchPtrInNurseryRange(reg, temp, &skipBarrier);
+
         masm.call(&postBarrierSlot_);
 
         masm.bind(&skipBarrier);
 #endif
     }
 
     masm.bind(&done);
     return true;
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -733,20 +733,17 @@ inline bool
 ICStubCompiler::emitPostWriteBarrierSlot(MacroAssembler &masm, Register obj, ValueOperand val,
                                          Register scratch, GeneralRegisterSet saveRegs)
 {
     Nursery &nursery = cx->runtime()->gcNursery;
 
     Label skipBarrier;
     masm.branchTestObject(Assembler::NotEqual, val, &skipBarrier);
 
-    Label isTenured;
-    masm.branchPtr(Assembler::Below, obj, ImmWord(nursery.start()), &isTenured);
-    masm.branchPtr(Assembler::Below, obj, ImmWord(nursery.heapEnd()), &skipBarrier);
-    masm.bind(&isTenured);
+    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);
 
     // void PostWriteBarrier(JSRuntime *rt, JSObject *obj);
 #ifdef JS_CODEGEN_ARM
     saveRegs.add(BaselineTailCallReg);
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -1826,67 +1826,51 @@ CodeGenerator::visitOutOfLineCallPostWri
 bool
 CodeGenerator::visitPostWriteBarrierO(LPostWriteBarrierO *lir)
 {
 #ifdef JSGC_GENERATIONAL
     OutOfLineCallPostWriteBarrier *ool = new(alloc()) OutOfLineCallPostWriteBarrier(lir, lir->object());
     if (!addOutOfLineCode(ool))
         return false;
 
-    const Nursery &nursery = GetIonContext()->runtime->gcNursery();
     Register temp = ToRegister(lir->temp());
 
     if (lir->object()->isConstant()) {
+        const Nursery &nursery = GetIonContext()->runtime->gcNursery();
         JS_ASSERT(!nursery.isInside(&lir->object()->toConstant()->toObject()));
     } else {
-        Register objreg = ToRegister(lir->object());
-        masm.movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp);
-        masm.addPtr(objreg, temp);
-        masm.branchPtr(Assembler::Below, temp, Imm32(Nursery::NurserySize), ool->rejoin());
-    }
-
-    Register valuereg = ToRegister(lir->value());
-    masm.movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp);
-    masm.addPtr(valuereg, temp);
-    masm.branchPtr(Assembler::Below, temp, Imm32(Nursery::NurserySize), ool->entry());
+        masm.branchPtrInNurseryRange(ToRegister(lir->object()), temp, ool->rejoin());
+    }
+
+    masm.branchPtrInNurseryRange(ToRegister(lir->value()), temp, ool->entry());
 
     masm.bind(ool->rejoin());
 #endif
     return true;
 }
 
 bool
 CodeGenerator::visitPostWriteBarrierV(LPostWriteBarrierV *lir)
 {
 #ifdef JSGC_GENERATIONAL
     OutOfLineCallPostWriteBarrier *ool = new(alloc()) OutOfLineCallPostWriteBarrier(lir, lir->object());
     if (!addOutOfLineCode(ool))
         return false;
 
-    const Nursery &nursery = GetIonContext()->runtime->gcNursery();
+    Register temp = ToRegister(lir->temp());
 
     if (lir->object()->isConstant()) {
+        const Nursery &nursery = GetIonContext()->runtime->gcNursery();
         JS_ASSERT(!nursery.isInside(&lir->object()->toConstant()->toObject()));
     } else {
-        Register temp = ToRegister(lir->temp());
-        Register objreg = ToRegister(lir->object());
-        masm.movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp);
-        masm.addPtr(objreg, temp);
-        masm.branchPtr(Assembler::Below, temp, Imm32(Nursery::NurserySize), ool->rejoin());
+        masm.branchPtrInNurseryRange(ToRegister(lir->object()), temp, ool->rejoin());
     }
 
     ValueOperand value = ToValue(lir, LPostWriteBarrierV::Input);
-    masm.branchTestObject(Assembler::NotEqual, value, ool->rejoin());
-
-    // This section is a little different because we mustn't trash the temp
-    // register before we use its contents.
-    Register temp = ToRegister(lir->temp());
-    masm.unboxObject(value, temp);
-    masm.addPtr(ImmWord(-ptrdiff_t(nursery.start())), temp);
-    masm.branchPtr(Assembler::Below, temp, Imm32(Nursery::NurserySize), ool->entry());
+    masm.branchValueIsNurseryObject(value, temp, ool->entry());
 
     masm.bind(ool->rejoin());
 #endif
     return true;
 }
 
 bool
 CodeGenerator::visitCallNative(LCallNative *call)
--- a/js/src/jit/IonMacroAssembler.cpp
+++ b/js/src/jit/IonMacroAssembler.cpp
@@ -1781,8 +1781,45 @@ MacroAssembler::spsUnmarkJit(SPSProfiler
     Label spsNotEnabled;
     pop(temp); // -4: Was the profiler enabled.
     branchTest32(Assembler::Equal, temp, temp, &spsNotEnabled);
 
     spsPopFrameSafe(p, temp);
 
     bind(&spsNotEnabled);
 }
+
+#ifdef JSGC_GENERATIONAL
+
+void
+MacroAssembler::branchPtrInNurseryRange(Register ptr, Register temp, Label *label)
+{
+    JS_ASSERT(ptr != temp);
+    JS_ASSERT(temp != InvalidReg);
+
+    const Nursery &nursery = GetIonContext()->runtime->gcNursery();
+    movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp);
+    addPtr(ptr, temp);
+    branchPtr(Assembler::Below, temp, Imm32(Nursery::NurserySize), label);
+}
+
+void
+MacroAssembler::branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label)
+{
+    Label done;
+
+    branchTestObject(Assembler::NotEqual, value, &done);
+
+    Register obj = extractObject(value, temp);
+    // valobj and temp may be the same register, in which case we mustn't trash it
+    // before we use its contents.
+    if (obj == temp) {
+        const Nursery &nursery = GetIonContext()->runtime->gcNursery();
+        addPtr(ImmWord(-ptrdiff_t(nursery.start())), obj);
+        branchPtr(Assembler::Below, obj, Imm32(Nursery::NurserySize), label);
+    } else {
+        branchPtrInNurseryRange(obj, temp, label);
+    }
+
+    bind(&done);
+}
+
+#endif
--- a/js/src/jit/IonMacroAssembler.h
+++ b/js/src/jit/IonMacroAssembler.h
@@ -1347,16 +1347,21 @@ class MacroAssembler : public MacroAssem
                                               IntConversion_ClampToUint8);
     }
     void clampTypedOrValueToUint8(TypedOrValueRegister src, FloatRegister temp, Register output,
                                   Label *fail)
     {
         convertTypedOrValueToInt(src, temp, output, fail, IntConversion_ClampToUint8);
     }
 
+#ifdef JSGC_GENERATIONAL
+    void branchPtrInNurseryRange(Register ptr, Register temp, Label *label);
+    void branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label);
+#endif
+
   public:
     class AfterICSaveLive {
         friend class MacroAssembler;
         AfterICSaveLive(uint32_t initialStack)
 #ifdef JS_DEBUG
           : initialStack(initialStack)
 #endif
         {}