Version 2.16.0-7.0.dev

Merge commit '8809779d80c6135070249067639aa4bccbf99184' into 'dev'
diff --git a/DEPS b/DEPS
index e93a12b..a79507d 100644
--- a/DEPS
+++ b/DEPS
@@ -44,9 +44,9 @@
   # co19 is a cipd package. Use update.sh in tests/co19[_2] to update these
   # hashes. It requires access to the dart-build-access group, which EngProd
   # has.
-  "co19_rev": "73545b2bf6c7f8e4eb931bb04d86e38d6485deee",
+  "co19_rev": "39c5bbc03bf5c5c0a3f9341abe811871eababfaf",
   # This line prevents conflicts when both packages are rolled simultaneously.
-  "co19_2_rev": "52d3d2a6d2550ccd69c8facf8a36099be66f1493",
+  "co19_2_rev": "86f01ade433fbb4eec3a7f93f5e1e4fed9a84fb3",
 
   # The internal benchmarks to use. See go/dart-benchmarks-internal
   "benchmarks_internal_rev": "076df10d9b77af337f2d8029725787155eb1cd52",
@@ -141,7 +141,7 @@
   "process_rev": "56ece43b53b64c63ae51ec184b76bd5360c28d0b",
   "protobuf_rev": "c1eb6cb51af39ccbaa1a8e19349546586a5c8e31",
   "pub_rev": "96404e0749864c9fbf8b12e1d424e8078809e00a",
-  "pub_semver_rev": "cee044a3dc867c1c8464408ed435bd21949510c0",
+  "pub_semver_rev": "a43ad72fb6b7869607581b5fedcb186d1e74276a",
   "root_certificates_rev": "692f6d6488af68e0121317a9c2c9eb393eb0ee50",
   "rust_revision": "b7856f695d65a8ebc846754f97d15814bcb1c244",
   "shelf_static_rev": "202ec1a53c9a830c17cf3b718d089cf7eba568ad",
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index b1b1ca0..98ff8fb 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -1781,15 +1781,11 @@
   }
 
   void _removePotentiallyAffectedLibraries(String path) {
-    _logger.run('Invalidate affected by $path.', () {
-      _logger.writeln('Work in $name');
-      var affected = <FileState>{};
-      _fsState.collectAffected(path, affected);
-      _logger.writeln('Remove ${affected.length} libraries.');
-      _libraryContext?.elementFactory.removeLibraries(
-        affected.map((e) => e.uriStr).toSet(),
-      );
-    });
+    var affected = <FileState>{};
+    _fsState.collectAffected(path, affected);
+    _libraryContext?.elementFactory.removeLibraries(
+      affected.map((e) => e.uriStr).toSet(),
+    );
   }
 
   void _reportException(String path, Object exception, StackTrace stackTrace) {
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
index b728d00..e74bf6d 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -129,6 +129,9 @@
 
   UnlinkedUnit? _unlinked2;
 
+  /// Files that reference this file.
+  final List<FileState> referencingFiles = [];
+
   List<FileState?>? _importedFiles;
   List<FileState?>? _exportedFiles;
   List<FileState?>? _partedFiles;
@@ -199,7 +202,10 @@
     return _exportedFiles ??= _unlinked2!.exports.map((directive) {
       var uri = _selectRelativeUri(directive);
       return _fileForRelativeUri(uri).map(
-        (file) => file,
+        (file) {
+          file?.referencingFiles.add(this);
+          return file;
+        },
         (_) => null,
       );
     }).toList();
@@ -213,7 +219,10 @@
     return _importedFiles ??= _unlinked2!.imports.map((directive) {
       var uri = _selectRelativeUri(directive);
       return _fileForRelativeUri(uri).map(
-        (file) => file,
+        (file) {
+          file?.referencingFiles.add(this);
+          return file;
+        },
         (_) => null,
       );
     }).toList();
@@ -279,6 +288,7 @@
       return _fileForRelativeUri(uri).map(
         (file) {
           if (file != null) {
+            file.referencingFiles.add(this);
             _fsState._partToLibraries
                 .putIfAbsent(file, () => <FileState>[])
                 .add(this);
@@ -423,6 +433,9 @@
       }
     }
 
+    // It is possible that this file does not reference these files.
+    _stopReferencingByThisFile();
+
     // Read imports/exports on demand.
     _importedFiles = null;
     _exportedFiles = null;
@@ -562,6 +575,20 @@
     return directive.uri;
   }
 
+  void _stopReferencingByThisFile() {
+    void removeForOne(List<FileState?>? referencedFiles) {
+      if (referencedFiles != null) {
+        for (var referenced in referencedFiles) {
+          referenced?.referencingFiles.remove(this);
+        }
+      }
+    }
+
+    removeForOne(_importedFiles);
+    removeForOne(_exportedFiles);
+    removeForOne(_partedFiles);
+  }
+
   static UnlinkedUnit serializeAstUnlinked2(CompilationUnit unit) {
     var exports = <UnlinkedNamespaceDirective>[];
     var imports = <UnlinkedNamespaceDirective>[];
@@ -740,23 +767,10 @@
   /// Collected files that transitively reference a file with the [path].
   /// These files are potentially affected by the change.
   void collectAffected(String path, Set<FileState> affected) {
-    final knownFiles = this.knownFiles.toList();
-
-    final fileToReferences = <FileState, List<FileState>>{};
-    for (var file in knownFiles) {
-      for (var referenced in file.directReferencedFiles) {
-        var references = fileToReferences[referenced] ??= [];
-        references.add(file);
-      }
-    }
-
     collectAffected(FileState file) {
       if (affected.add(file)) {
-        var references = fileToReferences[file];
-        if (references != null) {
-          for (var other in references) {
-            collectAffected(other);
-          }
+        for (var other in file.referencingFiles) {
+          collectAffected(other);
         }
       }
     }
diff --git a/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
index aa594c5..0391099 100644
--- a/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
@@ -263,6 +263,19 @@
     _visitArguments(node, whyNotPromotedList);
   }
 
+  void _localVariable(
+    AnnotationImpl node,
+    VariableElement element,
+    List<WhyNotPromotedGetter> whyNotPromotedList,
+  ) {
+    if (!element.isConst || node.arguments != null) {
+      _errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.INVALID_ANNOTATION, node);
+    }
+
+    _visitArguments(node, whyNotPromotedList);
+  }
+
   void _propertyAccessorElement(
     AnnotationImpl node,
     SimpleIdentifierImpl name,
@@ -393,8 +406,8 @@
       return;
     }
 
-    // TODO(scheglov) Must be const.
     if (element1 is VariableElement) {
+      _localVariable(node, element1, whyNotPromotedList);
       return;
     }
 
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_annotation_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_annotation_test.dart
index a72d21b..00abc76 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_annotation_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_annotation_test.dart
@@ -110,6 +110,40 @@
     ]);
   }
 
+  test_localVariable_const() async {
+    await assertNoErrorsInCode(r'''
+void f() {
+  const a = 0;
+  @a
+  var b; // ignore:unused_local_variable
+}
+''');
+  }
+
+  test_localVariable_const_withArguments() async {
+    await assertErrorsInCode(r'''
+void f() {
+  const a = 0;
+  @a(0)
+  var b; // ignore:unused_local_variable
+}
+''', [
+      error(CompileTimeErrorCode.INVALID_ANNOTATION, 28, 5),
+    ]);
+  }
+
+  test_localVariable_final() async {
+    await assertErrorsInCode(r'''
+void f() {
+  final a = 0;
+  @a
+  var b; // ignore:unused_local_variable
+}
+''', [
+      error(CompileTimeErrorCode.INVALID_ANNOTATION, 28, 2),
+    ]);
+  }
+
   test_notClass_importWithPrefix() async {
     newFile('$testPackageLibPath/annotations.dart', content: r'''
 class Property {
diff --git a/pkg/dartdev/lib/dartdev.dart b/pkg/dartdev/lib/dartdev.dart
index 3e75181..a545f1a 100644
--- a/pkg/dartdev/lib/dartdev.dart
+++ b/pkg/dartdev/lib/dartdev.dart
@@ -21,7 +21,6 @@
 import 'src/commands/compile.dart';
 import 'src/commands/create.dart';
 import 'src/commands/debug_adapter.dart';
-import 'src/commands/doc.dart';
 import 'src/commands/fix.dart';
 import 'src/commands/language_server.dart';
 import 'src/commands/migrate.dart';
@@ -115,7 +114,6 @@
     addCommand(CreateCommand(verbose: verbose));
     addCommand(DebugAdapterCommand(verbose: verbose));
     addCommand(CompileCommand(verbose: verbose));
-    addCommand(DocCommand(verbose: verbose));
     addCommand(DevToolsCommand(
       verbose: verbose,
       customDevToolsPath: sdk.devToolsBinaries,
diff --git a/pkg/dartdev/lib/src/commands/doc.dart b/pkg/dartdev/lib/src/commands/doc.dart
deleted file mode 100644
index 26e6abc..0000000
--- a/pkg/dartdev/lib/src/commands/doc.dart
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-import 'dart:io' as io;
-
-import 'package:dartdoc/dartdoc.dart';
-import 'package:dartdoc/options.dart';
-import 'package:path/path.dart' as path;
-
-import '../core.dart';
-
-/// A command to create a new project from a set of templates.
-class DocCommand extends DartdevCommand {
-  static const String cmdName = 'doc';
-  String outputPath;
-
-  DocCommand({bool verbose = false})
-      : super(
-          cmdName,
-          'Generate HTML API documentation from Dart documentation comments.',
-          verbose,
-        ) {
-    outputPath = path.join('.', 'doc', 'api');
-    argParser.addOption(
-      'output-dir',
-      abbr: 'o',
-      defaultsTo: outputPath,
-      help: 'Output directory',
-    );
-    argParser.addFlag(
-      'validate-links',
-      negatable: true,
-      help: 'Display context aware warnings for broken links (slow)',
-    );
-  }
-
-  @override
-  String get invocation => '${super.invocation} <input directory>';
-
-  @override
-  FutureOr<int> run() async {
-    // At least one argument, the input directory, is required.
-    if (argResults.rest.isEmpty) {
-      usageException("Error: Input directory not specified");
-    }
-
-    // Determine input directory.
-    final dir = io.Directory(argResults.rest[0]);
-    if (!dir.existsSync()) {
-      usageException("Error: Input directory doesn't exist: ${dir.path}");
-    }
-
-    // Parse options.
-    final options = [
-      '--input=${dir.path}',
-      '--output=${argResults['output-dir']}',
-    ];
-    if (argResults['validate-links']) {
-      options.add('--validate-links');
-    } else {
-      options.add('--no-validate-links');
-    }
-    final config = await parseOptions(pubPackageMetaProvider, options);
-    if (config == null) {
-      // There was an error while parsing options.
-      return 2;
-    }
-
-    // Call DartDoc.
-    if (verbose) {
-      log.stdout('Calling DartDoc with the following options: $options');
-    }
-    final packageConfigProvider = PhysicalPackageConfigProvider();
-    final packageBuilder = PubPackageBuilder(
-        config, pubPackageMetaProvider, packageConfigProvider);
-    final dartdoc = config.generateDocs
-        ? await Dartdoc.fromContext(config, packageBuilder)
-        : await Dartdoc.withEmptyGenerator(config, packageBuilder);
-    dartdoc.executeGuarded();
-    return 0;
-  }
-}
diff --git a/pkg/dartdev/pubspec.yaml b/pkg/dartdev/pubspec.yaml
index aa4f922..0145fab 100644
--- a/pkg/dartdev/pubspec.yaml
+++ b/pkg/dartdev/pubspec.yaml
@@ -17,7 +17,6 @@
   dart2native:
     path: ../dart2native
   dart_style: any
-  dartdoc: any
   dds:
     path: ../dds
   devtools_server: any
diff --git a/pkg/dartdev/test/commands/doc_test.dart b/pkg/dartdev/test/commands/doc_test.dart
deleted file mode 100644
index 84e5faf..0000000
--- a/pkg/dartdev/test/commands/doc_test.dart
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:test/test.dart';
-
-import '../utils.dart';
-
-const int compileErrorExitCode = 64;
-
-void main() {
-  group('doc', defineCompileTests, timeout: longTimeout);
-}
-
-void defineCompileTests() {
-  test('Passing no args fails', () {
-    final p = project();
-    var result = p.runSync(['doc']);
-    expect(result.stderr, contains('Input directory not specified'));
-    expect(result.exitCode, compileErrorExitCode);
-  });
-
-  test('--help', () {
-    final p = project();
-    final result = p.runSync(['doc', '--help']);
-    expect(
-      result.stdout,
-      contains('Usage: dart doc [arguments] <input directory>'),
-    );
-
-    expect(result.exitCode, 0);
-  });
-
-  test('Document a library', () {
-    final source = '''
-/// This is Foo. It uses [Bar].
-class Foo {
-    Bar bar;
-}
-
-/// Bar is very nice.
-class Bar {
-    _i = 42;
-}
-    ''';
-
-    final p = project(mainSrc: 'void main() { print("Hello, World"); }');
-    p.file('lib/foo.dart', source);
-    final result = p.runSync(['doc', '--validate-links', p.dirPath]);
-    print(
-        'exit: ${result.exitCode}, stderr:\n${result.stderr}\nstdout:\n${result.stdout}');
-    expect(result.stdout, contains('Documenting dartdev_temp'));
-  });
-
-  test('Document a library with broken link is flagged', () {
-    final source = '''
-/// This is Foo. It uses [Baz].
-class Foo {
-  //  Bar bar;
-}
-    ''';
-
-    final p = project(mainSrc: 'void main() { print("Hello, World"); }');
-    p.file('lib/foo.dart', source);
-    final result = p.runSync(['doc', '--validate-links', p.dirPath]);
-    print(
-        'exit: ${result.exitCode}, stderr:\n${result.stderr}\nstdout:\n${result.stdout}');
-    expect(result.stdout, contains('Documenting dartdev_temp'));
-  });
-}
diff --git a/pkg/dds/lib/src/dap/adapters/dart.dart b/pkg/dds/lib/src/dap/adapters/dart.dart
index 67be4b5..655d646 100644
--- a/pkg/dds/lib/src/dap/adapters/dart.dart
+++ b/pkg/dds/lib/src/dap/adapters/dart.dart
@@ -13,6 +13,7 @@
 import 'package:vm_service/vm_service.dart' as vm;
 
 import '../../../dds.dart';
+import '../../rpc_error_codes.dart';
 import '../base_debug_adapter.dart';
 import '../exceptions.dart';
 import '../isolate_manager.dart';
@@ -49,6 +50,9 @@
 /// will work.
 const threadExceptionExpression = r'$_threadException';
 
+/// Typedef for handlers of VM Service stream events.
+typedef _StreamEventHandler<T> = FutureOr<void> Function(T data);
+
 /// Pattern for extracting useful error messages from an evaluation exception.
 final _evalErrorMessagePattern = RegExp('Error: (.*)');
 
@@ -354,6 +358,17 @@
 
   late final sendLogsToClient = args.sendLogsToClient ?? false;
 
+  /// Whether or not the DAP is terminating.
+  ///
+  /// When set to `true`, some requests that return "Service Disappeared" errors
+  /// will be caught and dropped as these are expected if the process is
+  /// terminating.
+  ///
+  /// This flag may be set by incoming requests from the client
+  /// (terminateRequest/disconnectRequest) or when a process terminates, or the
+  /// VM Service disconnects.
+  bool isTerminating = false;
+
   DartDebugAdapter(
     ByteStreamServerChannel channel, {
     this.ipv6 = false,
@@ -531,16 +546,20 @@
     this.vmService = vmService;
 
     unawaited(vmService.onDone.then((_) => _handleVmServiceClosed()));
+
+    // Handlers must be wrapped to handle Service Disappeared errors if async
+    // code tries to call the VM Service after termination begins.
+    final wrap = _wrapHandlerWithErrorHandling;
     _subscriptions.addAll([
-      vmService.onIsolateEvent.listen(handleIsolateEvent),
-      vmService.onDebugEvent.listen(handleDebugEvent),
-      vmService.onLoggingEvent.listen(handleLoggingEvent),
-      vmService.onExtensionEvent.listen(handleExtensionEvent),
-      vmService.onServiceEvent.listen(handleServiceEvent),
+      vmService.onIsolateEvent.listen(wrap(handleIsolateEvent)),
+      vmService.onDebugEvent.listen(wrap(handleDebugEvent)),
+      vmService.onLoggingEvent.listen(wrap(handleLoggingEvent)),
+      vmService.onExtensionEvent.listen(wrap(handleExtensionEvent)),
+      vmService.onServiceEvent.listen(wrap(handleServiceEvent)),
       if (_subscribeToOutputStreams)
-        vmService.onStdoutEvent.listen(_handleStdoutEvent),
+        vmService.onStdoutEvent.listen(wrap(_handleStdoutEvent)),
       if (_subscribeToOutputStreams)
-        vmService.onStderrEvent.listen(_handleStderrEvent),
+        vmService.onStderrEvent.listen(wrap(_handleStderrEvent)),
     ]);
     await Future.wait([
       vmService.streamListen(vm.EventStreams.kIsolate),
@@ -558,8 +577,20 @@
     // Let the subclass do any existing setup once we have a connection.
     await debuggerConnected(vmInfo);
 
-    // Process any existing isolates that may have been created before the
-    // streams above were set up.
+    await _withErrorHandling(
+      () => _configureExistingIsolates(vmService, vmInfo, resumeIfStarting),
+    );
+
+    _debuggerInitializedCompleter.complete();
+  }
+
+  /// Process any existing isolates that may have been created before the
+  /// streams above were set up.
+  Future<void> _configureExistingIsolates(
+    vm.VmService vmService,
+    vm.VM vmInfo,
+    bool resumeIfStarting,
+  ) async {
     final existingIsolateRefs = vmInfo.isolates;
     final existingIsolates = existingIsolateRefs != null
         ? await Future.wait(existingIsolateRefs
@@ -596,8 +627,6 @@
         }
       }
     }));
-
-    _debuggerInitializedCompleter.complete();
   }
 
   /// Handles the clients "continue" ("resume") request for the thread in
@@ -695,6 +724,8 @@
     DisconnectArguments? args,
     void Function() sendResponse,
   ) async {
+    isTerminating = true;
+
     await disconnectImpl();
     await shutdown();
     sendResponse();
@@ -839,6 +870,7 @@
       return;
     }
 
+    isTerminating = true;
     _hasSentTerminatedEvent = true;
     // Always add a leading newline since the last written text might not have
     // had one.
@@ -1318,6 +1350,8 @@
     TerminateArguments? args,
     void Function() sendResponse,
   ) async {
+    isTerminating = true;
+
     await terminateImpl();
     await shutdown();
     sendResponse();
@@ -1661,6 +1695,7 @@
   }
 
   Future<void> _handleVmServiceClosed() async {
+    isTerminating = true;
     if (terminateOnVmServiceClose) {
       handleSessionTerminate();
     }
@@ -1767,6 +1802,40 @@
       streamClosed: streamClosedCompleter.future,
     );
   }
+
+  /// Wraps a function with an error handler that handles errors that occur when
+  /// the VM Service/DDS shuts down.
+  ///
+  /// When the debug adapter is terminating, it's possible in-flight requests
+  /// triggered by handlers will fail with "Service Disappeared". This is
+  /// normal and such errors can be ignored, rather than allowed to pass
+  /// uncaught.
+  _StreamEventHandler<T> _wrapHandlerWithErrorHandling<T>(
+    _StreamEventHandler<T> handler,
+  ) {
+    return (data) => _withErrorHandling(() => handler(data));
+  }
+
+  /// Calls a function with an error handler that handles errors that occur when
+  /// the VM Service/DDS shuts down.
+  ///
+  /// When the debug adapter is terminating, it's possible in-flight requests
+  /// will fail with "Service Disappeared". This is normal and such errors can
+  /// be ignored, rather than allowed to pass uncaught.
+  FutureOr<T?> _withErrorHandling<T>(FutureOr<T> Function() func) async {
+    try {
+      return await func();
+    } on vm.RPCError catch (e) {
+      // If we're been asked to shut down while this request was occurring,
+      // it's normal to get kServiceDisappeared so we should handle this
+      // silently.
+      if (isTerminating && e.code == RpcErrorCodes.kServiceDisappeared) {
+        return null;
+      }
+
+      rethrow;
+    }
+  }
 }
 
 /// An implementation of [LaunchRequestArguments] that includes all fields used
diff --git a/pkg/dds/test/dap/integration/debug_test.dart b/pkg/dds/test/dap/integration/debug_test.dart
index 6e7565b..12f17b4 100644
--- a/pkg/dds/test/dap/integration/debug_test.dart
+++ b/pkg/dds/test/dap/integration/debug_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'dart:async';
 import 'dart:io';
 
 import 'package:dds/src/dap/protocol_generated.dart';
@@ -159,6 +160,19 @@
       final source = await client.getValidSource(topFrame.source!);
       expect(source.content, contains('void print(Object? object) {'));
     });
+
+    test('can shutdown during startup', () async {
+      final testFile = dap.createTestFile(simpleArgPrintingProgram);
+
+      // Terminate the app immediately upon recieving the first Thread event.
+      // The DAP is also responding to this event to configure the isolate (eg.
+      // set breakpoints and exception pause behaviour) and will cause it to
+      // receive "Service has disappeared" responses if these are in-flight as
+      // the process terminates. These should not go unhandled since they are
+      // normal during shutdown.
+      unawaited(dap.client.event('thread').then((_) => dap.client.terminate()));
+      await dap.client.start(file: testFile);
+    });
     // These tests can be slow due to starting up the external server process.
   }, timeout: Timeout.none);
 
diff --git a/pkg/dds/test/dap/integration/test_client.dart b/pkg/dds/test/dap/integration/test_client.dart
index 66f44da..af40d1c 100644
--- a/pkg/dds/test/dap/integration/test_client.dart
+++ b/pkg/dds/test/dap/integration/test_client.dart
@@ -399,7 +399,7 @@
       } else {
         completer.completeError(message);
       }
-    } else if (message is Event) {
+    } else if (message is Event && !_eventController.isClosed) {
       _eventController.add(message);
 
       // When we see a terminated event, close the event stream so if any
diff --git a/pkg/dds/tool/dap/README.md b/pkg/dds/tool/dap/README.md
index 216d648..a65f707 100644
--- a/pkg/dds/tool/dap/README.md
+++ b/pkg/dds/tool/dap/README.md
@@ -15,7 +15,7 @@
 
 For details on the standard DAP functionality, see [the Debug Adapter Protocol Overview](https://microsoft.github.io/debug-adapter-protocol/) and [the Debug Adapter Protocol Specification](https://microsoft.github.io/debug-adapter-protocol/specification). Custom extensions are detailed below.
 
-**Flutter**: To run Flutter apps, the equivalent command should be run through the `flutter` tool. This is unavailable at the time of writing, but details will be linked here once available.
+**Flutter**: Flutter apps should be run using the debug adapter in the `flutter` tool - [see this document](https://github.com/flutter/flutter/blob/master/packages/flutter_tools/lib/src/debug_adapters/README.md).
 
 ## Launch/Attach Arguments
 
diff --git a/pkg/vm/lib/transformations/type_flow/analysis.dart b/pkg/vm/lib/transformations/type_flow/analysis.dart
index 61870d6..7cdec21 100644
--- a/pkg/vm/lib/transformations/type_flow/analysis.dart
+++ b/pkg/vm/lib/transformations/type_flow/analysis.dart
@@ -764,6 +764,16 @@
   /// different arguments reaches this limit.
   static const int maxInvocationsPerSelector = 5000;
 
+  /// [_DirectInvocation] can be approximated with raw arguments
+  /// if number of operations in its summary exceeds this threshold.
+  static const int largeSummarySize = 300;
+
+  /// If summary exceeds [largeSummarySize] and number of
+  /// [_DirectInvocation] objects with same selector but
+  /// different arguments exceeds this limit, then approximate
+  /// [_DirectInvocation] with raw arguments is created and used.
+  static const int maxDirectInvocationsPerSelector = 10;
+
   int count = 0;
   _Invocation? approximation;
 }
@@ -773,14 +783,19 @@
 class _InvocationsCache {
   final TypeFlowAnalysis _typeFlowAnalysis;
   final Set<_Invocation> _invocations = new Set<_Invocation>();
-  final Map<Selector, _SelectorApproximation> _approximations =
-      <Selector, _SelectorApproximation>{};
+  final Map<InterfaceSelector, _SelectorApproximation>
+      _interfaceSelectorApproximations =
+      <InterfaceSelector, _SelectorApproximation>{};
+  final Map<DirectSelector, _SelectorApproximation>
+      _directSelectorApproximations =
+      <DirectSelector, _SelectorApproximation>{};
 
   _InvocationsCache(this._typeFlowAnalysis);
 
   _Invocation getInvocation(Selector selector, Args<Type> args) {
     ++Statistics.invocationsQueriedInCache;
-    _Invocation invocation = (selector is DirectSelector)
+    final bool isDirectSelector = (selector is DirectSelector);
+    _Invocation invocation = isDirectSelector
         ? new _DirectInvocation(selector, args)
         : new _DispatchableInvocation(selector, args);
     _Invocation? result = _invocations.lookup(invocation);
@@ -788,12 +803,36 @@
       return result;
     }
 
-    if (selector is InterfaceSelector) {
+    if (isDirectSelector) {
+      // If there is a selector approximation (meaning the summary is large)
+      // then number of distinct invocations per selector should be limited
+      // in order to bound analysis time.
+
+      final sa = _directSelectorApproximations[selector];
+      if (sa != null) {
+        if (sa.count >=
+            _SelectorApproximation.maxDirectInvocationsPerSelector) {
+          _Invocation? approximation = sa.approximation;
+          if (approximation == null) {
+            final rawArgs =
+                _typeFlowAnalysis.summaryCollector.rawArguments(selector);
+            sa.approximation =
+                approximation = _DirectInvocation(selector, rawArgs);
+            approximation.init();
+            Statistics.approximateDirectInvocationsCreated++;
+          }
+          Statistics.approximateDirectInvocationsUsed++;
+          return approximation;
+        }
+        ++sa.count;
+      }
+    } else if (selector is InterfaceSelector) {
       // Detect if there are too many invocations per selector. In such case,
       // approximate extra invocations with a single invocation with raw
       // arguments.
 
-      final sa = (_approximations[selector] ??= new _SelectorApproximation());
+      final sa = (_interfaceSelectorApproximations[selector] ??=
+          new _SelectorApproximation());
 
       if (sa.count >= _SelectorApproximation.maxInvocationsPerSelector) {
         _Invocation? approximation = sa.approximation;
@@ -803,9 +842,9 @@
           sa.approximation =
               approximation = _DispatchableInvocation(selector, rawArgs);
           approximation.init();
-          Statistics.approximateInvocationsCreated++;
+          Statistics.approximateInterfaceInvocationsCreated++;
         }
-        Statistics.approximateInvocationsUsed++;
+        Statistics.approximateInterfaceInvocationsUsed++;
         return approximation;
       }
 
@@ -820,6 +859,10 @@
     ++Statistics.invocationsAddedToCache;
     return invocation;
   }
+
+  void addDirectSelectorApproximation(DirectSelector selector) {
+    _directSelectorApproximations[selector] ??= new _SelectorApproximation();
+  }
 }
 
 class _FieldValue extends _DependencyTracker {
@@ -1530,7 +1573,17 @@
   _Invocation get currentInvocation => workList.callStack.last;
 
   Summary getSummary(Member member) {
-    return _summaries[member] ??= summaryCollector.createSummary(member);
+    Summary? summary = _summaries[member];
+    if (summary == null) {
+      _summaries[member] = summary = summaryCollector.createSummary(member);
+      if (summary.statements.length >=
+          _SelectorApproximation.largeSummarySize) {
+        final DirectSelector selector =
+            currentInvocation.selector as DirectSelector;
+        _invocationsCache.addDirectSelectorApproximation(selector);
+      }
+    }
+    return summary;
   }
 
   _FieldValue getFieldValue(Field field) {
diff --git a/pkg/vm/lib/transformations/type_flow/summary.dart b/pkg/vm/lib/transformations/type_flow/summary.dart
index 72b0b68..a309138 100644
--- a/pkg/vm/lib/transformations/type_flow/summary.dart
+++ b/pkg/vm/lib/transformations/type_flow/summary.dart
@@ -682,8 +682,8 @@
       if (staticTypeForNarrowing != null) {
         types[i] = argType.intersection(staticTypeForNarrowing, typeHierarchy);
       } else {
-        // TODO(sjindel/tfa): Narrowing is performed inside a [TypeCheck] later.
-        types[i] = args[i];
+        // Narrowing is performed inside a [TypeCheck] later.
+        types[i] = argType;
       }
     }
 
diff --git a/pkg/vm/lib/transformations/type_flow/utils.dart b/pkg/vm/lib/transformations/type_flow/utils.dart
index c85dfc7..42f54c0 100644
--- a/pkg/vm/lib/transformations/type_flow/utils.dart
+++ b/pkg/vm/lib/transformations/type_flow/utils.dart
@@ -188,8 +188,10 @@
   static int invocationsQueriedInCache = 0;
   static int invocationsAddedToCache = 0;
   static int maxInvocationsCachedPerSelector = 0;
-  static int approximateInvocationsCreated = 0;
-  static int approximateInvocationsUsed = 0;
+  static int approximateDirectInvocationsCreated = 0;
+  static int approximateDirectInvocationsUsed = 0;
+  static int approximateInterfaceInvocationsCreated = 0;
+  static int approximateInterfaceInvocationsUsed = 0;
   static int deepInvocationsDeferred = 0;
   static int classesDropped = 0;
   static int membersDropped = 0;
@@ -222,8 +224,10 @@
     invocationsQueriedInCache = 0;
     invocationsAddedToCache = 0;
     maxInvocationsCachedPerSelector = 0;
-    approximateInvocationsCreated = 0;
-    approximateInvocationsUsed = 0;
+    approximateDirectInvocationsCreated = 0;
+    approximateDirectInvocationsUsed = 0;
+    approximateInterfaceInvocationsCreated = 0;
+    approximateInterfaceInvocationsUsed = 0;
     deepInvocationsDeferred = 0;
     classesDropped = 0;
     membersDropped = 0;
@@ -267,8 +271,10 @@
     ${invocationsQueriedInCache} invocations queried in cache
     ${invocationsAddedToCache} invocations added to cache
     ${maxInvocationsCachedPerSelector} maximum invocations cached per selector
-    ${approximateInvocationsCreated} approximate invocations created
-    ${approximateInvocationsUsed} times approximate invocation is used
+    ${approximateDirectInvocationsCreated} approximate direct invocations created
+    ${approximateDirectInvocationsUsed} times direct interface invocation is used
+    ${approximateInterfaceInvocationsCreated} approximate interface invocations created
+    ${approximateInterfaceInvocationsUsed} times approximate interface invocation is used
     ${deepInvocationsDeferred} times invocation processing was deferred due to deep call stack
     ${classesDropped} classes dropped
     ${membersDropped} members dropped
diff --git a/runtime/vm/compiler/aot/precompiler.cc b/runtime/vm/compiler/aot/precompiler.cc
index 6c373a5..87d430f 100644
--- a/runtime/vm/compiler/aot/precompiler.cc
+++ b/runtime/vm/compiler/aot/precompiler.cc
@@ -3130,6 +3130,7 @@
 
       CompilerState compiler_state(thread(), /*is_aot=*/true, optimized(),
                                    CompilerState::ShouldTrace(function));
+      compiler_state.set_function(function);
 
       {
         ic_data_array = new (zone) ZoneGrowableArray<const ICData*>();
diff --git a/runtime/vm/compiler/backend/flow_graph.cc b/runtime/vm/compiler/backend/flow_graph.cc
index a98f355..b0195987 100644
--- a/runtime/vm/compiler/backend/flow_graph.cc
+++ b/runtime/vm/compiler/backend/flow_graph.cc
@@ -2866,4 +2866,8 @@
   }
 }
 
+void FlowGraph::Print(const char* phase) {
+  FlowGraphPrinter::PrintGraph(phase, this);
+}
+
 }  // namespace dart
diff --git a/runtime/vm/compiler/backend/flow_graph.h b/runtime/vm/compiler/backend/flow_graph.h
index fe59272..c847bab 100644
--- a/runtime/vm/compiler/backend/flow_graph.h
+++ b/runtime/vm/compiler/backend/flow_graph.h
@@ -119,6 +119,8 @@
   const ParsedFunction& parsed_function() const { return parsed_function_; }
   const Function& function() const { return parsed_function_.function(); }
 
+  void Print(const char* phase = "unknown");
+
   // The number of directly accessable parameters (above the frame pointer).
   // All other parameters can only be indirectly loaded via metadata found in
   // the arguments descriptor.
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.h b/runtime/vm/compiler/backend/flow_graph_compiler.h
index 98488ae..e195a18 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.h
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.h
@@ -488,6 +488,9 @@
 
   BlockEntryInstr* current_block() const { return current_block_; }
   void set_current_block(BlockEntryInstr* value) { current_block_ = value; }
+
+  Instruction* current_instruction() const { return current_instruction_; }
+
   static bool CanOptimize();
   bool CanOptimizeFunction() const;
   bool CanOSRFunction() const;
@@ -1143,8 +1146,6 @@
     current_instruction_ = current_instruction;
   }
 
-  Instruction* current_instruction() { return current_instruction_; }
-
   void CompactBlock(BlockEntryInstr* block);
   void CompactBlocks();
 
diff --git a/runtime/vm/compiler/compiler_pass.cc b/runtime/vm/compiler/compiler_pass.cc
index d6071ee..0d91ec1 100644
--- a/runtime/vm/compiler/compiler_pass.cc
+++ b/runtime/vm/compiler/compiler_pass.cc
@@ -8,6 +8,7 @@
 #include "vm/compiler/backend/branch_optimizer.h"
 #include "vm/compiler/backend/constant_propagator.h"
 #include "vm/compiler/backend/flow_graph_checker.h"
+#include "vm/compiler/backend/flow_graph_compiler.h"
 #include "vm/compiler/backend/il_printer.h"
 #include "vm/compiler/backend/inliner.h"
 #include "vm/compiler/backend/linearscan.h"
@@ -206,6 +207,7 @@
       Get(kCanonicalize)->Run(state);
     }
 
+    CompilerState::Current().set_current_pass(this, state);
     PrintGraph(state, kTraceBefore, round);
     {
       TIMELINE_DURATION(thread, CompilerVerbose, name());
@@ -217,9 +219,12 @@
     }
     PrintGraph(state, kTraceAfter, round);
 #if defined(DEBUG)
-    FlowGraphChecker(state->flow_graph(), state->inline_id_to_function)
-        .Check(name());
+    if (CompilerState::Current().is_optimizing()) {
+      FlowGraphChecker(state->flow_graph(), state->inline_id_to_function)
+          .Check(name());
+    }
 #endif
+    CompilerState::Current().set_current_pass(nullptr, nullptr);
   }
 }
 
@@ -555,4 +560,6 @@
   flow_graph->RemoveRedefinitions();
 });
 
+COMPILER_PASS(GenerateCode, { state->graph_compiler->CompileGraph(); });
+
 }  // namespace dart
diff --git a/runtime/vm/compiler/compiler_pass.h b/runtime/vm/compiler/compiler_pass.h
index 1438db8..9afa960 100644
--- a/runtime/vm/compiler/compiler_pass.h
+++ b/runtime/vm/compiler/compiler_pass.h
@@ -52,12 +52,14 @@
   V(TypePropagation)                                                           \
   V(UseTableDispatch)                                                          \
   V(WidenSmiToInt32)                                                           \
-  V(EliminateWriteBarriers)
+  V(EliminateWriteBarriers)                                                    \
+  V(GenerateCode)
 
 class AllocationSinking;
 class BlockScheduler;
 class CallSpecializer;
 class FlowGraph;
+class FlowGraphCompiler;
 class Function;
 class Precompiler;
 class SpeculativeInliningPolicy;
@@ -95,6 +97,8 @@
 
   intptr_t sticky_flags;
 
+  FlowGraphCompiler* graph_compiler = nullptr;
+
  private:
   FlowGraph* flow_graph_;
 };
@@ -144,6 +148,10 @@
 
   enum PipelineMode { kJIT, kAOT };
 
+  static void GenerateCode(CompilerPassState* state) {
+    CompilerPass::Get(CompilerPass::kGenerateCode)->Run(state);
+  }
+
   static void RunGraphIntrinsicPipeline(CompilerPassState* state);
 
   static void RunInliningPipeline(PipelineMode mode, CompilerPassState* state);
diff --git a/runtime/vm/compiler/compiler_state.cc b/runtime/vm/compiler/compiler_state.cc
index b886b6f..dde29ec 100644
--- a/runtime/vm/compiler/compiler_state.cc
+++ b/runtime/vm/compiler/compiler_state.cc
@@ -7,6 +7,7 @@
 #include <functional>
 
 #include "vm/compiler/aot/precompiler.h"
+#include "vm/compiler/backend/flow_graph_compiler.h"
 #include "vm/compiler/backend/il_printer.h"
 #include "vm/compiler/backend/slot.h"
 #include "vm/growable_array.h"
@@ -128,4 +129,30 @@
   return *interpolate_;
 }
 
+void CompilerState::ReportCrash() {
+  OS::PrintErr("=== Crash occured when compiling %s in %s mode in %s pass\n",
+               function() != nullptr ? function()->ToFullyQualifiedCString()
+                                     : "unknown function",
+               is_aot()          ? "AOT"
+               : is_optimizing() ? "optimizing JIT"
+                                 : "unoptimized JIT",
+               pass() != nullptr ? pass()->name() : "unknown");
+  if (pass_state() != nullptr && pass()->id() == CompilerPass::kGenerateCode) {
+    if (pass_state()->graph_compiler->current_block() != nullptr) {
+      OS::PrintErr("=== When compiling block %s\n",
+                   pass_state()->graph_compiler->current_block()->ToCString());
+    }
+    if (pass_state()->graph_compiler->current_instruction() != nullptr) {
+      OS::PrintErr(
+          "=== When compiling instruction %s\n",
+          pass_state()->graph_compiler->current_instruction()->ToCString());
+    }
+  }
+  if (pass_state() != nullptr && pass_state()->flow_graph() != nullptr) {
+    pass_state()->flow_graph()->Print(pass()->name());
+  } else {
+    OS::PrintErr("=== Flow Graph not available\n");
+  }
+}
+
 }  // namespace dart
diff --git a/runtime/vm/compiler/compiler_state.h b/runtime/vm/compiler/compiler_state.h
index 1520b40..ff3ac87 100644
--- a/runtime/vm/compiler/compiler_state.h
+++ b/runtime/vm/compiler/compiler_state.h
@@ -17,6 +17,8 @@
 
 namespace dart {
 
+class CompilerPass;
+struct CompilerPassState;
 class Function;
 class LocalScope;
 class LocalVariable;
@@ -105,6 +107,20 @@
   // Returns _StringBase._interpolateSingle
   const Function& StringBaseInterpolateSingle();
 
+  const Function* function() const { return function_; }
+
+  void set_function(const Function& function) { function_ = &function; }
+  void set_current_pass(const CompilerPass* pass,
+                        const CompilerPassState* pass_state) {
+    pass_ = pass;
+    pass_state_ = pass_state;
+  }
+
+  const CompilerPass* pass() const { return pass_; }
+  const CompilerPassState* pass_state() const { return pass_state_; }
+
+  void ReportCrash();
+
  private:
   CHA cha_;
   intptr_t deopt_id_ = 0;
@@ -127,6 +143,10 @@
   const Function* interpolate_ = nullptr;
   const Function* interpolate_single_ = nullptr;
 
+  const Function* function_ = nullptr;
+  const CompilerPass* pass_ = nullptr;
+  const CompilerPassState* pass_state_ = nullptr;
+
   CompilerState* previous_;
 };
 
diff --git a/runtime/vm/compiler/jit/compiler.cc b/runtime/vm/compiler/jit/compiler.cc
index 5b08899..ff96abb 100644
--- a/runtime/vm/compiler/jit/compiler.cc
+++ b/runtime/vm/compiler/jit/compiler.cc
@@ -504,6 +504,7 @@
 
       CompilerState compiler_state(thread(), /*is_aot=*/false, optimized(),
                                    CompilerState::ShouldTrace(function));
+      compiler_state.set_function(function);
 
       {
         // Extract type feedback before the graph is built, as the graph
@@ -577,10 +578,9 @@
           &speculative_policy, pass_state.inline_id_to_function,
           pass_state.inline_id_to_token_pos, pass_state.caller_inline_id,
           ic_data_array);
-      {
-        TIMELINE_DURATION(thread(), CompilerVerbose, "CompileGraph");
-        graph_compiler.CompileGraph();
-      }
+      pass_state.graph_compiler = &graph_compiler;
+      CompilerPass::GenerateCode(&pass_state);
+
       {
         TIMELINE_DURATION(thread(), CompilerVerbose, "FinalizeCompilation");
 
diff --git a/runtime/vm/heap/marker.cc b/runtime/vm/heap/marker.cc
index e979a01..43b4c62 100644
--- a/runtime/vm/heap/marker.cc
+++ b/runtime/vm/heap/marker.cc
@@ -783,13 +783,31 @@
   ResetSlices();
   for (intptr_t i = 0; i < num_tasks; i++) {
     ASSERT(visitors_[i] == NULL);
-    visitors_[i] = new SyncMarkingVisitor(
+    SyncMarkingVisitor* visitor = new SyncMarkingVisitor(
         isolate_group_, page_space, &marking_stack_, &deferred_marking_stack_);
+    visitors_[i] = visitor;
 
-    // Begin marking on a helper thread.
-    bool result = Dart::thread_pool()->Run<ConcurrentMarkTask>(
-        this, isolate_group_, page_space, visitors_[i]);
-    ASSERT(result);
+    if (i < (num_tasks - 1)) {
+      // Begin marking on a helper thread.
+      bool result = Dart::thread_pool()->Run<ConcurrentMarkTask>(
+          this, isolate_group_, page_space, visitor);
+      ASSERT(result);
+    } else {
+      // Last worker is the main thread, which will only mark roots.
+      TIMELINE_FUNCTION_GC_DURATION(Thread::Current(), "ConcurrentMark");
+      int64_t start = OS::GetCurrentMonotonicMicros();
+      IterateRoots(visitor);
+      int64_t stop = OS::GetCurrentMonotonicMicros();
+      visitor->AddMicros(stop - start);
+      if (FLAG_log_marker_tasks) {
+        THR_Print("Task marked %" Pd " bytes in %" Pd64 " micros.\n",
+                  visitor->marked_bytes(), visitor->marked_micros());
+      }
+      // Continue non-root marking concurrently.
+      bool result = Dart::thread_pool()->Run<ConcurrentMarkTask>(
+          this, isolate_group_, page_space, visitor);
+      ASSERT(result);
+    }
   }
 
   isolate_group_->DeferredMarkLiveTemporaries();
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index aab5dec..58cab0e 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -9,6 +9,9 @@
 #include "platform/atomic.h"
 #include "vm/allocation.h"
 #include "vm/code_patcher.h"
+#if !defined(DART_PRECOMPILED_RUNTIME)
+#include "vm/compiler/compiler_state.h"
+#endif
 #include "vm/debugger.h"
 #include "vm/instructions.h"
 #include "vm/isolate.h"
@@ -1263,6 +1266,11 @@
       StackFrame::DumpCurrentTrace();
     } else if (thread->execution_state() == Thread::kThreadInVM) {
       StackFrame::DumpCurrentTrace();
+#if !defined(DART_PRECOMPILED_RUNTIME)
+      if (thread->HasCompilerState()) {
+        thread->compiler_state().ReportCrash();
+      }
+#endif
     }
   }
 }
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 6824dd8..1eb3222 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -474,8 +474,10 @@
   // Has |this| exited Dart code?
   bool HasExitedDartCode() const;
 
+  bool HasCompilerState() const { return compiler_state_ != nullptr; }
+
   CompilerState& compiler_state() {
-    ASSERT(compiler_state_ != nullptr);
+    ASSERT(HasCompilerState());
     return *compiler_state_;
   }
 
diff --git a/tools/VERSION b/tools/VERSION
index cc5ba9d..b8d6a86 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 16
 PATCH 0
-PRERELEASE 6
+PRERELEASE 7
 PRERELEASE_PATCH 0
\ No newline at end of file