[ic] Replace CopyGeneralize with Normalize
Rather than starting a new, orphaned transition tree in various bailout cases, simply drop down into dictionary mode. Aside from potential memory benefits, this allows us to remove CopyGeneralizeAllFields, which was the only path along which fields could end up in a different order than their descriptors. Change-Id: I5577e8a1ca51f0ffdadd7504e7895f367605aa27 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1662298 Commit-Queue: Leszek Swirski <leszeks@chromium.org> Reviewed-by: Igor Sheludko <ishell@chromium.org> Cr-Commit-Position: refs/heads/master@{#62279}
This commit is contained in:
parent
15709b5a3e
commit
7325d4ae98
@ -799,7 +799,9 @@ void DescriptorArray::DescriptorArrayVerify(Isolate* isolate) {
|
||||
CHECK_LT(0, number_of_all_descriptors());
|
||||
CHECK_LE(number_of_descriptors(), number_of_all_descriptors());
|
||||
|
||||
// Check that properties with private symbols names are non-enumerable.
|
||||
// Check that properties with private symbols names are non-enumerable, and
|
||||
// that fields are in order.
|
||||
int expected_field_index = 0;
|
||||
for (int descriptor = 0; descriptor < number_of_descriptors();
|
||||
descriptor++) {
|
||||
Object key = *(GetDescriptorSlot(descriptor) + kEntryKeyIndex);
|
||||
@ -813,11 +815,13 @@ void DescriptorArray::DescriptorArrayVerify(Isolate* isolate) {
|
||||
MaybeObject value = GetValue(descriptor);
|
||||
HeapObject heap_object;
|
||||
if (details.location() == kField) {
|
||||
CHECK_EQ(details.field_index(), expected_field_index);
|
||||
CHECK(
|
||||
value == MaybeObject::FromObject(FieldType::None()) ||
|
||||
value == MaybeObject::FromObject(FieldType::Any()) ||
|
||||
value->IsCleared() ||
|
||||
(value->GetHeapObjectIfWeak(&heap_object) && heap_object.IsMap()));
|
||||
expected_field_index += details.field_width_in_words();
|
||||
} else {
|
||||
CHECK(!value->IsWeakOrCleared());
|
||||
CHECK(!value->cast<Object>().IsMap());
|
||||
|
@ -3267,7 +3267,8 @@ void JSObject::NormalizeProperties(Isolate* isolate, Handle<JSObject> object,
|
||||
if (!object->HasFastProperties()) return;
|
||||
|
||||
Handle<Map> map(object->map(), isolate);
|
||||
Handle<Map> new_map = Map::Normalize(isolate, map, mode, reason);
|
||||
Handle<Map> new_map =
|
||||
Map::Normalize(isolate, map, map->elements_kind(), mode, reason);
|
||||
|
||||
JSObject::MigrateToMap(isolate, object, new_map,
|
||||
expected_additional_properties);
|
||||
|
@ -525,13 +525,18 @@ void LookupIterator::ReconfigureDataProperty(Handle<Object> value,
|
||||
ReloadPropertyInformation<true>();
|
||||
} else if (holder_obj->HasFastProperties()) {
|
||||
Handle<Map> old_map(holder_obj->map(), isolate_);
|
||||
Handle<Map> new_map = Map::ReconfigureExistingProperty(
|
||||
isolate_, old_map, descriptor_number(), i::kData, attributes);
|
||||
// Force mutable to avoid changing constant value by reconfiguring
|
||||
// kData -> kAccessor -> kData.
|
||||
new_map =
|
||||
Map::PrepareForDataProperty(isolate(), new_map, descriptor_number(),
|
||||
PropertyConstness::kMutable, value);
|
||||
Handle<Map> new_map = Map::ReconfigureExistingProperty(
|
||||
isolate_, old_map, descriptor_number(), i::kData, attributes,
|
||||
PropertyConstness::kMutable);
|
||||
if (!new_map->is_dictionary_map()) {
|
||||
// Make sure that the data property has a compatible representation.
|
||||
// TODO(leszeks): Do this as part of ReconfigureExistingProperty.
|
||||
new_map =
|
||||
Map::PrepareForDataProperty(isolate(), new_map, descriptor_number(),
|
||||
PropertyConstness::kMutable, value);
|
||||
}
|
||||
JSObject::MigrateToMap(isolate_, holder_obj, new_map);
|
||||
ReloadPropertyInformation<false>();
|
||||
}
|
||||
|
@ -132,6 +132,16 @@ void Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
|
||||
}
|
||||
}
|
||||
|
||||
Handle<Map> Map::Normalize(Isolate* isolate, Handle<Map> fast_map,
|
||||
PropertyNormalizationMode mode, const char* reason) {
|
||||
return Normalize(isolate, fast_map, fast_map->elements_kind(), mode, reason);
|
||||
}
|
||||
|
||||
bool Map::EquivalentToForNormalization(const Map other,
|
||||
PropertyNormalizationMode mode) const {
|
||||
return EquivalentToForNormalization(other, elements_kind(), mode);
|
||||
}
|
||||
|
||||
bool Map::IsUnboxedDoubleField(FieldIndex index) const {
|
||||
if (!FLAG_unbox_double_fields) return false;
|
||||
if (!index.is_inobject()) return false;
|
||||
|
@ -201,10 +201,9 @@ void MapUpdater::GeneralizeField(Handle<Map> map, int modify_index,
|
||||
*old_descriptors_ == integrity_source_map_->instance_descriptors());
|
||||
}
|
||||
|
||||
MapUpdater::State MapUpdater::CopyGeneralizeAllFields(const char* reason) {
|
||||
result_map_ = Map::CopyGeneralizeAllFields(
|
||||
isolate_, old_map_, new_elements_kind_, modified_descriptor_, new_kind_,
|
||||
new_attributes_, reason);
|
||||
MapUpdater::State MapUpdater::Normalize(const char* reason) {
|
||||
result_map_ = Map::Normalize(isolate_, old_map_, new_elements_kind_,
|
||||
CLEAR_INOBJECT_PROPERTIES, reason);
|
||||
state_ = kEnd;
|
||||
return state_; // Done.
|
||||
}
|
||||
@ -310,14 +309,14 @@ MapUpdater::State MapUpdater::FindRootMap() {
|
||||
}
|
||||
|
||||
if (!old_map_->EquivalentToForTransition(*root_map_)) {
|
||||
return CopyGeneralizeAllFields("GenAll_NotEquivalent");
|
||||
return Normalize("Normalize_NotEquivalent");
|
||||
} else if (old_map_->is_extensible() != root_map_->is_extensible()) {
|
||||
DCHECK(!old_map_->is_extensible());
|
||||
DCHECK(root_map_->is_extensible());
|
||||
// We have an integrity level transition in the tree, let us make a note
|
||||
// of that transition to be able to replay it later.
|
||||
if (!TrySaveIntegrityLevelTransitions()) {
|
||||
return CopyGeneralizeAllFields("GenAll_PrivateSymbolsOnNonExtensible");
|
||||
return Normalize("Normalize_PrivateSymbolsOnNonExtensible");
|
||||
}
|
||||
|
||||
// We want to build transitions to the original element kind (before
|
||||
@ -335,7 +334,7 @@ MapUpdater::State MapUpdater::FindRootMap() {
|
||||
to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS &&
|
||||
!(IsTransitionableFastElementsKind(from_kind) &&
|
||||
IsMoreGeneralElementsKindTransition(from_kind, to_kind))) {
|
||||
return CopyGeneralizeAllFields("GenAll_InvalidElementsTransition");
|
||||
return Normalize("Normalize_InvalidElementsTransition");
|
||||
}
|
||||
|
||||
int root_nof = root_map_->NumberOfOwnDescriptors();
|
||||
@ -344,13 +343,13 @@ MapUpdater::State MapUpdater::FindRootMap() {
|
||||
old_descriptors_->GetDetails(modified_descriptor_);
|
||||
if (old_details.kind() != new_kind_ ||
|
||||
old_details.attributes() != new_attributes_) {
|
||||
return CopyGeneralizeAllFields("GenAll_RootModification1");
|
||||
return Normalize("Normalize_RootModification1");
|
||||
}
|
||||
if (old_details.location() != kField) {
|
||||
return CopyGeneralizeAllFields("GenAll_RootModification2");
|
||||
return Normalize("Normalize_RootModification2");
|
||||
}
|
||||
if (!new_representation_.fits_into(old_details.representation())) {
|
||||
return CopyGeneralizeAllFields("GenAll_RootModification4");
|
||||
return Normalize("Normalize_RootModification4");
|
||||
}
|
||||
|
||||
DCHECK_EQ(kData, old_details.kind());
|
||||
@ -394,7 +393,7 @@ MapUpdater::State MapUpdater::FindTargetMap() {
|
||||
!EqualImmutableValues(GetValue(i),
|
||||
tmp_descriptors->GetStrongValue(i))) {
|
||||
// TODO(ishell): mutable accessors are not implemented yet.
|
||||
return CopyGeneralizeAllFields("GenAll_Incompatible");
|
||||
return Normalize("Normalize_Incompatible");
|
||||
}
|
||||
if (!IsGeneralizableTo(old_details.location(), tmp_details.location())) {
|
||||
break;
|
||||
@ -484,7 +483,7 @@ MapUpdater::State MapUpdater::FindTargetMap() {
|
||||
if (old_details.kind() == kAccessor &&
|
||||
!EqualImmutableValues(GetValue(i),
|
||||
tmp_descriptors->GetStrongValue(i))) {
|
||||
return CopyGeneralizeAllFields("GenAll_Incompatible");
|
||||
return Normalize("Normalize_Incompatible");
|
||||
}
|
||||
DCHECK(!tmp_map->is_deprecated());
|
||||
target_map_ = tmp_map;
|
||||
@ -723,7 +722,7 @@ MapUpdater::State MapUpdater::ConstructNewMap() {
|
||||
// contains entry for given descriptor. This means that the transition
|
||||
// could be inserted regardless of whether transitions array is full or not.
|
||||
if (maybe_transition.is_null() && !transitions.CanHaveMoreTransitions()) {
|
||||
return CopyGeneralizeAllFields("GenAll_CantHaveMoreTransitions");
|
||||
return Normalize("Normalize_CantHaveMoreTransitions");
|
||||
}
|
||||
|
||||
old_map_->NotifyLeafMapLayoutChange(isolate_);
|
||||
@ -787,7 +786,7 @@ MapUpdater::State MapUpdater::ConstructNewMapWithIntegrityLevelTransition() {
|
||||
|
||||
TransitionsAccessor transitions(isolate_, target_map_);
|
||||
if (!transitions.CanHaveMoreTransitions()) {
|
||||
return CopyGeneralizeAllFields("GenAll_CantHaveMoreTransitions");
|
||||
return Normalize("Normalize_CantHaveMoreTransitions");
|
||||
}
|
||||
|
||||
result_map_ = Map::CopyForPreventExtensions(
|
||||
|
@ -123,9 +123,8 @@ class MapUpdater {
|
||||
State ConstructNewMapWithIntegrityLevelTransition();
|
||||
|
||||
// When a requested reconfiguration can not be done the result is a copy
|
||||
// of |old_map_| where every field has |Tagged| representation and |Any|
|
||||
// field type. This map is disconnected from the transition tree.
|
||||
State CopyGeneralizeAllFields(const char* reason);
|
||||
// of |old_map_| in dictionary mode.
|
||||
State Normalize(const char* reason);
|
||||
|
||||
// Returns name of a |descriptor| property.
|
||||
inline Name GetKey(int descriptor) const;
|
||||
|
@ -570,61 +570,6 @@ bool Map::HasOutOfObjectProperties() const {
|
||||
return GetInObjectProperties() < NumberOfFields();
|
||||
}
|
||||
|
||||
Handle<Map> Map::CopyGeneralizeAllFields(Isolate* isolate, Handle<Map> map,
|
||||
ElementsKind elements_kind,
|
||||
int modify_index, PropertyKind kind,
|
||||
PropertyAttributes attributes,
|
||||
const char* reason) {
|
||||
Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
|
||||
int number_of_own_descriptors = map->NumberOfOwnDescriptors();
|
||||
Handle<DescriptorArray> descriptors = DescriptorArray::CopyUpTo(
|
||||
isolate, old_descriptors, number_of_own_descriptors);
|
||||
descriptors->GeneralizeAllFields();
|
||||
|
||||
Handle<LayoutDescriptor> new_layout_descriptor(
|
||||
LayoutDescriptor::FastPointerLayout(), isolate);
|
||||
Handle<Map> new_map = CopyReplaceDescriptors(
|
||||
isolate, map, descriptors, new_layout_descriptor, OMIT_TRANSITION,
|
||||
MaybeHandle<Name>(), reason, SPECIAL_TRANSITION);
|
||||
|
||||
// Unless the instance is being migrated, ensure that modify_index is a field.
|
||||
if (modify_index >= 0) {
|
||||
PropertyDetails details = descriptors->GetDetails(modify_index);
|
||||
if (details.constness() != PropertyConstness::kMutable ||
|
||||
details.location() != kField || details.attributes() != attributes) {
|
||||
int field_index = details.location() == kField
|
||||
? details.field_index()
|
||||
: new_map->NumberOfFields();
|
||||
Descriptor d = Descriptor::DataField(
|
||||
isolate, handle(descriptors->GetKey(modify_index), isolate),
|
||||
field_index, attributes, Representation::Tagged());
|
||||
descriptors->Replace(modify_index, &d);
|
||||
if (details.location() != kField) {
|
||||
new_map->AccountAddedPropertyField();
|
||||
}
|
||||
} else {
|
||||
DCHECK(details.attributes() == attributes);
|
||||
}
|
||||
|
||||
if (FLAG_trace_generalization) {
|
||||
MaybeHandle<FieldType> field_type = FieldType::None(isolate);
|
||||
if (details.location() == kField) {
|
||||
field_type = handle(
|
||||
map->instance_descriptors().GetFieldType(modify_index), isolate);
|
||||
}
|
||||
map->PrintGeneralization(
|
||||
isolate, stdout, reason, modify_index,
|
||||
new_map->NumberOfOwnDescriptors(), new_map->NumberOfOwnDescriptors(),
|
||||
details.location() == kDescriptor, details.representation(),
|
||||
Representation::Tagged(), details.constness(), details.constness(),
|
||||
field_type, MaybeHandle<Object>(), FieldType::Any(isolate),
|
||||
MaybeHandle<Object>());
|
||||
}
|
||||
}
|
||||
new_map->set_elements_kind(elements_kind);
|
||||
return new_map;
|
||||
}
|
||||
|
||||
void Map::DeprecateTransitionTree(Isolate* isolate) {
|
||||
if (is_deprecated()) return;
|
||||
DisallowHeapAllocation no_gc;
|
||||
@ -1477,6 +1422,7 @@ Handle<Map> Map::RawCopy(Isolate* isolate, Handle<Map> map, int instance_size,
|
||||
}
|
||||
|
||||
Handle<Map> Map::Normalize(Isolate* isolate, Handle<Map> fast_map,
|
||||
ElementsKind new_elements_kind,
|
||||
PropertyNormalizationMode mode, const char* reason) {
|
||||
DCHECK(!fast_map->is_dictionary_map());
|
||||
|
||||
@ -1488,7 +1434,8 @@ Handle<Map> Map::Normalize(Isolate* isolate, Handle<Map> fast_map,
|
||||
if (use_cache) cache = Handle<NormalizedMapCache>::cast(maybe_cache);
|
||||
|
||||
Handle<Map> new_map;
|
||||
if (use_cache && cache->Get(fast_map, mode).ToHandle(&new_map)) {
|
||||
if (use_cache &&
|
||||
cache->Get(fast_map, new_elements_kind, mode).ToHandle(&new_map)) {
|
||||
#ifdef VERIFY_HEAP
|
||||
if (FLAG_verify_heap) new_map->DictionaryMapVerify(isolate);
|
||||
#endif
|
||||
@ -1498,6 +1445,7 @@ Handle<Map> Map::Normalize(Isolate* isolate, Handle<Map> fast_map,
|
||||
// except for the code cache, which can contain some ICs which can be
|
||||
// applied to the shared map, dependent code and weak cell cache.
|
||||
Handle<Map> fresh = Map::CopyNormalized(isolate, fast_map, mode);
|
||||
fresh->set_elements_kind(new_elements_kind);
|
||||
|
||||
STATIC_ASSERT(Map::kPrototypeValidityCellOffset ==
|
||||
Map::kDependentCodeOffset + kTaggedSize);
|
||||
@ -1529,6 +1477,7 @@ Handle<Map> Map::Normalize(Isolate* isolate, Handle<Map> fast_map,
|
||||
#endif
|
||||
} else {
|
||||
new_map = Map::CopyNormalized(isolate, fast_map, mode);
|
||||
new_map->set_elements_kind(new_elements_kind);
|
||||
if (use_cache) {
|
||||
cache->Set(fast_map, new_map);
|
||||
isolate->counters()->maps_normalized()->Increment();
|
||||
@ -2203,16 +2152,16 @@ Handle<Map> Map::TransitionToDataProperty(Isolate* isolate, Handle<Map> map,
|
||||
|
||||
Handle<Map> Map::ReconfigureExistingProperty(Isolate* isolate, Handle<Map> map,
|
||||
int descriptor, PropertyKind kind,
|
||||
PropertyAttributes attributes) {
|
||||
PropertyAttributes attributes,
|
||||
PropertyConstness constness) {
|
||||
// Dictionaries have to be reconfigured in-place.
|
||||
DCHECK(!map->is_dictionary_map());
|
||||
|
||||
if (!map->GetBackPointer().IsMap()) {
|
||||
// There is no benefit from reconstructing transition tree for maps without
|
||||
// back pointers.
|
||||
return CopyGeneralizeAllFields(isolate, map, map->elements_kind(),
|
||||
descriptor, kind, attributes,
|
||||
"GenAll_AttributesMismatchProtoMap");
|
||||
// back pointers, normalize and try to hit the map cache instead.
|
||||
return Map::Normalize(isolate, map, CLEAR_INOBJECT_PROPERTIES,
|
||||
"Normalize_AttributesMismatchProtoMap");
|
||||
}
|
||||
|
||||
if (FLAG_trace_generalization) {
|
||||
@ -2222,7 +2171,7 @@ Handle<Map> Map::ReconfigureExistingProperty(Isolate* isolate, Handle<Map> map,
|
||||
MapUpdater mu(isolate, map);
|
||||
DCHECK_EQ(kData, kind); // Only kData case is supported so far.
|
||||
Handle<Map> new_map = mu.ReconfigureToDataField(
|
||||
descriptor, attributes, PropertyConstness::kConst, Representation::None(),
|
||||
descriptor, attributes, constness, Representation::None(),
|
||||
FieldType::None(isolate));
|
||||
return new_map;
|
||||
}
|
||||
@ -2474,10 +2423,16 @@ bool Map::EquivalentToForElementsKindTransition(const Map other) const {
|
||||
}
|
||||
|
||||
bool Map::EquivalentToForNormalization(const Map other,
|
||||
ElementsKind elements_kind,
|
||||
PropertyNormalizationMode mode) const {
|
||||
int properties =
|
||||
mode == CLEAR_INOBJECT_PROPERTIES ? 0 : other.GetInObjectProperties();
|
||||
return CheckEquivalent(*this, other) && bit_field2() == other.bit_field2() &&
|
||||
// Make sure the elements_kind bits are in bit_field2.
|
||||
DCHECK_EQ(this->elements_kind(), Map::ElementsKindBits::decode(bit_field2()));
|
||||
int adjusted_bit_field2 =
|
||||
Map::ElementsKindBits::update(bit_field2(), elements_kind);
|
||||
return CheckEquivalent(*this, other) &&
|
||||
adjusted_bit_field2 == other.bit_field2() &&
|
||||
GetInObjectProperties() == properties &&
|
||||
JSObject::GetEmbedderFieldCount(*this) ==
|
||||
JSObject::GetEmbedderFieldCount(other);
|
||||
@ -2668,6 +2623,7 @@ Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) {
|
||||
}
|
||||
|
||||
MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map,
|
||||
ElementsKind elements_kind,
|
||||
PropertyNormalizationMode mode) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
MaybeObject value = WeakFixedArray::Get(GetIndex(fast_map));
|
||||
@ -2677,7 +2633,8 @@ MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map,
|
||||
}
|
||||
|
||||
Map normalized_map = Map::cast(heap_object);
|
||||
if (!normalized_map.EquivalentToForNormalization(*fast_map, mode)) {
|
||||
if (!normalized_map.EquivalentToForNormalization(*fast_map, elements_kind,
|
||||
mode)) {
|
||||
return MaybeHandle<Map>();
|
||||
}
|
||||
return handle(normalized_map, GetIsolate());
|
||||
|
@ -542,9 +542,14 @@ class Map : public HeapObject {
|
||||
|
||||
V8_EXPORT_PRIVATE static Handle<Map> Normalize(Isolate* isolate,
|
||||
Handle<Map> map,
|
||||
ElementsKind new_elements_kind,
|
||||
PropertyNormalizationMode mode,
|
||||
const char* reason);
|
||||
|
||||
inline static Handle<Map> Normalize(Isolate* isolate, Handle<Map> fast_map,
|
||||
PropertyNormalizationMode mode,
|
||||
const char* reason);
|
||||
|
||||
// Tells whether the map is used for JSObjects in dictionary mode (ie
|
||||
// normalized objects, ie objects for which HasFastProperties returns false).
|
||||
// A map can never be used for both dictionary mode and fast mode JSObjects.
|
||||
@ -739,7 +744,7 @@ class Map : public HeapObject {
|
||||
PropertyAttributes attributes);
|
||||
V8_EXPORT_PRIVATE static Handle<Map> ReconfigureExistingProperty(
|
||||
Isolate* isolate, Handle<Map> map, int descriptor, PropertyKind kind,
|
||||
PropertyAttributes attributes);
|
||||
PropertyAttributes attributes, PropertyConstness constness);
|
||||
|
||||
inline void AppendDescriptor(Isolate* isolate, Descriptor* desc);
|
||||
|
||||
@ -833,12 +838,15 @@ class Map : public HeapObject {
|
||||
|
||||
class BodyDescriptor;
|
||||
|
||||
// Compares this map to another to see if they describe equivalent objects.
|
||||
// Compares this map to another to see if they describe equivalent objects,
|
||||
// up to the given |elements_kind|.
|
||||
// If |mode| is set to CLEAR_INOBJECT_PROPERTIES, |other| is treated as if
|
||||
// it had exactly zero inobject properties.
|
||||
// The "shared" flags of both this map and |other| are ignored.
|
||||
bool EquivalentToForNormalization(const Map other,
|
||||
bool EquivalentToForNormalization(const Map other, ElementsKind elements_kind,
|
||||
PropertyNormalizationMode mode) const;
|
||||
inline bool EquivalentToForNormalization(
|
||||
const Map other, PropertyNormalizationMode mode) const;
|
||||
|
||||
// Returns true if given field is unboxed double.
|
||||
inline bool IsUnboxedDoubleField(FieldIndex index) const;
|
||||
@ -929,14 +937,6 @@ class Map : public HeapObject {
|
||||
static Handle<Map> CopyNormalized(Isolate* isolate, Handle<Map> map,
|
||||
PropertyNormalizationMode mode);
|
||||
|
||||
// TODO(ishell): Move to MapUpdater.
|
||||
static Handle<Map> CopyGeneralizeAllFields(Isolate* isolate, Handle<Map> map,
|
||||
ElementsKind elements_kind,
|
||||
int modify_index,
|
||||
PropertyKind kind,
|
||||
PropertyAttributes attributes,
|
||||
const char* reason);
|
||||
|
||||
void DeprecateTransitionTree(Isolate* isolate);
|
||||
|
||||
void ReplaceDescriptors(Isolate* isolate, DescriptorArray new_descriptors,
|
||||
@ -983,6 +983,7 @@ class NormalizedMapCache : public WeakFixedArray {
|
||||
static Handle<NormalizedMapCache> New(Isolate* isolate);
|
||||
|
||||
V8_WARN_UNUSED_RESULT MaybeHandle<Map> Get(Handle<Map> fast_map,
|
||||
ElementsKind elements_kind,
|
||||
PropertyNormalizationMode mode);
|
||||
void Set(Handle<Map> fast_map, Handle<Map> normalized_map);
|
||||
|
||||
|
@ -306,6 +306,14 @@ class Expectations {
|
||||
|
||||
bool Check(Map map) const { return Check(map, number_of_properties_); }
|
||||
|
||||
bool CheckNormalized(Map map) const {
|
||||
CHECK(map.is_dictionary_map());
|
||||
CHECK_EQ(elements_kind_, map.elements_kind());
|
||||
// TODO(leszeks): Iterate over the key/value pairs of the map and compare
|
||||
// them against the expected fields.
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Helper methods for initializing expectations and adding properties to
|
||||
// given |map|.
|
||||
@ -1053,8 +1061,8 @@ void TestReconfigureDataFieldAttribute_GeneralizeField(
|
||||
|
||||
// Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which
|
||||
// should generalize representations in |map1|.
|
||||
Handle<Map> new_map =
|
||||
Map::ReconfigureExistingProperty(isolate, map2, kSplitProp, kData, NONE);
|
||||
Handle<Map> new_map = Map::ReconfigureExistingProperty(
|
||||
isolate, map2, kSplitProp, kData, NONE, PropertyConstness::kConst);
|
||||
|
||||
// |map2| should be left unchanged but marked unstable.
|
||||
CHECK(!map2->is_stable());
|
||||
@ -1141,8 +1149,8 @@ void TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
|
||||
|
||||
// Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which
|
||||
// should generalize representations in |map1|.
|
||||
Handle<Map> new_map =
|
||||
Map::ReconfigureExistingProperty(isolate, map2, kSplitProp, kData, NONE);
|
||||
Handle<Map> new_map = Map::ReconfigureExistingProperty(
|
||||
isolate, map2, kSplitProp, kData, NONE, PropertyConstness::kConst);
|
||||
|
||||
// |map2| should be left unchanged but marked unstable.
|
||||
CHECK(!map2->is_stable());
|
||||
@ -1399,22 +1407,17 @@ struct CheckUnrelated {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Checks that given |map| is NOT deprecated, and |new_map| is a result of
|
||||
// copy-generalize-all-representations.
|
||||
struct CheckCopyGeneralizeAllFields {
|
||||
// Checks that given |map| is NOT deprecated, and |new_map| is a result of going
|
||||
// dictionary mode.
|
||||
struct CheckNormalize {
|
||||
void Check(Isolate* isolate, Handle<Map> map, Handle<Map> new_map,
|
||||
Expectations& expectations) {
|
||||
const Expectations& expectations) {
|
||||
CHECK(!map->is_deprecated());
|
||||
CHECK_NE(*map, *new_map);
|
||||
|
||||
CHECK(new_map->GetBackPointer().IsUndefined(isolate));
|
||||
for (int i = 0; i < kPropCount; i++) {
|
||||
expectations.GeneralizeField(i);
|
||||
}
|
||||
|
||||
CHECK(!new_map->is_deprecated());
|
||||
CHECK(expectations.Check(*new_map));
|
||||
CHECK(expectations.CheckNormalized(*new_map));
|
||||
}
|
||||
};
|
||||
|
||||
@ -1497,8 +1500,8 @@ static void TestReconfigureProperty_CustomPropertyAfterTargetMap(
|
||||
|
||||
// Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which
|
||||
// should generalize representations in |map1|.
|
||||
Handle<Map> new_map =
|
||||
Map::ReconfigureExistingProperty(isolate, map2, kSplitProp, kData, NONE);
|
||||
Handle<Map> new_map = Map::ReconfigureExistingProperty(
|
||||
isolate, map2, kSplitProp, kData, NONE, PropertyConstness::kConst);
|
||||
|
||||
// |map2| should be left unchanged but marked unstable.
|
||||
CHECK(!map2->is_stable());
|
||||
@ -1671,8 +1674,8 @@ TEST(ReconfigureDataFieldAttribute_AccConstantToAccFieldAfterTargetMap) {
|
||||
if (IS_ACCESSOR_FIELD_SUPPORTED) {
|
||||
expectations.SetAccessorField(property_index);
|
||||
} else {
|
||||
// Currently we have a copy-generalize-all-representations case and
|
||||
// ACCESSOR property becomes ACCESSOR_CONSTANT.
|
||||
// Currently we have a normalize case and ACCESSOR property becomes
|
||||
// ACCESSOR_CONSTANT.
|
||||
expectations.SetAccessorConstant(property_index, pair2_);
|
||||
}
|
||||
}
|
||||
@ -1680,11 +1683,11 @@ TEST(ReconfigureDataFieldAttribute_AccConstantToAccFieldAfterTargetMap) {
|
||||
|
||||
TestConfig config;
|
||||
if (IS_ACCESSOR_FIELD_SUPPORTED) {
|
||||
CheckCopyGeneralizeAllFields checker;
|
||||
CheckSameMap checker;
|
||||
TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
|
||||
} else {
|
||||
// Currently we have a copy-generalize-all-representations case.
|
||||
CheckCopyGeneralizeAllFields checker;
|
||||
// Currently we have a normalize case.
|
||||
CheckNormalize checker;
|
||||
TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
|
||||
}
|
||||
}
|
||||
@ -2083,18 +2086,13 @@ TEST(ReconfigurePropertySplitMapTransitionsOverflow) {
|
||||
CHECK(!TransitionsAccessor(isolate, map2).CanHaveMoreTransitions());
|
||||
|
||||
// Try to update |map|, since there is no place for propX transition at |map2|
|
||||
// |map| should become "copy-generalized".
|
||||
// |map| should become normalized.
|
||||
Handle<Map> updated_map = Map::Update(isolate, map);
|
||||
CHECK(updated_map->GetBackPointer().IsUndefined(isolate));
|
||||
|
||||
for (int i = 0; i < kPropCount; i++) {
|
||||
expectations.SetDataField(i, PropertyConstness::kMutable,
|
||||
Representation::Tagged(), any_type);
|
||||
}
|
||||
CHECK(expectations.Check(*updated_map));
|
||||
CheckNormalize checker;
|
||||
checker.Check(isolate, map2, updated_map, expectations);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// A set of tests involving special transitions (such as elements kind
|
||||
// transition, observed transition or prototype transition).
|
||||
@ -2502,7 +2500,8 @@ struct ReconfigureAsDataPropertyOperator {
|
||||
expectations.SetDataField(descriptor_, PropertyConstness::kMutable,
|
||||
representation_, heap_type_);
|
||||
return Map::ReconfigureExistingProperty(isolate, map, descriptor_, kData,
|
||||
attributes_);
|
||||
attributes_,
|
||||
PropertyConstness::kConst);
|
||||
}
|
||||
};
|
||||
|
||||
@ -2519,7 +2518,8 @@ struct ReconfigureAsAccessorPropertyOperator {
|
||||
Handle<Map> map) {
|
||||
expectations.SetAccessorField(descriptor_);
|
||||
return Map::ReconfigureExistingProperty(isolate, map, descriptor_,
|
||||
kAccessor, attributes_);
|
||||
kAccessor, attributes_,
|
||||
PropertyConstness::kConst);
|
||||
}
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user