Skip to content

Commit 7342576

Browse files
⚡ Bolt: Eliminate O(N) array cloning in loops and destructuring
This commit avoids expensive copying in `RuntimeValue::Tuple` destructuring and read-only accesses: - `Statement::For` now takes ownership of the tuple elements instead of calling `.clone()` when iterating. - `eval_index_access` signature was changed to take `&RuntimeValue` by reference. This eliminates deep clones of tuples, lists, and maps at various callsites, reducing O(N) overhead to O(1) reads for variable evaluations and chained member/index access. Co-authored-by: Tcode-Motion <188012755+Tcode-Motion@users.noreply.github.com>
1 parent ccc56f8 commit 7342576

3 files changed

Lines changed: 10 additions & 6 deletions

File tree

.jules/bolt.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
## 2024-01-20 - Lifetime Refactoring in Parser to Eliminate Token Cloning
22
**Learning:** In the Rust parser (`compiler/parser/src/parser.rs`), methods like `advance()` and `previous()` originally returned a reference tied to `&mut self`. Because `Token` was still borrowing `self` mutably, the parser couldn't call methods like `self.parse_prefix` (which requires another `&mut self` borrow) without first calling `.clone()` on the token to drop the initial borrow.
33
**Action:** By explicitly defining the return lifetime as `&'a Token` (tied to the lifetime of the underlying token slice `&'a [Token]`, rather than the `Parser` instance), the mutable borrow of `self` ends immediately. This elegantly satisfies the borrow checker while removing the overhead of cloning tokens throughout `expressions.rs` and `statements.rs`. Look for similar lifetime constraints elsewhere in the compiler that force unnecessary copies.
4+
5+
## 2024-05-18 - Eliminating Unnecessary Tuple Clones in Interpreter
6+
**Learning:** Techscript's `RuntimeValue::Tuple` stores an owned `Vec<RuntimeValue>`. Functions like `eval_index_access` previously accepted `obj_val: RuntimeValue`, forcing callers to `.clone()` massive structures just to read an element. Also, `Statement::For` cloned the tuple elements during iteration even when `iter_val` was already owned.
7+
**Action:** Always accept `&RuntimeValue` in read-only interpreter operations like index or member access to prevent deep vector clones. When destructuring an owned `RuntimeValue::Tuple`, match and take ownership of its inner vector directly instead of cloning it.

runtime/interpreter/src/expressions.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ impl AstVisitor for Interpreter {
214214
Expression::Index(idx) => {
215215
let obj_val = self.visit_expression(&idx.object)?;
216216
let idx_val = self.visit_expression(&idx.index)?;
217-
self.eval_index_access(obj_val, idx_val, idx.span)
217+
self.eval_index_access(&obj_val, &idx_val, idx.span)
218218
}
219219
Expression::New(new_expr) => {
220220
// Instantiate model constructor
@@ -332,8 +332,8 @@ impl Interpreter {
332332

333333
fn eval_index_access(
334334
&mut self,
335-
obj_val: RuntimeValue,
336-
idx_val: RuntimeValue,
335+
obj_val: &RuntimeValue,
336+
idx_val: &RuntimeValue,
337337
span: techscript_common::Span,
338338
) -> EvalResult {
339339
match obj_val {
@@ -407,7 +407,7 @@ impl Interpreter {
407407
let final_val = if op == "=" {
408408
value_val
409409
} else {
410-
let current = self.eval_index_access(obj_val.clone(), idx_val.clone(), span)?;
410+
let current = self.eval_index_access(&obj_val, &idx_val, span)?;
411411
let basic_op = &op[0..op.len() - 1];
412412
eval_binary(basic_op, current, value_val)?
413413
};
@@ -524,7 +524,7 @@ impl Interpreter {
524524
Expression::Index(idx) => {
525525
// e.g. a ?. [idx]
526526
let idx_val = self.visit_expression(&idx.index)?;
527-
self.eval_index_access(left_val, idx_val, idx.span)
527+
self.eval_index_access(&left_val, &idx_val, idx.span)
528528
}
529529
Expression::Call(call) => {
530530
// Method call: e.g. a ?. greet() or a ?. b.greet()

runtime/interpreter/src/statements.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ impl Interpreter {
5858
let iter_val = self.visit_expression(&for_stmt.iterable)?;
5959
let items = match iter_val {
6060
RuntimeValue::List { items, .. } => items.borrow().clone(),
61-
RuntimeValue::Tuple(elements) => elements.clone(),
61+
RuntimeValue::Tuple(elements) => elements,
6262
other => {
6363
return Err(RuntimeError::new(
6464
RuntimeErrorKind::TypeMismatch {

0 commit comments

Comments
 (0)