blob: 85540bec439dc7a4ba29e337599c310e53871256 [file] [log] [blame]
// 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.
class MyUint8Array extends Uint8Array {};
class MyFloat32Array extends Float32Array {};
class MyBigInt64Array extends BigInt64Array {};
const builtinCtors = [
Uint8Array,
Int8Array,
Uint16Array,
Int16Array,
Uint32Array,
Int32Array,
Float16Array,
Float32Array,
Float64Array,
Uint8ClampedArray,
BigUint64Array,
BigInt64Array
];
const ctors = [
...builtinCtors,
MyUint8Array,
MyFloat32Array,
MyBigInt64Array,
];
const floatCtors = [
Float16Array,
Float32Array,
Float64Array,
MyFloat32Array
];
const intCtors = [
Uint8Array,
Int8Array,
Uint16Array,
Int16Array,
Uint32Array,
Int32Array,
BigUint64Array,
BigInt64Array,
MyUint8Array,
MyBigInt64Array,
];
// Each element of the following array is [getter, setter, size, isBigInt].
const dataViewAccessorsAndSizes = [[DataView.prototype.getUint8,
DataView.prototype.setUint8, 1, false],
[DataView.prototype.getInt8,
DataView.prototype.setInt8, 1, false],
[DataView.prototype.getUint16,
DataView.prototype.setUint16, 2, false],
[DataView.prototype.getInt16,
DataView.prototype.setInt16, 2, false],
[DataView.prototype.getInt32,
DataView.prototype.setInt32, 4, false],
[DataView.prototype.getFloat16,
DataView.prototype.setFloat16, 2, false],
[DataView.prototype.getFloat32,
DataView.prototype.setFloat32, 4, false],
[DataView.prototype.getFloat64,
DataView.prototype.setFloat64, 8, false],
[DataView.prototype.getBigUint64,
DataView.prototype.setBigUint64, 8, true],
[DataView.prototype.getBigInt64,
DataView.prototype.setBigInt64, 8, true]];
function CreateResizableArrayBuffer(byteLength, maxByteLength) {
return new ArrayBuffer(byteLength, {maxByteLength: maxByteLength});
}
function CreateGrowableSharedArrayBuffer(byteLength, maxByteLength) {
return new SharedArrayBuffer(byteLength, {maxByteLength: maxByteLength});
}
function IsBigIntTypedArray(ta) {
return (ta instanceof BigInt64Array) || (ta instanceof BigUint64Array);
}
function AllBigIntMatchedCtorCombinations(test) {
for (let targetCtor of ctors) {
for (let sourceCtor of ctors) {
if (IsBigIntTypedArray(new targetCtor()) !=
IsBigIntTypedArray(new sourceCtor())) {
// Can't mix BigInt and non-BigInt types.
continue;
}
test(targetCtor, sourceCtor);
}
}
}
function AllBigIntUnmatchedCtorCombinations(test) {
for (let targetCtor of ctors) {
for (let sourceCtor of ctors) {
if (IsBigIntTypedArray(new targetCtor()) ==
IsBigIntTypedArray(new sourceCtor())) {
continue;
}
test(targetCtor, sourceCtor);
}
}
}
function ReadDataFromBuffer(ab, ctor) {
let result = [];
const ta = new ctor(ab, 0, ab.byteLength / ctor.BYTES_PER_ELEMENT);
for (let item of ta) {
result.push(Number(item));
}
return result;
}
function WriteToTypedArray(array, index, value) {
if (array instanceof BigInt64Array ||
array instanceof BigUint64Array) {
array[index] = BigInt(value);
} else {
array[index] = value;
}
}
// Also preserves undefined.
function Convert(item) {
if (typeof item == 'bigint') {
return Number(item);
}
return item;
}
function ToNumbers(array) {
let result = [];
for (let item of array) {
result.push(Convert(item));
}
return result;
}
function TypedArrayEntriesHelper(ta) {
return ta.entries();
}
function ArrayEntriesHelper(ta) {
return Array.prototype.entries.call(ta);
}
function ValuesFromTypedArrayEntries(ta) {
let result = [];
let expectedKey = 0;
for (let [key, value] of ta.entries()) {
assertEquals(expectedKey, key);
++expectedKey;
result.push(Number(value));
}
return result;
}
function ValuesFromArrayEntries(ta) {
let result = [];
let expectedKey = 0;
for (let [key, value] of Array.prototype.entries.call(ta)) {
assertEquals(expectedKey, key);
++expectedKey;
result.push(Number(value));
}
return result;
}
function TypedArrayKeysHelper(ta) {
return ta.keys();
}
function ArrayKeysHelper(ta) {
return Array.prototype.keys.call(ta);
}
function TypedArrayValuesHelper(ta) {
return ta.values();
}
function ArrayValuesHelper(ta) {
return Array.prototype.values.call(ta);
}
function ValuesFromTypedArrayValues(ta) {
let result = [];
for (let value of ta.values()) {
result.push(Number(value));
}
return result;
}
function ValuesFromArrayValues(ta) {
const result = [];
for (let value of Array.prototype.values.call(ta)) {
result.push(Number(value));
}
return result;
}
function TypedArrayAtHelper(ta, index) {
const result = ta.at(index);
return Convert(result);
}
function ArrayAtHelper(ta, index) {
const result = Array.prototype.at.call(ta, index);
return Convert(result);
}
function TypedArrayFillHelper(ta, n, start, end) {
if (ta instanceof BigInt64Array || ta instanceof BigUint64Array) {
ta.fill(BigInt(n), start, end);
} else {
ta.fill(n, start, end);
}
}
function ArrayFillHelper(ta, n, start, end) {
if (ta instanceof BigInt64Array || ta instanceof BigUint64Array) {
Array.prototype.fill.call(ta, BigInt(n), start, end);
} else {
Array.prototype.fill.call(ta, n, start, end);
}
}
function TypedArrayFindHelper(ta, p) {
return ta.find(p);
}
function ArrayFindHelper(ta, p) {
return Array.prototype.find.call(ta, p);
}
function TypedArrayFindIndexHelper(ta, p) {
return ta.findIndex(p);
}
function ArrayFindIndexHelper(ta, p) {
return Array.prototype.findIndex.call(ta, p);
}
function TypedArrayFindLastHelper(ta, p) {
return ta.findLast(p);
}
function ArrayFindLastHelper(ta, p) {
return Array.prototype.findLast.call(ta, p);
}
function TypedArrayFindLastIndexHelper(ta, p) {
return ta.findLastIndex(p);
}
function ArrayFindLastIndexHelper(ta, p) {
return Array.prototype.findLastIndex.call(ta, p);
}
function TypedArrayIncludesHelper(array, n, fromIndex) {
if (typeof n == 'number' &&
(array instanceof BigInt64Array || array instanceof BigUint64Array)) {
return array.includes(BigInt(n), fromIndex);
}
return array.includes(n, fromIndex);
}
function ArrayIncludesHelper(array, n, fromIndex) {
if (typeof n == 'number' &&
(array instanceof BigInt64Array || array instanceof BigUint64Array)) {
return Array.prototype.includes.call(array, BigInt(n), fromIndex);
}
return Array.prototype.includes.call(array, n, fromIndex);
}
function TypedArrayIndexOfHelper(ta, n, fromIndex) {
if (typeof n == 'number' &&
(ta instanceof BigInt64Array || ta instanceof BigUint64Array)) {
if (fromIndex == undefined) {
// Technically, passing fromIndex here would still result in the correct
// behavior, since "undefined" gets converted to 0 which is a good
// "default" index. This is to test the "only 1 argument passed" code
// path, too.
return ta.indexOf(BigInt(n));
}
return ta.indexOf(BigInt(n), fromIndex);
}
if (fromIndex == undefined) {
return ta.indexOf(n);
}
return ta.indexOf(n, fromIndex);
}
function ArrayIndexOfHelper(ta, n, fromIndex) {
if (typeof n == 'number' &&
(ta instanceof BigInt64Array || ta instanceof BigUint64Array)) {
if (fromIndex == undefined) {
// Technically, passing fromIndex here would still result in the correct
// behavior, since "undefined" gets converted to 0 which is a good
// "default" index. This is to test the "only 1 argument passed" code
// path, too.
return Array.prototype.indexOf.call(ta, BigInt(n));
}
return Array.prototype.indexOf.call(ta, BigInt(n), fromIndex);
}
if (fromIndex == undefined) {
return Array.prototype.indexOf.call(ta, n);
}
return Array.prototype.indexOf.call(ta, n, fromIndex);
}
function TypedArrayLastIndexOfHelper(ta, n, fromIndex) {
if (typeof n == 'number' &&
(ta instanceof BigInt64Array || ta instanceof BigUint64Array)) {
if (fromIndex == undefined) {
// Shouldn't pass fromIndex here, since passing "undefined" is not the
// same as not passing the parameter at all. "Undefined" will get
// converted to 0 which is not a good "default" index, since lastIndexOf
// iterates from the index downwards.
return ta.lastIndexOf(BigInt(n));
}
return ta.lastIndexOf(BigInt(n), fromIndex);
}
if (fromIndex == undefined) {
return ta.lastIndexOf(n);
}
return ta.lastIndexOf(n, fromIndex);
}
function ArrayLastIndexOfHelper(ta, n, fromIndex) {
if (typeof n == 'number' &&
(ta instanceof BigInt64Array || ta instanceof BigUint64Array)) {
if (fromIndex == undefined) {
// Shouldn't pass fromIndex here, since passing "undefined" is not the
// same as not passing the parameter at all. "Undefined" will get
// converted to 0 which is not a good "default" index, since lastIndexOf
// iterates from the index downwards.
return Array.prototype.lastIndexOf.call(ta, BigInt(n));
}
return Array.prototype.lastIndexOf.call(ta, BigInt(n), fromIndex);
}
if (fromIndex == undefined) {
return Array.prototype.lastIndexOf.call(ta, n);
}
return Array.prototype.lastIndexOf.call(ta, n, fromIndex);
}
function SetHelper(target, source, offset) {
if (target instanceof BigInt64Array || target instanceof BigUint64Array) {
const bigIntSource = [];
for (s of source) {
bigIntSource.push(BigInt(s));
}
source = bigIntSource;
}
if (offset == undefined) {
return target.set(source);
}
return target.set(source, offset);
}
function testDataViewMethodsUpToSize(view, bufferSize) {
for (const [getter, setter, size, isBigInt] of dataViewAccessorsAndSizes) {
for (let i = 0; i <= bufferSize - size; ++i) {
if (isBigInt) {
setter.call(view, i, 3n);
} else {
setter.call(view, i, 3);
}
assertEquals(3, Number(getter.call(view, i)));
}
if (isBigInt) {
assertThrows(() => setter.call(view, bufferSize - size + 1, 0n),
RangeError);
} else {
assertThrows(() => setter.call(view, bufferSize - size + 1, 0),
RangeError);
}
assertThrows(() => getter.call(view, bufferSize - size + 1), RangeError);
}
}
function assertAllDataViewMethodsThrow(view, index, errorType) {
for (const [getter, setter, size, isBigInt] of dataViewAccessorsAndSizes) {
if (isBigInt) {
assertThrows(() => { setter.call(view, index, 3n); }, errorType);
} else {
assertThrows(() => { setter.call(view, index, 3); }, errorType);
}
assertThrows(() => { getter.call(view, index); }, errorType);
}
}
function ObjectDefinePropertyHelper(ta, index, value) {
if (ta instanceof BigInt64Array || ta instanceof BigUint64Array) {
Object.defineProperty(ta, index, {value: BigInt(value)});
} else {
Object.defineProperty(ta, index, {value: value});
}
}
function ObjectDefinePropertiesHelper(ta, index, value) {
const values = {};
if (ta instanceof BigInt64Array || ta instanceof BigUint64Array) {
values[index] = {value: BigInt(value)};
} else {
values[index] = {value: value};
}
Object.defineProperties(ta, values);
}
function TestAtomicsOperations(ta, index) {
const one = IsBigIntTypedArray(ta) ? 1n : 1;
const two = IsBigIntTypedArray(ta) ? 2n : 2;
const three = IsBigIntTypedArray(ta) ? 3n : 3;
Atomics.store(ta, index, one);
assertEquals(one, Atomics.load(ta, index));
assertEquals(one, Atomics.exchange(ta, index, two));
assertEquals(two, Atomics.load(ta, index));
assertEquals(two, Atomics.compareExchange(ta, index, two, three));
assertEquals(three, Atomics.load(ta, index));
assertEquals(three, Atomics.sub(ta, index, two)); // 3 - 2 = 1
assertEquals(one, Atomics.load(ta, index));
assertEquals(one, Atomics.add(ta, index, one)); // 1 + 1 = 2
assertEquals(two, Atomics.load(ta, index));
assertEquals(two, Atomics.or(ta, index, one)); // 2 | 1 = 3
assertEquals(three, Atomics.load(ta, index));
assertEquals(three, Atomics.xor(ta, index, one)); // 3 ^ 1 = 2
assertEquals(two, Atomics.load(ta, index));
assertEquals(two, Atomics.and(ta, index, three)); // 2 & 3 = 2
assertEquals(two, Atomics.load(ta, index));
}
function AssertAtomicsOperationsThrow(ta, index, error) {
const one = IsBigIntTypedArray(ta) ? 1n : 1;
assertThrows(() => { Atomics.store(ta, index, one); }, error);
assertThrows(() => { Atomics.load(ta, index); }, error);
assertThrows(() => { Atomics.exchange(ta, index, one); }, error);
assertThrows(() => { Atomics.compareExchange(ta, index, one, one); },
error);
assertThrows(() => { Atomics.add(ta, index, one); }, error);
assertThrows(() => { Atomics.sub(ta, index, one); }, error);
assertThrows(() => { Atomics.and(ta, index, one); }, error);
assertThrows(() => { Atomics.or(ta, index, one); }, error);
assertThrows(() => { Atomics.xor(ta, index, one); }, error);
}
const TypedArrayCopyWithinHelper = (ta, ...rest) => { ta.copyWithin(...rest); };
const ArrayCopyWithinHelper = (ta, ...rest) => {
Array.prototype.copyWithin.call(ta, ...rest); };
const TypedArrayReverseHelper = (ta) => { ta.reverse(); }
const ArrayReverseHelper = (ta) => { Array.prototype.reverse.call(ta); };
const TypedArraySortHelper = (ta, ...rest) => { ta.sort(...rest); }
const ArraySortHelper = (ta, ...rest) => {
Array.prototype.sort.call(ta, ...rest); };
const TypedArraySliceHelper = (ta, ...rest) => { return ta.slice(...rest); }
const ArraySliceHelper = (ta, ...rest) => {
return Array.prototype.slice.call(ta, ...rest); };
const ArrayFlatHelper = (ta, ...rest) => {
return Array.prototype.flat.call(ta, ...rest); };
const ArrayFlatMapHelper = (ta, ...rest) => {
return Array.prototype.flatMap.call(ta, ...rest); };
const TypedArrayJoinHelper = (ta, ...rest) => { return ta.join(...rest); }
const ArrayJoinHelper = (ta, ...rest) => {
return Array.prototype.join.call(ta, ...rest); };
const TypedArrayToLocaleStringHelper = (ta, ...rest) => {
return ta.toLocaleString(...rest); }
const ArrayToLocaleStringHelper = (ta, ...rest) => {
return Array.prototype.toLocaleString.call(ta, ...rest); };
const TypedArrayForEachHelper = (ta, ...rest) => {
return ta.forEach(...rest); }
const ArrayForEachHelper = (ta, ...rest) => {
return Array.prototype.forEach.call(ta, ...rest); };
const TypedArrayReduceHelper = (ta, ...rest) => {
return ta.reduce(...rest); }
const ArrayReduceHelper = (ta, ...rest) => {
return Array.prototype.reduce.call(ta, ...rest); };
const TypedArrayReduceRightHelper = (ta, ...rest) => {
return ta.reduceRight(...rest); }
const ArrayReduceRightHelper = (ta, ...rest) => {
return Array.prototype.reduceRight.call(ta, ...rest); };
const TypedArrayFilterHelper = (ta, ...rest) => {
return ta.filter(...rest); }
const ArrayFilterHelper = (ta, ...rest) => {
return Array.prototype.filter.call(ta, ...rest); };
const TypedArrayMapHelper = (ta, ...rest) => {
return ta.map(...rest); };
const ArrayMapHelper = (ta, ...rest) => {
return Array.prototype.map.call(ta, ...rest); };
const TypedArrayEveryHelper = (ta, ...rest) => {
return ta.every(...rest); };
const ArrayEveryHelper = (ta, ...rest) => {
return Array.prototype.every.call(ta, ...rest); };
const TypedArraySomeHelper = (ta, ...rest) => {
return ta.some(...rest); };
const ArraySomeHelper = (ta, ...rest) => {
return Array.prototype.some.call(ta, ...rest); };