tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 6d4f3606ee01ab3fdc46acb2e27ca65e6ccf1ec1
parent b2358de489029d15290ea1cd1d69b7a76ce588bc
Author: Iain Ireland <iireland@mozilla.com>
Date:   Fri, 19 Dec 2025 21:32:12 +0000

Bug 2007015: Check value before target in post-barrier r=spidermonkey-reviewers,dminor

This is a ~5% improvement in a microbenchmark that stores a mixture of GC things and non-GC things:

```
let os = [{x: 0}, {x:0}];

function foo(n) {
  for (var i = 0; i < n; i++) {
    os[i % 2].x = i % 2 ? {} : 0;
  }
}

foo(2000);

let start = performance.now();
foo(100000000);
print(performance.now() - start);
```

I don't see any significant wins on JS3/SP3 in CI, but it doesn't seem like it can hurt.

Differential Revision: https://phabricator.services.mozilla.com/D277217

Diffstat:
Mjs/src/jit/BaselineCodeGen.cpp | 10+++++-----
Mjs/src/jit/CodeGenerator.cpp | 31++++++++++++++++---------------
Mjs/src/wasm/WasmGC.cpp | 8++++----
3 files changed, 25 insertions(+), 24 deletions(-)

diff --git a/js/src/jit/BaselineCodeGen.cpp b/js/src/jit/BaselineCodeGen.cpp @@ -4021,8 +4021,8 @@ bool BaselineCompilerCodeGen::emit_SetAliasedVar() { // R2.scratchReg() has the scope coordinate object. Label skipBarrier; - masm.branchPtrInNurseryChunk(Assembler::Equal, objReg, temp, &skipBarrier); masm.branchValueIsNurseryCell(Assembler::NotEqual, R0, temp, &skipBarrier); + masm.branchPtrInNurseryChunk(Assembler::Equal, objReg, temp, &skipBarrier); // Uses R2.scratchReg() as input masm.call(&postBarrierSlot_); // Won't clobber R0 @@ -4088,9 +4088,9 @@ bool BaselineInterpreterCodeGen::emit_SetAliasedVar() { // Post barrier. Label skipBarrier; - masm.branchPtrInNurseryChunk(Assembler::Equal, env, scratch1, &skipBarrier); masm.branchValueIsNurseryCell(Assembler::NotEqual, R2, scratch1, &skipBarrier); + masm.branchPtrInNurseryChunk(Assembler::Equal, env, scratch1, &skipBarrier); { // Post barrier code expects the object in R2. masm.movePtr(env, R2.scratchReg()); @@ -4434,8 +4434,8 @@ bool BaselineCompilerCodeGen::emitFormalArgAccess(JSOp op) { Label skipBarrier; - masm.branchPtrInNurseryChunk(Assembler::Equal, reg, temp, &skipBarrier); masm.branchValueIsNurseryCell(Assembler::NotEqual, R0, temp, &skipBarrier); + masm.branchPtrInNurseryChunk(Assembler::Equal, reg, temp, &skipBarrier); masm.call(&postBarrierSlot_); @@ -4486,8 +4486,8 @@ bool BaselineInterpreterCodeGen::emitFormalArgAccess(JSOp op) { masm.loadPtr(frame.addressOfArgsObj(), reg); Register temp = R1.scratchReg(); - masm.branchPtrInNurseryChunk(Assembler::Equal, reg, temp, &done); masm.branchValueIsNurseryCell(Assembler::NotEqual, R0, temp, &done); + masm.branchPtrInNurseryChunk(Assembler::Equal, reg, temp, &done); masm.call(&postBarrierSlot_); } @@ -6737,8 +6737,8 @@ bool BaselineCodeGen<Handler>::emit_InitHomeObject() { masm.storeValue(R0, addr); Label skipBarrier; - masm.branchPtrInNurseryChunk(Assembler::Equal, func, temp, &skipBarrier); masm.branchValueIsNurseryCell(Assembler::NotEqual, R0, temp, &skipBarrier); + masm.branchPtrInNurseryChunk(Assembler::Equal, func, temp, &skipBarrier); masm.call(&postBarrierSlot_); masm.bind(&skipBarrier); diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp @@ -5025,8 +5025,8 @@ void CodeGenerator::visitMegamorphicStoreSlot(LMegamorphicStoreSlot* lir) { masm.jump(&done); masm.bind(&cacheHit); - masm.branchPtrInNurseryChunk(Assembler::Equal, obj, temp0, &done); masm.branchValueIsNurseryCell(Assembler::NotEqual, value, temp0, &done); + masm.branchPtrInNurseryChunk(Assembler::Equal, obj, temp0, &done); // Note: because this is a call-instruction, no registers need to be saved. MOZ_ASSERT(lir->isCall()); @@ -5839,15 +5839,14 @@ void CodeGenerator::emitElementPostWriteBarrier( }); addOutOfLineCode(ool, mir); - masm.branchPtrInNurseryChunk(Assembler::Equal, obj, scratch, ool->rejoin()); - if (reg.hasValue()) { - masm.branchValueIsNurseryCell(Assembler::Equal, reg.valueReg(), scratch, - ool->entry()); + masm.branchValueIsNurseryCell(Assembler::NotEqual, reg.valueReg(), scratch, + ool->rejoin()); } else { - masm.branchPtrInNurseryChunk(Assembler::Equal, reg.typedReg().gpr(), - scratch, ool->entry()); + masm.branchPtrInNurseryChunk(Assembler::NotEqual, reg.typedReg().gpr(), + scratch, ool->rejoin()); } + masm.branchPtrInNurseryChunk(Assembler::NotEqual, obj, scratch, ool->entry()); masm.bind(ool->rejoin()); } @@ -5933,20 +5932,22 @@ void CodeGenerator::visitPostWriteBarrierCommonV(LPostBarrierType* lir, Register temp = ToTempRegisterOrInvalid(lir->temp0()); + ValueOperand value = ToValue(lir->value()); + if (lir->object()->isConstant()) { // The object must be tenured because MIR and LIR can't contain nursery // pointers. MOZ_ASSERT(!IsInsideNursery(&lir->object()->toConstant()->toObject())); + masm.branchValueIsNurseryCell(Assembler::Equal, value, temp, ool->entry()); } else { - masm.branchPtrInNurseryChunk(Assembler::Equal, ToRegister(lir->object()), - temp, ool->rejoin()); + masm.branchValueIsNurseryCell(Assembler::NotEqual, value, temp, + ool->rejoin()); + masm.branchPtrInNurseryChunk(Assembler::NotEqual, ToRegister(lir->object()), + temp, ool->entry()); } maybeEmitGlobalBarrierCheck(lir->object(), ool); - ValueOperand value = ToValue(lir->value()); - masm.branchValueIsNurseryCell(Assembler::Equal, value, temp, ool->entry()); - masm.bind(ool->rejoin()); } @@ -6066,8 +6067,8 @@ void CodeGenerator::visitAssertCanElidePostWriteBarrier( Register temp = ToRegister(lir->temp0()); Label ok; - masm.branchPtrInNurseryChunk(Assembler::Equal, object, temp, &ok); masm.branchValueIsNurseryCell(Assembler::NotEqual, value, temp, &ok); + masm.branchPtrInNurseryChunk(Assembler::Equal, object, temp, &ok); masm.assumeUnreachable("Unexpected missing post write barrier"); @@ -17945,8 +17946,8 @@ void CodeGenerator::visitMegamorphicSetElement(LMegamorphicSetElement* lir) { masm.jump(&done); masm.bind(&cacheHit); - masm.branchPtrInNurseryChunk(Assembler::Equal, obj, temp0, &done); masm.branchValueIsNurseryCell(Assembler::NotEqual, value, temp0, &done); + masm.branchPtrInNurseryChunk(Assembler::Equal, obj, temp0, &done); // Note: because this is a call-instruction, no registers need to be saved. MOZ_ASSERT(lir->isCall()); @@ -18930,8 +18931,8 @@ void CodeGenerator::visitStoreSlotByIteratorIndexCommon(Register object, emitPreBarrier(storeAddress); masm.storeValue(value, storeAddress); - masm.branchPtrInNurseryChunk(Assembler::Equal, object, kindScratch, &done); masm.branchValueIsNurseryCell(Assembler::NotEqual, value, kindScratch, &done); + masm.branchPtrInNurseryChunk(Assembler::Equal, object, kindScratch, &done); saveVolatile(kindScratch); emitPostWriteBarrier(object); diff --git a/js/src/wasm/WasmGC.cpp b/js/src/wasm/WasmGC.cpp @@ -260,15 +260,15 @@ void wasm::EmitWasmPostBarrierGuard(MacroAssembler& masm, const mozilla::Maybe<Register>& object, Register otherScratch, Register setValue, Label* skipBarrier) { + // If the pointer being stored is to a tenured object, no barrier. + masm.branchWasmAnyRefIsNurseryCell(false, setValue, otherScratch, + skipBarrier); + // If there is a containing object and it is in the nursery, no barrier. if (object) { masm.branchPtrInNurseryChunk(Assembler::Equal, *object, otherScratch, skipBarrier); } - - // If the pointer being stored is to a tenured object, no barrier. - masm.branchWasmAnyRefIsNurseryCell(false, setValue, otherScratch, - skipBarrier); } void wasm::CheckWholeCellLastElementCache(MacroAssembler& masm,