Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@
## 2024-05-24 - Optimize rusqlite extraction in query_map
**Learning:** When mapping `rusqlite` query results to dynamic types like `IndexMap<String, RuntimeValue>` in `techscript_stdlib`, use `row.get_ref_unwrap(i)` to map the underlying `rusqlite::types::ValueRef` directly to the corresponding `RuntimeValue` (e.g., `Int`, `Float`, `Str`), avoiding the overhead and type issues of coercing all numeric and null columns to `String`s.
**Action:** When extracting data from rusqlite database rows, inspect the `ValueRef` directly with `get_ref` or `get_ref_unwrap` instead of eagerly copying out a target Rust type like `String`, significantly reducing allocations and retaining correct native types for numeric and null data.
## 2024-05-18 - String Concatenation Optimization in VM
**Learning:** String concatenation using `format!("{}{}", a, b)` creates unnecessary intermediate string allocations. Replacing it with `String::with_capacity(a.len() + b.len())` and `push_str()` significantly improves performance by allocating the exact required size once. Even better, if the first string is an owned `String` that is no longer needed (e.g., from popping a stack), reusing its buffer via `mut a` and `a.push_str(&b)` avoids allocating a new buffer entirely.
**Action:** When concatenating strings in hot paths like VM execution loops or native interop, prefer in-place buffer reuse (`a.push_str(&b)`) or `String::with_capacity` over `format!`.
7 changes: 4 additions & 3 deletions runtime/native_runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -505,10 +505,11 @@ pub unsafe extern "C" fn ts_add(left: *mut TsValue, right: *mut TsValue) -> *mut

// Concatenation if either is a string
if l.tag == TsTag::String as u32 || r.tag == TsTag::String as u32 {
let l_str = value_to_string(left);
let mut l_str = value_to_string(left);
let r_str = value_to_string(right);
let combined = format!("{}{}", l_str, r_str);
let combined_cstr = CString::new(combined).unwrap();
// Bolt ⚡: In-place string append avoids additional buffer allocations and format! overhead
l_str.push_str(&r_str);
let combined_cstr = CString::new(l_str).unwrap();
return ts_alloc_string(combined_cstr.as_ptr());
}

Expand Down
6 changes: 4 additions & 2 deletions runtime/vm/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,10 @@ impl VM {
(RuntimeValue::Float(a), RuntimeValue::Float(b)) => {
RuntimeValue::Float(a + b)
}
(RuntimeValue::Str(a), RuntimeValue::Str(b)) => {
RuntimeValue::Str(format!("{}{}", a, b))
(RuntimeValue::Str(mut a), RuntimeValue::Str(b)) => {
// Bolt ⚡: In-place string append reuses buffer capacity and avoids fresh allocation
a.push_str(&b);
RuntimeValue::Str(a)
}
_ => {
return Err(VMError::TypeError {
Expand Down
Loading