Version 2.18.0-59.0.dev

Merge commit 'efdffab8b77f5ca21ee08e2b7bb8b05a312a1317' into 'dev'
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 0e77b18..1f5bb85 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -19,7 +19,6 @@
 import 'package:analysis_server/src/domain_server.dart';
 import 'package:analysis_server/src/domains/analysis/occurrences.dart';
 import 'package:analysis_server/src/domains/analysis/occurrences_dart.dart';
-import 'package:analysis_server/src/flutter/flutter_domain.dart';
 import 'package:analysis_server/src/flutter/flutter_notifications.dart';
 import 'package:analysis_server/src/handler/legacy/analysis_get_errors.dart';
 import 'package:analysis_server/src/handler/legacy/analysis_get_hover.dart';
@@ -58,13 +57,21 @@
 import 'package:analysis_server/src/handler/legacy/execution_get_suggestions.dart';
 import 'package:analysis_server/src/handler/legacy/execution_map_uri.dart';
 import 'package:analysis_server/src/handler/legacy/execution_set_subscriptions.dart';
+import 'package:analysis_server/src/handler/legacy/flutter_get_widget_description.dart';
+import 'package:analysis_server/src/handler/legacy/flutter_set_subscriptions.dart';
+import 'package:analysis_server/src/handler/legacy/flutter_set_widget_property_value.dart';
 import 'package:analysis_server/src/handler/legacy/kythe_get_kythe_entries.dart';
 import 'package:analysis_server/src/handler/legacy/legacy_handler.dart';
+import 'package:analysis_server/src/handler/legacy/search_find_element_references.dart';
+import 'package:analysis_server/src/handler/legacy/search_find_member_declarations.dart';
+import 'package:analysis_server/src/handler/legacy/search_find_member_references.dart';
+import 'package:analysis_server/src/handler/legacy/search_find_top_level_declarations.dart';
+import 'package:analysis_server/src/handler/legacy/search_get_element_declarations.dart';
+import 'package:analysis_server/src/handler/legacy/search_get_type_hierarchy.dart';
 import 'package:analysis_server/src/handler/legacy/unsupported_request.dart';
 import 'package:analysis_server/src/operation/operation_analysis.dart';
 import 'package:analysis_server/src/plugin/notification_manager.dart';
 import 'package:analysis_server/src/protocol_server.dart' as server;
-import 'package:analysis_server/src/search/search_domain.dart';
 import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
 import 'package:analysis_server/src/server/debounce_requests.dart';
 import 'package:analysis_server/src/server/detachable_filesystem_manager.dart';
@@ -163,7 +170,25 @@
     EXECUTION_REQUEST_MAP_URI: ExecutionMapUriHandler.new,
     EXECUTION_REQUEST_SET_SUBSCRIPTIONS: ExecutionSetSubscriptionsHandler.new,
     //
+    FLUTTER_REQUEST_GET_WIDGET_DESCRIPTION:
+        FlutterGetWidgetDescriptionHandler.new,
+    FLUTTER_REQUEST_SET_WIDGET_PROPERTY_VALUE:
+        FlutterSetWidgetPropertyValueHandler.new,
+    FLUTTER_REQUEST_SET_SUBSCRIPTIONS: FlutterSetSubscriptionsHandler.new,
+    //
     KYTHE_REQUEST_GET_KYTHE_ENTRIES: KytheGetKytheEntriesHandler.new,
+    //
+    SEARCH_REQUEST_FIND_ELEMENT_REFERENCES:
+        SearchFindElementReferencesHandler.new,
+    SEARCH_REQUEST_FIND_MEMBER_DECLARATIONS:
+        SearchFindMemberDeclarationsHandler.new,
+    SEARCH_REQUEST_FIND_MEMBER_REFERENCES:
+        SearchFindMemberReferencesHandler.new,
+    SEARCH_REQUEST_FIND_TOP_LEVEL_DECLARATIONS:
+        SearchFindTopLevelDeclarationsHandler.new,
+    SEARCH_REQUEST_GET_ELEMENT_DECLARATIONS:
+        SearchGetElementDeclarationsHandler.new,
+    SEARCH_REQUEST_GET_TYPE_HIERARCHY: SearchGetTypeHierarchyHandler.new,
   };
 
   /// The channel from which requests are received and to which responses should
@@ -329,9 +354,7 @@
         .listen(handleRequest, onDone: done, onError: error);
     handlers = <server.RequestHandler>[
       ServerDomainHandler(this),
-      SearchDomainHandler(this),
       CompletionDomainHandler(this),
-      FlutterDomainHandler(this)
     ];
     refactoringWorkspace = RefactoringWorkspace(driverMap.values, searchEngine);
     _newRefactoringManager();
diff --git a/pkg/analysis_server/lib/src/flutter/flutter_domain.dart b/pkg/analysis_server/lib/src/flutter/flutter_domain.dart
deleted file mode 100644
index a57802c..0000000
--- a/pkg/analysis_server/lib/src/flutter/flutter_domain.dart
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 2018, 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:analysis_server/protocol/protocol_constants.dart';
-import 'package:analysis_server/src/domain_abstract.dart';
-import 'package:analysis_server/src/handler/legacy/flutter_get_widget_description.dart';
-import 'package:analysis_server/src/handler/legacy/flutter_set_subscriptions.dart';
-import 'package:analysis_server/src/handler/legacy/flutter_set_widget_property_value.dart';
-import 'package:analysis_server/src/protocol_server.dart';
-import 'package:analyzer/src/utilities/cancellation.dart';
-
-/// A [RequestHandler] that handles requests in the `flutter` domain.
-class FlutterDomainHandler extends AbstractRequestHandler {
-  /// Initialize a newly created handler to handle requests for the given
-  /// [server].
-  FlutterDomainHandler(super.server);
-
-  @override
-  Response? handleRequest(
-      Request request, CancellationToken cancellationToken) {
-    try {
-      var requestName = request.method;
-      if (requestName == FLUTTER_REQUEST_GET_WIDGET_DESCRIPTION) {
-        FlutterGetWidgetDescriptionHandler(server, request, cancellationToken)
-            .handle();
-        return Response.DELAYED_RESPONSE;
-      }
-      if (requestName == FLUTTER_REQUEST_SET_WIDGET_PROPERTY_VALUE) {
-        FlutterSetWidgetPropertyValueHandler(server, request, cancellationToken)
-            .handle();
-        return Response.DELAYED_RESPONSE;
-      }
-      if (requestName == FLUTTER_REQUEST_SET_SUBSCRIPTIONS) {
-        FlutterSetSubscriptionsHandler(server, request, cancellationToken)
-            .handle();
-        return Response.DELAYED_RESPONSE;
-      }
-    } on RequestFailure catch (exception) {
-      return exception.response;
-    }
-    return null;
-  }
-}
diff --git a/pkg/analysis_server/lib/src/handler/legacy/search_find_member_declarations.dart b/pkg/analysis_server/lib/src/handler/legacy/search_find_member_declarations.dart
index d5ade7e..7b459ea 100644
--- a/pkg/analysis_server/lib/src/handler/legacy/search_find_member_declarations.dart
+++ b/pkg/analysis_server/lib/src/handler/legacy/search_find_member_declarations.dart
@@ -4,9 +4,8 @@
 
 import 'dart:async';
 
-import 'package:analysis_server/protocol/protocol_generated.dart' as protocol;
 import 'package:analysis_server/src/handler/legacy/legacy_handler.dart';
-import 'package:analysis_server/src/search/search_domain.dart';
+import 'package:analysis_server/src/protocol_server.dart' as protocol;
 
 /// The handler for the `search.findMemberDeclarations` request.
 class SearchFindMemberDeclarationsHandler extends LegacyHandler {
@@ -26,7 +25,7 @@
     sendResult(protocol.SearchFindMemberDeclarationsResult(searchId));
     // search
     var matches = await searchEngine.searchMemberDeclarations(params.name);
-    sendSearchResults(protocol.SearchResultsParams(
-        searchId, matches.map(SearchDomainHandler.toResult).toList(), true));
+    sendSearchResults(protocol.SearchResultsParams(searchId,
+        matches.map(protocol.newSearchResult_fromMatch).toList(), true));
   }
 }
diff --git a/pkg/analysis_server/lib/src/handler/legacy/search_find_member_references.dart b/pkg/analysis_server/lib/src/handler/legacy/search_find_member_references.dart
index d460649..8f7b77b 100644
--- a/pkg/analysis_server/lib/src/handler/legacy/search_find_member_references.dart
+++ b/pkg/analysis_server/lib/src/handler/legacy/search_find_member_references.dart
@@ -4,9 +4,8 @@
 
 import 'dart:async';
 
-import 'package:analysis_server/protocol/protocol_generated.dart' as protocol;
 import 'package:analysis_server/src/handler/legacy/legacy_handler.dart';
-import 'package:analysis_server/src/search/search_domain.dart';
+import 'package:analysis_server/src/protocol_server.dart' as protocol;
 
 /// The handler for the `search.findMemberReferences` request.
 class SearchFindMemberReferencesHandler extends LegacyHandler {
@@ -25,7 +24,7 @@
     sendResult(protocol.SearchFindMemberReferencesResult(searchId));
     // search
     var matches = await searchEngine.searchMemberReferences(params.name);
-    sendSearchResults(protocol.SearchResultsParams(
-        searchId, matches.map(SearchDomainHandler.toResult).toList(), true));
+    sendSearchResults(protocol.SearchResultsParams(searchId,
+        matches.map(protocol.newSearchResult_fromMatch).toList(), true));
   }
 }
diff --git a/pkg/analysis_server/lib/src/handler/legacy/search_find_top_level_declarations.dart b/pkg/analysis_server/lib/src/handler/legacy/search_find_top_level_declarations.dart
index b24980a..2c29996 100644
--- a/pkg/analysis_server/lib/src/handler/legacy/search_find_top_level_declarations.dart
+++ b/pkg/analysis_server/lib/src/handler/legacy/search_find_top_level_declarations.dart
@@ -4,10 +4,8 @@
 
 import 'dart:async';
 
-import 'package:analysis_server/protocol/protocol.dart' as protocol;
-import 'package:analysis_server/protocol/protocol_generated.dart' as protocol;
 import 'package:analysis_server/src/handler/legacy/legacy_handler.dart';
-import 'package:analysis_server/src/search/search_domain.dart';
+import 'package:analysis_server/src/protocol_server.dart' as protocol;
 
 /// The handler for the `search.findTopLevelDeclarations` request.
 class SearchFindTopLevelDeclarationsHandler extends LegacyHandler {
@@ -36,7 +34,7 @@
     sendResult(protocol.SearchFindTopLevelDeclarationsResult(searchId));
     // search
     var matches = await searchEngine.searchTopLevelDeclarations(params.pattern);
-    sendSearchResults(protocol.SearchResultsParams(
-        searchId, matches.map(SearchDomainHandler.toResult).toList(), true));
+    sendSearchResults(protocol.SearchResultsParams(searchId,
+        matches.map(protocol.newSearchResult_fromMatch).toList(), true));
   }
 }
diff --git a/pkg/analysis_server/lib/src/search/search_domain.dart b/pkg/analysis_server/lib/src/search/search_domain.dart
deleted file mode 100644
index ab903d63..0000000
--- a/pkg/analysis_server/lib/src/search/search_domain.dart
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright (c) 2014, 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:analysis_server/protocol/protocol.dart';
-import 'package:analysis_server/protocol/protocol_constants.dart';
-import 'package:analysis_server/src/analysis_server.dart';
-import 'package:analysis_server/src/handler/legacy/search_find_element_references.dart';
-import 'package:analysis_server/src/handler/legacy/search_find_member_declarations.dart';
-import 'package:analysis_server/src/handler/legacy/search_find_member_references.dart';
-import 'package:analysis_server/src/handler/legacy/search_find_top_level_declarations.dart';
-import 'package:analysis_server/src/handler/legacy/search_get_element_declarations.dart';
-import 'package:analysis_server/src/handler/legacy/search_get_type_hierarchy.dart';
-import 'package:analysis_server/src/protocol_server.dart' as protocol;
-import 'package:analysis_server/src/services/search/search_engine.dart';
-import 'package:analyzer/src/utilities/cancellation.dart';
-
-/// Instances of the class [SearchDomainHandler] implement a [RequestHandler]
-/// that handles requests in the search domain.
-class SearchDomainHandler implements protocol.RequestHandler {
-  /// The analysis server that is using this handler to process requests.
-  final AnalysisServer server;
-
-  /// Initialize a newly created handler to handle requests for the given
-  /// [server].
-  SearchDomainHandler(this.server);
-
-  @override
-  protocol.Response? handleRequest(
-      protocol.Request request, CancellationToken cancellationToken) {
-    try {
-      var requestName = request.method;
-      if (requestName == SEARCH_REQUEST_FIND_ELEMENT_REFERENCES) {
-        SearchFindElementReferencesHandler(server, request, cancellationToken)
-            .handle();
-        return protocol.Response.DELAYED_RESPONSE;
-      } else if (requestName == SEARCH_REQUEST_FIND_MEMBER_DECLARATIONS) {
-        SearchFindMemberDeclarationsHandler(server, request, cancellationToken)
-            .handle();
-        return protocol.Response.DELAYED_RESPONSE;
-      } else if (requestName == SEARCH_REQUEST_FIND_MEMBER_REFERENCES) {
-        SearchFindMemberReferencesHandler(server, request, cancellationToken)
-            .handle();
-        return protocol.Response.DELAYED_RESPONSE;
-      } else if (requestName == SEARCH_REQUEST_FIND_TOP_LEVEL_DECLARATIONS) {
-        SearchFindTopLevelDeclarationsHandler(
-                server, request, cancellationToken)
-            .handle();
-        return protocol.Response.DELAYED_RESPONSE;
-      } else if (requestName == SEARCH_REQUEST_GET_ELEMENT_DECLARATIONS) {
-        SearchGetElementDeclarationsHandler(server, request, cancellationToken)
-            .handle();
-        return protocol.Response.DELAYED_RESPONSE;
-      } else if (requestName == SEARCH_REQUEST_GET_TYPE_HIERARCHY) {
-        SearchGetTypeHierarchyHandler(server, request, cancellationToken)
-            .handle();
-        return protocol.Response.DELAYED_RESPONSE;
-      }
-    } on protocol.RequestFailure catch (exception) {
-      return exception.response;
-    }
-    return null;
-  }
-
-  static protocol.SearchResult toResult(SearchMatch match) {
-    return protocol.newSearchResult_fromMatch(match);
-  }
-}
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
index 618627c..e6f16c0 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -148,6 +148,11 @@
   /// might be fixed by a change to another file.
   bool hasErrorOrWarning = false;
 
+  /// Set to `true` if this file contains code that might be executed by
+  /// a macro - declares a macro class itself, or is directly or indirectly
+  /// imported into a library that declares one.
+  bool mightBeExecutedByMacroClass = false;
+
   FileState._(
     this._fsState,
     this.path,
@@ -375,8 +380,8 @@
   /// Read the file content and ensure that all of the file properties are
   /// consistent with the read content, including API signature.
   ///
-  /// Return `true` if the API signature changed since the last refresh.
-  bool refresh() {
+  /// Return how the file changed since the last refresh.
+  FileStateRefreshResult refresh() {
     counterFileStateRefresh++;
 
     var timerWasRunning = timerFileStateRefresh.isRunning;
@@ -386,12 +391,11 @@
 
     _invalidateCurrentUnresolvedData();
 
-    {
-      var rawFileState = _fsState._fileContentCache.get(path);
-      _content = rawFileState.content;
-      _exists = rawFileState.exists;
-      _contentHash = rawFileState.contentHash;
-    }
+    final rawFileState = _fsState._fileContentCache.get(path);
+    final contentChanged = _contentHash != rawFileState.contentHash;
+    _content = rawFileState.content;
+    _exists = rawFileState.exists;
+    _contentHash = rawFileState.contentHash;
 
     // Prepare the unlinked bundle key.
     {
@@ -468,8 +472,14 @@
       timerFileStateRefresh.stop();
     }
 
-    // Return whether the API signature changed.
-    return apiSignatureChanged;
+    // Return how the file changed.
+    if (apiSignatureChanged) {
+      return FileStateRefreshResult.apiChanged;
+    } else if (contentChanged) {
+      return FileStateRefreshResult.contentChanged;
+    } else {
+      return FileStateRefreshResult.nothing;
+    }
   }
 
   @override
@@ -700,6 +710,17 @@
   }
 }
 
+enum FileStateRefreshResult {
+  /// No changes to the content, so no changes at all.
+  nothing,
+
+  /// The content changed, but the API of the file is the same.
+  contentChanged,
+
+  /// The content changed, and the API of the file is different.
+  apiChanged,
+}
+
 @visibleForTesting
 class FileStateTestView {
   final FileState file;
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_tracker.dart b/pkg/analyzer/lib/src/dart/analysis/file_tracker.dart
index 1e42d8e..7371c3f 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_tracker.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_tracker.dart
@@ -150,57 +150,67 @@
 
   /// Verify the API signature for the file with the given [path], and decide
   /// which linked libraries should be invalidated, and files reanalyzed.
-  FileState verifyApiSignature(String path) {
+  void verifyApiSignature(String path) {
     return _logger.run('Verify API signature of $path', () {
       _logger.writeln('Work in ${_fsState.contextName}');
 
       var file = _fsState.getFileForPath(path);
-      var apiChanged = file.refresh();
-      if (apiChanged) {
-        _logger.writeln('API signatures mismatch found.');
-        // TODO(scheglov) schedule analysis of only affected files
-        var pendingChangedFiles = <String>{};
-        var pendingImportFiles = <String>{};
-        var pendingErrorFiles = <String>{};
-        var pendingFiles = <String>{};
 
-        // Add the changed file.
-        if (addedFiles.contains(path)) {
-          pendingChangedFiles.add(path);
-        }
-
-        // Add files that directly import the changed file.
-        for (String addedPath in addedFiles) {
-          FileState addedFile = _fsState.getFileForPath(addedPath);
-          if (addedFile.importedFiles.contains(file)) {
-            pendingImportFiles.add(addedPath);
+      var changeKind = file.refresh();
+      switch (changeKind) {
+        case FileStateRefreshResult.nothing:
+          return;
+        case FileStateRefreshResult.contentChanged:
+          if (file.mightBeExecutedByMacroClass) {
+            break;
           }
-        }
-
-        // Add files with errors or warnings that might be fixed.
-        for (String addedPath in addedFiles) {
-          FileState addedFile = _fsState.getFileForPath(addedPath);
-          if (addedFile.hasErrorOrWarning) {
-            pendingErrorFiles.add(addedPath);
-          }
-        }
-
-        // Add all previous pending files.
-        pendingChangedFiles.addAll(_pendingChangedFiles);
-        pendingImportFiles.addAll(_pendingImportFiles);
-        pendingErrorFiles.addAll(_pendingErrorFiles);
-        pendingFiles.addAll(_pendingFiles);
-
-        // Add all the rest.
-        pendingFiles.addAll(addedFiles);
-
-        // Replace pending files.
-        _pendingChangedFiles = pendingChangedFiles;
-        _pendingImportFiles = pendingImportFiles;
-        _pendingErrorFiles = pendingErrorFiles;
-        _pendingFiles = pendingFiles;
+          return;
+        case FileStateRefreshResult.apiChanged:
+          break;
       }
-      return file;
+
+      _logger.writeln('API signatures mismatch found.');
+      // TODO(scheglov) schedule analysis of only affected files
+      var pendingChangedFiles = <String>{};
+      var pendingImportFiles = <String>{};
+      var pendingErrorFiles = <String>{};
+      var pendingFiles = <String>{};
+
+      // Add the changed file.
+      if (addedFiles.contains(path)) {
+        pendingChangedFiles.add(path);
+      }
+
+      // Add files that directly import the changed file.
+      for (String addedPath in addedFiles) {
+        FileState addedFile = _fsState.getFileForPath(addedPath);
+        if (addedFile.importedFiles.contains(file)) {
+          pendingImportFiles.add(addedPath);
+        }
+      }
+
+      // Add files with errors or warnings that might be fixed.
+      for (String addedPath in addedFiles) {
+        FileState addedFile = _fsState.getFileForPath(addedPath);
+        if (addedFile.hasErrorOrWarning) {
+          pendingErrorFiles.add(addedPath);
+        }
+      }
+
+      // Add all previous pending files.
+      pendingChangedFiles.addAll(_pendingChangedFiles);
+      pendingImportFiles.addAll(_pendingImportFiles);
+      pendingErrorFiles.addAll(_pendingErrorFiles);
+      pendingFiles.addAll(_pendingFiles);
+
+      // Add all the rest.
+      pendingFiles.addAll(addedFiles);
+
+      // Replace pending files.
+      _pendingChangedFiles = pendingChangedFiles;
+      _pendingImportFiles = pendingImportFiles;
+      _pendingErrorFiles = pendingErrorFiles;
+      _pendingFiles = pendingFiles;
     });
   }
 
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_graph.dart b/pkg/analyzer/lib/src/dart/analysis/library_graph.dart
index 1457c6b..95957aa 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_graph.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_graph.dart
@@ -63,6 +63,11 @@
     return false;
   }();
 
+  /// Set to `true` if this library cycle contains code that might be executed
+  /// by a macro - declares a macro class itself, or is directly or indirectly
+  /// imported into a cycle that declares one.
+  bool mightBeExecutedByMacroClass = false;
+
   LibraryCycle({
     required this.libraries,
     required this.directDependencies,
@@ -90,6 +95,23 @@
     }
   }
 
+  /// Mark this cycle and its dependencies are potentially executed by a macro.
+  void markMightBeExecutedByMacroClass() {
+    if (!mightBeExecutedByMacroClass) {
+      mightBeExecutedByMacroClass = true;
+      // Mark each file of the cycle.
+      for (final library in libraries) {
+        for (final file in library.libraryFiles) {
+          file.mightBeExecutedByMacroClass = true;
+        }
+      }
+      // Recursively mark all dependencies.
+      for (final dependency in directDependencies) {
+        dependency.markMightBeExecutedByMacroClass();
+      }
+    }
+  }
+
   @override
   String toString() {
     return '[${libraries.join(', ')}]';
@@ -183,6 +205,10 @@
       implSignature: implSignature.toHex(),
     );
 
+    if (cycle.hasMacroClass) {
+      cycle.markMightBeExecutedByMacroClass();
+    }
+
     // Set the instance into the libraries.
     for (var node in scc) {
       node.file.internal_setLibraryCycle(cycle);
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index 1a0b64c..631249a 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -858,7 +858,10 @@
   ExpressionImpl _expression;
 
   /// Initialize a newly created await expression.
-  AwaitExpressionImpl(this.awaitKeyword, this._expression) {
+  AwaitExpressionImpl({
+    required this.awaitKeyword,
+    required ExpressionImpl expression,
+  }) : _expression = expression {
     _becomeParentOf(_expression);
   }
 
diff --git a/pkg/analyzer/lib/src/dart/ast/ast_factory.dart b/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
index c7e7104..c14099a 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
@@ -79,10 +79,6 @@
       AssignmentExpressionImpl(leftHandSide as ExpressionImpl, operator,
           rightHandSide as ExpressionImpl);
 
-  AwaitExpressionImpl awaitExpression(
-          Token awaitKeyword, Expression expression) =>
-      AwaitExpressionImpl(awaitKeyword, expression as ExpressionImpl);
-
   BinaryExpressionImpl binaryExpression(
           Expression leftOperand, Token operator, Expression rightOperand) =>
       BinaryExpressionImpl(
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index 3438fa9..dd1ae59 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -702,8 +702,13 @@
     assert(optional('await', awaitKeyword));
     debugEvent("AwaitExpression");
 
-    var expression = pop() as Expression;
-    push(ast.awaitExpression(awaitKeyword, expression));
+    var expression = pop() as ExpressionImpl;
+    push(
+      AwaitExpressionImpl(
+        awaitKeyword: awaitKeyword,
+        expression: expression,
+      ),
+    );
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart b/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
index 1264004..79a78d7 100644
--- a/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
@@ -121,11 +121,6 @@
         semicolon: TokenFactory.tokenFromType(TokenType.SEMICOLON),
       );
 
-  static AwaitExpressionImpl awaitExpression(Expression expression) =>
-      astFactory.awaitExpression(
-          TokenFactory.tokenFromTypeAndString(TokenType.IDENTIFIER, "await"),
-          expression);
-
   static BlockImpl block([List<Statement> statements = const []]) =>
       astFactory.block(
           TokenFactory.tokenFromType(TokenType.OPEN_CURLY_BRACKET),
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
index be75c39..b1f8333 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
@@ -265,8 +265,11 @@
   }
 
   AwaitExpression _readAwaitExpression() {
-    var expression = readNode() as Expression;
-    return astFactory.awaitExpression(Tokens.await_(), expression);
+    var expression = readNode() as ExpressionImpl;
+    return AwaitExpressionImpl(
+      awaitKeyword: Tokens.await_(),
+      expression: expression,
+    );
   }
 
   BinaryExpression _readBinaryExpression() {
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_caching_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_caching_test.dart
index de7d1bc..7bb0a4e 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_caching_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_caching_test.dart
@@ -2,12 +2,15 @@
 // 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 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/dart/analysis/driver.dart';
 import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/utilities/extensions/stream.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -353,25 +356,7 @@
   }
 
   test_macro_libraryElement_changeMacroCode() async {
-    File newFileWithFixedNameMacro(String className) {
-      return newFile('$testPackageLibPath/my_macro.dart', '''
-import 'dart:async';
-import 'package:_fe_analyzer_shared/src/macros/api.dart';
-
-macro class MyMacro implements ClassTypesMacro {
-  const MyMacro();
-
-  FutureOr<void> buildTypesForClass(clazz, builder) {
-    builder.declareType(
-      '$className',
-      DeclarationCode.fromString('class $className {}'),
-    );
-  }
-}
-''');
-    }
-
-    final macroFile = newFileWithFixedNameMacro('MacroA');
+    final macroFile = _newFileWithFixedNameMacro('MacroA');
 
     var a = newFile('$testPackageLibPath/a.dart', r'''
 import 'my_macro.dart';
@@ -407,7 +392,7 @@
     _assertContainsLinkedCycle({b.path}, andClear: true);
 
     // The macro will generate `MacroB`.
-    newFileWithFixedNameMacro('MacroB');
+    _newFileWithFixedNameMacro('MacroB');
 
     // Notify about changes.
     analysisContext.changeFile(macroFile.path);
@@ -428,6 +413,158 @@
     _assertContainsLinkedCycle({b.path}, andClear: true);
   }
 
+  test_macro_reanalyze_errors_changeCodeUsedByMacro_importedLibrary() async {
+    final a = newFile('$testPackageLibPath/a.dart', r'''
+String getClassName() => 'MacroA';
+''');
+
+    newFile('$testPackageLibPath/my_macro.dart', r'''
+import 'package:_fe_analyzer_shared/src/macros/api.dart';
+import 'a.dart';
+
+macro class MyMacro implements ClassTypesMacro {
+  const MyMacro();
+
+  buildTypesForClass(clazz, builder) {
+    final className = getClassName();
+    builder.declareType(
+      '$className',
+      DeclarationCode.fromString('class $className {}'),
+    );
+  }
+}
+''');
+
+    var user = newFile('$testPackageLibPath/user.dart', r'''
+import 'my_macro.dart';
+
+@MyMacro()
+class A {}
+
+void f(MacroA a) {}
+''');
+
+    var analysisContext = contextFor(a.path);
+    var analysisDriver = driverFor(a.path);
+
+    var userErrors = analysisDriver.results
+        .whereType<ErrorsResult>()
+        .where((event) => event.path == user.path);
+
+    // We get errors when the file is added.
+    analysisDriver.addFile(user.path);
+    assertErrorsInList((await userErrors.first).errors, []);
+
+    // The macro will generate `MacroB`.
+    newFile('$testPackageLibPath/a.dart', r'''
+String getClassName() => 'MacroB';
+''');
+
+    // Notify about changes.
+    analysisContext.changeFile(a.path);
+    await analysisContext.applyPendingFileChanges();
+
+    // The change to the macro cause re-analysis of the user file.
+    assertErrorsInList((await userErrors.first).errors, [
+      error(CompileTimeErrorCode.UNDEFINED_CLASS, 55, 6),
+    ]);
+  }
+
+  test_macro_reanalyze_errors_changeCodeUsedByMacro_part() async {
+    final a = newFile('$testPackageLibPath/a.dart', r'''
+part of 'my_macro.dart';
+String getClassName() => 'MacroA';
+''');
+
+    newFile('$testPackageLibPath/my_macro.dart', r'''
+import 'package:_fe_analyzer_shared/src/macros/api.dart';
+part 'a.dart';
+
+macro class MyMacro implements ClassTypesMacro {
+  const MyMacro();
+
+  buildTypesForClass(clazz, builder) {
+    final className = getClassName();
+    builder.declareType(
+      '$className',
+      DeclarationCode.fromString('class $className {}'),
+    );
+  }
+}
+''');
+
+    var user = newFile('$testPackageLibPath/user.dart', r'''
+import 'my_macro.dart';
+
+@MyMacro()
+class A {}
+
+void f(MacroA a) {}
+''');
+
+    var analysisContext = contextFor(a.path);
+    var analysisDriver = driverFor(a.path);
+
+    var userErrors = analysisDriver.results
+        .whereType<ErrorsResult>()
+        .where((event) => event.path == user.path);
+
+    // We get errors when the file is added.
+    analysisDriver.addFile(user.path);
+    assertErrorsInList((await userErrors.first).errors, []);
+
+    // The macro will generate `MacroB`.
+    newFile('$testPackageLibPath/a.dart', r'''
+part of 'my_macro.dart';
+String getClassName() => 'MacroB';
+''');
+
+    // Notify about changes.
+    analysisContext.changeFile(a.path);
+    await analysisContext.applyPendingFileChanges();
+
+    // The change to the macro cause re-analysis of the user file.
+    assertErrorsInList((await userErrors.first).errors, [
+      error(CompileTimeErrorCode.UNDEFINED_CLASS, 55, 6),
+    ]);
+  }
+
+  test_macro_reanalyze_errors_changeMacroCode() async {
+    var macroFile = _newFileWithFixedNameMacro('MacroA');
+
+    var user = newFile('$testPackageLibPath/user.dart', r'''
+import 'my_macro.dart';
+
+@MyMacro()
+class A {}
+
+void f(MacroA a) {}
+''');
+
+    var analysisContext = contextFor(user.path);
+    var analysisDriver = driverFor(user.path);
+
+    var userErrors = analysisDriver.results
+        .whereType<ErrorsResult>()
+        .where((event) => event.path == user.path);
+
+    // We get errors when the file is added.
+    analysisDriver.addFile(user.path);
+    assertErrorsInList((await userErrors.first).errors, []);
+
+    // The macro will generate `MacroB`.
+    _newFileWithFixedNameMacro('MacroB');
+
+    // Notify about changes.
+    analysisContext.changeFile(macroFile.path);
+    await analysisContext.applyPendingFileChanges();
+
+    // The change to the macro cause re-analysis of the user file.
+    assertErrorsInList((await userErrors.first).errors, [
+      error(CompileTimeErrorCode.UNDEFINED_CLASS, 55, 6),
+    ]);
+  }
+
   test_macro_resolvedUnit_changeCodeUsedByMacro() async {
     final a = newFile('$testPackageLibPath/a.dart', r'''
 String getClassName() => 'MacroA';
@@ -479,53 +616,6 @@
     ]);
   }
 
-  test_macro_resolvedUnit_changeMacroCode() async {
-    File newFileWithFixedNameMacro(String className) {
-      return newFile('$testPackageLibPath/my_macro.dart', '''
-import 'dart:async';
-import 'package:_fe_analyzer_shared/src/macros/api.dart';
-
-macro class MyMacro implements ClassTypesMacro {
-  const MyMacro();
-
-  FutureOr<void> buildTypesForClass(clazz, builder) {
-    builder.declareType(
-      '$className',
-      DeclarationCode.fromString('class $className {}'),
-    );
-  }
-}
-''');
-    }
-
-    var macroFile = newFileWithFixedNameMacro('MacroA');
-
-    // The macro will generate `MacroA`, so no errors.
-    await assertNoErrorsInCode('''
-import 'my_macro.dart';
-
-@MyMacro()
-class A {}
-
-void f(MacroA a) {}
-''');
-
-    // The macro will generate `MacroB`.
-    newFileWithFixedNameMacro('MacroB');
-
-    // Notify about changes.
-    var analysisContext = contextFor(macroFile.path);
-    analysisContext.changeFile(macroFile.path);
-    await analysisContext.applyPendingFileChanges();
-
-    // Resolve the test file, it still references `MacroA`, but the updated
-    // macro generates `MacroB` now, so we have an error.
-    await resolveTestFile();
-    assertErrorsInResult([
-      error(CompileTimeErrorCode.UNDEFINED_CLASS, 55, 6),
-    ]);
-  }
-
   void _assertContainsLinkedCycle(Set<String> expectedPosix,
       {bool andClear = false}) {
     var expected = expectedPosix.map(convertPath).toSet();
@@ -560,6 +650,23 @@
         .getErrors(testFilePathConverted) as ErrorsResult;
     return errorsResult.errors;
   }
+
+  File _newFileWithFixedNameMacro(String className) {
+    return newFile('$testPackageLibPath/my_macro.dart', '''
+import 'package:_fe_analyzer_shared/src/macros/api.dart';
+
+macro class MyMacro implements ClassTypesMacro {
+  const MyMacro();
+
+  buildTypesForClass(clazz, builder) {
+    builder.declareType(
+      '$className',
+      DeclarationCode.fromString('class $className {}'),
+    );
+  }
+}
+''');
+  }
 }
 
 extension on AnalysisDriver {
diff --git a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
index 7fe7d8e..c789b2e 100644
--- a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
@@ -744,8 +744,8 @@
     newFile(path, r'''
 class B {}
 ''');
-    bool apiSignatureChanged = file.refresh();
-    expect(apiSignatureChanged, isTrue);
+    final changeKind = file.refresh();
+    expect(changeKind, FileStateRefreshResult.apiChanged);
 
     expect(file.definedTopLevelNames, contains('B'));
     expect(file.apiSignature, isNot(signature));
@@ -771,8 +771,8 @@
   }
 }
 ''');
-    bool apiSignatureChanged = file.refresh();
-    expect(apiSignatureChanged, isFalse);
+    final changeKind = file.refresh();
+    expect(changeKind, FileStateRefreshResult.contentChanged);
 
     expect(file.apiSignature, signature);
   }
diff --git a/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart b/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
index 2aac19c..48deb10 100644
--- a/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
+++ b/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
@@ -88,8 +88,13 @@
   }
 
   void test_visitAwaitExpression() {
-    _assertSource("await e",
-        AstTestFactory.awaitExpression(AstTestFactory.identifier3("e")));
+    var findNode = _parseStringToFindNode(r'''
+void f() async => await e;
+''');
+    _assertSource(
+      'await e',
+      findNode.awaitExpression('await e'),
+    );
   }
 
   void test_visitBinaryExpression() {
diff --git a/pkg/compiler/lib/src/common/names.dart b/pkg/compiler/lib/src/common/names.dart
index ce905a1..024be8a 100644
--- a/pkg/compiler/lib/src/common/names.dart
+++ b/pkg/compiler/lib/src/common/names.dart
@@ -2,8 +2,6 @@
 // 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.
 
-// @dart = 2.10
-
 /// Library containing identifier, names, and selectors commonly used through
 /// the compiler.
 library dart2js.common.names;
diff --git a/pkg/compiler/lib/src/elements/entities.dart b/pkg/compiler/lib/src/elements/entities.dart
index f4fc4e2..737b529 100644
--- a/pkg/compiler/lib/src/elements/entities.dart
+++ b/pkg/compiler/lib/src/elements/entities.dart
@@ -8,6 +8,7 @@
 
 // TODO(48820): Spannable was imported from `../common.dart`.
 import '../diagnostics/spannable.dart' show Spannable;
+import '../universe/call_structure.dart' show CallStructure;
 import '../util/util.dart';
 import 'names.dart';
 
@@ -66,6 +67,10 @@
 /// Currently only [ClassElement] but later also kernel based Dart classes
 /// and/or Dart-in-JS classes.
 abstract class ClassEntity extends Entity {
+  /// Classes always have a name.
+  @override
+  String get name;
+
   /// If this is a normal class, the enclosing library for this class. If this
   /// is a closure class, the enclosing class of the closure for which it was
   /// created.
@@ -351,8 +356,11 @@
   /// The total number of parameters (required or optional).
   int get totalParameters => positionalParameters + namedParameters.length;
 
-  // TODO(48820): Move definition back here:
-  // CallStructure get callStructure;
+  /// Returns the [CallStructure] corresponding to a call site passing all
+  /// parameters both required and optional.
+  CallStructure get callStructure {
+    return CallStructure(totalParameters, namedParameters, typeParameters);
+  }
 
   @override
   int get hashCode => Hashing.listHash(
diff --git a/pkg/compiler/lib/src/elements/entities_parameter_structure_methods.dart b/pkg/compiler/lib/src/elements/entities_parameter_structure_methods.dart
index a7f4702..bf75cbe 100644
--- a/pkg/compiler/lib/src/elements/entities_parameter_structure_methods.dart
+++ b/pkg/compiler/lib/src/elements/entities_parameter_structure_methods.dart
@@ -10,17 +10,10 @@
 library entities.parameter_structure_methods;
 
 import '../serialization/serialization.dart';
-import '../universe/call_structure.dart' show CallStructure;
 import 'entities.dart';
 import 'types.dart' show FunctionType;
 
 extension UnmigratedParameterStructureInstanceMethods on ParameterStructure {
-  /// Returns the [CallStructure] corresponding to a call site passing all
-  /// parameters both required and optional.
-  CallStructure get callStructure {
-    return CallStructure(totalParameters, namedParameters, typeParameters);
-  }
-
   /// Serializes this [ParameterStructure] to [sink].
   void writeToDataSink(DataSinkWriter sink) {
     final tag = ParameterStructure.tag;
diff --git a/pkg/compiler/lib/src/elements/entity_utils.dart b/pkg/compiler/lib/src/elements/entity_utils.dart
index dc5b5e0..ee1a37b 100644
--- a/pkg/compiler/lib/src/elements/entity_utils.dart
+++ b/pkg/compiler/lib/src/elements/entity_utils.dart
@@ -2,14 +2,11 @@
 // 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.
 
-// @dart = 2.10
-
 library entity_utils;
 
 import 'package:front_end/src/api_unstable/dart2js.dart'
     show isUserDefinableOperator, isMinusOperator;
 
-import '../js_backend/namer.dart';
 import 'entities.dart' show Entity, FunctionEntity;
 
 // Somewhat stable ordering for libraries using [Uri]s
@@ -67,8 +64,8 @@
 }
 
 /// Compare entities within the same compilation unit.
-int compareEntities(Entity element1, int line1, int column1, Entity element2,
-    int line2, int column2) {
+int compareEntities(Entity element1, int? line1, int? column1, Entity element2,
+    int? line2, int? column2) {
   line1 ??= -1;
   line2 ??= -1;
   int r = line1.compareTo(line2);
@@ -79,7 +76,7 @@
   r = column1.compareTo(column2);
   if (r != 0) return r;
 
-  r = element1.name.compareTo(element2.name);
+  r = element1.name!.compareTo(element2.name!);
   if (r != 0) return r;
 
   // Same file, position and name.  If this happens, we should find out why
@@ -88,7 +85,7 @@
 }
 
 String reconstructConstructorName(FunctionEntity element) {
-  String className = element.enclosingClass.name;
+  String className = element.enclosingClass!.name;
   if (element.name == '') {
     return className;
   } else {
@@ -98,7 +95,7 @@
 
 String reconstructConstructorNameSourceString(FunctionEntity element) {
   if (element.name == '') {
-    return element.enclosingClass.name;
+    return element.enclosingClass!.name;
   } else {
     return reconstructConstructorName(element);
   }
@@ -114,9 +111,9 @@
 // TODO(sra): The namer uses another, different, version of this function. Make
 // it clearer that this function is not used for JavaScript naming, but is
 // useful in creating identifiers for other purposes like data formats for file
-// names.  Break the connection to Namer.  Rename this function and move it to a
-// more general String utils place.
-String operatorNameToIdentifier(String name) {
+// names.  Rename this function and move it to a more general String utils
+// place.
+String? operatorNameToIdentifier(String? name) {
   if (name == null) {
     return name;
   } else if (name == '==') {
@@ -162,11 +159,13 @@
   } else if (name == 'unary-') {
     return r'operator$negate';
   } else {
-    return Namer.replaceNonIdentifierCharacters(name);
+    return name.replaceAll(_nonIdentifierRE, '_');
   }
 }
 
-String constructOperatorNameOrNull(String op, bool isUnary) {
+final RegExp _nonIdentifierRE = RegExp(r'[^A-Za-z0-9_$]');
+
+String? constructOperatorNameOrNull(String op, bool isUnary) {
   if (isMinusOperator(op)) {
     return isUnary ? 'unary-' : op;
   } else if (isUserDefinableOperator(op) || op == '??') {
@@ -177,7 +176,7 @@
 }
 
 String constructOperatorName(String op, bool isUnary) {
-  String operatorName = constructOperatorNameOrNull(op, isUnary);
+  String? operatorName = constructOperatorNameOrNull(op, isUnary);
   if (operatorName == null)
     throw 'Unhandled operator: $op';
   else
diff --git a/pkg/compiler/lib/src/js_backend/codegen_listener.dart b/pkg/compiler/lib/src/js_backend/codegen_listener.dart
index d2d4aa2..6682b3e 100644
--- a/pkg/compiler/lib/src/js_backend/codegen_listener.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen_listener.dart
@@ -12,7 +12,6 @@
 import '../common/names.dart' show Identifiers;
 import '../constants/values.dart';
 import '../elements/entities.dart';
-import '../elements/entities_parameter_structure_methods.dart';
 import '../elements/types.dart';
 import '../enqueue.dart' show Enqueuer, EnqueuerListener;
 import '../native/enqueue.dart';
diff --git a/pkg/compiler/lib/src/js_backend/resolution_listener.dart b/pkg/compiler/lib/src/js_backend/resolution_listener.dart
index c6b8b41..12113ce 100644
--- a/pkg/compiler/lib/src/js_backend/resolution_listener.dart
+++ b/pkg/compiler/lib/src/js_backend/resolution_listener.dart
@@ -11,7 +11,6 @@
 import '../constants/values.dart';
 import '../deferred_load/deferred_load.dart';
 import '../elements/entities.dart';
-import '../elements/entities_parameter_structure_methods.dart';
 import '../elements/types.dart';
 import '../enqueue.dart' show Enqueuer, EnqueuerListener;
 import '../native/enqueue.dart';
diff --git a/pkg/compiler/lib/src/kernel/invocation_mirror_constants.dart b/pkg/compiler/lib/src/kernel/invocation_mirror_constants.dart
index 1d24a30..246429e 100644
--- a/pkg/compiler/lib/src/kernel/invocation_mirror_constants.dart
+++ b/pkg/compiler/lib/src/kernel/invocation_mirror_constants.dart
@@ -2,8 +2,6 @@
 // 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.
 
-// @dart=2.12
-
 const int invocationMirrorMethodKind = 0;
 const int invocationMirrorGetterKind = 1;
 const int invocationMirrorSetterKind = 2;
diff --git a/pkg/compiler/lib/src/serialization/serialization.dart b/pkg/compiler/lib/src/serialization/serialization.dart
index 016192a..26a8468 100644
--- a/pkg/compiler/lib/src/serialization/serialization.dart
+++ b/pkg/compiler/lib/src/serialization/serialization.dart
@@ -24,6 +24,9 @@
 import '../js_model/locals.dart';
 import '../js_model/type_recipe.dart' show TypeRecipe;
 
+import 'serialization_interfaces.dart' as migrated
+    show DataSourceReader, DataSinkWriter;
+
 part 'sink.dart';
 part 'source.dart';
 part 'binary_sink.dart';
diff --git a/pkg/compiler/lib/src/serialization/serialization_interfaces.dart b/pkg/compiler/lib/src/serialization/serialization_interfaces.dart
new file mode 100644
index 0000000..4f241ec
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/serialization_interfaces.dart
@@ -0,0 +1,81 @@
+// Copyright (c) 2022, 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 '../elements/entities.dart';
+
+/// NNBD-migrated interface for methods of DataSinkWriter.
+///
+/// This is a pure interface or facade for DataSinkWriter.
+///
+/// This interface has the same name as the implementation class. Using the same
+/// name allows some libraries that use DataSinkWriter to be migrated before the
+/// serialization library by changing
+///
+///     import '../serialization/serialization.dart';
+///
+/// to:
+///
+///     import '../serialization/serialization_interfaces.dart';
+///
+/// Documentation of the methods can be found in source.dart.
+// TODO(sra): Copy documentation for methods?
+abstract class DataSinkWriter {
+  void begin(String tag);
+  void end(Object tag);
+
+  void writeBool(bool value);
+  void writeInt(int value);
+  void writeIntOrNull(int? value);
+  void writeString(String value);
+  void writeStringOrNull(String? value);
+  void writeStringMap<V>(Map<String, V>? map, void f(V value),
+      {bool allowNull = false});
+  void writeStrings(Iterable<String>? values, {bool allowNull = false});
+  void writeEnum(dynamic value);
+  void writeUri(Uri value);
+
+  // TODO(48820): 'covariant ClassEntity' is used below because the
+  // implementation takes IndexedClass. What this means is that in pre-NNBD
+  // code, the call site to the implementation DataSinkWriter has an implicit
+  // downcast from ClassEntity to IndexedClass. With NNND, these casts become
+  // explicit and quite tedious. It is cleaner to move the cast into the method,
+  // which is what 'covariant' achieves.
+  //
+  // If we want to retire this facade interface, we will have to make the
+  // DataSinkWriter implementation accept ClassEntity and manually check for
+  // IndexedClass. This is not necessarily a bad thing, since it opens the way
+  // for being able to serialize some non-indexed entities.
+
+  void writeClass(covariant ClassEntity value); // IndexedClass
+  void writeClassOrNull(covariant ClassEntity? value); // IndexedClass
+  void writeTypeVariable(
+      covariant TypeVariableEntity value); // IndexedTypeVariable
+
+  void writeLibrary(covariant LibraryEntity value); // IndexedLibrary
+  void writeLibraryOrNull(covariant LibraryEntity? value); // IndexedLibrary
+
+}
+
+/// Migrated interface for methods of DataSourceReader.
+abstract class DataSourceReader {
+  void begin(String tag);
+  void end(String tag);
+
+  bool readBool();
+  int readInt();
+  int? readIntOrNull();
+  String readString();
+  String? readStringOrNull();
+  List<String>? readStrings({bool emptyAsNull = false});
+  Map<String, V>? readStringMap<V>(V f(), {bool emptyAsNull = false});
+  E readEnum<E>(List<E> values);
+  Uri readUri();
+
+  ClassEntity readClass(); // IndexedClass
+  ClassEntity? readClassOrNull(); // IndexedClass
+  TypeVariableEntity readTypeVariable(); // IndexedTypeVariable
+
+  LibraryEntity readLibrary(); // IndexedLibrary;
+  LibraryEntity? readLibraryOrNull(); // IndexedLibrary;
+}
diff --git a/pkg/compiler/lib/src/serialization/sink.dart b/pkg/compiler/lib/src/serialization/sink.dart
index e7dfec8..b70e081 100644
--- a/pkg/compiler/lib/src/serialization/sink.dart
+++ b/pkg/compiler/lib/src/serialization/sink.dart
@@ -36,7 +36,7 @@
 ///
 /// To be used with [DataSourceReader] to read and write serialized data.
 /// Serialization format is deferred to provided [DataSink].
-class DataSinkWriter {
+class DataSinkWriter implements migrated.DataSinkWriter {
   final DataSink _sinkWriter;
 
   /// If `true`, serialization of every data kind is preceded by a [DataKind]
@@ -108,6 +108,7 @@
   ///
   /// This is used for debugging to verify that sections are correctly aligned
   /// between serialization and deserialization.
+  @override
   void begin(String tag) {
     if (tagFrequencyMap != null) {
       tagFrequencyMap[tag] ??= 0;
@@ -120,10 +121,11 @@
     }
   }
 
-  /// Registers that the section [tag] starts.
+  /// Registers that the section [tag] ends.
   ///
   /// This is used for debugging to verify that sections are correctly aligned
   /// between serialization and deserialization.
+  @override
   void end(Object tag) {
     if (useDataKinds) {
       _sinkWriter.endTag(tag);
@@ -170,6 +172,7 @@
   }
 
   /// Writes the boolean [value] to this data sink.
+  @override
   void writeBool(bool value) {
     assert(value != null);
     _writeDataKind(DataKind.bool);
@@ -181,6 +184,7 @@
   }
 
   /// Writes the non-negative 30 bit integer [value] to this data sink.
+  @override
   void writeInt(int value) {
     assert(value != null);
     assert(value >= 0 && value >> 30 == 0);
@@ -192,6 +196,7 @@
   ///
   /// This is a convenience method to be used together with
   /// [DataSourceReader.readIntOrNull].
+  @override
   void writeIntOrNull(int value) {
     writeBool(value != null);
     if (value != null) {
@@ -200,6 +205,7 @@
   }
 
   /// Writes the string [value] to this data sink.
+  @override
   void writeString(String value) {
     assert(value != null);
     _writeDataKind(DataKind.string);
@@ -214,6 +220,7 @@
   ///
   /// This is a convenience method to be used together with
   /// [DataSourceReader.readStringOrNull].
+  @override
   void writeStringOrNull(String value) {
     writeBool(value != null);
     if (value != null) {
@@ -227,6 +234,7 @@
   ///
   /// This is a convenience method to be used together with
   /// [DataSourceReader.readStringMap].
+  @override
   void writeStringMap<V>(Map<String, V> map, void f(V value),
       {bool allowNull = false}) {
     if (map == null) {
@@ -246,6 +254,7 @@
   ///
   /// This is a convenience method to be used together with
   /// [DataSourceReader.readStrings].
+  @override
   void writeStrings(Iterable<String> values, {bool allowNull = false}) {
     if (values == null) {
       assert(allowNull);
@@ -262,12 +271,14 @@
   // TODO(johnniwinther): Change the signature to
   // `void writeEnum<E extends Enum<E>>(E value);` when an interface for enums
   // is added to the language.
+  @override
   void writeEnum(dynamic value) {
     _writeDataKind(DataKind.enumValue);
     _sinkWriter.writeEnum(value);
   }
 
   /// Writes the URI [value] to this data sink.
+  @override
   void writeUri(Uri value) {
     assert(value != null);
     _writeDataKind(DataKind.uri);
@@ -676,6 +687,7 @@
   }
 
   /// Writes a reference to the indexed library [value] to this data sink.
+  @override
   void writeLibrary(IndexedLibrary value) {
     _entityWriter.writeLibraryToDataSink(this, value);
   }
@@ -685,6 +697,7 @@
   ///
   /// This is a convenience method to be used together with
   /// [DataSourceReader.readLibraryOrNull].
+  @override
   void writeLibraryOrNull(IndexedLibrary value) {
     writeBool(value != null);
     if (value != null) {
@@ -713,6 +726,7 @@
   }
 
   /// Writes a reference to the indexed class [value] to this data sink.
+  @override
   void writeClass(IndexedClass value) {
     _entityWriter.writeClassToDataSink(this, value);
   }
@@ -722,6 +736,7 @@
   ///
   /// This is a convenience method to be used together with
   /// [DataSourceReader.readClassOrNull].
+  @override
   void writeClassOrNull(IndexedClass value) {
     writeBool(value != null);
     if (value != null) {
@@ -822,6 +837,7 @@
   }
 
   /// Writes a reference to the indexed type variable [value] to this data sink.
+  @override
   void writeTypeVariable(IndexedTypeVariable value) {
     _entityWriter.writeTypeVariableToDataSink(this, value);
   }
diff --git a/pkg/compiler/lib/src/serialization/source.dart b/pkg/compiler/lib/src/serialization/source.dart
index 3d34dce..a81a4c9 100644
--- a/pkg/compiler/lib/src/serialization/source.dart
+++ b/pkg/compiler/lib/src/serialization/source.dart
@@ -36,7 +36,7 @@
 ///
 /// To be used with [DataSinkWriter] to read and write serialized data.
 /// Deserialization format is deferred to provided [DataSource].
-class DataSourceReader {
+class DataSourceReader implements migrated.DataSourceReader {
   final DataSource _sourceReader;
 
   static final List<ir.DartType> emptyListOfDartTypes =
@@ -102,6 +102,7 @@
   ///
   /// This is used for debugging to verify that sections are correctly aligned
   /// between serialization and deserialization.
+  @override
   void begin(String tag) {
     if (useDataKinds) _sourceReader.begin(tag);
   }
@@ -110,6 +111,7 @@
   ///
   /// This is used for debugging to verify that sections are correctly aligned
   /// between serialization and deserialization.
+  @override
   void end(String tag) {
     if (useDataKinds) _sourceReader.end(tag);
   }
@@ -226,6 +228,7 @@
     return list;
   }
 
+  @override
   bool readBool() {
     _checkDataKind(DataKind.bool);
     return _readBool();
@@ -239,6 +242,7 @@
   }
 
   /// Reads a non-negative 30 bit integer value from this data source.
+  @override
   int readInt() {
     _checkDataKind(DataKind.uint30);
     return _sourceReader.readInt();
@@ -249,6 +253,7 @@
   ///
   /// This is a convenience method to be used together with
   /// [DataSinkWriter.writeIntOrNull].
+  @override
   int readIntOrNull() {
     bool hasValue = readBool();
     if (hasValue) {
@@ -258,6 +263,7 @@
   }
 
   /// Reads a string value from this data source.
+  @override
   String readString() {
     _checkDataKind(DataKind.string);
     return _readString();
@@ -271,6 +277,7 @@
   ///
   /// This is a convenience method to be used together with
   /// [DataSinkWriter.writeStringOrNull].
+  @override
   String readStringOrNull() {
     bool hasValue = readBool();
     if (hasValue) {
@@ -284,6 +291,7 @@
   ///
   /// This is a convenience method to be used together with
   /// [DataSinkWriter.writeStrings].
+  @override
   List<String> readStrings({bool emptyAsNull = false}) {
     int count = readInt();
     if (count == 0 && emptyAsNull) return null;
@@ -300,6 +308,7 @@
   ///
   /// This is a convenience method to be used together with
   /// [DataSinkWriter.writeStringMap].
+  @override
   Map<String, V> readStringMap<V>(V f(), {bool emptyAsNull = false}) {
     int count = readInt();
     if (count == 0 && emptyAsNull) return null;
@@ -321,12 +330,14 @@
   ///    ...
   ///    Foo foo = source.readEnum(Foo.values);
   ///
+  @override
   E readEnum<E>(List<E> values) {
     _checkDataKind(DataKind.enumValue);
     return _sourceReader.readEnum(values);
   }
 
   /// Reads a URI value from this data source.
+  @override
   Uri readUri() {
     _checkDataKind(DataKind.uri);
     return _readUri();
@@ -814,12 +825,14 @@
   }
 
   /// Reads a reference to an indexed library from this data source.
+  @override
   IndexedLibrary readLibrary() {
     return _entityReader.readLibraryFromDataSource(this, entityLookup);
   }
 
   /// Reads a reference to a potentially `null` indexed library from this data
   /// source.
+  @override
   IndexedLibrary readLibraryOrNull() {
     bool hasValue = readBool();
     if (hasValue) {
@@ -849,12 +862,14 @@
   }
 
   /// Reads a reference to an indexed class from this data source.
+  @override
   IndexedClass readClass() {
     return _entityReader.readClassFromDataSource(this, entityLookup);
   }
 
   /// Reads a reference to a potentially `null` indexed class from this data
   /// source.
+  @override
   IndexedClass readClassOrNull() {
     bool hasClass = readBool();
     if (hasClass) {
@@ -958,6 +973,7 @@
   }
 
   /// Reads a reference to an indexed type variable from this data source.
+  @override
   IndexedTypeVariable readTypeVariable() {
     return _entityReader.readTypeVariableFromDataSource(this, entityLookup);
   }
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index 75f9512..a0ab430 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -12,7 +12,6 @@
 import '../constants/constant_system.dart' as constant_system;
 import '../constants/values.dart';
 import '../elements/entities.dart';
-import '../elements/entities_parameter_structure_methods.dart';
 import '../elements/types.dart';
 import '../inferrer/abstract_value_domain.dart';
 import '../inferrer/types.dart';
diff --git a/pkg/compiler/lib/src/universe/call_structure.dart b/pkg/compiler/lib/src/universe/call_structure.dart
index 84a10cb..448ad06 100644
--- a/pkg/compiler/lib/src/universe/call_structure.dart
+++ b/pkg/compiler/lib/src/universe/call_structure.dart
@@ -2,13 +2,11 @@
 // 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.
 
-// @dart = 2.10
-
 library dart2js.call_structure;
 
 import '../common/names.dart' show Names;
 import '../elements/entities.dart' show ParameterStructure;
-import '../serialization/serialization.dart';
+import '../serialization/serialization_interfaces.dart';
 import '../util/util.dart';
 import 'selector.dart' show Selector;
 
@@ -75,7 +73,7 @@
   }
 
   factory CallStructure(int argumentCount,
-      [List<String> namedArguments, int typeArgumentCount = 0]) {
+      [List<String>? namedArguments, int typeArgumentCount = 0]) {
     if (namedArguments == null || namedArguments.isEmpty) {
       return CallStructure.unnamed(argumentCount, typeArgumentCount);
     }
@@ -87,7 +85,7 @@
   factory CallStructure.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     int argumentCount = source.readInt();
-    List<String> namedArguments = source.readStrings() /*!*/;
+    List<String> namedArguments = source.readStrings()!;
     int typeArgumentCount = source.readInt();
     source.end(tag);
     return CallStructure(argumentCount, namedArguments, typeArgumentCount);
@@ -245,7 +243,7 @@
   final List<String> namedArguments;
 
   /// The list of ordered named arguments is computed lazily. Initially `null`.
-  List<String> /*?*/ _orderedNamedArguments;
+  List<String>? _orderedNamedArguments;
 
   _NamedCallStructure(int argumentCount, this.namedArguments,
       int typeArgumentCount, this._orderedNamedArguments)
diff --git a/pkg/compiler/lib/src/universe/selector.dart b/pkg/compiler/lib/src/universe/selector.dart
index 26ac29a..fa927f4 100644
--- a/pkg/compiler/lib/src/universe/selector.dart
+++ b/pkg/compiler/lib/src/universe/selector.dart
@@ -2,19 +2,16 @@
 // 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.
 
-// @dart = 2.10
-
 library dart2js.selector;
 
 import '../common.dart';
 import '../common/names.dart' show Names;
 import '../elements/entities.dart';
-import '../elements/entities_parameter_structure_methods.dart';
 import '../elements/entity_utils.dart' as utils;
 import '../elements/names.dart';
 import '../elements/operators.dart';
 import '../kernel/invocation_mirror_constants.dart';
-import '../serialization/serialization.dart';
+import '../serialization/serialization_interfaces.dart';
 import '../util/util.dart' show Hashing;
 import 'call_structure.dart' show CallStructure;
 
@@ -66,7 +63,7 @@
 
   String get name => memberName.text;
 
-  LibraryEntity get library => memberName.library;
+  LibraryEntity? get library => memberName.library;
 
   static bool isOperatorName(String name) {
     return instanceMethodOperatorNames.contains(name);
@@ -102,6 +99,10 @@
       Map<int, List<Selector>>();
 
   factory Selector(SelectorKind kind, Name name, CallStructure callStructure) {
+    // TODO(48820): Remove this check when callers are migrated.
+    if ((callStructure as dynamic) == null) {
+      throw ArgumentError('callStructure is null');
+    }
     // TODO(johnniwinther): Maybe use equality instead of implicit hashing.
     int hashCode = computeHashCode(kind, name, callStructure);
     List<Selector> list = canonicalizedValues.putIfAbsent(hashCode, () => []);
@@ -120,14 +121,14 @@
   factory Selector.fromElement(MemberEntity element) {
     Name name = element.memberName;
     if (element.isFunction) {
-      FunctionEntity function = element;
+      FunctionEntity function = element as FunctionEntity;
       if (name == Names.INDEX_NAME) {
         return Selector.index();
       } else if (name == Names.INDEX_SET_NAME) {
         return Selector.indexSet();
       }
       CallStructure callStructure = function.parameterStructure.callStructure;
-      if (isOperatorName(element.name)) {
+      if (isOperatorName(element.name!)) {
         // Operators cannot have named arguments, however, that doesn't prevent
         // a user from declaring such an operator.
         return Selector(SelectorKind.OPERATOR, name, callStructure);
@@ -173,7 +174,7 @@
       Selector(SelectorKind.CALL, name, callStructure);
 
   factory Selector.callClosure(int arity,
-          [List<String> namedArguments, int typeArgumentCount = 0]) =>
+          [List<String>? namedArguments, int typeArgumentCount = 0]) =>
       Selector(SelectorKind.CALL, Names.call,
           CallStructure(arity, namedArguments, typeArgumentCount));
 
@@ -181,7 +182,7 @@
       Selector(SelectorKind.CALL, Names.call, selector.callStructure);
 
   factory Selector.callConstructor(Name name,
-          [int arity = 0, List<String> namedArguments]) =>
+          [int arity = 0, List<String>? namedArguments]) =>
       Selector(SelectorKind.CALL, name, CallStructure(arity, namedArguments));
 
   factory Selector.callDefaultConstructor() =>
@@ -198,7 +199,7 @@
     source.begin(tag);
     SelectorKind kind = source.readEnum(SelectorKind.values);
     bool isSetter = source.readBool();
-    LibraryEntity library = source.readLibraryOrNull();
+    LibraryEntity? library = source.readLibraryOrNull();
     String text = source.readString();
     CallStructure callStructure = CallStructure.readFromDataSource(source);
     source.end(tag);
@@ -255,7 +256,7 @@
     }
     if (isGetter) return true;
     if (isSetter) return false;
-    return signatureApplies(element);
+    return signatureApplies(element as FunctionEntity);
   }
 
   /// Whether [this] could be a valid selector on `Null` without throwing.
diff --git a/pkg/compiler/lib/src/universe/use.dart b/pkg/compiler/lib/src/universe/use.dart
index f8861b1..9ddd60d 100644
--- a/pkg/compiler/lib/src/universe/use.dart
+++ b/pkg/compiler/lib/src/universe/use.dart
@@ -22,7 +22,6 @@
 import '../constants/values.dart';
 import '../elements/types.dart';
 import '../elements/entities.dart';
-import '../elements/entities_parameter_structure_methods.dart';
 import '../inferrer/abstract_value_domain.dart';
 import '../serialization/serialization.dart';
 import '../js_model/closure.dart';
diff --git a/pkg/compiler/test/generic_methods/generic_method_type_test.dart b/pkg/compiler/test/generic_methods/generic_method_type_test.dart
index 0d30632..6b2708d 100644
--- a/pkg/compiler/test/generic_methods/generic_method_type_test.dart
+++ b/pkg/compiler/test/generic_methods/generic_method_type_test.dart
@@ -7,7 +7,6 @@
 import 'package:async_helper/async_helper.dart';
 import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/elements/entities.dart';
-import 'package:compiler/src/elements/entities_parameter_structure_methods.dart';
 import 'package:compiler/src/elements/types.dart';
 import 'package:compiler/src/universe/call_structure.dart';
 import 'package:expect/expect.dart';
diff --git a/pkg/compiler/test/model/enqueuer_test.dart b/pkg/compiler/test/model/enqueuer_test.dart
index c3a7b5f..ac2f0c3 100644
--- a/pkg/compiler/test/model/enqueuer_test.dart
+++ b/pkg/compiler/test/model/enqueuer_test.dart
@@ -12,7 +12,6 @@
 import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/elements/entities.dart';
-import 'package:compiler/src/elements/entities_parameter_structure_methods.dart';
 import 'package:compiler/src/elements/names.dart';
 import 'package:compiler/src/elements/types.dart';
 import 'package:compiler/src/enqueue.dart';
diff --git a/pkg/dart2wasm/lib/code_generator.dart b/pkg/dart2wasm/lib/code_generator.dart
index 2489dfb..821c38f 100644
--- a/pkg/dart2wasm/lib/code_generator.dart
+++ b/pkg/dart2wasm/lib/code_generator.dart
@@ -116,30 +116,14 @@
     unimplemented(node, node.runtimeType, const []);
   }
 
-  /// Generate code for the body of the member.
+  /// Generate code for the member.
   void generate() {
     closures = Closures(this);
 
     Member member = this.member;
 
     if (reference.isTearOffReference) {
-      // Tear-off getter
-      w.DefinedFunction closureFunction =
-          translator.getTearOffFunction(member as Procedure);
-
-      int parameterCount = member.function.requiredParameterCount;
-      w.DefinedGlobal global = translator.makeFunctionRef(closureFunction);
-
-      ClassInfo info = translator.classInfo[translator.functionClass]!;
-      translator.functions.allocateClass(info.classId);
-
-      b.i32_const(info.classId);
-      b.i32_const(initialIdentityHash);
-      b.local_get(paramLocals[0]);
-      b.global_get(global);
-      translator.struct_new(b, parameterCount);
-      b.end();
-      return;
+      return generateTearOffGetter(member as Procedure);
     }
 
     if (intrinsifier.generateMemberIntrinsic(
@@ -160,57 +144,84 @@
 
     if (member is Field) {
       if (member.isStatic) {
-        // Static field initializer function
-        assert(reference == member.fieldReference);
-        closures.findCaptures(member);
-        closures.collectContexts(member);
-        closures.buildContexts();
-
-        w.Global global = translator.globals.getGlobal(member);
-        w.Global? flag = translator.globals.getGlobalInitializedFlag(member);
-        wrap(member.initializer!, global.type.type);
-        b.global_set(global);
-        if (flag != null) {
-          b.i32_const(1);
-          b.global_set(flag);
-        }
-        b.global_get(global);
-        translator.convertType(
-            function, global.type.type, function.type.outputs.single);
-        b.end();
-        return;
-      }
-
-      // Implicit getter or setter
-      w.StructType struct =
-          translator.classInfo[member.enclosingClass!]!.struct;
-      int fieldIndex = translator.fieldIndex[member]!;
-      w.ValueType fieldType = struct.fields[fieldIndex].type.unpacked;
-
-      void getThis() {
-        w.Local thisLocal = paramLocals[0];
-        w.RefType structType = w.RefType.def(struct, nullable: true);
-        b.local_get(thisLocal);
-        translator.convertType(function, thisLocal.type, structType);
-      }
-
-      if (reference.isImplicitGetter) {
-        // Implicit getter
-        getThis();
-        b.struct_get(struct, fieldIndex);
-        translator.convertType(function, fieldType, returnType);
+        return generateStaticFieldInitializer(member);
       } else {
-        // Implicit setter
-        w.Local valueLocal = paramLocals[1];
-        getThis();
-        b.local_get(valueLocal);
-        translator.convertType(function, valueLocal.type, fieldType);
-        b.struct_set(struct, fieldIndex);
+        return generateImplicitAccessor(member);
       }
-      b.end();
-      return;
     }
 
+    return generateBody(member);
+  }
+
+  void generateTearOffGetter(Procedure procedure) {
+    w.DefinedFunction closureFunction =
+        translator.getTearOffFunction(procedure);
+
+    int parameterCount = procedure.function.requiredParameterCount;
+    w.DefinedGlobal global = translator.makeFunctionRef(closureFunction);
+
+    ClassInfo info = translator.classInfo[translator.functionClass]!;
+    translator.functions.allocateClass(info.classId);
+
+    b.i32_const(info.classId);
+    b.i32_const(initialIdentityHash);
+    b.local_get(paramLocals[0]);
+    b.global_get(global);
+    translator.struct_new(b, parameterCount);
+    b.end();
+  }
+
+  void generateStaticFieldInitializer(Field field) {
+    // Static field initializer function
+    assert(reference == field.fieldReference);
+    closures.findCaptures(field);
+    closures.collectContexts(field);
+    closures.buildContexts();
+
+    w.Global global = translator.globals.getGlobal(field);
+    w.Global? flag = translator.globals.getGlobalInitializedFlag(field);
+    wrap(field.initializer!, global.type.type);
+    b.global_set(global);
+    if (flag != null) {
+      b.i32_const(1);
+      b.global_set(flag);
+    }
+    b.global_get(global);
+    translator.convertType(
+        function, global.type.type, function.type.outputs.single);
+    b.end();
+  }
+
+  void generateImplicitAccessor(Field field) {
+    // Implicit getter or setter
+    w.StructType struct = translator.classInfo[field.enclosingClass!]!.struct;
+    int fieldIndex = translator.fieldIndex[field]!;
+    w.ValueType fieldType = struct.fields[fieldIndex].type.unpacked;
+
+    void getThis() {
+      w.Local thisLocal = paramLocals[0];
+      w.RefType structType = w.RefType.def(struct, nullable: true);
+      b.local_get(thisLocal);
+      translator.convertType(function, thisLocal.type, structType);
+    }
+
+    if (reference.isImplicitGetter) {
+      // Implicit getter
+      getThis();
+      b.struct_get(struct, fieldIndex);
+      translator.convertType(function, fieldType, returnType);
+    } else {
+      // Implicit setter
+      w.Local valueLocal = paramLocals[1];
+      getThis();
+      b.local_get(valueLocal);
+      translator.convertType(function, valueLocal.type, fieldType);
+      b.struct_set(struct, fieldIndex);
+    }
+    b.end();
+  }
+
+  void generateBody(Member member) {
     ParameterInfo paramInfo = translator.paramInfoFor(reference);
     bool hasThis = member.isInstanceMember || member is Constructor;
     int typeParameterOffset = hasThis ? 1 : 0;
diff --git a/pkg/front_end/test/incremental_suite.dart b/pkg/front_end/test/incremental_suite.dart
index a8394f1..d4399ff 100644
--- a/pkg/front_end/test/incremental_suite.dart
+++ b/pkg/front_end/test/incremental_suite.dart
@@ -4,6 +4,8 @@
 
 import 'dart:developer' show debugger;
 
+import 'dart:convert' show jsonDecode;
+
 import 'dart:io' show Directory, File;
 
 import 'package:_fe_analyzer_shared/src/messages/diagnostic_message.dart'
@@ -79,7 +81,15 @@
     show NameSystem, Printer, componentToString;
 
 import "package:testing/testing.dart"
-    show Chain, ChainContext, Expectation, Result, Step, TestDescription, runMe;
+    show
+        Chain,
+        ChainContext,
+        Expectation,
+        ExpectationSet,
+        Result,
+        Step,
+        TestDescription,
+        runMe;
 
 import "package:vm/target/vm.dart" show VmTarget;
 
@@ -94,44 +104,140 @@
 void main([List<String> arguments = const []]) =>
     runMe(arguments, createContext, configurationPath: "../testing.json");
 
-const Expectation ExpectationFileMismatch =
-    const Expectation.fail("ExpectationFileMismatch");
-const Expectation ExpectationFileMissing =
-    const Expectation.fail("ExpectationFileMissing");
-const Expectation MissingErrors = const Expectation.fail("MissingErrors");
-const Expectation UnexpectedErrors = const Expectation.fail("UnexpectedErrors");
-const Expectation MissingWarnings = const Expectation.fail("MissingWarnings");
-const Expectation UnexpectedWarnings =
-    const Expectation.fail("UnexpectedWarnings");
-const Expectation ClassHierarchyError =
-    const Expectation.fail("ClassHierarchyError");
-const Expectation NeededDillMismatch =
-    const Expectation.fail("NeededDillMismatch");
-const Expectation IncrementalSerializationError =
-    const Expectation.fail("IncrementalSerializationError");
-const Expectation ContentDataMismatch =
-    const Expectation.fail("ContentDataMismatch");
-const Expectation MissingInitializationError =
-    const Expectation.fail("MissingInitializationError");
-const Expectation UnexpectedInitializationError =
-    const Expectation.fail("UnexpectedInitializationError");
-const Expectation ReachableLibrariesError =
-    const Expectation.fail("ReachableLibrariesError");
-const Expectation EquivalenceError = const Expectation.fail("EquivalenceError");
-const Expectation UriToSourceError = const Expectation.fail("UriToSourceError");
-const Expectation MissingPlatformLibraries =
-    const Expectation.fail("MissingPlatformLibraries");
-const Expectation UnexpectedPlatformLibraries =
-    const Expectation.fail("UnexpectedPlatformLibraries");
-const Expectation UnexpectedRebuildBodiesOnly =
-    const Expectation.fail("UnexpectedRebuildBodiesOnly");
-const Expectation UnexpectedEntryToLibraryCount =
-    const Expectation.fail("UnexpectedEntryToLibraryCount");
-const Expectation LibraryCountMismatch =
-    const Expectation.fail("LibraryCountMismatch");
-const Expectation InitializedFromDillMismatch =
-    const Expectation.fail("InitializedFromDillMismatch");
-const Expectation NNBDModeMismatch = const Expectation.fail("NNBDModeMismatch");
+final ExpectationSet staticExpectationSet =
+    new ExpectationSet.fromJsonList(jsonDecode(EXPECTATIONS));
+
+const String EXPECTATIONS = '''
+[
+  {
+    "name": "ExpectationFileMismatch",
+    "group": "Fail"
+  },
+  {
+    "name": "ExpectationFileMissing",
+    "group": "Fail"
+  },
+  {
+    "name": "MissingErrors",
+    "group": "Fail"
+  },
+  {
+    "name": "UnexpectedErrors",
+    "group": "Fail"
+  },
+  {
+    "name": "MissingWarnings",
+    "group": "Fail"
+  },
+  {
+    "name": "UnexpectedWarnings",
+    "group": "Fail"
+  },
+  {
+    "name": "ClassHierarchyError",
+    "group": "Fail"
+  },
+  {
+    "name": "NeededDillMismatch",
+    "group": "Fail"
+  },
+  {
+    "name": "IncrementalSerializationError",
+    "group": "Fail"
+  },
+  {
+    "name": "ContentDataMismatch",
+    "group": "Fail"
+  },
+  {
+    "name": "MissingInitializationError",
+    "group": "Fail"
+  },
+  {
+    "name": "UnexpectedInitializationError",
+    "group": "Fail"
+  },
+  {
+    "name": "ReachableLibrariesError",
+    "group": "Fail"
+  },
+  {
+    "name": "EquivalenceError",
+    "group": "Fail"
+  },
+  {
+    "name": "UriToSourceError",
+    "group": "Fail"
+  },
+  {
+    "name": "MissingPlatformLibraries",
+    "group": "Fail"
+  },
+  {
+    "name": "UnexpectedPlatformLibraries",
+    "group": "Fail"
+  },
+  {
+    "name": "UnexpectedRebuildBodiesOnly",
+    "group": "Fail"
+  },
+  {
+    "name": "UnexpectedEntryToLibraryCount",
+    "group": "Fail"
+  },
+  {
+    "name": "LibraryCountMismatch",
+    "group": "Fail"
+  },
+  {
+    "name": "InitializedFromDillMismatch",
+    "group": "Fail"
+  },
+  {
+    "name": "NNBDModeMismatch",
+    "group": "Fail"
+  }
+]
+''';
+
+final Expectation ExpectationFileMismatch =
+    staticExpectationSet["ExpectationFileMismatch"];
+final Expectation ExpectationFileMissing =
+    staticExpectationSet["ExpectationFileMissing"];
+final Expectation MissingErrors = staticExpectationSet["MissingErrors"];
+final Expectation UnexpectedErrors = staticExpectationSet["UnexpectedErrors"];
+final Expectation MissingWarnings = staticExpectationSet["MissingWarnings"];
+final Expectation UnexpectedWarnings =
+    staticExpectationSet["UnexpectedWarnings"];
+final Expectation ClassHierarchyError =
+    staticExpectationSet["ClassHierarchyError"];
+final Expectation NeededDillMismatch =
+    staticExpectationSet["NeededDillMismatch"];
+final Expectation IncrementalSerializationError =
+    staticExpectationSet["IncrementalSerializationError"];
+final Expectation ContentDataMismatch =
+    staticExpectationSet["ContentDataMismatch"];
+final Expectation MissingInitializationError =
+    staticExpectationSet["MissingInitializationError"];
+final Expectation UnexpectedInitializationError =
+    staticExpectationSet["UnexpectedInitializationError"];
+final Expectation ReachableLibrariesError =
+    staticExpectationSet["ReachableLibrariesError"];
+final Expectation EquivalenceError = staticExpectationSet["EquivalenceError"];
+final Expectation UriToSourceError = staticExpectationSet["UriToSourceError"];
+final Expectation MissingPlatformLibraries =
+    staticExpectationSet["MissingPlatformLibraries"];
+final Expectation UnexpectedPlatformLibraries =
+    staticExpectationSet["UnexpectedPlatformLibraries"];
+final Expectation UnexpectedRebuildBodiesOnly =
+    staticExpectationSet["UnexpectedRebuildBodiesOnly"];
+final Expectation UnexpectedEntryToLibraryCount =
+    staticExpectationSet["UnexpectedEntryToLibraryCount"];
+final Expectation LibraryCountMismatch =
+    staticExpectationSet["LibraryCountMismatch"];
+final Expectation InitializedFromDillMismatch =
+    staticExpectationSet["InitializedFromDillMismatch"];
+final Expectation NNBDModeMismatch = staticExpectationSet["NNBDModeMismatch"];
 
 Future<Context> createContext(Chain suite, Map<String, String> environment) {
   // Disable colors to ensure that expectation files are the same across
@@ -163,6 +269,9 @@
     cleanupHelper?.outDir = null;
   }
 
+  @override
+  final ExpectationSet expectationSet = staticExpectationSet;
+
   TestData? cleanupHelper;
 }
 
diff --git a/pkg/front_end/testcases/general/async_function.dart.weak.transformed.expect b/pkg/front_end/testcases/general/async_function.dart.weak.transformed.expect
index 373a8d8..aea2b09 100644
--- a/pkg/front_end/testcases/general/async_function.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general/async_function.dart.weak.transformed.expect
@@ -121,10 +121,10 @@
             return null;
           else
             [yield] null;
-          if(:controller.{asy::_AsyncStarStreamController::addStream}(self::asyncStarString2()){(asy::Stream<core::String>) → core::bool})
+          :controller.{asy::_AsyncStarStreamController::addStream}(self::asyncStarString2()){(asy::Stream<core::String>) → void};
+          [yield] null;
+          if(_in::unsafeCast<core::bool>(:result_or_exception))
             return null;
-          else
-            [yield] null;
           [yield] let dynamic #t1 = asy::_awaitHelper(self::asyncString(), :async_op_then, :async_op_error) in null;
           if(:controller.{asy::_AsyncStarStreamController::add}(_in::unsafeCast<core::String>(:result_or_exception)){(core::String) → core::bool})
             return null;
diff --git a/pkg/front_end/testcases/general/await_complex.dart.weak.transformed.expect b/pkg/front_end/testcases/general/await_complex.dart.weak.transformed.expect
index d3d1139..7af3671 100644
--- a/pkg/front_end/testcases/general/await_complex.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general/await_complex.dart.weak.transformed.expect
@@ -652,10 +652,10 @@
                       #L16:
                       {
                         [yield] let dynamic #t55 = asy::_awaitHelper(func<asy::Stream<core::int>>(self::intStream()){(asy::Stream<core::int>) → FutureOr<asy::Stream<core::int>>}, :async_op_then, :async_op_error) in null;
-                        if(:controller.{asy::_AsyncStarStreamController::addStream}(_in::unsafeCast<asy::Stream<core::int>>(:result_or_exception)){(asy::Stream<core::int>) → core::bool})
+                        :controller.{asy::_AsyncStarStreamController::addStream}(_in::unsafeCast<asy::Stream<core::int>>(:result_or_exception)){(asy::Stream<core::int>) → void};
+                        [yield] null;
+                        if(_in::unsafeCast<core::bool>(:result_or_exception))
                           return null;
-                        else
-                          [yield] null;
                       }
                       return;
                     }
diff --git a/pkg/front_end/testcases/general/statements.dart.weak.transformed.expect b/pkg/front_end/testcases/general/statements.dart.weak.transformed.expect
index 012142b..2db299f 100644
--- a/pkg/front_end/testcases/general/statements.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general/statements.dart.weak.transformed.expect
@@ -44,10 +44,10 @@
                       return null;
                     else
                       [yield] null;
-                    if(:controller.{asy::_AsyncStarStreamController::addStream}(x as{TypeError,ForDynamic,ForNonNullableByDefault} asy::Stream<dynamic>){(asy::Stream<dynamic>) → core::bool})
+                    :controller.{asy::_AsyncStarStreamController::addStream}(x as{TypeError,ForDynamic,ForNonNullableByDefault} asy::Stream<dynamic>){(asy::Stream<dynamic>) → void};
+                    [yield] null;
+                    if(_in::unsafeCast<core::bool>(:result_or_exception))
                       return null;
-                    else
-                      [yield] null;
                   }
                 }
                 else
diff --git a/pkg/front_end/testcases/incremental.status b/pkg/front_end/testcases/incremental.status
index f0401a1..aaa2393 100644
--- a/pkg/front_end/testcases/incremental.status
+++ b/pkg/front_end/testcases/incremental.status
@@ -7,4 +7,5 @@
 # http://dartbug.com/41812#issuecomment-684825703
 #strongmode_mixins_2: Crash
 
-changing_modules_16: Crash
\ No newline at end of file
+changing_modules_16: Crash
+late_lowering: EquivalenceError
\ No newline at end of file
diff --git a/pkg/front_end/testcases/incremental/late_lowering.yaml b/pkg/front_end/testcases/incremental/late_lowering.yaml
new file mode 100644
index 0000000..72995b9
--- /dev/null
+++ b/pkg/front_end/testcases/incremental/late_lowering.yaml
@@ -0,0 +1,31 @@
+# Copyright (c) 2022, 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.md file.
+
+# Recompiling with no change shouldn't change anything..
+
+type: newworld
+forceLateLoweringForTesting: true
+worlds:
+  - entry: main.dart
+    experiments: alternative-invalidation-strategy
+    sources:
+      main.dart: |
+        part "part.dart";
+        main() {
+        }
+      part.dart: |
+        part of 'main.dart';
+        class _Class {
+          late int _privateField = 1;
+        }
+    expectedLibraryCount: 1
+
+  - entry: main.dart
+    experiments: alternative-invalidation-strategy
+    worldType: updated
+    compareToPrevious: true
+    expectInitializeFromDill: false
+    invalidate:
+      - main.dart
+    expectedLibraryCount: 1
diff --git a/pkg/front_end/testcases/incremental/late_lowering.yaml.world.1.expect b/pkg/front_end/testcases/incremental/late_lowering.yaml.world.1.expect
new file mode 100644
index 0000000..ce71355
--- /dev/null
+++ b/pkg/front_end/testcases/incremental/late_lowering.yaml.world.1.expect
@@ -0,0 +1,24 @@
+main = main::main;
+library from "org-dartlang-test:///main.dart" as main {
+
+  part part.dart;
+  class _Class extends dart.core::Object { // from org-dartlang-test:///part.dart
+    field dart.core::int? _#_Class#_privateField = null;
+    field dart.core::bool _#_Class#_privateField#isSet = false;
+    synthetic constructor •() → main::_Class
+      : super dart.core::Object::•()
+      ;
+    get _privateField() → dart.core::int {
+      if(!this.{main::_Class::_#_Class#_privateField#isSet}{dart.core::bool}) {
+        this.{main::_Class::_#_Class#_privateField} = 1;
+        this.{main::_Class::_#_Class#_privateField#isSet} = true;
+      }
+      return let final dart.core::int? #t1 = this.{main::_Class::_#_Class#_privateField}{dart.core::int?} in #t1{dart.core::int};
+    }
+    set _privateField(dart.core::int library org-dartlang-test:///part.dart::_privateField#param) → void {
+      this.{main::_Class::_#_Class#_privateField#isSet} = true;
+      this.{main::_Class::_#_Class#_privateField} = library org-dartlang-test:///part.dart::_privateField#param;
+    }
+  }
+  static method main() → dynamic {}
+}
diff --git a/pkg/front_end/testcases/inference/block_bodied_lambdas_async_star.dart.weak.transformed.expect b/pkg/front_end/testcases/inference/block_bodied_lambdas_async_star.dart.weak.transformed.expect
index 2e127fbc..5730a20 100644
--- a/pkg/front_end/testcases/inference/block_bodied_lambdas_async_star.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/inference/block_bodied_lambdas_async_star.dart.weak.transformed.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:async" as asy;
 import "dart:core" as core;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -25,10 +26,10 @@
             else
               [yield] null;
             asy::Stream<core::double*>* s;
-            if(:controller.{asy::_AsyncStarStreamController::addStream}(s){(asy::Stream<core::num*>) → core::bool})
+            :controller.{asy::_AsyncStarStreamController::addStream}(s){(asy::Stream<core::num*>) → void};
+            [yield] null;
+            if(_in::unsafeCast<core::bool>(:result_or_exception))
               return null;
-            else
-              [yield] null;
           }
           return;
         }
diff --git a/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.weak.transformed.expect b/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.weak.transformed.expect
index 7f9840f..02bca84 100644
--- a/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.weak.transformed.expect
@@ -29,6 +29,7 @@
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -109,18 +110,18 @@
             return null;
           else
             [yield] null;
-          if(:controller.{asy::_AsyncStarStreamController::addStream}(invalid-expression "pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart:17:64: Error: A value of type 'List<dynamic>' can't be assigned to a variable of type 'Stream<List<int>>'.
+          :controller.{asy::_AsyncStarStreamController::addStream}(invalid-expression "pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart:17:64: Error: A value of type 'List<dynamic>' can't be assigned to a variable of type 'Stream<List<int>>'.
  - 'List' is from 'dart:core'.
  - 'Stream' is from 'dart:async'.
   yield* /*error:YIELD_OF_INVALID_TYPE*/ /*@typeArgs=dynamic*/ [];
-                                                               ^" in core::_GrowableList::•<dynamic>(0) as{TypeError} asy::Stream<core::List<core::int*>*>*){(asy::Stream<core::List<core::int*>*>) → core::bool})
+                                                               ^" in core::_GrowableList::•<dynamic>(0) as{TypeError} asy::Stream<core::List<core::int*>*>*){(asy::Stream<core::List<core::int*>*>) → void};
+          [yield] null;
+          if(_in::unsafeCast<core::bool>(:result_or_exception))
             return null;
-          else
-            [yield] null;
-          if(:controller.{asy::_AsyncStarStreamController::addStream}(self::MyStream::•<core::List<core::int*>*>()){(asy::Stream<core::List<core::int*>*>) → core::bool})
+          :controller.{asy::_AsyncStarStreamController::addStream}(self::MyStream::•<core::List<core::int*>*>()){(asy::Stream<core::List<core::int*>*>) → void};
+          [yield] null;
+          if(_in::unsafeCast<core::bool>(:result_or_exception))
             return null;
-          else
-            [yield] null;
         }
         return;
       }
diff --git a/pkg/front_end/testcases/inference/local_return_and_yield.dart.weak.transformed.expect b/pkg/front_end/testcases/inference/local_return_and_yield.dart.weak.transformed.expect
index fbcd719..251c281 100644
--- a/pkg/front_end/testcases/inference/local_return_and_yield.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/inference/local_return_and_yield.dart.weak.transformed.expect
@@ -10,6 +10,7 @@
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -129,10 +130,10 @@
         try {
           #L3:
           {
-            if(:controller.{asy::_AsyncStarStreamController::addStream}(asy::Stream::fromIterable<(core::int*) →* core::int*>(core::_GrowableList::_literal1<(core::int*) →* core::int*>((core::int* x) → core::int* => x))){(asy::Stream<(core::int*) →* core::int*>) → core::bool})
+            :controller.{asy::_AsyncStarStreamController::addStream}(asy::Stream::fromIterable<(core::int*) →* core::int*>(core::_GrowableList::_literal1<(core::int*) →* core::int*>((core::int* x) → core::int* => x))){(asy::Stream<(core::int*) →* core::int*>) → void};
+            [yield] null;
+            if(_in::unsafeCast<core::bool>(:result_or_exception))
               return null;
-            else
-              [yield] null;
           }
           return;
         }
diff --git a/pkg/front_end/testcases/inference/top_level_return_and_yield.dart.weak.transformed.expect b/pkg/front_end/testcases/inference/top_level_return_and_yield.dart.weak.transformed.expect
index 84ea22c..3d5e979 100644
--- a/pkg/front_end/testcases/inference/top_level_return_and_yield.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/inference/top_level_return_and_yield.dart.weak.transformed.expect
@@ -10,6 +10,7 @@
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -128,10 +129,10 @@
       try {
         #L3:
         {
-          if(:controller.{asy::_AsyncStarStreamController::addStream}(asy::Stream::fromIterable<(core::int*) →* core::int*>(core::_GrowableList::_literal1<(core::int*) →* core::int*>((core::int* x) → core::int* => x))){(asy::Stream<(core::int*) →* core::int*>) → core::bool})
+          :controller.{asy::_AsyncStarStreamController::addStream}(asy::Stream::fromIterable<(core::int*) →* core::int*>(core::_GrowableList::_literal1<(core::int*) →* core::int*>((core::int* x) → core::int* => x))){(asy::Stream<(core::int*) →* core::int*>) → void};
+          [yield] null;
+          if(_in::unsafeCast<core::bool>(:result_or_exception))
             return null;
-          else
-            [yield] null;
         }
         return;
       }
diff --git a/pkg/front_end/testcases/nnbd/issue41437c.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/issue41437c.dart.strong.transformed.expect
index cfc0b05..c8058e6 100644
--- a/pkg/front_end/testcases/nnbd/issue41437c.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/issue41437c.dart.strong.transformed.expect
@@ -40,6 +40,7 @@
 import self as self;
 import "dart:async" as asy;
 import "dart:core" as core;
+import "dart:_internal" as _in;
 
 static method getNull() → dynamic
   return null;
@@ -160,13 +161,13 @@
       try {
         #L4:
         {
-          if(:controller.{asy::_AsyncStarStreamController::addStream}(invalid-expression "pkg/front_end/testcases/nnbd/issue41437c.dart:21:10: Error: A value of type 'Stream<dynamic>' can't be assigned to a variable of type 'Stream<bool>'.
+          :controller.{asy::_AsyncStarStreamController::addStream}(invalid-expression "pkg/front_end/testcases/nnbd/issue41437c.dart:21:10: Error: A value of type 'Stream<dynamic>' can't be assigned to a variable of type 'Stream<bool>'.
  - 'Stream' is from 'dart:async'.
   yield* getStreamNull(); // error
-         ^" in self::getStreamNull() as{TypeError,ForNonNullableByDefault} asy::Stream<core::bool>){(asy::Stream<core::bool>) → core::bool})
+         ^" in self::getStreamNull() as{TypeError,ForNonNullableByDefault} asy::Stream<core::bool>){(asy::Stream<core::bool>) → void};
+          [yield] null;
+          if(_in::unsafeCast<core::bool>(:result_or_exception))
             return null;
-          else
-            [yield] null;
         }
         return;
       }
@@ -203,10 +204,10 @@
       try {
         #L5:
         {
-          if(:controller.{asy::_AsyncStarStreamController::addStream}(self::getStreamBool()){(asy::Stream<core::bool>) → core::bool})
+          :controller.{asy::_AsyncStarStreamController::addStream}(self::getStreamBool()){(asy::Stream<core::bool>) → void};
+          [yield] null;
+          if(_in::unsafeCast<core::bool>(:result_or_exception))
             return null;
-          else
-            [yield] null;
         }
         return;
       }
@@ -285,13 +286,13 @@
               try {
                 #L8:
                 {
-                  if(:controller.{asy::_AsyncStarStreamController::addStream}(invalid-expression "pkg/front_end/testcases/nnbd/issue41437c.dart:38:12: Error: A value of type 'Stream<dynamic>' can't be assigned to a variable of type 'Stream<bool>'.
+                  :controller.{asy::_AsyncStarStreamController::addStream}(invalid-expression "pkg/front_end/testcases/nnbd/issue41437c.dart:38:12: Error: A value of type 'Stream<dynamic>' can't be assigned to a variable of type 'Stream<bool>'.
  - 'Stream' is from 'dart:async'.
     yield* getStreamNull(); // error
-           ^" in self::getStreamNull() as{TypeError,ForNonNullableByDefault} asy::Stream<core::bool>){(asy::Stream<core::bool>) → core::bool})
+           ^" in self::getStreamNull() as{TypeError,ForNonNullableByDefault} asy::Stream<core::bool>){(asy::Stream<core::bool>) → void};
+                  [yield] null;
+                  if(_in::unsafeCast<core::bool>(:result_or_exception))
                     return null;
-                  else
-                    [yield] null;
                 }
                 return;
               }
@@ -328,10 +329,10 @@
               try {
                 #L9:
                 {
-                  if(:controller.{asy::_AsyncStarStreamController::addStream}(self::getStreamBool()){(asy::Stream<core::bool>) → core::bool})
+                  :controller.{asy::_AsyncStarStreamController::addStream}(self::getStreamBool()){(asy::Stream<core::bool>) → void};
+                  [yield] null;
+                  if(_in::unsafeCast<core::bool>(:result_or_exception))
                     return null;
-                  else
-                    [yield] null;
                 }
                 return;
               }
@@ -402,10 +403,10 @@
               try {
                 #L11:
                 {
-                  if(:controller.{asy::_AsyncStarStreamController::addStream}(self::getStreamNull()){(asy::Stream<dynamic>) → core::bool})
+                  :controller.{asy::_AsyncStarStreamController::addStream}(self::getStreamNull()){(asy::Stream<dynamic>) → void};
+                  [yield] null;
+                  if(_in::unsafeCast<core::bool>(:result_or_exception))
                     return null;
-                  else
-                    [yield] null;
                 }
                 return;
               }
@@ -440,10 +441,10 @@
               try {
                 #L12:
                 {
-                  if(:controller.{asy::_AsyncStarStreamController::addStream}(self::getStreamBool()){(asy::Stream<core::bool>) → core::bool})
+                  :controller.{asy::_AsyncStarStreamController::addStream}(self::getStreamBool()){(asy::Stream<core::bool>) → void};
+                  [yield] null;
+                  if(_in::unsafeCast<core::bool>(:result_or_exception))
                     return null;
-                  else
-                    [yield] null;
                 }
                 return;
               }
diff --git a/pkg/front_end/testcases/nnbd/issue41437c.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/issue41437c.dart.weak.transformed.expect
index cfc0b05..c8058e6 100644
--- a/pkg/front_end/testcases/nnbd/issue41437c.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/issue41437c.dart.weak.transformed.expect
@@ -40,6 +40,7 @@
 import self as self;
 import "dart:async" as asy;
 import "dart:core" as core;
+import "dart:_internal" as _in;
 
 static method getNull() → dynamic
   return null;
@@ -160,13 +161,13 @@
       try {
         #L4:
         {
-          if(:controller.{asy::_AsyncStarStreamController::addStream}(invalid-expression "pkg/front_end/testcases/nnbd/issue41437c.dart:21:10: Error: A value of type 'Stream<dynamic>' can't be assigned to a variable of type 'Stream<bool>'.
+          :controller.{asy::_AsyncStarStreamController::addStream}(invalid-expression "pkg/front_end/testcases/nnbd/issue41437c.dart:21:10: Error: A value of type 'Stream<dynamic>' can't be assigned to a variable of type 'Stream<bool>'.
  - 'Stream' is from 'dart:async'.
   yield* getStreamNull(); // error
-         ^" in self::getStreamNull() as{TypeError,ForNonNullableByDefault} asy::Stream<core::bool>){(asy::Stream<core::bool>) → core::bool})
+         ^" in self::getStreamNull() as{TypeError,ForNonNullableByDefault} asy::Stream<core::bool>){(asy::Stream<core::bool>) → void};
+          [yield] null;
+          if(_in::unsafeCast<core::bool>(:result_or_exception))
             return null;
-          else
-            [yield] null;
         }
         return;
       }
@@ -203,10 +204,10 @@
       try {
         #L5:
         {
-          if(:controller.{asy::_AsyncStarStreamController::addStream}(self::getStreamBool()){(asy::Stream<core::bool>) → core::bool})
+          :controller.{asy::_AsyncStarStreamController::addStream}(self::getStreamBool()){(asy::Stream<core::bool>) → void};
+          [yield] null;
+          if(_in::unsafeCast<core::bool>(:result_or_exception))
             return null;
-          else
-            [yield] null;
         }
         return;
       }
@@ -285,13 +286,13 @@
               try {
                 #L8:
                 {
-                  if(:controller.{asy::_AsyncStarStreamController::addStream}(invalid-expression "pkg/front_end/testcases/nnbd/issue41437c.dart:38:12: Error: A value of type 'Stream<dynamic>' can't be assigned to a variable of type 'Stream<bool>'.
+                  :controller.{asy::_AsyncStarStreamController::addStream}(invalid-expression "pkg/front_end/testcases/nnbd/issue41437c.dart:38:12: Error: A value of type 'Stream<dynamic>' can't be assigned to a variable of type 'Stream<bool>'.
  - 'Stream' is from 'dart:async'.
     yield* getStreamNull(); // error
-           ^" in self::getStreamNull() as{TypeError,ForNonNullableByDefault} asy::Stream<core::bool>){(asy::Stream<core::bool>) → core::bool})
+           ^" in self::getStreamNull() as{TypeError,ForNonNullableByDefault} asy::Stream<core::bool>){(asy::Stream<core::bool>) → void};
+                  [yield] null;
+                  if(_in::unsafeCast<core::bool>(:result_or_exception))
                     return null;
-                  else
-                    [yield] null;
                 }
                 return;
               }
@@ -328,10 +329,10 @@
               try {
                 #L9:
                 {
-                  if(:controller.{asy::_AsyncStarStreamController::addStream}(self::getStreamBool()){(asy::Stream<core::bool>) → core::bool})
+                  :controller.{asy::_AsyncStarStreamController::addStream}(self::getStreamBool()){(asy::Stream<core::bool>) → void};
+                  [yield] null;
+                  if(_in::unsafeCast<core::bool>(:result_or_exception))
                     return null;
-                  else
-                    [yield] null;
                 }
                 return;
               }
@@ -402,10 +403,10 @@
               try {
                 #L11:
                 {
-                  if(:controller.{asy::_AsyncStarStreamController::addStream}(self::getStreamNull()){(asy::Stream<dynamic>) → core::bool})
+                  :controller.{asy::_AsyncStarStreamController::addStream}(self::getStreamNull()){(asy::Stream<dynamic>) → void};
+                  [yield] null;
+                  if(_in::unsafeCast<core::bool>(:result_or_exception))
                     return null;
-                  else
-                    [yield] null;
                 }
                 return;
               }
@@ -440,10 +441,10 @@
               try {
                 #L12:
                 {
-                  if(:controller.{asy::_AsyncStarStreamController::addStream}(self::getStreamBool()){(asy::Stream<core::bool>) → core::bool})
+                  :controller.{asy::_AsyncStarStreamController::addStream}(self::getStreamBool()){(asy::Stream<core::bool>) → void};
+                  [yield] null;
+                  if(_in::unsafeCast<core::bool>(:result_or_exception))
                     return null;
-                  else
-                    [yield] null;
                 }
                 return;
               }
diff --git a/pkg/vm/lib/transformations/continuation.dart b/pkg/vm/lib/transformations/continuation.dart
index 455b281..f158e8e 100644
--- a/pkg/vm/lib/transformations/continuation.dart
+++ b/pkg/vm/lib/transformations/continuation.dart
@@ -1329,10 +1329,21 @@
         functionType: addMethodFunctionType)
       ..fileOffset = stmt.fileOffset;
 
-    statements.add(new IfStatement(
-        addExpression,
-        new ReturnStatement(new NullLiteral()),
-        createContinuationPoint()..fileOffset = stmt.fileOffset));
+    if (stmt.isYieldStar) {
+      statements.add(ExpressionStatement(addExpression));
+      statements.add(createContinuationPoint()..fileOffset = stmt.fileOffset);
+      final wasCancelled = StaticInvocation(
+          helper.unsafeCast,
+          Arguments(<Expression>[VariableGet(expressionRewriter!.asyncResult)],
+              types: <DartType>[helper.coreTypes.boolNonNullableRawType]));
+      statements
+          .add(IfStatement(wasCancelled, ReturnStatement(NullLiteral()), null));
+    } else {
+      statements.add(new IfStatement(
+          addExpression,
+          new ReturnStatement(new NullLiteral()),
+          createContinuationPoint()..fileOffset = stmt.fileOffset));
+    }
     return removalSentinel ?? EmptyStatement();
   }
 
diff --git a/runtime/docs/compiler/aot/entry_point_pragma.md b/runtime/docs/compiler/aot/entry_point_pragma.md
index 3694a98..fc68848 100644
--- a/runtime/docs/compiler/aot/entry_point_pragma.md
+++ b/runtime/docs/compiler/aot/entry_point_pragma.md
@@ -35,7 +35,7 @@
 ```dart
 @pragma("vm:entry-point")
 @pragma("vm:entry-point", true/false)
-@pragma("vm:entry-point", !const bool.formEnvironment("dart.vm.product"))
+@pragma("vm:entry-point", !const bool.fromEnvironment("dart.vm.product"))
 class C { ... }
 ```
 
@@ -54,7 +54,7 @@
 ```dart
 @pragma("vm:entry-point")
 @pragma("vm:entry-point", true/false)
-@pragma("vm:entry-point", !const bool.formEnvironment("dart.vm.product"))
+@pragma("vm:entry-point", !const bool.fromEnvironment("dart.vm.product"))
 @pragma("vm:entry-point", "get")
 @pragma("vm:entry-point", "call")
 void foo() { ... }
@@ -83,7 +83,7 @@
 @pragma("vm:entry-point")
 @pragma("vm:entry-point", null)
 @pragma("vm:entry-point", true/false)
-@pragma("vm:entry-point", !const bool.formEnvironment("dart.vm.product"))
+@pragma("vm:entry-point", !const bool.fromEnvironment("dart.vm.product"))
 @pragma("vm:entry-point", "get"/"set")
 int foo;
 ```
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index a3e51a4..181fd2b 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -1042,9 +1042,9 @@
       nativeZoneMemoryUsage = map['_nativeZoneMemoryUsage'];
     }
     pid = map['pid'];
-    mallocUsed = map['_mallocUsed'];
-    mallocCapacity = map['_mallocCapacity'];
-    mallocImplementation = map['_mallocImplementation'];
+    mallocUsed = map['_mallocUsed'] ?? -1;
+    mallocCapacity = map['_mallocCapacity'] ?? -1;
+    mallocImplementation = map['_mallocImplementation'] ?? 'unknown';
     embedder = map['_embedder'];
     currentMemory = map['_currentMemory'];
     maxRSS = map['_maxRSS'];
diff --git a/runtime/observatory/tests/service/developer_extension_test.dart b/runtime/observatory/tests/service/developer_extension_test.dart
index 9b18926..2983cf4 100644
--- a/runtime/observatory/tests/service/developer_extension_test.dart
+++ b/runtime/observatory/tests/service/developer_extension_test.dart
@@ -43,10 +43,15 @@
 }
 
 void test() {
+  Expect.isFalse(extensionStreamHasListener);
+  postEvent('Disabled event', {'foo': 'bar'});
+
   registerExtension('ext..delay', Handler);
   debugger();
+  Expect.isTrue(extensionStreamHasListener);
   postEvent('ALPHA', {'cat': 'dog'});
   debugger();
+
   registerExtension('ext..error', Handler);
   registerExtension('ext..exception', Handler);
   registerExtension('ext..success', Handler);
@@ -56,7 +61,7 @@
   } catch (e) {
     exceptionThrown = true;
   }
-  // This check is running in the target process so we can't used package:test.
+  // This check is running in the target process so we can't use package:test.
   Expect.isTrue(exceptionThrown);
 }
 
diff --git a/runtime/observatory_2/tests/service_2/developer_extension_test.dart b/runtime/observatory_2/tests/service_2/developer_extension_test.dart
index 61cab8f..e6df897 100644
--- a/runtime/observatory_2/tests/service_2/developer_extension_test.dart
+++ b/runtime/observatory_2/tests/service_2/developer_extension_test.dart
@@ -55,7 +55,7 @@
   } catch (e) {
     exceptionThrown = true;
   }
-  // This check is running in the target process so we can't used package:test.
+  // This check is running in the target process so we can't use package:test.
   Expect.isTrue(exceptionThrown);
 }
 
diff --git a/runtime/tests/vm/dart/causal_stacks/flutter_regress_100441_test.dart b/runtime/tests/vm/dart/causal_stacks/flutter_regress_100441_test.dart
new file mode 100644
index 0000000..b5ff8ad
--- /dev/null
+++ b/runtime/tests/vm/dart/causal_stacks/flutter_regress_100441_test.dart
@@ -0,0 +1,77 @@
+// Copyright (c) 2022, 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.
+//
+// VMOptions=--lazy-async-stacks
+
+import 'dart:async';
+
+import 'package:expect/expect.dart';
+
+import 'utils.dart' show assertStack;
+
+String effectOrder = '';
+StackTrace? stackAfterYield = null;
+
+void emit(String m) => effectOrder += m;
+
+main() async {
+  emit('1');
+  await for (final value in produce()) {
+    emit('5');
+    Expect.equals('|value|', value);
+  }
+  emit('8');
+  Expect.equals('12345678', effectOrder);
+
+  assertStack(const <String>[
+    r'^#0      produceInner .*$',
+    r'^<asynchronous suspension>$',
+    r'^#1      produce .*$',
+    r'^<asynchronous suspension>$',
+    r'^#2      main .*$',
+    r'^<asynchronous suspension>$',
+  ], stackAfterYield!);
+
+  effectOrder = '';
+
+  emit('1');
+  await for (final value in produceYieldStar()) {
+    emit('5');
+    Expect.equals('|value|', value);
+    break;
+  }
+  emit('6');
+  Expect.equals('123456', effectOrder);
+}
+
+Stream<dynamic> produce() async* {
+  emit('2');
+  await for (String response in produceInner()) {
+    emit('4');
+    yield response;
+  }
+  emit('7');
+}
+
+Stream produceInner() async* {
+  emit('3');
+  yield '|value|';
+  emit('6');
+  stackAfterYield = StackTrace.current;
+}
+
+Stream<dynamic> produceYieldStar() async* {
+  emit('2');
+  await for (String response in produceInner()) {
+    emit('4');
+    yield response;
+  }
+  emit('x');
+}
+
+Stream produceInnerYieldStar() async* {
+  emit('3');
+  yield* Stream.fromIterable(['|value|', '|value2|']);
+  emit('x');
+}
diff --git a/runtime/tests/vm/dart/flutter_regress_101514_test.dart b/runtime/tests/vm/dart/flutter_regress_101514_test.dart
new file mode 100644
index 0000000..6c78710
--- /dev/null
+++ b/runtime/tests/vm/dart/flutter_regress_101514_test.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2022, 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 'package:expect/expect.dart';
+
+late StreamSubscription sub;
+
+main() async {
+  sub = foo().listen((_) => throw 'unexpected item');
+}
+
+Stream<int> foo() async* {
+  // While the generator (i.e. this funtion) runs, we cancel the consumer and
+  // try to yield more.
+  sub.cancel();
+  yield* Stream.fromIterable([1, 2, 3]);
+  throw 'should not run';
+}
diff --git a/runtime/tests/vm/dart_2/causal_stacks/flutter_regress_100441_test.dart b/runtime/tests/vm/dart_2/causal_stacks/flutter_regress_100441_test.dart
new file mode 100644
index 0000000..2d4d2ef
--- /dev/null
+++ b/runtime/tests/vm/dart_2/causal_stacks/flutter_regress_100441_test.dart
@@ -0,0 +1,78 @@
+// Copyright (c) 2022, 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.
+//
+// VMOptions=--lazy-async-stacks
+
+// @dart = 2.9
+import 'dart:async';
+
+import 'package:expect/expect.dart';
+
+import 'utils.dart' show assertStack;
+
+String effectOrder = '';
+StackTrace stackAfterYield = null;
+
+void emit(String m) => effectOrder += m;
+
+main() async {
+  emit('1');
+  await for (final value in produce()) {
+    emit('5');
+    Expect.equals('|value|', value);
+  }
+  emit('8');
+  Expect.equals('12345678', effectOrder);
+
+  assertStack(const <String>[
+    r'^#0      produceInner .*$',
+    r'^<asynchronous suspension>$',
+    r'^#1      produce .*$',
+    r'^<asynchronous suspension>$',
+    r'^#2      main .*$',
+    r'^<asynchronous suspension>$',
+  ], stackAfterYield);
+
+  effectOrder = '';
+
+  emit('1');
+  await for (final value in produceYieldStar()) {
+    emit('5');
+    Expect.equals('|value|', value);
+    break;
+  }
+  emit('6');
+  Expect.equals('123456', effectOrder);
+}
+
+Stream<dynamic> produce() async* {
+  emit('2');
+  await for (String response in produceInner()) {
+    emit('4');
+    yield response;
+  }
+  emit('7');
+}
+
+Stream produceInner() async* {
+  emit('3');
+  yield '|value|';
+  emit('6');
+  stackAfterYield = StackTrace.current;
+}
+
+Stream<dynamic> produceYieldStar() async* {
+  emit('2');
+  await for (String response in produceInner()) {
+    emit('4');
+    yield response;
+  }
+  emit('x');
+}
+
+Stream produceInnerYieldStar() async* {
+  emit('3');
+  yield* Stream.fromIterable(['|value|', '|value2|']);
+  emit('x');
+}
diff --git a/runtime/tests/vm/dart_2/flutter_regress_101514_test.dart b/runtime/tests/vm/dart_2/flutter_regress_101514_test.dart
new file mode 100644
index 0000000..44d029a
--- /dev/null
+++ b/runtime/tests/vm/dart_2/flutter_regress_101514_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2022, 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.
+
+// @dart=2.9
+
+import 'dart:async';
+
+import 'package:expect/expect.dart';
+
+StreamSubscription sub;
+
+main() async {
+  sub = foo().listen((_) => throw 'unexpected item');
+}
+
+Stream<int> foo() async* {
+  // While the generator (i.e. this funtion) runs, we cancel the consumer and
+  // try to yield more.
+  sub.cancel();
+  yield* Stream.fromIterable([1, 2, 3]);
+  throw 'should not run';
+}
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 905570f..a769901 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -952,6 +952,7 @@
     case MethodRecognizer::kReachabilityFence:
     case MethodRecognizer::kUtf8DecoderScan:
     case MethodRecognizer::kHas63BitSmis:
+    case MethodRecognizer::kExtensionStreamHasListener:
 #define CASE(method, slot) case MethodRecognizer::k##method:
       LOAD_NATIVE_FIELD(CASE)
       STORE_NATIVE_FIELD(CASE)
@@ -1489,6 +1490,17 @@
       body += Constant(Bool::False());
 #endif  // defined(ARCH_IS_64_BIT)
     } break;
+    case MethodRecognizer::kExtensionStreamHasListener: {
+#ifdef PRODUCT
+      body += Constant(Bool::False());
+#else
+      body += LoadServiceExtensionStream();
+      body += RawLoadField(compiler::target::StreamInfo::enabled_offset());
+      // StreamInfo::enabled_ is a std::atomic<intptr_t>. This is effectively
+      // relaxed order access, which is acceptable for this use case.
+      body += IntToBool();
+#endif  // PRODUCT
+    } break;
     case MethodRecognizer::kFfiAsExternalTypedDataInt8:
     case MethodRecognizer::kFfiAsExternalTypedDataInt16:
     case MethodRecognizer::kFfiAsExternalTypedDataInt32:
@@ -4077,6 +4089,14 @@
   return body;
 }
 
+Fragment FlowGraphBuilder::LoadServiceExtensionStream() {
+  Fragment body;
+  body += LoadThread();
+  body +=
+      LoadUntagged(compiler::target::Thread::service_extension_stream_offset());
+  return body;
+}
+
 // TODO(http://dartbug.com/47487): Support unboxed output value.
 Fragment FlowGraphBuilder::BoolToInt() {
   // TODO(http://dartbug.com/36855) Build IfThenElseInstr, instead of letting
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.h b/runtime/vm/compiler/frontend/kernel_to_il.h
index 2a92d6a..eeab45d 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.h
+++ b/runtime/vm/compiler/frontend/kernel_to_il.h
@@ -282,6 +282,9 @@
   // Loads the (untagged) isolate address.
   Fragment LoadIsolate();
 
+  // Loads the (untagged) service extension stream address.
+  Fragment LoadServiceExtensionStream();
+
   // Converts a true to 1 and false to 0.
   Fragment BoolToInt();
 
diff --git a/runtime/vm/compiler/recognized_methods_list.h b/runtime/vm/compiler/recognized_methods_list.h
index 7055a02..0331e00 100644
--- a/runtime/vm/compiler/recognized_methods_list.h
+++ b/runtime/vm/compiler/recognized_methods_list.h
@@ -268,6 +268,7 @@
   V(_RootZone, runUnary, RootZoneRunUnary, 0xb607f8bf)                         \
   V(_FutureListener, handleValue, FutureListenerHandleValue, 0x438115a8)       \
   V(::, has63BitSmis, Has63BitSmis, 0xf61b56f1)                                \
+  V(::, get:extensionStreamHasListener, ExtensionStreamHasListener, 0xfab46343)\
 
 // List of intrinsics:
 // (class-name, function-name, intrinsification method, fingerprint).
diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h
index 41ad454..f36cdc7 100644
--- a/runtime/vm/compiler/runtime_api.h
+++ b/runtime/vm/compiler/runtime_api.h
@@ -1068,6 +1068,11 @@
   static word enabled_offset();
 };
 
+class StreamInfo : public AllStatic {
+ public:
+  static word enabled_offset();
+};
+
 class VMHandles : public AllStatic {
  public:
   static constexpr intptr_t kOffsetOfRawPtrInHandle = kWordSize;
@@ -1099,6 +1104,7 @@
   static uword exit_through_runtime_call();
   static uword exit_through_ffi();
   static word dart_stream_offset();
+  static word service_extension_stream_offset();
   static word predefined_symbols_address_offset();
   static word optimize_entry_offset();
   static word deoptimize_entry_offset();
diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h
index 04a65b3..49c7e26 100644
--- a/runtime/vm/compiler/runtime_offsets_extracted.h
+++ b/runtime/vm/compiler/runtime_offsets_extracted.h
@@ -240,6 +240,7 @@
 static constexpr dart::compiler::target::word StoreBufferBlock_pointers_offset =
     8;
 static constexpr dart::compiler::target::word StoreBufferBlock_top_offset = 4;
+static constexpr dart::compiler::target::word StreamInfo_enabled_offset = 4;
 static constexpr dart::compiler::target::word String_hash_offset = 8;
 static constexpr dart::compiler::target::word String_length_offset = 4;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 4;
@@ -287,6 +288,8 @@
     Thread_dispatch_table_array_offset = 44;
 static constexpr dart::compiler::target::word
     Thread_double_truncate_round_supported_offset = 796;
+static constexpr dart::compiler::target::word
+    Thread_service_extension_stream_offset = 820;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
     312;
 static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 224;
@@ -330,7 +333,7 @@
 static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
     788;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 40;
-static constexpr dart::compiler::target::word Thread_isolate_group_offset = 820;
+static constexpr dart::compiler::target::word Thread_isolate_group_offset = 824;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     64;
 static constexpr dart::compiler::target::word
@@ -832,6 +835,7 @@
 static constexpr dart::compiler::target::word StoreBufferBlock_pointers_offset =
     16;
 static constexpr dart::compiler::target::word StoreBufferBlock_top_offset = 8;
+static constexpr dart::compiler::target::word StreamInfo_enabled_offset = 8;
 static constexpr dart::compiler::target::word String_hash_offset = 4;
 static constexpr dart::compiler::target::word String_length_offset = 8;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 8;
@@ -880,6 +884,8 @@
     Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
     Thread_double_truncate_round_supported_offset = 1592;
+static constexpr dart::compiler::target::word
+    Thread_service_extension_stream_offset = 1632;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
     600;
 static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 424;
@@ -924,7 +930,7 @@
     1576;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word Thread_isolate_group_offset =
-    1632;
+    1640;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     128;
 static constexpr dart::compiler::target::word
@@ -1427,6 +1433,7 @@
 static constexpr dart::compiler::target::word StoreBufferBlock_pointers_offset =
     8;
 static constexpr dart::compiler::target::word StoreBufferBlock_top_offset = 4;
+static constexpr dart::compiler::target::word StreamInfo_enabled_offset = 4;
 static constexpr dart::compiler::target::word String_hash_offset = 8;
 static constexpr dart::compiler::target::word String_length_offset = 4;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 4;
@@ -1474,6 +1481,8 @@
     Thread_dispatch_table_array_offset = 44;
 static constexpr dart::compiler::target::word
     Thread_double_truncate_round_supported_offset = 764;
+static constexpr dart::compiler::target::word
+    Thread_service_extension_stream_offset = 788;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
     312;
 static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 224;
@@ -1517,7 +1526,7 @@
 static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
     756;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 40;
-static constexpr dart::compiler::target::word Thread_isolate_group_offset = 788;
+static constexpr dart::compiler::target::word Thread_isolate_group_offset = 792;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     64;
 static constexpr dart::compiler::target::word
@@ -2016,6 +2025,7 @@
 static constexpr dart::compiler::target::word StoreBufferBlock_pointers_offset =
     16;
 static constexpr dart::compiler::target::word StoreBufferBlock_top_offset = 8;
+static constexpr dart::compiler::target::word StreamInfo_enabled_offset = 8;
 static constexpr dart::compiler::target::word String_hash_offset = 4;
 static constexpr dart::compiler::target::word String_length_offset = 8;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 8;
@@ -2064,6 +2074,8 @@
     Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
     Thread_double_truncate_round_supported_offset = 1656;
+static constexpr dart::compiler::target::word
+    Thread_service_extension_stream_offset = 1696;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
     600;
 static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 424;
@@ -2108,7 +2120,7 @@
     1640;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word Thread_isolate_group_offset =
-    1696;
+    1704;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     128;
 static constexpr dart::compiler::target::word
@@ -2613,6 +2625,7 @@
 static constexpr dart::compiler::target::word StoreBufferBlock_pointers_offset =
     16;
 static constexpr dart::compiler::target::word StoreBufferBlock_top_offset = 8;
+static constexpr dart::compiler::target::word StreamInfo_enabled_offset = 8;
 static constexpr dart::compiler::target::word String_hash_offset = 4;
 static constexpr dart::compiler::target::word String_length_offset = 8;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 8;
@@ -2661,6 +2674,8 @@
     Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
     Thread_double_truncate_round_supported_offset = 1592;
+static constexpr dart::compiler::target::word
+    Thread_service_extension_stream_offset = 1632;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
     600;
 static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 424;
@@ -2705,7 +2720,7 @@
     1576;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word Thread_isolate_group_offset =
-    1632;
+    1640;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     128;
 static constexpr dart::compiler::target::word
@@ -3209,6 +3224,7 @@
 static constexpr dart::compiler::target::word StoreBufferBlock_pointers_offset =
     16;
 static constexpr dart::compiler::target::word StoreBufferBlock_top_offset = 8;
+static constexpr dart::compiler::target::word StreamInfo_enabled_offset = 8;
 static constexpr dart::compiler::target::word String_hash_offset = 4;
 static constexpr dart::compiler::target::word String_length_offset = 8;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 8;
@@ -3257,6 +3273,8 @@
     Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
     Thread_double_truncate_round_supported_offset = 1656;
+static constexpr dart::compiler::target::word
+    Thread_service_extension_stream_offset = 1696;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
     600;
 static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 424;
@@ -3301,7 +3319,7 @@
     1640;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word Thread_isolate_group_offset =
-    1696;
+    1704;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     128;
 static constexpr dart::compiler::target::word
@@ -3805,6 +3823,7 @@
 static constexpr dart::compiler::target::word StoreBufferBlock_pointers_offset =
     8;
 static constexpr dart::compiler::target::word StoreBufferBlock_top_offset = 4;
+static constexpr dart::compiler::target::word StreamInfo_enabled_offset = 4;
 static constexpr dart::compiler::target::word String_hash_offset = 8;
 static constexpr dart::compiler::target::word String_length_offset = 4;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 4;
@@ -3852,6 +3871,8 @@
     Thread_dispatch_table_array_offset = 44;
 static constexpr dart::compiler::target::word
     Thread_double_truncate_round_supported_offset = 836;
+static constexpr dart::compiler::target::word
+    Thread_service_extension_stream_offset = 860;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
     312;
 static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 224;
@@ -3895,7 +3916,7 @@
 static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
     828;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 40;
-static constexpr dart::compiler::target::word Thread_isolate_group_offset = 860;
+static constexpr dart::compiler::target::word Thread_isolate_group_offset = 864;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     64;
 static constexpr dart::compiler::target::word
@@ -4399,6 +4420,7 @@
 static constexpr dart::compiler::target::word StoreBufferBlock_pointers_offset =
     16;
 static constexpr dart::compiler::target::word StoreBufferBlock_top_offset = 8;
+static constexpr dart::compiler::target::word StreamInfo_enabled_offset = 8;
 static constexpr dart::compiler::target::word String_hash_offset = 4;
 static constexpr dart::compiler::target::word String_length_offset = 8;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 8;
@@ -4447,6 +4469,8 @@
     Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
     Thread_double_truncate_round_supported_offset = 1648;
+static constexpr dart::compiler::target::word
+    Thread_service_extension_stream_offset = 1688;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
     600;
 static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 424;
@@ -4491,7 +4515,7 @@
     1632;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word Thread_isolate_group_offset =
-    1688;
+    1696;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     128;
 static constexpr dart::compiler::target::word
@@ -4991,6 +5015,7 @@
 static constexpr dart::compiler::target::word StoreBufferBlock_pointers_offset =
     8;
 static constexpr dart::compiler::target::word StoreBufferBlock_top_offset = 4;
+static constexpr dart::compiler::target::word StreamInfo_enabled_offset = 4;
 static constexpr dart::compiler::target::word String_hash_offset = 8;
 static constexpr dart::compiler::target::word String_length_offset = 4;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 4;
@@ -5038,6 +5063,8 @@
     Thread_dispatch_table_array_offset = 44;
 static constexpr dart::compiler::target::word
     Thread_double_truncate_round_supported_offset = 796;
+static constexpr dart::compiler::target::word
+    Thread_service_extension_stream_offset = 820;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
     312;
 static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 224;
@@ -5081,7 +5108,7 @@
 static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
     788;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 40;
-static constexpr dart::compiler::target::word Thread_isolate_group_offset = 820;
+static constexpr dart::compiler::target::word Thread_isolate_group_offset = 824;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     64;
 static constexpr dart::compiler::target::word
@@ -5577,6 +5604,7 @@
 static constexpr dart::compiler::target::word StoreBufferBlock_pointers_offset =
     16;
 static constexpr dart::compiler::target::word StoreBufferBlock_top_offset = 8;
+static constexpr dart::compiler::target::word StreamInfo_enabled_offset = 8;
 static constexpr dart::compiler::target::word String_hash_offset = 4;
 static constexpr dart::compiler::target::word String_length_offset = 8;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 8;
@@ -5625,6 +5653,8 @@
     Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
     Thread_double_truncate_round_supported_offset = 1592;
+static constexpr dart::compiler::target::word
+    Thread_service_extension_stream_offset = 1632;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
     600;
 static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 424;
@@ -5669,7 +5699,7 @@
     1576;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word Thread_isolate_group_offset =
-    1632;
+    1640;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     128;
 static constexpr dart::compiler::target::word
@@ -6166,6 +6196,7 @@
 static constexpr dart::compiler::target::word StoreBufferBlock_pointers_offset =
     8;
 static constexpr dart::compiler::target::word StoreBufferBlock_top_offset = 4;
+static constexpr dart::compiler::target::word StreamInfo_enabled_offset = 4;
 static constexpr dart::compiler::target::word String_hash_offset = 8;
 static constexpr dart::compiler::target::word String_length_offset = 4;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 4;
@@ -6213,6 +6244,8 @@
     Thread_dispatch_table_array_offset = 44;
 static constexpr dart::compiler::target::word
     Thread_double_truncate_round_supported_offset = 764;
+static constexpr dart::compiler::target::word
+    Thread_service_extension_stream_offset = 788;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
     312;
 static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 224;
@@ -6256,7 +6289,7 @@
 static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
     756;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 40;
-static constexpr dart::compiler::target::word Thread_isolate_group_offset = 788;
+static constexpr dart::compiler::target::word Thread_isolate_group_offset = 792;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     64;
 static constexpr dart::compiler::target::word
@@ -6749,6 +6782,7 @@
 static constexpr dart::compiler::target::word StoreBufferBlock_pointers_offset =
     16;
 static constexpr dart::compiler::target::word StoreBufferBlock_top_offset = 8;
+static constexpr dart::compiler::target::word StreamInfo_enabled_offset = 8;
 static constexpr dart::compiler::target::word String_hash_offset = 4;
 static constexpr dart::compiler::target::word String_length_offset = 8;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 8;
@@ -6797,6 +6831,8 @@
     Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
     Thread_double_truncate_round_supported_offset = 1656;
+static constexpr dart::compiler::target::word
+    Thread_service_extension_stream_offset = 1696;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
     600;
 static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 424;
@@ -6841,7 +6877,7 @@
     1640;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word Thread_isolate_group_offset =
-    1696;
+    1704;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     128;
 static constexpr dart::compiler::target::word
@@ -7340,6 +7376,7 @@
 static constexpr dart::compiler::target::word StoreBufferBlock_pointers_offset =
     16;
 static constexpr dart::compiler::target::word StoreBufferBlock_top_offset = 8;
+static constexpr dart::compiler::target::word StreamInfo_enabled_offset = 8;
 static constexpr dart::compiler::target::word String_hash_offset = 4;
 static constexpr dart::compiler::target::word String_length_offset = 8;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 8;
@@ -7388,6 +7425,8 @@
     Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
     Thread_double_truncate_round_supported_offset = 1592;
+static constexpr dart::compiler::target::word
+    Thread_service_extension_stream_offset = 1632;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
     600;
 static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 424;
@@ -7432,7 +7471,7 @@
     1576;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word Thread_isolate_group_offset =
-    1632;
+    1640;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     128;
 static constexpr dart::compiler::target::word
@@ -7930,6 +7969,7 @@
 static constexpr dart::compiler::target::word StoreBufferBlock_pointers_offset =
     16;
 static constexpr dart::compiler::target::word StoreBufferBlock_top_offset = 8;
+static constexpr dart::compiler::target::word StreamInfo_enabled_offset = 8;
 static constexpr dart::compiler::target::word String_hash_offset = 4;
 static constexpr dart::compiler::target::word String_length_offset = 8;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 8;
@@ -7978,6 +8018,8 @@
     Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
     Thread_double_truncate_round_supported_offset = 1656;
+static constexpr dart::compiler::target::word
+    Thread_service_extension_stream_offset = 1696;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
     600;
 static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 424;
@@ -8022,7 +8064,7 @@
     1640;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word Thread_isolate_group_offset =
-    1696;
+    1704;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     128;
 static constexpr dart::compiler::target::word
@@ -8520,6 +8562,7 @@
 static constexpr dart::compiler::target::word StoreBufferBlock_pointers_offset =
     8;
 static constexpr dart::compiler::target::word StoreBufferBlock_top_offset = 4;
+static constexpr dart::compiler::target::word StreamInfo_enabled_offset = 4;
 static constexpr dart::compiler::target::word String_hash_offset = 8;
 static constexpr dart::compiler::target::word String_length_offset = 4;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 4;
@@ -8567,6 +8610,8 @@
     Thread_dispatch_table_array_offset = 44;
 static constexpr dart::compiler::target::word
     Thread_double_truncate_round_supported_offset = 836;
+static constexpr dart::compiler::target::word
+    Thread_service_extension_stream_offset = 860;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
     312;
 static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 224;
@@ -8610,7 +8655,7 @@
 static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
     828;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 40;
-static constexpr dart::compiler::target::word Thread_isolate_group_offset = 860;
+static constexpr dart::compiler::target::word Thread_isolate_group_offset = 864;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     64;
 static constexpr dart::compiler::target::word
@@ -9108,6 +9153,7 @@
 static constexpr dart::compiler::target::word StoreBufferBlock_pointers_offset =
     16;
 static constexpr dart::compiler::target::word StoreBufferBlock_top_offset = 8;
+static constexpr dart::compiler::target::word StreamInfo_enabled_offset = 8;
 static constexpr dart::compiler::target::word String_hash_offset = 4;
 static constexpr dart::compiler::target::word String_length_offset = 8;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 8;
@@ -9156,6 +9202,8 @@
     Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
     Thread_double_truncate_round_supported_offset = 1648;
+static constexpr dart::compiler::target::word
+    Thread_service_extension_stream_offset = 1688;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
     600;
 static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 424;
@@ -9200,7 +9248,7 @@
     1632;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word Thread_isolate_group_offset =
-    1688;
+    1696;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     128;
 static constexpr dart::compiler::target::word
@@ -9735,6 +9783,7 @@
     AOT_StoreBufferBlock_pointers_offset = 8;
 static constexpr dart::compiler::target::word AOT_StoreBufferBlock_top_offset =
     4;
+static constexpr dart::compiler::target::word AOT_StreamInfo_enabled_offset = 4;
 static constexpr dart::compiler::target::word AOT_String_hash_offset = 8;
 static constexpr dart::compiler::target::word AOT_String_length_offset = 4;
 static constexpr dart::compiler::target::word
@@ -9786,6 +9835,8 @@
     AOT_Thread_dispatch_table_array_offset = 44;
 static constexpr dart::compiler::target::word
     AOT_Thread_double_truncate_round_supported_offset = 796;
+static constexpr dart::compiler::target::word
+    AOT_Thread_service_extension_stream_offset = 820;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
     312;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
@@ -9831,7 +9882,7 @@
     AOT_Thread_exit_through_ffi_offset = 788;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 40;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_group_offset =
-    820;
+    824;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 64;
 static constexpr dart::compiler::target::word
@@ -10401,6 +10452,7 @@
     AOT_StoreBufferBlock_pointers_offset = 16;
 static constexpr dart::compiler::target::word AOT_StoreBufferBlock_top_offset =
     8;
+static constexpr dart::compiler::target::word AOT_StreamInfo_enabled_offset = 8;
 static constexpr dart::compiler::target::word AOT_String_hash_offset = 4;
 static constexpr dart::compiler::target::word AOT_String_length_offset = 8;
 static constexpr dart::compiler::target::word
@@ -10452,6 +10504,8 @@
     AOT_Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
     AOT_Thread_double_truncate_round_supported_offset = 1592;
+static constexpr dart::compiler::target::word
+    AOT_Thread_service_extension_stream_offset = 1632;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
     600;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
@@ -10497,7 +10551,7 @@
     AOT_Thread_exit_through_ffi_offset = 1576;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_group_offset =
-    1632;
+    1640;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 128;
 static constexpr dart::compiler::target::word
@@ -11073,6 +11127,7 @@
     AOT_StoreBufferBlock_pointers_offset = 16;
 static constexpr dart::compiler::target::word AOT_StoreBufferBlock_top_offset =
     8;
+static constexpr dart::compiler::target::word AOT_StreamInfo_enabled_offset = 8;
 static constexpr dart::compiler::target::word AOT_String_hash_offset = 4;
 static constexpr dart::compiler::target::word AOT_String_length_offset = 8;
 static constexpr dart::compiler::target::word
@@ -11124,6 +11179,8 @@
     AOT_Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
     AOT_Thread_double_truncate_round_supported_offset = 1656;
+static constexpr dart::compiler::target::word
+    AOT_Thread_service_extension_stream_offset = 1696;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
     600;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
@@ -11169,7 +11226,7 @@
     AOT_Thread_exit_through_ffi_offset = 1640;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_group_offset =
-    1696;
+    1704;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 128;
 static constexpr dart::compiler::target::word
@@ -11742,6 +11799,7 @@
     AOT_StoreBufferBlock_pointers_offset = 16;
 static constexpr dart::compiler::target::word AOT_StoreBufferBlock_top_offset =
     8;
+static constexpr dart::compiler::target::word AOT_StreamInfo_enabled_offset = 8;
 static constexpr dart::compiler::target::word AOT_String_hash_offset = 4;
 static constexpr dart::compiler::target::word AOT_String_length_offset = 8;
 static constexpr dart::compiler::target::word
@@ -11793,6 +11851,8 @@
     AOT_Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
     AOT_Thread_double_truncate_round_supported_offset = 1592;
+static constexpr dart::compiler::target::word
+    AOT_Thread_service_extension_stream_offset = 1632;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
     600;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
@@ -11838,7 +11898,7 @@
     AOT_Thread_exit_through_ffi_offset = 1576;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_group_offset =
-    1632;
+    1640;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 128;
 static constexpr dart::compiler::target::word
@@ -12410,6 +12470,7 @@
     AOT_StoreBufferBlock_pointers_offset = 16;
 static constexpr dart::compiler::target::word AOT_StoreBufferBlock_top_offset =
     8;
+static constexpr dart::compiler::target::word AOT_StreamInfo_enabled_offset = 8;
 static constexpr dart::compiler::target::word AOT_String_hash_offset = 4;
 static constexpr dart::compiler::target::word AOT_String_length_offset = 8;
 static constexpr dart::compiler::target::word
@@ -12461,6 +12522,8 @@
     AOT_Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
     AOT_Thread_double_truncate_round_supported_offset = 1656;
+static constexpr dart::compiler::target::word
+    AOT_Thread_service_extension_stream_offset = 1696;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
     600;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
@@ -12506,7 +12569,7 @@
     AOT_Thread_exit_through_ffi_offset = 1640;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_group_offset =
-    1696;
+    1704;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 128;
 static constexpr dart::compiler::target::word
@@ -13079,6 +13142,7 @@
     AOT_StoreBufferBlock_pointers_offset = 8;
 static constexpr dart::compiler::target::word AOT_StoreBufferBlock_top_offset =
     4;
+static constexpr dart::compiler::target::word AOT_StreamInfo_enabled_offset = 4;
 static constexpr dart::compiler::target::word AOT_String_hash_offset = 8;
 static constexpr dart::compiler::target::word AOT_String_length_offset = 4;
 static constexpr dart::compiler::target::word
@@ -13130,6 +13194,8 @@
     AOT_Thread_dispatch_table_array_offset = 44;
 static constexpr dart::compiler::target::word
     AOT_Thread_double_truncate_round_supported_offset = 836;
+static constexpr dart::compiler::target::word
+    AOT_Thread_service_extension_stream_offset = 860;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
     312;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
@@ -13175,7 +13241,7 @@
     AOT_Thread_exit_through_ffi_offset = 828;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 40;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_group_offset =
-    860;
+    864;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 64;
 static constexpr dart::compiler::target::word
@@ -13747,6 +13813,7 @@
     AOT_StoreBufferBlock_pointers_offset = 16;
 static constexpr dart::compiler::target::word AOT_StoreBufferBlock_top_offset =
     8;
+static constexpr dart::compiler::target::word AOT_StreamInfo_enabled_offset = 8;
 static constexpr dart::compiler::target::word AOT_String_hash_offset = 4;
 static constexpr dart::compiler::target::word AOT_String_length_offset = 8;
 static constexpr dart::compiler::target::word
@@ -13798,6 +13865,8 @@
     AOT_Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
     AOT_Thread_double_truncate_round_supported_offset = 1648;
+static constexpr dart::compiler::target::word
+    AOT_Thread_service_extension_stream_offset = 1688;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
     600;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
@@ -13843,7 +13912,7 @@
     AOT_Thread_exit_through_ffi_offset = 1632;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_group_offset =
-    1688;
+    1696;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 128;
 static constexpr dart::compiler::target::word
@@ -14411,6 +14480,7 @@
     AOT_StoreBufferBlock_pointers_offset = 8;
 static constexpr dart::compiler::target::word AOT_StoreBufferBlock_top_offset =
     4;
+static constexpr dart::compiler::target::word AOT_StreamInfo_enabled_offset = 4;
 static constexpr dart::compiler::target::word AOT_String_hash_offset = 8;
 static constexpr dart::compiler::target::word AOT_String_length_offset = 4;
 static constexpr dart::compiler::target::word
@@ -14462,6 +14532,8 @@
     AOT_Thread_dispatch_table_array_offset = 44;
 static constexpr dart::compiler::target::word
     AOT_Thread_double_truncate_round_supported_offset = 796;
+static constexpr dart::compiler::target::word
+    AOT_Thread_service_extension_stream_offset = 820;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
     312;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
@@ -14507,7 +14579,7 @@
     AOT_Thread_exit_through_ffi_offset = 788;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 40;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_group_offset =
-    820;
+    824;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 64;
 static constexpr dart::compiler::target::word
@@ -15070,6 +15142,7 @@
     AOT_StoreBufferBlock_pointers_offset = 16;
 static constexpr dart::compiler::target::word AOT_StoreBufferBlock_top_offset =
     8;
+static constexpr dart::compiler::target::word AOT_StreamInfo_enabled_offset = 8;
 static constexpr dart::compiler::target::word AOT_String_hash_offset = 4;
 static constexpr dart::compiler::target::word AOT_String_length_offset = 8;
 static constexpr dart::compiler::target::word
@@ -15121,6 +15194,8 @@
     AOT_Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
     AOT_Thread_double_truncate_round_supported_offset = 1592;
+static constexpr dart::compiler::target::word
+    AOT_Thread_service_extension_stream_offset = 1632;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
     600;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
@@ -15166,7 +15241,7 @@
     AOT_Thread_exit_through_ffi_offset = 1576;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_group_offset =
-    1632;
+    1640;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 128;
 static constexpr dart::compiler::target::word
@@ -15735,6 +15810,7 @@
     AOT_StoreBufferBlock_pointers_offset = 16;
 static constexpr dart::compiler::target::word AOT_StoreBufferBlock_top_offset =
     8;
+static constexpr dart::compiler::target::word AOT_StreamInfo_enabled_offset = 8;
 static constexpr dart::compiler::target::word AOT_String_hash_offset = 4;
 static constexpr dart::compiler::target::word AOT_String_length_offset = 8;
 static constexpr dart::compiler::target::word
@@ -15786,6 +15862,8 @@
     AOT_Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
     AOT_Thread_double_truncate_round_supported_offset = 1656;
+static constexpr dart::compiler::target::word
+    AOT_Thread_service_extension_stream_offset = 1696;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
     600;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
@@ -15831,7 +15909,7 @@
     AOT_Thread_exit_through_ffi_offset = 1640;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_group_offset =
-    1696;
+    1704;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 128;
 static constexpr dart::compiler::target::word
@@ -16397,6 +16475,7 @@
     AOT_StoreBufferBlock_pointers_offset = 16;
 static constexpr dart::compiler::target::word AOT_StoreBufferBlock_top_offset =
     8;
+static constexpr dart::compiler::target::word AOT_StreamInfo_enabled_offset = 8;
 static constexpr dart::compiler::target::word AOT_String_hash_offset = 4;
 static constexpr dart::compiler::target::word AOT_String_length_offset = 8;
 static constexpr dart::compiler::target::word
@@ -16448,6 +16527,8 @@
     AOT_Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
     AOT_Thread_double_truncate_round_supported_offset = 1592;
+static constexpr dart::compiler::target::word
+    AOT_Thread_service_extension_stream_offset = 1632;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
     600;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
@@ -16493,7 +16574,7 @@
     AOT_Thread_exit_through_ffi_offset = 1576;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_group_offset =
-    1632;
+    1640;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 128;
 static constexpr dart::compiler::target::word
@@ -17058,6 +17139,7 @@
     AOT_StoreBufferBlock_pointers_offset = 16;
 static constexpr dart::compiler::target::word AOT_StoreBufferBlock_top_offset =
     8;
+static constexpr dart::compiler::target::word AOT_StreamInfo_enabled_offset = 8;
 static constexpr dart::compiler::target::word AOT_String_hash_offset = 4;
 static constexpr dart::compiler::target::word AOT_String_length_offset = 8;
 static constexpr dart::compiler::target::word
@@ -17109,6 +17191,8 @@
     AOT_Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
     AOT_Thread_double_truncate_round_supported_offset = 1656;
+static constexpr dart::compiler::target::word
+    AOT_Thread_service_extension_stream_offset = 1696;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
     600;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
@@ -17154,7 +17238,7 @@
     AOT_Thread_exit_through_ffi_offset = 1640;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_group_offset =
-    1696;
+    1704;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 128;
 static constexpr dart::compiler::target::word
@@ -17720,6 +17804,7 @@
     AOT_StoreBufferBlock_pointers_offset = 8;
 static constexpr dart::compiler::target::word AOT_StoreBufferBlock_top_offset =
     4;
+static constexpr dart::compiler::target::word AOT_StreamInfo_enabled_offset = 4;
 static constexpr dart::compiler::target::word AOT_String_hash_offset = 8;
 static constexpr dart::compiler::target::word AOT_String_length_offset = 4;
 static constexpr dart::compiler::target::word
@@ -17771,6 +17856,8 @@
     AOT_Thread_dispatch_table_array_offset = 44;
 static constexpr dart::compiler::target::word
     AOT_Thread_double_truncate_round_supported_offset = 836;
+static constexpr dart::compiler::target::word
+    AOT_Thread_service_extension_stream_offset = 860;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
     312;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
@@ -17816,7 +17903,7 @@
     AOT_Thread_exit_through_ffi_offset = 828;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 40;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_group_offset =
-    860;
+    864;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 64;
 static constexpr dart::compiler::target::word
@@ -18381,6 +18468,7 @@
     AOT_StoreBufferBlock_pointers_offset = 16;
 static constexpr dart::compiler::target::word AOT_StoreBufferBlock_top_offset =
     8;
+static constexpr dart::compiler::target::word AOT_StreamInfo_enabled_offset = 8;
 static constexpr dart::compiler::target::word AOT_String_hash_offset = 4;
 static constexpr dart::compiler::target::word AOT_String_length_offset = 8;
 static constexpr dart::compiler::target::word
@@ -18432,6 +18520,8 @@
     AOT_Thread_dispatch_table_array_offset = 88;
 static constexpr dart::compiler::target::word
     AOT_Thread_double_truncate_round_supported_offset = 1648;
+static constexpr dart::compiler::target::word
+    AOT_Thread_service_extension_stream_offset = 1688;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
     600;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
@@ -18477,7 +18567,7 @@
     AOT_Thread_exit_through_ffi_offset = 1632;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 80;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_group_offset =
-    1688;
+    1696;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 128;
 static constexpr dart::compiler::target::word
diff --git a/runtime/vm/compiler/runtime_offsets_list.h b/runtime/vm/compiler/runtime_offsets_list.h
index 1e03be5..65982cf 100644
--- a/runtime/vm/compiler/runtime_offsets_list.h
+++ b/runtime/vm/compiler/runtime_offsets_list.h
@@ -186,6 +186,7 @@
   FIELD(SingleTargetCache, upper_limit_offset)                                 \
   FIELD(StoreBufferBlock, pointers_offset)                                     \
   FIELD(StoreBufferBlock, top_offset)                                          \
+  FIELD(StreamInfo, enabled_offset)                                            \
   FIELD(String, hash_offset)                                                   \
   FIELD(String, length_offset)                                                 \
   FIELD(SubtypeTestCache, cache_offset)                                        \
@@ -213,6 +214,7 @@
   FIELD(Thread, dart_stream_offset)                                            \
   FIELD(Thread, dispatch_table_array_offset)                                   \
   FIELD(Thread, double_truncate_round_supported_offset)                        \
+  FIELD(Thread, service_extension_stream_offset)                               \
   FIELD(Thread, optimize_entry_offset)                                         \
   FIELD(Thread, optimize_stub_offset)                                          \
   FIELD(Thread, deoptimize_entry_offset)                                       \
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 9162e8b..1ae59b4 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "compiler/method_recognizer.h"
 #include "include/dart_api.h"
 #include "lib/stacktrace.h"
 #include "platform/assert.h"
@@ -8097,31 +8098,66 @@
 }
 
 bool Function::ForceOptimize() const {
-  return IsFfiFromAddress() || IsFfiGetAddress() || IsFfiLoad() ||
-         IsFfiStore() || IsFfiTrampoline() || IsFfiAsExternalTypedData() ||
-         IsTypedDataViewFactory() || IsUtf8Scan() || IsGetNativeField() ||
-         IsFinalizerForceOptimized();
+  return RecognizedKindForceOptimize() || IsFfiTrampoline() ||
+         IsTypedDataViewFactory();
 }
 
-bool Function::IsFinalizerForceOptimized() const {
-  // Either because of unboxed/untagged data, or because we don't want the GC
-  // to trigger in between.
+bool Function::RecognizedKindForceOptimize() const {
   switch (recognized_kind()) {
+    // Uses unboxed/untagged data not supported in unoptimized.
     case MethodRecognizer::kFinalizerBase_getIsolateFinalizers:
     case MethodRecognizer::kFinalizerBase_setIsolate:
     case MethodRecognizer::kFinalizerBase_setIsolateFinalizers:
     case MethodRecognizer::kFinalizerEntry_getExternalSize:
-      // Unboxed/untagged representation not supported in unoptimized.
-      return true;
+    case MethodRecognizer::kExtensionStreamHasListener:
+    case MethodRecognizer::kFfiLoadInt8:
+    case MethodRecognizer::kFfiLoadInt16:
+    case MethodRecognizer::kFfiLoadInt32:
+    case MethodRecognizer::kFfiLoadInt64:
+    case MethodRecognizer::kFfiLoadUint8:
+    case MethodRecognizer::kFfiLoadUint16:
+    case MethodRecognizer::kFfiLoadUint32:
+    case MethodRecognizer::kFfiLoadUint64:
+    case MethodRecognizer::kFfiLoadFloat:
+    case MethodRecognizer::kFfiLoadFloatUnaligned:
+    case MethodRecognizer::kFfiLoadDouble:
+    case MethodRecognizer::kFfiLoadDoubleUnaligned:
+    case MethodRecognizer::kFfiLoadPointer:
+    case MethodRecognizer::kFfiStoreInt8:
+    case MethodRecognizer::kFfiStoreInt16:
+    case MethodRecognizer::kFfiStoreInt32:
+    case MethodRecognizer::kFfiStoreInt64:
+    case MethodRecognizer::kFfiStoreUint8:
+    case MethodRecognizer::kFfiStoreUint16:
+    case MethodRecognizer::kFfiStoreUint32:
+    case MethodRecognizer::kFfiStoreUint64:
+    case MethodRecognizer::kFfiStoreFloat:
+    case MethodRecognizer::kFfiStoreFloatUnaligned:
+    case MethodRecognizer::kFfiStoreDouble:
+    case MethodRecognizer::kFfiStoreDoubleUnaligned:
+    case MethodRecognizer::kFfiStorePointer:
+    case MethodRecognizer::kFfiFromAddress:
+    case MethodRecognizer::kFfiGetAddress:
+    case MethodRecognizer::kFfiAsExternalTypedDataInt8:
+    case MethodRecognizer::kFfiAsExternalTypedDataInt16:
+    case MethodRecognizer::kFfiAsExternalTypedDataInt32:
+    case MethodRecognizer::kFfiAsExternalTypedDataInt64:
+    case MethodRecognizer::kFfiAsExternalTypedDataUint8:
+    case MethodRecognizer::kFfiAsExternalTypedDataUint16:
+    case MethodRecognizer::kFfiAsExternalTypedDataUint32:
+    case MethodRecognizer::kFfiAsExternalTypedDataUint64:
+    case MethodRecognizer::kFfiAsExternalTypedDataFloat:
+    case MethodRecognizer::kFfiAsExternalTypedDataDouble:
+    case MethodRecognizer::kGetNativeField:
+    case MethodRecognizer::kUtf8DecoderScan:
+    // Prevent the GC from running so that the operation is atomic from
+    // a GC point of view. Always double check implementation in
+    // kernel_to_il.cc that no GC can happen in between the relevant IL
+    // instructions.
+    // TODO(https://dartbug.com/48527): Support inlining.
     case MethodRecognizer::kFinalizerBase_exchangeEntriesCollectedWithNull:
-      // Prevent the GC from running so that the operation is atomic from
-      // a GC point of view. Always double check implementation in
-      // kernel_to_il.cc that no GC can happen in between the relevant IL
-      // instructions.
-      // TODO(https://dartbug.com/48527): Support inlining.
-      return true;
+    // Both unboxed/untagged data and atomic-to-GC operation.
     case MethodRecognizer::kFinalizerEntry_allocate:
-      // Both of the above reasons.
       return true;
     default:
       return false;
@@ -14538,6 +14574,7 @@
   all_libs.Add(&Library::ZoneHandle(Library::InternalLibrary()));
   all_libs.Add(&Library::ZoneHandle(Library::FfiLibrary()));
   all_libs.Add(&Library::ZoneHandle(Library::NativeWrappersLibrary()));
+  all_libs.Add(&Library::ZoneHandle(Library::DeveloperLibrary()));
   INTERNAL_LIB_INTRINSIC_LIST(CHECK_FINGERPRINTS_ASM_INTRINSIC);
   OTHER_RECOGNIZED_LIST(CHECK_FINGERPRINTS_OTHER);
   POLYMORPHIC_TARGET_LIST(CHECK_FINGERPRINTS);
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 7d9ffe0..3bd1912 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -3240,7 +3240,8 @@
   // run.
   bool ForceOptimize() const;
 
-  bool IsFinalizerForceOptimized() const;
+  // Whether this function's |recognized_kind| requires optimization.
+  bool RecognizedKindForceOptimize() const;
 
   bool CanBeInlined() const;
 
@@ -3549,44 +3550,6 @@
            UntaggedFunction::kFfiTrampoline;
   }
 
-  bool IsFfiLoad() const {
-    const auto kind = recognized_kind();
-    return MethodRecognizer::kFfiLoadInt8 <= kind &&
-           kind <= MethodRecognizer::kFfiLoadPointer;
-  }
-
-  bool IsFfiStore() const {
-    const auto kind = recognized_kind();
-    return MethodRecognizer::kFfiStoreInt8 <= kind &&
-           kind <= MethodRecognizer::kFfiStorePointer;
-  }
-
-  bool IsFfiFromAddress() const {
-    const auto kind = recognized_kind();
-    return kind == MethodRecognizer::kFfiFromAddress;
-  }
-
-  bool IsFfiGetAddress() const {
-    const auto kind = recognized_kind();
-    return kind == MethodRecognizer::kFfiGetAddress;
-  }
-
-  bool IsFfiAsExternalTypedData() const {
-    const auto kind = recognized_kind();
-    return MethodRecognizer::kFfiAsExternalTypedDataInt8 <= kind &&
-           kind <= MethodRecognizer::kFfiAsExternalTypedDataDouble;
-  }
-
-  bool IsGetNativeField() const {
-    const auto kind = recognized_kind();
-    return kind == MethodRecognizer::kGetNativeField;
-  }
-
-  bool IsUtf8Scan() const {
-    const auto kind = recognized_kind();
-    return kind == MethodRecognizer::kUtf8DecoderScan;
-  }
-
   // Recognise async functions like:
   //   user_func async {
   //     // ...
diff --git a/runtime/vm/object_reload.cc b/runtime/vm/object_reload.cc
index f591661..85f6653 100644
--- a/runtime/vm/object_reload.cc
+++ b/runtime/vm/object_reload.cc
@@ -656,10 +656,15 @@
               TypeParametersChanged(context->zone(), *this, replacement));
       return;
     }
+  }
+
+  if (is_finalized() || is_allocate_finalized()) {
+    auto thread = Thread::Current();
 
     // Ensure the replacement class is also finalized.
-    const Error& error =
-        Error::Handle(replacement.EnsureIsFinalized(Thread::Current()));
+    const Error& error = Error::Handle(
+        is_allocate_finalized() ? replacement.EnsureIsAllocateFinalized(thread)
+                                : replacement.EnsureIsFinalized(thread));
     if (!error.IsNull()) {
       context->group_reload_context()->AddReasonForCancelling(
           new (context->zone())
diff --git a/runtime/vm/service.h b/runtime/vm/service.h
index 6bf1e40..7dc4d45 100644
--- a/runtime/vm/service.h
+++ b/runtime/vm/service.h
@@ -5,6 +5,8 @@
 #ifndef RUNTIME_VM_SERVICE_H_
 #define RUNTIME_VM_SERVICE_H_
 
+#include <atomic>
+
 #include "include/dart_tools_api.h"
 
 #include "vm/allocation.h"
@@ -73,17 +75,20 @@
 
   const char* id() const { return id_; }
 
-  void set_enabled(bool value) { enabled_ = value; }
-  bool enabled() const { return enabled_; }
+  void set_enabled(bool value) { enabled_ = value ? 1 : 0; }
+  bool enabled() const { return !!enabled_; }
 
   void set_include_private_members(bool value) {
     include_private_members_ = value;
   }
   bool include_private_members() const { return include_private_members_; }
 
+  // This may get access by multiple threads, but relaxed access is ok.
+  static intptr_t enabled_offset() { return OFFSET_OF(StreamInfo, enabled_); }
+
  private:
   const char* id_;
-  bool enabled_;
+  std::atomic<intptr_t> enabled_;
   bool include_private_members_;
 };
 
diff --git a/runtime/vm/stack_trace.cc b/runtime/vm/stack_trace.cc
index 4c7cbcf..eee21f8 100644
--- a/runtime/vm/stack_trace.cc
+++ b/runtime/vm/stack_trace.cc
@@ -71,7 +71,7 @@
       future_listener_class(Class::Handle(zone)),
       async_start_stream_controller_class(Class::Handle(zone)),
       stream_controller_class(Class::Handle(zone)),
-      async_stream_controller_class(Class::Handle(zone)),
+      sync_stream_controller_class(Class::Handle(zone)),
       controller_subscription_class(Class::Handle(zone)),
       buffering_stream_subscription_class(Class::Handle(zone)),
       stream_iterator_class(Class::Handle(zone)),
@@ -100,9 +100,9 @@
   stream_controller_class =
       async_lib.LookupClassAllowPrivate(Symbols::_StreamController());
   ASSERT(!stream_controller_class.IsNull());
-  async_stream_controller_class =
-      async_lib.LookupClassAllowPrivate(Symbols::_AsyncStreamController());
-  ASSERT(!async_stream_controller_class.IsNull());
+  sync_stream_controller_class =
+      async_lib.LookupClassAllowPrivate(Symbols::_SyncStreamController());
+  ASSERT(!sync_stream_controller_class.IsNull());
   controller_subscription_class =
       async_lib.LookupClassAllowPrivate(Symbols::_ControllerSubscription());
   ASSERT(!controller_subscription_class.IsNull());
@@ -171,7 +171,7 @@
   const Instance& controller = Instance::Cast(context_entry_);
   controller_ = controller.GetField(controller_controller_field);
   ASSERT(!controller_.IsNull());
-  ASSERT(controller_.GetClassId() == async_stream_controller_class.id());
+  ASSERT(controller_.GetClassId() == sync_stream_controller_class.id());
 
   // Get the _StreamController._state field.
   state_ = Instance::Cast(controller_).GetField(state_field);
@@ -209,7 +209,7 @@
     // contains the iterator's value. In that case we cannot unwind anymore.
     //
     // Notice: With correct async* semantics this may never be true: The async*
-    // generator should only be invoked to produce a vaue if there's an
+    // generator should only be invoked to produce a value if there's an
     // in-progress `await streamIterator.moveNext()` call. Once such call has
     // finished the async* generator should be paused/yielded until the next
     // such call - and being paused/yielded means it should not appear in stack
diff --git a/runtime/vm/stack_trace.h b/runtime/vm/stack_trace.h
index 0683cf7..58a4cba 100644
--- a/runtime/vm/stack_trace.h
+++ b/runtime/vm/stack_trace.h
@@ -78,7 +78,7 @@
   Class& future_listener_class;
   Class& async_start_stream_controller_class;
   Class& stream_controller_class;
-  Class& async_stream_controller_class;
+  Class& sync_stream_controller_class;
   Class& controller_subscription_class;
   Class& buffering_stream_subscription_class;
   Class& stream_iterator_class;
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 52ec048..f96d8d3 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -278,7 +278,6 @@
   V(Values, "values")                                                          \
   V(WeakSerializationReference, "WeakSerializationReference")                  \
   V(_AsyncStarStreamController, "_AsyncStarStreamController")                  \
-  V(_AsyncStreamController, "_AsyncStreamController")                          \
   V(_BufferingStreamSubscription, "_BufferingStreamSubscription")              \
   V(_ByteBuffer, "_ByteBuffer")                                                \
   V(_ByteBufferDot_New, "_ByteBuffer._New")                                    \
@@ -381,6 +380,7 @@
   V(_StreamIterator, "_StreamIterator")                                        \
   V(_String, "String")                                                         \
   V(_SyncIterator, "_SyncIterator")                                            \
+  V(_SyncStreamController, "_SyncStreamController")                            \
   V(_TransferableTypedDataImpl, "_TransferableTypedDataImpl")                  \
   V(_Type, "_Type")                                                            \
   V(_FunctionType, "_FunctionType")                                            \
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index e8ad780..573e775 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -19,6 +19,7 @@
 #include "vm/os_thread.h"
 #include "vm/profiler.h"
 #include "vm/runtime_entry.h"
+#include "vm/service.h"
 #include "vm/stub_code.h"
 #include "vm/symbols.h"
 #include "vm/thread_interrupter.h"
@@ -39,15 +40,15 @@
 
 Thread::~Thread() {
   // We should cleanly exit any isolate before destruction.
-  ASSERT(isolate_ == NULL);
-  ASSERT(store_buffer_block_ == NULL);
-  ASSERT(marking_stack_block_ == NULL);
+  ASSERT(isolate_ == nullptr);
+  ASSERT(store_buffer_block_ == nullptr);
+  ASSERT(marking_stack_block_ == nullptr);
   // There should be no top api scopes at this point.
-  ASSERT(api_top_scope() == NULL);
+  ASSERT(api_top_scope() == nullptr);
   // Delete the resusable api scope if there is one.
   if (api_reusable_scope_ != nullptr) {
     delete api_reusable_scope_;
-    api_reusable_scope_ = NULL;
+    api_reusable_scope_ = nullptr;
   }
 
   DO_IF_TSAN(delete tsan_utils_);
@@ -60,21 +61,21 @@
 #define REUSABLE_HANDLE_SCOPE_INIT(object)
 #endif  // defined(DEBUG)
 
-#define REUSABLE_HANDLE_INITIALIZERS(object) object##_handle_(NULL),
+#define REUSABLE_HANDLE_INITIALIZERS(object) object##_handle_(nullptr),
 
 Thread::Thread(bool is_vm_isolate)
     : ThreadState(false),
       stack_limit_(0),
       write_barrier_mask_(UntaggedObject::kGenerationalBarrierMask),
       heap_base_(0),
-      isolate_(NULL),
-      dispatch_table_array_(NULL),
+      isolate_(nullptr),
+      dispatch_table_array_(nullptr),
       saved_stack_limit_(0),
       stack_overflow_flags_(0),
-      heap_(NULL),
+      heap_(nullptr),
       top_exit_frame_info_(0),
-      store_buffer_block_(NULL),
-      marking_stack_block_(NULL),
+      store_buffer_block_(nullptr),
+      marking_stack_block_(nullptr),
       vm_tag_(0),
       unboxed_int64_runtime_arg_(0),
       unboxed_double_runtime_arg_(0.0),
@@ -86,32 +87,37 @@
       safepoint_state_(0),
       ffi_callback_code_(GrowableObjectArray::null()),
       ffi_callback_stack_return_(TypedData::null()),
-      api_top_scope_(NULL),
+      api_top_scope_(nullptr),
       double_truncate_round_supported_(
           TargetCPUFeatures::double_truncate_round_supported() ? 1 : 0),
       tsan_utils_(DO_IF_TSAN(new TsanUtils()) DO_IF_NOT_TSAN(nullptr)),
       task_kind_(kUnknownTask),
-      dart_stream_(NULL),
+      dart_stream_(nullptr),
+      service_extension_stream_(nullptr),
       thread_lock_(),
-      api_reusable_scope_(NULL),
+      api_reusable_scope_(nullptr),
       no_callback_scope_depth_(0),
 #if defined(DEBUG)
       no_safepoint_scope_depth_(0),
 #endif
       reusable_handles_(),
       stack_overflow_count_(0),
-      hierarchy_info_(NULL),
-      type_usage_info_(NULL),
+      hierarchy_info_(nullptr),
+      type_usage_info_(nullptr),
       sticky_error_(Error::null()),
       REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS)
           REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_SCOPE_INIT)
 #if defined(USING_SAFE_STACK)
               saved_safestack_limit_(0),
 #endif
-      next_(NULL) {
+      next_(nullptr) {
 #if defined(SUPPORT_TIMELINE)
   dart_stream_ = Timeline::GetDartStream();
-  ASSERT(dart_stream_ != NULL);
+  ASSERT(dart_stream_ != nullptr);
+#endif
+#ifndef PRODUCT
+  service_extension_stream_ = &Service::extension_stream;
+  ASSERT(service_extension_stream_ != nullptr);
 #endif
 #define DEFAULT_INIT(type_name, member_name, init_expr, default_init_value)    \
   member_name = default_init_value;
@@ -276,8 +282,8 @@
 
   Thread* thread = isolate->ScheduleThread(kIsMutatorThread, is_nested_reenter,
                                            kBypassSafepoint);
-  if (thread != NULL) {
-    ASSERT(thread->store_buffer_block_ == NULL);
+  if (thread != nullptr) {
+    ASSERT(thread->store_buffer_block_ == nullptr);
     ASSERT(thread->isolate() == isolate);
     ASSERT(thread->isolate_group() == isolate->group());
     thread->FinishEntering(kMutatorTask);
@@ -316,7 +322,7 @@
   const bool kIsNestedReenter = false;
   Thread* thread = isolate->ScheduleThread(kIsMutatorThread, kIsNestedReenter,
                                            bypass_safepoint);
-  if (thread != NULL) {
+  if (thread != nullptr) {
     ASSERT(!thread->IsMutatorThread());
     ASSERT(thread->isolate() == isolate);
     ASSERT(thread->isolate_group() == isolate->group());
@@ -336,7 +342,7 @@
   thread->PrepareLeaving();
 
   Isolate* isolate = thread->isolate();
-  ASSERT(isolate != NULL);
+  ASSERT(isolate != nullptr);
   const bool kIsMutatorThread = false;
   const bool kIsNestedExit = false;
   isolate->UnscheduleThread(thread, kIsMutatorThread, kIsNestedExit,
@@ -348,7 +354,7 @@
                                        bool bypass_safepoint) {
   ASSERT(kind != kMutatorTask);
   Thread* thread = isolate_group->ScheduleThread(bypass_safepoint);
-  if (thread != NULL) {
+  if (thread != nullptr) {
     ASSERT(!thread->IsMutatorThread());
     ASSERT(thread->isolate() == nullptr);
     ASSERT(thread->isolate_group() == isolate_group);
@@ -375,7 +381,7 @@
 void Thread::ReleaseStoreBuffer() {
   ASSERT(IsAtSafepoint());
   // Prevent scheduling another GC by ignoring the threshold.
-  ASSERT(store_buffer_block_ != NULL);
+  ASSERT(store_buffer_block_ != nullptr);
   StoreBufferRelease(StoreBuffer::kIgnoreThreshold);
   // Make sure to get an *empty* block; the isolate needs all entries
   // at GC time.
@@ -502,7 +508,7 @@
 
 void Thread::StoreBufferRelease(StoreBuffer::ThresholdPolicy policy) {
   StoreBufferBlock* block = store_buffer_block_;
-  store_buffer_block_ = NULL;
+  store_buffer_block_ = nullptr;
   isolate_group()->store_buffer()->PushBlock(block, policy);
 }
 
@@ -536,7 +542,7 @@
 
 void Thread::MarkingStackRelease() {
   MarkingStackBlock* block = marking_stack_block_;
-  marking_stack_block_ = NULL;
+  marking_stack_block_ = nullptr;
   write_barrier_mask_ = UntaggedObject::kGenerationalBarrierMask;
   isolate_group()->marking_stack()->PushBlock(block);
 }
@@ -549,7 +555,7 @@
 
 void Thread::DeferredMarkingStackRelease() {
   MarkingStackBlock* block = deferred_marking_stack_block_;
-  deferred_marking_stack_block_ = NULL;
+  deferred_marking_stack_block_ = nullptr;
   isolate_group()->deferred_marking_stack()->PushBlock(block);
 }
 
@@ -591,9 +597,9 @@
 
 void Thread::VisitObjectPointers(ObjectPointerVisitor* visitor,
                                  ValidationPolicy validation_policy) {
-  ASSERT(visitor != NULL);
+  ASSERT(visitor != nullptr);
 
-  if (zone() != NULL) {
+  if (zone() != nullptr) {
     zone()->VisitObjectPointers(visitor);
   }
 
@@ -610,7 +616,7 @@
 
   // Visit the api local scope as it has all the api local handles.
   ApiLocalScope* scope = api_top_scope_;
-  while (scope != NULL) {
+  while (scope != nullptr) {
     scope->local_handles()->VisitObjectPointers(visitor);
     scope = scope->previous();
   }
@@ -634,7 +640,7 @@
     StackFrameIterator frames_iterator(top_exit_frame_info(), validation_policy,
                                        this, cross_thread_policy);
     StackFrame* frame = frames_iterator.NextFrame();
-    while (frame != NULL) {
+    while (frame != nullptr) {
       frame->VisitObjectPointers(visitor);
       frame = frames_iterator.NextFrame();
     }
@@ -735,7 +741,7 @@
   RestoreWriteBarrierInvariantVisitor visitor(isolate_group(), this, op);
   ObjectStore* object_store = isolate_group()->object_store();
   bool scan_next_dart_frame = false;
-  for (StackFrame* frame = frames_iterator.NextFrame(); frame != NULL;
+  for (StackFrame* frame = frames_iterator.NextFrame(); frame != nullptr;
        frame = frames_iterator.NextFrame()) {
     if (frame->IsExitFrame()) {
       scan_next_dart_frame = true;
@@ -891,7 +897,7 @@
 
 bool Thread::IsValidLocalHandle(Dart_Handle object) const {
   ApiLocalScope* scope = api_top_scope_;
-  while (scope != NULL) {
+  while (scope != nullptr) {
     if (scope->local_handles()->IsValidHandle(object)) {
       return true;
     }
@@ -903,7 +909,7 @@
 intptr_t Thread::CountLocalHandles() const {
   intptr_t total = 0;
   ApiLocalScope* scope = api_top_scope_;
-  while (scope != NULL) {
+  while (scope != nullptr) {
     total += scope->local_handles()->CountHandles();
     scope = scope->previous();
   }
@@ -913,7 +919,7 @@
 int Thread::ZoneSizeInBytes() const {
   int total = 0;
   ApiLocalScope* scope = api_top_scope_;
-  while (scope != NULL) {
+  while (scope != nullptr) {
     total += scope->zone()->SizeInBytes();
     scope = scope->previous();
   }
@@ -923,12 +929,12 @@
 void Thread::EnterApiScope() {
   ASSERT(MayAllocateHandles());
   ApiLocalScope* new_scope = api_reusable_scope();
-  if (new_scope == NULL) {
+  if (new_scope == nullptr) {
     new_scope = new ApiLocalScope(api_top_scope(), top_exit_frame_info());
-    ASSERT(new_scope != NULL);
+    ASSERT(new_scope != nullptr);
   } else {
     new_scope->Reinit(this, api_top_scope(), top_exit_frame_info());
-    set_api_reusable_scope(NULL);
+    set_api_reusable_scope(nullptr);
   }
   set_api_top_scope(new_scope);  // New scope is now the top scope.
 }
@@ -938,7 +944,7 @@
   ApiLocalScope* scope = api_top_scope();
   ApiLocalScope* reusable_scope = api_reusable_scope();
   set_api_top_scope(scope->previous());  // Reset top scope to previous.
-  if (reusable_scope == NULL) {
+  if (reusable_scope == nullptr) {
     scope->Reset(this);  // Reset the old scope which we just exited.
     set_api_reusable_scope(scope);
   } else {
@@ -951,7 +957,7 @@
   // Unwind all scopes using the same stack_marker, i.e. all scopes allocated
   // under the same top_exit_frame_info.
   ApiLocalScope* scope = api_top_scope_;
-  while (scope != NULL && scope->stack_marker() != 0 &&
+  while (scope != nullptr && scope->stack_marker() != 0 &&
          scope->stack_marker() == stack_marker) {
     api_top_scope_ = scope->previous();
     delete scope;
@@ -975,7 +981,7 @@
   ASSERT(store_buffer_block_ == nullptr);
 
   task_kind_ = kind;
-  if (isolate_group()->marking_stack() != NULL) {
+  if (isolate_group()->marking_stack() != nullptr) {
     // Concurrent mark in progress. Enable barrier for this thread.
     MarkingStackAcquire();
     DeferredMarkingStackAcquire();
@@ -1004,17 +1010,17 @@
 
 DisableThreadInterruptsScope::DisableThreadInterruptsScope(Thread* thread)
     : StackResource(thread) {
-  if (thread != NULL) {
+  if (thread != nullptr) {
     OSThread* os_thread = thread->os_thread();
-    ASSERT(os_thread != NULL);
+    ASSERT(os_thread != nullptr);
     os_thread->DisableThreadInterrupts();
   }
 }
 
 DisableThreadInterruptsScope::~DisableThreadInterruptsScope() {
-  if (thread() != NULL) {
+  if (thread() != nullptr) {
     OSThread* os_thread = thread()->os_thread();
-    ASSERT(os_thread != NULL);
+    ASSERT(os_thread != nullptr);
     os_thread->EnableThreadInterrupts();
   }
 }
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 15a7bd9..5918a36 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -58,6 +58,7 @@
 class Smi;
 class StackResource;
 class StackTrace;
+class StreamInfo;
 class String;
 class TimelineStream;
 class TypeArguments;
@@ -512,6 +513,11 @@
     return OFFSET_OF(Thread, dart_stream_);
   }
 
+  // Offset of the Dart VM Service Extension StreamInfo object.
+  static intptr_t service_extension_stream_offset() {
+    return OFFSET_OF(Thread, service_extension_stream_);
+  }
+
   // Is |this| executing Dart code?
   bool IsExecutingDartCode() const;
 
@@ -1173,6 +1179,7 @@
 
   TaskKind task_kind_;
   TimelineStream* dart_stream_;
+  StreamInfo* service_extension_stream_;
   IsolateGroup* isolate_group_ = nullptr;
   mutable Monitor thread_lock_;
   ApiLocalScope* api_reusable_scope_;
diff --git a/sdk/lib/_internal/js_dev_runtime/patch/developer_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/developer_patch.dart
index 761bf6e..c451d7f 100644
--- a/sdk/lib/_internal/js_dev_runtime/patch/developer_patch.dart
+++ b/sdk/lib/_internal/js_dev_runtime/patch/developer_patch.dart
@@ -11,7 +11,6 @@
 import 'dart:convert' show json;
 import 'dart:isolate';
 
-var _issuedPostEventWarning = false;
 var _issuedRegisterExtensionWarning = false;
 final _developerSupportWarning = 'from dart:developer is only supported in '
     'build/run/test environments where the developer event method hooks have '
@@ -117,15 +116,10 @@
 }
 
 @patch
+bool get extensionStreamHasListener => _debuggerAttached;
+
+@patch
 void _postEvent(String eventKind, String eventData) {
-  if (!_debuggerAttached) {
-    if (!_issuedPostEventWarning) {
-      var message = 'postEvent() $_developerSupportWarning';
-      JS('', 'console.warn(#)', message);
-      _issuedPostEventWarning = true;
-    }
-    return;
-  }
   // TODO(46377) Update this check when we have a documented API for DDC apps.
   if (JS<bool>('!', r'!!#.$emitDebugEvent', dart.global_)) {
     // See hooks assigned by package:dwds:
diff --git a/sdk/lib/_internal/js_runtime/lib/developer_patch.dart b/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
index feb0d48..54f7ca1 100644
--- a/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
@@ -48,6 +48,9 @@
 }
 
 @patch
+bool get extensionStreamHasListener => false;
+
+@patch
 void _postEvent(String eventKind, String eventData) {
   // TODO.
 }
diff --git a/sdk/lib/_internal/vm/lib/async_patch.dart b/sdk/lib/_internal/vm/lib/async_patch.dart
index 2e322f1..3d4b20b 100644
--- a/sdk/lib/_internal/vm/lib/async_patch.dart
+++ b/sdk/lib/_internal/vm/lib/async_patch.dart
@@ -117,6 +117,13 @@
   bool isSuspendedAtYield = false;
   _Future? cancellationFuture = null;
 
+  /// Argument passed to the generator when it is resumed after an addStream.
+  ///
+  /// `true` if the generator should exit after `yield*` resumes.
+  /// `false` if the generator should continue after `yield*` resumes.
+  /// `null` otherwies.
+  bool? continuationArgument = null;
+
   Stream<T> get stream {
     final Stream<T> local = controller.stream;
     if (local is _StreamImpl<T>) {
@@ -128,7 +135,9 @@
   void runBody() {
     isScheduled = false;
     isSuspendedAtYield = false;
-    asyncStarBody(null, null);
+    final bool? argument = continuationArgument;
+    continuationArgument = null;
+    asyncStarBody(argument, null);
   }
 
   void scheduleGenerator() {
@@ -152,11 +161,11 @@
   bool add(T event) {
     if (!onListenReceived) _fatal("yield before stream is listened to");
     if (isSuspendedAtYield) _fatal("unexpected yield");
-    // If stream is cancelled, tell caller to exit the async generator.
+    controller.add(event);
     if (!controller.hasListener) {
       return true;
     }
-    controller.add(event);
+
     scheduleGenerator();
     isSuspendedAtYield = true;
     return false;
@@ -165,22 +174,41 @@
   // Adds the elements of stream into this controller's stream.
   // The generator will be scheduled again when all of the
   // elements of the added stream have been consumed.
-  // Returns true if the caller should terminate
-  // execution of the generator.
-  bool addStream(Stream<T> stream) {
+  void addStream(Stream<T> stream) {
     if (!onListenReceived) _fatal("yield before stream is listened to");
-    // If stream is cancelled, tell caller to exit the async generator.
-    if (!controller.hasListener) return true;
+
+    if (exitAfterYieldStarIfCancelled()) return;
+
     isAdding = true;
-    var whenDoneAdding = controller.addStream(stream, cancelOnError: false);
+    final whenDoneAdding = controller.addStream(stream, cancelOnError: false);
     whenDoneAdding.then((_) {
       isAdding = false;
-      scheduleGenerator();
-      if (!isScheduled) isSuspendedAtYield = true;
+      if (exitAfterYieldStarIfCancelled()) return;
+      resumeNormallyAfterYieldStar();
     });
+  }
+
+  /// Schedules the generator to exit after `yield*` if stream was cancelled.
+  ///
+  /// Returns `true` if generator is told to exit and `false` otherwise.
+  bool exitAfterYieldStarIfCancelled() {
+    // If consumer cancelled subscription we should tell async* generator to
+    // finish (i.e. run finally clauses and return).
+    if (!controller.hasListener) {
+      continuationArgument = true;
+      scheduleGenerator();
+      return true;
+    }
     return false;
   }
 
+  /// Schedules the generator to resume normally after `yield*`.
+  void resumeNormallyAfterYieldStar() {
+    continuationArgument = false;
+    scheduleGenerator();
+    if (!isScheduled) isSuspendedAtYield = true;
+  }
+
   void addError(Object error, StackTrace stackTrace) {
     // TODO(40614): Remove once non-nullability is sound.
     ArgumentError.checkNotNull(error, "error");
@@ -211,7 +239,7 @@
   }
 
   _AsyncStarStreamController(this.asyncStarBody)
-      : controller = new StreamController() {
+      : controller = new StreamController(sync: true) {
     controller.onListen = this.onListen;
     controller.onResume = this.onResume;
     controller.onCancel = this.onCancel;
diff --git a/sdk/lib/_internal/wasm/lib/developer.dart b/sdk/lib/_internal/wasm/lib/developer.dart
index ba930b3..32d3050 100644
--- a/sdk/lib/_internal/wasm/lib/developer.dart
+++ b/sdk/lib/_internal/wasm/lib/developer.dart
@@ -27,6 +27,9 @@
     StackTrace? stackTrace}) {}
 
 @patch
+bool get extensionStreamHasListener => false;
+
+@patch
 void _postEvent(String eventKind, String eventData) {}
 
 @patch
diff --git a/sdk/lib/developer/developer.dart b/sdk/lib/developer/developer.dart
index e9df841..2d8e15c 100644
--- a/sdk/lib/developer/developer.dart
+++ b/sdk/lib/developer/developer.dart
@@ -15,6 +15,7 @@
 /// {@category Core}
 library dart.developer;
 
+import "dart:_internal" show checkNotNullable;
 import 'dart:async';
 import 'dart:convert';
 import 'dart:isolate' show Isolate, RawReceivePort, SendPort;
diff --git a/sdk/lib/developer/extension.dart b/sdk/lib/developer/extension.dart
index 184a00f..aa10674 100644
--- a/sdk/lib/developer/extension.dart
+++ b/sdk/lib/developer/extension.dart
@@ -27,7 +27,7 @@
         errorCode = null,
         errorDetail = null {
     // TODO: When NNBD is complete, delete the following line.
-    ArgumentError.checkNotNull(result, "result");
+    checkNotNullable(result, "result");
   }
 
   /// Creates an error response to a service protocol extension RPC.
@@ -42,7 +42,7 @@
         errorDetail = errorDetail {
     _validateErrorCode(errorCode);
     // TODO: When NNBD is complete, delete the following line.
-    ArgumentError.checkNotNull(errorDetail, "errorDetail");
+    checkNotNullable(errorDetail, "errorDetail");
   }
 
   /// Invalid method parameter(s) error code.
@@ -83,7 +83,7 @@
 
   static _validateErrorCode(int errorCode) {
     // TODO: When NNBD is complete, delete the following line.
-    ArgumentError.checkNotNull(errorCode, "errorCode");
+    checkNotNullable(errorCode, "errorCode");
     if (errorCode == invalidParams) return;
     if ((errorCode >= extensionErrorMin) && (errorCode <= extensionErrorMax)) {
       return;
@@ -129,7 +129,7 @@
 /// must always include an 'isolateId' parameter with each RPC.
 void registerExtension(String method, ServiceExtensionHandler handler) {
   // TODO: When NNBD is complete, delete the following line.
-  ArgumentError.checkNotNull(method, 'method');
+  checkNotNullable(method, 'method');
   if (!method.startsWith('ext.')) {
     throw new ArgumentError.value(method, 'method', 'Must begin with ext.');
   }
@@ -137,16 +137,38 @@
     throw new ArgumentError('Extension already registered: $method');
   }
   // TODO: When NNBD is complete, delete the following line.
-  ArgumentError.checkNotNull(handler, 'handler');
+  checkNotNullable(handler, 'handler');
   _registerExtension(method, handler);
 }
 
-/// Post an event of [eventKind] with payload of [eventData] to the `Extension`
+/// Whether the "Extension" stream currently has at least one listener.
+///
+/// A client of the VM service can register as a listener
+/// on the extension stream using `listenStream` method.
+/// The extension stream has a listener while at least one such
+/// client has registered as a listener, and has not yet disconnected
+/// again.
+///
+/// Calling [postEvent] while the stream has listeners will attempt to
+/// deliver that event to all current listeners,
+/// although a listener can disconnect before the event is delivered.
+/// Calling [postEvent] when the stream has no listener means that
+/// no-one will receive the event, and the call is effectively a no-op.
+@pragma("vm:recognized", "other")
+@pragma("vm:prefer-inline")
+external bool get extensionStreamHasListener;
+
+/// Post an event of [eventKind] with payload of [eventData] to the "Extension"
 /// event stream.
+///
+/// If [extensionStreamHasListener] is false, this method is a no-op.
 void postEvent(String eventKind, Map eventData) {
+  if (!extensionStreamHasListener) {
+    return;
+  }
   // TODO: When NNBD is complete, delete the following two lines.
-  ArgumentError.checkNotNull(eventKind, 'eventKind');
-  ArgumentError.checkNotNull(eventData, 'eventData');
+  checkNotNullable(eventKind, 'eventKind');
+  checkNotNullable(eventData, 'eventData');
   String eventDataAsString = json.encode(eventData);
   _postEvent(eventKind, eventDataAsString);
 }
diff --git a/tests/dartdevc/developer_events_test.dart b/tests/dartdevc/developer_events_test.dart
index 907d801..22481f8 100644
--- a/tests/dartdevc/developer_events_test.dart
+++ b/tests/dartdevc/developer_events_test.dart
@@ -122,17 +122,15 @@
     var data0 = {'key0': 'value0'};
     postEvent('kind0', data0);
 
-    // A warning message was issued about calling `postEvent()` from
-    // dart:developer.
-    expect(consoleWarnLog.single.contains('postEvent() from dart:developer'),
-        true);
+    // Nothing is listening, so this was a no-op.
+    expect(consoleWarnLog.isEmpty, true);
 
     postEvent('kind0', data0);
     var data1 = {'key1': 'value1'};
     postEvent('kind1', data1);
 
-    // A warning is only issued on the first call of `postEvent()`.
-    expect(consoleWarnLog.length, 1);
+    // No warnings should be issued because postEvent is a no-op.
+    expect(consoleWarnLog.length, 0);
 
     consoleWarnLog.clear();
 
diff --git a/tests/dartdevc_2/developer_events_test.dart b/tests/dartdevc_2/developer_events_test.dart
index 8bc5ed8..d185121 100644
--- a/tests/dartdevc_2/developer_events_test.dart
+++ b/tests/dartdevc_2/developer_events_test.dart
@@ -122,17 +122,15 @@
     var data0 = {'key0': 'value0'};
     postEvent('kind0', data0);
 
-    // A warning message was issued about calling `postEvent()` from
-    // dart:developer.
-    expect(consoleWarnLog.single.contains('postEvent() from dart:developer'),
-        true);
+    // Nothing is listening, so this was a no-op.
+    expect(consoleWarnLog.isEmpty, true);
 
     postEvent('kind0', data0);
     var data1 = {'key1': 'value1'};
     postEvent('kind1', data1);
 
-    // A warning is only issued on the first call of `postEvent()`.
-    expect(consoleWarnLog.length, 1);
+    // No warnings should be issued because postEvent is a no-op.
+    expect(consoleWarnLog.length, 0);
 
     consoleWarnLog.clear();
 
diff --git a/tests/language/async_star/pause2_test.dart b/tests/language/async_star/pause2_test.dart
index a240d3d..3df0223 100644
--- a/tests/language/async_star/pause2_test.dart
+++ b/tests/language/async_star/pause2_test.dart
@@ -72,8 +72,8 @@
     f() async* {
       int i = 0;
       while (true) {
-        yield i;
         list.add(i);
+        yield i;
         i++;
       }
     }
diff --git a/tests/language/async_star/throw_in_catch_test.dart b/tests/language/async_star/throw_in_catch_test.dart
index 88982e5..7509a00 100644
--- a/tests/language/async_star/throw_in_catch_test.dart
+++ b/tests/language/async_star/throw_in_catch_test.dart
@@ -115,7 +115,7 @@
 test() async {
   // TODO(sigurdm): These tests are too dependent on scheduling, and buffering
   // behavior.
-  await runTest(foo1, "abcYdgC", null, true);
+  await runTest(foo1, "abcYgC", null, true);
   await runTest(foo2, "abcX", "Error", false);
   await runTest(foo3, "abcYX", "Error", false);
   await runTest(foo4, "abcYdYefX", "Error2", false);
diff --git a/tests/language_2/async_star/pause2_test.dart b/tests/language_2/async_star/pause2_test.dart
index 11e0429..f6e8d5f 100644
--- a/tests/language_2/async_star/pause2_test.dart
+++ b/tests/language_2/async_star/pause2_test.dart
@@ -74,8 +74,8 @@
     f() async* {
       int i = 0;
       while (true) {
-        yield i;
         list.add(i);
+        yield i;
         i++;
       }
     }
diff --git a/tests/language_2/async_star/throw_in_catch_test.dart b/tests/language_2/async_star/throw_in_catch_test.dart
index 57b6b0e..6a26245 100644
--- a/tests/language_2/async_star/throw_in_catch_test.dart
+++ b/tests/language_2/async_star/throw_in_catch_test.dart
@@ -118,7 +118,7 @@
 test() async {
   // TODO(sigurdm): These tests are too dependent on scheduling, and buffering
   // behavior.
-  await runTest(foo1, "abcYdgC", null, true);
+  await runTest(foo1, "abcYgC", null, true);
   await runTest(foo2, "abcX", "Error", false);
   await runTest(foo3, "abcYX", "Error", false);
   await runTest(foo4, "abcYdYefX", "Error2", false);
diff --git a/tools/VERSION b/tools/VERSION
index f388a5b..b8f61eb 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 18
 PATCH 0
-PRERELEASE 58
+PRERELEASE 59
 PRERELEASE_PATCH 0
\ No newline at end of file