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}
This commit is contained in:
parent
c50d9819c9
commit
1ebbaaa036
46
src/array.js
46
src/array.js
@ -10,6 +10,8 @@ var $arrayShift;
|
||||
var $arraySlice;
|
||||
var $arraySplice;
|
||||
var $arrayUnshift;
|
||||
var $innerArrayForEach;
|
||||
var $innerArrayEvery;
|
||||
|
||||
(function(global, shared, exports) {
|
||||
|
||||
@ -1179,15 +1181,7 @@ function ArrayFilter(f, receiver) {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
function InnerArrayForEach(f, receiver, array, length) {
|
||||
if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f);
|
||||
var needs_wrapper = false;
|
||||
if (IS_NULL(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
|
||||
// array until it finds one where callback returns true.
|
||||
@ -1243,14 +1247,7 @@ function ArraySome(f, receiver) {
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
function InnerArrayEvery(f, receiver, array, length) {
|
||||
if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f);
|
||||
var needs_wrapper = false;
|
||||
if (IS_NULL(receiver)) {
|
||||
@ -1273,6 +1270,16 @@ function ArrayEvery(f, receiver) {
|
||||
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) {
|
||||
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.map");
|
||||
@ -1595,4 +1602,7 @@ $arraySlice = ArraySlice;
|
||||
$arraySplice = ArraySplice;
|
||||
$arrayUnshift = ArrayUnshift;
|
||||
|
||||
})
|
||||
$innerArrayForEach = InnerArrayForEach;
|
||||
$innerArrayEvery = InnerArrayEvery;
|
||||
|
||||
});
|
||||
|
@ -30,70 +30,27 @@ TYPED_ARRAYS(DECLARE_GLOBALS)
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// ES6 draft 05-05-15, section 22.2.3.7
|
||||
function TypedArrayEvery(f /* thisArg */) { // length == 1
|
||||
if (!%IsTypedArray(this)) {
|
||||
throw MakeTypeError('not_typed_array', []);
|
||||
}
|
||||
if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f);
|
||||
function TypedArrayEvery(f, receiver) {
|
||||
if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
|
||||
|
||||
var length = %_TypedArrayGetLength(this);
|
||||
var receiver;
|
||||
|
||||
if (%_ArgumentsLength() > 1) {
|
||||
receiver = %_Arguments(1);
|
||||
}
|
||||
|
||||
var needs_wrapper = false;
|
||||
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;
|
||||
return $innerArrayEvery(f, receiver, this, length);
|
||||
}
|
||||
%FunctionSetLength(TypedArrayEvery, 1);
|
||||
|
||||
// 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 (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f);
|
||||
|
||||
var length = %_TypedArrayGetLength(this);
|
||||
var receiver;
|
||||
|
||||
if (%_ArgumentsLength() > 1) {
|
||||
receiver = %_Arguments(1);
|
||||
}
|
||||
|
||||
var needs_wrapper = false;
|
||||
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);
|
||||
}
|
||||
$innerArrayForEach(f, receiver, this, length);
|
||||
}
|
||||
%FunctionSetLength(TypedArrayForEach, 1);
|
||||
|
||||
// ES6 draft 08-24-14, section 22.2.2.2
|
||||
function TypedArrayOf() { // length == 0
|
||||
function TypedArrayOf() {
|
||||
var length = %_ArgumentsLength();
|
||||
var array = new this(length);
|
||||
for (var i = 0; i < length; i++) {
|
||||
|
@ -85,8 +85,9 @@ function TestTypedArrayForEach(constructor) {
|
||||
// still make .forEach() finish, and the array should keep being
|
||||
// empty after neutering it.
|
||||
count = 0;
|
||||
a = new constructor(2);
|
||||
a = new constructor(3);
|
||||
result = a.every(function (n, index, array) {
|
||||
assertFalse(array[index] === undefined); // don't get here if neutered
|
||||
if (count > 0) %ArrayBufferNeuter(array.buffer);
|
||||
array[index] = n + 1;
|
||||
count++;
|
||||
|
@ -85,8 +85,13 @@ function TestTypedArrayForEach(constructor) {
|
||||
assertEquals(42, a[1]);
|
||||
|
||||
// Neutering the buffer backing the typed array mid-way should
|
||||
// still make .forEach() finish, and the array should keep being
|
||||
// empty after neutering it.
|
||||
// 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);
|
||||
|
Loading…
Reference in New Issue
Block a user