Version 2.18.0-190.0.dev

Merge commit 'd1affb719fa57e999e96703555085d2065a77d29' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cbd5912..5a94e4e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -140,6 +140,13 @@
 
 ### Tools
 
+#### Dart command line
+
+- **Breaking change** [#46100](https://github.com/dart-lang/sdk/issues/46100):
+  The standalone `dart2js` and `dartdevc` tools have been removed as previously
+  announced. `dart2js` is replaced by the `dart compile js` command, `dartdevc`
+  is no longer exposed as a command-line tool.
+
 #### Linter
 
 Updated the Linter to `1.25.0`, which includes changes that
diff --git a/DEPS b/DEPS
index f159d22..d75b9ba 100644
--- a/DEPS
+++ b/DEPS
@@ -105,7 +105,7 @@
   # For more details, see https://github.com/dart-lang/sdk/issues/30164.
   "dart_style_rev": "d7b73536a8079331c888b7da539b80e6825270ea",
 
-  "dartdoc_rev": "b61647bc3833302c23bd79f03aa1fbe83578af50",
+  "dartdoc_rev": "58348a98b992ce99b95d23131b67227bdb2b4875",
   "devtools_rev": "51ac983d2db7eb19b3ce5956cb70b769d74fe784",
   "ffi_rev": "0c8364a728cfe4e4ba859c53b99d56b3dbe3add4",
   "file_rev": "0132eeedea2933513bf230513a766a8baeab0c4f",
@@ -114,7 +114,7 @@
   "html_rev": "f108bce59d136c584969fd24a5006914796cf213",
   "http_multi_server_rev": "35a3b947256768426090e3b1f5132e4fc23c175d",
   "http_parser_rev": "9126ee04e77fd8e4e2e6435b503ee4dd708d7ddc",
-  "http_rev": "2993ea5dff5ffb066b4a35c707e7a2b8dcfa17c2",
+  "http_rev": "0c2293062d7c1fa472f299da764a7dbb3895ee22",
   "icu_rev": "81d656878ec611cb0b42d52c82e9dae93920d9ba",
   "intl_rev": "9145f308f1458f37630a1ffce3b7d3b471ebbc56",
   "jinja2_rev": "2222b31554f03e62600cd7e383376a7c187967a1",
diff --git a/docs/process/breaking-changes.md b/docs/process/breaking-changes.md
index 65d85f7..88f2e27 100644
--- a/docs/process/breaking-changes.md
+++ b/docs/process/breaking-changes.md
@@ -42,6 +42,12 @@
   documentation (for example, must not mixin a class clearly documented as
   not intended to be used as a mixin).
 
+* Must set an explicit
+  [language version constraint](https://dart.dev/guides/language/evolution#language-versioning)
+  to indicate which version of the language it requires. Incompatibilities
+  introduced in new language versions are not considered breaking as long as
+  the SDK continues to support the older version of the language.
+
 Compatibility is only considered between stable releases (i.e. releases from the
 [Dart stable channel](https://dart.dev/tools/sdk/archive#stable-channel)).
 
diff --git a/pkg/_js_interop_checks/lib/src/transformations/js_util_wasm_optimizer.dart b/pkg/_js_interop_checks/lib/src/transformations/js_util_wasm_optimizer.dart
index 5abcdc2..3cb0bdc 100644
--- a/pkg/_js_interop_checks/lib/src/transformations/js_util_wasm_optimizer.dart
+++ b/pkg/_js_interop_checks/lib/src/transformations/js_util_wasm_optimizer.dart
@@ -49,7 +49,7 @@
   final Procedure _setPropertyTarget;
   final Procedure _jsifyRawTarget;
   final Procedure _newObjectTarget;
-  final Procedure _wrapDartCallbackTarget;
+  final Procedure _wrapDartFunctionTarget;
   final Procedure _allowInteropTarget;
   final Class _wasmAnyRefClass;
   final Class _objectClass;
@@ -57,7 +57,7 @@
   final Field _pragmaName;
   final Field _pragmaOptions;
   final Member _globalThisMember;
-  int _callbackTrampolineN = 1;
+  int _functionTrampolineN = 1;
 
   final CoreTypes _coreTypes;
   final StatefulStaticTypeContext _staticTypeContext;
@@ -77,8 +77,8 @@
             .getTopLevelProcedure('dart:js_util', 'setProperty'),
         _jsifyRawTarget = _coreTypes.index
             .getTopLevelProcedure('dart:_js_helper', 'jsifyRaw'),
-        _wrapDartCallbackTarget = _coreTypes.index
-            .getTopLevelProcedure('dart:_js_helper', '_wrapDartCallback'),
+        _wrapDartFunctionTarget = _coreTypes.index
+            .getTopLevelProcedure('dart:_js_helper', '_wrapDartFunction'),
         _newObjectTarget =
             _coreTypes.index.getTopLevelProcedure('dart:js_util', 'newObject'),
         _allowInteropTarget =
@@ -210,11 +210,11 @@
   /// trampoline expects a Dart callback as its first argument, followed by all
   /// of the arguments to the Dart callback as Dart objects. The trampoline will
   /// cast all incoming Dart objects to the appropriate types, dispatch, and
-  /// then `jsifyRaw` any returned value. [_createCallbackTrampoline] Returns a
+  /// then `jsifyRaw` any returned value. [_createFunctionTrampoline] Returns a
   /// [String] function name representing the name of the wrapping function.
   /// TODO(joshualitt): Share callback trampolines if the [FunctionType]
   /// matches.
-  String _createCallbackTrampoline(Procedure node, FunctionType function) {
+  String _createFunctionTrampoline(Procedure node, FunctionType function) {
     int fileOffset = node.fileOffset;
     Library library = node.enclosingLibrary;
 
@@ -245,11 +245,11 @@
     // a native JS value before being returned to JS.
     DartType nullableWasmAnyRefType =
         _wasmAnyRefClass.getThisType(_coreTypes, Nullability.nullable);
-    final callbackTrampolineName =
-        '|_callbackTrampoline${_callbackTrampolineN++}';
-    final callbackTrampolineImportName = '\$$callbackTrampolineName';
-    final callbackTrampoline = Procedure(
-        Name(callbackTrampolineName, library),
+    final functionTrampolineName =
+        '|_functionTrampoline${_functionTrampolineN++}';
+    final functionTrampolineImportName = '\$$functionTrampolineName';
+    final functionTrampoline = Procedure(
+        Name(functionTrampolineName, library),
         ProcedureKind.Method,
         FunctionNode(
             ReturnStatement(StaticInvocation(
@@ -268,24 +268,24 @@
         fileUri: node.fileUri)
       ..fileOffset = fileOffset
       ..isNonNullableByDefault = true;
-    callbackTrampoline.addAnnotation(
+    functionTrampoline.addAnnotation(
         ConstantExpression(InstanceConstant(_pragmaClass.reference, [], {
       _pragmaName.fieldReference: StringConstant('wasm:export'),
       _pragmaOptions.fieldReference:
-          StringConstant(callbackTrampolineImportName)
+          StringConstant(functionTrampolineImportName)
     })));
-    library.addProcedure(callbackTrampoline);
-    return callbackTrampolineImportName;
+    library.addProcedure(functionTrampoline);
+    return functionTrampolineImportName;
   }
 
   /// Lowers a [StaticInvocation] of `allowInterop` to
-  /// [_createCallbackTrampoline] followed by `_wrapDartCallback`.
+  /// [_createFunctionTrampoline] followed by `_wrapDartFunction`.
   StaticInvocation _allowInterop(
       Procedure node, FunctionType type, Expression argument) {
-    String callbackTrampolineName = _createCallbackTrampoline(node, type);
+    String functionTrampolineName = _createFunctionTrampoline(node, type);
     return StaticInvocation(
-        _wrapDartCallbackTarget,
-        Arguments([argument, StringLiteral(callbackTrampolineName)],
+        _wrapDartFunctionTarget,
+        Arguments([argument, StringLiteral(functionTrampolineName)],
             types: [type]));
   }
 
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart
index d9c3f09..ccea475 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart
@@ -153,6 +153,7 @@
           filterText: item.filterText,
           insertText: newInsertText,
           insertTextFormat: item.insertTextFormat,
+          insertTextMode: item.insertTextMode,
           textEdit: supportsInsertReplace && insertionRange != replacementRange
               ? Either2<InsertReplaceEdit, TextEdit>.t1(
                   InsertReplaceEdit(
diff --git a/pkg/analysis_server/lib/src/lsp/mapping.dart b/pkg/analysis_server/lib/src/lsp/mapping.dart
index db49280..b3053c1 100644
--- a/pkg/analysis_server/lib/src/lsp/mapping.dart
+++ b/pkg/analysis_server/lib/src/lsp/mapping.dart
@@ -299,6 +299,10 @@
     label += declaration.parameterNames?.isNotEmpty ?? false ? '(…)' : '()';
   }
 
+  final insertionRange = toRange(lineInfo, replacementOffset, insertLength);
+  final replacementRange =
+      toRange(lineInfo, replacementOffset, replacementLength);
+
   final insertTextInfo = _buildInsertText(
     supportsSnippets: supportsSnippets,
     includeCommitCharacters: includeCommitCharacters,
@@ -325,6 +329,7 @@
       .contains(lsp.CompletionItemTag.Deprecated);
   final supportsAsIsInsertMode =
       capabilities.completionInsertTextModes.contains(InsertTextMode.asIs);
+  final supportsInsertReplace = capabilities.insertReplaceCompletionRanges;
 
   final completionKind = declarationKindToCompletionItemKind(
       capabilities.completionItemKinds, declaration.kind);
@@ -364,6 +369,20 @@
     insertTextMode: supportsAsIsInsertMode && isMultilineCompletion
         ? InsertTextMode.asIs
         : null,
+    textEdit: supportsInsertReplace && insertionRange != replacementRange
+        ? Either2<InsertReplaceEdit, TextEdit>.t1(
+            InsertReplaceEdit(
+              insert: insertionRange,
+              replace: replacementRange,
+              newText: insertText,
+            ),
+          )
+        : Either2<InsertReplaceEdit, TextEdit>.t2(
+            TextEdit(
+              range: replacementRange,
+              newText: insertText,
+            ),
+          ),
     // data, used for completionItem/resolve.
     data: lsp.DartSuggestionSetCompletionItemResolutionInfo(
         file: file,
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_async.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_async.dart
index a26c922..f4585ed 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_async.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_async.dart
@@ -11,6 +11,8 @@
 import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
 
 class AddAsync extends CorrectionProducer {
+  // todo(pq): consider adding a variation that adds an `await` as well
+
   /// A flag indicating whether this producer is producing a fix in the case
   /// where a function is missing a return at the end.
   final bool isForMissingReturn;
diff --git a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
index 45ad2c3..3461471 100644
--- a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
+++ b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
@@ -1650,7 +1650,7 @@
 LintCode.directives_ordering:
   status: hasFix
 LintCode.discarded_futures:
-  status: needsEvaluation
+  status: hasFix
 LintCode.do_not_use_environment:
   status: needsEvaluation
 LintCode.empty_catches:
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 02cf698..a6c5906 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -447,6 +447,9 @@
     LintNames.directives_ordering: [
       OrganizeImports.new,
     ],
+    LintNames.discarded_futures: [
+      AddAsync.new,
+    ],
     LintNames.empty_catches: [
       RemoveEmptyCatch.new,
     ],
diff --git a/pkg/analysis_server/lib/src/services/linter/lint_names.dart b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
index 2ca0e71..e37937f 100644
--- a/pkg/analysis_server/lib/src/services/linter/lint_names.dart
+++ b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
@@ -53,6 +53,7 @@
   static const String diagnostic_describe_all_properties =
       'diagnostic_describe_all_properties';
   static const String directives_ordering = 'directives_ordering';
+  static const String discarded_futures = 'discarded_futures';
   static const String empty_catches = 'empty_catches';
   static const String empty_constructor_bodies = 'empty_constructor_bodies';
   static const String empty_statements = 'empty_statements';
diff --git a/pkg/analysis_server/test/lsp/completion_dart_test.dart b/pkg/analysis_server/test/lsp/completion_dart_test.dart
index 81b8f26..f55c2bd 100644
--- a/pkg/analysis_server/test/lsp/completion_dart_test.dart
+++ b/pkg/analysis_server/test/lsp/completion_dart_test.dart
@@ -480,11 +480,13 @@
     // placeholders.
     expect(item.insertTextFormat, equals(InsertTextFormat.Snippet));
     expect(item.insertText, equals(r'myFunction(${1:a}, ${2:b}, c: ${3:c})'));
-    expect(item.textEdit, isNull);
+    expect(item.textEdit, isNotNull);
+    final originalTextEdit = item.textEdit;
 
-    // Ensure the item can be resolved and gets a proper TextEdit.
+    // Ensure the item can be resolved and retains the correct textEdit (since
+    // textEdit may be recomputed during resolve).
     final resolved = await resolveCompletion(item);
-    expect(resolved.textEdit, isNotNull);
+    expect(resolved.textEdit, originalTextEdit);
     final textEdit = toTextEdit(resolved.textEdit!);
     expect(textEdit.newText, equals(item.insertText));
     expect(textEdit.range, equals(rangeFromMarkers(content)));
@@ -1612,21 +1614,24 @@
     // Find the completion for the class in the other file.
     final completion = res.singleWhere((c) => c.label == 'InOtherFile');
     expect(completion, isNotNull);
+    expect(completion.textEdit, isNotNull);
+    final originalTextEdit = completion.textEdit;
 
-    // Expect no docs or text edit, since these are added during resolve.
+    // Expect no docs, this is added during resolve.
     expect(completion.documentation, isNull);
-    expect(completion.textEdit, isNull);
 
-    // Resolve the completion item (via server) to get its edits. This is the
-    // LSP's equiv of getSuggestionDetails() and is invoked by LSP clients to
-    // populate additional info (in our case, the additional edits for inserting
-    // the import).
+    // Resolve the completion item (via server) to get any additional edits.
+    // This is LSP's equiv of getSuggestionDetails() and is invoked by LSP
+    // clients to populate additional info (in our case, any additional edits
+    // for inserting the import).
     final resolved = await resolveCompletion(completion);
     expect(resolved, isNotNull);
 
     // Ensure the detail field was update to show this will auto-import.
     expect(
-        resolved.detail, startsWith("Auto import from '../other_file.dart'"));
+      resolved.detail,
+      startsWith("Auto import from '../other_file.dart'"),
+    );
 
     // Ensure the doc comment was added.
     expect(
@@ -1634,8 +1639,8 @@
       isTrue,
     );
 
-    // Ensure the edit was added on.
-    expect(resolved.textEdit, isNotNull);
+    // Ensure the edit did not change.
+    expect(resolved.textEdit, originalTextEdit);
 
     // There should be no command for this item because it doesn't need imports
     // in other files. Same-file completions are in additionalEdits.
@@ -2047,21 +2052,24 @@
     // Find the completion for the class in the other file.
     final completion = res.singleWhere((c) => c.label == 'InOtherFile');
     expect(completion, isNotNull);
+    expect(completion.textEdit, isNotNull);
+    final originalTextEdit = completion.textEdit;
 
-    // Expect no docs or text edit, since these are added during resolve.
+    // Expect no docs, this is added during resolve.
     expect(completion.documentation, isNull);
-    expect(completion.textEdit, isNull);
 
-    // Resolve the completion item (via server) to get its edits. This is the
-    // LSP's equiv of getSuggestionDetails() and is invoked by LSP clients to
-    // populate additional info (in our case, the additional edits for inserting
-    // the import).
+    // Resolve the completion item (via server) to get any additional edits.
+    // This is LSP's equiv of getSuggestionDetails() and is invoked by LSP
+    // clients to populate additional info (in our case, any additional edits
+    // for inserting the import).
     final resolved = await resolveCompletion(completion);
     expect(resolved, isNotNull);
 
     // Ensure the detail field was update to show this will auto-import.
     expect(
-        resolved.detail, startsWith("Auto import from '../other_file.dart'"));
+      resolved.detail,
+      startsWith("Auto import from '../other_file.dart'"),
+    );
 
     // Ensure the doc comment was added.
     expect(
@@ -2069,8 +2077,8 @@
       isTrue,
     );
 
-    // Ensure the edit was added on.
-    expect(resolved.textEdit, isNotNull);
+    // Ensure the edit did not change.
+    expect(resolved.textEdit, originalTextEdit);
 
     // There should be no command for this item because it doesn't need imports
     // in other files. Same-file completions are in additionalEdits.
@@ -2265,15 +2273,15 @@
     final completion =
         res.singleWhere((c) => c.label == 'InOtherFile.fromJson()');
     expect(completion, isNotNull);
+    expect(completion.textEdit, isNotNull);
 
-    // Expect no docs or text edit, since these are added during resolve.
+    // Expect no docs, this is added during resolve.
     expect(completion.documentation, isNull);
-    expect(completion.textEdit, isNull);
 
-    // Resolve the completion item (via server) to get its edits. This is the
-    // LSP's equiv of getSuggestionDetails() and is invoked by LSP clients to
-    // populate additional info (in our case, the additional edits for inserting
-    // the import).
+    // Resolve the completion item (via server) to get any additional edits.
+    // This is LSP's equiv of getSuggestionDetails() and is invoked by LSP
+    // clients to populate additional info (in our case, any additional edits
+    // for inserting the import).
     final resolved = await resolveCompletion(completion);
     expect(resolved, isNotNull);
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_async_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_async_test.dart
index df3eb40..aff2684 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_async_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_async_test.dart
@@ -14,6 +14,7 @@
   defineReflectiveSuite(() {
     defineReflectiveTests(AddAsyncTest);
     defineReflectiveTests(AvoidReturningNullForFutureTest);
+    defineReflectiveTests(DiscardedFuturesTest);
   });
 }
 
@@ -358,3 +359,29 @@
 ''');
   }
 }
+
+@reflectiveTest
+class DiscardedFuturesTest extends FixProcessorLintTest {
+  @override
+  FixKind get kind => DartFixKind.ADD_ASYNC;
+
+  @override
+  String get lintCode => LintNames.discarded_futures;
+
+  Future<void> test_discardedFuture() async {
+    await resolveTestCode('''
+void f() {
+  g();
+}
+
+Future<void> g() async { }
+''');
+    await assertHasFix('''
+Future<void> f() async {
+  g();
+}
+
+Future<void> g() async { }
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/tool/lsp_spec/readme_test.dart b/pkg/analysis_server/test/tool/lsp_spec/readme_test.dart
new file mode 100644
index 0000000..81a8633
--- /dev/null
+++ b/pkg/analysis_server/test/tool/lsp_spec/readme_test.dart
@@ -0,0 +1,48 @@
+// 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:io';
+
+import 'package:path/path.dart' as path;
+import 'package:test/test.dart';
+
+import '../../../tool/lsp_spec/meta_model_reader.dart';
+
+void main() {
+  final serverPkgPath = _getAnalysisServerPkgPath();
+  final readmeFile = File(path.join(serverPkgPath, 'tool/lsp_spec/README.md'));
+  final metaModelJsonFile =
+      File(path.join(serverPkgPath, 'tool/lsp_spec/lsp_meta_model.json'));
+
+  group('LSP readme', () {
+    test('contains all methods', () {
+      final readmeContent = readmeFile.readAsStringSync();
+      final model = LspMetaModelReader().readFile(metaModelJsonFile);
+
+      final missingMethods = StringBuffer();
+      for (final method in model.methods) {
+        // Handle `foo/*` in the readme as well as `foo/bar`.
+        final methodWildcard = method.replaceAll(RegExp(r'\/[^\/]+$'), '/*');
+        if (!readmeContent.contains(' $method ') &&
+            !readmeContent.contains(' $methodWildcard ')) {
+          missingMethods.writeln(method);
+        }
+      }
+
+      if (missingMethods.isNotEmpty) {
+        fail(
+          'The following Methods are not listed in the README.md file:\n\n'
+          '$missingMethods',
+        );
+      }
+    });
+  });
+}
+
+String _getAnalysisServerPkgPath() {
+  final script = Platform.script.toFilePath();
+  final components = path.split(script);
+  final index = components.indexOf('analysis_server');
+  return path.joinAll(components.sublist(0, index + 1));
+}
diff --git a/pkg/analysis_server/test/tool/lsp_spec/test_all.dart b/pkg/analysis_server/test/tool/lsp_spec/test_all.dart
index 62b595f..c101149 100644
--- a/pkg/analysis_server/test/tool/lsp_spec/test_all.dart
+++ b/pkg/analysis_server/test/tool/lsp_spec/test_all.dart
@@ -8,6 +8,7 @@
 import 'generated_classes_test.dart' as generated_classes_test;
 import 'json_test.dart' as json_test;
 import 'meta_model_test.dart' as meta_model_test;
+import 'readme_test.dart' as readme_test;
 
 void main() {
   defineReflectiveSuite(() {
@@ -15,5 +16,6 @@
     generated_classes_test.main();
     json_test.main();
     meta_model_test.main();
+    readme_test.main();
   }, name: 'lsp-tool');
 }
diff --git a/pkg/analysis_server/tool/lsp_spec/README.md b/pkg/analysis_server/tool/lsp_spec/README.md
index 5c4e9fa..e2cdc3d 100644
--- a/pkg/analysis_server/tool/lsp_spec/README.md
+++ b/pkg/analysis_server/tool/lsp_spec/README.md
@@ -53,66 +53,101 @@
 - Tests: Has automated tests
 - Tested Client: Has been manually tested in at least one LSP client editor
 
-| Method | Basic Impl | Capabilities | Plugins | Tests | Tested Client | Notes |
-| - | - | - | - | - | - | - |
-| initialize | ✅ | ✅ | N/A | ✅ | ✅ | trace and other options NYI
-| initialized | ✅ | ✅ | N/A | ✅ | ✅ |
-| shutdown | ✅ | ✅ | N/A | ✅ | ✅ | supported but does nothing |
-| exit | ✅ | ✅ | N/A | ✅ | ✅ |
-| $/cancelRequest | ✅ | ✅ | | ✅ | ✅ |
-| window/showMessage | ✅ | | | | |
-| window/showMessageRequest | | | | | |
-| window/logMessage | ✅ | | | | |
-| telemetry/event | | | | | |
-| client/registerCapability | ✅ | ✅ | ✅ | ✅ | ✅ |
-| client/unregisterCapability | ✅ | ✅ | ✅ | ✅ | ✅ |
-| workspace/workspaceFolders | | | | | |
-| workspace/didChangeWorkspaceFolders | ✅ | ✅ | ✅ | ✅ | ✅ |
-| workspace/didChangeConfiguration | ✅ | ✅ | | ✅ | ✅ |
-| workspace/configuration | ✅ | ✅ | | ✅ | ✅ |
-| workspace/didChangeWatchedFiles | | | | | | unused, server does own watching |
-| workspace/symbol | ✅ | ✅ | | ✅ | ✅ |
-| workspace/executeCommand | ✅ | ✅ | | ✅ | ✅ |
-| workspace/applyEdit | ✅ | ✅ | | ✅ | ✅ |
-| workspace/onWillRenameFiles | ✅ | ✅ | | ✅ | ✅ |
-| textDocument/didOpen | ✅ | ✅ | ✅ | ✅ | ✅ |
-| textDocument/didChange | ✅ | ✅ | ✅ | ✅ | ✅ |
-| textDocument/willSave | | | | | |
-| textDocument/willSaveWaitUntil | | | | | |
-| textDocument/didClose | ✅ | ✅ | ✅ | ✅ | ✅ |
-| textDocument/publishDiagnostics | ✅ | ✅ | ✅ | ✅ | ✅ |
-| textDocument/completion | ✅ | ✅ | ✅ | ✅ | ✅ |
-| completionItem/resolve | ✅ | ✅ | ✅ | ✅ | ✅ |
-| textDocument/hover | ✅ | ✅ | | ✅ | ✅ |
-| textDocument/signatureHelp | ✅ | ✅ | | ✅ | ✅ | trigger character handling outstanding
-| textDocument/declaration | | | | | |
-| textDocument/definition | ✅ | ✅ | ✅ | ✅ | ✅ |
-| textDocument/typeDefinition | ✅ | ✅ | | ✅ | ✅ |
-| textDocument/implementation | ✅ | ✅ | | ✅ | ✅ |
-| textDocument/references | ✅ | ✅ | | ✅ | ✅ |
-| textDocument/documentHighlight | ✅ | ✅ | | ✅ | ✅ |
-| textDocument/documentSymbol | ✅ | ✅ | | ✅ | ✅ |
-| textDocument/selectionRanges | ✅ | ✅ | | ✅ | ✅ |
-| textDocument/codeAction (sortMembers) | ✅ | ✅ | | ✅ | ✅ |
-| textDocument/codeAction (organiseImports) | ✅ | ✅ | | ✅ | ✅ |
-| textDocument/codeAction (fixAll) | ✅ | ✅ | | ✅ | ✅ |
-| textDocument/codeAction (refactors) | ✅ | ✅ | | ✅ | ✅ |
-| textDocument/codeAction (assists) | ✅ | ✅ | ✅ | ✅ | ✅ | Only if the client advertises `codeActionLiteralSupport` with `Refactor`
-| textDocument/codeAction (fixes) | ✅ | ✅ | ✅ | ✅ | ✅ | Only if the client advertises `codeActionLiteralSupport` with `QuickFix`
-| textDocument/codeLens | | | | | |
-| codeLens/resolve | | | | | |
-| textDocument/documentLink | | | | | |
-| documentLink/resolve | | | | | |
-| textDocument/documentColor | ✅ | ✅ | | ✅ | ✅ |
-| textDocument/colorPresentation | ✅ | ✅ | | ✅ | ✅ |
-| textDocument/formatting | ✅ | ✅ | | ✅ | ✅ |
-| textDocument/rangeFormatting | ✅ | ✅ | | ✅ | ✅ |
-| textDocument/onTypeFormatting | ✅ | ✅ | | ✅ | ✅ |
-| textDocument/rename | ✅ | ✅ | | ✅ | ✅ |
-| textDocument/prepareRename | ✅ | ✅ | | ✅ | ✅ |
-| textDocument/foldingRange | ✅ | ✅ | ✅ | ✅ | ✅ |
-| textDocument/semanticTokens/full | ✅ | ✅ | ✅ | ✅ | ✅ |
-| textDocument/semanticTokens/range | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Method | Server | Plugins | Notes |
+| - | - | - | - |
+| initialize | ✅ | N/A | trace and other options NYI|
+| initialized | ✅ | N/A | |
+| shutdown | ✅ | N/A | supported but does nothing|
+| exit | ✅ | N/A | |
+| $/cancelRequest | ✅ | | |
+| $/logTrace | | | |
+| $/progress | | | |
+| $/setTrace | | | |
+| client/registerCapability | ✅ | ✅ | |
+| client/unregisterCapability | ✅ | ✅ | |
+| notebookDocument/* | | | |
+| telemetry/event | | | |
+| textDocument/codeAction (assists) | ✅ | ✅ | Only if the client advertises `codeActionLiteralSupport` with `Refactor`|
+| textDocument/codeAction (fixAll) | ✅ | | |
+| textDocument/codeAction (fixes) | ✅ | ✅ | Only if the client advertises `codeActionLiteralSupport` with `QuickFix`|
+| textDocument/codeAction (organiseImports) | ✅ | | |
+| textDocument/codeAction (refactors) | ✅ | | |
+| textDocument/codeAction (sortMembers) | ✅ | | |
+|  codeAction/resolve | | | |
+| textDocument/codeLens | | | |
+|   codeLens/resolve | | | |
+| textDocument/completion | ✅ | ✅ | |
+|   completionItem/resolve | ✅ | | |
+| textDocument/declaration | | | |
+| textDocument/definition | ✅ | ✅ | |
+| textDocument/diagnostic | | | |
+| textDocument/didChange | ✅ | ✅ | |
+| textDocument/didClose | ✅ | ✅ | |
+| textDocument/didOpen | ✅ | ✅ | |
+| textDocument/didSave | | | |
+| textDocument/documentColor | ✅ | | |
+|   textDocument/colorPresentation | ✅ | | |
+| textDocument/documentHighlight | ✅ | | |
+| textDocument/documentLink | | | |
+|   documentLink/resolve | | | |
+| textDocument/documentSymbol | ✅ | | |
+| textDocument/foldingRange | ✅ | ✅ | |
+| textDocument/formatting | ✅ | | |
+|   textDocument/onTypeFormatting | ✅ | | |
+|   textDocument/rangeFormatting | ✅ | | |
+| textDocument/hover | ✅ | | |
+| textDocument/implementation | ✅ | | |
+| textDocument/inlayHint | | | |
+|   inlayHint/resolve | | | |
+| textDocument/inlineValue | | | |
+| textDocument/linkedEditingRange | | | |
+| textDocument/moniker | | | |
+| textDocument/prepareCallHierarchy | | | |
+|   callHierarchy/incomingCalls | | | |
+|   callHierarchy/outgoingCalls | | | |
+| textDocument/prepareRename | ✅ | | |
+|   textDocument/rename | ✅ | | |
+| textDocument/prepareTypeHierarchy | | | |
+|   typeHierarchy/subtypes | | | |
+|   typeHierarchy/supertypes | | | |
+| textDocument/publishDiagnostics | ✅ | ✅ | |
+| textDocument/references | ✅ | | |
+| textDocument/selectionRange | ✅ | | |
+| textDocument/semanticTokens/full | ✅ | ✅ | |
+| textDocument/semanticTokens/full/delta | | | |
+| textDocument/semanticTokens/range | ✅ | ✅ | |
+| workspace/semanticTokens/refresh | | | |
+| textDocument/signatureHelp | ✅ | | |
+| textDocument/typeDefinition | ✅ | | |
+| textDocument/willSave | | | |
+| textDocument/willSaveWaitUntil | | | |
+| window/logMessage | ✅ | | |
+| window/showDocument | | | |
+| window/showMessage | ✅ | | |
+| window/showMessageRequest | | | |
+| window/workDoneProgress/cancel | | | |
+| window/workDoneProgress/create | ✅ | | |
+| workspace/applyEdit | ✅ | | |
+| workspace/codeLens/refresh | | | |
+| workspace/configuration | ✅ | | |
+| workspace/diagnostic | | | |
+| workspace/diagnostic/refresh | | | |
+| workspace/didChangeConfiguration | ✅ | | |
+| workspace/didChangeWatchedFiles | | | unused, server does own watching|
+| workspace/didChangeWorkspaceFolders | ✅ | ✅ | |
+| workspace/didCreateFiles | | | |
+| workspace/didDeleteFiles | | | |
+| workspace/didRenameFiles | | | |
+| workspace/executeCommand | ✅ | | |
+| workspace/inlayHint/refresh | | | |
+| workspace/inlineValue/refresh | | | |
+| workspace/symbol | ✅ | | |
+|   workspaceSymbol/resolve | | | |
+| workspace/willCreateFiles | | | |
+| workspace/willDeleteFiles | | | |
+| workspace/willRenameFiles | | | |
+| workspace/willRenameFiles | ✅ | | |
+| workspace/workspaceFolders | | | |
 
 ## Custom Fields, Methods and Notifications
 
diff --git a/pkg/analysis_server/tool/lsp_spec/meta_model.dart b/pkg/analysis_server/tool/lsp_spec/meta_model.dart
index 5f8d860..f6a0835 100644
--- a/pkg/analysis_server/tool/lsp_spec/meta_model.dart
+++ b/pkg/analysis_server/tool/lsp_spec/meta_model.dart
@@ -180,8 +180,9 @@
 
 class LspMetaModel {
   final List<LspEntity> types;
+  final List<String> methods;
 
-  LspMetaModel(this.types);
+  LspMetaModel({required this.types, required this.methods});
 }
 
 /// A [Map] type parsed from the LSP JSON model.
diff --git a/pkg/analysis_server/tool/lsp_spec/meta_model_cleaner.dart b/pkg/analysis_server/tool/lsp_spec/meta_model_cleaner.dart
index e28c919..ef71c3d 100644
--- a/pkg/analysis_server/tool/lsp_spec/meta_model_cleaner.dart
+++ b/pkg/analysis_server/tool/lsp_spec/meta_model_cleaner.dart
@@ -27,7 +27,7 @@
   /// Cleans an entire [LspMetaModel].
   LspMetaModel cleanModel(LspMetaModel model) {
     final types = cleanTypes(model.types);
-    return LspMetaModel(types);
+    return LspMetaModel(types: types, methods: model.methods);
   }
 
   /// Cleans a List of types.
diff --git a/pkg/analysis_server/tool/lsp_spec/meta_model_reader.dart b/pkg/analysis_server/tool/lsp_spec/meta_model_reader.dart
index 7b8919b..2da612d 100644
--- a/pkg/analysis_server/tool/lsp_spec/meta_model_reader.dart
+++ b/pkg/analysis_server/tool/lsp_spec/meta_model_reader.dart
@@ -40,18 +40,20 @@
     final structures = model['structures'] as List?;
     final enums = model['enumerations'] as List?;
     final typeAliases = model['typeAliases'] as List?;
+    final methodNames = [...?requests, ...?notifications]
+        .map((item) => item['method'] as String)
+        .toList();
     [
       ...?structures?.map(_readStructure),
       ...?enums?.map((e) => _readEnum(e)),
       ...?typeAliases?.map(_readTypeAlias),
     ].forEach(_addType);
-    final methodNames =
-        _createMethodNamesEnum([...?requests, ...?notifications]);
-    if (methodNames != null) {
-      _addType(methodNames);
+    final methodsEnum = _createMethodNamesEnum(methodNames);
+    if (methodsEnum != null) {
+      _addType(methodsEnum);
     }
 
-    return LspMetaModel(types);
+    return LspMetaModel(types: types, methods: methodNames);
   }
 
   /// Adds [type] to the current list and prevents its name from being used
@@ -65,7 +67,7 @@
       str.substring(0, 1).toLowerCase() + str.substring(1);
 
   /// Creates an enum for all LSP method names.
-  LspEnum? _createMethodNamesEnum(List items) {
+  LspEnum? _createMethodNamesEnum(List<String> methods) {
     Constant toConstant(String value) {
       final comment = '''Constant for the '$value' method.''';
       return Constant(
@@ -76,8 +78,7 @@
       );
     }
 
-    final methodConstants =
-        items.map((item) => item['method'] as String).map(toConstant).toList();
+    final methodConstants = methods.map(toConstant).toList();
 
     if (methodConstants.isEmpty) {
       return null;
diff --git a/pkg/analyzer/lib/src/dart/micro/cider_byte_store.dart b/pkg/analyzer/lib/src/dart/micro/cider_byte_store.dart
index ea0c573..acbd3f8 100644
--- a/pkg/analyzer/lib/src/dart/micro/cider_byte_store.dart
+++ b/pkg/analyzer/lib/src/dart/micro/cider_byte_store.dart
@@ -6,13 +6,6 @@
 
 import 'package:meta/meta.dart';
 
-class CacheData {
-  final int id;
-  final Uint8List bytes;
-
-  CacheData(this.id, this.bytes);
-}
-
 /// Store of bytes associated with string keys and a hash.
 ///
 /// Each key must be not longer than 100 characters and consist of only `[a-z]`,
@@ -40,18 +33,11 @@
   void release(Iterable<String> keys);
 }
 
-class CiderByteStoreTestView {
-  int length = 0;
-}
-
 /// [CiderByteStore] that keeps all data in local memory.
 class MemoryCiderByteStore implements CiderByteStore {
   @visibleForTesting
   final Map<String, MemoryCiderByteStoreEntry> map = {};
 
-  /// This field gets value only during testing.
-  CiderByteStoreTestView? testView;
-
   @override
   Uint8List? get(String key) {
     final entry = map[key];
@@ -69,7 +55,6 @@
       throw StateError('Overwriting is not allowed: $key');
     }
 
-    testView?.length++;
     map[key] = MemoryCiderByteStoreEntry._(bytes);
     return bytes;
   }
diff --git a/pkg/analyzer/test/src/dart/micro/file_resolution.dart b/pkg/analyzer/test/src/dart/micro/file_resolution.dart
index 8f688a4..fefd22b 100644
--- a/pkg/analyzer/test/src/dart/micro/file_resolution.dart
+++ b/pkg/analyzer/test/src/dart/micro/file_resolution.dart
@@ -85,7 +85,6 @@
       convertPath(_testFile),
     )!;
 
-    byteStore.testView = CiderByteStoreTestView();
     fileResolver = FileResolver(
       logger: logger,
       resourceProvider: resourceProvider,
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/container_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/container_type_mask.dart
index 6e5d625..b6dca48 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/container_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/container_type_mask.dart
@@ -17,8 +17,9 @@
   @override
   final TypeMask forwardTo;
 
+  final ir.Node /*?*/ _allocationNode;
   @override
-  final ir.Node allocationNode;
+  ir.Node get allocationNode => _allocationNode /*!*/;
 
   @override
   final MemberEntity allocationElement;
@@ -29,7 +30,7 @@
   // The length of the container.
   final int length;
 
-  const ContainerTypeMask(this.forwardTo, this.allocationNode,
+  const ContainerTypeMask(this.forwardTo, this._allocationNode,
       this.allocationElement, this.elementType, this.length);
 
   /// Deserializes a [ContainerTypeMask] object from [source].
@@ -37,13 +38,12 @@
       DataSourceReader source, CommonMasks domain) {
     source.begin(tag);
     TypeMask forwardTo = TypeMask.readFromDataSource(source, domain);
-    ir.TreeNode allocationNode = source.readTreeNodeOrNull();
     MemberEntity allocationElement = source.readMemberOrNull();
     TypeMask elementType = TypeMask.readFromDataSource(source, domain);
     int length = source.readIntOrNull();
     source.end(tag);
     return ContainerTypeMask(
-        forwardTo, allocationNode, allocationElement, elementType, length);
+        forwardTo, null, allocationElement, elementType, length);
   }
 
   /// Serializes this [ContainerTypeMask] to [sink].
@@ -52,7 +52,6 @@
     sink.writeEnum(TypeMaskKind.container);
     sink.begin(tag);
     forwardTo.writeToDataSink(sink);
-    sink.writeTreeNodeOrNull(allocationNode);
     sink.writeMemberOrNull(allocationElement);
     elementType.writeToDataSink(sink);
     sink.writeIntOrNull(length);
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/dictionary_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/dictionary_type_mask.dart
index fe414d6..c2a4730 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/dictionary_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/dictionary_type_mask.dart
@@ -34,15 +34,14 @@
       DataSourceReader source, CommonMasks domain) {
     source.begin(tag);
     TypeMask forwardTo = TypeMask.readFromDataSource(source, domain);
-    ir.TreeNode allocationNode = source.readTreeNodeOrNull();
     MemberEntity allocationElement = source.readMemberOrNull();
     TypeMask keyType = TypeMask.readFromDataSource(source, domain);
     TypeMask valueType = TypeMask.readFromDataSource(source, domain);
     Map<String, TypeMask> typeMap =
         source.readStringMap(() => TypeMask.readFromDataSource(source, domain));
     source.end(tag);
-    return DictionaryTypeMask(forwardTo, allocationNode, allocationElement,
-        keyType, valueType, typeMap);
+    return DictionaryTypeMask(
+        forwardTo, null, allocationElement, keyType, valueType, typeMap);
   }
 
   /// Serializes this [DictionaryTypeMask] to [sink].
@@ -51,7 +50,6 @@
     sink.writeEnum(TypeMaskKind.dictionary);
     sink.begin(tag);
     forwardTo.writeToDataSink(sink);
-    sink.writeTreeNodeOrNull(allocationNode);
     sink.writeMemberOrNull(allocationElement);
     keyType.writeToDataSink(sink);
     valueType.writeToDataSink(sink);
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/forwarding_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/forwarding_type_mask.dart
index 7b2651b..16e1cff 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/forwarding_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/forwarding_type_mask.dart
@@ -166,8 +166,11 @@
 abstract class AllocationTypeMask extends ForwardingTypeMask {
   const AllocationTypeMask();
 
-  // The [ir.Node] where this type mask was created.
-  ir.Node get allocationNode;
+  // The [ir.Node] where this type mask was created. This value is not used
+  // after type inference and therefore does not need to be serialized by
+  // subclasses. Using it outside of type inference may cause an exception to be
+  // thrown.
+  ir.Node /*?*/ get allocationNode;
 
   // The [Entity] where this type mask was created.
   MemberEntity get allocationElement;
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/map_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/map_type_mask.dart
index 22bb146..20f5caa 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/map_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/map_type_mask.dart
@@ -17,8 +17,9 @@
   @override
   final TypeMask forwardTo;
 
+  final ir.Node /*?*/ _allocationNode;
   @override
-  final ir.Node allocationNode;
+  ir.Node get allocationNode => _allocationNode /*!*/;
 
   @override
   final MemberEntity allocationElement;
@@ -29,21 +30,19 @@
   // The key type of this map.
   final TypeMask keyType;
 
-  const MapTypeMask(this.forwardTo, this.allocationNode, this.allocationElement,
-      this.keyType, this.valueType);
+  const MapTypeMask(this.forwardTo, this._allocationNode,
+      this.allocationElement, this.keyType, this.valueType);
 
   /// Deserializes a [MapTypeMask] object from [source].
   factory MapTypeMask.readFromDataSource(
       DataSourceReader source, CommonMasks domain) {
     source.begin(tag);
     TypeMask forwardTo = TypeMask.readFromDataSource(source, domain);
-    ir.TreeNode allocationNode = source.readTreeNodeOrNull();
     MemberEntity allocationElement = source.readMemberOrNull();
     TypeMask keyType = TypeMask.readFromDataSource(source, domain);
     TypeMask valueType = TypeMask.readFromDataSource(source, domain);
     source.end(tag);
-    return MapTypeMask(
-        forwardTo, allocationNode, allocationElement, keyType, valueType);
+    return MapTypeMask(forwardTo, null, allocationElement, keyType, valueType);
   }
 
   /// Serializes this [MapTypeMask] to [sink].
@@ -52,7 +51,6 @@
     sink.writeEnum(TypeMaskKind.map);
     sink.begin(tag);
     forwardTo.writeToDataSink(sink);
-    sink.writeTreeNodeOrNull(allocationNode);
     sink.writeMemberOrNull(allocationElement);
     keyType.writeToDataSink(sink);
     valueType.writeToDataSink(sink);
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/set_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/set_type_mask.dart
index ece92e5..2e83741 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/set_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/set_type_mask.dart
@@ -17,8 +17,9 @@
   @override
   final TypeMask forwardTo;
 
+  final ir.Node /*?*/ _allocationNode;
   @override
-  final ir.Node allocationNode;
+  ir.Node get allocationNode => _allocationNode /*!*/;
 
   @override
   final MemberEntity allocationElement;
@@ -26,20 +27,18 @@
   // The element type of this set.
   final TypeMask elementType;
 
-  const SetTypeMask(this.forwardTo, this.allocationNode, this.allocationElement,
-      this.elementType);
+  const SetTypeMask(this.forwardTo, this._allocationNode,
+      this.allocationElement, this.elementType);
 
   /// Deserializes a [SetTypeMask] object from [source].
   factory SetTypeMask.readFromDataSource(
       DataSourceReader source, CommonMasks domain) {
     source.begin(tag);
     TypeMask forwardTo = TypeMask.readFromDataSource(source, domain);
-    ir.TreeNode allocationNode = source.readTreeNodeOrNull();
     MemberEntity allocationElement = source.readMemberOrNull();
     TypeMask elementType = TypeMask.readFromDataSource(source, domain);
     source.end(tag);
-    return SetTypeMask(
-        forwardTo, allocationNode, allocationElement, elementType);
+    return SetTypeMask(forwardTo, null, allocationElement, elementType);
   }
 
   /// Serializes this [SetTypeMask] to [sink].
@@ -48,7 +47,6 @@
     sink.writeEnum(TypeMaskKind.set);
     sink.begin(tag);
     forwardTo.writeToDataSink(sink);
-    sink.writeTreeNodeOrNull(allocationNode);
     sink.writeMemberOrNull(allocationElement);
     elementType.writeToDataSink(sink);
     sink.end(tag);
diff --git a/pkg/compiler/lib/src/js_backend/annotations.dart b/pkg/compiler/lib/src/js_backend/annotations.dart
index fe70a94..7fc51bc 100644
--- a/pkg/compiler/lib/src/js_backend/annotations.dart
+++ b/pkg/compiler/lib/src/js_backend/annotations.dart
@@ -22,6 +22,10 @@
   final bool forFieldsOnly;
   final bool internalOnly;
 
+  // TODO(sra): Review [forFunctionsOnly] and [forFieldsOnly]. Fields have
+  // implied getters and setters, so some annotations meant only for functions
+  // could reasonable be placed on a field to apply to the getter and setter.
+
   const PragmaAnnotation(this._index, this.name,
       {this.forFunctionsOnly = false,
       this.forFieldsOnly = false,
@@ -41,15 +45,20 @@
   static const PragmaAnnotation tryInline =
       PragmaAnnotation(1, 'tryInline', forFunctionsOnly: true);
 
+  /// Annotation on a member that tells the optimizing compiler to disable
+  /// inlining at call sites within the member.
+  static const PragmaAnnotation disableInlining =
+      PragmaAnnotation(2, 'disable-inlining');
+
   static const PragmaAnnotation disableFinal = PragmaAnnotation(
-      2, 'disableFinal',
+      3, 'disableFinal',
       forFunctionsOnly: true, internalOnly: true);
 
-  static const PragmaAnnotation noElision = PragmaAnnotation(3, 'noElision');
+  static const PragmaAnnotation noElision = PragmaAnnotation(4, 'noElision');
 
   /// Tells the optimizing compiler that the annotated method cannot throw.
   /// Requires @pragma('dart2js:noInline') to function correctly.
-  static const PragmaAnnotation noThrows = PragmaAnnotation(4, 'noThrows',
+  static const PragmaAnnotation noThrows = PragmaAnnotation(5, 'noThrows',
       forFunctionsOnly: true, internalOnly: true);
 
   /// Tells the optimizing compiler that the annotated method has no
@@ -58,7 +67,7 @@
   ///
   /// Requires @pragma('dart2js:noInline') to function correctly.
   static const PragmaAnnotation noSideEffects = PragmaAnnotation(
-      5, 'noSideEffects',
+      6, 'noSideEffects',
       forFunctionsOnly: true, internalOnly: true);
 
   /// Use this as metadata on method declarations to disable closed world
@@ -66,48 +75,49 @@
   /// could be any value. Note that the constraints due to static types still
   /// apply.
   static const PragmaAnnotation assumeDynamic = PragmaAnnotation(
-      6, 'assumeDynamic',
+      7, 'assumeDynamic',
       forFunctionsOnly: true, internalOnly: true);
 
-  static const PragmaAnnotation asTrust = PragmaAnnotation(7, 'as:trust',
+  static const PragmaAnnotation asTrust = PragmaAnnotation(8, 'as:trust',
       forFunctionsOnly: false, internalOnly: false);
 
-  static const PragmaAnnotation asCheck = PragmaAnnotation(8, 'as:check',
+  static const PragmaAnnotation asCheck = PragmaAnnotation(9, 'as:check',
       forFunctionsOnly: false, internalOnly: false);
 
-  static const PragmaAnnotation typesTrust = PragmaAnnotation(9, 'types:trust',
+  static const PragmaAnnotation typesTrust = PragmaAnnotation(10, 'types:trust',
       forFunctionsOnly: false, internalOnly: false);
 
-  static const PragmaAnnotation typesCheck = PragmaAnnotation(10, 'types:check',
+  static const PragmaAnnotation typesCheck = PragmaAnnotation(11, 'types:check',
       forFunctionsOnly: false, internalOnly: false);
 
   static const PragmaAnnotation parameterTrust = PragmaAnnotation(
-      11, 'parameter:trust',
+      12, 'parameter:trust',
       forFunctionsOnly: false, internalOnly: false);
 
   static const PragmaAnnotation parameterCheck = PragmaAnnotation(
-      12, 'parameter:check',
+      13, 'parameter:check',
       forFunctionsOnly: false, internalOnly: false);
 
   static const PragmaAnnotation downcastTrust = PragmaAnnotation(
-      13, 'downcast:trust',
+      14, 'downcast:trust',
       forFunctionsOnly: false, internalOnly: false);
 
   static const PragmaAnnotation downcastCheck = PragmaAnnotation(
-      14, 'downcast:check',
+      15, 'downcast:check',
       forFunctionsOnly: false, internalOnly: false);
 
   static const PragmaAnnotation indexBoundsTrust = PragmaAnnotation(
-      15, 'index-bounds:trust',
+      16, 'index-bounds:trust',
       forFunctionsOnly: false, internalOnly: false);
 
   static const PragmaAnnotation indexBoundsCheck = PragmaAnnotation(
-      16, 'index-bounds:check',
+      17, 'index-bounds:check',
       forFunctionsOnly: false, internalOnly: false);
 
   static const List<PragmaAnnotation> values = [
     noInline,
     tryInline,
+    disableInlining,
     disableFinal,
     noElision,
     noThrows,
@@ -273,6 +283,9 @@
   /// annotation.
   bool hasTryInline(MemberEntity member);
 
+  /// Returns `true` if inlining is disabled at call sites inside [member].
+  bool hasDisableInlining(MemberEntity member);
+
   /// Returns `true` if [member] has a `@pragma('dart2js:disableFinal')`
   /// annotation.
   bool hasDisableFinal(MemberEntity member);
@@ -343,6 +356,7 @@
   final CheckPolicy _defaultConditionCheckPolicy;
   final CheckPolicy _defaultExplicitCastCheckPolicy;
   final CheckPolicy _defaultIndexBoundsCheckPolicy;
+  final bool _defaultDisableInlining;
   final Map<MemberEntity, EnumSet<PragmaAnnotation>> pragmaAnnotations;
 
   AnnotationsDataImpl(CompilerOptions options, this.pragmaAnnotations)
@@ -353,7 +367,8 @@
         this._defaultExplicitCastCheckPolicy =
             options.defaultExplicitCastCheckPolicy,
         this._defaultIndexBoundsCheckPolicy =
-            options.defaultIndexBoundsCheckPolicy;
+            options.defaultIndexBoundsCheckPolicy,
+        this._defaultDisableInlining = options.disableInlining;
 
   factory AnnotationsDataImpl.readFromDataSource(
       CompilerOptions options, DataSourceReader source) {
@@ -393,6 +408,11 @@
       _hasPragma(member, PragmaAnnotation.tryInline);
 
   @override
+  bool hasDisableInlining(MemberEntity member) =>
+      _hasPragma(member, PragmaAnnotation.disableInlining) ||
+      _defaultDisableInlining;
+
+  @override
   bool hasDisableFinal(MemberEntity member) =>
       _hasPragma(member, PragmaAnnotation.disableFinal);
 
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 8445d27..af68bc6 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -5830,6 +5830,13 @@
       return false;
     }
 
+    // Check if inlining is disabled for the current element (includes globally)
+    // before making decsions on the basis of the callee so that cached callee
+    // decisions are not a function of the call site's method.
+    if (closedWorld.annotationsData.hasDisableInlining(_currentFrame.member)) {
+      return false;
+    }
+
     bool insideLoop = loopDepth > 0 || graph.calledInLoop;
 
     // Bail out early if the inlining decision is in the cache and we can't
@@ -5840,8 +5847,6 @@
     if (cachedCanBeInlined == false) return false;
 
     bool meetsHardConstraints() {
-      if (options.disableInlining) return false;
-
       assert(
           selector != null ||
               function.isStatic ||
diff --git a/pkg/compiler/test/annotations/data/basic.dart b/pkg/compiler/test/annotations/data/basic.dart
index c7f29c9..5ffc870 100644
--- a/pkg/compiler/test/annotations/data/basic.dart
+++ b/pkg/compiler/test/annotations/data/basic.dart
@@ -11,6 +11,8 @@
   noThrows();
   noSideEffects();
   assumeDynamic();
+  disableInlining();
+  several();
 }
 
 /*member: noInline:noInline*/
@@ -38,3 +40,15 @@
 /*member: assumeDynamic:assumeDynamic*/
 @pragma('dart2js:assumeDynamic')
 assumeDynamic() {}
+
+/*member: disableInlining:disable-inlining*/
+@pragma('dart2js:disable-inlining')
+disableInlining() {}
+
+/*member: several:assumeDynamic,disable-inlining,noInline,noSideEffects,noThrows*/
+@pragma('dart2js:disable-inlining')
+@pragma('dart2js:noThrows')
+@pragma('dart2js:noSideEffects')
+@pragma('dart2js:assumeDynamic')
+@pragma('dart2js:noInline')
+several() {}
diff --git a/pkg/compiler/test/codegen/data/inlining_annotations.dart b/pkg/compiler/test/codegen/data/inlining_annotations.dart
new file mode 100644
index 0000000..4702bfd
--- /dev/null
+++ b/pkg/compiler/test/codegen/data/inlining_annotations.dart
@@ -0,0 +1,76 @@
+// 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.
+
+/*member: foo1:ignore*/
+@pragma('dart2js:tryInline')
+int foo1() => bar1();
+
+/*member: foo2:ignore*/
+@pragma('dart2js:tryInline')
+@pragma('dart2js:disable-inlining')
+int foo2() => bar2();
+
+/*member: foo3:ignore*/
+@pragma('dart2js:noInline')
+int foo3() => bar3();
+
+/*member: bar1:ignore*/
+int bar1() => 1;
+
+/*member: bar2:ignore*/
+int bar2() => 2;
+
+/*member: bar3:ignore*/
+int bar3() => 3;
+
+// All calls to `barN` are inlined because this improves size and performance.
+/*member: test1:function() {
+  A.use(1, 2, 3);
+}*/
+@pragma('dart2js:noInline')
+void test1() {
+  use(bar1(), bar2(), bar3());
+}
+
+// No calls to `barN` are inlined due to `disable-inlining`.
+/*member: test2:function() {
+  A.use(A.bar1(), A.bar2(), A.bar3());
+}*/
+@pragma('dart2js:noInline')
+@pragma('dart2js:disable-inlining')
+void test2() {
+  use(bar1(), bar2(), bar3());
+}
+
+// `foo` and `bar1` are inlined. `foo2` is inlined, but the contained call to
+// `bar2` is not inlined due to `disable-inlining` on `foo2`.
+/*member: test3:function() {
+  A.use(1, A.bar2(), A.foo3());
+}*/
+@pragma('dart2js:noInline')
+void test3() {
+  use(foo1(), foo2(), foo3());
+}
+
+// None of the `fooN` calls are inlined due to `disable-inlining`.
+/*member: test4:function() {
+  A.use(A.foo1(), A.foo2(), A.foo3());
+}*/
+@pragma('dart2js:noInline')
+@pragma('dart2js:disable-inlining')
+void test4() {
+  use(foo1(), foo2(), foo3());
+}
+
+/*member: use:ignore*/
+@pragma('dart2js:noInline')
+void use(int a, int b, int c) {}
+
+/*member: main:ignore*/
+main() {
+  test1();
+  test2();
+  test3();
+  test4();
+}
diff --git a/pkg/compiler/test/serialization/serialization_test_helper.dart b/pkg/compiler/test/serialization/serialization_test_helper.dart
index 240a922..f50d65b 100644
--- a/pkg/compiler/test/serialization/serialization_test_helper.dart
+++ b/pkg/compiler/test/serialization/serialization_test_helper.dart
@@ -235,6 +235,12 @@
   return newClosedWorldAndIndices;
 }
 
+/// Tests that cloned inference results serialize to the same data.
+///
+/// Does 3 round trips to serialize/deserialize the provided data. The first
+/// round normalizes the data as some information might be dropped in the
+/// serialization/deserialization process. The second and third rounds are
+/// compared for consistency.
 GlobalTypeInferenceResults cloneInferenceResults(
     DataSourceIndices indices,
     Compiler compiler,
@@ -256,7 +262,7 @@
       newComponent,
       closedWorldData);
   var newIndices = indices == null ? null : newClosedWorldAndIndices.indices;
-  GlobalTypeInferenceResults newResults = strategy
+  GlobalTypeInferenceResults initialResults = strategy
       .deserializeGlobalTypeInferenceResults(
           compiler.options,
           compiler.reporter,
@@ -267,8 +273,21 @@
           newIndices,
           worldData)
       .data;
-  List<int> newWorldData = strategy.serializeGlobalTypeInferenceResults(
-      newIndices, newResults, compiler.options);
-  checkData(worldData, newWorldData);
-  return newResults;
+  List<int> initialWorldData = strategy.serializeGlobalTypeInferenceResults(
+      newIndices, initialResults, compiler.options);
+  GlobalTypeInferenceResults finalResults = strategy
+      .deserializeGlobalTypeInferenceResults(
+          compiler.options,
+          compiler.reporter,
+          compiler.environment,
+          compiler.abstractValueStrategy,
+          newComponent,
+          newClosedWorldAndIndices.data,
+          newIndices,
+          worldData)
+      .data;
+  List<int> finalWorldData = strategy.serializeGlobalTypeInferenceResults(
+      newIndices, finalResults, compiler.options);
+  checkData(initialWorldData, finalWorldData);
+  return finalResults;
 }
diff --git a/pkg/dart2js_info/test/binary_serialization_test.dart b/pkg/dart2js_info/test/binary_serialization_test.dart
index 73869d5..27ac31a 100644
--- a/pkg/dart2js_info/test/binary_serialization_test.dart
+++ b/pkg/dart2js_info/test/binary_serialization_test.dart
@@ -5,7 +5,8 @@
 // @dart = 2.11
 
 import 'dart:convert';
-import 'dart:io';
+import 'dart:io' show File, Platform;
+import 'dart:typed_data' show BytesBuilder;
 
 import 'package:dart2js_info/json_info_codec.dart';
 import 'package:dart2js_info/binary_serialization.dart' as binary;
diff --git a/pkg/dart2wasm/bin/run_wasm.js b/pkg/dart2wasm/bin/run_wasm.js
index 5e6dcb9..0078a7b 100644
--- a/pkg/dart2wasm/bin/run_wasm.js
+++ b/pkg/dart2wasm/bin/run_wasm.js
@@ -42,17 +42,6 @@
     }
 }
 
-// Converts a JS array to a Dart List, and also recursively converts the items
-// in the array.
-function arrayToDartList(array, allocator, adder) {
-    var length = array.length;
-    var dartList = dartInstance.exports.$listAllocate();
-    for (var i = 0; i < length; i++) {
-        dartInstance.exports.$listAdd(dartList, array[i]);
-    }
-    return dartList;
-}
-
 // Converts a Dart List to a JS array. Any Dart objects will be converted, but
 // this will be cheap for JSValues.
 function arrayFromDartList(list, reader) {
@@ -64,35 +53,8 @@
     return array;
 }
 
-// TODO(joshualitt): Once we can properly return functions, then we can also try
-// returning a regular closure with some custom keys and a special symbol to
-// disambiguate it from other functions. I suspect this will also be necessary
-// for CSP.
-class WrappedDartCallback extends Function {
-    constructor(dartCallback, exportFunctionName) {
-        super('dartCallback', '...args',
-            `return dartInstance.exports['${exportFunctionName}'](
-                dartCallback, ...args.map(dartify));`);
-        this.bound = this.bind(this, dartCallback);
-        this.bound.dartCallback = dartCallback;
-        return this.bound;
-    }
-}
-
-// Recursively converts a JS object into a Dart object.
-function dartify(object) {
-    if (typeof object === "string") {
-        return stringToDartString(object);
-    } else if (object instanceof Array) {
-        return arrayToDartList(object);
-    } else if (object instanceof WrappedDartCallback) {
-        return object.dartCallback;
-    } else if (object instanceof Object) {
-        return dartInstance.exports.$boxJSValue(object);
-    } else {
-        return object;
-    }
-}
+// A special symbol attached to functions that wrap Dart functions.
+var jsWrappedDartFunctionSymbol = Symbol("JSWrappedDartFunction");
 
 // Imports for printing and event loop
 var dart2wasm = {
@@ -118,13 +80,64 @@
         return stringToDartString(userStackString);
     },
     arrayFromDartList: arrayFromDartList,
-    arrayToDartList: arrayToDartList,
     stringFromDartString: stringFromDartString,
     stringToDartString: stringToDartString,
-    wrapDartCallback: function(dartCallback, exportFunctionName) {
-        return new WrappedDartCallback(dartCallback, exportFunctionName);
+    wrapDartFunction: function(dartFunction, exportFunctionName) {
+        var wrapped = function (...args) {
+            return dartInstance.exports[`${exportFunctionName}`](
+                dartFunction, ...args.map(dartInstance.exports.$dartifyRaw));
+        }
+        wrapped.dartFunction = dartFunction;
+        wrapped[jsWrappedDartFunctionSymbol] = true;
+        return wrapped;
     },
-    dartify: dartify,
+    objectLength: function(o) {
+        return o.length;
+    },
+    objectReadIndex: function(o, i) {
+        return o[i];
+    },
+    unwrapJSWrappedDartFunction: function(o) {
+        return o.dartFunction;
+    },
+    isJSUndefined: function(o) {
+        return o === undefined;
+    },
+    isJSBoolean: function(o) {
+        return typeof o === "boolean";
+    },
+    isJSNumber: function(o) {
+        return typeof o === "number";
+    },
+    isJSBigInt: function(o) {
+        return typeof o === "bigint";
+    },
+    isJSString: function(o) {
+        return typeof o === "string";
+    },
+    isJSSymbol: function(o) {
+        return typeof o === "symbol";
+    },
+    isJSFunction: function(o) {
+        return typeof o === "function";
+    },
+    isJSArray: function(o) {
+        return o instanceof Array;
+    },
+    isJSWrappedDartFunction: function(o) {
+        return typeof o === "function" &&
+            o[jsWrappedDartFunctionSymbol] === true;
+    },
+    isJSObject: function(o) {
+        return o instanceof Object;
+    },
+    roundtrip: function (o) {
+      // This function exists as a hook for the native JS -> Wasm type
+      // conversion rules. The Dart runtime will overload variants of this
+      // function with the necessary return type to trigger the desired
+      // coercion.
+      return o;
+    },
     newObject: function() {
         return {};
     },
diff --git a/pkg/dds/CHANGELOG.md b/pkg/dds/CHANGELOG.md
index c0f272a..b4fa6ec0 100644
--- a/pkg/dds/CHANGELOG.md
+++ b/pkg/dds/CHANGELOG.md
@@ -1,3 +1,6 @@
+# 2.2.2
+- Updated `vm_service` version to 9.0.0.
+
 # 2.2.1
 - Reduce latency of `streamListen` calls through improved locking behavior.
 
diff --git a/pkg/dds/lib/src/dap/isolate_manager.dart b/pkg/dds/lib/src/dap/isolate_manager.dart
index df7dd76..5af7f41 100644
--- a/pkg/dds/lib/src/dap/isolate_manager.dart
+++ b/pkg/dds/lib/src/dap/isolate_manager.dart
@@ -10,6 +10,7 @@
 import 'package:path/path.dart' as path;
 import 'package:vm_service/vm_service.dart' as vm;
 
+import '../rpc_error_codes.dart';
 import 'adapters/dart.dart';
 import 'exceptions.dart';
 import 'protocol_generated.dart';
@@ -694,7 +695,22 @@
       final isDebuggable = libraryUri != null
           ? await _adapter.libraryIsDebuggable(thread, Uri.parse(libraryUri))
           : false;
-      await service.setLibraryDebuggable(isolateId, library.id!, isDebuggable);
+      try {
+        await service.setLibraryDebuggable(
+            isolateId, library.id!, isDebuggable);
+      } on vm.RPCError catch (e) {
+        // DWDS does not currently support `setLibraryDebuggable` so instead of
+        // failing (because this code runs in a VM event handler where there's
+        // no incoming request to fail/reject), just log this error.
+        // https://github.com/dart-lang/webdev/issues/606
+        if (e.code == RpcErrorCodes.kMethodNotFound) {
+          _adapter.logger?.call(
+            'setLibraryDebuggable not available ($libraryUri, $e)',
+          );
+        } else {
+          rethrow;
+        }
+      }
     }));
   }
 
diff --git a/pkg/dds/pubspec.yaml b/pkg/dds/pubspec.yaml
index 40e8453..4145ae3 100644
--- a/pkg/dds/pubspec.yaml
+++ b/pkg/dds/pubspec.yaml
@@ -1,5 +1,5 @@
 name: dds
-version: 2.2.1
+version: 2.2.2
 description: >-
   A library used to spawn the Dart Developer Service, used to communicate with
   a Dart VM Service instance.
@@ -26,7 +26,7 @@
   sse: ^4.0.0
   stack_trace: ^1.10.0
   stream_channel: ^2.0.0
-  vm_service: ^8.1.0
+  vm_service: ^9.0.0
   web_socket_channel: ^2.0.0
 
 # We use 'any' version constraints here as we get our package versions from
diff --git a/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart b/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
index 4ba953c..24a6751 100644
--- a/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
+++ b/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
@@ -6,8 +6,9 @@
 
 import 'dart:async';
 import 'dart:convert';
-import 'dart:io';
+import 'dart:io' show stdin, stdout;
 import 'dart:isolate';
+import 'dart:typed_data' show BytesBuilder;
 
 import 'package:args/args.dart';
 import 'package:build_integration/file_system/multi_root.dart';
diff --git a/pkg/dev_compiler/tool/ddb b/pkg/dev_compiler/tool/ddb
index 5f3a651..8cfc2e2 100755
--- a/pkg/dev_compiler/tool/ddb
+++ b/pkg/dev_compiler/tool/ddb
@@ -174,7 +174,7 @@
         mode: ProcessStartMode.inheritStdio, environment: environment);
   }
 
-  Future<void> runDdc(String command, List<String> args) async {
+  Future<void> runDdc(List<String> args) async {
     if (debug) {
       // Use unbuilt script.  This only works from a source checkout.
       var vmServicePort = options.wasParsed('vm-service-port')
@@ -188,14 +188,14 @@
           '--pause-isolates-on-start',
         ],
         '--enable-asserts',
-        p.join(ddcPath, 'bin', '$command.dart')
+        p.join(ddcPath, 'bin', 'dartdevc.dart')
       ]);
-      command = dartBinary;
     } else {
       // Use built snapshot.
-      command = p.join(dartSdk, 'bin', command);
+      args.insertAll(
+          0, [p.join(dartSdk, 'bin', 'snapshots', 'dartdevc.dart.snapshot')]);
     }
-    var process = await startProcess('DDC', command, args, <String, String>{
+    var process = await startProcess('DDC', dartBinary, args, <String, String>{
       if (options['compile-vm-options'] != null)
         'DART_VM_OPTIONS': options['compile-vm-options'] as String
     });
@@ -249,7 +249,7 @@
       out,
       entry
     ];
-    await runDdc('dartdevc', ddcArgs);
+    await runDdc(ddcArgs);
   }
 
   if (run) {
diff --git a/pkg/front_end/lib/src/fasta/kernel/benchmarker.dart b/pkg/front_end/lib/src/fasta/kernel/benchmarker.dart
index 63a7df3..8c4850d 100644
--- a/pkg/front_end/lib/src/fasta/kernel/benchmarker.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/benchmarker.dart
@@ -234,8 +234,6 @@
   body_buildBody_benchmark_specific_diet_parser,
   body_buildBody_benchmark_specific_parser,
 
-  inferConstructorParameterTypes,
-  inferDeclarationType,
   inferImplicitFieldType,
   inferFieldInitializer,
   inferFunctionBody,
diff --git a/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart b/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
index 2a69401..dac8657 100644
--- a/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
@@ -161,7 +161,8 @@
           bodyBuilder.parseFieldInitializer(initializerToken!);
       initializerToken = null;
 
-      inferredType = typeInferrer.inferImplicitFieldType(initializer);
+      inferredType =
+          typeInferrer.inferImplicitFieldType(bodyBuilder, initializer);
     } else {
       inferredType = const DynamicType();
     }
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index c3f4254..08270a4 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -44,7 +44,7 @@
         ExpressionVisitor1<ExpressionInferenceResult, DartType>,
         StatementVisitor<StatementInferenceResult>,
         InitializerVisitor<InitializerInferenceResult> {
-  final TypeInferrerImpl inferrer;
+  final InferenceVisitorBase inferrer;
 
   Class? mapEntryClass;
 
@@ -5058,11 +5058,11 @@
                     .computeFunctionType(inferrer.libraryBuilder.nonNullable)
                 : interfaceMember.function.returnType;
             checkReturn =
-                TypeInferrerImpl.returnedTypeParametersOccurNonCovariantly(
+                InferenceVisitorBase.returnedTypeParametersOccurNonCovariantly(
                     interfaceMember.enclosingClass!, typeToCheck);
           } else if (interfaceMember is Field) {
             checkReturn =
-                TypeInferrerImpl.returnedTypeParametersOccurNonCovariantly(
+                InferenceVisitorBase.returnedTypeParametersOccurNonCovariantly(
                     interfaceMember.enclosingClass!, interfaceMember.type);
           }
         }
diff --git a/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart b/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
index 1c0c5c4..b181fd5 100644
--- a/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
@@ -1019,7 +1019,7 @@
 }
 
 Expression? checkWebIntLiteralsErrorIfUnexact(
-    TypeInferrerImpl inferrer, int value, String? literal, int charOffset) {
+    InferenceVisitorBase inferrer, int value, String? literal, int charOffset) {
   if (value >= 0 && value <= (1 << 53)) return null;
   if (inferrer.isTopLevel) return null;
   if (!inferrer.libraryBuilder.loader.target.backendTarget
diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
index 25f5456..d1e61b6 100644
--- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
@@ -98,7 +98,6 @@
 import '../operator.dart';
 import '../problems.dart' show unexpected, unhandled;
 import '../scope.dart';
-import '../type_inference/type_inferrer.dart' show TypeInferrer;
 import '../util/helpers.dart';
 import 'name_scheme.dart';
 import 'source_class_builder.dart' show SourceClassBuilder;
@@ -4244,7 +4243,6 @@
       DartType receiverType,
       TypeEnvironment typeEnvironment,
       ClassHierarchy hierarchy,
-      TypeInferrer typeInferrer,
       Name name,
       Member? interfaceTarget,
       Arguments arguments,
@@ -4321,7 +4319,6 @@
   void checkBoundsInFunctionInvocation(
       TypeEnvironment typeEnvironment,
       ClassHierarchy hierarchy,
-      TypeInferrer typeInferrer,
       FunctionType functionType,
       String? localName,
       Arguments arguments,
@@ -4356,7 +4353,6 @@
   void checkBoundsInInstantiation(
       TypeEnvironment typeEnvironment,
       ClassHierarchy hierarchy,
-      TypeInferrer typeInferrer,
       FunctionType functionType,
       List<DartType> typeArguments,
       Uri fileUri,
diff --git a/pkg/front_end/lib/src/fasta/type_inference/closure_context.dart b/pkg/front_end/lib/src/fasta/type_inference/closure_context.dart
index c7f66b4..8d0c67b 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/closure_context.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/closure_context.dart
@@ -33,7 +33,7 @@
 
   DartType? get futureValueType;
 
-  factory ClosureContext(TypeInferrerImpl inferrer, AsyncMarker asyncMarker,
+  factory ClosureContext(InferenceVisitorBase inferrer, AsyncMarker asyncMarker,
       DartType returnContext, bool needToInferReturnType) {
     // ignore: unnecessary_null_comparison
     assert(returnContext != null);
@@ -85,7 +85,7 @@
   /// If the return type is declared, the expression type is checked. If the
   /// return type is inferred the expression type registered for inference
   /// in [inferReturnType].
-  void handleReturn(TypeInferrerImpl inferrer, ReturnStatement statement,
+  void handleReturn(InferenceVisitorBase inferrer, ReturnStatement statement,
       DartType type, bool isArrow);
 
   /// Handles an explicit yield statement.
@@ -93,7 +93,7 @@
   /// If the return type is declared, the expression type is checked. If the
   /// return type is inferred the expression type registered for inference
   /// in [inferReturnType].
-  void handleYield(TypeInferrerImpl inferrer, YieldStatement node,
+  void handleYield(InferenceVisitorBase inferrer, YieldStatement node,
       ExpressionInferenceResult expressionResult);
 
   /// Handles an implicit return statement.
@@ -101,7 +101,7 @@
   /// If the return type is declared, the expression type is checked. If the
   /// return type is inferred the expression type registered for inference
   /// in [inferReturnType].
-  StatementInferenceResult handleImplicitReturn(TypeInferrerImpl inferrer,
+  StatementInferenceResult handleImplicitReturn(InferenceVisitorBase inferrer,
       Statement body, StatementInferenceResult inferenceResult, int fileOffset);
 
   /// Infers the return type for the function.
@@ -112,7 +112,7 @@
   ///
   /// If the function is a generator function this is based on the explicit
   /// yield statements registered in [handleYield].
-  DartType inferReturnType(TypeInferrerImpl inferrer,
+  DartType inferReturnType(InferenceVisitorBase inferrer,
       {required bool hasImplicitReturn});
 }
 
@@ -160,7 +160,7 @@
     }
   }
 
-  void _checkValidReturn(TypeInferrerImpl inferrer, DartType returnType,
+  void _checkValidReturn(InferenceVisitorBase inferrer, DartType returnType,
       ReturnStatement statement, DartType expressionType) {
     assert(!inferrer.isTopLevel);
     if (inferrer.isNonNullableByDefault) {
@@ -289,7 +289,7 @@
   /// Updates the inferred return type based on the presence of a return
   /// statement returning the given [type].
   @override
-  void handleReturn(TypeInferrerImpl inferrer, ReturnStatement statement,
+  void handleReturn(InferenceVisitorBase inferrer, ReturnStatement statement,
       DartType type, bool isArrow) {
     // The first return we see tells us if we have an arrow function.
     if (this._isArrow == null) {
@@ -309,13 +309,13 @@
   }
 
   @override
-  void handleYield(TypeInferrerImpl inferrer, YieldStatement node,
+  void handleYield(InferenceVisitorBase inferrer, YieldStatement node,
       ExpressionInferenceResult expressionResult) {
     node.expression = expressionResult.expression..parent = node;
   }
 
   @override
-  DartType inferReturnType(TypeInferrerImpl inferrer,
+  DartType inferReturnType(InferenceVisitorBase inferrer,
       {required bool hasImplicitReturn}) {
     assert(_needToInferReturnType);
     // ignore: unnecessary_null_comparison
@@ -423,7 +423,7 @@
 
   @override
   StatementInferenceResult handleImplicitReturn(
-      TypeInferrerImpl inferrer,
+      InferenceVisitorBase inferrer,
       Statement body,
       StatementInferenceResult inferenceResult,
       int fileOffset) {
@@ -513,7 +513,7 @@
     }
   }
 
-  void _checkValidReturn(TypeInferrerImpl inferrer, DartType returnType,
+  void _checkValidReturn(InferenceVisitorBase inferrer, DartType returnType,
       ReturnStatement statement, DartType expressionType) {
     assert(!inferrer.isTopLevel);
     if (inferrer.isNonNullableByDefault) {
@@ -674,7 +674,7 @@
   /// Updates the inferred return type based on the presence of a return
   /// statement returning the given [type].
   @override
-  void handleReturn(TypeInferrerImpl inferrer, ReturnStatement statement,
+  void handleReturn(InferenceVisitorBase inferrer, ReturnStatement statement,
       DartType type, bool isArrow) {
     // The first return we see tells us if we have an arrow function.
     if (this._isArrow == null) {
@@ -694,12 +694,12 @@
   }
 
   @override
-  void handleYield(TypeInferrerImpl inferrer, YieldStatement node,
+  void handleYield(InferenceVisitorBase inferrer, YieldStatement node,
       ExpressionInferenceResult expressionResult) {
     node.expression = expressionResult.expression..parent = node;
   }
 
-  DartType computeAssignableType(TypeInferrerImpl inferrer,
+  DartType computeAssignableType(InferenceVisitorBase inferrer,
       DartType contextType, DartType expressionType) {
     contextType = inferrer.computeGreatestClosure(contextType);
 
@@ -722,7 +722,7 @@
   }
 
   @override
-  DartType inferReturnType(TypeInferrerImpl inferrer,
+  DartType inferReturnType(InferenceVisitorBase inferrer,
       {required bool hasImplicitReturn}) {
     assert(_needToInferReturnType);
     // ignore: unnecessary_null_comparison
@@ -835,7 +835,7 @@
 
   @override
   StatementInferenceResult handleImplicitReturn(
-      TypeInferrerImpl inferrer,
+      InferenceVisitorBase inferrer,
       Statement body,
       StatementInferenceResult inferenceResult,
       int fileOffset) {
@@ -922,11 +922,11 @@
   /// Updates the inferred return type based on the presence of a return
   /// statement returning the given [type].
   @override
-  void handleReturn(TypeInferrerImpl inferrer, ReturnStatement statement,
+  void handleReturn(InferenceVisitorBase inferrer, ReturnStatement statement,
       DartType type, bool isArrow) {}
 
   @override
-  void handleYield(TypeInferrerImpl inferrer, YieldStatement node,
+  void handleYield(InferenceVisitorBase inferrer, YieldStatement node,
       ExpressionInferenceResult expressionResult) {
     DartType expectedType = node.isYieldStar
         ? inferrer.wrapType(
@@ -955,7 +955,7 @@
   }
 
   @override
-  DartType inferReturnType(TypeInferrerImpl inferrer,
+  DartType inferReturnType(InferenceVisitorBase inferrer,
       {required bool hasImplicitReturn}) {
     assert(_needToInferReturnType);
     // ignore: unnecessary_null_comparison
@@ -1002,7 +1002,7 @@
 
   @override
   StatementInferenceResult handleImplicitReturn(
-      TypeInferrerImpl inferrer,
+      InferenceVisitorBase inferrer,
       Statement body,
       StatementInferenceResult inferenceResult,
       int fileOffset) {
@@ -1056,11 +1056,11 @@
   /// Updates the inferred return type based on the presence of a return
   /// statement returning the given [type].
   @override
-  void handleReturn(TypeInferrerImpl inferrer, ReturnStatement statement,
+  void handleReturn(InferenceVisitorBase inferrer, ReturnStatement statement,
       DartType type, bool isArrow) {}
 
   @override
-  void handleYield(TypeInferrerImpl inferrer, YieldStatement node,
+  void handleYield(InferenceVisitorBase inferrer, YieldStatement node,
       ExpressionInferenceResult expressionResult) {
     DartType expectedType = node.isYieldStar
         ? inferrer.wrapType(_yieldElementContext,
@@ -1088,7 +1088,7 @@
   }
 
   @override
-  DartType inferReturnType(TypeInferrerImpl inferrer,
+  DartType inferReturnType(InferenceVisitorBase inferrer,
       {required bool hasImplicitReturn}) {
     assert(_needToInferReturnType);
     // ignore: unnecessary_null_comparison
@@ -1134,7 +1134,7 @@
 
   @override
   StatementInferenceResult handleImplicitReturn(
-      TypeInferrerImpl inferrer,
+      InferenceVisitorBase inferrer,
       Statement body,
       StatementInferenceResult inferenceResult,
       int fileOffset) {
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index 293bd91..7a5c30e 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -173,8 +173,6 @@
 
   AssignedVariables<TreeNode, VariableDeclaration> get assignedVariables;
 
-  InferenceHelper get helper;
-
   /// Indicates whether the construct we are currently performing inference for
   /// is outside of a method body, and hence top level type inference rules
   /// should apply.
@@ -182,17 +180,13 @@
 
   /// Performs top level type inference on the given field initializer and
   /// returns the computed field type.
-  DartType inferImplicitFieldType(Expression initializer);
+  DartType inferImplicitFieldType(
+      InferenceHelper helper, Expression initializer);
 
   /// Performs full type inference on the given field initializer.
   ExpressionInferenceResult inferFieldInitializer(
       InferenceHelper helper, DartType declaredType, Expression initializer);
 
-  /// Returns the type used as the inferred type of a variable declaration,
-  /// based on the static type of the initializer expression, given by
-  /// [initializerType].
-  DartType inferDeclarationType(DartType initializerType);
-
   /// Performs type inference on the given function body.
   InferredFunctionBody inferFunctionBody(InferenceHelper helper, int fileOffset,
       DartType returnType, AsyncMarker asyncMarker, Statement body);
@@ -213,11 +207,6 @@
       DartType declaredType,
       bool hasDeclaredInitializer);
 
-  /// Ensures that all parameter types of [constructor] have been inferred.
-  // TODO(johnniwinther): We are still parameters on synthesized mixin
-  //  application constructors.
-  void inferConstructorParameterTypes(Constructor constructor);
-
   /// Infers the type arguments a redirecting factory target reference.
   List<DartType>? inferRedirectingFactoryTypeArguments(
       InferenceHelper helper,
@@ -245,7 +234,7 @@
               new TypeOperationsCfe(engine.typeSchemaEnvironment),
               assignedVariables,
               respectImplicitlyTypedVarInitializers:
-                  libraryFeatures.constructorTearoffs.isEnabled)
+                  libraryBuilder.libraryFeatures.constructorTearoffs.isEnabled)
           : new FlowAnalysis.legacy(
               new TypeOperationsCfe(engine.typeSchemaEnvironment),
               assignedVariables);
@@ -273,12 +262,10 @@
   @override
   final SourceLibraryBuilder libraryBuilder;
 
-  InferenceHelper? _helper;
-
   TypeInferrerImpl(
       this.engine,
       this.uriForInstrumentation,
-      bool topLevel,
+      this.isTopLevel,
       this.thisType,
       this.libraryBuilder,
       this.assignedVariables,
@@ -288,31 +275,200 @@
         unknownFunction = new FunctionType(
             const [], const DynamicType(), libraryBuilder.nonNullable),
         classHierarchy = engine.classHierarchy,
-        instrumentation = topLevel ? null : engine.instrumentation,
-        typeSchemaEnvironment = engine.typeSchemaEnvironment,
-        isTopLevel = topLevel {}
+        instrumentation = isTopLevel ? null : engine.instrumentation,
+        typeSchemaEnvironment = engine.typeSchemaEnvironment {}
 
-  @override
-  InferenceHelper get helper => _helper!;
-
-  void set helper(InferenceHelper helper) {
-    if (isTopLevel) {
-      throw new StateError("Attempting to assign TypeInferrerImpl.helper "
-          "during top-level inference.");
-    }
-    _helper = helper;
-  }
-
-  InferenceVisitor _createInferenceVisitor() {
+  InferenceVisitor _createInferenceVisitor(InferenceVisitorBase inferrer) {
     // For full (non-top level) inference, we need access to the
     // ExpressionGeneratorHelper so that we can perform error recovery.
-    assert(isTopLevel || _helper != null,
+    assert(isTopLevel || inferrer._helper != null,
         "Helper hasn't been set up for full inference.");
-    return new InferenceVisitor(this);
+    return new InferenceVisitor(inferrer);
   }
 
+  @override
+  DartType inferImplicitFieldType(
+      InferenceHelper helper, Expression initializer) {
+    InferenceVisitorBase inferrer = new InferenceVisitorBase(this, helper);
+    InferenceVisitor visitor = _createInferenceVisitor(inferrer);
+    ExpressionInferenceResult result = visitor.inferExpression(
+        initializer, const UnknownType(), true,
+        isVoidAllowed: true);
+    return inferrer.inferDeclarationType(result.inferredType);
+  }
+
+  @override
+  ExpressionInferenceResult inferFieldInitializer(
+      InferenceHelper helper, DartType declaredType, Expression initializer) {
+    assert(!isTopLevel);
+    InferenceVisitorBase inferrer = new InferenceVisitorBase(this, helper);
+    InferenceVisitor visitor = _createInferenceVisitor(inferrer);
+    ExpressionInferenceResult initializerResult = visitor
+        .inferExpression(initializer, declaredType, true, isVoidAllowed: true);
+    initializerResult = inferrer.ensureAssignableResult(
+        declaredType, initializerResult,
+        isVoidAllowed: declaredType is VoidType);
+    return initializerResult;
+  }
+
+  @override
+  InferredFunctionBody inferFunctionBody(InferenceHelper helper, int fileOffset,
+      DartType returnType, AsyncMarker asyncMarker, Statement body) {
+    // ignore: unnecessary_null_comparison
+    assert(body != null);
+    InferenceVisitorBase inferrer = new InferenceVisitorBase(this, helper);
+    ClosureContext closureContext =
+        new ClosureContext(inferrer, asyncMarker, returnType, false);
+    InferenceVisitor visitor = _createInferenceVisitor(inferrer);
+    StatementInferenceResult result =
+        visitor.inferStatement(body, closureContext);
+    if (dataForTesting != null) {
+      if (!flowAnalysis.isReachable) {
+        dataForTesting!.flowAnalysisResult.functionBodiesThatDontComplete
+            .add(body);
+      }
+    }
+    result =
+        closureContext.handleImplicitReturn(inferrer, body, result, fileOffset);
+    DartType? futureValueType = closureContext.futureValueType;
+    assert(!(asyncMarker == AsyncMarker.Async && futureValueType == null),
+        "No future value type computed.");
+    flowAnalysis.finish();
+    return new InferredFunctionBody(
+        result.hasChanged ? result.statement : body, futureValueType);
+  }
+
+  @override
+  List<DartType>? inferRedirectingFactoryTypeArguments(
+      InferenceHelper helper,
+      DartType typeContext,
+      FunctionNode redirectingFactoryFunction,
+      int fileOffset,
+      Member target,
+      FunctionType targetType) {
+    InferenceVisitorBase inferrer = new InferenceVisitorBase(this, helper);
+    InferenceVisitor visitor = _createInferenceVisitor(inferrer);
+    List<Expression> positionalArguments = <Expression>[];
+    for (VariableDeclaration parameter
+        in redirectingFactoryFunction.positionalParameters) {
+      flowAnalysis.declare(parameter, true);
+      positionalArguments
+          .add(new VariableGetImpl(parameter, forNullGuardedAccess: false));
+    }
+    List<NamedExpression> namedArguments = <NamedExpression>[];
+    for (VariableDeclaration parameter
+        in redirectingFactoryFunction.namedParameters) {
+      flowAnalysis.declare(parameter, true);
+      namedArguments.add(new NamedExpression(parameter.name!,
+          new VariableGetImpl(parameter, forNullGuardedAccess: false)));
+    }
+    // If arguments are created using [Forest.createArguments], and the
+    // type arguments are omitted, they are to be inferred.
+    ArgumentsImpl targetInvocationArguments = engine.forest.createArguments(
+        fileOffset, positionalArguments,
+        named: namedArguments);
+
+    InvocationInferenceResult result = inferrer.inferInvocation(
+        visitor, typeContext, fileOffset, targetType, targetInvocationArguments,
+        staticTarget: target);
+    DartType resultType = result.inferredType;
+    if (resultType is InterfaceType) {
+      return resultType.typeArguments;
+    } else {
+      return null;
+    }
+  }
+
+  @override
+  InitializerInferenceResult inferInitializer(
+      InferenceHelper helper, Initializer initializer) {
+    // Use polymorphic dispatch on [KernelInitializer] to perform whatever
+    // kind of type inference is correct for this kind of initializer.
+    // TODO(paulberry): experiment to see if dynamic dispatch would be better,
+    // so that the type hierarchy will be simpler (which may speed up "is"
+    // checks).
+    InferenceVisitorBase inferrer = new InferenceVisitorBase(this, helper);
+    InferenceVisitor visitor = _createInferenceVisitor(inferrer);
+    InitializerInferenceResult inferenceResult;
+    if (initializer is InitializerJudgment) {
+      inferenceResult = initializer.acceptInference(visitor);
+    } else {
+      inferenceResult = initializer.accept(visitor);
+    }
+    return inferenceResult;
+  }
+
+  @override
+  void inferMetadata(
+      InferenceHelper helper, TreeNode? parent, List<Expression>? annotations) {
+    if (annotations != null) {
+      // We bypass the check for assignment of the helper during top-level
+      // inference and use `_helper = helper` instead of `this.helper = helper`
+      // because inference on metadata requires the helper.
+      InferenceVisitorBase inferrer = new InferenceVisitorBase(this, helper);
+      InferenceVisitor visitor = _createInferenceVisitor(inferrer);
+      inferrer.inferMetadataKeepingHelper(visitor, parent, annotations);
+    }
+  }
+
+  @override
+  Expression inferParameterInitializer(
+      InferenceHelper helper,
+      Expression initializer,
+      DartType declaredType,
+      bool hasDeclaredInitializer) {
+    // ignore: unnecessary_null_comparison
+    assert(declaredType != null);
+    InferenceVisitorBase inferrer = new InferenceVisitorBase(this, helper);
+    InferenceVisitor visitor = _createInferenceVisitor(inferrer);
+    ExpressionInferenceResult result =
+        visitor.inferExpression(initializer, declaredType, true);
+    if (hasDeclaredInitializer) {
+      initializer =
+          inferrer.ensureAssignableResult(declaredType, result).expression;
+    }
+    return initializer;
+  }
+}
+
+class InferenceVisitorBase {
+  final TypeInferrerImpl _inferrer;
+
+  final InferenceHelper? _helper;
+
+  InferenceVisitorBase(this._inferrer, this._helper);
+
+  AssignedVariables<TreeNode, VariableDeclaration> get assignedVariables =>
+      _inferrer.assignedVariables;
+
+  FunctionType get unknownFunction => _inferrer.unknownFunction;
+
+  InterfaceType? get thisType => _inferrer.thisType;
+
+  Uri get uriForInstrumentation => _inferrer.uriForInstrumentation;
+
+  Instrumentation? get instrumentation => _inferrer.instrumentation;
+
+  ClassHierarchy get classHierarchy => _inferrer.classHierarchy;
+
+  InferenceDataForTesting? get dataForTesting => _inferrer.dataForTesting;
+
+  FlowAnalysis<TreeNode, Statement, Expression, VariableDeclaration, DartType>
+      get flowAnalysis => _inferrer.flowAnalysis;
+
+  TypeSchemaEnvironment get typeSchemaEnvironment =>
+      _inferrer.typeSchemaEnvironment;
+
+  TypeInferenceEngine get engine => _inferrer.engine;
+
+  bool get isTopLevel => _inferrer.isTopLevel;
+
+  InferenceHelper get helper => _helper!;
+
   CoreTypes get coreTypes => engine.coreTypes;
 
+  SourceLibraryBuilder get libraryBuilder => _inferrer.libraryBuilder;
+
   bool get isInferenceUpdate1Enabled =>
       libraryBuilder.isInferenceUpdate1Enabled;
 
@@ -456,7 +612,7 @@
     }
   }
 
-  @override
+  /// Ensures that all parameter types of [constructor] have been inferred.
   void inferConstructorParameterTypes(Constructor target) {
     SourceConstructorBuilder? constructor = engine.beingInferred[target];
     if (constructor != null) {
@@ -492,27 +648,6 @@
     }
   }
 
-  @override
-  InitializerInferenceResult inferInitializer(
-      InferenceHelper helper, Initializer initializer) {
-    this.helper = helper;
-
-    // Use polymorphic dispatch on [KernelInitializer] to perform whatever
-    // kind of type inference is correct for this kind of initializer.
-    // TODO(paulberry): experiment to see if dynamic dispatch would be better,
-    // so that the type hierarchy will be simpler (which may speed up "is"
-    // checks).
-    InferenceVisitor visitor = _createInferenceVisitor();
-    InitializerInferenceResult inferenceResult;
-    if (initializer is InitializerJudgment) {
-      inferenceResult = initializer.acceptInference(visitor);
-    } else {
-      inferenceResult = initializer.accept(visitor);
-    }
-    _helper = null;
-    return inferenceResult;
-  }
-
   bool isDoubleContext(DartType typeContext) {
     // A context is a double context if double is assignable to it but int is
     // not.  That is the type context is a double context if it is:
@@ -1979,8 +2114,9 @@
     }
   }
 
-  /// Modifies a type as appropriate when inferring a declared variable's type.
-  @override
+  /// Returns the type used as the inferred type of a variable declaration,
+  /// based on the static type of the initializer expression, given by
+  /// [initializerType].
   DartType inferDeclarationType(DartType initializerType,
       {bool forSyntheticVariable: false}) {
     if (initializerType is NullType) {
@@ -2031,99 +2167,6 @@
     }
   }
 
-  @override
-  DartType inferImplicitFieldType(Expression initializer) {
-    InferenceVisitor visitor = _createInferenceVisitor();
-    ExpressionInferenceResult result = visitor.inferExpression(
-        initializer, const UnknownType(), true,
-        isVoidAllowed: true);
-    return inferDeclarationType(result.inferredType);
-  }
-
-  @override
-  ExpressionInferenceResult inferFieldInitializer(
-      InferenceHelper helper, DartType declaredType, Expression initializer) {
-    assert(!isTopLevel);
-    this.helper = helper;
-    InferenceVisitor visitor = _createInferenceVisitor();
-    ExpressionInferenceResult initializerResult = visitor
-        .inferExpression(initializer, declaredType, true, isVoidAllowed: true);
-    initializerResult = ensureAssignableResult(declaredType, initializerResult,
-        isVoidAllowed: declaredType is VoidType);
-    _helper = null;
-    return initializerResult;
-  }
-
-  @override
-  InferredFunctionBody inferFunctionBody(InferenceHelper helper, int fileOffset,
-      DartType returnType, AsyncMarker asyncMarker, Statement body) {
-    // ignore: unnecessary_null_comparison
-    assert(body != null);
-    this.helper = helper;
-    ClosureContext closureContext =
-        new ClosureContext(this, asyncMarker, returnType, false);
-    InferenceVisitor visitor = _createInferenceVisitor();
-    StatementInferenceResult result =
-        visitor.inferStatement(body, closureContext);
-    if (dataForTesting != null) {
-      if (!flowAnalysis.isReachable) {
-        dataForTesting!.flowAnalysisResult.functionBodiesThatDontComplete
-            .add(body);
-      }
-    }
-    result =
-        closureContext.handleImplicitReturn(this, body, result, fileOffset);
-    DartType? futureValueType = closureContext.futureValueType;
-    assert(!(asyncMarker == AsyncMarker.Async && futureValueType == null),
-        "No future value type computed.");
-    _helper = null;
-    flowAnalysis.finish();
-    return new InferredFunctionBody(
-        result.hasChanged ? result.statement : body, futureValueType);
-  }
-
-  @override
-  List<DartType>? inferRedirectingFactoryTypeArguments(
-      InferenceHelper helper,
-      DartType typeContext,
-      FunctionNode redirectingFactoryFunction,
-      int fileOffset,
-      Member target,
-      FunctionType targetType) {
-    this.helper = helper;
-    InferenceVisitor visitor = _createInferenceVisitor();
-    List<Expression> positionalArguments = <Expression>[];
-    for (VariableDeclaration parameter
-        in redirectingFactoryFunction.positionalParameters) {
-      flowAnalysis.declare(parameter, true);
-      positionalArguments
-          .add(new VariableGetImpl(parameter, forNullGuardedAccess: false));
-    }
-    List<NamedExpression> namedArguments = <NamedExpression>[];
-    for (VariableDeclaration parameter
-        in redirectingFactoryFunction.namedParameters) {
-      flowAnalysis.declare(parameter, true);
-      namedArguments.add(new NamedExpression(parameter.name!,
-          new VariableGetImpl(parameter, forNullGuardedAccess: false)));
-    }
-    // If arguments are created using [Forest.createArguments], and the
-    // type arguments are omitted, they are to be inferred.
-    ArgumentsImpl targetInvocationArguments = engine.forest.createArguments(
-        fileOffset, positionalArguments,
-        named: namedArguments);
-
-    InvocationInferenceResult result = inferInvocation(
-        visitor, typeContext, fileOffset, targetType, targetInvocationArguments,
-        staticTarget: target);
-    DartType resultType = result.inferredType;
-    _helper = null;
-    if (resultType is InterfaceType) {
-      return resultType.typeArguments;
-    } else {
-      return null;
-    }
-  }
-
   InvocationInferenceResult inferInvocation(
       InferenceVisitor visitor,
       DartType typeContext,
@@ -2942,20 +2985,6 @@
     return function.computeFunctionType(libraryBuilder.nonNullable);
   }
 
-  @override
-  void inferMetadata(
-      InferenceHelper helper, TreeNode? parent, List<Expression>? annotations) {
-    if (annotations != null) {
-      // We bypass the check for assignment of the helper during top-level
-      // inference and use `_helper = helper` instead of `this.helper = helper`
-      // because inference on metadata requires the helper.
-      _helper = helper;
-      InferenceVisitor visitor = _createInferenceVisitor();
-      inferMetadataKeepingHelper(visitor, parent, annotations);
-      _helper = null;
-    }
-  }
-
   void inferMetadataKeepingHelper(InferenceVisitor visitor, TreeNode? parent,
       List<Expression>? annotations) {
     if (annotations != null) {
@@ -4023,7 +4052,6 @@
           actualReceiverType,
           typeSchemaEnvironment,
           classHierarchy,
-          this,
           actualMethodName,
           interfaceTarget,
           arguments,
@@ -4041,7 +4069,7 @@
     if (!isTopLevel) {
       // We only perform checks in full inference.
       libraryBuilder.checkBoundsInInstantiation(typeSchemaEnvironment,
-          classHierarchy, this, functionType, arguments, helper.uri, fileOffset,
+          classHierarchy, functionType, arguments, helper.uri, fileOffset,
           inferred: inferred);
     }
   }
@@ -4054,7 +4082,6 @@
       libraryBuilder.checkBoundsInFunctionInvocation(
           typeSchemaEnvironment,
           classHierarchy,
-          this,
           functionType,
           localName,
           arguments,
@@ -4134,25 +4161,6 @@
         inferredType, result.applyResult(expression));
   }
 
-  @override
-  Expression inferParameterInitializer(
-      InferenceHelper helper,
-      Expression initializer,
-      DartType declaredType,
-      bool hasDeclaredInitializer) {
-    this.helper = helper;
-    // ignore: unnecessary_null_comparison
-    assert(declaredType != null);
-    InferenceVisitor visitor = _createInferenceVisitor();
-    ExpressionInferenceResult result =
-        visitor.inferExpression(initializer, declaredType, true);
-    if (hasDeclaredInitializer) {
-      initializer = ensureAssignableResult(declaredType, result).expression;
-    }
-    _helper = null;
-    return initializer;
-  }
-
   /// Performs the core type inference algorithm for super property get.
   ExpressionInferenceResult inferSuperPropertyGet(
       Expression expression, Name name, DartType typeContext, Member? member) {
@@ -4872,25 +4880,10 @@
   Uri get uriForInstrumentation => impl.uriForInstrumentation;
 
   @override
-  void inferConstructorParameterTypes(Constructor constructor) {
-    benchmarker
-        .beginSubdivide(BenchmarkSubdivides.inferConstructorParameterTypes);
-    impl.inferConstructorParameterTypes(constructor);
-    benchmarker.endSubdivide();
-  }
-
-  @override
-  DartType inferDeclarationType(DartType initializerType) {
-    benchmarker.beginSubdivide(BenchmarkSubdivides.inferDeclarationType);
-    DartType result = impl.inferDeclarationType(initializerType);
-    benchmarker.endSubdivide();
-    return result;
-  }
-
-  @override
-  DartType inferImplicitFieldType(Expression initializer) {
+  DartType inferImplicitFieldType(
+      InferenceHelper helper, Expression initializer) {
     benchmarker.beginSubdivide(BenchmarkSubdivides.inferImplicitFieldType);
-    DartType result = impl.inferImplicitFieldType(initializer);
+    DartType result = impl.inferImplicitFieldType(helper, initializer);
     benchmarker.endSubdivide();
     return result;
   }
@@ -4966,9 +4959,6 @@
     benchmarker.endSubdivide();
     return result;
   }
-
-  @override
-  InferenceHelper get helper => impl.helper;
 }
 
 abstract class MixinInferrer {
@@ -5186,7 +5176,7 @@
 /// Tells the inferred type and how the code should be transformed.
 ///
 /// It is intended for use by generalized inference methods, such as
-/// [TypeInferrerImpl.inferInvocation], where the input [Expression] isn't
+/// [InferenceVisitorBase.inferInvocation], where the input [Expression] isn't
 /// available for rewriting.  So, instead of transforming the code, the result
 /// of the inference provides a way to transform the code at the point of
 /// invocation.
@@ -5449,7 +5439,7 @@
   /// The file offset used for the null-test.
   int _nullAwareFileOffset;
 
-  final TypeInferrerImpl _inferrer;
+  final InferenceVisitorBase _inferrer;
 
   NullAwareGuard(
       this._nullAwareVariable, this._nullAwareFileOffset, this._inferrer)
@@ -5905,7 +5895,7 @@
     implements
         NonPromotionReasonVisitor<LocatedMessage?, Node, VariableDeclaration,
             DartType> {
-  final TypeInferrerImpl inferrer;
+  final InferenceVisitorBase inferrer;
 
   Member? propertyReference;
 
diff --git a/pkg/test_runner/lib/src/compiler_configuration.dart b/pkg/test_runner/lib/src/compiler_configuration.dart
index 0cb0774..e222ac8 100644
--- a/pkg/test_runner/lib/src/compiler_configuration.dart
+++ b/pkg/test_runner/lib/src/compiler_configuration.dart
@@ -602,6 +602,7 @@
       ..._experimentsArgument(_configuration, testFile),
       ...testFile.ddcOptions,
       if (_configuration.nnbdMode == NnbdMode.strong) '--sound-null-safety',
+      if (_configuration.configuration.builderTag == 'canary') '--canary',
       // The file being compiled is the last argument.
       args.last
     ];
diff --git a/pkg/vm_service/test/coverage_async_test.dart b/pkg/vm_service/test/coverage_async_test.dart
new file mode 100644
index 0000000..9d4669f
--- /dev/null
+++ b/pkg/vm_service/test/coverage_async_test.dart
@@ -0,0 +1,123 @@
+// 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:developer';
+
+import 'package:test/test.dart';
+import 'package:vm_service/vm_service.dart';
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+Future<int> asyncFunction() async {
+  await Future.delayed(const Duration(milliseconds: 1));
+  return 123;
+}
+
+Stream<int> asyncGenerator() async* {
+  await Future.delayed(const Duration(milliseconds: 1));
+  yield 456;
+}
+
+Iterable<int> syncGenerator() sync* {
+  yield 789;
+}
+
+Future<void> wrapperFunction() async {
+  print(await asyncFunction());
+  await for (final value in asyncGenerator()) {
+    print(value);
+  }
+  for (final value in syncGenerator()) {
+    print(value);
+  }
+}
+
+Future<void> testFunction() async {
+  debugger();
+  await wrapperFunction();
+  debugger();
+}
+
+bool allRangesCompiled(coverage) {
+  for (int i = 0; i < coverage['ranges'].length; i++) {
+    if (!coverage['ranges'][i]['compiled']) {
+      return false;
+    }
+  }
+  return true;
+}
+
+IsolateTest coverageTest(Map<String, dynamic> expectedRange) {
+  return (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final isolate = await service.getIsolate(isolateId);
+    final stack = await service.getStack(isolateId);
+
+    // Make sure we are in the right place.
+    expect(stack.frames!.length, greaterThanOrEqualTo(1));
+    expect(stack.frames![0].function!.name, 'testFunction');
+
+    final root =
+        await service.getObject(isolateId, isolate.rootLib!.id!) as Library;
+    FuncRef funcRef =
+        root.functions!.singleWhere((f) => f.name == 'wrapperFunction');
+    Func func = await service.getObject(isolateId, funcRef.id!) as Func;
+    final location = func.location!;
+
+    final report = await service.getSourceReport(
+      isolateId,
+      [SourceReportKind.kCoverage],
+      scriptId: location.script!.id,
+      tokenPos: location.tokenPos,
+      endTokenPos: location.endTokenPos,
+      forceCompile: true,
+      reportLines: true,
+    );
+    expect(report.ranges!.length, 1);
+    expect(report.ranges![0].toJson(), expectedRange);
+    expect(report.scripts!.length, 1);
+    expect(
+      report.scripts![0].uri,
+      endsWith('coverage_async_test.dart'),
+    );
+  };
+}
+
+var tests = <IsolateTest>[
+  hasStoppedAtBreakpoint,
+  coverageTest(
+    {
+      'scriptIndex': 0,
+      'startPos': 674,
+      'endPos': 878,
+      'compiled': true,
+      'coverage': {
+        'hits': [],
+        'misses': [27, 28, 28, 29, 29, 29, 30, 32, 32, 33]
+      }
+    },
+  ),
+  resumeIsolate,
+  hasStoppedAtBreakpoint,
+  coverageTest(
+    {
+      'scriptIndex': 0,
+      'startPos': 674,
+      'endPos': 878,
+      'compiled': true,
+      'coverage': {
+        'hits': [27, 28, 28, 29, 29, 29, 30, 32, 32, 33],
+        'misses': []
+      }
+    },
+  ),
+];
+
+main([args = const <String>[]]) => runIsolateTests(
+      args,
+      tests,
+      'coverage_async_test.dart',
+      testeeConcurrent: testFunction,
+    );
diff --git a/pkg/vm_service/test/get_stack_test.dart b/pkg/vm_service/test/get_stack_test.dart
index d1b42d3..138876b 100644
--- a/pkg/vm_service/test/get_stack_test.dart
+++ b/pkg/vm_service/test/get_stack_test.dart
@@ -95,7 +95,7 @@
   (VmService service, IsolateRef isolateRef) async {
     final result = await service.getStack(isolateRef.id!);
 
-    expect(result.frames, hasLength(6));
+    expect(result.frames, hasLength(10));
     expect(result.asyncCausalFrames, hasLength(26));
     expect(result.awaiterFrames, hasLength(13));
 
@@ -105,6 +105,10 @@
       [equals('Regular'), anything], // Internal mech. ..
       [equals('Regular'), anything],
       [equals('Regular'), anything],
+      [equals('Regular'), anything],
+      [equals('Regular'), anything],
+      [equals('Regular'), anything],
+      [equals('Regular'), anything],
       [equals('Regular'), endsWith(' _RawReceivePortImpl._handleMessage')],
     ]);
 
diff --git a/runtime/observatory/tests/service/get_stack_limit_rpc_test.dart b/runtime/observatory/tests/service/get_stack_limit_rpc_test.dart
index f8decf0..35a6493 100644
--- a/runtime/observatory/tests/service/get_stack_limit_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_stack_limit_rpc_test.dart
@@ -51,7 +51,7 @@
     var frames = stack['frames'];
     var asyncFrames = stack['asyncCausalFrames'];
     var awaiterFrames = stack['awaiterFrames'];
-    expect(frames.length, greaterThanOrEqualTo(12));
+    expect(frames.length, greaterThanOrEqualTo(20));
     expect(asyncFrames.length, greaterThan(frames.length));
     expect(awaiterFrames.length, greaterThan(frames.length));
     expect(stack['truncated'], false);
diff --git a/runtime/observatory_2/tests/service_2/get_stack_limit_rpc_test.dart b/runtime/observatory_2/tests/service_2/get_stack_limit_rpc_test.dart
index 8570a28..e346afa 100644
--- a/runtime/observatory_2/tests/service_2/get_stack_limit_rpc_test.dart
+++ b/runtime/observatory_2/tests/service_2/get_stack_limit_rpc_test.dart
@@ -51,7 +51,7 @@
     var frames = stack['frames'];
     var asyncFrames = stack['asyncCausalFrames'];
     var awaiterFrames = stack['awaiterFrames'];
-    expect(frames.length, greaterThanOrEqualTo(12));
+    expect(frames.length, greaterThanOrEqualTo(20));
     expect(asyncFrames.length, greaterThan(frames.length));
     expect(awaiterFrames.length, greaterThan(frames.length));
     expect(stack['truncated'], false);
diff --git a/runtime/vm/heap/pages.cc b/runtime/vm/heap/pages.cc
index dbd960a..eb2bbd8 100644
--- a/runtime/vm/heap/pages.cc
+++ b/runtime/vm/heap/pages.cc
@@ -63,6 +63,7 @@
   result->used_in_bytes_ = 0;
   result->forwarding_page_ = NULL;
   result->card_table_ = NULL;
+  result->progress_bar_ = 0;
   result->type_ = type;
 
   LSAN_REGISTER_ROOT_REGION(result, sizeof(*result));
@@ -128,8 +129,6 @@
     return;
   }
 
-  bool table_is_empty = false;
-
   ArrayPtr obj =
       static_cast<ArrayPtr>(UntaggedObject::FromAddr(object_start()));
   ASSERT(obj->IsArray());
@@ -140,7 +139,10 @@
   uword heap_base = obj.heap_base();
 
   const intptr_t size = card_table_size();
-  for (intptr_t i = 0; i < size; i++) {
+  for (;;) {
+    intptr_t i = progress_bar_.fetch_add(1);
+    if (i >= size) break;
+
     if (card_table_[i] != 0) {
       CompressedObjectPtr* card_from =
           reinterpret_cast<CompressedObjectPtr*>(this) +
@@ -170,19 +172,15 @@
         }
       }
 
-      if (has_new_target) {
-        // Card remains remembered.
-        table_is_empty = false;
-      } else {
+      if (!has_new_target) {
         card_table_[i] = 0;
       }
     }
   }
+}
 
-  if (table_is_empty) {
-    free(card_table_);
-    card_table_ = NULL;
-  }
+void OldPage::ResetProgressBar() {
+  progress_bar_ = 0;
 }
 
 ObjectPtr OldPage::FindObject(FindObjectVisitor* visitor) const {
@@ -833,6 +831,12 @@
   }
 }
 
+void PageSpace::ResetProgressBars() const {
+  for (OldPage* page = large_pages_; page != NULL; page = page->next()) {
+    page->ResetProgressBar();
+  }
+}
+
 ObjectPtr PageSpace::FindObject(FindObjectVisitor* visitor,
                                 OldPage::PageType type) const {
   if (type == OldPage::kExecutable) {
@@ -1474,6 +1478,7 @@
   page->used_in_bytes_ = page->object_end_ - page->object_start();
   page->forwarding_page_ = NULL;
   page->card_table_ = NULL;
+  page->progress_bar_ = 0;
   if (is_executable) {
     page->type_ = OldPage::kExecutable;
   } else {
diff --git a/runtime/vm/heap/pages.h b/runtime/vm/heap/pages.h
index 50f334f..aff20f3 100644
--- a/runtime/vm/heap/pages.h
+++ b/runtime/vm/heap/pages.h
@@ -183,6 +183,7 @@
   }
 #endif
   void VisitRememberedCards(ObjectPointerVisitor* visitor);
+  void ResetProgressBar();
 
  private:
   void set_object_end(uword value) {
@@ -205,6 +206,7 @@
   uword used_in_bytes_;
   ForwardingPage* forwarding_page_;
   uint8_t* card_table_;  // Remembered set, not marking.
+  RelaxedAtomic<intptr_t> progress_bar_;
   PageType type_;
 
   friend class PageSpace;
@@ -403,6 +405,7 @@
   void VisitObjectPointers(ObjectPointerVisitor* visitor) const;
 
   void VisitRememberedCards(ObjectPointerVisitor* visitor) const;
+  void ResetProgressBars() const;
 
   ObjectPtr FindObject(FindObjectVisitor* visitor,
                        OldPage::PageType type) const;
diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc
index 9425afd..17155e2 100644
--- a/runtime/vm/heap/scavenger.cc
+++ b/runtime/vm/heap/scavenger.cc
@@ -247,7 +247,7 @@
     thread_ = Thread::Current();
     page_space_->AcquireLock(freelist_);
 
-    LongJumpScope jump;
+    LongJumpScope jump(thread_);
     if (setjmp(*jump.Set()) == 0) {
       scavenger_->IterateRoots(this);
     } else {
@@ -256,7 +256,7 @@
   }
 
   void ProcessSurvivors() {
-    LongJumpScope jump;
+    LongJumpScope jump(thread_);
     if (setjmp(*jump.Set()) == 0) {
       // Iterate until all work has been drained.
       do {
@@ -269,7 +269,7 @@
   }
 
   void ProcessAll() {
-    LongJumpScope jump;
+    LongJumpScope jump(thread_);
     if (setjmp(*jump.Set()) == 0) {
       do {
         do {
@@ -1282,7 +1282,6 @@
 enum RootSlices {
   kIsolate = 0,
   kObjectIdRing,
-  kCards,
   kStoreBuffer,
   kNumRootSlices,
 };
@@ -1292,7 +1291,7 @@
   for (;;) {
     intptr_t slice = root_slices_started_.fetch_add(1);
     if (slice >= kNumRootSlices) {
-      return;  // No more slices.
+      break;  // No more slices.
     }
 
     switch (slice) {
@@ -1302,9 +1301,6 @@
       case kObjectIdRing:
         IterateObjectIdTable(visitor);
         break;
-      case kCards:
-        IterateRememberedCards(visitor);
-        break;
       case kStoreBuffer:
         IterateStoreBuffers(visitor);
         break;
@@ -1312,6 +1308,8 @@
         UNREACHABLE();
     }
   }
+
+  IterateRememberedCards(visitor);
 }
 
 bool Scavenger::IsUnreachable(ObjectPtr* p) {
@@ -1801,6 +1799,7 @@
   ASSERT(promotion_stack_.IsEmpty());
   MournWeakHandles();
   MournWeakTables();
+  heap_->old_space()->ResetProgressBars();
 
   // Restore write-barrier assumptions.
   heap_->isolate_group()->RememberLiveTemporaries();
diff --git a/runtime/vm/source_report.cc b/runtime/vm/source_report.cc
index e9375c8..3cf19b9 100644
--- a/runtime/vm/source_report.cc
+++ b/runtime/vm/source_report.cc
@@ -553,11 +553,10 @@
   }
   ASSERT(!code.IsNull());
 
-  // We skip compiled async functions.  Once an async function has
-  // been compiled, there is another function with the same range which
-  // actually contains the user code.
-  if (!func.IsAsyncFunction() && !func.IsAsyncGenerator() &&
-      !func.IsSyncGenerator()) {
+  // We skip compiled sync generators. Once a sync generator has been compiled,
+  // there is another function with the same range which actually contains the
+  // user code.
+  if (!func.IsSyncGenerator()) {
     JSONObject range(jsarr);
     range.AddProperty("scriptIndex", script_index);
     range.AddProperty("startPos", begin_pos);
diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
index 281ad47..1e4b8f1 100644
--- a/sdk/BUILD.gn
+++ b/sdk/BUILD.gn
@@ -90,11 +90,7 @@
 # Scripts that go under bin/
 _platform_sdk_scripts = [ "dartanalyzer" ]
 
-_full_sdk_scripts = [
-  "dart2js",
-  "dartanalyzer",
-  "dartdevc",
-]
+_full_sdk_scripts = [ "dartanalyzer" ]
 
 # Snapshots that go under bin/snapshots
 _platform_sdk_snapshots = [
diff --git a/sdk/bin/dart2js_sdk b/sdk/bin/dart2js_sdk
deleted file mode 100755
index e7999b4..0000000
--- a/sdk/bin/dart2js_sdk
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/env bash
-# Copyright (c) 2012, 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.
-
-function follow_links() {
-  file="$1"
-  while [ -h "$file" ]; do
-    # On Mac OS, readlink -f doesn't work.
-    file="$(readlink "$file")"
-  done
-  echo "$file"
-}
-
-# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
-PROG_NAME="$(follow_links "$BASH_SOURCE")"
-
-# Handle the case where dart-sdk/bin has been symlinked to.
-BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
-
-SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
-
-DART="$BIN_DIR/dart"
-
-SNAPSHOT_DIR="$BIN_DIR/snapshots"
-SNAPSHOT="$SNAPSHOT_DIR/dart2js.dart.snapshot"
-
-unset EXTRA_OPTIONS
-declare -a EXTRA_OPTIONS
-
-if test -t 1; then
-  # Stdout is a terminal.
-  if test 8 -le `tput colors`; then
-    # Stdout has at least 8 colors, so enable colors.
-    EXTRA_OPTIONS+=('--enable-diagnostic-colors')
-  fi
-fi
-
-unset EXTRA_VM_OPTIONS
-declare -a EXTRA_VM_OPTIONS
-
-if test -f "$SNAPSHOT"; then
-  EXTRA_OPTIONS+=("--libraries-spec=$SDK_DIR/lib/libraries.json")
-fi
-
-case $0 in
-  *_developer)
-    EXTRA_VM_OPTIONS+=('--enable-asserts')
-    ;;
-esac
-
-# We allow extra vm options to be passed in through an environment variable.
-if [[ $DART_VM_OPTIONS ]]; then
-  read -a OPTIONS <<< "$DART_VM_OPTIONS"
-  EXTRA_VM_OPTIONS+=("${OPTIONS[@]}")
-fi
-
-exec "$DART" "${EXTRA_VM_OPTIONS[@]}" "$SNAPSHOT" "${EXTRA_OPTIONS[@]}" "$@"
diff --git a/sdk/bin/dart2js_sdk.bat b/sdk/bin/dart2js_sdk.bat
deleted file mode 100755
index 0a9293c..0000000
--- a/sdk/bin/dart2js_sdk.bat
+++ /dev/null
@@ -1,57 +0,0 @@
-@echo off
-REM Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-REM for details. All rights reserved. Use of this source code is governed by a
-REM BSD-style license that can be found in the LICENSE file.
-
-setlocal
-rem Handle the case where dart-sdk/bin has been symlinked to.
-set DIR_NAME_WITH_SLASH=%~dp0
-set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
-call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
-rem Get rid of surrounding quotes.
-for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
-
-rem Get absolute full name for SDK_DIR.
-for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
-
-rem Remove trailing backslash if there is one
-IF %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
-
-set DART=%BIN_DIR%\dart
-set SNAPSHOT=%BIN_DIR%\snapshots\dart2js.dart.snapshot
-
-set EXTRA_OPTIONS=
-set EXTRA_VM_OPTIONS=
-
-if _%DART2JS_DEVELOPER_MODE%_ == _1_ (
-  set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% --enable-asserts
-)
-
-if exist "%SNAPSHOT%" (
-  set EXTRA_OPTIONS=%EXTRA_OPTIONS% "--libraries-spec=%SDK_DIR%\lib\libraries.json"
-)
-
-rem We allow extra vm options to be passed in through an environment variable.
-if not "_%DART_VM_OPTIONS%_" == "__" (
-  set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% %DART_VM_OPTIONS%
-)
-
-"%DART%" %EXTRA_VM_OPTIONS% "%SNAPSHOT%" %EXTRA_OPTIONS% %*
-
-endlocal
-
-exit /b %errorlevel%
-
-:follow_links
-setlocal
-for %%i in (%1) do set result=%%~fi
-set current=
-for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
-                                             ^| %SystemRoot%\System32\find.exe ">     %~n1 [" 2^>nul`) do (
-  set current=%%i
-)
-if not "%current%"=="" call :follow_links "%current%", result
-endlocal & set %~2=%result%
-goto :eof
-
-:end
diff --git a/sdk/bin/dartdevc_sdk b/sdk/bin/dartdevc_sdk
deleted file mode 100755
index ba71205..0000000
--- a/sdk/bin/dartdevc_sdk
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env bash
-# Copyright (c) 2013, 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.
-
-# Run dev compiler on the Dart VM. This script assumes the Dart SDK's
-# directory structure.
-
-echo "Warning: this 'dartdevc' script is deprecated and will be removed. " 1>&2
-echo "More details at https://github.com/dart-lang/sdk/issues/46100." 1>&2
-
-function follow_links() {
-  file="$1"
-  while [ -h "$file" ]; do
-    # On Mac OS, readlink -f doesn't work.
-    file="$(readlink "$file")"
-  done
-  echo "$file"
-}
-
-# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
-PROG_NAME="$(follow_links "$BASH_SOURCE")"
-
-# Handle the case where dart-sdk/bin has been symlinked to.
-BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
-
-SNAPSHOT="$BIN_DIR/snapshots/dartdevc.dart.snapshot"
-
-# We are running the snapshot in the built SDK.
-DART="$BIN_DIR/dart"
-
-unset EXTRA_VM_OPTIONS
-declare -a EXTRA_VM_OPTIONS
-
-# We allow extra vm options to be passed in through an environment variable.
-if [[ $DART_VM_OPTIONS ]]; then
-  read -a OPTIONS <<< "$DART_VM_OPTIONS"
-  EXTRA_VM_OPTIONS+=("${OPTIONS[@]}")
-fi
-
-exec "$DART" --enable_experiment=non-nullable "${EXTRA_VM_OPTIONS[@]}" "$SNAPSHOT" "$@"
diff --git a/sdk/bin/dartdevc_sdk.bat b/sdk/bin/dartdevc_sdk.bat
deleted file mode 100644
index 931e410..0000000
--- a/sdk/bin/dartdevc_sdk.bat
+++ /dev/null
@@ -1,62 +0,0 @@
-@echo off
-REM Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-REM for details. All rights reserved. Use of this source code is governed by a
-REM BSD-style license that can be found in the LICENSE file.
-
-echo Warning: this 'dartdevc' script is deprecated and will be removed.  1>&2
-echo More details at https://github.com/dart-lang/sdk/issues/46100.      1>&2
-
-setlocal
-rem Handle the case where dart-sdk/bin has been symlinked to.
-set DIR_NAME_WITH_SLASH=%~dp0
-set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
-call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
-rem Get rid of surrounding quotes.
-for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
-
-set DART=%BIN_DIR%\dart
-set SNAPSHOT=%BIN_DIR%\snapshots\dartdevc.dart.snapshot
-
-rem Get absolute full name for SDK_DIR.
-for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
-
-rem Remove trailing backslash if there is one
-if %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
-
-set SDK_ARG=--dart-sdk=%SDK_DIR%
-
-set EXTRA_VM_OPTIONS=
-
-rem We allow extra vm options to be passed in through an environment variable.
-if not "_%DART_VM_OPTIONS%_" == "__" (
-  set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% %DART_VM_OPTIONS%
-)
-
-"%DART%" %EXTRA_VM_OPTIONS% "%SNAPSHOT%" "%SDK_ARG%" %*
-
-endlocal
-
-exit /b %errorlevel%
-
-rem Follow the symbolic links (junctions points) using `dir to determine the
-rem canonical path. Output with a link looks something like this
-rem
-rem 01/03/2013  10:11 PM    <JUNCTION>     abc def
-rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
-rem
-rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
-rem surrounded by right angle bracket and left square bracket. Once we get
-rem the filename, which is name of the link, we recursively follow that.
-:follow_links
-setlocal
-for %%i in (%1) do set result=%%~fi
-set current=
-for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
-                                             ^| %SystemRoot%\System32\find.exe ">     %~n1 ["`) do (
-  set current=%%i
-)
-if not "%current%"=="" call :follow_links "%current%", result
-endlocal & set %~2=%result%
-goto :eof
-
-:end
diff --git a/sdk/lib/_internal/vm/lib/async_patch.dart b/sdk/lib/_internal/vm/lib/async_patch.dart
index 8e1d110..99ebc23 100644
--- a/sdk/lib/_internal/vm/lib/async_patch.dart
+++ b/sdk/lib/_internal/vm/lib/async_patch.dart
@@ -372,69 +372,15 @@
     }
   }
 
-  @pragma("vm:invisible")
-  @pragma("vm:prefer-inline")
-  void _awaitCompletedFuture(_Future future) {
-    assert(future._isComplete);
-    final zone = Zone._current;
-    if (future._hasError) {
-      @pragma("vm:invisible")
-      void run() {
-        final AsyncError asyncError =
-            unsafeCast<AsyncError>(future._resultOrListeners);
-        zone.runBinary(
-            unsafeCast<dynamic Function(Object, StackTrace)>(_errorCallback),
-            asyncError.error,
-            asyncError.stackTrace);
-      }
-
-      zone.scheduleMicrotask(run);
-    } else {
-      @pragma("vm:invisible")
-      void run() {
-        zone.runUnary(unsafeCast<dynamic Function(dynamic)>(_thenCallback),
-            future._resultOrListeners);
-      }
-
-      zone.scheduleMicrotask(run);
-    }
-  }
-
-  @pragma("vm:invisible")
-  @pragma("vm:prefer-inline")
-  void _awaitNotFuture(Object? object) {
-    final zone = Zone._current;
-    @pragma("vm:invisible")
-    void run() {
-      zone.runUnary(
-          unsafeCast<dynamic Function(dynamic)>(_thenCallback), object);
-    }
-
-    zone.scheduleMicrotask(run);
-  }
-
   @pragma("vm:entry-point", "call")
   @pragma("vm:invisible")
   Object? _await(Object? object) {
-    if (_trace) print('_await (object=$object)');
+    if (_trace) print('_awaitAsync (object=$object)');
     if (_thenCallback == null) {
       _createAsyncCallbacks();
     }
-    if (object is _Future) {
-      if (object._isComplete) {
-        _awaitCompletedFuture(object);
-      } else {
-        object._thenAwait<dynamic>(
-            unsafeCast<dynamic Function(dynamic)>(_thenCallback),
-            unsafeCast<dynamic Function(Object, StackTrace)>(_errorCallback));
-      }
-    } else if (object is! Future) {
-      _awaitNotFuture(object);
-    } else {
-      object.then(unsafeCast<dynamic Function(dynamic)>(_thenCallback),
-          onError:
-              unsafeCast<dynamic Function(Object, StackTrace)>(_errorCallback));
-    }
+    _awaitHelper(object, unsafeCast<dynamic Function(dynamic)>(_thenCallback),
+        unsafeCast<dynamic Function(Object, StackTrace)>(_errorCallback));
     return _functionData;
   }
 
diff --git a/sdk/lib/_internal/wasm/lib/js_helper.dart b/sdk/lib/_internal/wasm/lib/js_helper.dart
index 5acce01..3bbe07a 100644
--- a/sdk/lib/_internal/wasm/lib/js_helper.dart
+++ b/sdk/lib/_internal/wasm/lib/js_helper.dart
@@ -18,7 +18,7 @@
 
   WasmAnyRef toAnyRef() => _ref;
   String toString() => jsStringToDartString(_ref);
-  List<Object?> toObjectList() => jsArrayToDartList(_ref);
+  List<Object?> toObjectList() => toDartList(_ref);
   Object toObject() => jsObjectToDartObject(_ref);
 }
 
@@ -34,24 +34,59 @@
   JSValue toJS() => JSValue(jsObjectFromDartObject(this));
 }
 
-Object? toDart(WasmAnyRef? ref) {
-  if (ref == null) {
-    return null;
-  }
-  return jsObjectToDartObject(dartifyRaw(ref)!);
-}
-
 Object jsObjectToDartObject(WasmAnyRef ref) => unsafeCastOpaque<Object>(ref);
 
 WasmAnyRef jsObjectFromDartObject(Object object) =>
     unsafeCastOpaque<WasmAnyRef>(object);
 
+@pragma("wasm:import", "dart2wasm.isJSUndefined")
+external bool isJSUndefined(WasmAnyRef? o);
+
+@pragma("wasm:import", "dart2wasm.isJSBoolean")
+external bool isJSBoolean(WasmAnyRef? o);
+
+@pragma("wasm:import", "dart2wasm.isJSNumber")
+external bool isJSNumber(WasmAnyRef? o);
+
+@pragma("wasm:import", "dart2wasm.isJSBigInt")
+external bool isJSBigInt(WasmAnyRef? o);
+
+@pragma("wasm:import", "dart2wasm.isJSString")
+external bool isJSString(WasmAnyRef? o);
+
+@pragma("wasm:import", "dart2wasm.isJSSymbol")
+external bool isJSSymbol(WasmAnyRef? o);
+
+@pragma("wasm:import", "dart2wasm.isJSFunction")
+external bool isJSFunction(WasmAnyRef? o);
+
+@pragma("wasm:import", "dart2wasm.isJSArray")
+external bool isJSArray(WasmAnyRef? o);
+
+@pragma("wasm:import", "dart2wasm.isJSWrappedDartFunction")
+external bool isJSWrappedDartFunction(WasmAnyRef? o);
+
+@pragma("wasm:import", "dart2wasm.isJSObject")
+external bool isJSObject(WasmAnyRef? o);
+
+@pragma("wasm:import", "dart2wasm.roundtrip")
+external double toDartNumber(WasmAnyRef ref);
+
+@pragma("wasm:import", "dart2wasm.roundtrip")
+external bool toDartBool(WasmAnyRef ref);
+
+@pragma("wasm:import", "dart2wasm.objectLength")
+external double objectLength(WasmAnyRef ref);
+
+@pragma("wasm:import", "dart2wasm.objectReadIndex")
+external WasmAnyRef? objectReadIndex(WasmAnyRef ref, int index);
+
+@pragma("wasm:import", "dart2wasm.unwrapJSWrappedDartFunction")
+external Object? unwrapJSWrappedDartFunction(WasmAnyRef f);
+
 @pragma("wasm:import", "dart2wasm.arrayFromDartList")
 external WasmAnyRef jsArrayFromDartList(List<Object?> list);
 
-@pragma("wasm:import", "dart2wasm.arrayToDartList")
-external List<Object?> jsArrayToDartList(WasmAnyRef list);
-
 @pragma("wasm:import", "dart2wasm.stringFromDartString")
 external WasmAnyRef jsStringFromDartString(String string);
 
@@ -61,9 +96,6 @@
 @pragma("wasm:import", "dart2wasm.eval")
 external void evalRaw(WasmAnyRef code);
 
-@pragma("wasm:import", "dart2wasm.dartify")
-external WasmAnyRef? dartifyRaw(WasmAnyRef? object);
-
 @pragma("wasm:import", "dart2wasm.newObject")
 external WasmAnyRef newObjectRaw();
 
@@ -113,15 +145,52 @@
   }
 }
 
-@pragma("wasm:import", "dart2wasm.wrapDartCallback")
-external WasmAnyRef _wrapDartCallbackRaw(
-    WasmAnyRef callback, WasmAnyRef trampolineName);
+/// TODO(joshualitt): We shouldn't need this, but otherwise we seem to get a
+/// cast error for certain oddball types(I think undefined, but need to dig
+/// deeper).
+@pragma("wasm:export", "\$dartifyRaw")
+Object? dartifyExported(WasmAnyRef? ref) => dartifyRaw(ref);
 
-F _wrapDartCallback<F extends Function>(F f, String trampolineName) {
+Object? dartifyRaw(WasmAnyRef? ref) {
+  if (ref == null) {
+    return null;
+  } else if (isJSUndefined(ref)) {
+    // TODO(joshualitt): Introduce a `JSUndefined` type.
+    return null;
+  } else if (isJSBoolean(ref)) {
+    return toDartBool(ref);
+  } else if (isJSNumber(ref)) {
+    return toDartNumber(ref);
+  } else if (isJSString(ref)) {
+    return jsStringToDartString(ref);
+  } else if (isJSArray(ref)) {
+    return toDartList(ref);
+  } else if (isJSWrappedDartFunction(ref)) {
+    return unwrapJSWrappedDartFunction(ref);
+  } else if (isJSObject(ref) ||
+      // TODO(joshualitt): We may want to create proxy types for some of these
+      // cases.
+      isJSBigInt(ref) ||
+      isJSSymbol(ref) ||
+      isJSFunction(ref)) {
+    return JSValue(ref);
+  } else {
+    return jsObjectToDartObject(ref);
+  }
+}
+
+List<Object?> toDartList(WasmAnyRef ref) => List<Object?>.generate(
+    objectLength(ref).round(), (int n) => dartifyRaw(objectReadIndex(ref, n)));
+
+@pragma("wasm:import", "dart2wasm.wrapDartFunction")
+external WasmAnyRef _wrapDartFunctionRaw(
+    WasmAnyRef dartFunction, WasmAnyRef trampolineName);
+
+F _wrapDartFunction<F extends Function>(F f, String trampolineName) {
   if (functionToJSWrapper.containsKey(f)) {
     return f;
   }
-  JSValue wrappedFunction = JSValue(_wrapDartCallbackRaw(
+  JSValue wrappedFunction = JSValue(_wrapDartFunctionRaw(
       f.toJS().toAnyRef(), trampolineName.toJS().toAnyRef()));
   functionToJSWrapper[f] = wrappedFunction;
   return f;
@@ -134,13 +203,3 @@
 @pragma("wasm:export", "\$listRead")
 WasmAnyRef? _listRead(List<Object?> list, double index) =>
     jsifyRaw(list[index.toInt()]);
-
-@pragma("wasm:export", "\$listAllocate")
-List<Object?> _listAllocate() => [];
-
-@pragma("wasm:export", "\$listAdd")
-void _listAdd(List<Object?> list, WasmAnyRef? item) =>
-    list.add(dartifyRaw(item));
-
-@pragma("wasm:export", "\$boxJSValue")
-JSValue _boxJSValue(WasmAnyRef ref) => JSValue(ref);
diff --git a/sdk/lib/_internal/wasm/lib/js_util_patch.dart b/sdk/lib/_internal/wasm/lib/js_util_patch.dart
index cbce99d..fb56093 100644
--- a/sdk/lib/_internal/wasm/lib/js_util_patch.dart
+++ b/sdk/lib/_internal/wasm/lib/js_util_patch.dart
@@ -22,15 +22,15 @@
 
 @patch
 T getProperty<T>(Object o, String name) =>
-    toDart(getPropertyRaw(jsifyRaw(o)!, name.toJS().toAnyRef())) as T;
+    dartifyRaw(getPropertyRaw(jsifyRaw(o)!, name.toJS().toAnyRef())) as T;
 
 @patch
-T setProperty<T>(Object o, String name, T? value) => toDart(
+T setProperty<T>(Object o, String name, T? value) => dartifyRaw(
     setPropertyRaw(jsifyRaw(o)!, name.toJS().toAnyRef(), jsifyRaw(value))) as T;
 
 @patch
 T callMethod<T>(Object o, String method, List<Object?> args) =>
-    toDart(callMethodVarArgsRaw(
+    dartifyRaw(callMethodVarArgsRaw(
         jsifyRaw(o)!, method.toJS().toAnyRef(), args.toJS().toAnyRef())) as T;
 
 @patch
@@ -38,7 +38,7 @@
 
 @patch
 T callConstructor<T>(Object o, List<Object?> args) =>
-    toDart(callConstructorVarArgsRaw(jsifyRaw(o)!, args.toJS().toAnyRef()))!
+    dartifyRaw(callConstructorVarArgsRaw(jsifyRaw(o)!, args.toJS().toAnyRef()))!
         as T;
 
 @patch
@@ -99,7 +99,7 @@
 @patch
 Object? dartify(Object? object) {
   if (object is JSValue) {
-    return jsObjectToDartObject(dartifyRaw(object.toAnyRef())!);
+    return dartifyRaw(object.toAnyRef())!;
   } else {
     return object;
   }
diff --git a/tests/web/wasm/js_util_test.dart b/tests/web/wasm/js_util_test.dart
index ce10c7b..9bcf43d 100644
--- a/tests/web/wasm/js_util_test.dart
+++ b/tests/web/wasm/js_util_test.dart
@@ -72,12 +72,21 @@
     globalThis.a = null;
     globalThis.b = 'foo';
     globalThis.c = ['a', 'b', 'c'];
+    globalThis.d = 2.5;
+    globalThis.e = true;
+    globalThis.f = function () { return 'hello world'; };
+    globalThis.invoke = function (f) { return f(); }
   ''');
   Object gt = globalThis;
-  Expect.isNull(dartify(getProperty(gt, 'a')));
-  Expect.equals('foo', dartify(getProperty(gt, 'b')));
-  _expectListEquals(
-      ['a', 'b', 'c'], dartify(getProperty(gt, 'c')) as List<Object?>);
+  Expect.isNull(getProperty(gt, 'a'));
+  Expect.equals('foo', getProperty(gt, 'b'));
+  _expectListEquals(['a', 'b', 'c'], getProperty<List<Object?>>(gt, 'c'));
+  Expect.equals(2.5, getProperty(gt, 'd'));
+  Expect.equals(true, getProperty(gt, 'e'));
+
+  // Confirm a function that takes a roundtrip remains a function.
+  Expect.equals('hello world',
+      callMethod(gt, 'invoke', <Object?>[dartify(getProperty(gt, 'f'))]));
 }
 
 void main() {
diff --git a/tools/VERSION b/tools/VERSION
index 3fa685a..10b6efa 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 18
 PATCH 0
-PRERELEASE 189
+PRERELEASE 190
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index d0f40b6..c47ad38 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -916,6 +916,42 @@
         "enable-asserts": true
       }
     },
+    "dartdevc-checked-(linux|mac|win)-(debug|product|release)-(chrome|firefox)-arm64": {
+      "options": {
+        "checked": true,
+        "use-sdk": true
+      }
+    },
+    "dartdevc-strong-linux-release-chrome-arm64": {
+      "options": {
+        "checked": true,
+        "use-sdk": true,
+        "enable-asserts": true
+      }
+    },
+    "dartdevc-weak-linux-release-chrome-arm64": {
+      "options": {
+        "checked": true,
+        "use-sdk": true,
+        "enable-asserts": true
+      }
+    },
+    "dartdevc-canary-strong-(linux|mac|win)-release-(chrome|firefox)-(x64|arm64)": {
+      "options": {
+        "builder-tag": "canary",
+        "checked": true,
+        "use-sdk": true,
+        "enable-asserts": true
+      }
+    },
+    "dartdevc-canary-weak-(linux|mac|win)-release-(chrome|firefox)-(x64|arm64)": {
+      "options": {
+        "builder-tag": "canary",
+        "checked": true,
+        "use-sdk": true,
+        "enable-asserts": true
+      }
+    },
     "cfe-(linux|mac|win)": {
       "options": {
         "compiler": "fasta"
@@ -2360,6 +2396,77 @@
     },
     {
       "builders": [
+        "ddc-canary-linux-release-chrome"
+      ],
+      "meta": {
+        "description": "This configuration is used by the ddc canary builder group."
+      },
+      "steps": [
+        {
+          "name": "build dart",
+          "script": "tools/build.py",
+          "arguments": [
+            "dartdevc_test",
+            "--gn-args=ddc_canary=true"
+          ]
+        },
+        {
+          "name": "ddc nnbd weak tests",
+          "arguments": [
+            "-ndartdevc-canary-weak-linux-release-chrome-x64",
+            "language",
+            "corelib",
+            "lib",
+            "dartdevc",
+            "web"
+          ],
+          "shards": 2,
+          "fileset": "web_platform_nnbd"
+        },
+        {
+          "name": "ddc nnbd weak co19 tests",
+          "arguments": [
+            "-ndartdevc-canary-weak-linux-release-chrome-x64",
+            "co19"
+          ],
+          "shards": 2,
+          "fileset": "web_platform_nnbd"
+        },
+        {
+          "name": "ddc nnbd strong co19 tests",
+          "arguments": [
+            "-ndartdevc-canary-strong-linux-release-chrome-x64",
+            "co19"
+          ],
+          "shards": 3,
+          "fileset": "web_platform_nnbd"
+        },
+        {
+          "name": "ddc weak modular tests",
+          "script": "out/ReleaseX64/dart-sdk/bin/dart",
+          "testRunner": true,
+          "arguments": [
+            "pkg/dev_compiler/test/modular_suite_nnbd.dart",
+            "-ndartdevc-canary-weak-linux-release-chrome-x64",
+            "--verbose",
+            "--use-sdk"
+          ]
+        },
+        {
+          "name": "ddc nnbd strong tests",
+          "arguments": [
+            "-ndartdevc-canary-strong-linux-release-chrome-x64",
+            "language",
+            "corelib",
+            "lib",
+            "dartdevc",
+            "web"
+          ]
+        }
+      ]
+    },
+    {
+      "builders": [
         "ddc-mac-release-chrome"
       ],
       "meta": {