Skip to content

perf: reduce per-value overhead in encode/dispatch and centralize string writing - #120

Merged
mcollina merged 2 commits into
masterfrom
perf/round3
Oct 17, 2026
Merged

mcollina merged 2 commits into
masterfrom
perf/round3

Conversation

@mcollina

Copy link
Copy Markdown
Owner

A profiling-driven cleanup of the remaining per-value overhead in the encoder and constant dispatch.

Changes

Encoder

  • Centralize string encoding into Writer.writeString. The length prefix and UTF-8 payload are written with a single buffer reservation per string, so the header and payload no longer each trigger a separate buffer-growth check. The four header forms (fixstr / str8 / str16 / str32) are handled in one place. encodeString reduces to computing the byte length and calling it.
  • Dispatch encodeValue on typeof first. For the most common values (strings, numbers, booleans), this replaces several strict-equality probes with a single typeof check. null is still handled explicitly (it is typeof 'object'), so behavior is unchanged.

Decoder

  • Inline null/false/true decoding directly in tryDecode, removing a decodeConstants call per constant.
  • Hoist the __proto__ constant to module scope, so building plain objects no longer re-creates the local binding for every map.

Validation

  • Full Tape suite: 4391 passing on Node 22, 24, and 26.
  • standard lint clean.
  • Byte-exact string encoding verified across the fixstr/str8/str16/str32 boundaries and surrogate pairs on all three CI Node versions.

Note on impact

These are reductions in per-value JS overhead; they do not change the wire format. Re-profiling shows encode/decode are dominated by inherent native UTF-8 work (utf8Slice/utf8Write), so measurements on msgpackr's string-heavy benchmark are within the machine's noise. The changes are correct and byte-exact, and simplify the hot paths.

Write the length prefix and UTF-8 payload with one _ensure per string in
Writer.writeString, instead of separate header/payload reservations that each
re-checked buffer growth. Also dispatch encodeValue on typeof for the
primitive types (string/number/boolean) before strict-equality probes, which
avoids several wasted comparisons for the most common values. Byte-exact for
fixstr/str8/str16/str32 boundaries and surrogate pairs; suite passes on Node
22/24/26.
Decode null/false/true directly in tryDecode instead of delegating to a
decodeConstants function (one less call per constant). Hoist '__proto__' to a
module-scope constant so building plain objects doesn't re-create a local
binding per map. Suite passes on Node 22/24/26.
@mcollina
mcollina merged commit 98a594d into master Oct 17, 2026
20 checks passed
@mcollina
mcollina deleted the perf/round3 branch October 17, 2026 13:56
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