
2026/06/21 2:02
Bun で、JavaScriptCore に共有メモリスレッドを追加するオープンされたPRがあります。
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
概要
このプロジェクトにおける最も重要な更新は、JSC 内で共有ヒープスレッドサポートの成功裏な実装であり、グローバルインタープリタロック(GIL)を除去することで、複数のスレッドが同時に安全にメモリを管理できる N-ミューテーター実行モデルを可能にしました。21 の戦略的コミットとデータ競合なしを厳密に確認したテストによって実現され、このリリースはスレッド分解用のストップザワールドコンダクタープロトコルを利用する VM-lite 実行状態、スレッド別アロケータ、TID/SW-タグ付けされたセグメンテッドバタフライを含む重要なアーキテクチャシフトを導入しています。また、ビルドの安定性に関する長年の問題、ICU スタティックアーカイブのリンク順序、外部ライブラリの依存関係の問題を解決しました。パフォーマンスベンチマークでは、「アロケーター課税」の著しい減少が見られ、共有ヒープ課税が〜1912ms から 453ms に低下し(76.3% の減少)、スリムシンク穿通の大部分を廃止したような特定の最適化も実現しました。主な安定性修正としては、
String.fromCharCode レースによって引き起こされる無限再コンパイルループの解消と、ファッジングキャンペーン中に発見された setButterfly foreign-TID owner-assert escape 問題への対処が含まれます。今後の仕事は、スレッドごとの高度なマイクロタスクキューの実装と、ヘビーな配列操作などの複雑なタスクに対してマルチコアハードウェアを完全に活用することを中心に行われます。本文
共通ヒープスレッドサポート設計仕様の追加と開発成果
以下の記事の内容に基づき、共通ヒープスレッドサポートに関する設計仕様の追加、実装詳細、および検証結果を整理しました。
概要
- 総コミット数: 21 回の実装が行われました。
- メイン目的: ヒープサーバーとスレッド固有のアロケータ、共有仮想マシン(VM)の状態などを統合した設計仕様の策定と実装です。
デザイン仕様とアーキテクチャ
設計ドキュメントの拡張
- TSAN(スレッドサニタイザ)、レース条増幅器、ベンチマークゲート: ドキュメントが作成・更新されました。
- THREAD.md: 共有ヒープ実装のための設計概要が含まれています。
シリアライゼーションと原子操作
- 有効化フラグ:
フラグを適用すると以下が有効化されます。--useThreads- Thread/Lock/Condition/ThreadLocal API
- プロパティ上の原子操作(VM の JSLock によりシリアライズ)
- 機能: これらは forthcoming の共有ヒープ実装のためのセマンティックなオラクルとして機能します。
実装構成とスレッドモデル
- N ユーザー(mutator)モデル:
- スレッド固有のアロケータ
- N スレッド安全ポイントを持つマルチユーターヒープ
- プロセス全体にまたがるシャード化された原子テーブル
- リソース管理:
- StructureID 割り当てロック
- スレッド固有の VM ライト実行状態
- TID/共有書き込みタグ付けバタフライ(セグメント化フォールバック付き、TTL ウォッチポイント省略)
- FTL とエポックベースのコードブロック回収付きティアごとの TID/SW チェック
- GIL 戦略:
- GIL は
のフォールバックレイヤーとして保持されます。--useThreadGIL
- GIL は
スレッドコーパスと待機者リスト修正
- ゲート主導の修正 (6 回):
- スレッド固有の CLoop スタックによる共有スタックフレーム汚損回避
- LocalAllocator とヒープの共有モードでのレース条件修正
- 引退した JIT アーティファクトの会計処理
- 待機者リストおよび条件ウェイクアップの修正
- 派生スレッド用の LLInt キーパス初期化
- パフォーマンス:
- バタフライレジームディスパッチ(スローパス)の修正
内のフラグオンによる JIT データリーク前のウォッチポイント解除(disarm)~CodeBlock
- テスト結果: コーパス 85 テスト中 81 テストが合格。ランナーへのタイムアウト追加、ハング状態の失敗報告対応済み。
スレッドコーパスとハンドアウト
- 派生スレッド (
):trySpreadFast- レーシングな同形状アッドストーム下での平坦専用
アクセッサへの到達butterfly() - パスのレジームに基づいたディスパッチ(汎用的なスローパスへフォールバック)
- スレッドエントリーシーケンスの物質化(実装):すべてのティアに対して JIT ステートを参照可能に。
- レーシングな同形状アッドストーム下での平坦専用
- SPEC-ungil.md (N ユーザー実行モデル):
- JSLock GIL オフエントートークンモード
- スレッド固有のマイクロタスク/タスクキュー(キープアライブライフタイム付き)
- ストップ・ザ・ワールドコンダクタープロトコル(seq_cst ストップビット/アクセスディッカーペア)
- スレッド破棄状態機械(ライトレジストリロック下での TEARDOWN/COLLECTED/DETACHED)
- VM 完了フェンス、レジーニシャット所有者再エントリー契約、終止モデルなど。
パフォーマンス評価とソース変更
測定結果:オーバーヘッドとギャップ分析
- 証拠パック:
が提出されました。SHAREDHEAP-ALLOC-EVIDENCE.md - キャッシュ効率:
- 7,090 万セルの**99.67%**はすでに間隔インクリメント(Riptide の bump-in-fresh-block パス)を受信済みです。
- リフィルはアロケーションの0.33% / ウォールクロック時間の約**4.1%**に過ぎません。
- 税(オーバーヘッド):
- 測定可能なセルあたりの税は、3 ホップのアロケータールックアップ(
→allocationClientForCurrentThread
→allocatorForSizeStep
で約250ms)です。allocateForClient - より高いレバレッジを持つゼロ RSS 候補としては、「(スレッド, サイズクラス) ごとに LocalAllocator* をキャッシュ」するアプローチがあります。
- 測定可能なセルあたりの税は、3 ホップのアロケータールックアップ(
- ギャップ分解 (intcs W=1):
- +5889msのギャップのうち、約**1912ms(33%)**のみが共有 GC ヒープ + GIL オフの税です。
- 残りの約**3937ms(67%)**は純粋な JSC の床価格(WTF::equal マップキー比較、lockProtoFuncHold、ロープ解決、IC ミスなど)です。
ベンチマークゲートと結果 (§41, §42, §43)
- §41 (clean-tree リベースライン化):
- すべての値が§40 と**±3%**以内。
- すべてのがリーン、RSS は **+10%**以内。
- §42:
- intcs W=1 で -646ms(税 1912 → 1214)。
- RSS: intcs W=1 は -2.3%、W=16 は -10.4%。
- 残存:約**75%**の単一メカニズム(JSRopeString+JSString = セルの 71%)。MakeRope チャンクトラバーサルが課題となっています。
- §43:
- intcs W=1 でさらに -761ms、累積削減量1,459ms。
- 元の 1,912ms の税の**76.3%**に減少しました(現在は 453ms)。
コード最適化とインフラ変更
- (H-VMLITE-TLCPTR): JIT コンパイル時にプロセス一定の TLC スロットインデックスを構築し、スレッド固有の LocalAllocator* を VMLite 相対値としてロードします。
- H-TLS-TABLE: C++
の共有 GC ヒープアームを簡素化しました。CompleteSubspace::allocate - H-TLC-FIXEDTABLE-NOREALLOC: TLC テーブルを事前に拡張することで、キャッシュされたポインタの古さを防ぎます。
- defer-hoist-lazyslow:
を引き上げ、定常状態から操作します。DeferGCForAWhile
詳細修正と機能追加 (§45, §48, 他)
JSArray とバタフライ処理 (Task-8)
- H-ISO-TLCSLOT: GCClient::Heap 作成時にタイプごとの IsoSubspace TLC スロットスタンプを設定します。
- JSArray は除外(nullopt を返す)。
- §4.2 ensureLength で fresh インライン JSArray は foreign として読み取られ -> セグメント化されます。
- Thin-thunk: gilOff 定常状態では、JIT コード内で T8 acquire-load
を行い、null でなければ tail-jumpします(no saveAllRegisters/restoreAllRegisters ダンプ)。m_stubCodePtr
DFGByteCodeParser および Bench Gate
- DFGByteCodeParser handleGetById:
下では、BadIndexingType チェックを行い、ヒット時は GetById IC ノードへフォールバックします。useJSThreads - bench.js: §44 prewarm が削除されました(もはや不要)。
フォーローイングおよびコンバージェンス (§45)
- force-worker-reify: 12/12 SLOW -> 12/12 FAST [1563, 1650]。
- String/Object は Flat (StayFlatShared)。
- Array はセグメント化(cap 8->16)ですが、バッフルは収束します。
- NEW r47: 2 時間再ファージ後、8/9 = 一つのルートファミリでエラーが発生しました。
- エスケープ要因:
が以下でエスケープします:setButterfly foreign-TID オーナーアサート- JSArrayBufferView::slowDownAndWasteMemory (uninitialized read)。
- shiftButterflyAfterFlattening。
- flattenDictionaryStructureImpl。
- 修正は決定的なアボートであり、r47 修正ラウンドへDEFERREDされました。
- エスケープ要因:
SlowDownAndWasteMemory 修正
- セルロック付き再チェック: build wastage バタフライ LOCAL + fill IndexingHeader::arrayBuffer をパブリッシュ前 -> storeStoreFence -> tag-PRESERVING seq_cst CAS。
- 結果: r47-001 オーナー TID と r47-002 パイズン arrayBuffer mid-publish が閉鎖されました。
既存バッファの認識 (SURFACED リード)
- existingBufferInButterfly + JIT emitLoadTypedArrayArrayBuffer — wasteful TA は SEGMENTED ワードを運ぶことができます(foreign-TID 命名プロパティ)。
- 「wasteful-mode バタフライは決してセグメント化されない」というコメントは誤りでした。
テスト、検証、および安定性確認
TSAN スキャンと結果 (Full-JIT GIL オフ)
- 修正ウェーブ: 27 の修正(racy-probe-vs-allocator-handout パターン上の relaxed-atomic 変換)。
- レース状態:
- 40 アクティブレース: すべて正当化あり。
- 6 つは既存アップストリーム並列 GC。
- 23 個はウェーブ 7 アトミックプローブ vs アロケーターリーダーサイド。
- その他:recordParse rule-1、JIT ワンサイダーアロケーターサイド §0 受容されたトレードオフなど。
- CLoop エントリ: 0(定常決まりによるオフ)。
- 40 アクティブレース: すべて正当化あり。
- Exit ステート: 229/247 exit-0(キャンペーンで最高のランヘルス)。ゼロでない exit はすべて 0 データレースレポートを運んでいます。
ベンチマークゲート (RED)
- transition-heavy-constructor +5.71%(loadavg 1.76 で再測定 +5.38% — ロード安定)。帰属は未証明;クロージアウトは +3.9%、r27 は +1.7pp より悪い。
- megamorphic-access -13.3%(記録、主張しない)。
リバースエンジニアリングと再試行
- 前キャンペーンクラッシュファイル (292 件): post-§46+TSAN Fuzz バイナリに対して 3 回再実行され、再現はゼロです。
- §46 正しさクローズ + TSAN r27 は、ファザーが以前に見つけたものをすべて閉鎖しました。
- triage-r1-batch.sh: TARGET ARGS トークンを検証し、配列としてパスします(防衛の深さ)。
最終確認と安定性
- 4 時間の post-§46+TSAN ツリーキャンペーン:
- 125/128 = ASSERT !hasAnyArrayStorage。
- シングルスレッド --useJSThreads=true;Debug 再現は決定論的。
- 再トリージ結果:292/292 NOREPRO。
- r3-001/002: tryPutDirectTransitionConcurrent で閉鎖(r3b 再トリージ 134/136 NOREPRO)。
- §48 (r47+r3b): 再トリージ10/11 NOREPRO 0、r47 ファミリは確認なし。
- コーパス100+102/0(+5)。
- チェックサムは安定。
- 2 時間再ファージ r48 (310K 実行): 2 つの flaky/NOREPRO、r47 ファミリは確認なし。