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:
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,