Always run our fast array builtins.

Before, we carefully turned on fast array builtins only if flag
--enable-fast-array-builtins was true (though it was implied true
if --turbo was on). Now, the set of Array.prototype.{some, forEach,
every, reduce} is good enough to always turn them on. This means
we can remove the JavaScript implementations.

The flag is renamed to --experimental-fast-array-builtins, which is
off. In the next days we'll add more non-javascript implementations
here for testing.

BUG=
R=danno@chromium.org

Review-Url: https://codereview.chromium.org/2761783002
Cr-Commit-Position: refs/heads/master@{#44026}
This commit is contained in:
mvstanton 2017-03-22 06:37:25 -07:00 committed by Commit bot
parent 8f033c2d0b
commit 1fe5f0e3ad
6 changed files with 125 additions and 183 deletions

View File

@ -218,7 +218,7 @@ class Genesis BASE_EMBEDDED {
void InstallOneBuiltinFunction(const char* object, const char* method,
Builtins::Name name);
void InitializeGlobal_enable_fast_array_builtins();
void InitializeGlobal_experimental_fast_array_builtins();
Handle<JSFunction> InstallArrayBuffer(Handle<JSObject> target,
const char* name, Builtins::Name call,
@ -433,6 +433,24 @@ Handle<JSFunction> SimpleCreateFunction(Isolate* isolate, Handle<String> name,
return fun;
}
Handle<JSFunction> InstallArrayBuiltinFunction(Handle<JSObject> base,
const char* name,
Builtins::Name call,
int argument_count) {
Isolate* isolate = base->GetIsolate();
Handle<String> str_name = isolate->factory()->InternalizeUtf8String(name);
Handle<JSFunction> fun =
CreateFunction(isolate, str_name, JS_OBJECT_TYPE, JSObject::kHeaderSize,
MaybeHandle<JSObject>(), call, true);
fun->shared()->set_internal_formal_parameter_count(argument_count);
// Set the length to 1 to satisfy ECMA-262.
fun->shared()->set_length(1);
fun->shared()->set_language_mode(STRICT);
InstallFunction(base, fun, str_name);
return fun;
}
Handle<JSFunction> SimpleInstallFunction(Handle<JSObject> base,
Handle<String> name,
Builtins::Name call, int len,
@ -3066,10 +3084,9 @@ void Genesis::InitializeExperimentalGlobal() {
HARMONY_SHIPPING(FEATURE_INITIALIZE_GLOBAL)
#undef FEATURE_INITIALIZE_GLOBAL
InitializeGlobal_enable_fast_array_builtins();
InitializeGlobal_experimental_fast_array_builtins();
}
bool Bootstrapper::CompileBuiltin(Isolate* isolate, int index) {
Vector<const char> name = Natives::GetScriptName(index);
Handle<String> source_code =
@ -3689,17 +3706,11 @@ void Genesis::InstallOneBuiltinFunction(const char* object_name,
isolate->builtins()->builtin(builtin_name));
}
void Genesis::InitializeGlobal_enable_fast_array_builtins() {
if (!FLAG_enable_fast_array_builtins) return;
void Genesis::InitializeGlobal_experimental_fast_array_builtins() {
if (!FLAG_experimental_fast_array_builtins) return;
InstallOneBuiltinFunction("Array", "forEach", Builtins::kArrayForEach);
InstallOneBuiltinFunction("Array", "every", Builtins::kArrayEvery);
InstallOneBuiltinFunction("Array", "some", Builtins::kArraySome);
InstallOneBuiltinFunction("Array", "reduce", Builtins::kArrayReduce);
if (FLAG_experimental_array_builtins) {
InstallOneBuiltinFunction("Array", "filter", Builtins::kArrayFilter);
}
// Insert experimental fast array builtins here.
InstallOneBuiltinFunction("Array", "filter", Builtins::kArrayFilter);
}
void Genesis::InitializeGlobal_harmony_sharedarraybuffer() {
@ -4143,10 +4154,21 @@ bool Genesis::InstallNatives(GlobalContextType context_type) {
SimpleInstallFunction(global_object, "isNaN", Builtins::kGlobalIsNaN, 1, true,
kGlobalIsNaN);
// Install Array.prototype.concat
// Install Array builtin functions.
{
Handle<JSFunction> array_constructor(native_context()->array_function());
Handle<JSObject> proto(JSObject::cast(array_constructor->prototype()));
Handle<JSArray> proto(JSArray::cast(array_constructor->prototype()));
// Verification of important array prototype properties.
Object* length = proto->length();
CHECK(length->IsSmi());
CHECK(Smi::cast(length)->value() == 0);
CHECK(proto->HasFastSmiOrObjectElements());
// This is necessary to enable fast checks for absence of elements
// on Array.prototype and below.
proto->set_elements(heap()->empty_fixed_array());
// Install Array.prototype.concat
Handle<JSFunction> concat =
InstallFunction(proto, "concat", JS_OBJECT_TYPE, JSObject::kHeaderSize,
MaybeHandle<JSObject>(), Builtins::kArrayConcat);
@ -4158,6 +4180,21 @@ bool Genesis::InstallNatives(GlobalContextType context_type) {
DCHECK(concat->is_compiled());
// Set the lengths for the functions to satisfy ECMA-262.
concat->shared()->set_length(1);
// Install Array.prototype.forEach
Handle<JSFunction> forEach = InstallArrayBuiltinFunction(
proto, "forEach", Builtins::kArrayForEach, 2);
// Add forEach to the context.
native_context()->set_array_for_each_iterator(*forEach);
// Install Array.prototype.every
InstallArrayBuiltinFunction(proto, "every", Builtins::kArrayEvery, 2);
// Install Array.prototype.some
InstallArrayBuiltinFunction(proto, "some", Builtins::kArraySome, 2);
// Install Array.prototype.reduce
InstallArrayBuiltinFunction(proto, "reduce", Builtins::kArrayReduce, 2);
}
// Install InternalArray.prototype.concat

View File

@ -269,7 +269,6 @@ DEFINE_BOOL(future, FUTURE_BOOL,
DEFINE_IMPLICATION(future, turbo)
DEFINE_DUAL_IMPLICATION(turbo, ignition)
DEFINE_DUAL_IMPLICATION(turbo, enable_fast_array_builtins)
DEFINE_DUAL_IMPLICATION(turbo, thin_strings)
// Flags for experimental implementation features.
@ -772,9 +771,8 @@ DEFINE_BOOL(builtins_in_stack_traces, false,
"show built-in functions in stack traces")
// builtins.cc
DEFINE_BOOL(enable_fast_array_builtins, false, "use optimized builtins")
DEFINE_BOOL(experimental_array_builtins, false,
"Experimental versions of array builtins")
DEFINE_BOOL(experimental_fast_array_builtins, false,
"use experimental array builtins")
DEFINE_BOOL(allow_unsafe_function_constructor, false,
"allow invoking the function constructor without security checks")

View File

@ -1033,88 +1033,6 @@ function ArrayFilter(f, receiver) {
return InnerArrayFilter(f, receiver, array, length, result);
}
function InnerArrayForEach(f, receiver, array, length) {
if (!IS_CALLABLE(f)) throw %make_type_error(kCalledNonCallable, f);
if (IS_UNDEFINED(receiver)) {
for (var i = 0; i < length; i++) {
if (i in array) {
var element = array[i];
f(element, i, array);
}
}
} else {
for (var i = 0; i < length; i++) {
if (i in array) {
var element = array[i];
%_Call(f, receiver, element, i, array);
}
}
}
}
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 = TO_OBJECT(this);
var length = TO_LENGTH(array.length);
InnerArrayForEach(f, receiver, array, length);
}
function InnerArraySome(f, receiver, array, length) {
if (!IS_CALLABLE(f)) throw %make_type_error(kCalledNonCallable, f);
for (var i = 0; i < length; i++) {
if (i in array) {
var element = array[i];
if (%_Call(f, receiver, element, i, array)) return true;
}
}
return false;
}
// 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 = TO_OBJECT(this);
var length = TO_LENGTH(array.length);
return InnerArraySome(f, receiver, array, length);
}
function InnerArrayEvery(f, receiver, array, length) {
if (!IS_CALLABLE(f)) throw %make_type_error(kCalledNonCallable, f);
for (var i = 0; i < length; i++) {
if (i in array) {
var element = array[i];
if (!%_Call(f, receiver, element, i, array)) return false;
}
}
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 = TO_OBJECT(this);
var length = TO_LENGTH(array.length);
return InnerArrayEvery(f, receiver, array, length);
}
function ArrayMap(f, receiver) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.map");
@ -1188,45 +1106,6 @@ function ArrayLastIndexOf(element, index) {
return -1;
}
function InnerArrayReduce(callback, current, array, length, argumentsLength) {
if (!IS_CALLABLE(callback)) {
throw %make_type_error(kCalledNonCallable, callback);
}
var i = 0;
find_initial: if (argumentsLength < 2) {
for (; i < length; i++) {
if (i in array) {
current = array[i++];
break find_initial;
}
}
throw %make_type_error(kReduceNoInitial);
}
for (; i < length; i++) {
if (i in array) {
var element = array[i];
current = callback(current, element, i, array);
}
}
return current;
}
function ArrayReduce(callback, current) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.reduce");
// 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 = TO_OBJECT(this);
var length = TO_LENGTH(array.length);
return InnerArrayReduce(callback, current, array, length,
arguments.length);
}
function InnerArrayReduceRight(callback, current, array, length,
argumentsLength) {
if (!IS_CALLABLE(callback)) {
@ -1522,7 +1401,6 @@ function getFunction(name, jsBuiltin, len) {
// public API via Template::SetIntrinsicDataProperty().
var IteratorFunctions = {
"entries": getFunction("entries", null, 0),
"forEach": getFunction("forEach", ArrayForEach, 1),
"keys": getFunction("keys", null, 0),
"values": getFunction("values", null, 0)
}
@ -1544,12 +1422,9 @@ utils.InstallFunctions(GlobalArray.prototype, DONT_ENUM, [
"splice", getFunction("splice", ArraySplice, 2),
"sort", getFunction("sort", ArraySort),
"filter", getFunction("filter", ArrayFilter, 1),
"some", getFunction("some", ArraySome, 1),
"every", getFunction("every", ArrayEvery, 1),
"map", getFunction("map", ArrayMap, 1),
"indexOf", getFunction("indexOf", null, 1),
"lastIndexOf", getFunction("lastIndexOf", ArrayLastIndexOf, 1),
"reduce", getFunction("reduce", ArrayReduce, 1),
"reduceRight", getFunction("reduceRight", ArrayReduceRight, 1),
"copyWithin", getFunction("copyWithin", ArrayCopyWithin, 2),
"find", getFunction("find", ArrayFind, 1),
@ -1557,20 +1432,14 @@ utils.InstallFunctions(GlobalArray.prototype, DONT_ENUM, [
"fill", getFunction("fill", ArrayFill, 1),
"includes", getFunction("includes", null, 1),
"entries", IteratorFunctions.entries,
"forEach", IteratorFunctions.forEach,
"keys", IteratorFunctions.keys,
iteratorSymbol, IteratorFunctions.values
]);
utils.ForEachFunction = GlobalArray.prototype.forEach;
%FunctionSetName(IteratorFunctions.entries, "entries");
%FunctionSetName(IteratorFunctions.forEach, "forEach");
%FunctionSetName(IteratorFunctions.keys, "keys");
%FunctionSetName(IteratorFunctions.values, "values");
%FinishArrayPrototypeSetup(GlobalArray.prototype);
// The internal Array prototype doesn't need to be fancy, since it's never
// exposed to user code.
// Adding only the functions that are actually used.
@ -1611,15 +1480,11 @@ utils.Export(function(to) {
to.ArrayPush = ArrayPush;
to.ArrayToString = ArrayToString;
to.ArrayValues = IteratorFunctions.values,
to.InnerArrayEvery = InnerArrayEvery;
to.InnerArrayFilter = InnerArrayFilter;
to.InnerArrayFind = InnerArrayFind;
to.InnerArrayFindIndex = InnerArrayFindIndex;
to.InnerArrayForEach = InnerArrayForEach;
to.InnerArrayJoin = InnerArrayJoin;
to.InnerArrayReduce = InnerArrayReduce;
to.InnerArrayReduceRight = InnerArrayReduceRight;
to.InnerArraySome = InnerArraySome;
to.InnerArraySort = InnerArraySort;
to.InnerArrayToLocaleString = InnerArrayToLocaleString;
to.PackedArrayReverse = PackedArrayReverse;
@ -1627,7 +1492,6 @@ utils.Export(function(to) {
%InstallToContext([
"array_entries_iterator", IteratorFunctions.entries,
"array_for_each_iterator", IteratorFunctions.forEach,
"array_keys_iterator", IteratorFunctions.keys,
"array_pop", ArrayPop,
"array_push", ArrayPush,

View File

@ -20,15 +20,11 @@ var GlobalArray = global.Array;
var GlobalArrayBuffer = global.ArrayBuffer;
var GlobalArrayBufferPrototype = GlobalArrayBuffer.prototype;
var GlobalObject = global.Object;
var InnerArrayEvery;
var InnerArrayFilter;
var InnerArrayFind;
var InnerArrayFindIndex;
var InnerArrayForEach;
var InnerArrayJoin;
var InnerArrayReduce;
var InnerArrayReduceRight;
var InnerArraySome;
var InnerArraySort;
var InnerArrayToLocaleString;
var InternalArray = utils.InternalArray;
@ -66,15 +62,11 @@ utils.Import(function(from) {
ArrayValues = from.ArrayValues;
GetIterator = from.GetIterator;
GetMethod = from.GetMethod;
InnerArrayEvery = from.InnerArrayEvery;
InnerArrayFilter = from.InnerArrayFilter;
InnerArrayFind = from.InnerArrayFind;
InnerArrayFindIndex = from.InnerArrayFindIndex;
InnerArrayForEach = from.InnerArrayForEach;
InnerArrayJoin = from.InnerArrayJoin;
InnerArrayReduce = from.InnerArrayReduce;
InnerArrayReduceRight = from.InnerArrayReduceRight;
InnerArraySome = from.InnerArraySome;
InnerArraySort = from.InnerArraySort;
InnerArrayToLocaleString = from.InnerArrayToLocaleString;
MaxSimple = from.MaxSimple;
@ -371,6 +363,17 @@ function TypedArrayGetToStringTag() {
return name;
}
function InnerTypedArrayEvery(f, receiver, array, length) {
if (!IS_CALLABLE(f)) throw %make_type_error(kCalledNonCallable, f);
for (var i = 0; i < length; i++) {
if (i in array) {
var element = array[i];
if (!%_Call(f, receiver, element, i, array)) return false;
}
}
return true;
}
// ES6 draft 05-05-15, section 22.2.3.7
function TypedArrayEvery(f, receiver) {
@ -378,10 +381,29 @@ function TypedArrayEvery(f, receiver) {
var length = %_TypedArrayGetLength(this);
return InnerArrayEvery(f, receiver, this, length);
return InnerTypedArrayEvery(f, receiver, this, length);
}
%FunctionSetLength(TypedArrayEvery, 1);
function InnerTypedArrayForEach(f, receiver, array, length) {
if (!IS_CALLABLE(f)) throw %make_type_error(kCalledNonCallable, f);
if (IS_UNDEFINED(receiver)) {
for (var i = 0; i < length; i++) {
if (i in array) {
var element = array[i];
f(element, i, array);
}
}
} else {
for (var i = 0; i < length; i++) {
if (i in array) {
var element = array[i];
%_Call(f, receiver, element, i, array);
}
}
}
}
// ES6 draft 08-24-14, section 22.2.3.12
function TypedArrayForEach(f, receiver) {
@ -389,7 +411,7 @@ function TypedArrayForEach(f, receiver) {
var length = %_TypedArrayGetLength(this);
InnerArrayForEach(f, receiver, this, length);
InnerTypedArrayForEach(f, receiver, this, length);
}
%FunctionSetLength(TypedArrayForEach, 1);
@ -472,6 +494,17 @@ function TypedArrayMap(f, thisArg) {
}
%FunctionSetLength(TypedArrayMap, 1);
function InnerTypedArraySome(f, receiver, array, length) {
if (!IS_CALLABLE(f)) throw %make_type_error(kCalledNonCallable, f);
for (var i = 0; i < length; i++) {
if (i in array) {
var element = array[i];
if (%_Call(f, receiver, element, i, array)) return true;
}
}
return false;
}
// ES6 draft 05-05-15, section 22.2.3.24
function TypedArraySome(f, receiver) {
@ -479,7 +512,7 @@ function TypedArraySome(f, receiver) {
var length = %_TypedArrayGetLength(this);
return InnerArraySome(f, receiver, this, length);
return InnerTypedArraySome(f, receiver, this, length);
}
%FunctionSetLength(TypedArraySome, 1);
@ -503,14 +536,39 @@ function TypedArrayJoin(separator) {
return InnerArrayJoin(separator, this, length);
}
function InnerTypedArrayReduce(
callback, current, array, length, argumentsLength) {
if (!IS_CALLABLE(callback)) {
throw %make_type_error(kCalledNonCallable, callback);
}
var i = 0;
find_initial: if (argumentsLength < 2) {
for (; i < length; i++) {
if (i in array) {
current = array[i++];
break find_initial;
}
}
throw %make_type_error(kReduceNoInitial);
}
for (; i < length; i++) {
if (i in array) {
var element = array[i];
current = callback(current, element, i, array);
}
}
return current;
}
// ES6 draft 07-15-13, section 22.2.3.19
function TypedArrayReduce(callback, current) {
if (!IS_TYPEDARRAY(this)) throw %make_type_error(kNotTypedArray);
var length = %_TypedArrayGetLength(this);
return InnerArrayReduce(callback, current, this, length,
arguments.length);
return InnerTypedArrayReduce(
callback, current, this, length, arguments.length);
}
%FunctionSetLength(TypedArrayReduce, 1);

View File

@ -17,20 +17,6 @@
namespace v8 {
namespace internal {
RUNTIME_FUNCTION(Runtime_FinishArrayPrototypeSetup) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
Object* length = prototype->length();
CHECK(length->IsSmi());
CHECK(Smi::cast(length)->value() == 0);
CHECK(prototype->HasFastSmiOrObjectElements());
// This is necessary to enable fast checks for absence of elements
// on Array.prototype and below.
prototype->set_elements(isolate->heap()->empty_fixed_array());
return Smi::kZero;
}
static void InstallCode(
Isolate* isolate, Handle<JSObject> holder, const char* name,
Handle<Code> code, int argc = -1,

View File

@ -37,7 +37,6 @@ namespace internal {
// are specified by inline comments
#define FOR_EACH_INTRINSIC_ARRAY(F) \
F(FinishArrayPrototypeSetup, 1, 1) \
F(SpecialArrayFunctions, 0, 1) \
F(TransitionElementsKind, 2, 1) \
F(RemoveArrayHoles, 2, 1) \