[vm] Move creation of closure functions to kernel loader

This change disentangles creation of closure functions from
flow graph building.

TEST=ci

Change-Id: Ia008c21202453062dd722f64be615e5e6af3bdc2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/357222
Reviewed-by: Slava Egorov <vegorov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
diff --git a/runtime/vm/closure_functions_cache.cc b/runtime/vm/closure_functions_cache.cc
index add92ff..0cb609b 100644
--- a/runtime/vm/closure_functions_cache.cc
+++ b/runtime/vm/closure_functions_cache.cc
@@ -75,9 +75,13 @@
   DEBUG_ASSERT(
       thread->isolate_group()->program_lock()->IsCurrentThreadWriter());
 
-  const auto& closures =
+  auto& closures =
       GrowableObjectArray::Handle(zone, object_store->closure_functions());
-  ASSERT(!closures.IsNull());
+  if (closures.IsNull()) {
+    closures = GrowableObjectArray::New();
+    object_store->set_closure_functions(closures);
+  }
+
   ASSERT(allow_implicit_closure_functions ||
          function.IsNonImplicitClosureFunction());
   closures.Add(function, Heap::kOld);
@@ -116,10 +120,12 @@
 
   const auto& closures_array =
       GrowableObjectArray::Handle(zone, object_store->closure_functions());
-  intptr_t num_closures = closures_array.Length();
-  for (intptr_t i = 0; i < num_closures; i++) {
-    if (closures_array.At(i) == needle.ptr()) {
-      return i;
+  if (!closures_array.IsNull()) {
+    intptr_t num_closures = closures_array.Length();
+    for (intptr_t i = 0; i < num_closures; i++) {
+      if (closures_array.At(i) == needle.ptr()) {
+        return i;
+      }
     }
   }
   return -1;
@@ -134,7 +140,7 @@
 
   const auto& closures_array =
       GrowableObjectArray::Handle(zone, object_store->closure_functions());
-  if (idx < 0 || idx >= closures_array.Length()) {
+  if (idx < 0 || closures_array.IsNull() || idx >= closures_array.Length()) {
     return Function::null();
   }
   return Function::RawCast(closures_array.At(idx));
@@ -161,6 +167,9 @@
   // happen).
   const auto& closures =
       GrowableObjectArray::Handle(zone, object_store->closure_functions());
+  if (closures.IsNull()) {
+    return;
+  }
 
   if (!thread->IsInStoppedMutatorsScope()) {
     // The empty read locker scope will implicitly issue an acquire memory
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index d9d2afa..eaa5a82 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -11,6 +11,7 @@
 #include "vm/compiler/frontend/prologue_builder.h"
 #include "vm/compiler/jit/compiler.h"
 #include "vm/kernel_binary.h"
+#include "vm/kernel_loader.h"
 #include "vm/object_store.h"
 #include "vm/resolver.h"
 #include "vm/stack_frame.h"
@@ -1208,7 +1209,6 @@
 
 Fragment StreamingFlowGraphBuilder::BuildStatement(TokenPosition* position) {
   ++num_ast_nodes_;
-  intptr_t offset = ReaderOffset();
   Tag tag = ReadTag();  // read tag.
   switch (tag) {
     case kExpressionStatement:
@@ -1248,7 +1248,7 @@
     case kVariableDeclaration:
       return BuildVariableDeclaration(position);
     case kFunctionDeclaration:
-      return BuildFunctionDeclaration(offset, position);
+      return BuildFunctionDeclaration(position);
     case kForInStatement:
     case kAsyncForInStatement:
     case kIfCaseStatement:
@@ -4268,10 +4268,9 @@
 }
 
 Fragment StreamingFlowGraphBuilder::BuildFunctionExpression() {
+  const intptr_t offset = ReaderOffset() - 1;  // Include the tag.
   ReadPosition();  // read position.
-  return BuildFunctionNode(TokenPosition::kNoSource, StringIndex(),
-                           /*has_valid_annotation=*/false, /*has_pragma=*/false,
-                           /*func_decl_offset=*/0);
+  return BuildFunctionNode(offset);
 }
 
 Fragment StreamingFlowGraphBuilder::BuildLet(TokenPosition* p) {
@@ -5887,180 +5886,56 @@
 }
 
 Fragment StreamingFlowGraphBuilder::BuildFunctionDeclaration(
-    intptr_t offset,
     TokenPosition* position) {
+  const intptr_t offset = ReaderOffset() - 1;  // Include the tag.
   const TokenPosition pos = ReadPosition();
   if (position != nullptr) *position = pos;
 
   const intptr_t variable_offset = ReaderOffset() + data_program_offset_;
-
-  // Read variable declaration.
-  VariableDeclarationHelper helper(this);
-
-  bool has_pragma = false;
-  bool has_valid_annotation = false;
-  helper.ReadUntilExcluding(VariableDeclarationHelper::kAnnotations);
-  const intptr_t annotation_count = ReadListLength();
-  for (intptr_t i = 0; i < annotation_count; ++i) {
-    const intptr_t tag = PeekTag();
-    if (tag != kInvalidExpression) {
-      has_valid_annotation = true;
-    }
-    if (tag == kConstantExpression || tag == kFileUriConstantExpression) {
-      auto& instance = Instance::Handle();
-      instance = constant_reader_.ReadConstantExpression();
-      if (instance.clazz() == IG->object_store()->pragma_class()) {
-        has_pragma = true;
-      }
-      continue;
-    }
-    SkipExpression();
-  }
-  helper.SetJustRead(VariableDeclarationHelper::kAnnotations);
-
-  helper.ReadUntilExcluding(VariableDeclarationHelper::kEnd);
+  SkipVariableDeclaration();
 
   Fragment instructions = DebugStepCheck(pos);
-  instructions += BuildFunctionNode(pos, helper.name_index_,
-                                    has_valid_annotation, has_pragma, offset);
+  instructions += BuildFunctionNode(offset);
   instructions += StoreLocal(pos, LookupVariable(variable_offset));
   instructions += Drop();
   return instructions;
 }
 
 Fragment StreamingFlowGraphBuilder::BuildFunctionNode(
-    TokenPosition parent_position,
-    StringIndex name_index,
-    bool has_valid_annotation,
-    bool has_pragma,
     intptr_t func_decl_offset) {
-  const intptr_t offset = ReaderOffset();
-
-  FunctionNodeHelper function_node_helper(this);
-  function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kTypeParameters);
-  TokenPosition position = function_node_helper.position_;
-
-  bool declaration = name_index >= 0;
-
-  if (declaration) {
-    position = parent_position;
-  }
-
+  const intptr_t func_node_offset = ReaderOffset();
   const auto& member_function =
       Function::Handle(Z, parsed_function()->function().GetOutermostFunction());
-  Function& function = Function::ZoneHandle(Z);
+  const Function& function = Function::ZoneHandle(
+      Z, KernelLoader::GetClosureFunction(
+             thread(), func_decl_offset, member_function,
+             parsed_function()->function(), closure_owner_));
 
-  {
-    SafepointReadRwLocker ml(thread(),
-                             thread()->isolate_group()->program_lock());
-    function = ClosureFunctionsCache::LookupClosureFunctionLocked(
-        member_function, offset);
-  }
-
-  if (function.IsNull()) {
+  if (function.context_scope() == ContextScope::null()) {
     SafepointWriteRwLocker ml(thread(),
                               thread()->isolate_group()->program_lock());
-    function = ClosureFunctionsCache::LookupClosureFunctionLocked(
-        member_function, offset);
-    if (function.IsNull()) {
+    if (function.context_scope() == ContextScope::null()) {
       for (intptr_t i = 0; i < scopes()->function_scopes.length(); ++i) {
-        if (scopes()->function_scopes[i].kernel_offset != offset) {
+        if (scopes()->function_scopes[i].kernel_offset !=
+            function.kernel_offset()) {
           continue;
         }
 
-        const String* name;
-        if (declaration) {
-          name = &H.DartSymbolObfuscate(name_index);
-        } else {
-          name = &Symbols::AnonymousClosure();
-        }
-        if (!closure_owner_.IsNull()) {
-          function = Function::NewClosureFunctionWithKind(
-              UntaggedFunction::kClosureFunction, *name,
-              parsed_function()->function(),
-              parsed_function()->function().is_static(), position,
-              closure_owner_);
-        } else {
-          function = Function::NewClosureFunction(
-              *name, parsed_function()->function(), position);
-        }
-
-        function.set_has_pragma(has_pragma);
-        if ((FLAG_enable_mirrors && has_valid_annotation) || has_pragma) {
-          auto& lib =
-              Library::Handle(Z, Class::Handle(Z, function.Owner()).library());
-          lib.AddMetadata(function, func_decl_offset);
-        }
-
-        if (function_node_helper.async_marker_ == FunctionNodeHelper::kAsync) {
-          function.set_modifier(UntaggedFunction::kAsync);
-          function.set_is_inlinable(false);
-          ASSERT(function.IsAsyncFunction());
-        } else if (function_node_helper.async_marker_ ==
-                   FunctionNodeHelper::kAsyncStar) {
-          function.set_modifier(UntaggedFunction::kAsyncGen);
-          function.set_is_inlinable(false);
-          ASSERT(function.IsAsyncGenerator());
-        } else if (function_node_helper.async_marker_ ==
-                   FunctionNodeHelper::kSyncStar) {
-          function.set_modifier(UntaggedFunction::kSyncGen);
-          function.set_is_inlinable(false);
-          ASSERT(function.IsSyncGenerator());
-        } else {
-          ASSERT(function_node_helper.async_marker_ ==
-                 FunctionNodeHelper::kSync);
-          ASSERT(!function.IsAsyncFunction());
-          ASSERT(!function.IsAsyncGenerator());
-          ASSERT(!function.IsSyncGenerator());
-        }
-
-        // If the start token position is synthetic, the end token position
-        // should be as well.
-        function.set_end_token_pos(
-            position.IsReal() ? function_node_helper.end_position_ : position);
-
         LocalScope* scope = scopes()->function_scopes[i].scope;
         const ContextScope& context_scope = ContextScope::Handle(
             Z, scope->PreserveOuterScope(function,
                                          flow_graph_builder_->context_depth_));
         function.set_context_scope(context_scope);
-        function.set_kernel_offset(offset);
-        type_translator_.SetupFunctionParameters(Class::Handle(Z), function,
-                                                 false,  // is_method
-                                                 true,   // is_closure
-                                                 &function_node_helper);
-        // type_translator_.SetupUnboxingInfoMetadata is not called here at the
-        // moment because closures do not have unboxed parameters and return
-        // value
-        function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kEnd);
-
-        // Finalize function type.
-        FunctionType& signature = FunctionType::Handle(Z, function.signature());
-        signature ^= ClassFinalizer::FinalizeType(signature);
-        function.SetSignature(signature);
-
-        if (has_pragma) {
-          if (Library::FindPragma(thread(), /*only_core=*/false, function,
-                                  Symbols::vm_invisible())) {
-            function.set_is_visible(false);
-          }
-        }
-
-        ASSERT(function.GetOutermostFunction() == member_function.ptr());
-        ASSERT(function.kernel_offset() == offset);
-        ClosureFunctionsCache::AddClosureFunctionLocked(function);
-        break;
       }
     }
   }
-  ASSERT(function.token_pos() == position);
-  ASSERT(function.parent_function() == parsed_function()->function().ptr());
 
-  function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kEnd);
+  ASSERT(function.kernel_offset() == func_node_offset);
+  SkipFunctionNode();
 
   Fragment instructions;
   instructions += Constant(function);
-  if (scopes()->IsClosureWithEmptyContext(offset)) {
+  if (scopes()->IsClosureWithEmptyContext(func_node_offset)) {
     instructions += NullConstant();
   } else {
     instructions += LoadLocal(parsed_function()->current_context_var());
@@ -6072,7 +5947,7 @@
     instructions += LoadInstantiatorTypeArguments();
   }
   instructions += flow_graph_builder_->AllocateClosure(
-      position, has_instantiator_type_args, function.IsGeneric());
+      function.token_pos(), has_instantiator_type_args, function.IsGeneric());
   LocalVariable* closure = MakeTemporary();
 
   // TODO(30455): We only need to save these if the closure uses any captured
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
index 3b9c6db..2590cb4 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
@@ -370,12 +370,8 @@
   Fragment BuildTryFinally(TokenPosition* position);
   Fragment BuildYieldStatement(TokenPosition* position);
   Fragment BuildVariableDeclaration(TokenPosition* position);
-  Fragment BuildFunctionDeclaration(intptr_t offset, TokenPosition* position);
-  Fragment BuildFunctionNode(TokenPosition parent_position,
-                             StringIndex name_index,
-                             bool has_valid_annotation,
-                             bool has_pragma,
-                             intptr_t func_decl_offset);
+  Fragment BuildFunctionDeclaration(TokenPosition* position);
+  Fragment BuildFunctionNode(intptr_t func_decl_offset);
 
   // Build flow graph for '_nativeEffect'.
   Fragment BuildNativeEffect();
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
index 8705862..994b174 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
@@ -5,6 +5,7 @@
 #include "vm/compiler/frontend/kernel_translation_helper.h"
 
 #include "vm/class_finalizer.h"
+#include "vm/closure_functions_cache.h"
 #include "vm/compiler/aot/precompiler.h"
 #include "vm/compiler/backend/flow_graph_compiler.h"
 #include "vm/compiler/frontend/constant_reader.h"
@@ -2247,21 +2248,39 @@
 
 void KernelReaderHelper::ReadUntilFunctionNode() {
   const Tag tag = PeekTag();
-  if (tag == kProcedure) {
-    ProcedureHelper procedure_helper(this);
-    procedure_helper.ReadUntilExcluding(ProcedureHelper::kFunction);
-    // Now at start of FunctionNode.
-  } else if (tag == kConstructor) {
-    ConstructorHelper constructor_helper(this);
-    constructor_helper.ReadUntilExcluding(ConstructorHelper::kFunction);
-    // Now at start of FunctionNode.
-    // Notice that we also have a list of initializers after that!
-  } else if (tag == kFunctionNode) {
-    // Already at start of FunctionNode.
-  } else {
-    ReportUnexpectedTag("a procedure, a constructor or a function node", tag);
-    UNREACHABLE();
+  switch (tag) {
+    case kProcedure: {
+      ProcedureHelper procedure_helper(this);
+      procedure_helper.ReadUntilExcluding(ProcedureHelper::kFunction);
+      // Now at start of FunctionNode.
+      break;
+    }
+    case kConstructor: {
+      ConstructorHelper constructor_helper(this);
+      constructor_helper.ReadUntilExcluding(ConstructorHelper::kFunction);
+      // Now at start of FunctionNode.
+      // Notice that we also have a list of initializers after that!
+      break;
+    }
+    case kFunctionDeclaration:
+      ReadTag();
+      ReadPosition();
+      SkipVariableDeclaration();
+      break;
+    case kFunctionExpression:
+      ReadTag();
+      ReadPosition();
+      break;
+    case kFunctionNode:
+      // Already at start of FunctionNode.
+      break;
+    default:
+      ReportUnexpectedTag(
+          "a procedure, a constructor, a local function or a function node",
+          tag);
+      UNREACHABLE();
   }
+  ASSERT(PeekTag() == kFunctionNode);
 }
 
 void KernelReaderHelper::SkipDartType() {
diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc
index 0824575..7c94481 100644
--- a/runtime/vm/kernel_loader.cc
+++ b/runtime/vm/kernel_loader.cc
@@ -9,6 +9,7 @@
 
 #include <memory>
 
+#include "vm/closure_functions_cache.h"
 #include "vm/compiler/backend/flow_graph_compiler.h"
 #include "vm/compiler/frontend/constant_reader.h"
 #include "vm/compiler/frontend/kernel_translation_helper.h"
@@ -1037,7 +1038,7 @@
     field_helper.ReadUntilExcluding(FieldHelper::kAnnotations);
     intptr_t annotation_count = helper_.ReadListLength();
     uint32_t pragma_bits = 0;
-    ReadVMAnnotations(library, annotation_count, &pragma_bits);
+    ReadVMAnnotations(annotation_count, &pragma_bits);
     field_helper.SetJustRead(FieldHelper::kAnnotations);
 
     field_helper.ReadUntilExcluding(FieldHelper::kType);
@@ -1351,7 +1352,7 @@
   class_helper.ReadUntilExcluding(ClassHelper::kAnnotations);
   intptr_t annotation_count = helper_.ReadListLength();
   uint32_t pragma_bits = 0;
-  ReadVMAnnotations(library, annotation_count, &pragma_bits);
+  ReadVMAnnotations(annotation_count, &pragma_bits);
   if (IsolateUnsendablePragma::decode(pragma_bits)) {
     out_class->set_is_isolate_unsendable_due_to_pragma(true);
   }
@@ -1440,7 +1441,7 @@
       field_helper.ReadUntilExcluding(FieldHelper::kAnnotations);
       const intptr_t annotation_count = helper_.ReadListLength();
       uint32_t pragma_bits = 0;
-      ReadVMAnnotations(library, annotation_count, &pragma_bits);
+      ReadVMAnnotations(annotation_count, &pragma_bits);
       field_helper.SetJustRead(FieldHelper::kAnnotations);
 
       field_helper.ReadUntilExcluding(FieldHelper::kType);
@@ -1567,7 +1568,7 @@
     constructor_helper.ReadUntilExcluding(ConstructorHelper::kAnnotations);
     const intptr_t annotation_count = helper_.ReadListLength();
     uint32_t pragma_bits = 0;
-    ReadVMAnnotations(library, annotation_count, &pragma_bits);
+    ReadVMAnnotations(annotation_count, &pragma_bits);
     constructor_helper.SetJustRead(ConstructorHelper::kAnnotations);
     constructor_helper.ReadUntilExcluding(ConstructorHelper::kFunction);
 
@@ -1721,8 +1722,7 @@
 //
 //   `pragma_bits`: any recognized pragma that was found
 //
-void KernelLoader::ReadVMAnnotations(const Library& library,
-                                     intptr_t annotation_count,
+void KernelLoader::ReadVMAnnotations(intptr_t annotation_count,
                                      uint32_t* pragma_bits,
                                      String* native_name) {
   *pragma_bits = 0;
@@ -1806,7 +1806,7 @@
   String& native_name = String::Handle(Z);
   uint32_t pragma_bits = 0;
   const intptr_t annotation_count = helper_.ReadListLength();
-  ReadVMAnnotations(library, annotation_count, &pragma_bits, &native_name);
+  ReadVMAnnotations(annotation_count, &pragma_bits, &native_name);
   is_external = is_external && native_name.IsNull();
   procedure_helper.SetJustRead(ProcedureHelper::kAnnotations);
   const Object& script_class =
@@ -2199,6 +2199,155 @@
   return static_cast<UntaggedFunction::Kind>(lookuptable[kind]);
 }
 
+FunctionPtr KernelLoader::LoadClosureFunction(const Function& parent_function,
+                                              const Object& closure_owner) {
+  const intptr_t func_decl_offset = helper_.ReaderOffset();
+  const Tag tag = helper_.ReadTag();
+  ASSERT((tag == kFunctionExpression) || (tag == kFunctionDeclaration));
+  const bool is_declaration = (tag == kFunctionDeclaration);
+
+  TokenPosition position = helper_.ReadPosition();  // read position.
+
+  uint32_t pragma_bits = 0;
+  intptr_t annotation_count = 0;
+  const String* name;
+  if (is_declaration) {
+    // Read variable declaration.
+    VariableDeclarationHelper variable_helper(&helper_);
+
+    variable_helper.ReadUntilExcluding(VariableDeclarationHelper::kAnnotations);
+    const intptr_t annotation_count = helper_.ReadListLength();
+    ReadVMAnnotations(annotation_count, &pragma_bits);
+    variable_helper.SetJustRead(VariableDeclarationHelper::kAnnotations);
+
+    variable_helper.ReadUntilExcluding(VariableDeclarationHelper::kEnd);
+    name = &H.DartSymbolObfuscate(variable_helper.name_index_);
+  } else {
+    name = &Symbols::AnonymousClosure();
+  }
+
+  const intptr_t func_node_offset = helper_.ReaderOffset();
+
+  FunctionNodeHelper function_node_helper(&helper_);
+  function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kTypeParameters);
+
+  Function& function = Function::Handle(Z);
+  if (!closure_owner.IsNull()) {
+    function = Function::NewClosureFunctionWithKind(
+        UntaggedFunction::kClosureFunction, *name, parent_function,
+        parent_function.is_static(), position, closure_owner);
+  } else {
+    function = Function::NewClosureFunction(*name, parent_function, position);
+  }
+
+  const bool has_pragma = HasPragma::decode(pragma_bits);
+  function.set_has_pragma(has_pragma);
+  function.set_is_visible(!InvisibleFunctionPragma::decode(pragma_bits));
+  if ((FLAG_enable_mirrors && (annotation_count > 0)) || has_pragma) {
+    const auto& lib =
+        Library::Handle(Z, Class::Handle(Z, function.Owner()).library());
+    lib.AddMetadata(function, func_decl_offset);
+  }
+
+  if (function_node_helper.async_marker_ == FunctionNodeHelper::kAsync) {
+    function.set_modifier(UntaggedFunction::kAsync);
+    function.set_is_inlinable(false);
+    ASSERT(function.IsAsyncFunction());
+  } else if (function_node_helper.async_marker_ ==
+             FunctionNodeHelper::kAsyncStar) {
+    function.set_modifier(UntaggedFunction::kAsyncGen);
+    function.set_is_inlinable(false);
+    ASSERT(function.IsAsyncGenerator());
+  } else if (function_node_helper.async_marker_ ==
+             FunctionNodeHelper::kSyncStar) {
+    function.set_modifier(UntaggedFunction::kSyncGen);
+    function.set_is_inlinable(false);
+    ASSERT(function.IsSyncGenerator());
+  } else {
+    ASSERT(function_node_helper.async_marker_ == FunctionNodeHelper::kSync);
+    ASSERT(!function.IsAsyncFunction());
+    ASSERT(!function.IsAsyncGenerator());
+    ASSERT(!function.IsSyncGenerator());
+  }
+
+  // If the start token position is synthetic, the end token position
+  // should be as well.
+  function.set_end_token_pos(
+      position.IsReal() ? function_node_helper.end_position_ : position);
+
+  function.set_kernel_offset(func_node_offset);
+  T.SetupFunctionParameters(Class::Handle(Z), function,
+                            false,  // is_method
+                            true,   // is_closure
+                            &function_node_helper);
+  // type_translator->SetupUnboxingInfoMetadata is not called here at the
+  // moment because closures do not have unboxed parameters and return
+  // value
+
+  // Finalize function type.
+  FunctionType& signature = FunctionType::Handle(Z, function.signature());
+  signature ^= ClassFinalizer::FinalizeType(signature);
+  function.SetSignature(signature);
+
+  ClosureFunctionsCache::AddClosureFunctionLocked(function);
+
+  return function.ptr();
+}
+
+FunctionPtr KernelLoader::GetClosureFunction(Thread* thread,
+                                             intptr_t func_decl_offset,
+                                             const Function& member_function,
+                                             const Function& parent_function,
+                                             const Object& closure_owner) {
+  Zone* zone = thread->zone();
+  Function& function = Function::Handle(zone);
+  intptr_t func_node_offset = -1;
+
+  const auto& kernel_info =
+      KernelProgramInfo::Handle(zone, member_function.KernelProgramInfo());
+  const auto& library_kernel_data =
+      TypedDataView::Handle(zone, member_function.KernelLibrary());
+  ASSERT(!library_kernel_data.IsNull());
+  const intptr_t library_kernel_offset = member_function.KernelLibraryOffset();
+
+  KernelLoader kernel_loader(kernel_info, library_kernel_data,
+                             library_kernel_offset);
+  {
+    // TODO(alexmarkov): Use func_decl_offset as a key in ClosureFunctionsCache
+    // instead of func_node_offset and avoid this reading.
+    kernel_loader.helper_.SetOffset(func_decl_offset);
+    kernel_loader.helper_.ReadUntilFunctionNode();
+    func_node_offset = kernel_loader.helper_.ReaderOffset();
+
+    {
+      SafepointReadRwLocker ml(thread, thread->isolate_group()->program_lock());
+      function = ClosureFunctionsCache::LookupClosureFunctionLocked(
+          member_function, func_node_offset);
+      if (!function.IsNull()) {
+        return function.ptr();
+      }
+    }
+  }
+
+  SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
+  function = ClosureFunctionsCache::LookupClosureFunctionLocked(
+      member_function, func_node_offset);
+  if (function.IsNull()) {
+    ActiveClassScope active_class_scope(
+        &kernel_loader.active_class_,
+        &Class::Handle(zone, member_function.Owner()));
+    ActiveMemberScope active_member(&kernel_loader.active_class_,
+                                    &member_function);
+    ActiveTypeParametersScope active_type_params(
+        &kernel_loader.active_class_, member_function,
+        &FunctionType::Handle(zone, parent_function.signature()), zone);
+    kernel_loader.helper_.SetOffset(func_decl_offset);
+    function =
+        kernel_loader.LoadClosureFunction(parent_function, closure_owner);
+  }
+  return function.ptr();
+}
+
 FunctionPtr CreateFieldInitializerFunction(Thread* thread,
                                            Zone* zone,
                                            const Field& field) {
diff --git a/runtime/vm/kernel_loader.h b/runtime/vm/kernel_loader.h
index 944fc94..f7e46e0 100644
--- a/runtime/vm/kernel_loader.h
+++ b/runtime/vm/kernel_loader.h
@@ -212,6 +212,14 @@
   void ReadObfuscationProhibitions();
   void ReadLoadingUnits();
 
+  // Get closure Function from cache or create it if it is not created yet.
+  // [func_decl_offset] is an offset FunctionExpression or FunctionDeclaration.
+  static FunctionPtr GetClosureFunction(Thread* thread,
+                                        intptr_t func_decl_offset,
+                                        const Function& member_function,
+                                        const Function& parent_function,
+                                        const Object& closure_owner);
+
  private:
   // Pragma bits
   using HasPragma = BitField<uint32_t, bool, 0, 1>;
@@ -231,8 +239,7 @@
 
   bool IsClassName(NameIndex name, const String& library, const String& klass);
 
-  void ReadVMAnnotations(const Library& library,
-                         intptr_t annotation_count,
+  void ReadVMAnnotations(intptr_t annotation_count,
                          uint32_t* pragma_bits,
                          String* native_name = nullptr);
 
@@ -336,6 +343,12 @@
 
   UntaggedFunction::Kind GetFunctionType(ProcedureHelper::Kind procedure_kind);
 
+  // Read local function (either FunctionExpression or FunctionDeclaration)
+  // and create corresponding Function object.
+  // If [closure_owner] is not null, it overrides closure function owner.
+  FunctionPtr LoadClosureFunction(const Function& parent_function,
+                                  const Object& closure_owner);
+
   Program* program_;
 
   Thread* thread_;
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index 30a31f6..a0e7304 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -181,8 +181,6 @@
   ASSERT(this->stack_overflow() == Instance::null());
   ASSERT(this->out_of_memory() == Instance::null());
 
-  this->closure_functions_ = GrowableObjectArray::New();
-
   Object& result = Object::Handle();
   const Library& library = Library::Handle(Library::CoreLibrary());