[vm/compiler] Make TemplateLoadField::CanCallDart more precise.

Only return true if the stub being invoked will call the
initializer function directly. Notably, return false if the stub
just calls the runtime.

This removes some write barriers in legacy code that were added
after 37d45743.

TEST=New asserts that check CanCallDart() is false when calling runtime
     and is true when calling stubs that call initializer functions
     directly, combined with legacy code tests that use non-late fields.

Change-Id: I4118968b6ea42371d068c35d50339574939556e5
Bug: b/208619946
Cq-Include-Trybots: luci.dart.try:vm-kernel-linux-release-simarm-try,vm-kernel-linux-release-simarm64-try,vm-kernel-linux-release-ia32-try,vm-kernel-linux-release-x64-try,vm-kernel-nnbd-linux-release-ia32-try,vm-kernel-nnbd-linux-release-simarm-try,vm-kernel-nnbd-linux-release-simarm64-try,vm-kernel-nnbd-linux-release-x64-try,vm-kernel-precomp-linux-release-simarm-try,vm-kernel-precomp-linux-release-simarm64-try,vm-kernel-precomp-linux-release-simarm_x64-try,vm-kernel-precomp-linux-release-x64-try,vm-kernel-precomp-nnbd-linux-release-simarm64-try,vm-kernel-precomp-nnbd-linux-release-simarm_x64-try,vm-kernel-precomp-nnbd-linux-release-x64-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/221943
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Tess Strickland <sstrickl@google.com>
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index c3683d0..0540135 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -4203,11 +4203,13 @@
     auto& stub = Code::ZoneHandle(compiler->zone());
     __ Bind(&call_initializer);
     if (field().needs_load_guard()) {
+      ASSERT(!CanCallDart());
       stub = object_store->init_static_field_stub();
     } else if (field().is_late()) {
       // The stubs below call the initializer function directly, so make sure
       // one is created.
       original_field.EnsureInitializerFunction();
+      ASSERT(CanCallDart());
       stub = field().is_final()
                  ? object_store->init_late_final_static_field_stub()
                  : object_store->init_late_static_field_stub();
@@ -4215,6 +4217,7 @@
       // We call to runtime for non-late fields because the stub would need to
       // catch any exception generated by the initialization function to change
       // the value of the static field from the transition sentinel to null.
+      ASSERT(!CanCallDart());
       stub = object_store->init_static_field_stub();
     }
 
@@ -4257,16 +4260,19 @@
   auto object_store = compiler->isolate_group()->object_store();
   auto& stub = Code::ZoneHandle(compiler->zone());
   if (field.needs_load_guard()) {
+    ASSERT(!CanCallDart());
     stub = object_store->init_instance_field_stub();
   } else if (field.is_late()) {
     if (!field.has_nontrivial_initializer()) {
       // Common stub calls runtime which will throw an exception.
+      ASSERT(!CanCallDart());
       stub = object_store->init_instance_field_stub();
     } else {
       // Stubs for late field initialization call initializer
       // function directly, so make sure one is created.
       original_field.EnsureInitializerFunction();
 
+      ASSERT(CanCallDart());
       if (field.is_final()) {
         stub = object_store->init_late_final_instance_field_stub();
       } else {
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index 3ef43cc..8d6cf9b 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -5596,15 +5596,15 @@
                     const Field* field = nullptr)
       : Base(source, deopt_id),
         token_pos_(source.token_pos),
-        calls_initializer_(calls_initializer),
-        throw_exception_on_initialization_(false) {
+        calls_runtime_on_initialization_(
+            field != nullptr &&
+            (!field->is_late() || field->needs_load_guard())),
+        throw_exception_on_initialization_(field != nullptr &&
+                                           !field->has_initializer() &&
+                                           !calls_runtime_on_initialization_),
+        calls_initializer_(calls_initializer) {
+    ASSERT(!calls_initializer || field != nullptr);
     ASSERT(!calls_initializer || (deopt_id != DeoptId::kNone));
-    if (calls_initializer_) {
-      ASSERT(field != nullptr);
-      throw_exception_on_initialization_ = !field->needs_load_guard() &&
-                                           field->is_late() &&
-                                           !field->has_initializer();
-    }
   }
 
   virtual TokenPosition token_pos() const { return token_pos_; }
@@ -5634,15 +5634,17 @@
   }
 
   virtual bool CanCallDart() const {
-    return calls_initializer() && !throw_exception_on_initialization();
+    return calls_initializer() && !throw_exception_on_initialization() &&
+           !calls_runtime_on_initialization_;
   }
   virtual bool CanTriggerGC() const { return calls_initializer(); }
   virtual bool MayThrow() const { return calls_initializer(); }
 
  private:
   const TokenPosition token_pos_;
+  const bool calls_runtime_on_initialization_;
+  const bool throw_exception_on_initialization_;
   bool calls_initializer_;
-  bool throw_exception_on_initialization_;
 
   DISALLOW_COPY_AND_ASSIGN(TemplateLoadField);
 };
diff --git a/runtime/vm/compiler/stub_code_compiler.cc b/runtime/vm/compiler/stub_code_compiler.cc
index a4c8a57..bec292f 100644
--- a/runtime/vm/compiler/stub_code_compiler.cc
+++ b/runtime/vm/compiler/stub_code_compiler.cc
@@ -61,8 +61,7 @@
   __ Comment("Calling initializer function");
   __ PushRegister(kFieldReg);
   __ LoadCompressedFieldFromOffset(
-      kFunctionReg, InitInstanceFieldABI::kFieldReg,
-      target::Field::initializer_function_offset());
+      kFunctionReg, kFieldReg, target::Field::initializer_function_offset());
   if (!FLAG_precompiled_mode) {
     __ LoadCompressedFieldFromOffset(CODE_REG, kFunctionReg,
                                      target::Function::code_offset());