summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKenta Moriuchi <moriken@kimamass.com>2023-01-29 23:15:01 +0900
committerGitHub <noreply@github.com>2023-01-29 15:15:01 +0100
commit266915d5ce354fde12b20f8f5ceb5ffdfacb7983 (patch)
tree8787d5b36ede178cd691492c5fdaab6b686b9f5f
parent04ba709b6ec994fd084e0d09ff9edc9df3a1eefc (diff)
fix(ext): internal `structuredClone` for `ArrayBuffer` and `TypedArray` subclasses (#17431)
-rw-r--r--cli/tests/unit/performance_test.ts26
-rw-r--r--cli/tests/unit/test_util.ts1
-rw-r--r--core/internal.d.ts23
-rw-r--r--ext/console/02_console.js6
-rw-r--r--ext/web/02_structured_clone.js94
-rw-r--r--ext/webidl/00_webidl.js8
6 files changed, 133 insertions, 25 deletions
diff --git a/cli/tests/unit/performance_test.ts b/cli/tests/unit/performance_test.ts
index a7dab5f9e..3211bb415 100644
--- a/cli/tests/unit/performance_test.ts
+++ b/cli/tests/unit/performance_test.ts
@@ -2,6 +2,7 @@
import {
assert,
assertEquals,
+ assertNotStrictEquals,
assertStringIncludes,
assertThrows,
deferred,
@@ -50,6 +51,31 @@ Deno.test(function performanceMark() {
assert(markEntries[markEntries.length - 1] === mark);
});
+Deno.test(function performanceMarkDetail() {
+ const detail = { foo: "foo" };
+ const mark = performance.mark("test", { detail });
+ assert(mark instanceof PerformanceMark);
+ assertEquals(mark.detail, { foo: "foo" });
+ assertNotStrictEquals(mark.detail, detail);
+});
+
+Deno.test(function performanceMarkDetailArrayBuffer() {
+ const detail = new ArrayBuffer(10);
+ const mark = performance.mark("test", { detail });
+ assert(mark instanceof PerformanceMark);
+ assertEquals(mark.detail, new ArrayBuffer(10));
+ assertNotStrictEquals(mark.detail, detail);
+});
+
+Deno.test(function performanceMarkDetailSubTypedArray() {
+ class SubUint8Array extends Uint8Array {}
+ const detail = new SubUint8Array([1, 2]);
+ const mark = performance.mark("test", { detail });
+ assert(mark instanceof PerformanceMark);
+ assertEquals(mark.detail, new Uint8Array([1, 2]));
+ assertNotStrictEquals(mark.detail, detail);
+});
+
Deno.test(function performanceMeasure() {
const markName1 = "mark1";
const measureName1 = "measure1";
diff --git a/cli/tests/unit/test_util.ts b/cli/tests/unit/test_util.ts
index dc7f698c5..64c399b2d 100644
--- a/cli/tests/unit/test_util.ts
+++ b/cli/tests/unit/test_util.ts
@@ -9,6 +9,7 @@ export {
assertFalse,
assertMatch,
assertNotEquals,
+ assertNotStrictEquals,
assertRejects,
assertStrictEquals,
assertStringIncludes,
diff --git a/core/internal.d.ts b/core/internal.d.ts
index efe6ed8a8..004e068ff 100644
--- a/core/internal.d.ts
+++ b/core/internal.d.ts
@@ -255,8 +255,11 @@ declare namespace __bootstrap {
export const ArrayBuffer: typeof globalThis.ArrayBuffer;
export const ArrayBufferLength: typeof ArrayBuffer.length;
export const ArrayBufferName: typeof ArrayBuffer.name;
- export const ArrayBufferPrototype: typeof ArrayBuffer.prototype;
export const ArrayBufferIsView: typeof ArrayBuffer.isView;
+ export const ArrayBufferPrototype: typeof ArrayBuffer.prototype;
+ export const ArrayBufferPrototypeGetByteLength: (
+ buffer: ArrayBuffer,
+ ) => number;
export const ArrayBufferPrototypeSlice: UncurryThis<
typeof ArrayBuffer.prototype.slice
>;
@@ -301,6 +304,11 @@ declare namespace __bootstrap {
export const DataViewLength: typeof DataView.length;
export const DataViewName: typeof DataView.name;
export const DataViewPrototype: typeof DataView.prototype;
+ export const DataViewPrototypeGetBuffer: (
+ view: DataView,
+ ) => ArrayBuffer | SharedArrayBuffer;
+ export const DataViewPrototypeGetByteLength: (view: DataView) => number;
+ export const DataViewPrototypeGetByteOffset: (view: DataView) => number;
export const DataViewPrototypeGetInt8: UncurryThis<
typeof DataView.prototype.getInt8
>;
@@ -979,6 +987,19 @@ declare namespace __bootstrap {
constructor: Uint8ArrayConstructor,
arrayLike: ArrayLike<number>,
) => Uint8Array;
+ export const TypedArrayPrototypeGetBuffer: (
+ array: Uint8Array,
+ ) => ArrayBuffer | SharedArrayBuffer;
+ export const TypedArrayPrototypeGetByteLength: (
+ array: Uint8Array,
+ ) => number;
+ export const TypedArrayPrototypeGetByteOffset: (
+ array: Uint8Array,
+ ) => number;
+ export const TypedArrayPrototypeGetLength: (array: Uint8Array) => number;
+ export const TypedArrayPrototypeGetSymbolToStringTag: (
+ v: unknown,
+ ) => string | undefined;
export const TypedArrayPrototypeCopyWithin: UncurryThis<
typeof Uint8Array.prototype.copyWithin
>;
diff --git a/ext/console/02_console.js b/ext/console/02_console.js
index 9b898a040..1720fe7e2 100644
--- a/ext/console/02_console.js
+++ b/ext/console/02_console.js
@@ -8,11 +8,9 @@
const core = window.Deno.core;
const colors = window.__bootstrap.colors;
const {
- ArrayBufferIsView,
AggregateErrorPrototype,
ArrayPrototypeUnshift,
isNaN,
- DataViewPrototype,
DatePrototype,
DateNow,
DatePrototypeGetTime,
@@ -114,6 +112,7 @@
ReflectGetPrototypeOf,
ReflectHas,
TypedArrayPrototypeGetLength,
+ TypedArrayPrototypeGetSymbolToStringTag,
WeakMapPrototype,
WeakSetPrototype,
} = window.__bootstrap.primordials;
@@ -144,8 +143,7 @@
// Forked from Node's lib/internal/cli_table.js
function isTypedArray(x) {
- return ArrayBufferIsView(x) &&
- !ObjectPrototypeIsPrototypeOf(DataViewPrototype, x);
+ return TypedArrayPrototypeGetSymbolToStringTag(x) !== undefined;
}
const tableChars = {
diff --git a/ext/web/02_structured_clone.js b/ext/web/02_structured_clone.js
index f8a88a7ef..793cb1c75 100644
--- a/ext/web/02_structured_clone.js
+++ b/ext/web/02_structured_clone.js
@@ -14,13 +14,32 @@
const {
ArrayBuffer,
ArrayBufferPrototype,
+ ArrayBufferPrototypeGetByteLength,
+ ArrayBufferPrototypeSlice,
ArrayBufferIsView,
- DataViewPrototype,
+ DataView,
+ DataViewPrototypeGetBuffer,
+ DataViewPrototypeGetByteLength,
+ DataViewPrototypeGetByteOffset,
ObjectPrototypeIsPrototypeOf,
- TypedArrayPrototypeSlice,
+ TypedArrayPrototypeGetBuffer,
+ TypedArrayPrototypeGetByteOffset,
+ TypedArrayPrototypeGetLength,
+ TypedArrayPrototypeGetSymbolToStringTag,
TypeErrorPrototype,
WeakMap,
WeakMapPrototypeSet,
+ Int8Array,
+ Int16Array,
+ Int32Array,
+ BigInt64Array,
+ Uint8Array,
+ Uint8ClampedArray,
+ Uint16Array,
+ Uint32Array,
+ BigUint64Array,
+ Float32Array,
+ Float64Array,
} = window.__bootstrap.primordials;
const objectCloneMemo = new WeakMap();
@@ -32,14 +51,15 @@
_cloneConstructor,
) {
// this function fudges the return type but SharedArrayBuffer is disabled for a while anyway
- return TypedArrayPrototypeSlice(
+ return ArrayBufferPrototypeSlice(
srcBuffer,
srcByteOffset,
srcByteOffset + srcLength,
);
}
- /** Clone a value in a similar way to structured cloning. It is similar to a
+ // TODO(petamoriken): Resizable ArrayBuffer support in the future
+ /** 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
@@ -48,28 +68,64 @@
const cloned = cloneArrayBuffer(
value,
0,
- value.byteLength,
+ ArrayBufferPrototypeGetByteLength(value),
ArrayBuffer,
);
WeakMapPrototypeSet(objectCloneMemo, value, cloned);
return cloned;
}
+
if (ArrayBufferIsView(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 (ObjectPrototypeIsPrototypeOf(DataViewPrototype, view)) {
- length = value.byteLength;
- } else {
- length = value.length;
+ const tag = TypedArrayPrototypeGetSymbolToStringTag(value);
+ // DataView
+ if (tag === undefined) {
+ return new DataView(
+ structuredClone(DataViewPrototypeGetBuffer(value)),
+ DataViewPrototypeGetByteOffset(value),
+ DataViewPrototypeGetByteLength(value),
+ );
+ }
+ // TypedArray
+ let Constructor;
+ switch (tag) {
+ case "Int8Array":
+ Constructor = Int8Array;
+ break;
+ case "Int16Array":
+ Constructor = Int16Array;
+ break;
+ case "Int32Array":
+ Constructor = Int32Array;
+ break;
+ case "BigInt64Array":
+ Constructor = BigInt64Array;
+ break;
+ case "Uint8Array":
+ Constructor = Uint8Array;
+ break;
+ case "Uint8ClampedArray":
+ Constructor = Uint8ClampedArray;
+ break;
+ case "Uint16Array":
+ Constructor = Uint16Array;
+ break;
+ case "Uint32Array":
+ Constructor = Uint32Array;
+ break;
+ case "BigUint64Array":
+ Constructor = BigUint64Array;
+ break;
+ case "Float32Array":
+ Constructor = Float32Array;
+ break;
+ case "Float64Array":
+ Constructor = Float64Array;
+ break;
}
- return new (value.constructor)(
- clonedBuffer,
- value.byteOffset,
- length,
+ return new Constructor(
+ structuredClone(TypedArrayPrototypeGetBuffer(value)),
+ TypedArrayPrototypeGetByteOffset(value),
+ TypedArrayPrototypeGetLength(value),
);
}
diff --git a/ext/webidl/00_webidl.js b/ext/webidl/00_webidl.js
index 4127d24bf..bb90d973e 100644
--- a/ext/webidl/00_webidl.js
+++ b/ext/webidl/00_webidl.js
@@ -77,6 +77,7 @@
Symbol,
SymbolIterator,
SymbolToStringTag,
+ TypedArrayPrototypeGetSymbolToStringTag,
TypeError,
Uint16Array,
Uint32Array,
@@ -442,6 +443,11 @@
return V;
}
+ function isDataView(V) {
+ return ArrayBufferIsView(V) &&
+ TypedArrayPrototypeGetSymbolToStringTag(V) === undefined;
+ }
+
function isNonSharedArrayBuffer(V) {
return ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, V);
}
@@ -467,7 +473,7 @@
};
converters.DataView = (V, opts = {}) => {
- if (!(ObjectPrototypeIsPrototypeOf(DataViewPrototype, V))) {
+ if (!isDataView(V)) {
throw makeException(TypeError, "is not a DataView", opts);
}