← All issues

DFG `ArrayIsArray` clobberize refinement

bc02c09

Source/JavaScriptCore/dfg/DFGClobberize.h

- // ArrayIsArray fell through to clobberTop() — no explicit case existed
+ case ArrayIsArray:
+ read(MiscFields);
+ write(SideState);
+ def(HeapLocation(ArrayIsArrayLoc, MiscFields, node->child1()), LazyNode(node));
+ return;

Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

case ArrayIsArray:
- clobberWorld();
setNonCellTypeForNode(node, SpecBoolean);
break;

Source/JavaScriptCore/dfg/DFGHeapLocation.h

+ ArrayIsArrayLoc,

The DFG JIT represents a JS function as a data-flow graph of nodes. Each node's clobberize rule tells the compiler which heap locations the node reads, writes, and defines — driving CSE, LICM, and alias analysis. A node that falls through to clobberTop() conservatively invalidates every heap location, preventing virtually all optimization around it. The abstract interpreter uses complementary annotations; clobberWorld() discards all inferred type information.

This commit replaces the overly conservative clobberTop() for the ArrayIsArray DFG node with precise read(MiscFields) / write(SideState) / def(ArrayIsArrayLoc) annotations and drops clobberWorld() from the abstract interpreter. The read(MiscFields) covers the proxy handler slot (which can be nullified by revoke()), write(SideState) models the conditional TypeError on revoked proxies, and def(ArrayIsArrayLoc) enables CSE of redundant Array.isArray() calls on the same value.

Before:
  Array.isArray(x)   →  clobberTop()  →  invalidates ALL heap locations
                                          no CSE, no LICM possible

After:
  Array.isArray(x)   →  read(MiscFields)      // proxy handler slot
                         write(SideState)      // TypeError on revoked proxy
                         def(ArrayIsArrayLoc)  // enables CSE

  revoke() Call node →  clobbers Heap ⊇ MiscFields  →  kills ArrayIsArrayLoc
                                                         (prevents CSE across revocation)

This yields a ~1.76x speedup on CSE-able Array.isArray() patterns, but more importantly it encodes new semantic claims about IsArray into the JIT's optimization model — claims that must be exactly correct or miscompilation follows.

🔒

New JIT optimization axioms about proxy semantics — the kill chain and chain-walk assumptions are worth auditing for edge cases.

Subscribe to read more