Skip to content

src: use stack allocation for small string encoding#62431

Open
thisalihassan wants to merge 2 commits intonodejs:mainfrom
thisalihassan:src-string-bytes-stack-encode
Open

src: use stack allocation for small string encoding#62431
thisalihassan wants to merge 2 commits intonodejs:mainfrom
thisalihassan:src-string-bytes-stack-encode

Conversation

@thisalihassan
Copy link
Copy Markdown
Contributor

  • Introduce EncodeOneByteString / EncodeTwoByteString helper templates in StringBytes::Encode() that use a 512 byte (256-char for two-byte) stack buffer for small inputs, falling back to heap allocation + ExternString for larger ones.
  • Covers all encoding paths: ASCII, HEX, BASE64, BASE64URL, UTF8 (two-byte), and UCS2.

Refs: nodejs/performance#194

                                                                       confidence improvement accuracy (*)   (**)  (***)
buffers/buffer-base64-encode.js n=32 len=67108864                                      1.82 %       ±2.53% ±3.38% ±4.42%
buffers/buffer-base64url-encode.js n=32 len=67108864                            *     -1.70 %       ±1.39% ±1.86% ±2.42%
buffers/buffer-tostring.js n=1000000 len=1 args=0 encoding=''                 ***      3.71 %       ±1.67% ±2.23% ±2.91%
buffers/buffer-tostring.js n=1000000 len=1 args=1 encoding='ascii'                     0.21 %       ±2.08% ±2.78% ±3.65%
buffers/buffer-tostring.js n=1000000 len=1 args=1 encoding='hex'              ***     40.34 %       ±4.17% ±5.60% ±7.39%
buffers/buffer-tostring.js n=1000000 len=1 args=1 encoding='latin1'           ***      2.52 %       ±1.15% ±1.53% ±1.99%
buffers/buffer-tostring.js n=1000000 len=1 args=1 encoding='UCS-2'            ***      3.33 %       ±1.26% ±1.68% ±2.19%
buffers/buffer-tostring.js n=1000000 len=1 args=1 encoding='utf8'             ***      2.03 %       ±0.90% ±1.19% ±1.55%
buffers/buffer-tostring.js n=1000000 len=1 args=3 encoding='ascii'              *      3.00 %       ±2.83% ±3.80% ±5.02%
buffers/buffer-tostring.js n=1000000 len=1 args=3 encoding='hex'              ***     40.40 %       ±3.23% ±4.30% ±5.59%
buffers/buffer-tostring.js n=1000000 len=1 args=3 encoding='latin1'            **      2.93 %       ±2.04% ±2.73% ±3.58%
buffers/buffer-tostring.js n=1000000 len=1 args=3 encoding='UCS-2'            ***      4.55 %       ±1.17% ±1.56% ±2.04%
buffers/buffer-tostring.js n=1000000 len=1 args=3 encoding='utf8'             ***      2.52 %       ±0.88% ±1.17% ±1.52%
buffers/buffer-tostring.js n=1000000 len=1024 args=0 encoding=''                      -0.48 %       ±1.75% ±2.35% ±3.09%
buffers/buffer-tostring.js n=1000000 len=1024 args=1 encoding='ascii'                  2.68 %       ±3.68% ±4.91% ±6.44%
buffers/buffer-tostring.js n=1000000 len=1024 args=1 encoding='hex'                   -0.05 %       ±1.47% ±1.96% ±2.55%
buffers/buffer-tostring.js n=1000000 len=1024 args=1 encoding='latin1'          *      2.53 %       ±1.94% ±2.60% ±3.41%
buffers/buffer-tostring.js n=1000000 len=1024 args=1 encoding='UCS-2'                  0.75 %       ±1.80% ±2.40% ±3.13%
buffers/buffer-tostring.js n=1000000 len=1024 args=1 encoding='utf8'            *      3.19 %       ±2.47% ±3.33% ±4.40%
buffers/buffer-tostring.js n=1000000 len=1024 args=3 encoding='ascii'                  0.01 %       ±2.15% ±2.86% ±3.72%
buffers/buffer-tostring.js n=1000000 len=1024 args=3 encoding='hex'                    0.40 %       ±1.31% ±1.74% ±2.26%
buffers/buffer-tostring.js n=1000000 len=1024 args=3 encoding='latin1'          *      1.96 %       ±1.86% ±2.48% ±3.23%
buffers/buffer-tostring.js n=1000000 len=1024 args=3 encoding='UCS-2'                  0.54 %       ±1.99% ±2.65% ±3.46%
buffers/buffer-tostring.js n=1000000 len=1024 args=3 encoding='utf8'                   1.05 %       ±1.11% ±1.48% ±1.93%
buffers/buffer-tostring.js n=1000000 len=64 args=0 encoding=''                        -0.37 %       ±1.28% ±1.72% ±2.26%
buffers/buffer-tostring.js n=1000000 len=64 args=1 encoding='ascii'                   -1.33 %       ±2.21% ±2.97% ±3.92%
buffers/buffer-tostring.js n=1000000 len=64 args=1 encoding='hex'             ***     41.64 %       ±2.07% ±2.76% ±3.62%
buffers/buffer-tostring.js n=1000000 len=64 args=1 encoding='latin1'            *      1.98 %       ±1.86% ±2.48% ±3.25%
buffers/buffer-tostring.js n=1000000 len=64 args=1 encoding='UCS-2'                   -0.38 %       ±2.76% ±3.68% ±4.80%
buffers/buffer-tostring.js n=1000000 len=64 args=1 encoding='utf8'                     0.64 %       ±0.88% ±1.18% ±1.53%
buffers/buffer-tostring.js n=1000000 len=64 args=3 encoding='ascii'                    0.35 %       ±2.91% ±3.88% ±5.07%
buffers/buffer-tostring.js n=1000000 len=64 args=3 encoding='hex'             ***     40.54 %       ±1.43% ±1.90% ±2.48%
buffers/buffer-tostring.js n=1000000 len=64 args=3 encoding='latin1'                   1.67 %       ±2.47% ±3.30% ±4.31%
buffers/buffer-tostring.js n=1000000 len=64 args=3 encoding='UCS-2'                    0.32 %       ±1.93% ±2.57% ±3.35%
buffers/buffer-tostring.js n=1000000 len=64 args=3 encoding='utf8'                     0.56 %       ±0.91% ±1.21% ±1.58%

Be aware that when doing many comparisons the risk of a false-positive
result increases. In this case, there are 35 comparisons, you can thus
expect the following amount of false-positive results:
  1.75 false positives, when considering a   5% risk acceptance (*, **, ***),
  0.35 false positives, when considering a   1% risk acceptance (**, ***),
  0.04 false positives, when considering a 0.1% risk acceptance (***)
thisalihassan@Alis-MacBook-Pro node % 

@nodejs-github-bot nodejs-github-bot added buffer Issues and PRs related to the buffer subsystem. c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run. labels Mar 25, 2026
@thisalihassan thisalihassan force-pushed the src-string-bytes-stack-encode branch from e5fbafb to 43fd2f8 Compare March 25, 2026 11:05
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 25, 2026

Codecov Report

❌ Patch coverage is 87.50000% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.71%. Comparing base (0d7e4b1) to head (fd449b1).
⚠️ Report is 27 commits behind head on main.

Files with missing lines Patch % Lines
src/string_bytes.cc 87.50% 0 Missing and 6 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #62431      +/-   ##
==========================================
+ Coverage   89.68%   89.71%   +0.03%     
==========================================
  Files         676      692      +16     
  Lines      206738   213994    +7256     
  Branches    39594    41050    +1456     
==========================================
+ Hits       185414   191994    +6580     
- Misses      13467    14090     +623     
- Partials     7857     7910      +53     
Files with missing lines Coverage Δ
src/string_bytes.cc 74.63% <87.50%> (+4.96%) ⬆️

... and 95 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Use stack-allocated buffers in StringBytes::Encode() for small inputs
instead of heap-allocating via UncheckedMalloc for every call.

Refs: nodejs/performance#194
@thisalihassan thisalihassan force-pushed the src-string-bytes-stack-encode branch from 43fd2f8 to 73eb342 Compare March 27, 2026 12:26
Comment on lines +553 to +560
case BUFFER: {
auto maybe_buf = Buffer::Copy(isolate, buf, buflen);
Local<v8::Object> buf;
if (!maybe_buf.ToLocal(&buf)) {
isolate->ThrowException(node::ERR_MEMORY_ALLOCATION_FAILED(isolate));
}
return buf;
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Seems like unnecessary whitespace change?

@ronag ronag added the author ready PRs that have at least one approval, no pending requests for changes, and a CI started. label Mar 29, 2026
@ronag ronag added the request-ci Add this label to start a Jenkins CI on a PR. label Mar 29, 2026
@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Mar 29, 2026
@nodejs-github-bot
Copy link
Copy Markdown
Collaborator

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author ready PRs that have at least one approval, no pending requests for changes, and a CI started. buffer Issues and PRs related to the buffer subsystem. c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants