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.80%. Comparing base (f48ac91) to head (f38c303).
⚠️ Report is 14 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.77%   89.80%   +0.02%     
==========================================
  Files         697      697              
  Lines      215749   215755       +6     
  Branches    41304    41285      -19     
==========================================
+ Hits       193681   193751      +70     
+ Misses      14161    14123      -38     
+ Partials     7907     7881      -26     
Files with missing lines Coverage Δ
src/string_bytes.cc 74.63% <87.50%> (+4.96%) ⬆️

... and 52 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.

@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

@ronag ronag added the request-ci Add this label to start a Jenkins CI on a PR. label Mar 31, 2026
@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Mar 31, 2026
@nodejs-github-bot

This comment was marked as outdated.

@nodejs-github-bot

This comment was marked as outdated.

@nodejs-github-bot

This comment was marked as outdated.

@nodejs-github-bot
Copy link
Copy Markdown
Collaborator

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 fd449b1 to f38c303 Compare April 7, 2026 11:08
@Flarna Flarna added the request-ci Add this label to start a Jenkins CI on a PR. label Apr 8, 2026
@thisalihassan
Copy link
Copy Markdown
Contributor Author

thisalihassan commented Apr 8, 2026

@Flarna for somereason CI is not getting triggered even after you added the label, is there a delay?
NVM it started after ~40min :')

@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Apr 8, 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.

5 participants