Skip to content

perf(stringbuilder): reuse unshared reset buffer - #3843

Open
mizchi wants to merge 3 commits into
moonbitlang:mainfrom
mizchi:perf/stringbuilder-reset
Open

perf(stringbuilder): reuse unshared reset buffer#3843
mizchi wants to merge 3 commits into
moonbitlang:mainfrom
mizchi:perf/stringbuilder-reset

Conversation

@mizchi

@mizchi mizchi commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Reuse StringBuilder storage on reset() unless a zero-copy to_string() result shares it.
  • Store spare capacity as UninitializedArray[UInt16], initializing only 0..<len and avoiding redundant zero-fills before writes.
  • Add whitebox coverage for grow/reset/string-conversion safety and large-buffer benchmarks.

Benchmark

Apple M5, MoonBit 0.1.20260824, native release. Three sequential runs per revision; lower is better.

Build size Before (93044073) After (48486332) Improvement
1 MiB 28.06 µs 16.34 µs 41.8%
8 MiB 273.48 µs 152.75 µs 44.1%
32 MiB 1.30 ms 0.89 ms 31.4%

Command: moon bench --release --target native builtin/stringbuilder_large_bench_test.mbt

Validation

  • moon test builtin --target all: wasm 2960, wasm-gc 2960, JS 2935, native 2919; all passed
  • moon check
  • moon info; no public interface changes

@mizchi
mizchi marked this pull request as ready for review July 20, 2026 14:37
Copilot AI review requested due to automatic review settings July 20, 2026 14:37

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR optimizes the native/wasm builtin StringBuilder implementation by allowing reset() to reuse the existing UTF-16 backing buffer when it’s safe (i.e., when the buffer hasn’t been exposed via the zero-copy to_string() fast path), reducing allocations and zero-fills while preserving correctness.

Changes:

  • Add an internal buffer_is_shared flag to track when to_string() returns a zero-copy string backed by the builder’s buffer.
  • Update reset() to reuse the existing buffer unless it has been shared, in which case it detaches by allocating a fresh buffer.
  • Add a non-JS whitebox regression test validating that reset() reuses an unshared buffer.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
builtin/stringbuilder_buffer.mbt Track zero-copy sharing in to_string() and reuse backing storage in reset() when safe.
builtin/stringbuilder_wbtest.mbt Add a non-JS whitebox test that asserts buffer reuse behavior across reset().

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@mizchi
mizchi force-pushed the perf/stringbuilder-reset branch from b512ce6 to 9304407 Compare August 24, 2026 15:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants