← All reports

[JSC] Inline string === "constant"

Component: JSC JIT | 8bd3c1b

JSTests/stress/string-strict-equal-short-constant-stale-8bit-substring.js

+// A substring rope caches its base's 8-bit flag, but atomizing the base can swap in an equal 16-bit StringImpl.
+function test(s) { return s === "abcde"; }
+noInline(test);
+...
+const sub = content.slice(0, 5);
+
+const wide16 = ["", ("\u3042" + content).replace("\u3042", "")].join("");
+const object = {};
+object[wide16] = 1;
+object[content] = 2;
+
+for (let i = 0; i < testLoopCount; ++i) {
+ if (test(sub) !== true)
+ throw new Error("substring of a base swapped to a 16-bit atom compared unequal");
+}

FTL is JSC's top-tier JIT, lowering DFG IR to B3, then Air, then machine code. A JSString may be a rope (concatenation or substring) or resolved to a StringImpl that is either 8-bit (Latin-1) or 16-bit (UTF-16), and JSString caches an is8Bit flag; atomizing a string can swap its StringImpl for an equal atom of a different width.

FTL now inlines string === "constant" when the constant is 8-bit and at most 16 chars: it checks length, loads the string's data, and compares one or two slices as BitOr(BitXor(slice0, c0), BitXor(slice1, c1)). A new ARM64 B3 lowering rule turns that XOR/OR shape into a cmp/ccmp chain. Stress tests cover keyword-style comparisons, 8- and 16-bit sources, and the stale-8-bit substring case above.

CompareStrictEq(str, K)   (K 8-bit, <= 16 chars)
  ├─► not a cell / not string ─► slow path
  ├─► length != len(K)        ─► false
  ├─► resolve + 8-bit check   ─► slow path
  └─► load slice(s): BitOr(BitXor(s0,k0), BitXor(s1,k1)) == 0
        └─► ARM64 B3 lowering: cmp + ccmp chain

Short-constant compares are common in parsers, tokenizers and keyword checks, and inlining removes the generic string-equality call from those hot paths. The new ARM64 cmp/ccmp lowering is not string-specific: any B3 code producing the same XOR/OR compare shape now takes it.