[JSC] MapIterator / SetIterator should be handled in DFG
// Source/JavaScriptCore/builtins/MapIteratorPrototype.js: 제거됨.
// Source/JavaScriptCore/builtins/SetIteratorPrototype.js: 제거됨.
+ JSC::VM::fastMapKeysSentinel
+ JSC::VM::fastMapValuesSentinel
+ JSC::VM::fastSetEntriesSentinel
+ JSC::iteratorOpenTryFastImpl
+ JSC::iteratorNextTryFastImpl
JSC의 DFG는 관찰된 타입을 기반으로 speculative optimization을 수행합니다. "iterator를 DFG에서 처리한다"는 것은 IteratorOpen과 IteratorNext IR 노드를 생성하는 동작을 의미합니다. 이 노드들은 JS 함수 호출 방식을 거치지 않고, C++ fast-path 함수를 직접 호출하도록 낮춰집니다. 이 fast path는 watchpoint로 보호됩니다. Watchpoint는 약한 참조로, MapIteratorPrototype.next나 Map.prototype[@@iterator] 같은 보호 대상 객체가 변경되면 즉시 발동하여 OSR-exit를 유발합니다.
이 commit은 MapIterator#next()와 SetIterator#next()를 builtin JavaScript에서 C++로 이동시켰습니다. 아울러 Map/Set 관련 여섯 가지 iteration 메서드 전체를 DFG의 first-class fast path로 연결했습니다. VM에는 세 가지 새로운 sentinel 값(fastMapKeysSentinel, fastMapValuesSentinel, fastSetEntriesSentinel)이 추가되었으며, iteration 모드 구분에 사용됩니다. 기존에는 next()가 JS 수준의 safety guarantee를 통해 실행되었지만, C++로 이동하면서 이 안전망이 제거되었습니다. 따라서 C++ 구현은 JS 버전이 자동으로 보장하던 모든 invariant를 직접 유지해야 합니다.
Significance
이번 변경으로 JIT fast-path가 대규모로 추가되었습니다. 새로운 C++ iterator state machine, DFG IR 노드, watchpoint guard, cross-realm check가 한 번에 도입되었습니다. 각 레이어 모두 type confusion, lifetime 버그, 또는 guard bypass의 잠재적 원인이 될 수 있습니다.
Audit directions
- Watchpoint coverage. stress test는
map-iterator-fast-watchpoint-invalidate-next.js와*-invalidate-symbol-iterator.js를 대상으로 합니다. 두 파일은 각각 서로 다른 prototype slot을 보호합니다. 어느 쪽 watchpoint도 발동시키지 않고 수정 가능한 prototype slot이나 prototype chain 위치가 존재하는지 살펴봐야 합니다. 특히 iterator의 prototype chain이 보호 대상 객체와 달라질 수 있는 cross-realm 시나리오에서 이 점을 중점적으로 점검해야 합니다. - Cross-realm fast path.
*-cross-realm.js테스트가 존재하는 이유는 realm identity 검사가 필요하기 때문입니다. DFG의 type check는 기본적으로 structure 기반이며, realm 기반이 아닙니다. iterator의 structure가 다른 global object에 속할 때 fast path가 올바르게 bail out하는지 확인해야 합니다. - Mid-iteration Map/Set mutation. C++ fast path는 backing storage의 내부 인덱스를 순차적으로 진행시킵니다. DFG가 Map의 structure를 speculate한 상태에서
IteratorNext호출 사이에 Map이 구조적으로 변경(add/delete)되는 경우, 인덱스 관리가 범위를 벗어나거나 삭제된 항목을 참조하게 되는지 확인해야 합니다. - VM sentinel identity. VM에 고정된 새로운 sentinel 세 가지는 pointer identity로 모드를 구분하는 태그입니다. fast path가 pointer identity로 모드를 판별하는 경우, identity check을 우회하는 동등한 객체를 공급해 모드 선택을 혼란시킬 수 있는 경로가 존재하는지 조사해야 합니다.
- OSR-exit safety. watchpoint 무효화로 인해 DFG가 루프 중간에 deoptimize되면, interpreter는 DFG frame에서 iterator 상태를 재구성해야 합니다. 특히
IteratorOpen과 첫 번째IteratorNext사이 구간에서 OSR-exit가 발생할 때, 내부 필드(index, done flag, backing storage pointer)가 올바르게 복원되는지 확인해야 합니다.