[vm] Follow up to 4a4eedd860a8af2b1cb27e68d9feae5550d0f511

* Avoid calling memmove(dst, nullptr, 0) as this is flagged by UBSAN.
* Avoid hitting a bug[1] in the linker: LLD's identical code folding
(ICF) happens to replace RecordCoverageInstr::DebugName() with
DispatchTable::LargestSmallOffset() because they happen to contain
the same machine code, ICF fails to accomodate that DebugName also
contains a relocation to constant string. To avoid this we simply
eliminate LargestSmallOffset and replace it with a constant. Same for
OriginElement.

TEST=manually tested previously failing tests

[1]: reported https://github.com/llvm/llvm-project/issues/57693

Change-Id: I38637df6475c7670081b7af0a2de75ca37f6f07c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/258801
Reviewed-by: Daco Harkes <dacoharkes@google.com>
Commit-Queue: Slava Egorov <vegorov@google.com>
diff --git a/runtime/vm/analyze_snapshot_api_impl.cc b/runtime/vm/analyze_snapshot_api_impl.cc
index fa45dd6..7f340ab 100644
--- a/runtime/vm/analyze_snapshot_api_impl.cc
+++ b/runtime/vm/analyze_snapshot_api_impl.cc
@@ -238,7 +238,7 @@
 //   auto dispatch = thread->isolate_group()->dispatch_table();
 //   auto length = dispatch->length();
 // We must unbias the array entries so we don't crash on null access.
-//   auto entries = dispatch->ArrayOrigin() - DispatchTable::OriginElement();
+//   auto entries = dispatch->ArrayOrigin() - DispatchTable::kOriginElement;
 //   for (intptr_t i = 0; i < length; i++) {
 //     OS::Print("0x%lx at %ld\n", entries[i], i);
 //   }
diff --git a/runtime/vm/class_table.h b/runtime/vm/class_table.h
index e4c21f7..a6fa4cb 100644
--- a/runtime/vm/class_table.h
+++ b/runtime/vm/class_table.h
@@ -98,6 +98,10 @@
   // Clone the given |array| with |size| elements.
   template <class T>
   inline T* Clone(T* array, intptr_t size) {
+    if (array == nullptr) {
+      ASSERT(size == 0);
+      return nullptr;
+    }
     auto result = Alloc<T>(size);
     memmove(result, array, size * sizeof(T));
     return result;
@@ -112,7 +116,10 @@
   inline T* Realloc(T* array, intptr_t size, intptr_t new_size) {
     ASSERT(size < new_size);
     auto result = AllocZeroInitialized<T>(new_size);
-    memmove(result, array, size * sizeof(T));
+    if (size != 0) {
+      ASSERT(result != nullptr);
+      memmove(result, array, size * sizeof(T));
+    }
     Free(array);
     return result;
   }
diff --git a/runtime/vm/compiler/aot/dispatch_table_generator.cc b/runtime/vm/compiler/aot/dispatch_table_generator.cc
index 1245c38..6d8694f 100644
--- a/runtime/vm/compiler/aot/dispatch_table_generator.cc
+++ b/runtime/vm/compiler/aot/dispatch_table_generator.cc
@@ -629,7 +629,7 @@
   table_rows_.Sort(PopularitySorter::Compare);
 
   // Try to allocate at optimal offset.
-  const int32_t optimal_offset = DispatchTable::OriginElement();
+  const int32_t optimal_offset = DispatchTable::kOriginElement;
   for (intptr_t i = 0; i < table_rows_.length(); i++) {
     fitter.FitAndAllocate(table_rows_[i], optimal_offset, optimal_offset);
   }
@@ -644,7 +644,7 @@
   table_rows_.Sort(PopularitySizeRatioSorter::Compare);
 
   // Try to allocate at small offsets.
-  const int32_t max_offset = DispatchTable::LargestSmallOffset();
+  const int32_t max_offset = DispatchTable::kLargestSmallOffset;
   for (intptr_t i = 0; i < table_rows_.length(); i++) {
     fitter.FitAndAllocate(table_rows_[i], 0, max_offset);
   }
@@ -658,7 +658,7 @@
   table_rows_.Sort(SizeSorter::Compare);
 
   // Allocate remaining rows at large offsets.
-  const int32_t min_large_offset = DispatchTable::LargestSmallOffset() + 1;
+  const int32_t min_large_offset = DispatchTable::kLargestSmallOffset + 1;
   for (intptr_t i = 0; i < table_rows_.length(); i++) {
     fitter.FitAndAllocate(table_rows_[i], min_large_offset);
   }
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
index 5a9918a..26d1a71 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
@@ -695,7 +695,7 @@
   if (!arguments_descriptor.IsNull()) {
     __ LoadObject(ARGS_DESC_REG, arguments_descriptor);
   }
-  intptr_t offset = (selector_offset - DispatchTable::OriginElement()) *
+  intptr_t offset = (selector_offset - DispatchTable::kOriginElement) *
                     compiler::target::kWordSize;
   CLOBBERS_LR({
     // Would like cid_reg to be available on entry to the target function
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
index fd697f2..9603a4f 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
@@ -696,7 +696,7 @@
   if (!arguments_descriptor.IsNull()) {
     __ LoadObject(ARGS_DESC_REG, arguments_descriptor);
   }
-  const intptr_t offset = selector_offset - DispatchTable::OriginElement();
+  const intptr_t offset = selector_offset - DispatchTable::kOriginElement;
   CLOBBERS_LR({
     // Would like cid_reg to be available on entry to the target function
     // for checking purposes.
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_riscv.cc b/runtime/vm/compiler/backend/flow_graph_compiler_riscv.cc
index 1decc19..97e7da8 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_riscv.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_riscv.cc
@@ -666,7 +666,7 @@
   if (!arguments_descriptor.IsNull()) {
     __ LoadObject(ARGS_DESC_REG, arguments_descriptor);
   }
-  const intptr_t offset = selector_offset - DispatchTable::OriginElement();
+  const intptr_t offset = selector_offset - DispatchTable::kOriginElement;
   // Would like cid_reg to be available on entry to the target function
   // for checking purposes.
   ASSERT(cid_reg != TMP);
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
index ba0add49..e8c2a7d 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
@@ -682,7 +682,7 @@
   if (!arguments_descriptor.IsNull()) {
     __ LoadObject(ARGS_DESC_REG, arguments_descriptor);
   }
-  const intptr_t offset = (selector_offset - DispatchTable::OriginElement()) *
+  const intptr_t offset = (selector_offset - DispatchTable::kOriginElement) *
                           compiler::target::kWordSize;
   __ LoadDispatchTable(table_reg);
   __ call(compiler::Address(table_reg, cid_reg, TIMES_8, offset));
diff --git a/runtime/vm/dispatch_table.cc b/runtime/vm/dispatch_table.cc
index 7aa3eca..8ec4661 100644
--- a/runtime/vm/dispatch_table.cc
+++ b/runtime/vm/dispatch_table.cc
@@ -8,54 +8,8 @@
 
 namespace dart {
 
-intptr_t DispatchTable::OriginElement() {
-#if defined(TARGET_ARCH_X64)
-  // Max negative byte offset / 8
-  return 16;
-#elif defined(TARGET_ARCH_ARM)
-  // Max negative load offset / 4
-  return 1023;
-#elif defined(TARGET_ARCH_ARM64)
-  // Max consecutive sub immediate value
-  return 4096;
-#elif defined(TARGET_ARCH_RISCV32)
-  // Max consecutive sub immediate value
-  return 2048 / 4;
-#elif defined(TARGET_ARCH_RISCV64)
-  // Max consecutive sub immediate value
-  return 2048 / 8;
-#else
-  // No AOT on IA32
-  UNREACHABLE();
-  return 0;
-#endif
-}
-
-intptr_t DispatchTable::LargestSmallOffset() {
-#if defined(TARGET_ARCH_X64)
-  // Origin + Max positive byte offset / 8
-  return 31;
-#elif defined(TARGET_ARCH_ARM)
-  // Origin + Max positive load offset / 4
-  return 2046;
-#elif defined(TARGET_ARCH_ARM64)
-  // Origin + Max consecutive add immediate value
-  return 8192;
-#elif defined(TARGET_ARCH_RISCV32)
-  // Origin + Max consecutive add immediate value
-  return 4096 / 4;
-#elif defined(TARGET_ARCH_RISCV64)
-  // Origin + Max consecutive add immediate value
-  return 4096 / 8;
-#else
-  // No AOT on IA32
-  UNREACHABLE();
-  return 0;
-#endif
-}
-
 const uword* DispatchTable::ArrayOrigin() const {
-  return &array_.get()[OriginElement()];
+  return &array_.get()[kOriginElement];
 }
 
 }  // namespace dart
diff --git a/runtime/vm/dispatch_table.h b/runtime/vm/dispatch_table.h
index 8d02cdf..6ba4369 100644
--- a/runtime/vm/dispatch_table.h
+++ b/runtime/vm/dispatch_table.h
@@ -20,8 +20,45 @@
 
   // The element of the dispatch table array to which the dispatch table
   // register points.
-  static intptr_t OriginElement();
-  static intptr_t LargestSmallOffset();
+#if defined(TARGET_ARCH_X64)
+  // Max negative byte offset / 8
+  static constexpr intptr_t kOriginElement = 16;
+#elif defined(TARGET_ARCH_ARM)
+  // Max negative load offset / 4
+  static constexpr intptr_t kOriginElement = 1023;
+#elif defined(TARGET_ARCH_ARM64)
+  // Max consecutive sub immediate value
+  static constexpr intptr_t kOriginElement = 4096;
+#elif defined(TARGET_ARCH_RISCV32)
+  // Max consecutive sub immediate value
+  static constexpr intptr_t kOriginElement = 2048 / 4;
+#elif defined(TARGET_ARCH_RISCV64)
+  // Max consecutive sub immediate value
+  static constexpr intptr_t kOriginElement = 2048 / 8;
+#else
+  static constexpr intptr_t kOriginElement = 0;
+#endif
+
+#if defined(TARGET_ARCH_X64)
+  // Origin + Max positive byte offset / 8
+  static constexpr intptr_t kLargestSmallOffset = 31;
+#elif defined(TARGET_ARCH_ARM)
+  // Origin + Max positive load offset / 4
+  static constexpr intptr_t kLargestSmallOffset = 2046;
+#elif defined(TARGET_ARCH_ARM64)
+  // Origin + Max consecutive add immediate value
+  static constexpr intptr_t kLargestSmallOffset = 8192;
+#elif defined(TARGET_ARCH_RISCV32)
+  // Origin + Max consecutive add immediate value
+  static constexpr intptr_t kLargestSmallOffset = 4096 / 4;
+#elif defined(TARGET_ARCH_RISCV64)
+  // Origin + Max consecutive add immediate value
+  static constexpr intptr_t kLargestSmallOffset = 4096 / 8;
+#else
+  // No AOT on IA32
+  static constexpr intptr_t kLargestSmallOffset = 0;
+#endif
+
   // Dispatch table array pointer to put into the dispatch table register.
   const uword* ArrayOrigin() const;