[vm/aot] Fix retaining of exception types and auxiliary functions

There are two fixes:

1) If a function was compiled but not retained, precompiler
should still trace through types used in exception handlers.

2) Certain auxiliary functions such as implicit closure functions
and field initializers were added to 'possibly_retained_functions_'
set but were not traced through AddTypesOf and were not added to
'functions_to_retain_' set.

Flutter gallery AOT snapshot size
release - no changes
release-sizeopt arm +0.13%, arm64 +0.14%

TEST=ci
Fixes https://github.com/dart-lang/sdk/issues/45179
Issue https://github.com/dart-lang/sdk/issues/44852

Change-Id: Ide9a7e82a7bb9098dc90bc41a76e527e7a5cb603
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/190781
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Tess Strickland <sstrickl@google.com>
diff --git a/runtime/vm/compiler/aot/precompiler.cc b/runtime/vm/compiler/aot/precompiler.cc
index 0753c3e..0beffef 100644
--- a/runtime/vm/compiler/aot/precompiler.cc
+++ b/runtime/vm/compiler/aot/precompiler.cc
@@ -667,6 +667,28 @@
     }
   }
 
+  const ExceptionHandlers& handlers =
+      ExceptionHandlers::Handle(Z, code.exception_handlers());
+  if (!handlers.IsNull()) {
+#if defined(PRODUCT)
+    // List of handled types is only used by debugger and
+    // can be removed in PRODUCT mode.
+    for (intptr_t i = 0; i < handlers.num_entries(); i++) {
+      handlers.SetHandledTypes(i, Array::empty_array());
+    }
+#else
+    Array& types = Array::Handle(Z);
+    AbstractType& type = AbstractType::Handle(Z);
+    for (intptr_t i = 0; i < handlers.num_entries(); i++) {
+      types = handlers.GetHandledTypes(i);
+      for (intptr_t j = 0; j < types.Length(); j++) {
+        type ^= types.At(j);
+        AddType(type);
+      }
+    }
+#endif  // defined(PRODUCT)
+  }
+
 #if defined(TARGET_ARCH_IA32)
   FATAL("Callee scanning unimplemented for IA32");
 #endif
@@ -806,7 +828,6 @@
   const FunctionType& signature = FunctionType::Handle(Z, function.signature());
   AddType(signature);
 
-  AbstractType& type = AbstractType::Handle(Z);
   // At this point, ensure any cached default type arguments are canonicalized.
   function.UpdateCachedDefaultTypeArguments(thread());
   if (function.CachesDefaultTypeArguments()) {
@@ -815,20 +836,6 @@
     ASSERT(defaults.IsCanonical());
     AddTypeArguments(defaults);
   }
-  Code& code = Code::Handle(Z, function.CurrentCode());
-  ASSERT(!code.IsNull());
-  const ExceptionHandlers& handlers =
-      ExceptionHandlers::Handle(Z, code.exception_handlers());
-  if (!handlers.IsNull()) {
-    Array& types = Array::Handle(Z);
-    for (intptr_t i = 0; i < handlers.num_entries(); i++) {
-      types = handlers.GetHandledTypes(i);
-      for (intptr_t j = 0; j < types.Length(); j++) {
-        type ^= types.At(j);
-        AddType(type);
-      }
-    }
-  }
   // A function can always be inlined and have only a nested local function
   // remain.
   const Function& parent = Function::Handle(Z, function.parent_function());
@@ -1607,6 +1614,8 @@
   String& name = String::Handle(Z);
   Function& function = Function::Handle(Z);
   Function& function2 = Function::Handle(Z);
+  Array& fields = Array::Handle(Z);
+  Field& field = Field::Handle(Z);
 
   for (intptr_t i = 0; i < libraries_.Length(); i++) {
     lib ^= libraries_.At(i);
@@ -1631,6 +1640,25 @@
         if (retain) {
           function.DropUncompiledImplicitClosureFunction();
           AddTypesOf(function);
+          if (function.HasImplicitClosureFunction()) {
+            function2 = function.ImplicitClosureFunction();
+            if (possibly_retained_functions_.ContainsKey(function2)) {
+              AddTypesOf(function2);
+            }
+          }
+        }
+      }
+
+      fields = cls.fields();
+      for (intptr_t j = 0; j < fields.Length(); j++) {
+        field ^= fields.At(j);
+        if (fields_to_retain_.HasKey(&field) &&
+            field.HasInitializerFunction()) {
+          function = field.InitializerFunction();
+          bool retain = possibly_retained_functions_.ContainsKey(function);
+          if (retain) {
+            AddTypesOf(function);
+          }
         }
       }
 
@@ -1670,6 +1698,22 @@
     }
     return true;  // Continue iteration.
   });
+
+#ifdef DEBUG
+  // Make sure functions_to_retain_ is a super-set of
+  // possibly_retained_functions_.
+  FunctionSet::Iterator it(&possibly_retained_functions_);
+  while (it.MoveNext()) {
+    function ^= possibly_retained_functions_.GetKey(it.Current());
+    // Ffi trampoline functions are not reachable from program structure,
+    // they are referenced only from code (object pool).
+    if (!functions_to_retain_.ContainsKey(function) &&
+        !function.IsFfiTrampoline()) {
+      FATAL1("Function %s was not traced in TraceForRetainedFunctions\n",
+             function.ToFullyQualifiedCString());
+    }
+  }
+#endif  // DEBUG
 }
 
 void Precompiler::FinalizeDispatchTable() {