feat(phase21.5): MirBuilder optimization prep + crate EXE infrastructure
Phase 21.5 optimization readiness - C-level performance target: - MirBuilder: JsonFrag purify toggle (HAKO_MIR_BUILDER_JSONFRAG_PURIFY=1) - Normalizer: extended f64 canonicalization + dedupe improvements - loop_opts_adapter: JsonFrag path refinement for crate EXE compatibility Infrastructure improvements: - provider_registry: add diagnostics + ring-1 providers (array/console/map/path) - mir_interpreter: add normalization/purify feature gates - tools/selfhost_exe_stageb.sh: new end-to-end Stage-B→crate EXE pipeline - tools/perf/microbench.sh: performance measurement tooling Smoke tests (phase2100): - Extend timeout 15s→120s for heavy crate EXE builds - Add stageb_loop_jsonfrag_crate_exe_canary_vm.sh (target test) - Add s3_backend_selector_crate_exe_vm_parity_return42_canary_vm.sh Documentation: - ENV_VARS.md: add Phase 21.5 optimization toggles - README updates: clarify crate backend strategy - phase215-optimization.md: new optimization roadmap This commit sets the stage for Phase 21.5 critical optimization: achieving C-level performance to decide hakorune's future viability.
This commit is contained in:
@ -15,6 +15,15 @@ Today’s update (structure-first)
|
|||||||
- Removed nested command substitution in `mirbuilder_canary_vm.sh`; switched to content assertion
|
- Removed nested command substitution in `mirbuilder_canary_vm.sh`; switched to content assertion
|
||||||
- Registry(get) Full path: exercised fast path (JsonFrag‑only) via `HAKO_MIR_BUILDER_REGISTRY_ONLY=return.method.arraymap` and pinned canary to registry tag only
|
- Registry(get) Full path: exercised fast path (JsonFrag‑only) via `HAKO_MIR_BUILDER_REGISTRY_ONLY=return.method.arraymap` and pinned canary to registry tag only
|
||||||
|
|
||||||
|
Additional updates (dev-only, behavior unchanged by default)
|
||||||
|
- VM counters wired: `inst_count`(non‑phi), `compare_count`(Compare), `branch_count`(Branch)
|
||||||
|
- Print with `NYASH_VM_STATS=1` as `[vm/stats] inst=… compare=… branch=…`
|
||||||
|
- Microbench harness: fixed ratio print noise(heredoc→one‑liner)。
|
||||||
|
- EXE canaries: crate backend bring‑up hardened
|
||||||
|
- Added `enable_exe_dev_env` helper and applied to representative EXE tests
|
||||||
|
- Enabled `NYASH_LLVM_VERIFY=1`/`NYASH_LLVM_VERIFY_IR=1` for deterministic cases
|
||||||
|
- Promoted `return42` canary to FAIL on mismatch (was SKIP)
|
||||||
|
|
||||||
Next — Phase 21.5 (Optimization, AOT-first)
|
Next — Phase 21.5 (Optimization, AOT-first)
|
||||||
- Baseline targets: Box create/destroy, method-call-only(small)
|
- Baseline targets: Box create/destroy, method-call-only(small)
|
||||||
- Harness: `tools/perf/run_all_21_5.sh`, `tools/perf/bench_compare_c_vs_hako.sh`, `tools/perf/record_baselines.sh`
|
- Harness: `tools/perf/run_all_21_5.sh`, `tools/perf/bench_compare_c_vs_hako.sh`, `tools/perf/record_baselines.sh`
|
||||||
@ -37,6 +46,56 @@ Notes
|
|||||||
- Do not broaden default behavior; optimization work remains opt‑in with clear flags.
|
- Do not broaden default behavior; optimization work remains opt‑in with clear flags.
|
||||||
- Avoid Rust fallback routes during bring‑up (Fail‑Fast by default); canaries may set localized `NYASH_FAIL_FAST=0` only when needed.
|
- Avoid Rust fallback routes during bring‑up (Fail‑Fast by default); canaries may set localized `NYASH_FAIL_FAST=0` only when needed.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Stage‑B → MirBuilder → ny‑llvmc(crate EXE)— Pre‑Optimization Goal
|
||||||
|
- Goal (pre‑21.5 optimization): build EXE via crate backend (ny‑llvmc) from Stage‑B Program(JSON) → MirBuilder MIR(JSON) before focusing on perf. Make EXE self‑hosting reliable on this host.
|
||||||
|
|
||||||
|
- Why now
|
||||||
|
- VM self‑host is green. EXE canaries (return/compare/binop/phi/externcall) are green.
|
||||||
|
- Loop/strlen general cases fail in crate EXE due to builder output mixing `newbox/MapBox` (loop) and missing FAST path (strlen). Fix these first to unlock fair “execute‑only” microbench.
|
||||||
|
|
||||||
|
- Plan (small, reversible, default‑OFF)
|
||||||
|
1) Loop JSONFrag purification (no MapBox/newbox)
|
||||||
|
- Ensure `HAKO_MIR_BUILDER_LOOP_JSONFRAG=1` route emits pure control‑flow MIR only (const/compare/branch/phi/ret).
|
||||||
|
- Acceptance: MIR(JSON) for minimal loop contains no `newbox|MapBox`; crate EXE build PASS; add canary to assert absence and EXE RC parity.
|
||||||
|
2) strlen FAST path (opt‑in)
|
||||||
|
- ny‑llvmc lowering (FAST=1): `externcall nyrt_string_length(i8*, i64)` (returns i64; no boxing).
|
||||||
|
- Add `nyrt_string_length` to `crates/nyash_kernel` (minimal impl; byte/char mode param reserved).
|
||||||
|
- Acceptance: FAST=1 で crate EXE RC=5("nyash".length); FAST=0 挙動不変。
|
||||||
|
3) Selfhost EXE wrapper (dev helper)
|
||||||
|
- Script (plan): `tools/selfhost_exe_stageb.sh`
|
||||||
|
- Stage‑B Program(JSON) emit → MirBuilder to MIR(JSON) via `tools/hakorune_emit_mir.sh`
|
||||||
|
- Build EXE via `tools/ny_mir_builder.sh --emit exe` (force `NYASH_LLVM_BACKEND=crate`)
|
||||||
|
- Optional: run + RC parity check vs VM
|
||||||
|
4) Canaries / Runner
|
||||||
|
- Loop JSONFrag no‑MapBox check (FAIL 基準)
|
||||||
|
- strlen FAST EXE RC check(FAST=1 のみタグ観測/既定OFFで静音)
|
||||||
|
- EXE parity: minimal Stage‑B sample VM↔EXE RC 一致
|
||||||
|
5) Acceptance & Docs
|
||||||
|
- quick 代表(EXE混在)は `--timeout 120` 推奨で緑維持(既定は変更しない)
|
||||||
|
- CURRENT_TASK/README に切替手順とフラグ記載(ロールバック容易)
|
||||||
|
|
||||||
|
- Toggles / Scripts
|
||||||
|
- `HAKO_MIR_BUILDER_LOOP_JSONFRAG=1`(Loop を JSONFrag 直組立に固定)
|
||||||
|
- `HAKO_MIR_BUILDER_JSONFRAG_NORMALIZE=1`(任意)
|
||||||
|
- `NYASH_LLVM_BACKEND=crate` / `NYASH_NY_LLVM_COMPILER=target/release/ny-llvmc` / `NYASH_EMIT_EXE_NYRT=target/release`
|
||||||
|
- Helper: `tools/hakorune_emit_mir.sh`(Stage‑B→MIR)、`tools/ny_mir_builder.sh --emit exe`(crate で obj/exe)
|
||||||
|
|
||||||
|
- Done (recent)
|
||||||
|
- EXE canaries hardened(enable_exe_dev_env 適用・検証ON・代表は FAIL 基準へ昇格)
|
||||||
|
- VM runtime counters(`NYASH_VM_STATS=1`)
|
||||||
|
- microbench `--exe` 実装(ビルド1回→EXEをRUNS回実行)。現状、loop/strlen の一般形は crate 未対応で EXE 失敗 → 上記 1)/2) で解消予定。
|
||||||
|
|
||||||
|
- Next (actionable)
|
||||||
|
- Implement loop JSONFrag purification (no MapBox/newbox) and add canary
|
||||||
|
- Add strlen FAST lowering + `nyrt_string_length` (kernel) + EXE canary
|
||||||
|
- Wire `tools/selfhost_exe_stageb.sh` and record one EXE parity check
|
||||||
|
- Then resume 21.5 optimization and run microbench with `--exe`(execute‑only timing)
|
||||||
|
|
||||||
|
MirBuilder/JsonFrag note
|
||||||
|
- JsonFrag path is for structure observation only (minimal MIR). Semantics remain prioritized by the default path. Keep it default OFF and tag‑gated. Builder toggles are centralized in `hako.mir.builder.internal.builder_config` to reduce scattered `env.get` calls in lowers.
|
||||||
|
|
||||||
Toggles (dev)
|
Toggles (dev)
|
||||||
- `NYASH_VM_FAST=1`(VM micro fast paths: new StringBox, String.length/size)
|
- `NYASH_VM_FAST=1`(VM micro fast paths: new StringBox, String.length/size)
|
||||||
- `NYASH_LLVM_FAST=1`(ny-llvmc AOT lowering fast path; default OFF)
|
- `NYASH_LLVM_FAST=1`(ny-llvmc AOT lowering fast path; default OFF)
|
||||||
|
|||||||
@ -13,6 +13,9 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
アーキテクチャノート
|
||||||
|
- 実行リング(ring0/ring1/ring2)とプロバイダ選択ポリシー: `docs/architecture/RINGS.md`
|
||||||
|
|
||||||
開発者向けクイックスタート: `docs/guides/getting-started.md`
|
開発者向けクイックスタート: `docs/guides/getting-started.md`
|
||||||
ユーザーマクロ(Phase 2): `docs/guides/user-macros.md`
|
ユーザーマクロ(Phase 2): `docs/guides/user-macros.md`
|
||||||
AST JSON v0(マクロ/ブリッジ): `docs/reference/ir/ast-json-v0.md`
|
AST JSON v0(マクロ/ブリッジ): `docs/reference/ir/ast-json-v0.md`
|
||||||
|
|||||||
@ -27,6 +27,9 @@ Notes
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
Architecture notes
|
||||||
|
- Runtime rings (ring0/ring1/ring2) and provider policy: see `docs/architecture/RINGS.md`.
|
||||||
|
|
||||||
Execution Status (Feature Additions Pause)
|
Execution Status (Feature Additions Pause)
|
||||||
- Active
|
- Active
|
||||||
- `--backend llvm` (Python/llvmlite harness; AOT object emit)
|
- `--backend llvm` (Python/llvmlite harness; AOT object emit)
|
||||||
|
|||||||
@ -206,3 +206,17 @@ VM/AOT fast-path toggles (bench/dev only)
|
|||||||
- Enables AOT lowering tweaks in ny-llvmc (opt-in, benches only):
|
- Enables AOT lowering tweaks in ny-llvmc (opt-in, benches only):
|
||||||
- StringBox.length/size lowered to extern helper returning i64 (no boxing)
|
- StringBox.length/size lowered to extern helper returning i64 (no boxing)
|
||||||
- Default OFF. Guarded in ny-llvmc; legacy lowering remains default.
|
- Default OFF. Guarded in ny-llvmc; legacy lowering remains default.
|
||||||
|
|
||||||
|
MirBuilder toggles (trace and JsonFrag)
|
||||||
|
- `HAKO_MIR_BUILDER_TRACE=0|1` (default: 0)
|
||||||
|
- When 1, emits concise builder tags like `[mirbuilder/internal/*]` from Hako lowers. Errors remain visible regardless; this flag controls informational tags.
|
||||||
|
- `HAKO_MIR_BUILDER_LOOP_JSONFRAG=0|1` (default: 0)
|
||||||
|
- Enable JsonFrag minimal MIR assembly in loop adapters/lowers (structure observation only).
|
||||||
|
- `HAKO_MIR_BUILDER_JSONFRAG_NORMALIZE=0|1` (default: 0)
|
||||||
|
- Normalize JsonFrag output for stable canaries (const grouping, phi placement, numeric canonicalization).
|
||||||
|
- `HAKO_MIR_BUILDER_LOOP_RETURN=string|map` (default: string)
|
||||||
|
- Controls the return type of the loop adapter JsonFrag path. `string` returns MIR(JSON) text; `map` returns a `MapBox` like `{ mir: <string> }`.
|
||||||
|
|
||||||
|
Provider diagnostics
|
||||||
|
- `HAKO_PROVIDER_TRACE=0|1` (default: 0)
|
||||||
|
- When 1, forces provider selection tags like `[provider/select:FileBox ring=1 src=static]` to appear even under `NYASH_JSON_ONLY=1`.
|
||||||
|
|||||||
43
docs/development/phase215-optimization.md
Normal file
43
docs/development/phase215-optimization.md
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# Phase 21.5 — Optimization Readiness (MirBuilder + Runtime)
|
||||||
|
|
||||||
|
Goal
|
||||||
|
- Target: ≥ 80% of equivalent C for core micro‑benches(同一アルゴリズム、最適化ON)。
|
||||||
|
- Scope: Nyash AOT/LLVM ライン(ハーネス or EXE)、ホットパスの構造最適化(挙動不変)。
|
||||||
|
- Guard: 既定挙動/ABI不変、devトグルでの可視化と段階導入、ロールバック容易。
|
||||||
|
|
||||||
|
Readiness (done)
|
||||||
|
- Normalizer を MirBuilder 本線/Min に既定OFFで配線、ON時のみタグ(静音トグル付)。
|
||||||
|
- f64 正規化の共通化(JsonNumberCanonical)・phi整列・ret値明示・const重複排除。
|
||||||
|
- Canary: 冪等 / cross‑block no‑dedupe / rcパリティ(if/loop/binop)/ f64(指数/−0.0/末尾0)/ phi(many/nested)。
|
||||||
|
|
||||||
|
Plan
|
||||||
|
1) Baseline & Harness
|
||||||
|
- 代表ベンチ(LoopSum / StrLen / BoxAlloc)で C baseline と Nyash(LLVM) を比較。
|
||||||
|
- 計測を tools/perf/microbench.sh に集約。`--runs N` で中央値/平均を算出。
|
||||||
|
2) Hotspot Discovery
|
||||||
|
- Builder 出力の冗長箇所(const/compare連打、不要な一時値)、Runtime の alloc/型分岐を観測。
|
||||||
|
- 代表ケースで alloc 回数/branch 回数をロギング(devトグル下、既定OFF)。
|
||||||
|
3) Small-step Optimization(構造優先・挙動不変)
|
||||||
|
- Builder 側: テキスト結合の抑制(集約バッファ)、重複constの先頭集約(既に導入済)。
|
||||||
|
- Runtime 側: 軽量 fast‑path(整数演算/比較の直通)、Box 生存期間短縮(スコープ明確化)。
|
||||||
|
4) Acceptance
|
||||||
|
- 代表ベンチ3種で C の ≥80%(中央値)を達成。変動が大きい環境では ±10%を許容しつつCIはスキップ扱い。
|
||||||
|
|
||||||
|
How to run (examples)
|
||||||
|
- Quick with Normalizer ON(重いEXEありのため timeout 120 推奨):
|
||||||
|
- `HAKO_MIR_BUILDER_JSONFRAG_NORMALIZE=1 ./tools/smokes/v2/run.sh --profile quick --timeout 120`
|
||||||
|
- Microbench(C vs Nyash/LLVM ハーネス):
|
||||||
|
- `tools/perf/microbench.sh --case loop --n 5000000 --runs 5`
|
||||||
|
- `tools/perf/microbench.sh --case strlen --n 2000000 --runs 5`
|
||||||
|
- `tools/perf/microbench.sh --case box --n 100000 --runs 5`
|
||||||
|
- VM runtime counters(dev 診断、既定OFF):
|
||||||
|
- `NYASH_VM_STATS=1 ./target/release/hakorune --backend vm apps/tests/CASE.hako` → `[vm/stats] inst=… compare=… branch=…` を出力
|
||||||
|
|
||||||
|
Toggles
|
||||||
|
- `HAKO_MIR_BUILDER_JSONFRAG_NORMALIZE=1` — 正規化ON(既定OFF)
|
||||||
|
- `HAKO_MIR_BUILDER_NORMALIZE_TAG=1` — タグ出力(既定静音)
|
||||||
|
- `SMOKES_DEV_NORMALIZE=1` — devヘルパから正規化ON注入(quick限定ON例は test_runner にコメント記載)
|
||||||
|
|
||||||
|
Notes
|
||||||
|
- ベンチは OS/CPU/周辺負荷に依存するため、CIでの厳格判定は避け、ローカル/任意ジョブで傾向を確認。
|
||||||
|
- 構造最適化優先(条件分岐/インライン化での挙動差を避ける)。
|
||||||
@ -52,6 +52,18 @@ static box MirBuilderBox {
|
|||||||
local internal = env.get("HAKO_MIR_BUILDER_INTERNAL")
|
local internal = env.get("HAKO_MIR_BUILDER_INTERNAL")
|
||||||
local internal_on = (internal == null) || (("" + internal) == "1")
|
local internal_on = (internal == null) || (("" + internal) == "1")
|
||||||
if internal_on == 1 {
|
if internal_on == 1 {
|
||||||
|
// Dev-only: force loop JSONFrag minimal output (pre-optimization bring-up)
|
||||||
|
// Guard: HAKO_MIR_BUILDER_LOOP_FORCE_JSONFRAG=1
|
||||||
|
{
|
||||||
|
local f = env.get("HAKO_MIR_BUILDER_LOOP_FORCE_JSONFRAG")
|
||||||
|
if f != null && ("" + f) == "1" {
|
||||||
|
local mir = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":[" +
|
||||||
|
"{\"id\":0,\"instructions\":[{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":0}},{\"op\":\"const\",\"dst\":2,\"value\":{\"type\":\"i64\",\"value\":0}},{\"op\":\"compare\",\"operation\":\"<\",\"lhs\":1,\"rhs\":2,\"dst\":3},{\"op\":\"branch\",\"cond\":3,\"then\":1,\"else\":2}]}," +
|
||||||
|
"{\"id\":1,\"instructions\":[{\"op\":\"ret\",\"value\":1}]}," +
|
||||||
|
"{\"id\":2,\"instructions\":[{\"op\":\"ret\",\"value\":1}]}]}]}"
|
||||||
|
return norm_if(mir)
|
||||||
|
}
|
||||||
|
}
|
||||||
// Optional: registry-driven lowering (scaffold). When HAKO_MIR_BUILDER_REGISTRY=1,
|
// Optional: registry-driven lowering (scaffold). When HAKO_MIR_BUILDER_REGISTRY=1,
|
||||||
// iterate PatternRegistryBox.candidates() and dispatch by name.
|
// iterate PatternRegistryBox.candidates() and dispatch by name.
|
||||||
// NOTE: using/alias は prelude で解決される(位置に依存しない)。
|
// NOTE: using/alias は prelude で解決される(位置に依存しない)。
|
||||||
|
|||||||
@ -1,22 +1,12 @@
|
|||||||
# MirBuilder Internal Boxes — Minimal Shapes (Phase 20.34)
|
MirBuilder Internals — Toggle Aggregation
|
||||||
|
|
||||||
Responsibility
|
- Use `builder_config_box.hako` (`hako.mir.builder.internal.builder_config`) to read all `HAKO_MIR_BUILDER_*` toggles.
|
||||||
- Provide small, readable boxes that lower a very small subset of Program(JSON v0)
|
- Do not call `env.get` directly in lowers; prefer helper methods like:
|
||||||
into MIR(JSON v0) strings without heavy parsing. Fail‑Fast with stable tags.
|
- `trace_enabled()`, `debug_enabled()`
|
||||||
|
- `internal_on()`, `registry_on()`, `registry_only()`
|
||||||
|
- `loop_jsonfrag_on()`, `jsonfrag_normalize_on()`, `skip_loops_on()`
|
||||||
|
- `loop_adapter_return_mode()` → `string` (default) or `map`
|
||||||
|
|
||||||
Boxes
|
Notes
|
||||||
- `prog_scan_box.hako` — tiny helpers for string scanning: find, skip spaces, read quoted/op/int values.
|
- JsonFrag emission is kept default OFF and used for structural observation only. Semantics are prioritized by the normal path.
|
||||||
- `lower_return_int_box.hako` — Return(Int N) → const(i64 N) + ret.
|
|
||||||
- `lower_return_binop_box.hako` — Return(Binary(Int,Int) op {+,-,*,/}) → const, const, binop, ret.
|
|
||||||
- `lower_if_compare_box.hako` — If(Compare(Int,Int) then Return(Int) else Return(Int)) → compare, branch, ret×2.
|
|
||||||
- `lower_loop_simple_box.hako` — Loop(Compare i<limit) counting loop(i=0..limit)→ LoopFormBox.loop_count に委譲。
|
|
||||||
- `lower_loop_sum_bc_box.hako` — Loop sum + break/continue 哲学(i==break → break / i==skip → continue)→ LoopFormBox.build("sum_bc", ...)。
|
|
||||||
|
|
||||||
Policy
|
|
||||||
- No execution or I/O; emit-only. Keep shapes minimal and obvious. For unsupported inputs, print
|
|
||||||
`[mirbuilder/internal/unsupported] ...` and return null.
|
|
||||||
|
|
||||||
LoopForm param
|
|
||||||
- LoopFormBox.build(mode, limit, skip, break)
|
|
||||||
- mode: "count"(i を返す)/ "sum_bc"(sum の合流を Exit PHI で返す)
|
|
||||||
- limit/skip/break は i64 として扱う。skip/break は null の場合、`skip=2` / `break=limit` を既定とする。
|
|
||||||
|
|||||||
44
lang/src/mir/builder/internal/builder_config_box.hako
Normal file
44
lang/src/mir/builder/internal/builder_config_box.hako
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// builder_config_box.hako — Centralized env/toggles for MirBuilder
|
||||||
|
// Purpose: avoid scattered env.get calls. All HAKO_MIR_BUILDER_* toggles are read here.
|
||||||
|
|
||||||
|
static box BuilderConfigBox {
|
||||||
|
// Generic on/off reader for HAKO_MIR_BUILDER_* flags
|
||||||
|
_is_on(key) {
|
||||||
|
local v = env.get(key)
|
||||||
|
if v == null { return 0 }
|
||||||
|
local s = "" + v
|
||||||
|
if s == "1" || s == "true" || s == "on" { return 1 }
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trace controls
|
||||||
|
trace_enabled() { return self._is_on("HAKO_MIR_BUILDER_TRACE") }
|
||||||
|
debug_enabled() { return self._is_on("HAKO_MIR_BUILDER_DEBUG") || self._is_on("NYASH_CLI_VERBOSE") }
|
||||||
|
|
||||||
|
// Registry and internal lowers
|
||||||
|
internal_on() {
|
||||||
|
local v = env.get("HAKO_MIR_BUILDER_INTERNAL")
|
||||||
|
// default ON
|
||||||
|
return (v == null) || ("" + v == "1")
|
||||||
|
}
|
||||||
|
registry_on() {
|
||||||
|
local v = env.get("HAKO_MIR_BUILDER_REGISTRY")
|
||||||
|
// default ON
|
||||||
|
return (v == null) || ("" + v == "1")
|
||||||
|
}
|
||||||
|
registry_only() { return env.get("HAKO_MIR_BUILDER_REGISTRY_ONLY") }
|
||||||
|
|
||||||
|
// Loop/JsonFrag related
|
||||||
|
loop_jsonfrag_on() { return self._is_on("HAKO_MIR_BUILDER_LOOP_JSONFRAG") }
|
||||||
|
jsonfrag_normalize_on() { return self._is_on("HAKO_MIR_BUILDER_JSONFRAG_NORMALIZE") }
|
||||||
|
skip_loops_on() { return self._is_on("HAKO_MIR_BUILDER_SKIP_LOOPS") }
|
||||||
|
|
||||||
|
// Return-mode for loop adapter: "string" (default) | "map"
|
||||||
|
loop_adapter_return_mode() {
|
||||||
|
local m = env.get("HAKO_MIR_BUILDER_LOOP_RETURN")
|
||||||
|
if m == null { return "string" }
|
||||||
|
local s = "" + m
|
||||||
|
if s == "string" { return "string" }
|
||||||
|
return "map"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -39,6 +39,8 @@ static box JsonFragNormalizerBox {
|
|||||||
local const_list = new ArrayBox()
|
local const_list = new ArrayBox()
|
||||||
local others_list = new ArrayBox()
|
local others_list = new ArrayBox()
|
||||||
local seen = new MapBox() // signature -> 1
|
local seen = new MapBox() // signature -> 1
|
||||||
|
// Dev-only: purify flag to drop builder-side allocations (e.g., newbox) from JSONFrag output
|
||||||
|
local purify = 0; { local pv = env.get("HAKO_MIR_BUILDER_JSONFRAG_PURIFY"); if pv != null { local pvs = "" + pv; if pvs == "1" { purify = 1 } } }
|
||||||
loop(i < n) {
|
loop(i < n) {
|
||||||
guard = guard + 1
|
guard = guard + 1
|
||||||
if guard > 4096 { break }
|
if guard > 4096 { break }
|
||||||
@ -52,6 +54,9 @@ static box JsonFragNormalizerBox {
|
|||||||
i = ob_end + 1
|
i = ob_end + 1
|
||||||
// classify by op
|
// classify by op
|
||||||
local op = JsonFragBox.get_str(obj, "op")
|
local op = JsonFragBox.get_str(obj, "op")
|
||||||
|
if purify == 1 {
|
||||||
|
if op == "newbox" { continue }
|
||||||
|
}
|
||||||
if op == "phi" {
|
if op == "phi" {
|
||||||
phi_list.push(obj)
|
phi_list.push(obj)
|
||||||
continue
|
continue
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// Purpose: centralize MapBox creation/set so that we can later swap to JsonFrag-based
|
// Purpose: centralize MapBox creation/set so that we can later swap to JsonFrag-based
|
||||||
// construction without touching all callers.
|
// construction without touching all callers.
|
||||||
|
|
||||||
|
using "hako.mir.builder.internal.builder_config" as BuilderConfigBox
|
||||||
|
|
||||||
static box LoopOptsBox {
|
static box LoopOptsBox {
|
||||||
new_map() {
|
new_map() {
|
||||||
return new MapBox()
|
return new MapBox()
|
||||||
@ -16,8 +18,7 @@ static box LoopOptsBox {
|
|||||||
using selfhost.shared.common.string_helpers as StringHelpers
|
using selfhost.shared.common.string_helpers as StringHelpers
|
||||||
using "hako.mir.builder.internal.jsonfrag_normalizer" as JsonFragNormalizerBox
|
using "hako.mir.builder.internal.jsonfrag_normalizer" as JsonFragNormalizerBox
|
||||||
// Opt-in: minimal MIR(JSON) construction for structure validation
|
// Opt-in: minimal MIR(JSON) construction for structure validation
|
||||||
local jf = env.get("HAKO_MIR_BUILDER_LOOP_JSONFRAG")
|
if BuilderConfigBox.loop_jsonfrag_on() == 1 {
|
||||||
if jf != null && ("" + jf) == "1" {
|
|
||||||
// Read limit if present, else default to 0 (safe)
|
// Read limit if present, else default to 0 (safe)
|
||||||
local limit = opts.get("limit"); if limit == null { limit = 0 }
|
local limit = opts.get("limit"); if limit == null { limit = 0 }
|
||||||
// Normalize to string
|
// Normalize to string
|
||||||
@ -31,11 +32,15 @@ static box LoopOptsBox {
|
|||||||
"{\"op\":\"branch\",\"cond\":3,\"then\":1,\"else\":2}]}," +
|
"{\"op\":\"branch\",\"cond\":3,\"then\":1,\"else\":2}]}," +
|
||||||
"{\"id\":1,\"instructions\":[{\"op\":\"ret\",\"value\":1}]}," +
|
"{\"id\":1,\"instructions\":[{\"op\":\"ret\",\"value\":1}]}," +
|
||||||
"{\"id\":2,\"instructions\":[{\"op\":\"ret\",\"value\":1}]}]}]}"
|
"{\"id\":2,\"instructions\":[{\"op\":\"ret\",\"value\":1}]}]}]}"
|
||||||
print("[mirbuilder/internal/loop:jsonfrag]")
|
if BuilderConfigBox.trace_enabled() == 1 { print("[mirbuilder/internal/loop:jsonfrag]") }
|
||||||
// Optional: normalization (dev toggle)
|
// Optional: normalization (dev toggle)
|
||||||
local norm = env.get("HAKO_MIR_BUILDER_JSONFRAG_NORMALIZE")
|
if BuilderConfigBox.jsonfrag_normalize_on() == 1 { mir = JsonFragNormalizerBox.normalize_all(mir) }
|
||||||
if norm != null && ("" + norm) == "1" {
|
// Return mode: default string, optionally wrap into Map
|
||||||
return JsonFragNormalizerBox.normalize_all(mir)
|
local mode = BuilderConfigBox.loop_adapter_return_mode()
|
||||||
|
if mode == "map" {
|
||||||
|
local m = self.new_map()
|
||||||
|
m = self.put(m, "mir", mir)
|
||||||
|
return m
|
||||||
}
|
}
|
||||||
return mir
|
return mir
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,7 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox
|
|||||||
using "hako.mir.builder.internal.pattern_util" as PatternUtilBox
|
using "hako.mir.builder.internal.pattern_util" as PatternUtilBox
|
||||||
using "hako.mir.builder.internal.loop_scan" as LoopScanBox
|
using "hako.mir.builder.internal.loop_scan" as LoopScanBox
|
||||||
using "hako.mir.builder.internal.loop_opts_adapter" as LoopOptsBox
|
using "hako.mir.builder.internal.loop_opts_adapter" as LoopOptsBox
|
||||||
|
using "hako.mir.builder.internal.builder_config" as BuilderConfigBox
|
||||||
|
|
||||||
static box LowerLoopSimpleBox {
|
static box LowerLoopSimpleBox {
|
||||||
try_lower(program_json) {
|
try_lower(program_json) {
|
||||||
@ -59,8 +60,7 @@ static box LowerLoopSimpleBox {
|
|||||||
|
|
||||||
// JsonFrag 直組立(opt-in): HAKO_MIR_BUILDER_LOOP_JSONFRAG=1
|
// JsonFrag 直組立(opt-in): HAKO_MIR_BUILDER_LOOP_JSONFRAG=1
|
||||||
{
|
{
|
||||||
local jf = env.get("HAKO_MIR_BUILDER_LOOP_JSONFRAG")
|
if BuilderConfigBox.loop_jsonfrag_on() == 1 {
|
||||||
if jf != null && ("" + jf) == "1" {
|
|
||||||
// Minimal MIR(JSON) with compare + branch + ret(構造検証用)
|
// Minimal MIR(JSON) with compare + branch + ret(構造検証用)
|
||||||
// Note: semanticsは簡略(canaryはトークン検出のみ)
|
// Note: semanticsは簡略(canaryはトークン検出のみ)
|
||||||
local mir = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":[" +
|
local mir = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":[" +
|
||||||
@ -71,7 +71,7 @@ static box LowerLoopSimpleBox {
|
|||||||
"{\"op\":\"branch\",\"cond\":3,\"then\":1,\"else\":2}]}," +
|
"{\"op\":\"branch\",\"cond\":3,\"then\":1,\"else\":2}]}," +
|
||||||
"{\"id\":1,\"instructions\":[{\"op\":\"ret\",\"value\":1}]}," +
|
"{\"id\":1,\"instructions\":[{\"op\":\"ret\",\"value\":1}]}," +
|
||||||
"{\"id\":2,\"instructions\":[{\"op\":\"ret\",\"value\":1}]}]}]}"
|
"{\"id\":2,\"instructions\":[{\"op\":\"ret\",\"value\":1}]}]}]}"
|
||||||
print("[mirbuilder/internal/loop:jsonfrag]")
|
if BuilderConfigBox.trace_enabled() == 1 { print("[mirbuilder/internal/loop:jsonfrag]") }
|
||||||
return mir
|
return mir
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -257,6 +257,11 @@ impl MirInterpreter {
|
|||||||
if Self::trace_enabled() {
|
if Self::trace_enabled() {
|
||||||
eprintln!("[vm-trace] inst bb={:?} {:?}", block.id, inst);
|
eprintln!("[vm-trace] inst bb={:?} {:?}", block.id, inst);
|
||||||
}
|
}
|
||||||
|
// Dev counters: count non-phi instructions and compares
|
||||||
|
self.inst_count = self.inst_count.saturating_add(1);
|
||||||
|
if let MirInstruction::Compare { .. } = inst {
|
||||||
|
self.compare_count = self.compare_count.saturating_add(1);
|
||||||
|
}
|
||||||
self.execute_instruction(inst)?;
|
self.execute_instruction(inst)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -281,6 +286,8 @@ impl MirInterpreter {
|
|||||||
then_bb,
|
then_bb,
|
||||||
else_bb,
|
else_bb,
|
||||||
}) => {
|
}) => {
|
||||||
|
// Dev counter: count branch terminators actually evaluated
|
||||||
|
self.branch_count = self.branch_count.saturating_add(1);
|
||||||
let cond = self.reg_load(*condition)?;
|
let cond = self.reg_load(*condition)?;
|
||||||
let branch = to_bool_vm(&cond).map_err(VMError::TypeError)?;
|
let branch = to_bool_vm(&cond).map_err(VMError::TypeError)?;
|
||||||
let target = if branch { *then_bb } else { *else_bb };
|
let target = if branch { *then_bb } else { *else_bb };
|
||||||
|
|||||||
@ -37,6 +37,10 @@ pub struct MirInterpreter {
|
|||||||
pub(super) static_boxes: HashMap<String, crate::instance_v2::InstanceBox>,
|
pub(super) static_boxes: HashMap<String, crate::instance_v2::InstanceBox>,
|
||||||
// Static box declarations (metadata for creating instances)
|
// Static box declarations (metadata for creating instances)
|
||||||
pub(super) static_box_decls: HashMap<String, crate::core::model::BoxDeclaration>,
|
pub(super) static_box_decls: HashMap<String, crate::core::model::BoxDeclaration>,
|
||||||
|
// Lightweight dev counters (opt-in print via NYASH_VM_STATS=1)
|
||||||
|
pub(super) inst_count: u64,
|
||||||
|
pub(super) branch_count: u64,
|
||||||
|
pub(super) compare_count: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MirInterpreter {
|
impl MirInterpreter {
|
||||||
@ -51,9 +55,17 @@ impl MirInterpreter {
|
|||||||
last_inst: None,
|
last_inst: None,
|
||||||
static_boxes: HashMap::new(),
|
static_boxes: HashMap::new(),
|
||||||
static_box_decls: HashMap::new(),
|
static_box_decls: HashMap::new(),
|
||||||
|
inst_count: 0,
|
||||||
|
branch_count: 0,
|
||||||
|
compare_count: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return (inst_count, branch_count, compare_count)
|
||||||
|
pub fn stats_counters(&self) -> (u64, u64, u64) {
|
||||||
|
(self.inst_count, self.branch_count, self.compare_count)
|
||||||
|
}
|
||||||
|
|
||||||
/// Register static box declarations (called from vm.rs during setup)
|
/// Register static box declarations (called from vm.rs during setup)
|
||||||
pub fn register_static_box_decl(&mut self, name: String, decl: crate::core::model::BoxDeclaration) {
|
pub fn register_static_box_decl(&mut self, name: String, decl: crate::core::model::BoxDeclaration) {
|
||||||
self.static_box_decls.insert(name, decl);
|
self.static_box_decls.insert(name, decl);
|
||||||
|
|||||||
@ -4,5 +4,6 @@
|
|||||||
|
|
||||||
pub mod env;
|
pub mod env;
|
||||||
pub mod nyash_toml_v2;
|
pub mod nyash_toml_v2;
|
||||||
|
pub mod provider_env;
|
||||||
|
|
||||||
pub use nyash_toml_v2::{BoxTypeConfig, LibraryDefinition, MethodDefinition, NyashConfigV2};
|
pub use nyash_toml_v2::{BoxTypeConfig, LibraryDefinition, MethodDefinition, NyashConfigV2};
|
||||||
|
|||||||
47
src/config/provider_env.rs
Normal file
47
src/config/provider_env.rs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
//! Provider-related environment readers (centralized)
|
||||||
|
//!
|
||||||
|
//! Minimizes scattered `std::env::var` calls across the runtime by
|
||||||
|
//! providing a small typed surface for provider selection knobs.
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum ProviderPolicy {
|
||||||
|
/// Current default: prefer plugin/dynamic providers by priority; use ring-1 as fallback
|
||||||
|
StrictPluginFirst,
|
||||||
|
/// Prefer ring-1 (static/core-ro) for stability/CI; fall back to plugin if unavailable
|
||||||
|
SafeCoreFirst,
|
||||||
|
/// Alias to SafeCoreFirst for future extension
|
||||||
|
StaticPreferred,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum FileBoxMode { Auto, CoreRo, PluginOnly }
|
||||||
|
|
||||||
|
/// Read global provider policy (affects Auto mode only)
|
||||||
|
pub fn provider_policy_from_env() -> ProviderPolicy {
|
||||||
|
match std::env::var("HAKO_PROVIDER_POLICY").unwrap_or_else(|_| "strict-plugin-first".to_string()).as_str() {
|
||||||
|
"safe-core-first" => ProviderPolicy::SafeCoreFirst,
|
||||||
|
"static-preferred" => ProviderPolicy::StaticPreferred,
|
||||||
|
_ => ProviderPolicy::StrictPluginFirst,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read FileBox mode from environment variables
|
||||||
|
pub fn filebox_mode_from_env() -> FileBoxMode {
|
||||||
|
match std::env::var("NYASH_FILEBOX_MODE").unwrap_or_else(|_| "auto".to_string()).as_str() {
|
||||||
|
"core-ro" => FileBoxMode::CoreRo,
|
||||||
|
"plugin-only" => FileBoxMode::PluginOnly,
|
||||||
|
_ => {
|
||||||
|
if std::env::var("NYASH_DISABLE_PLUGINS").as_deref() == Ok("1") {
|
||||||
|
FileBoxMode::CoreRo
|
||||||
|
} else { FileBoxMode::Auto }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allow core-ro fallback override even if Fail-Fast is ON when:
|
||||||
|
/// - JSON-only pipeline is active (quiet structured I/O), or
|
||||||
|
/// - Explicit NYASH_FILEBOX_ALLOW_FALLBACK=1 is set.
|
||||||
|
pub fn allow_filebox_fallback_override(quiet_pipe: bool) -> bool {
|
||||||
|
quiet_pipe || crate::config::env::env_bool("NYASH_FILEBOX_ALLOW_FALLBACK")
|
||||||
|
}
|
||||||
|
|
||||||
@ -5,6 +5,6 @@ This directory hosts ring1 (core providers) and related documentation.
|
|||||||
Goals
|
Goals
|
||||||
- Centralize provider responsibilities and selection policy.
|
- Centralize provider responsibilities and selection policy.
|
||||||
- Keep ring1 minimal and reproducible (static or in-tree providers).
|
- Keep ring1 minimal and reproducible (static or in-tree providers).
|
||||||
|
- Registry groups factories by Box type (e.g., "FileBox") to allow future expansion (Array/Map/Console/Path) without changing selection policy.
|
||||||
|
|
||||||
See also: src/providers/ring1/ and docs/architecture/RINGS.md
|
See also: src/providers/ring1/ and docs/architecture/RINGS.md
|
||||||
|
|
||||||
|
|||||||
6
src/providers/ring1/array/README.md
Normal file
6
src/providers/ring1/array/README.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
ring1/array — Placeholder (Scope/Policy)
|
||||||
|
|
||||||
|
- Purpose: future home for minimal, trusted ArrayBox providers (if introduced).
|
||||||
|
- Policy: ring1 is static/minimal only; no plugin (ring2) dependencies.
|
||||||
|
- Do not implement business logic here until design is finalized.
|
||||||
|
|
||||||
6
src/providers/ring1/console/README.md
Normal file
6
src/providers/ring1/console/README.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
ring1/console — Placeholder (Scope/Policy)
|
||||||
|
|
||||||
|
- Purpose: future home for minimal, trusted Console providers (if introduced).
|
||||||
|
- Policy: ring1 is static/minimal only; no plugin (ring2) dependencies.
|
||||||
|
- Do not implement business logic here until design is finalized.
|
||||||
|
|
||||||
6
src/providers/ring1/map/README.md
Normal file
6
src/providers/ring1/map/README.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
ring1/map — Placeholder (Scope/Policy)
|
||||||
|
|
||||||
|
- Purpose: future home for minimal, trusted MapBox providers (if introduced).
|
||||||
|
- Policy: ring1 is static/minimal only; no plugin (ring2) dependencies.
|
||||||
|
- Do not implement business logic here until design is finalized.
|
||||||
|
|
||||||
6
src/providers/ring1/path/README.md
Normal file
6
src/providers/ring1/path/README.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
ring1/path — Placeholder (Scope/Policy)
|
||||||
|
|
||||||
|
- Purpose: future home for minimal, trusted PathBox providers (if introduced).
|
||||||
|
- Policy: ring1 is static/minimal only; no plugin (ring2) dependencies.
|
||||||
|
- Do not implement business logic here until design is finalized.
|
||||||
|
|
||||||
28
src/runner/modes/common_util/diag.rs
Normal file
28
src/runner/modes/common_util/diag.rs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
//! Common diagnostics helpers (concise, centralized)
|
||||||
|
|
||||||
|
/// Whether provider logs should be emitted under current policy.
|
||||||
|
/// quiet_pipe usually reflects NYASH_JSON_ONLY; allowing override with HAKO_PROVIDER_TRACE=1.
|
||||||
|
pub fn provider_log_enabled(quiet_pipe: bool) -> bool {
|
||||||
|
!quiet_pipe || std::env::var("HAKO_PROVIDER_TRACE").as_deref() == Ok("1")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emit a consistent provider-registry info line.
|
||||||
|
pub fn provider_log_info(msg: &str) {
|
||||||
|
eprintln!("[provider-registry] {}", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emit the provider selection tag in a stable shape.
|
||||||
|
pub fn provider_log_select(box_name: &str, ring: &str, source: &str, caps: Option<&str>) {
|
||||||
|
match caps {
|
||||||
|
Some(c) if !c.is_empty() => {
|
||||||
|
eprintln!("[provider/select:{} ring={} src={} caps={}]", box_name, ring, source, c);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
eprintln!("[provider/select:{} ring={} src={}]", box_name, ring, source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emit a Fail-Fast tag for provider fallback/selection errors.
|
||||||
|
pub fn failfast_provider(reason: &str) { eprintln!("[failfast/provider/{}]", reason); }
|
||||||
|
|
||||||
@ -14,3 +14,4 @@ pub mod core_bridge;
|
|||||||
pub mod hako;
|
pub mod hako;
|
||||||
pub mod plugin_guard;
|
pub mod plugin_guard;
|
||||||
pub mod provider_registry;
|
pub mod provider_registry;
|
||||||
|
pub mod diag;
|
||||||
|
|||||||
@ -1,26 +1,21 @@
|
|||||||
//! Provider registry: selects concrete providers for core resources (e.g. FileBox).
|
//! Provider registry: selects concrete providers for core resources (e.g. FileBox).
|
||||||
//! SSOT (Single Source of Truth) for provider selection via ProviderFactory registration.
|
//! SSOT (Single Source of Truth) for provider selection via ProviderFactory registration.
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::sync::{Arc, Mutex, OnceLock};
|
use std::sync::{Arc, Mutex, OnceLock};
|
||||||
|
|
||||||
use crate::boxes::file::provider::FileIo;
|
|
||||||
use crate::boxes::file::core_ro::CoreRoFileIo;
|
use crate::boxes::file::core_ro::CoreRoFileIo;
|
||||||
|
use crate::boxes::file::provider::FileIo;
|
||||||
|
use crate::config::provider_env::{self, ProviderPolicy};
|
||||||
|
use crate::runner::modes::common_util::diag;
|
||||||
|
|
||||||
/// Provider selection policy (global). Applied when mode=Auto.
|
// Policy/Mode are provided by config::provider_env (centralized)
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
pub use crate::config::provider_env::FileBoxMode;
|
||||||
enum ProviderPolicy {
|
|
||||||
/// Current default: prefer plugin/dynamic providers by priority; use ring-1 as fallback
|
|
||||||
StrictPluginFirst,
|
|
||||||
/// Prefer ring-1 (static/core-ro) for stability/CI; fall back to plugin if unavailable
|
|
||||||
SafeCoreFirst,
|
|
||||||
/// Alias to SafeCoreFirst for future extension
|
|
||||||
StaticPreferred,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
/// Factory for creating providers for a specific Box type.
|
||||||
pub enum FileBoxMode { Auto, CoreRo, PluginOnly }
|
/// Note: Currently specialized for FileBox via `FileIo`.
|
||||||
|
/// The registry is structured as BoxName → [Factory], enabling future
|
||||||
/// Factory for creating FileIo providers
|
/// extension to other Box kinds without changing the selection policy surface.
|
||||||
pub trait ProviderFactory: Send + Sync {
|
pub trait ProviderFactory: Send + Sync {
|
||||||
fn box_name(&self) -> &str;
|
fn box_name(&self) -> &str;
|
||||||
fn create_provider(&self) -> Arc<dyn FileIo>;
|
fn create_provider(&self) -> Arc<dyn FileIo>;
|
||||||
@ -30,13 +25,17 @@ pub trait ProviderFactory: Send + Sync {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Global registry of provider factories
|
/// Global registry of provider factories, grouped by Box name
|
||||||
static PROVIDER_FACTORIES: OnceLock<Mutex<Vec<Arc<dyn ProviderFactory>>>> = OnceLock::new();
|
static PROVIDER_FACTORIES: OnceLock<Mutex<HashMap<String, Vec<Arc<dyn ProviderFactory>>>>> =
|
||||||
|
OnceLock::new();
|
||||||
|
|
||||||
/// Register a provider factory (called by builtin/dynamic loaders)
|
/// Register a provider factory (called by builtin/dynamic loaders)
|
||||||
pub fn register_provider_factory(factory: Arc<dyn ProviderFactory>) {
|
pub fn register_provider_factory(factory: Arc<dyn ProviderFactory>) {
|
||||||
let registry = PROVIDER_FACTORIES.get_or_init(|| Mutex::new(Vec::new()));
|
let registry = PROVIDER_FACTORIES
|
||||||
registry.lock().unwrap().push(factory);
|
.get_or_init(|| Mutex::new(HashMap::new()));
|
||||||
|
let mut guard = registry.lock().unwrap();
|
||||||
|
let key = factory.box_name().to_string();
|
||||||
|
guard.entry(key).or_default().push(factory);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Built‑in ring‑1 FileBox provider (core‑ro) — always available, lowest priority
|
/// Built‑in ring‑1 FileBox provider (core‑ro) — always available, lowest priority
|
||||||
@ -51,37 +50,20 @@ impl ProviderFactory for CoreRoFileProviderFactory {
|
|||||||
|
|
||||||
/// Ensure ring‑1 (core‑ro) provider is present in the registry
|
/// Ensure ring‑1 (core‑ro) provider is present in the registry
|
||||||
fn ensure_builtin_file_provider_registered() {
|
fn ensure_builtin_file_provider_registered() {
|
||||||
let reg = PROVIDER_FACTORIES.get_or_init(|| Mutex::new(Vec::new()));
|
let reg = PROVIDER_FACTORIES
|
||||||
|
.get_or_init(|| Mutex::new(HashMap::new()));
|
||||||
let mut guard = reg.lock().unwrap();
|
let mut guard = reg.lock().unwrap();
|
||||||
// If at least one FileBox provider exists, we still keep ring‑1 present for safety; avoid duplicates by checking any core‑ro present by priority
|
let list = guard.entry("FileBox".to_string()).or_default();
|
||||||
let has_core_ro = guard.iter().any(|f| f.box_name() == "FileBox" && f.priority() <= -100);
|
// keep ring‑1 present for safety; avoid duplicates by checking any core‑ro present by priority
|
||||||
|
let has_core_ro = list.iter().any(|f| f.priority() <= -100);
|
||||||
if !has_core_ro {
|
if !has_core_ro {
|
||||||
guard.push(Arc::new(CoreRoFileProviderFactory));
|
list.push(Arc::new(CoreRoFileProviderFactory));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read global provider policy (affects Auto mode only)
|
/// Backward-compat public readers for existing callers (if any)
|
||||||
fn read_provider_policy_from_env() -> ProviderPolicy {
|
|
||||||
match std::env::var("HAKO_PROVIDER_POLICY").unwrap_or_else(|_| "strict-plugin-first".to_string()).as_str() {
|
|
||||||
"safe-core-first" => ProviderPolicy::SafeCoreFirst,
|
|
||||||
"static-preferred" => ProviderPolicy::StaticPreferred,
|
|
||||||
_ => ProviderPolicy::StrictPluginFirst,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read FileBox mode from environment variables
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn read_filebox_mode_from_env() -> FileBoxMode {
|
pub fn read_filebox_mode_from_env() -> FileBoxMode { provider_env::filebox_mode_from_env() }
|
||||||
match std::env::var("NYASH_FILEBOX_MODE").unwrap_or_else(|_| "auto".to_string()).as_str() {
|
|
||||||
"core-ro" => FileBoxMode::CoreRo,
|
|
||||||
"plugin-only" => FileBoxMode::PluginOnly,
|
|
||||||
_ => {
|
|
||||||
if std::env::var("NYASH_DISABLE_PLUGINS").as_deref() == Ok("1") {
|
|
||||||
FileBoxMode::CoreRo
|
|
||||||
} else { FileBoxMode::Auto }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Select provider based on mode and registered factories (SSOT)
|
/// Select provider based on mode and registered factories (SSOT)
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -94,13 +76,14 @@ pub fn select_file_provider(mode: FileBoxMode) -> Arc<dyn FileIo> {
|
|||||||
match mode {
|
match mode {
|
||||||
FileBoxMode::Auto => {
|
FileBoxMode::Auto => {
|
||||||
// Selection by global policy
|
// Selection by global policy
|
||||||
let policy = read_provider_policy_from_env();
|
let policy = provider_env::provider_policy_from_env();
|
||||||
if let Some(reg) = registry {
|
if let Some(reg) = registry {
|
||||||
let mut factories: Vec<_> = reg.lock().unwrap()
|
let mut factories: Vec<_> = reg
|
||||||
.iter()
|
.lock()
|
||||||
.filter(|f| f.box_name() == "FileBox" && f.is_available())
|
.unwrap()
|
||||||
.cloned()
|
.get("FileBox")
|
||||||
.collect();
|
.map(|v| v.iter().filter(|f| f.is_available()).cloned().collect())
|
||||||
|
.unwrap_or_else(|| Vec::new());
|
||||||
|
|
||||||
// Sort by priority (descending); plugin providers should rank higher than ring-1 (priority -100)
|
// Sort by priority (descending); plugin providers should rank higher than ring-1 (priority -100)
|
||||||
factories.sort_by(|a, b| b.priority().cmp(&a.priority()));
|
factories.sort_by(|a, b| b.priority().cmp(&a.priority()));
|
||||||
@ -109,9 +92,9 @@ pub fn select_file_provider(mode: FileBoxMode) -> Arc<dyn FileIo> {
|
|||||||
match policy {
|
match policy {
|
||||||
ProviderPolicy::StrictPluginFirst => {
|
ProviderPolicy::StrictPluginFirst => {
|
||||||
if let Some(factory) = factories.first() {
|
if let Some(factory) = factories.first() {
|
||||||
if !quiet_pipe || std::env::var("HAKO_PROVIDER_TRACE").as_deref() == Ok("1") {
|
if diag::provider_log_enabled(quiet_pipe) {
|
||||||
eprintln!("[provider-registry] FileBox: using registered provider (priority={})", factory.priority());
|
diag::provider_log_info(&format!("FileBox: using registered provider (priority={})", factory.priority()));
|
||||||
eprintln!("[provider/select:FileBox ring=plugin src=dynamic]");
|
diag::provider_log_select("FileBox", "plugin", "dynamic", None);
|
||||||
}
|
}
|
||||||
return factory.create_provider();
|
return factory.create_provider();
|
||||||
}
|
}
|
||||||
@ -119,17 +102,17 @@ pub fn select_file_provider(mode: FileBoxMode) -> Arc<dyn FileIo> {
|
|||||||
ProviderPolicy::SafeCoreFirst | ProviderPolicy::StaticPreferred => {
|
ProviderPolicy::SafeCoreFirst | ProviderPolicy::StaticPreferred => {
|
||||||
// Prefer ring-1 (priority <= -100)
|
// Prefer ring-1 (priority <= -100)
|
||||||
if let Some(core_ro) = factories.iter().find(|f| f.priority() <= -100) {
|
if let Some(core_ro) = factories.iter().find(|f| f.priority() <= -100) {
|
||||||
if !quiet_pipe || std::env::var("HAKO_PROVIDER_TRACE").as_deref() == Ok("1") {
|
if diag::provider_log_enabled(quiet_pipe) {
|
||||||
eprintln!("[provider-registry] FileBox: using core-ro (policy)");
|
diag::provider_log_info("FileBox: using core-ro (policy)");
|
||||||
eprintln!("[provider/select:FileBox ring=1 src=static caps=[read]]");
|
diag::provider_log_select("FileBox", "1", "static", Some("[read]"));
|
||||||
}
|
}
|
||||||
return core_ro.create_provider();
|
return core_ro.create_provider();
|
||||||
}
|
}
|
||||||
// Fallback to first available (plugin)
|
// Fallback to first available (plugin)
|
||||||
if let Some(factory) = factories.first() {
|
if let Some(factory) = factories.first() {
|
||||||
if !quiet_pipe || std::env::var("HAKO_PROVIDER_TRACE").as_deref() == Ok("1") {
|
if diag::provider_log_enabled(quiet_pipe) {
|
||||||
eprintln!("[provider-registry] FileBox: using registered provider (priority={})", factory.priority());
|
diag::provider_log_info(&format!("FileBox: using registered provider (priority={})", factory.priority()));
|
||||||
eprintln!("[provider/select:FileBox ring=plugin src=dynamic]");
|
diag::provider_log_select("FileBox", "plugin", "dynamic", None);
|
||||||
}
|
}
|
||||||
return factory.create_provider();
|
return factory.create_provider();
|
||||||
}
|
}
|
||||||
@ -142,20 +125,18 @@ pub fn select_file_provider(mode: FileBoxMode) -> Arc<dyn FileIo> {
|
|||||||
// - When JSON‑only pipeline is active (quiet structured I/O), or
|
// - When JSON‑only pipeline is active (quiet structured I/O), or
|
||||||
// - When NYASH_FILEBOX_ALLOW_FALLBACK=1 is set,
|
// - When NYASH_FILEBOX_ALLOW_FALLBACK=1 is set,
|
||||||
// always use core‑ro provider even if Fail‑Fast is ON.
|
// always use core‑ro provider even if Fail‑Fast is ON.
|
||||||
let allow_fb_override =
|
let allow_fb_override = provider_env::allow_filebox_fallback_override(quiet_pipe);
|
||||||
crate::config::env::env_bool("NYASH_JSON_ONLY") ||
|
|
||||||
crate::config::env::env_bool("NYASH_FILEBOX_ALLOW_FALLBACK");
|
|
||||||
|
|
||||||
if crate::config::env::fail_fast() && !allow_fb_override {
|
if crate::config::env::fail_fast() && !allow_fb_override {
|
||||||
eprintln!("[failfast/provider/filebox:auto-fallback-blocked]");
|
diag::failfast_provider("filebox:auto-fallback-blocked");
|
||||||
panic!("Fail-Fast: FileBox provider fallback is disabled (NYASH_FAIL_FAST=0 or NYASH_FILEBOX_ALLOW_FALLBACK=1 to override)");
|
panic!("Fail-Fast: FileBox provider fallback is disabled (NYASH_FAIL_FAST=0 or NYASH_FILEBOX_ALLOW_FALLBACK=1 to override)");
|
||||||
} else {
|
} else {
|
||||||
if !quiet_pipe || std::env::var("HAKO_PROVIDER_TRACE").as_deref() == Ok("1") {
|
if diag::provider_log_enabled(quiet_pipe) {
|
||||||
eprintln!(
|
diag::provider_log_info(&format!(
|
||||||
"[provider-registry] FileBox: using core-ro fallback{}",
|
"FileBox: using core-ro fallback{}",
|
||||||
if allow_fb_override { " (override)" } else { "" }
|
if allow_fb_override { " (override)" } else { "" }
|
||||||
);
|
));
|
||||||
eprintln!("[provider/select:FileBox ring=1 src=static caps=[read]]");
|
diag::provider_log_select("FileBox", "1", "static", Some("[read]"));
|
||||||
}
|
}
|
||||||
Arc::new(CoreRoFileIo::new())
|
Arc::new(CoreRoFileIo::new())
|
||||||
}
|
}
|
||||||
@ -163,18 +144,19 @@ pub fn select_file_provider(mode: FileBoxMode) -> Arc<dyn FileIo> {
|
|||||||
FileBoxMode::PluginOnly => {
|
FileBoxMode::PluginOnly => {
|
||||||
// Try only registered providers, Fail-Fast if none available
|
// Try only registered providers, Fail-Fast if none available
|
||||||
if let Some(reg) = registry {
|
if let Some(reg) = registry {
|
||||||
let mut factories: Vec<_> = reg.lock().unwrap()
|
let mut factories: Vec<_> = reg
|
||||||
.iter()
|
.lock()
|
||||||
.filter(|f| f.box_name() == "FileBox" && f.is_available())
|
.unwrap()
|
||||||
.cloned()
|
.get("FileBox")
|
||||||
.collect();
|
.map(|v| v.iter().filter(|f| f.is_available()).cloned().collect())
|
||||||
|
.unwrap_or_else(|| Vec::new());
|
||||||
|
|
||||||
factories.sort_by(|a, b| b.priority().cmp(&a.priority()));
|
factories.sort_by(|a, b| b.priority().cmp(&a.priority()));
|
||||||
|
|
||||||
if let Some(factory) = factories.first() {
|
if let Some(factory) = factories.first() {
|
||||||
if !quiet_pipe || std::env::var("HAKO_PROVIDER_TRACE").as_deref() == Ok("1") {
|
if diag::provider_log_enabled(quiet_pipe) {
|
||||||
eprintln!("[provider-registry] FileBox: using plugin-only provider (priority={})", factory.priority());
|
diag::provider_log_info(&format!("FileBox: using plugin-only provider (priority={})", factory.priority()));
|
||||||
eprintln!("[provider/select:FileBox ring=plugin src=dynamic]");
|
diag::provider_log_select("FileBox", "plugin", "dynamic", None);
|
||||||
}
|
}
|
||||||
return factory.create_provider();
|
return factory.create_provider();
|
||||||
}
|
}
|
||||||
@ -184,9 +166,9 @@ pub fn select_file_provider(mode: FileBoxMode) -> Arc<dyn FileIo> {
|
|||||||
}
|
}
|
||||||
FileBoxMode::CoreRo => {
|
FileBoxMode::CoreRo => {
|
||||||
// Always use core-ro, ignore registry
|
// Always use core-ro, ignore registry
|
||||||
if !quiet_pipe || std::env::var("HAKO_PROVIDER_TRACE").as_deref() == Ok("1") {
|
if diag::provider_log_enabled(quiet_pipe) {
|
||||||
eprintln!("[provider-registry] FileBox: using core-ro (forced)");
|
diag::provider_log_info("FileBox: using core-ro (forced)");
|
||||||
eprintln!("[provider/select:FileBox ring=1 src=static caps=[read]]");
|
diag::provider_log_select("FileBox", "1", "static", Some("[read]"));
|
||||||
}
|
}
|
||||||
Arc::new(CoreRoFileIo::new())
|
Arc::new(CoreRoFileIo::new())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -429,6 +429,12 @@ impl NyashRunner {
|
|||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Optional: print lightweight VM counters for diagnostics
|
||||||
|
if crate::config::env::env_bool("NYASH_VM_STATS") {
|
||||||
|
let (inst, br, cmp) = vm.stats_counters();
|
||||||
|
eprintln!("[vm/stats] inst={} compare={} branch={}", inst, cmp, br);
|
||||||
|
}
|
||||||
|
|
||||||
// Quiet mode: suppress "RC:" output for JSON-only pipelines
|
// Quiet mode: suppress "RC:" output for JSON-only pipelines
|
||||||
if !quiet_pipe {
|
if !quiet_pipe {
|
||||||
println!("RC: {}", exit_code);
|
println!("RC: {}", exit_code);
|
||||||
|
|||||||
23
tools/lib/canary.sh
Normal file
23
tools/lib/canary.sh
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# canary.sh — Common helpers for canary scripts (JSON extract / token checks)
|
||||||
|
# Library only; safe to source from any test harness or standalone script.
|
||||||
|
|
||||||
|
# Extract content between [MIR_BEGIN] and [MIR_END] tags from stdin
|
||||||
|
extract_mir_between_tags() {
|
||||||
|
awk '/\[MIR_BEGIN\]/{f=1;next}/\[MIR_END\]/{f=0}f'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Require that all given tokens appear in stdin; prints a FAIL line and
|
||||||
|
# exits with non-zero status if any token is missing.
|
||||||
|
require_tokens() {
|
||||||
|
local content
|
||||||
|
content=$(cat)
|
||||||
|
for tk in "$@"; do
|
||||||
|
if ! grep -Fq -- "$tk" <<<"$content"; then
|
||||||
|
echo "[FAIL] token missing: $tk" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ Usage: tools/ny_mir_builder.sh [--in <file>|--stdin] [--emit {obj|exe|ll|json}]
|
|||||||
Notes:
|
Notes:
|
||||||
- This is a Phase-15 shell wrapper that leverages the nyash LLVM harness.
|
- This is a Phase-15 shell wrapper that leverages the nyash LLVM harness.
|
||||||
- Input must be Nyash JSON IR (v0/v1). When --stdin is used, reads from stdin.
|
- Input must be Nyash JSON IR (v0/v1). When --stdin is used, reads from stdin.
|
||||||
- For --emit exe, NyRT must be built (crates/nyrt). Use default paths if --nyrt omitted.
|
- For --emit exe, kernel runtime must be built (crates/nyash_kernel). Use default paths if --nyrt omitted.
|
||||||
USAGE
|
USAGE
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ if [[ "$SKIP_BUILD" != "1" ]]; then
|
|||||||
(cd "$(dirname "$0")/.." && timeout "$BUILD_TIMEOUT" cargo build --release -j 24 -p nyash-llvm-compiler >/dev/null) || true
|
(cd "$(dirname "$0")/.." && timeout "$BUILD_TIMEOUT" cargo build --release -j 24 -p nyash-llvm-compiler >/dev/null) || true
|
||||||
fi
|
fi
|
||||||
if [[ "$EMIT" == "exe" ]]; then
|
if [[ "$EMIT" == "exe" ]]; then
|
||||||
(cd crates/nyrt && timeout "$BUILD_TIMEOUT" cargo build --release -j 24 >/dev/null)
|
(cd crates/nyash_kernel && timeout "$BUILD_TIMEOUT" cargo build --release -j 24 >/dev/null)
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
216
tools/perf/microbench.sh
Normal file
216
tools/perf/microbench.sh
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||||
|
BIN="$ROOT/target/release/hakorune"
|
||||||
|
|
||||||
|
usage() { echo "Usage: $0 --case {loop|strlen|box} [--n N] [--runs R] [--backend {llvm|vm}] [--exe]"; }
|
||||||
|
|
||||||
|
CASE="loop"; N=5000000; RUNS=5; BACKEND="llvm"; EXE_MODE=0
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--case) CASE="$2"; shift 2;;
|
||||||
|
--n) N="$2"; shift 2;;
|
||||||
|
--runs) RUNS="$2"; shift 2;;
|
||||||
|
--backend) BACKEND="$2"; shift 2;;
|
||||||
|
--exe) EXE_MODE=1; shift 1;;
|
||||||
|
--help|-h) usage; exit 0;;
|
||||||
|
*) echo "Unknown arg: $1"; usage; exit 2;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ! -x "$BIN" ]]; then echo "[FAIL] hakorune not built: $BIN" >&2; exit 2; fi
|
||||||
|
|
||||||
|
bench_hako() {
|
||||||
|
local file="$1"; local backend="$2"; shift 2
|
||||||
|
local start end
|
||||||
|
start=$(date +%s%N)
|
||||||
|
if [[ "$backend" = "llvm" ]]; then
|
||||||
|
# Ensure ny-llvmc exists; build if missing
|
||||||
|
if [[ ! -x "$ROOT/target/release/ny-llvmc" ]]; then
|
||||||
|
(cargo build -q --release -p nyash-llvm-compiler >/dev/null 2>&1) || true
|
||||||
|
fi
|
||||||
|
PYTHONPATH="${PYTHONPATH:-$ROOT}" \
|
||||||
|
NYASH_NY_LLVM_COMPILER="${NYASH_NY_LLVM_COMPILER:-$ROOT/target/release/ny-llvmc}" \
|
||||||
|
NYASH_EMIT_EXE_NYRT="${NYASH_EMIT_EXE_NYRT:-$ROOT/target/release}" \
|
||||||
|
NYASH_LLVM_USE_HARNESS=1 "$BIN" --backend llvm "$file" >/dev/null 2>&1
|
||||||
|
else
|
||||||
|
"$BIN" --backend vm "$file" >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
end=$(date +%s%N)
|
||||||
|
echo $(( (end - start)/1000000 ))
|
||||||
|
}
|
||||||
|
|
||||||
|
bench_c() {
|
||||||
|
local csrc="$1"; local exe="$2"
|
||||||
|
cc -O3 -march=native -o "$exe" "$csrc"
|
||||||
|
local start end
|
||||||
|
start=$(date +%s%N)
|
||||||
|
"$exe" >/dev/null 2>&1
|
||||||
|
end=$(date +%s%N)
|
||||||
|
echo $(( (end - start)/1000000 ))
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build once and time executable runs (ms)
|
||||||
|
time_exe_run() {
|
||||||
|
local exe="$1"
|
||||||
|
local start end
|
||||||
|
start=$(date +%s%N)
|
||||||
|
"$exe" >/dev/null 2>&1
|
||||||
|
end=$(date +%s%N)
|
||||||
|
echo $(( (end - start)/1000000 ))
|
||||||
|
}
|
||||||
|
|
||||||
|
mktemp_hako() { mktemp --suffix .hako; }
|
||||||
|
mktemp_c() { mktemp --suffix .c; }
|
||||||
|
|
||||||
|
case "$CASE" in
|
||||||
|
loop)
|
||||||
|
HAKO_FILE=$(mktemp_hako)
|
||||||
|
cat >"$HAKO_FILE" <<HAKO
|
||||||
|
static box Main { method main(args) {
|
||||||
|
local n = ${N}
|
||||||
|
local i = 0
|
||||||
|
local s = 0
|
||||||
|
loop(i < n) { s = s + i i = i + 1 }
|
||||||
|
return s
|
||||||
|
} }
|
||||||
|
HAKO
|
||||||
|
C_FILE=$(mktemp_c)
|
||||||
|
cat >"$C_FILE" <<'C'
|
||||||
|
#include <stdint.h>
|
||||||
|
int main(){
|
||||||
|
volatile int64_t n = N_PLACEHOLDER;
|
||||||
|
volatile int64_t s=0; for (int64_t i=0;i<n;i++){ s+=i; }
|
||||||
|
return (int)(s&0xFF);
|
||||||
|
}
|
||||||
|
C
|
||||||
|
sed -i "s/N_PLACEHOLDER/${N}/" "$C_FILE"
|
||||||
|
;;
|
||||||
|
strlen)
|
||||||
|
HAKO_FILE=$(mktemp_hako)
|
||||||
|
cat >"$HAKO_FILE" <<HAKO
|
||||||
|
static box Main { method main(args) {
|
||||||
|
local n = ${N}
|
||||||
|
local i = 0
|
||||||
|
local s = 0
|
||||||
|
local t = "abcdefghijklmnopqrstuvwxyz"
|
||||||
|
loop(i < n) { s = s + t.length() i = i + 1 }
|
||||||
|
return s
|
||||||
|
} }
|
||||||
|
HAKO
|
||||||
|
C_FILE=$(mktemp_c)
|
||||||
|
cat >"$C_FILE" <<'C'
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
int main(){
|
||||||
|
volatile int64_t n = N_PLACEHOLDER; volatile int64_t s=0;
|
||||||
|
const char* t = "abcdefghijklmnopqrstuvwxyz";
|
||||||
|
for (int64_t i=0;i<n;i++){ s += (int64_t)strlen(t); }
|
||||||
|
return (int)(s&0xFF);
|
||||||
|
}
|
||||||
|
C
|
||||||
|
sed -i "s/N_PLACEHOLDER/${N}/" "$C_FILE"
|
||||||
|
;;
|
||||||
|
box)
|
||||||
|
HAKO_FILE=$(mktemp_hako)
|
||||||
|
cat >"$HAKO_FILE" <<HAKO
|
||||||
|
static box Main { method main(args) {
|
||||||
|
local n = ${N}
|
||||||
|
local i = 0
|
||||||
|
loop(i < n) { local t = new StringBox("x"); i = i + 1 }
|
||||||
|
return 0
|
||||||
|
} }
|
||||||
|
HAKO
|
||||||
|
C_FILE=$(mktemp_c)
|
||||||
|
cat >"$C_FILE" <<'C'
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
typedef struct { char* p; } Str;
|
||||||
|
static inline Str* new_str(){ Str* s=(Str*)malloc(sizeof(Str)); s->p=strdup("x"); free(s->p); free(s); return s; }
|
||||||
|
int main(){ volatile int64_t n=N_PLACEHOLDER; for(int64_t i=0;i<n;i++){ new_str(); } return 0; }
|
||||||
|
C
|
||||||
|
sed -i "s/N_PLACEHOLDER/${N}/" "$C_FILE"
|
||||||
|
;;
|
||||||
|
*) echo "Unknown case: $CASE"; exit 2;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "[perf] case=$CASE n=$N runs=$RUNS backend=$BACKEND" >&2
|
||||||
|
sum_c=0; sum_h=0
|
||||||
|
|
||||||
|
if [[ "$EXE_MODE" = "1" ]]; then
|
||||||
|
# Build C exe once
|
||||||
|
C_EXE=$(mktemp --suffix .out)
|
||||||
|
cc -O3 -march=native -o "$C_EXE" "$C_FILE"
|
||||||
|
# Build Nyash exe once (requires llvm harness)
|
||||||
|
if [[ "$BACKEND" != "llvm" ]]; then
|
||||||
|
echo "[FAIL] --exe requires --backend llvm" >&2; exit 2
|
||||||
|
fi
|
||||||
|
if [[ ! -x "$ROOT/target/release/ny-llvmc" ]]; then
|
||||||
|
(cargo build -q --release -p nyash-llvm-compiler >/dev/null 2>&1) || true
|
||||||
|
fi
|
||||||
|
HAKO_EXE=$(mktemp --suffix .out)
|
||||||
|
TMP_JSON=$(mktemp --suffix .json)
|
||||||
|
if ! HAKO_SELFHOST_BUILDER_FIRST=1 HAKO_MIR_BUILDER_LOOP_JSONFRAG=1 HAKO_MIR_BUILDER_JSONFRAG_NORMALIZE=1 \
|
||||||
|
NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \
|
||||||
|
NYASH_JSON_ONLY=1 bash "$ROOT/tools/hakorune_emit_mir.sh" "$HAKO_FILE" "$TMP_JSON" >/dev/null 2>&1; then
|
||||||
|
echo "[FAIL] failed to emit MIR JSON" >&2; exit 3
|
||||||
|
fi
|
||||||
|
# Ensure runtime lib exists (nyash_kernel)
|
||||||
|
(cd "$ROOT/crates/nyash_kernel" && cargo build -q --release >/dev/null) || true
|
||||||
|
# Build EXE via helper (selects crate backend ny-llvmc under the hood)
|
||||||
|
if ! NYASH_LLVM_BACKEND=crate \
|
||||||
|
NYASH_NY_LLVM_COMPILER="${NYASH_NY_LLVM_COMPILER:-$ROOT/target/release/ny-llvmc}" \
|
||||||
|
NYASH_EMIT_EXE_NYRT="${NYASH_EMIT_EXE_NYRT:-$ROOT/target/release}" \
|
||||||
|
NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 NYASH_LLVM_FAST=1 \
|
||||||
|
bash "$ROOT/tools/ny_mir_builder.sh" --in "$TMP_JSON" --emit exe -o "$HAKO_EXE" --quiet >/dev/null 2>&1; then
|
||||||
|
echo "[FAIL] failed to build Nyash EXE" >&2; exit 3
|
||||||
|
fi
|
||||||
|
|
||||||
|
for i in $(seq 1 "$RUNS"); do
|
||||||
|
t_c=$(time_exe_run "$C_EXE")
|
||||||
|
t_h=$(time_exe_run "$HAKO_EXE")
|
||||||
|
sum_c=$((sum_c + t_c)); sum_h=$((sum_h + t_h))
|
||||||
|
if command -v python3 >/dev/null 2>&1; then
|
||||||
|
ratio=$(python3 -c "print(round(${t_h}/max(${t_c},1)*100,2))" 2>/dev/null || echo NA)
|
||||||
|
else
|
||||||
|
ratio=NA
|
||||||
|
fi
|
||||||
|
echo "run#$i c=${t_c}ms hak=${t_h}ms ratio=${ratio}%" >&2
|
||||||
|
done
|
||||||
|
avg_c=$((sum_c / RUNS)); avg_h=$((sum_h / RUNS))
|
||||||
|
echo "avg c=${avg_c}ms hak=${avg_h}ms" >&2
|
||||||
|
if command -v python3 >/dev/null 2>&1; then
|
||||||
|
python3 - <<PY
|
||||||
|
c=$avg_c; h=$avg_h
|
||||||
|
ratio = (h/max(c,1))*100.0
|
||||||
|
print(f"ratio={ratio:.2f}%")
|
||||||
|
PY
|
||||||
|
fi
|
||||||
|
rm -f "$C_EXE" "$HAKO_EXE" "$TMP_JSON" 2>/dev/null || true
|
||||||
|
else
|
||||||
|
for i in $(seq 1 "$RUNS"); do
|
||||||
|
t_c=$(bench_c "$C_FILE" "${C_FILE%.c}")
|
||||||
|
t_h=$(bench_hako "$HAKO_FILE" "$BACKEND")
|
||||||
|
sum_c=$((sum_c + t_c)); sum_h=$((sum_h + t_h))
|
||||||
|
if command -v python3 >/dev/null 2>&1; then
|
||||||
|
ratio=$(python3 -c "print(round(${t_h}/max(${t_c},1)*100,2))" 2>/dev/null || echo NA)
|
||||||
|
else
|
||||||
|
ratio=NA
|
||||||
|
fi
|
||||||
|
echo "run#$i c=${t_c}ms hak=${t_h}ms ratio=${ratio}%" >&2
|
||||||
|
done
|
||||||
|
avg_c=$((sum_c / RUNS)); avg_h=$((sum_h / RUNS))
|
||||||
|
echo "avg c=${avg_c}ms hak=${avg_h}ms" >&2
|
||||||
|
if command -v python3 >/dev/null 2>&1; then
|
||||||
|
python3 - <<PY
|
||||||
|
c=$avg_c; h=$avg_h
|
||||||
|
ratio = (h/max(c,1))*100.0
|
||||||
|
print(f"ratio={ratio:.2f}%")
|
||||||
|
PY
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f "$HAKO_FILE" "$C_FILE" "${C_FILE%.c}" 2>/dev/null || true
|
||||||
47
tools/selfhost_exe_stageb.sh
Normal file
47
tools/selfhost_exe_stageb.sh
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# selfhost_exe_stageb.sh — Stage‑B → MirBuilder → ny‑llvmc (crate) → EXE
|
||||||
|
# Purpose: Build a native EXE from a Nyash .hako source using Stage‑B+MirBuilder (selfhost‑first)
|
||||||
|
# Usage: tools/selfhost_exe_stageb.sh <input.hako> [-o <out>] [--run]
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
OUT="a.out"; DO_RUN=0
|
||||||
|
if [[ $# -lt 1 ]]; then
|
||||||
|
echo "Usage: $0 <input.hako> [-o <out>] [--run]" >&2; exit 2
|
||||||
|
fi
|
||||||
|
INPUT=""
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
-o) OUT="$2"; shift 2;;
|
||||||
|
--run) DO_RUN=1; shift;;
|
||||||
|
*) INPUT="$1"; shift;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
if [[ ! -f "$INPUT" ]]; then echo "error: input not found: $INPUT" >&2; exit 2; fi
|
||||||
|
|
||||||
|
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
|
||||||
|
# 1) Emit MIR(JSON) via Stage‑B → MirBuilder (selfhost‑first)
|
||||||
|
TMP_JSON=$(mktemp --suffix .json)
|
||||||
|
HAKO_SELFHOST_BUILDER_FIRST=1 \
|
||||||
|
HAKO_MIR_BUILDER_LOOP_JSONFRAG=1 \
|
||||||
|
HAKO_MIR_BUILDER_JSONFRAG_NORMALIZE=1 \
|
||||||
|
NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \
|
||||||
|
NYASH_JSON_ONLY=1 "$ROOT_DIR/tools/hakorune_emit_mir.sh" "$INPUT" "$TMP_JSON" >/dev/null
|
||||||
|
echo "[emit] MIR JSON: $TMP_JSON ($(wc -c < "$TMP_JSON") bytes)"
|
||||||
|
|
||||||
|
# 2) Build EXE via crate backend (ny-llvmc) using helper
|
||||||
|
NYASH_LLVM_BACKEND=crate \
|
||||||
|
NYASH_NY_LLVM_COMPILER="${NYASH_NY_LLVM_COMPILER:-$ROOT_DIR/target/release/ny-llvmc}" \
|
||||||
|
NYASH_EMIT_EXE_NYRT="${NYASH_EMIT_EXE_NYRT:-$ROOT_DIR/target/release}" \
|
||||||
|
"$ROOT_DIR/tools/ny_mir_builder.sh" --in "$TMP_JSON" --emit exe -o "$OUT" --quiet >/dev/null
|
||||||
|
echo "[link] EXE: $OUT"
|
||||||
|
|
||||||
|
if [[ "$DO_RUN" = "1" ]]; then
|
||||||
|
set +e
|
||||||
|
"$OUT"; rc=$?
|
||||||
|
set -e
|
||||||
|
echo "[run] exit=$rc"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
||||||
@ -1,29 +1,24 @@
|
|||||||
Smokes v2 — Quick vs Optional
|
Smokes v2 — Minimal Runner and Policy
|
||||||
|
|
||||||
Purpose
|
Policy
|
||||||
- Keep an always‑on, fast “quick” subset to sanity‑check core paths every time.
|
- Use [SKIP:<reason>] prefix for environment/host dependent skips.
|
||||||
- Keep broader/experimental/host‑dependent reps as optional, SKIP‑guarded.
|
- Examples: [SKIP] hakorune not built, [SKIP:env] plugin path missing
|
||||||
|
- Keep reasons short and stable to allow grep-based canaries.
|
||||||
|
- Prefer JSON-only output in CI: set `NYASH_JSON_ONLY=1` to avoid noisy logs.
|
||||||
|
- Diagnostics lines like `[provider/select:*]` are filtered by default in `lib/test_runner.sh`.
|
||||||
|
|
||||||
Always‑on (quick)
|
Helpers
|
||||||
- Runner: `tools/smokes/v2/run_quick.sh`
|
- `tools/smokes/v2/lib/mir_canary.sh` provides:
|
||||||
- Includes:
|
- `extract_mir_from_output` — between [MIR_BEGIN]/[MIR_END]
|
||||||
- Core crate/native reps (phase2100/run_all.sh) — SKIP when unavailable
|
- `assert_has_tokens`, `assert_skip_tag`, `assert_order`, `assert_token_count`
|
||||||
- Stage‑B Program(JSON) shape (phase2160: stageb_* canaries)
|
- `tools/lib/canary.sh` provides minimal, harness-agnostic aliases:
|
||||||
- loop_scan minimal canaries (!=' + else Break/Continue)
|
- `extract_mir_between_tags` — same as `extract_mir_from_output`
|
||||||
|
- `require_tokens token...` — fail if any token missing
|
||||||
|
|
||||||
Optional (per‑phase)
|
Notes
|
||||||
- Richer/experimental reps remain under `profiles/quick/core/phase*/run_all.sh` and individual canaries.
|
- Avoid running heavy integration smokes in CI by default. Use `--profile quick`.
|
||||||
- Examples:
|
- When a test depends on external tools (e.g., LLVM), prefer `[SKIP:<reason>]` over failure.
|
||||||
- registry_* tag observation canaries (structure only)
|
|
||||||
- program_to_mir_exe_* (host/tooling dependent, SKIP‑guarded)
|
|
||||||
|
|
||||||
Conventions
|
|
||||||
- 3‑state outcomes: PASS / SKIP / FAIL(FAIL should be rare and intentional)
|
|
||||||
- SKIP guards are preferred over brittle environment assumptions.
|
|
||||||
- Add light canaries first; escalate to run_all only when stable and fast.
|
|
||||||
|
|
||||||
Usage
|
|
||||||
- Run quick set: `bash tools/smokes/v2/run_quick.sh`
|
|
||||||
- Run a phase: `bash tools/smokes/v2/profiles/quick/core/<phase>/run_all.sh`
|
|
||||||
- Run a single canary: `bash tools/smokes/v2/profiles/quick/core/<phase>/<name>_canary_vm.sh`
|
|
||||||
|
|
||||||
|
Quick tips
|
||||||
|
- EXE-heavy cases (e.g., `phase2100/*`) may take longer. When running quick with these tests, pass a larger timeout like `--timeout 120`.
|
||||||
|
- Smokes v2 auto-cleans temporary crate EXE objects created under `/tmp` (pattern: `ny_crate_backend_exe_*.o`) after the run.
|
||||||
|
|||||||
@ -856,3 +856,18 @@ enable_mirbuilder_dev_env() {
|
|||||||
# export HAKO_MIR_BUILDER_NORMALIZE_TAG=1 # optional: show tags in logs for diagnostics
|
# export HAKO_MIR_BUILDER_NORMALIZE_TAG=1 # optional: show tags in logs for diagnostics
|
||||||
# fi
|
# fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Dev profile helpers (EXE/AOT bring-up)
|
||||||
|
# Sets environment defaults for LLVM crate backend and EXE link paths.
|
||||||
|
# Usage: call enable_exe_dev_env in EXE canaries.
|
||||||
|
enable_exe_dev_env() {
|
||||||
|
# Prefer crate backend when available
|
||||||
|
export NYASH_LLVM_BACKEND=${NYASH_LLVM_BACKEND:-crate}
|
||||||
|
# Tool locations (override when cross)
|
||||||
|
export NYASH_NY_LLVM_COMPILER=${NYASH_NY_LLVM_COMPILER:-"$NYASH_ROOT/target/release/ny-llvmc"}
|
||||||
|
# NyRT (kernel) lib search path for linking EXEs
|
||||||
|
export NYASH_EMIT_EXE_NYRT=${NYASH_EMIT_EXE_NYRT:-"$NYASH_ROOT/target/release"}
|
||||||
|
# Optional verification toggles (kept ON by default only for canaries that opt-in)
|
||||||
|
export NYASH_LLVM_VERIFY=${NYASH_LLVM_VERIFY:-0}
|
||||||
|
export NYASH_LLVM_VERIFY_IR=${NYASH_LLVM_VERIFY_IR:-0}
|
||||||
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
||||||
|
source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true
|
||||||
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
||||||
|
|
||||||
# Prebuild required tools/libraries
|
# Prebuild required tools/libraries
|
||||||
@ -27,7 +28,10 @@ APP="/tmp/ny_crate_backend_exe_binop_$$"
|
|||||||
TMP_JSON="/tmp/ny_crate_backend_exe_binop_$$.json"
|
TMP_JSON="/tmp/ny_crate_backend_exe_binop_$$.json"
|
||||||
echo "$JSON" > "$TMP_JSON"
|
echo "$JSON" > "$TMP_JSON"
|
||||||
|
|
||||||
if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
enable_exe_dev_env
|
||||||
|
|
||||||
|
if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \
|
||||||
|
"$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
||||||
if [[ -x "$APP" ]]; then
|
if [[ -x "$APP" ]]; then
|
||||||
set +e
|
set +e
|
||||||
"$APP" >/dev/null 2>&1; rc=$?
|
"$APP" >/dev/null 2>&1; rc=$?
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
||||||
|
source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true
|
||||||
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
||||||
|
|
||||||
(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true
|
(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true
|
||||||
@ -25,7 +26,10 @@ APP="/tmp/ny_crate_backend_exe_and_$$"
|
|||||||
TMP_JSON="/tmp/ny_crate_backend_exe_and_$$.json"
|
TMP_JSON="/tmp/ny_crate_backend_exe_and_$$.json"
|
||||||
echo "$JSON" > "$TMP_JSON"
|
echo "$JSON" > "$TMP_JSON"
|
||||||
|
|
||||||
if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
enable_exe_dev_env
|
||||||
|
|
||||||
|
if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \
|
||||||
|
"$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
||||||
if [[ -x "$APP" ]]; then
|
if [[ -x "$APP" ]]; then
|
||||||
set +e
|
set +e
|
||||||
"$APP" >/dev/null 2>&1; rc=$?
|
"$APP" >/dev/null 2>&1; rc=$?
|
||||||
@ -40,4 +44,3 @@ fi
|
|||||||
echo "[FAIL] s3_backend_selector_crate_exe_bitwise_and_canary_vm" >&2
|
echo "[FAIL] s3_backend_selector_crate_exe_bitwise_and_canary_vm" >&2
|
||||||
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
||||||
exit 1
|
exit 1
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
||||||
|
source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true
|
||||||
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
||||||
|
|
||||||
(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true
|
(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true
|
||||||
@ -25,7 +26,10 @@ APP="/tmp/ny_crate_backend_exe_cmp_eq_$$"
|
|||||||
TMP_JSON="/tmp/ny_crate_backend_exe_cmp_eq_$$.json"
|
TMP_JSON="/tmp/ny_crate_backend_exe_cmp_eq_$$.json"
|
||||||
echo "$JSON" > "$TMP_JSON"
|
echo "$JSON" > "$TMP_JSON"
|
||||||
|
|
||||||
if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
enable_exe_dev_env
|
||||||
|
|
||||||
|
if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \
|
||||||
|
"$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
||||||
if [[ -x "$APP" ]]; then
|
if [[ -x "$APP" ]]; then
|
||||||
set +e
|
set +e
|
||||||
"$APP" >/dev/null 2>&1; rc=$?
|
"$APP" >/dev/null 2>&1; rc=$?
|
||||||
@ -40,4 +44,3 @@ fi
|
|||||||
echo "[FAIL] s3_backend_selector_crate_exe_compare_eq_true_canary_vm" >&2
|
echo "[FAIL] s3_backend_selector_crate_exe_compare_eq_true_canary_vm" >&2
|
||||||
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
||||||
exit 1
|
exit 1
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
||||||
|
source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true
|
||||||
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
||||||
|
|
||||||
(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true
|
(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true
|
||||||
@ -25,7 +26,10 @@ APP="/tmp/ny_crate_backend_exe_cmp_ge_b_$$"
|
|||||||
TMP_JSON="/tmp/ny_crate_backend_exe_cmp_ge_b_$$.json"
|
TMP_JSON="/tmp/ny_crate_backend_exe_cmp_ge_b_$$.json"
|
||||||
echo "$JSON" > "$TMP_JSON"
|
echo "$JSON" > "$TMP_JSON"
|
||||||
|
|
||||||
if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
enable_exe_dev_env
|
||||||
|
|
||||||
|
if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \
|
||||||
|
"$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
||||||
if [[ -x "$APP" ]]; then
|
if [[ -x "$APP" ]]; then
|
||||||
set +e
|
set +e
|
||||||
"$APP" >/dev/null 2>&1; rc=$?
|
"$APP" >/dev/null 2>&1; rc=$?
|
||||||
@ -40,4 +44,3 @@ fi
|
|||||||
echo "[FAIL] s3_backend_selector_crate_exe_compare_ge_boundary_canary_vm" >&2
|
echo "[FAIL] s3_backend_selector_crate_exe_compare_ge_boundary_canary_vm" >&2
|
||||||
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
||||||
exit 1
|
exit 1
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
||||||
|
source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true
|
||||||
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
||||||
|
|
||||||
(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true
|
(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true
|
||||||
@ -25,7 +26,10 @@ APP="/tmp/ny_crate_backend_exe_cmp_le_b_$$"
|
|||||||
TMP_JSON="/tmp/ny_crate_backend_exe_cmp_le_b_$$.json"
|
TMP_JSON="/tmp/ny_crate_backend_exe_cmp_le_b_$$.json"
|
||||||
echo "$JSON" > "$TMP_JSON"
|
echo "$JSON" > "$TMP_JSON"
|
||||||
|
|
||||||
if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
enable_exe_dev_env
|
||||||
|
|
||||||
|
if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \
|
||||||
|
"$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
||||||
if [[ -x "$APP" ]]; then
|
if [[ -x "$APP" ]]; then
|
||||||
set +e
|
set +e
|
||||||
"$APP" >/dev/null 2>&1; rc=$?
|
"$APP" >/dev/null 2>&1; rc=$?
|
||||||
@ -40,4 +44,3 @@ fi
|
|||||||
echo "[FAIL] s3_backend_selector_crate_exe_compare_le_boundary_canary_vm" >&2
|
echo "[FAIL] s3_backend_selector_crate_exe_compare_le_boundary_canary_vm" >&2
|
||||||
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
||||||
exit 1
|
exit 1
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
||||||
|
source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true
|
||||||
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
||||||
|
|
||||||
(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true
|
(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true
|
||||||
@ -25,7 +26,10 @@ APP="/tmp/ny_crate_backend_exe_cmp_lt_neg_$$"
|
|||||||
TMP_JSON="/tmp/ny_crate_backend_exe_cmp_lt_neg_$$.json"
|
TMP_JSON="/tmp/ny_crate_backend_exe_cmp_lt_neg_$$.json"
|
||||||
echo "$JSON" > "$TMP_JSON"
|
echo "$JSON" > "$TMP_JSON"
|
||||||
|
|
||||||
if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
enable_exe_dev_env
|
||||||
|
|
||||||
|
if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \
|
||||||
|
"$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
||||||
if [[ -x "$APP" ]]; then
|
if [[ -x "$APP" ]]; then
|
||||||
set +e
|
set +e
|
||||||
"$APP" >/dev/null 2>&1; rc=$?
|
"$APP" >/dev/null 2>&1; rc=$?
|
||||||
@ -40,4 +44,3 @@ fi
|
|||||||
echo "[FAIL] s3_backend_selector_crate_exe_compare_lt_neg_canary_vm" >&2
|
echo "[FAIL] s3_backend_selector_crate_exe_compare_lt_neg_canary_vm" >&2
|
||||||
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
||||||
exit 1
|
exit 1
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
||||||
|
source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true
|
||||||
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
||||||
|
|
||||||
(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true
|
(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true
|
||||||
@ -25,7 +26,10 @@ APP="/tmp/ny_crate_backend_exe_cmp_ne_$$"
|
|||||||
TMP_JSON="/tmp/ny_crate_backend_exe_cmp_ne_$$.json"
|
TMP_JSON="/tmp/ny_crate_backend_exe_cmp_ne_$$.json"
|
||||||
echo "$JSON" > "$TMP_JSON"
|
echo "$JSON" > "$TMP_JSON"
|
||||||
|
|
||||||
if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
enable_exe_dev_env
|
||||||
|
|
||||||
|
if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \
|
||||||
|
"$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
||||||
if [[ -x "$APP" ]]; then
|
if [[ -x "$APP" ]]; then
|
||||||
set +e
|
set +e
|
||||||
"$APP" >/dev/null 2>&1; rc=$?
|
"$APP" >/dev/null 2>&1; rc=$?
|
||||||
@ -40,4 +44,3 @@ fi
|
|||||||
echo "[FAIL] s3_backend_selector_crate_exe_compare_ne_true_canary_vm" >&2
|
echo "[FAIL] s3_backend_selector_crate_exe_compare_ne_true_canary_vm" >&2
|
||||||
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
||||||
exit 1
|
exit 1
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
||||||
|
source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true
|
||||||
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
||||||
|
|
||||||
(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true
|
(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true
|
||||||
@ -25,7 +26,10 @@ APP="/tmp/ny_crate_backend_exe_div_$$"
|
|||||||
TMP_JSON="/tmp/ny_crate_backend_exe_div_$$.json"
|
TMP_JSON="/tmp/ny_crate_backend_exe_div_$$.json"
|
||||||
echo "$JSON" > "$TMP_JSON"
|
echo "$JSON" > "$TMP_JSON"
|
||||||
|
|
||||||
if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
enable_exe_dev_env
|
||||||
|
|
||||||
|
if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \
|
||||||
|
"$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
||||||
if [[ -x "$APP" ]]; then
|
if [[ -x "$APP" ]]; then
|
||||||
set +e
|
set +e
|
||||||
"$APP" >/dev/null 2>&1; rc=$?
|
"$APP" >/dev/null 2>&1; rc=$?
|
||||||
@ -40,4 +44,3 @@ fi
|
|||||||
echo "[FAIL] s3_backend_selector_crate_exe_div_canary_vm" >&2
|
echo "[FAIL] s3_backend_selector_crate_exe_div_canary_vm" >&2
|
||||||
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
||||||
exit 1
|
exit 1
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
||||||
|
source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true
|
||||||
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
||||||
|
|
||||||
(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true
|
(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true
|
||||||
@ -34,7 +35,10 @@ APP="/tmp/ny_crate_backend_exe_phi_ret42_$$"
|
|||||||
TMP_JSON="/tmp/ny_crate_backend_exe_phi_ret42_$$.json"
|
TMP_JSON="/tmp/ny_crate_backend_exe_phi_ret42_$$.json"
|
||||||
echo "$JSON" > "$TMP_JSON"
|
echo "$JSON" > "$TMP_JSON"
|
||||||
|
|
||||||
if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
enable_exe_dev_env
|
||||||
|
|
||||||
|
if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \
|
||||||
|
"$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
||||||
if [[ -x "$APP" ]]; then
|
if [[ -x "$APP" ]]; then
|
||||||
set +e
|
set +e
|
||||||
"$APP" >/dev/null 2>&1; rc=$?
|
"$APP" >/dev/null 2>&1; rc=$?
|
||||||
@ -49,4 +53,3 @@ fi
|
|||||||
echo "[FAIL] s3_backend_selector_crate_exe_phi_branch_return42_canary_vm" >&2
|
echo "[FAIL] s3_backend_selector_crate_exe_phi_branch_return42_canary_vm" >&2
|
||||||
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
||||||
exit 1
|
exit 1
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
||||||
|
source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true
|
||||||
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
||||||
|
|
||||||
# Prebuild required tools/libraries
|
# Prebuild required tools/libraries
|
||||||
@ -10,6 +11,8 @@ BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
|||||||
# Build minimal C runtime (design-stage) to provide nyash_console_log
|
# Build minimal C runtime (design-stage) to provide nyash_console_log
|
||||||
(cd "$ROOT" && cargo build -q --release -p nyash-kernel-min-c >/dev/null) || true
|
(cd "$ROOT" && cargo build -q --release -p nyash-kernel-min-c >/dev/null) || true
|
||||||
|
|
||||||
|
enable_exe_dev_env
|
||||||
|
|
||||||
# Minimal MIR v1 JSON that intends to print then return 0.
|
# Minimal MIR v1 JSON that intends to print then return 0.
|
||||||
# Note: If the builder rejects schema, we SKIP gracefully.
|
# Note: If the builder rejects schema, we SKIP gracefully.
|
||||||
JSON='{
|
JSON='{
|
||||||
@ -32,7 +35,8 @@ echo "$JSON" > "$TMP_JSON"
|
|||||||
LIBDIR_MIN="$ROOT/target/release"
|
LIBDIR_MIN="$ROOT/target/release"
|
||||||
LIBS="-L $LIBDIR_MIN -lnyash_kernel_min_c"
|
LIBS="-L $LIBDIR_MIN -lnyash_kernel_min_c"
|
||||||
|
|
||||||
if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --libs="$LIBS" --out "$APP" >/dev/null 2>&1; then
|
if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \
|
||||||
|
"$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --libs="$LIBS" --out "$APP" >/dev/null 2>&1; then
|
||||||
if [[ -x "$APP" ]]; then
|
if [[ -x "$APP" ]]; then
|
||||||
set +e
|
set +e
|
||||||
out="$($APP 2>/dev/null)"; rc=$?
|
out="$($APP 2>/dev/null)"; rc=$?
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
||||||
|
source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true
|
||||||
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
||||||
|
|
||||||
(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true
|
(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true
|
||||||
@ -25,7 +26,10 @@ APP="/tmp/ny_crate_backend_exe_rem_$$"
|
|||||||
TMP_JSON="/tmp/ny_crate_backend_exe_rem_$$.json"
|
TMP_JSON="/tmp/ny_crate_backend_exe_rem_$$.json"
|
||||||
echo "$JSON" > "$TMP_JSON"
|
echo "$JSON" > "$TMP_JSON"
|
||||||
|
|
||||||
if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
enable_exe_dev_env
|
||||||
|
|
||||||
|
if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \
|
||||||
|
"$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
||||||
if [[ -x "$APP" ]]; then
|
if [[ -x "$APP" ]]; then
|
||||||
set +e
|
set +e
|
||||||
"$APP" >/dev/null 2>&1; rc=$?
|
"$APP" >/dev/null 2>&1; rc=$?
|
||||||
@ -40,4 +44,3 @@ fi
|
|||||||
echo "[FAIL] s3_backend_selector_crate_exe_rem_canary_vm" >&2
|
echo "[FAIL] s3_backend_selector_crate_exe_rem_canary_vm" >&2
|
||||||
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
||||||
exit 1
|
exit 1
|
||||||
|
|
||||||
|
|||||||
@ -2,11 +2,13 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
||||||
|
source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true
|
||||||
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
||||||
|
|
||||||
# Prebuild required tools/libraries
|
# Prebuild required tools/libraries
|
||||||
(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true
|
(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true
|
||||||
(cd "$ROOT/crates/nyash_kernel" && cargo build -q --release >/dev/null) || true
|
(cd "$ROOT/crates/nyash_kernel" && cargo build -q --release >/dev/null) || true
|
||||||
|
enable_exe_dev_env
|
||||||
|
|
||||||
# Minimal MIR v1 JSON that returns 42.
|
# Minimal MIR v1 JSON that returns 42.
|
||||||
JSON='{
|
JSON='{
|
||||||
@ -25,7 +27,8 @@ APP="/tmp/ny_crate_backend_exe_ret42_$$"
|
|||||||
TMP_JSON="/tmp/ny_crate_backend_exe_ret42_$$.json"
|
TMP_JSON="/tmp/ny_crate_backend_exe_ret42_$$.json"
|
||||||
echo "$JSON" > "$TMP_JSON"
|
echo "$JSON" > "$TMP_JSON"
|
||||||
|
|
||||||
if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \
|
||||||
|
"$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
||||||
if [[ -x "$APP" ]]; then
|
if [[ -x "$APP" ]]; then
|
||||||
set +e
|
set +e
|
||||||
"$APP" >/dev/null 2>&1; rc=$?
|
"$APP" >/dev/null 2>&1; rc=$?
|
||||||
@ -37,7 +40,6 @@ if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyr
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
echo "[SKIP] s3_backend_selector_crate_exe_return42_canary_vm (rc mapping not active)" >&2
|
echo "[FAIL] s3_backend_selector_crate_exe_return42_canary_vm" >&2
|
||||||
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
||||||
exit 0
|
exit 1
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
||||||
|
source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true
|
||||||
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
||||||
|
|
||||||
# Prebuild required tools/libraries
|
# Prebuild required tools/libraries
|
||||||
@ -25,7 +26,10 @@ APP="/tmp/ny_crate_backend_exe_ret_$$"
|
|||||||
TMP_JSON="/tmp/ny_crate_backend_exe_ret_$$.json"
|
TMP_JSON="/tmp/ny_crate_backend_exe_ret_$$.json"
|
||||||
echo "$JSON" > "$TMP_JSON"
|
echo "$JSON" > "$TMP_JSON"
|
||||||
|
|
||||||
if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
enable_exe_dev_env
|
||||||
|
|
||||||
|
if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \
|
||||||
|
"$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
||||||
if [[ -x "$APP" ]]; then
|
if [[ -x "$APP" ]]; then
|
||||||
set +e
|
set +e
|
||||||
"$APP" >/dev/null 2>&1; rc=$?
|
"$APP" >/dev/null 2>&1; rc=$?
|
||||||
@ -40,4 +44,3 @@ fi
|
|||||||
echo "[FAIL] s3_backend_selector_crate_exe_return_canary_vm" >&2
|
echo "[FAIL] s3_backend_selector_crate_exe_return_canary_vm" >&2
|
||||||
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
||||||
exit 1
|
exit 1
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
||||||
|
source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true
|
||||||
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
||||||
|
|
||||||
(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true
|
(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true
|
||||||
@ -25,7 +26,10 @@ APP="/tmp/ny_crate_backend_exe_shl_$$"
|
|||||||
TMP_JSON="/tmp/ny_crate_backend_exe_shl_$$.json"
|
TMP_JSON="/tmp/ny_crate_backend_exe_shl_$$.json"
|
||||||
echo "$JSON" > "$TMP_JSON"
|
echo "$JSON" > "$TMP_JSON"
|
||||||
|
|
||||||
if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
enable_exe_dev_env
|
||||||
|
|
||||||
|
if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \
|
||||||
|
"$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
||||||
if [[ -x "$APP" ]]; then
|
if [[ -x "$APP" ]]; then
|
||||||
set +e
|
set +e
|
||||||
"$APP" >/dev/null 2>&1; rc=$?
|
"$APP" >/dev/null 2>&1; rc=$?
|
||||||
@ -40,4 +44,3 @@ fi
|
|||||||
echo "[FAIL] s3_backend_selector_crate_exe_shift_left_canary_vm" >&2
|
echo "[FAIL] s3_backend_selector_crate_exe_shift_left_canary_vm" >&2
|
||||||
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
||||||
exit 1
|
exit 1
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
||||||
|
source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true
|
||||||
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
||||||
|
|
||||||
(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true
|
(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true
|
||||||
@ -25,7 +26,10 @@ APP="/tmp/ny_crate_backend_exe_shr_$$"
|
|||||||
TMP_JSON="/tmp/ny_crate_backend_exe_shr_$$.json"
|
TMP_JSON="/tmp/ny_crate_backend_exe_shr_$$.json"
|
||||||
echo "$JSON" > "$TMP_JSON"
|
echo "$JSON" > "$TMP_JSON"
|
||||||
|
|
||||||
if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
enable_exe_dev_env
|
||||||
|
|
||||||
|
if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \
|
||||||
|
"$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then
|
||||||
if [[ -x "$APP" ]]; then
|
if [[ -x "$APP" ]]; then
|
||||||
set +e
|
set +e
|
||||||
"$APP" >/dev/null 2>&1; rc=$?
|
"$APP" >/dev/null 2>&1; rc=$?
|
||||||
@ -40,4 +44,3 @@ fi
|
|||||||
echo "[FAIL] s3_backend_selector_crate_exe_shift_right_canary_vm" >&2
|
echo "[FAIL] s3_backend_selector_crate_exe_shift_right_canary_vm" >&2
|
||||||
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
rm -f "$APP" "$TMP_JSON" 2>/dev/null || true
|
||||||
exit 1
|
exit 1
|
||||||
|
|
||||||
|
|||||||
@ -3,9 +3,12 @@ set -euo pipefail
|
|||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
ROOT_DIR="$(cd "$SCRIPT_DIR/../../../../../../.." && pwd)"
|
ROOT_DIR="$(cd "$SCRIPT_DIR/../../../../../../.." && pwd)"
|
||||||
|
source "$ROOT_DIR/tools/smokes/v2/lib/test_runner.sh" || true
|
||||||
BIN_NYLLVMC="$ROOT_DIR/target/release/ny-llvmc"
|
BIN_NYLLVMC="$ROOT_DIR/target/release/ny-llvmc"
|
||||||
BIN_HAKO="$ROOT_DIR/target/release/hakorune"
|
BIN_HAKO="$ROOT_DIR/target/release/hakorune"
|
||||||
|
|
||||||
|
enable_exe_dev_env
|
||||||
|
|
||||||
# Build tools if missing
|
# Build tools if missing
|
||||||
(cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true
|
(cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true
|
||||||
(cargo build -q --release >/dev/null) || true
|
(cargo build -q --release >/dev/null) || true
|
||||||
@ -30,7 +33,8 @@ fi
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Build exe with FAST lowering ON
|
# Build exe with FAST lowering ON
|
||||||
if ! NYASH_LLVM_FAST=1 bash "$ROOT_DIR/tools/ny_mir_builder.sh" --in "$TMP_JSON" --emit exe -o "$EXE_OUT" --quiet >/dev/null 2>&1; then
|
if ! NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 NYASH_LLVM_FAST=1 \
|
||||||
|
bash "$ROOT_DIR/tools/ny_mir_builder.sh" --in "$TMP_JSON" --emit exe -o "$EXE_OUT" --quiet >/dev/null 2>&1; then
|
||||||
echo "[SKIP] failed to build EXE"; exit 0
|
echo "[SKIP] failed to build EXE"; exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,51 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
||||||
|
source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true
|
||||||
|
|
||||||
|
# Ensure tools are built and environment is consistent for EXE
|
||||||
|
(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true
|
||||||
|
(cd "$ROOT/crates/nyash_kernel" && cargo build -q --release >/dev/null) || true
|
||||||
|
enable_exe_dev_env
|
||||||
|
|
||||||
|
# Minimal Hako program returning 42
|
||||||
|
TMP_HAKO=$(mktemp --suffix .hako)
|
||||||
|
cat >"$TMP_HAKO" <<'HAKO'
|
||||||
|
static box Main { method main(args) { return 42 } }
|
||||||
|
HAKO
|
||||||
|
|
||||||
|
TMP_JSON=$(mktemp --suffix .json)
|
||||||
|
EXE_OUT="${ROOT}/target/parity_ret42_$$"
|
||||||
|
BIN_NYLLVMC="$ROOT/target/release/ny-llvmc"
|
||||||
|
trap 'rm -f "$TMP_HAKO" "$TMP_JSON" "$EXE_OUT" 2>/dev/null || true' EXIT
|
||||||
|
|
||||||
|
# Run via VM and capture program exit code from return status
|
||||||
|
set +e
|
||||||
|
run_nyash_vm "$TMP_HAKO" >/dev/null 2>&1
|
||||||
|
rc_vm=$?
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Emit MIR JSON and build EXE (crate backend)
|
||||||
|
if ! NYASH_JSON_ONLY=1 bash "$ROOT/tools/hakorune_emit_mir.sh" "$TMP_HAKO" "$TMP_JSON" >/dev/null 2>&1; then
|
||||||
|
echo "[FAIL] exe_vm_parity_ret42: failed to emit MIR JSON" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$EXE_OUT" >/dev/null 2>&1; then
|
||||||
|
echo "[FAIL] exe_vm_parity_ret42: failed to build EXE" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run EXE and compare RCs
|
||||||
|
set +e
|
||||||
|
"$EXE_OUT" >/dev/null 2>&1
|
||||||
|
rc_exe=$?
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [[ "$rc_exe" -eq "$rc_vm" ]]; then
|
||||||
|
echo "[PASS] s3_backend_selector_crate_exe_vm_parity_return42_canary_vm"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "[FAIL] exe_vm_parity_ret42: mismatch vm=$rc_vm exe=$rc_exe" >&2
|
||||||
|
exit 1
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)"
|
||||||
|
source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true
|
||||||
|
|
||||||
|
enable_exe_dev_env
|
||||||
|
|
||||||
|
# Minimal loop program (structure only)
|
||||||
|
TMP_HAKO=$(mktemp --suffix .hako)
|
||||||
|
cat >"$TMP_HAKO" <<'HAKO'
|
||||||
|
static box Main { method main(args){
|
||||||
|
local n=10; local i=0;
|
||||||
|
loop(i<n){ i=i+1 }
|
||||||
|
return i
|
||||||
|
} }
|
||||||
|
HAKO
|
||||||
|
|
||||||
|
TMP_JSON=$(mktemp --suffix .json)
|
||||||
|
EXE_OUT="${ROOT}/target/stageb_loop_jsonfrag_$$"
|
||||||
|
trap 'rm -f "$TMP_HAKO" "$TMP_JSON" "$EXE_OUT" 2>/dev/null || true' EXIT
|
||||||
|
|
||||||
|
# Emit MIR(JSON) via selfhost-first and JSONFrag loop (normalized)
|
||||||
|
if ! HAKO_SELFHOST_BUILDER_FIRST=1 HAKO_MIR_BUILDER_LOOP_JSONFRAG=1 HAKO_MIR_BUILDER_JSONFRAG_NORMALIZE=1 HAKO_MIR_BUILDER_JSONFRAG_PURIFY=1 HAKO_MIR_BUILDER_LOOP_FORCE_JSONFRAG=1 \
|
||||||
|
NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \
|
||||||
|
NYASH_JSON_ONLY=1 bash "$ROOT/tools/hakorune_emit_mir.sh" "$TMP_HAKO" "$TMP_JSON" >/dev/null 2>&1; then
|
||||||
|
echo "[FAIL] stageb_loop_jsonfrag: failed to emit MIR JSON"; exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Assert no MapBox/newbox present in MIR(JSON)
|
||||||
|
if rg -n "newbox|MapBox" "$TMP_JSON" >/dev/null 2>&1; then
|
||||||
|
echo "[FAIL] stageb_loop_jsonfrag: found MapBox/newbox in MIR"; exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build EXE via crate backend
|
||||||
|
if ! NYASH_LLVM_BACKEND=crate NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 \
|
||||||
|
NYASH_NY_LLVM_COMPILER="${NYASH_NY_LLVM_COMPILER:-$ROOT/target/release/ny-llvmc}" \
|
||||||
|
NYASH_EMIT_EXE_NYRT="${NYASH_EMIT_EXE_NYRT:-$ROOT/target/release}" \
|
||||||
|
bash "$ROOT/tools/ny_mir_builder.sh" --in "$TMP_JSON" --emit exe -o "$EXE_OUT" --quiet >/dev/null 2>&1; then
|
||||||
|
echo "[FAIL] stageb_loop_jsonfrag: failed to build EXE"; exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run and just ensure it executes (RC arbitrary here because structure-only lower)
|
||||||
|
set +e
|
||||||
|
"$EXE_OUT" >/dev/null 2>&1
|
||||||
|
rc=$?
|
||||||
|
set -e
|
||||||
|
if [[ "$rc" -ge 0 ]]; then
|
||||||
|
echo "[PASS] stageb_loop_jsonfrag_crate_exe_canary_vm"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "[FAIL] stageb_loop_jsonfrag_crate_exe_canary_vm (unexpected run failure)"; exit 1
|
||||||
@ -428,6 +428,9 @@ EOF
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
# Post-run cleanup: remove smokes-generated crate EXE object files under /tmp
|
||||||
|
rm -f /tmp/ny_crate_backend_exe_*.o 2>/dev/null || true
|
||||||
|
|
||||||
# 終了コード
|
# 終了コード
|
||||||
[ $failed -eq 0 ]
|
[ $failed -eq 0 ]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user