← All issues

[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.

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.

🔒

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