DFG node for `String.fromCodePoint`
The DFG abstract interpreter still folded `[...set]` as side-effect-free after a slow path was added that runs a user-defined Symbol.iterator.
Source/JavaScriptCore/dfg/DFGOperations.cpp
JSC의 계층형 JIT(Baseline → DFG → FTL)는 bytecode 파싱 단계에서 특정 built-in 함수를 인식하고 전용 IR node를 생성합니다. String.fromCodePoint는 String.fromCharCode보다 구현이 까다롭습니다. 첫째, 인자가 Int32로 증명된 경우에도 비정수, 음수, 0x10FFFF 초과 입력에 대해 RangeError를 throw해야 합니다. 둘째, supplementary plane의 code point는 high/low surrogate 두 단위로 구성된 surrogate pair를 생성해야 합니다.
이 commit은 StringFromCodePoint DFG node와 FromCodePointIntrinsic을 추가했습니다. [0, 0xFF] 범위의 Int32 인자에 대해서는 compileStringFromCharCodeOrCodePoint를 통해 StringFromCharCode와 fast path를 공유합니다. 더 큰 code point나 surrogate pair, RangeError 케이스는 operationStringFromCodePoint(Int32 slow path) 또는 operationStringFromCodePointUntyped로 fallback됩니다. 한편 node는 NodeMustGenerate를 유지하며 write(SideState)로 모델링되어, optimizer가 side effect 없는 연산으로 취급하지 못하도록 합니다.
Significance
이번 변경으로 Latin-1 code point에서 측정 기준 약 5.2배의 성능 향상이 달성되었으며, String.fromCodePoint가 JIT intrinsic 계층으로 편입되었습니다. 새로운 DFG intrinsic은 clobberize, doesGC, safeToExecute, prediction propagation, loop unrolling, 그리고 32-bit 및 64-bit speculative JIT backend 전체에 걸쳐 연결되어야 합니다. 각 phase와의 상호작용은 모두 잠재적인 miscompilation 지점에 해당합니다.
Audit directions
- Shared fast path with
StringFromCharCode.StringFromCharCode와 공유되는 Latin-1 branch는fromCharCode의 전제 조건을 그대로 계승합니다. signed/unsigned Int32 처리 방식의 차이나 음수 값이 fast path에 도달하는 경우,RangeError대신 잘못된 결과가 반환될 가능성이 있습니다. write(SideState)andNodeMustGenerateretention. 이 두 플래그는 optimizer가RangeErrorthrow를 재배치하거나 제거하지 못하도록 막는 유일한 방어 수단입니다. fixup 과정에서Int32Use를 할당하는 모든 code path가NodeMustGenerate를 유지하는지, 이후 phase에서 제거되지 않는지 확인해야 합니다.- Double-to-uint32 conversion in
operationStringFromCodePointUntyped.static_cast<uint32_t>(codePointAsDouble)으로 먼저 변환한 뒤codePoint != codePointAsDouble를 통해 유효성을 검사합니다. negative zero, 매우 큰 double 값, NaN truncation 동작을 면밀히 살펴볼 필요가 있습니다. - Surrogate-pair boundary at 0x10000 untyped operation 내부에서의
0x10000surrogate pair 경계는 고전적인 fuzz target입니다. high/low surrogate 계산이나 buffer 할당에서의 off-by-one 오류를 점검해야 합니다.