[turbofan] Serialize only the relevant property descriptor

Bug: v8:7790
Change-Id: Ib729393c38ca064bf3af141674ab5f697872a1b8
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1613991
Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
Commit-Queue: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61571}
diff --git a/src/compiler/access-info.cc b/src/compiler/access-info.cc
index b4d72b3..867099e 100644
--- a/src/compiler/access-info.cc
+++ b/src/compiler/access-info.cc
@@ -347,13 +347,12 @@
       MachineType::RepCompressedTagged();
   MaybeHandle<Map> field_map;
   MapRef map_ref(broker(), map);
-  map_ref.SerializeOwnDescriptors();  // TODO(neis): Remove later.
   ZoneVector<CompilationDependencies::Dependency const*>
       unrecorded_dependencies(zone());
   if (details_representation.IsSmi()) {
     field_type = Type::SignedSmall();
     field_representation = MachineType::RepCompressedTaggedSigned();
-    map_ref.SerializeOwnDescriptors();  // TODO(neis): Remove later.
+    map_ref.SerializeOwnDescriptor(descriptor);
     unrecorded_dependencies.push_back(
         dependencies()->FieldRepresentationDependencyOffTheRecord(map_ref,
                                                                   descriptor));
@@ -375,7 +374,7 @@
       // The field type was cleared by the GC, so we don't know anything
       // about the contents now.
     }
-    map_ref.SerializeOwnDescriptors();  // TODO(neis): Remove later.
+    map_ref.SerializeOwnDescriptor(descriptor);
     unrecorded_dependencies.push_back(
         dependencies()->FieldRepresentationDependencyOffTheRecord(map_ref,
                                                                   descriptor));
@@ -388,7 +387,7 @@
       field_map = MaybeHandle<Map>(map);
     }
   }
-  map_ref.SerializeOwnDescriptors();  // TODO(neis): Remove later.
+  map_ref.SerializeOwnDescriptor(descriptor);
   PropertyConstness constness =
       dependencies()->DependOnFieldConstness(map_ref, descriptor);
   switch (constness) {
@@ -779,7 +778,7 @@
   if (details_representation.IsSmi()) {
     field_type = Type::SignedSmall();
     field_representation = MachineType::RepCompressedTaggedSigned();
-    transition_map_ref.SerializeOwnDescriptors();  // TODO(neis): Remove later.
+    transition_map_ref.SerializeOwnDescriptor(number);
     unrecorded_dependencies.push_back(
         dependencies()->FieldRepresentationDependencyOffTheRecord(
             transition_map_ref, number));
@@ -797,7 +796,7 @@
       // Store is not safe if the field type was cleared.
       return PropertyAccessInfo::Invalid(zone());
     }
-    transition_map_ref.SerializeOwnDescriptors();  // TODO(neis): Remove later.
+    transition_map_ref.SerializeOwnDescriptor(number);
     unrecorded_dependencies.push_back(
         dependencies()->FieldRepresentationDependencyOffTheRecord(
             transition_map_ref, number));
diff --git a/src/compiler/js-heap-broker.cc b/src/compiler/js-heap-broker.cc
index f5efd59..e91d24f 100644
--- a/src/compiler/js-heap-broker.cc
+++ b/src/compiler/js-heap-broker.cc
@@ -854,11 +854,11 @@
     return elements_kind_generalizations_;
   }
 
-  // Serialize the own part of the descriptor array and, recursively, that of
-  // any field owner.
+  // Serialize a single (or all) own slot(s) of the descriptor array and recurse
+  // on field owner(s).
+  void SerializeOwnDescriptor(JSHeapBroker* broker, int descriptor_index);
   void SerializeOwnDescriptors(JSHeapBroker* broker);
   DescriptorArrayData* instance_descriptors() const {
-    CHECK(serialized_own_descriptors_);
     return instance_descriptors_;
   }
 
@@ -1102,10 +1102,10 @@
                       Handle<DescriptorArray> object)
       : HeapObjectData(broker, storage, object), contents_(broker->zone()) {}
 
-  ZoneVector<PropertyDescriptor>& contents() { return contents_; }
+  ZoneMap<int, PropertyDescriptor>& contents() { return contents_; }
 
  private:
-  ZoneVector<PropertyDescriptor> contents_;
+  ZoneMap<int, PropertyDescriptor> contents_;
 };
 
 class FeedbackCellData : public HeapObjectData {
@@ -1683,52 +1683,55 @@
   TraceScope tracer(broker, this, "MapData::SerializeOwnDescriptors");
   Handle<Map> map = Handle<Map>::cast(object());
 
-  DCHECK_NULL(instance_descriptors_);
-  instance_descriptors_ =
-      broker->GetOrCreateData(map->instance_descriptors())->AsDescriptorArray();
-
   int const number_of_own = map->NumberOfOwnDescriptors();
-  ZoneVector<PropertyDescriptor>& contents = instance_descriptors_->contents();
-  int const current_size = static_cast<int>(contents.size());
-  if (number_of_own <= current_size) return;
+  for (int i = 0; i < number_of_own; ++i) {
+    SerializeOwnDescriptor(broker, i);
+  }
+}
+
+void MapData::SerializeOwnDescriptor(JSHeapBroker* broker,
+                                     int descriptor_index) {
+  TraceScope tracer(broker, this, "MapData::SerializeOwnDescriptor");
+  Handle<Map> map = Handle<Map>::cast(object());
+
+  if (instance_descriptors_ == nullptr) {
+    instance_descriptors_ = broker->GetOrCreateData(map->instance_descriptors())
+                                ->AsDescriptorArray();
+  }
+
+  ZoneMap<int, PropertyDescriptor>& contents =
+      instance_descriptors_->contents();
+  CHECK_LT(descriptor_index, map->NumberOfOwnDescriptors());
+  if (contents.find(descriptor_index) != contents.end()) return;
 
   Isolate* const isolate = broker->isolate();
   auto descriptors =
       Handle<DescriptorArray>::cast(instance_descriptors_->object());
   CHECK_EQ(*descriptors, map->instance_descriptors());
-  contents.reserve(number_of_own);
 
-  // Copy the new descriptors.
-  for (int i = current_size; i < number_of_own; ++i) {
-    PropertyDescriptor d;
-    d.key = broker->GetOrCreateData(descriptors->GetKey(i))->AsName();
-    d.details = descriptors->GetDetails(i);
-    if (d.details.location() == kField) {
-      d.field_index = FieldIndex::ForDescriptor(*map, i);
-      d.field_owner =
-          broker->GetOrCreateData(map->FindFieldOwner(isolate, i))->AsMap();
-      d.field_type = broker->GetOrCreateData(descriptors->GetFieldType(i));
-      d.is_unboxed_double_field = map->IsUnboxedDoubleField(d.field_index);
-      // Recurse.
-    }
-    contents.push_back(d);
+  PropertyDescriptor d;
+  d.key =
+      broker->GetOrCreateData(descriptors->GetKey(descriptor_index))->AsName();
+  d.details = descriptors->GetDetails(descriptor_index);
+  if (d.details.location() == kField) {
+    d.field_index = FieldIndex::ForDescriptor(*map, descriptor_index);
+    d.field_owner =
+        broker->GetOrCreateData(map->FindFieldOwner(isolate, descriptor_index))
+            ->AsMap();
+    d.field_type =
+        broker->GetOrCreateData(descriptors->GetFieldType(descriptor_index));
+    d.is_unboxed_double_field = map->IsUnboxedDoubleField(d.field_index);
   }
-  CHECK_EQ(number_of_own, contents.size());
+  contents[descriptor_index] = d;
 
-  // Recurse on the new owner maps.
-  for (int i = current_size; i < number_of_own; ++i) {
-    const PropertyDescriptor& d = contents[i];
-    if (d.details.location() == kField) {
-      CHECK_LE(
-          Handle<Map>::cast(d.field_owner->object())->NumberOfOwnDescriptors(),
-          number_of_own);
-      d.field_owner->SerializeOwnDescriptors(broker);
-    }
+  if (d.details.location() == kField) {
+    // Recurse on the owner map.
+    d.field_owner->SerializeOwnDescriptor(broker, descriptor_index);
   }
 
-  TRACE(broker, "Copied " << number_of_own - current_size
-                          << " descriptors into " << instance_descriptors_
-                          << " (" << number_of_own << " total)");
+  TRACE(broker, "Copied descriptor " << descriptor_index << " into "
+                                     << instance_descriptors_ << " ("
+                                     << contents.size() << " total)");
 }
 
 void JSObjectData::SerializeRecursive(JSHeapBroker* broker, int depth) {
@@ -3161,6 +3164,12 @@
   data()->AsMap()->SerializeOwnDescriptors(broker());
 }
 
+void MapRef::SerializeOwnDescriptor(int descriptor_index) {
+  if (broker()->mode() == JSHeapBroker::kDisabled) return;
+  CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
+  data()->AsMap()->SerializeOwnDescriptor(broker(), descriptor_index);
+}
+
 void MapRef::SerializeBackPointer() {
   if (broker()->mode() == JSHeapBroker::kDisabled) return;
   CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
diff --git a/src/compiler/js-heap-broker.h b/src/compiler/js-heap-broker.h
index 2ebe198..e35f1c7 100644
--- a/src/compiler/js-heap-broker.h
+++ b/src/compiler/js-heap-broker.h
@@ -528,6 +528,7 @@
 
   // Concerning the underlying instance_descriptors:
   void SerializeOwnDescriptors();
+  void SerializeOwnDescriptor(int descriptor_index);
   MapRef FindFieldOwner(int descriptor_index) const;
   PropertyDetails GetPropertyDetails(int descriptor_index) const;
   NameRef GetPropertyKey(int descriptor_index) const;