fix(builder): 修正案A実装 - emit_unified_call↔emit_box_or_plugin_call再入防止
🎯 無限再帰の構造的防止(修正案A採用) ## 問題 Phase 2リファクタリング後、stack overflow発生: ``` emit_unified_call (emit.rs:15) ↓ emit_box_or_plugin_call (utils.rs:136) ↓ line 190 emit_unified_call (emit.rs:15) ← 無限ループ! ``` ## 修正案A: 再入防止ガード(採用理由) - B(Math機能削除): 対処療法で仕様削減 ❌ - C("birth"特別扱い): 局所的修正で他Boxに波及 ❌ - A(構造的再入防止): 根治的アプローチ ✅ ## 実装内容 ### 1. MirBuilder にフラグ追加 ```rust pub(super) in_unified_boxcall_fallback: bool ``` 役割: RouterPolicyでRoute::BoxCallと決めたフォールバック中マーク ### 2. emit_unified_call 側修正 (emit.rs) ```rust // Route::BoxCall のときだけ self.in_unified_boxcall_fallback = true; emit_box_or_plugin_call(...); self.in_unified_boxcall_fallback = false; ``` ### 3. emit_box_or_plugin_call 側修正 (utils.rs) ```rust if use_unified_env && matches!(route, Route::Unified) && !self.in_unified_boxcall_fallback // ← 追加 { // emit_unified_call(...) への再入を防止 } ``` ## 構造的改善 - RouterPolicyBox の決定を優先 - emit_unified_call → emit_box_or_plugin_call の一方向化 - 「上位の決定を尊重する」という明確なルール ## 残存課題 ⚠️ まだstack overflowが残存(別の再帰ルート存在の可能性) → 次のステップでstack trace解析が必要 ## テスト状況 - Test 1 (Direct VM): ✅ 成功 - Test 2 (Stage-B): ❌ stack overflow(別ルート調査中) - Test 3 (MIR verification): ✅ 成功 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -180,6 +180,14 @@ pub struct MirBuilder {
|
||||
pub(super) local_ssa_map: HashMap<(BasicBlockId, ValueId, u8), ValueId>,
|
||||
/// BlockSchedule cache: deduplicate materialize copies per (bb, src)
|
||||
pub(super) schedule_mat_map: HashMap<(BasicBlockId, ValueId), ValueId>,
|
||||
|
||||
/// Guard flag to prevent re-entering emit_unified_call from BoxCall fallback.
|
||||
/// Used when RouterPolicyBox in emit_unified_call has already decided to
|
||||
/// route a given Method call to BoxCall; emit_box_or_plugin_call must not
|
||||
/// bounce back into the unified path for the same call, otherwise an
|
||||
/// infinite recursion (emit_unified_call → emit_box_or_plugin_call →
|
||||
/// emit_unified_call …) can occur when routing decisions disagree.
|
||||
pub(super) in_unified_boxcall_fallback: bool,
|
||||
}
|
||||
|
||||
impl MirBuilder {
|
||||
@ -232,6 +240,8 @@ impl MirBuilder {
|
||||
|
||||
local_ssa_map: HashMap::new(),
|
||||
schedule_mat_map: HashMap::new(),
|
||||
|
||||
in_unified_boxcall_fallback: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -108,7 +108,16 @@ impl MirBuilder {
|
||||
eprintln!("[router-guard] {}.{} → BoxCall fallback (recv=%{})", box_name, method, r.0);
|
||||
}
|
||||
let effects = EffectMask::READ.add(Effect::ReadHeap);
|
||||
return self.emit_box_or_plugin_call(dst, *r, method.clone(), None, args, effects);
|
||||
// Prevent BoxCall helper from bouncing back into emit_unified_call
|
||||
// for the same call. RouterPolicyBox has already decided on
|
||||
// Route::BoxCall for this callee, so emit_box_or_plugin_call
|
||||
// must not re-enter the unified path even if its own heuristics
|
||||
// would otherwise choose Unified.
|
||||
let prev_flag = self.in_unified_boxcall_fallback;
|
||||
self.in_unified_boxcall_fallback = true;
|
||||
let res = self.emit_box_or_plugin_call(dst, *r, method.clone(), None, args, effects);
|
||||
self.in_unified_boxcall_fallback = prev_flag;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -181,7 +181,14 @@ impl super::MirBuilder {
|
||||
);
|
||||
}
|
||||
}
|
||||
if use_unified_env && matches!(route, crate::mir::builder::router::policy::Route::Unified) {
|
||||
// Unified path from BoxCall helper is only allowed when we are not
|
||||
// already in a BoxCall fallback originating from emit_unified_call.
|
||||
// in_unified_boxcall_fallback is set by emit_unified_call's RouterPolicy
|
||||
// guard when it has already decided that this call must be a BoxCall.
|
||||
if use_unified_env
|
||||
&& matches!(route, crate::mir::builder::router::policy::Route::Unified)
|
||||
&& !self.in_unified_boxcall_fallback
|
||||
{
|
||||
let target = super::builder_calls::CallTarget::Method {
|
||||
box_type,
|
||||
method: method.clone(),
|
||||
|
||||
Reference in New Issue
Block a user