[builtins] Skip iteration when constructing TypedArrays if possible.

This CL uses the same logic as spread calls to check whether the
iteration over an array would produce different results to simply
accessing the backing store directly. Skipping the full iteration
protocol for normal arrays gives us a ~10x speedup on the
construct-typedarray benchmark.

BUG=v8:5977,v8:5699,v8:4782,chromium:698173

Change-Id: Ib878d39691e99b739afef0dd05a6a6efc5b6b5d4
Reviewed-on: https://chromium-review.googlesource.com/463367
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Peter Marshall <petermarshall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#44304}
This commit is contained in:
Peter Marshall 2017-03-30 15:17:45 +02:00 committed by Commit Bot
parent 3f8b2aeb35
commit 143dcc6c41
5 changed files with 96 additions and 73 deletions

View File

@ -1524,6 +1524,11 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
array_function, isolate->factory()->InternalizeUtf8String("isArray"),
Builtins::kArrayIsArray, 1, true);
native_context()->set_is_arraylike(*is_arraylike);
Handle<JSFunction> has_side_effects = SimpleCreateFunction(
isolate, factory->NewStringFromAsciiChecked("hasIterationSideEffects"),
Builtins::kHasIterationSideEffects, 1, false);
native_context()->set_has_iteration_side_effects(*has_side_effects);
}
{ // --- A r r a y I t e r a t o r ---

View File

@ -1239,5 +1239,14 @@ BUILTIN(ArrayConcat) {
return Slow_ArrayConcat(&args, species, isolate);
}
BUILTIN(HasIterationSideEffects) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
bool observable = args[1]->IterationHasObservableEffects();
return isolate->heap()->ToBoolean(observable);
}
} // namespace internal
} // namespace v8

View File

@ -236,6 +236,7 @@ namespace internal {
/* Array */ \
ASM(ArrayCode) \
ASM(InternalArrayCode) \
CPP(HasIterationSideEffects) \
CPP(ArrayConcat) \
/* ES6 #sec-array.isarray */ \
TFJ(ArrayIsArray, 1, kArg) \

View File

@ -35,63 +35,64 @@ enum ContextLookupFlags {
// must always be allocated via Heap::AllocateContext() or
// Factory::NewContext.
#define NATIVE_CONTEXT_INTRINSIC_FUNCTIONS(V) \
V(ASYNC_FUNCTION_AWAIT_CAUGHT_INDEX, JSFunction, \
async_function_await_caught) \
V(ASYNC_FUNCTION_AWAIT_UNCAUGHT_INDEX, JSFunction, \
async_function_await_uncaught) \
V(ASYNC_FUNCTION_PROMISE_CREATE_INDEX, JSFunction, \
async_function_promise_create) \
V(ASYNC_FUNCTION_PROMISE_RELEASE_INDEX, JSFunction, \
async_function_promise_release) \
V(IS_ARRAYLIKE, JSFunction, is_arraylike) \
V(GENERATOR_NEXT_INTERNAL, JSFunction, generator_next_internal) \
V(GET_TEMPLATE_CALL_SITE_INDEX, JSFunction, get_template_call_site) \
V(MAKE_ERROR_INDEX, JSFunction, make_error) \
V(MAKE_RANGE_ERROR_INDEX, JSFunction, make_range_error) \
V(MAKE_SYNTAX_ERROR_INDEX, JSFunction, make_syntax_error) \
V(MAKE_TYPE_ERROR_INDEX, JSFunction, make_type_error) \
V(MAKE_URI_ERROR_INDEX, JSFunction, make_uri_error) \
V(OBJECT_CREATE, JSFunction, object_create) \
V(OBJECT_DEFINE_PROPERTIES, JSFunction, object_define_properties) \
V(OBJECT_DEFINE_PROPERTY, JSFunction, object_define_property) \
V(OBJECT_FREEZE, JSFunction, object_freeze) \
V(OBJECT_GET_PROTOTYPE_OF, JSFunction, object_get_prototype_of) \
V(OBJECT_IS_EXTENSIBLE, JSFunction, object_is_extensible) \
V(OBJECT_IS_FROZEN, JSFunction, object_is_frozen) \
V(OBJECT_IS_SEALED, JSFunction, object_is_sealed) \
V(OBJECT_KEYS, JSFunction, object_keys) \
V(REGEXP_INTERNAL_MATCH, JSFunction, regexp_internal_match) \
V(REFLECT_APPLY_INDEX, JSFunction, reflect_apply) \
V(REFLECT_CONSTRUCT_INDEX, JSFunction, reflect_construct) \
V(REFLECT_DEFINE_PROPERTY_INDEX, JSFunction, reflect_define_property) \
V(REFLECT_DELETE_PROPERTY_INDEX, JSFunction, reflect_delete_property) \
V(SPREAD_ARGUMENTS_INDEX, JSFunction, spread_arguments) \
V(SPREAD_ITERABLE_INDEX, JSFunction, spread_iterable) \
V(TYPED_ARRAY_CONSTRUCT_BY_ARRAY_BUFFER_INDEX, JSFunction, \
typed_array_construct_by_array_buffer) \
V(TYPED_ARRAY_CONSTRUCT_BY_ARRAY_LIKE_INDEX, JSFunction, \
typed_array_construct_by_array_like) \
V(TYPED_ARRAY_CONSTRUCT_BY_LENGTH_INDEX, JSFunction, \
typed_array_construct_by_length) \
V(TYPED_ARRAY_INITIALIZE_INDEX, JSFunction, typed_array_initialize) \
V(TYPED_ARRAY_SET_FROM_ARRAY_LIKE, JSFunction, \
typed_array_set_from_array_like) \
V(MATH_FLOOR_INDEX, JSFunction, math_floor) \
V(MATH_POW_INDEX, JSFunction, math_pow) \
V(NEW_PROMISE_CAPABILITY_INDEX, JSFunction, new_promise_capability) \
V(PROMISE_INTERNAL_CONSTRUCTOR_INDEX, JSFunction, \
promise_internal_constructor) \
V(PROMISE_INTERNAL_REJECT_INDEX, JSFunction, promise_internal_reject) \
V(IS_PROMISE_INDEX, JSFunction, is_promise) \
V(PROMISE_RESOLVE_INDEX, JSFunction, promise_resolve) \
V(PROMISE_THEN_INDEX, JSFunction, promise_then) \
V(PROMISE_HANDLE_INDEX, JSFunction, promise_handle) \
V(PROMISE_HANDLE_REJECT_INDEX, JSFunction, promise_handle_reject) \
V(ASYNC_GENERATOR_AWAIT_CAUGHT, JSFunction, async_generator_await_caught) \
V(ASYNC_GENERATOR_AWAIT_UNCAUGHT, JSFunction, \
async_generator_await_uncaught) \
V(ASYNC_GENERATOR_YIELD, JSFunction, async_generator_yield) \
#define NATIVE_CONTEXT_INTRINSIC_FUNCTIONS(V) \
V(ASYNC_FUNCTION_AWAIT_CAUGHT_INDEX, JSFunction, \
async_function_await_caught) \
V(ASYNC_FUNCTION_AWAIT_UNCAUGHT_INDEX, JSFunction, \
async_function_await_uncaught) \
V(ASYNC_FUNCTION_PROMISE_CREATE_INDEX, JSFunction, \
async_function_promise_create) \
V(ASYNC_FUNCTION_PROMISE_RELEASE_INDEX, JSFunction, \
async_function_promise_release) \
V(IS_ARRAYLIKE, JSFunction, is_arraylike) \
V(GENERATOR_NEXT_INTERNAL, JSFunction, generator_next_internal) \
V(GET_TEMPLATE_CALL_SITE_INDEX, JSFunction, get_template_call_site) \
V(HAS_ITERATION_SIDE_EFFECTS_INDEX, JSFunction, has_iteration_side_effects) \
V(MAKE_ERROR_INDEX, JSFunction, make_error) \
V(MAKE_RANGE_ERROR_INDEX, JSFunction, make_range_error) \
V(MAKE_SYNTAX_ERROR_INDEX, JSFunction, make_syntax_error) \
V(MAKE_TYPE_ERROR_INDEX, JSFunction, make_type_error) \
V(MAKE_URI_ERROR_INDEX, JSFunction, make_uri_error) \
V(OBJECT_CREATE, JSFunction, object_create) \
V(OBJECT_DEFINE_PROPERTIES, JSFunction, object_define_properties) \
V(OBJECT_DEFINE_PROPERTY, JSFunction, object_define_property) \
V(OBJECT_FREEZE, JSFunction, object_freeze) \
V(OBJECT_GET_PROTOTYPE_OF, JSFunction, object_get_prototype_of) \
V(OBJECT_IS_EXTENSIBLE, JSFunction, object_is_extensible) \
V(OBJECT_IS_FROZEN, JSFunction, object_is_frozen) \
V(OBJECT_IS_SEALED, JSFunction, object_is_sealed) \
V(OBJECT_KEYS, JSFunction, object_keys) \
V(REGEXP_INTERNAL_MATCH, JSFunction, regexp_internal_match) \
V(REFLECT_APPLY_INDEX, JSFunction, reflect_apply) \
V(REFLECT_CONSTRUCT_INDEX, JSFunction, reflect_construct) \
V(REFLECT_DEFINE_PROPERTY_INDEX, JSFunction, reflect_define_property) \
V(REFLECT_DELETE_PROPERTY_INDEX, JSFunction, reflect_delete_property) \
V(SPREAD_ARGUMENTS_INDEX, JSFunction, spread_arguments) \
V(SPREAD_ITERABLE_INDEX, JSFunction, spread_iterable) \
V(TYPED_ARRAY_CONSTRUCT_BY_ARRAY_BUFFER_INDEX, JSFunction, \
typed_array_construct_by_array_buffer) \
V(TYPED_ARRAY_CONSTRUCT_BY_ARRAY_LIKE_INDEX, JSFunction, \
typed_array_construct_by_array_like) \
V(TYPED_ARRAY_CONSTRUCT_BY_LENGTH_INDEX, JSFunction, \
typed_array_construct_by_length) \
V(TYPED_ARRAY_INITIALIZE_INDEX, JSFunction, typed_array_initialize) \
V(TYPED_ARRAY_SET_FROM_ARRAY_LIKE, JSFunction, \
typed_array_set_from_array_like) \
V(MATH_FLOOR_INDEX, JSFunction, math_floor) \
V(MATH_POW_INDEX, JSFunction, math_pow) \
V(NEW_PROMISE_CAPABILITY_INDEX, JSFunction, new_promise_capability) \
V(PROMISE_INTERNAL_CONSTRUCTOR_INDEX, JSFunction, \
promise_internal_constructor) \
V(PROMISE_INTERNAL_REJECT_INDEX, JSFunction, promise_internal_reject) \
V(IS_PROMISE_INDEX, JSFunction, is_promise) \
V(PROMISE_RESOLVE_INDEX, JSFunction, promise_resolve) \
V(PROMISE_THEN_INDEX, JSFunction, promise_then) \
V(PROMISE_HANDLE_INDEX, JSFunction, promise_handle) \
V(PROMISE_HANDLE_REJECT_INDEX, JSFunction, promise_handle_reject) \
V(ASYNC_GENERATOR_AWAIT_CAUGHT, JSFunction, async_generator_await_caught) \
V(ASYNC_GENERATOR_AWAIT_UNCAUGHT, JSFunction, \
async_generator_await_uncaught) \
V(ASYNC_GENERATOR_YIELD, JSFunction, async_generator_yield) \
V(ASYNC_GENERATOR_RAW_YIELD, JSFunction, async_generator_raw_yield)
#define NATIVE_CONTEXT_IMPORTED_FIELDS(V) \

View File

@ -113,23 +113,30 @@ function TypedArraySpeciesCreate(exemplar, arg0, arg1, arg2, conservative) {
macro TYPED_ARRAY_CONSTRUCTOR(NAME, ELEMENT_SIZE)
function NAMEConstructByIterable(obj, iterable, iteratorFn) {
var list = new InternalArray();
// Reading the Symbol.iterator property of iterable twice would be
// observable with getters, so instead, we call the function which
// was already looked up, and wrap it in another iterable. The
// __proto__ of the new iterable is set to null to avoid any chance
// of modifications to Object.prototype being observable here.
var iterator = %_Call(iteratorFn, iterable);
var newIterable = {
__proto__: null
};
// TODO(littledan): Computed properties don't work yet in nosnap.
// Rephrase when they do.
newIterable[iteratorSymbol] = function() { return iterator; }
for (var value of newIterable) {
list.push(value);
if (%has_iteration_side_effects(iterable)) {
var list = new InternalArray();
// Reading the Symbol.iterator property of iterable twice would be
// observable with getters, so instead, we call the function which
// was already looked up, and wrap it in another iterable. The
// __proto__ of the new iterable is set to null to avoid any chance
// of modifications to Object.prototype being observable here.
var iterator = %_Call(iteratorFn, iterable);
var newIterable = {
__proto__: null
};
// TODO(littledan): Computed properties don't work yet in nosnap.
// Rephrase when they do.
newIterable[iteratorSymbol] = function() { return iterator; }
for (var value of newIterable) {
list.push(value);
}
%typed_array_construct_by_array_like(obj, list, list.length, ELEMENT_SIZE);
} else {
// This .length access is unobservable, because it being observable would
// mean that iteration has side effects, and we wouldn't reach this path.
%typed_array_construct_by_array_like(
obj, iterable, iterable.length, ELEMENT_SIZE);
}
%typed_array_construct_by_array_like(obj, list, list.length, ELEMENT_SIZE);
}
// ES#sec-typedarray-typedarray TypedArray ( typedArray )