[vm] Do expensive kernel metadata verification only once per kernel

In DEBUG mode during AOT compilation MetadataHelper::SetMetadataMappings
may spend considerable time verifying that node offsets are sorted
in kernel metadata. The problem is that there are a lot of MetadataHelpers
created (several per each compiled function).

This change moves verification of kernel metadata mappings to
the kernel loader, so it is performed only once per kernel program.

AOT gen_snapshot time on a small test:
Before: 11.680s
After: 9.041s

Change-Id: I1c0a676b0ed28fc5cfa756ca60159f914190fac0
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/103486
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Aart Bik <ajcbik@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
index 9073d5c..b8bfb5d 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
@@ -1367,6 +1367,55 @@
   }
 }
 
+#if defined(DEBUG)
+
+void MetadataHelper::VerifyMetadataMappings(
+    const TypedDataBase& metadata_mappings) {
+  const intptr_t kUInt32Size = 4;
+  Reader reader(metadata_mappings);
+  if (reader.size() == 0) {
+    return;
+  }
+
+  // Scan through metadata mappings in reverse direction.
+
+  // Read metadataMappings length.
+  intptr_t offset = reader.size() - kUInt32Size;
+  const intptr_t metadata_num = reader.ReadUInt32At(offset);
+
+  if (metadata_num == 0) {
+    ASSERT(metadata_mappings.LengthInBytes() == kUInt32Size);
+    return;
+  }
+
+  // Read metadataMappings elements.
+  for (intptr_t i = 0; i < metadata_num; ++i) {
+    // Read nodeOffsetToMetadataOffset length.
+    offset -= kUInt32Size;
+    const intptr_t mappings_num = reader.ReadUInt32At(offset);
+
+    // Skip nodeOffsetToMetadataOffset.
+    offset -= mappings_num * 2 * kUInt32Size;
+
+    // Verify that node offsets are sorted.
+    intptr_t prev_node_offset = -1;
+    reader.set_offset(offset);
+    for (intptr_t j = 0; j < mappings_num; ++j) {
+      const intptr_t node_offset = reader.ReadUInt32();
+      const intptr_t md_offset = reader.ReadUInt32();
+
+      ASSERT(node_offset >= 0 && md_offset >= 0);
+      ASSERT(node_offset > prev_node_offset);
+      prev_node_offset = node_offset;
+    }
+
+    // Skip tag.
+    offset -= kUInt32Size;
+  }
+}
+
+#endif  // defined(DEBUG)
+
 MetadataHelper::MetadataHelper(KernelReaderHelper* helper,
                                const char* tag,
                                bool precompiler_only)
@@ -1386,25 +1435,6 @@
   ASSERT((mappings_offset != 0) && (mappings_num != 0));
   mappings_offset_ = mappings_offset;
   mappings_num_ = mappings_num;
-
-#ifdef DEBUG
-  // Verify that node offsets are sorted.
-  {
-    Reader reader(H.metadata_mappings());
-    reader.set_offset(mappings_offset);
-
-    intptr_t prev_node_offset = -1;
-    for (intptr_t i = 0; i < mappings_num; ++i) {
-      intptr_t node_offset = reader.ReadUInt32();
-      intptr_t md_offset = reader.ReadUInt32();
-
-      ASSERT((node_offset >= 0) && (md_offset >= 0));
-      ASSERT(node_offset > prev_node_offset);
-      prev_node_offset = node_offset;
-    }
-  }
-#endif  // DEBUG
-
   last_node_offset_ = kIntptrMax;
   last_mapping_index_ = 0;
 }
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.h b/runtime/vm/compiler/frontend/kernel_translation_helper.h
index d9a0fa8..0865a30 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.h
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.h
@@ -803,6 +803,10 @@
                  const char* tag,
                  bool precompiler_only);
 
+#if defined(DEBUG)
+  static void VerifyMetadataMappings(const TypedDataBase& metadata_mappings);
+#endif
+
  protected:
   // Look for metadata mapping with node offset greater or equal than the given.
   intptr_t FindMetadataMapping(intptr_t node_offset);
diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc
index 9c89a2d..698a664 100644
--- a/runtime/vm/kernel_loader.cc
+++ b/runtime/vm/kernel_loader.cc
@@ -408,6 +408,10 @@
                                      program_->string_table_offset() -
                                          program_->metadata_mappings_offset()));
 
+#if defined(DEBUG)
+  MetadataHelper::VerifyMetadataMappings(metadata_mappings);
+#endif
+
   const Array& libraries_cache =
       Array::Handle(Z, HashTables::New<UnorderedHashMap<SmiTraits>>(
                            program_->library_count(), Heap::kOld));