From 1fe5f0e3adcc447260d8ce88e01f6482eb9d9725 Mon Sep 17 00:00:00 2001 From: mvstanton Date: Wed, 22 Mar 2017 06:37:25 -0700 Subject: [PATCH] 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} --- src/bootstrapper.cc | 67 +++++++++++++---- src/flag-definitions.h | 6 +- src/js/array.js | 136 ----------------------------------- src/js/typedarray.js | 84 ++++++++++++++++++---- src/runtime/runtime-array.cc | 14 ---- src/runtime/runtime.h | 1 - 6 files changed, 125 insertions(+), 183 deletions(-) diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index 2ae03256df..68f5507a2c 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -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 InstallArrayBuffer(Handle target, const char* name, Builtins::Name call, @@ -433,6 +433,24 @@ Handle SimpleCreateFunction(Isolate* isolate, Handle name, return fun; } +Handle InstallArrayBuiltinFunction(Handle base, + const char* name, + Builtins::Name call, + int argument_count) { + Isolate* isolate = base->GetIsolate(); + Handle str_name = isolate->factory()->InternalizeUtf8String(name); + Handle fun = + CreateFunction(isolate, str_name, JS_OBJECT_TYPE, JSObject::kHeaderSize, + MaybeHandle(), 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 SimpleInstallFunction(Handle base, Handle 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 name = Natives::GetScriptName(index); Handle 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 array_constructor(native_context()->array_function()); - Handle proto(JSObject::cast(array_constructor->prototype())); + Handle 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 concat = InstallFunction(proto, "concat", JS_OBJECT_TYPE, JSObject::kHeaderSize, MaybeHandle(), 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 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 diff --git a/src/flag-definitions.h b/src/flag-definitions.h index 61aef468bb..d26d4f8a81 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -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") diff --git a/src/js/array.js b/src/js/array.js index 6bd31a8ebe..68831d33e4 100644 --- a/src/js/array.js +++ b/src/js/array.js @@ -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, diff --git a/src/js/typedarray.js b/src/js/typedarray.js index 06d1657d40..ac8609a826 100644 --- a/src/js/typedarray.js +++ b/src/js/typedarray.js @@ -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); diff --git a/src/runtime/runtime-array.cc b/src/runtime/runtime-array.cc index 07c6ad0116..97432b6ef1 100644 --- a/src/runtime/runtime-array.cc +++ b/src/runtime/runtime-array.cc @@ -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 holder, const char* name, Handle code, int argc = -1, diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index bae00571a0..4a0a802326 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -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) \