← All issues

[JSC] Add ArrayJoin DFG nodes

26b192b

DFG는 JSC의 mid-tier JIT compiler로, 각 연산이 그래프의 node로 표현됩니다. ArrayJoin을 node로 추가함으로써, 컴파일러는 generic C++ runtime으로 dispatch하는 대신 Array#join에 대한 native code를 직접 생성합니다. ArrayMode는 관찰된 storage type(Int32, Double, Contiguous, Generic)을 인코딩합니다.

핵심 correctness invariant는 separator object의 toString() side effect가 join() 호출당 정확히 한 번만 실행되어야 한다는 점입니다. toString() 내부에서 array mutation이 발생해 OSR exit가 유발되더라도 마찬가지입니다. JIT가 이미 toString()을 실행한 상태에서 bytecode slow path로 이동하면, 해당 slow path가 toString()을 다시 호출하기 때문입니다.

이 commit의 regression test는 해당 invariant를 직접 검증합니다. toString()이 array를 변형하는(length 축소, indexing type 전환) object separator를 사용할 때, 모든 tier에서 동일한 결과를 내야 하며 calls === testLoopCount가 성립해야 합니다.

OSR exit 경계를 넘나드는 side effect에 민감한 invariant를 가진 새로운 JIT intrinsic은, 역사적으로 JIT vulnerability가 가장 많이 발견된 유형 중 하나에 해당합니다.

OSR exit + toString 이중 호출: toString-once invariant는 미묘합니다. JIT가 array 순회 전에 ToString(sep)를 호출한 상황을 고려해야 합니다. 이때 separator가 아닌 element의 toString() 내부에서 array mutation이 발생해 OSR exit가 일어나면, slow path가 ToString(sep)를 다시 호출하는지 점검해야 합니다. element mutation 경로는 테스트가 부족할 가능성이 있습니다. empty separator fast path는 separator 할당을 건너뛰고 직접 문자열을 연결합니다. DFGSpeculativeJIT64.cppFTLLowerDFGToB3::compileArrayJoin()에서 hole 처리와 순회 중 type 전환을 점검해야 합니다. 누적 문자열 길이의 integer overflow도 확인이 필요합니다. StrengthReductionPhaseArrayJoin을 처리하도록 수정되었습니다. constant separator와 separator의 prototype에 존재하는 getter를 잘못 fold하면 필요한 side effect가 억제될 가능성이 있습니다. ArrayMode mis-speculation의 경우, Int32로 학습시킨 뒤 custom toString()을 가진 Contiguous array를 전달하는 시나리오를 고려할 수 있습니다. speculation guard가 첫 번째 element 접근보다 먼저 실행되는지 확인해야 합니다.