# 0004 0.2.0–0.4.0 路线：size、opt、compose、addr2line

- Status: Proposed
- Date: 2026-11-05
- Supersedes: —

## Context

0.1.0 已交付 core/component 的 validate/print/parse/dump/strip/metadata 与
`component wit`，并验证了 `moonx` 预编译资产链路。剩余缺口分两类：

1. **已交付面的正确性缺口**：`dump`/`metadata` 拒绝 component；`component wit`
   还没有带真实 WIT 的组件固件。
2. **新能力**：`size`、`opt`、`compose`、`addr2line`。其中 `size` 是
   `moonsize` native-only 留下的 moonx 缺口，`opt` 可以复用工具链自带的
   binaryen，`compose` 可以复用 `mizchi/mwac`，`addr2line` 需要先验证
   `dwarfscope` 的依赖与 wasm 兼容性。

## Decision

### 顺序

| 版本 | 内容 | 理由 |
|---|---|---|
| 0.2.0 ✅ | component 感知的 `dump`/`metadata`；`size` v1（section + function + call graph） | 无新依赖；先补齐已有命令的正确性，再交付差异化最大的 size |
| 0.3.0 ✅ | `opt`（包装 `moon-wasm-opt`）；`size --diff`/`--budget` | opt 依赖宿主 spawn，需要单独的失败路径与提示；diff/budget 建立在 size v1 上 |
| 0.4.0 | `compose`（WAC）；`addr2line` | 两者都引入新的上游依赖，放到最后，失败不影响前三个版本 |

`addr2line` 开工前先做 spike：`wuhaiting321/dwarfscope` 没有根包，需要导入
`src/dwarf_line` 等子包，且依赖 `moonbitlang/x@0.4.48`。若与项目的
`x@0.5.x` 冲突或 wasm 目标不可用，则本版本只交付 `compose`，addr2line 另立 ADR。

### 0.2.0：component 结构 + size

**component `dump`/`metadata`**

- 组件顶层 section id：0 custom、1 core module、2 core instance、3 core type、
  4 nested component、5 instance、6 alias、7 type、8 canon、9 start、10 import、
  11 export。按此表输出，不再复用 core 的 1..13 标签。
- `dump --instructions` 对组件只输出 section 表，不逐个展开嵌套 core module；
  需要展开时用 `print` 的多文档 WAT。
- `metadata` 读取组件顶层的 custom section；嵌套 core module 的 name/producers
  在输出中标记 `core[0]` 前缀。

**`size` v1**

```text
wsm size FILE [--top N] [--json]
```

- 总大小、header、各 section 的 `payload`/`total`/百分比。
- 函数大小：解析 code section 的每个 body 长度；函数索引加上 imported 数量；
  名字来自 name section subsection 1。
- 调用图：从 `Instruction::Call`/`ReturnCall` 建边；`CallIndirect`/`CallRef`
  记录为 `indirect` 但不猜测目标。
- 排序输出 top-N，`--json` 字段固定：`file`、`total`、`sections[]`、
  `functions[]`、`call_graph`、`indirect_calls`。

验收：

- 各 section `total` 之和 + 8 字节 header 等于文件大小。
- 函数 body 大小之和 + code section 头部 ≤ code section payload。
- MoonBit `wasm`/`wasm-gc` release 产物上，导出的入口函数出现在 top-N。
- `--json` 对同一输入稳定；不打印未排序的 Map 迭代结果。

### 0.3.0：opt 与 size 门禁

**`opt`**

```text
wsm opt FILE [-O1|-O2|-O3|-O4|-Os|-Oz] [--passes P1,P2] [-o OUT]
```

- 默认追加 `--all-features`：MoonBit 的 wasm-gc 产物含 GC/SIMD，binaryen 不加
  该开关会直接拒绝（已实测）。
- 查找顺序：`--wasm-opt PATH` → `$MOON_HOME/bin/moon-wasm-opt[.exe]` →
  `PATH` 中的 `moon-wasm-opt`。
- stdin 输入写到 `@fs.tmpdir` 的临时文件；stdout 输出也经临时文件转回。
- 子进程失败时透传 binaryen stderr，退出码 1；找不到/无法 spawn 退出码 2，
  并提示 `moon install` 或 `--wasm-opt`。
- 优化后先用本项目的 `validate` 再写出，避免产出损坏文件。

**`size --diff` / `--budget`**

```text
wsm size NEW.wasm --diff OLD.wasm [--json]
wsm size FILE --budget 200KB
```

- `--diff` 输出函数级 delta：`added`/`removed`/`changed`，按绝对值排序。
- `--budget` 超限退出码 1，供 CI 使用；单位支持 `B/KB/MB`（1024 进制）。
- 这两项不改变 `size` v1 的默认输出。

### 0.4.0：compose 与 addr2line

**`compose`**

```text
wsm compose FILE.wac [-o OUT] [--dep NAME=PATH]... [--dce]
```

- 默认按 mwac 约定解析 `<wac 所在目录>/deps/<ns>/<name>.wasm`；
  `--dep` 覆盖单个包路径。
- 输出前用 `wasm_component` 验证；失败时保留 WAC 的位置诊断。
- 依赖 `mizchi/mwac@0.2.2`（wasm 可编译，实测组合 102B 组件成功）。

**`addr2line`**

```text
wsm addr2line FILE OFFSET [--json]
```

- spike 通过后使用 `dwarfscope` 的 `dwarf_line`/`dwarf_die`；否则本版本不交付。

### 版本与兼容

- 0.2.0 只新增命令与可加字段，不改变 0.1.0 的输出与退出码。
- `size --json` 从 0.2.0 起视为稳定接口；新增字段必须可选。
- 每个版本发布前执行：`moon test`、`tests/smoke.sh`、`moon build` 双目标、
  `moon publish --dry-run`，发布后用 `moonx <module>@<version> --version` 验证资产。

## Consequences

- `size` 完全自研，但只依赖 `wasm_core` 已有的指令模型与 raw 层，不引入新包。
- `opt` 不维护优化 pass，但引入对宿主进程的依赖；沙箱环境需要降级提示。
- `compose` 让依赖树多出 `mizchi/wit` 与 `async`，预计二进制增加 0.3–0.5 MB；
  若超过 3.5 MB，再评估拆成 `wsm-compose` 子模块。
- `addr2line` 可能因上游依赖冲突推迟，不影响其他命令。

## Verification

0.2.0 的 size 用两类固件交叉验证：

- 手工构造的最小模块：section/body 大小可人工核对。
- MoonBit release 产物：与 `ls -l`、`wasm-opt --metrics`（若可用）对比总量。

`opt` 的验收必须包含 MoonBit wasm-gc 产物，因为它是 `--all-features` 的直接
动机；只测手写 WAT 不足以证明。0.3.0 的实测记录：

- Linux：`moon-wasm-opt` 走 PATH；139088 B -> 95389 B（`-Oz`），产物重新验证通过。
- Windows：从 Windows 工具链解出 `moonrun.exe` 与 `moon-wasm-opt.exe`，在 WSL
  interop 下直接运行 `wasm-tools.wasm`，`opt -Oz` 同样通过；`@fs.tmpdir` 返回
  `C:\Users\...\AppData\Local\Temp\...`，临时文件可读写与清理。
- 显式 `--wasm-opt PATH` 是权威路径：探测失败直接退出 2，不回退到其它 binaryen。

## Reconsideration

如果 `mizchi/mwac` 在 0.4.0 前修复发布流程并暴露更小的 composer-only 包，
`compose` 可以提前到 0.3.0；如果 `moon-wasm-opt` 在某个平台不随工具链分发，
`opt` 需要改为可选插件而不是内置命令。
