[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:
parent
3f8b2aeb35
commit
143dcc6c41
@ -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 ---
|
||||
|
@ -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
|
||||
|
@ -236,6 +236,7 @@ namespace internal {
|
||||
/* Array */ \
|
||||
ASM(ArrayCode) \
|
||||
ASM(InternalArrayCode) \
|
||||
CPP(HasIterationSideEffects) \
|
||||
CPP(ArrayConcat) \
|
||||
/* ES6 #sec-array.isarray */ \
|
||||
TFJ(ArrayIsArray, 1, kArg) \
|
||||
|
115
src/contexts.h
115
src/contexts.h
@ -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) \
|
||||
|
@ -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 )
|
||||
|
Loading…
Reference in New Issue
Block a user