tor-browser

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

commit c4efb2b73d8e3ca449e2cfe911a4250b8b55ff45
parent f40a0385489b38e2791467391a2741820d6b7803
Author: Norisz Fay <nfay@mozilla.com>
Date:   Thu, 27 Nov 2025 23:25:33 +0200

Revert "Bug 2000328: apply code formatting via Lando" for causing SM Bustages on CodeGenerator.cpp

This reverts commit f40a0385489b38e2791467391a2741820d6b7803.

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

This reverts commit 757f7f0b0abc7ab38112e7616c173ff1cc049ed9.

Revert "Bug 2000328: Implement MacroAssembler::emitValueReadBarrierFastPath r=jandem,jonco"

This reverts commit 28f7bc6772aeeb89a6fc4e7458ae1e62647aba72.

Revert "Bug 2000328: Remove unused argument from emitPreBarrierFastPath r=jandem"

This reverts commit 696cbdd758e921775adc1628e784faaac4f5c540.

Revert "Bug 2000328: Implement MacroAssembler::lookupMFBT r=jandem"

This reverts commit 147f2316380c2b808b37c7a65b2eee69b796619a.

Revert "Bug 2000328: Add MacroAssembler implementations of hash1/hash2/applyDoubleHash r=jandem"

This reverts commit 102bbcb8815e20a8f9717011114c8f653430af8f.

Revert "Bug 2000328: Remove bitfield in mozilla::detail::HashTable r=jandem"

This reverts commit 5414c2911e36572bc52a8e795aca85be09ea77a6.

Revert "Bug 2000328: Implement prepareHashMFBT r=jandem"

This reverts commit d8da973e94d8f363d4fb608f352b90a5cb615198.

Diffstat:
Mjs/public/HeapAPI.h | 7++-----
Mjs/src/gc/WeakMap.h | 7-------
Mjs/src/gdb/mozilla/ExecutableAllocator.py | 4+---
Mjs/src/jit-test/tests/cacheir/weakmapset-get-has.js | 24------------------------
Mjs/src/jit/ABIFunctionList-inl.h | 1-
Mjs/src/jit/CodeGenerator.cpp | 81-------------------------------------------------------------------------------
Mjs/src/jit/Lowering.cpp | 7-------
Mjs/src/jit/MIROps.yaml | 6+-----
Mjs/src/jit/MacroAssembler-inl.h | 34----------------------------------
Mjs/src/jit/MacroAssembler.cpp | 386+++++++++++++++----------------------------------------------------------------
Mjs/src/jit/MacroAssembler.h | 52++--------------------------------------------------
Mjs/src/jit/VMFunctions.cpp | 21---------------------
Mjs/src/jit/VMFunctions.h | 2--
Mjs/src/jit/arm/MacroAssembler-arm.h | 5-----
Mjs/src/jit/arm/Trampoline-arm.cpp | 3++-
Mjs/src/jit/arm64/Trampoline-arm64.cpp | 3++-
Mjs/src/jit/loong64/Trampoline-loong64.cpp | 3++-
Mjs/src/jit/mips64/Trampoline-mips64.cpp | 3++-
Mjs/src/jit/riscv64/Trampoline-riscv64.cpp | 3++-
Mjs/src/jit/x64/Trampoline-x64.cpp | 3++-
Mjs/src/jit/x86/MacroAssembler-x86.h | 5-----
Mjs/src/jit/x86/Trampoline-x86.cpp | 3++-
Mmfbt/HashTable.h | 113++++++++++++++++++++++++-------------------------------------------------------
23 files changed, 125 insertions(+), 651 deletions(-)

diff --git a/js/public/HeapAPI.h b/js/public/HeapAPI.h @@ -315,8 +315,8 @@ class alignas(TypicalCacheLineSize) ChunkMarkBitmap MOZ_ALWAYS_INLINE void getMarkWordAndMask(const void* cell, ColorBit colorBit, Word** wordp, uintptr_t* maskp) { - // Note: the JIT inlines this code. Update MacroAssembler::loadMarkBits and - // its callers when making changes here! + // Note: the JIT pre-barrier trampolines inline this code. Update + // MacroAssembler::emitPreBarrierFastPath code too when making changes here! MOZ_ASSERT(size_t(colorBit) < MarkBitsPerCell); @@ -868,9 +868,6 @@ namespace gc { extern JS_PUBLIC_API void PerformIncrementalReadBarrier(JS::GCCellPtr thing); static MOZ_ALWAYS_INLINE void ExposeGCThingToActiveJS(JS::GCCellPtr thing) { - // js::jit::ReadBarrier is a specialized version of this function designed to - // be called from jitcode. If this code is changed, it should be kept in sync. - // TODO: I'd like to assert !RuntimeHeapIsBusy() here but this gets // called while we are tracing the heap, e.g. during memory reporting // (see bug 1313318). diff --git a/js/src/gc/WeakMap.h b/js/src/gc/WeakMap.h @@ -432,13 +432,6 @@ class WeakMap : public WeakMapBase { size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf); - static size_t offsetOfHashShift() { - return offsetof(WeakMap, map_) + UnbarrieredMap::offsetOfHashShift(); - } - static size_t offsetOfTable() { - return offsetof(WeakMap, map_) + UnbarrieredMap::offsetOfTable(); - } - protected: inline void assertMapIsSameZoneWithValue(const BarrieredValue& v); diff --git a/js/src/gdb/mozilla/ExecutableAllocator.py b/js/src/gdb/mozilla/ExecutableAllocator.py @@ -58,9 +58,7 @@ class jsjitExecutableAllocator: self.table = allocator.value["m_pools"]["mImpl"]["mTable"] self.index = 0 kHashNumberBits = 32 - hashShiftMask = 0xFF - genAndHashShift = allocator.value["m_pools"]["mImpl"]["mGenAndHashShift"] - hashShift = genAndHashShift & hashShiftMask + hashShift = allocator.value["m_pools"]["mImpl"]["mHashShift"] self.capacity = 1 << (kHashNumberBits - hashShift) if self.table == 0: self.capacity = 0 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,27 +94,3 @@ 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/ABIFunctionList-inl.h b/js/src/jit/ABIFunctionList-inl.h @@ -178,7 +178,6 @@ namespace jit { _(js::jit::PreserveWrapper) \ _(js::jit::Printf0) \ _(js::jit::Printf1) \ - _(js::jit::ReadBarrier) \ _(js::jit::StringFromCharCodeNoGC) \ _(js::jit::StringTrimEndIndex) \ _(js::jit::StringTrimStartIndex) \ diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp @@ -22674,86 +22674,6 @@ 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()); @@ -22771,7 +22691,6 @@ 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,17 +8171,10 @@ 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,13 +3920,9 @@ result_type: Value alias_set: custom movable: false - generate_lir: true -#ifdef JS_CODEGEN_X86 possibly_calls: true + generate_lir: true lir_temps: 1 -#else - lir_temps: 7 -#endif - name: WeakMapHasObject operands: diff --git a/js/src/jit/MacroAssembler-inl.h b/js/src/jit/MacroAssembler-inl.h @@ -1024,40 +1024,6 @@ void MacroAssembler::loadStringLength(Register str, Register dest) { load32(Address(str, JSString::offsetOfLength()), dest); } -template <typename Table, typename Match> -void MacroAssembler::lookupMFBT(Register hashTable, Register hashCode, - Register scratch, Register scratch2, - Register scratch3, Register scratch4, - Register scratch5, Label* missing, - Match match) { - // Inline implementation of |lookup| for mozilla::detail::HashTable - - // Compute the primary hash address: - // HashNumber h1 = hash1(aKeyHash); - Register hash1 = scratch5; - computeHash1MFBT<Table>(hashTable, hashCode, hash1, scratch); - - Label primaryCollision; - checkForMatchMFBT<Table>(hashTable, hash1, hashCode, scratch, scratch2, - missing, &primaryCollision); - match(); - bind(&primaryCollision); - - // Otherwise, we've had a collision. Double-hash. - Register hash2 = scratch4; - Register sizeMask = scratch3; - computeHash2MFBT<Table>(hashTable, hashCode, hash2, sizeMask, scratch); - - Label loop; - bind(&loop); - - applyDoubleHashMFBT(hash1, hash2, sizeMask); - checkForMatchMFBT<Table>(hashTable, hash1, hashCode, scratch, scratch2, - missing, &loop); - match(); - jump(&loop); -} - void MacroAssembler::assertStackAlignment(uint32_t alignment, int32_t offset /* = 0 */) { #ifdef DEBUG diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp @@ -8067,60 +8067,13 @@ void MacroAssembler::nopPatchableToCall(const wasm::CallSiteDesc& desc) { append(desc, offset); } -// Given a cell and the chunk containing that cell, load the word containing -// the mark bits for that cell, and compute the bitIndex for a particular mark -// color. -void MacroAssembler::loadMarkBits(Register cell, Register chunk, - Register markWord, Register bitIndex, - Register temp, gc::ColorBit color) { - MOZ_ASSERT(temp != bitIndex); - MOZ_ASSERT(temp != chunk); - MOZ_ASSERT(chunk != bitIndex); - - // Determine the bit index and store in bitIndex. - // - // bit = (addr & js::gc::ChunkMask) / js::gc::CellBytesPerMarkBit + - // static_cast<uint32_t>(colorBit); - static_assert(gc::CellBytesPerMarkBit == 8, - "Calculation below relies on this"); - andPtr(Imm32(gc::ChunkMask), cell, bitIndex); - rshiftPtr(Imm32(3), bitIndex); - if (int32_t(color) != 0) { - addPtr(Imm32(int32_t(color)), bitIndex); - } - - static_assert(gc::ChunkMarkBitmap::BitsPerWord == JS_BITS_PER_WORD, - "Calculation below relies on this"); - - // Load the mark word - // - // word = chunk.bitmap[bit / WordBits]; - - // Fold the adjustment for the fact that arenas don't start at the beginning - // of the chunk into the offset to the chunk bitmap. - const size_t firstArenaAdjustment = - gc::ChunkMarkBitmap::FirstThingAdjustmentBits / CHAR_BIT; - const intptr_t offset = - intptr_t(gc::ChunkMarkBitmapOffset) - intptr_t(firstArenaAdjustment); - - uint8_t shift = mozilla::FloorLog2Size(JS_BITS_PER_WORD); - rshiftPtr(Imm32(shift), bitIndex, temp); - loadPtr(BaseIndex(chunk, temp, ScalePointer, offset), markWord); -} - -void MacroAssembler::emitPreBarrierFastPath(MIRType type, Register temp1, - Register temp2, Register temp3, - Label* noBarrier) { +void MacroAssembler::emitPreBarrierFastPath(JSRuntime* rt, MIRType type, + Register temp1, Register temp2, + Register temp3, Label* noBarrier) { MOZ_ASSERT(temp1 != PreBarrierReg); MOZ_ASSERT(temp2 != PreBarrierReg); MOZ_ASSERT(temp3 != PreBarrierReg); -#ifdef JS_CODEGEN_X64 - MOZ_ASSERT(temp3 == rcx); -#elif JS_CODEGEN_X86 - MOZ_ASSERT(temp3 == ecx); -#endif - // Load the GC thing in temp1. if (type == MIRType::Value) { unboxGCThingForGCBarrier(Address(PreBarrierReg, 0), temp1); @@ -8158,78 +8111,73 @@ void MacroAssembler::emitPreBarrierFastPath(MIRType type, Register temp1, #endif } - // Check if the cell is marked black. - // Load the bitindex into temp3 and the bitmap word into temp2. - loadMarkBits(temp1, temp2, temp2, temp3, temp1, gc::ColorBit::BlackBit); + // Determine the bit index and store in temp1. + // + // bit = (addr & js::gc::ChunkMask) / js::gc::CellBytesPerMarkBit + + // static_cast<uint32_t>(colorBit); + static_assert(gc::CellBytesPerMarkBit == 8, + "Calculation below relies on this"); + static_assert(size_t(gc::ColorBit::BlackBit) == 0, + "Calculation below relies on this"); + andPtr(Imm32(gc::ChunkMask), temp1); + rshiftPtr(Imm32(3), temp1); + + static_assert(gc::ChunkMarkBitmap::BitsPerWord == JS_BITS_PER_WORD, + "Calculation below relies on this"); + + // Load the bitmap word in temp2. + // + // word = chunk.bitmap[bit / WordBits]; + + // Fold the adjustment for the fact that arenas don't start at the beginning + // of the chunk into the offset to the chunk bitmap. + const size_t firstArenaAdjustment = + gc::ChunkMarkBitmap::FirstThingAdjustmentBits / CHAR_BIT; + const intptr_t offset = + intptr_t(gc::ChunkMarkBitmapOffset) - intptr_t(firstArenaAdjustment); + + movePtr(temp1, temp3); +#if JS_BITS_PER_WORD == 64 + rshiftPtr(Imm32(6), temp1); + loadPtr(BaseIndex(temp2, temp1, TimesEight, offset), temp2); +#else + rshiftPtr(Imm32(5), temp1); + loadPtr(BaseIndex(temp2, temp1, TimesFour, offset), temp2); +#endif // Load the mask in temp1. + // // mask = uintptr_t(1) << (bit % WordBits); andPtr(Imm32(gc::ChunkMarkBitmap::BitsPerWord - 1), temp3); move32(Imm32(1), temp1); - lshiftPtr(temp3, temp1); +#ifdef JS_CODEGEN_X64 + MOZ_ASSERT(temp3 == rcx); + shlq_cl(temp1); +#elif JS_CODEGEN_X86 + MOZ_ASSERT(temp3 == ecx); + shll_cl(temp1); +#elif JS_CODEGEN_ARM + ma_lsl(temp3, temp1, temp1); +#elif JS_CODEGEN_ARM64 + Lsl(ARMRegister(temp1, 64), ARMRegister(temp1, 64), ARMRegister(temp3, 64)); +#elif JS_CODEGEN_MIPS64 + ma_dsll(temp1, temp1, temp3); +#elif JS_CODEGEN_LOONG64 + as_sll_d(temp1, temp1, temp3); +#elif JS_CODEGEN_RISCV64 + sll(temp1, temp1, temp3); +#elif JS_CODEGEN_WASM32 + MOZ_CRASH(); +#elif JS_CODEGEN_NONE + MOZ_CRASH(); +#else +# error "Unknown architecture" +#endif // No barrier is needed if the bit is set, |word & mask != 0|. branchTestPtr(Assembler::NonZero, temp2, temp1, noBarrier); } -void MacroAssembler::emitValueReadBarrierFastPath( - ValueOperand value, Register cell, Register temp1, Register temp2, - Register temp3, Register temp4, Label* barrier) { - Label done; - - // No barrier needed for non-GC types - branchTestGCThing(Assembler::NotEqual, value, &done); - - // Load the GC thing in `cell`. - unboxGCThingForGCBarrier(value, cell); - - // Load the chunk address. - Register chunk = temp1; - andPtr(Imm32(int32_t(~gc::ChunkMask)), cell, chunk); - - // If the GC thing is in the nursery, we don't need to barrier it. - branchPtr(Assembler::NotEqual, Address(chunk, gc::ChunkStoreBufferOffset), - ImmWord(0), &done); - - // Load the mark word and bit index for the black bit. - Register markWord = temp2; - Register bitIndex = temp3; - loadMarkBits(cell, chunk, markWord, bitIndex, temp4, gc::ColorBit::BlackBit); - - // The mask for the black bit is 1 << (bitIndex % WordBits). - Register mask = temp4; - andPtr(Imm32(gc::ChunkMarkBitmap::BitsPerWord - 1), bitIndex); - move32(Imm32(1), mask); - flexibleLshiftPtr(bitIndex, mask); - - // No barrier is needed if the black bit is set. - branchTestPtr(Assembler::NonZero, markWord, mask, &done); - - // The bit index for the gray bit is bitIndex + 1. If the black bit - // is any bit except the highest bit of the mark word, we can reuse - // the mark word we've already loaded, and simply shift the mask by - // 1. - Label noMaskOverflow; - lshiftPtr(Imm32(1), mask); - branchTestPtr(Assembler::NonZero, mask, mask, &noMaskOverflow); - - // If the black bit was the high bit of the mark word, we need to load - // a new mark word. In this case the mask for the gray bit will always - // be 1 (the lowest bit of the next word). - loadMarkBits(cell, chunk, markWord, bitIndex, temp4, - gc::ColorBit::GrayOrBlackBit); - move32(Imm32(1), mask); - bind(&noMaskOverflow); - - // If the gray bit is set, then we *do* need a barrier. - branchTestPtr(Assembler::NonZero, markWord, mask, barrier); - - // Otherwise, we don't need a barrier unless we're in the middle of - // an incremental GC. - branchTestNeedsIncrementalBarrierAnyZone(Assembler::NonZero, barrier, temp1); - bind(&done); -} - // ======================================================================== // JS atomic operations. @@ -9988,13 +9936,17 @@ void MacroAssembler::scrambleHashCode(Register result) { mul32(Imm32(mozilla::kGoldenRatioU32), result); } -void MacroAssembler::hashAndScrambleValue(ValueOperand value, Register result, - Register temp) { - // Inline implementation of: - // mozilla::ScrambleHashCode(mozilla::HashGeneric(v.asRawBits())) - // Note that this uses the raw bits, which will change if a GC thing moves. - // This function should only be used for non-GC things, or in cases where - // moving GC things are handled specially (eg WeakMapObject). +void MacroAssembler::prepareHashNonGCThing(ValueOperand value, Register result, + Register temp) { + // Inline implementation of |OrderedHashTableImpl::prepareHash()| and + // |mozilla::HashGeneric(v.asRawBits())|. + +#ifdef DEBUG + Label ok; + branchTestGCThing(Assembler::NotEqual, value, &ok); + assumeUnreachable("Unexpected GC thing"); + bind(&ok); +#endif // uint32_t v1 = static_cast<uint32_t>(aValue); #ifdef JS_PUNBOX64 @@ -10030,21 +9982,6 @@ void MacroAssembler::hashAndScrambleValue(ValueOperand value, Register result, mul32(Imm32(mozilla::kGoldenRatioU32 * mozilla::kGoldenRatioU32), result); } -void MacroAssembler::prepareHashNonGCThing(ValueOperand value, Register result, - Register temp) { - // Inline implementation of |OrderedHashTableImpl::prepareHash()| and - // |mozilla::HashGeneric(v.asRawBits())|. - -#ifdef DEBUG - Label ok; - branchTestGCThing(Assembler::NotEqual, value, &ok); - assumeUnreachable("Unexpected GC thing"); - bind(&ok); -#endif - - hashAndScrambleValue(value, result, temp); -} - void MacroAssembler::prepareHashString(Register str, Register result, Register temp) { // Inline implementation of |OrderedHashTableImpl::prepareHash()| and @@ -10535,187 +10472,6 @@ void MacroAssembler::loadMapObjectSize(Register mapObj, Register result) { loadOrderedHashTableCount<MapObject>(mapObj, result); } -void MacroAssembler::prepareHashMFBT(Register hashCode, bool alreadyScrambled) { - // Inline implementation of |mozilla::HashTable::prepareHash()|. - static_assert(sizeof(HashNumber) == sizeof(uint32_t)); - - // In some cases scrambling can be more efficiently folded into the - // computation of the hash itself. - if (!alreadyScrambled) { - // HashNumber keyHash = ScrambleHashCode(aInputHash); - scrambleHashCode(hashCode); - } - - const mozilla::HashNumber RemovedKey = mozilla::detail::kHashTableRemovedKey; - const mozilla::HashNumber CollisionBit = - mozilla::detail::kHashTableCollisionBit; - - // Avoid reserved hash codes: - // if (!isLiveHash(keyHash)) { - Label isLive; - branch32(Assembler::Above, hashCode, Imm32(RemovedKey), &isLive); - // keyHash -= (sRemovedKey + 1); - sub32(Imm32(RemovedKey + 1), hashCode); - bind(&isLive); - - // return keyHash & ~sCollisionBit; - and32(Imm32(~CollisionBit), hashCode); -} - -template <typename Table> -void MacroAssembler::computeHash1MFBT(Register hashTable, Register hashCode, - Register hash1, Register scratch) { - // Inline implementation of |mozilla::HashTable::hash1| - // return aHash0 >> hashShift(); - move32(hashCode, hash1); - load8ZeroExtend(Address(hashTable, Table::offsetOfHashShift()), scratch); - flexibleRshift32(scratch, hash1); -} - -template void MacroAssembler::computeHash1MFBT<WeakMapObject::Map>( - Register hashTable, Register hashCode, Register hash1, Register scratch); - -template <typename Table> -void MacroAssembler::computeHash2MFBT(Register hashTable, Register hashCode, - Register hash2, Register sizeMask, - Register scratch) { - // Inline implementation of |mozilla::detail::HashTable::hash2| - - // Load hashShift into sizeMask - load8ZeroExtend(Address(hashTable, Table::offsetOfHashShift()), sizeMask); - - // uint32_t sizeLog2 = kHashNumberBits - hashShift(); - move32(Imm32(kHashNumberBits), scratch); - sub32(sizeMask, scratch); - - // DoubleHash dh = {((aCurKeyHash << sizeLog2) >> hashShift()) | 1, - move32(hashCode, hash2); - flexibleLshift32(scratch, hash2); - flexibleRshift32(sizeMask, hash2); - or32(Imm32(1), hash2); - - // sizeMask = (HashNumber(1) << sizeLog2) - 1}; - move32(Imm32(1), sizeMask); - flexibleLshift32(scratch, sizeMask); - sub32(Imm32(1), sizeMask); -} - -template void MacroAssembler::computeHash2MFBT<WeakMapObject::Map>( - Register hashTable, Register hashCode, Register hash2, Register sizeMask, - Register scratch); - -void MacroAssembler::applyDoubleHashMFBT(Register hash1, Register hash2, - Register sizeMask) { - // Inline implementation of |mozilla::detail::HashTable::applyDoubleHash| - - // return WrappingSubtract(aHash1, aDoubleHash.mHash2) & aDoubleHash.mSizeMask - sub32(hash2, hash1); - and32(sizeMask, hash1); -} - -template <typename Table> -void MacroAssembler::checkForMatchMFBT(Register hashTable, Register hashIndex, - Register hashCode, Register scratch, - Register scratch2, Label* missing, - Label* collision) { - // Helper for inline implementation of |mozilla::detail::HashTable::lookup| - // The following code is used twice in |lookup|: - // - // Slot slot = slotForIndex(h1); - // if (slot.isFree()) { - // <not found> - // } - // if (slot.matchHash(aKeyHash) && match(slot.get(), aLookup)) { - // <found> - // } - // - // To reduce register pressure, we do some inlining and reorder some - // intermediate computation. We inline the following functions: - // - // Slot slotForIndex(HashNumber aIndex) const { - // auto hashes = reinterpret_cast<HashNumber*>(mTable); - // auto entries = reinterpret_cast<Entry*>(&hashes[capacity()]); - // return Slot(&entries[aIndex], &hashes[aIndex]); - // } - // - // uint32_t rawCapacity() { return 1u << (kHashNumberBits - hashShift()); } - // - // bool isFree() const { return *mKeyHash == Entry::sFreeKey; } - // - // bool matchHash(HashNumber hn) { - // return (*mKeyHash & ~Entry::sCollisionBit) == hn; - // } - // - // Reordered, we implement: - // - // auto hashes = reinterpret_cast<HashNumber*>(mTable); - // HashNumber hashInTable = hashes[hashIndex]; - // if (hashInTable == Entry::sFreeKey) { - // <jump to missing label> - // } - // if (hashInTable & ~CollisionBit != hashCode) { - // <jump to collision label> - // } - // auto entries = hashes[capacity()]; - // Entry* entry = entries[hashIndex] - // <fall through to entry-specific match code> - const mozilla::HashNumber FreeKey = mozilla::detail::kHashTableFreeKey; - const mozilla::HashNumber CollisionBit = - mozilla::detail::kHashTableCollisionBit; - - Address tableAddr(hashTable, Table::offsetOfTable()); - Address hashShiftAddr(hashTable, Table::offsetOfHashShift()); - - // auto hashes = reinterpret_cast<HashNumber*>(mTable); - Register hashes = scratch; - loadPtr(tableAddr, scratch); - - // HashNumber hashInTable = hashes[hashIndex]; - Register hashInTable = scratch2; - static_assert(sizeof(HashNumber) == 4); - load32(BaseIndex(hashes, hashIndex, Scale::TimesFour), hashInTable); - - // if (hashInTable == Entry::sFreeKey) { - // <jump to missing label> - // } - branch32(Assembler::Equal, hashInTable, Imm32(FreeKey), missing); - - // if (hashInTable & ~CollisionBit != hashCode) { - // <jump to collision label> - // } - and32(Imm32(~CollisionBit), hashInTable); - branch32(Assembler::NotEqual, hashInTable, hashCode, collision); - - // entries = hashes[capacity()] - // = hashes[1 << (kHashNumberBits - hashShift()] - // = &hashes + (1 << (kHashNumberBits - hashShift())) * sizeof(HashNumber) - // = &hashes + sizeof(HashNumber) << (kHashNumberBits - hashShift()) - // = &hashes + sizeof(HashNumber) << (kHashNumberBits + -hashShift()) - Register capacityOffset = scratch; - load8ZeroExtend(hashShiftAddr, scratch2); - neg32(scratch2); - add32(Imm32(kHashNumberBits), scratch2); - move32(Imm32(sizeof(mozilla::HashNumber)), capacityOffset); - flexibleLshift32(scratch2, capacityOffset); - Register entries = scratch2; - loadPtr(tableAddr, entries); - addPtr(capacityOffset, entries); - - // Load entries[hashIndex] into |scratch| - // TODO: support non-power-of-2 entry sizes - constexpr size_t EntrySize = sizeof(typename Table::Entry); - static_assert(mozilla::IsPowerOfTwo(EntrySize)); - uint32_t shift = mozilla::FloorLog2(EntrySize); - lshiftPtr(Imm32(shift), hashIndex, scratch); - - computeEffectiveAddress(BaseIndex(entries, scratch, Scale::TimesOne), - scratch); -} - -template void MacroAssembler::checkForMatchMFBT<WeakMapObject::Map>( - Register hashTable, Register hashIndex, Register hashCode, Register scratch, - Register scratch2, Label* missing, Label* collision); - // Can't push large frames blindly on windows, so we must touch frame memory // incrementally, with no more than 4096 - 1 bytes between touches. // diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h @@ -4191,16 +4191,8 @@ class MacroAssembler : public MacroAssemblerSpecific { // ======================================================================== // Barrier functions. - void emitPreBarrierFastPath(MIRType type, Register temp1, Register temp2, - Register temp3, Label* noBarrier); - void emitValueReadBarrierFastPath(ValueOperand value, Register cell, - Register temp1, Register temp2, - Register temp3, Register temp4, - Label* barrier); - - private: - void loadMarkBits(Register cell, Register chunk, Register markWord, - Register bitIndex, Register temp, gc::ColorBit color); + void emitPreBarrierFastPath(JSRuntime* rt, MIRType type, Register temp1, + Register temp2, Register temp3, Label* noBarrier); public: // ======================================================================== @@ -5438,7 +5430,6 @@ class MacroAssembler : public MacroAssemblerSpecific { void scrambleHashCode(Register result); public: - void hashAndScrambleValue(ValueOperand value, Register result, Register temp); void prepareHashNonGCThing(ValueOperand value, Register result, Register temp); void prepareHashString(Register str, Register result, Register temp); @@ -5452,45 +5443,6 @@ class MacroAssembler : public MacroAssemblerSpecific { Register temp1, Register temp2, Register temp3, Register temp4); - // Helper functions used to implement mozilla::HashTable lookup inline - // in jitcode. - void prepareHashMFBT(Register hashCode, bool alreadyScrambled); - template <typename Table> - void computeHash1MFBT(Register hashTable, Register hashCode, Register hash1, - Register scratch); - template <typename Table> - void computeHash2MFBT(Register hashTable, Register hashCode, Register hash2, - Register sizeMask, Register scratch); - void applyDoubleHashMFBT(Register hash1, Register hash2, Register sizeMask); - template <typename Table> - void checkForMatchMFBT(Register hashTable, Register hashIndex, - Register hashCode, Register scratch, Register scratch2, - Label* missing, Label* collision); - - public: - // This generates an inlined version of mozilla::detail::HashTable::lookup - // (ForNonAdd). - // Inputs/requirements: - // - hashTable: A register containing a pointer to a Table. The Table type - // must define: - // - Table::Entry - // - Table::offsetOfHashShift() - // - Table::offsetOfTable() - // - hashCode: The 32-bit hash of the key to look up. This should already - // have been scrambled using prepareHashMFBT. - // - match: A lambda to generate code to compare keys. The code that it - // generates can assume that `scratch` contains the address of - // a Table::Entry with a matching hash value. `scratch2` can be - // safely used without clobbering anything. If the keys don't - // match, the generated code should fall through. If the keys - // match, the generated code is responsible for jumping to the - // correct continuation. - // - missing: A label to jump to if the key does not exist in the table. - template <typename Table, typename Match> - void lookupMFBT(Register hashTable, Register hashCode, Register scratch, - Register scratch2, Register scratch3, Register scratch4, - Register scratch5, Label* missing, Match match); - private: enum class IsBigInt { No, Yes, Maybe }; diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp @@ -3319,27 +3319,6 @@ void AssertPropertyLookup(NativeObject* obj, PropertyKey id, uint32_t slot) { #endif } -// This is a specialized version of ExposeJSThingToActiveJS -void ReadBarrier(gc::Cell* cell) { - AutoUnsafeCallWithABI unsafe; - - MOZ_ASSERT(!JS::RuntimeHeapIsCollecting()); - MOZ_ASSERT(!gc::IsInsideNursery(cell)); - - gc::TenuredCell* tenured = &cell->asTenured(); - MOZ_ASSERT(!gc::detail::TenuredCellIsMarkedBlack(tenured)); - - Zone* zone = tenured->zone(); - if (zone->needsIncrementalBarrier()) { - gc::PerformIncrementalReadBarrier(tenured); - } else if (!zone->isGCPreparing() && - gc::detail::NonBlackCellIsMarkedGray(tenured)) { - gc::UnmarkGrayGCThingRecursively(tenured); - } - MOZ_ASSERT_IF(!zone->isGCPreparing(), - !gc::detail::TenuredCellIsMarkedGray(tenured)); -} - void AssumeUnreachable(const char* output) { MOZ_ReportAssertionFailure(output, __FILE__, __LINE__); } diff --git a/js/src/jit/VMFunctions.h b/js/src/jit/VMFunctions.h @@ -733,8 +733,6 @@ void AssertMapObjectHash(JSContext* cx, MapObject* obj, const Value* value, void AssertPropertyLookup(NativeObject* obj, PropertyKey id, uint32_t slot); -void ReadBarrier(gc::Cell* cell); - // Functions used when JS_MASM_VERBOSE is enabled. void AssumeUnreachable(const char* output); void Printf0(const char* output); diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h @@ -875,11 +875,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM { void unboxGCThingForGCBarrier(const Address& src, Register dest) { load32(ToPayload(src), dest); } - void unboxGCThingForGCBarrier(const ValueOperand& src, Register dest) { - if (src.payloadReg() != dest) { - ma_mov(src.payloadReg(), dest); - } - } void unboxWasmAnyRefGCThingForGCBarrier(const Address& src, Register dest) { load32(ToPayload(src), dest); diff --git a/js/src/jit/arm/Trampoline-arm.cpp b/js/src/jit/arm/Trampoline-arm.cpp @@ -545,7 +545,8 @@ uint32_t JitRuntime::generatePreBarrier(JSContext* cx, MacroAssembler& masm, masm.push(temp3); Label noBarrier; - masm.emitPreBarrierFastPath(type, temp1, temp2, temp3, &noBarrier); + masm.emitPreBarrierFastPath(cx->runtime(), type, temp1, temp2, temp3, + &noBarrier); // Call into C++ to mark this GC thing. masm.pop(temp3); diff --git a/js/src/jit/arm64/Trampoline-arm64.cpp b/js/src/jit/arm64/Trampoline-arm64.cpp @@ -663,7 +663,8 @@ uint32_t JitRuntime::generatePreBarrier(JSContext* cx, MacroAssembler& masm, masm.push(temp3); Label noBarrier; - masm.emitPreBarrierFastPath(type, temp1, temp2, temp3, &noBarrier); + masm.emitPreBarrierFastPath(cx->runtime(), type, temp1, temp2, temp3, + &noBarrier); // Call into C++ to mark this GC thing. masm.pop(temp3); diff --git a/js/src/jit/loong64/Trampoline-loong64.cpp b/js/src/jit/loong64/Trampoline-loong64.cpp @@ -490,7 +490,8 @@ uint32_t JitRuntime::generatePreBarrier(JSContext* cx, MacroAssembler& masm, masm.push(temp3); Label noBarrier; - masm.emitPreBarrierFastPath(type, temp1, temp2, temp3, &noBarrier); + masm.emitPreBarrierFastPath(cx->runtime(), type, temp1, temp2, temp3, + &noBarrier); // Call into C++ to mark this GC thing. masm.pop(temp3); diff --git a/js/src/jit/mips64/Trampoline-mips64.cpp b/js/src/jit/mips64/Trampoline-mips64.cpp @@ -519,7 +519,8 @@ uint32_t JitRuntime::generatePreBarrier(JSContext* cx, MacroAssembler& masm, masm.push(temp3); Label noBarrier; - masm.emitPreBarrierFastPath(type, temp1, temp2, temp3, &noBarrier); + masm.emitPreBarrierFastPath(cx->runtime(), type, temp1, temp2, temp3, + &noBarrier); // Call into C++ to mark this GC thing. masm.pop(temp3); diff --git a/js/src/jit/riscv64/Trampoline-riscv64.cpp b/js/src/jit/riscv64/Trampoline-riscv64.cpp @@ -403,7 +403,8 @@ uint32_t JitRuntime::generatePreBarrier(JSContext* cx, MacroAssembler& masm, masm.push(temp3); Label noBarrier; - masm.emitPreBarrierFastPath(type, temp1, temp2, temp3, &noBarrier); + masm.emitPreBarrierFastPath(cx->runtime(), type, temp1, temp2, temp3, + &noBarrier); // Call into C++ to mark this GC thing. masm.pop(temp3); diff --git a/js/src/jit/x64/Trampoline-x64.cpp b/js/src/jit/x64/Trampoline-x64.cpp @@ -545,7 +545,8 @@ uint32_t JitRuntime::generatePreBarrier(JSContext* cx, MacroAssembler& masm, masm.push(temp3); Label noBarrier; - masm.emitPreBarrierFastPath(type, temp1, temp2, temp3, &noBarrier); + masm.emitPreBarrierFastPath(cx->runtime(), type, temp1, temp2, temp3, + &noBarrier); // Call into C++ to mark this GC thing. masm.pop(temp3); diff --git a/js/src/jit/x86/MacroAssembler-x86.h b/js/src/jit/x86/MacroAssembler-x86.h @@ -918,11 +918,6 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared { void unboxGCThingForGCBarrier(const Address& src, Register dest) { movl(payloadOf(src), dest); } - void unboxGCThingForGCBarrier(const ValueOperand& src, Register dest) { - if (src.payloadReg() != dest) { - movl(src.payloadReg(), dest); - } - } void unboxWasmAnyRefGCThingForGCBarrier(const Address& src, Register dest) { movl(ImmWord(wasm::AnyRef::GCThingMask), dest); diff --git a/js/src/jit/x86/Trampoline-x86.cpp b/js/src/jit/x86/Trampoline-x86.cpp @@ -473,7 +473,8 @@ uint32_t JitRuntime::generatePreBarrier(JSContext* cx, MacroAssembler& masm, masm.push(temp3); Label noBarrier; - masm.emitPreBarrierFastPath(type, temp1, temp2, temp3, &noBarrier); + masm.emitPreBarrierFastPath(cx->runtime(), type, temp1, temp2, temp3, + &noBarrier); // Call into C++ to mark this GC thing. masm.pop(temp3); diff --git a/mfbt/HashTable.h b/mfbt/HashTable.h @@ -81,7 +81,6 @@ #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/Casting.h" -#include "mozilla/EndianUtils.h" #include "mozilla/HashFunctions.h" #include "mozilla/MathAlgorithms.h" #include "mozilla/Maybe.h" @@ -425,13 +424,6 @@ class MOZ_STANDALONE_DEBUG HashMap { using Range = typename Impl::Range; using Enum = typename Impl::Enum; Range all() const { return mImpl.all(); } - - static size_t offsetOfHashShift() { - return offsetof(HashMap, mImpl) + Impl::offsetOfHashShift(); - } - static size_t offsetOfTable() { - return offsetof(HashMap, mImpl) + Impl::offsetOfTable(); - } }; //--------------------------------------------------------------------------- @@ -983,9 +975,6 @@ class HashMapEntry { const Value& value() const { return value_; } Value& value() { return value_; } - static size_t offsetOfKey() { return offsetof(HashMapEntry, key_); } - static size_t offsetOfValue() { return offsetof(HashMapEntry, value_); } - private: HashMapEntry(const HashMapEntry&) = delete; void operator=(const HashMapEntry&) = delete; @@ -993,10 +982,6 @@ class HashMapEntry { namespace detail { -static const HashNumber kHashTableFreeKey = 0; -static const HashNumber kHashTableRemovedKey = 1; -static const HashNumber kHashTableCollisionBit = 1; - template <class T, class HashPolicy, class AllocPolicy> class HashTable; @@ -1072,9 +1057,9 @@ class HashTableEntry { "subsequent N*2 T values must not require more than an even " "number of HashNumbers provides"); - static const HashNumber sFreeKey = kHashTableFreeKey; - static const HashNumber sRemovedKey = kHashTableRemovedKey; - static const HashNumber sCollisionBit = kHashTableCollisionBit; + static const HashNumber sFreeKey = 0; + static const HashNumber sRemovedKey = 1; + static const HashNumber sCollisionBit = 1; alignas(NonConstT) unsigned char mValueData[sizeof(NonConstT)]; @@ -1517,7 +1502,7 @@ class MOZ_STANDALONE_DEBUG HashTable : private AllocPolicy { // memory to be minimised after removing entries they should call compact(). ~ModIterator() { if (mRekeyed) { - mTable.incrementGeneration(); + mTable.mGen++; mTable.infallibleRehashIfOverloaded(); } @@ -1593,7 +1578,16 @@ class MOZ_STANDALONE_DEBUG HashTable : private AllocPolicy { ReentrancyGuard g1(*this); ReentrancyGuard g2(aOther); - std::swap(mGenAndHashShift, aOther.mGenAndHashShift); + // Manual swap of generation because it's a bitfield + uint64_t generation = mGen; + mGen = aOther.mGen; + aOther.mGen = generation; + + // Manual swap of hashShift because it's a bitfield + uint64_t hashShift = mHashShift; + mHashShift = aOther.mHashShift; + aOther.mHashShift = hashShift; + std::swap(mTable, aOther.mTable); std::swap(mEntryCount, aOther.mEntryCount); std::swap(mRemovedCount, aOther.mRemovedCount); @@ -1605,7 +1599,8 @@ class MOZ_STANDALONE_DEBUG HashTable : private AllocPolicy { private: void moveFrom(HashTable& aRhs) { - mGenAndHashShift = aRhs.mGenAndHashShift; + mGen = aRhs.mGen; + mHashShift = aRhs.mHashShift; mTable = aRhs.mTable; mEntryCount = aRhs.mEntryCount; mRemovedCount = aRhs.mRemovedCount; @@ -1624,11 +1619,11 @@ class MOZ_STANDALONE_DEBUG HashTable : private AllocPolicy { static const uint32_t CAP_BITS = 30; public: - uint64_t mGenAndHashShift; // entry storage generation number (56 bits) - // and multiplicative hash shift (8 bits) - char* mTable; // entry storage - uint32_t mEntryCount; // number of entries in mTable - uint32_t mRemovedCount; // removed entry sentinels in mTable + uint64_t mGen : 56; // entry storage generation number + uint64_t mHashShift : 8; // multiplicative hash shift + char* mTable; // entry storage + uint32_t mEntryCount; // number of entries in mTable + uint32_t mRemovedCount; // removed entry sentinels in mTable #ifdef DEBUG uint64_t mMutationCount; @@ -1654,29 +1649,6 @@ class MOZ_STANDALONE_DEBUG HashTable : private AllocPolicy { static const HashNumber sRemovedKey = Entry::sRemovedKey; static const HashNumber sCollisionBit = Entry::sCollisionBit; - static const uint64_t sHashShiftBits = 8; - static const uint64_t sHashShiftMask = (1 << sHashShiftBits) - 1; - static const uint64_t sGenerationShift = sHashShiftBits; - - MOZ_ALWAYS_INLINE uint8_t hashShift() const { - return uint8_t(mGenAndHashShift & sHashShiftMask); - } - MOZ_ALWAYS_INLINE uint64_t gen() const { - return mGenAndHashShift >> sGenerationShift; - } - - private: - void setGenAndHashShift(uint64_t aGeneration, uint8_t aHashShift) { - mGenAndHashShift = aGeneration << sGenerationShift | aHashShift; - } - - public: - void incrementGeneration() { setGenAndHashShift(gen() + 1, hashShift()); } - void setHashShift(uint32_t aHashShift) { - MOZ_ASSERT((aHashShift & sHashShiftMask) == aHashShift); - mGenAndHashShift = (mGenAndHashShift & ~sHashShiftMask) | aHashShift; - } - static uint32_t bestCapacity(uint32_t aLen) { static_assert( (sMaxInit * sAlphaDenominator) / sAlphaDenominator == sMaxInit, @@ -1701,7 +1673,7 @@ class MOZ_STANDALONE_DEBUG HashTable : private AllocPolicy { return capacity; } - static uint32_t hashShiftForLength(uint32_t aLen) { + static uint32_t hashShift(uint32_t aLen) { // Reject all lengths whose initial computed capacity would exceed // sMaxCapacity. Round that maximum aLen down to the nearest power of two // for speedier code. @@ -1771,7 +1743,8 @@ class MOZ_STANDALONE_DEBUG HashTable : private AllocPolicy { public: HashTable(AllocPolicy aAllocPolicy, uint32_t aLen) : AllocPolicy(std::move(aAllocPolicy)), - mGenAndHashShift(hashShiftForLength(aLen)), + mGen(0), + mHashShift(hashShift(aLen)), mTable(nullptr), mEntryCount(0), mRemovedCount(0) @@ -1793,7 +1766,7 @@ class MOZ_STANDALONE_DEBUG HashTable : private AllocPolicy { } private: - HashNumber hash1(HashNumber aHash0) const { return aHash0 >> hashShift(); } + HashNumber hash1(HashNumber aHash0) const { return aHash0 >> mHashShift; } struct DoubleHash { HashNumber mHash2; @@ -1801,8 +1774,8 @@ class MOZ_STANDALONE_DEBUG HashTable : private AllocPolicy { }; DoubleHash hash2(HashNumber aCurKeyHash) const { - uint32_t sizeLog2 = kHashNumberBits - hashShift(); - DoubleHash dh = {((aCurKeyHash << sizeLog2) >> hashShift()) | 1, + uint32_t sizeLog2 = kHashNumberBits - mHashShift; + DoubleHash dh = {((aCurKeyHash << sizeLog2) >> mHashShift) | 1, (HashNumber(1) << sizeLog2) - 1}; return dh; } @@ -1933,9 +1906,9 @@ class MOZ_STANDALONE_DEBUG HashTable : private AllocPolicy { } // We can't fail from here on, so update table parameters. + mHashShift = kHashNumberBits - newLog2; mRemovedCount = 0; - incrementGeneration(); - setHashShift(kHashNumberBits - newLog2); + mGen++; mTable = newTable; // Copy only live entries, leaving removed ones behind. @@ -2017,7 +1990,7 @@ class MOZ_STANDALONE_DEBUG HashTable : private AllocPolicy { // would have gotten through random insertion order. void rehashTableInPlace() { mRemovedCount = 0; - incrementGeneration(); + mGen++; forEachSlot(mTable, capacity(), [&](Slot& slot) { slot.unsetCollision(); }); for (uint32_t i = 0; i < capacity();) { Slot src = slotForIndex(i); @@ -2090,9 +2063,8 @@ class MOZ_STANDALONE_DEBUG HashTable : private AllocPolicy { if (empty()) { // Free the entry storage. freeTable(*this, mTable, capacity()); - incrementGeneration(); - setHashShift( - hashShiftForLength(0)); // gives minimum capacity on regrowth + mGen++; + mHashShift = hashShift(0); // gives minimum capacity on regrowth mTable = nullptr; mRemovedCount = 0; return; @@ -2143,11 +2115,11 @@ class MOZ_STANDALONE_DEBUG HashTable : private AllocPolicy { uint32_t count() const { return mEntryCount; } - uint32_t rawCapacity() const { return 1u << (kHashNumberBits - hashShift()); } + uint32_t rawCapacity() const { return 1u << (kHashNumberBits - mHashShift); } uint32_t capacity() const { return mTable ? rawCapacity() : 0; } - Generation generation() const { return Generation(gen()); } + Generation generation() const { return Generation(mGen); } size_t shallowSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const { return aMallocSizeOf(mTable); @@ -2342,23 +2314,6 @@ class MOZ_STANDALONE_DEBUG HashTable : private AllocPolicy { rekeyWithoutRehash(aPtr, aLookup, aKey); infallibleRehashIfOverloaded(); } - - static size_t offsetOfHashShift() { - static_assert(sHashShiftBits == 8, - "callers assume hash shift is stored in a byte"); - // The hash shift is stored in the least significant bits of - // mGenAndHashShift. On little-endian platforms, this is the - // same offset as mGenAndHashShift itself. On big-endian platforms, - // we have to add an additional offset to point to the last byte. - // (Or we would if we had JIT support for any big-endian platforms.) -#if MOZ_BIG_ENDIAN() - return offsetof(HashTable, mGenAndHashShift) + sizeof(mGenAndHashShift) - - sizeof(uint8_t); -#else - return offsetof(HashTable, mGenAndHashShift); -#endif - } - static size_t offsetOfTable() { return offsetof(HashTable, mTable); } }; } // namespace detail