Add zlib.crc32c(data[, value]), which computes the CRC-32C checksum
(Castagnoli polynomial, RFC 3720 section 12.1). CRC-32C has better
error detection properties than the CRC-32 of zlib.crc32() and is the
checksum required by many current protocols, formats and services,
among them:
- iSCSI header and data digests (RFC 7143)
- SCTP packet checksums (RFC 9260)
- iWARP MPA framing (RFC 5044)
- NVMe/TCP header and data digests
- ext4, Btrfs and XFS metadata checksums
- the Snappy framing format
- Apache Kafka record batches
- LevelDB and RocksDB block checksums
- TensorFlow TFRecord files
- Google Cloud Storage and Amazon S3 object checksums
Implementing any of these in JavaScript currently needs a userland
CRC-32C, which is far slower than native code.
The function mirrors zlib.crc32(): it accepts a string (encoded as
UTF-8) or an ArrayBufferView, takes an optional 32-bit unsigned
starting value so a checksum can be continued across chunks, and has a
V8 fast API path.
The checksum is computed by absl::ExtendCrc32c() from the bundled
Abseil, which is already built and linked into node, so this adds no
new dependency and no new checksum implementation. absl_crc32c is
added to the libraries linked with --shared-abseil.
Abseil selects its hardware-accelerated CRC-32C path (SSE4.2 and
PCLMULQDQ on x64, the CRC32 and PMULL extensions on arm64) at compile
time, so with node's default compiler flags the portable table-driven
implementation is used. It runs at about the same speed as zlib.crc32()
(about 6.5 GB/s on a recent x64 machine), while the hardware path
reaches about 38 GB/s. Builds whose target CPU baseline already
includes those instructions get the hardware path without changes.
Enabling it for generic builds is left out on purpose: on x64, Abseil
uses the accelerated code for unrecognized CPUs without a runtime
feature check, so compiling it in unconditionally would fault on CPUs
without SSE4.2.
Signed-off-by: Philipp Dunkel <pip@pipobscure.com>
PR-URL: https://github.com/nodejs/node/pull/66828
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
The existing get-function benchmark reuses the callable cached during
warmup, so it no longer measures trampoline creation.
Add a cache-miss benchmark that resolves a function once per library
instance. Construct the instances before timing to exclude library
loading while including symbol resolution, signature preparation,
and callable creation.
Update the existing benchmark comments to describe cache-hit lookups.
Signed-off-by: HoonDongKang <d159123@naver.com>
Assisted-by: Codex:Astra-medium
PR-URL: https://github.com/nodejs/node/pull/66456
Refs: https://github.com/nodejs/node/pull/64969
Refs: https://github.com/nodejs/node/pull/64971
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
decodeFormComponent() already finds the first percent character, but
hasPercentHex() scans the plain prefix again. Start the check at the
known position to avoid repeating that work.
Replacing plus signs with spaces preserves character positions, so
escape validation and decoding behavior remain unchanged.
Signed-off-by: Roberto Bianchi <roberto.bianchi@spendesk.com>
PR-URL: https://github.com/nodejs/node/pull/66696
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
`all()`, `get()` and `iterate()` built each row with the
`Object::New()` overload that takes names and values. That overload
always returns a dictionary-mode object, so no two rows shared a map
and every property read was a hash lookup.
Build rows from a `DictionaryTemplate` cached on the statement in place
of the column names, invalidated on re-prepare. Rows keep their null
prototype. Statements whose column names a template cannot express
(array indices, duplicates, non-ASCII names, which the template
interns as Latin-1) or with more than 64 columns keep the previous
path.
Add a benchmark that reads every column of each row, since the
existing ones only measure building rows.
Fixes: https://github.com/nodejs/node/issues/65799
Assisted-by: Claude
Signed-off-by: Guilherme Araújo <arauujogui@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66385
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
URLSearchParams.sort() copies both merge runs into temporary arrays.
Buffer only the left run and read the right run from the output array,
removing one scratch-array allocation and the right-run copying.
While left-side elements remain, the output cursor stays behind unread
right-side elements. Once the left run is exhausted, the right remainder
is already in place. Taking the left key on equality preserves
stability. The insertion-sort path below 50 pairs is unchanged.
Signed-off-by: Roberto Bianchi <roberto.bianchi@spendesk.com>
PR-URL: https://github.com/nodejs/node/pull/66665
Reviewed-By: Xuguang Mei <meixuguang@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Ilyas Shabi <ilyasshabi94@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Add websocketMask(source, mask, output[, offset[, length]]) and
websocketUnmask(buffer, mask), which XOR data with a repeating 4-byte
key. This is the masking that WebSocket clients apply to every frame
they send (RFC 6455, Section 5.3), and that servers undo on every frame
they receive.
Userland WebSocket implementations do this either with a byte-by-byte
JS loop (undici, and ws without optional dependencies) or with the
bufferutil native addon. bufferutil is installed for only about 3% of
ws downloads and has no linux-arm64 prebuild, so almost all users run
the JS loop. The signature matches bufferutil, so existing users can
switch with a feature check, as ws did for buffer.isUtf8().
The implementation uses a V8 fast API call and processes 8-byte words,
which the compiler vectorizes. It handles overlapping source and output
views, and treats every view type as raw bytes. It is about 20x faster
than the JS loop at 1 KiB and 40x faster at 64 KiB, and faster than
bufferutil at every size from 32 bytes up.
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/66335
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
ReadableStream.prototype.values() built each iterator from an object
literal with a computed symbol-key method plus five closures. Such a
literal is rebuilt through the runtime on every evaluation, costing
close to a microsecond per iterator, which dominates iterating a
short-lived stream.
Move next() and return() to a shared ReadableStreamAsyncIterator
prototype, as for any WebIDL async iterator, and keep the per-iterator
state in its read request. The prototype chain and property shape are
the ones WPT checks; the placeholder AsyncIterator object in util.js is
no longer needed. As in WebIDL, next() and return() now reject when
called on something that is not a ReadableStream async iterator, and
iterators no longer carry own next/return properties.
Add an async-iterator kind to benchmark/webstreams/lifecycle.js.
webstreams/lifecycle.js kind='async-iterator' *** +16.22%
Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/66392
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
Reviewed-By: René <contact.9a5d6388@renegade334.me.uk>
The existing `setHeader` and `setHeaderWH` cases set `Content-Length`
explicitly, and `normal` passes every header to `writeHead()`. The very
common handler shape `res.setHeader(...)` + `res.end(body)`, where
`end()` derives the framing, exercises a different path and was not
covered.
Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/66420
Reviewed-By: Tim Perry <pimterry@gmail.com>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
Compare http.isValidHeaderName() and http.isValidHeaderValue() with
http.validateHeaderName() and http.validateHeaderValue() wrapped in
try/catch, for valid and invalid input, and for both 'strict' and
'relaxed' header value validation.
Signed-off-by: James M Snell <jasnell@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66334
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: Tim Perry <pimterry@gmail.com>
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
The shared "no pending request" records in the writable stream were
`__proto__: null` literals, which V8 creates in dictionary mode. They
sit in inFlightWriteRequest, closeRequest and pendingAbortRequest
whenever nothing is pending, and their promise field is checked several
times per write, so those loads did a hash lookup on every write and
every pipe. They are now built as plain literals and get their null
prototype afterwards, which keeps them in fast mode.
The readable controllers also initialized their state slot with an
empty object that setup replaced immediately. That throwaway allocation
is gone, matching the writable and transform controllers.
Add a writable-write benchmark: nothing in benchmark/webstreams drove
WritableStreamDefaultWriter.write() directly.
Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/66230
Reviewed-By: Mattias Buelens <mattias@buelens.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Cloning a histogram with `structuredClone()` or `postMessage()` shares
the native histogram instead of copying it. Capturing the state of a
histogram at a point in time, while other code keeps recording into
it, requires serializing it with `export()` and parsing the result
with `importHistogram()`.
Add `histogram.snapshot()`, which returns a new, independent
`Histogram` containing a copy of the histogram's configuration,
recorded values, `exceeds` count, and EWMA state, without the
serialization round trip. Values cannot be recorded into the returned
histogram. The method is available on all histograms, including
`RecordableHistogram` and `ELDHistogram` instances.
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: OpenCode
PR-URL: https://github.com/nodejs/node/pull/66099
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Query salt length and digest restrictions instead of serializing the key
to SPKI and parsing its algorithm identifier. A readable salt length
distinguishes restricted keys, including empty parameter sequences, from
unrestricted keys.
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Assisted-by: Codex
PR-URL: https://github.com/nodejs/node/pull/66108
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Retrieving asymmetricKeyDetails only needs the modulus, public exponent,
and RSA-PSS restrictions. Add a public-only Rsa view so provider-backed
keys do not also extract private components or probe additional primes.
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Assisted-by: Codex
PR-URL: https://github.com/nodejs/node/pull/66108
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
`performance.nodeTiming.uvMetricsInfo` returns the libuv event loop
metrics as numbers, which are only exact up to
`Number.MAX_SAFE_INTEGER`. Add `uvMetricsInfoBigInt`, which returns
the same metrics as bigints backed by `uint64_t` storage, carrying the
full 64-bit range reported by libuv.
A single native call fills both a `Float64Array` and a
`BigUint64Array`, so `uvMetricsInfo` does not pay for bigint
allocation and conversion. The new property is omitted from
`toJSON()`, as `JSON.stringify()` cannot serialize bigints.
Assisted-by: OpenCode
Signed-off-by: James M Snell <jasnell@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66094
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Add `Buffer.stringLength(input[, encoding])`, the counterpart of
`Buffer.byteLength()`: it returns the number of UTF-16 code units that
`buf.toString(encoding)` would produce, without decoding.
For UTF-8 the count is computed with simdutf. Invalid input is counted
with the same maximal-subpart replacement that the decoder applies, so
the result always matches `toString().length`. The other encodings are
computed from `byteLength` alone.
This lets code that accumulates streamed input check the result against
`buffer.constants.MAX_STRING_LENGTH` and size its memory budget before
decoding.
Refs: https://github.com/nodejs/node/issues/66062
Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/66064
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Provider-backed keys can have no numeric OpenSSL ID. Identify and
construct asymmetric keys by algorithm name, replacing the custom PQC
name-to-NID substitution with provider-aware matching in ncrypto.
Centralize known algorithm names, public key-type names, capabilities,
and backend compatibility in ncrypto. Use named key generation jobs and
remove asymmetric EVP_PKEY constants from the internal JavaScript
binding.
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Assisted-by: Codex
PR-URL: https://github.com/nodejs/node/pull/65966
Reviewed-By: James M Snell <jasnell@gmail.com>
The current recordable `Histogram` does not maintain any sense
of time. Samples accumulate indefinitely as they are collected.
This implements a relatively simple sliding-window mechanism
that can be count or time based. The key benefit is that the
window remains fixed/bounded while samples are recorded.
The sliding window is chunk based. Internally, it maintains
a ring buffer of a fixed number of individual histograms.
When snapshot() is called, those are materialized into a
single combined histogram. As the window slides, older
chunks (and all of the samples they hold) are dropped from
the window so the window drops however many samples happened
to be in that chunk. This does mean that precision of the
window is determined by the chunk size.
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/65825
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Implements quantile-respectful density estimate calcuation
on Histogram. Helps with tail-focused latency analysis
without retaining raw samples.
Baking this directly into Node.js, based on a 1 million
sample, 1k bin workload, this impl is roughly 150-325x
faster than performing the equivalent in Rscript.
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/65806
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>