[vm/concurrency] Guard against concurrent creation of implicit closure functions

Once we share the program structure across isoltes we have to guard
against concurrent lazy creation of implicit closure functions.

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

TEST=Tests using --enable-isolate-groups with JIT sharing.

Change-Id: Ia8addf44106bea1b4777f5044c6c862cc76e354c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/175067
Reviewed-by: Alexander Aprelev <aam@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index f11ffea..9352916 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -8729,15 +8729,23 @@
   if (implicit_closure_function() != Function::null()) {
     return implicit_closure_function();
   }
+
 #if defined(DART_PRECOMPILED_RUNTIME)
   // In AOT mode all implicit closures are pre-created.
   FATAL("Cannot create implicit closure in AOT!");
   return Function::null();
 #else
   ASSERT(!IsSignatureFunction() && !IsClosureFunction());
+
   Thread* thread = Thread::Current();
-  Zone* zone = thread->zone();
+  SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
+
+  if (implicit_closure_function() != Function::null()) {
+    return implicit_closure_function();
+  }
+
   // Create closure function.
+  Zone* zone = thread->zone();
   const String& closure_name = String::Handle(zone, name());
   const Function& closure_function = Function::Handle(
       zone, NewImplicitClosureFunction(closure_name, *this, token_pos()));
@@ -8917,15 +8925,24 @@
 
 InstancePtr Function::ImplicitStaticClosure() const {
   ASSERT(IsImplicitStaticClosureFunction());
-  if (implicit_static_closure() == Instance::null()) {
-    Zone* zone = Thread::Current()->zone();
-    const Context& context = Context::Handle(zone);
-    Instance& closure =
-        Instance::Handle(zone, Closure::New(Object::null_type_arguments(),
-                                            Object::null_type_arguments(),
-                                            *this, context, Heap::kOld));
-    set_implicit_static_closure(closure);
+  if (implicit_static_closure() != Instance::null()) {
+    return implicit_static_closure();
   }
+
+  auto thread = Thread::Current();
+  SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
+
+  if (implicit_static_closure() != Instance::null()) {
+    return implicit_static_closure();
+  }
+
+  Zone* zone = thread->zone();
+  const auto& null_context = Context::Handle(zone);
+  const auto& closure =
+      Instance::Handle(zone, Closure::New(Object::null_type_arguments(),
+                                          Object::null_type_arguments(), *this,
+                                          null_context, Heap::kOld));
+  set_implicit_static_closure(closure);
   return implicit_static_closure();
 }