Skip to main content

runmat_vm/runtime/
gc.rs

1use runmat_builtins::Value;
2use runmat_gc::{
3    gc_register_root, gc_unregister_root, GlobalRoot, RootId, StackRoot, VariableArrayRoot,
4};
5
6/// RAII wrapper for GC root management during interpretation.
7pub struct InterpretContext {
8    pub(crate) stack_root_id: Option<RootId>,
9    pub(crate) vars_root_id: Option<RootId>,
10    pub(crate) extra_root_ids: Vec<RootId>,
11}
12
13impl InterpretContext {
14    pub fn new(stack: &Vec<Value>, vars: &Vec<Value>) -> Result<Self, String> {
15        let stack_root = Box::new(unsafe {
16            StackRoot::new(stack as *const Vec<Value>, "interpreter_stack".to_string())
17        });
18        let vars_root = Box::new(unsafe {
19            VariableArrayRoot::new(vars as *const Vec<Value>, "interpreter_vars".to_string())
20        });
21
22        let stack_root_id = gc_register_root(stack_root)
23            .map_err(|e| format!("Failed to register stack root: {e:?}"))?;
24        let vars_root_id = gc_register_root(vars_root)
25            .map_err(|e| format!("Failed to register vars root: {e:?}"))?;
26
27        Ok(InterpretContext {
28            stack_root_id: Some(stack_root_id),
29            vars_root_id: Some(vars_root_id),
30            extra_root_ids: Vec::new(),
31        })
32    }
33
34    pub fn register_global_values(
35        &mut self,
36        values: Vec<Value>,
37        description: &str,
38    ) -> Result<(), String> {
39        if values.is_empty() {
40            return Ok(());
41        }
42        let root = Box::new(GlobalRoot::new(values, description.to_string()));
43        let id =
44            gc_register_root(root).map_err(|e| format!("Failed to register global root: {e:?}"))?;
45        self.extra_root_ids.push(id);
46        Ok(())
47    }
48}
49
50impl Drop for InterpretContext {
51    fn drop(&mut self) {
52        if let Some(id) = self.stack_root_id.take() {
53            let _ = gc_unregister_root(id);
54        }
55        if let Some(id) = self.vars_root_id.take() {
56            let _ = gc_unregister_root(id);
57        }
58        while let Some(id) = self.extra_root_ids.pop() {
59            let _ = gc_unregister_root(id);
60        }
61    }
62}