vm(hako): dispatcher v1 flow scan (opt-in HAKO_V1_DISPATCHER_FLOW), extend extern_provider stubs, parity canary; share block scan used from Mini-VM; keep Core fallback for unsupported ops

This commit is contained in:
nyash-codex
2025-11-03 23:30:23 +09:00
parent 3bda84b136
commit 70a98ae09b
3 changed files with 110 additions and 0 deletions

View File

@ -38,8 +38,71 @@ static box NyVmDispatcherV1Box {
}
return 0
}
// Internal scanner with simple flow: const/compare/mir_call/branch/jump/ret (phi→fallback)
run_scan_flow(json) {
json = "" + json
local regs = new MiniMap()
local last_cmp_dst = -1
local last_cmp_val = 0
local bb = 0
local steps = 0
local max_steps = 200000
loop(true) {
steps = steps + 1
if steps > max_steps { return 0 }
local start = JsonV1ReaderBox.block_insts_start(json, bb)
if start < 0 { return 0 }
local endp = JsonCursorBox.seek_array_end(json, start)
if endp <= start { return 0 }
local seg = (""+json).substring(start + 1, endp)
local scan = 0
loop(true) {
if scan >= seg.length() { break }
local tup = InstructionScannerBox.next_tuple(seg, scan)
if tup == "" { break }
local c1 = StringOps.index_of_from(tup, ",", 0)
local c2 = StringOps.index_of_from(tup, ",", c1+1)
if c1 < 0 || c2 < 0 { break }
local s = JsonFragBox._str_to_int(tup.substring(0, c1))
local e = JsonFragBox._str_to_int(tup.substring(c1+1, c2))
local op = tup.substring(c2+1, tup.length())
local item = seg.substring(s, e)
if op == "const" { OpHandlersBox.handle_const(item, regs) }
else if op == "compare" {
OpHandlersBox.handle_compare(item, regs)
local dst = JsonFragBox.get_int(item, "dst")
if dst != null {
last_cmp_dst = dst
local sv = regs.getField(""+dst); if sv != null { last_cmp_val = JsonFragBox._str_to_int(""+sv) } else { last_cmp_val = 0 }
}
}
else if op == "mir_call" { MirCallV1HandlerBox.handle(item, regs) }
else if op == "branch" {
local c = JsonFragBox.get_int(item, "cond")
local t = JsonFragBox.get_int(item, "then")
local f = JsonFragBox.get_int(item, "else")
if c != null && t != null && f != null {
local cv = 0
if c == last_cmp_dst { cv = last_cmp_val } else { local sv = regs.getField(""+c); if sv != null { cv = JsonFragBox._str_to_int(""+sv) } }
bb = (cv != 0) ? t : f
break
} else { return MirVmMin.run_min(json) }
}
else if op == "jump" {
local tgt = JsonFragBox.get_int(item, "target"); if tgt == null { return MirVmMin.run_min(json) }
bb = tgt; break
}
else if op == "phi" {
return MirVmMin.run_min(json)
}
else if op == "ret" { return MirVmMin._handle_ret_op(item, regs, last_cmp_dst, last_cmp_val, 0) }
scan = e
}
}
}
// Main entry: Choose internal scanner when enabled; otherwise delegate to MiniVM
run(json) {
if env.get("HAKO_V1_DISPATCHER_FLOW") == "1" { return me.run_scan_flow(json) }
if env.get("HAKO_V1_DISPATCHER_INTERNAL") == "1" { return me.run_scan(json) }
return MirVmMin.run_min(json)
}

View File

@ -17,6 +17,14 @@ static box HakoruneExternProviderBox {
print("" + args)
return 0
}
if name == "env.mirbuilder.emit" {
// Stub only (20.38でCABI接続): return empty string
return ""
}
if name == "env.codegen.emit_object" {
// Stub only: return empty string (path placeholder)
return ""
}
// Unknown: return null for now (caller decides FailFast)
return null
}

View File

@ -0,0 +1,39 @@
#!/bin/bash
# Parity: MirCallV1Handler used by MiniVM and Hakovm dispatcher produce same rc
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi
source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2
tmp_json="/tmp/mir_v1_parity_mircall_$$.json"
cat > "$tmp_json" <<'JSON'
{
"schema_version": "1.0",
"functions": [
{"name":"main","blocks":[{"id":0,"instructions":[
{"op":"mir_call","dst":0, "callee":{"type":"Constructor","box_type":"ArrayBox"}, "args":[], "effects":[]},
{"op":"const","dst":1, "value": {"type": "i64", "value": 10}},
{"op":"const","dst":2, "value": {"type": "i64", "value": 20}},
{"op":"mir_call", "callee":{"type":"Method","box_name":"ArrayBox","method":"push","receiver":0}, "args":[1], "effects":[]},
{"op":"mir_call", "callee":{"type":"Method","box_name":"ArrayBox","method":"push","receiver":0}, "args":[2], "effects":[]},
{"op":"mir_call","dst":3, "callee":{"type":"Method","box_name":"ArrayBox","method":"size","receiver":0}, "args":[], "effects":[]},
{"op":"ret","value":3}
]}]}
]
}
JSON
set +e
# MiniVM path
rc_min=0; HAKO_VERIFY_PRIMARY=hakovm HAKO_V1_DISPATCHER_INTERNAL=0 HAKO_V1_DISPATCHER_FLOW=0 verify_mir_rc "$tmp_json" >/dev/null 2>&1; rc_min=$?
# Hakovm internal flow path
rc_hv1=0; HAKO_VERIFY_PRIMARY=hakovm HAKO_V1_DISPATCHER_FLOW=1 verify_mir_rc "$tmp_json" >/dev/null 2>&1; rc_hv1=$?
set -e
rm -f "$tmp_json" || true
if [ "$rc_min" -eq "$rc_hv1" ]; then
echo "[PASS] v1_mircall_parity_hakovm_minivm_vm (rc=$rc_hv1)"
exit 0
fi
echo "[FAIL] v1_mircall_parity_hakovm_minivm_vm (mini=$rc_min, hv1=$rc_hv1)" >&2; exit 1