tor-browser

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

commit 757f7f0b0abc7ab38112e7616c173ff1cc049ed9
parent 28f7bc6772aeeb89a6fc4e7458ae1e62647aba72
Author: Iain Ireland <iireland@mozilla.com>
Date:   Thu, 27 Nov 2025 21:04:50 +0000

Bug 2000328: Implement WeakMapObject::getObject inline r=jandem

I added the new tests in weakmapset-get-has.js because my first version of this patch was checking for a null pointer when the hash map didn't exist, instead of undefined, and the only testcase that seemed to catch it was a non262 test marked slow.

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

Diffstat:
Mjs/src/jit-test/tests/cacheir/weakmapset-get-has.js | 24++++++++++++++++++++++++
Mjs/src/jit/CodeGenerator.cpp | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mjs/src/jit/Lowering.cpp | 7+++++++
Mjs/src/jit/MIROps.yaml | 6+++++-
4 files changed, 117 insertions(+), 1 deletion(-)

diff --git a/js/src/jit-test/tests/cacheir/weakmapset-get-has.js b/js/src/jit-test/tests/cacheir/weakmapset-get-has.js @@ -94,3 +94,27 @@ function testWeakSetThisGuard() { } } testWeakSetThisGuard(); + +function testWeakMapEmptyGet() { + var obj = {}; + var wm1 = new WeakMap([[obj, 1]]); + var wm2 = new WeakMap(); + function get(wm) { return wm.get(obj); } + for (var i = 0; i < 100; i++) { + var val = get(i < 95 ? wm1 : wm2); + assertEq(val, i < 95 ? 1 : undefined); + } +} +testWeakMapEmptyGet(); + +function testWeakMapEmptyHas() { + var obj = {}; + var wm1 = new WeakMap([[obj, 1]]); + var wm2 = new WeakMap(); + function has(wm) { return wm.has(obj); } + for (var i = 0; i < 100; i++) { + var val = has(i < 95 ? wm1 : wm2); + assertEq(val, i < 95); + } +} +testWeakMapEmptyHas(); diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp @@ -22674,6 +22674,86 @@ void CodeGenerator::visitMapObjectSize(LMapObjectSize* ins) { } void CodeGenerator::visitWeakMapGetObject(LWeakMapGetObject* ins) { +#ifndef JS_CODEGEN_X86 + Register weakMap = ToRegister(ins->weakMap()); + Register obj = ToRegister(ins->object()); + Register hashTable = ToRegister(ins->temp0()); + Register hashCode = ToRegister(ins->temp1()); + Register scratch = ToRegister(ins->temp2()); + Register scratch2 = ToRegister(ins->temp3()); + Register scratch3 = ToRegister(ins->temp4()); + Register scratch4 = ToRegister(ins->temp5()); + Register scratch5 = ToRegister(ins->temp6()); + ValueOperand output = ToOutValue(ins); + + Label found, missing; + + // Load hash map if it exists. If not, return `undefined`. + Address mapAddr(weakMap, + NativeObject::getFixedSlotOffset(WeakMapObject::DataSlot)); + masm.branchTestUndefined(Assembler::Equal, mapAddr, missing); + masm.loadPrivate(mapAddr, hashTable); + + // Hash and scramble address of object. +#ifdef JS_PUNBOX64 + ValueOperand boxedObj(scratch); +#else + ValueOperand boxedObj(scratch, obj); +#endif + masm.tagValue(JSVAL_TYPE_OBJECT, obj, boxedObj); + masm.hashAndScrambleValue(boxedObj, hashCode, scratch2); + masm.prepareHashMFBT(hashCode, /*alreadyScrambled*/ true); + + using Entry = WeakMapObject::Map::Entry; + auto matchEntry = [&]() { + Register entry = scratch; + Label noMatch; + masm.fallibleUnboxObject(Address(entry, Entry::offsetOfKey()), scratch2, + &noMatch); + masm.branchPtr(Assembler::Equal, obj, scratch2, &found); + masm.bind(&noMatch); + }; + masm.lookupMFBT<WeakMapObject::Map>(hashTable, hashCode, scratch, scratch2, + scratch3, scratch4, scratch5, &missing, + matchEntry); + masm.bind(&found); + + masm.loadValue(Address(scratch, Entry::offsetOfValue()), output); + + auto* ool = new (alloc()) LambdaOutOfLineCode([=](OutOfLineCode& ool) { + // Unboxed, tenured GC cell that needs to be barriered is in scratch. + + LiveRegisterSet regsToSave(RegisterSet::Volatile()); + regsToSave.takeUnchecked(hashTable); + regsToSave.takeUnchecked(hashCode); + regsToSave.takeUnchecked(scratch); + regsToSave.takeUnchecked(scratch2); + regsToSave.takeUnchecked(scratch3); + regsToSave.takeUnchecked(scratch4); + regsToSave.takeUnchecked(scratch5); + masm.PushRegsInMask(regsToSave); + + using Fn = void (*)(js::gc::Cell* cell); + masm.setupAlignedABICall(); + masm.passABIArg(scratch); + masm.callWithABI<Fn, js::jit::ReadBarrier>(); + + masm.PopRegsInMask(regsToSave); + + masm.jump(ool.rejoin()); + }); + addOutOfLineCode(ool, ins->mir()); + + masm.emitValueReadBarrierFastPath(output, scratch, scratch2, scratch3, + scratch4, scratch5, ool->entry()); + masm.jump(ool->rejoin()); + + masm.bind(&missing); + masm.moveValue(UndefinedValue(), output); + + masm.bind(ool->rejoin()); +#else + // x86 doesn't have enough registers, so we call into the VM. Register weakMap = ToRegister(ins->weakMap()); Register obj = ToRegister(ins->object()); Register temp = ToRegister(ins->temp0()); @@ -22691,6 +22771,7 @@ void CodeGenerator::visitWeakMapGetObject(LWeakMapGetObject* ins) { masm.callWithABI<Fn, js::WeakMapObject::getObject>(); masm.Pop(output); +#endif } void CodeGenerator::visitWeakMapHasObject(LWeakMapHasObject* ins) { diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp @@ -8171,10 +8171,17 @@ void LIRGenerator::visitMapObjectSize(MMapObjectSize* ins) { } void LIRGenerator::visitWeakMapGetObject(MWeakMapGetObject* ins) { +#ifdef JS_CODEGEN_X86 auto* lir = new (alloc()) LWeakMapGetObject( useFixedAtStart(ins->weakMap(), CallTempReg0), useFixedAtStart(ins->object(), CallTempReg1), tempFixed(CallTempReg2)); defineReturn(lir, ins); +#else + auto* lir = new (alloc()) LWeakMapGetObject( + useRegisterAtStart(ins->weakMap()), useRegisterAtStart(ins->object()), + temp(), temp(), temp(), temp(), temp(), temp(), temp()); + defineBox(lir, ins); +#endif } void LIRGenerator::visitWeakMapHasObject(MWeakMapHasObject* ins) { diff --git a/js/src/jit/MIROps.yaml b/js/src/jit/MIROps.yaml @@ -3920,9 +3920,13 @@ result_type: Value alias_set: custom movable: false - possibly_calls: true generate_lir: true +#ifdef JS_CODEGEN_X86 + possibly_calls: true lir_temps: 1 +#else + lir_temps: 7 +#endif - name: WeakMapHasObject operands: