[vm] Avoid races for lookup and insert of local functions.

TEST=tsan
Bug: https://github.com/dart-lang/sdk/issues/36097
Change-Id: I8733417e7cedd5fb47b60935e16228d9a656470d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/175761
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Alexander Aprelev <aam@google.com>
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index 54435dc..d577091 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -4886,86 +4886,100 @@
   // function and token position.
   Function& function = Function::ZoneHandle(Z);
 
-  // NOTE: This is not TokenPosition in the general sense!
-  function = I->LookupClosureFunction(parsed_function()->function(), position);
+  {
+    SafepointReadRwLocker ml(thread(),
+                             thread()->isolate_group()->program_lock());
+    // NOTE: This is not TokenPosition in the general sense!
+    function =
+        I->LookupClosureFunction(parsed_function()->function(), position);
+  }
+
   if (function.IsNull()) {
-    for (intptr_t i = 0; i < scopes()->function_scopes.length(); ++i) {
-      if (scopes()->function_scopes[i].kernel_offset != offset) {
-        continue;
-      }
-
-      const String* name;
-      if (declaration) {
-        name = &H.DartSymbolObfuscate(name_index);
-      } else {
-        name = &Symbols::AnonymousClosure();
-      }
-      // NOTE: This is not TokenPosition in the general sense!
-      if (!closure_owner_.IsNull()) {
-        function = Function::NewClosureFunctionWithKind(
-            FunctionLayout::kClosureFunction, *name,
-            parsed_function()->function(), position, closure_owner_);
-      } else {
-        function = Function::NewClosureFunction(
-            *name, parsed_function()->function(), position);
-      }
-
-      function.set_is_debuggable(function_node_helper.dart_async_marker_ ==
-                                 FunctionNodeHelper::kSync);
-      switch (function_node_helper.dart_async_marker_) {
-        case FunctionNodeHelper::kSyncStar:
-          function.set_modifier(FunctionLayout::kSyncGen);
-          break;
-        case FunctionNodeHelper::kAsync:
-          function.set_modifier(FunctionLayout::kAsync);
-          function.set_is_inlinable(!FLAG_causal_async_stacks);
-          break;
-        case FunctionNodeHelper::kAsyncStar:
-          function.set_modifier(FunctionLayout::kAsyncGen);
-          function.set_is_inlinable(!FLAG_causal_async_stacks);
-          break;
-        default:
-          // no special modifier
-          break;
-      }
-      function.set_is_generated_body(function_node_helper.async_marker_ ==
-                                     FunctionNodeHelper::kSyncYielding);
-      // sync* functions contain two nested synthetic functions, the first of
-      // which (sync_op_gen) is a regular sync function so we need to manually
-      // label it generated:
-      if (function.parent_function() != Function::null()) {
-        const auto& parent = Function::Handle(function.parent_function());
-        if (parent.IsSyncGenerator()) {
-          function.set_is_generated_body(true);
+    SafepointWriteRwLocker ml(thread(),
+                              thread()->isolate_group()->program_lock());
+    // NOTE: This is not TokenPosition in the general sense!
+    function =
+        I->LookupClosureFunction(parsed_function()->function(), position);
+    if (function.IsNull()) {
+      for (intptr_t i = 0; i < scopes()->function_scopes.length(); ++i) {
+        if (scopes()->function_scopes[i].kernel_offset != offset) {
+          continue;
         }
+
+        const String* name;
+        if (declaration) {
+          name = &H.DartSymbolObfuscate(name_index);
+        } else {
+          name = &Symbols::AnonymousClosure();
+        }
+        // NOTE: This is not TokenPosition in the general sense!
+        if (!closure_owner_.IsNull()) {
+          function = Function::NewClosureFunctionWithKind(
+              FunctionLayout::kClosureFunction, *name,
+              parsed_function()->function(), position, closure_owner_);
+        } else {
+          function = Function::NewClosureFunction(
+              *name, parsed_function()->function(), position);
+        }
+
+        function.set_is_debuggable(function_node_helper.dart_async_marker_ ==
+                                   FunctionNodeHelper::kSync);
+        switch (function_node_helper.dart_async_marker_) {
+          case FunctionNodeHelper::kSyncStar:
+            function.set_modifier(FunctionLayout::kSyncGen);
+            break;
+          case FunctionNodeHelper::kAsync:
+            function.set_modifier(FunctionLayout::kAsync);
+            function.set_is_inlinable(!FLAG_causal_async_stacks);
+            break;
+          case FunctionNodeHelper::kAsyncStar:
+            function.set_modifier(FunctionLayout::kAsyncGen);
+            function.set_is_inlinable(!FLAG_causal_async_stacks);
+            break;
+          default:
+            // no special modifier
+            break;
+        }
+        function.set_is_generated_body(function_node_helper.async_marker_ ==
+                                       FunctionNodeHelper::kSyncYielding);
+        // sync* functions contain two nested synthetic functions, the first of
+        // which (sync_op_gen) is a regular sync function so we need to manually
+        // label it generated:
+        if (function.parent_function() != Function::null()) {
+          const auto& parent = Function::Handle(function.parent_function());
+          if (parent.IsSyncGenerator()) {
+            function.set_is_generated_body(true);
+          }
+        }
+        // Note: Is..() methods use the modifiers set above, so order matters.
+        if (function.IsAsyncClosure() || function.IsAsyncGenClosure()) {
+          function.set_is_inlinable(!FLAG_causal_async_stacks &&
+                                    !FLAG_lazy_async_stacks);
+        }
+
+        function.set_end_token_pos(function_node_helper.end_position_);
+        LocalScope* scope = scopes()->function_scopes[i].scope;
+        const ContextScope& context_scope = ContextScope::Handle(
+            Z, scope->PreserveOuterScope(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.
+        Type& signature_type = Type::Handle(Z, function.SignatureType());
+        signature_type ^= ClassFinalizer::FinalizeType(signature_type);
+        function.SetSignatureType(signature_type);
+
+        I->AddClosureFunction(function);
+        break;
       }
-      // Note: Is..() methods use the modifiers set above, so order matters.
-      if (function.IsAsyncClosure() || function.IsAsyncGenClosure()) {
-        function.set_is_inlinable(!FLAG_causal_async_stacks &&
-                                  !FLAG_lazy_async_stacks);
-      }
-
-      function.set_end_token_pos(function_node_helper.end_position_);
-      LocalScope* scope = scopes()->function_scopes[i].scope;
-      const ContextScope& context_scope = ContextScope::Handle(
-          Z, scope->PreserveOuterScope(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.
-      Type& signature_type = Type::Handle(Z, function.SignatureType());
-      signature_type ^= ClassFinalizer::FinalizeType(signature_type);
-      function.SetSignatureType(signature_type);
-
-      I->AddClosureFunction(function);
-      break;
     }
   }