From 37e2c4a150203d5435f8d2db609577890cbba749 Mon Sep 17 00:00:00 2001 From: Kannan Vijayan Date: Wed, 29 May 2013 16:02:02 -0400 Subject: [PATCH] Bug 831507 - Add generational-gc post-write barriers to baseline compiler. r=jandem --- js/src/gc/Nursery.h | 4 + js/src/ion/BaselineCompiler.cpp | 94 ++++++++++++++++-- js/src/ion/BaselineCompiler.h | 8 ++ js/src/ion/BaselineHelpers.h | 4 +- js/src/ion/BaselineIC.cpp | 170 +++++++++++++++++++++++++++----- js/src/ion/BaselineIC.h | 22 ++++- 6 files changed, 265 insertions(+), 37 deletions(-) diff --git a/js/src/gc/Nursery.h b/js/src/gc/Nursery.h index 274ae09f707e..d4f4bf1fd73c 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 bfe377ba46a5..6793d76d01ba 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 b79ecc61e7ea..c1da8aa4dbb7 100644 --- a/js/src/ion/BaselineCompiler.h +++ b/js/src/ion/BaselineCompiler.h @@ -171,6 +171,9 @@ class BaselineCompiler : public BaselineCompilerSpecific { FixedList