[vm] Avoid holding canonical hashes at rest.

Canonical hashes are only stored during a round of canonicalization to avoid expontential time in cases such as those in tests/language_2/canonicalization_hasing_*. Clearing them avoids the GC spending time to visit them.

Bug: https://github.com/dart-lang/sdk/issues/37523
Change-Id: Icad1fad30dcb7eb95864bea8a26991aeccd7adc6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/125760
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Siva Annamalai <asiva@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
diff --git a/runtime/vm/heap/marker.cc b/runtime/vm/heap/marker.cc
index 7b451bd..d6dad68 100644
--- a/runtime/vm/heap/marker.cc
+++ b/runtime/vm/heap/marker.cc
@@ -497,6 +497,8 @@
 }
 
 void GCMarker::ProcessWeakTables(PageSpace* page_space) {
+  TIMELINE_FUNCTION_GC_DURATION(Thread::Current(), "ProcessWeakTables");
+
   for (int sel = 0; sel < Heap::kNumWeakSelectors; sel++) {
     WeakTable* table =
         heap_->GetWeakTable(Heap::kOld, static_cast<Heap::WeakSelector>(sel));
diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc
index 01a8a96..20ffb82 100644
--- a/runtime/vm/heap/scavenger.cc
+++ b/runtime/vm/heap/scavenger.cc
@@ -831,6 +831,8 @@
 }
 
 void Scavenger::ProcessWeakReferences() {
+  TIMELINE_FUNCTION_GC_DURATION(Thread::Current(), "ProcessWeakReferences");
+
   auto rehash_weak_table = [](WeakTable* table, WeakTable* replacement_new,
                               WeakTable* replacement_old) {
     intptr_t size = table->size();
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index a63c300..ad59f52 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -540,6 +540,7 @@
   StackZone stack_zone(thread);
   Zone* zone = stack_zone.GetZone();
 
+  // Clear any old hashes, which may have become invalid.
   thread->heap()->ResetCanonicalHashTable();
 
   Class& cls = Class::Handle(zone);
@@ -557,6 +558,12 @@
     cls = class_table()->At(cid);
     cls.RehashConstants(zone);
   }
+
+  // Canonical hashes are only stored during a round of canonicalization to
+  // avoid expontential time in cases such as those in
+  // tests/language_2/canonicalization_hasing_*. Clear them after
+  // canonicalization is done so the GC won't need to update them.
+  thread->heap()->ResetCanonicalHashTable();
 }
 
 #if defined(DEBUG)
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index b03021b..27dd9ac 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -3766,6 +3766,11 @@
       UNREACHABLE();
     }
   }
+  // Canonical hashes are only stored during a round of canonicalization to
+  // avoid expontential time in cases such as those in
+  // tests/language_2/canonicalization_hasing_*. Clear them after
+  // canonicalization is done so the GC won't need to update them.
+  thread->heap()->ResetCanonicalHashTable();
   return error.raw();
 }