diff options
author | Michaël Zasso <targos@protonmail.com> | 2021-07-14 11:30:07 +0200 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2021-07-20 15:24:51 +0200 |
commit | 6cdd310275bb0f8056aa0ae6d95614e9ca5b70c7 (patch) | |
tree | 9ed37b19cd668894854b7f469010f7621e63ef81 /deps/v8/src/objects/map-updater.cc | |
parent | c0f10006c82d2d9896a552de98ed146f9542720d (diff) | |
download | node-new-6cdd310275bb0f8056aa0ae6d95614e9ca5b70c7.tar.gz |
deps: update V8 to 9.2.230.21
PR-URL: https://github.com/nodejs/node/pull/38990
Reviewed-By: Jiawen Geng <technicalcute@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Diffstat (limited to 'deps/v8/src/objects/map-updater.cc')
-rw-r--r-- | deps/v8/src/objects/map-updater.cc | 280 |
1 files changed, 268 insertions, 12 deletions
diff --git a/deps/v8/src/objects/map-updater.cc b/deps/v8/src/objects/map-updater.cc index 8ab15451a7..feb060fa51 100644 --- a/deps/v8/src/objects/map-updater.cc +++ b/deps/v8/src/objects/map-updater.cc @@ -4,6 +4,10 @@ #include "src/objects/map-updater.h" +#include <queue> + +#include "src/base/platform/mutex.h" +#include "src/execution/frames.h" #include "src/execution/isolate.h" #include "src/handles/handles.h" #include "src/objects/field-type.h" @@ -23,6 +27,66 @@ inline bool EqualImmutableValues(Object obj1, Object obj2) { return false; } +V8_WARN_UNUSED_RESULT Handle<FieldType> GeneralizeFieldType( + Representation rep1, Handle<FieldType> type1, Representation rep2, + Handle<FieldType> type2, Isolate* isolate) { + // Cleared field types need special treatment. They represent lost knowledge, + // so we must be conservative, so their generalization with any other type + // is "Any". + if (Map::FieldTypeIsCleared(rep1, *type1) || + Map::FieldTypeIsCleared(rep2, *type2)) { + return FieldType::Any(isolate); + } + if (type1->NowIs(type2)) return type2; + if (type2->NowIs(type1)) return type1; + return FieldType::Any(isolate); +} + +void PrintGeneralization( + Isolate* isolate, Handle<Map> map, FILE* file, const char* reason, + InternalIndex modify_index, int split, int descriptors, + bool descriptor_to_field, Representation old_representation, + Representation new_representation, PropertyConstness old_constness, + PropertyConstness new_constness, MaybeHandle<FieldType> old_field_type, + MaybeHandle<Object> old_value, MaybeHandle<FieldType> new_field_type, + MaybeHandle<Object> new_value) { + OFStream os(file); + os << "[generalizing]"; + Name name = map->instance_descriptors(isolate).GetKey(modify_index); + if (name.IsString()) { + String::cast(name).PrintOn(file); + } else { + os << "{symbol " << reinterpret_cast<void*>(name.ptr()) << "}"; + } + os << ":"; + if (descriptor_to_field) { + os << "c"; + } else { + os << old_representation.Mnemonic() << "{"; + if (old_field_type.is_null()) { + os << Brief(*(old_value.ToHandleChecked())); + } else { + old_field_type.ToHandleChecked()->PrintTo(os); + } + os << ";" << old_constness << "}"; + } + os << "->" << new_representation.Mnemonic() << "{"; + if (new_field_type.is_null()) { + os << Brief(*(new_value.ToHandleChecked())); + } else { + new_field_type.ToHandleChecked()->PrintTo(os); + } + os << ";" << new_constness << "} ("; + if (strlen(reason) > 0) { + os << reason; + } else { + os << "+" << (descriptors - split) << " maps"; + } + os << ") ["; + JavaScriptFrame::PrintTop(isolate, file, false, true); + os << "]\n"; +} + } // namespace MapUpdater::MapUpdater(Isolate* isolate, Handle<Map> old_map) @@ -142,8 +206,8 @@ Handle<Map> MapUpdater::ReconfigureToDataField(InternalIndex descriptor, old_details.location(), new_representation_); new_field_type_ = - Map::GeneralizeFieldType(old_representation, old_field_type, - new_representation_, field_type, isolate_); + GeneralizeFieldType(old_representation, old_field_type, + new_representation_, field_type, isolate_); } else { // We don't know if this is a first property kind reconfiguration // and we don't know which value was in this property previously @@ -222,8 +286,8 @@ void MapUpdater::GeneralizeField(Handle<Map> map, InternalIndex modify_index, PropertyConstness new_constness, Representation new_representation, Handle<FieldType> new_field_type) { - Map::GeneralizeField(isolate_, map, modify_index, new_constness, - new_representation, new_field_type); + GeneralizeField(isolate_, map, modify_index, new_constness, + new_representation, new_field_type); DCHECK(*old_descriptors_ == old_map_->instance_descriptors(isolate_) || *old_descriptors_ == @@ -237,6 +301,23 @@ MapUpdater::State MapUpdater::Normalize(const char* reason) { return state_; // Done. } +void MapUpdater::ShrinkInstanceSize(base::SharedMutex* map_updater_access, + Map map, int slack) { + DCHECK_GE(slack, 0); +#ifdef DEBUG + int old_visitor_id = Map::GetVisitorId(map); + int new_unused = map.UnusedPropertyFields() - slack; +#endif + + { + base::SharedMutexGuard<base::kExclusive> mutex_guard(map_updater_access); + map.set_instance_size(map.InstanceSizeFromSlack(slack)); + } + map.set_construction_counter(Map::kNoSlackTracking); + DCHECK_EQ(old_visitor_id, Map::GetVisitorId(map)); + DCHECK_EQ(new_unused, map.UnusedPropertyFields()); +} + MapUpdater::State MapUpdater::TryReconfigureToDataFieldInplace() { // Updating deprecated maps in-place doesn't make sense. if (old_map_->is_deprecated()) return state_; @@ -262,9 +343,9 @@ MapUpdater::State MapUpdater::TryReconfigureToDataFieldInplace() { DCHECK_EQ(new_attributes_, old_details.attributes()); DCHECK_EQ(kField, old_details.location()); if (FLAG_trace_generalization) { - old_map_->PrintGeneralization( - isolate_, stdout, "uninitialized field", modified_descriptor_, old_nof_, - old_nof_, false, old_representation, new_representation_, + PrintGeneralization( + isolate_, old_map_, stdout, "uninitialized field", modified_descriptor_, + old_nof_, old_nof_, false, old_representation, new_representation_, old_details.constness(), new_constness_, handle(old_descriptors_->GetFieldType(modified_descriptor_), isolate_), MaybeHandle<Object>(), new_field_type_, MaybeHandle<Object>()); @@ -615,9 +696,9 @@ Handle<DescriptorArray> MapUpdater::BuildDescriptorArray() { GetOrComputeFieldType(target_descriptors, i, target_details.location(), next_representation); - Handle<FieldType> next_field_type = Map::GeneralizeFieldType( - old_details.representation(), old_field_type, next_representation, - target_field_type, isolate_); + Handle<FieldType> next_field_type = + GeneralizeFieldType(old_details.representation(), old_field_type, + next_representation, target_field_type, isolate_); Map::GeneralizeIfCanHaveTransitionableFastElementsKind( isolate_, instance_type, &next_representation, &next_field_type); @@ -795,8 +876,9 @@ MapUpdater::State MapUpdater::ConstructNewMap() { isolate_); } - old_map_->PrintGeneralization( - isolate_, stdout, "", modified_descriptor_, split_nof, old_nof_, + PrintGeneralization( + isolate_, old_map_, stdout, "", modified_descriptor_, split_nof, + old_nof_, old_details.location() == kDescriptor && new_location_ == kField, old_details.representation(), new_details.representation(), old_details.constness(), new_details.constness(), old_field_type, @@ -840,5 +922,179 @@ MapUpdater::State MapUpdater::ConstructNewMapWithIntegrityLevelTransition() { return state_; } +namespace { + +void PrintReconfiguration(Isolate* isolate, Handle<Map> map, FILE* file, + InternalIndex modify_index, PropertyKind kind, + PropertyAttributes attributes) { + OFStream os(file); + os << "[reconfiguring]"; + Name name = map->instance_descriptors(isolate).GetKey(modify_index); + if (name.IsString()) { + String::cast(name).PrintOn(file); + } else { + os << "{symbol " << reinterpret_cast<void*>(name.ptr()) << "}"; + } + os << ": " << (kind == kData ? "kData" : "ACCESSORS") << ", attrs: "; + os << attributes << " ["; + JavaScriptFrame::PrintTop(isolate, file, false, true); + os << "]\n"; +} + +} // namespace + +// static +Handle<Map> MapUpdater::ReconfigureExistingProperty( + Isolate* isolate, Handle<Map> map, InternalIndex descriptor, + PropertyKind kind, PropertyAttributes attributes, + PropertyConstness constness) { + // Dictionaries have to be reconfigured in-place. + DCHECK(!map->is_dictionary_map()); + DCHECK_EQ(kData, kind); // Only kData case is supported so far. + + if (!map->GetBackPointer().IsMap()) { + // There is no benefit from reconstructing transition tree for maps without + // 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) { + PrintReconfiguration(isolate, map, stdout, descriptor, kind, attributes); + } + + return MapUpdater{isolate, map}.ReconfigureToDataField( + descriptor, attributes, constness, Representation::None(), + FieldType::None(isolate)); +} + +// static +void MapUpdater::UpdateFieldType(Isolate* isolate, Handle<Map> map, + InternalIndex descriptor, Handle<Name> name, + PropertyConstness new_constness, + Representation new_representation, + const MaybeObjectHandle& new_wrapped_type) { + DCHECK(new_wrapped_type->IsSmi() || new_wrapped_type->IsWeak()); + // We store raw pointers in the queue, so no allocations are allowed. + DisallowGarbageCollection no_gc; + PropertyDetails details = + map->instance_descriptors(isolate).GetDetails(descriptor); + if (details.location() != kField) return; + DCHECK_EQ(kData, details.kind()); + + if (new_constness != details.constness() && map->is_prototype_map()) { + JSObject::InvalidatePrototypeChains(*map); + } + + std::queue<Map> backlog; + backlog.push(*map); + + while (!backlog.empty()) { + Map current = backlog.front(); + backlog.pop(); + + TransitionsAccessor transitions(isolate, current, &no_gc); + int num_transitions = transitions.NumberOfTransitions(); + for (int i = 0; i < num_transitions; ++i) { + Map target = transitions.GetTarget(i); + backlog.push(target); + } + DescriptorArray descriptors = current.instance_descriptors(isolate); + PropertyDetails details = descriptors.GetDetails(descriptor); + + // It is allowed to change representation here only from None + // to something or from Smi or HeapObject to Tagged. + DCHECK(details.representation().Equals(new_representation) || + details.representation().CanBeInPlaceChangedTo(new_representation)); + + // Skip if already updated the shared descriptor. + if (new_constness != details.constness() || + !new_representation.Equals(details.representation()) || + descriptors.GetFieldType(descriptor) != *new_wrapped_type.object()) { + Descriptor d = Descriptor::DataField( + name, descriptors.GetFieldIndex(descriptor), details.attributes(), + new_constness, new_representation, new_wrapped_type); + descriptors.Replace(descriptor, &d); + } + } +} + +// TODO(jgruber): Lock the map-updater mutex. +// static +void MapUpdater::GeneralizeField(Isolate* isolate, Handle<Map> map, + InternalIndex modify_index, + PropertyConstness new_constness, + Representation new_representation, + Handle<FieldType> new_field_type) { + DCHECK(!map->is_deprecated()); + + // Check if we actually need to generalize the field type at all. + Handle<DescriptorArray> old_descriptors(map->instance_descriptors(isolate), + isolate); + PropertyDetails old_details = old_descriptors->GetDetails(modify_index); + PropertyConstness old_constness = old_details.constness(); + Representation old_representation = old_details.representation(); + Handle<FieldType> old_field_type(old_descriptors->GetFieldType(modify_index), + isolate); + + // Return if the current map is general enough to hold requested constness and + // representation/field type. + if (IsGeneralizableTo(new_constness, old_constness) && + old_representation.Equals(new_representation) && + !Map::FieldTypeIsCleared(new_representation, *new_field_type) && + // Checking old_field_type for being cleared is not necessary because + // the NowIs check below would fail anyway in that case. + new_field_type->NowIs(old_field_type)) { + DCHECK(GeneralizeFieldType(old_representation, old_field_type, + new_representation, new_field_type, isolate) + ->NowIs(old_field_type)); + return; + } + + // Determine the field owner. + Handle<Map> field_owner(map->FindFieldOwner(isolate, modify_index), isolate); + Handle<DescriptorArray> descriptors( + field_owner->instance_descriptors(isolate), isolate); + DCHECK_EQ(*old_field_type, descriptors->GetFieldType(modify_index)); + + new_field_type = + GeneralizeFieldType(old_representation, old_field_type, + new_representation, new_field_type, isolate); + + new_constness = GeneralizeConstness(old_constness, new_constness); + + PropertyDetails details = descriptors->GetDetails(modify_index); + Handle<Name> name(descriptors->GetKey(modify_index), isolate); + + MaybeObjectHandle wrapped_type(Map::WrapFieldType(isolate, new_field_type)); + UpdateFieldType(isolate, field_owner, modify_index, name, new_constness, + new_representation, wrapped_type); + + if (new_constness != old_constness) { + field_owner->dependent_code().DeoptimizeDependentCodeGroup( + DependentCode::kFieldConstGroup); + } + + if (!new_field_type->Equals(*old_field_type)) { + field_owner->dependent_code().DeoptimizeDependentCodeGroup( + DependentCode::kFieldTypeGroup); + } + + if (!new_representation.Equals(old_representation)) { + field_owner->dependent_code().DeoptimizeDependentCodeGroup( + DependentCode::kFieldRepresentationGroup); + } + + if (FLAG_trace_generalization) { + PrintGeneralization( + isolate, map, stdout, "field type generalization", modify_index, + map->NumberOfOwnDescriptors(), map->NumberOfOwnDescriptors(), false, + details.representation(), + descriptors->GetDetails(modify_index).representation(), old_constness, + new_constness, old_field_type, MaybeHandle<Object>(), new_field_type, + MaybeHandle<Object>()); + } +} + } // namespace internal } // namespace v8 |