← All reports

[JSC] New DateNow DFG node

Component: JSC DFG and FTL JIT | d53865e

Source/JavaScriptCore/dfg/DFGClobberize.h

+ case DateNow:
+ read(WallClock);
+ write(WallClock);
+ return;

Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

+ case DateNowIntrinsic: {
+ if (!is64Bit())
+ return CallOptimizationResult::DidNothing;
+ insertChecks();
+ setResult(addToGraph(DateNow));
+ return CallOptimizationResult::Inlined;
+ }

Source/JavaScriptCore/dfg/DFGOperations.cpp

+JSC_DEFINE_NOEXCEPT_JIT_OPERATION(operationDateNow, double, (void))
+{
+ return jsCurrentTime();
+}

JSC's DFG and FTL tiers keep a table of intrinsics — well-known functions like Math.random or Date.now that get special-cased during bytecode parsing so the JIT can emit direct, optimized code instead of a generic call. Each new intrinsic node has to declare its side effects to Clobberize (what memory or state it reads and writes, which governs whether the optimizer may CSE or hoist it), its type to the abstract interpreter, and whether it can GC or is safe to execute speculatively. This commit adds DateNow, inlining Date.now() as a direct call to operationDateNow and introducing a new abstract heap, WallClock, to model the observable state it depends on. Inlining is 64-bit only: the parser bails out via CallOptimizationResult::DidNothing on 32-bit, and DateNow joins the SpeculativeJIT32_64 unhandled-node list. It also joins LoopUnrollingPhase's isNumericComputationNode list, which affects unrolling profitability heuristics rather than loop-invariant hoisting.

Roughly 1.18-1.19x on Date.now()-heavy code by removing the host call boundary, at the cost of a new clobber category every compiler pass must reason about.

New DFG node types are a recurring source of JSC bugs precisely because Clobberize, SafeToExecute, the abstract interpreter, and DoesGC must all be updated consistently — one missed case lets the compiler wrongly CSE, reorder, or mis-speculate the node across an OSR exit. Narrow: verify DateNow's WallClock effects are respected everywhere Clobberize is consulted, including store elimination, dead-code elimination, and any pass that treats a call without declared effects as pure. Wider: the reusable hunt is for other recently added nodes with the same shape — grep DFGNodeType.h for node types added since the last audit and cross-check each against the four tables; a node present in clobberize but absent from safeToExecute (or vice versa) is the classic omission. Also confirm the 64-bit-only gating leaves no mismatched code path on 32-bit builds. Match tell: a new abstract heap introduced by one commit with exactly one reader and one writer — anything that consults heap ranges generically is where it will be missed.