Commit 1ebbaaa0 authored by dehrenberg's avatar dehrenberg Committed by Commit bot

Factor out core of Array.forEach and .every, for use in TypedArrays

The idea is to make this the model for future TypedArray methods.
A possible downside could be lower array method performance
if everything gets polymorhpic (but if enough inlining happens, it
should still be fast), but on the upside, this change means that
the TypedArray methods won't create as much code size bloat.

BUG=v8:3578
LOG=Y
R=adamk@chromium.org
CC=arv@chromium.org, caitpotter88@gmail.com

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

Cr-Commit-Position: refs/heads/master@{#28351}
parent c50d9819
...@@ -10,6 +10,8 @@ var $arrayShift; ...@@ -10,6 +10,8 @@ var $arrayShift;
var $arraySlice; var $arraySlice;
var $arraySplice; var $arraySplice;
var $arrayUnshift; var $arrayUnshift;
var $innerArrayForEach;
var $innerArrayEvery;
(function(global, shared, exports) { (function(global, shared, exports) {
...@@ -1179,15 +1181,7 @@ function ArrayFilter(f, receiver) { ...@@ -1179,15 +1181,7 @@ function ArrayFilter(f, receiver) {
return result; return result;
} }
function InnerArrayForEach(f, receiver, array, length) {
function ArrayForEach(f, receiver) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.forEach");
// 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);
if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f); if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f);
var needs_wrapper = false; var needs_wrapper = false;
if (IS_NULL(receiver)) { if (IS_NULL(receiver)) {
...@@ -1209,6 +1203,16 @@ function ArrayForEach(f, receiver) { ...@@ -1209,6 +1203,16 @@ function ArrayForEach(f, receiver) {
} }
} }
function ArrayForEach(f, receiver) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.forEach");
// 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);
InnerArrayForEach(f, receiver, array, length);
}
// Executes the function once for each element present in the // Executes the function once for each element present in the
// array until it finds one where callback returns true. // array until it finds one where callback returns true.
...@@ -1243,14 +1247,7 @@ function ArraySome(f, receiver) { ...@@ -1243,14 +1247,7 @@ function ArraySome(f, receiver) {
} }
function ArrayEvery(f, receiver) { function InnerArrayEvery(f, receiver, array, length) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.every");
// 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);
if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f); if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f);
var needs_wrapper = false; var needs_wrapper = false;
if (IS_NULL(receiver)) { if (IS_NULL(receiver)) {
...@@ -1273,6 +1270,16 @@ function ArrayEvery(f, receiver) { ...@@ -1273,6 +1270,16 @@ function ArrayEvery(f, receiver) {
return true; return true;
} }
function ArrayEvery(f, receiver) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.every");
// 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 InnerArrayEvery(f, receiver, array, length);
}
function ArrayMap(f, receiver) { function ArrayMap(f, receiver) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.map"); CHECK_OBJECT_COERCIBLE(this, "Array.prototype.map");
...@@ -1595,4 +1602,7 @@ $arraySlice = ArraySlice; ...@@ -1595,4 +1602,7 @@ $arraySlice = ArraySlice;
$arraySplice = ArraySplice; $arraySplice = ArraySplice;
$arrayUnshift = ArrayUnshift; $arrayUnshift = ArrayUnshift;
}) $innerArrayForEach = InnerArrayForEach;
$innerArrayEvery = InnerArrayEvery;
});
...@@ -30,70 +30,27 @@ TYPED_ARRAYS(DECLARE_GLOBALS) ...@@ -30,70 +30,27 @@ TYPED_ARRAYS(DECLARE_GLOBALS)
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// ES6 draft 05-05-15, section 22.2.3.7 // ES6 draft 05-05-15, section 22.2.3.7
function TypedArrayEvery(f /* thisArg */) { // length == 1 function TypedArrayEvery(f, receiver) {
if (!%IsTypedArray(this)) { if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
throw MakeTypeError('not_typed_array', []);
}
if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f);
var length = %_TypedArrayGetLength(this); var length = %_TypedArrayGetLength(this);
var receiver;
if (%_ArgumentsLength() > 1) {
receiver = %_Arguments(1);
}
var needs_wrapper = false; return $innerArrayEvery(f, receiver, this, length);
if (IS_NULL(receiver)) {
if (%IsSloppyModeFunction(mapfn)) receiver = UNDEFINED;
} else if (!IS_UNDEFINED(receiver)) {
needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
}
var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
for (var i = 0; i < length; i++) {
var element = this[i];
// Prepare break slots for debugger step in.
if (stepping) %DebugPrepareStepInIfStepping(f);
var new_receiver = needs_wrapper ? $toObject(receiver) : receiver;
if (!%_CallFunction(new_receiver, TO_OBJECT_INLINE(element), i, this, f)) {
return false;
}
}
return true;
} }
%FunctionSetLength(TypedArrayEvery, 1);
// ES6 draft 08-24-14, section 22.2.3.12 // ES6 draft 08-24-14, section 22.2.3.12
function TypedArrayForEach(f /* thisArg */) { // length == 1 function TypedArrayForEach(f, receiver) {
if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f);
var length = %_TypedArrayGetLength(this); var length = %_TypedArrayGetLength(this);
var receiver;
if (%_ArgumentsLength() > 1) {
receiver = %_Arguments(1);
}
var needs_wrapper = false; $innerArrayForEach(f, receiver, this, length);
if (IS_NULL(receiver)) {
if (%IsSloppyModeFunction(mapfn)) receiver = UNDEFINED;
} else if (!IS_UNDEFINED(receiver)) {
needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
}
var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
for (var i = 0; i < length; i++) {
var element = this[i];
// Prepare break slots for debugger step in.
if (stepping) %DebugPrepareStepInIfStepping(f);
var new_receiver = needs_wrapper ? $toObject(receiver) : receiver;
%_CallFunction(new_receiver, TO_OBJECT_INLINE(element), i, this, f);
}
} }
%FunctionSetLength(TypedArrayForEach, 1);
// ES6 draft 08-24-14, section 22.2.2.2 // ES6 draft 08-24-14, section 22.2.2.2
function TypedArrayOf() { // length == 0 function TypedArrayOf() {
var length = %_ArgumentsLength(); var length = %_ArgumentsLength();
var array = new this(length); var array = new this(length);
for (var i = 0; i < length; i++) { for (var i = 0; i < length; i++) {
......
...@@ -85,8 +85,9 @@ function TestTypedArrayForEach(constructor) { ...@@ -85,8 +85,9 @@ function TestTypedArrayForEach(constructor) {
// still make .forEach() finish, and the array should keep being // still make .forEach() finish, and the array should keep being
// empty after neutering it. // empty after neutering it.
count = 0; count = 0;
a = new constructor(2); a = new constructor(3);
result = a.every(function (n, index, array) { result = a.every(function (n, index, array) {
assertFalse(array[index] === undefined); // don't get here if neutered
if (count > 0) %ArrayBufferNeuter(array.buffer); if (count > 0) %ArrayBufferNeuter(array.buffer);
array[index] = n + 1; array[index] = n + 1;
count++; count++;
......
...@@ -85,8 +85,13 @@ function TestTypedArrayForEach(constructor) { ...@@ -85,8 +85,13 @@ function TestTypedArrayForEach(constructor) {
assertEquals(42, a[1]); assertEquals(42, a[1]);
// Neutering the buffer backing the typed array mid-way should // Neutering the buffer backing the typed array mid-way should
// still make .forEach() finish, and the array should keep being // still make .forEach() finish, but exiting early due to the missing
// empty after neutering it. // 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; count = 0;
a.forEach(function (n, index, array) { a.forEach(function (n, index, array) {
if (count > 0) %ArrayBufferNeuter(array.buffer); if (count > 0) %ArrayBufferNeuter(array.buffer);
......
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