mirror of
https://github.com/denoland/deno
synced 2024-08-24 18:47:06 +00:00
perf(ext/web): optimize structuredClone without transferables (#20730)
This PR optimizes `structuredClone` when it's called without transferables. ### Benchmarks **main** ``` cpu: 13th Gen Intel(R) Core(TM) i9-13900H runtime: deno 1.37.1 (x86_64-unknown-linux-gnu) benchmark time (avg) iter/s (min … max) p75 p99 p995 ----------------------------------------------------------------------------------- ----------------------------- structuredClone object 1.64 µs/iter 611,086.0 (1.58 µs … 1.84 µs) 1.66 µs 1.84 µs 1.84 µs structuredClone transferables 2.82 µs/iter 354,281.4 (2.78 µs … 2.92 µs) 2.84 µs 2.92 µs 2.92 µs ``` **this PR** ``` cpu: 13th Gen Intel(R) Core(TM) i9-13900H runtime: deno 1.37.1 (x86_64-unknown-linux-gnu) structuredClone object 1 µs/iter 998,383.5 (971.28 ns … 1.2 µs) 1 µs 1.2 µs 1.2 µs structuredClone transferables 2.82 µs/iter 355,087.5 (2.7 µs … 3.07 µs) 2.83 µs 3.07 µs 3.07 µs ``` ```js Deno.bench("structuredClone object", () => { structuredClone({ foo: "bar" }); }); Deno.bench("structuredClone transferables", () => { const buf = new Uint8Array([97]); structuredClone(buf, { transfer: [buf.buffer], }); }); ```
This commit is contained in:
parent
cba5ae45c2
commit
ceecd8c495
|
@ -205,34 +205,39 @@ function opCreateEntangledMessagePort() {
|
|||
function deserializeJsMessageData(messageData) {
|
||||
/** @type {object[]} */
|
||||
const transferables = [];
|
||||
const hostObjects = [];
|
||||
const arrayBufferIdsInTransferables = [];
|
||||
const transferredArrayBuffers = [];
|
||||
let options;
|
||||
|
||||
for (let i = 0; i < messageData.transferables.length; ++i) {
|
||||
const transferable = messageData.transferables[i];
|
||||
switch (transferable.kind) {
|
||||
case "messagePort": {
|
||||
const port = createMessagePort(transferable.data);
|
||||
ArrayPrototypePush(transferables, port);
|
||||
ArrayPrototypePush(hostObjects, port);
|
||||
break;
|
||||
if (messageData.transferables.length > 0) {
|
||||
const hostObjects = [];
|
||||
for (let i = 0; i < messageData.transferables.length; ++i) {
|
||||
const transferable = messageData.transferables[i];
|
||||
switch (transferable.kind) {
|
||||
case "messagePort": {
|
||||
const port = createMessagePort(transferable.data);
|
||||
ArrayPrototypePush(transferables, port);
|
||||
ArrayPrototypePush(hostObjects, port);
|
||||
break;
|
||||
}
|
||||
case "arrayBuffer": {
|
||||
ArrayPrototypePush(transferredArrayBuffers, transferable.data);
|
||||
const index = ArrayPrototypePush(transferables, null);
|
||||
ArrayPrototypePush(arrayBufferIdsInTransferables, index);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new TypeError("Unreachable");
|
||||
}
|
||||
case "arrayBuffer": {
|
||||
ArrayPrototypePush(transferredArrayBuffers, transferable.data);
|
||||
const index = ArrayPrototypePush(transferables, null);
|
||||
ArrayPrototypePush(arrayBufferIdsInTransferables, index);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new TypeError("Unreachable");
|
||||
}
|
||||
|
||||
options = {
|
||||
hostObjects,
|
||||
transferredArrayBuffers,
|
||||
};
|
||||
}
|
||||
|
||||
const data = core.deserialize(messageData.data, {
|
||||
hostObjects,
|
||||
transferredArrayBuffers,
|
||||
});
|
||||
const data = core.deserialize(messageData.data, options);
|
||||
|
||||
for (let i = 0; i < arrayBufferIdsInTransferables.length; ++i) {
|
||||
const id = arrayBufferIdsInTransferables[i];
|
||||
|
@ -248,31 +253,36 @@ function deserializeJsMessageData(messageData) {
|
|||
* @returns {messagePort.MessageData}
|
||||
*/
|
||||
function serializeJsMessageData(data, transferables) {
|
||||
let options;
|
||||
const transferredArrayBuffers = [];
|
||||
for (let i = 0, j = 0; i < transferables.length; i++) {
|
||||
const ab = transferables[i];
|
||||
if (ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, ab)) {
|
||||
if (
|
||||
ArrayBufferPrototypeGetByteLength(ab) === 0 &&
|
||||
ops.op_arraybuffer_was_detached(ab)
|
||||
) {
|
||||
throw new DOMException(
|
||||
`ArrayBuffer at index ${j} is already detached`,
|
||||
"DataCloneError",
|
||||
);
|
||||
if (transferables.length > 0) {
|
||||
const hostObjects = [];
|
||||
for (let i = 0, j = 0; i < transferables.length; i++) {
|
||||
const t = transferables[i];
|
||||
if (ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, t)) {
|
||||
if (
|
||||
ArrayBufferPrototypeGetByteLength(t) === 0 &&
|
||||
ops.op_arraybuffer_was_detached(t)
|
||||
) {
|
||||
throw new DOMException(
|
||||
`ArrayBuffer at index ${j} is already detached`,
|
||||
"DataCloneError",
|
||||
);
|
||||
}
|
||||
j++;
|
||||
ArrayPrototypePush(transferredArrayBuffers, t);
|
||||
} else if (ObjectPrototypeIsPrototypeOf(MessagePortPrototype, t)) {
|
||||
ArrayPrototypePush(hostObjects, t);
|
||||
}
|
||||
j++;
|
||||
ArrayPrototypePush(transferredArrayBuffers, ab);
|
||||
}
|
||||
|
||||
options = {
|
||||
hostObjects,
|
||||
transferredArrayBuffers,
|
||||
};
|
||||
}
|
||||
|
||||
const serializedData = core.serialize(data, {
|
||||
hostObjects: ArrayPrototypeFilter(
|
||||
transferables,
|
||||
(a) => ObjectPrototypeIsPrototypeOf(MessagePortPrototype, a),
|
||||
),
|
||||
transferredArrayBuffers,
|
||||
}, (err) => {
|
||||
const serializedData = core.serialize(data, options, (err) => {
|
||||
throw new DOMException(err, "DataCloneError");
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue