Promise combinator fast path for non-thenable elements
ECMAScript 명세는 Promise.all/allSettled/any/race가 각 입력 값에 대해 Promise.resolve(element)를 호출하도록 규정하고 있습니다. 이 과정에서 callable .then 프로퍼티가 있는지 확인합니다. Non-thenable 값의 경우, 이 과정은 오직 downstream callback을 microtask로 큐에 넣기 위한 fulfilled Promise를 생성하는 데 그칩니다. 이는 순수한 할당 오버헤드입니다. 이 최적화가 안전하려면 thenability 검사가 관찰 가능한 side effect 없이 수행될 수 있어야 합니다.
이 commit에서는 정적으로 non-thenable임이 확인된 요소에 대해 중간 Promise.resolve(value) JSPromise 셀 할당을 건너뛰는 fast path가 추가되었습니다. 대신 resolver microtask를 직접 큐에 삽입합니다. 새로운 isNonThenable predicate가 이 최적화의 진입 조건을 제어합니다.
Significance
primitive나 plain object로 구성된 배열에서 1.4~1.7배의 성능 향상이 벤치마크에서 확인되었습니다. 다만 isNonThenable predicate가 완벽하게 정확해야 합니다. false positive가 하나라도 발생하면 관찰 가능한 ECMAScript 동작이 달라집니다.
Audit directions
- Proxy 객체. 명세상
.then프로퍼티 접근은 관찰 가능해야 합니다.isNonThenable이 structure check나 fast-property lookup을 통해 Proxy 가로채기를 우회하는 경우,Proxy({ }, { get(t,p){ if(p==='then') return ()=>{}; } })형태의 객체가 잘못 분류될 가능성이 있습니다. - Prototype 체인 thenability. Plain object는 prototype 체인에
.then이 없으면 non-thenable입니다. 검사는 전체 체인을 순회하거나,Object.prototype또는 중간 prototype 어딘가에then이 추가될 때 무효화되는 structure-level guard를 사용해야 합니다. - Non-callable
then. ECMAScript는 thenable을 callable.then을 가진 객체로 정의합니다.then: 42처럼 callable이 아닌 값이 있는 객체는 thenable이 아닙니다. Predicate는 프로퍼티의 존재 여부가 아니라 callable 여부까지 검사해야 합니다. - Promise 서브클래스 /
Symbol.species상호작용.resolve를 재정의한 커스텀 서브클래스는 fast path가 해당 서브클래스의resolve를 완전히 우회하는 경우 영향을 받을 수 있습니다. - JIT 컴파일. JSC가 combinator hot loop 경로를 JIT 컴파일하고
isNonThenable을 인라인 처리할 경우, deoptimization 하에서도 type feedback과 guard가 올바르게 유지되는지 확인이 필요합니다.