Butterfly-less JSObject for Wasm GC
55783b9
Source/JavaScriptCore/runtime/JSObject.h
- WriteBarrier<Unknown> m_butterfly;
+ // m_butterfly moved to JSObjectWithButterfly
Butterfly* butterfly()
{
+ auto* b = *std::bit_cast<Butterfly**>(std::bit_cast<char*>(this) + butterflyOffset());
+ if (type() == WebAssemblyGCObjectType) [[unlikely]]
+ b = nullptr;
+ return b;
}
Source/JavaScriptCore/jit/AssemblyHelpers.cpp
- static_cast<int32_t>(sizeof(JSObject)) -
+ static_cast<int32_t>(JSObject::offsetOfInlineStorage()) -
Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
- loadp JSObject::m_butterfly[objectAndStorage], objectAndStorage
+ loadp JSObjectWithButterfly::m_butterfly[objectAndStorage], objectAndStorage
- addp sizeof JSObject - (firstOutOfLineOffset - 2) * 8, objectAndStorage
+ addp sizeof JSObjectWithButterfly - (firstOutOfLineOffset - 2) * 8, objectAndStorage
JSC에서 butterfly는 JSObject에 연결된 heap-allocated sidecar 구조체로, pointer 왼쪽에는 out-of-line named property를, 오른쪽에는 indexed storage를 보관합니다. JSObject 내에서 butterfly가 위치한 offset은 JIT 코드, LLInt assembly macro, B3 IR lowering 전반에 걸쳐 직접 내장된 값입니다. Wasm GC object(GC proposal로 정의된 struct와 array)는 JS property가 없는 고정된 typed layout을 사용하므로, butterfly를 구조적으로 가질 수 없었습니다. 항상 nullptr였고, 객체당 8바이트를 낭비해 왔습니다.
이 commit은 JSObject를 두 계층으로 분리합니다. butterfly가 없는 JSObject base와, m_butterfly를 담당하는 JSObjectWithButterfly subclass로 계층이 재편됩니다. Wasm GC object는 JSObject를 직접 상속하며, butterfly() accessor는 speculative load 방식으로 이를 보완합니다. HeapCell atom이 항상 16바이트 이상이라는 전제 하에, butterflyOffset()에서 무조건 값을 읽습니다. 이후 type() == WebAssemblyGCObjectType인 경우 결과를 0으로 설정해 common path가 branchless하게 유지됩니다. JIT가 생성한 butterfly load는 type check를 완전히 건너뜁니다. Wasm GC object가 butterfly dereference 이전의 structure/indexing-type guard를 절대 통과할 수 없다는 invariant에 의존하는 방식입니다.
Before: After:
JSObject { m_butterfly, inline... } JSObject { inline... } ← no m_butterfly
├── JSNonFinalObject ├── JSObjectWithButterfly { m_butterfly }
├── JSFinalObject │ ├── JSNonFinalObject
└── WebAssemblyGCObjectBase │ └── JSFinalObject
(m_butterfly always nullptr) └── WebAssemblyGCObjectBase ← 8 bytes saved
Significance
JSC의 핵심 object hierarchy 중 하나가 재구성되었습니다. butterfly pointer나 inline storage에 관여하는 모든 offset 계산, JIT inline cache, LLInt macro, B3 lowering을 빠짐없이 점검하고 수정해야 했습니다. 누락된 지점은 그대로 silent memory corruption으로 이어집니다. 직접적인 개선 효과는 Wasm GC heap 사용량 감소입니다.
Audit directions
a Aaaaaaaaaaaaaaaa Aaaaaaaaaaa Aaaaaaa a Aaaaaaaaa Aaaaaa Aaaaaaaaa Aaaaaaaaaaaaaaaaaaaa Aaa Aaaa Aaaaaaaa Aaaaa Aa Aaaaa Aaaaa Aaaaaaaaaa Aaaaaa Aa Aaaaaaaaaa Aaa Aaaaa Aaa Aaaaaa Aaaaaaa Aaa a Aaa Aaaaaaaaaaaaa Aaaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaa Aa a Aaaa Aaaa Aaaaaaaaaaa Aaaaa Aaa Aaaaaa
a Aaaaaa Aaaa Aaaaa Aaaaa a Aaaaaaa Aaaaaa Aaaaaaa Aaaaaaaaa Aaaa Aaa Aaaaaaaaaaaaaaaaaaaaaaa Aaaaaa Aaa a Aa Aaa Aaa Aaaaaaaaa Aaaaa Aaaaa Aaaaaa Aaa Aa Aaaaaaaaaaa Aaa Aaa Aa Aaa Aaaaaaaaaaaaa Aa Aaaaa Aa Aaaaaaaaaa Aaaa Aaa Aaaa Aaaaa Aaaaaaaaaaa Aaaaa Aaaaaa Aaaaaaa Aa Aaaaaaaa Aaa Aa Aaaa Aa Aa Aaa Aaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaaa Aaaa Aa Aaa Aaaaaa
a Aaaaaaaaaaaaaaaa a Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa a Aaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaa Aaaaa Aaaaaaaaaaa Aaa Aaaaaaaaaaaaaa Aaaaaa Aaaaa Aaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaa Aa Aaaa Aaaaaaaaaaaaaaa Aaaa Aaa Aaaa Aaaaaa Aaaa Aa Aaa Aaa Aaaaaa Aa Aa Aaa Aaaaaaa Aaa Aaaa Aaa Aaaaa Aaa Aaaaaa
a Aaaaaaaaaaaaaaaaaaaa Aaaaaaaa Aaaaaaaaaaaaaa Aaaaa Aaaaaa Aaaaaaaa Aaaaaaa Aaaaaaaa Aaaaaaaaaaaaaaaaaaa Aaaaaa Aaaaaaa Aaaa Aaaaa Aaaa Aaa Aa Aa Aaa Aa Aaaaaa Aaaaaaaaaaaaaaaaaa Aaaaaa Aa Aaa Aaaaaa Aaa a Aaaaa Aaaaaaaaaaaaaaaaa Aaa Aaaaaaaa Aaaaa Aa Aaaa Aaa Aaa Aaa Aaaaa
🔒The speculative butterfly load and the JIT bypass invariant both have edge cases in newly introduced code paths worth investigating.
더 확인하려면 구독해 주세요