Skip to content

Commit 070cec3

Browse files
⚡ Bolt: [performance improvement] Avoid string allocations in native runtime value_to_string
Co-authored-by: Tcode-Motion <188012755+Tcode-Motion@users.noreply.github.com>
1 parent 775f189 commit 070cec3

3 files changed

Lines changed: 66 additions & 29 deletions

File tree

‎.jules/bolt.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,9 @@
4444
## 2024-05-18 - Optimized CFG Successor Lookup
4545
**Learning:** During control flow graph validation in `compiler/optimizer/src/verifier.rs`, using `func.blocks.iter().find(|b| b.id == succ)` for every successor of every block created an O(V * E) time complexity bottleneck. By pre-computing a `HashMap` of `BlockId` to `&BasicBlock` in a single pass, the verification complexity was reduced to O(V + E).
4646
**Action:** When validating graph structures or resolving many cross-references within a known collection, construct a lookup map in advance instead of performing repeated O(N) linear scans.
47+
## 2026-09-26 - Native Runtime Stringification Optimization
48+
**Learning:** In the native runtime C FFI, generating strings for nested structures heavily penalized performance by using `format!` and `Vec::join`, creating `O(N)` intermediate heap allocations.
49+
**Action:** Use a recursive builder pattern by passing a mutable `&mut String` buffer downward and utilizing `std::fmt::Write` to directly push onto the buffer without intermediate allocations.
50+
## 2026-09-26 - Native Runtime Stringification Optimization
51+
**Learning:** In the native runtime C FFI, generating strings for nested TsValue structures heavily penalized performance by using format! and Vec::join, creating O(N) intermediate heap allocations.
52+
**Action:** Use a recursive builder pattern by passing a mutable &mut String buffer downward and utilizing std::fmt::Write to directly push onto the buffer without intermediate allocations.

‎runtime/native_runtime/src/lib.rs‎

Lines changed: 60 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// runtime/native_runtime/src/lib.rs
22
#![allow(clippy::not_unsafe_ptr_arg_deref, clippy::missing_safety_doc)]
33

4+
use std::fmt::Write as FmtWrite;
45
use std::collections::HashMap;
56
use std::ffi::{CStr, CString};
67
use std::io::{self, Write};
@@ -233,85 +234,115 @@ pub unsafe extern "C" fn ts_free_value(val: *mut TsValue) {
233234
}
234235

235236
// Convert TsValue to Rust String helper
236-
unsafe fn value_to_string(val: *mut TsValue) -> String {
237+
unsafe fn value_to_string_impl(val: *mut TsValue, buf: &mut String) {
237238
if val.is_null() {
238-
return "null".to_string();
239+
let _ = write!(buf, "null");
240+
return;
239241
}
240242
let v = &*val;
241243
if v.tag == TsTag::Null as u32 {
242-
"null".to_string()
244+
let _ = write!(buf, "null");
243245
} else if v.tag == TsTag::Bool as u32 {
244-
v.data.boolean.to_string()
246+
let _ = write!(buf, "{}", v.data.boolean);
245247
} else if v.tag == TsTag::Int as u32 {
246-
v.data.integer.to_string()
248+
let _ = write!(buf, "{}", v.data.integer);
247249
} else if v.tag == TsTag::Float as u32 {
248-
v.data.float.to_string()
250+
let _ = write!(buf, "{}", v.data.float);
249251
} else if v.tag == TsTag::String as u32 {
250252
if v.data.pointer.is_null() {
251-
"null".to_string()
253+
let _ = write!(buf, "null");
252254
} else {
253-
(*(v.data.pointer as *const String)).clone()
255+
buf.push_str(&*(v.data.pointer as *const String));
254256
}
255257
} else if v.tag == TsTag::List as u32 {
256258
if v.data.pointer.is_null() {
257-
"[]".to_string()
259+
let _ = write!(buf, "[]");
258260
} else {
261+
let _ = write!(buf, "[");
259262
let list = &*(v.data.pointer as *const Vec<*mut TsValue>);
260-
let mut parts = Vec::new();
261-
for &item in list {
262-
parts.push(value_to_string(item));
263+
for (i, &item) in list.iter().enumerate() {
264+
if i > 0 {
265+
let _ = write!(buf, ", ");
266+
}
267+
value_to_string_impl(item, buf);
263268
}
264-
format!("[{}]", parts.join(", "))
269+
let _ = write!(buf, "]");
265270
}
266271
} else if v.tag == TsTag::Map as u32 {
267272
if v.data.pointer.is_null() {
268-
"{}".to_string()
273+
let _ = write!(buf, "{{}}");
269274
} else {
275+
let _ = write!(buf, "{{");
270276
let map = &*(v.data.pointer as *const HashMap<String, *mut TsValue>);
271-
let mut parts = Vec::new();
277+
let mut first = true;
272278
for (k, &val) in map {
273-
parts.push(format!("{}: {}", k, value_to_string(val)));
279+
if !first {
280+
let _ = write!(buf, ", ");
281+
}
282+
first = false;
283+
let _ = write!(buf, "{}: ", k);
284+
value_to_string_impl(val, buf);
274285
}
275-
format!("{{{}}}", parts.join(", "))
286+
let _ = write!(buf, "}}");
276287
}
277288
} else if v.tag == TsTag::Struct as u32 {
278289
if v.data.pointer.is_null() {
279-
"unknown struct".to_string()
290+
let _ = write!(buf, "unknown struct");
280291
} else {
281292
let s = &*(v.data.pointer as *const TsStruct);
282-
let mut parts = Vec::new();
293+
let _ = write!(buf, "{} {{", s.name);
294+
let mut first = true;
283295
for (k, &val) in &s.fields {
284-
parts.push(format!("{}: {}", k, value_to_string(val)));
296+
if !first {
297+
let _ = write!(buf, ", ");
298+
}
299+
first = false;
300+
let _ = write!(buf, "{}: ", k);
301+
value_to_string_impl(val, buf);
285302
}
286-
format!("{} {{{}}}", s.name, parts.join(", "))
303+
let _ = write!(buf, "}}");
287304
}
288305
} else if v.tag == TsTag::Model as u32 {
289306
if v.data.pointer.is_null() {
290-
"unknown model".to_string()
307+
let _ = write!(buf, "unknown model");
291308
} else {
292309
let m = &*(v.data.pointer as *const TsModel);
293-
let mut parts = Vec::new();
310+
let _ = write!(buf, "{} {{", m.name);
311+
let mut first = true;
294312
for (k, &val) in &m.fields {
295-
parts.push(format!("{}: {}", k, value_to_string(val)));
313+
if !first {
314+
let _ = write!(buf, ", ");
315+
}
316+
first = false;
317+
let _ = write!(buf, "{}: ", k);
318+
value_to_string_impl(val, buf);
296319
}
297-
format!("{} {{{}}}", m.name, parts.join(", "))
320+
let _ = write!(buf, "}}");
298321
}
299322
} else if v.tag == TsTag::Enum as u32 {
300323
if v.data.pointer.is_null() {
301-
"unknown enum".to_string()
324+
let _ = write!(buf, "unknown enum");
302325
} else {
303326
let e = &*(v.data.pointer as *const TsEnum);
304327
if e.value.is_null() {
305-
format!("{}.{}", e.name, e.variant)
328+
let _ = write!(buf, "{}.{}", e.name, e.variant);
306329
} else {
307-
format!("{}.{}({})", e.name, e.variant, value_to_string(e.value))
330+
let _ = write!(buf, "{}.{}(", e.name, e.variant);
331+
value_to_string_impl(e.value, buf);
332+
let _ = write!(buf, ")");
308333
}
309334
}
310335
} else {
311-
"unknown".to_string()
336+
let _ = write!(buf, "unknown");
312337
}
313338
}
314339

340+
unsafe fn value_to_string(val: *mut TsValue) -> String {
341+
let mut s = String::new();
342+
value_to_string_impl(val, &mut s);
343+
s
344+
}
345+
315346
// Built-in functions
316347
#[no_mangle]
317348
pub unsafe extern "C" fn ts_say(val: *mut TsValue) {

‎test_value_to_string‎

3.77 MB
Binary file not shown.

0 commit comments

Comments
 (0)