JSC ArrayLengthStore inline cache for JSArray length assignment
JSTests/stress/array-length-store-ic-warm-then-freeze-strict.js
JSTests/stress/array-length-store-ic-cow.js
JSC의 inline cache(IC) 시스템은 property 연산을 type에 특화된 machine-code stub으로 캐싱합니다. JIT이 property access를 만나면 객체의 structure ID를 키로 삼아 stub을 생성하고, 이후의 접근은 generic slow path를 거치지 않고 직접 해당 stub으로 처리됩니다.
JSArray의 length property는 일반 stored property가 아닙니다. "custom value"로서, setter인 JSArray::setLength가 다섯 가지 array storage mode(Undecided, Int32, Contiguous, Double, ArrayStorage/SlowPutArrayStorage) 전반에 걸쳐 invariant를 강제합니다. 기존에는 JSArray::put이 length에 대한 PutPropertySlot을 uncacheable로 남겨두어, arr.length = N 대입이 호출마다 operationPutByIdStrictGaveUp, 즉 generic slow path를 통과했습니다.
이 commit은 AccessCase::ArrayLengthStore라는 새로운 IC 타입을 추가하여 일반적인 shrink case를 inline으로 처리합니다. Int32Shape 또는 ContiguousShape를 가진 배열에서, 새로운 length가 현재 publicLength 이하의 non-negative int32인 경우, 생성된 stub은 butterfly storage의 tail slot을 비우고 publicLength를 직접 갱신합니다. 그 외의 경우 — grow, ArrayStorage mode, non-integer length, COW 배열 — 는 slow path로 폴백됩니다.
Before:
arr.length = N
└─► putById ──► tryCachePutBy ──► (uncacheable, gives up)
└─► operationPutByIdStrictGaveUp
└─► JSArray::put (every call)
After:
arr.length = N
└─► putById ──► IC lookup
├─ [ArrayLengthStore stub: Int32/Contiguous, newLen ≤ publicLen]
│ └─► zero tail slots ──► update publicLength (fast, inline)
└─ [miss / grow / ArrayStorage / non-int]
└─► operationPutByIdStrictGaveUp ──► JSArray::put (slow)
Significance
DFG/FTL 티어에서 push-then-reset 패턴의 성능이 3.5–4.3배 향상되었습니다. 이 패턴은 pool 기반 allocation에서 매 반복마다 length를 0으로 줄여 배열을 재사용하는 방식에서 자주 나타납니다. 이 성능 향상은 hot shrink case에서 JSArray::put → setLength 전체 경로를 제거하고, 슬롯을 비우고 length를 저장하는 소수의 inline 명령으로 대체한 데서 비롯됩니다.