Version 2.17.0-185.0.dev

Merge commit '81860accbcf8d221b582f3c9e629adcd1fcc182d' into 'dev'
diff --git a/pkg/analysis_server/lib/src/analysis_server_abstract.dart b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
index b60182d..e2c434e 100644
--- a/pkg/analysis_server/lib/src/analysis_server_abstract.dart
+++ b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
@@ -390,13 +390,13 @@
   }
 
   /// Return the unresolved unit for the file with the given [path].
-  ParsedUnitResult? getParsedUnit(String path) {
+  Future<ParsedUnitResult?> getParsedUnit(String path) async {
     if (!file_paths.isDart(resourceProvider.pathContext, path)) {
       return null;
     }
 
     var session = getAnalysisDriver(path)?.currentSession;
-    var result = session?.getParsedUnit(path);
+    var result = await session?.getParsedUnit2(path);
     return result is ParsedUnitResult ? result : null;
   }
 
diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
index eeda336..3949a6f 100644
--- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -518,7 +518,7 @@
     }
 
     // Prepare the file information.
-    var result = server.getParsedUnit(file);
+    var result = await server.getParsedUnit(file);
     if (result == null) {
       server.sendResponse(Response.fileNotAnalyzed(request, file));
       return;
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart
index 36aff2e..3c54395 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart
@@ -180,7 +180,7 @@
   }
 
   /// Get the location of the code (excluding leading doc comments) for this element.
-  protocol.Location? _getCodeLocation(Element element) {
+  Future<protocol.Location?> _getCodeLocation(Element element) async {
     var codeElement = element;
     // For synthetic getters created for fields, we need to access the associated
     // variable to get the codeOffset/codeLength.
@@ -206,7 +206,7 @@
     // Read the declaration so we can get the offset after the doc comments.
     // TODO(dantup): Skip this for parts (getParsedLibrary will throw), but find
     // a better solution.
-    final declaration = _parsedDeclaration(codeElement);
+    final declaration = await _parsedDeclaration(codeElement);
     var node = declaration?.node;
     if (node is VariableDeclaration) {
       node = node.parent;
@@ -244,9 +244,11 @@
         : null;
   }
 
-  void _updateTargetsWithCodeLocations(NavigationCollectorImpl collector) {
+  Future<void> _updateTargetsWithCodeLocations(
+    NavigationCollectorImpl collector,
+  ) async {
     for (var targetToUpdate in collector.targetsToUpdate) {
-      var codeLocation = _getCodeLocation(targetToUpdate.element);
+      var codeLocation = await _getCodeLocation(targetToUpdate.element);
       if (codeLocation != null) {
         targetToUpdate.target
           ..codeOffset = codeLocation.offset
@@ -255,7 +257,9 @@
     }
   }
 
-  static ElementDeclarationResult? _parsedDeclaration(Element element) {
+  static Future<ElementDeclarationResult?> _parsedDeclaration(
+    Element element,
+  ) async {
     var session = element.session;
     if (session == null) {
       return null;
@@ -266,7 +270,7 @@
       return null;
     }
 
-    var parsedLibrary = session.getParsedLibrary(libraryPath);
+    var parsedLibrary = await session.getParsedLibrary2(libraryPath);
     if (parsedLibrary is! ParsedLibraryResult) {
       return null;
     }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_folding.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_folding.dart
index 1149fff..a14bb7d 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_folding.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_folding.dart
@@ -30,7 +30,7 @@
       final partialResults = <List<FoldingRegion>>[];
       LineInfo? lineInfo;
 
-      final unit = server.getParsedUnit(path);
+      final unit = await server.getParsedUnit(path);
       if (unit != null) {
         lineInfo = unit.lineInfo;
 
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_format_on_type.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_format_on_type.dart
index 84da8f2..528c52b 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_format_on_type.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_format_on_type.dart
@@ -20,14 +20,14 @@
   LspJsonHandler<DocumentOnTypeFormattingParams> get jsonHandler =>
       DocumentOnTypeFormattingParams.jsonHandler;
 
-  ErrorOr<List<TextEdit>?> formatFile(String path) {
+  Future<ErrorOr<List<TextEdit>?>> formatFile(String path) async {
     final file = server.resourceProvider.getFile(path);
     if (!file.exists) {
       return error(
           ServerErrorCodes.InvalidFilePath, 'File does not exist', path);
     }
 
-    final result = server.getParsedUnit(path);
+    final result = await server.getParsedUnit(path);
     if (result == null || result.errors.isNotEmpty) {
       return success(null);
     }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_format_range.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_format_range.dart
index f28ef15..44143fc 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_format_range.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_format_range.dart
@@ -20,14 +20,14 @@
   LspJsonHandler<DocumentRangeFormattingParams> get jsonHandler =>
       DocumentRangeFormattingParams.jsonHandler;
 
-  ErrorOr<List<TextEdit>?> formatRange(String path, Range range) {
+  Future<ErrorOr<List<TextEdit>?>> formatRange(String path, Range range) async {
     final file = server.resourceProvider.getFile(path);
     if (!file.exists) {
       return error(
           ServerErrorCodes.InvalidFilePath, 'File does not exist', path);
     }
 
-    final result = server.getParsedUnit(path);
+    final result = await server.getParsedUnit(path);
     if (result == null || result.errors.isNotEmpty) {
       return success(null);
     }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_formatting.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_formatting.dart
index 6ff4313..ea279ad 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_formatting.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_formatting.dart
@@ -20,14 +20,14 @@
   LspJsonHandler<DocumentFormattingParams> get jsonHandler =>
       DocumentFormattingParams.jsonHandler;
 
-  ErrorOr<List<TextEdit>?> formatFile(String path) {
+  Future<ErrorOr<List<TextEdit>?>> formatFile(String path) async {
     final file = server.resourceProvider.getFile(path);
     if (!file.exists) {
       return error(
           ServerErrorCodes.InvalidFilePath, 'File does not exist', path);
     }
 
-    final result = server.getParsedUnit(path);
+    final result = await server.getParsedUnit(path);
     if (result == null || result.errors.isNotEmpty) {
       return success(null);
     }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_select_range.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_select_range.dart
index 193002f..0a97e4d 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_select_range.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_select_range.dart
@@ -39,7 +39,7 @@
         return success(null);
       }
 
-      final unit = requireUnresolvedUnit(path);
+      final unit = await requireUnresolvedUnit(path);
       final positions = params.positions;
       final offsets = await unit.mapResult((unit) =>
           ErrorOr.all(positions.map((pos) => toOffset(unit.lineInfo, pos))));
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart b/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart
index ddd82dc..0e1c738 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart
@@ -83,8 +83,8 @@
     return success(result);
   }
 
-  ErrorOr<ParsedUnitResult> requireUnresolvedUnit(String path) {
-    final result = server.getParsedUnit(path);
+  Future<ErrorOr<ParsedUnitResult>> requireUnresolvedUnit(String path) async {
+    final result = await server.getParsedUnit(path);
     if (result == null) {
       if (server.isAnalyzed(path)) {
         // If the file was being analyzed and we got a null result, that usually
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart
index 4042b04..32d5365 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart
@@ -57,7 +57,7 @@
         if (prefix == null) {
           return;
         }
-        var node = _findNode();
+        var node = await _findNode();
         if (node != null) {
           var uriEnd = node.uri.end;
           var prefixEnd = prefix.nameOffset + prefix.nameLength;
@@ -66,7 +66,7 @@
         }
       } else {
         if (prefix == null) {
-          var node = _findNode();
+          var node = await _findNode();
           if (node != null) {
             var uriEnd = node.uri.end;
             edit = newSourceEdit_range(SourceRange(uriEnd, 0), ' as $newName');
@@ -88,15 +88,13 @@
       if (newName.isEmpty) {
         reference.addEdit(change, '');
       } else {
-        var interpolationIdentifier = _getInterpolationIdentifier(reference);
-        if (interpolationIdentifier != null) {
+        var identifier = await _getInterpolationIdentifier(reference);
+        if (identifier != null) {
           doSourceChange_addElementEdit(
               change,
               reference.element,
-              SourceEdit(
-                  interpolationIdentifier.offset,
-                  interpolationIdentifier.length,
-                  '{$newName.${interpolationIdentifier.name}}'));
+              SourceEdit(identifier.offset, identifier.length,
+                  '{$newName.${identifier.name}}'));
         } else {
           reference.addEdit(change, '$newName.');
         }
@@ -105,10 +103,10 @@
   }
 
   /// Return the [ImportDirective] node that corresponds to the [element].
-  ImportDirective? _findNode() {
+  Future<ImportDirective?> _findNode() async {
     var library = element.library;
     var path = library.source.fullName;
-    var unitResult = session.getParsedUnit(path);
+    var unitResult = await session.getParsedUnit2(path);
     if (unitResult is! ParsedUnitResult) {
       return null;
     }
@@ -120,9 +118,11 @@
   /// If the given [reference] is before an interpolated [SimpleIdentifier] in
   /// an [InterpolationExpression] without surrounding curly brackets, return
   /// it. Otherwise return `null`.
-  SimpleIdentifier? _getInterpolationIdentifier(SourceReference reference) {
+  Future<SimpleIdentifier?> _getInterpolationIdentifier(
+    SourceReference reference,
+  ) async {
     var source = reference.element.source!;
-    var unitResult = session.getParsedUnit(source.fullName);
+    var unitResult = await session.getParsedUnit2(source.fullName);
     if (unitResult is! ParsedUnitResult) {
       return null;
     }
diff --git a/pkg/analysis_server/test/integration/linter/lint_names_test.dart b/pkg/analysis_server/test/integration/linter/lint_names_test.dart
index 58031e7..20eea76 100644
--- a/pkg/analysis_server/test/integration/linter/lint_names_test.dart
+++ b/pkg/analysis_server/test/integration/linter/lint_names_test.dart
@@ -16,17 +16,17 @@
 void main() {
   /// Ensure server lint name representations correspond w/ actual lint rules.
   /// See, e.g., https://dart-review.googlesource.com/c/sdk/+/95743.
-  group('lint_names', () {
+  test('lint_names', () async {
     var pkgRootPath = path.normalize(packageRoot);
     var fixFilePath = path.join(pkgRootPath, 'analysis_server', 'lib', 'src',
         'services', 'linter', 'lint_names.dart');
     var contextCollection = AnalysisContextCollection(
       includedPaths: [fixFilePath],
     );
-    var parseResult = contextCollection
+    var parseResult = await contextCollection
         .contextFor(fixFilePath)
         .currentSession
-        .getParsedUnit(fixFilePath) as ParsedUnitResult;
+        .getParsedUnit2(fixFilePath) as ParsedUnitResult;
 
     if (parseResult.errors.isNotEmpty) {
       throw Exception(parseResult.errors);
@@ -38,9 +38,7 @@
     var collector = _FixCollector();
     lintNamesClass.accept(collector);
     for (var name in collector.lintNames) {
-      test(name, () {
-        expect(registeredLintNames, contains(name));
-      });
+      expect(registeredLintNames, contains(name));
     }
   });
 }
diff --git a/pkg/analysis_server/test/services/correction/sort_members_test.dart b/pkg/analysis_server/test/services/correction/sort_members_test.dart
index 5e7fb27..ab012ef 100644
--- a/pkg/analysis_server/test/services/correction/sort_members_test.dart
+++ b/pkg/analysis_server/test/services/correction/sort_members_test.dart
@@ -1512,7 +1512,7 @@
 
   Future<void> _parseTestUnit(String code) async {
     addTestSource(code);
-    var result = session.getParsedUnit(testFile) as ParsedUnitResult;
+    var result = await session.getParsedUnit2(testFile) as ParsedUnitResult;
     lineInfo = result.lineInfo;
     testUnit = result.unit;
   }
diff --git a/pkg/analysis_server/test/verify_no_solo_test.dart b/pkg/analysis_server/test/verify_no_solo_test.dart
index 150c731..5fe7b8c 100644
--- a/pkg/analysis_server/test/verify_no_solo_test.dart
+++ b/pkg/analysis_server/test/verify_no_solo_test.dart
@@ -45,9 +45,9 @@
     fail('The directory $testsPath contains multiple analysis contexts.');
   }
 
-  test('no @soloTest', () {
+  test('no @soloTest', () async {
     var failures = <String>[];
-    buildTestsIn(contexts[0].currentSession, testsPath,
+    await buildTestsIn(contexts[0].currentSession, testsPath,
         provider.getFolder(testsPath), failures);
 
     if (failures.isNotEmpty) {
@@ -56,19 +56,19 @@
   });
 }
 
-void buildTestsIn(AnalysisSession session, String testDirPath, Folder directory,
-    List<String> failures) {
+Future<void> buildTestsIn(AnalysisSession session, String testDirPath,
+    Folder directory, List<String> failures) async {
   var pathContext = session.resourceProvider.pathContext;
   var children = directory.getChildren();
   children.sort((first, second) => first.shortName.compareTo(second.shortName));
   for (var child in children) {
     if (child is Folder) {
-      buildTestsIn(session, testDirPath, child, failures);
+      await buildTestsIn(session, testDirPath, child, failures);
     } else if (child is File && child.shortName.endsWith('_test.dart')) {
       var path = child.path;
       var relativePath = pathContext.relative(path, from: testDirPath);
 
-      var result = session.getParsedUnit(path);
+      var result = await session.getParsedUnit2(path);
       if (result is! ParsedUnitResult) {
         fail('Could not parse $path');
       }
diff --git a/pkg/analysis_server/test/verify_sorted_test.dart b/pkg/analysis_server/test/verify_sorted_test.dart
index 37de909..b63109c 100644
--- a/pkg/analysis_server/test/verify_sorted_test.dart
+++ b/pkg/analysis_server/test/verify_sorted_test.dart
@@ -142,8 +142,8 @@
         continue;
       }
       var relativePath = pathContext.relative(path, from: testDirPath);
-      test(relativePath, () {
-        var result = session.getParsedUnit(path);
+      test(relativePath, () async {
+        var result = await session.getParsedUnit2(path);
         if (result is! ParsedUnitResult) {
           fail('Could not parse $path');
         }
diff --git a/pkg/analysis_server_client/test/verify_sorted_test.dart b/pkg/analysis_server_client/test/verify_sorted_test.dart
index 8380e74..a4c2904 100644
--- a/pkg/analysis_server_client/test/verify_sorted_test.dart
+++ b/pkg/analysis_server_client/test/verify_sorted_test.dart
@@ -54,8 +54,8 @@
         continue;
       }
       var relativePath = pathContext.relative(path, from: testDirPath);
-      test(relativePath, () {
-        var result = session.getParsedUnit(path);
+      test(relativePath, () async {
+        var result = await session.getParsedUnit2(path);
         if (result is! ParsedUnitResult) {
           fail('Could not parse $path');
         }
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index 0b6f526..aac32ba 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 3.4.0-dev
+* Deprecated synchronous `getFile`, `getParsedLibrary`, `getParsedLibraryByElement`,
+  `getParsedUnit` from `AnalysisSession`. Use corresponding `getXyz2` asynchronous
+  methods instead. This change is necessary for the future work on macros.
+* Deprecated synchronous `getFileSync` from `AnalysisDriver`, use `getFile` instead.
+
 ## 3.3.1
 * Report HintCode.OVERRIDE_ON_NON_OVERRIDING_xyz on enum.
 
diff --git a/pkg/analyzer/doc/tutorial/ast.md b/pkg/analyzer/doc/tutorial/ast.md
index ed449d8..7f64a05 100644
--- a/pkg/analyzer/doc/tutorial/ast.md
+++ b/pkg/analyzer/doc/tutorial/ast.md
@@ -54,8 +54,8 @@
 the AST:
 
 ```dart
-void processFile(AnalysisSession session, String path) {
-  var result = session.getParsedUnit(path);
+void processFile(AnalysisSession session, String path) async {
+  var result = await session.getParsedUnit2(path);
   if (result is ParsedUnitResult) {
     CompilationUnit unit = result.unit;
   }
diff --git a/pkg/analyzer/lib/dart/analysis/session.dart b/pkg/analyzer/lib/dart/analysis/session.dart
index dc14b0a..9f7e4ff 100644
--- a/pkg/analyzer/lib/dart/analysis/session.dart
+++ b/pkg/analyzer/lib/dart/analysis/session.dart
@@ -39,24 +39,46 @@
 
   /// Return information about the file at the given absolute, normalized
   /// [path].
+  @Deprecated('Use getFile2() instead')
   SomeFileResult getFile(String path);
 
+  /// Return information about the file at the given absolute, normalized
+  /// [path].
+  Future<SomeFileResult> getFile2(String path);
+
   /// Return a future that will complete with information about the library
   /// element representing the library with the given [uri].
   Future<SomeLibraryElementResult> getLibraryByUri(String uri);
 
   /// Return information about the results of parsing units of the library file
   /// with the given absolute, normalized [path].
+  @Deprecated('Use getParsedLibrary2() instead')
   SomeParsedLibraryResult getParsedLibrary(String path);
 
   /// Return information about the results of parsing units of the library file
+  /// with the given absolute, normalized [path].
+  Future<SomeParsedLibraryResult> getParsedLibrary2(String path);
+
+  /// Return information about the results of parsing units of the library file
   /// with the given library [element].
+  @Deprecated('Use getParsedLibraryByElement2() instead')
   SomeParsedLibraryResult getParsedLibraryByElement(LibraryElement element);
 
+  /// Return information about the results of parsing units of the library file
+  /// with the given library [element].
+  Future<SomeParsedLibraryResult> getParsedLibraryByElement2(
+    LibraryElement element,
+  );
+
   /// Return information about the results of parsing the file with the given
   /// absolute, normalized [path].
+  @Deprecated('Use getParsedUnit2() instead')
   SomeParsedUnitResult getParsedUnit(String path);
 
+  /// Return information about the results of parsing the file with the given
+  /// absolute, normalized [path].
+  Future<SomeParsedUnitResult> getParsedUnit2(String path);
+
   /// Return a future that will complete with information about the results of
   /// resolving all of the files in the library with the given absolute,
   /// normalized [path].
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 84644e4..7a3b593 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -588,6 +588,19 @@
     return getErrors(path);
   }
 
+  /// Return the [FileResult] for the Dart file with the given [path].
+  ///
+  /// The [path] must be absolute and normalized.
+  Future<SomeFileResult> getFile(String path) async {
+    if (!_isAbsolutePath(path)) {
+      return InvalidPathResult();
+    }
+
+    FileState file = _fileTracker.getFile(path);
+    return FileResultImpl(
+        currentSession, path, file.uri, file.lineInfo, file.isPart);
+  }
+
   /// Return a [Future] that completes with the list of added files that
   /// define a class member with the given [name].
   Future<List<String>> getFilesDefiningClassMemberName(String name) {
@@ -611,6 +624,7 @@
   /// Return the [FileResult] for the Dart file with the given [path].
   ///
   /// The [path] must be absolute and normalized.
+  @Deprecated('Use getFile() instead')
   SomeFileResult getFileSync(String path) {
     if (!_isAbsolutePath(path)) {
       return InvalidPathResult();
@@ -624,7 +638,7 @@
   /// Return the [FileResult] for the Dart file with the given [path].
   ///
   /// The [path] must be absolute and normalized.
-  @Deprecated('Use getFileSync() instead')
+  @Deprecated('Use getFile() instead')
   SomeFileResult getFileSync2(String path) {
     return getFileSync(path);
   }
diff --git a/pkg/analyzer/lib/src/dart/analysis/session.dart b/pkg/analyzer/lib/src/dart/analysis/session.dart
index 32eeaca..47df470 100644
--- a/pkg/analyzer/lib/src/dart/analysis/session.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/session.dart
@@ -60,6 +60,7 @@
     return _driver.getErrors(path);
   }
 
+  @Deprecated('Use getFile2() instead')
   @override
   SomeFileResult getFile(String path) {
     _checkConsistency();
@@ -67,11 +68,18 @@
   }
 
   @override
+  Future<SomeFileResult> getFile2(String path) async {
+    _checkConsistency();
+    return _driver.getFile(path);
+  }
+
+  @override
   Future<SomeLibraryElementResult> getLibraryByUri(String uri) {
     _checkConsistency();
     return _driver.getLibraryByUri(uri);
   }
 
+  @Deprecated('Use getParsedLibrary2() instead')
   @override
   SomeParsedLibraryResult getParsedLibrary(String path) {
     _checkConsistency();
@@ -79,6 +87,13 @@
   }
 
   @override
+  Future<SomeParsedLibraryResult> getParsedLibrary2(String path) async {
+    _checkConsistency();
+    return _driver.getParsedLibrary(path);
+  }
+
+  @Deprecated('Use getParsedLibraryByElement2() instead')
+  @override
   SomeParsedLibraryResult getParsedLibraryByElement(LibraryElement element) {
     _checkConsistency();
 
@@ -90,12 +105,32 @@
   }
 
   @override
+  Future<SomeParsedLibraryResult> getParsedLibraryByElement2(
+    LibraryElement element,
+  ) async {
+    _checkConsistency();
+
+    if (element.session != this) {
+      return NotElementOfThisSessionResult();
+    }
+
+    return _driver.getParsedLibraryByUri(element.source.uri);
+  }
+
+  @Deprecated('Use getParsedUnit2() instead')
+  @override
   SomeParsedUnitResult getParsedUnit(String path) {
     _checkConsistency();
     return _driver.parseFileSync(path);
   }
 
   @override
+  Future<SomeParsedUnitResult> getParsedUnit2(String path) async {
+    _checkConsistency();
+    return _driver.parseFileSync(path);
+  }
+
+  @override
   Future<SomeResolvedLibraryResult> getResolvedLibrary(String path) {
     _checkConsistency();
     return _driver.getResolvedLibrary(path);
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 064de4b..768ae62 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
 name: analyzer
-version: 3.3.1
+version: 3.4.0-dev
 description: This package provides a library that performs static analysis of Dart code.
 homepage: https://github.com/dart-lang/sdk/tree/main/pkg/analyzer
 
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
index afefd83..67951ae 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
@@ -1380,6 +1380,66 @@
     expect(result, isA<InvalidPathResult>());
   }
 
+  test_getFile_changedFile() async {
+    var a = convertPath('/test/lib/a.dart');
+    var b = convertPath('/test/lib/b.dart');
+
+    newFile(a, content: '');
+    newFile(b, content: r'''
+import 'a.dart';
+
+void f(A a) {}
+''');
+
+    // Ensure that [a.dart] library cycle is loaded.
+    // So, `a.dart` is in the library context.
+    await driver.getResultValid(a);
+
+    // Update the file, changing its API signature.
+    // Note that we don't call `changeFile`.
+    newFile(a, content: 'class A {}\n');
+
+    // Get the file.
+    // We have not called `changeFile(a)`, so we should not read the file.
+    // Moreover, doing this will create a new library cycle [a.dart].
+    // Library cycles are compared by their identity, so we would try to
+    // reload linked summary for [a.dart], and crash.
+    expect((await driver.getFileValid(a)).lineInfo.lineCount, 1);
+
+    // We have not read `a.dart`, so `A` is still not declared.
+    expect((await driver.getResultValid(b)).errors, isNotEmpty);
+
+    // Notify the driver that the file was changed.
+    driver.changeFile(a);
+
+    // So, `class A {}` is declared now.
+    expect((await driver.getFileValid(a)).lineInfo.lineCount, 2);
+    expect((await driver.getResultValid(b)).errors, isEmpty);
+  }
+
+  test_getFile_library() async {
+    var path = convertPath('/test/lib/a.dart');
+    newFile(path);
+    var file = await driver.getFileValid(path);
+    expect(file.path, path);
+    expect(file.uri.toString(), 'package:test/a.dart');
+    expect(file.isPart, isFalse);
+  }
+
+  test_getFile_notAbsolutePath() async {
+    var result = await driver.getFile('not_absolute.dart');
+    expect(result, isA<InvalidPathResult>());
+  }
+
+  test_getFile_part() async {
+    var path = convertPath('/test/lib/a.dart');
+    newFile(path, content: 'part of lib;');
+    var file = await driver.getFileValid(path);
+    expect(file.path, path);
+    expect(file.uri.toString(), 'package:test/a.dart');
+    expect(file.isPart, isTrue);
+  }
+
   test_getFilesDefiningClassMemberName_class() async {
     var a = convertPath('/test/bin/a.dart');
     var b = convertPath('/test/bin/b.dart');
@@ -1483,6 +1543,7 @@
     expect(files, isNot(contains(c)));
   }
 
+  @deprecated
   test_getFileSync_changedFile() async {
     var a = convertPath('/test/lib/a.dart');
     var b = convertPath('/test/lib/b.dart');
@@ -1520,6 +1581,7 @@
     expect((await driver.getResultValid(b)).errors, isEmpty);
   }
 
+  @deprecated
   test_getFileSync_library() async {
     var path = convertPath('/test/lib/a.dart');
     newFile(path);
@@ -1529,11 +1591,13 @@
     expect(file.isPart, isFalse);
   }
 
+  @deprecated
   test_getFileSync_notAbsolutePath() async {
     var result = driver.getFileSync('not_absolute.dart');
     expect(result, isA<InvalidPathResult>());
   }
 
+  @deprecated
   test_getFileSync_part() async {
     var path = convertPath('/test/lib/a.dart');
     newFile(path, content: 'part of lib;');
@@ -3451,10 +3515,15 @@
     }
   }
 
+  @deprecated
   FileResult getFileSyncValid(String path) {
     return getFileSync(path) as FileResult;
   }
 
+  Future<FileResult> getFileValid(String path) async {
+    return await getFile(path) as FileResult;
+  }
+
   Future<LibraryElementResult> getLibraryByUriValid(String uriStr) async {
     return await getLibraryByUri(uriStr) as LibraryElementResult;
   }
diff --git a/pkg/analyzer/test/src/dart/analysis/resolve_for_completion_test.dart b/pkg/analyzer/test/src/dart/analysis/resolve_for_completion_test.dart
index d570325..b1a26bd 100644
--- a/pkg/analyzer/test/src/dart/analysis/resolve_for_completion_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/resolve_for_completion_test.dart
@@ -461,7 +461,7 @@
     newFile(testFilePath, content: 'class A {}');
 
     // Read the file.
-    testDriver.getFileSync(testFilePathPlatform);
+    await testDriver.getFile(testFilePathPlatform);
 
     // Should call `changeFile()`, and the driver must re-read the file.
     var result = _resolveTestCode(r'''
diff --git a/pkg/analyzer/test/src/dart/analysis/results/get_element_declaration_test.dart b/pkg/analyzer/test/src/dart/analysis/results/get_element_declaration_test.dart
index 983d7bb..f60b34d 100644
--- a/pkg/analyzer/test/src/dart/analysis/results/get_element_declaration_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/results/get_element_declaration_test.dart
@@ -433,13 +433,13 @@
   Future<ElementDeclarationResult?> getElementDeclaration(
       Element element) async {
     var libraryPath = element.library!.source.fullName;
-    var library = _getParsedLibrary(libraryPath);
+    var library = await _getParsedLibrary(libraryPath);
     return library.getElementDeclaration(element);
   }
 
-  ParsedLibraryResult _getParsedLibrary(String path) {
+  Future<ParsedLibraryResult> _getParsedLibrary(String path) async {
     var session = contextFor(path).currentSession;
-    return session.getParsedLibrary(path) as ParsedLibraryResult;
+    return await session.getParsedLibrary2(path) as ParsedLibraryResult;
   }
 }
 
diff --git a/pkg/analyzer/test/src/dart/analysis/session_test.dart b/pkg/analyzer/test/src/dart/analysis/session_test.dart
index 6953e85..db20934 100644
--- a/pkg/analyzer/test/src/dart/analysis/session_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/session_test.dart
@@ -44,6 +44,17 @@
     expect(result.uri.toString(), 'package:dart.my/a.dart');
   }
 
+  void test_getParsedLibrary2_notFileOfUri() async {
+    var relPath = 'dart/my/lib/a.dart';
+    newFile('$workspaceRootPath/bazel-bin/$relPath');
+
+    var path = convertPath('$workspaceRootPath/$relPath');
+    var session = contextFor(path).currentSession;
+    var result = await session.getParsedLibrary2(path);
+    expect(result, isA<NotPathOfUriResult>());
+  }
+
+  @deprecated
   void test_getParsedLibrary_notFileOfUri() async {
     var relPath = 'dart/my/lib/a.dart';
     newFile('$workspaceRootPath/bazel-bin/$relPath');
@@ -150,13 +161,44 @@
     expect(errorsResult, isA<InvalidPathResult>());
   }
 
-  test_getFile_invalidPath_notAbsolute() async {
+  test_getFile2_inconsistent() async {
+    var test = newFile(testFilePath, content: '');
+    var session = contextFor(test.path).currentSession;
+    driverFor(test.path).changeFile(test.path);
+    expect(
+      () async => session.getFile2(test.path),
+      throwsA(isA<InconsistentAnalysisException>()),
+    );
+  }
+
+  test_getFile2_invalidPath_notAbsolute() async {
     var session = contextFor(testFilePath).currentSession;
-    var errorsResult = session.getFile('not_absolute.dart');
+    var errorsResult = await session.getFile2('not_absolute.dart');
     expect(errorsResult, isA<InvalidPathResult>());
   }
 
-  test_getFileSync_inconsistent() async {
+  test_getFile2_library() async {
+    var a = newFile('$testPackageLibPath/a.dart', content: '');
+
+    var session = contextFor(testFilePath).currentSession;
+    var file = await session.getFile2Valid(a.path);
+    expect(file.path, a.path);
+    expect(file.uri.toString(), 'package:test/a.dart');
+    expect(file.isPart, isFalse);
+  }
+
+  test_getFile2_part() async {
+    var a = newFile('$testPackageLibPath/a.dart', content: 'part of lib;');
+
+    var session = contextFor(testFilePath).currentSession;
+    var file = await session.getFile2Valid(a.path);
+    expect(file.path, a.path);
+    expect(file.uri.toString(), 'package:test/a.dart');
+    expect(file.isPart, isTrue);
+  }
+
+  @deprecated
+  test_getFile_inconsistent() async {
     var test = newFile(testFilePath, content: '');
     var session = contextFor(test.path).currentSession;
     driverFor(test.path).changeFile(test.path);
@@ -166,7 +208,15 @@
     );
   }
 
-  test_getFileSync_library() async {
+  @deprecated
+  test_getFile_invalidPath_notAbsolute() async {
+    var session = contextFor(testFilePath).currentSession;
+    var errorsResult = session.getFile('not_absolute.dart');
+    expect(errorsResult, isA<InvalidPathResult>());
+  }
+
+  @deprecated
+  test_getFile_library() async {
     var a = newFile('$testPackageLibPath/a.dart', content: '');
 
     var session = contextFor(testFilePath).currentSession;
@@ -176,7 +226,8 @@
     expect(file.isPart, isFalse);
   }
 
-  test_getFileSync_part() async {
+  @deprecated
+  test_getFile_part() async {
     var a = newFile('$testPackageLibPath/a.dart', content: 'part of lib;');
 
     var session = contextFor(testFilePath).currentSession;
@@ -216,6 +267,7 @@
     expect(result, isA<CannotResolveUriResult>());
   }
 
+  @deprecated
   test_getParsedLibrary() async {
     var test = newFile('$testPackageLibPath/a.dart', content: r'''
 class A {}
@@ -236,6 +288,189 @@
     }
   }
 
+  test_getParsedLibrary2() async {
+    var test = newFile('$testPackageLibPath/a.dart', content: r'''
+class A {}
+class B {}
+''');
+
+    var session = contextFor(testFilePath).currentSession;
+    var parsedLibrary = await session.getParsedLibrary2Valid(test.path);
+    expect(parsedLibrary.session, session);
+
+    expect(parsedLibrary.units, hasLength(1));
+    {
+      var parsedUnit = parsedLibrary.units[0];
+      expect(parsedUnit.session, session);
+      expect(parsedUnit.path, test.path);
+      expect(parsedUnit.uri, Uri.parse('package:test/a.dart'));
+      expect(parsedUnit.unit.declarations, hasLength(2));
+    }
+  }
+
+  test_getParsedLibrary2_getElementDeclaration_class() async {
+    var test = newFile(testFilePath, content: r'''
+class A {}
+class B {}
+''');
+
+    var session = contextFor(testFilePath).currentSession;
+    var libraryResult = await session.getLibraryByUriValid(
+      'package:test/test.dart',
+    );
+    var parsedLibrary = await session.getParsedLibrary2Valid(test.path);
+
+    var element = libraryResult.element.getType('A')!;
+    var declaration = parsedLibrary.getElementDeclaration(element)!;
+    var node = declaration.node as ClassDeclaration;
+    expect(node.name.name, 'A');
+    expect(node.offset, 0);
+    expect(node.length, 10);
+  }
+
+  test_getParsedLibrary2_getElementDeclaration_notThisLibrary() async {
+    var test = newFile(testFilePath, content: '');
+
+    var session = contextFor(testFilePath).currentSession;
+    var resolvedUnit =
+        await session.getResolvedUnit(test.path) as ResolvedUnitResult;
+    var typeProvider = resolvedUnit.typeProvider;
+    var intClass = typeProvider.intType.element;
+
+    var parsedLibrary = await session.getParsedLibrary2Valid(test.path);
+
+    expect(() {
+      parsedLibrary.getElementDeclaration(intClass);
+    }, throwsArgumentError);
+  }
+
+  test_getParsedLibrary2_getElementDeclaration_synthetic() async {
+    var test = newFile(testFilePath, content: r'''
+int foo = 0;
+''');
+
+    var session = contextFor(testFilePath).currentSession;
+    var parsedLibrary = await session.getParsedLibrary2Valid(test.path);
+
+    var unitResult = await session.getUnitElementValid(test.path);
+    var fooElement = unitResult.element.topLevelVariables[0];
+    expect(fooElement.name, 'foo');
+
+    // We can get the variable element declaration.
+    var fooDeclaration = parsedLibrary.getElementDeclaration(fooElement)!;
+    var fooNode = fooDeclaration.node as VariableDeclaration;
+    expect(fooNode.name.name, 'foo');
+    expect(fooNode.offset, 4);
+    expect(fooNode.length, 7);
+    expect(fooNode.name.staticElement, isNull);
+
+    // Synthetic elements don't have nodes.
+    expect(parsedLibrary.getElementDeclaration(fooElement.getter!), isNull);
+    expect(parsedLibrary.getElementDeclaration(fooElement.setter!), isNull);
+  }
+
+  test_getParsedLibrary2_inconsistent() async {
+    var test = newFile(testFilePath, content: '');
+    var session = contextFor(test.path).currentSession;
+    driverFor(test.path).changeFile(test.path);
+    expect(
+      () => session.getParsedLibrary2(test.path),
+      throwsA(isA<InconsistentAnalysisException>()),
+    );
+  }
+
+  test_getParsedLibrary2_invalidPartUri() async {
+    var test = newFile(testFilePath, content: r'''
+part 'a.dart';
+part ':[invalid uri].dart';
+part 'c.dart';
+''');
+
+    var session = contextFor(testFilePath).currentSession;
+    var parsedLibrary = await session.getParsedLibrary2Valid(test.path);
+
+    expect(parsedLibrary.units, hasLength(3));
+    expect(
+      parsedLibrary.units[0].path,
+      convertPath('/home/test/lib/test.dart'),
+    );
+    expect(
+      parsedLibrary.units[1].path,
+      convertPath('/home/test/lib/a.dart'),
+    );
+    expect(
+      parsedLibrary.units[2].path,
+      convertPath('/home/test/lib/c.dart'),
+    );
+  }
+
+  test_getParsedLibrary2_invalidPath_notAbsolute() async {
+    var session = contextFor(testFilePath).currentSession;
+    var result = await session.getParsedLibrary2('not_absolute.dart');
+    expect(result, isA<InvalidPathResult>());
+  }
+
+  test_getParsedLibrary2_notLibrary() async {
+    var test = newFile(testFilePath, content: 'part of "a.dart";');
+    var session = contextFor(testFilePath).currentSession;
+    var result = await session.getParsedLibrary2(test.path);
+    expect(result, isA<NotLibraryButPartResult>());
+  }
+
+  test_getParsedLibrary2_parts() async {
+    var aContent = r'''
+part 'b.dart';
+part 'c.dart';
+
+class A {}
+''';
+
+    var bContent = r'''
+part of 'a.dart';
+
+class B1 {}
+class B2 {}
+''';
+
+    var cContent = r'''
+part of 'a.dart';
+
+class C1 {}
+class C2 {}
+class C3 {}
+''';
+
+    var a = newFile('$testPackageLibPath/a.dart', content: aContent);
+    var b = newFile('$testPackageLibPath/b.dart', content: bContent);
+    var c = newFile('$testPackageLibPath/c.dart', content: cContent);
+
+    var session = contextFor(testFilePath).currentSession;
+    var parsedLibrary = await session.getParsedLibrary2Valid(a.path);
+    expect(parsedLibrary.units, hasLength(3));
+
+    {
+      var aUnit = parsedLibrary.units[0];
+      expect(aUnit.path, a.path);
+      expect(aUnit.uri, Uri.parse('package:test/a.dart'));
+      expect(aUnit.unit.declarations, hasLength(1));
+    }
+
+    {
+      var bUnit = parsedLibrary.units[1];
+      expect(bUnit.path, b.path);
+      expect(bUnit.uri, Uri.parse('package:test/b.dart'));
+      expect(bUnit.unit.declarations, hasLength(2));
+    }
+
+    {
+      var cUnit = parsedLibrary.units[2];
+      expect(cUnit.path, c.path);
+      expect(cUnit.uri, Uri.parse('package:test/c.dart'));
+      expect(cUnit.unit.declarations, hasLength(3));
+    }
+  }
+
+  @deprecated
   test_getParsedLibrary_getElementDeclaration_class() async {
     var test = newFile(testFilePath, content: r'''
 class A {}
@@ -256,6 +491,7 @@
     expect(node.length, 10);
   }
 
+  @deprecated
   test_getParsedLibrary_getElementDeclaration_notThisLibrary() async {
     var test = newFile(testFilePath, content: '');
 
@@ -272,6 +508,7 @@
     }, throwsArgumentError);
   }
 
+  @deprecated
   test_getParsedLibrary_getElementDeclaration_synthetic() async {
     var test = newFile(testFilePath, content: r'''
 int foo = 0;
@@ -297,6 +534,7 @@
     expect(parsedLibrary.getElementDeclaration(fooElement.setter!), isNull);
   }
 
+  @deprecated
   test_getParsedLibrary_inconsistent() async {
     var test = newFile(testFilePath, content: '');
     var session = contextFor(test.path).currentSession;
@@ -307,6 +545,7 @@
     );
   }
 
+  @deprecated
   test_getParsedLibrary_invalidPartUri() async {
     var test = newFile(testFilePath, content: r'''
 part 'a.dart';
@@ -332,18 +571,21 @@
     );
   }
 
+  @deprecated
   test_getParsedLibrary_invalidPath_notAbsolute() async {
     var session = contextFor(testFilePath).currentSession;
     var result = session.getParsedLibrary('not_absolute.dart');
     expect(result, isA<InvalidPathResult>());
   }
 
+  @deprecated
   test_getParsedLibrary_notLibrary() async {
     var test = newFile(testFilePath, content: 'part of "a.dart";');
     var session = contextFor(testFilePath).currentSession;
     expect(session.getParsedLibrary(test.path), isA<NotLibraryButPartResult>());
   }
 
+  @deprecated
   test_getParsedLibrary_parts() async {
     var aContent = r'''
 part 'b.dart';
@@ -397,6 +639,7 @@
     }
   }
 
+  @deprecated
   test_getParsedLibraryByElement() async {
     var test = newFile(testFilePath, content: '');
 
@@ -418,6 +661,43 @@
     }
   }
 
+  test_getParsedLibraryByElement2() async {
+    var test = newFile(testFilePath, content: '');
+
+    var session = contextFor(testFilePath).currentSession;
+    var libraryResult = await session.getLibraryByUriValid(
+      'package:test/test.dart',
+    );
+    var element = libraryResult.element;
+
+    var parsedLibrary = await session.getParsedLibraryByElement2Valid(element);
+    expect(parsedLibrary.session, session);
+    expect(parsedLibrary.units, hasLength(1));
+
+    {
+      var unit = parsedLibrary.units[0];
+      expect(unit.path, test.path);
+      expect(unit.uri, Uri.parse('package:test/test.dart'));
+      expect(unit.unit, isNotNull);
+    }
+  }
+
+  test_getParsedLibraryByElement2_differentSession() async {
+    newFile(testFilePath, content: '');
+
+    var session = contextFor(testFilePath).currentSession;
+    var libraryResult = await session.getLibraryByUriValid(
+      'package:test/test.dart',
+    );
+    var element = libraryResult.element;
+
+    var aaaSession = contextFor('$workspaceRootPath/aaa').currentSession;
+
+    var result = await aaaSession.getParsedLibraryByElement2(element);
+    expect(result, isA<NotElementOfThisSessionResult>());
+  }
+
+  @deprecated
   test_getParsedLibraryByElement_differentSession() async {
     newFile(testFilePath, content: '');
 
@@ -433,6 +713,7 @@
     expect(result, isA<NotElementOfThisSessionResult>());
   }
 
+  @deprecated
   test_getParsedUnit() async {
     var test = newFile(testFilePath, content: r'''
 class A {}
@@ -447,6 +728,37 @@
     expect(unitResult.unit.declarations, hasLength(2));
   }
 
+  test_getParsedUnit2() async {
+    var test = newFile(testFilePath, content: r'''
+class A {}
+class B {}
+''');
+
+    var session = contextFor(testFilePath).currentSession;
+    var unitResult = await session.getParsedUnit2Valid(test.path);
+    expect(unitResult.session, session);
+    expect(unitResult.path, test.path);
+    expect(unitResult.uri, Uri.parse('package:test/test.dart'));
+    expect(unitResult.unit.declarations, hasLength(2));
+  }
+
+  test_getParsedUnit2_inconsistent() async {
+    var test = newFile(testFilePath, content: '');
+    var session = contextFor(test.path).currentSession;
+    driverFor(test.path).changeFile(test.path);
+    expect(
+      () => session.getParsedUnit2(test.path),
+      throwsA(isA<InconsistentAnalysisException>()),
+    );
+  }
+
+  test_getParsedUnit2_invalidPath_notAbsolute() async {
+    var session = contextFor(testFilePath).currentSession;
+    var result = await session.getParsedUnit2('not_absolute.dart');
+    expect(result, isA<InvalidPathResult>());
+  }
+
+  @deprecated
   test_getParsedUnit_inconsistent() async {
     var test = newFile(testFilePath, content: '');
     var session = contextFor(test.path).currentSession;
@@ -457,6 +769,7 @@
     );
   }
 
+  @deprecated
   test_getParsedUnit_invalidPath_notAbsolute() async {
     var session = contextFor(testFilePath).currentSession;
     var result = session.getParsedUnit('not_absolute.dart');
@@ -705,6 +1018,11 @@
     return await getErrors(path) as ErrorsResult;
   }
 
+  Future<FileResult> getFile2Valid(String path) async {
+    return await getFile2(path) as FileResult;
+  }
+
+  @deprecated
   FileResult getFileValid(String path) {
     return getFile(path) as FileResult;
   }
@@ -713,14 +1031,31 @@
     return await getLibraryByUri(path) as LibraryElementResult;
   }
 
+  Future<ParsedLibraryResult> getParsedLibrary2Valid(String path) async {
+    return await getParsedLibrary2(path) as ParsedLibraryResult;
+  }
+
+  Future<ParsedLibraryResult> getParsedLibraryByElement2Valid(
+    LibraryElement element,
+  ) async {
+    return await getParsedLibraryByElement2(element) as ParsedLibraryResult;
+  }
+
+  @deprecated
   ParsedLibraryResult getParsedLibraryByElementValid(LibraryElement element) {
     return getParsedLibraryByElement(element) as ParsedLibraryResult;
   }
 
+  @deprecated
   ParsedLibraryResult getParsedLibraryValid(String path) {
     return getParsedLibrary(path) as ParsedLibraryResult;
   }
 
+  Future<ParsedUnitResult> getParsedUnit2Valid(String path) async {
+    return await getParsedUnit2(path) as ParsedUnitResult;
+  }
+
+  @deprecated
   ParsedUnitResult getParsedUnitValid(String path) {
     return getParsedUnit(path) as ParsedUnitResult;
   }
diff --git a/pkg/analyzer/test/src/services/available_declarations_test.dart b/pkg/analyzer/test/src/services/available_declarations_test.dart
index 357ca89..efd0cc1 100644
--- a/pkg/analyzer/test/src/services/available_declarations_test.dart
+++ b/pkg/analyzer/test/src/services/available_declarations_test.dart
@@ -3625,9 +3625,9 @@
     newFile(a, content: 'class A {}');
     newFile(b, content: 'class B {}');
     newFile(c, content: 'class C {}');
-    testAnalysisContext.currentSession.getFile(a);
-    testAnalysisContext.currentSession.getFile(b);
-    testAnalysisContext.currentSession.getFile(c);
+    await testAnalysisContext.currentSession.getFile2(a);
+    await testAnalysisContext.currentSession.getFile2(b);
+    await testAnalysisContext.currentSession.getFile2(c);
 
     var context = tracker.addContext(testAnalysisContext);
     await _doAllTrackerWork();
diff --git a/pkg/analyzer_cli/analysis_options.yaml b/pkg/analyzer_cli/analysis_options.yaml
index 8d202f9..2747e0f 100644
--- a/pkg/analyzer_cli/analysis_options.yaml
+++ b/pkg/analyzer_cli/analysis_options.yaml
@@ -9,11 +9,27 @@
 
 linter:
   rules:
+    always_declare_return_types: true
+    avoid_empty_else: true
+    avoid_relative_lib_imports: true
+    avoid_shadowing_type_parameters: true
+    avoid_types_as_parameter_names: true
     avoid_unused_constructor_parameters: true
+    camel_case_extensions: true
+    curly_braces_in_flow_control_structures: true
     depend_on_referenced_packages: true
     directives_ordering: true
+    empty_catches: true
 
     # We import heavily from package:analyzer/src.
     implementation_imports: false
     # This rule does not work well with package:test_reflective_loader.
+    no_duplicate_case_values: true
     non_constant_identifier_names: false
+    omit_local_variable_types: true
+    prefer_is_empty: true
+    prefer_is_not_empty: true
+    prefer_iterable_whereType: true
+    prefer_single_quotes: true
+    unawaited_futures: true
+    unrelated_type_equality_checks: true
diff --git a/pkg/analyzer_cli/lib/src/analyzer_impl.dart b/pkg/analyzer_cli/lib/src/analyzer_impl.dart
index fff1252..7e40fff 100644
--- a/pkg/analyzer_cli/lib/src/analyzer_impl.dart
+++ b/pkg/analyzer_cli/lib/src/analyzer_impl.dart
@@ -148,7 +148,7 @@
 
     // Print errors and performance numbers.
     if (printMode == 1) {
-      formatter.formatErrors(errorsResults);
+      await formatter.formatErrors(errorsResults);
     } else if (printMode == 2) {
       _printColdPerf();
     }
diff --git a/pkg/analyzer_cli/lib/src/driver.dart b/pkg/analyzer_cli/lib/src/driver.dart
index de1d3c0..6c75fd3 100644
--- a/pkg/analyzer_cli/lib/src/driver.dart
+++ b/pkg/analyzer_cli/lib/src/driver.dart
@@ -248,7 +248,7 @@
             analysisDriver.sourceFactory,
             analysisDriver.currentSession.analysisContext.contextRoot.root.path,
           );
-          formatter.formatErrors([
+          await formatter.formatErrors([
             ErrorsResultImpl(analysisDriver.currentSession, path,
                 pathContext.toUri(path), lineInfo, false, errors)
           ]);
@@ -304,7 +304,7 @@
                 allResult = allResult.max(severity);
               }
               var lineInfo = LineInfo.fromContent(content);
-              formatter.formatErrors([
+              await formatter.formatErrors([
                 ErrorsResultImpl(analysisDriver.currentSession, path,
                     pathContext.toUri(path), lineInfo, false, errors)
               ]);
@@ -320,7 +320,7 @@
             var lineInfo = LineInfo.fromContent(content);
             var errors = validator.validate(
                 content, analysisDriver.analysisOptions.chromeOsManifestChecks);
-            formatter.formatErrors([
+            await formatter.formatErrors([
               ErrorsResultImpl(analysisDriver.currentSession, path,
                   pathContext.toUri(path), lineInfo, false, errors)
             ]);
diff --git a/pkg/analyzer_cli/lib/src/error_formatter.dart b/pkg/analyzer_cli/lib/src/error_formatter.dart
index 51c7002..88147da 100644
--- a/pkg/analyzer_cli/lib/src/error_formatter.dart
+++ b/pkg/analyzer_cli/lib/src/error_formatter.dart
@@ -189,10 +189,10 @@
   /// Call to write any batched up errors from [formatErrors].
   void flush();
 
-  void formatError(
+  Future<void> formatError(
       Map<AnalysisError, ErrorsResult> errorToLine, AnalysisError error);
 
-  void formatErrors(List<ErrorsResult> results) {
+  Future<void> formatErrors(List<ErrorsResult> results) async {
     stats.unfilteredCount += results.length;
 
     var errors = <AnalysisError>[];
@@ -207,7 +207,7 @@
     }
 
     for (var error in errors) {
-      formatError(errorToLine, error);
+      await formatError(errorToLine, error);
     }
   }
 
@@ -276,8 +276,8 @@
   }
 
   @override
-  void formatError(
-      Map<AnalysisError, ErrorsResult> errorToLine, AnalysisError error) {
+  Future<void> formatError(
+      Map<AnalysisError, ErrorsResult> errorToLine, AnalysisError error) async {
     var source = error.source;
     var result = errorToLine[error]!;
     var location = result.lineInfo.getLocation(error.offset);
@@ -308,9 +308,10 @@
     }
     var contextMessages = <ContextMessage>[];
     for (var message in error.contextMessages) {
+      // TODO(scheglov) We should add `LineInfo` to `DiagnosticMessage`.
       var session = result.session.analysisContext;
       if (session is DriverBasedAnalysisContext) {
-        var fileResult = session.driver.getFileSync(message.filePath);
+        var fileResult = await session.driver.getFile(message.filePath);
         if (fileResult is FileResult) {
           var lineInfo = fileResult.lineInfo;
           var location = lineInfo.getLocation(message.offset);
@@ -348,13 +349,13 @@
   void flush() {}
 
   @override
-  void formatError(
-      Map<AnalysisError, ErrorsResult> errorToLine, AnalysisError error) {
+  Future<void> formatError(
+      Map<AnalysisError, ErrorsResult> errorToLine, AnalysisError error) async {
     throw UnsupportedError('Cannot format a single error');
   }
 
   @override
-  void formatErrors(List<ErrorsResult> results) {
+  Future<void> formatErrors(List<ErrorsResult> results) async {
     Map<String, dynamic> range(
             Map<String, dynamic> start, Map<String, dynamic> end) =>
         {
@@ -435,8 +436,8 @@
   void flush() {}
 
   @override
-  void formatError(
-      Map<AnalysisError, ErrorsResult> errorToLine, AnalysisError error) {
+  Future<void> formatError(
+      Map<AnalysisError, ErrorsResult> errorToLine, AnalysisError error) async {
     // Ensure we don't over-report (#36062).
     if (!_seenErrors.add(error)) {
       return;
diff --git a/pkg/analyzer_cli/test/driver_test.dart b/pkg/analyzer_cli/test/driver_test.dart
index de57da2..683562a 100644
--- a/pkg/analyzer_cli/test/driver_test.dart
+++ b/pkg/analyzer_cli/test/driver_test.dart
@@ -464,7 +464,7 @@
     ]);
     expect(processorFor(missing_return).severity, ErrorSeverity.ERROR);
     expect(bulletToDash(outSink),
-        contains("error - The body might complete normally"));
+        contains('error - The body might complete normally'));
     expect(outSink.toString(), contains('1 error and 1 warning found.'));
   }
 
diff --git a/pkg/analyzer_cli/test/mocks.dart b/pkg/analyzer_cli/test/mocks.dart
index a8b487a..3de1eb3 100644
--- a/pkg/analyzer_cli/test/mocks.dart
+++ b/pkg/analyzer_cli/test/mocks.dart
@@ -116,7 +116,7 @@
   }
 
   @override
-  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+  dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
 }
 
 class MockLineInfo implements LineInfo {
@@ -163,5 +163,5 @@
   MockSource(this.fullName, this.uri);
 
   @override
-  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+  dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
 }
diff --git a/pkg/analyzer_cli/test/reporter_test.dart b/pkg/analyzer_cli/test/reporter_test.dart
index cffb0ff..54a2964 100644
--- a/pkg/analyzer_cli/test/reporter_test.dart
+++ b/pkg/analyzer_cli/test/reporter_test.dart
@@ -44,27 +44,27 @@
         reporter = HumanErrorFormatter(out, options, stats);
       });
 
-      test('error', () {
+      test('error', () async {
         var error = mockResult(ErrorType.SYNTACTIC_ERROR, ErrorSeverity.ERROR);
-        reporter.formatErrors([error]);
+        await reporter.formatErrors([error]);
         reporter.flush();
 
         expect(out.toString().trim(),
             'error • MSG • /foo/bar/baz.dart:3:3 • mock_code');
       });
 
-      test('hint', () {
+      test('hint', () async {
         var error = mockResult(ErrorType.HINT, ErrorSeverity.INFO);
-        reporter.formatErrors([error]);
+        await reporter.formatErrors([error]);
         reporter.flush();
 
         expect(out.toString().trim(),
             'hint • MSG • /foo/bar/baz.dart:3:3 • mock_code');
       });
 
-      test('stats', () {
+      test('stats', () async {
         var error = mockResult(ErrorType.HINT, ErrorSeverity.INFO);
-        reporter.formatErrors([error]);
+        await reporter.formatErrors([error]);
         reporter.flush();
         stats.print(out);
         expect(
@@ -79,9 +79,9 @@
         reporter = JsonErrorFormatter(out, options, stats);
       });
 
-      test('error', () {
+      test('error', () async {
         var error = mockResult(ErrorType.SYNTACTIC_ERROR, ErrorSeverity.ERROR);
-        reporter.formatErrors([error]);
+        await reporter.formatErrors([error]);
         reporter.flush();
 
         expect(
@@ -108,11 +108,11 @@
   var source = MockSource(path, package_path.toUri(path));
   var error = MockAnalysisError(source, code, 20, 'MSG');
 
-  return ErrorsResultImpl(_MockAnslysisSession(), source.fullName,
+  return ErrorsResultImpl(_MockAnalysisSession(), source.fullName,
       Uri.file('/'), lineInfo, false, [error]);
 }
 
-class _MockAnslysisSession implements AnalysisSession {
+class _MockAnalysisSession implements AnalysisSession {
   @override
-  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+  dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
 }
diff --git a/pkg/analyzer_utilities/lib/verify_tests.dart b/pkg/analyzer_utilities/lib/verify_tests.dart
index de1bf43..9bc21e4 100644
--- a/pkg/analyzer_utilities/lib/verify_tests.dart
+++ b/pkg/analyzer_utilities/lib/verify_tests.dart
@@ -87,7 +87,7 @@
       }
     }
     var relativePath = path.relative(directory.path, from: testDirPath);
-    test(relativePath, () {
+    test(relativePath, () async {
       if (testFileNames.isEmpty) {
         return;
       }
@@ -103,7 +103,7 @@
       if (isOkForTestAllToBeMissing(directory)) {
         fail('Found "test_all.dart" in $relativePath but did not expect one');
       }
-      var result = session.getParsedUnit(testAllFile.path);
+      var result = await session.getParsedUnit2(testAllFile.path);
       if (result is! ParsedUnitResult) {
         fail('Could not parse ${testAllFile.path}');
       }
diff --git a/pkg/dart2wasm/lib/code_generator.dart b/pkg/dart2wasm/lib/code_generator.dart
index 5ae0b2a..96cdc9b 100644
--- a/pkg/dart2wasm/lib/code_generator.dart
+++ b/pkg/dart2wasm/lib/code_generator.dart
@@ -47,8 +47,9 @@
   final Map<VariableDeclaration, w.Local> locals = {};
   w.Local? thisLocal;
   w.Local? preciseThisLocal;
+  w.Local? returnValueLocal;
   final Map<TypeParameter, w.Local> typeLocals = {};
-  final List<Statement> finalizers = [];
+  final List<TryBlockFinalizer> finalizers = [];
   final List<w.Label> tryLabels = [];
   final Map<LabeledStatement, w.Label> labels = {};
   final Map<SwitchCase, w.Label> switchLabels = {};
@@ -622,9 +623,39 @@
 
   @override
   void visitTryFinally(TryFinally node) {
-    finalizers.add(node.finalizer);
+    // We lower a [TryFinally] to three nested blocks, and we emit the finalizer
+    // up to three times. Once in a catch, to handle the case where the try
+    // throws. Once outside of the catch, to handle the case where the try does
+    // not throw. Finally, if there is a return within the try block, then we
+    // emit the finalizer one more time along with logic to continue walking up
+    // the stack.
+    w.Label tryFinallyBlock = b.block();
+    w.Label finalizerBlock = b.block();
+    finalizers.add(TryBlockFinalizer(finalizerBlock));
+    w.Label tryBlock = b.try_();
     node.body.accept(this);
-    finalizers.removeLast().accept(this);
+    bool mustHandleReturn = finalizers.removeLast().mustHandleReturn;
+    b.br(tryBlock);
+    b.catch_(translator.exceptionTag);
+    node.finalizer.accept(this);
+    b.rethrow_(tryBlock);
+    b.end(); // end tryBlock.
+    node.finalizer.accept(this);
+    b.br(tryFinallyBlock);
+    b.end(); // end finalizerBlock.
+    if (mustHandleReturn) {
+      node.finalizer.accept(this);
+      if (finalizers.isNotEmpty) {
+        b.br(finalizers.last.label);
+      } else {
+        if (returnValueLocal != null) {
+          b.local_get(returnValueLocal!);
+          translator.convertType(function, returnValueLocal!.type, returnType);
+        }
+        _returnFromFunction();
+      }
+    }
+    b.end(); // end tryFinallyBlock.
   }
 
   @override
@@ -768,6 +799,17 @@
     throw "ForInStatement should have been desugared: $node";
   }
 
+  /// Handle the return from this function, either by jumping to [returnLabel]
+  /// in the case this function was inlined or just inserting a return
+  /// instruction.
+  void _returnFromFunction() {
+    if (returnLabel != null) {
+      b.br(returnLabel!);
+    } else {
+      b.return_();
+    }
+  }
+
   @override
   void visitReturnStatement(ReturnStatement node) {
     Expression? expression = node.expression;
@@ -776,13 +818,22 @@
     } else {
       translator.convertType(function, voidMarker, returnType);
     }
-    for (Statement finalizer in finalizers.reversed) {
-      finalizer.accept(this);
-    }
-    if (returnLabel != null) {
-      b.br(returnLabel!);
+
+    // If we are wrapped in a [TryFinally] node then we have to run finalizers
+    // as the stack unwinds. When we get to the top of the finalizer stack, we
+    // will handle the return using [returnValueLocal] if this function returns
+    // a value.
+    if (finalizers.isNotEmpty) {
+      for (TryBlockFinalizer finalizer in finalizers) {
+        finalizer.mustHandleReturn = true;
+      }
+      if (returnType != voidMarker) {
+        returnValueLocal ??= addLocal(returnType);
+        b.local_set(returnValueLocal!);
+      }
+      b.br(finalizers.last.label);
     } else {
-      b.return_();
+      _returnFromFunction();
     }
   }
 
@@ -2022,3 +2073,10 @@
     return wrap(node.operand, expectedType);
   }
 }
+
+class TryBlockFinalizer {
+  final w.Label label;
+  bool mustHandleReturn = false;
+
+  TryBlockFinalizer(this.label);
+}
diff --git a/pkg/dart2wasm/lib/translator.dart b/pkg/dart2wasm/lib/translator.dart
index 36a4b0d..1630176 100644
--- a/pkg/dart2wasm/lib/translator.dart
+++ b/pkg/dart2wasm/lib/translator.dart
@@ -352,9 +352,9 @@
   /// [stackTraceInfo.nonNullableType] to hold a stack trace. This single
   /// exception tag is used to throw and catch all Dart exceptions.
   w.Tag createExceptionTag() {
-    w.FunctionType functionType = m.addFunctionType(
+    w.FunctionType tagType = functionType(
         [topInfo.nonNullableType, stackTraceInfo.nonNullableType], const []);
-    w.Tag tag = m.addTag(functionType);
+    w.Tag tag = m.addTag(tagType);
     return tag;
   }
 
diff --git a/pkg/test_runner/tool/orphan_files.dart b/pkg/test_runner/tool/orphan_files.dart
index 968458b..4924123 100644
--- a/pkg/test_runner/tool/orphan_files.dart
+++ b/pkg/test_runner/tool/orphan_files.dart
@@ -15,12 +15,9 @@
 import 'package:analyzer/dart/analysis/context_locator.dart';
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/ast/ast.dart';
-
 import 'package:test_runner/src/path.dart';
 
-AnalysisContext _analysisContext;
-
-void main(List<String> arguments) {
+Future<void> main(List<String> arguments) async {
   _initAnalysisContext();
 
   var suites = Directory('tests').listSync();
@@ -29,21 +26,14 @@
   for (var entry in suites) {
     // Skip the co19 tests since they don't use '_test.dart'.
     if (entry is Directory && !entry.path.contains('co19')) {
-      _checkTestDirectory(entry);
+      await _checkTestDirectory(entry);
     }
   }
 }
 
-void _initAnalysisContext() {
-  var roots = ContextLocator().locateRoots(includedPaths: ['test']);
-  if (roots.length != 1) {
-    throw StateError('Expected to find exactly one context root, got $roots');
-  }
+AnalysisContext _analysisContext;
 
-  _analysisContext = ContextBuilder().createContext(contextRoot: roots[0]);
-}
-
-void _checkTestDirectory(Directory directory) {
+Future<void> _checkTestDirectory(Directory directory) async {
   print('-- ${directory.path} --');
   var paths = directory
       .listSync(recursive: true)
@@ -56,7 +46,7 @@
   print('Finding referenced files...');
   var importedPaths = <String>{};
   for (var path in paths) {
-    _parseReferences(importedPaths, path);
+    await _parseReferences(importedPaths, path);
   }
 
   // Find the ".dart" files that don't end in "_test.dart" but also aren't used
@@ -72,9 +62,20 @@
   if (!hasOrphan) print('No orphans :)');
 }
 
-void _parseReferences(Set<String> importedPaths, String filePath) {
+void _initAnalysisContext() {
+  var roots = ContextLocator().locateRoots(includedPaths: ['test']);
+  if (roots.length != 1) {
+    throw StateError('Expected to find exactly one context root, got $roots');
+  }
+
+  _analysisContext = ContextBuilder().createContext(contextRoot: roots[0]);
+}
+
+Future<void> _parseReferences(
+    Set<String> importedPaths, String filePath) async {
   var absolute = Path(filePath).absolute.toNativePath();
-  var parseResult = _analysisContext.currentSession.getParsedUnit(absolute);
+  var analysisSession = _analysisContext.currentSession;
+  var parseResult = await analysisSession.getParsedUnit2(absolute);
   var unit = (parseResult as ParsedUnitResult).unit;
 
   void add(String importPath) {
diff --git a/runtime/bin/platform_macos.cc b/runtime/bin/platform_macos.cc
index 0c22675..498df50 100644
--- a/runtime/bin/platform_macos.cc
+++ b/runtime/bin/platform_macos.cc
@@ -11,16 +11,18 @@
 #include <CoreFoundation/CoreFoundation.h>
 
 #if !DART_HOST_OS_IOS
-#include <crt_externs.h>  // NOLINT
+#include <crt_externs.h>
 #endif                    // !DART_HOST_OS_IOS
-#include <errno.h>        // NOLINT
+#include <dlfcn.h>
+#include <errno.h>
 #include <mach-o/dyld.h>
-#include <signal.h>        // NOLINT
-#include <sys/resource.h>  // NOLINT
-#include <sys/sysctl.h>    // NOLINT
-#include <sys/types.h>     // NOLINT
-#include <sys/utsname.h>   // NOLINT
-#include <unistd.h>        // NOLINT
+#include <pthread.h>
+#include <signal.h>
+#include <sys/resource.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <unistd.h>
 
 #include <string>
 
@@ -251,7 +253,98 @@
   return path_size;
 }
 
-void Platform::SetProcessName(const char* name) {}
+void Platform::SetProcessName(const char* name) {
+  pthread_setname_np(name);
+
+#if !defined(DART_HOST_OS_IOS)
+  // Attempt to set the name displayed in ActivityMonitor.
+  // https://codereview.chromium.org/659007
+
+  class ScopedDLHandle : public ValueObject {
+   public:
+    explicit ScopedDLHandle(void* handle) : handle_(handle) {}
+    ~ScopedDLHandle() {
+      if (handle_ != NULL) dlclose(handle_);
+    }
+    void* get() { return handle_; }
+
+   private:
+    void* handle_;
+    DISALLOW_COPY_AND_ASSIGN(ScopedDLHandle);
+  };
+
+  class ScopedCFStringRef : public ValueObject {
+   public:
+    explicit ScopedCFStringRef(const char* s)
+        : ref_(CFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)) {}
+    ~ScopedCFStringRef() {
+      if (ref_ != NULL) CFRelease(ref_);
+    }
+    CFStringRef get() { return ref_; }
+
+   private:
+    CFStringRef ref_;
+    DISALLOW_COPY_AND_ASSIGN(ScopedCFStringRef);
+  };
+
+  ScopedDLHandle application_services_handle(
+      dlopen("/System/Library/Frameworks/ApplicationServices.framework/"
+             "Versions/A/ApplicationServices",
+             RTLD_LAZY | RTLD_LOCAL));
+  if (application_services_handle.get() == NULL) return;
+
+  ScopedCFStringRef launch_services_bundle_name("com.apple.LaunchServices");
+  CFBundleRef launch_services_bundle =
+      CFBundleGetBundleWithIdentifier(launch_services_bundle_name.get());
+  if (launch_services_bundle == NULL) return;
+
+#define GET_FUNC(name, cstr)                                                   \
+  ScopedCFStringRef name##_id(cstr);                                           \
+  *reinterpret_cast<void**>(&name) = CFBundleGetFunctionPointerForName(        \
+      launch_services_bundle, name##_id.get());                                \
+  if (name == NULL) return;
+
+#define GET_DATA(name, cstr)                                                   \
+  ScopedCFStringRef name##_id(cstr);                                           \
+  *reinterpret_cast<void**>(&name) =                                           \
+      CFBundleGetDataPointerForName(launch_services_bundle, name##_id.get());  \
+  if (name == NULL) return;
+
+  CFTypeRef (*_LSGetCurrentApplicationASN)(void);
+  GET_FUNC(_LSGetCurrentApplicationASN, "_LSGetCurrentApplicationASN");
+
+  OSStatus (*_LSSetApplicationInformationItem)(int, CFTypeRef, CFStringRef,
+                                               CFStringRef, CFDictionaryRef*);
+  GET_FUNC(_LSSetApplicationInformationItem,
+           "_LSSetApplicationInformationItem");
+
+  CFDictionaryRef (*_LSApplicationCheckIn)(int, CFDictionaryRef);
+  GET_FUNC(_LSApplicationCheckIn, "_LSApplicationCheckIn");
+
+  void (*_LSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t,
+                                                                void*);
+  GET_FUNC(_LSSetApplicationLaunchServicesServerConnectionStatus,
+           "_LSSetApplicationLaunchServicesServerConnectionStatus");
+
+  CFStringRef* _kLSDisplayNameKey;
+  GET_DATA(_kLSDisplayNameKey, "_kLSDisplayNameKey");
+  if (*_kLSDisplayNameKey == NULL) return;
+
+  _LSSetApplicationLaunchServicesServerConnectionStatus(0, NULL);
+
+  _LSApplicationCheckIn(-2, CFBundleGetInfoDictionary(CFBundleGetMainBundle()));
+
+  CFTypeRef asn;
+  asn = _LSGetCurrentApplicationASN();
+  if (asn == NULL) return;
+
+  ScopedCFStringRef cf_name(name);
+  _LSSetApplicationInformationItem(-2, asn, *_kLSDisplayNameKey, cf_name.get(),
+                                   NULL);
+#undef GET_DATA
+#undef GET_FUNC
+#endif  // !defined(DART_HOST_OS_IOS)
+}
 
 void Platform::Exit(int exit_code) {
   Console::RestoreConfig();
diff --git a/runtime/vm/compiler/asm_intrinsifier_riscv.cc b/runtime/vm/compiler/asm_intrinsifier_riscv.cc
index db03989..c96447f 100644
--- a/runtime/vm/compiler/asm_intrinsifier_riscv.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_riscv.cc
@@ -537,7 +537,60 @@
                                             intptr_t other_cid,
                                             Label* return_true,
                                             Label* return_false) {
-  UNIMPLEMENTED();
+  __ SmiUntag(T0);
+  __ LoadCompressedSmi(
+      T1, FieldAddress(A0, target::String::length_offset()));  // this.length
+  __ SmiUntag(T1);
+  __ LoadCompressedSmi(
+      T2, FieldAddress(A1, target::String::length_offset()));  // other.length
+  __ SmiUntag(T2);
+
+  // if (other.length == 0) return true;
+  __ beqz(T2, return_true);
+
+  // if (start < 0) return false;
+  __ bltz(T0, return_false);
+
+  // if (start + other.length > this.length) return false;
+  __ add(T3, T0, T2);
+  __ bgt(T3, T1, return_false);
+
+  if (receiver_cid == kOneByteStringCid) {
+    __ add(A0, A0, T0);
+  } else {
+    ASSERT(receiver_cid == kTwoByteStringCid);
+    __ add(A0, A0, T0);
+    __ add(A0, A0, T0);
+  }
+
+  // i = 0
+  __ li(T3, 0);
+
+  // do
+  Label loop;
+  __ Bind(&loop);
+
+  // this.codeUnitAt(i + start)
+  if (receiver_cid == kOneByteStringCid) {
+    __ lbu(TMP, FieldAddress(A0, target::OneByteString::data_offset()));
+  } else {
+    __ lhu(TMP, FieldAddress(A0, target::TwoByteString::data_offset()));
+  }
+  // other.codeUnitAt(i)
+  if (other_cid == kOneByteStringCid) {
+    __ lbu(TMP2, FieldAddress(A1, target::OneByteString::data_offset()));
+  } else {
+    __ lhu(TMP2, FieldAddress(A1, target::TwoByteString::data_offset()));
+  }
+  __ bne(TMP, TMP2, return_false);
+
+  // i++, while (i < len)
+  __ addi(T3, T3, 1);
+  __ addi(A0, A0, receiver_cid == kOneByteStringCid ? 1 : 2);
+  __ addi(A1, A1, other_cid == kOneByteStringCid ? 1 : 2);
+  __ blt(T3, T2, &loop);
+
+  __ j(return_true);
 }
 
 // bool _substringMatches(int start, String other)
@@ -545,26 +598,277 @@
 // OneByteString other.
 void AsmIntrinsifier::StringBaseSubstringMatches(Assembler* assembler,
                                                  Label* normal_ir_body) {
-  // TODO(riscv)
+  Label return_true, return_false, try_two_byte;
+  __ lx(A0, Address(SP, 2 * target::kWordSize));  // this
+  __ lx(T0, Address(SP, 1 * target::kWordSize));  // start
+  __ lx(A1, Address(SP, 0 * target::kWordSize));  // other
+
+  __ BranchIfNotSmi(T0, normal_ir_body);
+
+  __ CompareClassId(A1, kOneByteStringCid, TMP);
+  __ BranchIf(NE, normal_ir_body);
+
+  __ CompareClassId(A0, kOneByteStringCid, TMP);
+  __ BranchIf(NE, normal_ir_body);
+
+  GenerateSubstringMatchesSpecialization(assembler, kOneByteStringCid,
+                                         kOneByteStringCid, &return_true,
+                                         &return_false);
+
+  __ Bind(&try_two_byte);
+  __ CompareClassId(A0, kTwoByteStringCid, TMP);
+  __ BranchIf(NE, normal_ir_body);
+
+  GenerateSubstringMatchesSpecialization(assembler, kTwoByteStringCid,
+                                         kOneByteStringCid, &return_true,
+                                         &return_false);
+
+  __ Bind(&return_true);
+  __ LoadObject(A0, CastHandle<Object>(TrueObject()));
+  __ ret();
+
+  __ Bind(&return_false);
+  __ LoadObject(A0, CastHandle<Object>(FalseObject()));
+  __ ret();
+
   __ Bind(normal_ir_body);
 }
 
 void AsmIntrinsifier::StringBaseCharAt(Assembler* assembler,
                                        Label* normal_ir_body) {
-  // TODO(riscv)
+  Label try_two_byte_string;
+
+  __ lx(A1, Address(SP, 0 * target::kWordSize));  // Index.
+  __ lx(A0, Address(SP, 1 * target::kWordSize));  // String.
+  __ BranchIfNotSmi(A1, normal_ir_body);          // Index is not a Smi.
+  // Range check.
+  __ lx(TMP, FieldAddress(A0, target::String::length_offset()));
+  __ bgeu(A1, TMP, normal_ir_body);  // Runtime throws exception.
+
+  __ CompareClassId(A0, kOneByteStringCid, TMP);
+  __ BranchIf(NE, &try_two_byte_string);
+  __ SmiUntag(A1);
+  __ add(A0, A0, A1);
+  __ lbu(A1, FieldAddress(A0, target::OneByteString::data_offset()));
+  __ CompareImmediate(A1, target::Symbols::kNumberOfOneCharCodeSymbols);
+  __ BranchIf(GE, normal_ir_body);
+  __ lx(A0, Address(THR, target::Thread::predefined_symbols_address_offset()));
+  __ slli(A1, A1, target::kWordSizeLog2);
+  __ add(A0, A0, A1);
+  __ lx(A0, Address(A0, target::Symbols::kNullCharCodeSymbolOffset *
+                            target::kWordSize));
+  __ ret();
+
+  __ Bind(&try_two_byte_string);
+  __ CompareClassId(A0, kTwoByteStringCid, TMP);
+  __ BranchIf(NE, normal_ir_body);
+  ASSERT(kSmiTagShift == 1);
+  __ add(A0, A0, A1);
+  __ lhu(A1, FieldAddress(A0, target::TwoByteString::data_offset()));
+  __ CompareImmediate(A1, target::Symbols::kNumberOfOneCharCodeSymbols);
+  __ BranchIf(GE, normal_ir_body);
+  __ lx(A0, Address(THR, target::Thread::predefined_symbols_address_offset()));
+  __ slli(A1, A1, target::kWordSizeLog2);
+  __ add(A0, A0, A1);
+  __ lx(A0, Address(A0, target::Symbols::kNullCharCodeSymbolOffset *
+                            target::kWordSize));
+  __ ret();
+
   __ Bind(normal_ir_body);
 }
 
 void AsmIntrinsifier::StringBaseIsEmpty(Assembler* assembler,
                                         Label* normal_ir_body) {
-  // TODO(riscv)
-  __ Bind(normal_ir_body);
+  Label is_true;
+  __ lx(A0, Address(SP, 0 * target::kWordSize));
+  __ lx(A0, FieldAddress(A0, target::String::length_offset()));
+  __ beqz(A0, &is_true, Assembler::kNearJump);
+  __ LoadObject(A0, CastHandle<Object>(FalseObject()));
+  __ ret();
+  __ Bind(&is_true);
+  __ LoadObject(A0, CastHandle<Object>(TrueObject()));
+  __ ret();
 }
 
 void AsmIntrinsifier::OneByteString_getHashCode(Assembler* assembler,
                                                 Label* normal_ir_body) {
-  // TODO(riscv)
-  __ Bind(normal_ir_body);
+  Label compute_hash;
+  __ lx(A1, Address(SP, 0 * target::kWordSize));  // OneByteString object.
+#if XLEN == 32
+  __ lw(A0, FieldAddress(A1, target::String::hash_offset()));
+#else
+  __ lwu(A0, FieldAddress(A1, target::String::hash_offset()));
+  __ SmiTag(A0);
+#endif
+  __ beqz(A0, &compute_hash);
+  __ ret();  // Return if already computed.
+
+  __ Bind(&compute_hash);
+  __ lx(T0, FieldAddress(A1, target::String::length_offset()));
+  __ SmiUntag(T0);
+
+  Label set_to_one, done;
+  // If the string is empty, set the hash to 1, and return.
+  __ beqz(T0, &set_to_one);
+
+  __ mv(T1, ZR);
+  __ addi(T2, A1, target::OneByteString::data_offset() - kHeapObjectTag);
+  // A1: Instance of OneByteString.
+  // T0: String length, untagged integer.
+  // T1: Loop counter, untagged integer.
+  // T2: String data.
+  // A0: Hash code, untagged integer.
+
+  Label loop;
+  // Add to hash code: (hash_ is uint32)
+  // hash_ += ch;
+  // hash_ += hash_ << 10;
+  // hash_ ^= hash_ >> 6;
+  // Get one characters (ch).
+  __ Bind(&loop);
+  __ lbu(T3, Address(T2, 0));
+  __ addi(T2, T2, 1);
+  // T3: ch.
+  __ addi(T1, T1, 1);
+#if XLEN == 32
+  __ add(A0, A0, T3);
+  __ slli(TMP, A0, 10);
+  __ add(A0, A0, TMP);
+  __ srli(TMP, A0, 6);
+#else
+  __ addw(A0, A0, T3);
+  __ slliw(TMP, A0, 10);
+  __ addw(A0, A0, TMP);
+  __ srliw(TMP, A0, 6);
+#endif
+  __ xor_(A0, A0, TMP);
+  __ bne(T1, T0, &loop);
+
+  // Finalize.
+  // hash_ += hash_ << 3;
+  // hash_ ^= hash_ >> 11;
+  // hash_ += hash_ << 15;
+#if XLEN == 32
+  __ slli(TMP, A0, 3);
+  __ add(A0, A0, TMP);
+  __ srli(TMP, A0, 11);
+  __ xor_(A0, A0, TMP);
+  __ slli(TMP, A0, 15);
+  __ add(A0, A0, TMP);
+#else
+  __ slliw(TMP, A0, 3);
+  __ addw(A0, A0, TMP);
+  __ srliw(TMP, A0, 11);
+  __ xor_(A0, A0, TMP);
+  __ slliw(TMP, A0, 15);
+  __ addw(A0, A0, TMP);
+#endif
+  // hash_ = hash_ & ((static_cast<intptr_t>(1) << bits) - 1);
+  __ AndImmediate(A0, A0,
+                  (static_cast<intptr_t>(1) << target::String::kHashBits) - 1);
+  // return hash_ == 0 ? 1 : hash_;
+  __ bnez(A0, &done, Assembler::kNearJump);
+  __ Bind(&set_to_one);
+  __ li(A0, 1);
+  __ Bind(&done);
+
+#if XLEN == 32
+  __ SmiTag(A0);
+  __ sx(A0, FieldAddress(A1, target::String::hash_offset()));
+  __ ret();
+#else
+  // A1: Untagged address of header word (lr/sc do not support offsets).
+  __ subi(A1, A1, kHeapObjectTag);
+  __ slli(A0, A0, target::UntaggedObject::kHashTagPos);
+  Label retry;
+  __ Bind(&retry);
+  __ lr(T0, Address(A1, 0));
+  __ or_(T0, T0, A0);
+  __ sc(TMP, T0, Address(A1, 0));
+  __ bnez(TMP, &retry);
+
+  __ srli(A0, A0, target::UntaggedObject::kHashTagPos);
+  __ SmiTag(A0);
+  __ ret();
+#endif
+}
+
+// Allocates a _OneByteString or _TwoByteString. The content is not initialized.
+// 'length-reg' (A1) contains the desired length as a _Smi or _Mint.
+// Returns new string as tagged pointer in A0.
+static void TryAllocateString(Assembler* assembler,
+                              classid_t cid,
+                              Label* ok,
+                              Label* failure) {
+  ASSERT(cid == kOneByteStringCid || cid == kTwoByteStringCid);
+  const Register length_reg = A1;
+  // _Mint length: call to runtime to produce error.
+  __ BranchIfNotSmi(length_reg, failure);
+  // negative length: call to runtime to produce error.
+  __ bltz(length_reg, failure);
+
+  NOT_IN_PRODUCT(__ MaybeTraceAllocation(cid, TMP, failure));
+  __ mv(T0, length_reg);  // Save the length register.
+  if (cid == kOneByteStringCid) {
+    // Untag length.
+    __ SmiUntag(length_reg);
+  } else {
+    // Untag length and multiply by element size -> no-op.
+    ASSERT(kSmiTagSize == 1);
+  }
+  const intptr_t fixed_size_plus_alignment_padding =
+      target::String::InstanceSize() +
+      target::ObjectAlignment::kObjectAlignment - 1;
+  __ addi(length_reg, length_reg, fixed_size_plus_alignment_padding);
+  __ andi(length_reg, length_reg,
+          ~(target::ObjectAlignment::kObjectAlignment - 1));
+
+  __ lx(A0, Address(THR, target::Thread::top_offset()));
+
+  // length_reg: allocation size.
+  __ add(T1, A0, length_reg);
+  __ bltu(T1, A0, failure);  // Fail on unsigned overflow.
+
+  // Check if the allocation fits into the remaining space.
+  // A0: potential new object start.
+  // T1: potential next object start.
+  // A1: allocation size.
+  __ lx(TMP, Address(THR, target::Thread::end_offset()));
+  __ bgtu(T1, TMP, failure);
+
+  // Successfully allocated the object(s), now update top to point to
+  // next object start and initialize the object.
+  __ sx(T1, Address(THR, target::Thread::top_offset()));
+  __ AddImmediate(A0, kHeapObjectTag);
+
+  // Initialize the tags.
+  // A0: new object start as a tagged pointer.
+  // T1: new object end address.
+  // A1: allocation size.
+  {
+    const intptr_t shift = target::UntaggedObject::kTagBitsSizeTagPos -
+                           target::ObjectAlignment::kObjectAlignmentLog2;
+
+    __ CompareImmediate(A1, target::UntaggedObject::kSizeTagMaxSizeTag);
+    Label dont_zero_tag;
+    __ BranchIf(UNSIGNED_LESS_EQUAL, &dont_zero_tag);
+    __ li(A1, 0);
+    __ Bind(&dont_zero_tag);
+    __ slli(A1, A1, shift);
+
+    // Get the class index and insert it into the tags.
+    // A1: size and bit tags.
+    // This also clears the hash, which is in the high word of the tags.
+    const uword tags =
+        target::MakeTagWordForNewSpaceObject(cid, /*instance_size=*/0);
+    __ OrImmediate(A1, A1, tags);
+    __ sx(A1, FieldAddress(A0, target::Object::tags_offset()));  // Store tags.
+  }
+
+  // Set the length field using the saved length (T0).
+  __ StoreIntoObjectNoBarrier(
+      A0, FieldAddress(A0, target::String::length_offset()), T0);
+  __ j(ok);
 }
 
 // Arg0: OneByteString (receiver).
@@ -573,7 +877,53 @@
 // The indexes must be valid.
 void AsmIntrinsifier::OneByteString_substringUnchecked(Assembler* assembler,
                                                        Label* normal_ir_body) {
-  // TODO(riscv)
+  const intptr_t kStringOffset = 2 * target::kWordSize;
+  const intptr_t kStartIndexOffset = 1 * target::kWordSize;
+  const intptr_t kEndIndexOffset = 0 * target::kWordSize;
+  Label ok;
+
+  __ lx(T0, Address(SP, kEndIndexOffset));
+  __ lx(TMP, Address(SP, kStartIndexOffset));
+  __ or_(T1, T0, TMP);
+  __ BranchIfNotSmi(T1, normal_ir_body);  // 'start', 'end' not Smi.
+
+  __ sub(A1, T0, TMP);
+  TryAllocateString(assembler, kOneByteStringCid, &ok, normal_ir_body);
+  __ Bind(&ok);
+  // A0: new string as tagged pointer.
+  // Copy string.
+  __ lx(T1, Address(SP, kStringOffset));
+  __ lx(T2, Address(SP, kStartIndexOffset));
+  __ SmiUntag(T2);
+  // Calculate start address.
+  __ add(T1, T1, T2);
+
+  // T1: Start address to copy from.
+  // T2: Untagged start index.
+  __ lx(T0, Address(SP, kEndIndexOffset));
+  __ SmiUntag(T0);
+  __ sub(T0, T0, T2);
+
+  // T1: Start address to copy from (untagged).
+  // T0: Untagged number of bytes to copy.
+  // A0: Tagged result string.
+  // T3: Pointer into T1.
+  // T4: Pointer into A0.
+  // T2: Scratch register.
+  Label loop, done;
+  __ blez(T0, &done, Assembler::kNearJump);
+  __ mv(T3, T1);
+  __ mv(T4, A0);
+  __ Bind(&loop);
+  __ subi(T0, T0, 1);
+  __ lbu(T2, FieldAddress(T3, target::OneByteString::data_offset()));
+  __ addi(T3, T3, 1);
+  __ sb(T2, FieldAddress(T4, target::OneByteString::data_offset()));
+  __ addi(T4, T4, 1);
+  __ bgtz(T0, &loop);
+
+  __ Bind(&done);
+  __ ret();
   __ Bind(normal_ir_body);
 }
 
@@ -603,13 +953,27 @@
 
 void AsmIntrinsifier::AllocateOneByteString(Assembler* assembler,
                                             Label* normal_ir_body) {
-  // TODO(riscv)
+  Label ok;
+
+  __ lx(A1, Address(SP, 0 * target::kWordSize));  // Length.
+  TryAllocateString(assembler, kOneByteStringCid, &ok, normal_ir_body);
+
+  __ Bind(&ok);
+  __ ret();
+
   __ Bind(normal_ir_body);
 }
 
 void AsmIntrinsifier::AllocateTwoByteString(Assembler* assembler,
                                             Label* normal_ir_body) {
-  // TODO(riscv)
+  Label ok;
+
+  __ lx(A1, Address(SP, 0 * target::kWordSize));  // Length.
+  TryAllocateString(assembler, kTwoByteStringCid, &ok, normal_ir_body);
+
+  __ Bind(&ok);
+  __ ret();
+
   __ Bind(normal_ir_body);
 }
 
@@ -617,7 +981,52 @@
 static void StringEquality(Assembler* assembler,
                            Label* normal_ir_body,
                            intptr_t string_cid) {
-  // TODO(riscv)
+  Label is_true, is_false, loop;
+  __ lx(A0, Address(SP, 1 * target::kWordSize));  // This.
+  __ lx(A1, Address(SP, 0 * target::kWordSize));  // Other.
+
+  // Are identical?
+  __ beq(A0, A1, &is_true, Assembler::kNearJump);
+
+  // Is other OneByteString?
+  __ BranchIfSmi(A1, normal_ir_body, Assembler::kNearJump);
+  __ CompareClassId(A1, string_cid, TMP);
+  __ BranchIf(NE, normal_ir_body, Assembler::kNearJump);
+
+  // Have same length?
+  __ lx(T2, FieldAddress(A0, target::String::length_offset()));
+  __ lx(T3, FieldAddress(A1, target::String::length_offset()));
+  __ bne(T2, T3, &is_false, Assembler::kNearJump);
+
+  // Check contents, no fall-through possible.
+  __ SmiUntag(T2);
+  __ Bind(&loop);
+  __ AddImmediate(T2, -1);
+  __ bltz(T2, &is_true, Assembler::kNearJump);
+  if (string_cid == kOneByteStringCid) {
+    __ lbu(TMP, FieldAddress(A0, target::OneByteString::data_offset()));
+    __ lbu(TMP2, FieldAddress(A1, target::OneByteString::data_offset()));
+    __ addi(A0, A0, 1);
+    __ addi(A1, A1, 1);
+  } else if (string_cid == kTwoByteStringCid) {
+    __ lhu(TMP, FieldAddress(A0, target::TwoByteString::data_offset()));
+    __ lhu(TMP2, FieldAddress(A1, target::TwoByteString::data_offset()));
+    __ addi(A0, A0, 2);
+    __ addi(A1, A1, 2);
+  } else {
+    UNIMPLEMENTED();
+  }
+  __ bne(TMP, TMP2, &is_false, Assembler::kNearJump);
+  __ j(&loop);
+
+  __ Bind(&is_true);
+  __ LoadObject(A0, CastHandle<Object>(TrueObject()));
+  __ ret();
+
+  __ Bind(&is_false);
+  __ LoadObject(A0, CastHandle<Object>(FalseObject()));
+  __ ret();
+
   __ Bind(normal_ir_body);
 }
 
@@ -645,7 +1054,7 @@
   // S4: Arguments descriptor. (Will be preserved.)
   // S5: Unknown. (Must be GC safe on tail call.)
 
-  // Load the specialized function pointer into R0. Leverage the fact the
+  // Load the specialized function pointer into T0. Leverage the fact the
   // string CIDs as well as stored function pointers are in sequence.
   __ lx(T2, Address(SP, kRegExpParamOffset));
   __ lx(T1, Address(SP, kStringParamOffset));
@@ -657,7 +1066,7 @@
                                                              sticky)));
 
   // Registers are now set up for the lazy compile stub. It expects the function
-  // in R0, the argument descriptor in R4, and IC-Data in R5.
+  // in T0, the argument descriptor in S4, and IC-Data in S5.
   __ li(S5, 0);
 
   // Tail-call the function.
diff --git a/tools/VERSION b/tools/VERSION
index 33ae06c..76b2b57 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 17
 PATCH 0
-PRERELEASE 184
+PRERELEASE 185
 PRERELEASE_PATCH 0
\ No newline at end of file