← All issues

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

a46d2fe

JIT가 RegExp 인자와 함께 String.prototype.replace, .match, .search, .split에 대한 fast intrinsic을 emit하려면, 해당 인자가 "primordial"한지 먼저 증명해야 합니다. 이는 spec이 경유하는 prototype 메서드를 instance가 shadowing하지 않는다는 것을 확인하는 과정입니다. 해당 메서드들은 observable하기 때문에 이 검증을 건너뛸 수 없습니다.

기존 fixup helper는 property마다 TryGetById+CheckIsConstant guard를 emit했습니다. replace helper는 exec, flags, 8개의 flag getter, @@replace까지 포함하면 총 11개에 달합니다. 이 TryGetById들은 profiling 이후에 삽입되므로 type 정보를 갖지 않으며, FTL에서는 비용이 높은 opaque IC patchpoint로 남게 됩니다.

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를 11회 실행 (exec, flags, flag getter 8개, @@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;

이 commit은 호출 지점마다 최대 11쌍의 TryGetById+CheckIsConstant를 단일 CheckStructure로 대체했습니다. 대조 대상은 패치되지 않은 원래 RegExp structure입니다. 동시에 StringPrototypeReplace, StringPrototypeReplaceAll, RegExpSearchIntrinsic에서 누락되어 있던 BadCache exit bail도 함께 추가되었습니다.

이 접근 방식은 두 가지 불변 조건을 활용합니다. 먼저 RegExp.prototype이 변경되면 regExpPrimordialPropertiesWatchpoint가 발동되어 컴파일된 코드 전체가 무효화됩니다. 또한 자체 property를 추가하면 객체의 structure가 전환됩니다. 따라서 structure가 일치한다는 사실은, 해당 instance에 shadowing own property가 없고 prototype도 이미 clean한 상태임을 증명하는 셈입니다.

FTL 컴파일 코드에서 호출 지점당 최대 11개의 opaque IC patchpoint가 제거됨으로써, hot regexp/string-replace path가 1.3~1.6배 빨라집니다. 또한 새 guard가 드러낸 잠재적 recompilation loop 버그도 이번 commit에서 함께 수정되었습니다.

🔒

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

더 확인하려면 구독해 주세요