v8/test/mjsunit/resizablearraybuffer-growablesharedarraybuffer.js
Marja Hölttä 6207d61ff8 [rab/gsab] Update to the new spec
- Remove ResizableArrayBuffer / GrowableSharedArrayBuffer constructors,
use options bags
- Add AB.prototype.resizable and SAB.prototype.growable
- Update receiver checks in (S?)AB.prototype methods

Bug: v8:11111
Change-Id: I4f8cb71a4c8e07483a3ffad83d98129da162b839
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3021174
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: Shu-yu Guo <syg@chromium.org>
Commit-Queue: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#75761}
2021-07-16 13:41:31 +00:00

546 lines
16 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-rab-gsab --allow-natives-syntax
"use strict";
function CreateResizableArrayBuffer(byteLength, maxByteLength) {
return new ArrayBuffer(byteLength, {maxByteLength: maxByteLength});
}
function CreateGrowableSharedArrayBuffer(byteLength, maxByteLength) {
return new SharedArrayBuffer(byteLength, {maxByteLength: maxByteLength});
}
function resizeHelper(ab, value) {
const return_value = ab.resize(value);
assertEquals(undefined, return_value);
assertEquals(value, ab.byteLength);
}
function growHelper(ab, value) {
const return_value = ab.grow(value);
assertEquals(undefined, return_value);
assertEquals(value, ab.byteLength);
}
(function TestRABBasics() {
const rab = CreateResizableArrayBuffer(10, 20);
assertTrue(rab instanceof ArrayBuffer);
assertFalse(rab instanceof SharedArrayBuffer);
assertEquals(10, rab.byteLength);
assertEquals(20, rab.maxByteLength);
})();
(function TestRABCtorByteLengthEqualsMax() {
const rab = CreateResizableArrayBuffer(10, 10);
assertEquals(10, rab.byteLength);
assertEquals(10, rab.maxByteLength);
})();
(function TestRABCtorByteLengthZero() {
const rab = CreateResizableArrayBuffer(0, 10);
assertEquals(0, rab.byteLength);
assertEquals(10, rab.maxByteLength);
})();
(function TestRABCtorByteLengthAndMaxZero() {
const rab = CreateResizableArrayBuffer(0, 0);
assertEquals(0, rab.byteLength);
assertEquals(0, rab.maxByteLength);
})();
const ctors = [[ArrayBuffer, (b) => b.resizable],
[SharedArrayBuffer, (b) => b.growable]];
(function TestOptionsBagNotObject() {
for (let [ctor, resizable] of ctors) {
const buffer = new ctor(10, 'this is not an options bag');
assertFalse(resizable(buffer));
}
})();
(function TestOptionsBagMaxByteLengthGetterThrows() {
let evil = {};
Object.defineProperty(evil, 'maxByteLength',
{get: () => { throw new Error('thrown'); }});
for (let [ctor, resizable] of ctors) {
let caught = false;
try {
new ctor(10, evil);
} catch(e) {
assertEquals('thrown', e.message);
caught = true;
}
assertTrue(caught);
}
})();
(function TestMaxByteLengthNonExisting() {
for (let [ctor, resizable] of ctors) {
const buffer = new ctor(10, {});
assertFalse(resizable(buffer));
}
})();
(function TestMaxByteLengthUndefinedOrNan() {
for (let [ctor, resizable] of ctors) {
const buffer1 = new ctor(10, {maxByteLength: undefined});
assertFalse(resizable(buffer1));
const buffer2 = new ctor(0, {maxByteLength: NaN});
assertTrue(resizable(buffer2));
assertEquals(0, buffer2.byteLength);
assertEquals(0, buffer2.maxByteLength);
}
})();
(function TestMaxByteLengthBooleanNullOrString() {
for (let [ctor, resizable] of ctors) {
const buffer1 = new ctor(0, {maxByteLength: true});
assertTrue(resizable(buffer1));
assertEquals(0, buffer1.byteLength);
assertEquals(1, buffer1.maxByteLength);
const buffer2 = new ctor(0, {maxByteLength: false});
assertTrue(resizable(buffer2));
assertEquals(0, buffer2.byteLength);
assertEquals(0, buffer2.maxByteLength);
const buffer3 = new ctor(0, {maxByteLength: null});
assertTrue(resizable(buffer3));
assertEquals(0, buffer3.byteLength);
assertEquals(0, buffer3.maxByteLength);
const buffer4 = new ctor(0, {maxByteLength: '100'});
assertTrue(resizable(buffer4));
assertEquals(0, buffer4.byteLength);
assertEquals(100, buffer4.maxByteLength);
}
})();
(function TestMaxByteLengthDouble() {
for (let [ctor, resizable] of ctors) {
const buffer1 = new ctor(0, {maxByteLength: -0.0});
assertTrue(resizable(buffer1));
assertEquals(0, buffer1.byteLength);
assertEquals(0, buffer1.maxByteLength);
const buffer2 = new ctor(0, {maxByteLength: -0.1});
assertTrue(resizable(buffer2));
assertEquals(0, buffer2.byteLength);
assertEquals(0, buffer2.maxByteLength);
const buffer3 = new ctor(0, {maxByteLength: 1.2});
assertTrue(resizable(buffer3));
assertEquals(0, buffer3.byteLength);
assertEquals(1, buffer3.maxByteLength);
assertThrows(() => { new ctor(0, {maxByteLength: -1.5}) });
assertThrows(() => { new ctor(0, {maxByteLength: -1}) });
}
})();
(function TestMaxByteLengthThrows() {
const evil = {valueOf: () => { throw new Error('thrown');}};
for (let [ctor, resizable] of ctors) {
let caught = false;
try {
new ctor(0, {maxByteLength: evil});
} catch (e) {
assertEquals('thrown', e.message);
caught = true;
}
assertTrue(caught);
}
})();
(function TestByteLengthThrows() {
const evil1 = {valueOf: () => { throw new Error('byteLength throws');}};
const evil2 = {valueOf: () => { throw new Error('maxByteLength throws');}};
for (let [ctor, resizable] of ctors) {
let caught = false;
try {
new ctor(evil1, {maxByteLength: evil2});
} catch (e) {
assertEquals('byteLength throws', e.message);
caught = true;
}
assertTrue(caught);
}
})();
(function TestAllocatingOutrageouslyMuchThrows() {
assertThrows(() => { CreateResizableArrayBuffer(0, 2 ** 100);}, RangeError);
})();
(function TestRABCtorOperationOrder() {
let log = '';
const mock_length = {valueOf: function() {
log += 'valueof length, '; return 10; }};
const mock_max_length = {valueOf: function() {
log += 'valueof max_length, '; return 10; }};
CreateResizableArrayBuffer(mock_length, mock_max_length);
assertEquals('valueof length, valueof max_length, ', log);
})();
(function TestGSABCtorOperationOrder() {
let log = '';
const mock_length = {valueOf: function() {
log += 'valueof length, '; return 10; }};
const mock_max_length = {valueOf: function() {
log += 'valueof max_length, '; return 10; }};
CreateResizableArrayBuffer(mock_length, mock_max_length);
assertEquals('valueof length, valueof max_length, ', log);
})();
(function TestByteLengthGetterReceiverChecks() {
const name = 'byteLength';
const ab_getter = Object.getOwnPropertyDescriptor(
ArrayBuffer.prototype, name).get;
const sab_getter = Object.getOwnPropertyDescriptor(
SharedArrayBuffer.prototype, name).get;
const ab = new ArrayBuffer(40);
const sab = new SharedArrayBuffer(40);
const rab = CreateResizableArrayBuffer(40, 40);
const gsab = CreateGrowableSharedArrayBuffer(40, 40);
assertEquals(40, ab_getter.call(ab));
assertEquals(40, ab_getter.call(rab));
assertEquals(40, sab_getter.call(sab));
assertEquals(40, sab_getter.call(gsab));
assertThrows(() => { ab_getter.call(sab);});
assertThrows(() => { ab_getter.call(gsab);});
assertThrows(() => { sab_getter.call(ab);});
assertThrows(() => { sab_getter.call(rab);});
})();
(function TestMaxByteLengthGetterReceiverChecks() {
const name = 'maxByteLength';
const ab_getter = Object.getOwnPropertyDescriptor(
ArrayBuffer.prototype, name).get;
const sab_getter = Object.getOwnPropertyDescriptor(
SharedArrayBuffer.prototype, name).get;
const ab = new ArrayBuffer(40);
const sab = new SharedArrayBuffer(40);
const rab = CreateResizableArrayBuffer(20, 40);
const gsab = CreateGrowableSharedArrayBuffer(20, 40);
assertEquals(40, ab_getter.call(ab));
assertEquals(40, ab_getter.call(rab));
assertEquals(40, sab_getter.call(sab));
assertEquals(40, sab_getter.call(gsab));
assertThrows(() => { ab_getter.call(sab);});
assertThrows(() => { ab_getter.call(gsab);});
assertThrows(() => { sab_getter.call(ab);});
assertThrows(() => { sab_getter.call(rab);});
})();
(function TestResizableGetterReceiverChecks() {
const ab_getter = Object.getOwnPropertyDescriptor(
ArrayBuffer.prototype, 'resizable').get;
const sab_getter = Object.getOwnPropertyDescriptor(
SharedArrayBuffer.prototype, 'growable').get;
const ab = new ArrayBuffer(40);
const sab = new SharedArrayBuffer(40);
const rab = CreateResizableArrayBuffer(40, 40);
const gsab = CreateGrowableSharedArrayBuffer(40, 40);
assertEquals(false, ab_getter.call(ab));
assertEquals(true, ab_getter.call(rab));
assertEquals(false, sab_getter.call(sab));
assertEquals(true, sab_getter.call(gsab));
assertThrows(() => { ab_getter.call(sab);});
assertThrows(() => { ab_getter.call(gsab);});
assertThrows(() => { sab_getter.call(ab);});
assertThrows(() => { sab_getter.call(rab);});
})();
(function TestByteLengthAndMaxByteLengthOfDetached() {
const rab = CreateResizableArrayBuffer(10, 20);
%ArrayBufferDetach(rab);
assertEquals(0, rab.byteLength);
assertEquals(0, rab.maxByteLength);
})();
(function TestResizeAndGrowReceiverChecks() {
const rab_resize = ArrayBuffer.prototype.resize;
const gsab_grow = SharedArrayBuffer.prototype.grow;
const ab = new ArrayBuffer(40);
const sab = new SharedArrayBuffer(40);
const rab = CreateResizableArrayBuffer(10, 40);
const gsab = CreateGrowableSharedArrayBuffer(10, 40);
rab_resize.call(rab, 20);
gsab_grow.call(gsab, 20);
assertThrows(() => { rab_resize.call(ab, 30);});
assertThrows(() => { rab_resize.call(sab, 30);});
assertThrows(() => { rab_resize.call(gsab, 30);});
assertThrows(() => { gsab_grow.call(ab, 30);});
assertThrows(() => { gsab_grow.call(sab, 30);});
assertThrows(() => { gsab_grow.call(rab, 30);});
})();
(function TestRABResizeToMax() {
const rab = CreateResizableArrayBuffer(10, 20);
resizeHelper(rab, 20);
})();
(function TestRABResizeToSameSize() {
const rab = CreateResizableArrayBuffer(10, 20);
resizeHelper(rab, 10);
})();
(function TestRABResizeToSmaller() {
const rab = CreateResizableArrayBuffer(10, 20);
resizeHelper(rab, 5);
})();
(function TestRABResizeToZero() {
const rab = CreateResizableArrayBuffer(10, 20);
resizeHelper(rab, 0);
})();
(function TestRABResizeZeroToZero() {
const rab = CreateResizableArrayBuffer(0, 20);
resizeHelper(rab, 0);
})();
(function TestRABGrowBeyondMaxThrows() {
const rab = CreateResizableArrayBuffer(10, 20);
assertEquals(10, rab.byteLength);
assertThrows(() => {rab.grow(21)});
assertEquals(10, rab.byteLength);
})();
(function TestRABResizeMultipleTimes() {
const rab = CreateResizableArrayBuffer(10, 20);
const sizes = [15, 7, 7, 0, 8, 20, 20, 10];
for (let s of sizes) {
resizeHelper(rab, s);
}
})();
(function TestRABResizeParameters() {
const rab = CreateResizableArrayBuffer(10, 20);
rab.resize('15');
assertEquals(15, rab.byteLength);
rab.resize({valueOf: function() { return 16; }});
assertEquals(16, rab.byteLength);
rab.resize(17.9);
assertEquals(17, rab.byteLength);
})();
(function TestRABResizeInvalidParameters() {
const rab = CreateResizableArrayBuffer(10, 20);
assertThrows(() => { rab.resize(-1) }, RangeError);
assertThrows(() => { rab.resize({valueOf: function() {
throw new Error('length param'); }})});
assertEquals(10, rab.byteLength);
// Various non-numbers are converted to NaN which is treated as 0.
rab.resize('string');
assertEquals(0, rab.byteLength);
rab.resize();
assertEquals(0, rab.byteLength);
})();
(function TestRABResizeDetached() {
const rab = CreateResizableArrayBuffer(10, 20);
%ArrayBufferDetach(rab);
assertThrows(() => { rab.resize(15) }, TypeError);
})();
(function DetachInsideResizeParameterConversion() {
const rab = CreateResizableArrayBuffer(40, 80);
const evil = {
valueOf: () => { %ArrayBufferDetach(rab); return 20; }
};
assertThrows(() => { rab.resize(evil); });
})();
(function ResizeInsideResizeParameterConversion() {
const rab = CreateResizableArrayBuffer(40, 80);
const evil = {
valueOf: () => { rab.resize(10); return 20; }
};
rab.resize(evil);
assertEquals(20, rab.byteLength);
})();
(function TestRABNewMemoryAfterResizeInitializedToZero() {
const maybe_page_size = 4096;
const rab = CreateResizableArrayBuffer(maybe_page_size, 2 * maybe_page_size);
const i8a = new Int8Array(rab);
rab.resize(2 * maybe_page_size);
for (let i = 0; i < 2 * maybe_page_size; ++i) {
assertEquals(0, i8a[i]);
}
})();
(function TestRABMemoryInitializedToZeroAfterShrinkAndGrow() {
const maybe_page_size = 4096;
const rab = CreateResizableArrayBuffer(maybe_page_size, 2 * maybe_page_size);
const i8a = new Int8Array(rab);
for (let i = 0; i < maybe_page_size; ++i) {
i8a[i] = 1;
}
rab.resize(maybe_page_size / 2);
rab.resize(maybe_page_size);
for (let i = maybe_page_size / 2; i < maybe_page_size; ++i) {
assertEquals(0, i8a[i]);
}
})();
(function TestGSABBasics() {
const gsab = CreateGrowableSharedArrayBuffer(10, 20);
assertFalse(gsab instanceof ArrayBuffer);
assertTrue(gsab instanceof SharedArrayBuffer);
assertEquals(10, gsab.byteLength);
assertEquals(20, gsab.maxByteLength);
})();
(function TestGSABCtorByteLengthEqualsMax() {
const gsab = CreateGrowableSharedArrayBuffer(10, 10);
assertEquals(10, gsab.byteLength);
assertEquals(10, gsab.maxByteLength);
})();
(function TestGSABCtorByteLengthZero() {
const gsab = CreateGrowableSharedArrayBuffer(0, 10);
assertEquals(0, gsab.byteLength);
assertEquals(10, gsab.maxByteLength);
})();
(function TestGSABCtorByteLengthAndMaxZero() {
const gsab = CreateGrowableSharedArrayBuffer(0, 0);
assertEquals(0, gsab.byteLength);
assertEquals(0, gsab.maxByteLength);
})();
(function TestAllocatingOutrageouslyMuchThrows() {
assertThrows(() => { CreateGrowableSharedArrayBuffer(0, 2 ** 100);},
RangeError);
})();
(function TestGSABGrowToMax() {
const gsab = CreateGrowableSharedArrayBuffer(10, 20);
assertEquals(10, gsab.byteLength);
growHelper(gsab, 20);
})();
(function TestGSABGrowToSameSize() {
const gsab = CreateGrowableSharedArrayBuffer(10, 20);
assertEquals(10, gsab.byteLength);
growHelper(gsab, 10);
})();
(function TestGSABGrowToSmallerThrows() {
const gsab = CreateGrowableSharedArrayBuffer(10, 20);
assertEquals(10, gsab.byteLength);
assertThrows(() => {gsab.grow(5)});
assertEquals(10, gsab.byteLength);
})();
(function TestGSABGrowToZeroThrows() {
const gsab = CreateGrowableSharedArrayBuffer(10, 20);
assertEquals(10, gsab.byteLength);
assertThrows(() => {gsab.grow(0)});
assertEquals(10, gsab.byteLength);
})();
(function TestGSABGrowBeyondMaxThrows() {
const gsab = CreateGrowableSharedArrayBuffer(10, 20);
assertEquals(10, gsab.byteLength);
assertThrows(() => {gsab.grow(21)});
assertEquals(10, gsab.byteLength);
})();
(function TestGSABGrowMultipleTimes() {
const gsab = CreateGrowableSharedArrayBuffer(10, 20);
assertEquals(10, gsab.byteLength);
const sizes = [15, 7, 7, 0, 8, 20, 20, 10];
for (let s of sizes) {
const current_size = gsab.byteLength;
if (s < gsab.byteLength) {
assertThrows(() => {gsab.grow(s)});
assertEquals(current_size, gsab.byteLength);
} else {
growHelper(gsab, s);
}
}
})();
(function TestGSABGrowParameters() {
const gsab = CreateGrowableSharedArrayBuffer(10, 20);
gsab.grow('15');
assertEquals(15, gsab.byteLength);
gsab.grow({valueOf: function() { return 16; }});
assertEquals(16, gsab.byteLength);
gsab.grow(17.9);
assertEquals(17, gsab.byteLength);
})();
(function TestGSABGrowInvalidParameters() {
const gsab = CreateGrowableSharedArrayBuffer(0, 20);
assertThrows(() => { gsab.grow(-1) }, RangeError);
assertThrows(() => { gsab.grow({valueOf: function() {
throw new Error('length param'); }})});
assertEquals(0, gsab.byteLength);
// Various non-numbers are converted to NaN which is treated as 0.
gsab.grow('string');
assertEquals(0, gsab.byteLength);
gsab.grow();
assertEquals(0, gsab.byteLength);
})();
(function TestGSABMemoryInitializedToZeroAfterGrow() {
const maybe_page_size = 4096;
const gsab = CreateGrowableSharedArrayBuffer(maybe_page_size,
2 * maybe_page_size);
const i8a = new Int8Array(gsab);
gsab.grow(2 * maybe_page_size);
assertEquals(2 * maybe_page_size, i8a.length);
for (let i = 0; i < 2 * maybe_page_size; ++i) {
assertEquals(0, i8a[i]);
}
})();
(function GrowGSABOnADifferentThread() {
const gsab = CreateGrowableSharedArrayBuffer(10, 20);
assertEquals(10, gsab.byteLength);
function workerCode() {
function assert(thing) {
if (!thing) {
postMessage('error');
}
}
onmessage = function(params) {
const gsab = params.gsab;
assert(!(gsab instanceof ArrayBuffer));
assert(gsab instanceof SharedArrayBuffer);
assert(10 == gsab.byteLength);
gsab.grow(15);
postMessage('ok');
}
}
const w = new Worker(workerCode, {type: 'function'});
w.postMessage({gsab: gsab});
assertEquals('ok', w.getMessage());
assertEquals(15, gsab.byteLength);
})();