commit dbce81a8d69d3bd649493cd459ca8342b53a28d7
parent 94e910dc62290e54846cf2362828a10d096fad49
Author: Iain Ireland <iireland@mozilla.com>
Date: Thu, 27 Nov 2025 21:39:56 +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:
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: