diff --git a/js/src/gc/Nursery.h b/js/src/gc/Nursery.h index 274ae09f707..d4f4bf1fd73 100644 --- a/js/src/gc/Nursery.h +++ b/js/src/gc/Nursery.h @@ -27,6 +27,8 @@ class MinorCollectionTracer; namespace ion { class CodeGenerator; class MacroAssembler; +class ICStubCompiler; +class BaselineCompiler; } class Nursery @@ -189,6 +191,8 @@ class Nursery friend class gc::MinorCollectionTracer; friend class ion::CodeGenerator; friend class ion::MacroAssembler; + friend class ion::ICStubCompiler; + friend class ion::BaselineCompiler; }; } /* namespace js */ diff --git a/js/src/ion/BaselineCompiler.cpp b/js/src/ion/BaselineCompiler.cpp index bfe377ba46a..6793d76d01b 100644 --- a/js/src/ion/BaselineCompiler.cpp +++ b/js/src/ion/BaselineCompiler.cpp @@ -23,6 +23,9 @@ using namespace js::ion; BaselineCompiler::BaselineCompiler(JSContext *cx, HandleScript script) : BaselineCompilerSpecific(cx, script), return_(new HeapLabel()) +#ifdef JSGC_GENERATIONAL + , postBarrierSlot_(new HeapLabel()) +#endif { } @@ -90,6 +93,11 @@ BaselineCompiler::compile() if (!emitEpilogue()) return Method_Error; +#ifdef JSGC_GENERATIONAL + if (!emitOutOfLinePostBarrierSlot()) + return Method_Error; +#endif + if (masm.oom()) return Method_Error; @@ -264,6 +272,40 @@ BaselineCompiler::emitEpilogue() 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_); + + Register objReg = R2.scratchReg(); + GeneralRegisterSet regs(GeneralRegisterSet::All()); + regs.take(objReg); + regs.take(BaselineFrameReg); + Register scratch = regs.takeAny(); +#if defined(JS_CPU_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); +#endif + + masm.setupUnalignedABICall(2, scratch); + masm.movePtr(ImmWord(cx->runtime), scratch); + masm.passABIArg(scratch); + masm.passABIArg(objReg); + masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, PostWriteBarrier)); + + masm.ret(); + return true; +} +#endif // JSGC_GENERATIONAL + bool BaselineCompiler::emitIC(ICStub *stub, bool isForOp) { @@ -1676,23 +1718,36 @@ BaselineCompiler::emit_JSOP_DELPROP() return true; } -Address -BaselineCompiler::getScopeCoordinateAddress(Register reg) +void +BaselineCompiler::getScopeCoordinateObject(Register reg) { ScopeCoordinate sc(pc); masm.loadPtr(frame.addressOfScopeChain(), reg); for (unsigned i = sc.hops; i; i--) masm.extractObject(Address(reg, ScopeObject::offsetOfEnclosingScope()), reg); +} +Address +BaselineCompiler::getScopeCoordinateAddressFromObject(Register objReg, Register reg) +{ + ScopeCoordinate sc(pc); Shape *shape = ScopeCoordinateToStaticScopeShape(cx, script, pc); + Address addr; if (shape->numFixedSlots() <= sc.slot) { - masm.loadPtr(Address(reg, JSObject::offsetOfSlots()), reg); + masm.loadPtr(Address(objReg, JSObject::offsetOfSlots()), reg); return Address(reg, (sc.slot - shape->numFixedSlots()) * sizeof(Value)); } - return Address(reg, JSObject::getFixedSlotOffset(sc.slot)); + return Address(objReg, JSObject::getFixedSlotOffset(sc.slot)); +} + +Address +BaselineCompiler::getScopeCoordinateAddress(Register reg) +{ + getScopeCoordinateObject(reg); + return getScopeCoordinateAddressFromObject(reg, reg); } bool @@ -1720,13 +1775,34 @@ BaselineCompiler::emit_JSOP_CALLALIASEDVAR() bool BaselineCompiler::emit_JSOP_SETALIASEDVAR() { - // Sync everything except the top value, so that we can use R0 as scratch - // (storeValue does not touch it if the top value is in R0). - frame.syncStack(1); + // Keep rvalue in R0. + frame.popRegsAndSync(1); + Register objReg = R2.scratchReg(); - Address address = getScopeCoordinateAddress(R2.scratchReg()); + getScopeCoordinateObject(objReg); + Address address = getScopeCoordinateAddressFromObject(objReg, R1.scratchReg()); masm.patchableCallPreBarrier(address, MIRType_Value); - storeValue(frame.peek(-1), address, R0); + 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); + + 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.end()), &skipBarrier); + + masm.bind(&isTenured); + masm.call(postBarrierSlot_); + + masm.bind(&skipBarrier); +#endif + return true; } diff --git a/js/src/ion/BaselineCompiler.h b/js/src/ion/BaselineCompiler.h index b79ecc61e7e..c1da8aa4dbb 100644 --- a/js/src/ion/BaselineCompiler.h +++ b/js/src/ion/BaselineCompiler.h @@ -171,6 +171,9 @@ class BaselineCompiler : public BaselineCompilerSpecific { FixedList