Version 2.17.0-256.0.dev

Merge commit 'b55dc762fa8858d747759bba29900891cb2ecc68' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9280fed..3e7b432 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -233,8 +233,16 @@
   tracker.
 
   `dart --verbose pub [command]` will also cause the log file to be written.
+- `dart pub global activate --source=git` now takes arguments `--git-path` to
+  specify the path of the activated package in the pubspec and `--git-ref` to
+  specify the branch or revision to check out.
 - `dart pub add` can now add multiple packages in one command.
-
+- `dart pub token add` can now add a token for [pub.dev](https://pub.dev).
+- `dart pub uploader` has been removed. To manage uploaders for a package use
+  the `https://pub.dev/<packagename>/admin` web-interface.
+- Pub now supports a separate `pubspec_overrides.yaml` file that can contain
+  `dependency_overrides`. This makes it easier to avoid checking the local
+  overrides into version control.
 #### Linter
 
 Updated the Linter to `1.18.0`, which includes changes that
diff --git a/DEPS b/DEPS
index 3dce774..9d89269 100644
--- a/DEPS
+++ b/DEPS
@@ -141,7 +141,7 @@
   "pool_rev": "7abe634002a1ba8a0928eded086062f1307ccfae",
   "process_rev": "56ece43b53b64c63ae51ec184b76bd5360c28d0b",
   "protobuf_rev": "c1eb6cb51af39ccbaa1a8e19349546586a5c8e31",
-  "pub_rev": "8f5ab7b1aba3b9f66b56246d77e167990339d317",
+  "pub_rev": "a3a102a549388a6dbfecc9252fabb618f9a2f5f7",
   "pub_semver_rev": "ea6c54019948dc03042c595ce9413e17aaf7aa38",
   "root_certificates_rev": "692f6d6488af68e0121317a9c2c9eb393eb0ee50",
   "rust_revision": "b7856f695d65a8ebc846754f97d15814bcb1c244",
diff --git a/benchmarks/AsyncLiveVars/dart/AsyncLiveVars.dart b/benchmarks/AsyncLiveVars/dart/AsyncLiveVars.dart
new file mode 100644
index 0000000..7969da6
--- /dev/null
+++ b/benchmarks/AsyncLiveVars/dart/AsyncLiveVars.dart
@@ -0,0 +1,305 @@
+// 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.
+
+// Micro-benchmark for testing async/await performance in presence of
+// different number of live values across await.
+
+import 'dart:async';
+
+import 'async_benchmark_base.dart' show AsyncBenchmarkBase;
+
+class MockClass {
+  static final String str = "${int.parse('42')}";
+  static final List<int> list =
+      List<int>.filled(int.parse('3'), int.parse('42'));
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  String get1() => str;
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  List<int> get2() => list;
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  void use1(String a0) => a0.length;
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  void use2(String a0, List<int> a1) => a0.length + a1.length;
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  void use4(String a0, List<int> a1, String a2, List<int> a3) =>
+      a0.length + a1.length + a2.length + a3.length;
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  void use8(String a0, List<int> a1, String a2, List<int> a3, String a4,
+          List<int> a5, String a6, List<int> a7) =>
+      a0.length +
+      a1.length +
+      a2.length +
+      a3.length +
+      a4.length +
+      a5.length +
+      a6.length +
+      a7.length;
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  Future<void> asyncMethod() async {}
+}
+
+class MockClass2 {
+  static int val1 = int.parse('42');
+  static int val2 = int.parse('43');
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  int get1() => val1;
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  int get2() => val2;
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  void use1(int a0) => a0;
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  void use2(int a0, int a1) => a0 + a1;
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  void use4(int a0, int a1, int a2, int a3) => a0 + a1 + a2 + a3;
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  Future<void> asyncMethod() async {}
+}
+
+class LiveVarsBench extends AsyncBenchmarkBase {
+  LiveVarsBench(String name) : super(name);
+  @override
+  Future<void> exercise() async {
+    // These micro-benchmarks are too small, so
+    // make a larger number of iterations per measurement.
+    for (var i = 0; i < 10000; i++) {
+      await run();
+    }
+  }
+}
+
+class LiveObj1 extends LiveVarsBench {
+  LiveObj1() : super('AsyncLiveVars.LiveObj1');
+  final field1 = MockClass();
+  @override
+  Future<void> run() async {
+    final obj1 = field1.get1();
+    await field1.asyncMethod();
+    field1.use1(obj1);
+    await field1.asyncMethod();
+    field1.use1(obj1);
+    await field1.asyncMethod();
+    field1.use1(obj1);
+  }
+}
+
+class LiveObj2 extends LiveVarsBench {
+  LiveObj2() : super('AsyncLiveVars.LiveObj2');
+  final field1 = MockClass();
+  @override
+  Future<void> run() async {
+    final obj1 = field1.get1();
+    final obj2 = field1.get2();
+    await field1.asyncMethod();
+    field1.use1(obj1);
+    await field1.asyncMethod();
+    field1.use1(obj1);
+    await field1.asyncMethod();
+    field1.use2(obj1, obj2);
+  }
+}
+
+class LiveObj4 extends LiveVarsBench {
+  LiveObj4() : super('AsyncLiveVars.LiveObj4');
+  final field1 = MockClass();
+  final field2 = MockClass();
+  @override
+  Future<void> run() async {
+    final obj1 = field1.get1();
+    final obj2 = field1.get2();
+    final obj3 = field2.get1();
+    final obj4 = field2.get2();
+    await field1.asyncMethod();
+    field1.use1(obj1);
+    await field1.asyncMethod();
+    field2.use1(obj3);
+    await field2.asyncMethod();
+    field1.use4(obj1, obj2, obj3, obj4);
+  }
+}
+
+class LiveObj8 extends LiveVarsBench {
+  LiveObj8() : super('AsyncLiveVars.LiveObj8');
+  final field1 = MockClass();
+  final field2 = MockClass();
+  final field3 = MockClass();
+  final field4 = MockClass();
+  @override
+  Future<void> run() async {
+    final obj1 = field1.get1();
+    final obj2 = field1.get2();
+    final obj3 = field2.get1();
+    final obj4 = field2.get2();
+    final obj5 = field3.get1();
+    final obj6 = field3.get2();
+    final obj7 = field4.get1();
+    final obj8 = field4.get2();
+    await field1.asyncMethod();
+    field1.use1(obj1);
+    await field2.asyncMethod();
+    field3.use2(obj5, obj6);
+    await field4.asyncMethod();
+    field2.use8(obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8);
+  }
+}
+
+class LiveObj16 extends LiveVarsBench {
+  LiveObj16() : super('AsyncLiveVars.LiveObj16');
+  final field1 = MockClass();
+  final field2 = MockClass();
+  final field3 = MockClass();
+  final field4 = MockClass();
+  final field5 = MockClass();
+  final field6 = MockClass();
+  final field7 = MockClass();
+  final field8 = MockClass();
+  @override
+  Future<void> run() async {
+    final obj1 = field1.get1();
+    final obj2 = field1.get2();
+    final obj3 = field2.get1();
+    final obj4 = field2.get2();
+    final obj5 = field3.get1();
+    final obj6 = field3.get2();
+    final obj7 = field4.get1();
+    final obj8 = field4.get2();
+    final obj9 = field5.get1();
+    final obj10 = field5.get2();
+    final obj11 = field6.get1();
+    final obj12 = field6.get2();
+    final obj13 = field7.get1();
+    final obj14 = field7.get2();
+    final obj15 = field8.get1();
+    final obj16 = field8.get2();
+    await field1.asyncMethod();
+    field1.use1(obj1);
+    await field2.asyncMethod();
+    field5.use2(obj11, obj12);
+    await field4.asyncMethod();
+    field2.use8(obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8);
+    field3.use8(obj9, obj10, obj11, obj12, obj13, obj14, obj15, obj16);
+  }
+}
+
+class LiveInt1 extends LiveVarsBench {
+  LiveInt1() : super('AsyncLiveVars.LiveInt1');
+  final field1 = MockClass2();
+  @override
+  Future<void> run() async {
+    final int1 = field1.get1();
+    await field1.asyncMethod();
+    field1.use1(int1);
+    await field1.asyncMethod();
+    field1.use1(int1);
+    await field1.asyncMethod();
+    field1.use1(int1);
+  }
+}
+
+class LiveInt4 extends LiveVarsBench {
+  LiveInt4() : super('AsyncLiveVars.LiveInt4');
+  final field1 = MockClass2();
+  final field2 = MockClass2();
+  @override
+  Future<void> run() async {
+    final int1 = field1.get1();
+    final int2 = field1.get2();
+    final int3 = field2.get1();
+    final int4 = field2.get2();
+    await field1.asyncMethod();
+    field1.use1(int1);
+    await field1.asyncMethod();
+    field2.use1(int3);
+    await field2.asyncMethod();
+    field1.use4(int1, int2, int3, int4);
+  }
+}
+
+class LiveObj2Int2 extends LiveVarsBench {
+  LiveObj2Int2() : super('AsyncLiveVars.LiveObj2Int2');
+  final field1 = MockClass();
+  final field2 = MockClass2();
+  @override
+  Future<void> run() async {
+    final obj1 = field1.get1();
+    final obj2 = field1.get2();
+    final int1 = field2.get1();
+    final int2 = field2.get2();
+    await field1.asyncMethod();
+    field1.use1(obj1);
+    await field1.asyncMethod();
+    field2.use1(int1);
+    await field2.asyncMethod();
+    field1.use2(obj1, obj2);
+    field2.use2(int1, int2);
+  }
+}
+
+class LiveObj4Int4 extends LiveVarsBench {
+  LiveObj4Int4() : super('AsyncLiveVars.LiveObj4Int4');
+  final field1 = MockClass();
+  final field2 = MockClass();
+  final field3 = MockClass2();
+  final field4 = MockClass2();
+  @override
+  Future<void> run() async {
+    final obj1 = field1.get1();
+    final obj2 = field1.get2();
+    final obj3 = field2.get1();
+    final obj4 = field2.get2();
+    final int1 = field3.get1();
+    final int2 = field3.get2();
+    final int3 = field4.get1();
+    final int4 = field4.get2();
+    await field1.asyncMethod();
+    field1.use1(obj1);
+    await field2.asyncMethod();
+    field3.use2(int2, int4);
+    await field4.asyncMethod();
+    field2.use4(obj1, obj2, obj3, obj4);
+    field4.use4(int1, int2, int3, int4);
+  }
+}
+
+Future<void> main() async {
+  final benchmarks = [
+    LiveObj1(),
+    LiveObj2(),
+    LiveObj4(),
+    LiveObj8(),
+    LiveObj16(),
+    LiveInt1(),
+    LiveInt4(),
+    LiveObj2Int2(),
+    LiveObj4Int4()
+  ];
+  for (final bench in benchmarks) {
+    await bench.report();
+  }
+}
diff --git a/benchmarks/AsyncLiveVars/dart/async_benchmark_base.dart b/benchmarks/AsyncLiveVars/dart/async_benchmark_base.dart
new file mode 100644
index 0000000..9a415b9
--- /dev/null
+++ b/benchmarks/AsyncLiveVars/dart/async_benchmark_base.dart
@@ -0,0 +1,68 @@
+// 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 'package:benchmark_harness/benchmark_harness.dart'
+    show PrintEmitter, ScoreEmitter;
+
+// Similar to BenchmarkBase from package:benchmark_harness.
+class AsyncBenchmarkBase {
+  final String name;
+  final ScoreEmitter emitter;
+
+  // Empty constructor.
+  const AsyncBenchmarkBase(this.name, {this.emitter = const PrintEmitter()});
+
+  // The benchmark code.
+  // This function is not used, if both [warmup] and [exercise] are overwritten.
+  Future<void> run() async {}
+
+  // Runs a short version of the benchmark. By default invokes [run] once.
+  Future<void> warmup() async {
+    await run();
+  }
+
+  // Exercises the benchmark. By default invokes [run] 10 times.
+  Future<void> exercise() async {
+    for (var i = 0; i < 10; i++) {
+      await run();
+    }
+  }
+
+  // Not measured setup code executed prior to the benchmark runs.
+  Future<void> setup() async {}
+
+  // Not measures teardown code executed after the benchark runs.
+  Future<void> teardown() async {}
+
+  // Measures the score for this benchmark by executing it repeatedly until
+  // time minimum has been reached.
+  static Future<double> measureFor(Function f, int minimumMillis) async {
+    final int minimumMicros = minimumMillis * 1000;
+    int iter = 0;
+    final watch = Stopwatch();
+    watch.start();
+    int elapsed = 0;
+    while (elapsed < minimumMicros) {
+      await f();
+      elapsed = watch.elapsedMicroseconds;
+      iter++;
+    }
+    return elapsed / iter;
+  }
+
+  // Measures the score for the benchmark and returns it.
+  Future<double> measure() async {
+    await setup();
+    // Warmup for at least 100ms. Discard result.
+    await measureFor(warmup, 100);
+    // Run the benchmark for at least 2000ms.
+    final result = await measureFor(exercise, 2000);
+    await teardown();
+    return result;
+  }
+
+  Future<void> report() async {
+    emitter.emit(name, await measure());
+  }
+}
diff --git a/benchmarks/AsyncLiveVars/dart2/AsyncLiveVars.dart b/benchmarks/AsyncLiveVars/dart2/AsyncLiveVars.dart
new file mode 100644
index 0000000..9176274
--- /dev/null
+++ b/benchmarks/AsyncLiveVars/dart2/AsyncLiveVars.dart
@@ -0,0 +1,307 @@
+// 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.
+
+// Micro-benchmark for testing async/await performance in presence of
+// different number of live values across await.
+
+// @dart=2.9
+
+import 'dart:async';
+
+import 'async_benchmark_base.dart' show AsyncBenchmarkBase;
+
+class MockClass {
+  static final String str = "${int.parse('42')}";
+  static final List<int> list =
+      List<int>.filled(int.parse('3'), int.parse('42'));
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  String get1() => str;
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  List<int> get2() => list;
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  void use1(String a0) => a0.length;
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  void use2(String a0, List<int> a1) => a0.length + a1.length;
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  void use4(String a0, List<int> a1, String a2, List<int> a3) =>
+      a0.length + a1.length + a2.length + a3.length;
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  void use8(String a0, List<int> a1, String a2, List<int> a3, String a4,
+          List<int> a5, String a6, List<int> a7) =>
+      a0.length +
+      a1.length +
+      a2.length +
+      a3.length +
+      a4.length +
+      a5.length +
+      a6.length +
+      a7.length;
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  Future<void> asyncMethod() async {}
+}
+
+class MockClass2 {
+  static int val1 = int.parse('42');
+  static int val2 = int.parse('43');
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  int get1() => val1;
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  int get2() => val2;
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  void use1(int a0) => a0;
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  void use2(int a0, int a1) => a0 + a1;
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  void use4(int a0, int a1, int a2, int a3) => a0 + a1 + a2 + a3;
+
+  @pragma('vm:never-inline')
+  @pragma('dart2js:noInline')
+  Future<void> asyncMethod() async {}
+}
+
+class LiveVarsBench extends AsyncBenchmarkBase {
+  LiveVarsBench(String name) : super(name);
+  @override
+  Future<void> exercise() async {
+    // These micro-benchmarks are too small, so
+    // make a larger number of iterations per measurement.
+    for (var i = 0; i < 10000; i++) {
+      await run();
+    }
+  }
+}
+
+class LiveObj1 extends LiveVarsBench {
+  LiveObj1() : super('AsyncLiveVars.LiveObj1');
+  final field1 = MockClass();
+  @override
+  Future<void> run() async {
+    final obj1 = field1.get1();
+    await field1.asyncMethod();
+    field1.use1(obj1);
+    await field1.asyncMethod();
+    field1.use1(obj1);
+    await field1.asyncMethod();
+    field1.use1(obj1);
+  }
+}
+
+class LiveObj2 extends LiveVarsBench {
+  LiveObj2() : super('AsyncLiveVars.LiveObj2');
+  final field1 = MockClass();
+  @override
+  Future<void> run() async {
+    final obj1 = field1.get1();
+    final obj2 = field1.get2();
+    await field1.asyncMethod();
+    field1.use1(obj1);
+    await field1.asyncMethod();
+    field1.use1(obj1);
+    await field1.asyncMethod();
+    field1.use2(obj1, obj2);
+  }
+}
+
+class LiveObj4 extends LiveVarsBench {
+  LiveObj4() : super('AsyncLiveVars.LiveObj4');
+  final field1 = MockClass();
+  final field2 = MockClass();
+  @override
+  Future<void> run() async {
+    final obj1 = field1.get1();
+    final obj2 = field1.get2();
+    final obj3 = field2.get1();
+    final obj4 = field2.get2();
+    await field1.asyncMethod();
+    field1.use1(obj1);
+    await field1.asyncMethod();
+    field2.use1(obj3);
+    await field2.asyncMethod();
+    field1.use4(obj1, obj2, obj3, obj4);
+  }
+}
+
+class LiveObj8 extends LiveVarsBench {
+  LiveObj8() : super('AsyncLiveVars.LiveObj8');
+  final field1 = MockClass();
+  final field2 = MockClass();
+  final field3 = MockClass();
+  final field4 = MockClass();
+  @override
+  Future<void> run() async {
+    final obj1 = field1.get1();
+    final obj2 = field1.get2();
+    final obj3 = field2.get1();
+    final obj4 = field2.get2();
+    final obj5 = field3.get1();
+    final obj6 = field3.get2();
+    final obj7 = field4.get1();
+    final obj8 = field4.get2();
+    await field1.asyncMethod();
+    field1.use1(obj1);
+    await field2.asyncMethod();
+    field3.use2(obj5, obj6);
+    await field4.asyncMethod();
+    field2.use8(obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8);
+  }
+}
+
+class LiveObj16 extends LiveVarsBench {
+  LiveObj16() : super('AsyncLiveVars.LiveObj16');
+  final field1 = MockClass();
+  final field2 = MockClass();
+  final field3 = MockClass();
+  final field4 = MockClass();
+  final field5 = MockClass();
+  final field6 = MockClass();
+  final field7 = MockClass();
+  final field8 = MockClass();
+  @override
+  Future<void> run() async {
+    final obj1 = field1.get1();
+    final obj2 = field1.get2();
+    final obj3 = field2.get1();
+    final obj4 = field2.get2();
+    final obj5 = field3.get1();
+    final obj6 = field3.get2();
+    final obj7 = field4.get1();
+    final obj8 = field4.get2();
+    final obj9 = field5.get1();
+    final obj10 = field5.get2();
+    final obj11 = field6.get1();
+    final obj12 = field6.get2();
+    final obj13 = field7.get1();
+    final obj14 = field7.get2();
+    final obj15 = field8.get1();
+    final obj16 = field8.get2();
+    await field1.asyncMethod();
+    field1.use1(obj1);
+    await field2.asyncMethod();
+    field5.use2(obj11, obj12);
+    await field4.asyncMethod();
+    field2.use8(obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8);
+    field3.use8(obj9, obj10, obj11, obj12, obj13, obj14, obj15, obj16);
+  }
+}
+
+class LiveInt1 extends LiveVarsBench {
+  LiveInt1() : super('AsyncLiveVars.LiveInt1');
+  final field1 = MockClass2();
+  @override
+  Future<void> run() async {
+    final int1 = field1.get1();
+    await field1.asyncMethod();
+    field1.use1(int1);
+    await field1.asyncMethod();
+    field1.use1(int1);
+    await field1.asyncMethod();
+    field1.use1(int1);
+  }
+}
+
+class LiveInt4 extends LiveVarsBench {
+  LiveInt4() : super('AsyncLiveVars.LiveInt4');
+  final field1 = MockClass2();
+  final field2 = MockClass2();
+  @override
+  Future<void> run() async {
+    final int1 = field1.get1();
+    final int2 = field1.get2();
+    final int3 = field2.get1();
+    final int4 = field2.get2();
+    await field1.asyncMethod();
+    field1.use1(int1);
+    await field1.asyncMethod();
+    field2.use1(int3);
+    await field2.asyncMethod();
+    field1.use4(int1, int2, int3, int4);
+  }
+}
+
+class LiveObj2Int2 extends LiveVarsBench {
+  LiveObj2Int2() : super('AsyncLiveVars.LiveObj2Int2');
+  final field1 = MockClass();
+  final field2 = MockClass2();
+  @override
+  Future<void> run() async {
+    final obj1 = field1.get1();
+    final obj2 = field1.get2();
+    final int1 = field2.get1();
+    final int2 = field2.get2();
+    await field1.asyncMethod();
+    field1.use1(obj1);
+    await field1.asyncMethod();
+    field2.use1(int1);
+    await field2.asyncMethod();
+    field1.use2(obj1, obj2);
+    field2.use2(int1, int2);
+  }
+}
+
+class LiveObj4Int4 extends LiveVarsBench {
+  LiveObj4Int4() : super('AsyncLiveVars.LiveObj4Int4');
+  final field1 = MockClass();
+  final field2 = MockClass();
+  final field3 = MockClass2();
+  final field4 = MockClass2();
+  @override
+  Future<void> run() async {
+    final obj1 = field1.get1();
+    final obj2 = field1.get2();
+    final obj3 = field2.get1();
+    final obj4 = field2.get2();
+    final int1 = field3.get1();
+    final int2 = field3.get2();
+    final int3 = field4.get1();
+    final int4 = field4.get2();
+    await field1.asyncMethod();
+    field1.use1(obj1);
+    await field2.asyncMethod();
+    field3.use2(int2, int4);
+    await field4.asyncMethod();
+    field2.use4(obj1, obj2, obj3, obj4);
+    field4.use4(int1, int2, int3, int4);
+  }
+}
+
+Future<void> main() async {
+  final benchmarks = [
+    LiveObj1(),
+    LiveObj2(),
+    LiveObj4(),
+    LiveObj8(),
+    LiveObj16(),
+    LiveInt1(),
+    LiveInt4(),
+    LiveObj2Int2(),
+    LiveObj4Int4()
+  ];
+  for (final bench in benchmarks) {
+    await bench.report();
+  }
+}
diff --git a/benchmarks/AsyncLiveVars/dart2/async_benchmark_base.dart b/benchmarks/AsyncLiveVars/dart2/async_benchmark_base.dart
new file mode 100644
index 0000000..9a415b9
--- /dev/null
+++ b/benchmarks/AsyncLiveVars/dart2/async_benchmark_base.dart
@@ -0,0 +1,68 @@
+// 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 'package:benchmark_harness/benchmark_harness.dart'
+    show PrintEmitter, ScoreEmitter;
+
+// Similar to BenchmarkBase from package:benchmark_harness.
+class AsyncBenchmarkBase {
+  final String name;
+  final ScoreEmitter emitter;
+
+  // Empty constructor.
+  const AsyncBenchmarkBase(this.name, {this.emitter = const PrintEmitter()});
+
+  // The benchmark code.
+  // This function is not used, if both [warmup] and [exercise] are overwritten.
+  Future<void> run() async {}
+
+  // Runs a short version of the benchmark. By default invokes [run] once.
+  Future<void> warmup() async {
+    await run();
+  }
+
+  // Exercises the benchmark. By default invokes [run] 10 times.
+  Future<void> exercise() async {
+    for (var i = 0; i < 10; i++) {
+      await run();
+    }
+  }
+
+  // Not measured setup code executed prior to the benchmark runs.
+  Future<void> setup() async {}
+
+  // Not measures teardown code executed after the benchark runs.
+  Future<void> teardown() async {}
+
+  // Measures the score for this benchmark by executing it repeatedly until
+  // time minimum has been reached.
+  static Future<double> measureFor(Function f, int minimumMillis) async {
+    final int minimumMicros = minimumMillis * 1000;
+    int iter = 0;
+    final watch = Stopwatch();
+    watch.start();
+    int elapsed = 0;
+    while (elapsed < minimumMicros) {
+      await f();
+      elapsed = watch.elapsedMicroseconds;
+      iter++;
+    }
+    return elapsed / iter;
+  }
+
+  // Measures the score for the benchmark and returns it.
+  Future<double> measure() async {
+    await setup();
+    // Warmup for at least 100ms. Discard result.
+    await measureFor(warmup, 100);
+    // Run the benchmark for at least 2000ms.
+    final result = await measureFor(exercise, 2000);
+    await teardown();
+    return result;
+  }
+
+  Future<void> report() async {
+    emitter.emit(name, await measure());
+  }
+}
diff --git a/pkg/_fe_analyzer_shared/lib/src/deferred_closure_heuristic.dart b/pkg/_fe_analyzer_shared/lib/src/deferred_closure_heuristic.dart
new file mode 100644
index 0000000..d5f823a
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/lib/src/deferred_closure_heuristic.dart
@@ -0,0 +1,139 @@
+// 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 'package:_fe_analyzer_shared/src/util/dependency_walker.dart';
+
+/// Data structure tracking the type inference dependencies between closures
+/// passed as invocation parameters.
+///
+/// [planClosureReconciliationStages] is used as part of support for
+/// https://github.com/dart-lang/language/issues/731 (improved inference for
+/// fold etc.) to choose the proper order in which to recursively analyze
+/// closures passed as invocation arguments.
+abstract class ClosureDependencies<TypeVariable, Closure> {
+  final List<_ClosureNode<Closure>> _closureNodes = [];
+
+  /// Construct a [ClosureDependencies] object that's prepared to determine the
+  /// order to resolve [closures] for a generic invocation involving the given
+  /// [typeVariables].
+  ClosureDependencies(
+      Iterable<Closure> closures, Iterable<TypeVariable> typeVariables) {
+    Map<TypeVariable, Set<_ClosureNode<Closure>>> closuresDependingOnTypeVar =
+        {};
+    Map<TypeVariable, Set<_ClosureNode<Closure>>> closuresConstrainingTypeVar =
+        {};
+    for (Closure closure in closures) {
+      _ClosureNode<Closure> closureNode = new _ClosureNode<Closure>(closure);
+      _closureNodes.add(closureNode);
+      for (TypeVariable v in typeVarsFreeInClosureArguments(closure)) {
+        (closuresDependingOnTypeVar[v] ??= {}).add(closureNode);
+      }
+      for (TypeVariable v in typeVarsFreeInClosureReturns(closure)) {
+        (closuresConstrainingTypeVar[v] ??= {}).add(closureNode);
+      }
+    }
+    for (TypeVariable typeVariable in typeVariables) {
+      for (_ClosureNode<Closure> closureNode
+          in closuresDependingOnTypeVar[typeVariable] ?? const {}) {
+        closureNode.dependencies
+            .addAll(closuresConstrainingTypeVar[typeVariable] ?? const {});
+      }
+    }
+  }
+
+  /// Computes the order in which to resolve the closures passed to the
+  /// constructor.
+  ///
+  /// Each entry in the returned list represents the set of closures that should
+  /// be visited during a single stage of resolution; after each stage, the
+  /// assignment of actual types to type variables should be refined.
+  ///
+  /// So, for example, if the closures in question are A, B, and C, and the
+  /// returned list is `[{A, B}, {C}]`, then first closures A and B should be
+  /// resolved, then the assignment of actual types to type variables should be
+  /// refined, and then C should be resolved, and then the final assignment of
+  /// actual types to type variables should be computed.
+  List<Set<Closure>> planClosureReconciliationStages() {
+    _DependencyWalker<Closure> walker = new _DependencyWalker<Closure>();
+    for (_ClosureNode<Closure> closureNode in _closureNodes) {
+      walker.walk(closureNode);
+    }
+    return walker.closureReconciliationStages;
+  }
+
+  /// If the type of the parameter corresponding to [closure] is a function
+  /// type, the set of type parameters referred to by the parameter types of
+  /// that parameter.  If the type of the parameter is not a function type, an
+  /// empty iterable should be returned.
+  ///
+  /// Should be overridden by the client.
+  Iterable<TypeVariable> typeVarsFreeInClosureArguments(Closure closure);
+
+  /// If the type of the parameter corresponding to [closure] is a function
+  /// type, the set of type parameters referred to by the return type of that
+  /// parameter.  If the type of the parameter is not a function type, the set
+  /// type parameters referred to by the type of the parameter should be
+  /// returned.
+  ///
+  /// Should be overridden by the client.
+  Iterable<TypeVariable> typeVarsFreeInClosureReturns(Closure closure);
+}
+
+/// Node type representing a single [Closure] for purposes of walking the
+/// graph of type inference dependencies among closures.
+class _ClosureNode<Closure> extends Node<_ClosureNode<Closure>> {
+  /// The [Closure] being represented by this node.
+  final Closure closure;
+
+  /// If not `null`, the index of the reconciliation stage to which this closure
+  /// has been assigned.
+  int? stageNum;
+
+  /// The nodes for the closures depended on by this closure.
+  final List<_ClosureNode<Closure>> dependencies = [];
+
+  _ClosureNode(this.closure);
+
+  @override
+  bool get isEvaluated => stageNum != null;
+
+  @override
+  List<_ClosureNode<Closure>> computeDependencies() => dependencies;
+}
+
+/// Derived class of [DependencyWalker] capable of walking the graph of type
+/// inference dependencies among closures.
+class _DependencyWalker<Closure>
+    extends DependencyWalker<_ClosureNode<Closure>> {
+  /// The set of closure reconciliation stages accumulated so far.
+  final List<Set<Closure>> closureReconciliationStages = [];
+
+  @override
+  void evaluate(_ClosureNode v) => evaluateScc([v]);
+
+  @override
+  void evaluateScc(List<_ClosureNode> nodes) {
+    int stageNum = 0;
+    for (_ClosureNode node in nodes) {
+      for (_ClosureNode dependency in node.dependencies) {
+        int? dependencyStageNum = dependency.stageNum;
+        if (dependencyStageNum != null && dependencyStageNum >= stageNum) {
+          stageNum = dependencyStageNum + 1;
+        }
+      }
+    }
+    if (closureReconciliationStages.length <= stageNum) {
+      closureReconciliationStages.add({});
+      // `stageNum` can't grow by more than 1 each time `evaluateScc` is called,
+      // so adding one stage is sufficient to make sure the list is now long
+      // enough.
+      assert(stageNum < closureReconciliationStages.length);
+    }
+    Set<Closure> stage = closureReconciliationStages[stageNum];
+    for (_ClosureNode node in nodes) {
+      node.stageNum = stageNum;
+      stage.add(node.closure);
+    }
+  }
+}
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor/message_grouper.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor/message_grouper.dart
index 7e2d390..382dd81 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/executor/message_grouper.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor/message_grouper.dart
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:async';
-import 'dart:math';
 import 'dart:typed_data';
 
 /// Collects messages from an input stream of bytes.
@@ -14,18 +13,11 @@
   /// The input bytes stream subscription.
   late final StreamSubscription _inputStreamSubscription;
 
-  /// The length of the current message to read, or `-1` if we are currently
-  /// reading the length.
-  int _length = -1;
-
   /// The buffer to store the length bytes in.
-  BytesBuilder _lengthBuffer = new BytesBuilder();
+  final _FixedBuffer _lengthBuffer = new _FixedBuffer(4);
 
   /// If reading raw data, buffer for the data.
-  Uint8List _messageBuffer = new Uint8List(0);
-
-  /// The position to write the next byte in [_messageBuffer].
-  int _messagePos = 0;
+  _FixedBuffer? _messageBuffer;
 
   late StreamController<Uint8List> _messageStreamController =
       new StreamController<Uint8List>(onCancel: () {
@@ -38,45 +30,36 @@
   }
 
   void _handleBytes(List<int> bytes, [int offset = 0]) {
-    if (_length == -1) {
-      while (_lengthBuffer.length < 4 && offset < bytes.length) {
+    final _FixedBuffer? messageBuffer = _messageBuffer;
+    if (messageBuffer == null) {
+      while (offset < bytes.length && !_lengthBuffer.isReady) {
         _lengthBuffer.addByte(bytes[offset++]);
       }
-      if (_lengthBuffer.length >= 4) {
-        Uint8List lengthBytes = _lengthBuffer.takeBytes();
-        _length = lengthBytes[0] << 24 |
-            lengthBytes[1] << 16 |
-            lengthBytes[2] << 8 |
-            lengthBytes[3];
+      if (_lengthBuffer.isReady) {
+        int length = _lengthBuffer[0] << 24 |
+            _lengthBuffer[1] << 16 |
+            _lengthBuffer[2] << 8 |
+            _lengthBuffer[3];
+        // Reset the length reading state.
+        _lengthBuffer.reset();
+        // Switch to the message payload reading state.
+        _messageBuffer = new _FixedBuffer(length);
+        _handleBytes(bytes, offset);
+      } else {
+        // Continue reading the length.
+        return;
       }
-    }
+    } else {
+      // Read the data from `bytes`.
+      while (offset < bytes.length && !messageBuffer.isReady) {
+        messageBuffer.addByte(bytes[offset++]);
+      }
 
-    // Just pass along `bytes` without a copy if we can, and reset our state
-    if (offset == 0 && bytes.length == _length && bytes is Uint8List) {
-      _length = -1;
-      _messageStreamController.add(bytes);
-      return;
-    }
-
-    // Initialize a new buffer.
-    if (_messagePos == 0) {
-      _messageBuffer = new Uint8List(_length);
-    }
-
-    // Read the data from `bytes`.
-    int lenToRead = min(_length - _messagePos, bytes.length - offset);
-    while (lenToRead-- > 0) {
-      _messageBuffer[_messagePos++] = bytes[offset++];
-    }
-
-    // If we completed a message, add it to the output stream, reset our state,
-    // and call ourselves again if we have more data to read.
-    if (_messagePos >= _length) {
-      _messageStreamController.add(_messageBuffer);
-      _length = -1;
-      _messagePos = 0;
-
-      if (offset < bytes.length) {
+      // If we completed a message, add it to the output stream.
+      if (messageBuffer.isReady) {
+        _messageStreamController.add(messageBuffer.bytes);
+        // Switch to the length reading state.
+        _messageBuffer = null;
         _handleBytes(bytes, offset);
       }
     }
@@ -89,3 +72,27 @@
     _messageStreamController.close();
   }
 }
+
+/// A buffer of fixed length.
+class _FixedBuffer {
+  final Uint8List bytes;
+
+  /// The offset in [bytes].
+  int _offset = 0;
+
+  _FixedBuffer(int length) : bytes = new Uint8List(length);
+
+  /// Return `true` when the required number of bytes added.
+  bool get isReady => _offset == bytes.length;
+
+  int operator [](int index) => bytes[index];
+
+  void addByte(int byte) {
+    bytes[_offset++] = byte;
+  }
+
+  /// Reset the number of added bytes to zero.
+  void reset() {
+    _offset = 0;
+  }
+}
diff --git a/pkg/_fe_analyzer_shared/test/deferred_closure_heuristic_test.dart b/pkg/_fe_analyzer_shared/test/deferred_closure_heuristic_test.dart
new file mode 100644
index 0000000..ab4b8f9
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/deferred_closure_heuristic_test.dart
@@ -0,0 +1,138 @@
+// 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 'package:_fe_analyzer_shared/src/deferred_closure_heuristic.dart';
+import 'package:test/test.dart';
+
+main() {
+  test('single', () {
+    // If there is just a single closure and no type variables, it is selected.
+    var f = Closure('f');
+    expect(
+        _TestClosureDeps(typeVars: [], closures: [f])
+            .planClosureReconciliationStages(),
+        [
+          {f}
+        ]);
+  });
+
+  test('simple dependency', () {
+    // If f depends on g, then g is selected first, and then f.
+    var f = Closure('f', argTypes: ['T']);
+    var g = Closure('g', retTypes: ['T']);
+    expect(
+        _TestClosureDeps(typeVars: ['T'], closures: [f, g])
+            .planClosureReconciliationStages(),
+        [
+          {g},
+          {f}
+        ]);
+  });
+
+  test('long chain', () {
+    // If f depends on g and g depends on h, then we do three separate stages:
+    // h, then g, then f.
+    var f = Closure('f', argTypes: ['T']);
+    var g = Closure('g', argTypes: ['U'], retTypes: ['T']);
+    var h = Closure('h', retTypes: ['U']);
+    expect(
+        _TestClosureDeps(typeVars: ['T', 'U'], closures: [f, g, h])
+            .planClosureReconciliationStages(),
+        [
+          {h},
+          {g},
+          {f}
+        ]);
+  });
+
+  test('unrelated closure', () {
+    // Closures that are independent of all the others are inferred during the
+    // first stage.
+    var f = Closure('f', argTypes: ['T']);
+    var g = Closure('g', retTypes: ['T']);
+    var h = Closure('h');
+    expect(
+        _TestClosureDeps(typeVars: ['T', 'U'], closures: [f, g, h])
+            .planClosureReconciliationStages(),
+        [
+          {g, h},
+          {f}
+        ]);
+  });
+
+  test('independent chains', () {
+    // If f depends on g, and h depends on i, then g and i are selected first,
+    // and then f and h.
+    var f = Closure('f', argTypes: ['T']);
+    var g = Closure('g', retTypes: ['T']);
+    var h = Closure('h', argTypes: ['U']);
+    var i = Closure('i', retTypes: ['U']);
+    expect(
+        _TestClosureDeps(typeVars: ['T', 'U'], closures: [f, g, h, i])
+            .planClosureReconciliationStages(),
+        [
+          {g, i},
+          {f, h}
+        ]);
+  });
+
+  test('diamond', () {
+    // Test a diamond dependency shape: f depends on g and h; g and h both
+    // depend on i.
+    var f = Closure('f', argTypes: ['T', 'U']);
+    var g = Closure('g', argTypes: ['V'], retTypes: ['T']);
+    var h = Closure('h', argTypes: ['V'], retTypes: ['U']);
+    var i = Closure('i', retTypes: ['V']);
+    expect(
+        _TestClosureDeps(typeVars: ['T', 'U', 'V'], closures: [f, g, h, i])
+            .planClosureReconciliationStages(),
+        [
+          {i},
+          {g, h},
+          {f}
+        ]);
+  });
+
+  test('cycle', () {
+    // A dependency cycle is inferred all at once.
+    var f = Closure('f', argTypes: ['T']);
+    var g = Closure('g', argTypes: ['U']);
+    var h = Closure('h', argTypes: ['U'], retTypes: ['T']);
+    var i = Closure('i', argTypes: ['T'], retTypes: ['U']);
+    expect(
+        _TestClosureDeps(typeVars: ['T', 'U'], closures: [f, g, h, i])
+            .planClosureReconciliationStages(),
+        [
+          {h, i},
+          {f, g}
+        ]);
+  });
+}
+
+class Closure {
+  final String name;
+  final List<String> argTypes;
+  final List<String> retTypes;
+
+  Closure(this.name, {this.argTypes = const [], this.retTypes = const []});
+
+  @override
+  String toString() => name;
+}
+
+class _TestClosureDeps extends ClosureDependencies<String, Closure> {
+  final List<String> typeVars;
+  final List<Closure> closures;
+
+  _TestClosureDeps({required this.typeVars, required this.closures})
+      : super(closures, typeVars);
+
+  @override
+  Set<String> typeVarsFreeInClosureArguments(Closure closure) =>
+      closure.argTypes.toSet();
+
+  @override
+  Set<String> typeVarsFreeInClosureReturns(Closure closure) =>
+      closure.retTypes.toSet();
+}
diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
index be22f29..3b7e4a3 100644
--- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -9,6 +9,7 @@
 import 'package:analysis_server/src/collections.dart';
 import 'package:analysis_server/src/domain_abstract.dart';
 import 'package:analysis_server/src/handler/legacy/edit_bulk_fixes.dart';
+import 'package:analysis_server/src/handler/legacy/edit_format.dart';
 import 'package:analysis_server/src/handler/legacy/edit_format_if_enabled.dart';
 import 'package:analysis_server/src/handler/legacy/edit_get_assists.dart';
 import 'package:analysis_server/src/handler/legacy/edit_get_fixes.dart';
@@ -16,11 +17,11 @@
 import 'package:analysis_server/src/handler/legacy/edit_get_statement_completion.dart';
 import 'package:analysis_server/src/handler/legacy/edit_import_elements.dart';
 import 'package:analysis_server/src/handler/legacy/edit_is_postfix_completion_applicable.dart';
+import 'package:analysis_server/src/handler/legacy/edit_list_postfix_completion_templates.dart';
 import 'package:analysis_server/src/handler/legacy/edit_organize_directives.dart';
 import 'package:analysis_server/src/handler/legacy/edit_sort_members.dart';
 import 'package:analysis_server/src/protocol_server.dart'
     hide AnalysisError, Element;
-import 'package:analysis_server/src/services/completion/postfix/postfix_completion.dart';
 import 'package:analysis_server/src/services/correction/status.dart';
 import 'package:analysis_server/src/services/refactoring/refactoring.dart';
 import 'package:analysis_server/src/services/search/search_engine.dart';
@@ -28,7 +29,6 @@
 import 'package:analyzer/dart/analysis/session.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/dart/ast/utilities.dart';
-import 'package:dart_style/dart_style.dart';
 
 int test_resetCount = 0;
 
@@ -57,69 +57,14 @@
     _newRefactoringManager();
   }
 
-  Response format(Request request) {
-    server.options.analytics?.sendEvent('edit', 'format');
-
-    var params = EditFormatParams.fromRequest(request);
-    var file = params.file;
-
-    String unformattedCode;
-    try {
-      var resource = server.resourceProvider.getFile(file);
-      unformattedCode = resource.readAsStringSync();
-    } catch (e) {
-      return Response.formatInvalidFile(request);
-    }
-
-    int? start = params.selectionOffset;
-    int? length = params.selectionLength;
-
-    // No need to preserve 0,0 selection
-    if (start == 0 && length == 0) {
-      start = null;
-      length = null;
-    }
-
-    var code = SourceCode(unformattedCode,
-        uri: null,
-        isCompilationUnit: true,
-        selectionStart: start,
-        selectionLength: length);
-    var formatter = DartFormatter(pageWidth: params.lineLength);
-    SourceCode formattedResult;
-    try {
-      formattedResult = formatter.formatSource(code);
-    } on FormatterException {
-      return Response.formatWithErrors(request);
-    }
-    var formattedSource = formattedResult.text;
-
-    var edits = <SourceEdit>[];
-
-    if (formattedSource != unformattedCode) {
-      //TODO: replace full replacements with smaller, more targeted edits
-      var edit = SourceEdit(0, unformattedCode.length, formattedSource);
-      edits.add(edit);
-    }
-
-    var newStart = formattedResult.selectionStart;
-    var newLength = formattedResult.selectionLength;
-
-    // Sending null start/length values would violate protocol, so convert back
-    // to 0.
-    newStart ??= 0;
-    newLength ??= 0;
-
-    return EditFormatResult(edits, newStart, newLength).toResponse(request.id);
-  }
-
   @override
   Response? handleRequest(
       Request request, CancellationToken cancellationToken) {
     try {
       var requestName = request.method;
       if (requestName == EDIT_REQUEST_FORMAT) {
-        return format(request);
+        EditFormatHandler(server, request, cancellationToken).handle();
+        return Response.DELAYED_RESPONSE;
       } else if (requestName == EDIT_REQUEST_FORMAT_IF_ENABLED) {
         EditFormatIfEnabledHandler(server, request, cancellationToken).handle();
         return Response.DELAYED_RESPONSE;
@@ -162,7 +107,10 @@
         return Response.DELAYED_RESPONSE;
       } else if (requestName ==
           EDIT_REQUEST_LIST_POSTFIX_COMPLETION_TEMPLATES) {
-        return listPostfixCompletionTemplates(request);
+        EditListPostfixCompletionTemplatesHandler(
+                server, request, cancellationToken)
+            .handle();
+        return Response.DELAYED_RESPONSE;
       }
     } on RequestFailure catch (exception) {
       return exception.response;
@@ -170,16 +118,6 @@
     return null;
   }
 
-  Response listPostfixCompletionTemplates(Request request) {
-    var templates = DartPostfixCompletion.ALL_TEMPLATES
-        .map((PostfixCompletionKind kind) =>
-            PostfixTemplateDescriptor(kind.name, kind.key, kind.example))
-        .toList();
-
-    return EditListPostfixCompletionTemplatesResult(templates)
-        .toResponse(request.id);
-  }
-
   Future<void> _getAvailableRefactorings(Request request) async {
     var params = EditGetAvailableRefactoringsParams.fromRequest(request);
     var file = params.file;
diff --git a/pkg/analysis_server/lib/src/handler/legacy/edit_format.dart b/pkg/analysis_server/lib/src/handler/legacy/edit_format.dart
new file mode 100644
index 0000000..ca6d691
--- /dev/null
+++ b/pkg/analysis_server/lib/src/handler/legacy/edit_format.dart
@@ -0,0 +1,83 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:analysis_server/protocol/protocol.dart';
+import 'package:analysis_server/protocol/protocol_generated.dart';
+import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analysis_server/src/handler/legacy/legacy_handler.dart';
+import 'package:analysis_server/src/utilities/progress.dart';
+import 'package:analyzer_plugin/protocol/protocol_common.dart';
+import 'package:dart_style/src/dart_formatter.dart';
+import 'package:dart_style/src/exceptions.dart';
+import 'package:dart_style/src/source_code.dart';
+
+/// The handler for the `edit.format` request.
+class EditFormatHandler extends LegacyHandler {
+  /// Initialize a newly created handler to be able to service requests for the
+  /// [server].
+  EditFormatHandler(AnalysisServer server, Request request,
+      CancellationToken cancellationToken)
+      : super(server, request, cancellationToken);
+
+  @override
+  Future<void> handle() async {
+    server.options.analytics?.sendEvent('edit', 'format');
+
+    var params = EditFormatParams.fromRequest(request);
+    var file = params.file;
+//
+    String unformattedCode;
+    try {
+      var resource = server.resourceProvider.getFile(file);
+      unformattedCode = resource.readAsStringSync();
+    } catch (e) {
+      sendResponse(Response.formatInvalidFile(request));
+      return;
+    }
+
+    int? start = params.selectionOffset;
+    int? length = params.selectionLength;
+
+    // No need to preserve 0,0 selection
+    if (start == 0 && length == 0) {
+      start = null;
+      length = null;
+    }
+
+    var code = SourceCode(unformattedCode,
+        uri: null,
+        isCompilationUnit: true,
+        selectionStart: start,
+        selectionLength: length);
+    var formatter = DartFormatter(pageWidth: params.lineLength);
+    SourceCode formattedResult;
+    try {
+      formattedResult = formatter.formatSource(code);
+    } on FormatterException {
+      sendResponse(Response.formatWithErrors(request));
+      return;
+    }
+    var formattedSource = formattedResult.text;
+
+    var edits = <SourceEdit>[];
+
+    if (formattedSource != unformattedCode) {
+      //TODO: replace full replacements with smaller, more targeted edits
+      var edit = SourceEdit(0, unformattedCode.length, formattedSource);
+      edits.add(edit);
+    }
+
+    var newStart = formattedResult.selectionStart;
+    var newLength = formattedResult.selectionLength;
+
+    // Sending null start/length values would violate protocol, so convert back
+    // to 0.
+    newStart ??= 0;
+    newLength ??= 0;
+
+    sendResult(EditFormatResult(edits, newStart, newLength));
+  }
+}
diff --git a/pkg/analysis_server/lib/src/handler/legacy/edit_list_postfix_completion_templates.dart b/pkg/analysis_server/lib/src/handler/legacy/edit_list_postfix_completion_templates.dart
new file mode 100644
index 0000000..b990eea
--- /dev/null
+++ b/pkg/analysis_server/lib/src/handler/legacy/edit_list_postfix_completion_templates.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:analysis_server/protocol/protocol.dart';
+import 'package:analysis_server/protocol/protocol_generated.dart';
+import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analysis_server/src/handler/legacy/legacy_handler.dart';
+import 'package:analysis_server/src/services/completion/postfix/postfix_completion.dart';
+import 'package:analysis_server/src/utilities/progress.dart';
+
+/// The handler for the `edit.listPostfixCompletionTemplates` request.
+class EditListPostfixCompletionTemplatesHandler extends LegacyHandler {
+  /// Initialize a newly created handler to be able to service requests for the
+  /// [server].
+  EditListPostfixCompletionTemplatesHandler(AnalysisServer server,
+      Request request, CancellationToken cancellationToken)
+      : super(server, request, cancellationToken);
+
+  @override
+  Future<void> handle() async {
+    var templates = DartPostfixCompletion.ALL_TEMPLATES
+        .map((PostfixCompletionKind kind) =>
+            PostfixTemplateDescriptor(kind.name, kind.key, kind.example))
+        .toList();
+    sendResult(EditListPostfixCompletionTemplatesResult(templates));
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/create_constructor_for_final_fields.dart b/pkg/analysis_server/lib/src/services/correction/dart/create_constructor_for_final_fields.dart
index 94e26f2..e125e84 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/create_constructor_for_final_fields.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/create_constructor_for_final_fields.dart
@@ -4,18 +4,19 @@
 
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analysis_server/src/services/correction/util.dart';
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
 import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
 
 class CreateConstructorForFinalFields extends CorrectionProducer {
   @override
   FixKind get fixKind => DartFixKind.CREATE_CONSTRUCTOR_FOR_FINAL_FIELDS;
 
-  bool get _isNonNullable => unit.featureSet.isEnabled(Feature.non_nullable);
-
   @override
   Future<void> compute(ChangeBuilder builder) async {
     if (node is! SimpleIdentifier || node.parent is! VariableDeclaration) {
@@ -33,15 +34,12 @@
       return;
     }
 
-    // prepare names of uninitialized final fields
-    var fieldNames = <String>[];
+    var variableLists = <VariableDeclarationList>[];
     for (var member in classDeclaration.members) {
       if (member is FieldDeclaration) {
         var variableList = member.fields;
         if (variableList.isFinal && !variableList.isLate) {
-          fieldNames.addAll(variableList.variables
-              .where((v) => v.initializer == null)
-              .map((v) => v.name.name));
+          variableLists.add(variableList);
         }
       }
     }
@@ -59,41 +57,22 @@
       if (keyClass == null) {
         return;
       }
-      await builder.addDartFileEdit(file, (builder) {
-        builder.addInsertion(targetLocation.offset, (builder) {
-          builder.write(targetLocation.prefix);
-          builder.write('const ');
-          builder.write(className);
-          builder.write('({');
-          builder.writeType(
-            keyClass.instantiate(
-              typeArguments: const [],
-              nullabilitySuffix: _isNonNullable
-                  ? NullabilitySuffix.question
-                  : NullabilitySuffix.star,
-            ),
-          );
-          builder.write(' key');
 
-          var childrenFields = <String>[];
-          for (var fieldName in fieldNames) {
-            if (fieldName == 'child' || fieldName == 'children') {
-              childrenFields.add(fieldName);
-              continue;
-            }
-            builder.write(', this.');
-            builder.write(fieldName);
-          }
-          for (var fieldName in childrenFields) {
-            builder.write(', this.');
-            builder.write(fieldName);
-          }
-
-          builder.write('}) : super(key: key);');
-          builder.write(targetLocation.suffix);
-        });
-      });
+      if (unit.featureSet.isEnabled(Feature.super_parameters)) {
+        await _withSuperParameters(
+            builder, targetLocation, className, variableLists);
+      } else {
+        await _withoutSuperParameters(
+            builder, targetLocation, className, keyClass, variableLists);
+      }
     } else {
+      var fieldNames = <String>[];
+      for (var variableList in variableLists) {
+        fieldNames.addAll(variableList.variables
+            .where((v) => v.initializer == null)
+            .map((v) => v.name.name));
+      }
+
       await builder.addDartFileEdit(file, (builder) {
         builder.addInsertion(targetLocation.offset, (builder) {
           builder.write(targetLocation.prefix);
@@ -105,6 +84,96 @@
     }
   }
 
+  Future<void> _withoutSuperParameters(
+      ChangeBuilder builder,
+      ClassMemberLocation targetLocation,
+      String className,
+      ClassElement keyClass,
+      List<VariableDeclarationList> variableLists) async {
+    var isNonNullable = unit.featureSet.isEnabled(Feature.non_nullable);
+    await builder.addDartFileEdit(file, (builder) {
+      builder.addInsertion(targetLocation.offset, (builder) {
+        builder.write(targetLocation.prefix);
+        builder.write('const ');
+        builder.write(className);
+        builder.write('({');
+        builder.writeType(
+          keyClass.instantiate(
+            typeArguments: const [],
+            nullabilitySuffix: isNonNullable
+                ? NullabilitySuffix.question
+                : NullabilitySuffix.star,
+          ),
+        );
+        builder.write(' key');
+
+        _writeParameters(builder, variableLists, isNonNullable);
+
+        builder.write('}) : super(key: key);');
+        builder.write(targetLocation.suffix);
+      });
+    });
+  }
+
+  Future<void> _withSuperParameters(
+      ChangeBuilder builder,
+      ClassMemberLocation targetLocation,
+      String className,
+      List<VariableDeclarationList> variableLists) async {
+    await builder.addDartFileEdit(file, (builder) {
+      builder.addInsertion(targetLocation.offset, (builder) {
+        builder.write(targetLocation.prefix);
+        builder.write('const ');
+        builder.write(className);
+        builder.write('({');
+        builder.write('super.key');
+
+        _writeParameters(builder, variableLists, true);
+
+        builder.write('});');
+        builder.write(targetLocation.suffix);
+      });
+    });
+  }
+
+  void _writeParameters(DartEditBuilder builder,
+      List<VariableDeclarationList> variableLists, bool isNonNullable) {
+    var childrenFields = <String>[];
+    var childrenNullables = <bool>[];
+    for (var variableList in variableLists) {
+      var fieldNames = variableList.variables
+          .where((v) => v.initializer == null)
+          .map((v) => v.name.name);
+
+      for (var fieldName in fieldNames) {
+        if (fieldName == 'child' || fieldName == 'children') {
+          childrenFields.add(fieldName);
+          childrenNullables.add(variableList.type?.type?.nullabilitySuffix ==
+              NullabilitySuffix.question);
+          continue;
+        }
+        builder.write(', ');
+        if (isNonNullable &&
+            variableList.type?.type?.nullabilitySuffix !=
+                NullabilitySuffix.question) {
+          builder.write('required ');
+        }
+        builder.write('this.');
+        builder.write(fieldName);
+      }
+    }
+    for (var i = 0; i < childrenFields.length; i++) {
+      var fieldName = childrenFields[i];
+      var nullableField = childrenNullables[i];
+      builder.write(', ');
+      if (isNonNullable && !nullableField) {
+        builder.write('required ');
+      }
+      builder.write('this.');
+      builder.write(fieldName);
+    }
+  }
+
   /// Return an instance of this class. Used as a tear-off in `FixProcessor`.
   static CreateConstructorForFinalFields newInstance() =>
       CreateConstructorForFinalFields();
diff --git a/pkg/analysis_server/test/analysis/get_errors_test.dart b/pkg/analysis_server/test/analysis/get_errors_test.dart
index 1ce1f0a..e3f0c6e 100644
--- a/pkg/analysis_server/test/analysis/get_errors_test.dart
+++ b/pkg/analysis_server/test/analysis/get_errors_test.dart
@@ -33,7 +33,7 @@
 }
 ''');
 
-    await server.onAnalysisComplete;
+    await waitForTasksFinished();
 
     var errors = await _getErrors(testFile.path);
     expect(errors, hasLength(1));
diff --git a/pkg/analysis_server/test/analysis/get_hover_test.dart b/pkg/analysis_server/test/analysis/get_hover_test.dart
index 9120539..bb65e9a 100644
--- a/pkg/analysis_server/test/analysis/get_hover_test.dart
+++ b/pkg/analysis_server/test/analysis/get_hover_test.dart
@@ -48,7 +48,7 @@
   }
 
   Future<HoverInformation?> prepareHoverAt(int offset) async {
-    await server.onAnalysisComplete;
+    await waitForTasksFinished();
     var request = AnalysisGetHoverParams(testFile.path, offset).toRequest('0');
     var response = await handleSuccessfulRequest(request);
     var result = AnalysisGetHoverResult.fromResponse(response);
diff --git a/pkg/analysis_server/test/analysis/notification_analysis_options_test.dart b/pkg/analysis_server/test/analysis/notification_analysis_options_test.dart
index b82f567..f783d03 100644
--- a/pkg/analysis_server/test/analysis/notification_analysis_options_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_analysis_options_test.dart
@@ -6,13 +6,13 @@
 import 'package:analysis_server/protocol/protocol_constants.dart';
 import 'package:analysis_server/protocol/protocol_generated.dart'
     hide AnalysisOptions;
-import 'package:analysis_server/src/domain_analysis.dart';
+import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart';
 import 'package:linter/src/rules.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import '../analysis_abstract.dart';
+import '../analysis_server_base.dart';
 
 void main() {
   defineReflectiveSuite(() {
@@ -21,8 +21,9 @@
 }
 
 @reflectiveTest
-class AnalysisOptionsFileNotificationTest extends AbstractAnalysisTest {
-  Map<String, List<AnalysisError>> filesErrors = {};
+class AnalysisOptionsFileNotificationTest extends PubPackageAnalysisServerTest {
+  late File optionsFile;
+  Map<File, List<AnalysisError>> filesErrors = {};
 
   final testSource = '''
 main() {
@@ -33,40 +34,27 @@
 
   List<AnalysisError> get errors => filesErrors[testFile]!;
 
-  List<AnalysisError> get optionsFileErrors => filesErrors[optionsFilePath]!;
-
-  String get optionsFilePath => '$projectPath/analysis_options.yaml';
+  List<AnalysisError> get optionsFileErrors => filesErrors[optionsFile]!;
 
   List<AnalysisError> get testFileErrors => filesErrors[testFile]!;
 
   void addOptionsFile(String contents) {
-    newFile2(optionsFilePath, contents);
+    optionsFile = newAnalysisOptionsYamlFile2(testPackageRootPath, contents);
   }
 
   @override
   void processNotification(Notification notification) {
     if (notification.event == ANALYSIS_NOTIFICATION_ERRORS) {
       var decoded = AnalysisErrorsParams.fromNotification(notification);
-      filesErrors[decoded.file] = decoded.errors;
+      filesErrors[getFile(decoded.file)] = decoded.errors;
     }
   }
 
-  Future<void> setAnalysisRoot() async {
-    await setRoots(included: [projectPath], excluded: []);
-  }
-
   @override
-  void setUp() {
+  Future<void> setUp() async {
     registerLintRules();
     super.setUp();
-    server.handlers = [AnalysisDomainHandler(server)];
-  }
-
-  @override
-  void tearDown() {
-    filesErrors[optionsFilePath] = [];
-    filesErrors[testFile] = [];
-    super.tearDown();
+    await setRoots(included: [workspaceRootPath], excluded: []);
   }
 
   Future<void> test_error_filter() async {
@@ -82,8 +70,6 @@
 }
 ''');
 
-    await setAnalysisRoot();
-
     await waitForTasksFinished();
 
     // Verify options file.
@@ -109,8 +95,6 @@
 }
 ''');
 
-    await setAnalysisRoot();
-
     await waitForTasksFinished();
 
     // Verify options file.
@@ -148,7 +132,6 @@
 ''');
 
     addTestFile(testSource);
-    await setAnalysisRoot();
 
     await waitForTasksFinished();
 
@@ -174,7 +157,6 @@
 ''');
 
     addTestFile(testSource);
-    await setAnalysisRoot();
 
     await waitForTasksFinished();
 
@@ -186,15 +168,11 @@
 
   Future<void> test_options_file_added() async {
     addTestFile(testSource);
-    await setAnalysisRoot();
 
     await waitForTasksFinished();
 
     // Verify that lints are disabled.
-    expect(analysisOptions.lint, false);
-
-    // Clear errors.
-    filesErrors[testFile] = [];
+    expect(testFileAnalysisOptions.lint, false);
 
     // Add options file with a lint enabled.
     addOptionsFile('''
@@ -213,7 +191,6 @@
     addOptionsFile('''
 ; #bang
 ''');
-    await setAnalysisRoot();
 
     await waitForTasksFinished();
 
@@ -231,25 +208,21 @@
 ''');
 
     addTestFile(testSource);
-    await setAnalysisRoot();
 
     await waitForTasksFinished();
 
     verifyLintsEnabled(['camel_case_types']);
 
-    // Clear errors.
-    filesErrors[testFile] = [];
-
-    deleteFile(optionsFilePath);
+    deleteFile(optionsFile.path);
 
     await pumpEventQueue();
     await waitForTasksFinished();
 
-    expect(analysisOptions.lint, false);
+    expect(testFileAnalysisOptions.lint, false);
   }
 
   void verifyLintsEnabled(List<String> lints) {
-    var options = analysisOptions;
+    var options = testFileAnalysisOptions;
     expect(options.lint, true);
     var rules = options.lintRules.map((rule) => rule.name);
     expect(rules, unorderedEquals(lints));
diff --git a/pkg/analysis_server/test/analysis/notification_analyzed_files_test.dart b/pkg/analysis_server/test/analysis/notification_analyzed_files_test.dart
index e2fce2f..31ae228 100644
--- a/pkg/analysis_server/test/analysis/notification_analyzed_files_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_analyzed_files_test.dart
@@ -5,10 +5,11 @@
 import 'package:analysis_server/protocol/protocol.dart';
 import 'package:analysis_server/protocol/protocol_constants.dart';
 import 'package:analysis_server/protocol/protocol_generated.dart';
+import 'package:analyzer/file_system/file_system.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import '../analysis_abstract.dart';
+import '../analysis_server_base.dart';
 
 void main() {
   defineReflectiveSuite(() {
@@ -17,13 +18,14 @@
 }
 
 @reflectiveTest
-class AnalysisNotificationAnalyzedFilesTest extends AbstractAnalysisTest {
+class AnalysisNotificationAnalyzedFilesTest
+    extends PubPackageAnalysisServerTest {
   late List<String> analyzedFiles;
   bool analyzedFilesReceived = false;
 
-  void assertHasFile(String filePath) {
+  void assertHasFile(File file) {
     expect(analyzedFilesReceived, isTrue);
-    expect(analyzedFiles, contains(filePath));
+    expect(analyzedFiles, contains(file.path));
   }
 
   void assertHasNoFile(String filePath) {
@@ -32,7 +34,9 @@
   }
 
   Future<void> prepareAnalyzedFiles() async {
-    addGeneralAnalysisSubscription(GeneralAnalysisService.ANALYZED_FILES);
+    await addGeneralAnalysisSubscription(
+      GeneralAnalysisService.ANALYZED_FILES,
+    );
     await pumpEventQueue(times: 5000);
   }
 
@@ -48,7 +52,7 @@
   @override
   Future<void> setUp() async {
     super.setUp();
-    await createProject();
+    await setRoots(included: [workspaceRootPath], excluded: []);
   }
 
   Future<void> test_afterAnalysis() async {
@@ -69,8 +73,7 @@
   }
 
   Future<void> test_beforeAnalysis_excludeYamlFiles() async {
-    var yamlFile = getFolder(projectPath).getChildAssumingFile('sample.yaml');
-    yamlFile.writeAsStringSync('');
+    var yamlFile = newFile2('$testPackageRootPath/sample.yaml', '');
     addTestFile('''
 class A {}
 ''');
@@ -111,17 +114,19 @@
     // Making a change that *does* affect the set of reachable files should
     // trigger the notification to be re-sent.
     addTestFile('class A {}');
-    newFile2('/foo.dart', 'library foo;');
+    var foo = newFile2('/foo.dart', 'library foo;');
     await prepareAnalyzedFiles();
     expect(analyzedFilesReceived, isTrue);
 
     analyzedFilesReceived = false;
     modifyTestFile('import "${toUriStr('/foo.dart')}";');
     await prepareAnalyzedFiles();
-    assertHasFile(convertPath('/foo.dart'));
+    assertHasFile(foo);
   }
 
   void unsubscribeAnalyzedFiles() {
-    removeGeneralAnalysisSubscription(GeneralAnalysisService.ANALYZED_FILES);
+    removeGeneralAnalysisSubscription(
+      GeneralAnalysisService.ANALYZED_FILES,
+    );
   }
 }
diff --git a/pkg/analysis_server/test/analysis/notification_closing_labels_test.dart b/pkg/analysis_server/test/analysis/notification_closing_labels_test.dart
index 42537b1..df55415 100644
--- a/pkg/analysis_server/test/analysis/notification_closing_labels_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_closing_labels_test.dart
@@ -10,7 +10,7 @@
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import '../analysis_abstract.dart';
+import '../analysis_server_base.dart';
 
 void main() {
   defineReflectiveSuite(() {
@@ -19,7 +19,8 @@
 }
 
 @reflectiveTest
-class AnalysisNotificationClosingLabelsTest extends AbstractAnalysisTest {
+class AnalysisNotificationClosingLabelsTest
+    extends PubPackageAnalysisServerTest {
   static const sampleCode = '''
 Widget build(BuildContext context) {
   return /*1*/new Row(
@@ -44,7 +45,7 @@
   void processNotification(Notification notification) {
     if (notification.event == ANALYSIS_NOTIFICATION_CLOSING_LABELS) {
       var params = AnalysisClosingLabelsParams.fromNotification(notification);
-      if (params.file == testFile) {
+      if (params.file == testFile.path) {
         lastLabels = params.labels;
         _labelsReceived.complete(null);
       }
@@ -57,7 +58,7 @@
   @override
   Future<void> setUp() async {
     super.setUp();
-    await createProject();
+    await setRoots(included: [workspaceRootPath], excluded: []);
   }
 
   Future<void> subscribeForLabels() async {
diff --git a/pkg/analysis_server/test/analysis/notification_errors_test.dart b/pkg/analysis_server/test/analysis/notification_errors_test.dart
index ab0e04d..ba24eaa 100644
--- a/pkg/analysis_server/test/analysis/notification_errors_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_errors_test.dart
@@ -5,16 +5,16 @@
 import 'package:analysis_server/protocol/protocol.dart';
 import 'package:analysis_server/protocol/protocol_constants.dart';
 import 'package:analysis_server/protocol/protocol_generated.dart';
-import 'package:analysis_server/src/domain_analysis.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/lint/linter.dart';
 import 'package:analyzer/src/test_utilities/package_config_file_builder.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart';
 import 'package:linter/src/rules.dart';
+import 'package:path/path.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import '../analysis_abstract.dart';
+import '../analysis_server_base.dart';
 import '../src/utilities/mock_packages.dart';
 
 void main() {
@@ -24,19 +24,19 @@
 }
 
 @reflectiveTest
-class NotificationErrorsTest extends AbstractAnalysisTest {
+class NotificationErrorsTest extends PubPackageAnalysisServerTest {
   late Folder pedanticFolder;
-  Map<String, List<AnalysisError>?> filesErrors = {};
+  Map<File, List<AnalysisError>?> filesErrors = {};
 
   @override
   void processNotification(Notification notification) {
     if (notification.event == ANALYSIS_NOTIFICATION_ERRORS) {
       var decoded = AnalysisErrorsParams.fromNotification(notification);
-      filesErrors[decoded.file] = decoded.errors;
+      filesErrors[getFile(decoded.file)] = decoded.errors;
     } else if (notification.event == ANALYSIS_NOTIFICATION_FLUSH_RESULTS) {
       var decoded = AnalysisFlushResultsParams.fromNotification(notification);
       for (var file in decoded.files) {
-        filesErrors[file] = null;
+        filesErrors[getFile(file)] = null;
       }
     }
   }
@@ -46,55 +46,50 @@
     registerLintRules();
     super.setUp();
     server.pendingFilesRemoveOverlayDelay = const Duration(milliseconds: 10);
-    server.handlers = [
-      AnalysisDomainHandler(server),
-    ];
     pedanticFolder = MockPackages.instance.addPedantic(resourceProvider);
   }
 
   Future<void> test_analysisOptionsFile() async {
-    var filePath = join(projectPath, 'analysis_options.yaml');
-    var analysisOptionsFile = newFile2(filePath, '''
+    var analysisOptions = newAnalysisOptionsYamlFile2(testPackageRootPath, '''
 linter:
   rules:
     - invalid_lint_rule_name
-''').path;
+''');
 
-    await setRoots(included: [projectPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await waitForTasksFinished();
     await pumpEventQueue();
     //
     // Verify the error result.
     //
-    var errors = filesErrors[analysisOptionsFile]!;
+    var errors = filesErrors[analysisOptions]!;
     expect(errors, hasLength(1));
     var error = errors[0];
-    expect(error.location.file, filePath);
+    expect(error.location.file, analysisOptions.path);
     expect(error.severity, AnalysisErrorSeverity.WARNING);
     expect(error.type, AnalysisErrorType.STATIC_WARNING);
   }
 
   Future<void> test_analysisOptionsFile_packageInclude() async {
-    var filePath = join(projectPath, 'analysis_options.yaml');
-    var analysisOptionsFile = newFile2(filePath, '''
+    var analysisOptions = newAnalysisOptionsYamlFile2(testPackageRootPath, '''
 include: package:pedantic/analysis_options.yaml
-''').path;
+''');
 
-    await setRoots(included: [projectPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await waitForTasksFinished();
     await pumpEventQueue();
 
     // Verify there's an error for the import.
-    var errors = filesErrors[analysisOptionsFile]!;
+    var errors = filesErrors[analysisOptions]!;
     expect(errors, hasLength(1));
     var error = errors[0];
-    expect(error.location.file, filePath);
+    expect(error.location.file, analysisOptions.path);
     expect(error.severity, AnalysisErrorSeverity.WARNING);
     expect(error.type, AnalysisErrorType.STATIC_WARNING);
 
     // Write a package file that allows resolving the include.
     newPackageConfigJsonFile(
-      projectPath,
+      testPackageRootPath,
       (PackageConfigFileBuilder()
             ..add(name: 'pedantic', rootPath: pedanticFolder.parent.path))
           .toContent(toUriStr: toUriStr),
@@ -103,26 +98,27 @@
     // Ensure the errors disappear.
     await waitForTasksFinished();
     await pumpEventQueue();
-    errors = filesErrors[analysisOptionsFile]!;
+    errors = filesErrors[analysisOptions]!;
     expect(errors, hasLength(0));
   }
 
   Future<void> test_androidManifestFile() async {
-    var filePath = join(projectPath, 'android', 'AndroidManifest.xml');
-    var manifestFile = newFile2(filePath, '''
+    var manifestPath =
+        join(testPackageRootPath, 'android', 'AndroidManifest.xml');
+    var manifestFile = newFile2(manifestPath, '''
 <manifest
     xmlns:android="http://schemas.android.com/apk/res/android">
     <uses-feature android:name="android.hardware.touchscreen" android:required="false" />
     <uses-feature android:name="android.software.home_screen" />
 </manifest>
-''').path;
-    newAnalysisOptionsYamlFile2(projectPath, '''
+''');
+    newAnalysisOptionsYamlFile2(testPackageRootPath, '''
 analyzer:
   optional-checks:
     chrome-os-manifest-checks: true
 ''');
 
-    await setRoots(included: [projectPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await waitForTasksFinished();
     await pumpEventQueue();
     //
@@ -131,27 +127,28 @@
     var errors = filesErrors[manifestFile]!;
     expect(errors, hasLength(1));
     var error = errors[0];
-    expect(error.location.file, filePath);
+    expect(error.location.file, manifestFile.path);
     expect(error.severity, AnalysisErrorSeverity.WARNING);
     expect(error.type, AnalysisErrorType.STATIC_WARNING);
   }
 
   Future<void> test_androidManifestFile_dotDirectoryIgnored() async {
-    var filePath = join(projectPath, 'ios', '.symlinks', 'AndroidManifest.xml');
-    var manifestFile = newFile2(filePath, '''
+    var manifestPath =
+        join(testPackageRootPath, 'ios', '.symlinks', 'AndroidManifest.xml');
+    var manifestFile = newFile2(manifestPath, '''
 <manifest
     xmlns:android="http://schemas.android.com/apk/res/android">
     <uses-feature android:name="android.hardware.touchscreen" android:required="false" />
     <uses-feature android:name="android.software.home_screen" />
 </manifest>
 ''').path;
-    newAnalysisOptionsYamlFile2(projectPath, '''
+    newAnalysisOptionsYamlFile2(testPackageRootPath, '''
 analyzer:
   optional-checks:
     chrome-os-manifest-checks: true
 ''');
 
-    await setRoots(included: [projectPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await waitForTasksFinished();
     await pumpEventQueue();
     //
@@ -165,8 +162,9 @@
     // Although errors are not generated for dotfolders, their contents should
     // still be analyzed so that code that references them (for example
     // flutter_gen) should still be updated.
-    final configPath = join(projectPath, '.dart_tool/package_config.json');
-    final generatedProject = join(projectPath, '.dart_tool/foo');
+    final configPath =
+        join(testPackageRootPath, '.dart_tool/package_config.json');
+    final generatedProject = join(testPackageRootPath, '.dart_tool/foo');
     final generatedFile = join(generatedProject, 'lib', 'foo.dart');
 
     // Add the generated project into package_config.json.
@@ -181,7 +179,7 @@
 A? a;
     ''');
 
-    await createProject();
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await waitForTasksFinished();
     await pumpEventQueue(times: 5000);
     expect(filesErrors[testFile], isEmpty);
@@ -196,13 +194,12 @@
   }
 
   Future<void> test_dataFile() async {
-    var filePath = join(projectPath, 'lib', 'fix_data.yaml');
-    var dataFile = newFile2(filePath, '''
+    var dataFile = newFile2('$testPackageLibPath/fix_data.yaml', '''
 version: 1
 transforms:
-''').path;
+''');
 
-    await setRoots(included: [projectPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await waitForTasksFinished();
     await pumpEventQueue();
     //
@@ -211,7 +208,7 @@
     var errors = filesErrors[dataFile]!;
     expect(errors, hasLength(1));
     var error = errors[0];
-    expect(error.location.file, filePath);
+    expect(error.location.file, dataFile.path);
     expect(error.severity, AnalysisErrorSeverity.ERROR);
     expect(error.type, AnalysisErrorType.COMPILE_TIME_ERROR);
   }
@@ -220,10 +217,10 @@
     // Files inside dotFolders should not generate error notifications even
     // if they are added to priority (priority affects only priority, not what
     // is analyzed).
-    await createProject();
+    await setRoots(included: [workspaceRootPath], excluded: []);
     addTestFile('');
     var brokenFile =
-        newFile2(join(projectPath, '.dart_tool/broken.dart'), 'err').path;
+        newFile2(join(testPackageRootPath, '.dart_tool/broken.dart'), 'err');
 
     await waitForTasksFinished();
     await pumpEventQueue(times: 5000);
@@ -244,17 +241,19 @@
     // them to be opened (such as hovers) should not result in error notifications
     // because there is no event that would flush them and they'd remain in the
     // editor forever.
-    await createProject();
+    await setRoots(included: [workspaceRootPath], excluded: []);
     addTestFile('');
     var brokenFile =
-        newFile2(join(projectPath, '.dart_tool/broken.dart'), 'err').path;
+        newFile2('$testPackageRootPath/.dart_tool/broken.dart', 'err');
 
     await waitForTasksFinished();
     await pumpEventQueue(times: 5000);
     expect(filesErrors[brokenFile], isNull);
 
     // Send a getHover request for the file that will cause it to be read from disk.
-    await waitResponse(AnalysisGetHoverParams(brokenFile, 0).toRequest('0'));
+    await handleSuccessfulRequest(
+      AnalysisGetHoverParams(brokenFile.path, 0).toRequest('0'),
+    );
     await waitForTasksFinished();
     await pumpEventQueue(times: 5000);
 
@@ -263,14 +262,14 @@
   }
 
   Future<void> test_excludedFolder() async {
-    newAnalysisOptionsYamlFile2(projectPath, '''
+    newAnalysisOptionsYamlFile2(testPackageRootPath, '''
 analyzer:
   exclude:
     - excluded/**
 ''');
-    await createProject();
+    await setRoots(included: [workspaceRootPath], excluded: []);
     var excludedFile =
-        newFile2(join(projectPath, 'excluded/broken.dart'), 'err').path;
+        newFile2('$testPackageRootPath/excluded/broken.dart', 'err');
 
     // There should be no errors initially.
     await waitForTasksFinished();
@@ -278,21 +277,24 @@
     expect(filesErrors[excludedFile], isNull);
 
     // Triggering the file to be processed should still generate no errors.
-    await waitResponse(AnalysisGetHoverParams(excludedFile, 0).toRequest('0'));
+    await handleSuccessfulRequest(
+      AnalysisGetHoverParams(excludedFile.path, 0).toRequest('0'),
+    );
     await waitForTasksFinished();
     await pumpEventQueue(times: 5000);
     expect(filesErrors[excludedFile], isNull);
 
     // Opening the file should still generate no errors.
-    await waitResponse(
-        AnalysisSetPriorityFilesParams([excludedFile]).toRequest('0'));
+    await handleSuccessfulRequest(
+      AnalysisSetPriorityFilesParams([excludedFile.path]).toRequest('0'),
+    );
     await waitForTasksFinished();
     await pumpEventQueue(times: 5000);
     expect(filesErrors[excludedFile], isNull);
   }
 
   Future<void> test_importError() async {
-    await createProject();
+    await setRoots(included: [workspaceRootPath], excluded: []);
 
     addTestFile('''
 import 'does_not_exist.dart';
@@ -312,7 +314,7 @@
   Future<void> test_lintError() async {
     var camelCaseTypesLintName = 'camel_case_types';
 
-    newAnalysisOptionsYamlFile2(projectPath, '''
+    newAnalysisOptionsYamlFile2(testPackageRootPath, '''
 linter:
   rules:
     - $camelCaseTypesLintName
@@ -320,11 +322,10 @@
 
     addTestFile('class a { }');
 
-    await setRoots(included: [projectPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await waitForTasksFinished();
 
-    var testDriver = server.getAnalysisDriver(testFile)!;
-    var lints = testDriver.analysisOptions.lintRules;
+    var lints = testFileAnalysisOptions.lintRules;
 
     // Registry should only contain single lint rule.
     expect(lints, hasLength(1));
@@ -335,15 +336,15 @@
     var errors = filesErrors[testFile]!;
     expect(errors, hasLength(1));
     var error = errors[0];
-    expect(error.location.file, join(projectPath, 'bin', 'test.dart'));
+    expect(error.location.file, testFile.path);
     expect(error.severity, AnalysisErrorSeverity.INFO);
     expect(error.type, AnalysisErrorType.LINT);
     expect(error.message, lint.description);
   }
 
   Future<void> test_notInAnalysisRoot() async {
-    await createProject();
-    var otherFile = newFile2('/other.dart', 'UnknownType V;').path;
+    await setRoots(included: [workspaceRootPath], excluded: []);
+    var otherFile = newFile2('/other.dart', 'UnknownType V;');
     addTestFile('''
 import '/other.dart';
 main() {
@@ -357,10 +358,10 @@
   Future<void> test_overlay_dotFolder() async {
     // Files inside dotFolders should not generate error notifications even
     // if they have overlays added.
-    await createProject();
+    await setRoots(included: [workspaceRootPath], excluded: []);
     addTestFile('');
     var brokenFile =
-        newFile2(join(projectPath, '.dart_tool/broken.dart'), 'err').path;
+        newFile2('$testPackageRootPath/.dart_tool/broken.dart', 'err');
 
     await waitForTasksFinished();
     await pumpEventQueue(times: 5000);
@@ -368,9 +369,9 @@
 
     // Add and overlay and give chance for the file to be analyzed (if
     // it would).
-    await waitResponse(
+    await handleSuccessfulRequest(
       AnalysisUpdateContentParams({
-        brokenFile: AddContentOverlay('err'),
+        brokenFile.path: AddContentOverlay('err'),
       }).toRequest('1'),
     );
     await waitForTasksFinished();
@@ -384,14 +385,14 @@
     // Overlays added for files that don't exist on disk should still generate
     // error notifications. Removing the overlay if the file is not on disk
     // should clear the errors.
-    await createProject();
+    await setRoots(included: [workspaceRootPath], excluded: []);
     addTestFile('');
-    var brokenFile = convertPath(join(projectPath, 'broken.dart'));
+    var brokenFile = getFile('$testPackageRootPath/broken.dart');
 
     // Add and overlay and give chance for the file to be analyzed.
-    await waitResponse(
+    await handleSuccessfulRequest(
       AnalysisUpdateContentParams({
-        brokenFile: AddContentOverlay('err'),
+        brokenFile.path: AddContentOverlay('err'),
       }).toRequest('0'),
     );
     await waitForTasksFinished();
@@ -401,9 +402,9 @@
     expect(filesErrors[brokenFile], hasLength(greaterThan(0)));
 
     // Remove the overlay (this file no longer exists anywhere).
-    await waitResponse(
+    await handleSuccessfulRequest(
       AnalysisUpdateContentParams({
-        brokenFile: RemoveContentOverlay(),
+        brokenFile.path: RemoveContentOverlay(),
       }).toRequest('1'),
     );
 
@@ -424,14 +425,14 @@
     // error notifications. If the file is subsequently saved to disk before the
     // overlay is removed, the errors should not be flushed when the overlay is
     // removed.
-    await createProject();
+    await setRoots(included: [workspaceRootPath], excluded: []);
     addTestFile('');
-    var brokenFile = convertPath(join(projectPath, 'broken.dart'));
+    var brokenFile = getFile('$testPackageRootPath/broken.dart');
 
     // Add and overlay and give chance for the file to be analyzed.
-    await waitResponse(
+    await handleSuccessfulRequest(
       AnalysisUpdateContentParams({
-        brokenFile: AddContentOverlay('err'),
+        brokenFile.path: AddContentOverlay('err'),
       }).toRequest('0'),
     );
     await waitForTasksFinished();
@@ -441,14 +442,14 @@
     expect(filesErrors[brokenFile], hasLength(greaterThan(0)));
 
     // Write the file to disk.
-    newFile2(brokenFile, 'err');
+    brokenFile.writeAsStringSync('err');
     await waitForTasksFinished();
     await pumpEventQueue(times: 5000);
 
     // Remove the overlay.
-    await waitResponse(
+    await handleSuccessfulRequest(
       AnalysisUpdateContentParams({
-        brokenFile: RemoveContentOverlay(),
+        brokenFile.path: RemoveContentOverlay(),
       }).toRequest('1'),
     );
     await waitForTasksFinished();
@@ -460,14 +461,14 @@
   }
 
   Future<void> test_ParserError() async {
-    await createProject();
+    await setRoots(included: [workspaceRootPath], excluded: []);
     addTestFile('library lib');
     await waitForTasksFinished();
     await pumpEventQueue(times: 5000);
     var errors = filesErrors[testFile]!;
     expect(errors, hasLength(1));
     var error = errors[0];
-    expect(error.location.file, join(projectPath, 'bin', 'test.dart'));
+    expect(error.location.file, testFile.path);
     expect(error.location.offset, isPositive);
     expect(error.location.length, isNonNegative);
     expect(error.severity, AnalysisErrorSeverity.ERROR);
@@ -476,11 +477,11 @@
   }
 
   Future<void> test_pubspecFile() async {
-    var pubspecFile = newPubspecYamlFile(projectPath, '''
+    var pubspecFile = newPubspecYamlFile(testPackageRootPath, '''
 version: 1.3.2
-''').path;
+''');
 
-    await setRoots(included: [projectPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await waitForTasksFinished();
     await pumpEventQueue();
     //
@@ -489,13 +490,13 @@
     var errors = filesErrors[pubspecFile]!;
     expect(errors, hasLength(1));
     var error = errors[0];
-    expect(error.location.file, pubspecFile);
+    expect(error.location.file, pubspecFile.path);
     expect(error.severity, AnalysisErrorSeverity.WARNING);
     expect(error.type, AnalysisErrorType.STATIC_WARNING);
     //
     // Fix the error and verify the new results.
     //
-    modifyFile(pubspecFile, '''
+    pubspecFile.writeAsStringSync('''
 name: sample
 version: 1.3.2
 ''');
@@ -507,21 +508,21 @@
   }
 
   Future<void> test_pubspecFile_lint() async {
-    newAnalysisOptionsYamlFile2(projectPath, '''
+    newAnalysisOptionsYamlFile2(testPackageRootPath, '''
 linter:
   rules:
     - sort_pub_dependencies
 ''');
 
-    var pubspecFile = newPubspecYamlFile(projectPath, '''
+    var pubspecFile = newPubspecYamlFile(testPackageRootPath, '''
 name: sample
 
 dependencies:
   b: any
   a: any
-''').path;
+''');
 
-    await setRoots(included: [projectPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await waitForTasksFinished();
     await pumpEventQueue();
     //
@@ -530,13 +531,13 @@
     var errors = filesErrors[pubspecFile]!;
     expect(errors, hasLength(1));
     var error = errors[0];
-    expect(error.location.file, pubspecFile);
+    expect(error.location.file, pubspecFile.path);
     expect(error.severity, AnalysisErrorSeverity.INFO);
     expect(error.type, AnalysisErrorType.LINT);
     //
     // Fix the error and verify the new results.
     //
-    modifyFile(pubspecFile, '''
+    pubspecFile.writeAsStringSync('''
 name: sample
 
 dependencies:
@@ -551,7 +552,7 @@
   }
 
   Future<void> test_StaticWarning() async {
-    await createProject();
+    await setRoots(included: [workspaceRootPath], excluded: []);
     addTestFile('''
 enum E {e1, e2}
 
diff --git a/pkg/analysis_server/test/analysis/notification_folding_test.dart b/pkg/analysis_server/test/analysis/notification_folding_test.dart
index add62cf..7cbda58 100644
--- a/pkg/analysis_server/test/analysis/notification_folding_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_folding_test.dart
@@ -9,7 +9,7 @@
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import '../analysis_abstract.dart';
+import '../analysis_server_base.dart';
 
 void main() {
   defineReflectiveSuite(() {
@@ -18,7 +18,7 @@
 }
 
 @reflectiveTest
-class AnalysisNotificationFoldingTest extends AbstractAnalysisTest {
+class AnalysisNotificationFoldingTest extends PubPackageAnalysisServerTest {
   static const sampleCode = '''
 import 'dart:async';
 import 'dart:core';
@@ -40,7 +40,7 @@
   void processNotification(Notification notification) {
     if (notification.event == ANALYSIS_NOTIFICATION_FOLDING) {
       var params = AnalysisFoldingParams.fromNotification(notification);
-      if (params.file == testFile) {
+      if (params.file == testFile.path) {
         lastRegions = params.regions;
         _regionsReceived.complete(null);
       }
@@ -53,7 +53,7 @@
   @override
   Future<void> setUp() async {
     super.setUp();
-    await createProject();
+    await setRoots(included: [workspaceRootPath], excluded: []);
   }
 
   Future<void> subscribeForFolding() async {
diff --git a/pkg/analysis_server/test/analysis/notification_highlights2_test.dart b/pkg/analysis_server/test/analysis/notification_highlights2_test.dart
index 6b6ebd6..2e70411 100644
--- a/pkg/analysis_server/test/analysis/notification_highlights2_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_highlights2_test.dart
@@ -11,7 +11,7 @@
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import '../analysis_abstract.dart';
+import '../analysis_server_base.dart';
 
 void main() {
   defineReflectiveSuite(() {
@@ -1593,7 +1593,7 @@
   }
 }
 
-class HighlightsTestSupport extends AbstractAnalysisTest {
+class HighlightsTestSupport extends PubPackageAnalysisServerTest {
   late List<HighlightRegion> regions;
 
   final Completer<void> _resultsAvailable = Completer();
@@ -1676,7 +1676,7 @@
     }
     if (notification.event == ANALYSIS_NOTIFICATION_HIGHLIGHTS) {
       var params = AnalysisHighlightsParams.fromNotification(notification);
-      if (params.file == testFile) {
+      if (params.file == testFile.path) {
         regions = params.regions;
         _resultsAvailable.complete();
       }
@@ -1686,11 +1686,11 @@
   @override
   Future<void> setUp() async {
     super.setUp();
-    await createProject();
+    await setRoots(included: [workspaceRootPath], excluded: []);
   }
 
   void _addLibraryForTestPart() {
-    newFile2(join(testFolder, 'my_lib.dart'), '''
+    newFile2('$testPackageLibPath/my_lib.dart', '''
 library lib;
 part 'test.dart';
     ''');
diff --git a/pkg/analysis_server/test/analysis/notification_implemented_test.dart b/pkg/analysis_server/test/analysis/notification_implemented_test.dart
index 0544f28..1b978de 100644
--- a/pkg/analysis_server/test/analysis/notification_implemented_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_implemented_test.dart
@@ -5,11 +5,11 @@
 import 'package:analysis_server/protocol/protocol.dart';
 import 'package:analysis_server/protocol/protocol_constants.dart';
 import 'package:analysis_server/protocol/protocol_generated.dart';
-import 'package:analyzer_plugin/protocol/protocol_common.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../analysis_abstract.dart';
+import '../analysis_server_base.dart';
 
 void main() {
   defineReflectiveSuite(() {
@@ -18,7 +18,7 @@
 }
 
 @reflectiveTest
-class AnalysisNotificationImplementedTest extends AbstractAnalysisTest {
+class AnalysisNotificationImplementedTest extends PubPackageAnalysisServerTest {
   List<ImplementedClass>? implementedClasses;
   List<ImplementedMember>? implementedMembers;
 
@@ -94,7 +94,7 @@
   void processNotification(Notification notification) {
     if (notification.event == ANALYSIS_NOTIFICATION_IMPLEMENTED) {
       var params = AnalysisImplementedParams.fromNotification(notification);
-      if (params.file == testFile) {
+      if (params.file == testFile.path) {
         implementedClasses = params.classes;
         implementedMembers = params.members;
       }
@@ -104,7 +104,7 @@
   @override
   Future<void> setUp() async {
     super.setUp();
-    await createProject();
+    await setRoots(included: [workspaceRootPath], excluded: []);
   }
 
   Future<void> subscribeForImplemented() async {
@@ -122,25 +122,6 @@
     assertHasImplementedClass('A {');
   }
 
-  Future<void> test_afterIncrementalResolution() async {
-    await subscribeForImplemented();
-    addTestFile('''
-class A {}
-class B extends A {}
-''');
-    await prepareImplementedElements();
-    assertHasImplementedClass('A {');
-    // add a space
-    implementedClasses = null;
-    testCode = '''
-class A  {}
-class B extends A {}
-''';
-    server.updateContent('1', {testFile: AddContentOverlay(testCode)});
-    await waitForImplementedElements();
-    assertHasImplementedClass('A  {');
-  }
-
   Future<void> test_class_extended() async {
     addTestFile('''
 class A {}
@@ -365,7 +346,7 @@
   }
 
   Future<void> test_method_withMethod_private_differentLib() async {
-    newFile2(join(testFolder, 'lib.dart'), r'''
+    newFile2('$testPackageLibPath/lib.dart', r'''
 import 'test.dart';
 class B extends A {
   void _m() {}
diff --git a/pkg/analysis_server/test/analysis/notification_navigation_test.dart b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
index e869127..b657168 100644
--- a/pkg/analysis_server/test/analysis/notification_navigation_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
@@ -214,7 +214,7 @@
 class AAA {}
 AAA aaa;
 ''');
-    await server.onAnalysisComplete;
+    await waitForTasksFinished();
     await prepareNavigation();
     assertHasRegionTarget('AAA aaa;', 'AAA {}');
   }
diff --git a/pkg/analysis_server/test/analysis/notification_occurrences_test.dart b/pkg/analysis_server/test/analysis/notification_occurrences_test.dart
index ca7d1e2..8880291 100644
--- a/pkg/analysis_server/test/analysis/notification_occurrences_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_occurrences_test.dart
@@ -12,6 +12,7 @@
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../analysis_abstract.dart';
+import '../analysis_server_base.dart';
 
 void main() {
   defineReflectiveSuite(() {
@@ -20,7 +21,7 @@
 }
 
 @reflectiveTest
-class AnalysisNotificationOccurrencesTest extends AbstractAnalysisTest {
+class AnalysisNotificationOccurrencesTest extends PubPackageAnalysisServerTest {
   late List<Occurrences> occurrencesList;
   late Occurrences testOccurrences;
 
@@ -80,7 +81,7 @@
   void processNotification(Notification notification) {
     if (notification.event == ANALYSIS_NOTIFICATION_OCCURRENCES) {
       var params = AnalysisOccurrencesParams.fromNotification(notification);
-      if (params.file == testFile) {
+      if (params.file == testFile.path) {
         occurrencesList = params.occurrences;
         _resultsAvailable.complete();
       }
@@ -90,7 +91,7 @@
   @override
   Future<void> setUp() async {
     super.setUp();
-    await createProject();
+    await setRoots(included: [workspaceRootPath], excluded: []);
   }
 
   Future<void> test_afterAnalysis() async {
diff --git a/pkg/analysis_server/test/analysis/notification_outline_test.dart b/pkg/analysis_server/test/analysis/notification_outline_test.dart
index 14dc697..262673b 100644
--- a/pkg/analysis_server/test/analysis/notification_outline_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_outline_test.dart
@@ -11,7 +11,7 @@
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import '../analysis_abstract.dart';
+import '../analysis_server_base.dart';
 
 void main() {
   defineReflectiveSuite(() {
@@ -20,7 +20,7 @@
 }
 
 @reflectiveTest
-class AnalysisNotificationOutlineTest extends AbstractAnalysisTest {
+class AnalysisNotificationOutlineTest extends PubPackageAnalysisServerTest {
   late FileKind fileKind;
   String? libraryName;
   Outline? outline;
@@ -37,7 +37,7 @@
   void processNotification(Notification notification) {
     if (notification.event == ANALYSIS_NOTIFICATION_OUTLINE) {
       var params = AnalysisOutlineParams.fromNotification(notification);
-      if (params.file == testFile) {
+      if (params.file == testFile.path) {
         fileKind = params.kind;
         libraryName = params.libraryName;
         outline = params.outline;
@@ -46,7 +46,7 @@
     }
     if (notification.event == ANALYSIS_NOTIFICATION_HIGHLIGHTS) {
       var params = AnalysisHighlightsParams.fromNotification(notification);
-      if (params.file == testFile) {
+      if (params.file == testFile.path) {
         _highlightsReceived?.complete(null);
         _highlightsReceived = null;
       }
@@ -56,7 +56,7 @@
   @override
   Future<void> setUp() async {
     super.setUp();
-    await createProject();
+    await setRoots(included: [workspaceRootPath], excluded: []);
   }
 
   Future<void> test_afterAnalysis() async {
diff --git a/pkg/analysis_server/test/analysis/notification_overrides_test.dart b/pkg/analysis_server/test/analysis/notification_overrides_test.dart
index 77b9230..ac0e7c8 100644
--- a/pkg/analysis_server/test/analysis/notification_overrides_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_overrides_test.dart
@@ -11,6 +11,7 @@
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../analysis_abstract.dart';
+import '../analysis_server_base.dart';
 
 void main() {
   defineReflectiveSuite(() {
@@ -19,7 +20,7 @@
 }
 
 @reflectiveTest
-class AnalysisNotificationOverridesTest extends AbstractAnalysisTest {
+class AnalysisNotificationOverridesTest extends PubPackageAnalysisServerTest {
   late List<Override> overridesList;
   late Override overrideObject;
 
@@ -113,7 +114,7 @@
   void processNotification(Notification notification) {
     if (notification.event == ANALYSIS_NOTIFICATION_OVERRIDES) {
       var params = AnalysisOverridesParams.fromNotification(notification);
-      if (params.file == testFile) {
+      if (params.file == testFile.path) {
         overridesList = params.overrides;
         _resultsAvailable.complete();
       }
@@ -123,7 +124,7 @@
   @override
   Future<void> setUp() async {
     super.setUp();
-    await createProject();
+    await setRoots(included: [workspaceRootPath], excluded: []);
   }
 
   Future<void> test_afterAnalysis() async {
@@ -221,7 +222,7 @@
   }
 
   Future<void> test_class_BAD_privateByPrivate_inDifferentLib() async {
-    newFile2(join(testFolder, 'lib.dart'), r'''
+    newFile2('$testPackageLibPath/lib.dart', r'''
 class A {
   void _m() {}
 }
diff --git a/pkg/analysis_server/test/analysis/reanalyze_test.dart b/pkg/analysis_server/test/analysis/reanalyze_test.dart
index 84aea11..d460e3e 100644
--- a/pkg/analysis_server/test/analysis/reanalyze_test.dart
+++ b/pkg/analysis_server/test/analysis/reanalyze_test.dart
@@ -5,11 +5,12 @@
 import 'package:analysis_server/protocol/protocol.dart';
 import 'package:analysis_server/protocol/protocol_constants.dart';
 import 'package:analysis_server/protocol/protocol_generated.dart';
+import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import '../analysis_abstract.dart';
+import '../analysis_server_base.dart';
 
 void main() {
   defineReflectiveSuite(() {
@@ -18,42 +19,45 @@
 }
 
 @reflectiveTest
-class ReanalyzeTest extends AbstractAnalysisTest {
-  Map<String, List<AnalysisError>> filesErrors = {};
+class ReanalyzeTest extends PubPackageAnalysisServerTest {
+  Map<File, List<AnalysisError>> filesErrors = {};
 
   @override
   void processNotification(Notification notification) {
     if (notification.event == ANALYSIS_NOTIFICATION_ERRORS) {
       var decoded = AnalysisErrorsParams.fromNotification(notification);
-      filesErrors[decoded.file] = decoded.errors;
+      filesErrors[getFile(decoded.file)] = decoded.errors;
     }
   }
 
   Future<void> test_reanalyze() async {
-    var b = convertPath('/other/b.dart');
+    var b = getFolder(testPackageLibPath).parent.getChildAssumingFile('b.dart');
 
-    newFile2(testFile, r'''
-import '../../other/b.dart';
+    var file = newFile2('$testPackageTestPath/a.dart', r'''
+import '../b.dart';
 
 var b = B();
 ''');
-    await createProject();
+
+    await setRoots(included: [testPackageTestPath], excluded: []);
 
     // b.dart does not exist, and `B` is unresolved.
     await waitForTasksFinished();
-    expect(filesErrors[testFile], hasLength(2));
+    expect(filesErrors[file], hasLength(2));
 
     // Clear errors, so that we'll notice new results.
     filesErrors.clear();
 
     // Create b.dart, reanalyzing should fix the error.
-    newFile2(b, 'class B {}');
+    b.writeAsStringSync('class B {}');
 
     // Reanalyze.
-    await server.reanalyze();
+    await handleSuccessfulRequest(
+      AnalysisReanalyzeParams().toRequest('0'),
+    );
     await waitForTasksFinished();
 
     // No errors.
-    expect(filesErrors[testFile], isEmpty);
+    expect(filesErrors[file], isEmpty);
   }
 }
diff --git a/pkg/analysis_server/test/analysis/set_priority_files_test.dart b/pkg/analysis_server/test/analysis/set_priority_files_test.dart
index 16b93d0..47b2f68 100644
--- a/pkg/analysis_server/test/analysis/set_priority_files_test.dart
+++ b/pkg/analysis_server/test/analysis/set_priority_files_test.dart
@@ -4,12 +4,11 @@
 
 import 'package:analysis_server/protocol/protocol.dart';
 import 'package:analysis_server/protocol/protocol_generated.dart';
-import 'package:analysis_server/src/domain_analysis.dart';
-import 'package:analyzer/src/util/file_paths.dart' as file_paths;
+import 'package:analyzer/file_system/file_system.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import '../analysis_abstract.dart';
+import '../analysis_server_base.dart';
 import '../mocks.dart';
 
 void main() {
@@ -19,18 +18,15 @@
 }
 
 @reflectiveTest
-class SetPriorityFilesTest extends AbstractAnalysisTest {
+class SetPriorityFilesTest extends PubPackageAnalysisServerTest {
   @override
   Future<void> setUp() async {
     super.setUp();
-    server.handlers = [
-      AnalysisDomainHandler(server),
-    ];
-    await createProject();
+    await setRoots(included: [workspaceRootPath], excluded: []);
   }
 
   Future<void> test_fileDoesNotExist() async {
-    var file = convertPath('$projectPath/doesNotExist.dart');
+    var file = getFile('$testPackageLibPath/doesNotExist.dart');
     var response = await _setPriorityFile(file);
     expect(response, isResponseSuccess('0'));
   }
@@ -45,90 +41,98 @@
   }
 
   Future<void> test_fileInAnalysisRootAddedLater() async {
-    var path = convertPath('/other/file.dart');
-    newFile2(path, '');
-    await _setPriorityFile(path);
-    await _setAnalysisRoots('/other');
-    _verifyPriorityFiles(path);
+    var file = newFile2('/other/file.dart', '');
+    await _setPriorityFile(file);
+    await setRoots(included: [file.parent.path], excluded: []);
+    _verifyPriorityFiles(file);
   }
 
   Future<void> test_fileInSdk() async {
     addTestFile('');
     // set priority files
-    var filePath = convertPath('/lib/convert/convert.dart');
-    var response = await _setPriorityFile(filePath);
+    var file = sdkRoot
+        .getChildAssumingFolder('lib')
+        .getChildAssumingFolder('convert')
+        .getChildAssumingFile('convert.dart');
+    var response = await _setPriorityFile(file);
     expect(response, isResponseSuccess('0'));
     // verify
-    _verifyPriorityFiles(filePath);
+    _verifyPriorityFiles(file);
   }
 
   Future<void> test_fileNotInAnalysisRoot() async {
-    var path = convertPath('/other/file.dart');
-    newFile2(path, '');
-    await _setPriorityFile(path);
-    _verifyPriorityFiles(path);
+    var file = newFile2('/other/file.dart', '');
+    await _setPriorityFile(file);
+    _verifyPriorityFiles(file);
   }
 
   Future<void> test_ignoredInAnalysisOptions() async {
-    var sampleFile = convertPath('$projectPath/samples/sample.dart');
-    newFile2('$projectPath/${file_paths.analysisOptionsYaml}', r'''
+    newAnalysisOptionsYamlFile2(testPackageRootPath, r'''
 analyzer:
   exclude:
     - 'samples/**'
 ''');
-    newFile2(sampleFile, '');
+    var file = newFile2('$testPackageRootPath/samples/sample.dart', '');
     // attempt to set priority file
-    await _setPriorityFile(sampleFile);
-    _verifyPriorityFiles(sampleFile);
+    await _setPriorityFile(file);
+    _verifyPriorityFiles(file);
   }
 
   Future<void> test_ignoredInAnalysisOptions_inChildContext() async {
-    newPackageConfigJsonFile(projectPath, '');
-    newPackageConfigJsonFile('$projectPath/child', '');
-    var sampleFile = convertPath('$projectPath/child/samples/sample.dart');
-    newFile2('$projectPath/child/${file_paths.analysisOptionsYaml}', r'''
+    newPackageConfigJsonFile(testPackageRootPath, '');
+    newPackageConfigJsonFile('$testPackageRootPath/child', '');
+    var sampleFile = newFile2(
+      '$testPackageRootPath/child/samples/sample.dart',
+      '',
+    );
+    newAnalysisOptionsYamlFile2(testPackageRootPath, r'''
 analyzer:
   exclude:
     - 'samples/**'
 ''');
-    newFile2(sampleFile, '');
     // attempt to set priority file
     await _setPriorityFile(sampleFile);
     _verifyPriorityFiles(sampleFile);
   }
 
   Future<void> test_ignoredInAnalysisOptions_inRootContext() async {
-    newPackageConfigJsonFile(projectPath, '');
-    newPackageConfigJsonFile('$projectPath/child', '');
-    var sampleFile = convertPath('$projectPath/child/samples/sample.dart');
-    newFile2('$projectPath/${file_paths.analysisOptionsYaml}', r'''
+    newPackageConfigJsonFile(testPackageRootPath, '');
+    newPackageConfigJsonFile('$testPackageRootPath/child', '');
+    var sampleFile = newFile2(
+      '$testPackageRootPath/child/samples/sample.dart',
+      '',
+    );
+    newAnalysisOptionsYamlFile2(testPackageRootPath, r'''
 analyzer:
   exclude:
     - 'child/samples/**'
 ''');
-    newFile2(sampleFile, '');
     // attempt to set priority file
     await _setPriorityFile(sampleFile);
     _verifyPriorityFiles(sampleFile);
   }
 
   Future<void> test_invalidFilePathFormat_notAbsolute() async {
-    var request = AnalysisSetPriorityFilesParams(['test.dart']).toRequest('0');
-    var response = await waitResponse(request);
-    expect(
+    var response = await handleRequest(
+      AnalysisSetPriorityFilesParams([
+        'test.dart',
+      ]).toRequest('0'),
+    );
+    assertResponseFailure(
       response,
-      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+      requestId: '0',
+      errorCode: RequestErrorCode.INVALID_FILE_PATH_FORMAT,
     );
   }
 
   Future<void> test_invalidFilePathFormat_notNormalized() async {
-    var request =
-        AnalysisSetPriorityFilesParams([convertPath('/foo/../bar/test.dart')])
-            .toRequest('0');
-    var response = await waitResponse(request);
-    expect(
+    var response = await handleRequest(AnalysisSetPriorityFilesParams([
+      convertPath('/foo/../bar/test.dart'),
+    ]).toRequest('0'));
+    assertResponseFailure(
       response,
-      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+      requestId: '0',
+      errorCode: RequestErrorCode.INVALID_FILE_PATH_FORMAT,
     );
   }
 
@@ -139,22 +143,20 @@
     expect(response, isResponseSuccess('0'));
     // verify
     var params = pluginManager.analysisSetPriorityFilesParams!;
-    expect(params.files, <String>[testFile]);
+    expect(params.files, [testFile.path]);
   }
 
-  Future<Response> _setAnalysisRoots(String folder) async {
-    var request = AnalysisSetAnalysisRootsParams([folder], []).toRequest('1');
-    return await serverChannel.sendRequest(request);
+  Future<Response> _setPriorityFile(File file) async {
+    return await handleSuccessfulRequest(
+      AnalysisSetPriorityFilesParams(<String>[
+        file.path,
+      ]).toRequest('0'),
+    );
   }
 
-  Future<Response> _setPriorityFile(String file) async {
-    var request = AnalysisSetPriorityFilesParams(<String>[file]).toRequest('0');
-    return await serverChannel.sendRequest(request);
-  }
-
-  void _verifyPriorityFiles(String path) {
-    var driver = server.getAnalysisDriver(path)!;
+  void _verifyPriorityFiles(File file) {
+    var driver = server.getAnalysisDriver(file.path)!;
     var prioritySources = driver.priorityFiles;
-    expect(prioritySources, [path]);
+    expect(prioritySources, [file.path]);
   }
 }
diff --git a/pkg/analysis_server/test/analysis/update_content_test.dart b/pkg/analysis_server/test/analysis/update_content_test.dart
index b5213d9..853eebb 100644
--- a/pkg/analysis_server/test/analysis/update_content_test.dart
+++ b/pkg/analysis_server/test/analysis/update_content_test.dart
@@ -5,13 +5,14 @@
 import 'package:analysis_server/protocol/protocol.dart';
 import 'package:analysis_server/protocol/protocol_constants.dart';
 import 'package:analysis_server/protocol/protocol_generated.dart';
-import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import '../analysis_abstract.dart';
+import '../analysis_server_base.dart';
 import '../mocks.dart';
+import '../services/refactoring/abstract_rename.dart';
 
 void main() {
   defineReflectiveSuite(() {
@@ -20,8 +21,8 @@
 }
 
 @reflectiveTest
-class UpdateContentTest extends AbstractAnalysisTest {
-  Map<String, List<String>> filesErrors = {};
+class UpdateContentTest extends PubPackageAnalysisServerTest {
+  Map<File, List<String>> filesErrors = {};
   int serverErrorCount = 0;
   int navigationCount = 0;
 
@@ -31,7 +32,7 @@
       var decoded = AnalysisErrorsParams.fromNotification(notification);
       String _format(AnalysisError e) =>
           '${e.location.startLine}: ${e.message}';
-      filesErrors[decoded.file] = decoded.errors.map(_format).toList();
+      filesErrors[getFile(decoded.file)] = decoded.errors.map(_format).toList();
     }
     if (notification.event == ANALYSIS_NOTIFICATION_NAVIGATION) {
       navigationCount++;
@@ -44,25 +45,28 @@
   void test_illegal_ChangeContentOverlay() async {
     // It should be illegal to send a ChangeContentOverlay for a file that
     // doesn't have an overlay yet.
-    await createProject();
-    addTestFile('library foo;');
-    var id = 'myId';
-    try {
-      server.updateContent(id, {
-        testFile: ChangeContentOverlay([SourceEdit(8, 3, 'bar')])
-      });
-      fail('Expected an exception to be thrown');
-    } on RequestFailure catch (e) {
-      expect(e.response.id, id);
-      expect(e.response.error!.code, RequestErrorCode.INVALID_OVERLAY_CHANGE);
-    }
+    addTestFile('');
+    await setRoots(included: [workspaceRootPath], excluded: []);
+    var response = await handleRequest(
+      AnalysisUpdateContentParams({
+        testFile.path: ChangeContentOverlay([
+          SourceEdit(0, 0, ''),
+        ]),
+      }).toRequest('0'),
+    );
+    assertResponseFailure(
+      response,
+      requestId: '0',
+      errorCode: RequestErrorCode.INVALID_OVERLAY_CHANGE,
+    );
   }
 
   Future<void> test_invalidFilePathFormat_notAbsolute() async {
-    var request = AnalysisUpdateContentParams(
-      {'test.dart': AddContentOverlay('')},
-    ).toRequest('0');
-    var response = await waitResponse(request);
+    var response = await handleRequest(
+      AnalysisUpdateContentParams({
+        'test.dart': AddContentOverlay(''),
+      }).toRequest('0'),
+    );
     expect(
       response,
       isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
@@ -70,10 +74,11 @@
   }
 
   Future<void> test_invalidFilePathFormat_notNormalized() async {
-    var request = AnalysisUpdateContentParams(
-      {convertPath('/foo/../bar/test.dart'): AddContentOverlay('')},
-    ).toRequest('0');
-    var response = await waitResponse(request);
+    var response = await handleRequest(
+      AnalysisUpdateContentParams({
+        convertPath('/foo/../bar/test.dart'): AddContentOverlay(''),
+      }).toRequest('0'),
+    );
     expect(
       response,
       isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
@@ -81,41 +86,54 @@
   }
 
   Future<void> test_multiple_contexts() async {
-    var project1path = convertPath('/project1');
-    var project2path = convertPath('/project2');
-    var fooPath = newFile2('/project1/foo.dart', '''
-library foo;
-import '../project2/baz.dart';
-main() { f(); }''').path;
-    var barPath = newFile2('/project2/bar.dart', '''
-library bar;
-import 'baz.dart';
-main() { f(); }''').path;
-    var bazPath = newFile2('/project2/baz.dart', '''
-library baz;
-f(int i) {}
-''').path;
-    await setRoots(included: [project1path, project2path], excluded: []);
+    writePackageConfig(
+      getFolder(workspaceRootPath),
+      PackageConfigFileBuilder()
+        ..add(name: 'aaa', rootPath: '$workspaceRootPath/aaa'),
+    );
+
+    var aaa = newFile2('$workspaceRootPath/aaa/lib/aaa.dart', r'''
+void f(int _) {}
+''');
+
+    var foo = newFile2('$workspaceRootPath/foo/lib/foo.dart', r'''
+import 'package:aaa/aaa.dart';
+void main() {
+  f();
+}
+''');
+
+    var bar = newFile2('$workspaceRootPath/bar/lib/bar.dart', r'''
+import 'package:aaa/aaa.dart';
+void main() {
+  f();
+}
+''');
+
+    await setRoots(included: [
+      foo.parent.path,
+      bar.parent.path,
+    ], excluded: []);
+
     {
-      await server.onAnalysisComplete;
+      await waitForTasksFinished();
       // Files foo.dart and bar.dart should both have errors, since they both
       // call f() with the wrong number of arguments.
-      expect(filesErrors[fooPath], hasLength(1));
-      expect(filesErrors[barPath], hasLength(1));
+      expect(filesErrors[foo], hasLength(1));
+      expect(filesErrors[bar], hasLength(1));
       // Overlay the content of baz.dart to eliminate the errors.
-      server.updateContent('1', {
-        bazPath: AddContentOverlay('''
-library baz;
-f() {}
-''')
-      });
+      await handleSuccessfulRequest(
+        AnalysisUpdateContentParams(
+            {aaa.path: AddContentOverlay('void f() {}')}).toRequest('0'),
+      );
     }
+
     {
-      await server.onAnalysisComplete;
+      await waitForTasksFinished();
       // The overlay should have been propagated to both contexts, causing both
       // foo.dart and bar.dart to be reanalyzed and found to be free of errors.
-      expect(filesErrors[fooPath], isEmpty);
-      expect(filesErrors[barPath], isEmpty);
+      expect(filesErrors[foo], isEmpty);
+      expect(filesErrors[bar], isEmpty);
     }
   }
 
@@ -125,17 +143,23 @@
     var project = newFolder('/project');
     await setRoots(included: [project.path], excluded: []);
 
-    server.updateContent('1',
-        {'/project/main.dart': AddContentOverlay('import "target.dart";')});
-    await server.onAnalysisComplete;
+    await handleSuccessfulRequest(
+      AnalysisUpdateContentParams({
+        '/project/main.dart': AddContentOverlay('import "target.dart";'),
+      }).toRequest('0'),
+    );
+    await waitForTasksFinished();
     expect(filesErrors, {
       '/project/main.dart': ["1: Target of URI doesn't exist: 'target.dart'."],
       '/project/target.dart': []
     });
 
-    server.updateContent('1',
-        {'/project/target.dart': AddContentOverlay('import "none.dart";')});
-    await server.onAnalysisComplete;
+    await handleSuccessfulRequest(
+      AnalysisUpdateContentParams({
+        '/project/target.dart': AddContentOverlay('import "none.dart";')
+      }).toRequest('0'),
+    );
+    await waitForTasksFinished();
     expect(filesErrors, {
       '/project/main.dart': ['1: Unused import.'],
       '/project/target.dart': ["1: Target of URI doesn't exist: 'none.dart'."],
@@ -144,51 +168,59 @@
   }
 
   Future<void> test_overlayOnly() async {
-    var filePath1 = convertPath('/User/project1/test.dart');
-    var filePath2 = convertPath('/User/project2/test.dart');
-    var folderPath1 = newFolder('/User/project1').path;
-    var folderPath2 = newFolder('/User/project2').path;
+    var a = newFile2('$testPackageLibPath/a.dart', '');
+    var b = getFile('$testPackageLibPath/b.dart');
 
-    await setRoots(included: [folderPath1, folderPath2], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
+    await waitForTasksFinished();
+    expect(filesErrors[a], isEmpty);
+    expect(filesErrors[b], isNull);
 
-    // exactly 2 contexts
-    expect(server.driverMap, hasLength(2));
-    var driver1 = server.getAnalysisDriver(filePath1)!;
-    var driver2 = server.getAnalysisDriver(filePath2)!;
+    // Add `b.dart` overlay, analyzed.
+    await handleSuccessfulRequest(
+      AnalysisUpdateContentParams({
+        b.path: AddContentOverlay(''),
+      }).toRequest('0'),
+    );
+    await waitForTasksFinished();
+    expect(filesErrors[a], isEmpty);
+    expect(filesErrors[b], isEmpty);
 
-    // no sources
-    expect(await _getUserSources(driver1), isEmpty);
-    expect(await _getUserSources(driver2), isEmpty);
-
-    // add an overlay - new Source in context1
-    server.updateContent('1', {filePath1: AddContentOverlay('')});
-    expect(await _getUserSources(driver1), [filePath1]);
-    expect(await _getUserSources(driver2), isEmpty);
-
-    // remove the overlay - no sources
-    server.updateContent('2', {filePath1: RemoveContentOverlay()});
-
-    // The file isn't removed from the list of added sources.
-//    expect(_getUserSources(driver1), isEmpty);
-    expect(await _getUserSources(driver2), isEmpty);
+    // Add `b.dart` overlay, analyzed.
+    await handleSuccessfulRequest(
+      AnalysisUpdateContentParams({
+        b.path: RemoveContentOverlay(),
+      }).toRequest('0'),
+    );
+    await waitForTasksFinished();
+    expect(filesErrors[a], isEmpty);
+    // TODO(scheglov) We should get "flush" notification.
+    // expect(filesErrors[b], isNull);
   }
 
   @failingTest
   Future<void> test_sendNoticesAfterNopChange() async {
     // The errors are empty on the last line.
     addTestFile('');
-    await createProject();
-    await server.onAnalysisComplete;
+    await setRoots(included: [workspaceRootPath], excluded: []);
+    await waitForTasksFinished();
     // add an overlay
-    server.updateContent(
-        '1', {testFile: AddContentOverlay('main() {} main() {}')});
-    await server.onAnalysisComplete;
+    await handleSuccessfulRequest(
+      AnalysisUpdateContentParams({
+        testFile.path: AddContentOverlay('main() {} main() {}'),
+      }).toRequest('0'),
+    );
+    await waitForTasksFinished();
     // clear errors and make a no-op change
     filesErrors.clear();
-    server.updateContent('2', {
-      testFile: ChangeContentOverlay([SourceEdit(0, 4, 'main')])
-    });
-    await server.onAnalysisComplete;
+    await handleSuccessfulRequest(
+      AnalysisUpdateContentParams({
+        testFile.path: ChangeContentOverlay([
+          SourceEdit(0, 4, 'main'),
+        ]),
+      }).toRequest('0'),
+    );
+    await waitForTasksFinished();
     // errors should have been resent
     expect(filesErrors, isNotEmpty);
   }
@@ -197,31 +229,40 @@
   Future<void> test_sendNoticesAfterNopChange_flushedUnit() async {
     // The list of errors is empty on the last line.
     addTestFile('');
-    await createProject();
-    await server.onAnalysisComplete;
+    await setRoots(included: [workspaceRootPath], excluded: []);
+    await waitForTasksFinished();
     // add an overlay
-    server.updateContent(
-        '1', {testFile: AddContentOverlay('main() {} main() {}')});
-    await server.onAnalysisComplete;
+    await handleSuccessfulRequest(
+      AnalysisUpdateContentParams({
+        testFile.path: AddContentOverlay('main() {} main() {}'),
+      }).toRequest('0'),
+    );
+    await waitForTasksFinished();
     // clear errors and make a no-op change
     filesErrors.clear();
-    server.updateContent('2', {
-      testFile: ChangeContentOverlay([SourceEdit(0, 4, 'main')])
-    });
-    await server.onAnalysisComplete;
+    await handleSuccessfulRequest(
+      AnalysisUpdateContentParams({
+        testFile.path: ChangeContentOverlay([
+          SourceEdit(0, 4, 'main'),
+        ]),
+      }).toRequest('0'),
+    );
+    await waitForTasksFinished();
     // errors should have been resent
     expect(filesErrors, isNotEmpty);
   }
 
-  void test_sentToPlugins() {
-    var filePath = convertPath('/project/target.dart');
+  Future<void> test_sentToPlugins() async {
+    var filePath = convertPath('$testPackageLibPath/a.dart');
     var fileContent = 'import "none.dart";';
     //
     // Add
     //
-    handleSuccessfulRequest(AnalysisUpdateContentParams(
-            <String, Object>{filePath: AddContentOverlay(fileContent)})
-        .toRequest('0'));
+    await handleSuccessfulRequest(
+      AnalysisUpdateContentParams(<String, Object>{
+        filePath: AddContentOverlay(fileContent),
+      }).toRequest('0'),
+    );
     var params = pluginManager.analysisUpdateContentParams!;
     var files = params.files;
     expect(files, hasLength(1));
@@ -233,10 +274,14 @@
     // Change
     //
     pluginManager.analysisUpdateContentParams = null;
-    handleSuccessfulRequest(AnalysisUpdateContentParams(<String, Object>{
-      filePath: ChangeContentOverlay(
-          <SourceEdit>[SourceEdit(8, 1, "'"), SourceEdit(18, 1, "'")])
-    }).toRequest('1'));
+    await handleSuccessfulRequest(
+      AnalysisUpdateContentParams(<String, Object>{
+        filePath: ChangeContentOverlay(<SourceEdit>[
+          SourceEdit(8, 1, "'"),
+          SourceEdit(18, 1, "'"),
+        ]),
+      }).toRequest('1'),
+    );
     params = pluginManager.analysisUpdateContentParams!;
     expect(params, isNotNull);
     files = params.files;
@@ -249,8 +294,11 @@
     // Remove
     //
     pluginManager.analysisUpdateContentParams = null;
-    handleSuccessfulRequest(AnalysisUpdateContentParams(
-        <String, Object>{filePath: RemoveContentOverlay()}).toRequest('2'));
+    await handleSuccessfulRequest(
+      AnalysisUpdateContentParams(<String, Object>{
+        filePath: RemoveContentOverlay(),
+      }).toRequest('2'),
+    );
     params = pluginManager.analysisUpdateContentParams!;
     expect(params, isNotNull);
     files = params.files;
@@ -258,15 +306,4 @@
     overlay = files[filePath];
     expect(overlay, const TypeMatcher<RemoveContentOverlay>());
   }
-
-  Future<List<String>> _getUserSources(AnalysisDriver driver) async {
-    var sources = <String>[];
-    await driver.applyPendingFileChanges();
-    driver.addedFiles.forEach((path) {
-      if (path.startsWith(convertPath('/User/'))) {
-        sources.add(path);
-      }
-    });
-    return sources;
-  }
 }
diff --git a/pkg/analysis_server/test/analysis_server_base.dart b/pkg/analysis_server/test/analysis_server_base.dart
index a6d5579..804f079 100644
--- a/pkg/analysis_server/test/analysis_server_base.dart
+++ b/pkg/analysis_server/test/analysis_server_base.dart
@@ -10,6 +10,7 @@
 import 'package:analysis_server/src/protocol_server.dart';
 import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
 import 'package:analysis_server/src/utilities/mocks.dart';
+import 'package:analyzer/dart/analysis/analysis_options.dart' as analysis;
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/instrumentation/service.dart';
 import 'package:analyzer/src/dart/analysis/experiments.dart';
@@ -69,9 +70,13 @@
 }
 
 class PubPackageAnalysisServerTest with ResourceProviderMixin {
+  final TestPluginManager pluginManager = TestPluginManager();
   late final MockServerChannel serverChannel;
   late final AnalysisServer server;
 
+  final List<GeneralAnalysisService> _analysisGeneralServices = [];
+  final Map<AnalysisService, List<String>> _analysisFileSubscriptions = {};
+
   AnalysisDomainHandler get analysisDomain {
     return server.handlers.whereType<AnalysisDomainHandler>().single;
   }
@@ -86,8 +91,15 @@
         EnableString.super_parameters,
       ];
 
+  Folder get sdkRoot => newFolder('/sdk');
+
   File get testFile => getFile(testFilePath);
 
+  analysis.AnalysisOptions get testFileAnalysisOptions {
+    var analysisDriver = server.getAnalysisDriver(testFile.path)!;
+    return analysisDriver.analysisOptions;
+  }
+
   String get testFileContent => testFile.readAsStringSync();
 
   String get testFilePath => '$testPackageLibPath/test.dart';
@@ -102,6 +114,25 @@
 
   String get workspaceRootPath => '/home';
 
+  Future<void> addAnalysisSubscription(
+    AnalysisService service,
+    File file,
+  ) async {
+    (_analysisFileSubscriptions[service] ??= []).add(file.path);
+    await handleSuccessfulRequest(
+      AnalysisSetSubscriptionsParams(
+        _analysisFileSubscriptions,
+      ).toRequest('0'),
+    );
+  }
+
+  Future<void> addGeneralAnalysisSubscription(
+    GeneralAnalysisService service,
+  ) async {
+    _analysisGeneralServices.add(service);
+    await _setGeneralAnalysisSubscriptions();
+  }
+
   /// TODO(scheglov) rename
   void addTestFile(String content) {
     newFile2(testFilePath, content);
@@ -144,6 +175,10 @@
     return response;
   }
 
+  void modifyTestFile(String content) {
+    modifyFile(testFilePath, content);
+  }
+
   /// Returns the offset of [search] in [file].
   /// Fails if not found.
   int offsetInFile(File file, String search) {
@@ -155,6 +190,21 @@
 
   void processNotification(Notification notification) {}
 
+  Future<void> removeGeneralAnalysisSubscription(
+    GeneralAnalysisService service,
+  ) async {
+    _analysisGeneralServices.remove(service);
+    await _setGeneralAnalysisSubscriptions();
+  }
+
+  void setPriorityFiles(List<File> files) {
+    handleSuccessfulRequest(
+      AnalysisSetPriorityFilesParams(
+        files.map((e) => e.path).toList(),
+      ).toRequest('0'),
+    );
+  }
+
   Future<void> setRoots({
     required List<String> included,
     required List<String> excluded,
@@ -174,7 +224,6 @@
   void setUp() {
     serverChannel = MockServerChannel();
 
-    var sdkRoot = newFolder('/sdk');
     createMockSdk(
       resourceProvider: resourceProvider,
       root: sdkRoot,
@@ -200,6 +249,7 @@
     );
 
     server.pendingFilesRemoveOverlayDelay = const Duration(milliseconds: 10);
+    server.pluginManager = pluginManager;
     completionDomain.budgetDuration = const Duration(seconds: 30);
   }
 
@@ -249,4 +299,12 @@
   void writeTestPackagePubspecYamlFile(String content) {
     newPubspecYamlFile(testPackageRootPath, content);
   }
+
+  Future<void> _setGeneralAnalysisSubscriptions() async {
+    await handleSuccessfulRequest(
+      AnalysisSetGeneralSubscriptionsParams(
+        _analysisGeneralServices,
+      ).toRequest('0'),
+    );
+  }
 }
diff --git a/pkg/analysis_server/test/edit/format_test.dart b/pkg/analysis_server/test/edit/format_test.dart
index d62a67e..742ae2a 100644
--- a/pkg/analysis_server/test/edit/format_test.dart
+++ b/pkg/analysis_server/test/edit/format_test.dart
@@ -4,7 +4,6 @@
 
 import 'package:analysis_server/protocol/protocol_generated.dart';
 import 'package:analysis_server/src/edit/edit_domain.dart';
-import 'package:analysis_server/src/utilities/progress.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -26,44 +25,42 @@
     handler = EditDomainHandler(server);
   }
 
-  Future test_format_longLine() {
+  Future<void> test_format_longLine() async {
     var content = '''
 fun(firstParam, secondParam, thirdParam, fourthParam) {
   if (firstParam.noNull && secondParam.noNull && thirdParam.noNull && fourthParam.noNull) {}
 }
 ''';
     addTestFile(content);
-    return waitForTasksFinished().then((_) {
-      var formatResult = _formatAt(0, 3, lineLength: 100);
+    await waitForTasksFinished();
+    var formatResult = await _formatAt(0, 3, lineLength: 100);
 
-      expect(formatResult.edits, isNotNull);
-      expect(formatResult.edits, hasLength(0));
+    expect(formatResult.edits, isNotNull);
+    expect(formatResult.edits, hasLength(0));
 
-      expect(formatResult.selectionOffset, equals(0));
-      expect(formatResult.selectionLength, equals(3));
-    });
+    expect(formatResult.selectionOffset, equals(0));
+    expect(formatResult.selectionLength, equals(3));
   }
 
-  Future test_format_noOp() {
+  Future<void> test_format_noOp() async {
     // Already formatted source
     addTestFile('''
 main() {
   int x = 3;
 }
 ''');
-    return waitForTasksFinished().then((_) {
-      var formatResult = _formatAt(0, 3);
-      expect(formatResult.edits, isNotNull);
-      expect(formatResult.edits, hasLength(0));
-    });
+    await waitForTasksFinished();
+    var formatResult = await _formatAt(0, 3);
+    expect(formatResult.edits, isNotNull);
+    expect(formatResult.edits, hasLength(0));
   }
 
-  Future test_format_noSelection() async {
+  Future<void> test_format_noSelection() async {
     addTestFile('''
 main() { int x = 3; }
 ''');
     await waitForTasksFinished();
-    var formatResult = _formatAt(0, 0);
+    var formatResult = await _formatAt(0, 0);
 
     expect(formatResult.edits, isNotNull);
     expect(formatResult.edits, hasLength(1));
@@ -78,44 +75,42 @@
     expect(formatResult.selectionLength, equals(0));
   }
 
-  Future test_format_simple() {
+  Future<void> test_format_simple() async {
     addTestFile('''
 main() { int x = 3; }
 ''');
-    return waitForTasksFinished().then((_) {
-      var formatResult = _formatAt(0, 3);
+    await waitForTasksFinished();
+    var formatResult = await _formatAt(0, 3);
 
-      expect(formatResult.edits, isNotNull);
-      expect(formatResult.edits, hasLength(1));
+    expect(formatResult.edits, isNotNull);
+    expect(formatResult.edits, hasLength(1));
 
-      var edit = formatResult.edits[0];
-      expect(edit.replacement, equals('''
+    var edit = formatResult.edits[0];
+    expect(edit.replacement, equals('''
 main() {
   int x = 3;
 }
 '''));
-      expect(formatResult.selectionOffset, equals(0));
-      expect(formatResult.selectionLength, equals(3));
-    });
+    expect(formatResult.selectionOffset, equals(0));
+    expect(formatResult.selectionLength, equals(3));
   }
 
-  Future test_format_withErrors() {
+  Future<void> test_format_withErrors() async {
     addTestFile('''
 main() { int x =
 ''');
-    return waitForTasksFinished().then((_) {
-      var request = EditFormatParams(testFile, 0, 3).toRequest('0');
-      var response = handler.handleRequest(request, NotCancelableToken());
-      expect(response, isResponseFailure('0'));
-    });
+    await waitForTasksFinished();
+    var request = EditFormatParams(testFile, 0, 3).toRequest('0');
+    var response = await waitResponse(request);
+    expect(response, isResponseFailure('0'));
   }
 
-  EditFormatResult _formatAt(int selectionOffset, int selectionLength,
-      {int? lineLength}) {
+  Future<EditFormatResult> _formatAt(int selectionOffset, int selectionLength,
+      {int? lineLength}) async {
     var request = EditFormatParams(testFile, selectionOffset, selectionLength,
             lineLength: lineLength)
         .toRequest('0');
-    var response = handleSuccessfulRequest(request);
+    var response = await waitResponse(request);
     return EditFormatResult.fromResponse(response);
   }
 }
diff --git a/pkg/analysis_server/test/lsp/type_definition_test.dart b/pkg/analysis_server/test/lsp/type_definition_test.dart
index 9f003e8..b7c92ea 100644
--- a/pkg/analysis_server/test/lsp/type_definition_test.dart
+++ b/pkg/analysis_server/test/lsp/type_definition_test.dart
@@ -16,6 +16,11 @@
 
 @reflectiveTest
 class TypeDefinitionTest extends AbstractLspAnalysisServerTest {
+  Uri get sdkCoreUri {
+    final sdkCorePath = convertPath('/sdk/lib/core/core.dart');
+    return Uri.file(sdkCorePath);
+  }
+
   Future<void> test_currentFile() async {
     final contents = '''
 class [[A]] {}
@@ -78,7 +83,7 @@
 ''';
 
     final result = await _getLocationResult(contents);
-    expect(result.uri, 'file:///sdk/lib/core/core.dart');
+    expect(result.uri, '$sdkCoreUri');
     _expectNameRange(result.range, 'String');
   }
 
@@ -264,7 +269,7 @@
   /// This is used for SDK sources where the exact location is not known to the
   /// test.
   void _expectSdkCoreType(LocationLink result, String typeName) {
-    expect(result.targetUri, 'file:///sdk/lib/core/core.dart');
+    expect(result.targetUri, '$sdkCoreUri');
     _expectNameRange(result.targetSelectionRange, typeName);
     _expectCodeRange(result.targetRange);
   }
diff --git a/pkg/analysis_server/test/src/services/correction/fix/create_constructor_for_final_fields_test.dart b/pkg/analysis_server/test/src/services/correction/fix/create_constructor_for_final_fields_test.dart
index 92c5799..783000a 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/create_constructor_for_final_fields_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/create_constructor_for_final_fields_test.dart
@@ -12,6 +12,9 @@
 void main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(CreateConstructorForFinalFieldsTest);
+    defineReflectiveTests(CreateConstructorForFinalFieldsWithoutNullSafetyTest);
+    defineReflectiveTests(
+        CreateConstructorForFinalFieldsWithoutSuperParametersTest);
   });
 }
 
@@ -45,7 +48,7 @@
 class MyWidget extends StatelessWidget {
   final int a;
   final int b = 2;
-  final int c;
+  final int? c;
 }
 ''');
     await assertHasFix('''
@@ -54,9 +57,9 @@
 class MyWidget extends StatelessWidget {
   final int a;
   final int b = 2;
-  final int c;
+  final int? c;
 
-  const MyWidget({Key? key, this.a, this.c}) : super(key: key);
+  const MyWidget({super.key, required this.a, this.c});
 }
 ''', errorFilter: (error) {
       return error.message.contains("'a'");
@@ -71,7 +74,7 @@
 class MyWidget extends StatelessWidget {
   final int a;
   final Widget child;
-  final int b;
+  final int? b;
 }
 ''');
     await assertHasFix('''
@@ -80,9 +83,9 @@
 class MyWidget extends StatelessWidget {
   final int a;
   final Widget child;
-  final int b;
+  final int? b;
 
-  const MyWidget({Key? key, this.a, this.b, this.child}) : super(key: key);
+  const MyWidget({super.key, required this.a, this.b, required this.child});
 }
 ''', errorFilter: (error) {
       return error.message.contains("'a'");
@@ -97,7 +100,7 @@
 class MyWidget extends StatelessWidget {
   final int a;
   final List<Widget> children;
-  final int b;
+  final int? b;
 }
 ''');
     await assertHasFix('''
@@ -106,9 +109,9 @@
 class MyWidget extends StatelessWidget {
   final int a;
   final List<Widget> children;
-  final int b;
+  final int? b;
 
-  const MyWidget({Key? key, this.a, this.b, this.children}) : super(key: key);
+  const MyWidget({super.key, required this.a, this.b, required this.children});
 }
 ''', errorFilter: (error) {
       return error.message.contains("'a'");
@@ -175,3 +178,179 @@
     await assertNoFix();
   }
 }
+
+@reflectiveTest
+class CreateConstructorForFinalFieldsWithoutNullSafetyTest
+    extends FixProcessorTest {
+  @override
+  FixKind get kind => DartFixKind.CREATE_CONSTRUCTOR_FOR_FINAL_FIELDS;
+
+  @override
+  String get testPackageLanguageVersion => '2.9';
+
+  Future<void> test_flutter() async {
+    writeTestPackageConfig(flutter: true);
+    await resolveTestCode('''
+import 'package:flutter/widgets.dart';
+
+class MyWidget extends StatelessWidget {
+  final int a;
+  final int b = 2;
+  final int c;
+}
+''');
+    await assertHasFix('''
+import 'package:flutter/widgets.dart';
+
+class MyWidget extends StatelessWidget {
+  final int a;
+  final int b = 2;
+  final int c;
+
+  const MyWidget({Key key, this.a, this.c}) : super(key: key);
+}
+''', errorFilter: (error) {
+      return error.message.contains("'a'");
+    });
+  }
+
+  Future<void> test_flutter_childLast() async {
+    writeTestPackageConfig(flutter: true);
+    await resolveTestCode('''
+import 'package:flutter/widgets.dart';
+
+class MyWidget extends StatelessWidget {
+  final int a;
+  final Widget child;
+  final int b;
+}
+''');
+    await assertHasFix('''
+import 'package:flutter/widgets.dart';
+
+class MyWidget extends StatelessWidget {
+  final int a;
+  final Widget child;
+  final int b;
+
+  const MyWidget({Key key, this.a, this.b, this.child}) : super(key: key);
+}
+''', errorFilter: (error) {
+      return error.message.contains("'a'");
+    });
+  }
+
+  Future<void> test_flutter_childrenLast() async {
+    writeTestPackageConfig(flutter: true);
+    await resolveTestCode('''
+import 'package:flutter/widgets.dart';
+
+class MyWidget extends StatelessWidget {
+  final int a;
+  final List<Widget> children;
+  final int b;
+}
+''');
+    await assertHasFix('''
+import 'package:flutter/widgets.dart';
+
+class MyWidget extends StatelessWidget {
+  final int a;
+  final List<Widget> children;
+  final int b;
+
+  const MyWidget({Key key, this.a, this.b, this.children}) : super(key: key);
+}
+''', errorFilter: (error) {
+      return error.message.contains("'a'");
+    });
+  }
+}
+
+@reflectiveTest
+class CreateConstructorForFinalFieldsWithoutSuperParametersTest
+    extends FixProcessorTest {
+  @override
+  FixKind get kind => DartFixKind.CREATE_CONSTRUCTOR_FOR_FINAL_FIELDS;
+
+  @override
+  String get testPackageLanguageVersion => '2.16';
+
+  Future<void> test_flutter() async {
+    writeTestPackageConfig(flutter: true);
+    await resolveTestCode('''
+import 'package:flutter/widgets.dart';
+
+class MyWidget extends StatelessWidget {
+  final int a;
+  final int b = 2;
+  final int? c;
+}
+''');
+    await assertHasFix('''
+import 'package:flutter/widgets.dart';
+
+class MyWidget extends StatelessWidget {
+  final int a;
+  final int b = 2;
+  final int? c;
+
+  const MyWidget({Key? key, required this.a, this.c}) : super(key: key);
+}
+''', errorFilter: (error) {
+      return error.message.contains("'a'");
+    });
+  }
+
+  Future<void> test_flutter_childLast() async {
+    writeTestPackageConfig(flutter: true);
+    await resolveTestCode('''
+import 'package:flutter/widgets.dart';
+
+class MyWidget extends StatelessWidget {
+  final int a;
+  final Widget child;
+  final int? b;
+}
+''');
+    await assertHasFix('''
+import 'package:flutter/widgets.dart';
+
+class MyWidget extends StatelessWidget {
+  final int a;
+  final Widget child;
+  final int? b;
+
+  const MyWidget({Key? key, required this.a, this.b, required this.child}) : super(key: key);
+}
+''', errorFilter: (error) {
+      return error.message.contains("'a'");
+    });
+  }
+
+  Future<void> test_flutter_childrenLast() async {
+    writeTestPackageConfig(flutter: true);
+    await resolveTestCode('''
+import 'package:flutter/widgets.dart';
+
+class MyWidget extends StatelessWidget {
+  final int a;
+  final List<Widget>? children;
+  final int? b;
+}
+''');
+    await assertHasFix('''
+import 'package:flutter/widgets.dart';
+
+class MyWidget extends StatelessWidget {
+  final int a;
+  final List<Widget>? children;
+  final int? b;
+
+  const MyWidget({Key? key, required this.a, this.b, this.children}) : super(key: key);
+}
+''', errorFilter: (error) {
+      return error.message.contains("'a'");
+    });
+  }
+}
diff --git a/pkg/analyzer/lib/src/summary2/top_level_inference.dart b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
index 9708fbb..50db402 100644
--- a/pkg/analyzer/lib/src/summary2/top_level_inference.dart
+++ b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
@@ -203,7 +203,7 @@
 
     if (_superParameters.isNotEmpty) {
       dependencies.addIfNotNull(
-        _walker.getNode(_constructor.superConstructor),
+        _walker.getNode(_constructor.superConstructor?.declaration),
       );
     }
 
diff --git a/pkg/analyzer/test/src/summary/elements_test.dart b/pkg/analyzer/test/src/summary/elements_test.dart
index 1a23546..b5bc665 100644
--- a/pkg/analyzer/test/src/summary/elements_test.dart
+++ b/pkg/analyzer/test/src/summary/elements_test.dart
@@ -1761,19 +1761,19 @@
   }
 
   test_class_constructor_parameters_super_requiredPositional_inferenceOrder() async {
-    // It is important that `C` is declared after `B`, so that we check that
-    // inference happens in order - first `C`, then `B`.
+    // It is important that `B` is declared after `C`, so that we check that
+    // inference happens in order - first `B`, then `C`.
     var library = await buildLibrary('''
 abstract class A {
   A(int a);
 }
 
-class B extends C {
-  B(super.a);
+class C extends B {
+  C(super.a);
 }
 
-class C extends A {
-  C(super.a);
+class B extends A {
+  B(super.a);
 }
 ''');
     checkElementText(library, r'''
@@ -1786,16 +1786,16 @@
             parameters
               requiredPositional a @27
                 type: int
-      class B @40
-        supertype: C
+      class C @40
+        supertype: B
         constructors
           @56
             parameters
               requiredPositional final super.a @64
                 type: int
                 superConstructorParameter: a@101
-            superConstructor: self::@class::C::@constructor::•
-      class C @77
+            superConstructor: self::@class::B::@constructor::•
+      class B @77
         supertype: A
         constructors
           @93
@@ -1807,6 +1807,60 @@
 ''');
   }
 
+  test_class_constructor_parameters_super_requiredPositional_inferenceOrder_generic() async {
+    // It is important that `C` is declared before `B`, so that we check that
+    // inference happens in order - first `B`, then `C`.
+    var library = await buildLibrary('''
+class A {
+  A(int a);
+}
+
+class C extends B<String> {
+  C(super.a);
+}
+
+class B<T> extends A {
+  B(super.a);
+}
+''');
+    checkElementText(library, r'''
+library
+  definingUnit
+    classes
+      class A @6
+        constructors
+          @12
+            parameters
+              requiredPositional a @18
+                type: int
+      class C @31
+        supertype: B<String>
+        constructors
+          @55
+            parameters
+              requiredPositional final super.a @63
+                type: int
+                superConstructorParameter: ParameterMember
+                  base: a@103
+                  substitution: {T: String}
+            superConstructor: ConstructorMember
+              base: self::@class::B::@constructor::•
+              substitution: {T: String}
+      class B @76
+        typeParameters
+          covariant T @78
+            defaultType: dynamic
+        supertype: A
+        constructors
+          @95
+            parameters
+              requiredPositional final super.a @103
+                type: int
+                superConstructorParameter: a@18
+            superConstructor: self::@class::A::@constructor::•
+''');
+  }
+
   test_class_constructor_parameters_super_requiredPositional_unresolved() async {
     var library = await buildLibrary('''
 class A {}
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index fcdf267..029efeb 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -304,13 +304,9 @@
       programSplitConstraintsData = constraintParser.read(programSplitJson);
     }
 
-    if (options.cfeOnly) {
-      await runLoadKernel();
-    } else if (options.modularMode) {
-      await runModularAnalysis();
-    } else {
+    await selfTask.measureSubtask("compileFromKernel", () async {
       await runSequentialPhases();
-    }
+    });
   }
 
   /// Clear the internal compiler state to prevent memory leaks when invoking
@@ -329,7 +325,13 @@
     }
   }
 
-  JClosedWorld computeClosedWorld(Uri rootLibraryUri, Iterable<Uri> libraries) {
+  JClosedWorld computeClosedWorld(
+      ir.Component component,
+      List<ModuleData> moduleData,
+      Uri rootLibraryUri,
+      Iterable<Uri> libraries) {
+    frontendStrategy.registerLoadedLibraries(component, libraries);
+    frontendStrategy.registerModuleData(moduleData);
     ResolutionEnqueuer resolutionEnqueuer = frontendStrategy
         .createResolutionEnqueuer(enqueueTask, this)
       ..onEmptyForTesting = onResolutionQueueEmptyForTesting;
@@ -379,59 +381,83 @@
     return closedWorld;
   }
 
-  Future<load_kernel.Output> runLoadKernel() async {
+  Future<load_kernel.Output> loadKernel() async {
     final input = load_kernel.Input(options, provider, reporter,
         initializedCompilerState, forceSerializationForTesting);
     load_kernel.Output output =
         await loadKernelTask.measure(() async => load_kernel.run(input));
-    if (output == null || compilationFailed) return null;
     reporter.log("Kernel load complete");
-    if (retainDataForTesting) {
-      componentForTesting = output.component;
-    }
-    if (options.features.newDumpInfo.isEnabled && options.dumpInfo) {
-      untrimmedComponentForDumpInfo = output.component;
-    }
-
-    if (options.cfeOnly) {
-      ir.Component component = output.component;
-      dumpUnusedLibrariesAndTrimComponent(component, output.libraries);
-      await serializationTask.serializeComponent(component);
-    }
     return output;
   }
 
-  void dumpUnusedLibrariesAndTrimComponent(
-      ir.Component component, List<Uri> libraries) {
-    if (options.fromDill) {
-      if (options.dumpUnusedLibraries) {
-        dumpUnusedLibraries(component, libraries);
+  Future<load_kernel.Output> produceKernel() async {
+    if (options.readClosedWorldUri == null) {
+      load_kernel.Output output = await loadKernel();
+      if (output == null || compilationFailed) return null;
+      ir.Component component = output.component;
+      if (retainDataForTesting) {
+        componentForTesting = component;
       }
-      if (options.entryUri != null) {
-        component = trimComponent(component, libraries);
+      if (options.features.newDumpInfo.isEnabled && options.dumpInfo) {
+        untrimmedComponentForDumpInfo = component;
       }
+      if (options.cfeOnly) {
+        if (options.fromDill) {
+          List<Uri> libraries = output.libraries;
+          if (options.dumpUnusedLibraries) {
+            dumpUnusedLibraries(component, libraries);
+          }
+          if (options.entryUri != null) {
+            component = trimComponent(component, libraries);
+          }
+        }
+        await serializationTask.serializeComponent(component);
+      }
+      // We currently do not return the trimmed component from [produceKernel]
+      // because downstream phases, in particular modular analysis, currently
+      // depend on the untrimmed dill.
+      return output;
+    } else {
+      ir.Component component =
+          await serializationTask.deserializeComponentAndUpdateOptions();
+      return load_kernel.Output(component, null, null, null, null);
     }
   }
 
-  void runModularAnalysis() async {
-    load_kernel.Output output = await runLoadKernel();
-    if (output == null || compilationFailed) return;
+  bool shouldStopAfterLoadKernel(load_kernel.Output output) =>
+      output == null || compilationFailed || options.cfeOnly;
 
+  Future<ModuleData> runModularAnalysis(
+      load_kernel.Output output, Set<Uri> moduleLibraries) async {
     ir.Component component = output.component;
     List<Uri> libraries = output.libraries;
-    Set<Uri> moduleLibraries = output.moduleLibraries.toSet();
     _userCodeLocations
         .addAll(moduleLibraries.map((module) => CodeLocation(module)));
     final input = modular_analysis.Input(
         options, reporter, environment, component, libraries, moduleLibraries);
-    ModuleData moduleData = await selfTask.measureSubtask(
+    return await selfTask.measureSubtask(
         'runModularAnalysis', () async => modular_analysis.run(input));
-    if (compilationFailed) return;
-    serializationTask.testModuleSerialization(moduleData, component);
-    serializationTask.serializeModuleData(
-        moduleData, component, moduleLibraries);
   }
 
+  Future<List<ModuleData>> produceModuleData(load_kernel.Output output) async {
+    ir.Component component = output.component;
+    if (options.modularMode) {
+      Set<Uri> moduleLibraries = output.moduleLibraries.toSet();
+      ModuleData moduleData = await runModularAnalysis(output, moduleLibraries);
+      if (options.writeModularAnalysisUri != null && !compilationFailed) {
+        serializationTask.testModuleSerialization(moduleData, component);
+        serializationTask.serializeModuleData(
+            moduleData, component, moduleLibraries);
+      }
+      return [moduleData];
+    } else {
+      return await serializationTask.deserializeModuleData(component);
+    }
+  }
+
+  bool get shouldStopAfterModularAnalysis =>
+      compilationFailed || options.writeModularAnalysisUri != null;
+
   GlobalTypeInferenceResults performGlobalTypeInference(
       JClosedWorld closedWorld) {
     FunctionEntity mainFunction = closedWorld.elementEnvironment.mainFunction;
@@ -508,48 +534,23 @@
         globalTypeInferenceResultsData);
   }
 
-  Future<load_kernel.Output> loadComponent() async {
-    load_kernel.Output output = await runLoadKernel();
-    if (output == null || compilationFailed) return null;
-
+  Future<ClosedWorldAndIndices> produceClosedWorld(
+      load_kernel.Output output, List<ModuleData> moduleData) async {
     ir.Component component = output.component;
-    List<Uri> libraries = output.libraries;
-    frontendStrategy.registerLoadedLibraries(component, libraries);
-    List<ModuleData> data;
-    if (options.hasModularAnalysisInputs) {
-      data = await serializationTask.deserializeModuleData(component);
-    }
-    frontendStrategy.registerModuleData(data);
-
-    // After we've deserialized modular data, we trim the component of any
-    // unnecessary dependencies.
-    // Note: It is critical we wait to trim the dill until after we've
-    // deserialized modular data because some of this data may reference
-    // 'trimmed' elements.
-    dumpUnusedLibrariesAndTrimComponent(component, libraries);
-    return output;
-  }
-
-  Future<ClosedWorldAndIndices> produceClosedWorld() async {
     ClosedWorldAndIndices closedWorldAndIndices;
     if (options.readClosedWorldUri == null) {
-      load_kernel.Output loadKernelOutput = await loadComponent();
-      if (loadKernelOutput != null) {
-        Uri rootLibraryUri = loadKernelOutput.rootLibraryUri;
-        Iterable<Uri> libraries = loadKernelOutput.libraries;
-        _userCodeLocations.add(CodeLocation(rootLibraryUri));
-        JsClosedWorld closedWorld =
-            computeClosedWorld(rootLibraryUri, libraries);
-        closedWorldAndIndices = ClosedWorldAndIndices(closedWorld, null);
-        if (options.writeClosedWorldUri != null) {
-          serializationTask.serializeComponent(
-              closedWorld.elementMap.programEnv.mainComponent);
-          serializationTask.serializeClosedWorld(closedWorld);
-        }
+      Uri rootLibraryUri = output.rootLibraryUri;
+      Iterable<Uri> libraries = output.libraries;
+      _userCodeLocations.add(CodeLocation(rootLibraryUri));
+      JsClosedWorld closedWorld =
+          computeClosedWorld(component, moduleData, rootLibraryUri, libraries);
+      closedWorldAndIndices = ClosedWorldAndIndices(closedWorld, null);
+      if (options.writeClosedWorldUri != null) {
+        serializationTask.serializeComponent(
+            closedWorld.elementMap.programEnv.mainComponent);
+        serializationTask.serializeClosedWorld(closedWorld);
       }
     } else {
-      ir.Component component =
-          await serializationTask.deserializeComponentAndUpdateOptions();
       closedWorldAndIndices = await serializationTask.deserializeClosedWorld(
           environment, abstractValueStrategy, component);
     }
@@ -625,29 +626,40 @@
   bool get shouldStopAfterCodegen => options.writeCodegenUri != null;
 
   void runSequentialPhases() async {
-    await selfTask.measureSubtask("compileFromKernel", () async {
-      // Load kernel and compute closed world.
-      ClosedWorldAndIndices closedWorldAndIndices = await produceClosedWorld();
-      if (shouldStopAfterClosedWorld(closedWorldAndIndices)) return;
+    // Load kernel.
+    load_kernel.Output output = await produceKernel();
+    if (shouldStopAfterLoadKernel(output)) return;
 
-      // Run global analysis.
-      GlobalTypeInferenceResults globalTypeInferenceResults =
-          await produceGlobalTypeInferenceResults(closedWorldAndIndices);
-      if (shouldStopAfterGlobalTypeInference) return;
+    // Run modular analysis. This may be null if modular analysis was not
+    // requested for this pipeline.
+    List<ModuleData> moduleData;
+    if (options.modularMode || options.hasModularAnalysisInputs) {
+      moduleData = await produceModuleData(output);
+    }
+    if (shouldStopAfterModularAnalysis) return;
 
-      // Run codegen.
-      CodegenResults codegenResults = await produceCodegenResults(
-          globalTypeInferenceResults, closedWorldAndIndices.indices);
-      if (shouldStopAfterCodegen) return;
+    // Compute closed world.
+    ClosedWorldAndIndices closedWorldAndIndices =
+        await produceClosedWorld(output, moduleData);
+    if (shouldStopAfterClosedWorld(closedWorldAndIndices)) return;
 
-      // Link.
-      int programSize = runCodegenEnqueuer(codegenResults);
+    // Run global analysis.
+    GlobalTypeInferenceResults globalTypeInferenceResults =
+        await produceGlobalTypeInferenceResults(closedWorldAndIndices);
+    if (shouldStopAfterGlobalTypeInference) return;
 
-      // Dump Info.
-      if (options.dumpInfo) {
-        runDumpInfo(codegenResults, programSize);
-      }
-    });
+    // Run codegen.
+    CodegenResults codegenResults = await produceCodegenResults(
+        globalTypeInferenceResults, closedWorldAndIndices.indices);
+    if (shouldStopAfterCodegen) return;
+
+    // Link.
+    int programSize = runCodegenEnqueuer(codegenResults);
+
+    // Dump Info.
+    if (options.dumpInfo) {
+      runDumpInfo(codegenResults, programSize);
+    }
   }
 
   void runDumpInfo(CodegenResults codegenResults, int programSize) {
diff --git a/pkg/dart2wasm/bin/run_wasm.js b/pkg/dart2wasm/bin/run_wasm.js
index b5034ea..593f159 100644
--- a/pkg/dart2wasm/bin/run_wasm.js
+++ b/pkg/dart2wasm/bin/run_wasm.js
@@ -42,6 +42,39 @@
     }
 }
 
+// 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) {
+    var length = dartInstance.exports.$listLength(list);
+    var array = new Array(length);
+    for (var i = 0; i < length; i++) {
+        array[i] = dartInstance.exports.$listRead(list, i);
+    }
+    return array;
+}
+
+// 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 {
+        return object;
+    }
+}
+
 // Imports for printing and event loop
 var dart2wasm = {
     printToConsole: function(string) {
@@ -64,6 +97,41 @@
         // stack trace.
         let userStackString = stackString.split('\n').slice(3).join('\n');
         return stringToDartString(userStackString);
+    },
+    arrayFromDartList: arrayFromDartList,
+    arrayToDartList: arrayToDartList,
+    stringFromDartString: stringFromDartString,
+    stringToDartString: stringToDartString,
+    dartify: dartify,
+    newObject: function() {
+        return {};
+    },
+    globalThis: function() {
+        return globalThis;
+    },
+    getProperty: function(object, name) {
+        return object[name];
+    },
+    hasProperty: function(object, name) {
+        return name in object;
+    },
+    setProperty: function(object, name, value) {
+        return object[name] = value;
+    },
+    callMethodVarArgs: function(object, name, args) {
+        return object[name].apply(object, args);
+    },
+    callConstructorVarArgs: function(object, name, args) {
+        // Gets a constructor property at object[name], and apply bind to the
+        // constructor. We pass `null` as the first argument to `bind.apply`
+        // because this is `bind`'s unused context argument(`new` will
+        // explicitly create a new context).
+        var constructor = object[name];
+        var factoryFunction = constructor.bind.apply(constructor, [null, ...args]);
+        return new factoryFunction();
+    },
+    eval: function(string) {
+        eval(string);
     }
 };
 
diff --git a/pkg/dart2wasm/lib/code_generator.dart b/pkg/dart2wasm/lib/code_generator.dart
index 658a618..6631460 100644
--- a/pkg/dart2wasm/lib/code_generator.dart
+++ b/pkg/dart2wasm/lib/code_generator.dart
@@ -1181,7 +1181,7 @@
 
   @override
   w.ValueType visitEqualsNull(EqualsNull node, w.ValueType expectedType) {
-    wrap(node.expression, translator.topInfo.nullableType);
+    wrap(node.expression, const w.RefType.any());
     b.ref_is_null();
     return w.NumType.i32;
   }
diff --git a/pkg/dart2wasm/lib/target.dart b/pkg/dart2wasm/lib/target.dart
index 15e6651..cb5310be 100644
--- a/pkg/dart2wasm/lib/target.dart
+++ b/pkg/dart2wasm/lib/target.dart
@@ -46,6 +46,7 @@
         'dart:_internal',
         'dart:typed_data',
         'dart:nativewrappers',
+        'dart:js_util_wasm',
       ];
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
index 4bb0a08..2f58bb1 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -479,9 +479,6 @@
     constantEvaluator.withNewEnvironment(() {
       transformAnnotations(node.annotations, node);
       transformTypeParameterList(node.typeParameters, node);
-      transformTypeParameterList(node.typeParametersOfFunctionType, node);
-      transformVariableDeclarationList(node.positionalParameters, node);
-      transformVariableDeclarationList(node.namedParameters, node);
     });
     return node;
   }
diff --git a/pkg/front_end/lib/src/fasta/source/diet_listener.dart b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
index 86e5832..5bbfd4a 100644
--- a/pkg/front_end/lib/src/fasta/source/diet_listener.dart
+++ b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
@@ -299,24 +299,7 @@
               // hood, so we only need the offset of the first annotation.
               Token metadataToken = tokenForOffset(
                   typedefKeyword, endToken, metadata[0].charOffset)!;
-              List<Expression> annotations =
-                  parseMetadata(typedefBuilder, metadataToken, null)!;
-              if (formal.isPositional) {
-                VariableDeclaration parameter =
-                    typedefBuilder.typedef.positionalParameters[i];
-                for (Expression annotation in annotations) {
-                  parameter.addAnnotation(annotation);
-                }
-              } else {
-                for (VariableDeclaration named
-                    in typedefBuilder.typedef.namedParameters) {
-                  if (named.name == formal.name) {
-                    for (Expression annotation in annotations) {
-                      named.addAnnotation(annotation);
-                    }
-                  }
-                }
-              }
+              parseMetadata(typedefBuilder, metadataToken, null)!;
             }
           }
         }
diff --git a/pkg/front_end/lib/src/fasta/source/source_type_alias_builder.dart b/pkg/front_end/lib/src/fasta/source/source_type_alias_builder.dart
index 638253e..f6fd8b7 100644
--- a/pkg/front_end/lib/src/fasta/source/source_type_alias_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_type_alias_builder.dart
@@ -7,37 +7,27 @@
 import 'package:front_end/src/fasta/kernel/expression_generator_helper.dart';
 import 'package:kernel/ast.dart';
 import 'package:kernel/class_hierarchy.dart';
-
-import 'package:kernel/type_algebra.dart'
-    show FreshTypeParameters, getFreshTypeParameters;
-
 import 'package:kernel/type_environment.dart';
 
-import '../fasta_codes.dart'
-    show noLength, templateCyclicTypedef, templateTypeArgumentMismatch;
-
-import '../problems.dart' show unhandled;
-import '../scope.dart';
-
 import '../builder/builder.dart';
 import '../builder/class_builder.dart';
 import '../builder/fixed_type_builder.dart';
-import '../builder/formal_parameter_builder.dart';
 import '../builder/function_type_builder.dart';
 import '../builder/library_builder.dart';
 import '../builder/member_builder.dart';
 import '../builder/metadata_builder.dart';
 import '../builder/named_type_builder.dart';
-import '../builder/type_builder.dart';
 import '../builder/type_alias_builder.dart';
+import '../builder/type_builder.dart';
 import '../builder/type_declaration_builder.dart';
 import '../builder/type_variable_builder.dart';
-
+import '../fasta_codes.dart'
+    show noLength, templateCyclicTypedef, templateTypeArgumentMismatch;
 import '../kernel/constructor_tearoff_lowering.dart';
 import '../kernel/kernel_helper.dart';
-
+import '../problems.dart' show unhandled;
+import '../scope.dart';
 import '../util/helpers.dart';
-
 import 'source_library_builder.dart' show SourceLibraryBuilder;
 
 class SourceTypeAliasBuilder extends TypeAliasBuilderImpl {
@@ -101,33 +91,9 @@
     typedef.type ??= buildThisType();
 
     TypeBuilder? type = this.type;
-    if (type is FunctionTypeBuilder) {
-      List<TypeParameter> typeParameters = new List<TypeParameter>.generate(
-          type.typeVariables?.length ?? 0,
-          (int i) => type.typeVariables![i].parameter,
-          growable: false);
-      FreshTypeParameters freshTypeParameters =
-          getFreshTypeParameters(typeParameters);
-      for (int i = 0; i < freshTypeParameters.freshTypeParameters.length; i++) {
-        TypeParameter typeParameter =
-            freshTypeParameters.freshTypeParameters[i];
-        typedef.typeParametersOfFunctionType
-            .add(typeParameter..parent = typedef);
-      }
-
-      if (type.formals != null) {
-        for (FormalParameterBuilder formal in type.formals!) {
-          VariableDeclaration parameter = formal.build(libraryBuilder, 0);
-          parameter.type = freshTypeParameters.substitute(parameter.type);
-          if (formal.isNamed) {
-            typedef.namedParameters.add(parameter);
-          } else {
-            typedef.positionalParameters.add(parameter);
-          }
-          parameter.parent = typedef;
-        }
-      }
-    } else if (type is NamedTypeBuilder || type is FixedTypeBuilder) {
+    if (type is FunctionTypeBuilder ||
+        type is NamedTypeBuilder ||
+        type is FixedTypeBuilder) {
       // No error, but also no additional setup work.
       // ignore: unnecessary_null_comparison
     } else if (type != null) {
diff --git a/pkg/front_end/test/fasta/expression_suite.dart b/pkg/front_end/test/fasta/expression_suite.dart
index e8871b6..2e0a4a9 100644
--- a/pkg/front_end/test/fasta/expression_suite.dart
+++ b/pkg/front_end/test/fasta/expression_suite.dart
@@ -73,6 +73,7 @@
 
 class Context extends ChainContext {
   final CompilerContext compilerContext;
+  final CompilerContext compilerContextNoNNBD;
   final List<DiagnosticMessage> errors;
 
   @override
@@ -82,7 +83,8 @@
   final Set<Uri> fuzzedLibraries = {};
   int fuzzCompiles = 0;
 
-  Context(this.compilerContext, this.errors, bool updateExpectations, this.fuzz)
+  Context(this.compilerContext, this.compilerContextNoNNBD, this.errors,
+      bool updateExpectations, this.fuzz)
       : steps = <Step>[
           const ReadTest(),
           const CompileExpression(),
@@ -362,8 +364,12 @@
 
   // Compile [test.expression], update [test.errors] with results.
   // As a side effect - verify that generated procedure can be serialized.
-  Future<void> compileExpression(TestCase test, IncrementalCompiler compiler,
-      IncrementalCompilerResult compilerResult, Context context) async {
+  Future<void> compileExpression(
+      TestCase test,
+      IncrementalCompiler compiler,
+      IncrementalCompiler? compilerNoNNBD,
+      IncrementalCompilerResult compilerResult,
+      Context context) async {
     Map<String, DartType>? definitions = createDefinitionsWithTypes(
         compilerResult.classHierarchy?.knownLibraries,
         test.definitionTypes,
@@ -408,29 +414,36 @@
     }
 
     if (context.fuzz) {
-      await fuzz(compiler, compilerResult, context);
+      await fuzz(compiler, compilerNoNNBD!, compilerResult, context);
     }
   }
 
-  Future<void> fuzz(IncrementalCompiler compiler,
-      IncrementalCompilerResult compilerResult, Context context) async {
+  Future<void> fuzz(
+      IncrementalCompiler compiler,
+      IncrementalCompiler compilerNoNNBD,
+      IncrementalCompilerResult compilerResult,
+      Context context) async {
     for (Library lib in compilerResult.classHierarchy!.knownLibraries) {
       if (!context.fuzzedLibraries.add(lib.importUri)) continue;
 
       for (Member m in lib.members) {
-        await fuzzMember(m, compiler, lib.importUri, context);
+        await fuzzMember(m, compiler, compilerNoNNBD, lib.importUri, context);
       }
 
       for (Class c in lib.classes) {
         for (Member m in c.members) {
-          await fuzzMember(m, compiler, lib.importUri, context);
+          await fuzzMember(m, compiler, compilerNoNNBD, lib.importUri, context);
         }
       }
     }
   }
 
-  Future<void> fuzzMember(Member m, IncrementalCompiler compiler,
-      Uri libraryUri, Context context) async {
+  Future<void> fuzzMember(
+      Member m,
+      IncrementalCompiler compiler,
+      IncrementalCompiler compilerNoNNBD,
+      Uri libraryUri,
+      Context context) async {
     String expression = m.name.text;
     if (m is Field || (m is Procedure && m.isGetter)) {
       // fields and getters are fine as-is
@@ -447,8 +460,7 @@
         expression = "${parent.name}()";
       }
     } else {
-      print("Ignoring $m (${m.runtimeType})");
-      return;
+      throw "Didn't know ${m.runtimeType}";
     }
 
     String? className;
@@ -457,23 +469,36 @@
       className = parent.name;
     }
 
-    await fuzzTryCompile(compiler, "$expression", libraryUri, className,
-        !m.isInstanceMember, context);
-    if (className != null && !m.isInstanceMember) {
-      await fuzzTryCompile(compiler, "$className.$expression", libraryUri, null,
-          !m.isInstanceMember, context);
-    }
-    await fuzzTryCompile(compiler, "$expression.toString()", libraryUri,
+    await fuzzTryCompile(compiler, compilerNoNNBD, "$expression", libraryUri,
         className, !m.isInstanceMember, context);
     if (className != null && !m.isInstanceMember) {
-      await fuzzTryCompile(compiler, "$className.$expression.toString()",
+      await fuzzTryCompile(compiler, compilerNoNNBD, "$className.$expression",
           libraryUri, null, !m.isInstanceMember, context);
     }
-    await fuzzTryCompile(compiler, "$expression.toString() == '42'", libraryUri,
-        className, !m.isInstanceMember, context);
+    await fuzzTryCompile(compiler, compilerNoNNBD, "$expression.toString()",
+        libraryUri, className, !m.isInstanceMember, context);
     if (className != null && !m.isInstanceMember) {
       await fuzzTryCompile(
           compiler,
+          compilerNoNNBD,
+          "$className.$expression.toString()",
+          libraryUri,
+          null,
+          !m.isInstanceMember,
+          context);
+    }
+    await fuzzTryCompile(
+        compiler,
+        compilerNoNNBD,
+        "$expression.toString() == '42'",
+        libraryUri,
+        className,
+        !m.isInstanceMember,
+        context);
+    if (className != null && !m.isInstanceMember) {
+      await fuzzTryCompile(
+          compiler,
+          compilerNoNNBD,
           "$className.$expression.toString() == '42'",
           libraryUri,
           null,
@@ -482,6 +507,7 @@
     }
     await fuzzTryCompile(
         compiler,
+        compilerNoNNBD,
         "() { var x = $expression.toString(); x == '42'; }()",
         libraryUri,
         className,
@@ -490,6 +516,7 @@
     if (className != null && !m.isInstanceMember) {
       await fuzzTryCompile(
           compiler,
+          compilerNoNNBD,
           "() { var x = $className.$expression.toString(); x == '42'; }()",
           libraryUri,
           null,
@@ -498,25 +525,50 @@
     }
   }
 
-  Future<void> fuzzTryCompile(IncrementalCompiler compiler, String expression,
-      Uri libraryUri, String? className, bool isStatic, Context context) async {
+  Future<void> fuzzTryCompile(
+      IncrementalCompiler compiler,
+      IncrementalCompiler compilerNoNNBD,
+      String expression,
+      Uri libraryUri,
+      String? className,
+      bool isStatic,
+      Context context) async {
     context.fuzzCompiles++;
     print("Fuzz compile #${context.fuzzCompiles} "
         "('$expression' in $libraryUri $className)");
-    Procedure? compiledProcedure = await compiler.compileExpression(
-      expression,
-      {},
-      [],
-      "debugExpr",
-      libraryUri,
-      className: className,
-      isStatic: isStatic,
-    );
-    context.takeErrors();
-    if (compiledProcedure != null) {
-      // Confirm we can serialize generated procedure.
-      List<int> list = serializeProcedure(compiledProcedure);
-      assert(list.length > 0);
+    {
+      Procedure? compiledProcedure = await compiler.compileExpression(
+        expression,
+        {},
+        [],
+        "debugExpr",
+        libraryUri,
+        className: className,
+        isStatic: isStatic,
+      );
+      context.takeErrors();
+      if (compiledProcedure != null) {
+        // Confirm we can serialize generated procedure.
+        List<int> list = serializeProcedure(compiledProcedure);
+        assert(list.length > 0);
+      }
+    }
+    {
+      Procedure? compiledProcedure = await compilerNoNNBD.compileExpression(
+        expression,
+        {},
+        [],
+        "debugExpr",
+        libraryUri,
+        className: className,
+        isStatic: isStatic,
+      );
+      context.takeErrors();
+      if (compiledProcedure != null) {
+        // Confirm we can serialize generated procedure.
+        List<int> list = serializeProcedure(compiledProcedure);
+        assert(list.length > 0);
+      }
     }
   }
 
@@ -543,11 +595,27 @@
             "${errors.map((e) => e.plainTextFormatted.first).toList()}");
       }
       Uri dillFileUri = toTestUri("${test.description.shortName}.dill");
+      Uri dillFileNoNNBDUri =
+          toTestUri("${test.description.shortName}.no.nnbd.dill");
       Uint8List dillData = await serializeComponent(component);
       context.fileSystem.entityForUri(dillFileUri).writeAsBytesSync(dillData);
       Set<Uri> beforeFuzzedLibraries = context.fuzzedLibraries.toSet();
-      await compileExpression(
-          test, sourceCompiler, sourceCompilerResult, context);
+      IncrementalCompiler? sourceCompilerNoNNBD;
+      if (context.fuzz) {
+        sourceCompilerNoNNBD =
+            new IncrementalCompiler(context.compilerContextNoNNBD);
+        IncrementalCompilerResult sourceCompilerNoNNBDResult =
+            await sourceCompilerNoNNBD
+                .computeDelta(entryPoints: [test.entryPoint]);
+        Component componentNoNNBD = sourceCompilerNoNNBDResult.component;
+        Uint8List dillDataNoNNBD = await serializeComponent(componentNoNNBD);
+        context.fileSystem
+            .entityForUri(dillFileNoNNBDUri)
+            .writeAsBytesSync(dillDataNoNNBD);
+        context.takeErrors();
+      }
+      await compileExpression(test, sourceCompiler, sourceCompilerNoNNBD,
+          sourceCompilerResult, context);
 
       IncrementalCompiler dillCompiler =
           new IncrementalCompiler(context.compilerContext, dillFileUri);
@@ -560,9 +628,23 @@
       // Since it compiled successfully from source, the bootstrap-from-Dill
       // should also succeed without errors.
       assert(errors.isEmpty);
+
+      IncrementalCompiler? dillCompilerNoNNBD;
+      if (context.fuzz) {
+        dillCompilerNoNNBD = new IncrementalCompiler(
+            context.compilerContextNoNNBD, dillFileNoNNBDUri);
+        IncrementalCompilerResult dillCompilerNoNNBDResult =
+            await dillCompilerNoNNBD
+                .computeDelta(entryPoints: [test.entryPoint]);
+        Component componentNoNNBD = dillCompilerNoNNBDResult.component;
+        componentNoNNBD.computeCanonicalNames();
+        context.takeErrors();
+      }
+
       context.fuzzedLibraries.clear();
       context.fuzzedLibraries.addAll(beforeFuzzedLibraries);
-      await compileExpression(test, dillCompiler, dillCompilerResult, context);
+      await compileExpression(
+          test, dillCompiler, dillCompilerNoNNBD, dillCompilerResult, context);
     }
     return new Result.pass(tests);
   }
@@ -614,17 +696,37 @@
   final ProcessedOptions options =
       new ProcessedOptions(options: optionBuilder, inputs: [entryPoint]);
 
+  final CompilerOptions optionBuilderNoNNBD = new CompilerOptions()
+    ..target = new VmTarget(new TargetFlags())
+    ..verbose = true
+    ..omitPlatform = true
+    ..fileSystem = fs
+    ..sdkSummary = sdkSummary
+    ..onDiagnostic = (DiagnosticMessage message) {
+      printDiagnosticMessage(message, print);
+      errors.add(message);
+    }
+    ..environmentDefines = const {}
+    ..explicitExperimentalFlags = {ExperimentalFlag.nonNullable: false}
+    ..allowedExperimentalFlagsForTesting = const AllowedExperimentalFlags();
+
+  final ProcessedOptions optionsNoNNBD =
+      new ProcessedOptions(options: optionBuilderNoNNBD, inputs: [entryPoint]);
+
   final bool updateExpectations = environment["updateExpectations"] == "true";
 
   final bool fuzz = environment["fuzz"] == "true";
 
   final CompilerContext compilerContext = new CompilerContext(options);
+  final CompilerContext compilerContextNoNNBD =
+      new CompilerContext(optionsNoNNBD);
 
   // Disable colors to ensure that expectation files are the same across
   // platforms and independent of stdin/stderr.
   colors.enableColors = false;
 
-  return new Context(compilerContext, errors, updateExpectations, fuzz);
+  return new Context(
+      compilerContext, compilerContextNoNNBD, errors, updateExpectations, fuzz);
 }
 
 void main([List<String> arguments = const []]) =>
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 5b21bf7..a85eeaf 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -245,6 +245,7 @@
 connectivity
 consideration
 constness
+constraining
 consult
 consumers
 container
@@ -320,6 +321,7 @@
 demangle
 demangled
 dep
+depended
 dependency's
 deps
 dereferencing
@@ -1024,6 +1026,7 @@
 recompiling
 recompute
 recomputed
+reconciliation
 reconstruct
 recorder
 recoveries
@@ -1038,6 +1041,7 @@
 reexports
 ref
 refactoring
+refined
 reflect
 reflectee
 reflective
@@ -1214,6 +1218,7 @@
 stability
 stacktrace
 stacktraces
+stages
 stale
 stand
 starter
diff --git a/pkg/front_end/testcases/general/annotation_typedef_formals.dart.weak.expect b/pkg/front_end/testcases/general/annotation_typedef_formals.dart.weak.expect
index 44bd339..3f168f4 100644
--- a/pkg/front_end/testcases/general/annotation_typedef_formals.dart.weak.expect
+++ b/pkg/front_end/testcases/general/annotation_typedef_formals.dart.weak.expect
@@ -2,8 +2,8 @@
 import self as self;
 import "dart:core" as core;
 
-typedef F = (@#C1 core::int x, core::num y, {@#C2 @#C3 core::String z, core::Object w}) → void;
-typedef G = (@#C1 core::int a, core::num b, [@#C2 @#C3 core::String c, core::Object d]) → void;
+typedef F = (core::int, core::num, {w: core::Object, z: core::String}) → void;
+typedef G = (core::int, core::num, [core::String, core::Object]) → void;
 static const field core::int foo = #C1;
 static const field core::int bar = #C2;
 static const field core::int baz = #C3;
diff --git a/pkg/front_end/testcases/general/annotation_typedef_formals.dart.weak.modular.expect b/pkg/front_end/testcases/general/annotation_typedef_formals.dart.weak.modular.expect
index 44bd339..3f168f4 100644
--- a/pkg/front_end/testcases/general/annotation_typedef_formals.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/general/annotation_typedef_formals.dart.weak.modular.expect
@@ -2,8 +2,8 @@
 import self as self;
 import "dart:core" as core;
 
-typedef F = (@#C1 core::int x, core::num y, {@#C2 @#C3 core::String z, core::Object w}) → void;
-typedef G = (@#C1 core::int a, core::num b, [@#C2 @#C3 core::String c, core::Object d]) → void;
+typedef F = (core::int, core::num, {w: core::Object, z: core::String}) → void;
+typedef G = (core::int, core::num, [core::String, core::Object]) → void;
 static const field core::int foo = #C1;
 static const field core::int bar = #C2;
 static const field core::int baz = #C3;
diff --git a/pkg/front_end/testcases/general/annotation_typedef_formals.dart.weak.transformed.expect b/pkg/front_end/testcases/general/annotation_typedef_formals.dart.weak.transformed.expect
index 44bd339..3f168f4 100644
--- a/pkg/front_end/testcases/general/annotation_typedef_formals.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general/annotation_typedef_formals.dart.weak.transformed.expect
@@ -2,8 +2,8 @@
 import self as self;
 import "dart:core" as core;
 
-typedef F = (@#C1 core::int x, core::num y, {@#C2 @#C3 core::String z, core::Object w}) → void;
-typedef G = (@#C1 core::int a, core::num b, [@#C2 @#C3 core::String c, core::Object d]) → void;
+typedef F = (core::int, core::num, {w: core::Object, z: core::String}) → void;
+typedef G = (core::int, core::num, [core::String, core::Object]) → void;
 static const field core::int foo = #C1;
 static const field core::int bar = #C2;
 static const field core::int baz = #C3;
diff --git a/pkg/front_end/testcases/general/annotation_typedef_formals_resolution.dart.weak.expect b/pkg/front_end/testcases/general/annotation_typedef_formals_resolution.dart.weak.expect
index 95d7ed5..707fc20 100644
--- a/pkg/front_end/testcases/general/annotation_typedef_formals_resolution.dart.weak.expect
+++ b/pkg/front_end/testcases/general/annotation_typedef_formals_resolution.dart.weak.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-typedef F = (@#C1 core::int app) → core::int;
+typedef F = (core::int) → core::int;
 static const field core::int app = #C1;
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/general/annotation_typedef_formals_resolution.dart.weak.modular.expect b/pkg/front_end/testcases/general/annotation_typedef_formals_resolution.dart.weak.modular.expect
index 95d7ed5..707fc20 100644
--- a/pkg/front_end/testcases/general/annotation_typedef_formals_resolution.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/general/annotation_typedef_formals_resolution.dart.weak.modular.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-typedef F = (@#C1 core::int app) → core::int;
+typedef F = (core::int) → core::int;
 static const field core::int app = #C1;
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/general/annotation_typedef_formals_resolution.dart.weak.transformed.expect b/pkg/front_end/testcases/general/annotation_typedef_formals_resolution.dart.weak.transformed.expect
index 95d7ed5..707fc20 100644
--- a/pkg/front_end/testcases/general/annotation_typedef_formals_resolution.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general/annotation_typedef_formals_resolution.dart.weak.transformed.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-typedef F = (@#C1 core::int app) → core::int;
+typedef F = (core::int) → core::int;
 static const field core::int app = #C1;
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/general/annotation_variable_declaration.dart.weak.expect b/pkg/front_end/testcases/general/annotation_variable_declaration.dart.weak.expect
index d111b25..8329d57 100644
--- a/pkg/front_end/testcases/general/annotation_variable_declaration.dart.weak.expect
+++ b/pkg/front_end/testcases/general/annotation_variable_declaration.dart.weak.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-typedef hest_t = ({@#C1 dynamic named}) → dynamic;
+typedef hest_t = ({named: dynamic}) → dynamic;
 class Bar extends core::Object /*hasConstConstructor*/  {
   const constructor •() → self::Bar
     : super core::Object::•()
diff --git a/pkg/front_end/testcases/general/annotation_variable_declaration.dart.weak.modular.expect b/pkg/front_end/testcases/general/annotation_variable_declaration.dart.weak.modular.expect
index d111b25..8329d57 100644
--- a/pkg/front_end/testcases/general/annotation_variable_declaration.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/general/annotation_variable_declaration.dart.weak.modular.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-typedef hest_t = ({@#C1 dynamic named}) → dynamic;
+typedef hest_t = ({named: dynamic}) → dynamic;
 class Bar extends core::Object /*hasConstConstructor*/  {
   const constructor •() → self::Bar
     : super core::Object::•()
diff --git a/pkg/front_end/testcases/general/annotation_variable_declaration.dart.weak.transformed.expect b/pkg/front_end/testcases/general/annotation_variable_declaration.dart.weak.transformed.expect
index d111b25..8329d57 100644
--- a/pkg/front_end/testcases/general/annotation_variable_declaration.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general/annotation_variable_declaration.dart.weak.transformed.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-typedef hest_t = ({@#C1 dynamic named}) → dynamic;
+typedef hest_t = ({named: dynamic}) → dynamic;
 class Bar extends core::Object /*hasConstConstructor*/  {
   const constructor •() → self::Bar
     : super core::Object::•()
diff --git a/pkg/front_end/testcases/general/redirecting_factory_invocation_metadata.dart.weak.expect b/pkg/front_end/testcases/general/redirecting_factory_invocation_metadata.dart.weak.expect
index 95a7fb9..41d3f4f 100644
--- a/pkg/front_end/testcases/general/redirecting_factory_invocation_metadata.dart.weak.expect
+++ b/pkg/front_end/testcases/general/redirecting_factory_invocation_metadata.dart.weak.expect
@@ -11,13 +11,13 @@
 @#C1
 part redirecting_factory_invocation_metadata_lib.dart;
 @#C1
-typedef Typedef1<@#C1 unrelated T extends core::Object? = dynamic> = <T extends core::Object? = dynamic>(@#C1 self::Class<dynamic> #t1, [@#C1 self::Class<dynamic> #t2]) → dynamic;
+typedef Typedef1<@#C1 unrelated T extends core::Object? = dynamic> = <T extends core::Object? = dynamic>(self::Class<dynamic>, [self::Class<dynamic>]) → dynamic;
 @#C1
-typedef Typedef2<@#C1 unrelated T extends core::Object? = dynamic> = <T extends core::Object? = dynamic>(@#C1 self::Class<dynamic> #t3, {@#C1 self::Class<dynamic> o2}) → dynamic;
+typedef Typedef2<@#C1 unrelated T extends core::Object? = dynamic> = <T extends core::Object? = dynamic>(self::Class<dynamic>, {o2: self::Class<dynamic>}) → dynamic;
 @#C1
-typedef Typedef3<@#C1 unrelated T extends core::Object? = dynamic> = (@#C1 dynamic o1, [@#C1 dynamic o2]) → void;
+typedef Typedef3<@#C1 unrelated T extends core::Object? = dynamic> = (dynamic, [dynamic]) → void;
 @#C1
-typedef Typedef4<@#C1 unrelated T extends core::Object? = dynamic> = (@#C1 dynamic o1, {@#C1 dynamic o2}) → void;
+typedef Typedef4<@#C1 unrelated T extends core::Object? = dynamic> = (dynamic, {o2: dynamic}) → void;
 @#C1
 class Const extends core::Object /*hasConstConstructor*/  {
   static final field dynamic _redirecting# = <dynamic>[#C2]/*isLegacy*/;
diff --git a/pkg/front_end/testcases/general/redirecting_factory_invocation_metadata.dart.weak.modular.expect b/pkg/front_end/testcases/general/redirecting_factory_invocation_metadata.dart.weak.modular.expect
index 95a7fb9..41d3f4f 100644
--- a/pkg/front_end/testcases/general/redirecting_factory_invocation_metadata.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/general/redirecting_factory_invocation_metadata.dart.weak.modular.expect
@@ -11,13 +11,13 @@
 @#C1
 part redirecting_factory_invocation_metadata_lib.dart;
 @#C1
-typedef Typedef1<@#C1 unrelated T extends core::Object? = dynamic> = <T extends core::Object? = dynamic>(@#C1 self::Class<dynamic> #t1, [@#C1 self::Class<dynamic> #t2]) → dynamic;
+typedef Typedef1<@#C1 unrelated T extends core::Object? = dynamic> = <T extends core::Object? = dynamic>(self::Class<dynamic>, [self::Class<dynamic>]) → dynamic;
 @#C1
-typedef Typedef2<@#C1 unrelated T extends core::Object? = dynamic> = <T extends core::Object? = dynamic>(@#C1 self::Class<dynamic> #t3, {@#C1 self::Class<dynamic> o2}) → dynamic;
+typedef Typedef2<@#C1 unrelated T extends core::Object? = dynamic> = <T extends core::Object? = dynamic>(self::Class<dynamic>, {o2: self::Class<dynamic>}) → dynamic;
 @#C1
-typedef Typedef3<@#C1 unrelated T extends core::Object? = dynamic> = (@#C1 dynamic o1, [@#C1 dynamic o2]) → void;
+typedef Typedef3<@#C1 unrelated T extends core::Object? = dynamic> = (dynamic, [dynamic]) → void;
 @#C1
-typedef Typedef4<@#C1 unrelated T extends core::Object? = dynamic> = (@#C1 dynamic o1, {@#C1 dynamic o2}) → void;
+typedef Typedef4<@#C1 unrelated T extends core::Object? = dynamic> = (dynamic, {o2: dynamic}) → void;
 @#C1
 class Const extends core::Object /*hasConstConstructor*/  {
   static final field dynamic _redirecting# = <dynamic>[#C2]/*isLegacy*/;
diff --git a/pkg/front_end/testcases/general/redirecting_factory_invocation_metadata.dart.weak.transformed.expect b/pkg/front_end/testcases/general/redirecting_factory_invocation_metadata.dart.weak.transformed.expect
index 95a7fb9..41d3f4f 100644
--- a/pkg/front_end/testcases/general/redirecting_factory_invocation_metadata.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general/redirecting_factory_invocation_metadata.dart.weak.transformed.expect
@@ -11,13 +11,13 @@
 @#C1
 part redirecting_factory_invocation_metadata_lib.dart;
 @#C1
-typedef Typedef1<@#C1 unrelated T extends core::Object? = dynamic> = <T extends core::Object? = dynamic>(@#C1 self::Class<dynamic> #t1, [@#C1 self::Class<dynamic> #t2]) → dynamic;
+typedef Typedef1<@#C1 unrelated T extends core::Object? = dynamic> = <T extends core::Object? = dynamic>(self::Class<dynamic>, [self::Class<dynamic>]) → dynamic;
 @#C1
-typedef Typedef2<@#C1 unrelated T extends core::Object? = dynamic> = <T extends core::Object? = dynamic>(@#C1 self::Class<dynamic> #t3, {@#C1 self::Class<dynamic> o2}) → dynamic;
+typedef Typedef2<@#C1 unrelated T extends core::Object? = dynamic> = <T extends core::Object? = dynamic>(self::Class<dynamic>, {o2: self::Class<dynamic>}) → dynamic;
 @#C1
-typedef Typedef3<@#C1 unrelated T extends core::Object? = dynamic> = (@#C1 dynamic o1, [@#C1 dynamic o2]) → void;
+typedef Typedef3<@#C1 unrelated T extends core::Object? = dynamic> = (dynamic, [dynamic]) → void;
 @#C1
-typedef Typedef4<@#C1 unrelated T extends core::Object? = dynamic> = (@#C1 dynamic o1, {@#C1 dynamic o2}) → void;
+typedef Typedef4<@#C1 unrelated T extends core::Object? = dynamic> = (dynamic, {o2: dynamic}) → void;
 @#C1
 class Const extends core::Object /*hasConstConstructor*/  {
   static final field dynamic _redirecting# = <dynamic>[#C2]/*isLegacy*/;
diff --git a/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.expect b/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.expect
index 50a886c..3444c42 100644
--- a/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.expect
+++ b/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.expect
@@ -7,7 +7,6 @@
 //                ^
 //
 import self as self;
-import "dart:core" as core;
 
 typedef Handle = invalid-type;
 static method main() → dynamic {
diff --git a/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.modular.expect b/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.modular.expect
index 50a886c..3444c42 100644
--- a/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.modular.expect
@@ -7,7 +7,6 @@
 //                ^
 //
 import self as self;
-import "dart:core" as core;
 
 typedef Handle = invalid-type;
 static method main() → dynamic {
diff --git a/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.outline.expect b/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.outline.expect
index 74c6c6a..dc3f69b 100644
--- a/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.outline.expect
@@ -7,7 +7,6 @@
 //                ^
 //
 import self as self;
-import "dart:core" as core;
 
 typedef Handle = invalid-type;
 static method main() → dynamic
diff --git a/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.transformed.expect b/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.transformed.expect
index 50a886c..3444c42 100644
--- a/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.transformed.expect
@@ -7,7 +7,6 @@
 //                ^
 //
 import self as self;
-import "dart:core" as core;
 
 typedef Handle = invalid-type;
 static method main() → dynamic {
diff --git a/pkg/front_end/tool/ast_model.dart b/pkg/front_end/tool/ast_model.dart
index e06996a..9979dcb 100644
--- a/pkg/front_end/tool/ast_model.dart
+++ b/pkg/front_end/tool/ast_model.dart
@@ -128,9 +128,6 @@
   },
   'Typedef': {
     'typeParameters': FieldRule(isDeclaration: true),
-    'typeParametersOfFunctionType': FieldRule(isDeclaration: false),
-    'positionalParameters': FieldRule(isDeclaration: false),
-    'namedParameters': FieldRule(isDeclaration: false),
   },
   'TypedefTearOff': {
     'typeParameters': FieldRule(isDeclaration: true),
diff --git a/pkg/kernel/binary.md b/pkg/kernel/binary.md
index 3df728f..b3f1a41 100644
--- a/pkg/kernel/binary.md
+++ b/pkg/kernel/binary.md
@@ -147,7 +147,7 @@
 
 type ComponentFile {
   UInt32 magic = 0x90ABCDEF;
-  UInt32 formatVersion = 76;
+  UInt32 formatVersion = 77;
   Byte[10] shortSdkHash;
   List<String> problemsAsJson; // Described in problems.md.
   Library[] libraries;
@@ -288,9 +288,6 @@
   List<Expression> annotations;
   List<TypeParameter> typeParameters;
   DartType type;
-  List<TypeParameter> typeParametersOfFunctionType;
-  List<VariableDeclarationPlain> positionalParameters;
-  List<VariableDeclarationPlain> namedParameters;
 }
 
 type Combinator {
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index 17ac253..c98194e 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -840,14 +840,6 @@
   // TODO(johnniwinther): Make this non-nullable.
   DartType? type;
 
-  // The following fields describe parameters of the underlying type when
-  // that is a function type.  They are needed to keep such attributes as names
-  // and annotations. When the underlying type is not a function type, they are
-  // empty.
-  final List<TypeParameter> typeParametersOfFunctionType;
-  final List<VariableDeclaration> positionalParameters;
-  final List<VariableDeclaration> namedParameters;
-
   Typedef(this.name, this.type,
       {Reference? reference,
       required this.fileUri,
@@ -858,16 +850,8 @@
       // ignore: unnecessary_null_comparison
       : assert(fileUri != null),
         this.typeParameters = typeParameters ?? <TypeParameter>[],
-        this.typeParametersOfFunctionType =
-            typeParametersOfFunctionType ?? <TypeParameter>[],
-        this.positionalParameters =
-            positionalParameters ?? <VariableDeclaration>[],
-        this.namedParameters = namedParameters ?? <VariableDeclaration>[],
         super(reference) {
     setParents(this.typeParameters, this);
-    setParents(this.typeParametersOfFunctionType, this);
-    setParents(this.positionalParameters, this);
-    setParents(this.namedParameters, this);
   }
 
   Library get enclosingLibrary => parent as Library;
@@ -883,9 +867,6 @@
     visitList(annotations, v);
     visitList(typeParameters, v);
     type?.accept(v);
-    visitList(typeParametersOfFunctionType, v);
-    visitList(positionalParameters, v);
-    visitList(namedParameters, v);
   }
 
   @override
@@ -895,9 +876,6 @@
     if (type != null) {
       type = v.visitDartType(type!);
     }
-    v.transformList(typeParametersOfFunctionType, this);
-    v.transformList(positionalParameters, this);
-    v.transformList(namedParameters, this);
   }
 
   @override
@@ -912,9 +890,6 @@
         type = newType;
       }
     }
-    v.transformTypeParameterList(typeParametersOfFunctionType, this);
-    v.transformVariableDeclarationList(positionalParameters, this);
-    v.transformVariableDeclarationList(namedParameters, this);
   }
 
   @override
diff --git a/pkg/kernel/lib/binary/ast_from_binary.dart b/pkg/kernel/lib/binary/ast_from_binary.dart
index e067807..8952e40 100644
--- a/pkg/kernel/lib/binary/ast_from_binary.dart
+++ b/pkg/kernel/lib/binary/ast_from_binary.dart
@@ -1340,13 +1340,6 @@
     node.annotations = readAnnotationList(node);
     readAndPushTypeParameterList(node.typeParameters, node);
     DartType type = readDartType();
-    readAndPushTypeParameterList(node.typeParametersOfFunctionType, node);
-    node.positionalParameters.clear();
-    node.positionalParameters.addAll(readAndPushVariableDeclarationList());
-    setParents(node.positionalParameters, node);
-    node.namedParameters.clear();
-    node.namedParameters.addAll(readAndPushVariableDeclarationList());
-    setParents(node.namedParameters, node);
     typeParameterStack.length = 0;
     variableStack.length = 0;
     node.fileOffset = fileOffset;
diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart
index dc9ece8..c048177 100644
--- a/pkg/kernel/lib/binary/ast_to_binary.dart
+++ b/pkg/kernel/lib/binary/ast_to_binary.dart
@@ -1166,12 +1166,6 @@
     writeNodeList(node.typeParameters);
     writeNode(node.type!);
 
-    enterScope(typeParameters: node.typeParametersOfFunctionType);
-    writeNodeList(node.typeParametersOfFunctionType);
-    writeVariableDeclarationList(node.positionalParameters);
-    writeVariableDeclarationList(node.namedParameters);
-
-    leaveScope(typeParameters: node.typeParametersOfFunctionType);
     leaveScope(typeParameters: node.typeParameters, variableScope: true);
     leaveScope(memberScope: true);
   }
diff --git a/pkg/kernel/lib/binary/tag.dart b/pkg/kernel/lib/binary/tag.dart
index a8a29ff..39dbd8c 100644
--- a/pkg/kernel/lib/binary/tag.dart
+++ b/pkg/kernel/lib/binary/tag.dart
@@ -176,7 +176,7 @@
   /// Internal version of kernel binary format.
   /// Bump it when making incompatible changes in kernel binaries.
   /// Keep in sync with runtime/vm/kernel_binary.h, pkg/kernel/binary.md.
-  static const int BinaryFormatVersion = 76;
+  static const int BinaryFormatVersion = 77;
 }
 
 abstract class ConstantTag {
diff --git a/pkg/kernel/lib/src/equivalence.dart b/pkg/kernel/lib/src/equivalence.dart
index 9e8ae3f..3f11abc 100644
--- a/pkg/kernel/lib/src/equivalence.dart
+++ b/pkg/kernel/lib/src/equivalence.dart
@@ -1436,15 +1436,6 @@
     if (!checkTypedef_type(visitor, node, other)) {
       result = visitor.resultOnInequivalence;
     }
-    if (!checkTypedef_typeParametersOfFunctionType(visitor, node, other)) {
-      result = visitor.resultOnInequivalence;
-    }
-    if (!checkTypedef_positionalParameters(visitor, node, other)) {
-      result = visitor.resultOnInequivalence;
-    }
-    if (!checkTypedef_namedParameters(visitor, node, other)) {
-      result = visitor.resultOnInequivalence;
-    }
     if (!checkTypedef_reference(visitor, node, other)) {
       result = visitor.resultOnInequivalence;
     }
@@ -4634,30 +4625,6 @@
     return visitor.checkNodes(node.type, other.type, 'type');
   }
 
-  bool checkTypedef_typeParametersOfFunctionType(
-      EquivalenceVisitor visitor, Typedef node, Typedef other) {
-    return visitor.checkLists(
-        node.typeParametersOfFunctionType,
-        other.typeParametersOfFunctionType,
-        visitor.checkDeclarations,
-        'typeParametersOfFunctionType');
-  }
-
-  bool checkTypedef_positionalParameters(
-      EquivalenceVisitor visitor, Typedef node, Typedef other) {
-    return visitor.checkLists(
-        node.positionalParameters,
-        other.positionalParameters,
-        visitor.checkDeclarations,
-        'positionalParameters');
-  }
-
-  bool checkTypedef_namedParameters(
-      EquivalenceVisitor visitor, Typedef node, Typedef other) {
-    return visitor.checkLists(node.namedParameters, other.namedParameters,
-        visitor.checkDeclarations, 'namedParameters');
-  }
-
   bool checkTypedef_reference(
       EquivalenceVisitor visitor, Typedef node, Typedef other) {
     return checkNamedNode_reference(visitor, node, other);
diff --git a/pkg/kernel/lib/text/ast_to_text.dart b/pkg/kernel/lib/text/ast_to_text.dart
index 94b7cf2..46969af 100644
--- a/pkg/kernel/lib/text/ast_to_text.dart
+++ b/pkg/kernel/lib/text/ast_to_text.dart
@@ -853,9 +853,7 @@
     }
   }
 
-  void writeFunctionType(FunctionType node,
-      {List<VariableDeclaration>? typedefPositional,
-      List<VariableDeclaration>? typedefNamed}) {
+  void writeFunctionType(FunctionType node) {
     if (state == WORD) {
       ensureSpace();
     }
@@ -863,38 +861,14 @@
     writeSymbol('(');
     List<DartType> positional = node.positionalParameters;
 
-    bool parametersAnnotated = false;
-    if (typedefPositional != null) {
-      for (VariableDeclaration formal in typedefPositional) {
-        parametersAnnotated =
-            parametersAnnotated || formal.annotations.length > 0;
-      }
-    }
-    if (typedefNamed != null) {
-      for (VariableDeclaration formal in typedefNamed) {
-        parametersAnnotated =
-            parametersAnnotated || formal.annotations.length > 0;
-      }
-    }
-
-    if (parametersAnnotated && typedefPositional != null) {
-      writeList(typedefPositional.take(node.requiredParameterCount),
-          writeVariableDeclaration);
-    } else {
-      writeList(positional.take(node.requiredParameterCount), writeType);
-    }
+    writeList(positional.take(node.requiredParameterCount), writeType);
 
     if (node.requiredParameterCount < positional.length) {
       if (node.requiredParameterCount > 0) {
         writeComma();
       }
       writeSymbol('[');
-      if (parametersAnnotated && typedefPositional != null) {
-        writeList(typedefPositional.skip(node.requiredParameterCount),
-            writeVariableDeclaration);
-      } else {
-        writeList(positional.skip(node.requiredParameterCount), writeType);
-      }
+      writeList(positional.skip(node.requiredParameterCount), writeType);
       writeSymbol(']');
     }
     if (node.namedParameters.isNotEmpty) {
@@ -902,11 +876,7 @@
         writeComma();
       }
       writeSymbol('{');
-      if (parametersAnnotated && typedefNamed != null) {
-        writeList(typedefNamed, writeVariableDeclaration);
-      } else {
-        writeList(node.namedParameters, visitNamedType);
-      }
+      writeList(node.namedParameters, visitNamedType);
       writeSymbol('}');
     }
     writeSymbol(')');
@@ -1483,9 +1453,7 @@
     writeSpaced('=');
     DartType? type = node.type;
     if (type is FunctionType) {
-      writeFunctionType(type,
-          typedefPositional: node.positionalParameters,
-          typedefNamed: node.namedParameters);
+      writeFunctionType(type);
     } else {
       writeNode(type);
     }
diff --git a/pkg/kernel/lib/verifier.dart b/pkg/kernel/lib/verifier.dart
index 858e978..d9f95f6 100644
--- a/pkg/kernel/lib/verifier.dart
+++ b/pkg/kernel/lib/verifier.dart
@@ -282,8 +282,7 @@
     assert(state == null);
     typedefState[node] = TypedefState.BeingChecked;
     Set<TypeParameter> savedTypeParameters = typeParametersInScope;
-    typeParametersInScope = node.typeParameters.toSet()
-      ..addAll(node.typeParametersOfFunctionType);
+    typeParametersInScope = node.typeParameters.toSet();
     TreeNode? savedParent = currentParent;
     currentParent = node;
     // Visit children without checking the parent pointer on the typedef itself
diff --git a/pkg/vm/lib/transformations/type_flow/transformer.dart b/pkg/vm/lib/transformations/type_flow/transformer.dart
index 02cab5e..209910e 100644
--- a/pkg/vm/lib/transformations/type_flow/transformer.dart
+++ b/pkg/vm/lib/transformations/type_flow/transformer.dart
@@ -875,11 +875,6 @@
     if (_usedTypedefs.add(typedef)) {
       typedef.annotations = const <Expression>[];
       _pass1.transformTypeParameterList(typedef.typeParameters, typedef);
-      _pass1.transformTypeParameterList(
-          typedef.typeParametersOfFunctionType, typedef);
-      _pass1.transformVariableDeclarationList(
-          typedef.positionalParameters, typedef);
-      _pass1.transformVariableDeclarationList(typedef.namedParameters, typedef);
       typedef.type?.accept(typeVisitor);
     }
   }
diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn
index f30a460..3e6c317 100644
--- a/runtime/BUILD.gn
+++ b/runtime/BUILD.gn
@@ -203,11 +203,13 @@
       "-ggdb3",
       "-fno-rtti",
       "-fno-exceptions",
-      "-fno-strict-vtable-pointers",  # Handle assignment updates vtable
-                                      # pointers.
     ]
     if (is_clang) {
-      cflags += [ "-Wimplicit-fallthrough" ]
+      cflags += [
+        "-Wimplicit-fallthrough",
+        "-fno-strict-vtable-pointers",  # Handle assignment updates vtable
+                                        # pointers.
+      ]
     } else {
       cflags += [ "-Wno-cast-function-type" ]
     }
diff --git a/runtime/tests/vm/dart/flutter_regress_100441_test.dart b/runtime/tests/vm/dart/flutter_regress_100441_test.dart
new file mode 100644
index 0000000..d51cdff
--- /dev/null
+++ b/runtime/tests/vm/dart/flutter_regress_100441_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:expect/expect.dart';
+
+StackTrace? stackTrace;
+
+main() async {
+  final values = [];
+  await for (final value in produce()) {
+    values.add(value);
+  }
+  Expect.equals('foo', values.single);
+  Expect.isNotNull(stackTrace!);
+}
+
+Stream<String> produce() async* {
+  await for (String response in produceInner()) {
+    yield response;
+  }
+}
+
+Stream<String> produceInner() async* {
+  yield 'foo';
+  stackTrace = StackTrace.current;
+}
diff --git a/runtime/tests/vm/dart_2/flutter_regress_100441_test.dart b/runtime/tests/vm/dart_2/flutter_regress_100441_test.dart
new file mode 100644
index 0000000..9250b6b
--- /dev/null
+++ b/runtime/tests/vm/dart_2/flutter_regress_100441_test.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// @dart=2.9
+
+import 'dart:async';
+
+import 'package:expect/expect.dart';
+
+StackTrace stackTrace;
+
+main() async {
+  final values = [];
+  await for (final value in produce()) {
+    values.add(value);
+  }
+  Expect.equals('foo', values.single);
+  Expect.isNotNull(stackTrace);
+}
+
+Stream<String> produce() async* {
+  await for (String response in produceInner()) {
+    yield response;
+  }
+}
+
+Stream<String> produceInner() async* {
+  yield 'foo';
+  stackTrace = StackTrace.current;
+}
diff --git a/runtime/vm/compiler/assembler/assembler_ia32.cc b/runtime/vm/compiler/assembler/assembler_ia32.cc
index a6d5523..de73c0f 100644
--- a/runtime/vm/compiler/assembler/assembler_ia32.cc
+++ b/runtime/vm/compiler/assembler/assembler_ia32.cc
@@ -2180,7 +2180,7 @@
   addl(dest, inc_imm);
 }
 
-void Assembler::LoadDoubleConstant(XmmRegister dst, double value) {
+void Assembler::LoadDImmediate(XmmRegister dst, double value) {
   // TODO(5410843): Need to have a code constants table.
   int64_t constant = bit_cast<int64_t, double>(value);
   pushl(Immediate(Utils::High32Bits(constant)));
diff --git a/runtime/vm/compiler/assembler/assembler_ia32.h b/runtime/vm/compiler/assembler/assembler_ia32.h
index f059fb2..8cee67d 100644
--- a/runtime/vm/compiler/assembler/assembler_ia32.h
+++ b/runtime/vm/compiler/assembler/assembler_ia32.h
@@ -713,6 +713,8 @@
     }
   }
 
+  void LoadDImmediate(XmmRegister dst, double value);
+
   void Drop(intptr_t stack_elements);
 
   void LoadIsolate(Register dst);
@@ -732,7 +734,6 @@
 
   void PushObject(const Object& object);
   void CompareObject(Register reg, const Object& object);
-  void LoadDoubleConstant(XmmRegister dst, double value);
 
   void LoadCompressed(Register dest, const Address& slot) { movl(dest, slot); }
 
diff --git a/runtime/vm/compiler/assembler/assembler_ia32_test.cc b/runtime/vm/compiler/assembler/assembler_ia32_test.cc
index 43c4818..e89073d 100644
--- a/runtime/vm/compiler/assembler/assembler_ia32_test.cc
+++ b/runtime/vm/compiler/assembler/assembler_ia32_test.cc
@@ -4558,8 +4558,8 @@
       "ret\n");
 }
 
-ASSEMBLER_TEST_GENERATE(TestLoadDoubleConstant, assembler) {
-  __ LoadDoubleConstant(XMM3, -12.34);
+ASSEMBLER_TEST_GENERATE(TestLoadDImmediate, assembler) {
+  __ LoadDImmediate(XMM3, -12.34);
   __ pushl(EAX);
   __ pushl(EAX);
   __ movsd(Address(ESP, 0), XMM3);
@@ -4569,9 +4569,9 @@
   __ ret();
 }
 
-ASSEMBLER_TEST_RUN(TestLoadDoubleConstant, test) {
-  typedef double (*TestLoadDoubleConstantCode)();
-  double res = reinterpret_cast<TestLoadDoubleConstantCode>(test->entry())();
+ASSEMBLER_TEST_RUN(TestLoadDImmediate, test) {
+  typedef double (*TestLoadDImmediateCode)();
+  double res = reinterpret_cast<TestLoadDImmediateCode>(test->entry())();
   EXPECT_FLOAT_EQ(-12.34, res, 0.0001);
   EXPECT_DISASSEMBLY(
       "push 0xc028ae14\n"
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index 08da16e..3ec06a6 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -1796,9 +1796,6 @@
         result_location = Location::FpuRegisterLocation(
             AllocateFreeFpuRegister(blocked_fpu_registers));
         break;
-      case Location::kRequiresStackSlot:
-        UNREACHABLE();
-        break;
     }
     locs->set_out(0, result_location);
   }
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index f9e6f0e..30f6bec 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -6494,26 +6494,21 @@
 LocationSummary* FfiCallInstr::MakeLocationSummaryInternal(
     Zone* zone,
     bool is_optimizing,
-    const Register temp) const {
-  // The temporary register needs to be callee-saved and not an argument
-  // register.
-  ASSERT(((1 << CallingConventions::kFfiAnyNonAbiRegister) &
-          CallingConventions::kArgumentRegisters) == 0);
+    const RegList temps) const {
+  auto contains_call =
+      is_leaf_ ? LocationSummary::kNativeLeafCall : LocationSummary::kCall;
 
-  // TODO(dartbug.com/45468): Investigate whether we can avoid spilling
-  // registers across ffi leaf calls by not using `kCall` here.
   LocationSummary* summary = new (zone) LocationSummary(
       zone, /*num_inputs=*/InputCount(),
-      /*num_temps=*/temp == kNoRegister ? 2 : 3, LocationSummary::kCall);
+      /*num_temps=*/Utils::CountOneBitsWord(temps), contains_call);
 
-  const Register temp0 = CallingConventions::kFfiAnyNonAbiRegister;
-  const Register temp1 = CallingConventions::kSecondNonArgumentRegister;
-  ASSERT(temp0 != temp1);
-  summary->set_temp(0, Location::RegisterLocation(temp0));
-  summary->set_temp(1, Location::RegisterLocation(temp1));
-
-  if (temp != kNoRegister) {
-    summary->set_temp(2, Location::RegisterLocation(temp));
+  intptr_t reg_i = 0;
+  for (intptr_t reg = 0; reg < kNumberOfCpuRegisters; reg++) {
+    if ((temps & (1 << reg)) != 0) {
+      summary->set_temp(reg_i,
+                        Location::RegisterLocation(static_cast<Register>(reg)));
+      reg_i++;
+    }
   }
 
   summary->set_in(TargetAddressIndex(),
@@ -6524,10 +6519,7 @@
   }
 
   if (marshaller_.PassTypedData()) {
-    // The register allocator already preserves this value across the call on
-    // a stack slot, so we'll use the spilled value directly.
-    summary->set_in(TypedDataIndex(), Location::RequiresStackSlot());
-
+    summary->set_in(TypedDataIndex(), Location::Any());
     // We don't care about return location, but we need to pass a register.
     summary->set_out(
         0, Location::RegisterLocation(CallingConventions::kReturnReg));
@@ -6654,14 +6646,14 @@
 void FfiCallInstr::EmitReturnMoves(FlowGraphCompiler* compiler,
                                    const Register temp0,
                                    const Register temp1) {
-  __ Comment("EmitReturnMoves");
-
   const auto& returnLocation =
       marshaller_.Location(compiler::ffi::kResultIndex);
   if (returnLocation.payload_type().IsVoid()) {
     return;
   }
 
+  __ Comment("EmitReturnMoves");
+
   NoTemporaryAllocator no_temp;
   if (returnLocation.IsRegisters() || returnLocation.IsFpuRegisters()) {
     const auto& src = returnLocation;
@@ -6675,15 +6667,20 @@
 
     // Get the typed data pointer which we have pinned to a stack slot.
     const Location typed_data_loc = locs()->in(TypedDataIndex());
-    ASSERT(typed_data_loc.IsStackSlot());
-    ASSERT(typed_data_loc.base_reg() == FPREG);
-    // If this is a leaf call there is no extra call frame to step through.
-    if (is_leaf_) {
-      __ LoadMemoryValue(temp0, FPREG, typed_data_loc.ToStackSlotOffset());
+    if (typed_data_loc.IsStackSlot()) {
+      ASSERT(typed_data_loc.base_reg() == FPREG);
+      // If this is a leaf call there is no extra call frame to step through.
+      if (is_leaf_) {
+        __ LoadMemoryValue(temp0, FPREG, typed_data_loc.ToStackSlotOffset());
+      } else {
+        __ LoadMemoryValue(
+            temp0, FPREG,
+            kSavedCallerFpSlotFromFp * compiler::target::kWordSize);
+        __ LoadMemoryValue(temp0, temp0, typed_data_loc.ToStackSlotOffset());
+      }
     } else {
-      __ LoadMemoryValue(
-          temp0, FPREG, kSavedCallerFpSlotFromFp * compiler::target::kWordSize);
-      __ LoadMemoryValue(temp0, temp0, typed_data_loc.ToStackSlotOffset());
+      compiler->EmitMove(Location::RegisterLocation(temp0), typed_data_loc,
+                         &no_temp);
     }
     __ LoadField(temp0,
                  compiler::FieldAddress(
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index 65a9afb..a7dd7aa 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -5305,7 +5305,7 @@
 
   LocationSummary* MakeLocationSummaryInternal(Zone* zone,
                                                bool is_optimizing,
-                                               const Register temp) const;
+                                               const RegList temps) const;
 
   // Clobbers both given registers.
   // `saved_fp` is used as the frame base to rebase off of.
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index 411d58b..3dab29a 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -1402,27 +1402,34 @@
   __ Drop(ArgumentCount());  // Drop the arguments.
 }
 
+#define R(r) (1 << r)
+
 LocationSummary* FfiCallInstr::MakeLocationSummary(Zone* zone,
                                                    bool is_optimizing) const {
-  return MakeLocationSummaryInternal(zone, is_optimizing, R0);
+  return MakeLocationSummaryInternal(
+      zone, is_optimizing,
+      (R(R0) | R(CallingConventions::kFfiAnyNonAbiRegister) |
+       R(CallingConventions::kSecondNonArgumentRegister)));
 }
 
+#undef R
+
 void FfiCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  const Register branch = locs()->in(TargetAddressIndex()).reg();
+
+  // The temps are indexed according to their register number.
+  const Register temp2 = locs()->temp(0).reg();
   // For regular calls, this holds the FP for rebasing the original locations
   // during EmitParamMoves.
   // For leaf calls, this holds the SP used to restore the pre-aligned SP after
   // the call.
-  const Register saved_fp_or_sp = locs()->temp(0).reg();
-  RELEASE_ASSERT((CallingConventions::kCalleeSaveCpuRegisters &
-                  (1 << saved_fp_or_sp)) != 0);
-  const Register temp1 = locs()->temp(1).reg();
-  const Register temp2 = locs()->temp(2).reg();
-  const Register branch = locs()->in(TargetAddressIndex()).reg();
+  const Register saved_fp_or_sp = locs()->temp(1).reg();
+  const Register temp1 = locs()->temp(2).reg();
 
   // Ensure these are callee-saved register and are preserved across the call.
   ASSERT((CallingConventions::kCalleeSaveCpuRegisters &
           (1 << saved_fp_or_sp)) != 0);
-  // temp doesn't need to be preserved.
+  // Other temps don't need to be preserved.
 
   __ mov(saved_fp_or_sp,
          is_leaf_ ? compiler::Operand(SPREG) : compiler::Operand(FPREG));
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index 410cb0e..7ba8603 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -1227,27 +1227,36 @@
   __ Drop(ArgumentCount());  // Drop the arguments.
 }
 
+#define R(r) (1 << r)
+
 LocationSummary* FfiCallInstr::MakeLocationSummary(Zone* zone,
                                                    bool is_optimizing) const {
-  return MakeLocationSummaryInternal(zone, is_optimizing, R11);
+  return MakeLocationSummaryInternal(
+      zone, is_optimizing,
+      (R(CallingConventions::kSecondNonArgumentRegister) | R(R11) |
+       R(CallingConventions::kFfiAnyNonAbiRegister) | R(R25)));
 }
 
+#undef R
+
 void FfiCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  const Register branch = locs()->in(TargetAddressIndex()).reg();
+
+  // The temps are indexed according to their register number.
+  const Register temp1 = locs()->temp(0).reg();
+  const Register temp2 = locs()->temp(1).reg();
   // For regular calls, this holds the FP for rebasing the original locations
   // during EmitParamMoves.
   // For leaf calls, this holds the SP used to restore the pre-aligned SP after
   // the call.
-  const Register saved_fp_or_sp = locs()->temp(0).reg();
-  RELEASE_ASSERT((CallingConventions::kCalleeSaveCpuRegisters &
-                  (1 << saved_fp_or_sp)) != 0);
-  const Register temp1 = locs()->temp(1).reg();
-  const Register temp2 = locs()->temp(2).reg();
-  const Register branch = locs()->in(TargetAddressIndex()).reg();
+  const Register saved_fp_or_sp = locs()->temp(2).reg();
+  const Register temp_csp = locs()->temp(3).reg();
 
   // Ensure these are callee-saved register and are preserved across the call.
   ASSERT((CallingConventions::kCalleeSaveCpuRegisters &
           (1 << saved_fp_or_sp)) != 0);
-  // temps don't need to be preserved.
+  ASSERT((CallingConventions::kCalleeSaveCpuRegisters & (1 << temp_csp)) != 0);
+  // Other temps don't need to be preserved.
 
   __ mov(saved_fp_or_sp, is_leaf_ ? SPREG : FPREG);
 
@@ -1279,14 +1288,14 @@
 
     // We are entering runtime code, so the C stack pointer must be restored
     // from the stack limit to the top of the stack.
-    __ mov(R25, CSP);
+    __ mov(temp_csp, CSP);
     __ mov(CSP, SP);
 
     __ blr(branch);
 
     // Restore the Dart stack pointer.
     __ mov(SP, CSP);
-    __ mov(CSP, R25);
+    __ mov(CSP, temp_csp);
 
 #if !defined(PRODUCT)
     __ LoadImmediate(temp1, compiler::target::Thread::vm_tag_dart_id());
@@ -1315,14 +1324,14 @@
 
       // We are entering runtime code, so the C stack pointer must be restored
       // from the stack limit to the top of the stack.
-      __ mov(R25, CSP);
+      __ mov(temp_csp, CSP);
       __ mov(CSP, SP);
 
       __ blr(branch);
 
       // Restore the Dart stack pointer.
       __ mov(SP, CSP);
-      __ mov(CSP, R25);
+      __ mov(CSP, temp_csp);
 
       // Update information in the thread object and leave the safepoint.
       __ TransitionNativeToGenerated(temp1, /*leave_safepoint=*/true);
diff --git a/runtime/vm/compiler/backend/il_ia32.cc b/runtime/vm/compiler/backend/il_ia32.cc
index ce4c368..d608637 100644
--- a/runtime/vm/compiler/backend/il_ia32.cc
+++ b/runtime/vm/compiler/backend/il_ia32.cc
@@ -998,24 +998,33 @@
   __ Drop(ArgumentCount());  // Drop the arguments.
 }
 
+#define R(r) (1 << r)
+
 LocationSummary* FfiCallInstr::MakeLocationSummary(Zone* zone,
                                                    bool is_optimizing) const {
-  return MakeLocationSummaryInternal(zone, is_optimizing, kNoRegister);
+  return MakeLocationSummaryInternal(
+      zone, is_optimizing,
+      (R(CallingConventions::kSecondNonArgumentRegister) |
+       R(CallingConventions::kFfiAnyNonAbiRegister)));
 }
 
+#undef R
+
 void FfiCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  const Register branch = locs()->in(TargetAddressIndex()).reg();
+
+  // The temps are indexed according to their register number.
+  const Register temp = locs()->temp(0).reg();
   // For regular calls, this holds the FP for rebasing the original locations
   // during EmitParamMoves.
   // For leaf calls, this holds the SP used to restore the pre-aligned SP after
   // the call.
-  const Register saved_fp_or_sp = locs()->temp(0).reg();
-  const Register temp = locs()->temp(1).reg();
-  const Register branch = locs()->in(TargetAddressIndex()).reg();
+  const Register saved_fp_or_sp = locs()->temp(1).reg();
 
   // Ensure these are callee-saved register and are preserved across the call.
   ASSERT((CallingConventions::kCalleeSaveCpuRegisters &
           (1 << saved_fp_or_sp)) != 0);
-  // temp doesn't need to be preserved.
+  // Other temps don't need to be preserved.
 
   __ movl(saved_fp_or_sp, is_leaf_ ? SPREG : FPREG);
 
diff --git a/runtime/vm/compiler/backend/il_riscv.cc b/runtime/vm/compiler/backend/il_riscv.cc
index 9068abb..9f576c9 100644
--- a/runtime/vm/compiler/backend/il_riscv.cc
+++ b/runtime/vm/compiler/backend/il_riscv.cc
@@ -1374,10 +1374,14 @@
   __ Drop(ArgumentCount() + 1);  // Drop the arguments and result.
 }
 
+#define R(r) (1 << r)
+
 LocationSummary* FfiCallInstr::MakeLocationSummary(Zone* zone,
                                                    bool is_optimizing) const {
-  LocationSummary* summary =
-      MakeLocationSummaryInternal(zone, is_optimizing, CALLEE_SAVED_TEMP2);
+  LocationSummary* summary = MakeLocationSummaryInternal(
+      zone, is_optimizing,
+      (R(CallingConventions::kSecondNonArgumentRegister) |
+       R(CallingConventions::kFfiAnyNonAbiRegister) | R(CALLEE_SAVED_TEMP2)));
   // A3/A4/A5 are blocked during Dart register allocation because they are
   // assigned to TMP/TMP2/PP. This assignment is important for reducing code
   // size. To work around this for FFI calls, the FFI argument definitions are
@@ -1400,17 +1404,20 @@
   return summary;
 }
 
+#undef R
+
 void FfiCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  const Register target = locs()->in(TargetAddressIndex()).reg();
+
+  // The temps are indexed according to their register number.
+  const Register temp1 = locs()->temp(0).reg();
   // For regular calls, this holds the FP for rebasing the original locations
   // during EmitParamMoves.
   // For leaf calls, this holds the SP used to restore the pre-aligned SP after
   // the call.
-  const Register saved_fp_or_sp = locs()->temp(0).reg();
-  RELEASE_ASSERT((CallingConventions::kCalleeSaveCpuRegisters &
-                  (1 << saved_fp_or_sp)) != 0);
-  const Register temp1 = locs()->temp(1).reg();
+  const Register saved_fp_or_sp = locs()->temp(1).reg();
   const Register temp2 = locs()->temp(2).reg();
-  const Register target = locs()->in(TargetAddressIndex()).reg();
+
   ASSERT(temp1 != target);
   ASSERT(temp2 != target);
   ASSERT(temp1 != saved_fp_or_sp);
@@ -1420,7 +1427,7 @@
   // Ensure these are callee-saved register and are preserved across the call.
   ASSERT((CallingConventions::kCalleeSaveCpuRegisters &
           (1 << saved_fp_or_sp)) != 0);
-  // temps don't need to be preserved.
+  // Other temps don't need to be preserved.
 
   __ mv(saved_fp_or_sp, is_leaf_ ? SPREG : FPREG);
 
diff --git a/runtime/vm/compiler/backend/il_test.cc b/runtime/vm/compiler/backend/il_test.cc
index a03d0e86..95f8ac0 100644
--- a/runtime/vm/compiler/backend/il_test.cc
+++ b/runtime/vm/compiler/backend/il_test.cc
@@ -952,6 +952,227 @@
   EXPECT_EQ(reinterpret_cast<intptr_t>(thread), result_int);
 }
 
+// Helper to set up an inlined FfiCall by replacing a StaticCall.
+FlowGraph* SetupFfiFlowgraph(TestPipeline* pipeline,
+                             Zone* zone,
+                             const compiler::ffi::CallMarshaller& marshaller,
+                             uword native_entry,
+                             bool is_leaf) {
+  FlowGraph* flow_graph = pipeline->RunPasses({CompilerPass::kComputeSSA});
+
+  // Make an FfiCall based on ffi_trampoline that calls our native function.
+  auto ffi_call = new FfiCallInstr(zone, DeoptId::kNone, marshaller, is_leaf);
+  RELEASE_ASSERT(ffi_call->InputCount() == 1);
+  // TargetAddress is the function pointer called.
+  const Representation address_repr =
+      compiler::target::kWordSize == 4 ? kUnboxedUint32 : kUnboxedInt64;
+  ffi_call->SetInputAt(
+      ffi_call->TargetAddressIndex(),
+      new Value(flow_graph->GetConstant(
+          Integer::Handle(Integer::NewCanonical(native_entry)), address_repr)));
+
+  // Replace the placeholder StaticCall with an FfiCall to our native function.
+  {
+    StaticCallInstr* static_call = nullptr;
+    {
+      ILMatcher cursor(flow_graph, flow_graph->graph_entry()->normal_entry(),
+                       /*trace=*/false);
+      cursor.TryMatch({kMoveGlob, {kMatchStaticCall, &static_call}});
+    }
+    RELEASE_ASSERT(static_call != nullptr);
+
+    flow_graph->InsertBefore(static_call, ffi_call, /*env=*/nullptr,
+                             FlowGraph::kEffect);
+    static_call->RemoveFromGraph(/*return_previous=*/false);
+  }
+
+  // Run remaining relevant compiler passes.
+  pipeline->RunAdditionalPasses({
+      CompilerPass::kApplyICData,
+      CompilerPass::kTryOptimizePatterns,
+      CompilerPass::kSetOuterInliningId,
+      CompilerPass::kTypePropagation,
+      // Skipping passes that don't seem to do anything for this test.
+      CompilerPass::kWidenSmiToInt32,
+      CompilerPass::kSelectRepresentations,
+      // Skipping passes that don't seem to do anything for this test.
+      CompilerPass::kTypePropagation,
+      CompilerPass::kRangeAnalysis,
+      // Skipping passes that don't seem to do anything for this test.
+      CompilerPass::kFinalizeGraph,
+      CompilerPass::kCanonicalize,
+      CompilerPass::kAllocateRegisters,
+      CompilerPass::kReorderBlocks,
+  });
+
+  return flow_graph;
+}
+
+// Test that FFI calls spill all live values to the stack, and that FFI leaf
+// calls are free to use available ABI callee-save registers to avoid spilling.
+// Additionally test that register allocation is done correctly by clobbering
+// all volatile registers in the native function being called.
+ISOLATE_UNIT_TEST_CASE(IRTest_FfiCallInstrLeafDoesntSpill) {
+  SetFlagScope<int> sfs(&FLAG_sound_null_safety, kNullSafetyOptionStrong);
+
+  const char* kScript = R"(
+    import 'dart:ffi';
+
+    // This is purely a placeholder and is never called.
+    void placeholder() {}
+
+    // Will call the "doFfiCall" and exercise its code.
+    bool invokeDoFfiCall() {
+      final double result = doFfiCall(1, 2, 3, 1.0, 2.0, 3.0);
+      if (result != (2 + 3 + 4 + 2.0 + 3.0 + 4.0)) {
+        throw 'Failed. Result was $result.';
+      }
+      return true;
+    }
+
+    // Will perform a "C" call while having live values in registers
+    // across the FfiCall.
+    double doFfiCall(int a, int b, int c, double x, double y, double z) {
+      // Ensure there is at least one live value in a register.
+      a += 1;
+      b += 1;
+      c += 1;
+      x += 1.0;
+      y += 1.0;
+      z += 1.0;
+      // We'll replace this StaticCall with an FfiCall.
+      placeholder();
+      // Use the live value.
+      return (a + b + c + x + y + z);
+    }
+
+    // FFI trampoline function.
+    typedef NT = Void Function();
+    typedef DT = void Function();
+    Pointer<NativeFunction<NT>> ptr = Pointer.fromAddress(0);
+    DT getFfiTrampolineClosure() => ptr.asFunction(isLeaf:true);
+  )";
+
+  const auto& root_library = Library::Handle(LoadTestScript(kScript));
+
+  // Build a "C" function that we can actually invoke.
+  auto& c_function = Instructions::Handle(
+      BuildInstructions([](compiler::Assembler* assembler) {
+        // Clobber all volatile registers to make sure caller doesn't rely on
+        // any non-callee-save register.
+        for (intptr_t reg = 0; reg < kNumberOfFpuRegisters; reg++) {
+          if ((kAbiVolatileFpuRegs & (1 << reg)) != 0) {
+#if defined(TARGET_ARCH_ARM)
+            // On ARM we need an extra scratch register for LoadDImmediate.
+            assembler->LoadDImmediate(static_cast<DRegister>(reg), 0.0, R3);
+#else
+            assembler->LoadDImmediate(static_cast<FpuRegister>(reg), 0.0);
+#endif
+          }
+        }
+        for (intptr_t reg = 0; reg < kNumberOfCpuRegisters; reg++) {
+          if ((kDartVolatileCpuRegs & (1 << reg)) != 0) {
+            assembler->LoadImmediate(static_cast<Register>(reg), 0xDEADBEEF);
+          }
+        }
+        assembler->Ret();
+      }));
+  uword native_entry = c_function.EntryPoint();
+
+  // Get initial compilation done.
+  Invoke(root_library, "invokeDoFfiCall");
+
+  const Function& do_ffi_call =
+      Function::Handle(GetFunction(root_library, "doFfiCall"));
+  RELEASE_ASSERT(!do_ffi_call.IsNull());
+
+  const auto& value = Closure::Handle(
+      Closure::RawCast(Invoke(root_library, "getFfiTrampolineClosure")));
+  RELEASE_ASSERT(value.IsClosure());
+  const auto& ffi_trampoline =
+      Function::ZoneHandle(Closure::Cast(value).function());
+  RELEASE_ASSERT(!ffi_trampoline.IsNull());
+
+  // Construct the FFICallInstr from the trampoline matching our native
+  // function.
+  const char* error = nullptr;
+  const auto marshaller_ptr = compiler::ffi::CallMarshaller::FromFunction(
+      thread->zone(), ffi_trampoline, &error);
+  RELEASE_ASSERT(error == nullptr);
+  RELEASE_ASSERT(marshaller_ptr != nullptr);
+  const auto& marshaller = *marshaller_ptr;
+
+  const auto& compile_and_run =
+      [&](bool is_leaf, std::function<void(ParallelMoveInstr*)> verify) {
+        // Build the SSA graph for "doFfiCall"
+        TestPipeline pipeline(do_ffi_call, CompilerPass::kJIT);
+        FlowGraph* flow_graph = SetupFfiFlowgraph(
+            &pipeline, thread->zone(), marshaller, native_entry, is_leaf);
+
+        {
+          ParallelMoveInstr* parallel_move = nullptr;
+          ILMatcher cursor(flow_graph,
+                           flow_graph->graph_entry()->normal_entry(),
+                           /*trace=*/false);
+          while (cursor.TryMatch(
+              {kMoveGlob, {kMatchAndMoveParallelMove, &parallel_move}})) {
+            verify(parallel_move);
+          }
+        }
+
+        // Finish the compilation and attach code so we can run it.
+        pipeline.CompileGraphAndAttachFunction();
+
+        // Ensure we can successfully invoke the FFI call.
+        auto& result = Object::Handle(Invoke(root_library, "invokeDoFfiCall"));
+        RELEASE_ASSERT(result.IsBool());
+        EXPECT(Bool::Cast(result).value());
+      };
+
+  intptr_t num_cpu_reg_to_stack_nonleaf = 0;
+  intptr_t num_cpu_reg_to_stack_leaf = 0;
+  intptr_t num_fpu_reg_to_stack_nonleaf = 0;
+  intptr_t num_fpu_reg_to_stack_leaf = 0;
+
+  // Test non-leaf spills live values.
+  compile_and_run(/*is_leaf=*/false, [&](ParallelMoveInstr* parallel_move) {
+    // TargetAddress is passed in register, live values are all spilled.
+    for (int i = 0; i < parallel_move->NumMoves(); i++) {
+      auto move = parallel_move->moves()[i];
+      if (move->src_slot()->IsRegister() && move->dest_slot()->IsStackSlot()) {
+        num_cpu_reg_to_stack_nonleaf++;
+      } else if (move->src_slot()->IsFpuRegister() &&
+                 move->dest_slot()->IsDoubleStackSlot()) {
+        num_fpu_reg_to_stack_nonleaf++;
+      }
+    }
+  });
+
+  // Test leaf calls do not cause spills of live values.
+  compile_and_run(/*is_leaf=*/true, [&](ParallelMoveInstr* parallel_move) {
+    // TargetAddress is passed in registers, live values are not spilled and
+    // remains in callee-save registers.
+    for (int i = 0; i < parallel_move->NumMoves(); i++) {
+      auto move = parallel_move->moves()[i];
+      if (move->src_slot()->IsRegister() && move->dest_slot()->IsStackSlot()) {
+        num_cpu_reg_to_stack_leaf++;
+      } else if (move->src_slot()->IsFpuRegister() &&
+                 move->dest_slot()->IsDoubleStackSlot()) {
+        num_fpu_reg_to_stack_leaf++;
+      }
+    }
+  });
+
+  // We should have less moves to the stack (i.e. spilling) in leaf calls.
+  EXPECT_LT(num_cpu_reg_to_stack_leaf, num_cpu_reg_to_stack_nonleaf);
+  // We don't have volatile FPU registers on all platforms.
+  const bool has_callee_save_fpu_regs =
+      Utils::CountOneBitsWord(kAbiVolatileFpuRegs) <
+      Utils::CountOneBitsWord(kAllFpuRegistersList);
+  EXPECT(!has_callee_save_fpu_regs ||
+         num_fpu_reg_to_stack_leaf < num_fpu_reg_to_stack_nonleaf);
+}
+
 static void TestConstantFoldToSmi(const Library& root_library,
                                   const char* function_name,
                                   CompilerPass::PipelineMode mode,
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index 33b66ee..9a12a65 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -1175,29 +1175,38 @@
   __ Drop(ArgumentCount());  // Drop the arguments.
 }
 
+#define R(r) (1 << r)
+
 LocationSummary* FfiCallInstr::MakeLocationSummary(Zone* zone,
                                                    bool is_optimizing) const {
-  // Use R10 as a temp register. We can't use RDI, RSI, RDX, R8, R9 as they are
-  // arg registers, and R11 is TMP.
-  return MakeLocationSummaryInternal(zone, is_optimizing, R10);
+  // Use R10 as a temp. register. We can't use RDI, RSI, RDX, R8, R9 as they are
+  // argument registers, and R11 is TMP.
+  return MakeLocationSummaryInternal(
+      zone, is_optimizing,
+      (R(CallingConventions::kSecondNonArgumentRegister) | R(R10) |
+       R(CallingConventions::kFfiAnyNonAbiRegister)));
 }
 
+#undef R
+
 void FfiCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  const Register target_address = locs()->in(TargetAddressIndex()).reg();
+
+  // The temps are indexed according to their register number.
+  // For regular calls, this holds the FP for rebasing the original locations
+  // during EmitParamMoves.
+  const Register saved_fp = locs()->temp(0).reg();
+  const Register temp = locs()->temp(1).reg();
   // For leaf calls, this holds the SP used to restore the pre-aligned SP after
   // the call.
   // Note: R12 doubles as CODE_REG, which gets clobbered during frame setup in
   // regular calls.
-  const Register saved_sp = locs()->temp(0).reg();
-  // For regular calls, this holds the FP for rebasing the original locations
-  // during EmitParamMoves.
-  const Register saved_fp = locs()->temp(1).reg();
-  const Register temp = locs()->temp(2).reg();
-  const Register target_address = locs()->in(TargetAddressIndex()).reg();
+  const Register saved_sp = locs()->temp(2).reg();
 
   // Ensure these are callee-saved register and are preserved across the call.
   ASSERT((CallingConventions::kCalleeSaveCpuRegisters & (1 << saved_sp)) != 0);
   ASSERT((CallingConventions::kCalleeSaveCpuRegisters & (1 << saved_fp)) != 0);
-  // temp doesn't need to be preserved.
+  // Other temps don't need to be preserved.
 
   if (is_leaf_) {
     __ movq(saved_sp, SPREG);
diff --git a/runtime/vm/compiler/backend/linearscan.cc b/runtime/vm/compiler/backend/linearscan.cc
index 19191d1..266b485 100644
--- a/runtime/vm/compiler/backend/linearscan.cc
+++ b/runtime/vm/compiler/backend/linearscan.cc
@@ -465,6 +465,28 @@
   }
 }
 
+void FlowGraphAllocator::BlockCpuRegisters(intptr_t registers,
+                                           intptr_t from,
+                                           intptr_t to) {
+  for (intptr_t r = 0; r < kNumberOfCpuRegisters; r++) {
+    if ((registers & (1 << r)) != 0) {
+      BlockLocation(Location::RegisterLocation(static_cast<Register>(r)), from,
+                    to);
+    }
+  }
+}
+
+void FlowGraphAllocator::BlockFpuRegisters(intptr_t fpu_registers,
+                                           intptr_t from,
+                                           intptr_t to) {
+  for (intptr_t r = 0; r < kNumberOfFpuRegisters; r++) {
+    if ((fpu_registers & (1 << r)) != 0) {
+      BlockLocation(Location::FpuRegisterLocation(static_cast<FpuRegister>(r)),
+                    from, to);
+    }
+  }
+}
+
 void LiveRange::Print() {
   if (first_use_interval() == NULL) {
     return;
@@ -1389,6 +1411,21 @@
     }
   }
 
+  // Block all volatile (i.e. not native ABI callee-save) registers.
+  if (locs->native_leaf_call()) {
+    BlockCpuRegisters(kDartVolatileCpuRegs, pos, pos + 1);
+    BlockFpuRegisters(kAbiVolatileFpuRegs, pos, pos + 1);
+#if defined(TARGET_ARCH_ARM)
+    // We do not yet have a way to say that we only want FPU registers that
+    // overlap S registers.
+    // Block all Q/D FPU registers above the 8/16 that have S registers in
+    // VFPv3-D32.
+    // This way we avoid ending up trying to do single-word operations on
+    // registers that don't support it.
+    BlockFpuRegisters(kFpuRegistersWithoutSOverlap, pos, pos + 1);
+#endif
+  }
+
   // Block all allocatable registers for calls.
   if (locs->always_calls() && !locs->callee_safe_call()) {
     // Expected shape of live range:
@@ -1397,16 +1434,9 @@
     //              [--)
     //
     // The stack bitmap describes the position i.
-    for (intptr_t reg = 0; reg < kNumberOfCpuRegisters; reg++) {
-      BlockLocation(Location::RegisterLocation(static_cast<Register>(reg)), pos,
-                    pos + 1);
-    }
+    BlockCpuRegisters(kAllCpuRegistersList, pos, pos + 1);
 
-    for (intptr_t reg = 0; reg < kNumberOfFpuRegisters; reg++) {
-      BlockLocation(
-          Location::FpuRegisterLocation(static_cast<FpuRegister>(reg)), pos,
-          pos + 1);
-    }
+    BlockFpuRegisters(kAllFpuRegistersList, pos, pos + 1);
 
 #if defined(DEBUG)
     // Verify that temps, inputs and output were specified as fixed
@@ -1426,8 +1456,7 @@
                pair->At(1).policy() == Location::kAny);
       } else {
         ASSERT(!locs->in(j).IsUnallocated() ||
-               locs->in(j).policy() == Location::kAny ||
-               locs->in(j).policy() == Location::kRequiresStackSlot);
+               locs->in(j).policy() == Location::kAny);
       }
     }
 
@@ -1441,7 +1470,7 @@
 #endif
   }
 
-  if (locs->can_call()) {
+  if (locs->can_call() && !locs->native_leaf_call()) {
     safepoints_.Add(current);
   }
 
diff --git a/runtime/vm/compiler/backend/linearscan.h b/runtime/vm/compiler/backend/linearscan.h
index 2d6e919..bc26c63 100644
--- a/runtime/vm/compiler/backend/linearscan.h
+++ b/runtime/vm/compiler/backend/linearscan.h
@@ -156,6 +156,10 @@
                              bool* blocked_registers,
                              LiveRange** blocking_ranges);
 
+  void BlockCpuRegisters(intptr_t registers, intptr_t from, intptr_t to);
+
+  void BlockFpuRegisters(intptr_t fpu_registers, intptr_t from, intptr_t to);
+
   intptr_t NumberOfRegisters() const { return number_of_registers_; }
 
   // Find all safepoints that are covered by this live range.
diff --git a/runtime/vm/compiler/backend/locations.cc b/runtime/vm/compiler/backend/locations.cc
index 56640f8..9b5b166 100644
--- a/runtime/vm/compiler/backend/locations.cc
+++ b/runtime/vm/compiler/backend/locations.cc
@@ -185,8 +185,7 @@
   // restrictions.
   if (always_calls()) {
     if (loc.IsUnallocated()) {
-      ASSERT(loc.policy() == Location::kAny ||
-             loc.policy() == Location::kRequiresStackSlot);
+      ASSERT(loc.policy() == Location::kAny);
     } else if (loc.IsPairLocation()) {
       ASSERT(!loc.AsPairLocation()->At(0).IsUnallocated() ||
              loc.AsPairLocation()->At(0).policy() == Location::kAny);
@@ -311,8 +310,6 @@
           return "R";
         case kRequiresFpuRegister:
           return "DR";
-        case kRequiresStackSlot:
-          return "RS";
         case kWritableRegister:
           return "WR";
         case kSameAsFirstInput:
diff --git a/runtime/vm/compiler/backend/locations.h b/runtime/vm/compiler/backend/locations.h
index b9988948..754852e 100644
--- a/runtime/vm/compiler/backend/locations.h
+++ b/runtime/vm/compiler/backend/locations.h
@@ -257,7 +257,6 @@
     kPrefersRegister,
     kRequiresRegister,
     kRequiresFpuRegister,
-    kRequiresStackSlot,
     kWritableRegister,
     kSameAsFirstInput,
   };
@@ -285,10 +284,6 @@
     return UnallocatedLocation(kRequiresFpuRegister);
   }
 
-  static Location RequiresStackSlot() {
-    return UnallocatedLocation(kRequiresStackSlot);
-  }
-
   static Location WritableRegister() {
     return UnallocatedLocation(kWritableRegister);
   }
@@ -719,12 +714,19 @@
 class LocationSummary : public ZoneAllocated {
  public:
   enum ContainsCall {
-    kNoCall,  // Used registers must be reserved as tmp.
-    kCall,    // Registers have been saved and can be used without reservation.
-    kCallCalleeSafe,       // Registers will be saved by the callee.
-    kCallOnSlowPath,       // Used registers must be reserved as tmp.
-    kCallOnSharedSlowPath  // Registers used to invoke shared stub must be
-                           // reserved as tmp.
+    // Used registers must be reserved as tmp.
+    kNoCall,
+    // Registers have been saved and can be used without reservation.
+    kCall,
+    // Registers will be saved by the callee.
+    kCallCalleeSafe,
+    // Used registers must be reserved as tmp.
+    kCallOnSlowPath,
+    // Registers used to invoke shared stub must be reserved as tmp.
+    kCallOnSharedSlowPath,
+    // Location is a native leaf call so any register not in the native ABI
+    // callee-save (or input/output/tmp) set might get clobbered.
+    kNativeLeafCall
   };
 
   LocationSummary(Zone* zone,
@@ -800,6 +802,8 @@
     return contains_call_ == kCallOnSharedSlowPath;
   }
 
+  bool native_leaf_call() const { return contains_call_ == kNativeLeafCall; }
+
   void PrintTo(BaseTextBuffer* f) const;
 
   static LocationSummary* Make(Zone* zone,
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
index 15f48ef..a94761c 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
@@ -2832,19 +2832,6 @@
   SkipStringReference();    // Read part URI index.
 }
 
-void KernelReaderHelper::SkipLibraryTypedef() {
-  SkipCanonicalNameReference();      // read canonical name.
-  ReadUInt();                        // read source_uri_index.
-  ReadPosition();                    // read position.
-  SkipStringReference();             // read name index.
-  SkipListOfExpressions();           // read annotations.
-  SkipTypeParametersList();          // read type parameters.
-  SkipDartType();                    // read type.
-  SkipTypeParametersList();          // read type parameters of function type.
-  SkipListOfVariableDeclarations();  // read positional parameters.
-  SkipListOfVariableDeclarations();  // read named parameters.
-}
-
 TokenPosition KernelReaderHelper::ReadPosition() {
   TokenPosition position = reader_.ReadPosition();
   RecordTokenPosition(position);
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.h b/runtime/vm/compiler/frontend/kernel_translation_helper.h
index 315e468..4016697 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.h
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.h
@@ -1279,7 +1279,6 @@
   void SkipLibraryCombinator();
   void SkipLibraryDependency();
   void SkipLibraryPart();
-  void SkipLibraryTypedef();
   TokenPosition ReadPosition();
   Tag ReadTag(uint8_t* payload = NULL);
   uint8_t ReadFlags() { return reader_.ReadFlags(); }
diff --git a/runtime/vm/constants_arm.h b/runtime/vm/constants_arm.h
index 7b43812..7406b47 100644
--- a/runtime/vm/constants_arm.h
+++ b/runtime/vm/constants_arm.h
@@ -30,6 +30,8 @@
 // to compare LR register code.
 #define LR LR_DO_NOT_USE_DIRECTLY
 
+#define R(reg) (static_cast<RegList>(1) << (reg))
+
 // We support both VFPv3-D16 and VFPv3-D32 profiles, but currently only one at
 // a time.
 #if defined(__ARM_ARCH_7A__)
@@ -209,6 +211,9 @@
   D31 = 31,
   kNumberOfDRegisters = 32,
 #endif
+  // Number of D registers that overlap S registers.
+  // One D register overlaps two S registers, so regardless of the numbers of D
+  // registers, there are only 32 S registers that are overlapped.
   kNumberOfOverlappingDRegisters = 16,
 };
 
@@ -243,6 +248,10 @@
   Q15 = 15,
   kNumberOfQRegisters = 16,
 #endif
+  // Number of Q registers that overlap S registers.
+  // One Q register overlaps four S registers, so regardless of the numbers of Q
+  // registers, there are only 32 S registers that are overlapped.
+  kNumberOfOverlappingQRegisters = 8,
 };
 
 static inline DRegister EvenDRegisterOf(QRegister q) {
@@ -256,7 +265,7 @@
 static inline SRegister EvenSRegisterOf(DRegister d) {
 #if defined(VFPv3_D32)
   // When we have 32 D registers, the S registers only overlap the first 16.
-  // That is, there are only 32 S registers.
+  // That is, there are only ever 32 S registers in any extension.
   ASSERT(d < D16);
 #endif
   return static_cast<SRegister>(d * 2);
@@ -535,6 +544,7 @@
 // List of registers used in load/store multiple.
 typedef uint16_t RegList;
 const RegList kAllCpuRegistersList = 0xFFFF;
+const RegList kAllFpuRegistersList = (1 << kNumberOfFpuRegisters) - 1;
 
 // C++ ABI call registers.
 const RegList kAbiArgumentCpuRegs =
@@ -572,7 +582,11 @@
 const int kDartVolatileCpuRegCount = 5;
 #endif
 
-#define R(reg) (static_cast<RegList>(1) << (reg))
+const RegList kAbiVolatileFpuRegs = R(Q0) | R(Q1) | R(Q2) | R(Q3);
+
+const RegList kFpuRegistersWithoutSOverlap =
+    kAllFpuRegistersList &
+    ~((1 << QRegister::kNumberOfOverlappingQRegisters) - 1);
 
 class CallingConventions {
  public:
diff --git a/runtime/vm/constants_arm64.h b/runtime/vm/constants_arm64.h
index a7f00d9..5be6e98 100644
--- a/runtime/vm/constants_arm64.h
+++ b/runtime/vm/constants_arm64.h
@@ -81,7 +81,9 @@
 };
 
 enum VRegister {
+  // v0 Volatile; Parameter/scratch register, result register.
   V0 = 0,
+  // v1-v7 Volatile; Parameter/scratch register.
   V1 = 1,
   V2 = 2,
   V3 = 3,
@@ -89,6 +91,8 @@
   V5 = 5,
   V6 = 6,
   V7 = 7,
+  // v8-v15 Non-volatile; Scratch registers
+  // Only the bottom 64 bits are non-volatile! [ARM IHI 0055B, 5.1.2]
   V8 = 8,
   V9 = 9,
   V10 = 10,
@@ -97,6 +101,7 @@
   V13 = 13,
   V14 = 14,
   V15 = 15,
+  // v16-v31 Volatile; Scratch registers.
   V16 = 16,
   V17 = 17,
   V18 = 18,
@@ -104,7 +109,7 @@
   V20 = 20,
   V21 = 21,
   V22 = 22,
-  V23 = 24,
+  V23 = 23,
   V24 = 24,
   V25 = 25,
   V26 = 26,
@@ -430,6 +435,11 @@
 const int kDartVolatileCpuRegCount = 15;
 const int kDartVolatileFpuRegCount = 24;
 
+const RegList kAbiVolatileFpuRegs =
+    R(V0) | R(V1) | R(V2) | R(V3) | R(V4) | R(V5) | R(V6) | R(V7) | R(V16) |
+    R(V17) | R(V18) | R(V19) | R(V20) | R(V21) | R(V22) | R(V23) | R(V24) |
+    R(V25) | R(V26) | R(V27) | R(V28) | R(V29) | R(V30) | R(V31);
+
 constexpr int kStoreBufferWrapperSize = 32;
 
 class CallingConventions {
diff --git a/runtime/vm/constants_ia32.h b/runtime/vm/constants_ia32.h
index 061771d..733dd8c 100644
--- a/runtime/vm/constants_ia32.h
+++ b/runtime/vm/constants_ia32.h
@@ -16,6 +16,8 @@
 
 namespace dart {
 
+#define R(reg) (1 << (reg))
+
 enum Register {
   EAX = 0,
   ECX = 1,
@@ -29,6 +31,8 @@
   kNoRegister = -1,  // Signals an illegal register.
 };
 
+// Low and high bytes registers of the the first four general purpose registers.
+// The other four general purpose registers do not have byte registers.
 enum ByteRegister {
   AL = 0,
   CL = 1,
@@ -42,6 +46,10 @@
 };
 
 inline ByteRegister ByteRegisterOf(Register reg) {
+  // This only works for EAX, ECX, EDX, EBX.
+  // Remaining Register values map to high byte of the above registers.
+  RELEASE_ASSERT(reg == Register::EAX || reg == Register::ECX ||
+                 reg == Register::EDX || reg == Register::EBX);
   return static_cast<ByteRegister>(reg);
 }
 
@@ -263,12 +271,23 @@
 
 typedef uint32_t RegList;
 const RegList kAllCpuRegistersList = 0xFF;
+const RegList kAllFpuRegistersList = (1 << kNumberOfFpuRegisters) - 1;
 
 const intptr_t kReservedCpuRegisters = (1 << SPREG) | (1 << FPREG) | (1 << THR);
 // CPU registers available to Dart allocator.
 const RegList kDartAvailableCpuRegs =
     kAllCpuRegistersList & ~kReservedCpuRegisters;
 
+const RegList kAbiPreservedCpuRegs = (1 << EDI) | (1 << ESI) | (1 << EBX);
+
+// Registers available to Dart that are not preserved by runtime calls.
+const RegList kDartVolatileCpuRegs =
+    kDartAvailableCpuRegs & ~kAbiPreservedCpuRegs;
+
+const RegList kAbiVolatileFpuRegs = kAllFpuRegistersList;
+
+#undef R
+
 enum ScaleFactor {
   TIMES_1 = 0,
   TIMES_2 = 1,
@@ -332,8 +351,7 @@
   static const intptr_t kXmmArgumentRegisters = 0;
   static const intptr_t kNumFpuArgRegs = 0;
 
-  static constexpr intptr_t kCalleeSaveCpuRegisters =
-      (1 << EDI) | (1 << ESI) | (1 << EBX);
+  static constexpr intptr_t kCalleeSaveCpuRegisters = kAbiPreservedCpuRegs;
 
   static const bool kArgumentIntRegXorFpuReg = false;
 
diff --git a/runtime/vm/constants_riscv.h b/runtime/vm/constants_riscv.h
index 30a720f..f8430df 100644
--- a/runtime/vm/constants_riscv.h
+++ b/runtime/vm/constants_riscv.h
@@ -387,6 +387,7 @@
 
 typedef uint32_t RegList;
 const RegList kAllCpuRegistersList = 0xFFFFFFFF;
+const RegList kAllFpuRegistersList = 0xFFFFFFFF;
 
 #define R(reg) (static_cast<RegList>(1) << (reg))
 
diff --git a/runtime/vm/constants_x64.h b/runtime/vm/constants_x64.h
index b8bc0e7..930f588 100644
--- a/runtime/vm/constants_x64.h
+++ b/runtime/vm/constants_x64.h
@@ -16,6 +16,8 @@
 
 namespace dart {
 
+#define R(reg) (static_cast<RegList>(1) << (reg))
+
 enum Register {
   RAX = 0,
   RCX = 1,
@@ -345,7 +347,7 @@
 const RegList kAllFpuRegistersList = 0xFFFF;
 
 const RegList kReservedCpuRegisters =
-    (1 << SPREG) | (1 << FPREG) | (1 << TMP) | (1 << PP) | (1 << THR);
+    R(SPREG) | R(FPREG) | R(TMP) | R(PP) | R(THR);
 constexpr intptr_t kNumberOfReservedCpuRegisters = 5;
 // CPU registers available to Dart allocator.
 const RegList kDartAvailableCpuRegs =
@@ -354,6 +356,20 @@
     kNumberOfCpuRegisters - kNumberOfReservedCpuRegisters;
 constexpr int kStoreBufferWrapperSize = 13;
 
+#if defined(DART_TARGET_OS_WINDOWS)
+const RegList kAbiPreservedCpuRegs =
+    R(RBX) | R(RSI) | R(RDI) | R(R12) | R(R13) | R(R14) | R(R15);
+const RegList kAbiVolatileFpuRegs =
+    R(XMM0) | R(XMM1) | R(XMM2) | R(XMM3) | R(XMM4) | R(XMM5);
+#else
+const RegList kAbiPreservedCpuRegs = R(RBX) | R(R12) | R(R13) | R(R14) | R(R15);
+const RegList kAbiVolatileFpuRegs = kAllFpuRegistersList;
+#endif
+
+// Registers available to Dart that are not preserved by runtime calls.
+const RegList kDartVolatileCpuRegs =
+    kDartAvailableCpuRegs & ~kAbiPreservedCpuRegs;
+
 enum ScaleFactor {
   TIMES_1 = 0,
   TIMES_2 = 1,
@@ -383,8 +399,6 @@
   TIMES_COMPRESSED_HALF_WORD_SIZE = TIMES_COMPRESSED_WORD_SIZE - 1,
 };
 
-#define R(reg) (static_cast<RegList>(1) << (reg))
-
 class CallingConventions {
  public:
 #if defined(DART_TARGET_OS_WINDOWS)
@@ -422,11 +436,7 @@
   static const intptr_t kVolatileCpuRegisters =
       R(RAX) | R(RCX) | R(RDX) | R(R8) | R(R9) | R(R10) | R(R11);
 
-  static const intptr_t kVolatileXmmRegisters =
-      R(XMM0) | R(XMM1) | R(XMM2) | R(XMM3) | R(XMM4) | R(XMM5);
-
-  static const intptr_t kCalleeSaveCpuRegisters =
-      R(RBX) | R(RSI) | R(RDI) | R(R12) | R(R13) | R(R14) | R(R15);
+  static const RegList kVolatileXmmRegisters = kAbiVolatileFpuRegs;
 
   static const intptr_t kCalleeSaveXmmRegisters =
       R(XMM6) | R(XMM7) | R(XMM8) | R(XMM9) | R(XMM10) | R(XMM11) | R(XMM12) |
@@ -490,13 +500,7 @@
                                                 R(RSI) | R(RDI) | R(R8) |
                                                 R(R9) | R(R10) | R(R11);
 
-  static const intptr_t kVolatileXmmRegisters =
-      R(XMM0) | R(XMM1) | R(XMM2) | R(XMM3) | R(XMM4) | R(XMM5) | R(XMM6) |
-      R(XMM7) | R(XMM8) | R(XMM9) | R(XMM10) | R(XMM11) | R(XMM12) | R(XMM13) |
-      R(XMM14) | R(XMM15);
-
-  static const intptr_t kCalleeSaveCpuRegisters =
-      R(RBX) | R(R12) | R(R13) | R(R14) | R(R15);
+  static const RegList kVolatileXmmRegisters = kAbiVolatileFpuRegs;
 
   static const intptr_t kCalleeSaveXmmRegisters = 0;
 
@@ -530,6 +534,8 @@
 
 #endif
 
+  static const intptr_t kCalleeSaveCpuRegisters = kAbiPreservedCpuRegs;
+
   COMPILE_ASSERT((kArgumentRegisters & kReservedCpuRegisters) == 0);
 
   static constexpr Register kFfiAnyNonAbiRegister = R12;
@@ -544,9 +550,6 @@
        (kArgumentRegisters | R(kPointerToReturnStructRegisterCall))) == 0);
 };
 
-constexpr intptr_t kAbiPreservedCpuRegs =
-    CallingConventions::kCalleeSaveCpuRegisters;
-
 #undef R
 
 class Instr {
diff --git a/runtime/vm/kernel_binary.h b/runtime/vm/kernel_binary.h
index ff0cfa2..0efa27f 100644
--- a/runtime/vm/kernel_binary.h
+++ b/runtime/vm/kernel_binary.h
@@ -20,8 +20,8 @@
 static const uint32_t kMagicProgramFile = 0x90ABCDEFu;
 
 // Both version numbers are inclusive.
-static const uint32_t kMinSupportedKernelFormatVersion = 76;
-static const uint32_t kMaxSupportedKernelFormatVersion = 76;
+static const uint32_t kMinSupportedKernelFormatVersion = 77;
+static const uint32_t kMaxSupportedKernelFormatVersion = 77;
 
 // Keep in sync with package:kernel/lib/binary/tag.dart
 #define KERNEL_TAG_LIST(V)                                                     \
diff --git a/runtime/vm/stack_trace.cc b/runtime/vm/stack_trace.cc
index 9b665c2..4c7cbcf 100644
--- a/runtime/vm/stack_trace.cc
+++ b/runtime/vm/stack_trace.cc
@@ -83,7 +83,8 @@
       var_data_field(Field::Handle(zone)),
       state_field(Field::Handle(zone)),
       on_data_field(Field::Handle(zone)),
-      state_data_field(Field::Handle(zone)) {
+      state_data_field(Field::Handle(zone)),
+      has_value_field(Field::Handle(zone)) {
   const auto& async_lib = Library::Handle(zone, Library::AsyncLibrary());
   // Look up classes:
   // - async:
@@ -143,6 +144,9 @@
   state_data_field =
       stream_iterator_class.LookupFieldAllowPrivate(Symbols::_stateData());
   ASSERT(!state_data_field.IsNull());
+  has_value_field =
+      stream_iterator_class.LookupFieldAllowPrivate(Symbols::_hasValue());
+  ASSERT(!has_value_field.IsNull());
 }
 
 ClosurePtr CallerClosureFinder::GetCallerInFutureImpl(const Object& future) {
@@ -201,9 +205,33 @@
 
   // If the async* stream is await-for'd:
   if (callback_instance_.GetClassId() == stream_iterator_class.id()) {
-    // _StreamIterator._stateData
-    future_ = Instance::Cast(callback_instance_).GetField(state_data_field);
-    return GetCallerInFutureImpl(future_);
+    // If `_hasValue` is true then the `StreamIterator._stateData` field
+    // contains the iterator's value. In that case we cannot unwind anymore.
+    //
+    // Notice: With correct async* semantics this may never be true: The async*
+    // generator should only be invoked to produce a vaue if there's an
+    // in-progress `await streamIterator.moveNext()` call. Once such call has
+    // finished the async* generator should be paused/yielded until the next
+    // such call - and being paused/yielded means it should not appear in stack
+    // traces.
+    //
+    // See dartbug.com/48695.
+    const auto& stream_iterator = Instance::Cast(callback_instance_);
+    if (stream_iterator.GetField(has_value_field) ==
+        Object::bool_true().ptr()) {
+      return Closure::null();
+    }
+
+    // If we have an await'er for `await streamIterator.moveNext()` we continue
+    // unwinding there.
+    //
+    // Notice: With correct async* semantics this may always contain a Future
+    // See also comment above as well as dartbug.com/48695.
+    future_ = stream_iterator.GetField(state_data_field);
+    if (future_.GetClassId() == future_impl_class.id()) {
+      return GetCallerInFutureImpl(future_);
+    }
+    return Closure::null();
   }
 
   UNREACHABLE();  // If no onData is found we have a bug.
diff --git a/runtime/vm/stack_trace.h b/runtime/vm/stack_trace.h
index 566a0a8..0683cf7 100644
--- a/runtime/vm/stack_trace.h
+++ b/runtime/vm/stack_trace.h
@@ -92,6 +92,7 @@
   Field& state_field;
   Field& on_data_field;
   Field& state_data_field;
+  Field& has_value_field;
 
   DISALLOW_COPY_AND_ASSIGN(CallerClosureFinder);
 };
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index ba78ad7..52ec048 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -414,6 +414,7 @@
   V(_handleMessage, "_handleMessage")                                          \
   V(_handleFinalizerMessage, "_handleFinalizerMessage")                        \
   V(_handleNativeFinalizerMessage, "_handleNativeFinalizerMessage")            \
+  V(_hasValue, "_hasValue")                                                    \
   V(_instanceOf, "_instanceOf")                                                \
   V(_listGetAt, "_listGetAt")                                                  \
   V(_listLength, "_listLength")                                                \
diff --git a/sdk/lib/_internal/wasm/lib/js_util_wasm_patch.dart b/sdk/lib/_internal/wasm/lib/js_util_wasm_patch.dart
new file mode 100644
index 0000000..f4e7512
--- /dev/null
+++ b/sdk/lib/_internal/wasm/lib/js_util_wasm_patch.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart.js_util_wasm;
+
+import "dart:_internal";
+import "dart:js_util_wasm";
+import "dart:wasm";
+
+/// js_util_wasm methods used by the wasm runtime.
+@pragma("wasm:export", "\$listLength")
+double _listLength(List list) => list.length.toDouble();
+
+@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));
+
+@patch
+Object _jsObjectToDartObject(WasmAnyRef ref) => unsafeCastOpaque<Object>(ref);
+
+@patch
+WasmAnyRef _jsObjectFromDartObject(Object object) =>
+    unsafeCastOpaque<WasmAnyRef>(object);
diff --git a/sdk/lib/async/stream_impl.dart b/sdk/lib/async/stream_impl.dart
index 3de0d58..42b6082 100644
--- a/sdk/lib/async/stream_impl.dart
+++ b/sdk/lib/async/stream_impl.dart
@@ -978,6 +978,7 @@
   /// This will usually cause the [_subscription] to be paused, but as an
   /// optimization, we only pause after the [moveNext] future has been
   /// completed.
+  @pragma("vm:entry-point")
   bool _hasValue = false;
 
   _StreamIterator(final Stream<T> stream)
diff --git a/sdk/lib/js_util/js_util_sources.gni b/sdk/lib/js_util/js_util_sources.gni
index d3ac6d2..011df2e 100644
--- a/sdk/lib/js_util/js_util_sources.gni
+++ b/sdk/lib/js_util/js_util_sources.gni
@@ -2,4 +2,7 @@
 # for details. All rights reserved. Use of this source code is governed by a
 # BSD-style license that can be found in the LICENSE file.
 
-js_util_sdk_sources = [ "js_util.dart" ]
+js_util_sdk_sources = [
+  "js_util.dart",
+  "js_util_wasm.dart",
+]
diff --git a/sdk/lib/js_util/js_util_wasm.dart b/sdk/lib/js_util/js_util_wasm.dart
new file mode 100644
index 0000000..49b4a90
--- /dev/null
+++ b/sdk/lib/js_util/js_util_wasm.dart
@@ -0,0 +1,164 @@
+// 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.
+
+// Prototype js util library for wasm.
+library dart.js_util_wasm;
+
+import 'dart:wasm';
+
+/// [JSValue] is the root of the JS interop object hierarchy.
+class JSValue {
+  final WasmAnyRef _ref;
+
+  JSValue(this._ref);
+
+  static JSValue? box(WasmAnyRef? ref) => ref == null ? null : JSValue(ref);
+
+  WasmAnyRef toAnyRef() => _ref;
+  String toString() => _jsStringToDartString(_ref);
+  List<Object?> toObjectList() => _jsArrayToDartList(_ref);
+  Object toObject() => _jsObjectToDartObject(_ref);
+}
+
+/// Raw private JS functions.
+external WasmAnyRef _jsObjectFromDartObject(Object object);
+
+external Object _jsObjectToDartObject(WasmAnyRef ref);
+
+@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);
+
+@pragma("wasm:import", "dart2wasm.stringToDartString")
+external String _jsStringToDartString(WasmAnyRef string);
+
+/// Raw public JS functions.
+/// These are public temporarily to give performance conscious users an escape
+/// hatch while we decide what this API will actually look like. They may
+/// become private in the future, or disappear entirely. For descriptions of the
+/// API, please see the corresponding non-raw functions.
+@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();
+
+@pragma("wasm:import", "dart2wasm.globalThis")
+external WasmAnyRef globalThisRaw();
+
+@pragma("wasm:import", "dart2wasm.callConstructorVarArgs")
+external WasmAnyRef callConstructorVarArgsRaw(
+    WasmAnyRef o, WasmAnyRef name, WasmAnyRef args);
+
+@pragma("wasm:import", "dart2wasm.hasProperty")
+external bool hasPropertyRaw(WasmAnyRef o, WasmAnyRef name);
+
+@pragma("wasm:import", "dart2wasm.getProperty")
+external WasmAnyRef? getPropertyRaw(WasmAnyRef o, WasmAnyRef name);
+
+@pragma("wasm:import", "dart2wasm.setProperty")
+external WasmAnyRef? setPropertyRaw(
+    WasmAnyRef o, WasmAnyRef name, WasmAnyRef? value);
+
+@pragma("wasm:import", "dart2wasm.callMethodVarArgs")
+external WasmAnyRef? callMethodVarArgsRaw(
+    WasmAnyRef o, WasmAnyRef method, WasmAnyRef? args);
+
+WasmAnyRef? jsifyRaw(Object? object) {
+  if (object == null) {
+    return null;
+  } else if (object is JSValue) {
+    return object.toAnyRef();
+  } else if (object is String) {
+    return _jsStringFromDartString(object);
+  } else if (object is List<Object?>) {
+    return _jsArrayFromDartList(object);
+  } else {
+    return _jsObjectFromDartObject(object);
+  }
+}
+
+/// Conversion functions.
+/// TODO(joshualitt): Only a small set of types currently work:
+///   JS -> Dart:
+///     null
+///     strings
+///     arrays
+///     opaque Dart objects passed to JS
+///   Dart -> JS:
+///     null
+///     boolean
+///     doubles
+///     strings
+///     lists
+///     opaque JS objects passed to Dart
+/// In the future we would like to support more types, at least maps,
+/// and to fix some of the issues returning some types from JS.
+
+/// Extension methods for conversions.
+extension StringToJS on String {
+  JSValue toJS() => JSValue(_jsStringFromDartString(this));
+}
+
+extension ListOfObjectToJS on List<Object?> {
+  JSValue toJS() => JSValue(_jsArrayFromDartList(this));
+}
+
+extension ObjectToJS on Object {
+  JSValue toJS() => JSValue(_jsObjectFromDartObject(this));
+}
+
+/// Recursively converts objects from Dart to JS.
+JSValue? jsify(Object? object) => JSValue.box(jsifyRaw(object));
+
+/// Recursively converts objects from JS to Dart.
+Object? dartify(JSValue? object) => object == null
+    ? null
+    : _jsObjectToDartObject(dartifyRaw(object.toAnyRef())!);
+
+/// js util methods.
+/// These are low level calls into JS, and require care to use correctly.
+
+/// Evals a snippet of JS code in a Dart string.
+void eval(String code) => evalRaw(code.toJS().toAnyRef());
+
+/// Creates a new JS object literal and returns it.
+JSValue newObject() => JSValue(newObjectRaw());
+
+/// Returns a reference to `globalThis`.
+JSValue globalThis() => JSValue(globalThisRaw());
+
+/// Gets a [String] name property off of a JS object [o], invokes it as
+/// a constructor with a JS array of arguments [args], and returns the
+/// constructed JS object.
+JSValue callConstructorVarArgs(JSValue o, String name, List<JSValue?> args) =>
+    JSValue(callConstructorVarArgsRaw(
+        o.toAnyRef(), name.toJS().toAnyRef(), args.toJS().toAnyRef()));
+
+/// Checks for a [String] name on a JS object [o].
+bool hasProperty(JSValue o, String name) =>
+    hasPropertyRaw(o.toAnyRef(), name.toJS().toAnyRef());
+
+/// Gets a JS property with [String] name off of a JS object [o].
+JSValue? getProperty(JSValue o, String name) =>
+    JSValue.box(getPropertyRaw(o.toAnyRef(), name.toJS().toAnyRef()));
+
+/// Sets a JS property with [String] name on JS object [o] to the JS value
+/// [value], then returns [value].
+JSValue? setProperty(JSValue o, String name, JSValue? value) => JSValue.box(
+    setPropertyRaw(o.toAnyRef(), name.toJS().toAnyRef(), value?.toAnyRef()));
+
+/// Calls a JS method with a [String] name on JS object [o] with a JS array
+/// of arguments [args] and returns the resulting JS value.
+JSValue? callMethodVarArgs(JSValue o, String method, List<JSValue?> args) =>
+    JSValue.box(callMethodVarArgsRaw(
+        o.toAnyRef(), method.toJS().toAnyRef(), args.toJS().toAnyRef()));
diff --git a/sdk/lib/libraries.json b/sdk/lib/libraries.json
index dae53f7..212955e 100644
--- a/sdk/lib/libraries.json
+++ b/sdk/lib/libraries.json
@@ -232,6 +232,10 @@
       "isolate": {
         "uri": "isolate/isolate.dart"
       },
+      "js_util_wasm": {
+        "uri": "js_util/js_util_wasm.dart",
+        "patches": "_internal/wasm/lib/js_util_wasm_patch.dart"
+      },
       "math": {
         "uri": "math/math.dart",
         "patches": "_internal/wasm/lib/math_patch.dart"
diff --git a/sdk/lib/libraries.yaml b/sdk/lib/libraries.yaml
index ca10300..e0a8e42 100644
--- a/sdk/lib/libraries.yaml
+++ b/sdk/lib/libraries.yaml
@@ -216,6 +216,9 @@
       uri: "html/dartium/nativewrappers.dart"
     isolate:
       uri: isolate/isolate.dart
+    js_util_wasm:
+      uri: js_util/js_util_wasm.dart
+      patches: _internal/wasm/lib/js_util_wasm_patch.dart
     math:
       uri: math/math.dart
       patches: _internal/wasm/lib/math_patch.dart
diff --git a/tests/web/wasm/js_util_test.dart b/tests/web/wasm/js_util_test.dart
new file mode 100644
index 0000000..a5b31c1
--- /dev/null
+++ b/tests/web/wasm/js_util_test.dart
@@ -0,0 +1,85 @@
+// 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:js_util_wasm';
+
+import 'package:expect/expect.dart';
+
+void createObjectTest() {
+  JSValue o = newObject();
+  Expect.isFalse(hasProperty(o, 'foo'));
+  Expect.equals('bar', setProperty(o, 'foo', 'bar'.toJS()).toString());
+  Expect.isTrue(hasProperty(o, 'foo'));
+  Expect.equals('bar', getProperty(o, 'foo').toString());
+}
+
+// Unfortunately, lists do not currently compare identically.
+void _expectListEquals(List<Object?> l, List<Object?> r) {
+  Expect.equals(l.length, r.length);
+  for (int i = 0; i < l.length; i++) {
+    Expect.equals(l[i], r[i]);
+  }
+}
+
+void evalAndConstructTest() {
+  eval(r'''
+    function JSClass(c) {
+      this.c = c;
+      this.sum = (a, b) => {
+        return a + b + this.c;
+      }
+      this.list = ['a', 'b', 'c'];
+    }
+    globalThis.JSClass = JSClass;
+  ''');
+  JSValue gt = globalThis();
+  JSValue jsClass = callConstructorVarArgs(gt, 'JSClass', ['world!'.toJS()]);
+  Expect.equals(
+      'hello world!',
+      callMethodVarArgs(jsClass, 'sum', ['hello'.toJS(), ' '.toJS()])
+          .toString());
+  _expectListEquals(
+      ['a', 'b', 'c'], getProperty(jsClass, 'list')!.toObjectList());
+}
+
+class Foo {
+  final int i;
+  Foo(this.i);
+}
+
+void dartObjectRoundTripTest() {
+  JSValue o = newObject();
+  setProperty(o, 'foo', Foo(4).toJS());
+  Object foo = getProperty(o, 'foo')!.toObject();
+  Expect.equals(4, (foo as Foo).i);
+}
+
+void deepConversionsTest() {
+  // Dart to JS.
+  Expect.isNull(dartify(jsify(null)));
+  Expect.equals(true, dartify(jsify(true)));
+  Expect.equals(2.0, dartify(jsify(2.0)));
+  Expect.equals('foo', dartify(jsify('foo')));
+  _expectListEquals(
+      ['a', 'b', 'c'], dartify(jsify(['a', 'b', 'c'])) as List<Object?>);
+
+  // JS to Dart.
+  eval(r'''
+    globalThis.a = null;
+    globalThis.b = 'foo';
+    globalThis.c = ['a', 'b', 'c'];
+  ''');
+  JSValue 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?>);
+}
+
+void main() {
+  createObjectTest();
+  evalAndConstructTest();
+  dartObjectRoundTripTest();
+  deepConversionsTest();
+}
diff --git a/tests/web/web.status b/tests/web/web.status
index c54cd80..d20e136 100644
--- a/tests/web/web.status
+++ b/tests/web/web.status
@@ -5,6 +5,9 @@
 [ $compiler != dart2js ]
 dummy_compiler_test: SkipByDesign # Issue 30773. Test should be migrated as a unit test of dart2js, is only intended to test self-hosting.
 
+[ $compiler != dart2wasm ]
+wasm/*: SkipByDesign
+
 [ $runtime == jsshell ]
 deferred/load_in_correct_order_test: SkipByDesign # jsshell preamble does not support this test.
 
diff --git a/tools/VERSION b/tools/VERSION
index 3bced45..7b9e5d4 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 17
 PATCH 0
-PRERELEASE 255
+PRERELEASE 256
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index cf5a954..4f67da1 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -2969,7 +2969,8 @@
           "arguments": [
             "-ndart2wasm-hostasserts-linux-x64-d8",
             "language",
-            "corelib"
+            "corelib",
+            "web/wasm"
           ],
           "shards": 30,
           "fileset": "dart2wasm_hostasserts"
diff --git a/tools/manage_deps.dart b/tools/manage_deps.dart
index f954327..80b1b56 100755
--- a/tools/manage_deps.dart
+++ b/tools/manage_deps.dart
@@ -231,6 +231,7 @@
     cmd[0],
     cmd.skip(1).toList(),
     workingDirectory: workingDirectory,
+    environment: {'DEPOT_TOOLS_UPDATE': '0'},
   );
   printSuccessTrailer(result, onFailure);
   final output = (result.stdout as String);