[vm/concurrency] Use ICData::NewWithCheck() when creating new ICData with initial checks

Issue https://github.com/dart-lang/sdk/issues/36097

TEST=Refactoring, covered by existing test suite.

Change-Id: Idb1a3e8024dc257bac31267d7f9657c6faa3cbcb
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/174464
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 1844961..160aa54 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -14879,6 +14879,24 @@
 }
 #endif
 
+void ICData::SetTargetAtPos(const Array& data,
+                            intptr_t data_pos,
+                            intptr_t num_args_tested,
+                            const Function& target) {
+#if !defined(DART_PRECOMPILED_RUNTIME)
+  // JIT
+  data.SetAt(data_pos + TargetIndexFor(num_args_tested), target);
+#else
+  // AOT
+  ASSERT(target.HasCode());
+  const Code& code = Code::Handle(target.CurrentCode());
+  const Smi& entry_point =
+      Smi::Handle(Smi::FromAlignedAddress(code.EntryPoint()));
+  data.SetAt(data_pos + CodeIndexFor(num_args_tested), code);
+  data.SetAt(data_pos + EntryPointIndexFor(num_args_tested), entry_point);
+#endif
+}
+
 const char* ICData::ToCString() const {
   Zone* zone = Thread::Current()->zone();
   const String& name = String::Handle(zone, target_name());
@@ -15330,24 +15348,15 @@
     data_pos = 0;
   }
   data.SetAt(data_pos, Smi::Handle(Smi::New(receiver_class_id)));
+  SetTargetAtPos(data, data_pos, kNumArgsTested, target);
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
-  // JIT
-  data.SetAt(data_pos + TargetIndexFor(kNumArgsTested), target);
   data.SetAt(data_pos + CountIndexFor(kNumArgsTested),
              Smi::Handle(Smi::New(count)));
   if (is_tracking_exactness()) {
     data.SetAt(data_pos + ExactnessIndexFor(kNumArgsTested),
                Smi::Handle(Smi::New(exactness.Encode())));
   }
-#else
-  // AOT
-  ASSERT(target.HasCode());
-  const Code& code = Code::Handle(target.CurrentCode());
-  const Smi& entry_point =
-      Smi::Handle(Smi::FromAlignedAddress(code.EntryPoint()));
-  data.SetAt(data_pos + CodeIndexFor(kNumArgsTested), code);
-  data.SetAt(data_pos + EntryPointIndexFor(kNumArgsTested), entry_point);
 #endif
 
   // Multithreaded access to ICData requires setting of array to be the last
@@ -15822,9 +15831,13 @@
     cid = Smi::New((*cids)[i]);
     array.SetAt(i, cid);
   }
+
+  SetTargetAtPos(array, 0, num_args_tested, target);
+#if !defined(DART_PRECOMPILED_RUNTIME)
   array.SetAt(CountIndexFor(num_args_tested), Object::smi_zero());
-  array.SetAt(TargetIndexFor(num_args_tested), target);
+#endif
   WriteSentinel(array, entry_len);
+
   result.set_entries(array);
 
   return result.raw();
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index b5d8548..3c70ead 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2258,6 +2258,11 @@
   void SetNumArgsTested(intptr_t value) const;
   void SetReceiversStaticType(const AbstractType& type) const;
 
+  static void SetTargetAtPos(const Array& data,
+                             intptr_t data_pos,
+                             intptr_t num_args_tested,
+                             const Function& target);
+
   // This bit is set when a call site becomes megamorphic and starts using a
   // MegamorphicCache instead of ICData. It means that the entries in the
   // ICData are incomplete and the MegamorphicCache needs to also be consulted
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index f241c0c..8ef9463 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -1596,6 +1596,9 @@
   void DoMegamorphicMiss(const MegamorphicCache& data,
                          const Function& target_function);
 
+  ICDataPtr NewICData();
+  ICDataPtr NewICDataWithTarget(intptr_t cid, const Function& target);
+
   Isolate* isolate_;
   Thread* thread_;
   Zone* zone_;
@@ -1613,16 +1616,11 @@
 
 void SwitchableCallHandler::DoUnlinkedCall(const UnlinkedCall& unlinked,
                                            const Function& target_function) {
-  const String& name = String::Handle(zone_, unlinked.target_name());
-  const Array& descriptor =
-      Array::Handle(zone_, unlinked.arguments_descriptor());
-  const ICData& ic_data =
-      ICData::Handle(zone_, ICData::New(caller_function_, name, descriptor,
-                                        DeoptId::kNone, 1, /* args_tested */
-                                        ICData::kInstance));
-  if (!target_function.IsNull()) {
-    ic_data.AddReceiverCheck(receiver_.GetClassId(), target_function);
-  }
+  const auto& ic_data = ICData::Handle(
+      zone_,
+      target_function.IsNull()
+          ? NewICData()
+          : NewICDataWithTarget(receiver_.GetClassId(), target_function));
 
   Object& object = Object::Handle(zone_, ic_data.raw());
   Code& code = Code::Handle(zone_, StubCode::ICCallThroughCode().raw());
@@ -1746,14 +1744,10 @@
       zone_,
       Resolve(thread_, zone_, old_receiver_class, name_, args_descriptor_));
 
-  const ICData& ic_data = ICData::Handle(
-      zone_, ICData::New(caller_function_, name_, args_descriptor_,
-                         DeoptId::kNone, 1, /* args_tested */
-                         ICData::kInstance));
-  // Add the first target.
-  if (!old_target.IsNull()) {
-    ic_data.AddReceiverCheck(old_expected_cid, old_target);
-  }
+  const auto& ic_data = ICData::Handle(
+      zone_, old_target.IsNull()
+                 ? NewICData()
+                 : NewICDataWithTarget(old_expected_cid, old_target));
 
   if (is_monomorphic_hit) {
     // The site just have been updated to monomorphic state with same
@@ -1794,6 +1788,7 @@
   arguments_.SetArgAt(0, stub);
   arguments_.SetReturn(ic_data);
 #else   // JIT
+
   const ICData& ic_data = ICData::Handle(
       zone_,
       FindICDataForInstanceCall(zone_, caller_code_, caller_frame_->pc()));
@@ -1836,13 +1831,11 @@
       Function::Handle(zone_, Function::RawCast(old_target_code.owner()));
 
   // We lost the original ICData when we patched to the monomorphic case.
-  const ICData& ic_data = ICData::Handle(
-      zone_, ICData::New(caller_function_, name_, args_descriptor_,
-                         DeoptId::kNone, 1, /* args_tested */
-                         ICData::kInstance));
-  if (!target_function.IsNull()) {
-    ic_data.AddReceiverCheck(receiver_.GetClassId(), target_function);
-  }
+  const auto& ic_data = ICData::Handle(
+      zone_,
+      target_function.IsNull()
+          ? NewICData()
+          : NewICDataWithTarget(receiver_.GetClassId(), target_function));
 
   intptr_t lower = data.lower_limit();
   intptr_t upper = data.upper_limit();
@@ -1957,6 +1950,20 @@
   arguments_.SetReturn(data);
 }
 
+ICDataPtr SwitchableCallHandler::NewICData() {
+  return ICData::New(caller_function_, name_, args_descriptor_, DeoptId::kNone,
+                     /*num_args_tested=*/1, ICData::kInstance);
+}
+
+ICDataPtr SwitchableCallHandler::NewICDataWithTarget(intptr_t cid,
+                                                     const Function& target) {
+  GrowableArray<intptr_t> cids(1);
+  cids.Add(cid);
+  return ICData::NewWithCheck(caller_function_, name_, args_descriptor_,
+                              DeoptId::kNone, /*num_args_tested=*/1,
+                              ICData::kInstance, &cids, target);
+}
+
 FunctionPtr SwitchableCallHandler::ResolveTargetFunction(const Object& data) {
   switch (data.GetClassId()) {
     case kUnlinkedCallCid: {