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 vm_init_error;
|
||||||
pub mod object;
|
pub mod object;
|
||||||
pub mod heap;
|
pub mod heap;
|
||||||
|
pub mod roots;
|
||||||
|
|
||||||
pub use prometeu_hal::{HostContext, HostReturn, NativeInterface, SyscallId};
|
pub use prometeu_hal::{HostContext, HostReturn, NativeInterface, SyscallId};
|
||||||
pub use virtual_machine::{BudgetReport, LogicalFrameEndingReason, VirtualMachine};
|
pub use virtual_machine::{BudgetReport, LogicalFrameEndingReason, VirtualMachine};
|
||||||
pub use object::{object_flags, ObjectHeader, ObjectKind};
|
pub use object::{object_flags, ObjectHeader, ObjectKind};
|
||||||
pub use heap::{Heap, StoredObject};
|
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::isa::core::CoreOpCode as OpCode;
|
||||||
use prometeu_bytecode::ProgramImage;
|
use prometeu_bytecode::ProgramImage;
|
||||||
use prometeu_bytecode::Value;
|
use prometeu_bytecode::Value;
|
||||||
|
use crate::roots::{RootVisitor, visit_value_for_roots};
|
||||||
use crate::heap::Heap;
|
use crate::heap::Heap;
|
||||||
use prometeu_bytecode::{
|
use prometeu_bytecode::{
|
||||||
TRAP_BAD_RET_SLOTS, TRAP_DIV_ZERO, TRAP_INVALID_FUNC, TRAP_INVALID_SYSCALL, TRAP_OOB,
|
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)),
|
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)]
|
#[cfg(test)]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user