phase(9.78h): stabilize MIR/VM pipeline

- Add MIR26 doc≡code sync test (tests/mir_instruction_set_sync.rs)
- Quiet snapshots; filter plugin/net logs; golden all green
- Delegate VM phi selection to LoopExecutor (borrow-safe)
- ResultBox migration: remove legacy box_trait::ResultBox paths
- VM BoxRef arithmetic fallbacks via toString().parse::<i64>()
- Bridge BoxCall(InstanceBox) to Class.method/arity in VM
- Fix Effects purity (READ -> readonly, not pure)
- Mark Catch as CONTROL to prevent DCE; Try/Catch test green
- Add env-gated debug logs (effects, verifier, mir-printer, trycatch, ref, bin)
- Update CURRENT_TASK with progress and next steps
This commit is contained in:
Moe Charm
2025-08-26 05:49:23 +09:00
parent 248c3ba183
commit bf4b87526e
21 changed files with 310 additions and 95 deletions

View File

@ -222,25 +222,35 @@ pub struct VM {
}
impl VM {
/// Helper: execute phi selection based on previous_block (borrow-safe minimal)
pub(super) fn loop_execute_phi(&mut self, _dst: ValueId, inputs: &[(BasicBlockId, ValueId)]) -> Result<VMValue, VMError> {
/// Helper: execute phi via LoopExecutor with previous_block-based selection (Step2 skeleton)
pub(super) fn loop_execute_phi(&mut self, dst: ValueId, inputs: &[(BasicBlockId, ValueId)]) -> Result<VMValue, VMError> {
if inputs.is_empty() {
return Err(VMError::InvalidInstruction("Phi node has no inputs".to_string()));
}
let debug_phi = std::env::var("NYASH_VM_DEBUG").ok().as_deref() == Some("1")
|| std::env::var("NYASH_VM_DEBUG_PHI").ok().as_deref() == Some("1");
let prev = self.previous_block;
if debug_phi { eprintln!("[VM] phi-select prev={:?} inputs={:?}", prev, inputs); }
if let Some(prev_bb) = prev {
if let Some((_, val_id)) = inputs.iter().find(|(bb, _)| *bb == prev_bb) {
if debug_phi { eprintln!("[VM] phi-select hit prev={:?} -> {:?}", prev_bb, val_id); }
return self.get_value(*val_id);
if debug_phi { eprintln!("[VM] phi-select (delegated) prev={:?} inputs={:?}", self.previous_block, inputs); }
// Borrow just the values storage immutably to avoid borrowing entire &self in closure
let values_ref = &self.values;
let res = self.loop_executor.execute_phi(dst, inputs, |val_id| {
let index = val_id.to_usize();
if index < values_ref.len() {
if let Some(ref value) = values_ref[index] {
Ok(value.clone())
} else {
Err(VMError::InvalidValue(format!("Value {} not set", val_id)))
}
} else {
Err(VMError::InvalidValue(format!("Value {} out of bounds", val_id)))
}
});
if debug_phi {
match &res {
Ok(v) => eprintln!("[VM] phi-result -> {:?}", v),
Err(e) => eprintln!("[VM] phi-error -> {:?}", e),
}
}
// Fallback: first input
let (_, val_id) = inputs[0];
if debug_phi { eprintln!("[VM] phi-select fallback first -> {:?}", val_id); }
self.get_value(val_id)
res
}
/// Create a new VM instance
pub fn new() -> Self {
@ -395,7 +405,7 @@ impl VM {
.ok_or_else(|| VMError::InvalidBasicBlock(format!("Block {} not found", current_block)))?;
self.frame.current_block = Some(current_block);
self.pc = 0;
self.frame.pc = 0;
let mut next_block = None;
let mut should_return = None;
@ -403,7 +413,7 @@ impl VM {
// Execute instructions in this block (including terminator)
let all_instructions: Vec<_> = block.all_instructions().collect();
for (index, instruction) in all_instructions.iter().enumerate() {
self.pc = index;
self.frame.pc = index;
match self.execute_instruction(instruction)? {
ControlFlow::Continue => continue,
@ -550,24 +560,7 @@ impl VM {
}
}
// ResultBox (box_trait::ResultBox - legacy)
{
#[allow(deprecated)]
if let Some(result_box_legacy) = box_value.as_any().downcast_ref::<crate::box_trait::ResultBox>() {
match method {
"is_ok" | "isOk" => {
return Ok(result_box_legacy.is_ok());
}
"get_value" | "getValue" => {
return Ok(result_box_legacy.get_value());
}
"get_error" | "getError" => {
return Ok(result_box_legacy.get_error());
}
_ => return Ok(Box::new(VoidBox::new())),
}
}
}
// Legacy box_trait::ResultBox is no longer handled here (migration complete)
// Generic fallback: toString for any Box type
if method == "toString" {