Commit d2ea316f authored by Benedikt Meurer's avatar Benedikt Meurer Committed by Commit Bot

[map] Properly share the map for builtin iterator result objects.

Previously we had a special, unshared map on the native context that was
used for results of builtin iterators, which was different from the map
that is created from an object literal like `{value, done}`. This not
only leads to unnecessary polymorphism, but also makes it impossible
for user defined iterators to take the fast-paths that we have in
various places (i.e. in collections or promises).

With this change we now properly share the map for `{value, done}` and
use that for the builtin iterator result objects, as well as the
fast-paths.

Drive-by-fix: Remove the restrictions on map caching and transition
caching during bootstrapping. This no longer makes sense.

Bug: v8:9114, v8:9243
Change-Id: I19eb9071f7ec0ed58f8a6f87eed781bc790174b7
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1609794
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61488}
parent f7602bb8
...@@ -3510,26 +3510,32 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object, ...@@ -3510,26 +3510,32 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
} }
{ // -- I t e r a t o r R e s u l t { // -- I t e r a t o r R e s u l t
Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE, JSIteratorResult::kSize, // Setup the map for IterResultObjects created from builtins in such a
TERMINAL_FAST_ELEMENTS_KIND, 2); // way that it's exactly the same map as the one produced by object
Map::SetPrototype(isolate(), map, isolate_->initial_object_prototype()); // literals in the form `{value, done}`. This way we have better sharing
Map::EnsureDescriptorSlack(isolate_, map, 2); // of maps (i.e. less polymorphism) and also make it possible to hit the
// fast-paths in various builtins (i.e. promises and collections) with
{ // value // user defined iterators.
Descriptor d = Descriptor::DataField(isolate(), factory->value_string(), Handle<Map> map = factory->ObjectLiteralMapFromCache(native_context(), 2);
JSIteratorResult::kValueIndex, NONE,
Representation::Tagged()); // value
map->AppendDescriptor(isolate(), &d); map = Map::CopyWithField(isolate(), map, factory->value_string(),
} FieldType::Any(isolate()), NONE,
PropertyConstness::kConst,
{ // done Representation::Tagged(), INSERT_TRANSITION)
Descriptor d = Descriptor::DataField(isolate(), factory->done_string(), .ToHandleChecked();
JSIteratorResult::kDoneIndex, NONE,
Representation::Tagged()); // done
map->AppendDescriptor(isolate(), &d); // TODO(bmeurer): Once FLAG_modify_field_representation_inplace is always
} // on, we can say Representation::HeapObject() here and have the inplace
// update logic take care of the case where someone ever stores a Smi into
// the done field.
map = Map::CopyWithField(isolate(), map, factory->done_string(),
FieldType::Any(isolate()), NONE,
PropertyConstness::kConst,
Representation::Tagged(), INSERT_TRANSITION)
.ToHandleChecked();
map->SetConstructor(native_context()->object_function());
native_context()->set_iterator_result_map(*map); native_context()->set_iterator_result_map(*map);
} }
......
...@@ -3901,11 +3901,6 @@ Handle<Map> Factory::ObjectLiteralMapFromCache(Handle<NativeContext> context, ...@@ -3901,11 +3901,6 @@ Handle<Map> Factory::ObjectLiteralMapFromCache(Handle<NativeContext> context,
return handle(context->object_function()->initial_map(), isolate()); return handle(context->object_function()->initial_map(), isolate());
} }
// We do not cache maps for too many properties or when running builtin code.
if (isolate()->bootstrapper()->IsActive()) {
return Map::Create(isolate(), number_of_properties);
}
// Use initial slow object proto map for too many properties. // Use initial slow object proto map for too many properties.
const int kMapCacheSize = 128; const int kMapCacheSize = 128;
if (number_of_properties > kMapCacheSize) { if (number_of_properties > kMapCacheSize) {
......
...@@ -1700,16 +1700,6 @@ void Map::ConnectTransition(Isolate* isolate, Handle<Map> parent, ...@@ -1700,16 +1700,6 @@ void Map::ConnectTransition(Isolate* isolate, Handle<Map> parent,
child->may_have_interesting_symbols()); child->may_have_interesting_symbols());
DCHECK_IMPLIES(parent->may_have_interesting_symbols(), DCHECK_IMPLIES(parent->may_have_interesting_symbols(),
child->may_have_interesting_symbols()); child->may_have_interesting_symbols());
// Do not track transitions during bootstrap except for element transitions.
if (isolate->bootstrapper()->IsActive() &&
!name.is_identical_to(isolate->factory()->elements_transition_symbol())) {
if (FLAG_trace_maps) {
LOG(isolate,
MapEvent("Transition", *parent, *child,
child->is_prototype_map() ? "prototype" : "", *name));
}
return;
}
if (!parent->GetBackPointer()->IsUndefined(isolate)) { if (!parent->GetBackPointer()->IsUndefined(isolate)) {
parent->set_owns_descriptors(false); parent->set_owns_descriptors(false);
} else { } else {
...@@ -2015,9 +2005,12 @@ Handle<Map> Map::CopyForPreventExtensions( ...@@ -2015,9 +2005,12 @@ Handle<Map> Map::CopyForPreventExtensions(
attrs_to_add); attrs_to_add);
Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(), Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
isolate); isolate);
// Do not track transitions during bootstrapping.
TransitionFlag flag =
isolate->bootstrapper()->IsActive() ? OMIT_TRANSITION : INSERT_TRANSITION;
Handle<Map> new_map = CopyReplaceDescriptors( Handle<Map> new_map = CopyReplaceDescriptors(
isolate, map, new_desc, new_layout_descriptor, INSERT_TRANSITION, isolate, map, new_desc, new_layout_descriptor, flag, transition_marker,
transition_marker, reason, SPECIAL_TRANSITION); reason, SPECIAL_TRANSITION);
new_map->set_is_extensible(false); new_map->set_is_extensible(false);
if (!IsFixedTypedArrayElementsKind(map->elements_kind())) { if (!IsFixedTypedArrayElementsKind(map->elements_kind())) {
ElementsKind new_kind = IsStringWrapperElementsKind(map->elements_kind()) ElementsKind new_kind = IsStringWrapperElementsKind(map->elements_kind())
...@@ -2153,7 +2146,9 @@ Handle<Map> Map::TransitionToDataProperty(Isolate* isolate, Handle<Map> map, ...@@ -2153,7 +2146,9 @@ Handle<Map> Map::TransitionToDataProperty(Isolate* isolate, Handle<Map> map,
value); value);
} }
TransitionFlag flag = INSERT_TRANSITION; // Do not track transitions during bootstrapping.
TransitionFlag flag =
isolate->bootstrapper()->IsActive() ? OMIT_TRANSITION : INSERT_TRANSITION;
MaybeHandle<Map> maybe_map; MaybeHandle<Map> maybe_map;
if (!map->TooManyFastProperties(store_origin)) { if (!map->TooManyFastProperties(store_origin)) {
Representation representation = value->OptimalRepresentation(); Representation representation = value->OptimalRepresentation();
...@@ -2335,7 +2330,9 @@ Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map, ...@@ -2335,7 +2330,9 @@ Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map,
pair->SetComponents(*getter, *setter); pair->SetComponents(*getter, *setter);
TransitionFlag flag = INSERT_TRANSITION; // Do not track transitions during bootstrapping.
TransitionFlag flag =
isolate->bootstrapper()->IsActive() ? OMIT_TRANSITION : INSERT_TRANSITION;
Descriptor d = Descriptor::AccessorConstant(name, pair, attributes); Descriptor d = Descriptor::AccessorConstant(name, pair, attributes);
return Map::CopyInsertDescriptor(isolate, map, &d, flag); return Map::CopyInsertDescriptor(isolate, map, &d, flag);
} }
......
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax
// The special IterResultObject map that builtins use should be the same
// as the one produced by the `{value, done}` object literal.
const user = {value:undefined, done:true};
// Array iterator.
const arrayResult = (new Array())[Symbol.iterator]().next();
assertTrue(%HaveSameMap(user, arrayResult));
// Map iterator.
const mapResult = (new Map())[Symbol.iterator]().next();
assertTrue(%HaveSameMap(user, mapResult));
// Set iterator.
const setResult = (new Set())[Symbol.iterator]().next();
assertTrue(%HaveSameMap(user, setResult));
// Generator.
function* generator() {}
const generatorResult = generator().next();
assertTrue(%HaveSameMap(user, setResult));
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment