From 14c1d64579fee422a8106cb83758461478c6e310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guilherme=20Ara=C3=BAjo?= Date: Sun, 28 Jun 2026 11:22:06 -0300 Subject: [PATCH 1/2] lib: add primitive fast path to structuredClone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Guilherme Araújo --- benchmark/misc/structured-clone.js | 7 ++++++- lib/internal/worker/js_transferable.js | 11 +++++++++++ test/parallel/test-structuredClone-global.js | 11 +++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/benchmark/misc/structured-clone.js b/benchmark/misc/structured-clone.js index 257671df44b07f..741cffc4944d1b 100644 --- a/benchmark/misc/structured-clone.js +++ b/benchmark/misc/structured-clone.js @@ -4,7 +4,7 @@ const common = require('../common.js'); const assert = require('assert'); const bench = common.createBenchmark(main, { - type: ['string', 'object', 'arraybuffer'], + type: ['primitive', 'string', 'object', 'arraybuffer'], n: [1e4], }); @@ -12,6 +12,11 @@ function main({ n, type }) { const data = []; switch (type) { + case 'primitive': + for (let i = 0; i < n; ++i) { + data.push(i); + } + break; case 'string': for (let i = 0; i < n; ++i) { data.push(new Date().toISOString()); diff --git a/lib/internal/worker/js_transferable.js b/lib/internal/worker/js_transferable.js index 0ae80d9a728725..f7b87097f20702 100644 --- a/lib/internal/worker/js_transferable.js +++ b/lib/internal/worker/js_transferable.js @@ -115,6 +115,17 @@ function structuredClone(value, options) { throw new ERR_MISSING_ARGS('The value argument must be specified'); } + // Fast path: primitives clone to themselves, so skip the native + // serialize/deserialize round-trip when no options were provided. + // Symbols are excluded. they are not cloneable and must throw below. + if (options === undefined && + (value === null || + (typeof value !== 'object' && + typeof value !== 'function' && + typeof value !== 'symbol'))) { + return value; + } + const idlOptions = webidl.converters.StructuredSerializeOptions( options, { diff --git a/test/parallel/test-structuredClone-global.js b/test/parallel/test-structuredClone-global.js index 09e36ad47940ea..c0f8137a1ed8a3 100644 --- a/test/parallel/test-structuredClone-global.js +++ b/test/parallel/test-structuredClone-global.js @@ -27,6 +27,17 @@ assert.strictEqual(structuredClone(undefined, null), undefined); // Transfer can be null or undefined. assert.strictEqual(structuredClone(undefined, { }), undefined); +// Primitives clone to themselves. +assert.strictEqual(structuredClone(null), null); +assert.strictEqual(structuredClone(1), 1); +assert.strictEqual(structuredClone('x'), 'x'); +assert.strictEqual(structuredClone(true), true); +assert.strictEqual(structuredClone(10n), 10n); +// -0 is preserved. +assert.ok(Object.is(structuredClone(-0), -0)); +// Symbols are not cloneable and must throw. +assert.throws(() => structuredClone(Symbol()), { name: 'DataCloneError' }); + // Transferables or its subclasses should be received with its closest transferable superclass for (const StreamClass of [ReadableStream, WritableStream, TransformStream]) { const original = new StreamClass(); From 10fb3d708cf69f787de90625e73b953110cf0d48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guilherme=20Ara=C3=BAjo?= Date: Mon, 29 Jun 2026 10:21:55 -0300 Subject: [PATCH 2/2] benchmark: rename structuredClone primitive type to int MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Guilherme Araújo --- benchmark/misc/structured-clone.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/benchmark/misc/structured-clone.js b/benchmark/misc/structured-clone.js index 741cffc4944d1b..38c0d0aed232b3 100644 --- a/benchmark/misc/structured-clone.js +++ b/benchmark/misc/structured-clone.js @@ -4,7 +4,7 @@ const common = require('../common.js'); const assert = require('assert'); const bench = common.createBenchmark(main, { - type: ['primitive', 'string', 'object', 'arraybuffer'], + type: ['int', 'string', 'object', 'arraybuffer'], n: [1e4], }); @@ -12,7 +12,7 @@ function main({ n, type }) { const data = []; switch (type) { - case 'primitive': + case 'int': for (let i = 0; i < n; ++i) { data.push(i); }