[JSC] Add String fast iteration
// JSTests/stress/iterator-fast-path-mode-mixing.js
var array = [1, 2, 3];
var map = new Map([[1, 2], [3, 4]]);
var set = new Set([1, 2, 3, 4]);
var ascii = "abcde";
var unicode = "a\u{20BB7}b";
// Mixing more iterable types at one for-of site than the fast iteration
// mode limit must keep working correctly.
JSC의 fast iteration protocol은 JIT가 특정 for-of 루프가 타입이 확정된 컬렉션을 순회한다고 인식할 수 있게 합니다. 이 경우 전체 ECMAScript iteration protocol을 건너뜁니다. Symbol.iterator 호출도, .next() dispatch도, 매 단계마다 {value, done} 객체를 생성하는 작업도 필요하지 않습니다. 기존에는 Array, Map, Set만 fast mode를 지원했습니다. DFG/FTL에서는 루프 본체의 출력을 tuple node로 표현합니다. 이 node의 결과는 GetProjection으로 추출됩니다. ObjectAllocationSinking이 backing iterator가 escape하지 않음을 증명하면, 해당 iterator를 완전히 제거할 수 있습니다.
이번 commit은 이 protocol을 JSString으로 확장하여 네 가지 JIT 티어 전체에 적용합니다. LLInt/Baseline에서는 result 객체 allocation을 방지하기 위해 새로운 JSStringIterator::nextWithAdvance() helper가 도입되었습니다. DFG/FTL에서는 StringIteratorNext(string, position)이 추가되었는데, 이는 tuple을 반환하는 node입니다. allocation sinking과 결합하면 JSStringIterator 자체를 완전히 제거할 수 있습니다. 8-bit 단일 문자의 경우 캐시된 JSString을 반환하는 inline fast path가 적용됩니다. 한편 rope, 16-bit 문자열, surrogate pair는 operationStringIteratorNext를 통해 처리됩니다. per-site fast mode 상한은 2개로 제한되어 inline code 증가를 억제합니다. 3개 이상의 iterable 타입을 혼합하는 사이트는 Generic으로 강등됩니다.
Significance
ASCII for-of 루프에서 약 4배, surrogate pair 문자열에서 약 1.8배의 성능이 향상됩니다. 전체 JS iteration protocol을 우회하는 JIT fast path에 string이 네 번째 인식 타입으로 추가되어, JIT correctness 버그의 새로운 고가치 공격 대상이 됩니다.
Audit directions
advance()의 surrogate pair 경계 처리 정확성. 공유 core 로직은 high/low surrogate pair를 정확히 감지하고 index를 2만큼 전진시켜야 합니다. rope 페이지 경계에 걸친 surrogate, 단독 surrogate, 위치 0과 length-1의 surrogate, BMP와 surrogate가 혼합된 문자열을 대상으로 fuzzing을 수행해야 합니다. off-by-one 오류가 발생하면 이후 모든 iteration에서 정확한 위치보다 한 code unit 앞선 값이 반환됩니다.ObjectAllocationSinking의 escape analysis. getter,Symbol.iteratoroverride, 또는 DFG가 모델링하지 않는 effect 경로를 통해JSStringIterator가 escape하는 경우에도 sinking이 allocation을 제거한다면, 엔진이 가상 iterator로부터 stale하거나 초기화되지 않은 데이터를 읽게 됩니다.DFGClobberize가StringIteratorNext의 모든 effect를 올바르게 표시하는지 점검해야 합니다.- Tuple node pipeline 일관성. AbstractInterpreter, Clobberize, DoesGC, SafeToExecute, FixupPhase, FTL lowering — 각 pass는
StringIteratorNext의 semantics에 대해 일관된 이해를 가져야 합니다. DoesGC가 false를 반환하는데 fallback이 실제로 allocate하거나, SafeToExecute가 잘못된 speculation을 수행하는 경우, JIT로 최적화된 루프가 조용히 잘못 컴파일될 수 있습니다. - fast mode 2개 상한과 mode 강등 시의 race condition. 세 번째 타입이 추가되어 사이트가 특정 fast mode에서 Generic으로 강등될 때, LLInt/Baseline profiling metadata가 짧은 전환 window 안에서 변경됩니다. concurrent JIT 컴파일이 전환 도중 mode를 snapshot하여 잘못된 타입에도 통과하는 guard를 생성할 가능성이 있는지 살펴볼 필요가 있습니다.