Refactor global variable access in VM and optimizer
Replaces `Rc<RefCell<Vec<Value>>>` with a new `GlobalStore` struct for accessing global variables. This provides a more structured way to manage global values and allows for future optimizations like sharing immutable RTL portions across environments. The `GlobalStore` also includes an `rtl_len` field to distinguish between RTL and user global slots, enabling debug-time checks for writes to immutable RTL slots.
This commit is contained in:
+40
-15
@@ -82,9 +82,43 @@ impl VMObserver for TracingObserver {
|
||||
}
|
||||
}
|
||||
|
||||
/// Unified view of the global value space for VM and optimizer access.
|
||||
///
|
||||
/// Wraps a flat `Vec<Value>` containing both RTL slots `[0..rtl_len)` and user
|
||||
/// slots `[rtl_len..)`. The `rtl_len` boundary is informational — it enables
|
||||
/// a debug-mode write guard and prepares for future RTL sharing.
|
||||
///
|
||||
/// True RTL/user splitting (sharing the immutable RTL portion across environments)
|
||||
/// is a planned future optimization once the stream-bootstrap timing is resolved.
|
||||
#[derive(Clone)]
|
||||
pub struct GlobalStore {
|
||||
values: Rc<RefCell<Vec<Value>>>,
|
||||
/// Index boundary between frozen RTL slots and mutable user slots.
|
||||
pub rtl_len: usize,
|
||||
}
|
||||
|
||||
impl GlobalStore {
|
||||
pub fn new(values: Rc<RefCell<Vec<Value>>>, rtl_len: usize) -> Self {
|
||||
Self { values, rtl_len }
|
||||
}
|
||||
|
||||
pub fn get(&self, idx: usize) -> Option<Value> {
|
||||
self.values.borrow().get(idx).cloned()
|
||||
}
|
||||
|
||||
fn set(&self, idx: usize, value: Value) {
|
||||
debug_assert!(idx >= self.rtl_len, "Cannot write to immutable RTL slot {}", idx);
|
||||
let mut v = self.values.borrow_mut();
|
||||
if idx >= v.len() {
|
||||
v.resize(idx + 1, Value::Void);
|
||||
}
|
||||
v[idx] = value;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VM {
|
||||
stack: Vec<Value>,
|
||||
globals: Rc<RefCell<Vec<Value>>>,
|
||||
globals: GlobalStore,
|
||||
frames: Vec<CallFrame>,
|
||||
/// Side-channel for tail-call signaling. Set by `eval_internal` when a tail-call
|
||||
/// is requested; consumed by `resolve_tail_calls` and the inline TCO loop.
|
||||
@@ -92,7 +126,7 @@ pub struct VM {
|
||||
}
|
||||
|
||||
impl VM {
|
||||
pub fn new(globals: Rc<RefCell<Vec<Value>>>) -> Self {
|
||||
pub fn new(globals: GlobalStore) -> Self {
|
||||
Self {
|
||||
stack: Vec::new(),
|
||||
globals,
|
||||
@@ -883,13 +917,9 @@ impl VM {
|
||||
}
|
||||
}
|
||||
Address::Global(idx) => {
|
||||
let g_idx = idx.0 as usize;
|
||||
let globals = self.globals.borrow();
|
||||
if g_idx < globals.len() {
|
||||
Ok(globals[g_idx].clone())
|
||||
} else {
|
||||
Err(format!("Global access out of bounds {}", idx))
|
||||
}
|
||||
self.globals
|
||||
.get(idx.0 as usize)
|
||||
.ok_or_else(|| format!("Global access out of bounds {}", idx))
|
||||
}
|
||||
Address::Upvalue(idx) => {
|
||||
let frame = self.frames.last().ok_or("No call frame")?;
|
||||
@@ -926,12 +956,7 @@ impl VM {
|
||||
Ok(())
|
||||
}
|
||||
Address::Global(idx) => {
|
||||
let g_idx = idx.0 as usize;
|
||||
let mut globals = self.globals.borrow_mut();
|
||||
if g_idx >= globals.len() {
|
||||
globals.resize(g_idx + 1, Value::Void);
|
||||
}
|
||||
globals[g_idx] = value;
|
||||
self.globals.set(idx.0 as usize, value);
|
||||
Ok(())
|
||||
}
|
||||
Address::Upvalue(idx) => {
|
||||
|
||||
Reference in New Issue
Block a user