pr3.4
This commit is contained in:
parent
46146993aa
commit
13f025e448
@ -5,8 +5,10 @@ mod virtual_machine;
|
||||
pub mod vm_init_error;
|
||||
pub mod object;
|
||||
pub mod heap;
|
||||
pub mod roots;
|
||||
|
||||
pub use prometeu_hal::{HostContext, HostReturn, NativeInterface, SyscallId};
|
||||
pub use virtual_machine::{BudgetReport, LogicalFrameEndingReason, VirtualMachine};
|
||||
pub use object::{object_flags, ObjectHeader, ObjectKind};
|
||||
pub use heap::{Heap, StoredObject};
|
||||
pub use roots::{RootVisitor, visit_value_for_roots};
|
||||
|
||||
37
crates/console/prometeu-vm/src/roots.rs
Normal file
37
crates/console/prometeu-vm/src/roots.rs
Normal file
@ -0,0 +1,37 @@
|
||||
use prometeu_bytecode::{HeapRef, Value};
|
||||
|
||||
/// Visitor for GC roots. Implementors receive every `HeapRef` discovered
|
||||
/// during root traversal. No marking/sweeping semantics here.
|
||||
pub trait RootVisitor {
|
||||
fn visit_heap_ref(&mut self, r: HeapRef);
|
||||
}
|
||||
|
||||
/// Helper: if `val` is a `Value::HeapRef`, call the visitor.
|
||||
pub fn visit_value_for_roots<V: RootVisitor + ?Sized>(val: &Value, visitor: &mut V) {
|
||||
if let Value::HeapRef(r) = val {
|
||||
visitor.visit_heap_ref(*r);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::VirtualMachine;
|
||||
|
||||
struct CollectVisitor { pub seen: Vec<HeapRef> }
|
||||
impl RootVisitor for CollectVisitor {
|
||||
fn visit_heap_ref(&mut self, r: HeapRef) { self.seen.push(r); }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn visits_heapref_on_operand_stack() {
|
||||
let mut vm = VirtualMachine::default();
|
||||
// Place a HeapRef on the operand stack
|
||||
vm.operand_stack.push(Value::HeapRef(HeapRef(123)));
|
||||
|
||||
let mut v = CollectVisitor { seen: vec![] };
|
||||
vm.visit_roots(&mut v);
|
||||
|
||||
assert_eq!(v.seen, vec![HeapRef(123)]);
|
||||
}
|
||||
}
|
||||
@ -5,6 +5,7 @@ use crate::{HostContext, NativeInterface};
|
||||
use prometeu_bytecode::isa::core::CoreOpCode as OpCode;
|
||||
use prometeu_bytecode::ProgramImage;
|
||||
use prometeu_bytecode::Value;
|
||||
use crate::roots::{RootVisitor, visit_value_for_roots};
|
||||
use crate::heap::Heap;
|
||||
use prometeu_bytecode::{
|
||||
TRAP_BAD_RET_SLOTS, TRAP_DIV_ZERO, TRAP_INVALID_FUNC, TRAP_INVALID_SYSCALL, TRAP_OOB,
|
||||
@ -1030,6 +1031,39 @@ impl VirtualMachine {
|
||||
Err(OpError::Panic(msg)) => Err(LogicalFrameEndingReason::Panic(msg)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Visit all GC roots reachable from the VM state.
|
||||
/// This includes:
|
||||
/// - Entire operand stack values
|
||||
/// - Locals/args in each call frame (derived from `stack_base` and function layout)
|
||||
/// - Global variables
|
||||
pub fn visit_roots<V: RootVisitor + ?Sized>(&self, visitor: &mut V) {
|
||||
// 1) Operand stack (all values are roots)
|
||||
for v in &self.operand_stack {
|
||||
visit_value_for_roots(v, visitor);
|
||||
}
|
||||
|
||||
// 2) Call frames: iterate locals/args range for each frame
|
||||
for frame in &self.call_stack {
|
||||
if let Some(func_meta) = self.program.functions.get(frame.func_idx) {
|
||||
let start = frame.stack_base;
|
||||
let frame_slots = (func_meta.param_slots as usize) + (func_meta.local_slots as usize);
|
||||
let mut end = start.saturating_add(frame_slots);
|
||||
// Clamp to current stack height just in case
|
||||
if end > self.operand_stack.len() { end = self.operand_stack.len(); }
|
||||
for i in start..end {
|
||||
if let Some(v) = self.operand_stack.get(i) {
|
||||
visit_value_for_roots(v, visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3) Globals
|
||||
for g in &self.globals {
|
||||
visit_value_for_roots(g, visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user