diff options
author | Marcos Casagrande <marcos@denode.com> | 2023-10-06 23:21:48 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-10-06 23:21:48 +0200 |
commit | ceecd8c495619284eee5763c1adb4afba345dceb (patch) | |
tree | 098e8cb76c5df08dd006bcda62343d0a02d6a199 /ext | |
parent | cba5ae45c2422a4cf9df3a149a646a191a8f27b2 (diff) |
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],
});
});
```
Diffstat (limited to 'ext')
-rw-r--r-- | ext/web/13_message_port.js | 92 |
1 files changed, 51 insertions, 41 deletions
diff --git a/ext/web/13_message_port.js b/ext/web/13_message_port.js index 40145db78..ffbc48812 100644 --- a/ext/web/13_message_port.js +++ b/ext/web/13_message_port.js @@ -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; - } - case "arrayBuffer": { - ArrayPrototypePush(transferredArrayBuffers, transferable.data); - const index = ArrayPrototypePush(transferables, null); - ArrayPrototypePush(arrayBufferIdsInTransferables, index); - 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"); } - 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"); }); |