| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index 425d7703752554a1dd6a264ba1733402d1df7d59..775a66479bff7cd527592cacadfb79f491610a47 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -1269,6 +1269,25 @@ void JSObject::PrintElementsTransition(
|
| }
|
|
|
|
|
| +void Map::PrintReconfiguration(FILE* file, int modify_index, PropertyKind kind,
|
| + PropertyAttributes attributes) {
|
| + OFStream os(file);
|
| + os << "[reconfiguring ";
|
| + constructor_name()->PrintOn(file);
|
| + os << "] ";
|
| + Name* name = instance_descriptors()->GetKey(modify_index);
|
| + if (name->IsString()) {
|
| + String::cast(name)->PrintOn(file);
|
| + } else {
|
| + os << "{symbol " << static_cast<void*>(name) << "}";
|
| + }
|
| + os << ": " << (kind == kData ? "kData" : "ACCESSORS") << ", attrs: ";
|
| + os << attributes << " [";
|
| + JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
|
| + os << "]\n";
|
| +}
|
| +
|
| +
|
| void Map::PrintGeneralization(FILE* file,
|
| const char* reason,
|
| int modify_index,
|
| @@ -1977,15 +1996,19 @@ void JSObject::MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
|
| PropertyDetails details = new_descriptors->GetDetails(i);
|
| if (details.type() != DATA) continue;
|
| PropertyDetails old_details = old_descriptors->GetDetails(i);
|
| - if (old_details.type() == ACCESSOR_CONSTANT) {
|
| - DCHECK(details.representation().IsTagged());
|
| - continue;
|
| - }
|
| Representation old_representation = old_details.representation();
|
| Representation representation = details.representation();
|
| - DCHECK(old_details.type() == DATA_CONSTANT || old_details.type() == DATA);
|
| Handle<Object> value;
|
| - if (old_details.type() == DATA_CONSTANT) {
|
| + if (old_details.type() == ACCESSOR_CONSTANT) {
|
| + // In case of kAccessor -> kData property reconfiguration, the property
|
| + // must already be prepared for data or certain type.
|
| + DCHECK(!details.representation().IsNone());
|
| + if (details.representation().IsDouble()) {
|
| + value = isolate->factory()->NewHeapNumber(0, MUTABLE);
|
| + } else {
|
| + value = isolate->factory()->uninitialized_value();
|
| + }
|
| + } else if (old_details.type() == DATA_CONSTANT) {
|
| value = handle(old_descriptors->GetValue(i), isolate);
|
| DCHECK(!old_representation.IsDouble() && !representation.IsDouble());
|
| } else {
|
| @@ -2079,17 +2102,15 @@ int Map::NumberOfFields() {
|
| DescriptorArray* descriptors = instance_descriptors();
|
| int result = 0;
|
| for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
|
| - if (descriptors->GetDetails(i).type() == DATA) result++;
|
| + if (descriptors->GetDetails(i).location() == kField) result++;
|
| }
|
| return result;
|
| }
|
|
|
|
|
| -Handle<Map> Map::CopyGeneralizeAllRepresentations(Handle<Map> map,
|
| - int modify_index,
|
| - StoreMode store_mode,
|
| - PropertyAttributes attributes,
|
| - const char* reason) {
|
| +Handle<Map> Map::CopyGeneralizeAllRepresentations(
|
| + Handle<Map> map, 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();
|
| @@ -2110,53 +2131,43 @@ Handle<Map> Map::CopyGeneralizeAllRepresentations(Handle<Map> map,
|
| MaybeHandle<Name>(), reason, SPECIAL_TRANSITION);
|
|
|
| // Unless the instance is being migrated, ensure that modify_index is a field.
|
| - PropertyDetails details = descriptors->GetDetails(modify_index);
|
| - if (store_mode == FORCE_FIELD &&
|
| - (details.type() != DATA || details.attributes() != attributes)) {
|
| - int field_index = details.type() == DATA ? details.field_index()
|
| - : new_map->NumberOfFields();
|
| - DataDescriptor d(handle(descriptors->GetKey(modify_index), isolate),
|
| - field_index, attributes, Representation::Tagged());
|
| - descriptors->Replace(modify_index, &d);
|
| - if (details.type() != DATA) {
|
| - int unused_property_fields = new_map->unused_property_fields() - 1;
|
| - if (unused_property_fields < 0) {
|
| - unused_property_fields += JSObject::kFieldsAdded;
|
| + if (modify_index >= 0) {
|
| + PropertyDetails details = descriptors->GetDetails(modify_index);
|
| + if (store_mode == FORCE_FIELD &&
|
| + (details.type() != DATA || details.attributes() != attributes)) {
|
| + int field_index = details.type() == DATA ? details.field_index()
|
| + : new_map->NumberOfFields();
|
| + DataDescriptor d(handle(descriptors->GetKey(modify_index), isolate),
|
| + field_index, attributes, Representation::Tagged());
|
| + descriptors->Replace(modify_index, &d);
|
| + if (details.type() != DATA) {
|
| + int unused_property_fields = new_map->unused_property_fields() - 1;
|
| + if (unused_property_fields < 0) {
|
| + unused_property_fields += JSObject::kFieldsAdded;
|
| + }
|
| + new_map->set_unused_property_fields(unused_property_fields);
|
| }
|
| - new_map->set_unused_property_fields(unused_property_fields);
|
| + } else {
|
| + DCHECK(details.attributes() == attributes);
|
| }
|
| - } else {
|
| - DCHECK(details.attributes() == attributes);
|
| - }
|
|
|
| - if (FLAG_trace_generalization) {
|
| - HeapType* field_type =
|
| - (details.type() == DATA)
|
| - ? map->instance_descriptors()->GetFieldType(modify_index)
|
| - : NULL;
|
| - map->PrintGeneralization(
|
| - stdout, reason, modify_index, new_map->NumberOfOwnDescriptors(),
|
| - new_map->NumberOfOwnDescriptors(),
|
| - details.type() == DATA_CONSTANT && store_mode == FORCE_FIELD,
|
| - details.representation(), Representation::Tagged(), field_type,
|
| - HeapType::Any());
|
| + if (FLAG_trace_generalization) {
|
| + HeapType* field_type =
|
| + (details.type() == DATA)
|
| + ? map->instance_descriptors()->GetFieldType(modify_index)
|
| + : NULL;
|
| + map->PrintGeneralization(
|
| + stdout, reason, modify_index, new_map->NumberOfOwnDescriptors(),
|
| + new_map->NumberOfOwnDescriptors(),
|
| + details.type() == DATA_CONSTANT && store_mode == FORCE_FIELD,
|
| + details.representation(), Representation::Tagged(), field_type,
|
| + HeapType::Any());
|
| + }
|
| }
|
| return new_map;
|
| }
|
|
|
|
|
| -// static
|
| -Handle<Map> Map::CopyGeneralizeAllRepresentations(Handle<Map> map,
|
| - int modify_index,
|
| - StoreMode store_mode,
|
| - const char* reason) {
|
| - PropertyDetails details =
|
| - map->instance_descriptors()->GetDetails(modify_index);
|
| - return CopyGeneralizeAllRepresentations(map, modify_index, store_mode,
|
| - details.attributes(), reason);
|
| -}
|
| -
|
| -
|
| void Map::DeprecateTransitionTree() {
|
| if (is_deprecated()) return;
|
| if (HasTransitionArray()) {
|
| @@ -2172,6 +2183,13 @@ void Map::DeprecateTransitionTree() {
|
| }
|
|
|
|
|
| +static inline bool EqualImmutableValues(Object* obj1, Object* obj2) {
|
| + if (obj1 == obj2) return true; // Valid for both kData and kAccessor kinds.
|
| + // TODO(ishell): compare AccessorPairs.
|
| + return false;
|
| +}
|
| +
|
| +
|
| // Invalidates a transition target at |key|, and installs |new_descriptors| over
|
| // the current instance_descriptors to ensure proper sharing of descriptor
|
| // arrays.
|
| @@ -2242,16 +2260,22 @@ Map* Map::FindLastMatchMap(int verbatim,
|
| DescriptorArray* next_descriptors = next->instance_descriptors();
|
|
|
| PropertyDetails next_details = next_descriptors->GetDetails(i);
|
| - if (details.type() != next_details.type()) break;
|
| - if (details.attributes() != next_details.attributes()) break;
|
| + DCHECK_EQ(details.kind(), next_details.kind());
|
| + DCHECK_EQ(details.attributes(), next_details.attributes());
|
| + if (details.location() != next_details.location()) break;
|
| if (!details.representation().Equals(next_details.representation())) break;
|
| - if (next_details.type() == DATA) {
|
| - if (!descriptors->GetFieldType(i)->NowIs(
|
| - next_descriptors->GetFieldType(i))) break;
|
| +
|
| + if (next_details.location() == kField) {
|
| + HeapType* next_field_type = next_descriptors->GetFieldType(i);
|
| + if (!descriptors->GetFieldType(i)->NowIs(next_field_type)) {
|
| + break;
|
| + }
|
| } else {
|
| - if (descriptors->GetValue(i) != next_descriptors->GetValue(i)) break;
|
| + if (!EqualImmutableValues(descriptors->GetValue(i),
|
| + next_descriptors->GetValue(i))) {
|
| + break;
|
| + }
|
| }
|
| -
|
| current = next;
|
| }
|
| return current;
|
| @@ -2367,16 +2391,42 @@ void Map::GeneralizeFieldType(Handle<Map> map, int modify_index,
|
| }
|
|
|
|
|
| -// Generalize the representation of the descriptor at |modify_index|.
|
| -// This method rewrites the transition tree to reflect the new change. To avoid
|
| -// high degrees over polymorphism, and to stabilize quickly, on every rewrite
|
| -// the new type is deduced by merging the current type with any potential new
|
| -// (partial) version of the type in the transition tree.
|
| +static inline Handle<HeapType> GetFieldType(Isolate* isolate,
|
| + Handle<DescriptorArray> descriptors,
|
| + int descriptor,
|
| + PropertyLocation location,
|
| + Representation representation) {
|
| +#ifdef DEBUG
|
| + PropertyDetails details = descriptors->GetDetails(descriptor);
|
| + DCHECK_EQ(kData, details.kind());
|
| + DCHECK_EQ(details.location(), location);
|
| +#endif
|
| + if (location == kField) {
|
| + return handle(descriptors->GetFieldType(descriptor), isolate);
|
| + } else {
|
| + return descriptors->GetValue(descriptor)
|
| + ->OptimalType(isolate, representation);
|
| + }
|
| +}
|
| +
|
| +
|
| +// Reconfigures 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.
|
| +//
|
| +// This method rewrites or completes the transition tree to reflect the new
|
| +// change. To avoid high degrees over polymorphism, and to stabilize quickly,
|
| +// on every rewrite the new type is deduced by merging the current type with
|
| +// 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 |target_map|, the newest matching version of this map using the keys
|
| -// in the |old_map|'s descriptor array to walk the transition tree.
|
| -// - Merge/generalize the descriptor array of the |old_map| and |target_map|.
|
| +// - 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
|
| +// |new_attributes|) to walk the transition tree.
|
| +// - Merge/generalize the "enhanced" descriptor array of the |old_map| and
|
| +// descriptor array of the |target_map|.
|
| // - Generalize the |modify_index| descriptor using |new_representation| and
|
| // |new_field_type|.
|
| // - Walk the tree again starting from the root towards |target_map|. Stop at
|
| @@ -2386,68 +2436,113 @@ void Map::GeneralizeFieldType(Handle<Map> map, int modify_index,
|
| // 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::GeneralizeRepresentation(Handle<Map> old_map,
|
| - int modify_index,
|
| - Representation new_representation,
|
| - Handle<HeapType> new_field_type,
|
| - StoreMode store_mode) {
|
| +Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
|
| + PropertyKind new_kind,
|
| + PropertyAttributes new_attributes,
|
| + Representation new_representation,
|
| + Handle<HeapType> 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();
|
|
|
| Handle<DescriptorArray> old_descriptors(
|
| old_map->instance_descriptors(), isolate);
|
| int old_nof = old_map->NumberOfOwnDescriptors();
|
| - PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
|
| - Representation old_representation = old_details.representation();
|
| -
|
| - // It's fine to transition from None to anything but double without any
|
| - // modification to the object, because the default uninitialized value for
|
| - // representation None can be overwritten by both smi and tagged values.
|
| - // Doubles, however, would require a box allocation.
|
| - if (old_representation.IsNone() && !new_representation.IsNone() &&
|
| +
|
| + // If it's just a representation generalization case (i.e. property kind and
|
| + // attributes stays unchanged) it's fine to transition from None to anything
|
| + // but double without any modification to the object, because the default
|
| + // 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()) {
|
| - DCHECK(old_details.type() == DATA);
|
| - if (FLAG_trace_generalization) {
|
| - old_map->PrintGeneralization(
|
| - stdout, "uninitialized field",
|
| - modify_index, old_map->NumberOfOwnDescriptors(),
|
| - old_map->NumberOfOwnDescriptors(), false,
|
| - old_representation, new_representation,
|
| - old_descriptors->GetFieldType(modify_index), *new_field_type);
|
| - }
|
| - Handle<Map> field_owner(old_map->FindFieldOwner(modify_index), isolate);
|
| + PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
|
| + Representation old_representation = old_details.representation();
|
| +
|
| + if (old_representation.IsNone()) {
|
| + DCHECK_EQ(new_kind, old_details.kind());
|
| + DCHECK_EQ(new_attributes, old_details.attributes());
|
| + DCHECK_EQ(DATA, old_details.type());
|
| + if (FLAG_trace_generalization) {
|
| + old_map->PrintGeneralization(
|
| + stdout, "uninitialized field", modify_index,
|
| + old_map->NumberOfOwnDescriptors(),
|
| + old_map->NumberOfOwnDescriptors(), false, old_representation,
|
| + new_representation, old_descriptors->GetFieldType(modify_index),
|
| + *new_field_type);
|
| + }
|
| + Handle<Map> field_owner(old_map->FindFieldOwner(modify_index), isolate);
|
|
|
| - GeneralizeFieldType(field_owner, modify_index, new_representation,
|
| - new_field_type);
|
| - DCHECK(old_descriptors->GetDetails(modify_index).representation().Equals(
|
| - new_representation));
|
| - DCHECK(old_descriptors->GetFieldType(modify_index)->NowIs(new_field_type));
|
| - return old_map;
|
| + GeneralizeFieldType(field_owner, modify_index, new_representation,
|
| + new_field_type);
|
| + DCHECK(old_descriptors->GetDetails(modify_index)
|
| + .representation()
|
| + .Equals(new_representation));
|
| + DCHECK(
|
| + old_descriptors->GetFieldType(modify_index)->NowIs(new_field_type));
|
| + return old_map;
|
| + }
|
| }
|
|
|
| // 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");
|
| }
|
| int root_nof = root_map->NumberOfOwnDescriptors();
|
| - if (modify_index < root_nof) {
|
| + 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");
|
| + }
|
| 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,
|
| - "GenAll_RootModification");
|
| + new_kind, new_attributes,
|
| + "GenAll_RootModification2");
|
| }
|
| }
|
|
|
| Handle<Map> target_map = root_map;
|
| for (int i = root_nof; i < old_nof; ++i) {
|
| PropertyDetails old_details = old_descriptors->GetDetails(i);
|
| - int j = target_map->SearchTransition(old_details.kind(),
|
| - old_descriptors->GetKey(i),
|
| - old_details.attributes());
|
| + PropertyKind next_kind;
|
| + PropertyLocation next_location;
|
| + PropertyAttributes next_attributes;
|
| + Representation next_representation;
|
| + bool property_kind_reconfiguration = false;
|
| +
|
| + if (modify_index == i) {
|
| + DCHECK_EQ(FORCE_FIELD, store_mode);
|
| + property_kind_reconfiguration = old_details.kind() != new_kind;
|
| +
|
| + next_kind = new_kind;
|
| + next_location = kField;
|
| + next_attributes = new_attributes;
|
| + // If property kind is not reconfigured merge the result with
|
| + // representation/field type from the old descriptor.
|
| + next_representation = new_representation;
|
| + if (!property_kind_reconfiguration) {
|
| + next_representation =
|
| + next_representation.generalize(old_details.representation());
|
| + }
|
| +
|
| + } else {
|
| + next_kind = old_details.kind();
|
| + next_location = old_details.location();
|
| + next_attributes = old_details.attributes();
|
| + next_representation = old_details.representation();
|
| + }
|
| + int j = target_map->SearchTransition(next_kind, old_descriptors->GetKey(i),
|
| + next_attributes);
|
| if (j == TransitionArray::kNotFound) break;
|
| Handle<Map> tmp_map(target_map->GetTransition(j), isolate);
|
| Handle<DescriptorArray> tmp_descriptors = handle(
|
| @@ -2455,42 +2550,48 @@ Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
|
|
|
| // Check if target map is incompatible.
|
| PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
|
| - PropertyType old_type = old_details.type();
|
| - PropertyType tmp_type = tmp_details.type();
|
| - DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
|
| - if ((tmp_type == ACCESSOR_CONSTANT || old_type == ACCESSOR_CONSTANT) &&
|
| - (tmp_type != old_type ||
|
| - tmp_descriptors->GetValue(i) != old_descriptors->GetValue(i))) {
|
| + DCHECK_EQ(next_kind, tmp_details.kind());
|
| + DCHECK_EQ(next_attributes, tmp_details.attributes());
|
| + 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");
|
| }
|
| - Representation old_representation = old_details.representation();
|
| + if (next_location == kField && tmp_details.location() == kDescriptor) break;
|
| +
|
| Representation tmp_representation = tmp_details.representation();
|
| - if (!old_representation.fits_into(tmp_representation) ||
|
| - (!new_representation.fits_into(tmp_representation) &&
|
| - modify_index == i)) {
|
| - break;
|
| - }
|
| - if (tmp_type == DATA) {
|
| - // Generalize the field type as necessary.
|
| - Handle<HeapType> old_field_type =
|
| - (old_type == DATA) ? handle(old_descriptors->GetFieldType(i), isolate)
|
| - : old_descriptors->GetValue(i)
|
| - ->OptimalType(isolate, tmp_representation);
|
| - if (modify_index == i) {
|
| - old_field_type = GeneralizeFieldType(
|
| - new_field_type, old_field_type, isolate);
|
| - }
|
| - GeneralizeFieldType(tmp_map, i, tmp_representation, old_field_type);
|
| - } else if (tmp_type == DATA_CONSTANT) {
|
| - if (old_type != DATA_CONSTANT ||
|
| - old_descriptors->GetConstant(i) != tmp_descriptors->GetConstant(i)) {
|
| - break;
|
| + if (!next_representation.fits_into(tmp_representation)) break;
|
| +
|
| + PropertyLocation old_location = old_details.location();
|
| + PropertyLocation tmp_location = tmp_details.location();
|
| + if (tmp_location == kField) {
|
| + if (next_kind == kData) {
|
| + Handle<HeapType> next_field_type;
|
| + if (modify_index == i) {
|
| + next_field_type = new_field_type;
|
| + if (!property_kind_reconfiguration) {
|
| + Handle<HeapType> old_field_type =
|
| + GetFieldType(isolate, old_descriptors, i,
|
| + old_details.location(), tmp_representation);
|
| + next_field_type =
|
| + GeneralizeFieldType(next_field_type, old_field_type, isolate);
|
| + }
|
| + } else {
|
| + Handle<HeapType> old_field_type =
|
| + GetFieldType(isolate, old_descriptors, i, old_details.location(),
|
| + tmp_representation);
|
| + next_field_type = old_field_type;
|
| + }
|
| + GeneralizeFieldType(tmp_map, i, tmp_representation, next_field_type);
|
| }
|
| - } else {
|
| - DCHECK_EQ(tmp_type, old_type);
|
| - DCHECK_EQ(tmp_descriptors->GetValue(i), old_descriptors->GetValue(i));
|
| + } else if (old_location == kField ||
|
| + !EqualImmutableValues(old_descriptors->GetValue(i),
|
| + tmp_descriptors->GetValue(i))) {
|
| + break;
|
| }
|
| + DCHECK(!tmp_map->is_deprecated());
|
| target_map = tmp_map;
|
| }
|
|
|
| @@ -2500,37 +2601,55 @@ Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
|
| int target_nof = target_map->NumberOfOwnDescriptors();
|
| if (target_nof == old_nof &&
|
| (store_mode != FORCE_FIELD ||
|
| - target_descriptors->GetDetails(modify_index).type() == DATA)) {
|
| - DCHECK(modify_index < target_nof);
|
| - DCHECK(new_representation.fits_into(
|
| - target_descriptors->GetDetails(modify_index).representation()));
|
| - DCHECK(
|
| - target_descriptors->GetDetails(modify_index).type() != DATA ||
|
| - new_field_type->NowIs(target_descriptors->GetFieldType(modify_index)));
|
| + (modify_index >= 0 &&
|
| + target_descriptors->GetDetails(modify_index).location() == kField))) {
|
| +#ifdef DEBUG
|
| + if (modify_index >= 0) {
|
| + PropertyDetails details = target_descriptors->GetDetails(modify_index);
|
| + DCHECK_EQ(new_kind, details.kind());
|
| + DCHECK_EQ(new_attributes, details.attributes());
|
| + DCHECK(new_representation.fits_into(details.representation()));
|
| + DCHECK(details.location() != kField ||
|
| + new_field_type->NowIs(
|
| + target_descriptors->GetFieldType(modify_index)));
|
| + }
|
| +#endif
|
| return target_map;
|
| }
|
|
|
| // Find the last compatible target map in the transition tree.
|
| for (int i = target_nof; i < old_nof; ++i) {
|
| PropertyDetails old_details = old_descriptors->GetDetails(i);
|
| - int j = target_map->SearchTransition(old_details.kind(),
|
| - old_descriptors->GetKey(i),
|
| - old_details.attributes());
|
| + PropertyKind next_kind;
|
| + PropertyAttributes next_attributes;
|
| + if (modify_index == i) {
|
| + next_kind = new_kind;
|
| + next_attributes = new_attributes;
|
| + } else {
|
| + next_kind = old_details.kind();
|
| + next_attributes = old_details.attributes();
|
| + }
|
| + int j = target_map->SearchTransition(next_kind, old_descriptors->GetKey(i),
|
| + next_attributes);
|
| if (j == TransitionArray::kNotFound) break;
|
| Handle<Map> tmp_map(target_map->GetTransition(j), isolate);
|
| Handle<DescriptorArray> tmp_descriptors(
|
| tmp_map->instance_descriptors(), isolate);
|
|
|
| // Check if target map is compatible.
|
| +#ifdef DEBUG
|
| PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
|
| - DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
|
| - if ((tmp_details.type() == ACCESSOR_CONSTANT ||
|
| - old_details.type() == ACCESSOR_CONSTANT) &&
|
| - (tmp_details.type() != old_details.type() ||
|
| - tmp_descriptors->GetValue(i) != old_descriptors->GetValue(i))) {
|
| + DCHECK_EQ(next_kind, tmp_details.kind());
|
| + DCHECK_EQ(next_attributes, tmp_details.attributes());
|
| +#endif
|
| + 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");
|
| }
|
| + DCHECK(!tmp_map->is_deprecated());
|
| target_map = tmp_map;
|
| }
|
| target_nof = target_map->NumberOfOwnDescriptors();
|
| @@ -2553,7 +2672,7 @@ Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
|
| int current_offset = 0;
|
| for (int i = 0; i < root_nof; ++i) {
|
| PropertyDetails old_details = old_descriptors->GetDetails(i);
|
| - if (old_details.type() == DATA) {
|
| + if (old_details.location() == kField) {
|
| current_offset += old_details.field_width_in_words();
|
| }
|
| Descriptor d(handle(old_descriptors->GetKey(i), isolate),
|
| @@ -2567,43 +2686,85 @@ Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
|
| Handle<Name> target_key(target_descriptors->GetKey(i), isolate);
|
| PropertyDetails old_details = old_descriptors->GetDetails(i);
|
| PropertyDetails target_details = target_descriptors->GetDetails(i);
|
| - target_details = target_details.CopyWithRepresentation(
|
| - old_details.representation().generalize(
|
| - target_details.representation()));
|
| +
|
| + PropertyKind next_kind;
|
| + PropertyAttributes next_attributes;
|
| + PropertyLocation next_location;
|
| + Representation next_representation;
|
| + bool property_kind_reconfiguration = false;
|
| +
|
| if (modify_index == i) {
|
| - target_details = target_details.CopyWithRepresentation(
|
| - new_representation.generalize(target_details.representation()));
|
| - }
|
| - DCHECK_EQ(old_details.attributes(), target_details.attributes());
|
| - if (old_details.type() == DATA || target_details.type() == DATA ||
|
| - (modify_index == i && store_mode == FORCE_FIELD) ||
|
| - (target_descriptors->GetValue(i) != old_descriptors->GetValue(i))) {
|
| - Handle<HeapType> old_field_type =
|
| - (old_details.type() == DATA)
|
| - ? handle(old_descriptors->GetFieldType(i), isolate)
|
| - : old_descriptors->GetValue(i)
|
| - ->OptimalType(isolate, target_details.representation());
|
| - Handle<HeapType> target_field_type =
|
| - (target_details.type() == DATA)
|
| - ? handle(target_descriptors->GetFieldType(i), isolate)
|
| - : target_descriptors->GetValue(i)
|
| - ->OptimalType(isolate, target_details.representation());
|
| - target_field_type = GeneralizeFieldType(
|
| - target_field_type, old_field_type, isolate);
|
| - if (modify_index == i) {
|
| - target_field_type = GeneralizeFieldType(
|
| - target_field_type, new_field_type, isolate);
|
| + DCHECK_EQ(FORCE_FIELD, store_mode);
|
| + property_kind_reconfiguration = old_details.kind() != new_kind;
|
| +
|
| + next_kind = new_kind;
|
| + next_attributes = new_attributes;
|
| + next_location = kField;
|
| +
|
| + // Merge new representation/field type with ones from the target
|
| + // descriptor. If property kind is not reconfigured merge the result with
|
| + // representation/field type from the old descriptor.
|
| + next_representation =
|
| + new_representation.generalize(target_details.representation());
|
| + if (!property_kind_reconfiguration) {
|
| + next_representation =
|
| + next_representation.generalize(old_details.representation());
|
| }
|
| - DataDescriptor d(target_key, current_offset, target_field_type,
|
| - target_details.attributes(),
|
| - target_details.representation());
|
| - current_offset += d.GetDetails().field_width_in_words();
|
| - new_descriptors->Set(i, &d);
|
| } else {
|
| - DCHECK_NE(DATA, target_details.type());
|
| - Descriptor d(target_key,
|
| - handle(target_descriptors->GetValue(i), isolate),
|
| - target_details);
|
| + // Merge old_descriptor and target_descriptor entries.
|
| + DCHECK_EQ(target_details.kind(), old_details.kind());
|
| + next_kind = target_details.kind();
|
| + next_attributes = target_details.attributes();
|
| + next_location =
|
| + old_details.location() == kField ||
|
| + target_details.location() == kField ||
|
| + !EqualImmutableValues(target_descriptors->GetValue(i),
|
| + old_descriptors->GetValue(i))
|
| + ? kField
|
| + : kDescriptor;
|
| +
|
| + next_representation = old_details.representation().generalize(
|
| + target_details.representation());
|
| + }
|
| + DCHECK_EQ(next_kind, target_details.kind());
|
| + DCHECK_EQ(next_attributes, target_details.attributes());
|
| +
|
| + if (next_location == kField) {
|
| + if (next_kind == kData) {
|
| + Handle<HeapType> target_field_type =
|
| + GetFieldType(isolate, target_descriptors, i,
|
| + target_details.location(), next_representation);
|
| +
|
| + Handle<HeapType> next_field_type;
|
| + if (modify_index == i) {
|
| + next_field_type =
|
| + GeneralizeFieldType(target_field_type, new_field_type, isolate);
|
| + if (!property_kind_reconfiguration) {
|
| + Handle<HeapType> old_field_type =
|
| + GetFieldType(isolate, old_descriptors, i,
|
| + old_details.location(), next_representation);
|
| + next_field_type =
|
| + GeneralizeFieldType(next_field_type, old_field_type, isolate);
|
| + }
|
| + } else {
|
| + Handle<HeapType> old_field_type =
|
| + GetFieldType(isolate, old_descriptors, i, old_details.location(),
|
| + next_representation);
|
| + next_field_type =
|
| + GeneralizeFieldType(target_field_type, old_field_type, isolate);
|
| + }
|
| + DataDescriptor d(target_key, current_offset, next_field_type,
|
| + next_attributes, next_representation);
|
| + current_offset += d.GetDetails().field_width_in_words();
|
| + new_descriptors->Set(i, &d);
|
| + } else {
|
| + UNIMPLEMENTED(); // TODO(ishell): implement.
|
| + }
|
| + } else {
|
| + PropertyDetails details(next_attributes, next_kind, next_location,
|
| + next_representation);
|
| + Descriptor d(target_key, handle(target_descriptors->GetValue(i), isolate),
|
| + details);
|
| new_descriptors->Set(i, &d);
|
| }
|
| }
|
| @@ -2612,47 +2773,74 @@ Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
|
| for (int i = target_nof; i < old_nof; ++i) {
|
| PropertyDetails old_details = old_descriptors->GetDetails(i);
|
| Handle<Name> old_key(old_descriptors->GetKey(i), isolate);
|
| +
|
| + // Merge old_descriptor entry and modified details together.
|
| + PropertyKind next_kind;
|
| + PropertyAttributes next_attributes;
|
| + PropertyLocation next_location;
|
| + Representation next_representation;
|
| + bool property_kind_reconfiguration = false;
|
| +
|
| if (modify_index == i) {
|
| - old_details = old_details.CopyWithRepresentation(
|
| - new_representation.generalize(old_details.representation()));
|
| - }
|
| - if (old_details.type() == DATA) {
|
| - Handle<HeapType> old_field_type(
|
| - old_descriptors->GetFieldType(i), isolate);
|
| - if (modify_index == i) {
|
| - old_field_type = GeneralizeFieldType(
|
| - old_field_type, new_field_type, isolate);
|
| + DCHECK_EQ(FORCE_FIELD, store_mode);
|
| + // In case of property kind reconfiguration it is not necessary to
|
| + // take into account representation/field type of the old descriptor.
|
| + property_kind_reconfiguration = old_details.kind() != new_kind;
|
| +
|
| + next_kind = new_kind;
|
| + next_attributes = new_attributes;
|
| + next_location = kField;
|
| + next_representation = new_representation;
|
| + if (!property_kind_reconfiguration) {
|
| + next_representation =
|
| + next_representation.generalize(old_details.representation());
|
| }
|
| - DataDescriptor d(old_key, current_offset, old_field_type,
|
| - old_details.attributes(), old_details.representation());
|
| - current_offset += d.GetDetails().field_width_in_words();
|
| - new_descriptors->Set(i, &d);
|
| } else {
|
| - DCHECK(old_details.type() == DATA_CONSTANT ||
|
| - old_details.type() == ACCESSOR_CONSTANT);
|
| - if (modify_index == i && store_mode == FORCE_FIELD) {
|
| - DataDescriptor d(
|
| - old_key, current_offset,
|
| - GeneralizeFieldType(old_descriptors->GetValue(i)->OptimalType(
|
| - isolate, old_details.representation()),
|
| - new_field_type, isolate),
|
| - old_details.attributes(), old_details.representation());
|
| + next_kind = old_details.kind();
|
| + next_attributes = old_details.attributes();
|
| + next_location = old_details.location();
|
| + next_representation = old_details.representation();
|
| + }
|
| +
|
| + if (next_location == kField) {
|
| + if (next_kind == kData) {
|
| + Handle<HeapType> next_field_type;
|
| + if (modify_index == i) {
|
| + next_field_type = new_field_type;
|
| + if (!property_kind_reconfiguration) {
|
| + Handle<HeapType> old_field_type =
|
| + GetFieldType(isolate, old_descriptors, i,
|
| + old_details.location(), next_representation);
|
| + old_field_type =
|
| + GeneralizeFieldType(old_field_type, next_field_type, isolate);
|
| + }
|
| + } else {
|
| + Handle<HeapType> old_field_type =
|
| + GetFieldType(isolate, old_descriptors, i, old_details.location(),
|
| + next_representation);
|
| + next_field_type = old_field_type;
|
| + }
|
| +
|
| + DataDescriptor d(old_key, current_offset, next_field_type,
|
| + next_attributes, next_representation);
|
| current_offset += d.GetDetails().field_width_in_words();
|
| new_descriptors->Set(i, &d);
|
| } else {
|
| - DCHECK_NE(DATA, old_details.type());
|
| - Descriptor d(old_key,
|
| - handle(old_descriptors->GetValue(i), isolate),
|
| - old_details);
|
| - new_descriptors->Set(i, &d);
|
| + UNIMPLEMENTED(); // TODO(ishell): implement.
|
| }
|
| + } else {
|
| + PropertyDetails details(next_attributes, next_kind, next_location,
|
| + next_representation);
|
| + Descriptor d(old_key, handle(old_descriptors->GetValue(i), isolate),
|
| + details);
|
| + new_descriptors->Set(i, &d);
|
| }
|
| }
|
|
|
| new_descriptors->Sort();
|
|
|
| DCHECK(store_mode != FORCE_FIELD ||
|
| - new_descriptors->GetDetails(modify_index).type() == DATA);
|
| + new_descriptors->GetDetails(modify_index).location() == kField);
|
|
|
| Handle<Map> split_map(root_map->FindLastMatchMap(
|
| root_nof, old_nof, *new_descriptors), isolate);
|
| @@ -2661,21 +2849,31 @@ Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
|
|
|
| Handle<LayoutDescriptor> new_layout_descriptor =
|
| LayoutDescriptor::New(split_map, new_descriptors, old_nof);
|
| - PropertyDetails split_prop_details = old_descriptors->GetDetails(split_nof);
|
| +
|
| + PropertyKind split_kind;
|
| + PropertyAttributes split_attributes;
|
| + if (modify_index == split_nof) {
|
| + split_kind = new_kind;
|
| + split_attributes = new_attributes;
|
| + } else {
|
| + PropertyDetails split_prop_details = old_descriptors->GetDetails(split_nof);
|
| + split_kind = split_prop_details.kind();
|
| + split_attributes = split_prop_details.attributes();
|
| + }
|
| bool transition_target_deprecated = split_map->DeprecateTarget(
|
| - split_prop_details.kind(), old_descriptors->GetKey(split_nof),
|
| - split_prop_details.attributes(), *new_descriptors,
|
| - *new_layout_descriptor);
|
| + split_kind, old_descriptors->GetKey(split_nof), split_attributes,
|
| + *new_descriptors, *new_layout_descriptor);
|
|
|
| // If |transition_target_deprecated| is true then the transition array
|
| // already contains entry for given descriptor. This means that the transition
|
| // could be inserted regardless of whether transitions array is full or not.
|
| if (!transition_target_deprecated && !split_map->CanHaveMoreTransitions()) {
|
| return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
|
| + new_kind, new_attributes,
|
| "GenAll_CantHaveMoreTransitions");
|
| }
|
|
|
| - if (FLAG_trace_generalization) {
|
| + if (FLAG_trace_generalization && modify_index >= 0) {
|
| PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
|
| PropertyDetails new_details = new_descriptors->GetDetails(modify_index);
|
| Handle<HeapType> old_field_type =
|
| @@ -2692,7 +2890,7 @@ Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
|
| isolate);
|
| old_map->PrintGeneralization(
|
| stdout, "", modify_index, split_nof, old_nof,
|
| - old_details.type() == DATA_CONSTANT && store_mode == FORCE_FIELD,
|
| + old_details.location() == kDescriptor && store_mode == FORCE_FIELD,
|
| old_details.representation(), new_details.representation(),
|
| *old_field_type, *new_field_type);
|
| }
|
| @@ -2713,10 +2911,11 @@ Handle<Map> Map::GeneralizeAllFieldRepresentations(
|
| Handle<Map> map) {
|
| Handle<DescriptorArray> descriptors(map->instance_descriptors());
|
| for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) {
|
| - if (descriptors->GetDetails(i).type() == DATA) {
|
| - map = GeneralizeRepresentation(map, i, Representation::Tagged(),
|
| - HeapType::Any(map->GetIsolate()),
|
| - FORCE_FIELD);
|
| + PropertyDetails details = descriptors->GetDetails(i);
|
| + if (details.type() == DATA) {
|
| + map = ReconfigureProperty(map, i, kData, details.attributes(),
|
| + Representation::Tagged(),
|
| + HeapType::Any(map->GetIsolate()), FORCE_FIELD);
|
| }
|
| }
|
| return map;
|
| @@ -2740,9 +2939,9 @@ MaybeHandle<Map> Map::TryUpdate(Handle<Map> map) {
|
| // static
|
| Handle<Map> Map::Update(Handle<Map> map) {
|
| if (!map->is_deprecated()) return map;
|
| - return GeneralizeRepresentation(map, 0, Representation::None(),
|
| - HeapType::None(map->GetIsolate()),
|
| - ALLOW_IN_DESCRIPTOR);
|
| + return ReconfigureProperty(map, -1, kData, NONE, Representation::None(),
|
| + HeapType::None(map->GetIsolate()),
|
| + ALLOW_IN_DESCRIPTOR);
|
| }
|
|
|
|
|
| @@ -3952,7 +4151,6 @@ MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
|
| }
|
|
|
| it.ReconfigureDataProperty(value, attributes);
|
| - it.PrepareForDataProperty(value);
|
| value = it.WriteDataValue(value);
|
|
|
| if (is_observed) {
|
| @@ -3977,7 +4175,6 @@ MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
|
| if (is_observed) old_value = it.GetDataValue();
|
|
|
| it.ReconfigureDataProperty(value, attributes);
|
| - it.PrepareForDataProperty(value);
|
| value = it.WriteDataValue(value);
|
|
|
| if (is_observed) {
|
| @@ -5846,7 +6043,7 @@ int Map::NextFreePropertyIndex() {
|
| DescriptorArray* descs = instance_descriptors();
|
| for (int i = 0; i < number_of_own_descriptors; i++) {
|
| PropertyDetails details = descs->GetDetails(i);
|
| - if (details.type() == DATA) {
|
| + if (details.location() == kField) {
|
| int candidate = details.field_index() + details.field_width_in_words();
|
| if (candidate > free_index) free_index = candidate;
|
| }
|
| @@ -6841,7 +7038,7 @@ Handle<Map> Map::CopyInstallDescriptors(
|
|
|
| int unused_property_fields = map->unused_property_fields();
|
| PropertyDetails details = descriptors->GetDetails(new_descriptor);
|
| - if (details.type() == DATA) {
|
| + if (details.location() == kField) {
|
| unused_property_fields = map->unused_property_fields() - 1;
|
| if (unused_property_fields < 0) {
|
| unused_property_fields += JSObject::kFieldsAdded;
|
| @@ -7059,11 +7256,13 @@ Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor,
|
| if (descriptors->CanHoldValue(descriptor, *value)) return map;
|
|
|
| Isolate* isolate = map->GetIsolate();
|
| + PropertyAttributes attributes =
|
| + descriptors->GetDetails(descriptor).attributes();
|
| Representation representation = value->OptimalRepresentation();
|
| Handle<HeapType> type = value->OptimalType(isolate, representation);
|
|
|
| - return GeneralizeRepresentation(map, descriptor, representation, type,
|
| - FORCE_FIELD);
|
| + return ReconfigureProperty(map, descriptor, kData, attributes, representation,
|
| + type, FORCE_FIELD);
|
| }
|
|
|
|
|
| @@ -7120,15 +7319,29 @@ Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
|
| }
|
|
|
|
|
| -Handle<Map> Map::ReconfigureDataProperty(Handle<Map> map, int descriptor,
|
| - PropertyAttributes attributes) {
|
| +Handle<Map> Map::ReconfigureExistingProperty(Handle<Map> map, int descriptor,
|
| + PropertyKind kind,
|
| + PropertyAttributes attributes) {
|
| // Dictionaries have to be reconfigured in-place.
|
| DCHECK(!map->is_dictionary_map());
|
|
|
| - // For now, give up on transitioning and just create a unique map.
|
| - // TODO(verwaest/ishell): Cache transitions with different attributes.
|
| - return CopyGeneralizeAllRepresentations(
|
| - map, descriptor, FORCE_FIELD, attributes, "GenAll_AttributesMismatch");
|
| + if (!map->GetBackPointer()->IsMap()) {
|
| + // There is no benefit from reconstructing transition tree for maps without
|
| + // back pointers.
|
| + return CopyGeneralizeAllRepresentations(
|
| + map, descriptor, FORCE_FIELD, kind, attributes,
|
| + "GenAll_AttributesMismatchProtoMap");
|
| + }
|
| +
|
| + if (FLAG_trace_generalization) {
|
| + map->PrintReconfiguration(stdout, descriptor, kind, attributes);
|
| + }
|
| +
|
| + Isolate* isolate = map->GetIsolate();
|
| + Handle<Map> new_map = ReconfigureProperty(
|
| + map, descriptor, kind, attributes, Representation::None(),
|
| + HeapType::None(isolate), FORCE_FIELD);
|
| + return new_map;
|
| }
|
|
|
|
|
|
|