Version 2.16.0-1.0.dev

Merge commit '8bdae002f165883312a82b7549517930bfa6fe75' into 'dev'
diff --git a/pkg/analysis_server/lib/src/cider/rename.dart b/pkg/analysis_server/lib/src/cider/rename.dart
index 29f89fc..980ace6 100644
--- a/pkg/analysis_server/lib/src/cider/rename.dart
+++ b/pkg/analysis_server/lib/src/cider/rename.dart
@@ -50,8 +50,8 @@
   String get oldName => canRename.refactoringElement.element.displayName;
 
   RenameResponse? computeRenameRanges() {
-    var matches = canRename._fileResolver.findReferences(
-        canRename.refactoringElement.element, canRename.filePath);
+    var matches = canRename._fileResolver
+        .findReferences(canRename.refactoringElement.element);
     return RenameResponse(matches, this);
   }
 }
diff --git a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
index 24876d2..3ec3691 100644
--- a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
+++ b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
@@ -185,25 +185,34 @@
     removedCacheIds.addAll(libraryContext!.collectSharedDataIdentifiers());
   }
 
-  /// Looks for references to the given Element in the path. All the
-  /// files currently cached by the resolver are searched, generated files are
-  /// ignored.
-  List<CiderSearchMatch> findReferences(Element element, String path,
+  /// Looks for references to the given Element. All the files currently
+  ///  cached by the resolver are searched, generated files are ignored.
+  List<CiderSearchMatch> findReferences(Element element,
       {OperationPerformanceImpl? performance}) {
     var references = <CiderSearchMatch>[];
-    // TODO(keertip): check if element is named constructor.
-    var result = fsState!.getFilesContaining(element.displayName);
-    result.forEach((filePath) {
-      var resolved = resolve(path: filePath);
+
+    void collectReferences(String path) {
+      var resolved = resolve(path: path);
       var collector = ReferencesCollector(element);
       resolved.unit.accept(collector);
       var offsets = collector.offsets;
       if (offsets.isNotEmpty) {
         var lineInfo = resolved.unit.lineInfo;
-        references.add(CiderSearchMatch(filePath,
+        references.add(CiderSearchMatch(path,
             offsets.map((offset) => lineInfo?.getLocation(offset)).toList()));
       }
-    });
+    }
+
+    // TODO(keertip): check if element is named constructor.
+    if (element is LocalVariableElement ||
+        (element is ParameterElement && !element.isNamed)) {
+      collectReferences(element.source!.fullName);
+    } else {
+      var result = fsState!.getFilesContaining(element.displayName);
+      result.forEach((filePath) {
+        collectReferences(filePath);
+      });
+    }
     return references;
   }
 
diff --git a/pkg/analyzer/lib/src/lint/linter.dart b/pkg/analyzer/lib/src/lint/linter.dart
index 0c8f774..95f08a1 100644
--- a/pkg/analyzer/lib/src/lint/linter.dart
+++ b/pkg/analyzer/lib/src/lint/linter.dart
@@ -16,6 +16,7 @@
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/file_system/file_system.dart' as file_system;
+import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/ast/token.dart';
 import 'package:analyzer/src/dart/constant/compute.dart';
@@ -368,11 +369,26 @@
       isNonNullableByDefault: libraryElement.isNonNullableByDefault,
     );
 
+    var evaluationEngine = ConstantEvaluationEngine(
+      declaredVariables: declaredVariables,
+      isNonNullableByDefault: isEnabled(Feature.non_nullable),
+    );
+
+    var dependencies = <ConstantEvaluationTarget>[];
+    node.accept(
+      ReferenceFinder(dependencies.add),
+    );
+
+    computeConstants(
+      typeProvider,
+      typeSystem,
+      declaredVariables,
+      dependencies,
+      libraryElement.featureSet as ExperimentStatus,
+    );
+
     var visitor = ConstantVisitor(
-      ConstantEvaluationEngine(
-        declaredVariables: declaredVariables,
-        isNonNullableByDefault: isEnabled(Feature.non_nullable),
-      ),
+      evaluationEngine,
       libraryElement,
       errorReporter,
     );
diff --git a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
index 3b59012..0b35e99 100644
--- a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
+++ b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
@@ -394,7 +394,7 @@
 ''');
 
     await resolveFile(bPath);
-    var result = fileResolver.findReferences(_findElement(6, aPath), aPath);
+    var result = fileResolver.findReferences(_findElement(6, aPath));
     var expected = <CiderSearchMatch>[
       CiderSearchMatch(bPath, [CharacterLocation(4, 11)]),
       CiderSearchMatch(aPath, [CharacterLocation(1, 7)])
@@ -415,7 +415,7 @@
 ''');
 
     await resolveFile(aPath);
-    var result = fileResolver.findReferences(_findElement(16, aPath), aPath);
+    var result = fileResolver.findReferences(_findElement(16, aPath));
     var expected = <CiderSearchMatch>[
       CiderSearchMatch(
           aPath, [CharacterLocation(2, 7), CharacterLocation(5, 5)])
@@ -434,7 +434,7 @@
 ''');
 
     await resolveFile(aPath);
-    var result = fileResolver.findReferences(_findElement(11, aPath), aPath);
+    var result = fileResolver.findReferences(_findElement(11, aPath));
     var expected = <CiderSearchMatch>[
       CiderSearchMatch(
           aPath, [CharacterLocation(2, 3), CharacterLocation(5, 1)])
@@ -460,7 +460,7 @@
 ''');
 
     await resolveFile(bPath);
-    var result = fileResolver.findReferences(_findElement(20, aPath), aPath);
+    var result = fileResolver.findReferences(_findElement(20, aPath));
     var expected = <CiderSearchMatch>[
       CiderSearchMatch(bPath, [CharacterLocation(5, 15)]),
       CiderSearchMatch(aPath, [CharacterLocation(2, 11)])
@@ -479,7 +479,7 @@
 }
 ''');
     await resolveFile(aPath);
-    var result = fileResolver.findReferences(_findElement(39, aPath), aPath);
+    var result = fileResolver.findReferences(_findElement(39, aPath));
     var expected = <CiderSearchMatch>[
       CiderSearchMatch(
           aPath, [CharacterLocation(3, 9), CharacterLocation(4, 11)])
@@ -512,7 +512,7 @@
 ''');
 
     await resolveFile(bPath);
-    var result = fileResolver.findReferences(_findElement(17, aPath), aPath);
+    var result = fileResolver.findReferences(_findElement(17, aPath));
     var expected = <CiderSearchMatch>[
       CiderSearchMatch(bPath, [CharacterLocation(5, 5)]),
       CiderSearchMatch(
@@ -539,7 +539,7 @@
 ''');
 
     await resolveFile(bPath);
-    var result = fileResolver.findReferences(_findElement(21, aPath), aPath);
+    var result = fileResolver.findReferences(_findElement(21, aPath));
     var expected = <CiderSearchMatch>[
       CiderSearchMatch(bPath, [CharacterLocation(5, 5)]),
       CiderSearchMatch(aPath, [CharacterLocation(2, 12)])
@@ -566,7 +566,7 @@
 ''');
 
     await resolveFile(bPath);
-    var result = fileResolver.findReferences(_findElement(19, aPath), aPath);
+    var result = fileResolver.findReferences(_findElement(19, aPath));
     var expected = <CiderSearchMatch>[
       CiderSearchMatch(bPath, [CharacterLocation(4, 13)]),
       CiderSearchMatch(aPath, [CharacterLocation(3, 9)])
@@ -593,7 +593,7 @@
 ''');
 
     await resolveFile(bPath);
-    var result = fileResolver.findReferences(_findElement(20, aPath), aPath);
+    var result = fileResolver.findReferences(_findElement(20, aPath));
     var expected = <CiderSearchMatch>[
       CiderSearchMatch(bPath, [CharacterLocation(4, 3)]),
       CiderSearchMatch(aPath, [CharacterLocation(3, 10)])
@@ -613,7 +613,7 @@
 ''');
 
     await resolveFile(aPath);
-    var result = fileResolver.findReferences(_findElement(10, aPath), aPath);
+    var result = fileResolver.findReferences(_findElement(10, aPath));
     var expected = <CiderSearchMatch>[
       CiderSearchMatch(
           aPath, [CharacterLocation(1, 11), CharacterLocation(4, 11)])
@@ -631,7 +631,7 @@
 }
 ''');
     await resolveFile(aPath);
-    var result = fileResolver.findReferences(_findElement(10, aPath), aPath);
+    var result = fileResolver.findReferences(_findElement(10, aPath));
     var expected = <CiderSearchMatch>[
       CiderSearchMatch(aPath, [
         CharacterLocation(1, 11),
@@ -659,7 +659,7 @@
 ''');
 
     await resolveFile(bPath);
-    var result = fileResolver.findReferences(_findElement(8, aPath), aPath);
+    var result = fileResolver.findReferences(_findElement(8, aPath));
     var expected = <CiderSearchMatch>[
       CiderSearchMatch(bPath, [CharacterLocation(3, 8)]),
       CiderSearchMatch(aPath, [CharacterLocation(1, 9)])
diff --git a/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart b/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
index 4212464..5beaead 100644
--- a/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
+++ b/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
@@ -488,6 +488,29 @@
     expect(result.value!.toIntValue(), 3);
   }
 
+  test_hasValue_constantReference() async {
+    await resolve('''
+const a = 42;
+var x = a;
+''');
+    var result = _evaluateX();
+    expect(result.errors, isEmpty);
+    expect(result.value!.toIntValue(), 42);
+  }
+
+  test_hasValue_constantReference_imported() async {
+    newFile('$testPackageLibPath/a.dart', content: r'''
+const a = 42;
+''');
+    await resolve('''
+import 'a.dart';
+var x = a;
+''');
+    var result = _evaluateX();
+    expect(result.errors, isEmpty);
+    expect(result.value!.toIntValue(), 42);
+  }
+
   test_hasValue_intLiteral() async {
     await resolve('''
 var x = 42;
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index 3569eb9..f3bb2bd 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -111,9 +111,8 @@
   // We have to check whether the reciever has the same isolate group (e.g.
   // native message handlers such as an IOService handler does not but does
   // share the same origin port).
-  const bool same_group =
-      FLAG_enable_isolate_groups && PortMap::IsReceiverInThisIsolateGroup(
-                                        destination_port_id, isolate->group());
+  const bool same_group = PortMap::IsReceiverInThisIsolateGroup(
+      destination_port_id, isolate->group());
   // TODO(turnidge): Throw an exception when the return value is false?
   PortMap::PostMessage(WriteMessage(can_send_any_object, same_group, obj,
                                     destination_port_id,
@@ -639,7 +638,7 @@
     ASSERT(name != nullptr);
 
     auto group = state_->isolate_group();
-    if (!FLAG_enable_isolate_groups || group == nullptr) {
+    if (group == nullptr) {
       RunHeavyweight(name);
     } else {
       RunLightweight(name);
@@ -676,8 +675,7 @@
   }
 
   void RunLightweight(const char* name) {
-    // The create isolate initialize callback is mandatory if
-    // --enable-isolate-groups was passed.
+    // The create isolate initialize callback is mandatory.
     auto initialize_callback = Isolate::InitializeCallback();
     if (initialize_callback == nullptr) {
       FailedSpawn(
@@ -934,22 +932,16 @@
   const auto& func = Function::Handle(zone, GetTopLevelFunction(zone, closure));
   PersistentHandle* closure_tuple_handle = nullptr;
   if (func.IsNull()) {
-    if (!FLAG_enable_isolate_groups) {
-      const String& msg = String::Handle(String::New(
-          "Isolate.spawn expects to be passed a static or top-level function"));
-      Exceptions::ThrowArgumentError(msg);
-    } else {
-      // We have a non-toplevel closure that we might need to copy.
-      // Result will be [<closure-copy>, <objects-in-msg-to-rehash>]
-      const auto& closure_copy_tuple = Object::Handle(
-          zone, CopyMutableObjectGraph(closure));  // Throws if it fails.
-      ASSERT(closure_copy_tuple.IsArray());
-      ASSERT(Object::Handle(zone, Array::Cast(closure_copy_tuple).At(0))
-                 .IsClosure());
-      closure_tuple_handle =
-          isolate->group()->api_state()->AllocatePersistentHandle();
-      closure_tuple_handle->set_ptr(closure_copy_tuple.ptr());
-    }
+    // We have a non-toplevel closure that we might need to copy.
+    // Result will be [<closure-copy>, <objects-in-msg-to-rehash>]
+    const auto& closure_copy_tuple = Object::Handle(
+        zone, CopyMutableObjectGraph(closure));  // Throws if it fails.
+    ASSERT(closure_copy_tuple.IsArray());
+    ASSERT(Object::Handle(zone, Array::Cast(closure_copy_tuple).At(0))
+               .IsClosure());
+    closure_tuple_handle =
+        isolate->group()->api_state()->AllocatePersistentHandle();
+    closure_tuple_handle->set_ptr(closure_copy_tuple.ptr());
   }
 
   bool fatal_errors = fatalErrors.IsNull() ? true : fatalErrors.value();
@@ -960,9 +952,8 @@
   // serializable this will throw an exception.
   SerializedObjectBuffer message_buffer;
   message_buffer.set_message(WriteMessage(
-      /* can_send_any_object */ true,
-      /* same_group */ FLAG_enable_isolate_groups, message, ILLEGAL_PORT,
-      Message::kNormalPriority));
+      /*can_send_any_object=*/true,
+      /*same_group=*/true, message, ILLEGAL_PORT, Message::kNormalPriority));
 
   const char* utf8_package_config =
       packageConfig.IsNull() ? NULL : String2UTF8(packageConfig);
diff --git a/runtime/tests/vm/dart/causal_stacks/utils.dart b/runtime/tests/vm/dart/causal_stacks/utils.dart
index c8b3774..077e9bd 100644
--- a/runtime/tests/vm/dart/causal_stacks/utils.dart
+++ b/runtime/tests/vm/dart/causal_stacks/utils.dart
@@ -850,7 +850,7 @@
       r'^<asynchronous suspension>$',
       r'^#1      asyncStarThrowAsync \(.*/utils.dart:126(:5)?\)$',
       r'^<asynchronous suspension>$',
-      r'^#2      listenAsyncStarThrowAsync.<anonymous closure> \(.+/utils.dart(:0)?\)$',
+      r'^#2      listenAsyncStarThrowAsync.<anonymous closure> \(.+/utils.dart:132(:56)?\)$',
       r'^<asynchronous suspension>$',
     ];
     await doTestAwait(
diff --git a/runtime/tests/vm/dart_2/causal_stacks/utils.dart b/runtime/tests/vm/dart_2/causal_stacks/utils.dart
index cd46b03..a17cade 100644
--- a/runtime/tests/vm/dart_2/causal_stacks/utils.dart
+++ b/runtime/tests/vm/dart_2/causal_stacks/utils.dart
@@ -852,7 +852,7 @@
       r'^<asynchronous suspension>$',
       r'^#1      asyncStarThrowAsync \(.*/utils.dart:128(:5)?\)$',
       r'^<asynchronous suspension>$',
-      r'^#2      listenAsyncStarThrowAsync.<anonymous closure> \(.+/utils.dart(:0)?\)$',
+      r'^#2      listenAsyncStarThrowAsync.<anonymous closure> \(.+/utils.dart:134(:56)?\)$',
       r'^<asynchronous suspension>$',
     ];
     await doTestAwait(
diff --git a/runtime/vm/code_descriptors.cc b/runtime/vm/code_descriptors.cc
index dd8bc1d..87625f3 100644
--- a/runtime/vm/code_descriptors.cc
+++ b/runtime/vm/code_descriptors.cc
@@ -417,6 +417,14 @@
   }
 }
 
+void CodeSourceMapBuilder::WriteFunctionEntrySourcePosition(
+    const InstructionSource& source) {
+  ASSERT(written_pc_offset_ == 0 && buffered_pc_offset_ == 0);
+  ASSERT(stream_.bytes_written() == 0);
+  WriteChangePosition(source.token_pos);
+  WriteAdvancePC(0);
+}
+
 void CodeSourceMapBuilder::BeginCodeSourceRange(
     int32_t pc_offset,
     const InstructionSource& source) {
diff --git a/runtime/vm/code_descriptors.h b/runtime/vm/code_descriptors.h
index ac29be7..bd0d358 100644
--- a/runtime/vm/code_descriptors.h
+++ b/runtime/vm/code_descriptors.h
@@ -246,6 +246,7 @@
   void NoteNullCheck(int32_t pc_offset,
                      const InstructionSource& source,
                      intptr_t name_index);
+  void WriteFunctionEntrySourcePosition(const InstructionSource& source);
 
   // If source is from an inlined call, returns the token position of the
   // original call in the root function, otherwise the source's token position.
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index d8ce910..88106b2 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -560,6 +560,53 @@
   return false;
 }
 
+void FlowGraphCompiler::EmitFunctionEntrySourcePositionDescriptorIfNeeded() {
+  // When unwinding async stacks we might produce frames which correspond
+  // to future listeners which are going to be called when the future completes.
+  // These listeners are not yet called and thus their frame pc_offset is set
+  // to 0 - which does not actually correspond to any call- or yield- site
+  // inside the code object. Nevertheless we would like to be able to
+  // produce proper position information for it when symbolizing the stack.
+  // To achieve that in AOT mode (where we don't actually have
+  // |Function::token_pos| available) we instead emit an artificial descriptor
+  // at the very beginning of the function.
+  if (FLAG_precompiled_mode && flow_graph().function().IsClosureFunction()) {
+    code_source_map_builder_->WriteFunctionEntrySourcePosition(
+        InstructionSource(flow_graph().function().token_pos()));
+  }
+}
+
+void FlowGraphCompiler::CompileGraph() {
+  InitCompiler();
+
+#if !defined(TARGET_ARCH_IA32)
+  // For JIT we have multiple entrypoints functionality which moved the frame
+  // setup into the [TargetEntryInstr] (which will set the constant pool
+  // allowed bit to true).  Despite this we still have to set the
+  // constant pool allowed bit to true here as well, because we can generate
+  // code for [CatchEntryInstr]s, which need the pool.
+  assembler()->set_constant_pool_allowed(true);
+#endif
+
+  EmitFunctionEntrySourcePositionDescriptorIfNeeded();
+  VisitBlocks();
+
+#if defined(DEBUG)
+  assembler()->Breakpoint();
+#endif
+
+  if (!skip_body_compilation()) {
+#if !defined(TARGET_ARCH_IA32)
+    ASSERT(assembler()->constant_pool_allowed());
+#endif
+    GenerateDeferredCode();
+  }
+
+  for (intptr_t i = 0; i < indirect_gotos_.length(); ++i) {
+    indirect_gotos_[i]->ComputeOffsetTable(this);
+  }
+}
+
 void FlowGraphCompiler::VisitBlocks() {
   CompactBlocks();
   if (compiler::Assembler::EmittingComments()) {
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.h b/runtime/vm/compiler/backend/flow_graph_compiler.h
index 7669e78..98488ae 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.h
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.h
@@ -559,6 +559,8 @@
 
   void VisitBlocks();
 
+  void EmitFunctionEntrySourcePositionDescriptorIfNeeded();
+
   // Bail out of the flow graph compiler. Does not return to the caller.
   void Bailout(const char* reason);
 
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
index fbe3e61..ac4e0f8 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
@@ -382,38 +382,6 @@
   EndCodeSourceRange(PrologueSource());
 }
 
-// Input parameters:
-//   LR: return address.
-//   SP: address of last argument.
-//   FP: caller's frame pointer.
-//   PP: caller's pool pointer.
-//   R4: arguments descriptor array.
-void FlowGraphCompiler::CompileGraph() {
-  InitCompiler();
-
-  // For JIT we have multiple entrypoints functionality which moved the frame
-  // setup into the [TargetEntryInstr] (which will set the constant pool
-  // allowed bit to true).  Despite this we still have to set the
-  // constant pool allowed bit to true here as well, because we can generate
-  // code for [CatchEntryInstr]s, which need the pool.
-  __ set_constant_pool_allowed(true);
-
-  VisitBlocks();
-
-#if defined(DEBUG)
-  __ bkpt(0);
-#endif
-
-  if (!skip_body_compilation()) {
-    ASSERT(assembler()->constant_pool_allowed());
-    GenerateDeferredCode();
-  }
-
-  for (intptr_t i = 0; i < indirect_gotos_.length(); ++i) {
-    indirect_gotos_[i]->ComputeOffsetTable(this);
-  }
-}
-
 void FlowGraphCompiler::EmitCallToStub(const Code& stub) {
   ASSERT(!stub.IsNull());
   if (CanPcRelativeCall(stub)) {
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
index fdbf099..233821a 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
@@ -372,38 +372,6 @@
   EndCodeSourceRange(PrologueSource());
 }
 
-// Input parameters:
-//   LR: return address.
-//   SP: address of last argument.
-//   FP: caller's frame pointer.
-//   PP: caller's pool pointer.
-//   R4: arguments descriptor array.
-void FlowGraphCompiler::CompileGraph() {
-  InitCompiler();
-
-  // For JIT we have multiple entrypoints functionality which moved the frame
-  // setup into the [TargetEntryInstr] (which will set the constant pool
-  // allowed bit to true).  Despite this we still have to set the
-  // constant pool allowed bit to true here as well, because we can generate
-  // code for [CatchEntryInstr]s, which need the pool.
-  __ set_constant_pool_allowed(true);
-
-  VisitBlocks();
-
-#if defined(DEBUG)
-  __ brk(0);
-#endif
-
-  if (!skip_body_compilation()) {
-    ASSERT(assembler()->constant_pool_allowed());
-    GenerateDeferredCode();
-  }
-
-  for (intptr_t i = 0; i < indirect_gotos_.length(); ++i) {
-    indirect_gotos_[i]->ComputeOffsetTable(this);
-  }
-}
-
 void FlowGraphCompiler::EmitCallToStub(const Code& stub) {
   ASSERT(!stub.IsNull());
   if (CanPcRelativeCall(stub)) {
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
index 0b232dd..d613572 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
@@ -459,24 +459,6 @@
   EndCodeSourceRange(PrologueSource());
 }
 
-void FlowGraphCompiler::CompileGraph() {
-  InitCompiler();
-
-  ASSERT(!block_order().is_empty());
-  VisitBlocks();
-
-  if (!skip_body_compilation()) {
-#if defined(DEBUG)
-    __ int3();
-#endif
-    GenerateDeferredCode();
-  }
-
-  for (intptr_t i = 0; i < indirect_gotos_.length(); ++i) {
-    indirect_gotos_[i]->ComputeOffsetTable(this);
-  }
-}
-
 void FlowGraphCompiler::EmitCallToStub(const Code& stub) {
   if (stub.InVMIsolateHeap()) {
     __ CallVmStub(stub);
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
index 573add6..3abdf84 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
@@ -378,33 +378,6 @@
   EndCodeSourceRange(PrologueSource());
 }
 
-void FlowGraphCompiler::CompileGraph() {
-  InitCompiler();
-
-  // We have multiple entrypoints functionality which moved the frame
-  // setup into the [FunctionEntryInstr] (which will set the constant pool
-  // allowed bit to true).  Despite this we still have to set the
-  // constant pool allowed bit to true here as well, because we can generate
-  // code for [CatchEntryInstr]s, which need the pool.
-  __ set_constant_pool_allowed(true);
-
-  ASSERT(!block_order().is_empty());
-  VisitBlocks();
-
-#if defined(DEBUG)
-  __ int3();
-#endif
-
-  if (!skip_body_compilation()) {
-    ASSERT(assembler()->constant_pool_allowed());
-    GenerateDeferredCode();
-  }
-
-  for (intptr_t i = 0; i < indirect_gotos_.length(); ++i) {
-    indirect_gotos_[i]->ComputeOffsetTable(this);
-  }
-}
-
 void FlowGraphCompiler::EmitCallToStub(const Code& stub) {
   ASSERT(!stub.IsNull());
   if (CanPcRelativeCall(stub)) {
diff --git a/runtime/vm/compiler/jit/compiler.cc b/runtime/vm/compiler/jit/compiler.cc
index 1ec2adc..5b08899 100644
--- a/runtime/vm/compiler/jit/compiler.cc
+++ b/runtime/vm/compiler/jit/compiler.cc
@@ -211,7 +211,7 @@
   ASSERT(thread->IsMutatorThread());
   const Function& function = Function::CheckedHandle(zone, arguments.ArgAt(0));
 
-  if (FLAG_enable_isolate_groups) {
+  {
     // Another isolate's mutator thread may have created [function] and
     // published it via an ICData, MegamorphicCache etc. Entering the lock below
     // is an acquire operation that pairs with the release operation when the
@@ -220,12 +220,6 @@
     SafepointReadRwLocker ml(thread, thread->isolate_group()->program_lock());
   }
 
-  // In single-isolate scenarios the lazy compile stub is only invoked if
-  // there's no existing code. In multi-isolate scenarios with shared JITed code
-  // we can end up in the lazy compile runtime entry here with code being
-  // installed.
-  ASSERT(!function.HasCode() || FLAG_enable_isolate_groups);
-
   // Will throw if compilation failed (e.g. with compile-time error).
   function.EnsureHasCode();
 }
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 1c7026a..88dc441 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1463,13 +1463,6 @@
 
   *error = nullptr;
 
-  if (!FLAG_enable_isolate_groups) {
-    *error = Utils::StrDup(
-        "Lightweight isolates need to be explicitly enabled by passing "
-        "--enable-isolate-groups.");
-    return nullptr;
-  }
-
   Isolate* isolate;
   isolate = CreateWithinExistingIsolateGroup(member->group(), name, error);
   if (isolate != nullptr) {
diff --git a/runtime/vm/dwarf.cc b/runtime/vm/dwarf.cc
index 4f98848..d661bd7 100644
--- a/runtime/vm/dwarf.cc
+++ b/runtime/vm/dwarf.cc
@@ -717,6 +717,26 @@
     function_stack.Clear();
     token_positions.Clear();
 
+    // CodeSourceMap might start in the following way:
+    //
+    //   ChangePosition function.token_pos()
+    //   AdvancePC 0
+    //   ChangePosition x
+    //   AdvancePC y
+    //
+    // This entry is emitted to ensure correct symbolization of
+    // function listener frames produced by async unwinding.
+    // (See EmitFunctionEntrySourcePositionDescriptorIfNeeded).
+    // Directly interpreting this sequence would cause us to emit
+    // multiple with the same pc into line number table and different
+    // position information. To avoid this will make an adjustment for
+    // the second record we emit: if position x is a synthetic one we will
+    // simply drop the second record, if position x is real then we will
+    // emit row with a slightly adjusted PC (by 1 byte). This would not
+    // affect symbolization (you can't have a call that is 1 byte long)
+    // but will avoid line number table entries with the same PC.
+    bool function_entry_position_was_emitted = false;
+
     int32_t current_pc_offset = 0;
     function_stack.Add(&root_function);
     token_positions.Add(kNoDwarfPositionInfo);
@@ -740,9 +760,30 @@
           const intptr_t file = LookupScript(script);
           const intptr_t line = token_positions.Last().line();
           const intptr_t column = token_positions.Last().column();
-          writer->EmitRow(file, line, column, asm_name, current_pc_offset);
+          intptr_t pc_offset_adjustment = 0;
+          bool should_emit = true;
+
+          // If we are at the function entry and have already emitted a row
+          // then adjust current_pc_offset to avoid duplicated entries.
+          // See the comment below which explains why this code is here.
+          if (current_pc_offset == 0 && function_entry_position_was_emitted) {
+            pc_offset_adjustment = 1;
+            // Ignore synthetic positions. Function entry position gives
+            // more information anyway.
+            should_emit = !(line == 0 && column == 0);
+          }
+
+          if (should_emit) {
+            writer->EmitRow(file, line, column, asm_name,
+                            current_pc_offset + pc_offset_adjustment);
+          }
 
           current_pc_offset += arg1;
+          if (arg1 == 0) {  // Special case of AdvancePC 0.
+            ASSERT(current_pc_offset == 0);
+            ASSERT(!function_entry_position_was_emitted);
+            function_entry_position_was_emitted = true;
+          }
           break;
         }
         case CodeSourceMapOps::kPushFunction: {
diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h
index 224a6b1..eccc2ac 100644
--- a/runtime/vm/flag_list.h
+++ b/runtime/vm/flag_list.h
@@ -194,7 +194,6 @@
   P(retain_code_objects, bool, true,                                           \
     "Serialize all code objects even if not otherwise "                        \
     "needed in the precompiled runtime.")                                      \
-  P(enable_isolate_groups, bool, true, "Enable isolate group support.")        \
   P(show_invisible_frames, bool, false,                                        \
     "Show invisible frames in stack traces.")                                  \
   D(trace_cha, bool, false, "Trace CHA operations")                            \
diff --git a/runtime/vm/heap/heap_test.cc b/runtime/vm/heap/heap_test.cc
index b30bf66..c45765c 100644
--- a/runtime/vm/heap/heap_test.cc
+++ b/runtime/vm/heap/heap_test.cc
@@ -574,9 +574,6 @@
 };
 
 VM_UNIT_TEST_CASE(CleanupBequestNeverReceived) {
-  // This test uses features from isolate groups
-  FLAG_enable_isolate_groups = true;
-
   const char* TEST_MESSAGE = "hello, world";
   Dart_Isolate parent = TestCase::CreateTestIsolate("parent");
   EXPECT_EQ(parent, Dart_CurrentIsolate());
@@ -608,9 +605,6 @@
 }
 
 VM_UNIT_TEST_CASE(ReceivesSendAndExitMessage) {
-  // This test uses features from isolate groups
-  FLAG_enable_isolate_groups = true;
-
   const char* TEST_MESSAGE = "hello, world";
   Dart_Isolate parent = TestCase::CreateTestIsolate("parent");
   EXPECT_EQ(parent, Dart_CurrentIsolate());
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index ef5cdad..34521bc 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -2673,11 +2673,9 @@
       Dart::thread_pool()->Run<ShutdownGroupTask>(isolate_group);
     }
   } else {
-    if (FLAG_enable_isolate_groups) {
-      // TODO(dartbug.com/36097): An isolate just died. A significant amount of
-      // memory might have become unreachable. We should evaluate how to best
-      // inform the GC about this situation.
-    }
+    // TODO(dartbug.com/36097): An isolate just died. A significant amount of
+    // memory might have become unreachable. We should evaluate how to best
+    // inform the GC about this situation.
   }
 }  // namespace dart
 
@@ -2842,11 +2840,6 @@
   auto thread = Thread::Current();
   StoppedMutatorsScope stopped_mutators_scope(thread);
 
-  if (thread->IsMutatorThread() && !FLAG_enable_isolate_groups) {
-    single_current_mutator->Call();
-    return;
-  }
-
   if (thread->IsAtSafepoint()) {
     RELEASE_ASSERT(safepoint_handler()->IsOwnedByTheThread(thread));
     single_current_mutator->Call();
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index e272c5c..fd8822c 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -25851,6 +25851,15 @@
       // A visible frame ends any gap we might be in.
       in_gap = false;
 
+      // Zero pc_offset can only occur in the frame produced by the async
+      // unwinding and it corresponds to the next future listener in the
+      // chain. This function is not yet called (it will be called when
+      // the future completes) hence pc_offset is set to 0. This frame
+      // is very different from other frames which have pc_offsets
+      // corresponding to call- or yield-sites in the generated code and
+      // should be handled specially.
+      const bool is_future_listener = pc_offset == 0;
+
 #if defined(DART_PRECOMPILED_RUNTIME)
       // When printing non-symbolic frames, we normally print call
       // addresses, not return addresses, by subtracting one from the PC to
@@ -25861,7 +25870,6 @@
       // is invoked with the value of the resolved future. Thus, we must
       // report the return address, as returning a value before the closure
       // payload will cause failures to decode the frame using DWARF info.
-      const bool is_future_listener = pc_offset == 0;
       const uword call_addr = is_future_listener ? pc : pc - 1;
 
       if (FLAG_dwarf_stack_traces_mode) {
@@ -25887,7 +25895,11 @@
       }
 #endif
 
-      if (code.is_optimized() && stack_trace.expand_inlined()) {
+      if (code.is_optimized() && stack_trace.expand_inlined() &&
+          (FLAG_precompiled_mode || !is_future_listener)) {
+        // Note: In AOT mode EmitFunctionEntrySourcePositionDescriptorIfNeeded
+        // will take care of emitting a descriptor that would allow us to
+        // symbolize stack frame with 0 offset.
         code.GetInlinedFunctionsAtReturnAddress(pc_offset, &inlined_functions,
                                                 &inlined_token_positions);
         ASSERT(inlined_functions.length() >= 1);
@@ -25901,7 +25913,8 @@
         continue;
       }
 
-      auto const pos = code.GetTokenIndexOfPC(pc);
+      auto const pos = is_future_listener ? function.token_pos()
+                                          : code.GetTokenIndexOfPC(pc);
       PrintSymbolicStackFrame(zone, &buffer, function, pos, frame_index);
       frame_index++;
     }
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index 549dd9b..c693c02 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -869,9 +869,6 @@
         new_cache.WriteEntryToBuffer(zone, &buffer, colliding_index, "      ");
         THR_Print("%s\n", buffer.buffer());
       }
-      if (!FLAG_enable_isolate_groups) {
-        FATAL("Duplicate subtype test cache entry");
-      }
       if (old_result.ptr() != result.ptr()) {
         FATAL("Existing subtype test cache entry has result %s, not %s",
               old_result.ToCString(), result.ToCString());
@@ -1246,9 +1243,6 @@
   const Code& target_code = Code::Handle(zone, target_function.EnsureHasCode());
   // Before patching verify that we are not repeatedly patching to the same
   // target.
-  ASSERT(FLAG_enable_isolate_groups ||
-         target_code.ptr() != CodePatcher::GetStaticCallTargetAt(
-                                  caller_frame->pc(), caller_code));
   if (target_code.ptr() !=
       CodePatcher::GetStaticCallTargetAt(caller_frame->pc(), caller_code)) {
     GcSafepointOperationScope safepoint(thread);
@@ -3018,10 +3012,6 @@
         current_target_code.EntryPoint(),
         current_target_code.is_optimized() ? "optimized" : "unoptimized");
   }
-  // With isolate groups enabled, it is possible that the target code
-  // has been deactivated just now(as a result of re-optimizatin for example),
-  // which will result in another run through FixCallersTarget.
-  ASSERT(!current_target_code.IsDisabled() || FLAG_enable_isolate_groups);
   arguments.SetReturn(current_target_code);
 #else
   UNREACHABLE();
diff --git a/runtime/vm/symbols.cc b/runtime/vm/symbols.cc
index 673f26e..a60edfa 100644
--- a/runtime/vm/symbols.cc
+++ b/runtime/vm/symbols.cc
@@ -401,11 +401,6 @@
     // cases.
     if (thread->IsAtSafepoint()) {
       RELEASE_ASSERT(group->safepoint_handler()->IsOwnedByTheThread(thread));
-      // In DEBUG mode the snapshot writer also calls this method inside a
-      // safepoint.
-#if !defined(DEBUG)
-      RELEASE_ASSERT(FLAG_enable_isolate_groups || !USING_PRODUCT);
-#endif
       data = object_store->symbol_table();
       CanonicalStringSet table(&key, &value, &data);
       symbol ^= table.GetOrNull(str);
diff --git a/tools/VERSION b/tools/VERSION
index 859524f..3fdef2c 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 16
 PATCH 0
-PRERELEASE 0
+PRERELEASE 1
 PRERELEASE_PATCH 0
\ No newline at end of file