Repository navigation
Conversation
|
Reviewed The shared sizing logic keeps numeric buffers within their bounds and stack budget, and their lifetimes cover the full operand evaluation and copy. Evaluating all parts before writing, together with the builder buffer/header overlap snapshot, preserves the relevant aliasing and side-effect behavior. Local validation passed: compiler self-build and Looks good to merge from this review. CI was not considered. |
|
The code-review verdict still stands, but this branch now conflicts with master at the early optimization hooks in I resolved the conflict locally against master if !callee_is_fn_value && g.gen_builder_interpolation_call(node, target_name, resolved_target_name) {
return
}
if node.children_count == 2 && target_name.len in [12, 13] && !callee_is_fn_value
&& target_name in ['string.bytes', 'string__bytes']
&& g.gen_temporary_bytes_chain(node, resolved_target_name) {
return
}The resulting change relative to master is still the original seven-file PR scope (+429/-44); the added/deleted source lines match the approved change. The resolved tree passed:
GitHub rejected publishing the resolution to the fork with |
Move the interpolation buffer sizing out of str_intp.v into a shared interpolation_buffers.v, so cleanc.v, str_intp.v and the new builder path agree on when a numeric conversion may return a view of a stack buffer. Add a strings.Builder.write_string fast path that fills the parts array with those views instead of converting each part to an owning string, keeping every buffer alive until all operands are copied.
1689c7c to
7a1b22f
Compare
Move the interpolation buffer sizing out of str_intp.v into a shared interpolation_buffers.v, so cleanc.v, str_intp.v and the new builder path agree on when a numeric conversion may return a view of a stack buffer.
Add a strings.Builder.write_string fast path that fills the parts array with those views instead of converting each part to an owning string, keeping every buffer alive until all operands are copied.
What this does
strings.Builder.write_stringused to turn every interpolation part into anowning string, even when the part was a numeric formatting call whose result
already lives in a caller-provided stack buffer. Each of those conversions
costs an allocation and a copy, and the copy is discarded as soon as the
builder snapshots its argument.
This reworks that path. Buffer sizing moves out of
str_intp.vinto a sharedgen/c/interpolation_buffers.v, socleanc.v,str_intp.vand the new builderpath agree on when a numeric conversion may return a view into a buffer and on
how much stack is safe to reserve. On top of that, a new
gen/c/builder_interpolation.vfills the parts array with those views insteadof owning strings when the argument is a join, a nested
+, or a singlebuffered conversion. Parts are all evaluated before any write happens, and
every buffer stays alive until
string_plus_manyhas copied the operands.Everything outside that set keeps the old path: user
str()methods,dynamically sized formats,
-autofree, and nested joins whose bytes may besnapshotted before later side effects.
Benchmarks
One million writes, ten paired runs, median wall time:
${name}:${n}Testing
New
vlib/v/compiler_tests/builder_interpolation_test.vchecks the generated Cand then runs the compiled program under default,
-gc none,-prodand-autofree. Existing interpolation and exponent tests pass. The compilerbenchmark and full suite are still running; I'll report back here.