Refactor VM to use trait objects for closures
The `CallFrame` struct and various VM methods now use `Rc<dyn Object>` to hold closures, allowing for more flexibility and avoiding unnecessary cloning. This change also addresses the performance concern regarding deep copies of closures, preferring `Rc<dyn Trait>` with local `downcast_ref` where appropriate. Additionally, a documentation note has been added to `gemini.md` regarding this performance preference in Rust.
This commit is contained in:
@@ -33,6 +33,10 @@ Wichtig: zentraler Einstiegspunkt ist Delphi/Myc.Ast.Environment.pasund die dort
|
|||||||
* Dokumentation nach Rust-Regeln.
|
* Dokumentation nach Rust-Regeln.
|
||||||
* Im Code und den Kommentaren muss alles auf englisch sein.
|
* Im Code und den Kommentaren muss alles auf englisch sein.
|
||||||
|
|
||||||
|
## Rust
|
||||||
|
|
||||||
|
* Performance: Bevorzuge `Rc<dyn Trait>` + lokales `downcast_ref` gegenüber Deep Copies via `Rc::new(obj.clone())`.
|
||||||
|
|
||||||
## Interaktion
|
## Interaktion
|
||||||
|
|
||||||
* Ich kann Rust noch nicht so gut. Erkläre mir, was du machst und welche Konzepte du nutzt. Ich will was dazulernen.
|
* Ich kann Rust noch nicht so gut. Erkläre mir, was du machst und welche Konzepte du nutzt. Ich will was dazulernen.
|
||||||
|
|||||||
@@ -261,12 +261,13 @@ impl Environment {
|
|||||||
vec![],
|
vec![],
|
||||||
*positional_count,
|
*positional_count,
|
||||||
));
|
));
|
||||||
|
let closure_obj: Rc<dyn crate::ast::types::Object> = closure;
|
||||||
|
|
||||||
return Rc::new(crate::ast::types::NativeFunction {
|
return Rc::new(crate::ast::types::NativeFunction {
|
||||||
purity: Purity::Impure,
|
purity: Purity::Impure,
|
||||||
func: Rc::new(move |args| {
|
func: Rc::new(move |args| {
|
||||||
let mut vm = VM::new(global_values.clone());
|
let mut vm = VM::new(global_values.clone());
|
||||||
let res = match vm.run_with_args(&closure, args) {
|
let res = match vm.run_with_args(closure_obj.clone(), args) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(e) => panic!("Myc Runtime Error: {}", e),
|
Err(e) => panic!("Myc Runtime Error: {}", e),
|
||||||
};
|
};
|
||||||
@@ -287,9 +288,9 @@ impl Environment {
|
|||||||
|
|
||||||
let mut final_res = res;
|
let mut final_res = res;
|
||||||
if let Value::Object(obj) = &final_res
|
if let Value::Object(obj) = &final_res
|
||||||
&& let Some(closure) = obj.as_any().downcast_ref::<crate::ast::vm::Closure>()
|
&& obj.as_any().downcast_ref::<crate::ast::vm::Closure>().is_some()
|
||||||
{
|
{
|
||||||
final_res = match vm.run_with_args(closure, args) {
|
final_res = match vm.run_with_args(obj.clone(), args) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(e) => panic!("Myc Runtime Error (Closure): {}", e),
|
Err(e) => panic!("Myc Runtime Error (Closure): {}", e),
|
||||||
};
|
};
|
||||||
@@ -396,8 +397,8 @@ impl Environment {
|
|||||||
|
|
||||||
while let Ok(Value::TailCallRequest(payload)) = result {
|
while let Ok(Value::TailCallRequest(payload)) = result {
|
||||||
let (next_obj, next_args) = *payload;
|
let (next_obj, next_args) = *payload;
|
||||||
if let Some(closure) = next_obj.as_any().downcast_ref::<crate::ast::vm::Closure>() {
|
if next_obj.as_any().downcast_ref::<crate::ast::vm::Closure>().is_some() {
|
||||||
result = vm.run_with_args_observed(&mut observer, closure, next_args);
|
result = vm.run_with_args_observed(&mut observer, next_obj, next_args);
|
||||||
} else {
|
} else {
|
||||||
result = Err(format!(
|
result = Err(format!(
|
||||||
"Tail call target is not a closure: {}",
|
"Tail call target is not a closure: {}",
|
||||||
|
|||||||
+19
-15
@@ -49,7 +49,7 @@ impl Object for Closure {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct CallFrame {
|
struct CallFrame {
|
||||||
stack_base: usize,
|
stack_base: usize,
|
||||||
closure: Option<Rc<Closure>>,
|
closure: Option<Rc<dyn Object>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait VMObserver {
|
pub trait VMObserver {
|
||||||
@@ -154,7 +154,7 @@ impl VM {
|
|||||||
self.stack.clear();
|
self.stack.clear();
|
||||||
self.frames.push(CallFrame {
|
self.frames.push(CallFrame {
|
||||||
stack_base: 0,
|
stack_base: 0,
|
||||||
closure: Some(Rc::new(closure.clone())),
|
closure: Some(next_obj.clone()),
|
||||||
});
|
});
|
||||||
if let Some(count) = closure.positional_count
|
if let Some(count) = closure.positional_count
|
||||||
&& next_args.len() == count as usize
|
&& next_args.len() == count as usize
|
||||||
@@ -177,12 +177,13 @@ impl VM {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_with_args(&mut self, closure: &Closure, args: Vec<Value>) -> Result<Value, String> {
|
pub fn run_with_args(&mut self, closure_obj: Rc<dyn Object>, args: Vec<Value>) -> Result<Value, String> {
|
||||||
|
let closure = closure_obj.as_any().downcast_ref::<Closure>().unwrap();
|
||||||
self.stack.clear();
|
self.stack.clear();
|
||||||
self.frames.clear();
|
self.frames.clear();
|
||||||
self.frames.push(CallFrame {
|
self.frames.push(CallFrame {
|
||||||
stack_base: 0,
|
stack_base: 0,
|
||||||
closure: Some(Rc::new(closure.clone())),
|
closure: Some(closure_obj.clone()),
|
||||||
});
|
});
|
||||||
if let Some(count) = closure.positional_count
|
if let Some(count) = closure.positional_count
|
||||||
&& args.len() == count as usize
|
&& args.len() == count as usize
|
||||||
@@ -197,14 +198,15 @@ impl VM {
|
|||||||
pub fn run_with_args_observed<O: VMObserver>(
|
pub fn run_with_args_observed<O: VMObserver>(
|
||||||
&mut self,
|
&mut self,
|
||||||
observer: &mut O,
|
observer: &mut O,
|
||||||
closure: &Closure,
|
closure_obj: Rc<dyn Object>,
|
||||||
args: Vec<Value>,
|
args: Vec<Value>,
|
||||||
) -> Result<Value, String> {
|
) -> Result<Value, String> {
|
||||||
|
let closure = closure_obj.as_any().downcast_ref::<Closure>().unwrap();
|
||||||
self.stack.clear();
|
self.stack.clear();
|
||||||
self.frames.clear();
|
self.frames.clear();
|
||||||
self.frames.push(CallFrame {
|
self.frames.push(CallFrame {
|
||||||
stack_base: 0,
|
stack_base: 0,
|
||||||
closure: Some(Rc::new(closure.clone())),
|
closure: Some(closure_obj.clone()),
|
||||||
});
|
});
|
||||||
if let Some(count) = closure.positional_count
|
if let Some(count) = closure.positional_count
|
||||||
&& args.len() == count as usize
|
&& args.len() == count as usize
|
||||||
@@ -445,10 +447,9 @@ impl VM {
|
|||||||
Value::Object(obj) => {
|
Value::Object(obj) => {
|
||||||
if let Some(closure) = obj.as_any().downcast_ref::<Closure>() {
|
if let Some(closure) = obj.as_any().downcast_ref::<Closure>() {
|
||||||
let old_stack_top = self.stack.len();
|
let old_stack_top = self.stack.len();
|
||||||
let closure_rc = Rc::new(closure.clone());
|
|
||||||
self.frames.push(CallFrame {
|
self.frames.push(CallFrame {
|
||||||
stack_base: old_stack_top,
|
stack_base: old_stack_top,
|
||||||
closure: Some(closure_rc.clone()),
|
closure: Some(obj.clone()),
|
||||||
});
|
});
|
||||||
if let Some(count) = closure.positional_count
|
if let Some(count) = closure.positional_count
|
||||||
&& arg_vals.len() == count as usize
|
&& arg_vals.len() == count as usize
|
||||||
@@ -509,9 +510,9 @@ impl VM {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let frame = self.frames.last().ok_or("No call frame for 'again'")?;
|
let frame = self.frames.last().ok_or("No call frame for 'again'")?;
|
||||||
if let Some(closure) = &frame.closure {
|
if let Some(closure_obj) = &frame.closure {
|
||||||
Ok(Value::TailCallRequest(Box::new((
|
Ok(Value::TailCallRequest(Box::new((
|
||||||
closure.clone() as Rc<dyn Object>,
|
closure_obj.clone(),
|
||||||
arg_vals,
|
arg_vals,
|
||||||
))))
|
))))
|
||||||
} else {
|
} else {
|
||||||
@@ -551,8 +552,8 @@ impl VM {
|
|||||||
pub fn resolve_tail_calls(&mut self, mut result: Value) -> Value {
|
pub fn resolve_tail_calls(&mut self, mut result: Value) -> Value {
|
||||||
while let Value::TailCallRequest(payload) = result {
|
while let Value::TailCallRequest(payload) = result {
|
||||||
let (next_obj, next_args) = *payload;
|
let (next_obj, next_args) = *payload;
|
||||||
if let Some(closure) = next_obj.as_any().downcast_ref::<Closure>() {
|
if next_obj.as_any().downcast_ref::<Closure>().is_some() {
|
||||||
result = match self.run_with_args(closure, next_args) {
|
result = match self.run_with_args(next_obj, next_args) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(e) => panic!("Myc Runtime Error (TailCall): {}", e),
|
Err(e) => panic!("Myc Runtime Error (TailCall): {}", e),
|
||||||
};
|
};
|
||||||
@@ -586,7 +587,8 @@ impl VM {
|
|||||||
}
|
}
|
||||||
Address::Upvalue(idx) => {
|
Address::Upvalue(idx) => {
|
||||||
let frame = self.frames.last().ok_or("No call frame")?;
|
let frame = self.frames.last().ok_or("No call frame")?;
|
||||||
if let Some(closure) = &frame.closure {
|
if let Some(closure_obj) = &frame.closure {
|
||||||
|
let closure = closure_obj.as_any().downcast_ref::<Closure>().unwrap();
|
||||||
let u_idx = idx.0 as usize;
|
let u_idx = idx.0 as usize;
|
||||||
if u_idx < closure.upvalues.len() {
|
if u_idx < closure.upvalues.len() {
|
||||||
Ok(closure.upvalues[u_idx].clone())
|
Ok(closure.upvalues[u_idx].clone())
|
||||||
@@ -626,7 +628,8 @@ impl VM {
|
|||||||
}
|
}
|
||||||
Address::Upvalue(idx) => {
|
Address::Upvalue(idx) => {
|
||||||
let frame = self.frames.last().ok_or("No call frame")?;
|
let frame = self.frames.last().ok_or("No call frame")?;
|
||||||
if let Some(closure) = &frame.closure {
|
if let Some(closure_obj) = &frame.closure {
|
||||||
|
let closure = closure_obj.as_any().downcast_ref::<Closure>().unwrap();
|
||||||
let u_idx = idx.0 as usize;
|
let u_idx = idx.0 as usize;
|
||||||
if u_idx < closure.upvalues.len() {
|
if u_idx < closure.upvalues.len() {
|
||||||
Ok(closure.upvalues[u_idx].borrow().clone())
|
Ok(closure.upvalues[u_idx].borrow().clone())
|
||||||
@@ -669,7 +672,8 @@ impl VM {
|
|||||||
}
|
}
|
||||||
Address::Upvalue(idx) => {
|
Address::Upvalue(idx) => {
|
||||||
let frame = self.frames.last().ok_or("No call frame")?;
|
let frame = self.frames.last().ok_or("No call frame")?;
|
||||||
if let Some(closure) = &frame.closure {
|
if let Some(closure_obj) = &frame.closure {
|
||||||
|
let closure = closure_obj.as_any().downcast_ref::<Closure>().unwrap();
|
||||||
let u_idx = idx.0 as usize;
|
let u_idx = idx.0 as usize;
|
||||||
if u_idx < closure.upvalues.len() {
|
if u_idx < closure.upvalues.len() {
|
||||||
*closure.upvalues[u_idx].borrow_mut() = value;
|
*closure.upvalues[u_idx].borrow_mut() = value;
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
(while (< 1 2) (print 1))
|
|
||||||
Reference in New Issue
Block a user