Skip to content

v1.9.1 remove per-encode allocations from varint and field iteration - #23

Merged
reececomo merged 2 commits into
mainfrom
perf/encode-no-boxing
Nov 9, 2026
Merged

reececomo merged 2 commits into
mainfrom
perf/encode-no-boxing

Conversation

@reececomo

@reececomo reececomo commented Nov 9, 2026 •

Copy link
Copy Markdown
Owner

encode() no longer allocates for varint fields or field iteration, and the output bytes are unchanged.

More details

Double and float fields never allocated. I verified this on Node 20 and 24, with and without TurboFan. The allocations came from two other places:

  • Field iteration: The for...of loop over fields in _$write allocated about 2.5 KB per encode before TurboFan optimized it. It is now an indexed loop.
  • Varints: UInt and Int values at or above 2^14 were boxed by V8, because value + 0xc0000000 falls outside the Smi range. This cost about 16 B per field. The writes now pass Smi-range int32 values, and the low 32 bits are written as two uint16 values.

Allocation per encode, measured with heapUsed on a nested schema with 45 float fields:

Case Before After
Unoptimized (--max-opt=0) 3385 B 113 B
Optimized 114 B 98 B
UInt-heavy, optimized 181 B 101 B

The remaining ~96 B is the subarray() view returned by encode(data, false). I left it alone because avoiding it would change the identity of the returned view.

New tests check the float64 bytes for special values (NaN, ±Infinity, -0, subnormals and MAX_VALUE). They also compare varint bytes against the previous formulas across about 2,400 values. All 120 tests pass and lint is clean. This bumps the version to 1.9.1 and rebuilds dist, so merging publishes it.

🤖 Generated with Claude Code

Varint UInt/Int writes now pass Smi-range int32 values to the writer instead
of out-of-range doubles that V8 boxes, and object fields are iterated with an
indexed loop instead of for...of. Output bytes are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@reececomo
reececomo marked this pull request as ready for review November 9, 2026 02:11
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@reececomo reececomo changed the title Remove per-encode allocations from varint and field iteration v1.9.1 remove per-encode allocations from varint and field iteration Nov 9, 2026
@reececomo
reececomo merged commit 4ccea22 into main Nov 9, 2026
2 checks passed
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.

1 participant