← All issues

DFG/FTL ArrayUnshift intrinsic

5965900

JSTests/stress/array-unshift-intrinsic-ftl.js

+(function () {
+ function unshiftDouble(a, v) { return a.unshift(v); }
+ noInline(unshiftDouble);
+ for (var i = 0; i < testLoopCount; ++i) {
+ var array = [1.5];
+ shouldBe(unshiftDouble(array, 2.5), 2);
+ }
+ var array = [1.5];
+ var r = unshiftDouble(array, NaN);
+ shouldBe(r, 2);
+ shouldBe(array.length, 2);
+ shouldBe(Number.isNaN(array[0]), true);
+ shouldBe(array[1], 1.5);
+})();

JSC uses a tiered JIT (Baseline → DFG → FTL). For hot built-in functions, the DFG bytecode parser recognises an "intrinsic" and emits a specialised DFG node. Array.prototype.unshift is more complex than push: it must shift all existing elements one or more positions toward higher indices, involving a memmove of the butterfly storage. For Contiguous arrays (which hold GC-managed JSValues), every moved element also requires a write barrier.

This commit implements Array.prototype.unshift as a first-class DFG and FTL intrinsic. Int32, Double, and Contiguous array storage types are supported with inline fast paths for 0- and 1-element unshift; ArrayStorage falls back to the slow path. The intrinsic is wired through bytecode parser, fixup, clobberize, abstract interpreter, speculative JIT (64-bit), and FTL B3 lowering.

Adds a new JIT-compiled code path for a mutation-heavy array operation that shifts all existing elements rightward in memory — a historically fertile area for type confusion and bounds errors in JIT compilers.

🔒

New JIT-compiled memory-mutation fast paths with inline butterfly writes and GC barriers — several edge cases are worth security investigation.

Subscribe to read more