[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한 상태임을 증명하는 셈입니다.
Significance
FTL 컴파일 코드에서 호출 지점당 최대 11개의 opaque IC patchpoint가 제거됨으로써, hot regexp/string-replace path가 1.3~1.6배 빨라집니다. 또한 새 guard가 드러낸 잠재적 recompilation loop 버그도 이번 commit에서 함께 수정되었습니다.
Audit directions
a Aaa Aaaaaaaa Aaaaaaa Aaaaaaaaa Aaaaaaaaa Aa Aaaa Aaaa Aaaaaaaaaa Aaaaaa Aaaaaa Aaaaaaaaaaaa Aaaaaaaaa Aaaaaaaaaa Aaa Aa Aaa Aaaa Aaaaa Aaaaaa Aaa Aa Aaaaaaaa Aaaaaaaaaa Aa Aaaaaaaaaa Aa Aaa Aaa a Aa Aaa Aaa Aaa Aaa Aaaaa Aaaaaa a Aaa Aaaaa Aa Aaaaaaaaaa Aaaaaa Aaaa Aa Aaaaaa Aaa a Aa Aaaaaa
Aaaaa Aaaaa Aaa Aaaaaa Aaaaaaa Aaa Aaaaaa Aa Aaaaaaaaaa Aaaa Aaa Aaa Aaaa Aaaaaaaaa Aaaa Aa Aaa Aa Aaa Aaa Aaaaa
Aa Aaa Aa Aaa Aaaa Aa Aaaaaaaaaa Aaaaaaaa Aa Aaaa Aaaaaaaa Aaaaaaa Aaaaaaaaaaaaaaaaaaaaa Aaaaaa Aaaa Aaaaaa Aaaa Aaaaaaaaaaa Aaaa Aaaaaa a Aaa Aaaaaaaaaaaaa Aaa Aaaaaaaaaa Aa Aaaa Aa Aaaaa Aa Aaaa Aaaaaa
Aaaaaa Aaaaa Aaaaaaaaa Aaa Aaa Aaaaaa Aaaaaaaaaa Aaaa Aaaa Aaaaa Aaa Aaaaaa Aa Aaaaaaaaaaaa a Aaa Aa Aaa Aaaa Aaa Aaa Aaaaa a Aaaaaaaaaaaaaaaa Aaa Aa Aaaaaaaaa Aaaaaa Aaaaaaaaaaaaaaa Aaa a Aaa Aaaaaaaaa Aaaa Aa Aaaaa
🔒The narrowed guard and new fast-exit paths raise several edge cases worth security investigation.
더 확인하려면 구독해 주세요