← All issues

[15] FTL MultiGetByOffset constant-function reduced under DoubleRepUse (test backport)

Severity: Low | Component: JSC FTL JIT | 267af1c

이 commit은 regression test만 backport하므로 Low로 평가합니다. 기반이 되는 type confusion fix는 이미 release branch에 적용된 상태이며, 이번 변경이 mainline에 추가하는 것은 fix의 regression 방지 범위를 넓히는 것 이상이 아닙니다.

이 commit은 DFGValueRepReductionPhaseMultiGetByOffset 노드를 처리하는 과정에서 발생했던 FTL 버그(305413.251@safari-7624-branch)의 regression test를 backport합니다. 해당 버그는 case set에 Constant:Function slot과 numeric slot이 혼재하는 상황에서 발생했습니다.

JSTests/stress/ftl-multigetbyoffset-constant-numberuse.js

+let proto = { prop: function() {} };
+let obj1 = Object.create(proto); // Structure A: Property는 Constant:Function
+let obj2 = Object.create(proto);
+obj2.prop = NaN; // Structure B: Property는 Load:0
+
+function trigger(arr) {
+ let res = 0;
+ for (let i = 0; i < arr.length; i++) {
+ let val = arr[i].prop;
+ // Math.min이 DoubleRepUse edge를 강제함
+ res += Math.min(val, 1.0);
+ }
+ return res;
+}
+let arr_warmup = new Array(100).fill(obj2);
+for (let i = 0; i < 5; i++) trigger(arr_warmup);
+let arr_once = [obj1, obj2, obj2, obj2, obj2];
+trigger(arr_once);
+let arr_dfg = new Array(1000).fill(obj2);
+for (let i = 0; i < 1000; i++) trigger(arr_dfg);

이 commit에서 추가된 것은 test 파일 하나뿐입니다. test는 prototype slot을 공유하는 두 가지 object 구조를 구성합니다. obj1은 prototype에서 propConstant:Function으로 상속받고, obj2propNaN으로 shadowing합니다. 이후 IC와 ValueProfile을 warm up한 뒤, DFG/FTL이 두 structure를 모두 포함하면서도 Number만 예측하는 MultiGetByOffset을 바라보도록 만듭니다. 이를 통해 value-rep reduction pass가 buggy path로 진입하도록 유도합니다.

double-typed use 하에서 MultiGetByOffset을 lower할 때, 비수치형 case constant에 대한 escape 처리 누락.

MultiGetByOffset은 property access의 inline cache가 두 개 이상의 structure를 관찰했지만 set의 크기가 inline 가능한 수준일 때 생성되는 DFG/FTL IR 노드입니다. 각 case마다 GetByOffsetMethod를 하나씩 가지며, case 종류로는 offset에서 Load하는 방식, 값이 IR에 직접 고정되는 Constant 방식, 그 외의 변형이 있습니다. ValueProfile은 Baseline JIT와 LLInt가 use 지점에서 관찰한 JSValue 종류를 기록하는 per-bytecode profiling slot입니다. Constant:Function case는 property가 단일 함수를 정적으로 보유하는 것으로 알려진 structure에서 오는 상황에 해당합니다. prototype method에서 흔히 나타나는 패턴으로, IC는 해당 값을 function cell의 Constant로 기록합니다. DoubleRepUseNumberUse는 consumer가 값을 boxed JSValue가 아닌 unboxed IEEE-754 double 형태로 받기를 원한다는 사실을 FTL backend에 알리는 edge-kind annotation입니다. DFGValueRepReductionPhase는 FTL 계층의 DFG phase로, unboxed double representation을 정의 지점 가까이로 끌어당기도록 IR을 재작성합니다.

이전 fix가 적용되기 전, downstream consumer가 DoubleRepUse를 요구하면 DFGValueRepReductionPhaseConstant:Function slot을 포함한 case set을 가진 MultiGetByOffset을 double-typed value chain으로 lower하려 시도했습니다. 이 pass는 MultiGetByOffset의 constant case slot 값을 직접 사용합니다. case가 JSCell constant(여기서는 prototype에서 상속된 function 객체)를 반환하는 상황에서, pass가 모든 값이 수치로 표현 가능하다고 전제하고 double로 변환하면, function cell의 bit pattern이 double로 처리됩니다. 또는 cell을 정확히 표현하지 못하는 강제 변환이 수행될 가능성도 있습니다.

🔒

How a polymorphic property-access node lowered under a double-typed use chain can mis-represent a non-numeric constant — and what that mis-representation means for renderer type safety.

더 확인하려면 구독해 주세요

🔒

Three reusable audit patterns identified, covering the IC/ValueProfile observation skew that has produced this class of FTL type confusion before.

더 확인하려면 구독해 주세요