[vm/types] Ensure type arguments canonicalization doesn't race with readers.


Fixes https://github.com/dart-lang/sdk/issues/47140
TEST=ci, stress bot

Change-Id: I0df3eab99754224344da9a18b8b4b2748e45a8b6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/237761
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Alexander Aprelev <aam@google.com>
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 0ef9ca6..fe33347 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -6908,6 +6908,8 @@
   if (result.IsNull()) {
     // Canonicalize each type argument.
     AbstractType& type_arg = AbstractType::Handle(zone);
+    GrowableHandlePtrArray<const AbstractType> canonicalized_types(zone,
+                                                                   num_types);
     for (intptr_t i = 0; i < num_types; i++) {
       type_arg = TypeAt(i);
       type_arg = type_arg.Canonicalize(thread, trail);
@@ -6916,7 +6918,7 @@
         ASSERT(IsRecursive());
         return this->ptr();
       }
-      SetTypeAt(i, type_arg);
+      canonicalized_types.Add(type_arg);
     }
     // Canonicalization of a type argument of a recursive type argument vector
     // may change the hash of the vector, so invalidate.
@@ -6931,6 +6933,9 @@
     // canonical entry.
     result ^= table.GetOrNull(CanonicalTypeArgumentsKey(*this));
     if (result.IsNull()) {
+      for (intptr_t i = 0; i < num_types; i++) {
+        SetTypeAt(i, canonicalized_types.At(i));
+      }
       // Make sure we have an old space object and add it to the table.
       if (this->IsNew()) {
         result ^= Object::Clone(*this, Heap::kOld);