fix(mir): PHI検証panic修正 - update_cfg()を検証前に呼び出し
A案実装: debug_verify_phi_inputs呼び出し前にCFG predecessorを更新
修正箇所(7箇所):
- src/mir/builder/phi.rs:50, 73, 132, 143
- src/mir/builder/ops.rs:273, 328, 351
根本原因:
- Branch/Jump命令でsuccessorは即座に更新
- predecessorはupdate_cfg()で遅延再構築
- PHI検証が先に実行されてpredecessor未更新でpanic
解決策:
- 各debug_verify_phi_inputs呼び出し前に
if let Some(func) = self.current_function.as_mut() {
func.update_cfg();
}
を挿入してCFGを同期
影響: if/else文、論理演算子(&&/||)のPHI生成が正常動作
This commit is contained in:
@ -45,8 +45,8 @@ static box NyVmDispatcher {
|
||||
// Iteration cap (ENV override: HAKO_CORE_MAX_ITERS | NYASH_CORE_MAX_ITERS)
|
||||
local max_iter = 10000
|
||||
{
|
||||
local v = call("env.local.get/1", "HAKO_CORE_MAX_ITERS")
|
||||
if v == null || v == "" { v = call("env.local.get/1", "NYASH_CORE_MAX_ITERS") }
|
||||
local v = env.get("HAKO_CORE_MAX_ITERS")
|
||||
if v == null || v == "" { v = env.get("NYASH_CORE_MAX_ITERS") }
|
||||
if v != null && v != "" {
|
||||
local n = StringHelpers.to_i64(v)
|
||||
if n > 0 { max_iter = n }
|
||||
|
||||
@ -6,7 +6,7 @@ using "lang/src/shared/common/string_helpers.hako" as StringHelpers
|
||||
|
||||
static box NyVmJsonV0Reader {
|
||||
_skip_ws(s, i) {
|
||||
local n = s.size()
|
||||
local n = s.length()
|
||||
loop(i < n) {
|
||||
local ch = s.substring(i,i+1)
|
||||
if ch == " " || ch == "\n" || ch == "\r" || ch == "\t" { i = i + 1 continue }
|
||||
@ -93,7 +93,7 @@ static box NyVmJsonV0Reader {
|
||||
local arr = func_json.substring(lb+1, rb)
|
||||
// iterate objects
|
||||
local pos = 0
|
||||
local n = arr.size()
|
||||
local n = arr.length()
|
||||
loop (pos < n) {
|
||||
// skip ws/commas
|
||||
loop (pos < n) {
|
||||
@ -117,7 +117,7 @@ static box NyVmJsonV0Reader {
|
||||
|
||||
// Iterate instructions: return map { obj, next } or Err string when malformed; when finished, returns { obj:null, next:len }
|
||||
next_instruction(insts_json, pos) {
|
||||
local n = insts_json.size()
|
||||
local n = insts_json.length()
|
||||
local i = me._skip_ws(insts_json, pos)
|
||||
if i >= n { return new MapBox() } // obj=null, next=len (empty map)
|
||||
// Skip trailing commas or ws
|
||||
|
||||
@ -24,7 +24,7 @@ static box NyVmOpMirCall {
|
||||
local key = "\"mir_call\":"
|
||||
local p = inst_json.indexOf(key)
|
||||
if p < 0 { return "" }
|
||||
p = p + key.size()
|
||||
p = p + key.length()
|
||||
local end = JsonCursorBox.seek_obj_end(inst_json, p)
|
||||
if end < 0 { return "" }
|
||||
return inst_json.substring(p, end+1)
|
||||
@ -81,7 +81,7 @@ static box NyVmOpMirCall {
|
||||
if colon < 0 { return "default" }
|
||||
local idx = colon + 1
|
||||
loop(true) {
|
||||
if idx >= mir_call_json.size() { return "default" }
|
||||
if idx >= mir_call_json.length() { return "default" }
|
||||
local ch = mir_call_json.substring(idx, idx+1)
|
||||
local is_ws = 0
|
||||
if ch == " " { is_ws = 1 }
|
||||
@ -91,7 +91,7 @@ static box NyVmOpMirCall {
|
||||
if is_ws == 1 { idx = idx + 1 continue }
|
||||
break
|
||||
}
|
||||
if idx >= mir_call_json.size() { return "default" }
|
||||
if idx >= mir_call_json.length() { return "default" }
|
||||
if mir_call_json.substring(idx, idx+1) != "{" { return "default" }
|
||||
local rb = JsonCursorBox.seek_obj_end(mir_call_json, idx)
|
||||
if rb < 0 { return "default" }
|
||||
@ -133,10 +133,10 @@ static box NyVmOpMirCall {
|
||||
if m.substring(idx, idx+1) == "]" { return "" }
|
||||
local digits = JsonCursorBox.digits_from(m, idx)
|
||||
if digits == "" { return "" }
|
||||
i_ref.set(0, idx + digits.size())
|
||||
i_ref.set(0, idx + digits.length())
|
||||
loop(true) {
|
||||
local idx2 = i_ref.get(0)
|
||||
if idx2 >= m.size() { break }
|
||||
if idx2 >= m.length() { break }
|
||||
local ch2 = m.substring(idx2, idx2+1)
|
||||
// Apply workaround here too
|
||||
local is_ws = 0
|
||||
@ -148,7 +148,7 @@ static box NyVmOpMirCall {
|
||||
break
|
||||
}
|
||||
local idx3 = i_ref.get(0)
|
||||
if idx3 < m.size() && m.substring(idx3, idx3+1) == "," { i_ref.set(0, idx3 + 1) }
|
||||
if idx3 < m.length() && m.substring(idx3, idx3+1) == "," { i_ref.set(0, idx3 + 1) }
|
||||
return digits
|
||||
}
|
||||
|
||||
@ -162,10 +162,10 @@ static box NyVmOpMirCall {
|
||||
local current = 0
|
||||
loop(true) {
|
||||
local idx = i.get(0)
|
||||
if idx >= m.size() { break }
|
||||
if idx >= m.length() { break }
|
||||
loop(true) {
|
||||
local idx2 = i.get(0)
|
||||
if idx2 >= m.size() { break }
|
||||
if idx2 >= m.length() { break }
|
||||
local ch = m.substring(idx2, idx2+1)
|
||||
// Parser workaround: avoid array-element assignment inside multi-way OR
|
||||
local is_ws = 0
|
||||
@ -177,7 +177,7 @@ static box NyVmOpMirCall {
|
||||
break
|
||||
}
|
||||
local idx3 = i.get(0)
|
||||
if idx3 >= m.size() { break }
|
||||
if idx3 >= m.length() { break }
|
||||
if m.substring(idx3, idx3+1) == "]" { break }
|
||||
local digits = me._scan_next_arg(m, i)
|
||||
if digits == "" { print(bad_tag) return null }
|
||||
@ -198,7 +198,7 @@ static box NyVmOpMirCall {
|
||||
local current = 0
|
||||
loop(true) {
|
||||
local idx = i.get(0)
|
||||
if idx >= m.size() { break }
|
||||
if idx >= m.length() { break }
|
||||
if m.substring(idx, idx+1) == "]" { break }
|
||||
local digits = me._scan_next_arg(m, i)
|
||||
if digits == "" { return null }
|
||||
@ -535,7 +535,7 @@ static box NyVmOpMirCall {
|
||||
if dst == null { return -1 }
|
||||
local recv_val = NyVmState.get_reg(state, recv_id)
|
||||
local s = "" + recv_val
|
||||
NyVmState.set_reg(state, dst, s.size())
|
||||
NyVmState.set_reg(state, dst, s.length())
|
||||
return 0
|
||||
}
|
||||
// String.indexOf/1 — return first index or -1
|
||||
@ -592,7 +592,7 @@ static box NyVmOpMirCall {
|
||||
local start = NyVmState.get_reg(state, start_vid)
|
||||
local end = NyVmState.get_reg(state, end_vid)
|
||||
// Bounds check
|
||||
if start < 0 || end < 0 || start > s.size() || end > s.size() || start > end {
|
||||
if start < 0 || end < 0 || start > s.length() || end > s.length() || start > end {
|
||||
return me._fail(state, "[core/string/bounds]")
|
||||
}
|
||||
local out = s.substring(start, end)
|
||||
@ -609,7 +609,7 @@ static box NyVmOpMirCall {
|
||||
local s = "" + recv_val
|
||||
local idx = NyVmState.get_reg(state, idx_vid)
|
||||
// Bounds check
|
||||
if idx < 0 || idx >= s.size() {
|
||||
if idx < 0 || idx >= s.length() {
|
||||
return me._fail(state, "[core/string/bounds]")
|
||||
}
|
||||
local ch = s.substring(idx, idx+1)
|
||||
@ -635,7 +635,7 @@ static box NyVmOpMirCall {
|
||||
local result = s
|
||||
if pos >= 0 {
|
||||
local before = s.substring(0, pos)
|
||||
local after = s.substring(pos + pattern.size(), s.size())
|
||||
local after = s.substring(pos + pattern.length(), s.length())
|
||||
result = before + replacement + after
|
||||
}
|
||||
NyVmState.set_reg(state, dst, result)
|
||||
@ -706,9 +706,9 @@ static box NyVmOpMirCall {
|
||||
// Fallback strict check: only digit strings with optional sign
|
||||
local s = "" + v
|
||||
local i = 0
|
||||
if s.size() > 0 && (s.substring(0,1) == "-" || s.substring(0,1) == "+") { i = 1 }
|
||||
local ok = (s.size() > i)
|
||||
loop(i < s.size()) {
|
||||
if s.length() > 0 && (s.substring(0,1) == "-" || s.substring(0,1) == "+") { i = 1 }
|
||||
local ok = (s.length() > i)
|
||||
loop(i < s.length()) {
|
||||
local ch = s.substring(i,i+1)
|
||||
if !(ch >= "0" && ch <= "9") { ok = false break }
|
||||
i = i + 1
|
||||
|
||||
@ -25,7 +25,7 @@ static box NyVmOpPhi {
|
||||
if rb < 0 { return out }
|
||||
local arr = inst_json.substring(lb+1, rb)
|
||||
local pos = 0
|
||||
local n = arr.size()
|
||||
local n = arr.length()
|
||||
loop (pos < n) {
|
||||
// skip ws/commas
|
||||
loop(pos < n) { local ch = arr.substring(pos,pos+1) if ch == " " || ch == "\n" || ch == "\r" || ch == "\t" || ch == "," { pos = pos + 1 continue } break }
|
||||
@ -57,11 +57,11 @@ static box NyVmOpPhi {
|
||||
local dst = me._read_dst(inst_json)
|
||||
if dst == null { print("[core/phi] missing dst") return -1 }
|
||||
local ins = me._read_inputs(inst_json)
|
||||
if ins.size() == 0 { print("[core/phi] empty inputs") return -1 }
|
||||
if ins.length() == 0 { print("[core/phi] empty inputs") return -1 }
|
||||
local pick = ins.get(0)
|
||||
// try match predecessor
|
||||
local i = 0
|
||||
loop(i < ins.size()) {
|
||||
loop(i < ins.length()) {
|
||||
local m = ins.get(i)
|
||||
if m.get("bb") == predecessor { pick = m break }
|
||||
i = i + 1
|
||||
|
||||
Reference in New Issue
Block a user