// 22.2.4.5 TypedArray ( buffer [ , byteOffset [ , length ] ] ) // Ensure the various error conditions are tested in the correct order. const otherGlobal = newGlobal(); function* createBuffers(lengths = [0, 8]) { for (let length of lengths) { let buffer = new ArrayBuffer(length); yield {buffer, detach: () => detachArrayBuffer(buffer)}; } for (let length of lengths) { let buffer = new otherGlobal.ArrayBuffer(length); yield {buffer, detach: () => otherGlobal.detachArrayBuffer(buffer)}; } } const poisonedValue = new Proxy({}, new Proxy({}, { get() { // Throws an exception when any proxy trap is invoked. throw new Error("Poisoned Value"); } })); class ExpectedError extends Error { } function ConstructorWithThrowingPrototype(detach) { return Object.defineProperty(function(){}.bind(null), "prototype", { get() { if (detach) detach(); throw new ExpectedError(); } }); } function ValueThrowing(detach) { return { valueOf() { if (detach) detach(); throw new ExpectedError(); } }; } function ValueReturning(value, detach) { return { valueOf() { if (detach) detach(); return value; } }; } // Ensure step 4 |AllocateTypedArray| is executed before step 6 |ToIndex(byteOffset)|. for (let {buffer} of createBuffers()) { let constructor = ConstructorWithThrowingPrototype(); assertThrowsInstanceOf(() => Reflect.construct(Int32Array, [buffer, poisonedValue, 0], constructor), ExpectedError); } // Ensure step 4 |AllocateTypedArray| is executed before step 9 |IsDetachedBuffer(buffer)|. for (let {buffer, detach} of createBuffers()) { let constructor = ConstructorWithThrowingPrototype(); detach(); assertThrowsInstanceOf(() => Reflect.construct(Int32Array, [buffer, 0, 0], constructor), ExpectedError); } // Ensure step 4 |AllocateTypedArray| is executed before step 9 |IsDetachedBuffer(buffer)|. // - Variant: Detach buffer dynamically. for (let {buffer, detach} of createBuffers()) { let constructor = ConstructorWithThrowingPrototype(detach); assertThrowsInstanceOf(() => Reflect.construct(Int32Array, [buffer, 0, 0], constructor), ExpectedError); } // Ensure step 4 |AllocateTypedArray| is executed before step 8.a |ToIndex(length)|. for (let {buffer} of createBuffers()) { let constructor = ConstructorWithThrowingPrototype(); assertThrowsInstanceOf(() => Reflect.construct(Int32Array, [buffer, 0, poisonedValue], constructor), ExpectedError); } // Ensure step 6 |ToIndex(byteOffset)| is executed before step 9 |IsDetachedBuffer(buffer)|. for (let {buffer, detach} of createBuffers()) { let byteOffset = ValueThrowing(); detach(); assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset, 0), ExpectedError); } // Ensure step 6 |ToIndex(byteOffset)| is executed before step 9 |IsDetachedBuffer(buffer)|. // - Variant: Detach buffer dynamically. for (let {buffer, detach} of createBuffers()) { let byteOffset = ValueThrowing(detach); assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset, 0), ExpectedError); } // Ensure step 6 |ToIndex(byteOffset)| is executed before step 8.a |ToIndex(length)|. for (let {buffer} of createBuffers()) { let byteOffset = ValueThrowing(); assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset, poisonedValue), ExpectedError); } // Ensure step 7 |offset modulo elementSize ≠ 0| is executed before step 9 |IsDetachedBuffer(buffer)|. for (let {buffer, detach} of createBuffers()) { let byteOffset = 1; detach(); assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset, 0), RangeError); } // Ensure step 7 |offset modulo elementSize ≠ 0| is executed before step 9 |IsDetachedBuffer(buffer)|. // - Variant: Detach buffer dynamically. for (let {buffer, detach} of createBuffers()) { let byteOffset = ValueReturning(1, detach); assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset, 0), RangeError); } // Ensure step 7 |offset modulo elementSize ≠ 0| is executed before step 8.a |ToIndex(length)|. for (let {buffer} of createBuffers()) { assertThrowsInstanceOf(() => new Int32Array(buffer, 1, poisonedValue), RangeError); } // Ensure step 8.a |ToIndex(length)| is executed before step 9 |IsDetachedBuffer(buffer)|. for (let {buffer, detach} of createBuffers()) { let byteOffset = 0; let length = ValueThrowing(); detach(); assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset, length), ExpectedError); } // Ensure step 8.a |ToIndex(length)| is executed before step 9 |IsDetachedBuffer(buffer)|. // - Variant: Detach buffer dynamically (1). for (let {buffer, detach} of createBuffers()) { let byteOffset = ValueReturning(0, detach); let length = ValueThrowing(); assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset, length), ExpectedError); } // Ensure step 8.a |ToIndex(length)| is executed before step 9 |IsDetachedBuffer(buffer)|. // - Variant: Detach buffer dynamically (2). for (let {buffer, detach} of createBuffers()) { let byteOffset = 0; let length = ValueThrowing(detach); assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset, length), ExpectedError); } // Ensure step 9 |IsDetachedBuffer(buffer)| is executed before step 11.a |bufferByteLength modulo elementSize ≠ 0|. for (let {buffer, detach} of createBuffers([1, 9])) { let byteOffset = 0; detach(); assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset), TypeError); } // Ensure step 9 |IsDetachedBuffer(buffer)| is executed before step 11.a |bufferByteLength modulo elementSize ≠ 0|. // - Variant: Detach buffer dynamically. for (let {buffer, detach} of createBuffers([1, 9])) { let byteOffset = ValueReturning(0, detach); assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset), TypeError); } // Ensure step 9 |IsDetachedBuffer(buffer)| is executed before step 11.c |newByteLength < 0|. for (let {buffer, detach} of createBuffers()) { let byteOffset = 64; detach(); assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset), TypeError); } // Ensure step 9 |IsDetachedBuffer(buffer)| is executed before step 11.c |newByteLength < 0|. // - Variant: Detach buffer dynamically. for (let {buffer, detach} of createBuffers()) { let byteOffset = ValueReturning(64, detach); assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset), TypeError); } // Ensure step 9 |IsDetachedBuffer(buffer)| is executed before step 12.b |offset+newByteLength > bufferByteLength|. // - Case A: The given byteOffset is too large. for (let {buffer, detach} of createBuffers()) { let byteOffset = 64; let length = ValueReturning(0, detach); assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset, length), TypeError); } // Ensure step 9 |IsDetachedBuffer(buffer)| is executed before step 12.b |offset+newByteLength > bufferByteLength|. // - Case B: The given length is too large. for (let {buffer, detach} of createBuffers()) { let byteOffset = 0; let length = ValueReturning(64, detach); assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset, length), TypeError); } // Ensure we handle the case when ToIndex(byteOffset) detaches the array buffer. for (let {buffer, detach} of createBuffers()) { let byteOffset = ValueReturning(0, detach); let length = 0; assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset, length), TypeError); } // Ensure we handle the case when ToIndex(length) detaches the array buffer. for (let {buffer, detach} of createBuffers()) { let byteOffset = 0; let length = ValueReturning(0, detach); assertThrowsInstanceOf(() => new Int32Array(buffer, byteOffset, length), TypeError); } if (typeof reportCompare === "function") reportCompare(true, true);