Source code
Revision control
Copy as Markdown
Other Tools
// |reftest| shell-option(--enable-float16array)
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
// Summary: Ensure typed array validation is called for TypedArray.prototype.subarray.
const otherGlobal = newGlobal({newCompartment: true});
const typedArrayLengths = [0, 1, 1024];
// Note: subarray uses CallTypedArrayMethodIfWrapped, which results in throwing
// a TypeError from the wrong Realm if cross-compartment. The browser
// runner doesn't support the "newCompartment" option, so it can't create
// cross-compartment globals, which means it throws the error from the
// correct Realm.
const eitherGlobalTypeError = {
[Symbol.hasInstance](obj) {
return obj instanceof TypeError || obj instanceof otherGlobal.TypeError;
}
};
function createTestCases(TAConstructor, constructor, constructorCrossRealm) {
let testCases = [];
testCases.push({
species: constructor,
method: TAConstructor.prototype.subarray,
error: TypeError,
});
testCases.push({
species: constructorCrossRealm,
method: TAConstructor.prototype.subarray,
error: TypeError,
});
testCases.push({
species: constructor,
method: otherGlobal[TAConstructor.name].prototype.subarray,
error: eitherGlobalTypeError,
});
return testCases;
}
// Throws TypeError when the returned value is not a typed array.
for (const TAConstructor of anyTypedArrayConstructors) {
let callCount = 0, expectedCallCount = 0;
function NoTypedArrayConstructor(...args) {
let a = [];
callCount += 1;
return a;
}
function NoTypedArrayConstructorCrossRealm(...args) {
let a = new otherGlobal.Array();
callCount += 1;
return a;
}
let testCases = createTestCases(TAConstructor, NoTypedArrayConstructor, NoTypedArrayConstructorCrossRealm);
for (let {species, method, error} of testCases) {
for (let length of typedArrayLengths) {
let ta = new TAConstructor(length);
ta.constructor = {[Symbol.species]: species};
assertThrowsInstanceOf(() => method.call(ta, 0), error);
assertEq(callCount, ++expectedCallCount);
}
}
for (let {species, method, error} of testCases) {
for (let length of typedArrayLengths) {
let ta = new TAConstructor(length);
ta.constructor = {[Symbol.species]: species};
assertThrowsInstanceOf(() => method.call(ta, 0, 0), error);
assertEq(callCount, ++expectedCallCount);
}
}
}
// Throws TypeError exception when returned array is detached.
if (typeof detachArrayBuffer === "function") {
for (const TAConstructor of typedArrayConstructors) {
let callCount = 0, expectedCallCount = 0;
function DetachConstructor(...args) {
let a = new TAConstructor(...args);
detachArrayBuffer(a.buffer);
callCount += 1;
return a;
}
function DetachConstructorCrossRealm(...args) {
let a = new otherGlobal[TAConstructor.name](...args);
// Note: TypedArray |a| is (currently) created in this global, not
// |otherGlobal|, because a typed array and its buffer must
// use the same compartment.
detachArrayBuffer(a.buffer);
callCount += 1;
return a;
}
let testCases = createTestCases(TAConstructor, DetachConstructor, DetachConstructorCrossRealm);
for (let {species, method, error} of testCases) {
for (let length of typedArrayLengths) {
let ta = new TAConstructor(length);
ta.constructor = {[Symbol.species]: species};
assertThrowsInstanceOf(() => method.call(ta, 0), error);
assertEq(callCount, ++expectedCallCount);
}
}
for (let {species, method, error} of testCases) {
for (let length of typedArrayLengths) {
let ta = new TAConstructor(length);
ta.constructor = {[Symbol.species]: species};
assertThrowsInstanceOf(() => method.call(ta, 0, 0), error);
assertEq(callCount, ++expectedCallCount);
}
}
}
}
if (typeof reportCompare === "function")
reportCompare(0, 0);