← All issues

[JSC] Replace fixup-inserted RegExp primordial `TryGetById` chains with a single `CheckStructure`

a46d2fe

Before the JIT can emit a fast intrinsic for String.prototype.replace, .match, .search, or .split with a RegExp argument, it must prove the argument is "primordial" — that the instance doesn't shadow any prototype methods the spec routes through, since those are observable. The old fixup helpers emitted a TryGetById+CheckIsConstant guard per property (the replace helper checked exec, flags, eight individual flag getters, and @@replace — eleven total). These TryGetByIds are inserted after profiling, so they carry no type information and survive in FTL as expensive opaque IC patchpoints.

Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

- void addStringReplacePrimordialChecks(Node* searchRegExp)
+ void addRegExpPrimordialStructureCheck(Node* regExp)
{
Node* node = m_currentNode;
JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic);
- // ... emitPrimordialCheckFor x11 (exec, flags, 8 flag getters, @@replace)
+ m_insertionSet.insertNode(
+ m_indexInBlock, SpecNone, Check, node->origin,
+ Edge(regExp, RegExpObjectUse));
+ Node* lastIndexProperty = m_insertionSet.insertNode(
+ m_indexInBlock, SpecNone, GetRegExpObjectLastIndex, node->origin,
+ Edge(regExp, RegExpObjectUse));
}

Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

+ if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache))
+ return CallOptimizationResult::DidNothing;

This commit replaces up to eleven TryGetById+CheckIsConstant pairs per call site with a single CheckStructure against the original unpatched RegExp structure, and simultaneously adds the previously absent BadCache exit bail to StringPrototypeReplace, StringPrototypeReplaceAll, and RegExpSearchIntrinsic. It exploits two invariants: regExpPrimordialPropertiesWatchpoint fires (invalidating all compiled code) if RegExp.prototype is mutated, and adding any own property transitions an object's structure. So a structure match proves the instance has no shadowing own properties and the prototype is already known clean.

Hot regexp/string-replace paths run 1.3–1.6x faster because up to 11 opaque IC patchpoints per call site are eliminated from FTL-compiled code; the change also fixes a latent recompilation loop bug exposed by the new guard.

🔒

The narrowed guard and new fast-exit paths raise several edge cases worth security investigation.

Subscribe to read more