Files
hakorune/docs/説明書/reference/box-design/ffi-abi-specification.md

294 lines
11 KiB
Markdown
Raw Normal View History

# Box FFI/ABI v0 (Draft)
Purpose
- Define a language-agnostic ABI to call external libraries as Boxes.
- Serve as a single source of truth for MIR ExternCall, WASM RuntimeImports, VM stubs, and future language codegens (TS/Python/Rust/LLVM IR).
Design Goals
- Simple first: UTF-8 strings as (ptr,len), i32 for small integers, 32-bit linear memory alignment friendly.
- Deterministic and portable across WASM/VM/native backends.
- Align with MIR effect system (pure/mut/io/control) to preserve optimization safety.
Core Types
- i32, i64, f32, f64, bool (0|1)
- string: UTF-8 in linear memory as (ptr: i32, len: i32)
- boxref: opaque 32-bit handle or pointer (backend-dependent)
- array(T): (ptr: i32, len: i32, [cap: i32 optional])
- void, null (represented as 0 for pointer-like values)
Memory & Alignment
- All pointers are 32-bit in WASM MVP. Align to 4 bytes.
- Strings/arrays must be contiguous in linear memory; no NUL terminator required (len is authoritative).
- Box layout examples for built-ins (for backends that materialize Boxes in memory):
- Header: [type_id:i32][ref_count:i32][field_count:i32]
- StringBox: header + [data_ptr:i32][length:i32]
Naming & Resolution
- Interface namespace: `env.console`, `env.canvas`, etc.
- Method: `log`, `fillRect`, `fillText`.
- Fully-qualified name: `env.console.log`, `env.canvas.fillRect`.
Calling Convention (v0)
- Positional parameters, no varargs.
- Strings/arrays passed as (ptr,len) pairs.
- Return values:
- Single scalar (i32/i64/f32/f64/bool) or void.
- Box/complex returns are out-of-scope for v0; use out-params if necessary.
Error Model (v0)
- Prefer total functions for v0 demos.
- If needed, return i32 status (0=ok, nonzero=error) and use out-params.
- Exceptions/signals are out-of-scope.
Effects
- Each BID method declares one of: pure | mut | io | control.
- Optimizer/verifier rules:
- pure: reordering permitted
- mut: preserve order w.r.t same resource
- io: preserve program order
- control: affects CFG; handled as terminators or dedicated ops
BID (Box Interface Definition) — YAML
```yaml
version: 0
interfaces:
- name: env.console
box: Console
methods:
- name: log
params: [ {string: msg} ]
returns: void
effect: io
- name: env.canvas
box: Canvas
methods:
- name: fillRect
params:
- {string: canvas_id}
- {i32: x}
- {i32: y}
- {i32: w}
- {i32: h}
- {string: color}
returns: void
effect: io
- name: fillText
params:
- {string: canvas_id}
- {string: text}
- {i32: x}
- {i32: y}
- {string: font}
- {string: color}
returns: void
effect: io
```
WASM Mapping (RuntimeImports)
- Import examples:
- `(import "env" "console_log" (func $console_log (param i32 i32)))` // (ptr,len)
- `(import "env" "canvas_fillRect" (func $canvas_fillRect (param i32 i32 i32 i32 i32 i32)))`
- `(import "env" "canvas_fillText" (func $canvas_fillText (param i32 i32 i32 i32 i32 i32 i32 i32)))` // two strings as (ptr,len) each
- Host responsibilities:
- Resolve strings from memory via `(ptr,len)` using TextDecoder('utf-8')
- Map to DOM/Canvas/Console as appropriate
WASM Mapping Rules (v0)
- String marshalling: UTF-8 `(ptr:i32, len:i32)`; memory exported as `memory`.
- Alignment: `ptr` 4-byte aligned is推奨必須ではないが実装簡素化のため
- Import naming: `env.<iface>_<method>` or nested `env` modules実装都合でどちらでも可
- 推奨: `env.console_log`, `env.canvas_fillRect`, `env.canvas_fillText`
- Argument order: 文字列は `(ptr,len)` を1引数扱いで連続配置。複数文字列はその都度 `(ptr,len)`
- Return: v0では`void`または整数のみ複合戻りはout-paramに委譲
- Memory growth: ホストは`memory.buffer`の再割当を考慮(必要に応じて毎回ビューを取り直す)。
RuntimeImportsとBIDの関係
- `RuntimeImports` は ABI/BID をWASM向けに具体化した実装レイヤーWASM専用の橋渡し
- 生成方針: 将来的にBIDYAML/JSONから`importObject``(import ...)`宣言を自動生成する。
-BID→WASM:
- `env.console.log(string msg)``console_log(ptr:i32, len:i32)`
- `env.canvas.fillRect(string canvasId, i32 x, i32 y, i32 w, i32 h, string color)`
`canvas_fillRect(id_ptr, id_len, x, y, w, h, color_ptr, color_len)`
============================================================
ABIの確定事項v0, 日本語)
============================================================
基本方針v0
- 文字列は UTF-8 の `(ptr:i32, len:i32)` で受け渡すNUL終端不要
- 配列/バイト列は `(ptr:i32, len:i32[, cap:i32])` とし、v0では `(ptr,len)` を基本とする。
- 数値は WASM/LLVM と親和性の高い素のプリミティブi32/i64/f32/f64
- 真偽値は `i32` で 0=false, 1=true。
- ポインタは `i32`WASM MVPを基本。ネイティブAOTではプラットフォーム幅に合わせる将来
- エンディアンはリトルエンディアンWASM/一般的なネイティブと一致)。
- 呼出規約は位置パラメータのみ(可変長/キーワードは範囲外)。
- 戻り値は単一スカラvoid含む。複合は out-param で表現(将来拡張)。
- メモリは `memory` をエクスポートWASM`TextDecoder('utf-8')` 等で復元Host側責務
- 効果effectは BID に必須。pure は再順序化可、mut/io は順序保持。
- 同期のみ(非同期は将来拡張)。
型と表現v0
- `i32`: 32bit 符号付き整数
- `i64`: 64bit 符号付き整数WASMではJSブリッジ注意。Host側はBigInt等
- `f32/f64`: IEEE 754
- `bool`: i320/1
- `string`: UTF-8 `(ptr:i32, len:i32)`
- `array<T>`: `(ptr:i32, len:i32[, cap:i32])`v0は `(ptr,len)` を優先)
- `boxref`: Opaque数値ハンドル or ポインタ。v0では数値 i32 を推奨。
アラインメント/境界
- `ptr` は 4byte アライン推奨(必須ではないが実装が簡潔)。
- 範囲外アクセスは未定義ではなく「Hostが防ぐ/検証する」方針将来、Verifier/境界チェック生成)。
命名規約
- `env.console.log`, `env.canvas.fillRect` のように `<namespace>.<iface>.<method>`
- WASM import 名は `env.console_log` 等の平坦化でも可(生成側で一貫)。
エラー/例外
- v0は例外なし。失敗は整数ステータス or 明示エラーコールバックに委譲(将来)。
セキュリティ/権限(将来)
- BID に必要権限console/canvas/storage/net…を記述。HostはAllowlistで制御Phase 9.9)。
============================================================
BIDサンプルYAML, 日本語)
============================================================
```yaml
version: 0
interfaces:
- name: env.console
box: Console
methods:
- name: log
params: [ { string: msg } ]
returns: void
effect: io
- name: env.canvas
box: Canvas
methods:
- name: fillRect
params:
- { string: canvas_id }
- { i32: x }
- { i32: y }
- { i32: w }
- { i32: h }
- { string: color }
returns: void
effect: io
- name: fillText
params:
- { string: canvas_id }
- { string: text }
- { i32: x }
- { i32: y }
- { string: font }
- { string: color }
returns: void
effect: io
```
ファイルとしてのサンプル(同等内容)
- `docs/nyir/bid_samples/console.yaml`
- `docs/nyir/bid_samples/canvas.yaml`
============================================================
Host側 importObject サンプル(ブラウザ, 日本語)
============================================================
```js
// 文字列(ptr,len)の復元ヘルパ
function utf8FromMemory(memory, ptr, len) {
const u8 = new Uint8Array(memory.buffer, ptr, len);
return new TextDecoder('utf-8').decode(u8);
}
const importObject = {
env: {
print: (v) => console.log(v),
print_str: (ptr, len) => {
console.log(utf8FromMemory(wasmInstance.exports.memory, ptr, len));
},
console_log: (ptr, len) => {
console.log(utf8FromMemory(wasmInstance.exports.memory, ptr, len));
},
canvas_fillRect: (idPtr, idLen, x, y, w, h, colorPtr, colorLen) => {
const mem = wasmInstance.exports.memory;
const id = utf8FromMemory(mem, idPtr, idLen);
const color = utf8FromMemory(mem, colorPtr, colorLen);
const cv = document.getElementById(id);
if (!cv) return;
const ctx = cv.getContext('2d');
ctx.fillStyle = color;
ctx.fillRect(x, y, w, h);
},
canvas_fillText: (idPtr, idLen, textPtr, textLen, x, y, fontPtr, fontLen, colorPtr, colorLen) => {
const mem = wasmInstance.exports.memory;
const id = utf8FromMemory(mem, idPtr, idLen);
const text = utf8FromMemory(mem, textPtr, textLen);
const font = utf8FromMemory(mem, fontPtr, fontLen);
const color = utf8FromMemory(mem, colorPtr, colorLen);
const cv = document.getElementById(id);
if (!cv) return;
const ctx = cv.getContext('2d');
ctx.font = font;
ctx.fillStyle = color;
ctx.fillText(text, x, y);
}
}
};
```
============================================================
ExternCall → WASM 呼び出しの例(日本語)
============================================================
Nyash コード(概念):
```
console = new WebConsoleBox("output")
console.log("Hello Nyash!")
canvas = new WebCanvasBox("game-canvas", 400, 300)
canvas.fillRect(50, 50, 80, 60, "red")
```
MIRExternCall化のイメージ:
```
ExternCall { iface: "env.console", method: "log", args: [ string("Hello Nyash!") ] }
ExternCall { iface: "env.canvas", method: "fillRect", args: [ string("game-canvas"), 50, 50, 80, 60, string("red") ] }
```
WASM import 呼び出し(概念):
```
call $console_log(msg_ptr, msg_len)
call $canvas_fillRect(id_ptr, id_len, 50, 50, 80, 60, color_ptr, color_len)
```
備考
- 文字列定数は data segment に配置し、実行時に (ptr,len) を与える。
- 動的文字列はランタイムでバッファ確保→(ptr,len) を渡す。
VM Mapping (Stub v0)
- Maintain a registry of externs by FQN (e.g., env.console.log) → function pointer.
- Console: print to stdout; Canvas: log params or no-op.
LLVM IR Mapping (Preview)
- Declare external functions with matching signatures (i32/i64/f32/f64/bool, i8* + i32 for strings).
- Example: `declare void @env_console_log(i8* nocapture, i32)`
- Strings allocated in data segment or heap; pass pointer + length.
Versioning
- `version: 0` for the first public draft.
- Backward-compatible extensions should add new methods/imports; breaking changes bump major.
Open Points (to validate post v0)
- Boxref passing across FFI boundaries (opaque handles vs pointers).
- Async externs and scheduling.
- Error model harmonization (status vs result-box).