From 23cc2fb3b8c619c9451b8139704d9cedd58af7e0 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 8 Sep 2026 08:26:20 +0000 Subject: [PATCH] perf: optimize replace_call fast path and string allocation in migrate command Avoid unnecessary memory allocations and formatting overhead in `replace_call` by adding a `contains` fast path and replacing `format!` with `push_str`. Co-authored-by: Tcode-Motion <188012755+Tcode-Motion@users.noreply.github.com> --- .jules/bolt.md | 3 +++ cli/src/commands/migrate.rs | 13 +++++++++++-- docs/benchmarks/benchmark_report.md | 12 ++++++------ 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index c80a25c7..e4a077e3 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -8,3 +8,6 @@ ## 2024-05-18 - Removed redundant clone of VM stack during trace logs **Learning:** In `runtime/vm/src/executor.rs`, the debugging instruction trace `self.debugger.trace_instruction` was cloning the entire VM stack using `&self.stack.get_dump()` for every single instruction executed. This caused significant `O(N)` overhead inside the main fetch-decode-execute loop just to format debug output. A new `data_slice()` method was added to `ValueStack` to provide zero-copy slice access (`&[RuntimeValue]`) instead, completely eliminating the allocation overhead. **Action:** Always scrutinize deep clones in logging, tracing, or hot path loops. Use slice references (`&[T]`) instead of `Vec::clone` when the caller only needs read-only access to a collection. +## 2024-05-24 - Fast-Path and String Allocation Avoidance in Loop-based Parsers +**Learning:** In string manipulation routines like `replace_call` inside `cli/src/commands/migrate.rs`, repeatedly using `format!()` inside a loop creates temporary heap-allocated `String`s, and failing to verify the target's existence before entering the parsing loop forces unnecessary allocations (`String::with_capacity`). +**Action:** When refactoring iterative string parsers/replacers, always add an early-return fast path (e.g. `if !source.contains(target) { return source.to_string(); }`) and replace `format!()` in loops with sequential `.push_str()` and `.push()` calls onto a pre-allocated buffer. diff --git a/cli/src/commands/migrate.rs b/cli/src/commands/migrate.rs index 8bbd611d..c39b64ec 100644 --- a/cli/src/commands/migrate.rs +++ b/cli/src/commands/migrate.rs @@ -250,10 +250,17 @@ fn post_process(source: &str) -> String { /// Replace `prefix(args)` calls with `keyword args` (implicit call style). fn replace_call(source: &str, prefix: &str, keyword: &str) -> String { let full = format!("{prefix}("); + let full_str = full.as_str(); + + // Fast path: if the substring is not in the source, just return a copy. + if !source.contains(full_str) { + return source.to_string(); + } + let mut result = String::with_capacity(source.len()); let mut remaining = source; loop { - match remaining.find(full.as_str()) { + match remaining.find(full_str) { None => { result.push_str(remaining); break; @@ -263,7 +270,9 @@ fn replace_call(source: &str, prefix: &str, keyword: &str) -> String { remaining = &remaining[pos + full.len()..]; if let Some(close) = remaining.find(')') { let args = &remaining[..close]; - result.push_str(&format!("{keyword} {args}")); + result.push_str(keyword); + result.push(' '); + result.push_str(args); remaining = &remaining[close + 1..]; } else { result.push_str(remaining); diff --git a/docs/benchmarks/benchmark_report.md b/docs/benchmarks/benchmark_report.md index 45a01438..d21cbb3f 100644 --- a/docs/benchmarks/benchmark_report.md +++ b/docs/benchmarks/benchmark_report.md @@ -5,12 +5,12 @@ Generated on standard test environment (Windows target execution). ## Compilation Phase Speeds | Phase | Duration | | :--- | :--- | -| **Lexing & Tokenization** | 0.092 ms | -| **Pratt Parsing & AST Building** | 0.116 ms | -| **Semantic Check & Name Binding** | 0.199 ms | -| **SSA IR Lowering & Optimization** | 0.194 ms | -| **Bytecode Generation** | 0.110 ms | -| **VM Execution (Fibonacci 25)** | 38629.399 ms | +| **Lexing & Tokenization** | 0.090 ms | +| **Pratt Parsing & AST Building** | 0.245 ms | +| **Semantic Check & Name Binding** | 0.454 ms | +| **SSA IR Lowering & Optimization** | 0.103 ms | +| **Bytecode Generation** | 0.138 ms | +| **VM Execution (Fibonacci 25)** | 1279.449 ms | ## Benchmark Details - **Test File**: Recursive Fibonacci 25 calculation (`fib(25)`)