Skip to content

Commit b588ced

Browse files
authored
Merge pull request #16 from Tcode-Motion/bolt-perf-tuple-no-clone-12063508566212123643
⚡ Bolt: Eliminate O(N) array cloning in loops and destructuring
2 parents 9d3989c + 023c16a commit b588ced

3 files changed

Lines changed: 7 additions & 9 deletions

File tree

.jules/bolt.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
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-
## 2024-08-18 - Eliminating instruction cloning in VM executor loop
5-
**Learning:** In the bytecode executor (`runtime/vm/src/executor.rs`), fetching instructions inside the tight `execute_loop` originally involved `inst.clone()`. Since `Instruction` contains a `Vec<Operand>`, cloning it in the inner execution loop causes massive allocation overhead on every instruction dispatch, severely degrading performance. By maintaining references to instructions from the chunk rather than cloning, we bypassed significant garbage collection and allocation costs.
6-
**Action:** Always scrutinize `.clone()` inside hot execution loops, especially for structs that own heap-allocated fields (like `Vec` or `String`).
4+

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)