[JSC] Add DFG MultiGetByVal and MultiPutByVal
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
JSC의 JIT pipeline은 Baseline → DFG → FTL의 세 단계로 구성됩니다. DFG(Data Flow Graph)는 node 기반 IR을 사용해 비교적 빠르게 컴파일하는 speculative JIT입니다. FTL은 그 위에 위치하며, LLVM 기반 IR과 ValueRep phase를 포함한 추가 최적화 pass를 수행합니다. ValueRep phase는 각 값의 표현 방식(tagged JSValue, unboxed int32, int52, double)을 주석 형태로 추적합니다.
MultiGetByVal과 MultiPutByVal은 "polymorphic merge" node입니다. GetByVal 호출 지점에서 여러 array 형태(예: Int32 JSArray, Float64Array, Contiguous JSArray)가 관찰된 경우, JIT는 각 타입별로 specialized fast path로 dispatch하는 branch tree를 생성합니다. 이를 통해 호출마다 generic IC slow path를 거치지 않아도 됩니다.
이 commit은 MultiGetByVal과 MultiPutByVal을 FTL에서 DFG 단계로 이식하였습니다. 다만 Int32Result와 Int52Result 표현 방식은 의도적으로 제외되었습니다. DFG에는 unboxed 정수 표현을 추적하는 FTL의 ValueRep annotation phase가 없기 때문입니다. 결과적으로 지원되는 result 타입은 JSResult와 DoubleResult로 한정됩니다. fixup phase에서는 case가 Int32/Int52 result를 요구할 경우 해당 node를 일반 GetByVal로 변환합니다.
Before: After:
DFG tier DFG tier
GetByVal (polymorphic site) MultiGetByVal (NEW)
└─► IC miss → slow path ├─► Int32 array fast path
├─► Double array fast path
├─► Contiguous fast path
├─► TypedArray fast paths
└─► OOB → undefined (sane chain)
(JSResult / DoubleResult only)
Significance
다양한 타입이 관찰된 array 접근이 FTL 승격을 기다리지 않고 DFG 단계에서 inlined multi-shape dispatch로 최적화될 수 있게 되었습니다. 역사적으로 버그가 많았던 type-specialized JIT code path의 attack surface가 그만큼 넓어진 셈입니다. 이 로직은 이제 SpeculativeJIT라는 별도의 코드 생성기를 통해 생성됩니다. 해당 코드 생성기는 자체적인 OOB 및 speculation 메커니즘을 갖추고 있으며, FTL 대비 테스트가 충분히 수행되지 않은 상태입니다.
Audit directions
- 각 shape별 type check 및 fast-path branch. 특정 array 타입에 대한 type check가 누락되거나 잘못 구현된 경우, 잘못된 fast path에 도달하는 misspeculation이 발생할 수 있으며, type confusion으로 이어질 가능성이 있습니다.
- "sane chain" OOB path. index가 음수가 아님을 추정하여 slow-path 호출 없이
undefined를 반환하는 방식입니다. 이 추정이 잘못 분류되면 trap 없이 OOB read가 발생합니다. MultiGetByValnode를 일반GetByVal로 되돌릴지 결정하는 fixup phase 로직. 조건이 잘못 구현된 경우,Int32/Int52result를 가진 DFG node가 코드 생성 단계까지 살아남을 가능성이 있습니다. DFG는 ValueRep 없이 이 result 타입을 올바르게 표현할 수 없습니다.- result type 분기 자체. emitter에서
JSResult와DoubleResult가 분기하는 지점에서, tag 처리의 off-by-one 오류나 unbox 단계의 누락은 JIT에서 고전적인 type confusion의 원인이 됩니다. 새로 추가된 5개의 stress test가 주요 경로를 다루고 있으나,--useFTLJIT=0옵션으로 실행되므로 DFG와 FTL path 간 커버리지 검증은 아직 이루어지지 않은 상태입니다.
PageAgent에 Page.getResourceTree를 구현했습니다. WebFrameProxy에는 frameName(), childFrames(), null 검사가 포함된 documentSecurityOriginData()가 신설되었으며, multiplexing backendTarget 초기화 시 NetworkManager가 동작 중인 per-page frame 트리를 덮어쓰지 않도록 guard도 추가되었습니다. 한 가지 핵심적인 제약이 있는데, UIProcess의 WebFrameProxy가 cross-origin child의 didCommitLoadForFrame을 수신하지 못한다는 점입니다. 이로 인해 새로운 순회는 frame ID, 부모 연결, name 등 구조적 데이터는 정확하게 반환하지만, cross-origin frame의 URL과 security origin 정보는 stale하거나 부정확한 상태로 남게 됩니다. 이 격차는 commit에서 명시적으로 follow-up 버그로 미뤄두었습니다.
Before: After:
Inspector Frontend Inspector Frontend
└─► per-page PageAgent.getResourceTree └─► backendTarget ProxyingPageAgent.getResourceTree
└─► WebContent A only └─► UIProcess WebFrameProxy tree
(cross-origin: invisible) ├─► main frame [A] url/origin: live
└─► cross-origin [B] url/origin: STALE
└─► grandchild [A] ⚠ ID collision
Significance
이 변경은 Site Isolation process 경계를 넘어 inspector 가시성을 완전히 확보하기 위한 첫 번째 기반 작업입니다. 이전까지 remote process에 위치한 cross-origin child frame은 inspector frontend에서 보이지 않았습니다. 아울러 security origin 데이터에 접근하는 UIProcess 측 새로운 경로가 열렸으며, commit은 cross-origin URL과 origin 보고가 stale한 상태로 남아 있다는 점을 명시적으로 인정하고 있습니다.
Audit directions
- Frame ID collisions. commit은
FrameIdentifier하위 32비트의 충돌 문제를 명시적으로 지적합니다(bug 316663). grandchild가 main frame과 같은 process에 있는 경우 — main(A) → child(B) → grandchild(A) — 현재 순회 로직이 충돌하는 ID를 그대로 생성하며, frame ID를 보안 결정의 고유 키로 사용하는 inspector 로직이 있다면 grandchild(A)와 main(A)를 혼동할 가능성이 있습니다. 이 경우 cross-origin frame이 main frame의 inspector identity를 사칭하는 데 악용될 가능성이 존재합니다. - The new
documentSecurityOriginData()null guard 는 이전의securityOrigin()이 origin이 아직 확정되지 않은 uncommitted frame에서 ASSERT 실패를 일으켰기 때문에 추가되었습니다. frame commit과getResourceTree호출 사이에 race가 발생하면, mid-commit 상태의 frame에서 null 또는 stale origin이 반환될 가능성이 있습니다. 이 null 경로가 downstream의 cross-origin origin 검사를 억제하는 방식으로 유발될 수 있는지 살펴볼 필요가 있습니다. - The
NetworkManagerbootstrap guard 는TargetType.WebPage에 대해getResourceTree를 건너뜁니다. 이 target type 검사가 우회되거나 type이 잘못 설정된 경우, 빈 snapshot이 동작 중인 inspector frame 트리를 덮어쓸 가능성이 있습니다. 결과적으로 cross-origin frame이 security inspector 뷰에서 완전히 숨겨지는 상황이 발생할 수 있습니다.