[rab/gsab] Add WPT tests for resizable ArrayBuffer
Bug: v8:11111
Change-Id: I531f10cae15dd09e7934ad698acf9dcae225ca4c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4082152
Reviewed-by: Domenic Denicola <domenic@chromium.org>
Commit-Queue: Shu-yu Guo <syg@chromium.org>
Reviewed-by: Mason Freed <masonf@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1086557}
diff --git a/common/sab.js b/common/sab.js
index 47d1297..a3ea610 100644
--- a/common/sab.js
+++ b/common/sab.js
@@ -6,14 +6,14 @@
} catch(e) {
sabConstructor = null;
}
- return (type, length) => {
+ return (type, length, opts) => {
if (type === "ArrayBuffer") {
- return new ArrayBuffer(length);
+ return new ArrayBuffer(length, opts);
} else if (type === "SharedArrayBuffer") {
if (sabConstructor && sabConstructor.name !== "SharedArrayBuffer") {
throw new Error("WebAssembly.Memory does not support shared:true");
}
- return new sabConstructor(length);
+ return new sabConstructor(length, opts);
} else {
throw new Error("type has to be ArrayBuffer or SharedArrayBuffer");
}
diff --git a/html/infrastructure/safe-passing-of-structured-data/messagechannel.any.js b/html/infrastructure/safe-passing-of-structured-data/messagechannel.any.js
index 1814df3..6ba17f7 100644
--- a/html/infrastructure/safe-passing-of-structured-data/messagechannel.any.js
+++ b/html/infrastructure/safe-passing-of-structured-data/messagechannel.any.js
@@ -1,4 +1,5 @@
// META: global=window,worker
+// META: script=/common/sab.js
// META: script=/html/webappapis/structured-clone/structured-clone-battery-of-tests.js
// META: script=/html/webappapis/structured-clone/structured-clone-battery-of-tests-with-transferables.js
// META: script=/html/webappapis/structured-clone/structured-clone-battery-of-tests-harness.js
diff --git a/html/infrastructure/safe-passing-of-structured-data/window-postmessage.window.js b/html/infrastructure/safe-passing-of-structured-data/window-postmessage.window.js
index ebbda99..2a46d79 100644
--- a/html/infrastructure/safe-passing-of-structured-data/window-postmessage.window.js
+++ b/html/infrastructure/safe-passing-of-structured-data/window-postmessage.window.js
@@ -1,3 +1,4 @@
+// META: script=/common/sab.js
// META: script=/html/webappapis/structured-clone/structured-clone-battery-of-tests.js
// META: script=/html/webappapis/structured-clone/structured-clone-battery-of-tests-with-transferables.js
// META: script=/html/webappapis/structured-clone/structured-clone-battery-of-tests-harness.js
diff --git a/html/webappapis/structured-clone/structured-clone-battery-of-tests-with-transferables.js b/html/webappapis/structured-clone/structured-clone-battery-of-tests-with-transferables.js
index 65e4085..23cf4f6 100644
--- a/html/webappapis/structured-clone/structured-clone-battery-of-tests-with-transferables.js
+++ b/html/webappapis/structured-clone/structured-clone-battery-of-tests-with-transferables.js
@@ -97,3 +97,73 @@
assert_equals(Object.getPrototypeOf(transfer), ReadableStream.prototype);
}
});
+
+structuredCloneBatteryOfTests.push({
+ description: 'Resizable ArrayBuffer is transferable',
+ async f(runner) {
+ const buffer = new ArrayBuffer(16, { maxByteLength: 1024 });
+ const copy = await runner.structuredClone(buffer, [buffer]);
+ assert_equals(buffer.byteLength, 0);
+ assert_equals(copy.byteLength, 16);
+ assert_equals(copy.maxByteLength, 1024);
+ assert_true(copy.resizable);
+ }
+});
+
+structuredCloneBatteryOfTests.push({
+ description: 'Length-tracking TypedArray is transferable',
+ async f(runner) {
+ const ab = new ArrayBuffer(16, { maxByteLength: 1024 });
+ const ta = new Uint8Array(ab);
+ const copy = await runner.structuredClone(ta, [ab]);
+ assert_equals(ab.byteLength, 0);
+ assert_equals(copy.buffer.byteLength, 16);
+ assert_equals(copy.buffer.maxByteLength, 1024);
+ assert_true(copy.buffer.resizable);
+ copy.buffer.resize(32);
+ assert_equals(copy.byteLength, 32);
+ }
+});
+
+structuredCloneBatteryOfTests.push({
+ description: 'Length-tracking DataView is transferable',
+ async f(runner) {
+ const ab = new ArrayBuffer(16, { maxByteLength: 1024 });
+ const dv = new DataView(ab);
+ const copy = await runner.structuredClone(dv, [ab]);
+ assert_equals(ab.byteLength, 0);
+ assert_equals(copy.buffer.byteLength, 16);
+ assert_equals(copy.buffer.maxByteLength, 1024);
+ assert_true(copy.buffer.resizable);
+ copy.buffer.resize(32);
+ assert_equals(copy.byteLength, 32);
+ }
+});
+
+structuredCloneBatteryOfTests.push({
+ description: 'Transferring OOB TypedArray throws',
+ async f(runner, t) {
+ const ab = new ArrayBuffer(16, { maxByteLength: 1024 });
+ const ta = new Uint8Array(ab, 8);
+ ab.resize(0);
+ await promise_rejects_dom(
+ t,
+ "DataCloneError",
+ runner.structuredClone(ta, [ab])
+ );
+ }
+});
+
+structuredCloneBatteryOfTests.push({
+ description: 'Transferring OOB DataView throws',
+ async f(runner, t) {
+ const ab = new ArrayBuffer(16, { maxByteLength: 1024 });
+ const dv = new DataView(ab, 8);
+ ab.resize(0);
+ await promise_rejects_dom(
+ t,
+ "DataCloneError",
+ runner.structuredClone(dv, [ab])
+ );
+ }
+});
diff --git a/html/webappapis/structured-clone/structured-clone-battery-of-tests.js b/html/webappapis/structured-clone/structured-clone-battery-of-tests.js
index 580a81a..923ac9d 100644
--- a/html/webappapis/structured-clone/structured-clone-battery-of-tests.js
+++ b/html/webappapis/structured-clone/structured-clone-battery-of-tests.js
@@ -379,6 +379,14 @@
check('Array FileList object, FileList empty', () => ([func_FileList_empty()]), compare_Array(enumerate_props(compare_FileList)), true);
check('Object FileList object, FileList empty', () => ({'x':func_FileList_empty()}), compare_Object(enumerate_props(compare_FileList)), true);
+function compare_ArrayBuffer(actual, input) {
+ assert_true(actual instanceof ArrayBuffer, 'instanceof ArrayBuffer');
+ assert_equals(actual.byteLength, input.byteLength, 'byteLength');
+ assert_equals(actual.maxByteLength, input.maxByteLength, 'maxByteLength');
+ assert_equals(actual.resizable, input.resizable, 'resizable');
+ assert_equals(actual.growable, input.growable, 'growable');
+}
+
function compare_ArrayBufferView(view) {
const Type = self[view];
return function(actual, input) {
@@ -386,6 +394,8 @@
assert_unreached(actual);
assert_true(actual instanceof Type, 'instanceof '+view);
assert_equals(actual.length, input.length, 'length');
+ assert_equals(actual.byteLength, input.byteLength, 'byteLength');
+ assert_equals(actual.byteOffset, input.byteOffset, 'byteOffset');
assert_not_equals(actual.buffer, input.buffer, 'buffer');
for (let i = 0; i < actual.length; ++i) {
assert_equals(actual[i], input[i], 'actual['+i+']');
@@ -667,3 +677,77 @@
assert_equals(Object.getPrototypeOf(copy), File.prototype);
}
);
+
+check(
+ 'Resizable ArrayBuffer',
+ () => {
+ const ab = new ArrayBuffer(16, { maxByteLength: 1024 });
+ assert_true(ab.resizable);
+ return ab;
+ },
+ compare_ArrayBuffer);
+
+structuredCloneBatteryOfTests.push({
+ description: 'Growable SharedArrayBuffer',
+ async f(runner) {
+ const sab = createBuffer('SharedArrayBuffer', 16, { maxByteLength: 1024 });
+ assert_true(sab.growable);
+ try {
+ const copy = await runner.structuredClone(sab);
+ compare_ArrayBuffer(sab, copy);
+ } catch (e) {
+ // If we're cross-origin isolated, cloning SABs should not fail.
+ if (e instanceof DOMException && e.code === DOMException.DATA_CLONE_ERR) {
+ assert_false(self.crossOriginIsolated);
+ } else {
+ throw e;
+ }
+ }
+ }
+});
+
+check(
+ 'Length-tracking TypedArray',
+ () => {
+ const ab = new ArrayBuffer(16, { maxByteLength: 1024 });
+ assert_true(ab.resizable);
+ return new Uint8Array(ab);
+ },
+ compare_ArrayBufferView('Uint8Array'));
+
+check(
+ 'Length-tracking DataView',
+ () => {
+ const ab = new ArrayBuffer(16, { maxByteLength: 1024 });
+ assert_true(ab.resizable);
+ return new DataView(ab);
+ },
+ compare_ArrayBufferView('DataView'));
+
+structuredCloneBatteryOfTests.push({
+ description: 'Serializing OOB TypedArray throws',
+ async f(runner, t) {
+ const ab = new ArrayBuffer(16, { maxByteLength: 1024 });
+ const ta = new Uint8Array(ab, 8);
+ ab.resize(0);
+ await promise_rejects_dom(
+ t,
+ "DataCloneError",
+ runner.structuredClone(ta)
+ );
+ }
+});
+
+structuredCloneBatteryOfTests.push({
+ description: 'Serializing OOB DataView throws',
+ async f(runner, t) {
+ const ab = new ArrayBuffer(16, { maxByteLength: 1024 });
+ const dv = new DataView(ab, 8);
+ ab.resize(0);
+ await promise_rejects_dom(
+ t,
+ "DataCloneError",
+ runner.structuredClone(dv)
+ );
+ }
+});
diff --git a/html/webappapis/structured-clone/structured-clone.any.js b/html/webappapis/structured-clone/structured-clone.any.js
index 90ba5df..1358a71 100644
--- a/html/webappapis/structured-clone/structured-clone.any.js
+++ b/html/webappapis/structured-clone/structured-clone.any.js
@@ -1,4 +1,5 @@
// META: title=structuredClone() tests
+// META: script=/common/sab.js
// META: script=/html/webappapis/structured-clone/structured-clone-battery-of-tests.js
// META: script=/html/webappapis/structured-clone/structured-clone-battery-of-tests-with-transferables.js
// META: script=/html/webappapis/structured-clone/structured-clone-battery-of-tests-harness.js
diff --git a/webidl/ecmascript-binding/allow-resizable.html b/webidl/ecmascript-binding/allow-resizable.html
new file mode 100644
index 0000000..be9df55
--- /dev/null
+++ b/webidl/ecmascript-binding/allow-resizable.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/sab.js"></script>
+<script type="module">
+test(t => {
+ // Fixed-length ABs should not throw
+ const ab = new ArrayBuffer(16);
+ new Response(new Uint8Array(ab));
+
+ const rab = new ArrayBuffer(16, { maxByteLength: 1024 });
+ // Response doesn't have [AllowResizable] or [AllowShared]
+ assert_throws_js(TypeError, () => {
+ new Response(new Uint8Array(rab));
+ });
+}, "APIs without [AllowResizable] throw when passed resizable ArrayBuffers");
+
+test(t => {
+ const enc = new TextEncoder();
+
+ // Fixed-length SABs should not throw
+ const sab = createBuffer('SharedArrayBuffer', 16, { maxByteLength: 1024 });
+ enc.encodeInto("foobar", new Uint8Array(sab));
+
+ const gsab = createBuffer('SharedArrayBuffer', 16, { maxByteLength: 1024 });
+ // TextEncoder.encodeInto doesn't have [AllowResizable] but has [AllowShared]
+ assert_throws_js(TypeError, () => {
+ enc.encodeInto("foobar", new Uint8Array(gsab));
+ });
+}, "APIs with [AllowShared] but without [AllowResizable] throw when passed growable SharedArrayBuffers");
+</script>
diff --git a/workers/semantics/structured-clone/dedicated.html b/workers/semantics/structured-clone/dedicated.html
index 2f1732c..16b6be5 100644
--- a/workers/semantics/structured-clone/dedicated.html
+++ b/workers/semantics/structured-clone/dedicated.html
@@ -2,6 +2,7 @@
<title>structured clone to dedicated worker</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
+<script src=/common/sab.js></script>
<script src=/html/webappapis/structured-clone/structured-clone-battery-of-tests.js></script>
<script src=/html/webappapis/structured-clone/structured-clone-battery-of-tests-with-transferables.js></script>
<script src=/html/webappapis/structured-clone/structured-clone-battery-of-tests-harness.js></script>
diff --git a/workers/semantics/structured-clone/shared.html b/workers/semantics/structured-clone/shared.html
index 793da8f..eb85499 100644
--- a/workers/semantics/structured-clone/shared.html
+++ b/workers/semantics/structured-clone/shared.html
@@ -2,6 +2,7 @@
<title>structured clone to shared worker</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
+<script src=/common/sab.js></script>
<script src=/html/webappapis/structured-clone/structured-clone-battery-of-tests.js></script>
<script src=/html/webappapis/structured-clone/structured-clone-battery-of-tests-with-transferables.js></script>
<script src=/html/webappapis/structured-clone/structured-clone-battery-of-tests-harness.js></script>