Refactor: Use Rc/RefCell for shared mutable state
This commit replaces `Arc<Mutex<T>>` with `Rc<RefCell<T>>` for managing shared mutable state within the AST and VM. This change is primarily an internal refactoring to leverage Rust's standard library more effectively for single-threaded scenarios, improving performance by avoiding the overhead of mutexes. The following types and their usage have been updated: - `Environment.global_names` and `Environment.global_values` - `Binder.globals` - `bound_nodes::BoundKind::Lambda.body` (now `Rc<Node>`) - `ast::types::NodeIdentity` (now `Rc<NodeIdentity>`) - `ast::types::Value::List`, `Value::Record`, `Value::Function`, `Value::Object`, `Value::Cell` - `ast::nodes::Scope` and `ast::nodes::Context` - `ast::vm::Closure.function_node` and `Closure.upvalues` - `ast::vm::VM.globals` This change does not alter the external behavior of the library but streamlines internal data management.
This commit is contained in:
+26
-22
@@ -1,4 +1,5 @@
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
use std::any::Any;
|
||||
use crate::ast::compiler::bound_nodes::{Address, BoundKind};
|
||||
use crate::ast::nodes::Node;
|
||||
@@ -6,8 +7,8 @@ use crate::ast::types::{Value, Object, StaticType};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Closure {
|
||||
pub function_node: Arc<Node<BoundKind, StaticType>>,
|
||||
pub upvalues: Vec<Arc<Mutex<Value>>>,
|
||||
pub function_node: Rc<Node<BoundKind, StaticType>>,
|
||||
pub upvalues: Vec<Rc<RefCell<Value>>>,
|
||||
}
|
||||
|
||||
impl Object for Closure {
|
||||
@@ -22,17 +23,20 @@ impl Object for Closure {
|
||||
#[derive(Debug)]
|
||||
struct CallFrame {
|
||||
stack_base: usize,
|
||||
closure: Option<Arc<Closure>>,
|
||||
closure: Option<Rc<Closure>>,
|
||||
}
|
||||
|
||||
pub struct VM {
|
||||
stack: Vec<Value>,
|
||||
globals: Arc<Mutex<Vec<Value>>>,
|
||||
// Globals are mutable shared state within the VM thread.
|
||||
// However, if we move to frozen roots, this might change to a read-only structure.
|
||||
// For now, mutable RefCell Vec is fine for single threaded execution.
|
||||
globals: Rc<RefCell<Vec<Value>>>,
|
||||
frames: Vec<CallFrame>,
|
||||
}
|
||||
|
||||
impl VM {
|
||||
pub fn new(globals: Arc<Mutex<Vec<Value>>>) -> Self {
|
||||
pub fn new(globals: Rc<RefCell<Vec<Value>>>) -> Self {
|
||||
Self {
|
||||
stack: Vec::new(),
|
||||
globals,
|
||||
@@ -64,7 +68,7 @@ impl VM {
|
||||
BoundKind::DefGlobal { global_index, value } => {
|
||||
let val = self.eval(value)?;
|
||||
let idx = *global_index as usize;
|
||||
let mut globals = self.globals.lock().unwrap();
|
||||
let mut globals = self.globals.borrow_mut();
|
||||
if idx >= globals.len() {
|
||||
globals.resize(idx + 1, Value::Void);
|
||||
}
|
||||
@@ -110,7 +114,7 @@ impl VM {
|
||||
upvalues: captured,
|
||||
};
|
||||
|
||||
Ok(Value::Object(Arc::new(closure)))
|
||||
Ok(Value::Object(Rc::new(closure)))
|
||||
},
|
||||
|
||||
BoundKind::Call { callee, args } => {
|
||||
@@ -126,13 +130,13 @@ impl VM {
|
||||
Value::Object(obj) => {
|
||||
if let Some(closure) = obj.as_any().downcast_ref::<Closure>() {
|
||||
let old_stack_top = self.stack.len();
|
||||
let closure_arc = Arc::new(closure.clone());
|
||||
let closure_rc = Rc::new(closure.clone());
|
||||
|
||||
self.stack.extend(arg_vals);
|
||||
|
||||
self.frames.push(CallFrame {
|
||||
stack_base: old_stack_top,
|
||||
closure: Some(closure_arc.clone()),
|
||||
closure: Some(closure_rc.clone()),
|
||||
});
|
||||
|
||||
let result = self.eval(&closure.function_node);
|
||||
@@ -151,7 +155,7 @@ impl VM {
|
||||
}
|
||||
}
|
||||
|
||||
fn capture_upvalue(&mut self, addr: Address) -> Result<Arc<Mutex<Value>>, String> {
|
||||
fn capture_upvalue(&mut self, addr: Address) -> Result<Rc<RefCell<Value>>, String> {
|
||||
match addr {
|
||||
Address::Local(idx) => {
|
||||
let frame = self.frames.last().ok_or("No call frame")?;
|
||||
@@ -163,7 +167,7 @@ impl VM {
|
||||
} else {
|
||||
// Box it
|
||||
let val = self.stack[abs_index].clone();
|
||||
let cell = Arc::new(Mutex::new(val));
|
||||
let cell = Rc::new(RefCell::new(val));
|
||||
self.stack[abs_index] = Value::Cell(cell.clone());
|
||||
Ok(cell)
|
||||
}
|
||||
@@ -195,7 +199,7 @@ impl VM {
|
||||
let abs_index = frame.stack_base + (idx as usize);
|
||||
if abs_index < self.stack.len() {
|
||||
match &self.stack[abs_index] {
|
||||
Value::Cell(cell) => Ok(cell.lock().unwrap().clone()),
|
||||
Value::Cell(cell) => Ok(cell.borrow().clone()),
|
||||
val => Ok(val.clone()),
|
||||
}
|
||||
} else {
|
||||
@@ -204,7 +208,7 @@ impl VM {
|
||||
},
|
||||
Address::Global(idx) => {
|
||||
let idx = idx as usize;
|
||||
let globals = self.globals.lock().unwrap();
|
||||
let globals = self.globals.borrow();
|
||||
if idx < globals.len() {
|
||||
Ok(globals[idx].clone())
|
||||
} else {
|
||||
@@ -216,7 +220,7 @@ impl VM {
|
||||
if let Some(closure) = &frame.closure {
|
||||
let idx = idx as usize;
|
||||
if idx < closure.upvalues.len() {
|
||||
Ok(closure.upvalues[idx].lock().unwrap().clone())
|
||||
Ok(closure.upvalues[idx].borrow().clone())
|
||||
} else {
|
||||
Err(format!("Upvalue access out of bounds {}", idx))
|
||||
}
|
||||
@@ -234,7 +238,7 @@ impl VM {
|
||||
let abs_index = frame.stack_base + (idx as usize);
|
||||
if abs_index < self.stack.len() {
|
||||
if let Value::Cell(cell) = &self.stack[abs_index] {
|
||||
*cell.lock().unwrap() = value;
|
||||
*cell.borrow_mut() = value;
|
||||
} else {
|
||||
self.stack[abs_index] = value;
|
||||
}
|
||||
@@ -247,7 +251,7 @@ impl VM {
|
||||
},
|
||||
Address::Global(idx) => {
|
||||
let idx = idx as usize;
|
||||
let mut globals = self.globals.lock().unwrap();
|
||||
let mut globals = self.globals.borrow_mut();
|
||||
if idx >= globals.len() {
|
||||
globals.resize(idx + 1, Value::Void);
|
||||
}
|
||||
@@ -259,7 +263,7 @@ impl VM {
|
||||
if let Some(closure) = &frame.closure {
|
||||
let idx = idx as usize;
|
||||
if idx < closure.upvalues.len() {
|
||||
*closure.upvalues[idx].lock().unwrap() = value;
|
||||
*closure.upvalues[idx].borrow_mut() = value;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!("Upvalue assignment out of bounds {}", idx))
|
||||
@@ -277,8 +281,8 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::ast::types::{SourceLocation, NodeIdentity};
|
||||
|
||||
fn make_dummy_identity() -> Arc<NodeIdentity> {
|
||||
Arc::new(NodeIdentity {
|
||||
fn make_dummy_identity() -> Rc<NodeIdentity> {
|
||||
Rc::new(NodeIdentity {
|
||||
location: SourceLocation { line: 0, col: 0 },
|
||||
})
|
||||
}
|
||||
@@ -338,7 +342,7 @@ mod tests {
|
||||
kind: BoundKind::Lambda {
|
||||
param_count: 0,
|
||||
upvalues: vec![Address::Local(0)], // Capture x
|
||||
body: Arc::new(lambda_body),
|
||||
body: Rc::new(lambda_body),
|
||||
},
|
||||
}),
|
||||
},
|
||||
@@ -366,7 +370,7 @@ mod tests {
|
||||
},
|
||||
};
|
||||
|
||||
let globals = Arc::new(Mutex::new(Vec::new()));
|
||||
let globals = Rc::new(RefCell::new(Vec::new()));
|
||||
let mut vm = VM::new(globals);
|
||||
|
||||
let result = vm.run(&root);
|
||||
|
||||
Reference in New Issue
Block a user