DFG node for `String.fromCodePoint`
93a4fbe
Source/JavaScriptCore/dfg/DFGOperations.cpp
+JSC_DEFINE_JIT_OPERATION(operationStringFromCodePointUntyped, EncodedJSValue, (JSGlobalObject* globalObject, EncodedJSValue encodedValue))
+{
+ ...
+ double codePointAsDouble = value.toNumber(globalObject);
+ OPERATION_RETURN_IF_EXCEPTION(scope, encodedJSValue());
+
+ uint32_t codePoint = static_cast<uint32_t>(codePointAsDouble);
+ if (codePoint != codePointAsDouble || codePoint > UCHAR_MAX_VALUE) [[unlikely]] {
+ throwRangeError(globalObject, scope, "Arguments contain a value that is out of range of code points"_s);
+ OPERATION_RETURN(scope, encodedJSValue());
+ }
+
+ if (U_IS_BMP(codePoint))
+ OPERATION_RETURN(scope, JSValue::encode(jsSingleCharacterString(vm, static_cast<char16_t>(codePoint))));
+
+ char16_t buffer[2] = { U16_LEAD(codePoint), U16_TRAIL(codePoint) };
+ OPERATION_RETURN(scope, JSValue::encode(jsNontrivialString(vm, String({ buffer, 2 }))));
+}
JSC's tiered JIT (Baseline → DFG → FTL) recognises specific built-in functions at the bytecode parsing stage and emits purpose-built IR nodes. String.fromCodePoint is harder than String.fromCharCode because (1) it must throw RangeError for non-integer, negative, or >0x10FFFF inputs — even when the JIT has proven the argument is an Int32 — and (2) supplementary-plane code points require emitting a two-unit surrogate pair.
This commit adds a StringFromCodePoint DFG node and FromCodePointIntrinsic. For Int32 arguments in [0, 0xFF], the fast path is shared with StringFromCharCode via a unified compileStringFromCharCodeOrCodePoint. Larger code points, surrogate pairs, and RangeError cases fall back to operationStringFromCodePoint (Int32 slow path) or operationStringFromCodePointUntyped. The node keeps NodeMustGenerate set and models itself as write(SideState) to prevent the optimiser from treating it as side-effect-free.
Significance
The change delivers a measured ~5.2x speedup for Latin-1 code points and brings String.fromCodePoint into the JIT intrinsic tier. Every new DFG intrinsic must be wired through clobberize, doesGC, safeToExecute, prediction propagation, loop unrolling, and both 32-bit and 64-bit speculative JIT backends, making each of those phase interactions a potential miscompilation surface.
Audit directions
a Aaaaaaaa Aaaa Aaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaa Aaaaaa Aaaaaaaa Aaaaaaaaaaaaaa Aaaaaaaaaaa a Aaa Aaaaaaaaaa Aa Aaaaaaaaaaaaa Aaaaaaa Aa Aaaaaaaa Aaaaa Aaaaaaaaaa Aaaaaaaa Aaaaaa Aaaaaaaa Aaa Aaaa Aaaaa Aaaaa Aaaaaaa Aaaaaaaaa Aaaaaa Aaaaaaa Aa a Aaaaaaaaaaaaa
a Aaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaaa Aaaaaaaaaaaa Aaaaa Aaa Aaa Aaaa Aaaaaa Aaaaaaaaaa Aaa Aaaaaaaaa Aaaa Aaaaaaaaaa Aa Aaaaaaaaaaa Aaa Aaaaaaaaaaaa Aaaaa a Aaaaaa Aaa Aaaa Aaaaa Aaaaaaa Aaaaa Aaaa Aaaaaa Aaaaaaaaaa Aaaaa Aaaaaa Aaaaaaaaaaaaaaaaaa Aaa Aaaaaa Aa Aaaaaaaa Aa Aaaaa Aaaaaaa
a Aaaaaaaaaaaaaaaaaa Aaaaaaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaa Aaaaaa Aaaaaaaaaa Aa Aaaaaaaaaaaaaaaaaa a Aaaaa Aaaaaaaaaaaa Aaa Aaaaaaaa Aaaaa Aaaa Aaaaa Aaaaaaaa Aaa Aaaaaaaaaa Aaaaaaaaaa
a Aaaaaaaaaaaaaaaa Aaaaaaaa Aa Aaaaaaaaa Aaaaaa Aaa Aaaaaaa Aaaaaaaaa a Aaaaaaa Aaaa Aaaaaa Aaa Aaaaaaaaaa Aa Aaa Aaaaaaaa Aaaaaaaaa Aaaaaaaaaaa Aa Aaaaaa Aaaaaaaaaaa
🔒New JIT code paths for a spec function with error semantics — edge cases in the fast path and runtime helpers warrant security investigation.
Subscribe to read more