Perf: Restore core optimizations and stabilize VM execution

This commit restores and enhances several high-performance features that
were
previously lost, while fixing critical bugs in scope management.

Performance Optimizations:
- Zero-Copy TCO: Refactored TailCallRequest to use (Rc, usize), moving
  arguments
  directly on the VM stack via drain/resize instead of heap-allocating
  Vecs.
- Slice-based Calls: Native functions and field accessors now operate
  directly
  on stack slices, significantly reducing memory churn.
- SoA Push Fast-Path: Restored specialized 'push' intrinsic for
  RecordSeries.
  Matches layouts via Arc::ptr_eq to distribute values directly into
  columns
  without keyword lookups.

Architectural Improvements:
- Static Stack Frames (max_slots): The Binder now calculates the maximum

  required slots per lambda. The VM pre-resizes the stack frame,
  preventing
  collisions between local variables and temporary call arguments.
- Macro Hygiene: Fixed a bug where macro-internal variables could
  overwrite
  outer call arguments due to stack overlap.
- Trait Refactoring: Unified series operations via a polymorphic
  'push_value'
  on the Series trait, with a generic implementation for
  ScalarSeries<T>.

Code Quality:
- Resolved all 'cargo clippy' warnings (collapsible ifs, redundant
  borrows, etc).
- Restored 100% test pass rate (64/64 tests).
- Verified stability of all examples and benchmarks.
This commit is contained in:
Michael Schimmel
2026-03-10 13:06:56 +01:00
parent beb693a068
commit 260669cba1
16 changed files with 237 additions and 260 deletions
+21 -9
View File
@@ -202,6 +202,9 @@ pub trait Series {
/// Gets the value at the specified lookback index (0 = newest).
fn get_item(&self, index: usize) -> Option<Value>;
/// Pushes a new value into the series.
fn push_value(&self, value: Value);
/// Returns the current number of elements in the buffer.
fn len(&self) -> usize;
@@ -259,7 +262,7 @@ pub enum Value {
Function(Rc<NativeFunction>),
Object(Rc<dyn Object>), // For compiled Closures and other opaque types
Cell(Rc<RefCell<Value>>), // Boxed value for captures
TailCallRequest(Box<(Rc<dyn Object>, Vec<Value>)>), // Internal: For TCO (Boxed to keep Value small)
TailCallRequest(Rc<dyn Object>, usize), // Internal: For TCO (target object + argc on stack)
}
impl PartialEq for Value {
@@ -280,8 +283,8 @@ impl PartialEq for Value {
(Value::Function(a), Value::Function(b)) => Rc::ptr_eq(a, b),
(Value::Object(a), Value::Object(b)) => Rc::ptr_eq(a, b),
(Value::Cell(a), Value::Cell(b)) => Rc::ptr_eq(a, b),
(Value::TailCallRequest(a), Value::TailCallRequest(b)) => {
Rc::ptr_eq(&a.0, &b.0) && a.1 == b.1
(Value::TailCallRequest(oa, ca), Value::TailCallRequest(ob, cb)) => {
Rc::ptr_eq(oa, ob) && ca == cb
}
_ => false,
}
@@ -527,11 +530,12 @@ impl StaticType {
}
impl Value {
pub fn as_float(&self) -> Option<f64> {
pub fn get_field(&self, key: Keyword) -> Option<Value> {
match self {
Value::Float(f) => Some(*f),
Value::Int(i) => Some(*i as f64),
_ => None,
Value::Record(layout, values) => {
layout.index_of(key).map(|idx| values[idx].clone())
}
_ => None
}
}
@@ -544,6 +548,14 @@ impl Value {
}
}
pub fn as_float(&self) -> Option<f64> {
match self {
Value::Float(f) => Some(*f),
Value::Int(i) => Some(*i as f64),
_ => None,
}
}
pub fn is_truthy(&self) -> bool {
match self {
Value::Void => false,
@@ -623,7 +635,7 @@ impl Value {
Value::Function(_) => StaticType::Any, // Dynamic function
Value::Object(o) => StaticType::Object(o.type_name()),
Value::Cell(c) => c.borrow().static_type(),
Value::TailCallRequest(_) => StaticType::Any, // Internal state, but typable as Any
Value::TailCallRequest(_, _) => StaticType::Any, // Internal state, but typable as Any
}
}
}
@@ -680,7 +692,7 @@ impl fmt::Display for Value {
}
}
Value::Cell(c) => write!(f, "{}", c.borrow()),
Value::TailCallRequest(_) => write!(f, "<tail call request>"),
Value::TailCallRequest(_, _) => write!(f, "<tail call request>"),
}
}
}