trace: add execution route visibility + debug passthrough; phase2170 canaries; docs
- Add HAKO_TRACE_EXECUTION to trace executor route - Rust hv1_inline: stderr [trace] executor: hv1_inline (rust) - Hakovm dispatcher: stdout [trace] executor: hakovm (hako) - test_runner: trace lines for hv1_inline/core/hakovm routes - Add HAKO_VERIFY_SHOW_LOGS and HAKO_DEBUG=1 (enables both) - verify_v1_inline_file() log passthrough with numeric rc extraction - test_runner exports via HAKO_DEBUG - Canary expansion under phase2170 (state spec) - Array: push×5/10 → size, len/length alias, per‑recv/global, flow across blocks - Map: set dup-key non-increment, value_state get/has - run_all.sh: unify, remove SKIPs; all PASS - Docs - ENV_VARS.md: add Debug/Tracing toggles and examples - PLAN.md/CURRENT_TASK.md: mark 21.7 green, add Quickstart lines All changes gated by env vars; default behavior unchanged.
This commit is contained in:
@ -10,7 +10,43 @@ using selfhost.vm.helpers.method_alias_policy as MethodAliasPolicy
|
||||
using selfhost.vm.boxes.abi_adapter_registry as AbiAdapterRegistryBox
|
||||
|
||||
static box MirCallV1HandlerBox {
|
||||
// キー正規化ヘルパー(SSOT)
|
||||
_norm_key_str(s) {
|
||||
if s == null { return null }
|
||||
local orig = s
|
||||
|
||||
// 先頭・末尾の引用符を除去("k1" → k1)
|
||||
local len = s.length()
|
||||
if len >= 2 {
|
||||
local first = s.substring(0, 1)
|
||||
local last = s.substring(len - 1, len)
|
||||
if first == "\"" && last == "\"" {
|
||||
s = s.substring(1, len - 1)
|
||||
}
|
||||
}
|
||||
|
||||
// [map/missing] はnullを返す
|
||||
if s.indexOf("[map/missing]") >= 0 {
|
||||
return null
|
||||
}
|
||||
|
||||
if env.get("HAKO_VM_MIRCALL_TRACE_KEYS") == "1" {
|
||||
print("[vm/_norm_key_str] IN=" + orig + " OUT=" + s)
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// デバッグトレース(任意)
|
||||
_norm_key_dbg(raw, norm) {
|
||||
local trace_keys = env.get("HAKO_VM_MIRCALL_TRACE_KEYS")
|
||||
if trace_keys == "1" {
|
||||
print("[vm/trace/keys] raw=" + raw + " norm=" + norm)
|
||||
}
|
||||
}
|
||||
|
||||
handle(seg, regs) {
|
||||
print("[DEBUG_HANDLER_ENTRY] seg=" + seg.substring(0, 80))
|
||||
// Constructor: write dst=0 (SSA continuity)
|
||||
if seg.indexOf("\"type\":\"Constructor\"") >= 0 {
|
||||
local d0 = JsonFragBox.get_int(seg, "dst"); if d0 != null { regs.setField(StringHelpers.int_to_str(d0), "0") }
|
||||
@ -83,19 +119,22 @@ static box MirCallV1HandlerBox {
|
||||
}
|
||||
// Map.set: 重複キー検知つきでサイズ更新 + 値保存(値状態ON時)
|
||||
if btype == "MapBox" && mname == "set" {
|
||||
print("[DEBUG_ADAPTER_MAP_SET] ENTER")
|
||||
// 受信者・キー抽出
|
||||
local arg0 = MiniMirV1Scan.first_arg_register(seg)
|
||||
local key_str = null
|
||||
if arg0 >= 0 {
|
||||
key_str = regs.getField(StringHelpers.int_to_str(arg0))
|
||||
// MapBox.get returns "[map/missing] ..." for missing keys; treat as null
|
||||
if key_str != null && key_str.indexOf("[map/missing]") >= 0 { key_str = null }
|
||||
local key_str_raw = regs.getField(StringHelpers.int_to_str(arg0))
|
||||
key_str = me._norm_key_str(key_str_raw)
|
||||
me._norm_key_dbg(key_str_raw, key_str)
|
||||
print("[DEBUG_ADAPTER_MAP_SET] raw=" + key_str_raw + " norm=" + key_str)
|
||||
}
|
||||
// 重複キー検知(presence フラグを別ネーム空間に保持)
|
||||
if key_str != null {
|
||||
local rid_s = rid == null ? "null" : (""+rid)
|
||||
local pres_key = "hvm.map.k:" + (per_recv == "1" ? rid_s : "*") + ":" + key_str
|
||||
local had = regs.getField(pres_key)
|
||||
if env.get("HAKO_VM_MIRCALL_TRACE") == "1" { print("[vm/trace/adapter] pres_key=" + pres_key + " had=" + had + " cur_len=" + cur_len) }
|
||||
if had == null {
|
||||
regs.setField(pres_key, "1")
|
||||
cur_len = cur_len + 1
|
||||
@ -126,9 +165,9 @@ static box MirCallV1HandlerBox {
|
||||
if btype == "MapBox" && mname == "get" && value_state == "1" {
|
||||
local arg0 = MiniMirV1Scan.first_arg_register(seg)
|
||||
if arg0 >= 0 {
|
||||
local key_str = regs.getField(StringHelpers.int_to_str(arg0))
|
||||
// MapBox.get returns "[map/missing] ..." for missing keys; treat as null
|
||||
if key_str != null && key_str.indexOf("[map/missing]") >= 0 { key_str = null }
|
||||
local key_str_raw = regs.getField(StringHelpers.int_to_str(arg0))
|
||||
local key_str = me._norm_key_str(key_str_raw)
|
||||
me._norm_key_dbg(key_str_raw, key_str)
|
||||
if key_str != null {
|
||||
local val_key = MethodAliasPolicy.recv_map_key(per_recv, rid, key_str)
|
||||
local val_str = regs.getField(val_key)
|
||||
@ -146,9 +185,9 @@ static box MirCallV1HandlerBox {
|
||||
local arg0 = MiniMirV1Scan.first_arg_register(seg)
|
||||
local has_result = 0
|
||||
if arg0 >= 0 {
|
||||
local key_str = regs.getField(StringHelpers.int_to_str(arg0))
|
||||
// MapBox.get returns "[map/missing] ..." for missing keys; treat as null
|
||||
if key_str != null && key_str.indexOf("[map/missing]") >= 0 { key_str = null }
|
||||
local key_str_raw = regs.getField(StringHelpers.int_to_str(arg0))
|
||||
local key_str = me._norm_key_str(key_str_raw)
|
||||
me._norm_key_dbg(key_str_raw, key_str)
|
||||
if key_str != null {
|
||||
local val_key = MethodAliasPolicy.recv_map_key(per_recv, rid, key_str)
|
||||
local val_str = regs.getField(val_key)
|
||||
@ -193,23 +232,41 @@ static box MirCallV1HandlerBox {
|
||||
local d1 = JsonFragBox.get_int(seg, "dst"); if d1 != null { regs.setField(StringHelpers.int_to_str(d1), "0") }
|
||||
return
|
||||
}
|
||||
// Map.set: 重複キー検知つきサイズ更新(値状態に依存しない最小実装)
|
||||
// Map.set: 重複キー検知つきサイズ更新(値状態ONなら値も保存)
|
||||
if btype == "MapBox" && mname == "set" {
|
||||
// キー抽出
|
||||
local arg0 = MiniMirV1Scan.first_arg_register(seg)
|
||||
if arg0 >= 0 {
|
||||
local key_str = regs.getField(StringHelpers.int_to_str(arg0))
|
||||
// MapBox.get returns "[map/missing] ..." for missing keys; treat as null
|
||||
if key_str != null && key_str.indexOf("[map/missing]") >= 0 { key_str = null }
|
||||
local key_str_raw = regs.getField(StringHelpers.int_to_str(arg0))
|
||||
local key_str = me._norm_key_str(key_str_raw)
|
||||
me._norm_key_dbg(key_str_raw, key_str)
|
||||
print("[DEBUG_MAP_SET] raw=" + key_str_raw + " norm=" + key_str)
|
||||
if key_str != null {
|
||||
local rid_s = rid == null ? "null" : (""+rid)
|
||||
local pres_key = "hvm.map.k:" + (per_recv == "1" ? rid_s : "*") + ":" + key_str
|
||||
local had = regs.getField(pres_key)
|
||||
print("[DEBUG_MAP_SET] pres_key=" + pres_key + " had=" + had + " cur_len=" + cur_len)
|
||||
if env.get("HAKO_VM_MIRCALL_TRACE") == "1" { print("[vm/trace/fallback] pres_key=" + pres_key + " had=" + had + " cur_len=" + cur_len) }
|
||||
if had == null {
|
||||
regs.setField(pres_key, "1")
|
||||
cur_len = cur_len + 1
|
||||
regs.setField(key, StringHelpers.int_to_str(cur_len))
|
||||
print("[DEBUG_MAP_SET] NEW KEY, cur_len now=" + cur_len)
|
||||
if env.get("HAKO_VM_MIRCALL_TRACE") == "1" { print("[vm/trace] map.set(fallback,new) cur_len=" + cur_len) }
|
||||
} else {
|
||||
print("[DEBUG_MAP_SET] DUP KEY, cur_len unchanged=" + cur_len)
|
||||
}
|
||||
// 値状態ON時は値も保持(get/hasで参照可能に)
|
||||
local value_state2 = env.get("HAKO_VM_MIRCALL_VALUESTATE"); if value_state2 == null { value_state2 = "0" }
|
||||
if value_state2 == "1" {
|
||||
local arg1_id2 = MiniMirV1Scan.nth_arg_register(seg, 1)
|
||||
if arg1_id2 >= 0 {
|
||||
local val_str2 = regs.getField(StringHelpers.int_to_str(arg1_id2))
|
||||
if val_str2 != null {
|
||||
local vkey2 = MethodAliasPolicy.recv_map_key(per_recv, rid, key_str)
|
||||
regs.setField(vkey2, ""+val_str2)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cur_len = cur_len + 1
|
||||
|
||||
@ -164,6 +164,7 @@ static box NyVmDispatcherV1Box {
|
||||
}
|
||||
// Main entry: Choose internal scanner when enabled; otherwise delegate to Mini‑VM
|
||||
run(json) {
|
||||
if env.get("HAKO_TRACE_EXECUTION") == "1" { print("[trace] executor: hakovm (hako)") }
|
||||
// Typed IR primary (限定): 構造IR生成を有効化しつつ既存フローを使用(挙動不変)
|
||||
if env.get("HAKO_V1_TYPED_IR_PRIMARY") == "1" {
|
||||
// ShadowをONにして構造IR生成のオーバーヘッドを観測(必要時)
|
||||
|
||||
Reference in New Issue
Block a user