← All issues

[JSC] Add Array#concat DFG nodes

94e35cf

Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

+ case ArrayConcatIntrinsic: {
+ if (argumentCountIncludingThis != 2)
+ return CallOptimizationResult::DidNothing;
+
+ if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadConstantCache)
+ || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)
+ || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)
+ || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, ExoticObjectMode))
+ return CallOptimizationResult::DidNothing;
+
+ ArrayMode arrayMode = getArrayMode(Array::Read);
+ if (!arrayMode.isJSArray())
+ return CallOptimizationResult::DidNothing;
+
+ if (!arrayMode.isJSArrayWithOriginalStructure())
+ return CallOptimizationResult::DidNothing;

Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

+ case ArrayConcatArray:
+ case ArrayConcatAppendOne:
+ setTypeForNode(node, SpecArray);
+ break;

DFG (Data Flow Graph) JIT는 JSC의 mid-tier speculative compiler입니다. bytecode를 typed node로 구성된 IR로 변환하고, type prediction 기반의 최적화를 단계적으로 적용한 뒤, assumption이 실패하는 시점에 OSR-exit할 수 있는 speculative machine code를 생성합니다. COW (Copy-on-Write) butterfly array는 array literal을 위한 storage 최적화입니다. backing store를 공유 상태로 유지하면서 read-only로 표시해두다가, 쓰기가 발생하는 시점에 복사가 수행됩니다. Array.prototype.concat은 특히 복잡한 연산입니다. spec이 임의의 객체에 [Symbol.isConcatSpreadable]을 통해 spreading 참여 여부를 결정할 수 있도록 허용하기 때문에, fast path를 적용하려면 반드시 해당 hook의 개입 가능성을 배제해야 합니다.

이 commit은 ArrayConcatArrayArrayConcatAppendOne이라는 두 개의 새로운 DFG/FTL intrinsic IR node를 추가하여 Array.prototype.concat의 JIT 컴파일을 가능하게 했습니다. fixup 단계에서는 type prediction을 활용해 범용 append node를 array 전용 variant로 특수화합니다. fast path는 arrayIsConcatSpreadableWatchpointSet에 대한 watchpoint와 isJSArrayWithOriginalStructure 검사로 보호됩니다. 런타임에 복잡한 side effect가 감지되면 연산은 nullptr를 반환하고, JIT는 ExoticObjectMode를 통해 OSR-exit합니다. 한편 이 patch의 계기가 된 runtime test에는 fix 이전에 존재하던 crash 사례가 기록되어 있습니다. tryConcatOneArgFast에서 non-array 객체가 JSArray에 대한 uncheckedDowncast에 도달해 잘못된 butterfly pointer를 역참조하던 문제였습니다.

fixup 단계는 type prediction을 기반으로 ArrayConcatAppendOneArrayConcatArray로 변환합니다. fixup 결정이 내려진 이후에 type이 바뀌는 입력을 조작하는 것은, JIT type confusion을 유발하는 전형적인 기법입니다. COW butterfly 재사용과 새로운 OSR-exit boundary가 결합되면, JSC가 올해 추가한 코드 중 correctness 버그가 가장 발생하기 쉬운 영역 중 하나에 해당합니다.

🔒

New JIT fast paths for a complex builtin — edge cases in type specialization and COW handling are worth close inspection.

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