// Copyright 2014 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: --allow-natives-syntax var typedArrayConstructors = [ Uint8Array, Int8Array, Uint16Array, Int16Array, Uint32Array, Int32Array, Uint8ClampedArray, Float32Array, Float64Array]; function CheckTypedArrayIsNeutered(array) { assertEquals(0, array.byteLength); assertEquals(0, array.byteOffset); assertEquals(0, array.length); } function TestTypedArrayForEach(constructor) { assertEquals(1, constructor.prototype.forEach.length); var a = new constructor(2); a[0] = 0; a[1] = 1; var count = 0; a.forEach(function (n) { count++; }); assertEquals(2, count); // Use specified object as this object when calling the function. var o = { value: 42 }; var result = []; a.forEach(function (n, index, array) { result.push(this.value); }, o); assertArrayEquals([42, 42], result); // Modify the original array. count = 0; a.forEach(function (n, index, array) { array[index] = n + 1; count++ }); assertEquals(2, count); assertArrayEquals([1, 2], a); // Check that values passed as second argument are wrapped into // objects when calling into sloppy mode functions. function CheckWrapping(value, wrapper) { var wrappedValue = new wrapper(value); a.forEach(function () { assertEquals("object", typeof this); assertEquals(wrappedValue, this); }, value); a.forEach(function () { "use strict"; assertEquals(typeof value, typeof this); assertEquals(value, this); }, value); } CheckWrapping(true, Boolean); CheckWrapping(false, Boolean); CheckWrapping("xxx", String); CheckWrapping(42, Number); CheckWrapping(3.14, Number); CheckWrapping({}, Object); // Throw before completing iteration, only the first element // should be modified when thorwing mid-way. count = 0; a[0] = 42; a[1] = 42; try { a.forEach(function (n, index, array) { if (count > 0) throw "meh"; array[index] = n + 1; count++; }); } catch (e) { } assertEquals(1, count); assertEquals(43, a[0]); assertEquals(42, a[1]); // Neutering the buffer backing the typed array mid-way should // still make .forEach() finish, but exiting early due to the missing // elements, and the array should keep being empty after detaching it. // TODO(dehrenberg): According to the ES6 spec, accessing or testing // for members on a detached TypedArray should throw, so really this // should throw in the third iteration. However, this behavior matches // the Khronos spec. a = new constructor(3); count = 0; a.forEach(function (n, index, array) { if (count > 0) %ArrayBufferNeuter(array.buffer); array[index] = n + 1; count++; }); assertEquals(2, count); CheckTypedArrayIsNeutered(a); assertEquals(undefined, a[0]); // The method must work for typed arrays created from ArrayBuffer. // The length of the ArrayBuffer is chosen so it is a multiple of // all lengths of the typed array items. a = new constructor(new ArrayBuffer(64)); count = 0; a.forEach(function (n) { count++ }); assertEquals(a.length, count); // Externalizing the array mid-way accessing the .buffer property // should work. a = new constructor(2); count = 0; var buffer = undefined; a.forEach(function (n, index, array) { if (count++ > 0) buffer = array.buffer; }); assertEquals(2, count); assertTrue(!!buffer); assertEquals("ArrayBuffer", %_ClassOf(buffer)); assertSame(buffer, a.buffer); // The %TypedArray%.forEach() method should not work when // transplanted to objects that are not typed arrays. assertThrows(function () { constructor.prototype.forEach.call([1, 2, 3], function (x) {}) }, TypeError); assertThrows(function () { constructor.prototype.forEach.call("abc", function (x) {}) }, TypeError); assertThrows(function () { constructor.prototype.forEach.call({}, function (x) {}) }, TypeError); assertThrows(function () { constructor.prototype.forEach.call(0, function (x) {}) }, TypeError); // Method must be useable on instances of other typed arrays. for (var i = 0; i < typedArrayConstructors.length; i++) { count = 0; a = new typedArrayConstructors[i](4); constructor.prototype.forEach.call(a, function (x) { count++ }); assertEquals(a.length, count); } // Shadowing length doesn't affect forEach, unlike Array.prototype.forEach a = new constructor([1, 2]); Object.defineProperty(a, 'length', {value: 1}); var x = 0; assertEquals(a.forEach(function(elt) { x += elt; }), undefined); assertEquals(x, 3); assertEquals(Array.prototype.forEach.call(a, function(elt) { x += elt; }), undefined); assertEquals(x, 4); // Detached Operation var array = new constructor([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); %ArrayBufferNeuter(array.buffer); assertThrows(() => array.forEach(() => true), TypeError); } for (i = 0; i < typedArrayConstructors.length; i++) { TestTypedArrayForEach(typedArrayConstructors[i]); }