8.2 KiB
8.2 KiB
Phase 8: MIR→WASM codegen (browser/wasmtime; sandboxed; Rust runtime free)
Summary
- MIR から素の WebAssembly を生成し、ブラウザ/wasmtime(WASI)でサンドボックス実行する。
- Rust は「コンパイラ本体」のみ。実行は純WASM+ホストimport(env.print 等)。
- Phase 6/7で実装済みのMIR命令(RefNew/RefGet/RefSet, FutureNew/Await等)をWASM命令に変換
Technical Architecture
WASM Module Structure
(module
(memory (export "memory") 1) ; 64KB initial
(import "env" "print" (func $print (param i32)))
;; Heap management
(global $heap_ptr (mut i32) (i32.const 1024))
;; Main entry point
(func (export "main") (result i32)
;; Generated from MIR main function
)
)
Memory Layout
0x000-0x3FF: Reserved/globals0x400-0x7FF: Stack space0x800+: Heap (bump allocator)- Box layout:
[type_id:i32][field_count:i32][field0:i32][field1:i32]...
Scope
- ABI/Imports/Exports(最小)
- exports:
main() -> i32,memory - imports:
env.print(i32)(デバッグ用に整数のみ。将来文字列ABIを定義)
- exports:
- メモリ/ヒープ
- 線形メモリに簡易ヒープ(bump allocator → フリーリスト)
- Box の固定レイアウト(フィールド→オフセット表; 型名→レイアウトは暫定固定)
- 命令カバレッジ(段階導入)
- PoC1: 算術/比較/分岐/loop/return/print
- PoC2: RefNew/RefSet/RefGet(Phase 6 と整合)で
print(o.x) - PoC3: Weak/Barrier の下地(WeakLoad は当面 Some 相当、Barrier は no-op)
- PoC4: Future/Await の基本実装(スレッドなしの即座完了)
- CLI 統合
nyash --backend wasm program.hakoで生成・実行(wasmtime 呼び出し)--output program.wasmでWASMファイル出力のみ
Implementation Plan
Phase 8.1: 基盤構築 (Foundation)
-
Task 1.1: WASMバックエンドモジュール作成
src/backend/wasm/mod.rs- エントリポイントsrc/backend/wasm/codegen.rs- MIR→WASM変換器src/backend/wasm/memory.rs- メモリ管理src/backend/wasm/runtime.rs- ランタイムヘルパー
-
Task 1.2: WASM出力基盤
- WAT形式での出力(人間可読、デバッグ用)
wabtcrateでWAT→WASMバイナリ変換 -基本的なmodule structure生成
Phase 8.2: PoC1 - 基本演算 (Basic Operations)
-
Task 2.1: MIR基本命令の変換実装
MirInstruction::Const→ WASMi32.constMirInstruction::BinOp→ WASM算術命令 (i32.add,i32.muletc.)MirInstruction::Compare→ WASM比較命令 (i32.eq,i32.ltetc.)
-
Task 2.2: 制御フロー実装
MirInstruction::Branch→ WASMbr_ifMirInstruction::Jump→ WASMbrMirInstruction::Return→ WASMreturn
-
Task 2.3: Print機能実装
MirInstruction::Print→call $print- env.print import の定義
PoC1目標: 42 + 8 のような基本計算がWASMで動作
Phase 8.3: PoC2 - オブジェクト操作 (Object Operations)
-
Task 3.1: メモリ管理実装
- Bump allocator (
$heap_ptrglobal) malloc(size) -> ptrWASM function- Box layout定義 (
[type_id][field_count][fields...])
- Bump allocator (
-
Task 3.2: 参照操作実装
MirInstruction::RefNew→call $malloc+ 初期化MirInstruction::RefGet→ memory load (i32.load offset=...)MirInstruction::RefSet→ memory store (i32.store offset=...)
PoC2目標: o = new Obj(); o.x = 1; print(o.x) 相当がWASMで動作
Phase 8.4: PoC3 - 拡張機能下地 (Extension Foundation)
-
Task 4.1: Weak参照ダミー実装
MirInstruction::WeakNew→ 通常の参照として処理MirInstruction::WeakLoad→ 常にSome相当で成功
-
Task 4.2: Barrier命令ダミー実装
MirInstruction::BarrierRead/Write→ no-op
-
Task 4.3: Future基本実装
MirInstruction::FutureNew→ 即座に完了状態のFutureMirInstruction::Await→ 値をそのまま返す
Phase 8.5: CLI統合 (CLI Integration)
-
Task 5.1: CLI実装
--backend wasmオプション追加--output file.wasmオプション追加- wasmtimeとの連携(
wasmtime run)
-
Task 5.2: エラーハンドリング
- 未対応MIR命令の明確なエラーメッセージ
- WASM生成失敗時の診断情報
Acceptance Criteria
PoC1 (Basic Operations)
- ✅ WASM Generation: 基本MIR命令がvalid WASMに変換される
- ✅ Wasmtime Execution:
wasmtime run output.wasmで正常実行 - ✅ Arithmetic:
print(42 + 8)→ stdout:50 - ✅ Control Flow: if文、loop文が正しく動作
PoC2 (Object Operations)
- ✅ Memory Allocation: RefNew でヒープメモリが正しく割り当てられる
- ✅ Field Access:
o = new DataBox(); o.value = 1; print(o.value)→ stdout:1 - ✅ Memory Layout: Box構造がメモリ上で正しいレイアウトになる
PoC3 (Extension Foundation)
- ✅ Weak Reference: WeakNew/WeakLoad命令がno-opとして動作
- ✅ Memory Barriers: BarrierRead/Write命令が含まれても実行できる
- ✅ Future Operations: FutureNew/Await が即座完了として動作
CLI Integration
- ✅ Command Line:
nyash --backend wasm test.hakoで実行可能 - ✅ File Output:
nyash --backend wasm --output test.wasm test.hakoでファイル出力 - ✅ Error Messages: 未対応機能の明確なエラーメッセージ
Test Strategy
Unit Tests (Rust)
// tests/wasm_codegen_tests.rs
#[test]
fn test_basic_arithmetic_codegen() {
let mir = /* 42 + 8 のMIR */;
let wasm_bytes = WasmBackend::new().compile_module(mir).unwrap();
let result = wasmtime_execute(&wasm_bytes);
assert_eq!(result.stdout, "50\n");
}
#[test]
fn test_ref_operations_codegen() {
let mir = /* object field access のMIR */;
let wasm_bytes = WasmBackend::new().compile_module(mir).unwrap();
let result = wasmtime_execute(&wasm_bytes);
assert_eq!(result.stdout, "1\n");
}
Integration Tests
tests/wasm_poc1_arithmetic.hako→ MIR → WASM → wasmtime実行tests/wasm_poc2_objects.hako→ RefNew/RefGet/RefSet使用 → WASM実行tests/wasm_poc3_features.hako→ Weak/Future命令含む → WASM実行
Browser Testing
<!-- tests/browser_test.html -->
<script type="module">
const importObject = {
env: {
print: (value) => console.log(value)
}
};
const wasmModule = await WebAssembly.instantiateStreaming(
fetch('./test.wasm'), importObject
);
const result = wasmModule.instance.exports.main();
console.log('Result:', result);
</script>
Technical Dependencies
Required Crates
wabt- WAT ↔ WASM conversionwasmtime- Runtime execution (dev dependency)wat- WAT text format parsing (optional)
WASM Tools
wasmtimeCLI - Local execution & testingwasm-objdump- Binary inspection (optional)wasm-validate- Validation (optional)
Development Notes
Memory Management Strategy
- Phase 8.3: Simple bump allocator (no free)
- Future: Free list allocator
- Future: Generational GC integration
Type System Mapping
| Nyash Type | MIR Type | WASM Type | Memory Layout |
|---|---|---|---|
| IntegerBox | Integer | i32 | 4 bytes |
| BoolBox | Bool | i32 | 4 bytes (0/1) |
| DataBox | Box("DataBox") | i32 | ptr to [type_id, field_count, fields...] |
Debugging Support
- WAT output for human inspection
- Source map generation (future)
- WASM stack trace integration (future)
Out of Scope (Phase 8)
- 本格的なGC(mark-sweep、generational等)
- Weak参照の実際の無効化メカニズム
- Pin/Unpin、fini()のカスケード処理
- JIT/AOTコンパイル最適化
- 複雑な文字列ABI(UTF-8、length prefixed等)
- WASI I/O インターフェース(file、network等)
References & Dependencies
- Phase 6: RefNew/RefGet/RefSet MIR命令 (実装済み)
- Phase 7: FutureNew/Await MIR命令 (実装済み)
- docs/予定/native-plan/README.md(Phase 8詳細)
- docs/説明書/wasm/* (WASM関連ドキュメント)
- WebAssembly Specification