← All issues

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

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

Rated Low because the commit only backports a regression test; the underlying type-confusion fix landed earlier on a release branch, so this change does not introduce a new mitigation in mainline beyond improved coverage against regression of the fix.

This commit backports a regression test for a previously-landed FTL bug (305413.251@safari-7624-branch) in DFGValueRepReductionPhase's handling of MultiGetByOffset nodes whose case set mixes a Constant:Function slot with a numeric slot.

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

+let proto = { prop: function() {} };
+let obj1 = Object.create(proto); // Structure A: Property is Constant:Function
+let obj2 = Object.create(proto);
+obj2.prop = NaN; // Structure B: Property is Load:0
+
+function trigger(arr) {
+ let res = 0;
+ for (let i = 0; i < arr.length; i++) {
+ let val = arr[i].prop;
+ // Math.min forces a 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);

Only the test file is added in this commit. The test constructs two object structures sharing a prototype slot — obj1 inherits prop as a Constant:Function from the prototype, obj2 shadows prop with NaN — then warms up the IC and ValueProfile so the DFG/FTL sees a MultiGetByOffset with both structures but a Number-only prediction, driving the value-rep reduction pass through the buggy path.

Missing escape of non-numeric case constants in MultiGetByOffset when ValueRepReduction lowers the node under a double-typed use.

MultiGetByOffset is a DFG/FTL IR node emitted when an inline cache for a property access has observed more than one structure but the set is small enough to inline; it carries a GetByOffsetMethod per case, where a case can be Load-from-offset, Constant (the value is baked into the IR), or other variants. ValueProfile is a per-bytecode profiling slot updated by the Baseline JIT/LLInt that records the JSValue kinds seen at a use site. Constant:Function case: when a property comes from a structure whose slot is statically known to hold a single function (typical for prototype methods), the IC records the value as a Constant of a function cell. DoubleRepUse/NumberUse are edge-kind annotations that tell the FTL backend the consumer wants the value materialised as an unboxed IEEE-754 double rather than a boxed JSValue. DFGValueRepReductionPhase is an FTL-tier DFG phase that rewrites the IR to push unboxed double representation closer to definitions.

Before the prior fix, DFGValueRepReductionPhase would attempt to lower a MultiGetByOffset whose case-set contained a Constant:Function slot into a double-typed value chain when the downstream consumer demanded DoubleRepUse. The pass uses the MultiGetByOffset's constant case slot values directly; when a case yields a JSCell constant (here, a function object inherited from the prototype) and the pass converts it to a double under the assumption that all values are numerically representable, the function-cell bit pattern is either treated as a double or the pass forces a conversion that does not faithfully represent the 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.

Subscribe to read more

🔒

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

Subscribe to read more