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:
@ -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: {:?}",
|
||||
|
||||
Reference in New Issue
Block a user