[JSC] Inline `NumericStrings` int cache lookup in DFG and FTL `ToString(Int32)`
186e2a9
NumericStrings is a per-VM cache mapping integers to their precomputed JSString representations, with two tiers: a direct-mapped small-int array (indices 0..1023) and a hash-based m_intCache for arbitrary 32-bit values, keyed by WTF::IntHash<int> (the rapidHashMix64 mum mixer). When DFG/FTL inlines a cache lookup, it emits the hash arithmetic, memory loads, and conditional branches as native instructions — no C++ call frame, no runtime guards beyond what is explicitly emitted.
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
- slowCases.append(branch32(AboveOrEqual, valueGPR, TrustedImm32(NumericStrings::cacheSize)));
- move(valueGPR, resultGPR);
- lshiftPtr(TrustedImm32(WTF::fastLog2(static_cast<unsigned>(sizeof(NumericStrings::StringWithJSString)))), resultGPR);
- addPtr(TrustedImmPtr(vm().numericStrings.smallIntCache()), resultGPR);
- loadPtr(Address(resultGPR, NumericStrings::StringWithJSString::offsetOfJSString()), resultGPR);
- doneCases.append(branchTestPtr(NonZero, resultGPR));
- callOperation(operationInt32ToStringWithValidRadix, resultGPR, LinkableConstant::globalObject(*this, node), valueGPR, TrustedImm32(10));
Source/JavaScriptCore/b3/B3AbstractHeapRepository.h
+ macro(IntCache, 0, sizeof(NumericStrings::CacheEntryWithJSString<int>)) \
This commit inlines the NumericStrings int-cache hash lookup for radix-10 ToString(Int32) in the 64-bit DFG and FTL backends, covering values outside the existing 0..1023 small-int range. It emits rapidHashMix64 directly as JIT machine code to index into m_intCache, returning the cached JSString on a key match and only falling through to the vmCall on a miss. A new IntCache B3 abstract heap controls how the optimizer may reorder those loads. The 32-bit DFG backend keeps the old small-int-only path since the 128-bit multiply in rapidHashMix64 is not viable there.
Significance
The result is a ~2.38x speedup for large-integer-to-string conversions in hot JIT code, at the cost of new JIT-emitted code that directly dereferences GC-managed JSString pointers out of a runtime hash table.
Audit directions
Aaa Aaaaaaaaa Aaa Aaaaaaaaaaaaaaaaa Aaaaa Aaa Aaa Aaaaaaaa Aaaaa Aaaa Aaa Aaaaa Aaaa a Aa a Aaaaa Aa Aaa Aaaaa Aaaaa Aaaaaaa Aaaaaaaaaa Aa a Aaaaaaaaa Aaaa Aaaaa Aaaaaaa Aaa Aaa Aaaaaa Aaa Aaa Aaaaa Aaa Aaaa Aa Aaa Aaaaa Aaaaa Aaaaaaaaaa Aaaaaaa Aa a Aaaaaaaaa Aaaaaaaa Aaa Aaaaaaaaaaaaaaaa Aaa Aaaaaaaa Aaaa Aa Aaaaaaaaaaa Aaaaaaaaa Aa Aaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaaaa Aa Aaaaaaa Aaaaaa Aaaa Aaaaaaaaaa Aa Aaaaaaaa Aaaaaaaaaa Aaaaa Aaaaa a Aaaaaaaaa Aaaa Aaaa Aaa Aaaaaaaa Aaaaaaaaa a Aaaaaaaaaa Aaa Aaa Aaaaa Aaaaaaaa Aaa Aaa Aa Aaaaaaaaaa Aaaaaaaa Aaaa Aaaaaaa Aaaaaaaaaa Aa Aaa Aaaa Aaaa Aaaaaaaa Aa Aaaaaaaaaaa Aaaaaa a Aa Aaa Aaaaaaaa Aaaa Aa Aaaaaa Aa Aaaaaa Aaa Aaaaaaaaa Aaaaa Aaa a Aaaaa Aaaa Aaaaa Aaaaa Aaaaaaaaa Aaa Aaaa Aaa Aaaaaaaaaaa Aaaaaaaa Aaa Aaaaaaaaa Aaaaa Aaaaaaa a Aaaaaaaaa Aaaaaaaaaaa Aaaaaaaaaaa Aa Aaaaaaaaaa Aaaaaa Aaaaaa Aa Aaa Aaaaa Aaaaaaaaa Aaaaa Aaaaaaaa Aaaaaaa Aaaaaaa Aa Aaaaaa Aaaaa Aaaaaa Aaaaa Aaaaaaaa
🔒New JIT-emitted GC-pointer loads from a hash table — edge cases in the inline fast path and B3 alias analysis are worth security investigation.
Subscribe to read more