Commit f6af3a49 authored by dehrenberg's avatar dehrenberg Committed by Commit bot

Re-land %TypedArray%.prototype.{map,filter,some}

Previously this patch was attempted with reduce and reduceRight included;
however, some of those tests crashed in the trybots. This version has
just map, fiter and some, together with their tests.

R=arv@chromium.org
BUG=v8:3578
LOG=Y

Review URL: https://codereview.chromium.org/1145013002

Cr-Commit-Position: refs/heads/master@{#28529}
parent 37706b3d
......@@ -12,9 +12,12 @@ var $arraySplice;
var $arrayUnshift;
var $innerArrayForEach;
var $innerArrayEvery;
var $innerArrayFilter;
var $innerArrayIndexOf;
var $innerArrayLastIndexOf;
var $innerArrayMap;
var $innerArrayReverse;
var $innerArraySome;
var $innerArraySort;
(function(global, shared, exports) {
......@@ -1164,14 +1167,7 @@ function ArraySort(comparefn) {
// The following functions cannot be made efficient on sparse arrays while
// preserving the semantics, since the calls to the receiver function can add
// or delete elements from the array.
function ArrayFilter(f, receiver) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.filter");
// Pull out the length so that modifications to the length in the
// loop will not affect the looping and side effects are visible.
var array = $toObject(this);
var length = $toUint32(array.length);
function InnerArrayFilter(f, receiver, array, length) {
if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f);
var needs_wrapper = false;
if (IS_NULL(receiver)) {
......@@ -1180,7 +1176,6 @@ function ArrayFilter(f, receiver) {
needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
}
var result = new GlobalArray();
var accumulator = new InternalArray();
var accumulator_length = 0;
var is_array = IS_ARRAY(array);
......@@ -1196,6 +1191,18 @@ function ArrayFilter(f, receiver) {
}
}
}
return accumulator;
}
function ArrayFilter(f, receiver) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.filter");
// Pull out the length so that modifications to the length in the
// loop will not affect the looping and side effects are visible.
var array = $toObject(this);
var length = $toUint32(array.length);
var accumulator = InnerArrayFilter(f, receiver, array, length);
var result = new GlobalArray();
%MoveArrayContents(accumulator, result);
return result;
}
......@@ -1233,16 +1240,7 @@ function ArrayForEach(f, receiver) {
}
// Executes the function once for each element present in the
// array until it finds one where callback returns true.
function ArraySome(f, receiver) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.some");
// Pull out the length so that modifications to the length in the
// loop will not affect the looping and side effects are visible.
var array = $toObject(this);
var length = TO_UINT32(array.length);
function InnerArraySome(f, receiver, array, length) {
if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f);
var needs_wrapper = false;
if (IS_NULL(receiver)) {
......@@ -1266,6 +1264,19 @@ function ArraySome(f, receiver) {
}
// Executes the function once for each element present in the
// array until it finds one where callback returns true.
function ArraySome(f, receiver) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.some");
// Pull out the length so that modifications to the length in the
// loop will not affect the looping and side effects are visible.
var array = $toObject(this);
var length = TO_UINT32(array.length);
return InnerArraySome(f, receiver, array, length);
}
function InnerArrayEvery(f, receiver, array, length) {
if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f);
var needs_wrapper = false;
......@@ -1300,14 +1311,7 @@ function ArrayEvery(f, receiver) {
}
function ArrayMap(f, receiver) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.map");
// Pull out the length so that modifications to the length in the
// loop will not affect the looping and side effects are visible.
var array = $toObject(this);
var length = TO_UINT32(array.length);
function InnerArrayMap(f, receiver, array, length) {
if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f);
var needs_wrapper = false;
if (IS_NULL(receiver)) {
......@@ -1316,7 +1320,6 @@ function ArrayMap(f, receiver) {
needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
}
var result = new GlobalArray();
var accumulator = new InternalArray(length);
var is_array = IS_ARRAY(array);
var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
......@@ -1329,6 +1332,19 @@ function ArrayMap(f, receiver) {
accumulator[i] = %_CallFunction(new_receiver, element, i, array, f);
}
}
return accumulator;
}
function ArrayMap(f, receiver) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.map");
// Pull out the length so that modifications to the length in the
// loop will not affect the looping and side effects are visible.
var array = $toObject(this);
var length = TO_UINT32(array.length);
var accumulator = InnerArrayMap(f, receiver, array, length);
var result = new GlobalArray();
%MoveArrayContents(accumulator, result);
return result;
}
......@@ -1636,11 +1652,14 @@ $arraySlice = ArraySlice;
$arraySplice = ArraySplice;
$arrayUnshift = ArrayUnshift;
$innerArrayForEach = InnerArrayForEach;
$innerArrayEvery = InnerArrayEvery;
$innerArrayFilter = InnerArrayFilter;
$innerArrayForEach = InnerArrayForEach;
$innerArrayIndexOf = InnerArrayIndexOf;
$innerArrayLastIndexOf = InnerArrayLastIndexOf;
$innerArrayMap = InnerArrayMap;
$innerArrayReverse = InnerArrayReverse;
$innerArraySome = InnerArraySome;
$innerArraySort = InnerArraySort;
});
......@@ -30,6 +30,28 @@ DECLARE_GLOBALS(Array)
// -------------------------------------------------------------------
function ConstructTypedArray(constructor, array) {
// TODO(littledan): This is an approximation of the spec, which requires
// that only real TypedArray classes should be accepted (22.2.2.1.1)
if (!%IsConstructor(constructor) || IS_UNDEFINED(constructor.prototype) ||
!%HasOwnProperty(constructor.prototype, "BYTES_PER_ELEMENT")) {
throw MakeTypeError(kNotTypedArray);
}
// TODO(littledan): The spec requires that, rather than directly calling
// the constructor, a TypedArray is created with the proper proto and
// underlying size and element size, and elements are put in one by one.
// By contrast, this would allow subclasses to make a radically different
// constructor with different semantics.
return new constructor(array);
}
function ConstructTypedArrayLike(typedArray, arrayContents) {
// TODO(littledan): The spec requires that we actuallly use
// typedArray.constructor[Symbol.species] (bug v8:4093)
return ConstructTypedArray(typedArray.constructor, arrayContents);
}
function TypedArrayCopyWithin(target, start, end) {
if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
......@@ -61,7 +83,7 @@ function TypedArrayForEach(f, receiver) {
%FunctionSetLength(TypedArrayForEach, 1);
// ES6 draft 04-05-14 section 22.2.3.8
function TypedArrayFill(value, start , end) {
function TypedArrayFill(value, start, end) {
if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
var length = %_TypedArrayGetLength(this);
......@@ -70,6 +92,16 @@ function TypedArrayFill(value, start , end) {
}
%FunctionSetLength(TypedArrayFill, 1);
// ES6 draft 07-15-13, section 22.2.3.9
function TypedArrayFilter(predicate, thisArg) {
if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
var length = %_TypedArrayGetLength(this);
var array = $innerArrayFilter(predicate, thisArg, this, length);
return ConstructTypedArrayLike(this, array);
}
%FunctionSetLength(TypedArrayFilter, 1);
// ES6 draft 07-15-13, section 22.2.3.10
function TypedArrayFind(predicate, thisArg) {
if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
......@@ -157,6 +189,30 @@ function TypedArrayLastIndexOf(element, index) {
%FunctionSetLength(TypedArrayLastIndexOf, 1);
// ES6 draft 07-15-13, section 22.2.3.18
function TypedArrayMap(predicate, thisArg) {
if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
// TODO(littledan): Preallocate rather than making an intermediate
// InternalArray, for better performance.
var length = %_TypedArrayGetLength(this);
var array = $innerArrayMap(predicate, thisArg, this, length);
return ConstructTypedArrayLike(this, array);
}
%FunctionSetLength(TypedArrayMap, 1);
// ES6 draft 05-05-15, section 22.2.3.24
function TypedArraySome(f, receiver) {
if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
var length = %_TypedArrayGetLength(this);
return $innerArraySome(f, receiver, this, length);
}
%FunctionSetLength(TypedArraySome, 1);
// ES6 draft 08-24-14, section 22.2.2.2
function TypedArrayOf() {
var length = %_ArgumentsLength();
......@@ -167,21 +223,6 @@ function TypedArrayOf() {
return array;
}
function ConstructTypedArray(constructor, array) {
// TODO(littledan): This is an approximation of the spec, which requires
// that only real TypedArray classes should be accepted (22.2.2.1.1)
if (!IS_SPEC_OBJECT(constructor) || IS_UNDEFINED(constructor.prototype) ||
!%HasOwnProperty(constructor.prototype, "BYTES_PER_ELEMENT")) {
throw MakeTypeError(kNotTypedArray);
}
// TODO(littledan): The spec requires that, rather than directly calling
// the constructor, a TypedArray is created with the proper proto and
// underlying size and element size, and elements are put in one by one.
// By contrast, this would allow subclasses to make a radically different
// constructor with different semantics.
return new constructor(array);
}
function TypedArrayFrom(source, mapfn, thisArg) {
// TODO(littledan): Investigate if there is a receiver which could be
......@@ -203,13 +244,16 @@ macro EXTEND_TYPED_ARRAY(NAME)
$installFunctions(GlobalNAME.prototype, DONT_ENUM, [
"copyWithin", TypedArrayCopyWithin,
"every", TypedArrayEvery,
"forEach", TypedArrayForEach,
"fill", TypedArrayFill,
"filter", TypedArrayFilter,
"find", TypedArrayFind,
"findIndex", TypedArrayFindIndex,
"fill", TypedArrayFill,
"indexOf", TypedArrayIndexOf,
"lastIndexOf", TypedArrayLastIndexOf,
"forEach", TypedArrayForEach,
"map", TypedArrayMap,
"reverse", TypedArrayReverse,
"some", TypedArraySome,
"sort", TypedArraySort
]);
endmacro
......
// Copyright 2015 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-arrays
// Tests for standard TypedArray array iteration functions.
var typedArrayConstructors = [
Uint8Array,
Int8Array,
Uint16Array,
Int16Array,
Uint32Array,
Int32Array,
Uint8ClampedArray,
Float32Array,
Float64Array
];
function assertArrayLikeEquals(expected, value, type) {
assertEquals(value.__proto__, type.prototype);
assertEquals(expected.length, value.length);
for (var i = 0; i < value.length; ++i) {
assertEquals(expected[i], value[i]);
}
}
for (var constructor of typedArrayConstructors) {
(function TypedArrayFilterTest() {
// Simple use.
var a = new constructor([0, 1]);
assertArrayLikeEquals([0], a.filter(function(n) { return n == 0; }),
constructor);
assertArrayLikeEquals([0, 1], a, constructor);
// Use specified object as this object when calling the function.
var o = { value: 42 }
a = new constructor([1, 42, 3, 42, 4]);
assertArrayLikeEquals([42, 42], a.filter(function(n) {
return this.value == n
}, o), constructor);
// Modify original array.
a = new constructor([1, 42, 3, 42, 4]);
assertArrayLikeEquals([42, 42], a.filter(function(n, index, array) {
array[index] = 43; return 42 == n;
}), constructor);
assertArrayLikeEquals([43, 43, 43, 43, 43], a, constructor);
// Create a new object in each function call when receiver is a
// primitive value. See ECMA-262, Annex C.
a = [];
new constructor([1, 2]).filter(function() { a.push(this) }, '');
assertTrue(a[0] !== a[1]);
// Do not create a new object otherwise.
a = [];
new constructor([1, 2]).filter(function() { a.push(this) }, {});
assertEquals(a[0], a[1]);
// In strict mode primitive values should not be coerced to an object.
a = [];
new constructor([1, 2]).filter(function() {
'use strict';
a.push(this);
}, '');
assertEquals('', a[0]);
assertEquals(a[0], a[1]);
// Calling this method on other types is a TypeError
assertThrows(function() {
constructor.prototype.filter.call([], function() {});
}, TypeError);
// Shadowing the length property doesn't change anything
a = new constructor([1, 2]);
Object.defineProperty(a, 'length', { value: 1 });
assertArrayLikeEquals([2], a.filter(function(elt) {
return elt == 2;
}), constructor);
})();
(function TypedArrayMapTest() {
var a = new constructor([0, 1, 2, 3, 4]);
// Simple use.
var result = [1, 2, 3, 4, 5];
assertArrayLikeEquals(result, a.map(function(n) { return n + 1; }),
constructor);
assertEquals(a, a);
// Use specified object as this object when calling the function.
var o = { delta: 42 }
result = [42, 43, 44, 45, 46];
assertArrayLikeEquals(result, a.map(function(n) {
return this.delta + n;
}, o), constructor);
// Modify original array.
a = new constructor([0, 1, 2, 3, 4]);
result = [1, 2, 3, 4, 5];
assertArrayLikeEquals(result, a.map(function(n, index, array) {
array[index] = n + 1;
return n + 1;
}), constructor);
assertArrayLikeEquals(result, a, constructor);
// Create a new object in each function call when receiver is a
// primitive value. See ECMA-262, Annex C.
a = [];
new constructor([1, 2]).map(function() { a.push(this) }, '');
assertTrue(a[0] !== a[1]);
// Do not create a new object otherwise.
a = [];
new constructor([1, 2]).map(function() { a.push(this) }, {});
assertEquals(a[0], a[1]);
// In strict mode primitive values should not be coerced to an object.
a = [];
new constructor([1, 2]).map(function() { 'use strict'; a.push(this); }, '');
assertEquals('', a[0]);
assertEquals(a[0], a[1]);
// Test that the result is converted to the right type
assertArrayLikeEquals([3, 3], new constructor([1, 2]).map(function() {
return "3";
}), constructor);
if (constructor !== Float32Array && constructor !== Float64Array) {
assertArrayLikeEquals([0, 0], new constructor([1, 2]).map(function() {
return NaN;
}), constructor);
}
})();
//
// %TypedArray%.prototype.some
//
(function TypedArraySomeTest() {
var a = new constructor([0, 1, 2, 3, 4]);
// Simple use.
assertTrue(a.some(function(n) { return n == 3}));
assertFalse(a.some(function(n) { return n == 5}));
// Use specified object as this object when calling the function.
var o = { element: 42 };
a = new constructor([1, 42, 3]);
assertTrue(a.some(function(n) { return this.element == n; }, o));
a = new constructor([1]);
assertFalse(a.some(function(n) { return this.element == n; }, o));
// Modify original array.
a = new constructor([0, 1, 2, 3]);
assertTrue(a.some(function(n, index, array) {
array[index] = n + 1;
return n == 2;
}));
assertArrayLikeEquals([1, 2, 3, 3], a, constructor);
// Create a new object in each function call when receiver is a
// primitive value. See ECMA-262, Annex C.
a = [];
new constructor([1, 2]).some(function() { a.push(this) }, '');
assertTrue(a[0] !== a[1]);
// Do not create a new object otherwise.
a = [];
new constructor([1, 2]).some(function() { a.push(this) }, {});
assertEquals(a[0], a[1]);
// In strict mode primitive values should not be coerced to an object.
a = [];
new constructor([1, 2]).some(function() {
'use strict';
a.push(this);
}, '');
assertEquals('', a[0]);
assertEquals(a[0], a[1]);
// Calling this method on other types is a TypeError
assertThrows(function() {
constructor.prototype.some.call([], function() {});
}, TypeError);
// Shadowing the length property doesn't change anything
a = new constructor([1, 2]);
Object.defineProperty(a, 'length', { value: 1 });
assertEquals(true, a.some(function(elt) { return elt == 2; }));
assertEquals(false, Array.prototype.some.call(a, function(elt) {
return elt == 2;
}));
})();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment