| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index fa6edfced8ea41e77f42f251ed4e75bb7a180f20..c2b15a13278b5443a2898b575bd3bf6ddf86548e 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -3216,10 +3216,10 @@ int Map::NumberOfFields() {
|
| return result;
|
| }
|
|
|
| -
|
| Handle<Map> Map::CopyGeneralizeAllRepresentations(
|
| - Handle<Map> map, int modify_index, StoreMode store_mode, PropertyKind kind,
|
| - PropertyAttributes attributes, const char* reason) {
|
| + Handle<Map> map, ElementsKind elements_kind, int modify_index,
|
| + StoreMode store_mode, PropertyKind kind, PropertyAttributes attributes,
|
| + const char* reason) {
|
| Isolate* isolate = map->GetIsolate();
|
| Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
|
| int number_of_own_descriptors = map->NumberOfOwnDescriptors();
|
| @@ -3275,6 +3275,7 @@ Handle<Map> Map::CopyGeneralizeAllRepresentations(
|
| MaybeHandle<Object>());
|
| }
|
| }
|
| + new_map->set_elements_kind(elements_kind);
|
| return new_map;
|
| }
|
|
|
| @@ -3527,9 +3528,9 @@ static inline Handle<FieldType> GetFieldType(
|
| }
|
| }
|
|
|
| -
|
| -// Reconfigures property at |modify_index| with |new_kind|, |new_attributes|,
|
| -// |store_mode| and/or |new_representation|/|new_field_type|.
|
| +// Reconfigures elements kind to |new_elements_kind| and/or property at
|
| +// |modify_index| with |new_kind|, |new_attributes|, |store_mode| and/or
|
| +// |new_representation|/|new_field_type|.
|
| // If |modify_index| is negative then no properties are reconfigured but the
|
| // map is migrated to the up-to-date non-deprecated state.
|
| //
|
| @@ -3539,6 +3540,7 @@ static inline Handle<FieldType> GetFieldType(
|
| // any potential new (partial) version of the type in the transition tree.
|
| // To do this, on each rewrite:
|
| // - Search the root of the transition tree using FindRootMap.
|
| +// - Find/create a |root_map| with requested |new_elements_kind|.
|
| // - Find |target_map|, the newest matching version of this map using the
|
| // virtually "enhanced" |old_map|'s descriptor array (i.e. whose entry at
|
| // |modify_index| is considered to be of |new_kind| and having
|
| @@ -3554,12 +3556,13 @@ static inline Handle<FieldType> GetFieldType(
|
| // Return it.
|
| // - Otherwise, invalidate the outdated transition target from |target_map|, and
|
| // replace its transition tree with a new branch for the updated descriptors.
|
| -Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
|
| - PropertyKind new_kind,
|
| - PropertyAttributes new_attributes,
|
| - Representation new_representation,
|
| - Handle<FieldType> new_field_type,
|
| - StoreMode store_mode) {
|
| +Handle<Map> Map::Reconfigure(Handle<Map> old_map,
|
| + ElementsKind new_elements_kind, int modify_index,
|
| + PropertyKind new_kind,
|
| + PropertyAttributes new_attributes,
|
| + Representation new_representation,
|
| + Handle<FieldType> new_field_type,
|
| + StoreMode store_mode) {
|
| DCHECK_NE(kAccessor, new_kind); // TODO(ishell): not supported yet.
|
| DCHECK(store_mode != FORCE_FIELD || modify_index >= 0);
|
| Isolate* isolate = old_map->GetIsolate();
|
| @@ -3574,7 +3577,8 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
|
| // uninitialized value for representation None can be overwritten by both
|
| // smi and tagged values. Doubles, however, would require a box allocation.
|
| if (modify_index >= 0 && !new_representation.IsNone() &&
|
| - !new_representation.IsDouble()) {
|
| + !new_representation.IsDouble() &&
|
| + old_map->elements_kind() == new_elements_kind) {
|
| PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
|
| Representation old_representation = old_details.representation();
|
|
|
| @@ -3607,38 +3611,39 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
|
| // Check the state of the root map.
|
| Handle<Map> root_map(old_map->FindRootMap(), isolate);
|
| if (!old_map->EquivalentToForTransition(*root_map)) {
|
| - return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
|
| - new_kind, new_attributes,
|
| - "GenAll_NotEquivalent");
|
| + return CopyGeneralizeAllRepresentations(
|
| + old_map, new_elements_kind, modify_index, store_mode, new_kind,
|
| + new_attributes, "GenAll_NotEquivalent");
|
| }
|
|
|
| ElementsKind from_kind = root_map->elements_kind();
|
| - ElementsKind to_kind = old_map->elements_kind();
|
| + ElementsKind to_kind = new_elements_kind;
|
| // TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS.
|
| if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS &&
|
| + to_kind != SLOW_STRING_WRAPPER_ELEMENTS &&
|
| to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS &&
|
| !(IsTransitionableFastElementsKind(from_kind) &&
|
| IsMoreGeneralElementsKindTransition(from_kind, to_kind))) {
|
| - return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
|
| - new_kind, new_attributes,
|
| - "GenAll_InvalidElementsTransition");
|
| + return CopyGeneralizeAllRepresentations(
|
| + old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
|
| + "GenAll_InvalidElementsTransition");
|
| }
|
| int root_nof = root_map->NumberOfOwnDescriptors();
|
| if (modify_index >= 0 && modify_index < root_nof) {
|
| PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
|
| if (old_details.kind() != new_kind ||
|
| old_details.attributes() != new_attributes) {
|
| - return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
|
| - new_kind, new_attributes,
|
| - "GenAll_RootModification1");
|
| + return CopyGeneralizeAllRepresentations(
|
| + old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
|
| + "GenAll_RootModification1");
|
| }
|
| if ((old_details.type() != DATA && store_mode == FORCE_FIELD) ||
|
| (old_details.type() == DATA &&
|
| (!new_field_type->NowIs(old_descriptors->GetFieldType(modify_index)) ||
|
| !new_representation.fits_into(old_details.representation())))) {
|
| - return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
|
| - new_kind, new_attributes,
|
| - "GenAll_RootModification2");
|
| + return CopyGeneralizeAllRepresentations(
|
| + old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
|
| + "GenAll_RootModification2");
|
| }
|
| }
|
|
|
| @@ -3692,9 +3697,9 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
|
| if (next_kind == kAccessor &&
|
| !EqualImmutableValues(old_descriptors->GetValue(i),
|
| tmp_descriptors->GetValue(i))) {
|
| - return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
|
| - new_kind, new_attributes,
|
| - "GenAll_Incompatible");
|
| + return CopyGeneralizeAllRepresentations(
|
| + old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
|
| + "GenAll_Incompatible");
|
| }
|
| if (next_location == kField && tmp_details.location() == kDescriptor) break;
|
|
|
| @@ -3787,9 +3792,9 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
|
| if (next_kind == kAccessor &&
|
| !EqualImmutableValues(old_descriptors->GetValue(i),
|
| tmp_descriptors->GetValue(i))) {
|
| - return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
|
| - new_kind, new_attributes,
|
| - "GenAll_Incompatible");
|
| + return CopyGeneralizeAllRepresentations(
|
| + old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
|
| + "GenAll_Incompatible");
|
| }
|
| DCHECK(!tmp_map->is_deprecated());
|
| target_map = tmp_map;
|
| @@ -4020,9 +4025,9 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
|
| // could be inserted regardless of whether transitions array is full or not.
|
| if (maybe_transition == NULL &&
|
| !TransitionArray::CanHaveMoreTransitions(split_map)) {
|
| - return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
|
| - new_kind, new_attributes,
|
| - "GenAll_CantHaveMoreTransitions");
|
| + return CopyGeneralizeAllRepresentations(
|
| + old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
|
| + "GenAll_CantHaveMoreTransitions");
|
| }
|
|
|
| old_map->NotifyLeafMapLayoutChange();
|
| @@ -4103,18 +4108,27 @@ MaybeHandle<Map> Map::TryUpdate(Handle<Map> old_map) {
|
| if (root_map == NULL) return MaybeHandle<Map>();
|
| // From here on, use the map with correct elements kind as root map.
|
| }
|
| - int root_nof = root_map->NumberOfOwnDescriptors();
|
| + Map* new_map = root_map->TryReplayPropertyTransitions(*old_map);
|
| + if (new_map == nullptr) return MaybeHandle<Map>();
|
| + return handle(new_map);
|
| +}
|
| +
|
| +Map* Map::TryReplayPropertyTransitions(Map* old_map) {
|
| + DisallowHeapAllocation no_allocation;
|
| + DisallowDeoptimization no_deoptimization(GetIsolate());
|
| +
|
| + int root_nof = NumberOfOwnDescriptors();
|
|
|
| int old_nof = old_map->NumberOfOwnDescriptors();
|
| DescriptorArray* old_descriptors = old_map->instance_descriptors();
|
|
|
| - Map* new_map = root_map;
|
| + Map* new_map = this;
|
| for (int i = root_nof; i < old_nof; ++i) {
|
| PropertyDetails old_details = old_descriptors->GetDetails(i);
|
| Map* transition = TransitionArray::SearchTransition(
|
| new_map, old_details.kind(), old_descriptors->GetKey(i),
|
| old_details.attributes());
|
| - if (transition == NULL) return MaybeHandle<Map>();
|
| + if (transition == NULL) return nullptr;
|
| new_map = transition;
|
| DescriptorArray* new_descriptors = new_map->instance_descriptors();
|
|
|
| @@ -4122,7 +4136,7 @@ MaybeHandle<Map> Map::TryUpdate(Handle<Map> old_map) {
|
| DCHECK_EQ(old_details.kind(), new_details.kind());
|
| DCHECK_EQ(old_details.attributes(), new_details.attributes());
|
| if (!old_details.representation().fits_into(new_details.representation())) {
|
| - return MaybeHandle<Map>();
|
| + return nullptr;
|
| }
|
| switch (new_details.type()) {
|
| case DATA: {
|
| @@ -4130,20 +4144,20 @@ MaybeHandle<Map> Map::TryUpdate(Handle<Map> old_map) {
|
| // Cleared field types need special treatment. They represent lost
|
| // knowledge, so we must first generalize the new_type to "Any".
|
| if (FieldTypeIsCleared(new_details.representation(), new_type)) {
|
| - return MaybeHandle<Map>();
|
| + return nullptr;
|
| }
|
| PropertyType old_property_type = old_details.type();
|
| if (old_property_type == DATA) {
|
| FieldType* old_type = old_descriptors->GetFieldType(i);
|
| if (FieldTypeIsCleared(old_details.representation(), old_type) ||
|
| !old_type->NowIs(new_type)) {
|
| - return MaybeHandle<Map>();
|
| + return nullptr;
|
| }
|
| } else {
|
| DCHECK(old_property_type == DATA_CONSTANT);
|
| Object* old_value = old_descriptors->GetValue(i);
|
| if (!new_type->NowContains(old_value)) {
|
| - return MaybeHandle<Map>();
|
| + return nullptr;
|
| }
|
| }
|
| break;
|
| @@ -4161,14 +4175,14 @@ MaybeHandle<Map> Map::TryUpdate(Handle<Map> old_map) {
|
| Object* old_value = old_descriptors->GetValue(i);
|
| Object* new_value = new_descriptors->GetValue(i);
|
| if (old_details.location() == kField || old_value != new_value) {
|
| - return MaybeHandle<Map>();
|
| + return nullptr;
|
| }
|
| break;
|
| }
|
| }
|
| }
|
| - if (new_map->NumberOfOwnDescriptors() != old_nof) return MaybeHandle<Map>();
|
| - return handle(new_map);
|
| + if (new_map->NumberOfOwnDescriptors() != old_nof) return nullptr;
|
| + return new_map;
|
| }
|
|
|
|
|
| @@ -4761,17 +4775,28 @@ static bool ContainsMap(MapHandleList* maps, Map* map) {
|
| return false;
|
| }
|
|
|
| +Map* Map::FindElementsKindTransitionedMap(MapHandleList* candidates) {
|
| + DisallowHeapAllocation no_allocation;
|
| + DisallowDeoptimization no_deoptimization(GetIsolate());
|
|
|
| -Handle<Map> Map::FindTransitionedMap(Handle<Map> map,
|
| - MapHandleList* candidates) {
|
| - ElementsKind kind = map->elements_kind();
|
| + ElementsKind kind = elements_kind();
|
| bool packed = IsFastPackedElementsKind(kind);
|
|
|
| Map* transition = nullptr;
|
| if (IsTransitionableFastElementsKind(kind)) {
|
| - for (Map* current = map->ElementsTransitionMap();
|
| - current != nullptr && current->has_fast_elements();
|
| - current = current->ElementsTransitionMap()) {
|
| + // Check the state of the root map.
|
| + Map* root_map = FindRootMap();
|
| + if (!EquivalentToForTransition(root_map)) return nullptr;
|
| + root_map = root_map->LookupElementsTransitionMap(kind);
|
| + DCHECK_NOT_NULL(root_map);
|
| + // Starting from the next existing elements kind transition try to
|
| + // replay the property transitions.
|
| + for (root_map = root_map->ElementsTransitionMap();
|
| + root_map != nullptr && root_map->has_fast_elements();
|
| + root_map = root_map->ElementsTransitionMap()) {
|
| + Map* current = root_map->TryReplayPropertyTransitions(this);
|
| + if (current == nullptr) continue;
|
| +
|
| if (ContainsMap(candidates, current) &&
|
| (packed || !IsFastPackedElementsKind(current->elements_kind()))) {
|
| transition = current;
|
| @@ -4779,11 +4804,14 @@ Handle<Map> Map::FindTransitionedMap(Handle<Map> map,
|
| }
|
| }
|
| }
|
| - return transition == nullptr ? Handle<Map>() : handle(transition);
|
| + return transition;
|
| }
|
|
|
|
|
| static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
|
| + // Ensure we are requested to search elements kind transition "near the root".
|
| + DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(),
|
| + map->NumberOfOwnDescriptors());
|
| Map* current_map = map;
|
|
|
| ElementsKind kind = map->elements_kind();
|
| @@ -4912,7 +4940,7 @@ Handle<Map> Map::TransitionElementsTo(Handle<Map> map,
|
| return Map::CopyAsElementsKind(map, to_kind, OMIT_TRANSITION);
|
| }
|
|
|
| - return Map::AsElementsKind(map, to_kind);
|
| + return Map::ReconfigureElementsKind(map, to_kind);
|
| }
|
|
|
|
|
| @@ -5274,7 +5302,7 @@ void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
|
| } else {
|
| TransitionElementsKind(object, to_kind);
|
| }
|
| - map = Map::AsElementsKind(map, to_kind);
|
| + map = Map::ReconfigureElementsKind(map, to_kind);
|
| }
|
| JSObject::MigrateToMap(object, map);
|
| }
|
| @@ -8857,6 +8885,10 @@ Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind,
|
| TransitionFlag flag) {
|
| Map* maybe_elements_transition_map = NULL;
|
| if (flag == INSERT_TRANSITION) {
|
| + // Ensure we are requested to add elements kind transition "near the root".
|
| + DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(),
|
| + map->NumberOfOwnDescriptors());
|
| +
|
| maybe_elements_transition_map = map->ElementsTransitionMap();
|
| DCHECK(maybe_elements_transition_map == NULL ||
|
| (maybe_elements_transition_map->elements_kind() ==
|
| @@ -9161,7 +9193,7 @@ Handle<Map> Map::ReconfigureExistingProperty(Handle<Map> map, int descriptor,
|
| // There is no benefit from reconstructing transition tree for maps without
|
| // back pointers.
|
| return CopyGeneralizeAllRepresentations(
|
| - map, descriptor, FORCE_FIELD, kind, attributes,
|
| + map, map->elements_kind(), descriptor, FORCE_FIELD, kind, attributes,
|
| "GenAll_AttributesMismatchProtoMap");
|
| }
|
|
|
|
|