feat(mir): Phase 285 P2.1 - KeepAlive instruction for weak ref semantics

Add KeepAlive instruction to fix hidden root problem where x = null
doesn't properly drop the strong reference.

Key changes:
- Add KeepAlive { values, drop_after } instruction to MIR
- Emit KeepAlive[drop=true] in build_assignment() before variable overwrite
- Emit KeepAlive[drop=false] in pop_lexical_scope() at scope end
- VM handler: when drop_after=true, remove ALL ValueIds pointing to
  the same Arc (handles SSA Copy chains)

Test results:
- weak_upgrade_fail: exit 1  (weak_to_strong returns null after x=null)
- weak_basic: exit 2  (weak_to_strong succeeds while x alive)
- quick smoke: 154/154 PASS 

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-26 13:08:32 +09:00
parent 58ceb3de2f
commit 3bf0dee2b0
12 changed files with 165 additions and 19 deletions

View File

@ -133,8 +133,53 @@ impl MirInterpreter {
MirInstruction::BarrierRead { .. }
| MirInstruction::BarrierWrite { .. }
| MirInstruction::Barrier { .. }
| MirInstruction::Safepoint
| MirInstruction::Nop => {}
| MirInstruction::Safepoint => {}
MirInstruction::KeepAlive { values, drop_after } => {
// Phase 285 P2.1: Handle KeepAlive based on drop_after flag
// - drop_after=true: Release values (for variable overwrite, enables weak ref failure)
// - drop_after=false: Just keep alive (for scope end, values may be needed for PHI)
if *drop_after {
// IMPORTANT: Due to SSA Copy instructions, a single Box may have multiple
// ValueIds pointing to it (e.g., %5 = NewBox, %6 = Copy %5).
// We need to find and remove ALL ValueIds that point to the same Arc.
use std::sync::Arc;
use super::super::vm_types::VMValue;
// Collect raw pointers of Arcs being released
let mut arc_ptrs: Vec<*const dyn crate::box_trait::NyashBox> = Vec::new();
for v in values {
if let Some(VMValue::BoxRef(arc)) = self.regs.get(v) {
arc_ptrs.push(Arc::as_ptr(arc));
}
}
// Remove the specified values first
for v in values {
self.regs.remove(v);
}
// Find and remove ALL other ValueIds that point to the same Arcs
if !arc_ptrs.is_empty() {
let to_remove: Vec<crate::mir::ValueId> = self.regs
.iter()
.filter_map(|(vid, val)| {
if let VMValue::BoxRef(arc) = val {
let ptr = Arc::as_ptr(arc);
if arc_ptrs.contains(&ptr) {
return Some(*vid);
}
}
None
})
.collect();
for vid in to_remove {
self.regs.remove(&vid);
}
}
}
// If drop_after=false, do nothing (values stay alive)
}
MirInstruction::Nop => {}
other => {
return Err(self.err_invalid(format!(
"MIR interp: unimplemented instruction: {:?}",