From b6400a25a0ee60467a0287d725e61c876677e103 Mon Sep 17 00:00:00 2001 From: Satya Rohith Date: Mon, 7 Jun 2021 17:49:33 +0530 Subject: [PATCH] refactor(runtime): move performance API to timers extension (#10818) Co-authored-by: Luca Casonato --- .../broadcast_channel/01_broadcast_channel.js | 2 +- .../timers/02_performance.js | 12 +-- extensions/timers/lib.rs | 1 + extensions/web/02_structured_clone.js | 73 +++++++++++++++++++ extensions/web/lib.rs | 1 + runtime/js/01_web_util.js | 60 --------------- 6 files changed, 82 insertions(+), 67 deletions(-) rename runtime/js/40_performance.js => extensions/timers/02_performance.js (96%) create mode 100644 extensions/web/02_structured_clone.js diff --git a/extensions/broadcast_channel/01_broadcast_channel.js b/extensions/broadcast_channel/01_broadcast_channel.js index 7670b0cfd0..c2937105ec 100644 --- a/extensions/broadcast_channel/01_broadcast_channel.js +++ b/extensions/broadcast_channel/01_broadcast_channel.js @@ -105,7 +105,7 @@ constructor(name) { super(); - const prefix = "Failed to construct 'broadcastChannel'"; + const prefix = "Failed to construct 'BroadcastChannel'"; webidl.requiredArguments(arguments.length, 1, { prefix }); this[_name] = webidl.converters["DOMString"](name, { diff --git a/runtime/js/40_performance.js b/extensions/timers/02_performance.js similarity index 96% rename from runtime/js/40_performance.js rename to extensions/timers/02_performance.js index 24c35b5c0e..bca98fdbd1 100644 --- a/runtime/js/40_performance.js +++ b/extensions/timers/02_performance.js @@ -2,10 +2,9 @@ "use strict"; ((window) => { + const { webidl, structuredClone } = window.__bootstrap; const { opNow } = window.__bootstrap.timers; - const { cloneValue, illegalConstructorKey } = window.__bootstrap.webUtil; - const { requiredArguments } = window.__bootstrap.webUtil; - + const illegalConstructorKey = Symbol("illegalConstructorKey"); const customInspect = Symbol.for("Deno.customInspect"); let performanceEntries = []; @@ -118,7 +117,8 @@ name, options = {}, ) { - requiredArguments("PerformanceMark", arguments.length, 1); + const prefix = "Failed to construct 'PerformanceMark'"; + webidl.requiredArguments(arguments.length, 1, { prefix }); // ensure options is object-ish, or null-ish switch (typeof options) { @@ -138,7 +138,7 @@ if (startTime < 0) { throw new TypeError("startTime cannot be negative"); } - this.#detail = cloneValue(detail); + this.#detail = structuredClone(detail); } toJSON() { @@ -184,7 +184,7 @@ throw new TypeError("Illegal constructor."); } super(name, "measure", startTime, duration, illegalConstructorKey); - this.#detail = cloneValue(detail); + this.#detail = structuredClone(detail); } toJSON() { diff --git a/extensions/timers/lib.rs b/extensions/timers/lib.rs index e9580c4b5a..66e7d05eda 100644 --- a/extensions/timers/lib.rs +++ b/extensions/timers/lib.rs @@ -45,6 +45,7 @@ pub fn init() -> Extension { .js(include_js_files!( prefix "deno:extensions/timers", "01_timers.js", + "02_performance.js", )) .ops(vec![ ("op_global_timer_stop", op_sync(op_global_timer_stop)), diff --git a/extensions/web/02_structured_clone.js b/extensions/web/02_structured_clone.js new file mode 100644 index 0000000000..2170095d9d --- /dev/null +++ b/extensions/web/02_structured_clone.js @@ -0,0 +1,73 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +// @ts-check +/// +/// +/// + +"use strict"; + +((window) => { + const core = window.Deno.core; + + const objectCloneMemo = new WeakMap(); + + function cloneArrayBuffer( + srcBuffer, + srcByteOffset, + srcLength, + _cloneConstructor, + ) { + // this function fudges the return type but SharedArrayBuffer is disabled for a while anyway + return srcBuffer.slice( + srcByteOffset, + srcByteOffset + srcLength, + ); + } + + /** Clone a value in a similar way to structured cloning. It is similar to a +* StructureDeserialize(StructuredSerialize(...)). */ + function structuredClone(value) { + // Performance optimization for buffers, otherwise + // `serialize/deserialize` will allocate new buffer. + if (value instanceof ArrayBuffer) { + const cloned = cloneArrayBuffer( + value, + 0, + value.byteLength, + ArrayBuffer, + ); + objectCloneMemo.set(value, cloned); + return cloned; + } + if (ArrayBuffer.isView(value)) { + const clonedBuffer = structuredClone(value.buffer); + // Use DataViewConstructor type purely for type-checking, can be a + // DataView or TypedArray. They use the same constructor signature, + // only DataView has a length in bytes and TypedArrays use a length in + // terms of elements, so we adjust for that. + let length; + if (value instanceof DataView) { + length = value.byteLength; + } else { + length = value.length; + } + return new (value.constructor)( + clonedBuffer, + value.byteOffset, + length, + ); + } + + try { + return core.deserialize(core.serialize(value)); + } catch (e) { + if (e instanceof TypeError) { + throw new DOMException("Uncloneable value", "DataCloneError"); + } + throw e; + } + } + + window.__bootstrap.structuredClone = structuredClone; +})(globalThis); diff --git a/extensions/web/lib.rs b/extensions/web/lib.rs index 2f2f159426..95adb822a0 100644 --- a/extensions/web/lib.rs +++ b/extensions/web/lib.rs @@ -33,6 +33,7 @@ pub fn init() -> Extension { "01_dom_exception.js", "01_mimesniff.js", "02_event.js", + "02_structured_clone.js", "03_abort_signal.js", "04_global_interfaces.js", "05_base64.js", diff --git a/runtime/js/01_web_util.js b/runtime/js/01_web_util.js index 5960691eb2..11294a9bb3 100644 --- a/runtime/js/01_web_util.js +++ b/runtime/js/01_web_util.js @@ -17,65 +17,6 @@ } } - const objectCloneMemo = new WeakMap(); - - function cloneArrayBuffer( - srcBuffer, - srcByteOffset, - srcLength, - _cloneConstructor, - ) { - // this function fudges the return type but SharedArrayBuffer is disabled for a while anyway - return srcBuffer.slice( - srcByteOffset, - srcByteOffset + srcLength, - ); - } - - /** Clone a value in a similar way to structured cloning. It is similar to a - * StructureDeserialize(StructuredSerialize(...)). */ - function cloneValue(value) { - // Performance optimization for buffers, otherwise - // `serialize/deserialize` will allocate new buffer. - if (value instanceof ArrayBuffer) { - const cloned = cloneArrayBuffer( - value, - 0, - value.byteLength, - ArrayBuffer, - ); - objectCloneMemo.set(value, cloned); - return cloned; - } - if (ArrayBuffer.isView(value)) { - const clonedBuffer = cloneValue(value.buffer); - // Use DataViewConstructor type purely for type-checking, can be a - // DataView or TypedArray. They use the same constructor signature, - // only DataView has a length in bytes and TypedArrays use a length in - // terms of elements, so we adjust for that. - let length; - if (value instanceof DataView) { - length = value.byteLength; - } else { - length = value.length; - } - return new (value.constructor)( - clonedBuffer, - value.byteOffset, - length, - ); - } - - try { - return Deno.core.deserialize(Deno.core.serialize(value)); - } catch (e) { - if (e instanceof TypeError) { - throw new DOMException("Uncloneable value", "DataCloneError"); - } - throw e; - } - } - const handlerSymbol = Symbol("eventHandlers"); function makeWrappedHandler(handler) { function wrappedHandler(...args) { @@ -114,6 +55,5 @@ illegalConstructorKey, requiredArguments, defineEventHandler, - cloneValue, }; })(this);