皆さまこんにちは。初見の方は、初めまして。普段はマネジメントや別事業をしつつ、インフラからアプリまで何でもこなす現場のIT何でも屋です。
今回は、自ら言語作者の kanryu さんへ提案を行った結果、コンパイラ本体へと見事機能が公式実装され、Hike がさらに劇的な進化を遂げた話をお届けします。
つたない部分や至らない点もあるかと思いますが、温かく見守っていただけますと幸いです!
1. はじめに
新世代の静的型付けシステムプログラミング言語 Hike (hike-lang) は、ゼロランタイム・完全ゼロGC・生ポインタ直結で、極小かつ超高速な WebAssembly やネイティブバイナリを出力できる言語です。
前回の記事 では、ブラウザだけで動く Wasm/LLVM 命令とメモリの動きが見える Web IDE 「Hike Web Studio」 を作ったお話をお届けしました。
しかし、前回の Hike Web Studio をはじめとする各種実用コードの開発現場では、水面下でずっと避けられない構造的な苦悩を抱えていました。
それが、「WebAssembly のスタック制限を回避するための、外部 C言語との二重管理」 です。
今回は、この二重管理の苦しみから脱却するために自作 PoC を言語作者の kanryu さん へ提案し、コンパイラ本体へ見事に取り込んでいただいた経緯と、その具体的な成果をお届けします!
成果ハイライトと注意点
今回のコンパイラ公式実装と移行により、プロジェクト全体で以下のような劇的な改善を達成しました。
- 外部 C言語の完全撤廃: 手書きの Cコードやビルド時の二重管理がゼロになり、Hike コード 1本で完全完結。
- 実行スループットの向上: 状態遷移やループ処理のスループットが +120% 〜 +172.5%(約2.2〜2.7倍)向上。
- スタックオーバーフロー耐性の完全解決: $O(1)$ 定数スタックによる自己末尾再帰となり、100万回ループでもスタック消費ゼロ(0.6 µs)を達成。
- パスキー等のモジュールサイズ劇的削減: パスキー処理などの純粋コードも最新最適化により 約 79.8% 削減(1KB 未満へ突入)。
注意点:
ほとんどの環境でメリットしかありませんが、挙げるならレガシー環境でのTail Call未対応リスク(シェア約7%未満)や、厳格なCSP環境でのWasmブロックなどのトレードオフがわずかに存在するため、必要に応じたフォールバックの考慮を想定しておくと安心です。
2. 苦悩:Wasm スタック上限と「外部 C言語との二重管理」
Wasm は深い再帰やループ処理でクラッシュする
WebAssembly (WASM) の通常の関数呼び出しでは、呼び出しごとにスタックフレームが消費されます。
ブラウザや Node.js (V8) ではコールスタック上限が厳しく、VM インタプリタの命令ディスパッチや深い再帰ループを回すと、あっという間に以下のエラーで落ちてしまいます:
RangeError: Maximum call stack size exceeded
苦肉の策:外部 C言語(musttail)との二重管理
スタックを消費しない末尾呼び出し(Tail Call: return_call / musttail)を実現するため、前回記事の Hikeスタジオ関連の基盤でも、苦肉の策として**「再帰や状態マシンの一部だけを C言語で別書きし、Hike コードと手動リンクする」** という二重管理を行っていました。
【従来の二重管理モデル】
[Hike 言語コード] ──(hikec)─➔ 中間 LLVM IR ┐
├─➔ Clang (-mtail-call) で無理やり合体 ➔ Wasm
[外部 C言語コード] ───────────────────────┘ (環境依存パス・手動型合わせが必須)
この二重管理には大きなストレスが伴いました:
- ビルドの二重管理: C言語をコンパイルするために PC 環境ごとの Clang/LLVM パスをハードコードする必要があり、環境が変わるとビルドが即崩壊する。
-
型合わせの不安: C言語の関数と Hike の
extern funcのシグネチャを手動で一致させる必要があり、保守コストが高い。 - 言語哲学との乖離: 「Hike 単体でクリーンに完結する」という最大の魅力が損なわれてしまう。
「Hike 言語コンパイラ自身が直接末尾呼び出しを最適化してくれれば、外部 C言語をすべて捨てられるのに……!」という思いが強まりました。
3. 提案と公式取り込み
そこで、末尾呼び出しのコード生成に関する具体的な PoC(概念実証)を添えて、Hike 言語作者の kanryu さんへ改善提案を行いました。
すると……kanryu さんから神速のレスポンスがあり、コンパイラ本体(hikec)の Lowering 層からバックエンドまで一貫して末尾再帰を最適化する基盤(PR #25)を公式実装していただきました!
単にジャンプ命令を出すだけでなく、Hike の特徴である defer やエリアメモリの解放といったゼロランタイム・メモリ安全性を損なわない形で先行クリーンアップを組み込んだ洗練された設計で取り込んでいただけたのです。
これにより、外部 C言語のコードを 1 行も残さず完全撤廃し、純粋な Hike コード 1本だけで完結できる理想の環境 が整いました。
4. 実働コードでの改善結果(総合改善率サマリー)
実際にプロダクション環境で稼働している多数の Hike モジュールや各種コード全てを最新の公式コンパイラ環境へと置き換え、ビルドし直した結果、システム全体として平均して以下のような劇的な改善を達成しました:
| 改善項目 | 改善率・成果 | 詳細・効果 |
|---|---|---|
| 実用実行スループット (状態遷移・ループ処理) | +120% 向上 | 2.2倍 高速化 |
| 高頻度再帰スループット (2,000万回走査) | +172.5% 向上 | 2.73倍 高速化 |
| 処理所要時間 (レイテンシ) | 55% 〜 63% 短縮 | 応答速度の大幅な向上 |
| パスキー等のモジュールサイズ | 79.8% 削減 | 約80%減 / 1KB未満へ突入 |
| コールスタック消費量 | 99.99% 以上削減 | $O(1)$ 定数スタック化 |
| スタックオーバーフローによるクラッシュ率 | 100% 撲滅 | 完全ゼロ化 |
| 外部 C言語の併用(手書き・二重ビルド) | 完全撤廃 | Cコード 0行 / Hike 1本で完結 |
5. 実用コードの劇的な改善(具体例)
システム内で実働している多数の Hike コードを最新の公式コンパイラ環境でビルドし直したところ、手動の最適化や工夫の有無を問わず、あらゆるモジュールでパフォーマンスの向上とバイナリサイズの劇的な軽量化が確認できました。
具体例として、前回記事で扱った仮想マシン実行基盤である**「Hikeスタジオ」と、もともと外部C言語を使用していなかった純粋なコードである「パスキー認証」**の 2 つのモジュールでの改善事例を挙げます。
① 仮想マシン実行エンジン:Hike Web Studio
前回の記事でご紹介した、ブラウザ完結の Web IDE「Hike Web Studio」の仮想マシン実行コアです。
-
外部 C言語による手動最適化からの移行:
- 従来はスタック制限を回避するために一部の再帰や状態マシンを外部 C言語で個別最適化していた箇所について、コンパイラ公式の末尾呼び出し最適化(Tail Call)への移行により、外部ライブラリを完全撤廃。
- スループットが +120% 〜 +172.5%(約2.2〜2.7倍)向上。
-
スタックオーバーフロー耐性の完全解決:
- 手動でのC言語連携を廃し、純粋な Hike の自己末尾再帰($O(1)$ 定数スタック)としてクリーンに実行可能に。
- 100万回の再帰・状態ループでもスタック消費ゼロ(0.6 µs)で完全走破 し、ブラウザ環境でのクラッシュが完全に撲滅されました。
② パスキー認証モジュール (passkey)
ブラウザのパスキー認証(WebAuthn authData 解析および X.509 DER 変換)を行うモジュールです。
こちらはもともと外部 C言語を一切使っていなかった純粋な Hike コードですが、最新コンパイラの最適化基盤とコード生成の効率化により、次のような恩恵を受けています:
-
旧版の Wasm サイズ:
4,234 bytes(4.13 KB) -
最新の Wasm サイズ: わずか
857 bytes(0.84 KB) 【約 79.8% 削減!】
手動での工夫の有無に関わらず、不要なオーバーヘッドがコンパイラ側の進化によって自動的に削ぎ落とされ、4KB 台から一気に 1KB 未満の極小フットプリントへと突入 しました。これから新たにモジュールを組み込む開発者にとっても、極めて軽量なバンドルサイズを実現できます。
動作要件と環境依存性について
末尾呼び出し最適化(Tail Call)がコンパイラへ公式実装されたことにより、スタック制限対策として必要だった複雑な回避策や二重管理は不要となり、Hikeは最初から「コード1本でクリーンに完結する」言語仕様へと進化しました。
アップデートに伴う留意点は以下の通りです(実運用への影響は極めて限定的です):
| 項目 | 主な内容・影響 | 備考・仕様背景 |
|---|---|---|
| Tail Call 依存性 | レガシー環境等では通常スタックへフォールバック | 約 7% 未満のシェアがある未対応ブラウザ等の影響([1] 参照) |
| デバッグの可観測性 | スタックフレーム再利用の性質上、クラッシュ時のバックトレースが途切れる場合あり | 最適化ビルドにおける一般的な挙動 |
| セキュリティ制約 (CSP) | 企業や組織等の厳格なセキュリティポリシーによる動的Wasm実行のブロックリスク | 一般的な標準ブラウザ単体では稀だが、厳格なエンタープライズ環境等で考慮が必要([2], [3], [4] 参照) |
万が一に備え、純JS等へのフォールバック(想定レイテンシ増加: +10ms 〜 +50ms 程度)を適宜考慮しておくと万全です。
6. まとめ
今回の取り組みを通じて得られた成果と、運用上の留意点は以下の通りです。
📌 今回の成果
- コンパイラ本体への公式実装: 末尾呼び出し最適化(Tail Call)が言語バックエンドに標準搭載され、外部 C言語との連携や手動リンクのセットアップが完全に不要に。
- 言語単体で完結するクリーンなDX: メモリ安全性を損なわない洗練されたアーキテクチャにより、Hike コード 1本だけで極小かつ超高速なバイナリを構築可能に。
- 波及効果による全体最適化: 末尾最適化の恩恵に加え、パスキーなどの実用コードも軒並みサイズ削減(最大約80%減 / 79.8%削減)。
⚠️ 主な留意点(動作要件)
- レガシー環境での Tail Call 未対応: 約 7% 未満のシェア([1])
- 厳格な CSP 環境による制限: 特殊例のみ([2], [3], [4])
いずれも実運用への影響は極めて限定的ですが、万が一に備えたフォールバックや要件の把握を想定しておけば、現場で非常に強力な武器となります。
Hike 言語は、シンプルな記述で極小・超高速なバイナリを生み出せる素晴らしい言語へと進化し続けています。皆さまもぜひ、新しくなった Hike 言語 (hike-lang) を体験してみてください!
謝辞
前回の Hike Web Studio に続き、ユーザーからの提案や PoC を深く汲み取り、理想的な形でコンパイラを進化させてくださった作者の kanryu さん に、心より深く感謝申し上げます。
また、Wasm やモダンなコンパイラ最適化を支える素晴らしいエコシステムのすべてのコントリビューターの皆様、そしていつも温かく見守ってくださる読者の皆様にも厚く御礼申し上げます。
本記事の構成案の壁打ちや技術検証のサポートには生成AI(Gemini)を活用しました。AIの強力なアシストを受けながら、スムーズに検証から執筆までをやり切ることができました。
関連記事
本記事の前提となる前回のツール開発や、Hike言語・Wasm・パスキー最適化に関する連載記事です。ぜひあわせてご覧ください!
-
【Hike軽速化:パスキー編】新言語「Hike」でPasskey/WebAuthnをフルWasm・ステートレス化。サイズ1/5・セッションI/Oゼロ(0ms)・秒間83万回検証を達成した話
- 【Hike言語】アセンブラに挫折した私が、バイナリとメモリの動きが見えるWeb IDEを新言語「Hike」で自作した話 - うっかり世界最強のWasmコンパイラを作ってしまった件
- うっかり世界最強のWasmコンパイラに並行処理(マルチスレッド)を載せたら、なぜか1.46KBまで縮んだ件