Version 2.17.0-98.0.dev

Merge commit '20401b32ec009344287120d546c381815bdb7a48' into 'dev'
diff --git a/DEPS b/DEPS
index 17285f6..7827868 100644
--- a/DEPS
+++ b/DEPS
@@ -93,7 +93,7 @@
   "collection_rev": "a4c941ab94044d118b2086a3f261c30377604127",
   "convert_rev": "e063fdca4bebffecbb5e6aa5525995120982d9ce",
   "crypto_rev": "b5024e4de2b1c474dd558bef593ddbf0bfade152",
-  "csslib_rev": "158bfa94eed08c12c07a8ee0a3fded0ebdcd1fcb",
+  "csslib_rev": "f746368a0a53cf8f68fd71b218239034e88841d5",
 
   # Note: Updates to dart_style have to be coordinated with the infrastructure
   # team so that the internal formatter `tools/sdks/dart-sdk/bin/dart format`
@@ -130,7 +130,7 @@
   "markupsafe_rev": "8f45f5cfa0009d2a70589bcda0349b8cb2b72783",
   "markdown_rev": "7479783f0493f6717e1d7ae31cb37d39a91026b2",
   "matcher_rev": "07595a7739d47a8315caba5a8e58fb9ae3d81261",
-  "mime_rev": "c931f4bed87221beaece356494b43731445ce7b8",
+  "mime_rev": "7f4252d469de032aa4df9f90e827dbac4b8efa48",
   "mockito_rev": "d39ac507483b9891165e422ec98d9fb480037c8b",
   "oauth2_rev": "7cd3284049fe5badbec9f2bea2afc41d14c01057",
   "package_config_rev": "8731bf10b5375542792a32a0f7c8a6f370583d96",
diff --git a/benchmarks/Iterators/dart/Iterators.dart b/benchmarks/Iterators/dart/Iterators.dart
index b58e880..d4ff6c4 100644
--- a/benchmarks/Iterators/dart/Iterators.dart
+++ b/benchmarks/Iterators/dart/Iterators.dart
@@ -331,6 +331,60 @@
   }
 }
 
+class BenchmarkListIntSystem1 extends MonoBenchmark {
+  // The List type here is not quite monomorphic. It is the choice between two
+  // 'system' Lists: a const List and a growable List. It is quite common to
+  // have growable and const lists at the same use-site (e.g. the const coming
+  // from a default argument).
+  //
+  // Ideally some combination of the class heirarchy or compiler tricks would
+  // ensure there is little cost of having this gentle polymorphism.
+  BenchmarkListIntSystem1(int size)
+      : _list1 = List.generate(size, (i) => i),
+        _list2 = generateConstListOfInt(size),
+        super('List.int.growable.and.const', size);
+
+  final List<int> _list1;
+  final List<int> _list2;
+  bool _flip = false;
+
+  @override
+  void sinkMono() {
+    _flip = !_flip;
+    final list = _flip ? _list1 : _list2;
+    for (final value in list) {
+      sink = value;
+    }
+  }
+}
+
+class BenchmarkListIntSystem2 extends MonoBenchmark {
+  // The List type here is not quite monomorphic. It is the choice between two
+  // 'system' Lists: a const List and a fixed-length List. It is quite common to
+  // have fixed-length and const lists at the same use-site (e.g. the const
+  // coming from a default argument).
+  //
+  // Ideally some combination of the class heirarchy or compiler tricks would
+  // ensure there is little cost of having this gentle polymorphism.
+  BenchmarkListIntSystem2(int size)
+      : _list1 = List.generate(size, (i) => i, growable: false),
+        _list2 = generateConstListOfInt(size),
+        super('List.int.fixed.and.const', size);
+
+  final List<int> _list1;
+  final List<int> _list2;
+  bool _flip = false;
+
+  @override
+  void sinkMono() {
+    _flip = !_flip;
+    final list = _flip ? _list1 : _list2;
+    for (final value in list) {
+      sink = value;
+    }
+  }
+}
+
 /// A simple Iterable that yields the integers 0 through `length`.
 ///
 /// This Iterable serves as the minimal interesting example to serve as a
@@ -492,6 +546,8 @@
       Benchmark('Runes', size, (n) => generateString(n).runes),
       // ---
       BenchmarkListIntGrowable(size),
+      BenchmarkListIntSystem1(size),
+      BenchmarkListIntSystem2(size),
       Benchmark('List.int.growable', size,
           (n) => List<int>.of(UpTo(n), growable: true)),
       Benchmark('List.int.fixed', size,
diff --git a/benchmarks/Iterators/dart/data.dart b/benchmarks/Iterators/dart/data.dart
index eabe7f4..f59c26f 100644
--- a/benchmarks/Iterators/dart/data.dart
+++ b/benchmarks/Iterators/dart/data.dart
@@ -12,6 +12,11 @@
       (throw ArgumentError.value(n, 'n', 'size not supported'));
 }
 
+List<int> generateConstListOfInt(int n) {
+  return constListOfIntTable[n] ??
+      (throw ArgumentError.value(n, 'n', 'size not supported'));
+}
+
 const Map<int, Map<int, int>> constMapIntIntTable = {
   0: constMapIntInt0,
   1: constMapIntInt1,
@@ -136,104 +141,37 @@
 const Set<int> constSetOfInt1 = {0};
 const Set<int> constSetOfInt2 = {0, 1};
 const Set<int> constSetOfInt100 = {
-  0,
-  1,
-  2,
-  3,
-  4,
-  5,
-  6,
-  7,
-  8,
-  9,
-  10,
-  11,
-  12,
-  13,
-  14,
-  15,
-  16,
-  17,
-  18,
-  19,
-  20,
-  21,
-  22,
-  23,
-  24,
-  25,
-  26,
-  27,
-  28,
-  29,
-  30,
-  31,
-  32,
-  33,
-  34,
-  35,
-  36,
-  37,
-  38,
-  39,
-  40,
-  41,
-  42,
-  43,
-  44,
-  45,
-  46,
-  47,
-  48,
-  49,
-  50,
-  51,
-  52,
-  53,
-  54,
-  55,
-  56,
-  57,
-  58,
-  59,
-  60,
-  61,
-  62,
-  63,
-  64,
-  65,
-  66,
-  67,
-  68,
-  69,
-  70,
-  71,
-  72,
-  73,
-  74,
-  75,
-  76,
-  77,
-  78,
-  79,
-  80,
-  81,
-  82,
-  83,
-  84,
-  85,
-  86,
-  87,
-  88,
-  89,
-  90,
-  91,
-  92,
-  93,
-  94,
-  95,
-  96,
-  97,
-  98,
-  99
+  ...{0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
+  ...{10, 11, 12, 13, 14, 15, 16, 17, 18, 19},
+  ...{20, 21, 22, 23, 24, 25, 26, 27, 28, 29},
+  ...{30, 31, 32, 33, 34, 35, 36, 37, 38, 39},
+  ...{40, 41, 42, 43, 44, 45, 46, 47, 48, 49},
+  ...{50, 51, 52, 53, 54, 55, 56, 57, 58, 59},
+  ...{60, 61, 62, 63, 64, 65, 66, 67, 68, 69},
+  ...{70, 71, 72, 73, 74, 75, 76, 77, 78, 79},
+  ...{80, 81, 82, 83, 84, 85, 86, 87, 88, 89},
+  ...{90, 91, 92, 93, 94, 95, 96, 97, 98, 99}
 };
+
+const Map<int, List<int>> constListOfIntTable = {
+  0: constListOfInt0,
+  1: constListOfInt1,
+  2: constListOfInt2,
+  100: constListOfInt100
+};
+
+const List<int> constListOfInt0 = [];
+const List<int> constListOfInt1 = [0];
+const List<int> constListOfInt2 = [0, 1];
+const List<int> constListOfInt100 = [
+  ...[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
+  ...[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
+  ...[20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
+  ...[30, 31, 32, 33, 34, 35, 36, 37, 38, 39],
+  ...[40, 41, 42, 43, 44, 45, 46, 47, 48, 49],
+  ...[50, 51, 52, 53, 54, 55, 56, 57, 58, 59],
+  ...[60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
+  ...[70, 71, 72, 73, 74, 75, 76, 77, 78, 79],
+  ...[80, 81, 82, 83, 84, 85, 86, 87, 88, 89],
+  ...[90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
+];
diff --git a/pkg/_fe_analyzer_shared/analysis_options_no_lints.yaml b/pkg/_fe_analyzer_shared/analysis_options_no_lints.yaml
index 24c5c54..310a360 100644
--- a/pkg/_fe_analyzer_shared/analysis_options_no_lints.yaml
+++ b/pkg/_fe_analyzer_shared/analysis_options_no_lints.yaml
@@ -19,3 +19,4 @@
     - test/inference/inferred_type_arguments/data/**
     - test/inference/inferred_variable_types/data/**
     - test/inheritance/data/**
+    - test/macros/api/**
diff --git a/pkg/_fe_analyzer_shared/test/macros/api/api_test_data.dart b/pkg/_fe_analyzer_shared/test/macros/api/api_test_data.dart
new file mode 100644
index 0000000..82c2e5f
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/macros/api/api_test_data.dart
@@ -0,0 +1,19 @@
+// 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 'api_test_macro.dart';
+
+main() {}
+
+@ClassMacro()
+class Class1 {}
+
+@ClassMacro()
+abstract class Class2 {}
+
+@FunctionMacro()
+void topLevelFunction1(Class1 a, {Class1? b, required Class2? c}) {}
+
+@FunctionMacro()
+external Class2 topLevelFunction2(Class1 a, [Class2? b]);
diff --git a/pkg/_fe_analyzer_shared/test/macros/api/api_test_expectations.dart b/pkg/_fe_analyzer_shared/test/macros/api/api_test_expectations.dart
new file mode 100644
index 0000000..b43d1e6
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/macros/api/api_test_expectations.dart
@@ -0,0 +1,159 @@
+// 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/macros/api.dart';
+
+const Map<String, ClassData> expectedClassData = {
+  'Class1': ClassData(),
+  'Class2': ClassData(isAbstract: true),
+};
+
+const Map<String, FunctionData> expectedFunctionData = {
+  'topLevelFunction1': FunctionData(
+      returnType: NamedTypeData(name: 'void'),
+      positionalParameters: [
+        ParameterData('a',
+            type: NamedTypeData(name: 'Class1'), isRequired: true),
+      ],
+      namedParameters: [
+        ParameterData('b',
+            type: NamedTypeData(name: 'Class1', isNullable: true),
+            isNamed: true,
+            isRequired: false),
+        ParameterData('c',
+            type: NamedTypeData(name: 'Class2', isNullable: true),
+            isNamed: true,
+            isRequired: true),
+      ]),
+  'topLevelFunction2': FunctionData(
+    isExternal: true,
+    returnType: NamedTypeData(name: 'Class2'),
+    positionalParameters: [
+      ParameterData('a', type: NamedTypeData(name: 'Class1'), isRequired: true),
+      ParameterData('b', type: NamedTypeData(name: 'Class2', isNullable: true)),
+    ],
+  ),
+};
+
+expect(expected, actual, property) {
+  if (expected != actual) {
+    throw 'Expected $expected, actual $actual on $property';
+  }
+}
+
+void checkTypeAnnotation(
+    TypeData expected, TypeAnnotation typeAnnotation, String context) {
+  expect(expected.isNullable, typeAnnotation.isNullable, '$context.isNullable');
+  expect(expected is NamedTypeData, typeAnnotation is NamedTypeAnnotation,
+      '$context is NamedTypeAnnotation');
+  if (expected is NamedTypeData && typeAnnotation is NamedTypeAnnotation) {
+    expect(expected.name, typeAnnotation.identifier.name, '$context.name');
+    // TODO(johnniwinther): Test more properties.
+  }
+}
+
+void checkParameterDeclaration(
+    ParameterData expected, ParameterDeclaration declaration, String context) {
+  expect(expected.name, declaration.identifier.name, '$context.identifer.name');
+  expect(expected.isNamed, declaration.isNamed, '$context.isNamed');
+  expect(expected.isRequired, declaration.isRequired, '$context.isRequired');
+  checkTypeAnnotation(expected.type, declaration.type, '$context.type');
+}
+
+void checkClassDeclaration(ClassDeclaration declaration) {
+  String name = declaration.identifier.name;
+  ClassData? expected = expectedClassData[name];
+  if (expected != null) {
+    expect(expected.isAbstract, declaration.isAbstract, '$name.isAbstract');
+    expect(expected.isExternal, declaration.isExternal, '$name.isExternal');
+    // TODO(johnniwinther): Test more properties when there are supported.
+  } else {
+    throw 'Unexpected class declaration "${name}"';
+  }
+}
+
+void checkFunctionDeclaration(FunctionDeclaration actual) {
+  String name = actual.identifier.name;
+  FunctionData? expected = expectedFunctionData[name];
+  if (expected != null) {
+    expect(expected.isAbstract, actual.isAbstract, '$name.isAbstract');
+    expect(expected.isExternal, actual.isExternal, '$name.isExternal');
+    expect(expected.isOperator, actual.isOperator, '$name.isOperator');
+    expect(expected.isGetter, actual.isGetter, '$name.isGetter');
+    expect(expected.isSetter, actual.isSetter, '$name.isSetter');
+    checkTypeAnnotation(
+        expected.returnType, actual.returnType, '$name.returnType');
+    expect(
+        expected.positionalParameters.length,
+        actual.positionalParameters.length,
+        '$name.positionalParameters.length');
+    for (int i = 0; i < expected.positionalParameters.length; i++) {
+      checkParameterDeclaration(
+          expected.positionalParameters[i],
+          actual.positionalParameters.elementAt(i),
+          '$name.positionalParameters[$i]');
+    }
+    expect(expected.namedParameters.length, actual.namedParameters.length,
+        '$name.namedParameters.length');
+    for (int i = 0; i < expected.namedParameters.length; i++) {
+      checkParameterDeclaration(expected.namedParameters[i],
+          actual.namedParameters.elementAt(i), '$name.namedParameters[$i]');
+    }
+    // TODO(johnniwinther): Test more properties.
+  } else {
+    throw 'Unexpected function declaration "${name}"';
+  }
+}
+
+class ClassData {
+  final bool isAbstract;
+  final bool isExternal;
+
+  const ClassData({this.isAbstract: false, this.isExternal: false});
+}
+
+class FunctionData {
+  final bool isAbstract;
+  final bool isExternal;
+  final bool isOperator;
+  final bool isGetter;
+  final bool isSetter;
+  final TypeData returnType;
+  final List<ParameterData> positionalParameters;
+  final List<ParameterData> namedParameters;
+
+  const FunctionData(
+      {this.isAbstract: false,
+      this.isExternal: false,
+      this.isOperator: false,
+      this.isGetter: false,
+      this.isSetter: false,
+      required this.returnType,
+      this.positionalParameters: const [],
+      this.namedParameters: const []});
+}
+
+class TypeData {
+  final bool isNullable;
+
+  const TypeData({this.isNullable: false});
+}
+
+class NamedTypeData extends TypeData {
+  final String? name;
+  final List<TypeData>? typeArguments;
+
+  const NamedTypeData({bool isNullable: false, this.name, this.typeArguments})
+      : super(isNullable: isNullable);
+}
+
+class ParameterData {
+  final String name;
+  final TypeData type;
+  final bool isRequired;
+  final bool isNamed;
+
+  const ParameterData(this.name,
+      {required this.type, this.isNamed: false, this.isRequired: false});
+}
diff --git a/pkg/_fe_analyzer_shared/test/macros/api/api_test_macro.dart b/pkg/_fe_analyzer_shared/test/macros/api/api_test_macro.dart
new file mode 100644
index 0000000..2110615
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/macros/api/api_test_macro.dart
@@ -0,0 +1,52 @@
+// 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:_fe_analyzer_shared/src/macros/api.dart';
+import 'api_test_expectations.dart';
+
+
+
+macro class ClassMacro
+    implements ClassTypesMacro, ClassDeclarationsMacro, ClassDefinitionMacro {
+  const ClassMacro();
+
+  FutureOr<void> buildTypesForClass(
+      ClassDeclaration clazz, TypeBuilder builder) {
+    checkClassDeclaration(clazz);
+  }
+
+  FutureOr<void> buildDeclarationsForClass(
+      ClassDeclaration clazz, ClassMemberDeclarationBuilder builder) {
+    checkClassDeclaration(clazz);
+  }
+
+  FutureOr<void> buildDefinitionForClass(
+      ClassDeclaration clazz, ClassDefinitionBuilder builder) {
+    checkClassDeclaration(clazz);
+  }
+}
+
+macro class FunctionMacro
+    implements
+        FunctionTypesMacro,
+        FunctionDeclarationsMacro,
+        FunctionDefinitionMacro {
+  const FunctionMacro();
+
+  FutureOr<void> buildTypesForFunction(
+      FunctionDeclaration function, TypeBuilder builder) {
+    checkFunctionDeclaration(function);
+  }
+
+  FutureOr<void> buildDeclarationsForFunction(
+      FunctionDeclaration function, DeclarationBuilder builder) {
+    checkFunctionDeclaration(function);
+  }
+
+  FutureOr<void> buildDefinitionForFunction(
+      FunctionDeclaration function, FunctionDefinitionBuilder builder) {
+    checkFunctionDeclaration(function);
+  }
+}
diff --git a/pkg/_fe_analyzer_shared/test/macros/api/package_config.json b/pkg/_fe_analyzer_shared/test/macros/api/package_config.json
new file mode 100644
index 0000000..8fa0595
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/macros/api/package_config.json
@@ -0,0 +1,18 @@
+{
+  "configVersion": 2,
+  "packages": [
+    {
+      "name": "macro_api_test",
+      "rootUri": "../../../../_fe_analyzer_shared/test/macros/api/"
+    },
+    {
+      "name": "meta",
+      "rootUri": "../../../../meta/",
+      "packageUri": "lib/"
+    },
+    {
+      "name": "_fe_analyzer_shared",
+      "rootUri": "../../../../_fe_analyzer_shared/lib/"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index 560c08b..4e9864a 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -4754,7 +4754,8 @@
   <dl><dt class="field"><b>positions: List&lt;<a href="#type_Position">Position</a>&gt;</b></dt><dd>
         
         <p>
-          The positions of the regions that should be edited simultaneously.
+          The positions of the regions (after applying the relevant edits) that
+          should be edited simultaneously.
         </p>
       </dd><dt class="field"><b>length: int</b></dt><dd>
         
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index 47504a4..ba94d24 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -32,8 +32,8 @@
 import 'package:analyzer/src/dart/sdk/sdk.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/sdk.dart';
+import 'package:analyzer/src/util/sdk.dart';
 import 'package:args/args.dart';
-import 'package:cli_util/cli_util.dart';
 import 'package:linter/src/rules.dart' as linter;
 import 'package:telemetry/crash_reporting.dart';
 import 'package:telemetry/telemetry.dart' as telemetry;
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
index 1dbfe52..f7d945a 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
@@ -264,6 +264,29 @@
   }
 
   @override
+  void visitEnumDeclaration(EnumDeclaration node) {
+    if (!request.featureSet.isEnabled(Feature.enhanced_enums)) {
+      return;
+    }
+
+    if (entity == node.name) {
+      return;
+    }
+
+    var semicolon = node.semicolon;
+    if (request.offset <= node.leftBracket.offset) {
+      if (node.withClause == null) {
+        _addSuggestion(Keyword.WITH);
+      }
+      if (node.implementsClause == null) {
+        _addSuggestion(Keyword.IMPLEMENTS);
+      }
+    } else if (semicolon != null && semicolon.end <= request.offset) {
+      _addEnumBodyKeywords();
+    }
+  }
+
+  @override
   void visitExpression(Expression node) {
     _addExpressionKeywords(node);
   }
@@ -860,6 +883,21 @@
     }
   }
 
+  void _addEnumBodyKeywords() {
+    _addSuggestions([
+      Keyword.CONST,
+      Keyword.DYNAMIC,
+      Keyword.FINAL,
+      Keyword.GET,
+      Keyword.LATE,
+      Keyword.OPERATOR,
+      Keyword.SET,
+      Keyword.STATIC,
+      Keyword.VAR,
+      Keyword.VOID
+    ]);
+  }
+
   void _addExpressionKeywords(AstNode node) {
     _addSuggestions([
       Keyword.FALSE,
diff --git a/pkg/analysis_server/lib/src/services/correction/error_fix_status.txt b/pkg/analysis_server/lib/src/services/correction/error_fix_status.txt
index d19627a..0c07171 100644
--- a/pkg/analysis_server/lib/src/services/correction/error_fix_status.txt
+++ b/pkg/analysis_server/lib/src/services/correction/error_fix_status.txt
@@ -633,7 +633,7 @@
 LintNames.always_put_required_named_parameters_first: needs evaluation
 LintNames.always_require_non_null_named_parameters: has fix(es)
 LintNames.always_specify_types: has fix(es)
-LintNames.always_use_package_imports: needs evaluation
+LintNames.always_use_package_imports: has fix(es)
 LintNames.annotate_overrides: has fix(es)
 LintNames.avoid_annotating_with_dynamic: has fix(es)
 LintNames.avoid_as: needs evaluation
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 6f03b72..9258b2f 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -347,6 +347,9 @@
     LintNames.always_specify_types: [
       AddTypeAnnotation.newInstanceBulkFixable,
     ],
+    LintNames.always_use_package_imports: [
+      ConvertToPackageImport.newInstance,
+    ],
     LintNames.annotate_overrides: [
       AddOverride.newInstance,
     ],
diff --git a/pkg/analysis_server/lib/src/services/linter/lint_names.dart b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
index 62d8f5e..123600d 100644
--- a/pkg/analysis_server/lib/src/services/linter/lint_names.dart
+++ b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
@@ -9,6 +9,7 @@
   static const String always_require_non_null_named_parameters =
       'always_require_non_null_named_parameters';
   static const String always_specify_types = 'always_specify_types';
+  static const String always_use_package_imports = 'always_use_package_imports';
   static const String annotate_overrides = 'annotate_overrides';
   static const String avoid_annotating_with_dynamic =
       'avoid_annotating_with_dynamic';
diff --git a/pkg/analysis_server/pubspec.yaml b/pkg/analysis_server/pubspec.yaml
index 39518e8..5f62d61 100644
--- a/pkg/analysis_server/pubspec.yaml
+++ b/pkg/analysis_server/pubspec.yaml
@@ -13,7 +13,6 @@
   analyzer_plugin:
     path: ../analyzer_plugin
   args: any
-  cli_util: any
   collection: any
   convert: any
   crypto: any
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index 8b4050d..0ecd2f7 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -14,6 +14,7 @@
 import 'package:analysis_server/src/utilities/mocks.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/instrumentation/service.dart';
+import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/test_utilities/mock_sdk.dart';
 import 'package:analyzer/src/test_utilities/package_config_file_builder.dart';
@@ -39,6 +40,52 @@
   });
 }
 
+/// TODO(scheglov) this is duplicate
+class AnalysisOptionsFileConfig {
+  final List<String> experiments;
+  final bool implicitCasts;
+  final bool implicitDynamic;
+  final List<String> lints;
+  final bool strictCasts;
+  final bool strictInference;
+  final bool strictRawTypes;
+
+  AnalysisOptionsFileConfig({
+    this.experiments = const [],
+    this.implicitCasts = true,
+    this.implicitDynamic = true,
+    this.lints = const [],
+    this.strictCasts = false,
+    this.strictInference = false,
+    this.strictRawTypes = false,
+  });
+
+  String toContent() {
+    var buffer = StringBuffer();
+
+    buffer.writeln('analyzer:');
+    buffer.writeln('  enable-experiment:');
+    for (var experiment in experiments) {
+      buffer.writeln('    - $experiment');
+    }
+    buffer.writeln('  language:');
+    buffer.writeln('    strict-casts: $strictCasts');
+    buffer.writeln('    strict-inference: $strictInference');
+    buffer.writeln('    strict-raw-types: $strictRawTypes');
+    buffer.writeln('  strong-mode:');
+    buffer.writeln('    implicit-casts: $implicitCasts');
+    buffer.writeln('    implicit-dynamic: $implicitDynamic');
+
+    buffer.writeln('linter:');
+    buffer.writeln('  rules:');
+    for (var lint in lints) {
+      buffer.writeln('    - $lint');
+    }
+
+    return buffer.toString();
+  }
+}
+
 @reflectiveTest
 class CompletionDomainHandlerGetSuggestionDetails2Test
     extends PubPackageAnalysisServerTest {
@@ -2882,6 +2929,12 @@
     return server.handlers.whereType<CompletionDomainHandler>().single;
   }
 
+  List<String> get experiments => [
+        EnableString.enhanced_enums,
+        EnableString.named_arguments_anywhere,
+        EnableString.super_parameters,
+      ];
+
   String get testFileContent => getFile(testFilePath).readAsStringSync();
 
   String get testFilePath => '$testPackageLibPath/test.dart';
@@ -2929,6 +2982,12 @@
 
     writeTestPackageConfig();
 
+    writeTestPackageAnalysisOptionsFile(
+      AnalysisOptionsFileConfig(
+        experiments: experiments,
+      ),
+    );
+
     server = AnalysisServer(
       serverChannel,
       resourceProvider,
@@ -2948,6 +3007,13 @@
     );
   }
 
+  void writeTestPackageAnalysisOptionsFile(AnalysisOptionsFileConfig config) {
+    newAnalysisOptionsYamlFile(
+      testPackageRootPath,
+      content: config.toContent(),
+    );
+  }
+
   void writeTestPackageConfig({
     PackageConfigFileBuilder? config,
     String? languageVersion,
diff --git a/pkg/analysis_server/test/integration/edit/import_elements_test.dart b/pkg/analysis_server/test/integration/edit/import_elements_test.dart
index 43ecb92..40e370d 100644
--- a/pkg/analysis_server/test/integration/edit/import_elements_test.dart
+++ b/pkg/analysis_server/test/integration/edit/import_elements_test.dart
@@ -4,8 +4,8 @@
 
 import 'package:analysis_server/protocol/protocol_generated.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/src/util/sdk.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart';
-import 'package:cli_util/cli_util.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
diff --git a/pkg/analysis_server/test/services/completion/dart/completion_check.dart b/pkg/analysis_server/test/services/completion/dart/completion_check.dart
index 6ecb423..eeab07a 100644
--- a/pkg/analysis_server/test/services/completion/dart/completion_check.dart
+++ b/pkg/analysis_server/test/services/completion/dart/completion_check.dart
@@ -3,9 +3,17 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analysis_server/src/protocol_server.dart';
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer_utilities/check/check.dart';
 import 'package:meta/meta.dart';
 
+typedef CompletionSuggestionChecker = void Function(
+  CompletionSuggestionTarget suggestion,
+);
+
+typedef CompletionSuggestionTarget
+    = CheckTarget<CompletionSuggestionForTesting>;
+
 class CompletionResponseForTesting {
   final int requestOffset;
   final int replacementOffset;
@@ -209,11 +217,20 @@
     element.isNotNull.kind.isPrefix;
   }
 
+  void get isKeywordAny {
+    kind.isKeyword;
+  }
+
   void get isMethodInvocation {
     kind.isInvocation;
     element.isNotNull.kind.isMethod;
   }
 
+  void get isMixin {
+    kind.isIdentifier;
+    element.isNotNull.kind.isMixin;
+  }
+
   void get isNamedArgument {
     kind.isNamedArgument;
     element.isNull;
@@ -335,6 +352,11 @@
     selectionOffset.isEqualTo(offset);
     selectionLength.isEqualTo(length);
   }
+
+  void isKeyword(Keyword keyword) {
+    kind.isKeyword;
+    completion.isEqualTo(keyword.lexeme);
+  }
 }
 
 extension CompletionSuggestionKindExtension
@@ -347,6 +369,10 @@
     isEqualTo(CompletionSuggestionKind.INVOCATION);
   }
 
+  void get isKeyword {
+    isEqualTo(CompletionSuggestionKind.KEYWORD);
+  }
+
   void get isNamedArgument {
     isEqualTo(CompletionSuggestionKind.NAMED_ARGUMENT);
   }
@@ -437,6 +463,10 @@
     isEqualTo(ElementKind.METHOD);
   }
 
+  void get isMixin {
+    isEqualTo(ElementKind.MIXIN);
+  }
+
   void get isParameter {
     isEqualTo(ElementKind.PARAMETER);
   }
@@ -453,3 +483,10 @@
     isEqualTo(ElementKind.TOP_LEVEL_VARIABLE);
   }
 }
+
+extension KeywordsExtension on Iterable<Keyword> {
+  List<CompletionSuggestionChecker> get asKeywordChecks {
+    return map((e) => (CompletionSuggestionTarget suggestion) =>
+        suggestion.isKeyword(e)).toList();
+  }
+}
diff --git a/pkg/analysis_server/test/services/completion/dart/location/enum_constant_test.dart b/pkg/analysis_server/test/services/completion/dart/location/enum_constant_test.dart
new file mode 100644
index 0000000..c9d4bf1
--- /dev/null
+++ b/pkg/analysis_server/test/services/completion/dart/location/enum_constant_test.dart
@@ -0,0 +1,45 @@
+// 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:analyzer_utilities/check/check.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../../../../client/completion_driver_test.dart';
+import '../completion_check.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(EnumConstantDeclarationTest1);
+    defineReflectiveTests(EnumConstantDeclarationTest2);
+  });
+}
+
+@reflectiveTest
+class EnumConstantDeclarationTest1 extends AbstractCompletionDriverTest
+    with EnumConstantDeclarationTestCases {
+  @override
+  TestingCompletionProtocol get protocol => TestingCompletionProtocol.version1;
+}
+
+@reflectiveTest
+class EnumConstantDeclarationTest2 extends AbstractCompletionDriverTest
+    with EnumConstantDeclarationTestCases {
+  @override
+  TestingCompletionProtocol get protocol => TestingCompletionProtocol.version2;
+}
+
+mixin EnumConstantDeclarationTestCases on AbstractCompletionDriverTest {
+  @override
+  bool get supportsAvailableSuggestions => true;
+
+  Future<void> test_afterName_atEnd() async {
+    var response = await getTestCodeSuggestions('''
+enum E {
+  v^
+}
+''');
+
+    check(response).suggestions.isEmpty;
+  }
+}
diff --git a/pkg/analysis_server/test/services/completion/dart/location/enum_test.dart b/pkg/analysis_server/test/services/completion/dart/location/enum_test.dart
new file mode 100644
index 0000000..ad76948
--- /dev/null
+++ b/pkg/analysis_server/test/services/completion/dart/location/enum_test.dart
@@ -0,0 +1,255 @@
+// 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:analyzer/dart/ast/token.dart';
+import 'package:analyzer_utilities/check/check.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../../../../client/completion_driver_test.dart';
+import '../completion_check.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(EnumDeclarationTest1);
+    defineReflectiveTests(EnumDeclarationTest2);
+  });
+}
+
+@reflectiveTest
+class EnumDeclarationTest1 extends AbstractCompletionDriverTest
+    with EnumDeclarationTestCases {
+  @override
+  TestingCompletionProtocol get protocol => TestingCompletionProtocol.version1;
+}
+
+@reflectiveTest
+class EnumDeclarationTest2 extends AbstractCompletionDriverTest
+    with EnumDeclarationTestCases {
+  @override
+  TestingCompletionProtocol get protocol => TestingCompletionProtocol.version2;
+
+  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/48371')
+  Future<void> test_afterName_w() async {
+    var response = await getTestCodeSuggestions('''
+enum E w^ {
+  v
+}
+''');
+
+    check(response).suggestions.matchesInAnyOrder([
+      (suggestion) => suggestion.isKeyword(Keyword.WITH),
+    ]);
+  }
+}
+
+mixin EnumDeclarationTestCases on AbstractCompletionDriverTest {
+  static List<CompletionSuggestionChecker> get _bodyKeywords {
+    const keywords = [
+      Keyword.CONST,
+      Keyword.DYNAMIC,
+      Keyword.FINAL,
+      Keyword.GET,
+      Keyword.LATE,
+      Keyword.OPERATOR,
+      Keyword.SET,
+      Keyword.STATIC,
+      Keyword.VAR,
+      Keyword.VOID
+    ];
+    return keywords.asKeywordChecks;
+  }
+
+  @override
+  bool get supportsAvailableSuggestions => true;
+
+  Future<void> test_afterConstants_noSemicolon() async {
+    var response = await getTestCodeSuggestions('''
+enum E {
+  v ^
+}
+''');
+
+    check(response).suggestions.isEmpty;
+  }
+
+  Future<void> test_afterImplements() async {
+    var response = await getTestCodeSuggestions('''
+enum E implements ^ {
+  v
+}
+''');
+
+    check(response).suggestions
+      ..includesAll([
+        (suggestion) => suggestion
+          ..completion.isEqualTo('Object')
+          ..isClass,
+      ])
+      ..excludesAll([
+        (suggestion) => suggestion.isKeywordAny,
+      ]);
+  }
+
+  Future<void> test_afterImplementsClause() async {
+    var response = await getTestCodeSuggestions('''
+enum E implements A ^ {
+  v
+}
+''');
+
+    check(response).suggestions.matchesInAnyOrder([
+      (suggestion) => suggestion.isKeyword(Keyword.WITH),
+    ]);
+  }
+
+  Future<void> test_afterName() async {
+    var response = await getTestCodeSuggestions('''
+enum E ^ {
+  v
+}
+''');
+
+    check(response).suggestions.matchesInAnyOrder([
+      (suggestion) => suggestion.isKeyword(Keyword.IMPLEMENTS),
+      (suggestion) => suggestion.isKeyword(Keyword.WITH),
+    ]);
+  }
+
+  Future<void> test_afterName_atEnd() async {
+    var response = await getTestCodeSuggestions('''
+enum E^ {
+  v
+}
+''');
+
+    check(response).suggestions.isEmpty;
+  }
+
+  Future<void> test_afterName_atLeftCurlyBracket() async {
+    var response = await getTestCodeSuggestions('''
+enum E ^{
+  v
+}
+''');
+
+    check(response).suggestions.matchesInAnyOrder([
+      (suggestion) => suggestion.isKeyword(Keyword.IMPLEMENTS),
+      (suggestion) => suggestion.isKeyword(Keyword.WITH),
+    ]);
+  }
+
+  Future<void> test_afterName_beforeImplements() async {
+    var response = await getTestCodeSuggestions('''
+enum E ^ implements A {
+  v
+}
+''');
+
+    check(response).suggestions.matchesInAnyOrder([
+      (suggestion) => suggestion.isKeyword(Keyword.WITH),
+    ]);
+  }
+
+  Future<void> test_afterName_hasWith_hasImplements() async {
+    var response = await getTestCodeSuggestions('''
+enum E ^ with M implements A {
+  v
+}
+''');
+
+    check(response).suggestions.isEmpty;
+  }
+
+  Future<void> test_afterName_language216() async {
+    var response = await getTestCodeSuggestions('''
+// @dart = 2.16
+enum E ^ {
+  v
+}
+''');
+
+    check(response).suggestions.isEmpty;
+  }
+
+  Future<void> test_afterSemicolon() async {
+    var response = await getTestCodeSuggestions('''
+enum E {
+  v;^
+}
+''');
+
+    check(response).suggestions.includesAll([
+      (suggestion) => suggestion
+        ..completion.isEqualTo('Object')
+        ..isClass,
+      ..._bodyKeywords,
+    ]);
+  }
+
+  Future<void> test_afterSemicolon_beforeVoid() async {
+    var response = await getTestCodeSuggestions('''
+enum E {
+  v;
+  ^void foo() {}
+}
+''');
+
+    check(response).suggestions.includesAll([
+      (suggestion) => suggestion
+        ..completion.isEqualTo('Object')
+        ..isClass,
+      ..._bodyKeywords,
+    ]);
+  }
+
+  Future<void> test_afterWith() async {
+    var response = await getTestCodeSuggestions('''
+enum E with ^ {
+  v
+}
+''');
+
+    check(response).suggestions
+      ..includesAll([
+        (suggestion) => suggestion
+          ..completion.isEqualTo('Object')
+          ..isClass,
+      ])
+      ..excludesAll([
+        (suggestion) => suggestion.isKeywordAny,
+      ]);
+  }
+
+  Future<void> test_afterWithClause() async {
+    var response = await getTestCodeSuggestions('''
+enum E with M ^ {
+  v
+}
+''');
+
+    check(response).suggestions.matchesInAnyOrder([
+      (suggestion) => suggestion.isKeyword(Keyword.IMPLEMENTS),
+    ]);
+  }
+
+  Future<void> test_beforeConstants_hasSemicolon() async {
+    var response = await getTestCodeSuggestions('''
+enum E {
+ ^ v;
+}
+''');
+
+    check(response).suggestions.isEmpty;
+  }
+
+  Future<void> test_beforeConstants_noSemicolon() async {
+    var response = await getTestCodeSuggestions('''
+enum E {
+ ^ v
+}
+''');
+
+    check(response).suggestions.isEmpty;
+  }
+}
diff --git a/pkg/analysis_server/test/services/completion/dart/location/test_all.dart b/pkg/analysis_server/test/services/completion/dart/location/test_all.dart
index 3e30b45..bd42780 100644
--- a/pkg/analysis_server/test/services/completion/dart/location/test_all.dart
+++ b/pkg/analysis_server/test/services/completion/dart/location/test_all.dart
@@ -4,6 +4,8 @@
 
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
+import 'enum_constant_test.dart' as enum_constant;
+import 'enum_test.dart' as enum_;
 import 'field_formal_parameter_test.dart' as field_formal_parameter;
 import 'named_expression_test.dart' as named_expression;
 import 'super_formal_parameter_test.dart' as super_formal_parameter;
@@ -11,6 +13,8 @@
 /// Tests suggestions produced at specific locations.
 void main() {
   defineReflectiveSuite(() {
+    enum_constant.main();
+    enum_.main();
     field_formal_parameter.main();
     named_expression.main();
     super_formal_parameter.main();
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_package_import_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_package_import_test.dart
index c59880a..9e78353 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/convert_to_package_import_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_package_import_test.dart
@@ -11,13 +11,75 @@
 
 void main() {
   defineReflectiveSuite(() {
-    defineReflectiveTests(ConvertToPackageImportBulkTest);
-    defineReflectiveTests(ConvertToPackageImportTest);
+    defineReflectiveTests(
+        ConvertToPackageImport_AvoidRelativeLibImportsBulkTest);
+    defineReflectiveTests(ConvertToPackageImport_AvoidRelativeLibImportsTest);
+    defineReflectiveTests(
+        ConvertToPackageImport_AlwaysUsePackageImportsBulkTest);
+    defineReflectiveTests(ConvertToPackageImport_AlwaysUsePackageImportsTest);
   });
 }
 
 @reflectiveTest
-class ConvertToPackageImportBulkTest extends BulkFixProcessorTest {
+class ConvertToPackageImport_AlwaysUsePackageImportsBulkTest
+    extends BulkFixProcessorTest {
+  @override
+  String get lintCode => LintNames.always_use_package_imports;
+
+  Future<void> test_singleFile() async {
+    writeTestPackageConfig(config: PackageConfigFileBuilder());
+    addSource('$testPackageLibPath/foo.dart', 'class Foo {}');
+    addSource('$testPackageLibPath/bar.dart', 'class Bar {}');
+
+    testFile = convertPath('$testPackageLibPath/test.dart');
+
+    await resolveTestCode('''
+import 'foo.dart';
+import 'bar.dart';
+
+var foo = Foo();
+var bar = Bar();
+''');
+    await assertHasFix('''
+import 'package:test/foo.dart';
+import 'package:test/bar.dart';
+
+var foo = Foo();
+var bar = Bar();
+''');
+  }
+}
+
+@reflectiveTest
+class ConvertToPackageImport_AlwaysUsePackageImportsTest
+    extends FixProcessorLintTest {
+  @override
+  FixKind get kind => DartFixKind.CONVERT_TO_PACKAGE_IMPORT;
+
+  @override
+  String get lintCode => LintNames.always_use_package_imports;
+
+  Future<void> test_relativeImport() async {
+    newFile('$testPackageLibPath/foo.dart', content: '''
+class Foo {}
+''');
+    await resolveTestCode('''
+import 'foo.dart';
+
+var foo = Foo();
+''');
+
+    await assertHasFix('''
+import 'package:test/foo.dart';
+
+var foo = Foo();
+''');
+  }
+}
+
+@reflectiveTest
+class ConvertToPackageImport_AvoidRelativeLibImportsBulkTest
+    extends BulkFixProcessorTest {
   @override
   String get lintCode => LintNames.avoid_relative_lib_imports;
 
@@ -42,7 +104,8 @@
 }
 
 @reflectiveTest
-class ConvertToPackageImportTest extends FixProcessorLintTest {
+class ConvertToPackageImport_AvoidRelativeLibImportsTest
+    extends FixProcessorLintTest {
   @override
   FixKind get kind => DartFixKind.CONVERT_TO_PACKAGE_IMPORT;
 
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/LinkedEditGroup.java b/pkg/analysis_server/tool/spec/generated/java/types/LinkedEditGroup.java
index c315c1c..e858201 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/LinkedEditGroup.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/LinkedEditGroup.java
@@ -40,7 +40,8 @@
   public static final List<LinkedEditGroup> EMPTY_LIST = Lists.newArrayList();
 
   /**
-   * The positions of the regions that should be edited simultaneously.
+   * The positions of the regions (after applying the relevant edits) that should be edited
+   * simultaneously.
    */
   private final List<Position> positions;
 
@@ -102,7 +103,8 @@
   }
 
   /**
-   * The positions of the regions that should be edited simultaneously.
+   * The positions of the regions (after applying the relevant edits) that should be edited
+   * simultaneously.
    */
   public List<Position> getPositions() {
     return positions;
diff --git a/pkg/analysis_server_client/lib/src/protocol/protocol_common.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_common.dart
index 71431b4..ca03c4d 100644
--- a/pkg/analysis_server_client/lib/src/protocol/protocol_common.dart
+++ b/pkg/analysis_server_client/lib/src/protocol/protocol_common.dart
@@ -2715,7 +2715,8 @@
 ///
 /// Clients may not extend, implement or mix-in this class.
 class LinkedEditGroup implements HasToJson {
-  /// The positions of the regions that should be edited simultaneously.
+  /// The positions of the regions (after applying the relevant edits) that
+  /// should be edited simultaneously.
   List<Position> positions;
 
   /// The length of the regions that should be edited simultaneously.
diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart
index 748df11..0d9c573 100644
--- a/pkg/analyzer/lib/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/dart/ast/ast.dart
@@ -1654,6 +1654,9 @@
   /// Return the right curly bracket.
   Token get rightBracket;
 
+  /// Return the optional semicolon after the last constant.
+  Token? get semicolon;
+
   /// Returns the type parameters for the enumeration, or `null` if the
   /// enumeration does not have any type parameters.
   TypeParameterList? get typeParameters;
diff --git a/pkg/analyzer/lib/dart/ast/ast_factory.dart b/pkg/analyzer/lib/dart/ast/ast_factory.dart
index 9cb8248..78698ce 100644
--- a/pkg/analyzer/lib/dart/ast/ast_factory.dart
+++ b/pkg/analyzer/lib/dart/ast/ast_factory.dart
@@ -329,6 +329,7 @@
     required ImplementsClause? implementsClause,
     required Token leftBracket,
     required List<EnumConstantDeclaration> constants,
+    required Token? semicolon,
     required List<ClassMember> members,
     required Token rightBracket,
   });
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 9e6fc22..2b44892 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -82,7 +82,7 @@
 /// TODO(scheglov) Clean up the list of implicitly analyzed files.
 class AnalysisDriver implements AnalysisDriverGeneric {
   /// The version of data format, should be incremented on every format change.
-  static const int DATA_VERSION = 204;
+  static const int DATA_VERSION = 205;
 
   /// The number of exception contexts allowed to write. Once this field is
   /// zero, we stop writing any new exception contexts in this process.
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index d188c60..50f88f8 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -3429,6 +3429,9 @@
   /// The enumeration constants being declared.
   final NodeListImpl<EnumConstantDeclaration> _constants = NodeListImpl._();
 
+  @override
+  Token? semicolon;
+
   /// The members defined by the enum.
   final NodeListImpl<ClassMember> _members = NodeListImpl._();
 
@@ -3450,6 +3453,7 @@
       this._implementsClause,
       this.leftBracket,
       List<EnumConstantDeclaration> constants,
+      this.semicolon,
       List<ClassMember> members,
       this.rightBracket)
       : super(comment, metadata, name) {
diff --git a/pkg/analyzer/lib/src/dart/ast/ast_factory.dart b/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
index 37cfef3..9f80d70 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
@@ -411,6 +411,7 @@
           implementsClause: null,
           leftBracket: leftBracket,
           constants: constants,
+          semicolon: null,
           members: [],
           rightBracket: rightBracket);
 
@@ -426,6 +427,7 @@
     required Token leftBracket,
     required List<EnumConstantDeclaration> constants,
     required List<ClassMember> members,
+    required Token? semicolon,
     required Token rightBracket,
   }) {
     return EnumDeclarationImpl(
@@ -438,6 +440,7 @@
       implementsClause as ImplementsClauseImpl?,
       leftBracket,
       constants,
+      semicolon,
       members,
       rightBracket,
     );
diff --git a/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart b/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart
index d2c7f88..2fc1149 100644
--- a/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart
@@ -335,7 +335,8 @@
     _visitNode(node.implementsClause, prefix: ' ');
     sink.write(' {');
     _visitNodeList(node.constants, separator: ', ');
-    _visitNodeList(node.members, prefix: '; ', separator: ' ');
+    _visitToken(node.semicolon);
+    _visitNodeList(node.members, prefix: ' ', separator: ' ');
     sink.write('}');
   }
 
diff --git a/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
index c94eb2b..2feaac9 100644
--- a/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
@@ -48,6 +48,7 @@
       return;
     }
 
+    var operand = node.operand;
     if (operator.isIncrementOperator) {
       var operandResolution = _resolver.resolveForWrite(
         node: node.operand,
@@ -57,7 +58,6 @@
       var readElement = operandResolution.readElement;
       var writeElement = operandResolution.writeElement;
 
-      var operand = node.operand;
       _resolver.setReadElement(operand, readElement);
       _resolver.setWriteElement(operand, writeElement);
       _resolver.migrationResolutionHooks
@@ -65,7 +65,14 @@
 
       _assignmentShared.checkFinalAlreadyAssigned(node.operand);
     } else {
-      node.operand.accept(_resolver);
+      DartType? innerContextType;
+      if (operator == TokenType.MINUS && operand is IntegerLiteralImpl) {
+        // Negated integer literals should undergo int->double conversion in the
+        // same circumstances as non-negated integer literals, so pass the
+        // context type through.
+        innerContextType = InferenceContext.getContext(node);
+      }
+      _resolver.analyzeExpression(operand, innerContextType);
     }
 
     _resolve1(node);
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index 0816e6c..e04f113 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -2884,6 +2884,10 @@
     var constants = popTypedList2<EnumConstantDeclaration>(elementsCount);
     enumDeclaration!.constants.addAll(constants);
 
+    if (optional(';', elementsEndToken)) {
+      enumDeclaration!.semicolon = elementsEndToken;
+    }
+
     if (!enableEnhancedEnums && optional(';', elementsEndToken)) {
       var feature = ExperimentalFeatures.enhanced_enums;
       handleRecoverableError(
@@ -2941,6 +2945,7 @@
         implementsClause: implementsClause,
         leftBracket: leftBrace,
         constants: [],
+        semicolon: null,
         members: [],
         rightBracket: leftBrace.endGroup!,
       ),
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 793d021..512107b 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -1996,7 +1996,7 @@
   void visitIntegerLiteral(IntegerLiteral node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    typeAnalyzer.visitIntegerLiteral(node);
+    typeAnalyzer.visitIntegerLiteral(node as IntegerLiteralImpl);
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 6bd3016..b5c5db4 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -170,13 +170,11 @@
   /// type of $e$ is the same as the static type of an integer literal with the
   /// same contexttype
   /// </blockquote>
-  void visitIntegerLiteral(IntegerLiteral node) {
-    // Check the parent context for negated integer literals.
-    var context = InferenceContext.getContext(
-        (node as IntegerLiteralImpl).immediatelyNegated ? node.parent : node);
-    if (context == null ||
-        _typeSystem.isAssignableTo(_typeProvider.intType, context) ||
-        !_typeSystem.isAssignableTo(_typeProvider.doubleType, context)) {
+  void visitIntegerLiteral(IntegerLiteralImpl node) {
+    var contextType = InferenceContext.getContext(node);
+    if (contextType == null ||
+        _typeSystem.isAssignableTo(_typeProvider.intType, contextType) ||
+        !_typeSystem.isAssignableTo(_typeProvider.doubleType, contextType)) {
       _inferenceHelper.recordStaticType(node, _typeProvider.intType);
     } else {
       _inferenceHelper.recordStaticType(node, _typeProvider.doubleType);
diff --git a/pkg/analyzer/lib/src/summary2/element_builder.dart b/pkg/analyzer/lib/src/summary2/element_builder.dart
index 3330307..c4deaa9 100644
--- a/pkg/analyzer/lib/src/summary2/element_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/element_builder.dart
@@ -362,20 +362,12 @@
       );
     }
 
-    MethodElementImpl? syntheticToStringMethod;
-    if (holder.getMethod('toString').element == null) {
-      syntheticToStringMethod = MethodElementImpl('toString', -1)
-        ..isSynthetic = true;
-      holder.addMethod(name, syntheticToStringMethod);
-    }
-
     _libraryBuilder.implicitEnumNodes.add(
       ImplicitEnumNodes(
         element: element,
         indexField: indexField,
         valuesTypeNode: valuesTypeNode,
         valuesField: valuesField,
-        syntheticToStringMethod: syntheticToStringMethod,
       ),
     );
 
diff --git a/pkg/analyzer/lib/src/summary2/library_builder.dart b/pkg/analyzer/lib/src/summary2/library_builder.dart
index e6caec3..048cdaf 100644
--- a/pkg/analyzer/lib/src/summary2/library_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/library_builder.dart
@@ -25,14 +25,12 @@
   final FieldElementImpl indexField;
   final ast.NamedTypeImpl valuesTypeNode;
   final ConstFieldElementImpl valuesField;
-  final MethodElementImpl? syntheticToStringMethod;
 
   ImplicitEnumNodes({
     required this.element,
     required this.indexField,
     required this.valuesTypeNode,
     required this.valuesField,
-    required this.syntheticToStringMethod,
   });
 }
 
@@ -145,7 +143,6 @@
       );
       enum_.valuesTypeNode.type = valuesType;
       enum_.valuesField.type = valuesType;
-      enum_.syntheticToStringMethod?.returnType = typeProvider.stringType;
     }
   }
 
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
index 82900cd..620abd3 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
@@ -1685,9 +1685,6 @@
 ''');
     await resolveTestFile();
 
-    var enumNode = result.unit.declarations[0] as EnumDeclaration;
-    ClassElement enumElement = enumNode.declaredElement!;
-
     List<Statement> mainStatements = _getMainStatements(result);
 
     var statement = mainStatements[0] as ExpressionStatement;
@@ -1696,7 +1693,7 @@
 
     var methodElement = invocation.methodName.staticElement as MethodElement;
     expect(methodElement.name, 'toString');
-    expect(methodElement.enclosingElement, same(enumElement));
+    expect(methodElement.enclosingElement, same(objectElement));
   }
 
   test_error_unresolvedTypeAnnotation() async {
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_implementation_override_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_implementation_override_test.dart
index 5985dde..883271d 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_implementation_override_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_implementation_override_test.dart
@@ -16,7 +16,54 @@
 
 @reflectiveTest
 class InvalidImplementationOverrideTest extends PubPackageResolutionTest
-    with InvalidImplementationOverrideTestCases {}
+    with InvalidImplementationOverrideTestCases {
+  test_enum_getter_abstractOverridesConcrete() async {
+    await assertErrorsInCode('''
+mixin M {
+  num get foo => 0;
+}
+enum E with M {
+  v;
+  int get foo;
+}
+''', [
+      error(CompileTimeErrorCode.INVALID_IMPLEMENTATION_OVERRIDE, 37, 1),
+    ]);
+  }
+
+  test_enum_method_abstractOverridesConcrete() async {
+    await assertErrorsInCode('''
+mixin M {
+  num foo() => 0;
+}
+enum E with M {
+  v;
+  int foo();
+}
+''', [
+      error(CompileTimeErrorCode.INVALID_IMPLEMENTATION_OVERRIDE, 35, 1),
+    ]);
+  }
+
+  test_enum_method_mixin_toString() async {
+    await assertErrorsInCode('''
+abstract class I {
+  String toString([int? value]);
+}
+
+enum E1 implements I {
+  v
+}
+
+enum E2 implements I {
+  v;
+  String toString([int? value]) => '';
+}
+''', [
+      error(CompileTimeErrorCode.INVALID_IMPLEMENTATION_OVERRIDE, 60, 2),
+    ]);
+  }
+}
 
 mixin InvalidImplementationOverrideTestCases on PubPackageResolutionTest {
   test_class_generic_method_generic_hasCovariantParameter() async {
@@ -28,7 +75,7 @@
 ''');
   }
 
-  test_getter_abstractOverridesConcrete() async {
+  test_class_getter_abstractOverridesConcrete() async {
     await assertErrorsInCode('''
 class A {
   num get g => 7;
@@ -41,7 +88,7 @@
     ]);
   }
 
-  test_method_abstractOverridesConcrete() async {
+  test_class_method_abstractOverridesConcrete() async {
     await assertErrorsInCode('''
 class A	{
   int add(int a, int b) => a + b;
@@ -56,7 +103,7 @@
     ]);
   }
 
-  test_method_abstractOverridesConcrete_expandedParameterType() async {
+  test_class_method_abstractOverridesConcrete_expandedParameterType() async {
     await assertErrorsInCode('''
 class A {
   int add(int a) => a;
@@ -69,7 +116,7 @@
     ]);
   }
 
-  test_method_abstractOverridesConcrete_expandedParameterType_covariant() async {
+  test_class_method_abstractOverridesConcrete_expandedParameterType_covariant() async {
     await assertNoErrorsInCode('''
 class A {
   int add(covariant int a) => a;
@@ -80,7 +127,7 @@
 ''');
   }
 
-  test_method_abstractOverridesConcrete_withOptional() async {
+  test_class_method_abstractOverridesConcrete_withOptional() async {
     await assertErrorsInCode('''
 class A {
   int add() => 7;
@@ -93,7 +140,7 @@
     ]);
   }
 
-  test_method_abstractOverridesConcreteInMixin() async {
+  test_class_method_abstractOverridesConcreteInMixin() async {
     await assertErrorsInCode('''
 mixin M {
   int add(int a, int b) => a + b;
@@ -108,7 +155,7 @@
     ]);
   }
 
-  test_method_abstractOverridesConcreteViaMixin() async {
+  test_class_method_abstractOverridesConcreteViaMixin() async {
     await assertErrorsInCode('''
 class A {
   int add(int a, int b) => a + b;
@@ -124,7 +171,7 @@
     ]);
   }
 
-  test_method_covariant_inheritance_merge() async {
+  test_class_method_covariant_inheritance_merge() async {
     await assertNoErrorsInCode(r'''
 class A {}
 class B extends A {}
diff --git a/pkg/analyzer/test/src/diagnostics/use_of_void_result_test.dart b/pkg/analyzer/test/src/diagnostics/use_of_void_result_test.dart
index dfbc1a7..7048e2e 100644
--- a/pkg/analyzer/test/src/diagnostics/use_of_void_result_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/use_of_void_result_test.dart
@@ -223,6 +223,17 @@
     ]);
   }
 
+  test_unaryNegativeVoidFunction() async {
+    await assertErrorsInCode('''
+void test(void f()) {
+  -f();
+}
+''', [
+      error(CompileTimeErrorCode.UNDEFINED_OPERATOR, 24, 1),
+      error(CompileTimeErrorCode.USE_OF_VOID_RESULT, 25, 3),
+    ]);
+  }
+
   test_unaryNegativeVoidValueError() async {
     await assertErrorsInCode('''
 void main() {
diff --git a/pkg/analyzer/test/src/fasta/ast_builder_test.dart b/pkg/analyzer/test/src/fasta/ast_builder_test.dart
index fd2f5aa..cdc7a64 100644
--- a/pkg/analyzer/test/src/fasta/ast_builder_test.dart
+++ b/pkg/analyzer/test/src/fasta/ast_builder_test.dart
@@ -76,6 +76,30 @@
       ..argumentList.isSynthetic;
   }
 
+  void test_enum_semicolon_null() {
+    var parseResult = parseStringWithErrors(r'''
+enum E {
+  v
+}
+''');
+    parseResult.assertNoErrors();
+
+    var v = parseResult.findNode.enumDeclaration('enum E');
+    check(v).semicolon.isNull;
+  }
+
+  void test_enum_semicolon_optional() {
+    var parseResult = parseStringWithErrors(r'''
+enum E {
+  v;
+}
+''');
+    parseResult.assertNoErrors();
+
+    var v = parseResult.findNode.enumDeclaration('enum E');
+    check(v).semicolon.isNotNull.isSemicolon;
+  }
+
   void test_getter_sameNameAsClass() {
     var parseResult = parseStringWithErrors(r'''
 class A {
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 7b09082..64ba014 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -8405,9 +8405,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''',
         withCodeRanges: true);
   }
@@ -13651,9 +13648,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
     typeAliases
       functionTypeAliasBased F @50
         aliasedType: dynamic Function(int, String)
@@ -15946,9 +15940,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
     topLevelVariables
       static final vValue @23
         type: E
@@ -16022,9 +16013,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
     topLevelVariables
       static final vToString @17
         type: String
@@ -17050,9 +17038,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
       enum E @19
         supertype: Enum
         fields
@@ -17154,9 +17139,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -17481,9 +17463,6 @@
             returnType: List<E<dynamic>>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -17545,9 +17524,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -17633,9 +17609,6 @@
             returnType: List<E<dynamic>>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -17696,9 +17669,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -17763,9 +17733,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -17827,9 +17794,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -17903,9 +17867,6 @@
             returnType: int
           synthetic get x @-1
             returnType: dynamic
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -17981,9 +17942,6 @@
             returnType: int
           synthetic get x @-1
             returnType: String
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -18049,9 +18007,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -18122,9 +18077,6 @@
             returnType: int
           synthetic get x @-1
             returnType: num
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -18195,9 +18147,6 @@
             returnType: int
           synthetic get x @-1
             returnType: dynamic
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -18268,9 +18217,6 @@
             returnType: int
           synthetic get x @-1
             returnType: dynamic
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -18341,9 +18287,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -18412,9 +18355,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -18477,9 +18417,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -18549,9 +18486,6 @@
             returnType: int
           synthetic get foo @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -18617,9 +18551,6 @@
             returnType: int
           get foo @23
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -18687,9 +18618,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -18767,9 +18695,6 @@
             returnType: List<E<dynamic>>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -18842,9 +18767,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -18923,8 +18845,6 @@
               requiredPositional u @37
                 type: U
             returnType: int
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -19052,9 +18972,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
     mixins
       mixin M @6
         superclassConstraints
@@ -19126,9 +19043,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
     mixins
       mixin M1 @6
         typeParameters
@@ -19214,9 +19128,6 @@
               requiredPositional _ @27
                 type: int
             returnType: void
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -19284,9 +19195,6 @@
             returnType: List<E<dynamic>>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -19358,9 +19266,6 @@
             returnType: List<E<num, num>>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -19395,9 +19300,6 @@
             returnType: List<E<dynamic>>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -19438,9 +19340,6 @@
             returnType: List<E<dynamic, num, dynamic>>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -19475,9 +19374,6 @@
             returnType: List<E<dynamic>>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -19511,9 +19407,6 @@
             returnType: List<E<dynamic>>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -19547,9 +19440,6 @@
             returnType: List<E<dynamic>>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -19583,9 +19473,6 @@
             returnType: List<E<dynamic>>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -19623,9 +19510,6 @@
             returnType: List<E<dynamic, dynamic, dynamic>>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -19719,9 +19603,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -19836,9 +19717,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
     topLevelVariables
       static const annotation @91
         type: int
@@ -19932,9 +19810,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -19991,9 +19866,6 @@
             returnType: List<E1>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
       enum E2 @20
         supertype: Enum
         fields
@@ -20041,9 +19913,6 @@
             returnType: List<E2>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -20212,9 +20081,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -27102,9 +26968,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
     topLevelVariables
       static const a @6
         type: int
@@ -27280,9 +27143,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -27347,9 +27207,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
     topLevelVariables
       static const a @6
         type: int
@@ -28947,9 +28804,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
     topLevelVariables
       static const foo @6
         type: int
@@ -30036,9 +29890,6 @@
             returnType: List<E<dynamic>>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
     topLevelVariables
       static const a @6
         type: int
@@ -30341,9 +30192,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
 ''');
   }
 
@@ -31711,10 +31559,6 @@
           synthetic get index @-1
             returnType: int
             nonSynthetic: self::@enum::E
-        methods
-          synthetic toString @-1
-            returnType: String
-            nonSynthetic: self::@enum::E
 ''',
         withNonSynthetic: true);
   }
@@ -33731,9 +33575,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
     typeAliases
       functionTypeAliasBased F @32
         aliasedType: dynamic Function()
@@ -33869,9 +33710,6 @@
               returnType: List<E>
             synthetic get index @-1
               returnType: int
-          methods
-            synthetic toString @-1
-              returnType: String
       typeAliases
         functionTypeAliasBased F @43
           aliasedType: dynamic Function()
@@ -33941,9 +33779,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
     typeAliases
       functionTypeAliasBased F @58
         aliasedType: dynamic Function()
@@ -34050,9 +33885,6 @@
               returnType: List<E>
             synthetic get index @-1
               returnType: int
-          methods
-            synthetic toString @-1
-              returnType: String
       typeAliases
         functionTypeAliasBased F @43
           aliasedType: dynamic Function()
@@ -34157,9 +33989,6 @@
               returnType: List<E>
             synthetic get index @-1
               returnType: int
-          methods
-            synthetic toString @-1
-              returnType: String
       typeAliases
         functionTypeAliasBased F @43
           aliasedType: dynamic Function()
@@ -34332,9 +34161,6 @@
             returnType: List<E>
           synthetic get index @-1
             returnType: int
-        methods
-          synthetic toString @-1
-            returnType: String
     topLevelVariables
       static e @15
         type: E
diff --git a/pkg/analyzer/test/util/ast_check.dart b/pkg/analyzer/test/util/ast_check.dart
index c744058..65e0da9 100644
--- a/pkg/analyzer/test/util/ast_check.dart
+++ b/pkg/analyzer/test/util/ast_check.dart
@@ -74,6 +74,15 @@
   }
 }
 
+extension EnumDeclarationExtension on CheckTarget<EnumDeclaration> {
+  CheckTarget<Token?> get semicolon {
+    return nest(
+      value.semicolon,
+      (selected) => 'has semicolon ${valueStr(selected)}',
+    );
+  }
+}
+
 extension FormalParameterExtension on CheckTarget<FormalParameter> {
   CheckTarget<SimpleIdentifier?> get identifier {
     return nest(
diff --git a/pkg/analyzer/test/util/token_check.dart b/pkg/analyzer/test/util/token_check.dart
index d07687b..ac26ede 100644
--- a/pkg/analyzer/test/util/token_check.dart
+++ b/pkg/analyzer/test/util/token_check.dart
@@ -24,6 +24,10 @@
     type.isEqualTo(TokenType.OPEN_PAREN);
   }
 
+  void get isSemicolon {
+    type.isEqualTo(TokenType.SEMICOLON);
+  }
+
   void get isSynthetic {
     if (value.isSynthetic) return;
     fail('Not synthetic');
diff --git a/pkg/analyzer_plugin/doc/api.html b/pkg/analyzer_plugin/doc/api.html
index a1c3097..0c0d3d7 100644
--- a/pkg/analyzer_plugin/doc/api.html
+++ b/pkg/analyzer_plugin/doc/api.html
@@ -1511,7 +1511,8 @@
   <dl><dt class="field"><b>positions: List&lt;<a href="#type_Position">Position</a>&gt;</b></dt><dd>
         
         <p>
-          The positions of the regions that should be edited simultaneously.
+          The positions of the regions (after applying the relevant edits) that
+          should be edited simultaneously.
         </p>
       </dd><dt class="field"><b>length: int</b></dt><dd>
         
diff --git a/pkg/analyzer_plugin/lib/protocol/protocol_common.dart b/pkg/analyzer_plugin/lib/protocol/protocol_common.dart
index 524dae5..5ca19e2 100644
--- a/pkg/analyzer_plugin/lib/protocol/protocol_common.dart
+++ b/pkg/analyzer_plugin/lib/protocol/protocol_common.dart
@@ -2715,7 +2715,8 @@
 ///
 /// Clients may not extend, implement or mix-in this class.
 class LinkedEditGroup implements HasToJson {
-  /// The positions of the regions that should be edited simultaneously.
+  /// The positions of the regions (after applying the relevant edits) that
+  /// should be edited simultaneously.
   List<Position> positions;
 
   /// The length of the regions that should be edited simultaneously.
diff --git a/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart b/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart
index a525245..f54edf3 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart
@@ -496,6 +496,17 @@
   }
 
   @override
+  void visitEnumDeclaration(EnumDeclaration node) {
+    if (node.semicolon != null) {
+      if (node.members.contains(entity) ||
+          identical(entity, node.rightBracket)) {
+        optype.completionLocation = 'EnumDeclaration_member';
+        optype.includeTypeNameSuggestions = true;
+      }
+    }
+  }
+
+  @override
   void visitExpression(Expression node) {
     // This should never be called; we should always dispatch to the visitor
     // for a particular kind of expression.
diff --git a/pkg/analyzer_plugin/test/src/utilities/completion/optype_test.dart b/pkg/analyzer_plugin/test/src/utilities/completion/optype_test.dart
index 0f66c92..7f1dc4c 100644
--- a/pkg/analyzer_plugin/test/src/utilities/completion/optype_test.dart
+++ b/pkg/analyzer_plugin/test/src/utilities/completion/optype_test.dart
@@ -1026,6 +1026,42 @@
     await assertOpType();
   }
 
+  Future<void> test_enumDeclaration_afterSemicolon() async {
+    addTestSource('''
+enum E {
+  v;
+  ^
+}
+''');
+    await assertOpType(
+      completionLocation: 'EnumDeclaration_member',
+      typeNames: true,
+    );
+  }
+
+  Future<void> test_enumDeclaration_afterSemicolon_beforeMethod() async {
+    addTestSource('''
+enum E {
+  v;
+  ^foo() {}
+}
+''');
+    await assertOpType(
+      completionLocation: 'EnumDeclaration_member',
+      typeNames: true,
+    );
+  }
+
+  Future<void> test_enumDeclaration_noSemicolon() async {
+    addTestSource('''
+enum E {
+  v
+  ^
+}
+''');
+    await assertOpType();
+  }
+
   Future<void> test_expressionFunctionBody_beginning() async {
     // SimpleIdentifier  ExpressionFunctionBody  FunctionExpression
     addTestSource('m(){[1].forEach((x)=>^x);}');
diff --git a/pkg/analyzer_plugin/tool/spec/common_types_spec.html b/pkg/analyzer_plugin/tool/spec/common_types_spec.html
index e284b4f..9a3d257 100644
--- a/pkg/analyzer_plugin/tool/spec/common_types_spec.html
+++ b/pkg/analyzer_plugin/tool/spec/common_types_spec.html
@@ -1014,7 +1014,8 @@
           <ref>Position</ref>
         </list>
         <p>
-          The positions of the regions that should be edited simultaneously.
+          The positions of the regions (after applying the relevant edits) that
+          should be edited simultaneously.
         </p>
       </field>
       <field name="length">
diff --git a/pkg/compiler/README.md b/pkg/compiler/README.md
index b40befe..a0c6462 100644
--- a/pkg/compiler/README.md
+++ b/pkg/compiler/README.md
@@ -14,10 +14,10 @@
 
   1. **load kernel**: Load all the code as kernel
       * Collect dart sources transtively
-      * Convert to kernel AST  
-  
+      * Convert to kernel AST
+
   (this will be handled by invoking the front-end package)
-  
+
   Alternatively, the compiler can start compilation directly from kernel files.
 
   2. **model**: Create a Dart model of the program
@@ -245,21 +245,13 @@
 command-line tool to launch dart2js, but also by pub to invoke dart2js as a
 library during `pub-build` and `pub-serve`.
 
-* `lib/compiler_new.dart`: the current API. This API is used by our command-line
+* `lib/compiler.dart`: the compiler API. This API is used by our command-line
   tool to spawn the dart2js compiler. This API (and everything that is
   transitively created from it) has no dependencies on `dart:io` so that the
   compiler can be used in contexts where `dart:io` is not available (e.g.
   running in a browser worker) or where `dart:io` is not used explicitly (e.g.
   running as a pub transformer).
 
-  AI: rename to `compiler.dart`.
-
-* `lib/compiler.dart`: a legacy API that now is implemented by adapting calls to
-  the new API in `compiler_new.dart`.
-
-  AI: migrate users to the new API (pub is one of those users, possibly dart-pad
-  is another), and delete the legacy API.
-
 **lib/src folder**: most of the compiler lives here, as very little of its
 functionality is publicly exposed.
 
@@ -267,7 +259,7 @@
 * `lib/src/dart2js.dart`: the command-line script that runs dart2js. When
   building the SDK, the dart2js snapshot is built using the main method on this
   script.  This file creates the parameters needed to invoke the API defined in
-  `lib/compiler_new.dart`. All dependencies on `dart:io` come from here. This is
+  `lib/compiler.dart`. All dependencies on `dart:io` come from here. This is
   also where we process options (although some of the logic is done in
   `options.dart`).
 
@@ -289,9 +281,6 @@
   AI: Once all tests are migrated to this memory compiler, we should merge
   `Compiler` and `CompilerImpl` and remove this file.
 
-* `lib/src/old_to_new_api.dart`: helper library used to adapt the public API in
-  `lib/compiler.dart` to `lib/compiler_new.dart`.
-
 * `lib/src/closure.dart`: closures are compiled as classes, this file has the
   logic to do this kind of conversion in the Dart element model. This includes
   computing what needs to be boxed and creating fake element models to represent
@@ -404,7 +393,7 @@
 * Input/output: the compiler is designed to avoid all dependencies on dart:io.
   Most data is consumed and emitted via provider APIs.
 
-  * `lib/src/compiler_new.dart`: defines the interface of these providers (see
+  * `lib/src/compiler.dart`: defines the interface of these providers (see
     `CompilerInput` and `CompilerOutput`).
 
   * `lib/src/null_compiler_output.dart`: a `CompilerOutput` that discards all
diff --git a/pkg/compiler/lib/compiler.dart b/pkg/compiler/lib/compiler.dart
index b9c098a..c90854f 100644
--- a/pkg/compiler/lib/compiler.dart
+++ b/pkg/compiler/lib/compiler.dart
@@ -6,115 +6,14 @@
 
 import 'dart:async';
 
-import 'compiler_new.dart' as new_api;
-import 'src/old_to_new_api.dart';
+import 'package:front_end/src/api_unstable/dart2js.dart' as fe;
+
+import 'src/apiimpl.dart';
 import 'src/options.dart' show CompilerOptions;
 
 // Unless explicitly allowed, passing [:null:] for any argument to the
 // methods of library will result in an Error being thrown.
 
-/// Returns a future that completes to the source corresponding to [uri].
-/// If an exception occurs, the future completes with this exception.
-///
-/// The source can be represented either as a [:List<int>:] of UTF-8 bytes or as
-/// a [String].
-///
-/// The following text is non-normative:
-///
-/// It is recommended to return a UTF-8 encoded list of bytes because the
-/// scanner is more efficient in this case. In either case, the data structure
-/// is expected to hold a zero element at the last position. If this is not the
-/// case, the entire data structure is copied before scanning.
-typedef Future /* <String | List<int>> */ CompilerInputProvider(Uri uri);
-
-/// Deprecated, please use [CompilerInputProvider] instead.
-typedef Future<String> ReadStringFromUri(Uri uri);
-
-/// Returns an [EventSink] that will serve as compiler output for the given
-/// component.
-///
-/// Components are identified by [name] and [extension]. By convention,
-/// the empty string [:"":] will represent the main script
-/// (corresponding to the script parameter of [compile]) even if the
-/// main script is a library. For libraries that are compiled
-/// separately, the library name is used.
-///
-/// At least the following extensions can be expected:
-///
-/// * "js" for JavaScript output.
-/// * "js.map" for source maps.
-/// * "dart" for Dart output.
-/// * "dart.map" for source maps.
-///
-/// As more features are added to the compiler, new names and
-/// extensions may be introduced.
-typedef EventSink<String> CompilerOutputProvider(String name, String extension);
-
-/// Invoked by the compiler to report diagnostics. If [uri] is
-/// [:null:], so are [begin] and [end]. No other arguments may be
-/// [:null:]. If [uri] is not [:null:], neither are [begin] and
-/// [end]. [uri] indicates the compilation unit from where the
-/// diagnostic originates. [begin] and [end] are zero-based character
-/// offsets from the beginning of the compilation unit. [message] is the
-/// diagnostic message, and [kind] indicates indicates what kind of
-/// diagnostic it is.
-typedef void DiagnosticHandler(
-    Uri uri, int begin, int end, String message, Diagnostic kind);
-
-/// Information resulting from the compilation.
-class CompilationResult {
-  /// `true` if the compilation succeeded, that is, compilation didn't fail due
-  /// to compile-time errors and/or internal errors.
-  final bool isSuccess;
-
-  /// The compiler object used for the compilation.
-  ///
-  /// Note: The type of [compiler] is implementation dependent and may vary.
-  /// Use only for debugging and testing.
-  final compiler;
-
-  CompilationResult(this.compiler, {this.isSuccess: true});
-}
-
-/// Returns a future that completes to a non-null String when [script]
-/// has been successfully compiled.
-///
-/// The compiler output is obtained by providing an [outputProvider].
-///
-/// If the compilation fails, the future's value will be [:null:] and
-/// [handler] will have been invoked at least once with [:kind ==
-/// Diagnostic.ERROR:] or [:kind == Diagnostic.CRASH:].
-///
-/// Deprecated: if no [outputProvider] is given, the future completes
-/// to the compiled script. This behavior will be removed in the future
-/// as the compiler may create multiple files to support lazy loading
-/// of libraries.
-Future<CompilationResult> compile(Uri script, Uri librariesSpecificationUri,
-    CompilerInputProvider inputProvider, DiagnosticHandler handler,
-    [List<String> options = const [],
-    CompilerOutputProvider outputProvider,
-    Map<String, String> environment = const {},
-    Uri packageConfig]) {
-  CompilerOptions compilerOptions = CompilerOptions.parse(options,
-      librariesSpecificationUri: librariesSpecificationUri)
-    ..entryUri = script
-    ..packageConfig = packageConfig
-    ..environment = environment;
-
-  new_api.CompilerInput compilerInput = new LegacyCompilerInput(inputProvider);
-  new_api.CompilerDiagnostics compilerDiagnostics =
-      new LegacyCompilerDiagnostics(handler);
-  new_api.CompilerOutput compilerOutput =
-      new LegacyCompilerOutput(outputProvider);
-
-  return new_api
-      .compile(
-          compilerOptions, compilerInput, compilerDiagnostics, compilerOutput)
-      .then((new_api.CompilationResult result) {
-    return new CompilationResult(result.compiler, isSuccess: result.isSuccess);
-  });
-}
-
 /// Kind of diagnostics that the compiler can report.
 class Diagnostic {
   /// An error as identified by the "Dart Programming Language
@@ -168,3 +67,187 @@
   @override
   String toString() => name;
 }
+
+// Unless explicitly allowed, passing `null` for any argument to the
+// methods of library will result in an Error being thrown.
+
+/// Input kinds used by [CompilerInput.readFromUri].
+enum InputKind {
+  /// Data is read as UTF8 either as a [String] or a zero-terminated
+  /// `List<int>`.
+  UTF8,
+
+  /// Data is read as bytes in a `List<int>`.
+  binary,
+}
+
+/// Interface for data read through [CompilerInput.readFromUri].
+abstract class Input<T> {
+  /// The URI from which data was read.
+  Uri get uri;
+
+  /// The format of the read [data].
+  InputKind get inputKind;
+
+  /// The raw data read from [uri].
+  T get data;
+
+  /// Release any resources held by the input. After releasing, a call to `get
+  /// data` will fail, and previously returned data may be invalid.
+  void release();
+}
+
+/// Interface for providing the compiler with input. That is, Dart source files,
+/// package config files, etc.
+abstract class CompilerInput {
+  /// Returns a future that completes to the source corresponding to [uri].
+  /// If an exception occurs, the future completes with this exception.
+  ///
+  /// If [inputKind] is `InputKind.UTF8` the source can be represented either as
+  /// a zero-terminated `List<int>` of UTF-8 bytes or as a [String]. If
+  /// [inputKind] is `InputKind.binary` the source is a read a `List<int>`.
+  ///
+  /// The following text is non-normative:
+  ///
+  /// It is recommended to return a UTF-8 encoded list of bytes because the
+  /// scanner is more efficient in this case. In either case, the data structure
+  /// is expected to hold a zero element at the last position. If this is not
+  /// the case, the entire data structure is copied before scanning.
+  Future<Input> readFromUri(Uri uri, {InputKind inputKind: InputKind.UTF8});
+}
+
+/// Output types used in `CompilerOutput.createOutputSink`.
+enum OutputType {
+  /// The main JavaScript output.
+  js,
+
+  /// A deferred JavaScript output part.
+  jsPart,
+
+  /// A source map for a JavaScript output.
+  sourceMap,
+
+  /// Dump info output.
+  dumpInfo,
+
+  /// Deferred map output.
+  deferredMap,
+
+  /// Unused libraries output.
+  dumpUnusedLibraries,
+
+  /// Implementation specific output used for debugging the compiler.
+  debug,
+}
+
+/// Sink interface used for generating output from the compiler.
+abstract class OutputSink {
+  /// Adds [text] to the sink.
+  void add(String text);
+
+  /// Closes the sink.
+  void close();
+}
+
+/// Sink interface used for generating binary data from the compiler.
+abstract class BinaryOutputSink {
+  /// Writes indices [start] to [end] of [buffer] to the sink.
+  void write(List<int> buffer, [int start = 0, int end]);
+
+  /// Closes the sink.
+  void close();
+}
+
+/// Interface for producing output from the compiler. That is, JavaScript target
+/// files, source map files, dump info files, etc.
+abstract class CompilerOutput {
+  /// Returns an [OutputSink] that will serve as compiler output for the given
+  /// component.
+  ///
+  /// Components are identified by [name], [extension], and [type]. By
+  /// convention, the empty string `""` will represent the main output of the
+  /// provided [type]. [name] and [extension] are otherwise suggestive.
+  // TODO(johnniwinther): Replace [name] and [extension] with something like
+  // [id] and [uri].
+  OutputSink createOutputSink(String name, String extension, OutputType type);
+
+  /// Returns an [BinaryOutputSink] that will serve as compiler output for the
+  /// given URI.
+  BinaryOutputSink createBinarySink(Uri uri);
+}
+
+/// Interface for receiving diagnostic message from the compiler. That is,
+/// errors, warnings, hints, etc.
+abstract class CompilerDiagnostics {
+  /// Invoked by the compiler to report diagnostics. If [uri] is `null`, so are
+  /// [begin] and [end]. No other arguments may be `null`. If [uri] is not
+  /// `null`, neither are [begin] and [end]. [uri] indicates the compilation
+  /// unit from where the diagnostic originates. [begin] and [end] are
+  /// zero-based character offsets from the beginning of the compilation unit.
+  /// [message] is the diagnostic message, and [kind] indicates indicates what
+  /// kind of diagnostic it is.
+  ///
+  /// Experimental: [code] gives access to an id for the messages. Currently it
+  /// is the [Message] used to create the diagnostic, if available, from which
+  /// the [MessageKind] is accessible.
+  void report(
+      var code, Uri uri, int begin, int end, String text, Diagnostic kind);
+}
+
+/// Information resulting from the compilation.
+class CompilationResult {
+  /// `true` if the compilation succeeded, that is, compilation didn't fail due
+  /// to compile-time errors and/or internal errors.
+  final bool isSuccess;
+
+  /// The compiler object used for the compilation.
+  ///
+  /// Note: The type of [compiler] is implementation dependent and may vary.
+  /// Use only for debugging and testing.
+  final compiler;
+
+  /// Shared state between compilations.
+  ///
+  /// This is used to speed up batch mode.
+  final fe.InitializedCompilerState kernelInitializedCompilerState;
+
+  CompilationResult(this.compiler,
+      {this.isSuccess: true, this.kernelInitializedCompilerState: null});
+}
+
+/// Returns a future that completes to a [CompilationResult] when the Dart
+/// sources in [options] have been compiled.
+///
+/// The generated compiler output is obtained by providing a [compilerOutput].
+///
+/// If the compilation fails, the future's `CompilationResult.isSuccess` is
+/// `false` and [CompilerDiagnostics.report] on [compilerDiagnostics]
+/// is invoked at least once with `kind == Diagnostic.ERROR` or
+/// `kind == Diagnostic.CRASH`.
+Future<CompilationResult> compile(
+    CompilerOptions compilerOptions,
+    CompilerInput compilerInput,
+    CompilerDiagnostics compilerDiagnostics,
+    CompilerOutput compilerOutput) {
+  if (compilerOptions == null) {
+    throw new ArgumentError("compilerOptions must be non-null");
+  }
+  if (compilerInput == null) {
+    throw new ArgumentError("compilerInput must be non-null");
+  }
+  if (compilerDiagnostics == null) {
+    throw new ArgumentError("compilerDiagnostics must be non-null");
+  }
+  if (compilerOutput == null) {
+    throw new ArgumentError("compilerOutput must be non-null");
+  }
+
+  CompilerImpl compiler = new CompilerImpl(
+      compilerInput, compilerOutput, compilerDiagnostics, compilerOptions);
+  return compiler.run().then((bool success) {
+    return new CompilationResult(compiler,
+        isSuccess: success,
+        kernelInitializedCompilerState:
+            compiler.kernelLoader.initializedCompilerState);
+  });
+}
diff --git a/pkg/compiler/lib/compiler_new.dart b/pkg/compiler/lib/compiler_new.dart
deleted file mode 100644
index 5a4ccc8..0000000
--- a/pkg/compiler/lib/compiler_new.dart
+++ /dev/null
@@ -1,202 +0,0 @@
-// Copyright (c) 2015, 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.
-
-/// New Compiler API. This API is under construction, use only internally or
-/// in unittests.
-
-library compiler_new;
-
-import 'dart:async';
-
-import 'package:front_end/src/api_unstable/dart2js.dart' as fe;
-
-import 'compiler.dart' show Diagnostic;
-import 'src/apiimpl.dart';
-import 'src/options.dart' show CompilerOptions;
-
-export 'compiler.dart' show Diagnostic;
-
-// Unless explicitly allowed, passing `null` for any argument to the
-// methods of library will result in an Error being thrown.
-
-/// Input kinds used by [CompilerInput.readFromUri].
-enum InputKind {
-  /// Data is read as UTF8 either as a [String] or a zero-terminated
-  /// `List<int>`.
-  UTF8,
-
-  /// Data is read as bytes in a `List<int>`.
-  binary,
-}
-
-/// Interface for data read through [CompilerInput.readFromUri].
-abstract class Input<T> {
-  /// The URI from which data was read.
-  Uri get uri;
-
-  /// The format of the read [data].
-  InputKind get inputKind;
-
-  /// The raw data read from [uri].
-  T get data;
-
-  /// Release any resources held by the input. After releasing, a call to `get
-  /// data` will fail, and previously returned data may be invalid.
-  void release();
-}
-
-/// Interface for providing the compiler with input. That is, Dart source files,
-/// package config files, etc.
-abstract class CompilerInput {
-  /// Returns a future that completes to the source corresponding to [uri].
-  /// If an exception occurs, the future completes with this exception.
-  ///
-  /// If [inputKind] is `InputKind.UTF8` the source can be represented either as
-  /// a zero-terminated `List<int>` of UTF-8 bytes or as a [String]. If
-  /// [inputKind] is `InputKind.binary` the source is a read a `List<int>`.
-  ///
-  /// The following text is non-normative:
-  ///
-  /// It is recommended to return a UTF-8 encoded list of bytes because the
-  /// scanner is more efficient in this case. In either case, the data structure
-  /// is expected to hold a zero element at the last position. If this is not
-  /// the case, the entire data structure is copied before scanning.
-  Future<Input> readFromUri(Uri uri, {InputKind inputKind: InputKind.UTF8});
-}
-
-/// Output types used in `CompilerOutput.createOutputSink`.
-enum OutputType {
-  /// The main JavaScript output.
-  js,
-
-  /// A deferred JavaScript output part.
-  jsPart,
-
-  /// A source map for a JavaScript output.
-  sourceMap,
-
-  /// Dump info output.
-  dumpInfo,
-
-  /// Deferred map output.
-  deferredMap,
-
-  /// Unused libraries output.
-  dumpUnusedLibraries,
-
-  /// Implementation specific output used for debugging the compiler.
-  debug,
-}
-
-/// Sink interface used for generating output from the compiler.
-abstract class OutputSink {
-  /// Adds [text] to the sink.
-  void add(String text);
-
-  /// Closes the sink.
-  void close();
-}
-
-/// Sink interface used for generating binary data from the compiler.
-abstract class BinaryOutputSink {
-  /// Writes indices [start] to [end] of [buffer] to the sink.
-  void write(List<int> buffer, [int start = 0, int end]);
-
-  /// Closes the sink.
-  void close();
-}
-
-/// Interface for producing output from the compiler. That is, JavaScript target
-/// files, source map files, dump info files, etc.
-abstract class CompilerOutput {
-  /// Returns an [OutputSink] that will serve as compiler output for the given
-  /// component.
-  ///
-  /// Components are identified by [name], [extension], and [type]. By
-  /// convention, the empty string `""` will represent the main output of the
-  /// provided [type]. [name] and [extension] are otherwise suggestive.
-  // TODO(johnniwinther): Replace [name] and [extension] with something like
-  // [id] and [uri].
-  OutputSink createOutputSink(String name, String extension, OutputType type);
-
-  /// Returns an [BinaryOutputSink] that will serve as compiler output for the
-  /// given URI.
-  BinaryOutputSink createBinarySink(Uri uri);
-}
-
-/// Interface for receiving diagnostic message from the compiler. That is,
-/// errors, warnings, hints, etc.
-abstract class CompilerDiagnostics {
-  /// Invoked by the compiler to report diagnostics. If [uri] is `null`, so are
-  /// [begin] and [end]. No other arguments may be `null`. If [uri] is not
-  /// `null`, neither are [begin] and [end]. [uri] indicates the compilation
-  /// unit from where the diagnostic originates. [begin] and [end] are
-  /// zero-based character offsets from the beginning of the compilation unit.
-  /// [message] is the diagnostic message, and [kind] indicates indicates what
-  /// kind of diagnostic it is.
-  ///
-  /// Experimental: [code] gives access to an id for the messages. Currently it
-  /// is the [Message] used to create the diagnostic, if available, from which
-  /// the [MessageKind] is accessible.
-  void report(
-      var code, Uri uri, int begin, int end, String text, Diagnostic kind);
-}
-
-/// Information resulting from the compilation.
-class CompilationResult {
-  /// `true` if the compilation succeeded, that is, compilation didn't fail due
-  /// to compile-time errors and/or internal errors.
-  final bool isSuccess;
-
-  /// The compiler object used for the compilation.
-  ///
-  /// Note: The type of [compiler] is implementation dependent and may vary.
-  /// Use only for debugging and testing.
-  final compiler;
-
-  /// Shared state between compilations.
-  ///
-  /// This is used to speed up batch mode.
-  final fe.InitializedCompilerState kernelInitializedCompilerState;
-
-  CompilationResult(this.compiler,
-      {this.isSuccess: true, this.kernelInitializedCompilerState: null});
-}
-
-/// Returns a future that completes to a [CompilationResult] when the Dart
-/// sources in [options] have been compiled.
-///
-/// The generated compiler output is obtained by providing a [compilerOutput].
-///
-/// If the compilation fails, the future's `CompilationResult.isSuccess` is
-/// `false` and [CompilerDiagnostics.report] on [compilerDiagnostics]
-/// is invoked at least once with `kind == Diagnostic.ERROR` or
-/// `kind == Diagnostic.CRASH`.
-Future<CompilationResult> compile(
-    CompilerOptions compilerOptions,
-    CompilerInput compilerInput,
-    CompilerDiagnostics compilerDiagnostics,
-    CompilerOutput compilerOutput) {
-  if (compilerOptions == null) {
-    throw new ArgumentError("compilerOptions must be non-null");
-  }
-  if (compilerInput == null) {
-    throw new ArgumentError("compilerInput must be non-null");
-  }
-  if (compilerDiagnostics == null) {
-    throw new ArgumentError("compilerDiagnostics must be non-null");
-  }
-  if (compilerOutput == null) {
-    throw new ArgumentError("compilerOutput must be non-null");
-  }
-
-  CompilerImpl compiler = new CompilerImpl(
-      compilerInput, compilerOutput, compilerDiagnostics, compilerOptions);
-  return compiler.run().then((bool success) {
-    return new CompilationResult(compiler,
-        isSuccess: success,
-        kernelInitializedCompilerState:
-            compiler.kernelLoader.initializedCompilerState);
-  });
-}
diff --git a/pkg/compiler/lib/src/apiimpl.dart b/pkg/compiler/lib/src/apiimpl.dart
index ed1087c..3759604 100644
--- a/pkg/compiler/lib/src/apiimpl.dart
+++ b/pkg/compiler/lib/src/apiimpl.dart
@@ -6,7 +6,7 @@
 
 import 'dart:async';
 
-import '../compiler_new.dart' as api;
+import '../compiler.dart' as api;
 import 'common/metrics.dart' show Metrics, Metric;
 import 'common/tasks.dart' show GenericTask, Measurer;
 import 'common.dart';
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 9ea97ce..7928a2b 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -11,7 +11,7 @@
     show clearStringTokenCanonicalizer;
 import 'package:kernel/ast.dart' as ir;
 
-import '../compiler_new.dart' as api;
+import '../compiler.dart' as api;
 import 'backend_strategy.dart';
 import 'common.dart';
 import 'common/codegen.dart';
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index 7cb0173..11c2d38 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -11,7 +11,7 @@
 
 import 'package:front_end/src/api_unstable/dart2js.dart' as fe;
 
-import '../compiler_new.dart' as api;
+import '../compiler.dart' as api;
 import 'commandline_options.dart';
 import 'options.dart' show CompilerOptions, FeatureOptions;
 import 'source_file_provider.dart';
diff --git a/pkg/compiler/lib/src/deferred_load/deferred_load.dart b/pkg/compiler/lib/src/deferred_load/deferred_load.dart
index 6aeafcd..d99d431 100644
--- a/pkg/compiler/lib/src/deferred_load/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load/deferred_load.dart
@@ -275,7 +275,7 @@
 import 'import_set.dart';
 import 'output_unit.dart';
 
-import '../../compiler_new.dart' show OutputType;
+import '../../compiler.dart' show OutputType;
 import '../common.dart';
 import '../common/elements.dart' show KElementEnvironment;
 import '../common/metrics.dart'
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index 38b59d0..e0b9941 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -11,7 +11,7 @@
 import 'package:dart2js_info/json_info_codec.dart';
 import 'package:dart2js_info/binary_serialization.dart' as dump_info;
 
-import '../compiler_new.dart';
+import '../compiler.dart';
 import 'backend_strategy.dart';
 import 'common.dart';
 import 'common/elements.dart' show JElementEnvironment;
diff --git a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
index 89caef1..ef3a7d2 100644
--- a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
+++ b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
@@ -4,7 +4,7 @@
 
 import 'package:kernel/ast.dart' as ir;
 
-import '../../compiler_new.dart';
+import '../../compiler.dart';
 import '../closure.dart';
 import '../common.dart';
 import '../common/elements.dart';
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_dump.dart b/pkg/compiler/lib/src/inferrer/type_graph_dump.dart
index ff82843..9a0d7e8 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_dump.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_dump.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 library dart2js.inferrer.type_graph_dump;
 
-import '../../compiler_new.dart';
+import '../../compiler.dart';
 import '../elements/entities.dart';
 import '../elements/entity_utils.dart' as utils;
 import 'abstract_value_domain.dart';
diff --git a/pkg/compiler/lib/src/io/code_output.dart b/pkg/compiler/lib/src/io/code_output.dart
index 43e9fcc..b5f87ea 100644
--- a/pkg/compiler/lib/src/io/code_output.dart
+++ b/pkg/compiler/lib/src/io/code_output.dart
@@ -4,7 +4,7 @@
 
 library dart2js.code_output;
 
-import '../../compiler_new.dart';
+import '../../compiler.dart';
 import 'source_information.dart';
 
 /// Listener interface for [CodeOutput] activity.
diff --git a/pkg/compiler/lib/src/io/source_file.dart b/pkg/compiler/lib/src/io/source_file.dart
index 49b27d8..a95008c 100644
--- a/pkg/compiler/lib/src/io/source_file.dart
+++ b/pkg/compiler/lib/src/io/source_file.dart
@@ -11,7 +11,7 @@
 import 'package:kernel/ast.dart' as kernel show Location, Source;
 
 import 'location_provider.dart' show LocationProvider;
-import '../../compiler_new.dart';
+import '../../compiler.dart';
 
 /// Represents a file of source code. The content can be either a [String] or
 /// a UTF-8 encoded [List<int>] of bytes.
diff --git a/pkg/compiler/lib/src/io/source_map_builder.dart b/pkg/compiler/lib/src/io/source_map_builder.dart
index 750a95d..d05c9cb 100644
--- a/pkg/compiler/lib/src/io/source_map_builder.dart
+++ b/pkg/compiler/lib/src/io/source_map_builder.dart
@@ -6,7 +6,7 @@
 
 import 'package:front_end/src/api_unstable/dart2js.dart' as fe;
 import 'package:kernel/ast.dart' show Location;
-import '../../compiler_new.dart' show CompilerOutput, OutputSink, OutputType;
+import '../../compiler.dart' show CompilerOutput, OutputSink, OutputType;
 import '../util/util.dart';
 import 'location_provider.dart';
 import 'code_output.dart' show SourceLocationsProvider, SourceLocations;
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
index 1f60860..09d0938 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
@@ -4,7 +4,7 @@
 
 library dart2js.js_emitter.startup_emitter;
 
-import '../../../compiler_new.dart';
+import '../../../compiler.dart';
 import '../../common.dart';
 import '../../common/codegen.dart';
 import '../../constants/values.dart';
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
index 88049eb..0783eff 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
@@ -32,7 +32,7 @@
 
 import 'package:js_ast/src/precedence.dart' as js_precedence;
 
-import '../../../compiler_new.dart';
+import '../../../compiler.dart';
 import '../../common.dart';
 import '../../common/elements.dart' show CommonElements, JElementEnvironment;
 import '../../common/tasks.dart';
diff --git a/pkg/compiler/lib/src/kernel/front_end_adapter.dart b/pkg/compiler/lib/src/kernel/front_end_adapter.dart
index 605b3bd..5dca150 100644
--- a/pkg/compiler/lib/src/kernel/front_end_adapter.dart
+++ b/pkg/compiler/lib/src/kernel/front_end_adapter.dart
@@ -10,7 +10,7 @@
 
 import 'package:front_end/src/api_unstable/dart2js.dart' as fe;
 
-import '../../compiler_new.dart' as api;
+import '../../compiler.dart' as api;
 
 import '../common.dart';
 import '../io/source_file.dart';
diff --git a/pkg/compiler/lib/src/kernel/loader.dart b/pkg/compiler/lib/src/kernel/loader.dart
index aaf5016..8e7520e 100644
--- a/pkg/compiler/lib/src/kernel/loader.dart
+++ b/pkg/compiler/lib/src/kernel/loader.dart
@@ -14,7 +14,7 @@
 import 'package:kernel/kernel.dart' hide LibraryDependency, Combinator;
 import 'package:kernel/target/targets.dart' hide DiagnosticReporter;
 
-import '../../compiler_new.dart' as api;
+import '../../compiler.dart' as api;
 import '../commandline_options.dart' show Flags;
 import '../common/tasks.dart' show CompilerTask, Measurer;
 import '../common.dart';
diff --git a/pkg/compiler/lib/src/null_compiler_output.dart b/pkg/compiler/lib/src/null_compiler_output.dart
index a6443e7..497bf50 100644
--- a/pkg/compiler/lib/src/null_compiler_output.dart
+++ b/pkg/compiler/lib/src/null_compiler_output.dart
@@ -6,7 +6,7 @@
 
 library compiler.null_api;
 
-import '../compiler_new.dart';
+import '../compiler.dart';
 
 /// Null pattern implementation of the [CompilerOutput] interface.
 class NullCompilerOutput implements CompilerOutput {
diff --git a/pkg/compiler/lib/src/old_to_new_api.dart b/pkg/compiler/lib/src/old_to_new_api.dart
deleted file mode 100644
index 73ab528..0000000
--- a/pkg/compiler/lib/src/old_to_new_api.dart
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright (c) 2015, 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.
-
-/// Implementation of the new compiler API in '../compiler_new.dart' through the
-/// old compiler API in '../compiler.dart'.
-
-library compiler.api.legacy;
-
-import 'dart:async' show EventSink, Future;
-import 'dart:convert' show utf8;
-
-import '../compiler.dart';
-import '../compiler_new.dart';
-import 'io/source_file.dart';
-import 'null_compiler_output.dart' show NullSink;
-
-/// Implementation of [CompilerInput] using a [CompilerInputProvider].
-class LegacyCompilerInput implements CompilerInput {
-  final CompilerInputProvider _inputProvider;
-
-  LegacyCompilerInput(this._inputProvider);
-
-  @override
-  Future<Input> readFromUri(Uri uri, {InputKind inputKind = InputKind.UTF8}) {
-    // The switch handles all enum values, but not null.
-    // ignore: missing_return
-    return _inputProvider(uri).then((/*String|List<int>*/ data) {
-      switch (inputKind) {
-        case InputKind.UTF8:
-          SourceFile sourceFile;
-          if (data is List<int>) {
-            sourceFile = Utf8BytesSourceFile(uri, data);
-          } else if (data is String) {
-            sourceFile = StringSourceFile.fromUri(uri, data);
-          } else {
-            throw "Expected a 'String' or a 'List<int>' from the input "
-                "provider, but got: ${Error.safeToString(data)}.";
-          }
-          return sourceFile;
-        case InputKind.binary:
-          if (data is String) {
-            data = utf8.encode(data);
-          }
-          return Binary(uri, data);
-      }
-    });
-  }
-}
-
-/// Implementation of [CompilerDiagnostics] using a [DiagnosticHandler].
-class LegacyCompilerDiagnostics implements CompilerDiagnostics {
-  final DiagnosticHandler _handler;
-
-  LegacyCompilerDiagnostics(this._handler);
-
-  @override
-  void report(
-      var code, Uri uri, int begin, int end, String message, Diagnostic kind) {
-    _handler(uri, begin, end, message, kind);
-  }
-}
-
-/// Implementation of [CompilerOutput] using an optional
-/// [CompilerOutputProvider].
-// TODO(johnniwinther): Change Pub to use the new interface and remove this.
-class LegacyCompilerOutput implements CompilerOutput {
-  final CompilerOutputProvider _outputProvider;
-
-  LegacyCompilerOutput([this._outputProvider]);
-
-  @override
-  OutputSink createOutputSink(String name, String extension, OutputType type) {
-    if (_outputProvider != null) {
-      switch (type) {
-        case OutputType.dumpInfo:
-        case OutputType.deferredMap:
-          if (extension == '') {
-            // Needed to make Pub generate the same output name.
-            extension = 'deferred_map';
-          }
-          break;
-        default:
-      }
-      return LegacyOutputSink(_outputProvider(name, extension));
-    }
-    return NullSink.outputProvider(name, extension, type);
-  }
-
-  @override
-  BinaryOutputSink createBinarySink(Uri uri) {
-    throw UnsupportedError("LegacyCompilerOutput.createBinarySink");
-  }
-}
-
-class LegacyOutputSink implements OutputSink {
-  final EventSink<String> sink;
-
-  LegacyOutputSink(this.sink);
-
-  @override
-  void add(String event) => sink.add(event);
-
-  @override
-  void close() => sink.close();
-}
diff --git a/pkg/compiler/lib/src/serialization/task.dart b/pkg/compiler/lib/src/serialization/task.dart
index e63f515..0e6e7d5 100644
--- a/pkg/compiler/lib/src/serialization/task.dart
+++ b/pkg/compiler/lib/src/serialization/task.dart
@@ -7,7 +7,7 @@
 import 'package:kernel/binary/ast_from_binary.dart' as ir;
 import 'package:kernel/binary/ast_to_binary.dart' as ir;
 import 'package:front_end/src/fasta/util/bytes_sink.dart';
-import '../../compiler_new.dart' as api;
+import '../../compiler.dart' as api;
 import '../backend_strategy.dart';
 import '../commandline_options.dart' show Flags;
 import '../common/codegen.dart';
diff --git a/pkg/compiler/lib/src/source_file_provider.dart b/pkg/compiler/lib/src/source_file_provider.dart
index c869d49..894d7fc 100644
--- a/pkg/compiler/lib/src/source_file_provider.dart
+++ b/pkg/compiler/lib/src/source_file_provider.dart
@@ -11,8 +11,8 @@
 
 import 'package:front_end/src/api_unstable/dart2js.dart' as fe;
 
-import '../compiler_new.dart' as api;
-import '../compiler_new.dart';
+import '../compiler.dart' as api;
+import '../compiler.dart';
 import 'colors.dart' as colors;
 import 'dart2js.dart' show AbortLeg;
 import 'io/source_file.dart';
@@ -136,12 +136,6 @@
     });
   }
 
-  // TODO(johnniwinther): Remove this when no longer needed for the old compiler
-  // API.
-  Future /* <List<int> | String> */ call(Uri resourceUri) {
-    throw "unimplemented";
-  }
-
   relativizeUri(Uri uri) => fe.relativizeUri(cwd, uri, isWindows);
 
   SourceFile<List<int>> getUtf8SourceFile(Uri resourceUri) {
@@ -171,12 +165,6 @@
 }
 
 class CompilerSourceFileProvider extends SourceFileProvider {
-  // TODO(johnniwinther): Remove this when no longer needed for the old compiler
-  // API.
-  @override
-  Future<List<int>> call(Uri resourceUri) =>
-      readFromUri(resourceUri).then((input) => input.data);
-
   @override
   Future<api.Input<List<int>>> readFromUri(Uri uri,
           {InputKind inputKind = InputKind.UTF8}) =>
@@ -302,12 +290,6 @@
       throw AbortLeg(message);
     }
   }
-
-  // TODO(johnniwinther): Remove this when no longer needed for the old compiler
-  // API.
-  void call(Uri uri, int begin, int end, String message, api.Diagnostic kind) {
-    return report(null, uri, begin, end, message, kind);
-  }
 }
 
 typedef MessageCallback = void Function(String message);
diff --git a/pkg/compiler/lib/src/ssa/ssa_tracer.dart b/pkg/compiler/lib/src/ssa/ssa_tracer.dart
index c8a843f..231e4a3 100644
--- a/pkg/compiler/lib/src/ssa/ssa_tracer.dart
+++ b/pkg/compiler/lib/src/ssa/ssa_tracer.dart
@@ -4,7 +4,7 @@
 
 library ssa.tracer;
 
-import '../../compiler_new.dart' show OutputSink;
+import '../../compiler.dart' show OutputSink;
 import '../diagnostics/invariant.dart' show DEBUG_MODE;
 import '../inferrer/abstract_value_domain.dart';
 import '../js_backend/namer.dart' show suffixForGetInterceptor;
diff --git a/pkg/compiler/lib/src/tracer.dart b/pkg/compiler/lib/src/tracer.dart
index 26f4bb3d..4e03751 100644
--- a/pkg/compiler/lib/src/tracer.dart
+++ b/pkg/compiler/lib/src/tracer.dart
@@ -6,7 +6,7 @@
 
 import 'package:kernel/text/indentation.dart' show Indentation;
 
-import '../compiler_new.dart' as api;
+import '../compiler.dart' as api;
 import 'options.dart' show CompilerOptions;
 import 'ssa/nodes.dart' as ssa show HGraph;
 import 'ssa/ssa_tracer.dart' show HTracer;
diff --git a/pkg/compiler/lib/src/util/sink_adapter.dart b/pkg/compiler/lib/src/util/sink_adapter.dart
index 685d611..bcb9b33 100644
--- a/pkg/compiler/lib/src/util/sink_adapter.dart
+++ b/pkg/compiler/lib/src/util/sink_adapter.dart
@@ -1,4 +1,4 @@
-import '../../compiler_new.dart' as api;
+import '../../compiler.dart' as api;
 
 class BinaryOutputSinkAdapter implements Sink<List<int>> {
   api.BinaryOutputSink output;
diff --git a/pkg/compiler/test/codegen/expect_annotations2_test.dart b/pkg/compiler/test/codegen/expect_annotations2_test.dart
index b4d1338..6c2cb0f 100644
--- a/pkg/compiler/test/codegen/expect_annotations2_test.dart
+++ b/pkg/compiler/test/codegen/expect_annotations2_test.dart
@@ -6,7 +6,7 @@
 
 import "package:expect/expect.dart";
 import "package:async_helper/async_helper.dart";
-import 'package:compiler/compiler_new.dart';
+import 'package:compiler/compiler.dart';
 import 'package:compiler/src/commandline_options.dart';
 import '../helpers/memory_compiler.dart';
 
diff --git a/pkg/compiler/test/codegen/number_output_test.dart b/pkg/compiler/test/codegen/number_output_test.dart
index fa212c9..8ddf7f1 100644
--- a/pkg/compiler/test/codegen/number_output_test.dart
+++ b/pkg/compiler/test/codegen/number_output_test.dart
@@ -6,7 +6,7 @@
 
 import 'dart:async';
 import 'package:expect/expect.dart';
-import 'package:compiler/compiler_new.dart';
+import 'package:compiler/compiler.dart';
 import 'package:compiler/src/commandline_options.dart';
 import 'package:async_helper/async_helper.dart';
 import '../helpers/memory_compiler.dart';
diff --git a/pkg/compiler/test/codegen/unused_empty_map_test.dart b/pkg/compiler/test/codegen/unused_empty_map_test.dart
index c705b09..c38440f 100644
--- a/pkg/compiler/test/codegen/unused_empty_map_test.dart
+++ b/pkg/compiler/test/codegen/unused_empty_map_test.dart
@@ -7,7 +7,7 @@
 // Ensure that unused empty HashMap nodes are dropped from the output.
 
 import 'package:async_helper/async_helper.dart';
-import 'package:compiler/compiler_new.dart';
+import 'package:compiler/compiler.dart';
 import 'package:expect/expect.dart';
 import '../helpers/memory_compiler.dart';
 
diff --git a/pkg/compiler/test/codegen/use_strict_test.dart b/pkg/compiler/test/codegen/use_strict_test.dart
index d6cbaf4..520d986 100644
--- a/pkg/compiler/test/codegen/use_strict_test.dart
+++ b/pkg/compiler/test/codegen/use_strict_test.dart
@@ -5,7 +5,7 @@
 // @dart = 2.7
 
 import 'package:async_helper/async_helper.dart';
-import 'package:compiler/compiler_new.dart';
+import 'package:compiler/compiler.dart';
 import 'package:expect/expect.dart';
 import '../helpers/memory_compiler.dart';
 
diff --git a/pkg/compiler/test/deferred/closures_test.dart b/pkg/compiler/test/deferred/closures_test.dart
index a972d68..1f60716 100644
--- a/pkg/compiler/test/deferred/closures_test.dart
+++ b/pkg/compiler/test/deferred/closures_test.dart
@@ -7,7 +7,7 @@
 // Ensures that closures are in the output unit of their enclosing element.
 
 import 'package:async_helper/async_helper.dart';
-import 'package:compiler/compiler_new.dart';
+import 'package:compiler/compiler.dart';
 import 'package:expect/expect.dart';
 
 import '../helpers/memory_compiler.dart';
diff --git a/pkg/compiler/test/deferred/emit_type_checks_test.dart b/pkg/compiler/test/deferred/emit_type_checks_test.dart
index d4184ad8..6e0ba61 100644
--- a/pkg/compiler/test/deferred/emit_type_checks_test.dart
+++ b/pkg/compiler/test/deferred/emit_type_checks_test.dart
@@ -8,7 +8,7 @@
 // Files when using deferred loading.
 
 import 'package:async_helper/async_helper.dart';
-import 'package:compiler/compiler_new.dart';
+import 'package:compiler/compiler.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/js_model/js_strategy.dart';
 import 'package:expect/expect.dart';
diff --git a/pkg/compiler/test/deferred/inline_restrictions_test.dart b/pkg/compiler/test/deferred/inline_restrictions_test.dart
index 7432ea3..7a47744 100644
--- a/pkg/compiler/test/deferred/inline_restrictions_test.dart
+++ b/pkg/compiler/test/deferred/inline_restrictions_test.dart
@@ -8,7 +8,7 @@
 // allow inlining of empty functions and from main.
 
 import 'package:async_helper/async_helper.dart';
-import 'package:compiler/compiler_new.dart';
+import 'package:compiler/compiler.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:expect/expect.dart';
 import '../helpers/memory_compiler.dart';
diff --git a/pkg/compiler/test/deferred/load_mapping_test.dart b/pkg/compiler/test/deferred/load_mapping_test.dart
index ffb7b84..dd18b21 100644
--- a/pkg/compiler/test/deferred/load_mapping_test.dart
+++ b/pkg/compiler/test/deferred/load_mapping_test.dart
@@ -7,7 +7,7 @@
 import 'dart:convert';
 import 'package:expect/expect.dart';
 import 'package:async_helper/async_helper.dart';
-import 'package:compiler/compiler_new.dart';
+import 'package:compiler/compiler.dart';
 import '../helpers/memory_compiler.dart';
 
 void testLoadMap() async {
diff --git a/pkg/compiler/test/end_to_end/async_compiler_input_provider_test.dart b/pkg/compiler/test/end_to_end/async_compiler_input_provider_test.dart
deleted file mode 100644
index 1919b8a..0000000
--- a/pkg/compiler/test/end_to_end/async_compiler_input_provider_test.dart
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// @dart = 2.7
-
-import "dart:async";
-import "dart:io";
-
-import "package:expect/expect.dart";
-import "package:async_helper/async_helper.dart";
-
-import 'package:compiler/compiler.dart' as compiler;
-
-import '../helpers/memory_compiler.dart';
-
-const Map<String, String> SOURCES = const {
-  "/main.dart": """
-    import "foo.dart";
-    main() => foo();
-    """,
-  "/foo.dart": """
-    library foo;
-    import "bar.dart";
-    foo() => bar();
-    """,
-  "/bar.dart": """
-    library bar;
-    bar() => print("bar");
-    """
-};
-
-Future provideInput(Uri uri) {
-  dynamic source = SOURCES[uri.path];
-  if (source == null) {
-    // Not one of our source files, so assume it's a built-in.
-    if (uri.path.endsWith('.dill')) {
-      source = new File(uri.toFilePath()).readAsBytesSync();
-    } else {
-      source = new File(uri.toFilePath()).readAsStringSync();
-    }
-  }
-
-  // Deliver the input asynchronously.
-  return new Future(() => source);
-}
-
-main() {
-  var entrypoint = Uri.parse("file:///main.dart");
-
-  // Find the path to sdk/ in the repo relative to this script.
-  Uri librariesSpec = sdkLibrariesSpecificationUri;
-  var platformDir = sdkPlatformBinariesPath;
-  asyncTest(() => compiler.compile(
-          entrypoint,
-          librariesSpec,
-          provideInput,
-          handleDiagnostic,
-          ['--platform-binaries=${platformDir}']).then((code) {
-        Expect.isNotNull(code);
-      }));
-}
-
-void handleDiagnostic(
-    Uri uri, int begin, int end, String message, compiler.Diagnostic kind) {
-  print(message);
-  if (kind != compiler.Diagnostic.VERBOSE_INFO) {
-    throw 'Unexpected diagnostic kind $kind';
-  }
-}
diff --git a/pkg/compiler/test/end_to_end/command_line_test.dart b/pkg/compiler/test/end_to_end/command_line_test.dart
index f3ecc57..2d8b6f8 100644
--- a/pkg/compiler/test/end_to_end/command_line_test.dart
+++ b/pkg/compiler/test/end_to_end/command_line_test.dart
@@ -11,7 +11,7 @@
 import 'package:async_helper/async_helper.dart';
 import 'package:expect/expect.dart';
 
-import 'package:compiler/compiler_new.dart' as api;
+import 'package:compiler/compiler.dart' as api;
 import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/dart2js.dart' as entry;
 import 'package:compiler/src/options.dart' show CompilerOptions;
diff --git a/pkg/compiler/test/end_to_end/dump_info2_test.dart b/pkg/compiler/test/end_to_end/dump_info2_test.dart
index d7c74d6..dc28204 100644
--- a/pkg/compiler/test/end_to_end/dump_info2_test.dart
+++ b/pkg/compiler/test/end_to_end/dump_info2_test.dart
@@ -6,7 +6,7 @@
 
 import 'dart:convert';
 
-import 'package:compiler/compiler_new.dart';
+import 'package:compiler/compiler.dart';
 import 'package:dart2js_info/info.dart';
 import 'package:dart2js_info/json_info_codec.dart';
 import 'package:dart2js_info/binary_serialization.dart' as binary;
diff --git a/pkg/compiler/test/end_to_end/exit_code_test.dart b/pkg/compiler/test/end_to_end/exit_code_test.dart
index b830f92..76920d1 100644
--- a/pkg/compiler/test/end_to_end/exit_code_test.dart
+++ b/pkg/compiler/test/end_to_end/exit_code_test.dart
@@ -11,7 +11,7 @@
 import 'package:async_helper/async_helper.dart';
 import 'package:expect/expect.dart';
 
-import 'package:compiler/compiler_new.dart' as api;
+import 'package:compiler/compiler.dart' as api;
 import 'package:compiler/src/backend_strategy.dart';
 import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/common/codegen.dart';
diff --git a/pkg/compiler/test/end_to_end/output_type_test.dart b/pkg/compiler/test/end_to_end/output_type_test.dart
index 848b1ff..a1bc868 100644
--- a/pkg/compiler/test/end_to_end/output_type_test.dart
+++ b/pkg/compiler/test/end_to_end/output_type_test.dart
@@ -11,7 +11,7 @@
 import 'dart:io';
 
 import 'package:async_helper/async_helper.dart';
-import 'package:compiler/compiler_new.dart';
+import 'package:compiler/compiler.dart';
 import 'package:compiler/src/dart2js.dart';
 import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/null_compiler_output.dart';
diff --git a/pkg/compiler/test/end_to_end/user_crash_test.dart b/pkg/compiler/test/end_to_end/user_crash_test.dart
index 6dfea6d..1aeaba9 100644
--- a/pkg/compiler/test/end_to_end/user_crash_test.dart
+++ b/pkg/compiler/test/end_to_end/user_crash_test.dart
@@ -9,7 +9,7 @@
 import 'package:expect/expect.dart';
 import 'package:front_end/src/fasta/messages.dart'
     show templateCantReadFile, messageMissingMain;
-import 'package:compiler/compiler_new.dart';
+import 'package:compiler/compiler.dart';
 import '../helpers/memory_compiler.dart';
 
 final EXCEPTION = 'Crash-marker';
diff --git a/pkg/compiler/test/equivalence/id_equivalence_helper.dart b/pkg/compiler/test/equivalence/id_equivalence_helper.dart
index 30524c0..d09b6c0 100644
--- a/pkg/compiler/test/equivalence/id_equivalence_helper.dart
+++ b/pkg/compiler/test/equivalence/id_equivalence_helper.dart
@@ -9,7 +9,7 @@
 
 import 'package:_fe_analyzer_shared/src/testing/id_testing.dart';
 import 'package:compiler/src/common.dart';
-import 'package:compiler/compiler_new.dart';
+import 'package:compiler/compiler.dart';
 import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/compiler.dart';
diff --git a/pkg/compiler/test/helpers/compiler_helper.dart b/pkg/compiler/test/helpers/compiler_helper.dart
index 648db35..12abc75 100644
--- a/pkg/compiler/test/helpers/compiler_helper.dart
+++ b/pkg/compiler/test/helpers/compiler_helper.dart
@@ -7,7 +7,7 @@
 library compiler_helper;
 
 import 'dart:async';
-import 'package:compiler/compiler_new.dart';
+import 'package:compiler/compiler.dart';
 import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/compiler.dart' show Compiler;
diff --git a/pkg/compiler/test/helpers/diagnostic_helper.dart b/pkg/compiler/test/helpers/diagnostic_helper.dart
index 68a34ff..9e91050 100644
--- a/pkg/compiler/test/helpers/diagnostic_helper.dart
+++ b/pkg/compiler/test/helpers/diagnostic_helper.dart
@@ -8,8 +8,7 @@
 
 import 'dart:collection';
 
-import 'package:compiler/compiler_new.dart'
-    show CompilerDiagnostics, Diagnostic;
+import 'package:compiler/compiler.dart' show CompilerDiagnostics, Diagnostic;
 import 'package:compiler/src/diagnostics/messages.dart'
     show Message, MessageKind;
 import 'package:expect/expect.dart';
diff --git a/pkg/compiler/test/helpers/memory_compiler.dart b/pkg/compiler/test/helpers/memory_compiler.dart
index 3b6ca9a..0e3ed0c 100644
--- a/pkg/compiler/test/helpers/memory_compiler.dart
+++ b/pkg/compiler/test/helpers/memory_compiler.dart
@@ -8,8 +8,7 @@
 
 import 'dart:async';
 
-import 'package:compiler/compiler.dart' show DiagnosticHandler;
-import 'package:compiler/compiler_new.dart'
+import 'package:compiler/compiler.dart'
     show CompilationResult, CompilerDiagnostics, CompilerOutput, Diagnostic;
 import 'package:compiler/src/common.dart';
 import 'package:compiler/src/commandline_options.dart';
@@ -24,7 +23,7 @@
 import 'memory_source_file_helper.dart';
 
 export 'output_collector.dart';
-export 'package:compiler/compiler_new.dart' show CompilationResult;
+export 'package:compiler/compiler.dart' show CompilationResult;
 export 'diagnostic_helper.dart';
 
 String sdkPath = 'sdk/lib';
@@ -180,25 +179,6 @@
   return compiler;
 }
 
-DiagnosticHandler createDiagnosticHandler(DiagnosticHandler diagnosticHandler,
-    SourceFileProvider provider, bool showDiagnostics) {
-  var handler = diagnosticHandler;
-  if (showDiagnostics) {
-    if (diagnosticHandler == null) {
-      handler = new FormattingDiagnosticHandler(provider);
-    } else {
-      var formattingHandler = new FormattingDiagnosticHandler(provider);
-      handler = (Uri uri, int begin, int end, String message, Diagnostic kind) {
-        diagnosticHandler(uri, begin, end, message, kind);
-        formattingHandler(uri, begin, end, message, kind);
-      };
-    }
-  } else if (diagnosticHandler == null) {
-    handler = (Uri uri, int begin, int end, String message, Diagnostic kind) {};
-  }
-  return handler;
-}
-
 main() {
   runCompiler(memorySourceFiles: {'main.dart': 'main() {}'});
 }
diff --git a/pkg/compiler/test/helpers/memory_source_file_helper.dart b/pkg/compiler/test/helpers/memory_source_file_helper.dart
index a15262b..3591263 100644
--- a/pkg/compiler/test/helpers/memory_source_file_helper.dart
+++ b/pkg/compiler/test/helpers/memory_source_file_helper.dart
@@ -9,7 +9,7 @@
 import 'dart:async' show Future;
 export 'dart:io' show Platform;
 
-import 'package:compiler/compiler_new.dart';
+import 'package:compiler/compiler.dart';
 
 export 'package:compiler/src/apiimpl.dart' show CompilerImpl;
 
diff --git a/pkg/compiler/test/helpers/output_collector.dart b/pkg/compiler/test/helpers/output_collector.dart
index 3b47963..541a2fa 100644
--- a/pkg/compiler/test/helpers/output_collector.dart
+++ b/pkg/compiler/test/helpers/output_collector.dart
@@ -8,7 +8,7 @@
 
 library output_collector;
 
-import 'package:compiler/compiler_new.dart';
+import 'package:compiler/compiler.dart';
 
 class BufferedOutputSink implements OutputSink {
   StringBuffer sb = new StringBuffer();
diff --git a/pkg/compiler/test/inlining/meta_annotations2_test.dart b/pkg/compiler/test/inlining/meta_annotations2_test.dart
index 8c3d0da..2c719cc 100644
--- a/pkg/compiler/test/inlining/meta_annotations2_test.dart
+++ b/pkg/compiler/test/inlining/meta_annotations2_test.dart
@@ -8,7 +8,7 @@
 
 import "package:expect/expect.dart";
 import "package:async_helper/async_helper.dart";
-import 'package:compiler/compiler_new.dart';
+import 'package:compiler/compiler.dart';
 import 'package:compiler/src/commandline_options.dart';
 import '../helpers/memory_compiler.dart';
 
diff --git a/pkg/compiler/test/inlining/meta_annotations3_test.dart b/pkg/compiler/test/inlining/meta_annotations3_test.dart
index ad71d47..ad42b08 100644
--- a/pkg/compiler/test/inlining/meta_annotations3_test.dart
+++ b/pkg/compiler/test/inlining/meta_annotations3_test.dart
@@ -8,7 +8,7 @@
 
 import "package:expect/expect.dart";
 import "package:async_helper/async_helper.dart";
-import 'package:compiler/compiler_new.dart';
+import 'package:compiler/compiler.dart';
 import '../helpers/memory_compiler.dart';
 
 const MEMORY_SOURCE_FILES = const {
diff --git a/pkg/compiler/test/serialization/serialization_test_helper.dart b/pkg/compiler/test/serialization/serialization_test_helper.dart
index 0a7b306..a29a79c 100644
--- a/pkg/compiler/test/serialization/serialization_test_helper.dart
+++ b/pkg/compiler/test/serialization/serialization_test_helper.dart
@@ -6,7 +6,7 @@
 
 import 'dart:io';
 
-import 'package:compiler/compiler_new.dart';
+import 'package:compiler/compiler.dart';
 import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/js_model/js_world.dart';
diff --git a/pkg/compiler/test/sourcemaps/helpers/sourcemap_helper.dart b/pkg/compiler/test/sourcemaps/helpers/sourcemap_helper.dart
index 424345f..09a86fd 100644
--- a/pkg/compiler/test/sourcemaps/helpers/sourcemap_helper.dart
+++ b/pkg/compiler/test/sourcemaps/helpers/sourcemap_helper.dart
@@ -8,7 +8,7 @@
 
 import 'dart:async';
 import 'dart:io';
-import 'package:compiler/compiler_new.dart';
+import 'package:compiler/compiler.dart';
 import 'package:compiler/src/apiimpl.dart' as api;
 import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/elements/entities.dart';
diff --git a/pkg/compiler/test/sourcemaps/mapping_test.dart b/pkg/compiler/test/sourcemaps/mapping_test.dart
index e569599..e976ff8 100644
--- a/pkg/compiler/test/sourcemaps/mapping_test.dart
+++ b/pkg/compiler/test/sourcemaps/mapping_test.dart
@@ -9,7 +9,7 @@
 
 import 'package:_fe_analyzer_shared/src/testing/annotated_code_helper.dart';
 import 'package:async_helper/async_helper.dart';
-import 'package:compiler/compiler_new.dart';
+import 'package:compiler/compiler.dart';
 import 'package:expect/expect.dart';
 import 'package:source_maps/source_maps.dart';
 
diff --git a/pkg/compiler/test/sourcemaps/nomapping_test.dart b/pkg/compiler/test/sourcemaps/nomapping_test.dart
index 06cbf4f..fdbd62b 100644
--- a/pkg/compiler/test/sourcemaps/nomapping_test.dart
+++ b/pkg/compiler/test/sourcemaps/nomapping_test.dart
@@ -8,7 +8,7 @@
 import 'dart:io';
 
 import 'package:async_helper/async_helper.dart';
-import 'package:compiler/compiler_new.dart';
+import 'package:compiler/compiler.dart';
 import 'package:compiler/src/commandline_options.dart';
 import 'package:expect/expect.dart';
 import 'package:source_maps/source_maps.dart';
diff --git a/pkg/compiler/test/sourcemaps/source_map_test.dart b/pkg/compiler/test/sourcemaps/source_map_test.dart
index 2afead7..4d2664b 100644
--- a/pkg/compiler/test/sourcemaps/source_map_test.dart
+++ b/pkg/compiler/test/sourcemaps/source_map_test.dart
@@ -10,7 +10,7 @@
 library test.source_map;
 
 import 'package:async_helper/async_helper.dart';
-import 'package:compiler/compiler_new.dart';
+import 'package:compiler/compiler.dart';
 import 'package:expect/expect.dart';
 import '../helpers/memory_compiler.dart';
 
diff --git a/pkg/compiler/test/tool/graph_isomorphizer/graph_isomorphizer_test.dart b/pkg/compiler/test/tool/graph_isomorphizer/graph_isomorphizer_test.dart
index 228adcd..dad02c9 100644
--- a/pkg/compiler/test/tool/graph_isomorphizer/graph_isomorphizer_test.dart
+++ b/pkg/compiler/test/tool/graph_isomorphizer/graph_isomorphizer_test.dart
@@ -7,7 +7,7 @@
 import 'dart:io';
 
 import 'package:expect/expect.dart';
-import 'package:compiler/compiler_new.dart';
+import 'package:compiler/compiler.dart';
 import 'package:dart_style/dart_style.dart' show DartFormatter;
 import '../../helpers/memory_compiler.dart';
 import '../../../tool/graph_isomorphizer.dart';
diff --git a/pkg/dartdev/lib/src/commands/doc.dart b/pkg/dartdev/lib/src/commands/doc.dart
index f3cdccf..9a9c4a2 100644
--- a/pkg/dartdev/lib/src/commands/doc.dart
+++ b/pkg/dartdev/lib/src/commands/doc.dart
@@ -49,8 +49,6 @@
       negatable: false,
       help: 'Try to generate the docs without saving them.',
     );
-    argParser.addFlag('fatal-warnings',
-        help: 'Treat warning level issues as fatal.', defaultsTo: false);
   }
 
   @override
@@ -87,9 +85,9 @@
     options.addAll([
       '--output=${args['output']}',
       '--resources-dir=$resourcesPath',
-      if (args['validate-links']) '--validate-links',
+      args['validate-links'] ? '--validate-links' : '--no-validate-links',
       if (args['dry-run']) '--no-generate-docs',
-      if (verbose) '--no-quiet',
+      if (verbose) ...['--verbose-warnings', '--show-stats'],
     ]);
 
     final config = await parseOptions(pubPackageMetaProvider, options);
diff --git a/pkg/dartdev/test/commands/doc_test.dart b/pkg/dartdev/test/commands/doc_test.dart
index b6f80ff..c0550b8 100644
--- a/pkg/dartdev/test/commands/doc_test.dart
+++ b/pkg/dartdev/test/commands/doc_test.dart
@@ -76,7 +76,10 @@
 }
 ''');
     final result = await p.run(['doc', '--dry-run', '--verbose', p.dirPath]);
-    expect(result.stdout, contains('Documenting dartdev_temp'));
+    expect(result.stdout, contains('Using the following options: [--input='));
+    // TODO(devoncarew): We should update package:dartdoc to emit some
+    // "Documenting ..." text here.
+    expect(result.stdout, isNot(contains('Documenting dartdev_temp')));
     expect(result.exitCode, 0);
   });
 
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 9aca3e3..4bb0a08 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -728,7 +728,7 @@
     TreeNode result = super.visitSwitchStatement(node, removalSentinel);
     Library library = constantEvaluator.libraryOf(node);
     // ignore: unnecessary_null_comparison
-    if (library != null && library.isNonNullableByDefault) {
+    if (library != null) {
       for (SwitchCase switchCase in node.cases) {
         for (Expression caseExpression in switchCase.expressions) {
           if (caseExpression is ConstantExpression) {
diff --git a/pkg/front_end/test/macro_api_test.dart b/pkg/front_end/test/macro_api_test.dart
new file mode 100644
index 0000000..f05b92b
--- /dev/null
+++ b/pkg/front_end/test/macro_api_test.dart
@@ -0,0 +1,55 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io' show Directory, Platform;
+
+import 'package:_fe_analyzer_shared/src/macros/isolated_executor/isolated_executor.dart'
+    as isolatedExecutor;
+import 'package:expect/expect.dart';
+import 'package:front_end/src/api_prototype/experimental_flags.dart';
+import 'package:front_end/src/api_prototype/front_end.dart';
+import 'package:front_end/src/compute_platform_binaries_location.dart';
+import 'package:front_end/src/fasta/kernel/macro.dart';
+import 'package:front_end/src/fasta/kernel/utils.dart';
+import 'package:front_end/src/testing/id_testing_helper.dart';
+import 'package:kernel/ast.dart' hide Arguments;
+import 'package:kernel/kernel.dart';
+import 'package:kernel/target/targets.dart';
+import 'package:vm/target/vm.dart';
+
+Future<void> main(List<String> args) async {
+  enableMacros = true;
+
+  Directory tempDirectory =
+      await Directory.systemTemp.createTemp('macro_api_test');
+  int precompiledCount = 0;
+  try {
+    CompilerOptions options = new CompilerOptions();
+    options.sdkRoot = computePlatformBinariesLocation();
+    options.environmentDefines = {};
+    options.explicitExperimentalFlags[ExperimentalFlag.macros] = true;
+    options.packagesFileUri = Platform.script.resolve(
+        '../../_fe_analyzer_shared/test/macros/api/package_config.json');
+    options.macroExecutorProvider = () async {
+      return await isolatedExecutor.start();
+    };
+    options.precompiledMacroUris = {};
+    options.target = options.macroTarget = new VmTarget(new TargetFlags());
+    options.macroSerializer = (Component component) async {
+      Uri uri = tempDirectory.absolute.uri
+          .resolve('macros${precompiledCount++}.dill');
+      await writeComponentToFile(component, uri);
+      return uri;
+    };
+
+    InternalCompilerResult result = await kernelForProgramInternal(
+        Platform.script.resolve(
+            '../../_fe_analyzer_shared/test/macros/api/api_test_data.dart'),
+        options,
+        retainDataForTesting: true) as InternalCompilerResult;
+    Expect.isFalse(result.kernelTargetForTesting!.loader.hasSeenError);
+  } finally {
+    await tempDirectory.delete(recursive: true);
+  }
+}
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart
index 4b03467..bac0513 100644
--- a/pkg/nnbd_migration/lib/src/edge_builder.dart
+++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -392,7 +392,6 @@
           respectImplicitlyTypedVarInitializers: true);
     }
     try {
-      _dispatch(node.name);
       _dispatch(node.constructorName);
       _dispatchList(node.arguments?.arguments);
     } finally {
diff --git a/pkg/nnbd_migration/lib/src/node_builder.dart b/pkg/nnbd_migration/lib/src/node_builder.dart
index 9f7c831..2e7fa25 100644
--- a/pkg/nnbd_migration/lib/src/node_builder.dart
+++ b/pkg/nnbd_migration/lib/src/node_builder.dart
@@ -290,13 +290,6 @@
         DecoratedType(indexGetter.type, makeNonNullNode(indexTarget),
             returnType: DecoratedType(indexGetter.returnType,
                 makeNonNullNode(indexTarget.returnType()))));
-    final toString = classElement.getMethod('toString')!;
-    var toStringTarget = NullabilityNodeTarget.element(toString, _getLineInfo);
-    _variables!.recordDecoratedElementType(
-        toString,
-        DecoratedType(toString.type, makeNonNullNode(toStringTarget),
-            returnType: DecoratedType(toString.returnType,
-                makeNonNullNode(toStringTarget.returnType()))));
     return null;
   }
 
diff --git a/pkg/nnbd_migration/test/api_test.dart b/pkg/nnbd_migration/test/api_test.dart
index 2301e5b..8efdc63 100644
--- a/pkg/nnbd_migration/test/api_test.dart
+++ b/pkg/nnbd_migration/test/api_test.dart
@@ -695,6 +695,30 @@
     await _checkSingleFileChanges(content, expected);
   }
 
+  Future<void> test_annotation_named_constructor() async {
+    var content = '''
+class C {
+  final List<Object> values;
+  const factory C.ints(List<int> list) = C;
+  const C(this.values);
+}
+
+@C.ints([1, 2, 3])
+class D {}
+''';
+    var expected = '''
+class C {
+  final List<Object> values;
+  const factory C.ints(List<int> list) = C;
+  const C(this.values);
+}
+
+@C.ints([1, 2, 3])
+class D {}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
   Future<void> test_argumentError_checkNotNull_implies_non_null_intent() async {
     var content = '''
 void f(int i) {
diff --git a/runtime/tests/vm/dart/finalizer/weak_reference_run_gc_test.dart b/runtime/tests/vm/dart/finalizer/weak_reference_run_gc_test.dart
index 5679b3c..15b330d 100644
--- a/runtime/tests/vm/dart/finalizer/weak_reference_run_gc_test.dart
+++ b/runtime/tests/vm/dart/finalizer/weak_reference_run_gc_test.dart
@@ -1,17 +1,15 @@
 // 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.
-//
-// SharedObjects=ffi_test_functions
 
-import 'dart:async';
-import 'dart:ffi';
-import 'dart:io';
+// ignore: import_internal_library, unused_import
+import 'dart:_internal';
 
 import 'package:expect/expect.dart';
 
 void main() {
   testWeakReferenceNonExpandoKey();
+  testWeakReferenceTypeArgument();
   testWeakReference();
 }
 
@@ -29,23 +27,28 @@
   });
 }
 
-void testWeakReference() async {
-  final weakRef = () {
-    final object = Nonce(23);
-    final weakRef = WeakReference(object);
-    // Left to right argument evaluation: evaluate weakRef.target first.
-    Expect.equals(weakRef.target, object);
-    return weakRef;
-  }();
+void testWeakReferenceTypeArgument() {
+  final object = Nonce(23);
+  final weakRef = WeakReference(object);
+  Expect.type<WeakReference<Nonce>>(weakRef);
+}
+
+/// Never inline to ensure `object` becomes unreachable.
+@pragma('vm:never-inline')
+WeakReference<Nonce> makeWeakRef() {
+  final object = Nonce(23);
+  final weakRef = WeakReference(object);
+  // Left to right argument evaluation: evaluate weakRef.target first.
+  Expect.equals(weakRef.target, object);
+  return weakRef;
+}
+
+void testWeakReference() {
+  final weakRef = makeWeakRef();
 
   print('do gc');
   triggerGc();
-  await Future.delayed(Duration(milliseconds: 1));
-  triggerGc();
-  await Future.delayed(Duration(milliseconds: 1));
-  triggerGc();
-  await Future.delayed(Duration(milliseconds: 1));
-  triggerGc();
+  print('gc done');
 
   // The weak reference should not target anything anymore.
   Expect.isNull(weakRef.target);
@@ -53,23 +56,6 @@
   print('End of test, shutting down.');
 }
 
-final void Function() triggerGc = () {
-  String _platformPath(String name, {String? path}) {
-    if (path == null) path = "";
-    if (Platform.isLinux || Platform.isAndroid || Platform.isFuchsia)
-      return path + "lib" + name + ".so";
-    if (Platform.isMacOS) return path + "lib" + name + ".dylib";
-    if (Platform.isWindows) return path + name + ".dll";
-    throw Exception("Platform not implemented");
-  }
-
-  DynamicLibrary dlopenPlatformSpecific(String name, {String? path}) {
-    String fullPath = _platformPath(name, path: path);
-    return DynamicLibrary.open(fullPath);
-  }
-
-  final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
-
-  return ffiTestFunctions
-      .lookupFunction<Void Function(), void Function()>("TriggerGC");
-}();
+// Defined in `dart:_internal`.
+// ignore: undefined_identifier
+void triggerGc() => VMInternalsForTesting.collectAllGarbage();
diff --git a/runtime/tests/vm/dart/isolates/fast_object_copy_test.dart b/runtime/tests/vm/dart/isolates/fast_object_copy_test.dart
index 955e13d..cd24fbc 100644
--- a/runtime/tests/vm/dart/isolates/fast_object_copy_test.dart
+++ b/runtime/tests/vm/dart/isolates/fast_object_copy_test.dart
@@ -6,6 +6,8 @@
 // VMOptions=--enable-fast-object-copy
 // VMOptions=--no-enable-fast-object-copy --gc-on-foc-slow-path --force-evacuation --verify-store-buffer
 // VMOptions=--enable-fast-object-copy --gc-on-foc-slow-path --force-evacuation --verify-store-buffer
+// VMOptions=--no-enable-fast-object-copy --gc-on-foc-slow-path --force-evacuation --verify-store-buffer --deterministic
+// VMOptions=--enable-fast-object-copy --gc-on-foc-slow-path --force-evacuation --verify-store-buffer --deterministic
 
 // The tests in this file are particularly for an implementation that tries to
 // allocate the entire graph in BFS order using a fast new space allocation
@@ -242,6 +244,7 @@
     await testSlowOnly();
 
     await testWeakProperty();
+    await testWeakReference();
 
     await testForbiddenClosures();
   }
@@ -690,6 +693,69 @@
     }
   }
 
+  Future testWeakReference() async {
+    print('testWeakReference');
+
+    final object1 = Nonce(1);
+    final weakRef1 = WeakReference(object1);
+    final object2 = Nonce(2);
+    final weakRef2 = WeakReference(object2);
+    final object3 = Nonce(3);
+    final weakRef3 = WeakReference(object3);
+    final object4 = Nonce(4);
+    final weakRef4 = WeakReference(object4);
+
+    final key3 = Object();
+    final expando3 = Expando()..[key3] = object3;
+    final key4 = Object();
+    final expando4 = Expando()..[key4] = object4;
+
+    {
+      final result = await sendReceive([
+        weakRef1, // Does not have its target inluded.
+        weakRef2, // Has its target included later than itself.
+        object2,
+        weakRef3, // Does not have its target inluded.
+        expando3,
+        weakRef4, // Has its target included due to expando.
+        expando4,
+        key4,
+      ]);
+
+      final weakRef1copy = result[0] as WeakReference<Nonce>;
+      final weakRef2copy = result[1] as WeakReference<Nonce>;
+      final weakRef3copy = result[3] as WeakReference<Nonce>;
+      final weakRef4copy = result[5] as WeakReference<Nonce>;
+      Expect.isNull(weakRef1copy.target);
+      Expect.equals(weakRef2.target?.value, weakRef2copy.target?.value);
+      Expect.isNull(weakRef3copy.target);
+      Expect.equals(weakRef4.target?.value, weakRef4copy.target?.value);
+    }
+
+    {
+      final result = await sendReceive([
+        weakRef1, // Does not have its target inluded.
+        weakRef2, // Has its target included later than itself.
+        notAllocatableInTLAB,
+        object2,
+        weakRef3, // Does not have its target inluded.
+        expando3,
+        weakRef4, // Has its target included due to expando.
+        expando4,
+        key4,
+      ]);
+
+      final weakRef1copy = result[0] as WeakReference<Nonce>;
+      final weakRef2copy = result[1] as WeakReference<Nonce>;
+      final weakRef3copy = result[4] as WeakReference<Nonce>;
+      final weakRef4copy = result[6] as WeakReference<Nonce>;
+      Expect.isNull(weakRef1copy.target);
+      Expect.equals(weakRef2.target?.value, weakRef2copy.target?.value);
+      Expect.isNull(weakRef3copy.target);
+      Expect.equals(weakRef4.target?.value, weakRef4copy.target?.value);
+    }
+  }
+
   Future testForbiddenClosures() async {
     print('testForbiddenClosures');
     for (final closure in nonCopyableClosures) {
@@ -705,6 +771,14 @@
   }
 }
 
+class Nonce {
+  final int value;
+
+  Nonce(this.value);
+
+  String toString() => 'Nonce($value)';
+}
+
 main() async {
   await SendReceiveTest().run();
 }
diff --git a/runtime/tests/vm/dart_2/finalizer/weak_reference_run_gc_test.dart b/runtime/tests/vm/dart_2/finalizer/weak_reference_run_gc_test.dart
new file mode 100644
index 0000000..8c7583d
--- /dev/null
+++ b/runtime/tests/vm/dart_2/finalizer/weak_reference_run_gc_test.dart
@@ -0,0 +1,63 @@
+// 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
+
+// ignore: import_internal_library, unused_import
+import 'dart:_internal';
+
+import 'package:expect/expect.dart';
+
+void main() {
+  testWeakReferenceNonExpandoKey();
+  testWeakReferenceTypeArgument();
+  testWeakReference();
+}
+
+class Nonce {
+  final int value;
+
+  Nonce(this.value);
+
+  String toString() => 'Nonce($value)';
+}
+
+void testWeakReferenceNonExpandoKey() {
+  Expect.throwsArgumentError(() {
+    WeakReference<String>("Hello world!");
+  });
+}
+
+void testWeakReferenceTypeArgument() {
+  final object = Nonce(23);
+  final weakRef = WeakReference(object);
+  Expect.type<WeakReference<Nonce>>(weakRef);
+}
+
+/// Never inline to ensure `object` becomes unreachable.
+@pragma('vm:never-inline')
+WeakReference<Nonce> makeWeakRef() {
+  final object = Nonce(23);
+  final weakRef = WeakReference(object);
+  // Left to right argument evaluation: evaluate weakRef.target first.
+  Expect.equals(weakRef.target, object);
+  return weakRef;
+}
+
+void testWeakReference() {
+  final weakRef = makeWeakRef();
+
+  print('do gc');
+  triggerGc();
+  print('gc done');
+
+  // The weak reference should not target anything anymore.
+  Expect.isNull(weakRef.target);
+
+  print('End of test, shutting down.');
+}
+
+// Defined in `dart:_internal`.
+// ignore: undefined_identifier
+void triggerGc() => VMInternalsForTesting.collectAllGarbage();
diff --git a/runtime/tests/vm/dart_2/isolates/fast_object_copy_test.dart b/runtime/tests/vm/dart_2/isolates/fast_object_copy_test.dart
index 09aa46f..1843f0c 100644
--- a/runtime/tests/vm/dart_2/isolates/fast_object_copy_test.dart
+++ b/runtime/tests/vm/dart_2/isolates/fast_object_copy_test.dart
@@ -8,6 +8,8 @@
 // VMOptions=--enable-fast-object-copy
 // VMOptions=--no-enable-fast-object-copy --gc-on-foc-slow-path --force-evacuation --verify-store-buffer
 // VMOptions=--enable-fast-object-copy --gc-on-foc-slow-path --force-evacuation --verify-store-buffer
+// VMOptions=--no-enable-fast-object-copy --gc-on-foc-slow-path --force-evacuation --verify-store-buffer --deterministic
+// VMOptions=--enable-fast-object-copy --gc-on-foc-slow-path --force-evacuation --verify-store-buffer --deterministic
 
 // The tests in this file are particularly for an implementation that tries to
 // allocate the entire graph in BFS order using a fast new space allocation
@@ -244,6 +246,7 @@
     await testSlowOnly();
 
     await testWeakProperty();
+    await testWeakReference();
 
     await testForbiddenClosures();
   }
@@ -692,6 +695,69 @@
     }
   }
 
+  Future testWeakReference() async {
+    print('testWeakReference');
+
+    final object1 = Nonce(1);
+    final weakRef1 = WeakReference(object1);
+    final object2 = Nonce(2);
+    final weakRef2 = WeakReference(object2);
+    final object3 = Nonce(3);
+    final weakRef3 = WeakReference(object3);
+    final object4 = Nonce(4);
+    final weakRef4 = WeakReference(object4);
+
+    final key3 = Object();
+    final expando3 = Expando()..[key3] = object3;
+    final key4 = Object();
+    final expando4 = Expando()..[key4] = object4;
+
+    {
+      final result = await sendReceive([
+        weakRef1, // Does not have its target inluded.
+        weakRef2, // Has its target included later than itself.
+        object2,
+        weakRef3, // Does not have its target inluded.
+        expando3,
+        weakRef4, // Has its target included due to expando.
+        expando4,
+        key4,
+      ]);
+
+      final weakRef1copy = result[0] as WeakReference<Nonce>;
+      final weakRef2copy = result[1] as WeakReference<Nonce>;
+      final weakRef3copy = result[3] as WeakReference<Nonce>;
+      final weakRef4copy = result[5] as WeakReference<Nonce>;
+      Expect.isNull(weakRef1copy.target);
+      Expect.equals(weakRef2.target?.value, weakRef2copy.target?.value);
+      Expect.isNull(weakRef3copy.target);
+      Expect.equals(weakRef4.target?.value, weakRef4copy.target?.value);
+    }
+
+    {
+      final result = await sendReceive([
+        weakRef1, // Does not have its target inluded.
+        weakRef2, // Has its target included later than itself.
+        notAllocatableInTLAB,
+        object2,
+        weakRef3, // Does not have its target inluded.
+        expando3,
+        weakRef4, // Has its target included due to expando.
+        expando4,
+        key4,
+      ]);
+
+      final weakRef1copy = result[0] as WeakReference<Nonce>;
+      final weakRef2copy = result[1] as WeakReference<Nonce>;
+      final weakRef3copy = result[4] as WeakReference<Nonce>;
+      final weakRef4copy = result[6] as WeakReference<Nonce>;
+      Expect.isNull(weakRef1copy.target);
+      Expect.equals(weakRef2.target?.value, weakRef2copy.target?.value);
+      Expect.isNull(weakRef3copy.target);
+      Expect.equals(weakRef4.target?.value, weakRef4copy.target?.value);
+    }
+  }
+
   Future testForbiddenClosures() async {
     print('testForbiddenClosures');
     for (final closure in nonCopyableClosures) {
@@ -707,6 +773,14 @@
   }
 }
 
+class Nonce {
+  final int value;
+
+  Nonce(this.value);
+
+  String toString() => 'Nonce($value)';
+}
+
 main() async {
   await SendReceiveTest().run();
 }
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index c850c6c..7a97443 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -280,7 +280,6 @@
 dart_2/snapshot_depfile_test: SkipByDesign # Test needs to run from source
 
 [ $compiler == dartkp && $system == windows ]
-dart/finalizer/weak_reference_run_gc_test: SkipByDesign # https://dartbug.com/40579 Dart C API symbols not available.
 dart/isolates/dart_api_create_lightweight_isolate_test: SkipByDesign # https://dartbug.com/40579 Dart C API symbols not available.
 dart_2/isolates/dart_api_create_lightweight_isolate_test: SkipByDesign # https://dartbug.com/40579 Dart C API symbols not available.
 
@@ -357,7 +356,6 @@
 cc/Profiler_TrivialRecordAllocation: SkipByDesign
 cc/Profiler_TypedArrayAllocation: SkipByDesign
 cc/Service_Profile: SkipByDesign
-dart/finalizer/weak_reference_run_gc_test: SkipByDesign # https://dartbug.com/37299 FFI not yet supported on simulators.
 dart/isolates/dart_api_create_lightweight_isolate_test: SkipByDesign # https://dartbug.com/37299 Test uses dart:ffi which is not supported on simulators.
 dart/isolates/thread_pool_test: SkipByDesign # https://dartbug.com/37299 Test uses dart:ffi which is not supported on simulators.
 dart/regress_41971_test: SkipByDesign # https://dartbug.com/37299 dart:ffi is not supported on simulator
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 587b538..dc432e3 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -265,6 +265,8 @@
   ASSERT_EQUAL(ImmutableArray::InstanceSize(), cls.host_instance_size());
   cls = object_store->weak_property_class();
   ASSERT_EQUAL(WeakProperty::InstanceSize(), cls.host_instance_size());
+  cls = object_store->weak_reference_class();
+  ASSERT_EQUAL(WeakReference::InstanceSize(), cls.host_instance_size());
   cls = object_store->linked_hash_map_class();
   ASSERT_EQUAL(LinkedHashMap::InstanceSize(), cls.host_instance_size());
   cls = object_store->immutable_linked_hash_map_class();
diff --git a/runtime/vm/class_id.h b/runtime/vm/class_id.h
index 6edd6b9..93e1979 100644
--- a/runtime/vm/class_id.h
+++ b/runtime/vm/class_id.h
@@ -93,6 +93,7 @@
   V(StackTrace)                                                                \
   V(RegExp)                                                                    \
   V(WeakProperty)                                                              \
+  V(WeakReference)                                                             \
   V(MirrorReference)                                                           \
   V(FutureOr)                                                                  \
   V(UserTag)                                                                   \
diff --git a/runtime/vm/compiler/backend/il_riscv.cc b/runtime/vm/compiler/backend/il_riscv.cc
index 1d0562a..1442eed 100644
--- a/runtime/vm/compiler/backend/il_riscv.cc
+++ b/runtime/vm/compiler/backend/il_riscv.cc
@@ -4340,9 +4340,6 @@
 
 LocationSummary* BoxInt64Instr::MakeLocationSummary(Zone* zone,
                                                     bool opt) const {
-  const intptr_t kNumInputs = 1;
-  const intptr_t kNumTemps = 0;
-#if XLEN == 32
   // Shared slow path is used in BoxInt64Instr::EmitNativeCode in
   // FLAG_use_bare_instructions mode and only after VM isolate stubs where
   // replaced with isolate-specific stubs.
@@ -4356,51 +4353,30 @@
           ->InVMIsolateHeap();
   const bool shared_slow_path_call =
       SlowPathSharingSupported(opt) && !stubs_in_vm_isolate;
+  const intptr_t kNumInputs = 1;
+  const intptr_t kNumTemps = ValueFitsSmi() ? 0 : 1;
   LocationSummary* summary = new (zone) LocationSummary(
       zone, kNumInputs, kNumTemps,
       ValueFitsSmi()
           ? LocationSummary::kNoCall
           : ((shared_slow_path_call ? LocationSummary::kCallOnSharedSlowPath
                                     : LocationSummary::kCallOnSlowPath)));
+#if XLEN == 32
   summary->set_in(0, Location::Pair(Location::RequiresRegister(),
                                     Location::RequiresRegister()));
-  if (ValueFitsSmi()) {
-    summary->set_out(0, Location::RequiresRegister());
-  } else if (shared_slow_path_call) {
-    summary->set_out(0,
-                     Location::RegisterLocation(AllocateMintABI::kResultReg));
-  } else {
-    summary->set_out(0, Location::RequiresRegister());
-  }
 #else
-  // Shared slow path is used in BoxInt64Instr::EmitNativeCode in
-  // FLAG_use_bare_instructions mode and only after VM isolate stubs where
-  // replaced with isolate-specific stubs.
-  auto object_store = IsolateGroup::Current()->object_store();
-  const bool stubs_in_vm_isolate =
-      object_store->allocate_mint_with_fpu_regs_stub()
-          ->untag()
-          ->InVMIsolateHeap() ||
-      object_store->allocate_mint_without_fpu_regs_stub()
-          ->untag()
-          ->InVMIsolateHeap();
-  const bool shared_slow_path_call =
-      SlowPathSharingSupported(opt) && !stubs_in_vm_isolate;
-  LocationSummary* summary = new (zone) LocationSummary(
-      zone, kNumInputs, kNumTemps,
-      ValueFitsSmi() ? LocationSummary::kNoCall
-      : shared_slow_path_call ? LocationSummary::kCallOnSharedSlowPath
-                              : LocationSummary::kCallOnSlowPath);
   summary->set_in(0, Location::RequiresRegister());
+#endif
   if (ValueFitsSmi()) {
     summary->set_out(0, Location::RequiresRegister());
   } else if (shared_slow_path_call) {
     summary->set_out(0,
                      Location::RegisterLocation(AllocateMintABI::kResultReg));
+    summary->set_temp(0, Location::RegisterLocation(AllocateMintABI::kTempReg));
   } else {
     summary->set_out(0, Location::RequiresRegister());
+    summary->set_temp(0, Location::RequiresRegister());
   }
-#endif
   return summary;
 }
 
diff --git a/runtime/vm/compiler/backend/range_analysis.cc b/runtime/vm/compiler/backend/range_analysis.cc
index 0d25a71..4d28937 100644
--- a/runtime/vm/compiler/backend/range_analysis.cc
+++ b/runtime/vm/compiler/backend/range_analysis.cc
@@ -2815,6 +2815,8 @@
     case Slot::Kind::kUnhandledException_stacktrace:
     case Slot::Kind::kWeakProperty_key:
     case Slot::Kind::kWeakProperty_value:
+    case Slot::Kind::kWeakReference_target:
+    case Slot::Kind::kWeakReference_type_arguments:
       // Not an integer valued field.
       UNREACHABLE();
       break;
diff --git a/runtime/vm/compiler/backend/slot.cc b/runtime/vm/compiler/backend/slot.cc
index db64e39..4a512f8 100644
--- a/runtime/vm/compiler/backend/slot.cc
+++ b/runtime/vm/compiler/backend/slot.cc
@@ -243,6 +243,8 @@
     case Slot::Kind::kUnhandledException_stacktrace:
     case Slot::Kind::kWeakProperty_key:
     case Slot::Kind::kWeakProperty_value:
+    case Slot::Kind::kWeakReference_target:
+    case Slot::Kind::kWeakReference_type_arguments:
       return false;
   }
   UNREACHABLE();
diff --git a/runtime/vm/compiler/backend/slot.h b/runtime/vm/compiler/backend/slot.h
index 09b1186..65cafe9 100644
--- a/runtime/vm/compiler/backend/slot.h
+++ b/runtime/vm/compiler/backend/slot.h
@@ -69,7 +69,9 @@
   V(TypeParameters, UntaggedTypeParameters, bounds, TypeArguments, FINAL)      \
   V(TypeParameters, UntaggedTypeParameters, defaults, TypeArguments, FINAL)    \
   V(WeakProperty, UntaggedWeakProperty, key, Dynamic, VAR)                     \
-  V(WeakProperty, UntaggedWeakProperty, value, Dynamic, VAR)
+  V(WeakProperty, UntaggedWeakProperty, value, Dynamic, VAR)                   \
+  V(WeakReference, UntaggedWeakReference, target, Dynamic, VAR)                \
+  V(WeakReference, UntaggedWeakReference, type_arguments, TypeArguments, FINAL)
 
 // The list of slots that correspond to non-nullable boxed fields of native
 // objects in the following format:
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index eb4d2c9..0311465 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -898,6 +898,8 @@
     case MethodRecognizer::kWeakProperty_setKey:
     case MethodRecognizer::kWeakProperty_getValue:
     case MethodRecognizer::kWeakProperty_setValue:
+    case MethodRecognizer::kWeakReference_getTarget:
+    case MethodRecognizer::kWeakReference_setTarget:
     case MethodRecognizer::kFfiAbi:
     case MethodRecognizer::kReachabilityFence:
     case MethodRecognizer::kUtf8DecoderScan:
@@ -1319,6 +1321,18 @@
       body += StoreNativeField(Slot::WeakProperty_value());
       body += NullConstant();
       break;
+    case MethodRecognizer::kWeakReference_getTarget:
+      ASSERT_EQUAL(function.NumParameters(), 1);
+      body += LoadLocal(parsed_function_->RawParameterVariable(0));
+      body += LoadNativeField(Slot::WeakReference_target());
+      break;
+    case MethodRecognizer::kWeakReference_setTarget:
+      ASSERT_EQUAL(function.NumParameters(), 2);
+      body += LoadLocal(parsed_function_->RawParameterVariable(0));
+      body += LoadLocal(parsed_function_->RawParameterVariable(1));
+      body += StoreNativeField(Slot::WeakReference_target());
+      body += NullConstant();
+      break;
     case MethodRecognizer::kUtf8DecoderScan:
       ASSERT_EQUAL(function.NumParameters(), 5);
       body += LoadLocal(parsed_function_->RawParameterVariable(0));  // decoder
diff --git a/runtime/vm/compiler/recognized_methods_list.h b/runtime/vm/compiler/recognized_methods_list.h
index 341e699..aa35336 100644
--- a/runtime/vm/compiler/recognized_methods_list.h
+++ b/runtime/vm/compiler/recognized_methods_list.h
@@ -186,6 +186,8 @@
   V(_WeakProperty, set:key, WeakProperty_setKey, 0x963a095f)                   \
   V(_WeakProperty, get:value, WeakProperty_getValue, 0xd2f28aae)               \
   V(_WeakProperty, set:value, WeakProperty_setValue, 0x8b2bafab)               \
+  V(_WeakReferenceImpl, get:target, WeakReference_getTarget, 0x632d6ca8)       \
+  V(_WeakReferenceImpl, set:_target, WeakReference_setTarget, 0x6edc7518)      \
   V(::, _classRangeCheck, ClassRangeCheck, 0x00269620)                         \
   V(::, _abi, FfiAbi, 0x7c4ab3b4)                                              \
   V(::, _asFunctionInternal, FfiAsFunctionInternal, 0x92ae104f)                \
diff --git a/runtime/vm/compiler/runtime_api.cc b/runtime/vm/compiler/runtime_api.cc
index 51062e6..9cc619d 100644
--- a/runtime/vm/compiler/runtime_api.cc
+++ b/runtime/vm/compiler/runtime_api.cc
@@ -437,6 +437,8 @@
       return UnhandledException::InstanceSize();
     case kWeakPropertyCid:
       return WeakProperty::InstanceSize();
+    case kWeakReferenceCid:
+      return WeakReference::InstanceSize();
     case kByteBufferCid:
     case kByteDataViewCid:
     case kPointerCid:
diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h
index a23de21..f502d99 100644
--- a/runtime/vm/compiler/runtime_api.h
+++ b/runtime/vm/compiler/runtime_api.h
@@ -1037,6 +1037,14 @@
   FINAL_CLASS();
 };
 
+class WeakReference : public AllStatic {
+ public:
+  static word target_offset();
+  static word type_arguments_offset();
+  static word InstanceSize();
+  FINAL_CLASS();
+};
+
 class MirrorReference : public AllStatic {
  public:
   static word InstanceSize();
diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h
index 5b0ad83..6f1d535 100644
--- a/runtime/vm/compiler/runtime_offsets_extracted.h
+++ b/runtime/vm/compiler/runtime_offsets_extracted.h
@@ -485,6 +485,9 @@
     MonomorphicSmiableCall_entrypoint_offset = 8;
 static constexpr dart::compiler::target::word WeakProperty_key_offset = 4;
 static constexpr dart::compiler::target::word WeakProperty_value_offset = 8;
+static constexpr dart::compiler::target::word WeakReference_target_offset = 4;
+static constexpr dart::compiler::target::word
+    WeakReference_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     4, 12, 8, 16};
 static constexpr dart::compiler::target::word
@@ -577,6 +580,7 @@
 static constexpr dart::compiler::target::word UnwindError_InstanceSize = 12;
 static constexpr dart::compiler::target::word UserTag_InstanceSize = 16;
 static constexpr dart::compiler::target::word WeakProperty_InstanceSize = 16;
+static constexpr dart::compiler::target::word WeakReference_InstanceSize = 16;
 static constexpr dart::compiler::target::word
     WeakSerializationReference_InstanceSize = 12;
 #endif  // defined(TARGET_ARCH_ARM) && !defined(DART_COMPRESSED_POINTERS)
@@ -1058,6 +1062,9 @@
     MonomorphicSmiableCall_entrypoint_offset = 16;
 static constexpr dart::compiler::target::word WeakProperty_key_offset = 8;
 static constexpr dart::compiler::target::word WeakProperty_value_offset = 16;
+static constexpr dart::compiler::target::word WeakReference_target_offset = 8;
+static constexpr dart::compiler::target::word
+    WeakReference_type_arguments_offset = 16;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
@@ -1152,6 +1159,7 @@
 static constexpr dart::compiler::target::word UnwindError_InstanceSize = 24;
 static constexpr dart::compiler::target::word UserTag_InstanceSize = 32;
 static constexpr dart::compiler::target::word WeakProperty_InstanceSize = 32;
+static constexpr dart::compiler::target::word WeakReference_InstanceSize = 32;
 static constexpr dart::compiler::target::word
     WeakSerializationReference_InstanceSize = 24;
 #endif  // defined(TARGET_ARCH_X64) && !defined(DART_COMPRESSED_POINTERS)
@@ -1624,6 +1632,9 @@
     MonomorphicSmiableCall_entrypoint_offset = 8;
 static constexpr dart::compiler::target::word WeakProperty_key_offset = 4;
 static constexpr dart::compiler::target::word WeakProperty_value_offset = 8;
+static constexpr dart::compiler::target::word WeakReference_target_offset = 4;
+static constexpr dart::compiler::target::word
+    WeakReference_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     4, 12, 8, 16};
 static constexpr dart::compiler::target::word AbstractType_InstanceSize = 12;
@@ -1713,6 +1724,7 @@
 static constexpr dart::compiler::target::word UnwindError_InstanceSize = 12;
 static constexpr dart::compiler::target::word UserTag_InstanceSize = 16;
 static constexpr dart::compiler::target::word WeakProperty_InstanceSize = 16;
+static constexpr dart::compiler::target::word WeakReference_InstanceSize = 16;
 static constexpr dart::compiler::target::word
     WeakSerializationReference_InstanceSize = 12;
 #endif  // defined(TARGET_ARCH_IA32) && !defined(DART_COMPRESSED_POINTERS)
@@ -2194,6 +2206,9 @@
     MonomorphicSmiableCall_entrypoint_offset = 16;
 static constexpr dart::compiler::target::word WeakProperty_key_offset = 8;
 static constexpr dart::compiler::target::word WeakProperty_value_offset = 16;
+static constexpr dart::compiler::target::word WeakReference_target_offset = 8;
+static constexpr dart::compiler::target::word
+    WeakReference_type_arguments_offset = 16;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
@@ -2289,6 +2304,7 @@
 static constexpr dart::compiler::target::word UnwindError_InstanceSize = 24;
 static constexpr dart::compiler::target::word UserTag_InstanceSize = 32;
 static constexpr dart::compiler::target::word WeakProperty_InstanceSize = 32;
+static constexpr dart::compiler::target::word WeakReference_InstanceSize = 32;
 static constexpr dart::compiler::target::word
     WeakSerializationReference_InstanceSize = 24;
 #endif  // defined(TARGET_ARCH_ARM64) && !defined(DART_COMPRESSED_POINTERS)
@@ -2767,6 +2783,9 @@
     MonomorphicSmiableCall_entrypoint_offset = 16;
 static constexpr dart::compiler::target::word WeakProperty_key_offset = 8;
 static constexpr dart::compiler::target::word WeakProperty_value_offset = 12;
+static constexpr dart::compiler::target::word WeakReference_target_offset = 8;
+static constexpr dart::compiler::target::word
+    WeakReference_type_arguments_offset = 12;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
@@ -2861,6 +2880,7 @@
 static constexpr dart::compiler::target::word UnwindError_InstanceSize = 16;
 static constexpr dart::compiler::target::word UserTag_InstanceSize = 32;
 static constexpr dart::compiler::target::word WeakProperty_InstanceSize = 24;
+static constexpr dart::compiler::target::word WeakReference_InstanceSize = 24;
 static constexpr dart::compiler::target::word
     WeakSerializationReference_InstanceSize = 16;
 #endif  // defined(TARGET_ARCH_X64) && defined(DART_COMPRESSED_POINTERS)
@@ -3339,6 +3359,9 @@
     MonomorphicSmiableCall_entrypoint_offset = 16;
 static constexpr dart::compiler::target::word WeakProperty_key_offset = 8;
 static constexpr dart::compiler::target::word WeakProperty_value_offset = 12;
+static constexpr dart::compiler::target::word WeakReference_target_offset = 8;
+static constexpr dart::compiler::target::word
+    WeakReference_type_arguments_offset = 12;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
@@ -3434,6 +3457,7 @@
 static constexpr dart::compiler::target::word UnwindError_InstanceSize = 16;
 static constexpr dart::compiler::target::word UserTag_InstanceSize = 32;
 static constexpr dart::compiler::target::word WeakProperty_InstanceSize = 24;
+static constexpr dart::compiler::target::word WeakReference_InstanceSize = 24;
 static constexpr dart::compiler::target::word
     WeakSerializationReference_InstanceSize = 16;
 #endif  // defined(TARGET_ARCH_ARM64) && defined(DART_COMPRESSED_POINTERS)
@@ -3906,6 +3930,9 @@
     MonomorphicSmiableCall_entrypoint_offset = 8;
 static constexpr dart::compiler::target::word WeakProperty_key_offset = 4;
 static constexpr dart::compiler::target::word WeakProperty_value_offset = 8;
+static constexpr dart::compiler::target::word WeakReference_target_offset = 4;
+static constexpr dart::compiler::target::word
+    WeakReference_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     4, 12, 8, 16};
 static constexpr dart::compiler::target::word
@@ -4000,6 +4027,7 @@
 static constexpr dart::compiler::target::word UnwindError_InstanceSize = 12;
 static constexpr dart::compiler::target::word UserTag_InstanceSize = 16;
 static constexpr dart::compiler::target::word WeakProperty_InstanceSize = 16;
+static constexpr dart::compiler::target::word WeakReference_InstanceSize = 16;
 static constexpr dart::compiler::target::word
     WeakSerializationReference_InstanceSize = 12;
 #endif  // defined(TARGET_ARCH_RISCV32) && !defined(DART_COMPRESSED_POINTERS)
@@ -4481,6 +4509,9 @@
     MonomorphicSmiableCall_entrypoint_offset = 16;
 static constexpr dart::compiler::target::word WeakProperty_key_offset = 8;
 static constexpr dart::compiler::target::word WeakProperty_value_offset = 16;
+static constexpr dart::compiler::target::word WeakReference_target_offset = 8;
+static constexpr dart::compiler::target::word
+    WeakReference_type_arguments_offset = 16;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
@@ -4576,6 +4607,7 @@
 static constexpr dart::compiler::target::word UnwindError_InstanceSize = 24;
 static constexpr dart::compiler::target::word UserTag_InstanceSize = 32;
 static constexpr dart::compiler::target::word WeakProperty_InstanceSize = 32;
+static constexpr dart::compiler::target::word WeakReference_InstanceSize = 32;
 static constexpr dart::compiler::target::word
     WeakSerializationReference_InstanceSize = 24;
 #endif  // defined(TARGET_ARCH_RISCV64) && !defined(DART_COMPRESSED_POINTERS)
@@ -5044,6 +5076,9 @@
     MonomorphicSmiableCall_entrypoint_offset = 8;
 static constexpr dart::compiler::target::word WeakProperty_key_offset = 4;
 static constexpr dart::compiler::target::word WeakProperty_value_offset = 8;
+static constexpr dart::compiler::target::word WeakReference_target_offset = 4;
+static constexpr dart::compiler::target::word
+    WeakReference_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     4, 12, 8, 16};
 static constexpr dart::compiler::target::word
@@ -5136,6 +5171,7 @@
 static constexpr dart::compiler::target::word UnwindError_InstanceSize = 12;
 static constexpr dart::compiler::target::word UserTag_InstanceSize = 16;
 static constexpr dart::compiler::target::word WeakProperty_InstanceSize = 16;
+static constexpr dart::compiler::target::word WeakReference_InstanceSize = 16;
 static constexpr dart::compiler::target::word
     WeakSerializationReference_InstanceSize = 12;
 #endif  // defined(TARGET_ARCH_ARM) && !defined(DART_COMPRESSED_POINTERS)
@@ -5611,6 +5647,9 @@
     MonomorphicSmiableCall_entrypoint_offset = 16;
 static constexpr dart::compiler::target::word WeakProperty_key_offset = 8;
 static constexpr dart::compiler::target::word WeakProperty_value_offset = 16;
+static constexpr dart::compiler::target::word WeakReference_target_offset = 8;
+static constexpr dart::compiler::target::word
+    WeakReference_type_arguments_offset = 16;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
@@ -5705,6 +5744,7 @@
 static constexpr dart::compiler::target::word UnwindError_InstanceSize = 24;
 static constexpr dart::compiler::target::word UserTag_InstanceSize = 32;
 static constexpr dart::compiler::target::word WeakProperty_InstanceSize = 32;
+static constexpr dart::compiler::target::word WeakReference_InstanceSize = 32;
 static constexpr dart::compiler::target::word
     WeakSerializationReference_InstanceSize = 24;
 #endif  // defined(TARGET_ARCH_X64) && !defined(DART_COMPRESSED_POINTERS)
@@ -6171,6 +6211,9 @@
     MonomorphicSmiableCall_entrypoint_offset = 8;
 static constexpr dart::compiler::target::word WeakProperty_key_offset = 4;
 static constexpr dart::compiler::target::word WeakProperty_value_offset = 8;
+static constexpr dart::compiler::target::word WeakReference_target_offset = 4;
+static constexpr dart::compiler::target::word
+    WeakReference_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     4, 12, 8, 16};
 static constexpr dart::compiler::target::word AbstractType_InstanceSize = 12;
@@ -6260,6 +6303,7 @@
 static constexpr dart::compiler::target::word UnwindError_InstanceSize = 12;
 static constexpr dart::compiler::target::word UserTag_InstanceSize = 16;
 static constexpr dart::compiler::target::word WeakProperty_InstanceSize = 16;
+static constexpr dart::compiler::target::word WeakReference_InstanceSize = 16;
 static constexpr dart::compiler::target::word
     WeakSerializationReference_InstanceSize = 12;
 #endif  // defined(TARGET_ARCH_IA32) && !defined(DART_COMPRESSED_POINTERS)
@@ -6735,6 +6779,9 @@
     MonomorphicSmiableCall_entrypoint_offset = 16;
 static constexpr dart::compiler::target::word WeakProperty_key_offset = 8;
 static constexpr dart::compiler::target::word WeakProperty_value_offset = 16;
+static constexpr dart::compiler::target::word WeakReference_target_offset = 8;
+static constexpr dart::compiler::target::word
+    WeakReference_type_arguments_offset = 16;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
@@ -6830,6 +6877,7 @@
 static constexpr dart::compiler::target::word UnwindError_InstanceSize = 24;
 static constexpr dart::compiler::target::word UserTag_InstanceSize = 32;
 static constexpr dart::compiler::target::word WeakProperty_InstanceSize = 32;
+static constexpr dart::compiler::target::word WeakReference_InstanceSize = 32;
 static constexpr dart::compiler::target::word
     WeakSerializationReference_InstanceSize = 24;
 #endif  // defined(TARGET_ARCH_ARM64) && !defined(DART_COMPRESSED_POINTERS)
@@ -7302,6 +7350,9 @@
     MonomorphicSmiableCall_entrypoint_offset = 16;
 static constexpr dart::compiler::target::word WeakProperty_key_offset = 8;
 static constexpr dart::compiler::target::word WeakProperty_value_offset = 12;
+static constexpr dart::compiler::target::word WeakReference_target_offset = 8;
+static constexpr dart::compiler::target::word
+    WeakReference_type_arguments_offset = 12;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
@@ -7396,6 +7447,7 @@
 static constexpr dart::compiler::target::word UnwindError_InstanceSize = 16;
 static constexpr dart::compiler::target::word UserTag_InstanceSize = 32;
 static constexpr dart::compiler::target::word WeakProperty_InstanceSize = 24;
+static constexpr dart::compiler::target::word WeakReference_InstanceSize = 24;
 static constexpr dart::compiler::target::word
     WeakSerializationReference_InstanceSize = 16;
 #endif  // defined(TARGET_ARCH_X64) && defined(DART_COMPRESSED_POINTERS)
@@ -7868,6 +7920,9 @@
     MonomorphicSmiableCall_entrypoint_offset = 16;
 static constexpr dart::compiler::target::word WeakProperty_key_offset = 8;
 static constexpr dart::compiler::target::word WeakProperty_value_offset = 12;
+static constexpr dart::compiler::target::word WeakReference_target_offset = 8;
+static constexpr dart::compiler::target::word
+    WeakReference_type_arguments_offset = 12;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
@@ -7963,6 +8018,7 @@
 static constexpr dart::compiler::target::word UnwindError_InstanceSize = 16;
 static constexpr dart::compiler::target::word UserTag_InstanceSize = 32;
 static constexpr dart::compiler::target::word WeakProperty_InstanceSize = 24;
+static constexpr dart::compiler::target::word WeakReference_InstanceSize = 24;
 static constexpr dart::compiler::target::word
     WeakSerializationReference_InstanceSize = 16;
 #endif  // defined(TARGET_ARCH_ARM64) && defined(DART_COMPRESSED_POINTERS)
@@ -8429,6 +8485,9 @@
     MonomorphicSmiableCall_entrypoint_offset = 8;
 static constexpr dart::compiler::target::word WeakProperty_key_offset = 4;
 static constexpr dart::compiler::target::word WeakProperty_value_offset = 8;
+static constexpr dart::compiler::target::word WeakReference_target_offset = 4;
+static constexpr dart::compiler::target::word
+    WeakReference_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     4, 12, 8, 16};
 static constexpr dart::compiler::target::word
@@ -8523,6 +8582,7 @@
 static constexpr dart::compiler::target::word UnwindError_InstanceSize = 12;
 static constexpr dart::compiler::target::word UserTag_InstanceSize = 16;
 static constexpr dart::compiler::target::word WeakProperty_InstanceSize = 16;
+static constexpr dart::compiler::target::word WeakReference_InstanceSize = 16;
 static constexpr dart::compiler::target::word
     WeakSerializationReference_InstanceSize = 12;
 #endif  // defined(TARGET_ARCH_RISCV32) && !defined(DART_COMPRESSED_POINTERS)
@@ -8998,6 +9058,9 @@
     MonomorphicSmiableCall_entrypoint_offset = 16;
 static constexpr dart::compiler::target::word WeakProperty_key_offset = 8;
 static constexpr dart::compiler::target::word WeakProperty_value_offset = 16;
+static constexpr dart::compiler::target::word WeakReference_target_offset = 8;
+static constexpr dart::compiler::target::word
+    WeakReference_type_arguments_offset = 16;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
@@ -9093,6 +9156,7 @@
 static constexpr dart::compiler::target::word UnwindError_InstanceSize = 24;
 static constexpr dart::compiler::target::word UserTag_InstanceSize = 32;
 static constexpr dart::compiler::target::word WeakProperty_InstanceSize = 32;
+static constexpr dart::compiler::target::word WeakReference_InstanceSize = 32;
 static constexpr dart::compiler::target::word
     WeakSerializationReference_InstanceSize = 24;
 #endif  // defined(TARGET_ARCH_RISCV64) && !defined(DART_COMPRESSED_POINTERS)
@@ -9620,6 +9684,10 @@
     AOT_MonomorphicSmiableCall_entrypoint_offset = 8;
 static constexpr dart::compiler::target::word AOT_WeakProperty_key_offset = 4;
 static constexpr dart::compiler::target::word AOT_WeakProperty_value_offset = 8;
+static constexpr dart::compiler::target::word AOT_WeakReference_target_offset =
+    4;
+static constexpr dart::compiler::target::word
+    AOT_WeakReference_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word AOT_Code_entry_point_offset[] = {
     4, 12, 8, 16};
 static constexpr dart::compiler::target::word
@@ -9727,6 +9795,8 @@
 static constexpr dart::compiler::target::word AOT_UserTag_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_WeakProperty_InstanceSize =
     16;
+static constexpr dart::compiler::target::word AOT_WeakReference_InstanceSize =
+    16;
 static constexpr dart::compiler::target::word
     AOT_WeakSerializationReference_InstanceSize = 12;
 #endif  // defined(TARGET_ARCH_ARM) && !defined(DART_COMPRESSED_POINTERS)
@@ -10253,6 +10323,10 @@
 static constexpr dart::compiler::target::word AOT_WeakProperty_key_offset = 8;
 static constexpr dart::compiler::target::word AOT_WeakProperty_value_offset =
     16;
+static constexpr dart::compiler::target::word AOT_WeakReference_target_offset =
+    8;
+static constexpr dart::compiler::target::word
+    AOT_WeakReference_type_arguments_offset = 16;
 static constexpr dart::compiler::target::word AOT_Code_entry_point_offset[] = {
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
@@ -10361,6 +10435,8 @@
 static constexpr dart::compiler::target::word AOT_UserTag_InstanceSize = 32;
 static constexpr dart::compiler::target::word AOT_WeakProperty_InstanceSize =
     32;
+static constexpr dart::compiler::target::word AOT_WeakReference_InstanceSize =
+    32;
 static constexpr dart::compiler::target::word
     AOT_WeakSerializationReference_InstanceSize = 24;
 #endif  // defined(TARGET_ARCH_X64) && !defined(DART_COMPRESSED_POINTERS)
@@ -10890,6 +10966,10 @@
 static constexpr dart::compiler::target::word AOT_WeakProperty_key_offset = 8;
 static constexpr dart::compiler::target::word AOT_WeakProperty_value_offset =
     16;
+static constexpr dart::compiler::target::word AOT_WeakReference_target_offset =
+    8;
+static constexpr dart::compiler::target::word
+    AOT_WeakReference_type_arguments_offset = 16;
 static constexpr dart::compiler::target::word AOT_Code_entry_point_offset[] = {
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
@@ -10999,6 +11079,8 @@
 static constexpr dart::compiler::target::word AOT_UserTag_InstanceSize = 32;
 static constexpr dart::compiler::target::word AOT_WeakProperty_InstanceSize =
     32;
+static constexpr dart::compiler::target::word AOT_WeakReference_InstanceSize =
+    32;
 static constexpr dart::compiler::target::word
     AOT_WeakSerializationReference_InstanceSize = 24;
 #endif  // defined(TARGET_ARCH_ARM64) && !defined(DART_COMPRESSED_POINTERS)
@@ -11524,6 +11606,10 @@
 static constexpr dart::compiler::target::word AOT_WeakProperty_key_offset = 8;
 static constexpr dart::compiler::target::word AOT_WeakProperty_value_offset =
     12;
+static constexpr dart::compiler::target::word AOT_WeakReference_target_offset =
+    8;
+static constexpr dart::compiler::target::word
+    AOT_WeakReference_type_arguments_offset = 12;
 static constexpr dart::compiler::target::word AOT_Code_entry_point_offset[] = {
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
@@ -11632,6 +11718,8 @@
 static constexpr dart::compiler::target::word AOT_UserTag_InstanceSize = 32;
 static constexpr dart::compiler::target::word AOT_WeakProperty_InstanceSize =
     24;
+static constexpr dart::compiler::target::word AOT_WeakReference_InstanceSize =
+    24;
 static constexpr dart::compiler::target::word
     AOT_WeakSerializationReference_InstanceSize = 16;
 #endif  // defined(TARGET_ARCH_X64) && defined(DART_COMPRESSED_POINTERS)
@@ -12157,6 +12245,10 @@
 static constexpr dart::compiler::target::word AOT_WeakProperty_key_offset = 8;
 static constexpr dart::compiler::target::word AOT_WeakProperty_value_offset =
     12;
+static constexpr dart::compiler::target::word AOT_WeakReference_target_offset =
+    8;
+static constexpr dart::compiler::target::word
+    AOT_WeakReference_type_arguments_offset = 12;
 static constexpr dart::compiler::target::word AOT_Code_entry_point_offset[] = {
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
@@ -12266,6 +12358,8 @@
 static constexpr dart::compiler::target::word AOT_UserTag_InstanceSize = 32;
 static constexpr dart::compiler::target::word AOT_WeakProperty_InstanceSize =
     24;
+static constexpr dart::compiler::target::word AOT_WeakReference_InstanceSize =
+    24;
 static constexpr dart::compiler::target::word
     AOT_WeakSerializationReference_InstanceSize = 16;
 #endif  // defined(TARGET_ARCH_ARM64) && defined(DART_COMPRESSED_POINTERS)
@@ -12789,6 +12883,10 @@
     AOT_MonomorphicSmiableCall_entrypoint_offset = 8;
 static constexpr dart::compiler::target::word AOT_WeakProperty_key_offset = 4;
 static constexpr dart::compiler::target::word AOT_WeakProperty_value_offset = 8;
+static constexpr dart::compiler::target::word AOT_WeakReference_target_offset =
+    4;
+static constexpr dart::compiler::target::word
+    AOT_WeakReference_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word AOT_Code_entry_point_offset[] = {
     4, 12, 8, 16};
 static constexpr dart::compiler::target::word
@@ -12898,6 +12996,8 @@
 static constexpr dart::compiler::target::word AOT_UserTag_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_WeakProperty_InstanceSize =
     16;
+static constexpr dart::compiler::target::word AOT_WeakReference_InstanceSize =
+    16;
 static constexpr dart::compiler::target::word
     AOT_WeakSerializationReference_InstanceSize = 12;
 #endif  // defined(TARGET_ARCH_RISCV32) && !defined(DART_COMPRESSED_POINTERS)
@@ -13424,6 +13524,10 @@
 static constexpr dart::compiler::target::word AOT_WeakProperty_key_offset = 8;
 static constexpr dart::compiler::target::word AOT_WeakProperty_value_offset =
     16;
+static constexpr dart::compiler::target::word AOT_WeakReference_target_offset =
+    8;
+static constexpr dart::compiler::target::word
+    AOT_WeakReference_type_arguments_offset = 16;
 static constexpr dart::compiler::target::word AOT_Code_entry_point_offset[] = {
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
@@ -13533,6 +13637,8 @@
 static constexpr dart::compiler::target::word AOT_UserTag_InstanceSize = 32;
 static constexpr dart::compiler::target::word AOT_WeakProperty_InstanceSize =
     32;
+static constexpr dart::compiler::target::word AOT_WeakReference_InstanceSize =
+    32;
 static constexpr dart::compiler::target::word
     AOT_WeakSerializationReference_InstanceSize = 24;
 #endif  // defined(TARGET_ARCH_RISCV64) && !defined(DART_COMPRESSED_POINTERS)
@@ -14051,6 +14157,10 @@
     AOT_MonomorphicSmiableCall_entrypoint_offset = 8;
 static constexpr dart::compiler::target::word AOT_WeakProperty_key_offset = 4;
 static constexpr dart::compiler::target::word AOT_WeakProperty_value_offset = 8;
+static constexpr dart::compiler::target::word AOT_WeakReference_target_offset =
+    4;
+static constexpr dart::compiler::target::word
+    AOT_WeakReference_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word AOT_Code_entry_point_offset[] = {
     4, 12, 8, 16};
 static constexpr dart::compiler::target::word
@@ -14158,6 +14268,8 @@
 static constexpr dart::compiler::target::word AOT_UserTag_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_WeakProperty_InstanceSize =
     16;
+static constexpr dart::compiler::target::word AOT_WeakReference_InstanceSize =
+    16;
 static constexpr dart::compiler::target::word
     AOT_WeakSerializationReference_InstanceSize = 12;
 #endif  // defined(TARGET_ARCH_ARM) && !defined(DART_COMPRESSED_POINTERS)
@@ -14677,6 +14789,10 @@
 static constexpr dart::compiler::target::word AOT_WeakProperty_key_offset = 8;
 static constexpr dart::compiler::target::word AOT_WeakProperty_value_offset =
     16;
+static constexpr dart::compiler::target::word AOT_WeakReference_target_offset =
+    8;
+static constexpr dart::compiler::target::word
+    AOT_WeakReference_type_arguments_offset = 16;
 static constexpr dart::compiler::target::word AOT_Code_entry_point_offset[] = {
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
@@ -14785,6 +14901,8 @@
 static constexpr dart::compiler::target::word AOT_UserTag_InstanceSize = 32;
 static constexpr dart::compiler::target::word AOT_WeakProperty_InstanceSize =
     32;
+static constexpr dart::compiler::target::word AOT_WeakReference_InstanceSize =
+    32;
 static constexpr dart::compiler::target::word
     AOT_WeakSerializationReference_InstanceSize = 24;
 #endif  // defined(TARGET_ARCH_X64) && !defined(DART_COMPRESSED_POINTERS)
@@ -15307,6 +15425,10 @@
 static constexpr dart::compiler::target::word AOT_WeakProperty_key_offset = 8;
 static constexpr dart::compiler::target::word AOT_WeakProperty_value_offset =
     16;
+static constexpr dart::compiler::target::word AOT_WeakReference_target_offset =
+    8;
+static constexpr dart::compiler::target::word
+    AOT_WeakReference_type_arguments_offset = 16;
 static constexpr dart::compiler::target::word AOT_Code_entry_point_offset[] = {
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
@@ -15416,6 +15538,8 @@
 static constexpr dart::compiler::target::word AOT_UserTag_InstanceSize = 32;
 static constexpr dart::compiler::target::word AOT_WeakProperty_InstanceSize =
     32;
+static constexpr dart::compiler::target::word AOT_WeakReference_InstanceSize =
+    32;
 static constexpr dart::compiler::target::word
     AOT_WeakSerializationReference_InstanceSize = 24;
 #endif  // defined(TARGET_ARCH_ARM64) && !defined(DART_COMPRESSED_POINTERS)
@@ -15934,6 +16058,10 @@
 static constexpr dart::compiler::target::word AOT_WeakProperty_key_offset = 8;
 static constexpr dart::compiler::target::word AOT_WeakProperty_value_offset =
     12;
+static constexpr dart::compiler::target::word AOT_WeakReference_target_offset =
+    8;
+static constexpr dart::compiler::target::word
+    AOT_WeakReference_type_arguments_offset = 12;
 static constexpr dart::compiler::target::word AOT_Code_entry_point_offset[] = {
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
@@ -16042,6 +16170,8 @@
 static constexpr dart::compiler::target::word AOT_UserTag_InstanceSize = 32;
 static constexpr dart::compiler::target::word AOT_WeakProperty_InstanceSize =
     24;
+static constexpr dart::compiler::target::word AOT_WeakReference_InstanceSize =
+    24;
 static constexpr dart::compiler::target::word
     AOT_WeakSerializationReference_InstanceSize = 16;
 #endif  // defined(TARGET_ARCH_X64) && defined(DART_COMPRESSED_POINTERS)
@@ -16560,6 +16690,10 @@
 static constexpr dart::compiler::target::word AOT_WeakProperty_key_offset = 8;
 static constexpr dart::compiler::target::word AOT_WeakProperty_value_offset =
     12;
+static constexpr dart::compiler::target::word AOT_WeakReference_target_offset =
+    8;
+static constexpr dart::compiler::target::word
+    AOT_WeakReference_type_arguments_offset = 12;
 static constexpr dart::compiler::target::word AOT_Code_entry_point_offset[] = {
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
@@ -16669,6 +16803,8 @@
 static constexpr dart::compiler::target::word AOT_UserTag_InstanceSize = 32;
 static constexpr dart::compiler::target::word AOT_WeakProperty_InstanceSize =
     24;
+static constexpr dart::compiler::target::word AOT_WeakReference_InstanceSize =
+    24;
 static constexpr dart::compiler::target::word
     AOT_WeakSerializationReference_InstanceSize = 16;
 #endif  // defined(TARGET_ARCH_ARM64) && defined(DART_COMPRESSED_POINTERS)
@@ -17185,6 +17321,10 @@
     AOT_MonomorphicSmiableCall_entrypoint_offset = 8;
 static constexpr dart::compiler::target::word AOT_WeakProperty_key_offset = 4;
 static constexpr dart::compiler::target::word AOT_WeakProperty_value_offset = 8;
+static constexpr dart::compiler::target::word AOT_WeakReference_target_offset =
+    4;
+static constexpr dart::compiler::target::word
+    AOT_WeakReference_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word AOT_Code_entry_point_offset[] = {
     4, 12, 8, 16};
 static constexpr dart::compiler::target::word
@@ -17294,6 +17434,8 @@
 static constexpr dart::compiler::target::word AOT_UserTag_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_WeakProperty_InstanceSize =
     16;
+static constexpr dart::compiler::target::word AOT_WeakReference_InstanceSize =
+    16;
 static constexpr dart::compiler::target::word
     AOT_WeakSerializationReference_InstanceSize = 12;
 #endif  // defined(TARGET_ARCH_RISCV32) && !defined(DART_COMPRESSED_POINTERS)
@@ -17813,6 +17955,10 @@
 static constexpr dart::compiler::target::word AOT_WeakProperty_key_offset = 8;
 static constexpr dart::compiler::target::word AOT_WeakProperty_value_offset =
     16;
+static constexpr dart::compiler::target::word AOT_WeakReference_target_offset =
+    8;
+static constexpr dart::compiler::target::word
+    AOT_WeakReference_type_arguments_offset = 16;
 static constexpr dart::compiler::target::word AOT_Code_entry_point_offset[] = {
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
@@ -17922,6 +18068,8 @@
 static constexpr dart::compiler::target::word AOT_UserTag_InstanceSize = 32;
 static constexpr dart::compiler::target::word AOT_WeakProperty_InstanceSize =
     32;
+static constexpr dart::compiler::target::word AOT_WeakReference_InstanceSize =
+    32;
 static constexpr dart::compiler::target::word
     AOT_WeakSerializationReference_InstanceSize = 24;
 #endif  // defined(TARGET_ARCH_RISCV64) && !defined(DART_COMPRESSED_POINTERS)
diff --git a/runtime/vm/compiler/runtime_offsets_list.h b/runtime/vm/compiler/runtime_offsets_list.h
index 0d36d9b..cbd470c 100644
--- a/runtime/vm/compiler/runtime_offsets_list.h
+++ b/runtime/vm/compiler/runtime_offsets_list.h
@@ -332,6 +332,8 @@
   FIELD(MonomorphicSmiableCall, entrypoint_offset)                             \
   FIELD(WeakProperty, key_offset)                                              \
   FIELD(WeakProperty, value_offset)                                            \
+  FIELD(WeakReference, target_offset)                                          \
+  FIELD(WeakReference, type_arguments_offset)                                  \
   RANGE(Code, entry_point_offset, CodeEntryKind, CodeEntryKind::kNormal,       \
         CodeEntryKind::kMonomorphicUnchecked,                                  \
         [](CodeEntryKind value) { return true; })                              \
@@ -413,6 +415,7 @@
   SIZEOF(UnwindError, InstanceSize, UntaggedUnwindError)                       \
   SIZEOF(UserTag, InstanceSize, UntaggedUserTag)                               \
   SIZEOF(WeakProperty, InstanceSize, UntaggedWeakProperty)                     \
+  SIZEOF(WeakReference, InstanceSize, UntaggedWeakReference)                   \
   SIZEOF(WeakSerializationReference, InstanceSize,                             \
          UntaggedWeakSerializationReference)                                   \
   PAYLOAD_SIZEOF(CodeSourceMap, InstanceSize, HeaderSize)                      \
diff --git a/runtime/vm/heap/marker.cc b/runtime/vm/heap/marker.cc
index adbaab4..3309815 100644
--- a/runtime/vm/heap/marker.cc
+++ b/runtime/vm/heap/marker.cc
@@ -35,13 +35,16 @@
         work_list_(marking_stack),
         deferred_work_list_(deferred_marking_stack),
         delayed_weak_properties_(WeakProperty::null()),
-        tail_(WeakProperty::null()),
+        delayed_weak_properties_tail_(WeakProperty::null()),
+        delayed_weak_references_(WeakReference::null()),
+        delayed_weak_references_tail_(WeakReference::null()),
         marked_bytes_(0),
         marked_micros_(0) {
     ASSERT(thread_->isolate_group() == isolate_group);
   }
   ~MarkingVisitorBase() {
     ASSERT(delayed_weak_properties_ == WeakProperty::null());
+    ASSERT(delayed_weak_references_ == WeakReference::null());
   }
 
   uintptr_t marked_bytes() const { return marked_bytes_; }
@@ -51,7 +54,8 @@
   bool ProcessPendingWeakProperties() {
     bool more_to_mark = false;
     WeakPropertyPtr cur_weak = delayed_weak_properties_;
-    tail_ = delayed_weak_properties_ = WeakProperty::null();
+    delayed_weak_properties_tail_ = delayed_weak_properties_ =
+        WeakProperty::null();
     while (cur_weak != WeakProperty::null()) {
       WeakPropertyPtr next_weak =
           cur_weak->untag()->next_.Decompress(cur_weak->heap_base());
@@ -115,11 +119,14 @@
         const intptr_t class_id = raw_obj->GetClassId();
 
         intptr_t size;
-        if (class_id != kWeakPropertyCid) {
-          size = raw_obj->untag()->VisitPointersNonvirtual(this);
-        } else {
+        if (class_id == kWeakPropertyCid) {
           WeakPropertyPtr raw_weak = static_cast<WeakPropertyPtr>(raw_obj);
-          size = ProcessWeakProperty(raw_weak, /* did_mark */ true);
+          size = ProcessWeakProperty(raw_weak);
+        } else if (class_id == kWeakReferenceCid) {
+          WeakReferencePtr raw_weak = static_cast<WeakReferencePtr>(raw_obj);
+          size = ProcessWeakReference(raw_weak);
+        } else {
+          size = raw_obj->untag()->VisitPointersNonvirtual(this);
         }
         marked_bytes_ += size;
         remaining_budget -= size;
@@ -184,12 +191,26 @@
            CompressedWeakPropertyPtr(WeakProperty::null()));
     raw_weak->untag()->next_ = delayed_weak_properties_;
     if (delayed_weak_properties_ == WeakProperty::null()) {
-      tail_ = raw_weak;
+      delayed_weak_properties_tail_ = raw_weak;
     }
     delayed_weak_properties_ = raw_weak;
   }
 
-  intptr_t ProcessWeakProperty(WeakPropertyPtr raw_weak, bool did_mark) {
+  void EnqueueWeakReference(WeakReferencePtr raw_weak) {
+    ASSERT(raw_weak->IsHeapObject());
+    ASSERT(raw_weak->IsOldObject());
+    ASSERT(raw_weak->IsWeakReference());
+    ASSERT(raw_weak->untag()->IsMarked());
+    ASSERT(raw_weak->untag()->next_ ==
+           CompressedWeakReferencePtr(WeakReference::null()));
+    raw_weak->untag()->next_ = delayed_weak_references_;
+    if (delayed_weak_references_ == WeakReference::null()) {
+      delayed_weak_references_tail_ = raw_weak;
+    }
+    delayed_weak_references_ = raw_weak;
+  }
+
+  intptr_t ProcessWeakProperty(WeakPropertyPtr raw_weak) {
     // The fate of the weak property is determined by its key.
     ObjectPtr raw_key =
         LoadCompressedPointerIgnoreRace(&raw_weak->untag()->key_)
@@ -197,15 +218,33 @@
     if (raw_key->IsHeapObject() && raw_key->IsOldObject() &&
         !raw_key->untag()->IsMarked()) {
       // Key was white. Enqueue the weak property.
-      if (did_mark) {
-        EnqueueWeakProperty(raw_weak);
-      }
+      EnqueueWeakProperty(raw_weak);
       return raw_weak->untag()->HeapSize();
     }
     // Key is gray or black. Make the weak property black.
     return raw_weak->untag()->VisitPointersNonvirtual(this);
   }
 
+  intptr_t ProcessWeakReference(WeakReferencePtr raw_weak) {
+    // The fate of the target field is determined by the target.
+    // The type arguments always stay alive.
+    ObjectPtr raw_target =
+        LoadCompressedPointerIgnoreRace(&raw_weak->untag()->target_)
+            .Decompress(raw_weak->heap_base());
+    if (raw_target->IsHeapObject() && raw_target->IsOldObject() &&
+        !raw_target->untag()->IsMarked()) {
+      // Target was white. Enqueue the weak reference. It is potentially dead.
+      // It might still be made alive by weak properties in next rounds.
+      EnqueueWeakReference(raw_weak);
+    }
+    // Always visit the type argument.
+    ObjectPtr raw_type_arguments =
+        LoadCompressedPointerIgnoreRace(&raw_weak->untag()->type_arguments_)
+            .Decompress(raw_weak->heap_base());
+    MarkObject(raw_type_arguments);
+    return raw_weak->untag()->HeapSize();
+  }
+
   void ProcessDeferredMarking() {
     ObjectPtr raw_obj;
     while ((raw_obj = deferred_work_list_.Pop()) != nullptr) {
@@ -226,11 +265,10 @@
       // encounters it during ordinary marking. This is in the same spirit as
       // the eliminated write barrier, which would have added the newly written
       // key and value to the ordinary marking stack.
-      bool did_mark = TryAcquireMarkBit(raw_obj);
       intptr_t size = raw_obj->untag()->VisitPointersNonvirtual(this);
       // Add the size only if we win the marking race to prevent
       // double-counting.
-      if (did_mark) {
+      if (TryAcquireMarkBit(raw_obj)) {
         marked_bytes_ += size;
       }
     }
@@ -256,34 +294,73 @@
     }
   }
 
+  void MournWeakReferences() {
+    WeakReferencePtr cur_weak = delayed_weak_references_;
+    delayed_weak_references_ = WeakReference::null();
+    while (cur_weak != WeakReference::null()) {
+      WeakReferencePtr next_weak =
+          cur_weak->untag()->next_.Decompress(cur_weak->heap_base());
+      cur_weak->untag()->next_ = WeakReference::null();
+      // If we did not mark the target through a weak property in a later round,
+      // then the target is dead and we should clear it.
+      if (!cur_weak->untag()->target()->untag()->IsMarked()) {
+        WeakReference::Clear(cur_weak);
+      }
+      cur_weak = next_weak;
+    }
+  }
+
   bool WaitForWork(RelaxedAtomic<uintptr_t>* num_busy) {
     return work_list_.WaitForWork(num_busy);
   }
 
-  void Flush(WeakPropertyPtr* head, WeakPropertyPtr* tail) {
+  void Flush(WeakPropertyPtr* weak_properties_head,
+             WeakPropertyPtr* weak_properties_tail,
+             WeakReferencePtr* weak_references_head,
+             WeakReferencePtr* weak_references_tail) {
     work_list_.Flush();
     deferred_work_list_.Flush();
-    if (*head == WeakProperty::null()) {
-      *head = delayed_weak_properties_;
-      *tail = tail_;
+
+    if (*weak_properties_head == WeakProperty::null()) {
+      *weak_properties_head = delayed_weak_properties_;
+      *weak_properties_tail = delayed_weak_properties_tail_;
     } else {
-      (*tail)->untag()->next_ = delayed_weak_properties_;
-      *tail = tail_;
+      (*weak_properties_tail)->untag()->next_ = delayed_weak_properties_;
+      *weak_properties_tail = delayed_weak_properties_tail_;
     }
-    tail_ = delayed_weak_properties_ = WeakProperty::null();
+    delayed_weak_properties_tail_ = delayed_weak_properties_ =
+        WeakProperty::null();
+
+    if (*weak_references_head == WeakReference::null()) {
+      *weak_references_head = delayed_weak_references_;
+      *weak_references_tail = delayed_weak_references_tail_;
+    } else {
+      (*weak_references_tail)->untag()->next_ = delayed_weak_references_;
+      *weak_references_tail = delayed_weak_references_tail_;
+    }
+    delayed_weak_references_tail_ = delayed_weak_references_ =
+        WeakReference::null();
   }
 
-  void Adopt(WeakPropertyPtr head, WeakPropertyPtr tail) {
+  void Adopt(WeakPropertyPtr weak_properties_head,
+             WeakPropertyPtr weak_properties_tail,
+             WeakReferencePtr weak_references_head,
+             WeakReferencePtr weak_references_tail) {
     ASSERT(delayed_weak_properties_ == WeakProperty::null());
-    ASSERT(tail_ == WeakProperty::null());
-    delayed_weak_properties_ = head;
-    tail_ = tail;
+    ASSERT(delayed_weak_properties_tail_ == WeakProperty::null());
+    ASSERT(delayed_weak_references_ == WeakReference::null());
+    ASSERT(delayed_weak_references_tail_ == WeakReference::null());
+    delayed_weak_properties_ = weak_properties_head;
+    delayed_weak_properties_tail_ = weak_properties_tail;
+    delayed_weak_references_ = weak_references_head;
+    delayed_weak_references_tail_ = weak_references_tail;
   }
 
   void AbandonWork() {
     work_list_.AbandonWork();
     deferred_work_list_.AbandonWork();
     delayed_weak_properties_ = WeakProperty::null();
+    delayed_weak_references_ = WeakReference::null();
   }
 
  private:
@@ -354,7 +431,9 @@
   MarkerWorkList work_list_;
   MarkerWorkList deferred_work_list_;
   WeakPropertyPtr delayed_weak_properties_;
-  WeakPropertyPtr tail_;
+  WeakPropertyPtr delayed_weak_properties_tail_;
+  WeakReferencePtr delayed_weak_references_;
+  WeakReferencePtr delayed_weak_references_tail_;
   uintptr_t marked_bytes_;
   int64_t marked_micros_;
 
@@ -666,6 +745,7 @@
 
       // Phase 3: Weak processing and statistics.
       visitor_->MournWeakProperties();
+      visitor_->MournWeakReferences();
       marker_->IterateWeakRoots(thread);
       int64_t stop = OS::GetCurrentMonotonicMicros();
       visitor_->AddMicros(stop - start);
@@ -903,6 +983,7 @@
       visitor.ProcessDeferredMarking();
       visitor.FinalizeMarking();
       visitor.MournWeakProperties();
+      visitor.MournWeakReferences();
       IterateWeakRoots(thread);
       // All marking done; detach code, etc.
       int64_t stop = OS::GetCurrentMonotonicMicros();
@@ -917,8 +998,10 @@
       RelaxedAtomic<uintptr_t> num_busy = 0;
       // Phase 1: Iterate over roots and drain marking stack in tasks.
 
-      WeakPropertyPtr head = WeakProperty::null();
-      WeakPropertyPtr tail = WeakProperty::null();
+      WeakPropertyPtr weak_properties_head = WeakProperty::null();
+      WeakPropertyPtr weak_properties_tail = WeakProperty::null();
+      WeakReferencePtr weak_references_head = WeakReference::null();
+      WeakReferencePtr weak_references_tail = WeakReference::null();
 
       for (intptr_t i = 0; i < num_tasks; ++i) {
         SyncMarkingVisitor* visitor = visitors_[i];
@@ -934,7 +1017,8 @@
         // visitor might not get to run if it fails to reach TryEnter soon
         // enough, and we must fail to visit objects but they're sitting in
         // such a visitor's local blocks.
-        visitor->Flush(&head, &tail);
+        visitor->Flush(&weak_properties_head, &weak_properties_tail,
+                       &weak_references_head, &weak_references_tail);
         // Need to move weak property list too.
 
         if (i < (num_tasks - 1)) {
@@ -945,7 +1029,8 @@
           ASSERT(result);
         } else {
           // Last worker is the main thread.
-          visitor->Adopt(head, tail);
+          visitor->Adopt(weak_properties_head, weak_properties_tail,
+                         weak_references_head, weak_references_tail);
           ParallelMarkTask task(this, isolate_group_, &marking_stack_, barrier,
                                 visitor, &num_busy);
           task.RunEnteredIsolateGroup();
diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc
index 8c736b2..bed2610 100644
--- a/runtime/vm/heap/scavenger.cc
+++ b/runtime/vm/heap/scavenger.cc
@@ -132,9 +132,11 @@
         bytes_promoted_(0),
         visiting_old_object_(nullptr),
         promoted_list_(promotion_stack),
-        delayed_weak_properties_(WeakProperty::null()) {}
+        delayed_weak_properties_(WeakProperty::null()),
+        delayed_weak_references_(WeakReference::null()) {}
   ~ScavengerVisitorBase() {
     ASSERT(delayed_weak_properties_ == WeakProperty::null());
+    ASSERT(delayed_weak_references_ == WeakReference::null());
   }
 
   virtual void VisitTypedDataViewPointers(TypedDataViewPtr view,
@@ -180,8 +182,13 @@
     if (!parallel) {
       const uword td_header = ReadHeaderRelaxed(td);
       ASSERT(!IsForwarding(td_header) || td->IsOldObject());
-
-      ASSERT_EQUAL(IsExternalTypedDataClassId(td->GetClassId()), is_external);
+      if (td != Object::null()) {
+        // Fast object copy temporarily stores null in the typed_data field of
+        // views. This can cause the RecomputeDataFieldForInternalTypedData to
+        // run inappropriately, but when the object copy continues it will fix
+        // the data_ pointer.
+        ASSERT_EQUAL(IsExternalTypedDataClassId(td->GetClassId()), is_external);
+      }
     }
 #endif
 
@@ -291,6 +298,7 @@
       }
 
       MournWeakProperties();
+      MournOrUpdateWeakReferences();
     }
     page_space_->ReleaseLock(freelist_);
     thread_ = nullptr;
@@ -301,6 +309,7 @@
   void AbandonWork() {
     promoted_list_.AbandonWork();
     delayed_weak_properties_ = WeakProperty::null();
+    delayed_weak_references_ = WeakReference::null();
   }
 
   NewPage* head() const { return head_; }
@@ -503,7 +512,9 @@
   DART_FORCE_INLINE intptr_t ProcessCopied(ObjectPtr raw_obj);
   inline void ProcessPromotedList();
   inline void EnqueueWeakProperty(WeakPropertyPtr raw_weak);
+  inline void EnqueueWeakReference(WeakReferencePtr raw_weak);
   inline void MournWeakProperties();
+  inline void MournOrUpdateWeakReferences();
 
   Thread* thread_;
   Scavenger* scavenger_;
@@ -515,6 +526,7 @@
 
   PromotionWorkList promoted_list_;
   WeakPropertyPtr delayed_weak_properties_;
+  WeakReferencePtr delayed_weak_references_;
 
   NewPage* head_ = nullptr;
   NewPage* tail_ = nullptr;  // Allocating from here.
@@ -1382,13 +1394,29 @@
 }
 
 template <bool parallel>
+void ScavengerVisitorBase<parallel>::EnqueueWeakReference(
+    WeakReferencePtr raw_weak) {
+  ASSERT(raw_weak->IsHeapObject());
+  ASSERT(raw_weak->IsNewObject());
+  ASSERT(raw_weak->IsWeakReference());
+#if defined(DEBUG)
+  uword header = ReadHeaderRelaxed(raw_weak);
+  ASSERT(!IsForwarding(header));
+#endif  // defined(DEBUG)
+  ASSERT(raw_weak->untag()->next_ ==
+         CompressedWeakReferencePtr(WeakReference::null()));
+  raw_weak->untag()->next_ = delayed_weak_references_;
+  delayed_weak_references_ = raw_weak;
+}
+
+template <bool parallel>
 intptr_t ScavengerVisitorBase<parallel>::ProcessCopied(ObjectPtr raw_obj) {
   intptr_t class_id = raw_obj->GetClassId();
   if (UNLIKELY(class_id == kWeakPropertyCid)) {
     WeakPropertyPtr raw_weak = static_cast<WeakPropertyPtr>(raw_obj);
     // The fate of the weak property is determined by its key.
     ObjectPtr raw_key = raw_weak->untag()->key();
-    if (raw_key->IsHeapObject() && raw_key->IsNewObject()) {
+    if (!raw_key->IsSmiOrOldObject()) {
       uword header = ReadHeaderRelaxed(raw_key);
       if (!IsForwarding(header)) {
         // Key is white.  Enqueue the weak property.
@@ -1397,6 +1425,25 @@
       }
     }
     // Key is gray or black.  Make the weak property black.
+  } else if (UNLIKELY(class_id == kWeakReferenceCid)) {
+    WeakReferencePtr raw_weak = static_cast<WeakReferencePtr>(raw_obj);
+    // The fate of the weak reference target is determined by its target.
+    ObjectPtr raw_target = raw_weak->untag()->target();
+    if (!raw_target->IsSmiOrOldObject()) {
+      uword header = ReadHeaderRelaxed(raw_target);
+      if (!IsForwarding(header)) {
+        // Target is white. Enqueue the weak reference. Always visit type
+        // arguments.
+        EnqueueWeakReference(raw_weak);
+#if !defined(DART_COMPRESSED_POINTERS)
+        ScavengePointer(&raw_weak->untag()->type_arguments_);
+#else
+        ScavengeCompressedPointer(raw_weak->heap_base(),
+                                  &raw_weak->untag()->type_arguments_);
+#endif
+        return raw_weak->untag()->HeapSize();
+      }
+    }
   }
   return raw_obj->untag()->VisitPointersNonvirtual(this);
 }
@@ -1484,6 +1531,37 @@
   }
 }
 
+template <bool parallel>
+void ScavengerVisitorBase<parallel>::MournOrUpdateWeakReferences() {
+  ASSERT(!scavenger_->abort_);
+
+  // The queued weak references at this point either should have their target
+  // updated or should be cleared.
+  WeakReferencePtr cur_weak = delayed_weak_references_;
+  delayed_weak_references_ = WeakReference::null();
+  while (cur_weak != WeakReference::null()) {
+    WeakReferencePtr next_weak =
+        cur_weak->untag()->next_.Decompress(cur_weak->heap_base());
+    // Reset the next pointer in the weak reference.
+    cur_weak->untag()->next_ = WeakReference::null();
+
+    ObjectPtr raw_target = cur_weak->untag()->target();
+    uword raw_addr = UntaggedObject::ToAddr(raw_target);
+    uword header = *reinterpret_cast<uword*>(raw_addr);
+    if (IsForwarding(header)) {
+      // Get the new location of the object.
+      cur_weak->untag()->target_ = ForwardedObj(header);
+    } else {
+      ASSERT(raw_target->IsHeapObject());
+      ASSERT(raw_target->IsNewObject());
+      WeakReference::Clear(cur_weak);
+    }
+
+    // Advance to next weak reference in the queue.
+    cur_weak = next_weak;
+  }
+}
+
 void Scavenger::VisitObjectPointers(ObjectPointerVisitor* visitor) const {
   ASSERT(Thread::Current()->IsAtSafepoint() ||
          (Thread::Current()->task_kind() == Thread::kMarkerTask) ||
diff --git a/runtime/vm/message_snapshot.cc b/runtime/vm/message_snapshot.cc
index afc2bc3..22de126 100644
--- a/runtime/vm/message_snapshot.cc
+++ b/runtime/vm/message_snapshot.cc
@@ -502,7 +502,7 @@
   }
 
   void WriteNodes(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     s->WriteUnsigned(count);
     Library& lib = Library::Handle(s->zone());
     String& str = String::Handle(s->zone());
@@ -597,7 +597,7 @@
   }
 
   void WriteNodes(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     s->WriteUnsigned(count);
     for (intptr_t i = 0; i < count; i++) {
       TypeArguments* type_args = objects_[i];
@@ -608,7 +608,7 @@
   }
 
   void WriteEdges(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     for (intptr_t i = 0; i < count; i++) {
       TypeArguments* type_args = objects_[i];
       intptr_t hash = Smi::Value(type_args->untag()->hash());
@@ -637,7 +637,7 @@
   ~TypeArgumentsMessageDeserializationCluster() {}
 
   void ReadNodes(MessageDeserializer* d) {
-    intptr_t count = d->ReadUnsigned();
+    const intptr_t count = d->ReadUnsigned();
     for (intptr_t i = 0; i < count; i++) {
       intptr_t length = d->ReadUnsigned();
       d->AssignRef(TypeArguments::New(length));
@@ -705,7 +705,7 @@
   }
 
   void WriteNodes(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     s->WriteUnsigned(count);
     Library& lib = Library::Handle(s->zone());
     Class& cls = Class::Handle(s->zone());
@@ -736,7 +736,7 @@
   ~FunctionMessageDeserializationCluster() {}
 
   void ReadNodes(MessageDeserializer* d) {
-    intptr_t count = d->ReadUnsigned();
+    const intptr_t count = d->ReadUnsigned();
     String& str = String::Handle(d->zone());
     Library& lib = Library::Handle(d->zone());
     Class& cls = Class::Handle(d->zone());
@@ -810,7 +810,7 @@
   }
 
   void WriteEdges(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     for (intptr_t i = 0; i < count; i++) {
       Instance* instance = objects_[i];
 
@@ -964,7 +964,7 @@
   }
 
   void WriteNodes(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     s->WriteUnsigned(count);
     for (intptr_t i = 0; i < count; i++) {
       Type* type = objects_[i];
@@ -973,7 +973,7 @@
   }
 
   void WriteEdges(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     for (intptr_t i = 0; i < count; i++) {
       Type* type = objects_[i];
       s->WriteRef(type->type_class());
@@ -993,7 +993,7 @@
   ~TypeMessageDeserializationCluster() {}
 
   void ReadNodes(MessageDeserializer* d) {
-    intptr_t count = d->ReadUnsigned();
+    const intptr_t count = d->ReadUnsigned();
     for (intptr_t i = 0; i < count; i++) {
       d->AssignRef(Type::New());
     }
@@ -1050,7 +1050,7 @@
   }
 
   void WriteNodes(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     s->WriteUnsigned(count);
     for (intptr_t i = 0; i < count; i++) {
       TypeRef* type = objects_[i];
@@ -1059,7 +1059,7 @@
   }
 
   void WriteEdges(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     for (intptr_t i = 0; i < count; i++) {
       TypeRef* type = objects_[i];
       s->WriteRef(type->type());
@@ -1078,7 +1078,7 @@
   ~TypeRefMessageDeserializationCluster() {}
 
   void ReadNodes(MessageDeserializer* d) {
-    intptr_t count = d->ReadUnsigned();
+    const intptr_t count = d->ReadUnsigned();
     for (intptr_t i = 0; i < count; i++) {
       d->AssignRef(TypeRef::New());
     }
@@ -1150,7 +1150,7 @@
   }
 
   void WriteNodes(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     s->WriteUnsigned(count);
     for (intptr_t i = 0; i < count; i++) {
       Closure* closure = objects_[i];
@@ -1214,7 +1214,7 @@
   }
 
   void WriteNodes(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     s->WriteUnsigned(count);
     for (intptr_t i = 0; i < count; i++) {
       Smi* smi = static_cast<Smi*>(objects_[i]);
@@ -1250,7 +1250,7 @@
   ~SmiMessageDeserializationCluster() {}
 
   void ReadNodes(MessageDeserializer* d) {
-    intptr_t count = d->ReadUnsigned();
+    const intptr_t count = d->ReadUnsigned();
     for (intptr_t i = 0; i < count; i++) {
       d->AssignRef(Smi::New(d->Read<intptr_t>()));
     }
@@ -1289,7 +1289,7 @@
   }
 
   void WriteNodes(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     s->WriteUnsigned(count);
     for (intptr_t i = 0; i < count; i++) {
       Mint* mint = static_cast<Mint*>(objects_[i]);
@@ -1325,7 +1325,7 @@
   ~MintMessageDeserializationCluster() {}
 
   void ReadNodes(MessageDeserializer* d) {
-    intptr_t count = d->ReadUnsigned();
+    const intptr_t count = d->ReadUnsigned();
     for (intptr_t i = 0; i < count; i++) {
       int64_t value = d->Read<int64_t>();
       d->AssignRef(is_canonical() ? Mint::NewCanonical(value)
@@ -1367,7 +1367,7 @@
   }
 
   void WriteNodes(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     s->WriteUnsigned(count);
     for (intptr_t i = 0; i < count; i++) {
       Double* dbl = objects_[i];
@@ -1402,7 +1402,7 @@
   ~DoubleMessageDeserializationCluster() {}
 
   void ReadNodes(MessageDeserializer* d) {
-    intptr_t count = d->ReadUnsigned();
+    const intptr_t count = d->ReadUnsigned();
     for (intptr_t i = 0; i < count; i++) {
       double value = d->Read<double>();
       d->AssignRef(is_canonical() ? Double::NewCanonical(value)
@@ -1440,7 +1440,7 @@
   }
 
   void WriteNodes(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     s->WriteUnsigned(count);
     for (intptr_t i = 0; i < count; i++) {
       GrowableObjectArray* array = objects_[i];
@@ -1450,7 +1450,7 @@
   }
 
   void WriteEdges(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     for (intptr_t i = 0; i < count; i++) {
       GrowableObjectArray* array = objects_[i];
       s->WriteRef(array->GetTypeArguments());
@@ -1472,7 +1472,7 @@
   ~GrowableObjectArrayMessageDeserializationCluster() {}
 
   void ReadNodes(MessageDeserializer* d) {
-    intptr_t count = d->ReadUnsigned();
+    const intptr_t count = d->ReadUnsigned();
     GrowableObjectArray& array = GrowableObjectArray::Handle(d->zone());
     for (intptr_t i = 0; i < count; i++) {
       intptr_t length = d->ReadUnsigned();
@@ -1876,7 +1876,7 @@
   ~NativePointerMessageDeserializationCluster() {}
 
   void ReadNodes(MessageDeserializer* d) {
-    intptr_t count = d->ReadUnsigned();
+    const intptr_t count = d->ReadUnsigned();
     for (intptr_t i = 0; i < count; i++) {
       FinalizableData finalizable_data = d->finalizable_data()->Take();
       intptr_t ptr = reinterpret_cast<intptr_t>(finalizable_data.data);
@@ -1910,7 +1910,7 @@
   }
 
   void WriteNodes(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     s->WriteUnsigned(count);
     for (intptr_t i = 0; i < count; i++) {
       TypedDataView* view = objects_[i];
@@ -1919,7 +1919,7 @@
   }
 
   void WriteEdges(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     for (intptr_t i = 0; i < count; i++) {
       TypedDataView* view = objects_[i];
       s->WriteRef(view->untag()->length());
@@ -1940,7 +1940,7 @@
   ~TypedDataViewMessageDeserializationCluster() {}
 
   void ReadNodes(MessageDeserializer* d) {
-    intptr_t count = d->ReadUnsigned();
+    const intptr_t count = d->ReadUnsigned();
     for (intptr_t i = 0; i < count; i++) {
       d->AssignRef(TypedDataView::New(cid_));
     }
@@ -2083,7 +2083,7 @@
   }
 
   void WriteNodes(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     s->WriteUnsigned(count);
     for (intptr_t i = 0; i < count; i++) {
       TransferableTypedData* transferable = objects_[i];
@@ -2125,7 +2125,7 @@
   ~TransferableTypedDataMessageDeserializationCluster() {}
 
   void ReadNodes(MessageDeserializer* d) {
-    intptr_t count = d->ReadUnsigned();
+    const intptr_t count = d->ReadUnsigned();
     for (intptr_t i = 0; i < count; i++) {
       intptr_t length = d->ReadUnsigned();
       const FinalizableData finalizable_data = d->finalizable_data()->Take();
@@ -2159,7 +2159,7 @@
   void Trace(MessageSerializer* s, Object* object) { objects_.Add(object); }
 
   void WriteNodes(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     s->WriteUnsigned(count);
     for (intptr_t i = 0; i < count; i++) {
       Object* vector = objects_[i];
@@ -2183,7 +2183,7 @@
   ~Simd128MessageDeserializationCluster() {}
 
   void ReadNodes(MessageDeserializer* d) {
-    intptr_t count = d->ReadUnsigned();
+    const intptr_t count = d->ReadUnsigned();
     for (intptr_t i = 0; i < count; i++) {
       ASSERT_EQUAL(Int32x4::InstanceSize(), Float32x4::InstanceSize());
       ASSERT_EQUAL(Int32x4::InstanceSize(), Float64x2::InstanceSize());
@@ -2219,7 +2219,7 @@
   }
 
   void WriteNodes(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     s->WriteUnsigned(count);
     for (intptr_t i = 0; i < count; i++) {
       RegExp* regexp = objects_[i];
@@ -2275,7 +2275,7 @@
   }
 
   void WriteNodes(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     s->WriteUnsigned(count);
     for (intptr_t i = 0; i < count; i++) {
       SendPort* port = objects_[i];
@@ -2312,7 +2312,7 @@
   ~SendPortMessageDeserializationCluster() {}
 
   void ReadNodes(MessageDeserializer* d) {
-    intptr_t count = d->ReadUnsigned();
+    const intptr_t count = d->ReadUnsigned();
     for (intptr_t i = 0; i < count; i++) {
       Dart_Port id = d->Read<Dart_Port>();
       Dart_Port origin_id = d->Read<Dart_Port>();
@@ -2347,7 +2347,7 @@
   }
 
   void WriteNodes(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     s->WriteUnsigned(count);
     for (intptr_t i = 0; i < count; i++) {
       Capability* cap = objects_[i];
@@ -2382,7 +2382,7 @@
   ~CapabilityMessageDeserializationCluster() {}
 
   void ReadNodes(MessageDeserializer* d) {
-    intptr_t count = d->ReadUnsigned();
+    const intptr_t count = d->ReadUnsigned();
     for (intptr_t i = 0; i < count; i++) {
       uint64_t id = d->Read<uint64_t>();
       d->AssignRef(Capability::New(id));
@@ -2423,7 +2423,7 @@
   }
 
   void WriteNodes(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     s->WriteUnsigned(count);
     for (intptr_t i = 0; i < count; i++) {
       WeakProperty* property = objects_[i];
@@ -2432,7 +2432,7 @@
   }
 
   void WriteEdges(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     for (intptr_t i = 0; i < count; i++) {
       WeakProperty* property = objects_[i];
       if (s->HasRef(property->untag()->key())) {
@@ -2457,7 +2457,7 @@
   ~WeakPropertyMessageDeserializationCluster() {}
 
   void ReadNodes(MessageDeserializer* d) {
-    intptr_t count = d->ReadUnsigned();
+    const intptr_t count = d->ReadUnsigned();
     for (intptr_t i = 0; i < count; i++) {
       d->AssignRef(WeakProperty::New());
     }
@@ -2473,6 +2473,73 @@
   }
 };
 
+class WeakReferenceMessageSerializationCluster
+    : public MessageSerializationCluster {
+ public:
+  WeakReferenceMessageSerializationCluster()
+      : MessageSerializationCluster("WeakReference",
+                                    MessagePhase::kNonCanonicalInstances,
+                                    kWeakReferenceCid) {}
+  ~WeakReferenceMessageSerializationCluster() {}
+
+  void Trace(MessageSerializer* s, Object* object) {
+    WeakReference* reference = static_cast<WeakReference*>(object);
+    objects_.Add(reference);
+
+    s->Push(reference->untag()->type_arguments());
+  }
+
+  void WriteNodes(MessageSerializer* s) {
+    const intptr_t count = objects_.length();
+    s->WriteUnsigned(count);
+    for (intptr_t i = 0; i < count; i++) {
+      WeakReference* reference = objects_[i];
+      s->AssignRef(reference);
+    }
+  }
+
+  void WriteEdges(MessageSerializer* s) {
+    const intptr_t count = objects_.length();
+    for (intptr_t i = 0; i < count; i++) {
+      WeakReference* reference = objects_[i];
+      if (s->HasRef(reference->untag()->target())) {
+        s->WriteRef(reference->untag()->target());
+      } else {
+        s->WriteRef(Object::null());
+      }
+      s->WriteRef(reference->untag()->type_arguments());
+    }
+  }
+
+ private:
+  GrowableArray<WeakReference*> objects_;
+};
+
+class WeakReferenceMessageDeserializationCluster
+    : public MessageDeserializationCluster {
+ public:
+  WeakReferenceMessageDeserializationCluster()
+      : MessageDeserializationCluster("WeakReference") {}
+  ~WeakReferenceMessageDeserializationCluster() {}
+
+  void ReadNodes(MessageDeserializer* d) {
+    const intptr_t count = d->ReadUnsigned();
+    for (intptr_t i = 0; i < count; i++) {
+      d->AssignRef(WeakReference::New());
+    }
+  }
+
+  void ReadEdges(MessageDeserializer* d) {
+    ASSERT(!is_canonical());  // Never canonical.
+    for (intptr_t id = start_index_; id < stop_index_; id++) {
+      WeakReferencePtr reference = static_cast<WeakReferencePtr>(d->Ref(id));
+      reference->untag()->set_target(d->ReadRef());
+      reference->untag()->set_type_arguments(
+          static_cast<TypeArgumentsPtr>(d->ReadRef()));
+    }
+  }
+};
+
 class LinkedHashMapMessageSerializationCluster
     : public MessageSerializationCluster {
  public:
@@ -2498,7 +2565,7 @@
   }
 
   void WriteNodes(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     s->WriteUnsigned(count);
     for (intptr_t i = 0; i < count; i++) {
       LinkedHashMap* map = objects_[i];
@@ -2507,7 +2574,7 @@
   }
 
   void WriteEdges(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     for (intptr_t i = 0; i < count; i++) {
       LinkedHashMap* map = objects_[i];
       s->WriteRef(map->untag()->type_arguments());
@@ -2529,7 +2596,7 @@
   ~LinkedHashMapMessageDeserializationCluster() {}
 
   void ReadNodes(MessageDeserializer* d) {
-    intptr_t count = d->ReadUnsigned();
+    const intptr_t count = d->ReadUnsigned();
     for (intptr_t i = 0; i < count; i++) {
       d->AssignRef(LinkedHashMap::NewUninitialized(cid_));
     }
@@ -2594,7 +2661,7 @@
   }
 
   void WriteNodes(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     s->WriteUnsigned(count);
     for (intptr_t i = 0; i < count; i++) {
       LinkedHashSet* map = objects_[i];
@@ -2603,7 +2670,7 @@
   }
 
   void WriteEdges(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     for (intptr_t i = 0; i < count; i++) {
       LinkedHashSet* map = objects_[i];
       s->WriteRef(map->untag()->type_arguments());
@@ -2625,7 +2692,7 @@
   ~LinkedHashSetMessageDeserializationCluster() {}
 
   void ReadNodes(MessageDeserializer* d) {
-    intptr_t count = d->ReadUnsigned();
+    const intptr_t count = d->ReadUnsigned();
     for (intptr_t i = 0; i < count; i++) {
       d->AssignRef(LinkedHashSet::NewUninitialized(cid_));
     }
@@ -2689,7 +2756,7 @@
   }
 
   void WriteNodes(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     s->WriteUnsigned(count);
     for (intptr_t i = 0; i < count; i++) {
       Array* array = objects_[i];
@@ -2700,7 +2767,7 @@
   }
 
   void WriteEdges(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     for (intptr_t i = 0; i < count; i++) {
       Array* array = objects_[i];
       intptr_t length = array->Length();
@@ -2753,7 +2820,7 @@
   ~ArrayMessageDeserializationCluster() {}
 
   void ReadNodes(MessageDeserializer* d) {
-    intptr_t count = d->ReadUnsigned();
+    const intptr_t count = d->ReadUnsigned();
     for (intptr_t i = 0; i < count; i++) {
       intptr_t length = d->ReadUnsigned();
       d->AssignRef(Array::New(cid_, length));
@@ -2834,7 +2901,7 @@
   }
 
   void WriteNodes(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     s->WriteUnsigned(count);
     for (intptr_t i = 0; i < count; i++) {
       String* str = objects_[i];
@@ -2886,7 +2953,7 @@
   ~OneByteStringMessageDeserializationCluster() {}
 
   void ReadNodes(MessageDeserializer* d) {
-    intptr_t count = d->ReadUnsigned();
+    const intptr_t count = d->ReadUnsigned();
     for (intptr_t i = 0; i < count; i++) {
       intptr_t length = d->ReadUnsigned();
       const uint8_t* data = d->CurrentBufferAddress();
@@ -2940,7 +3007,7 @@
   }
 
   void WriteNodes(MessageSerializer* s) {
-    intptr_t count = objects_.length();
+    const intptr_t count = objects_.length();
     s->WriteUnsigned(count);
     for (intptr_t i = 0; i < count; i++) {
       String* str = objects_[i];
@@ -2995,7 +3062,7 @@
   ~TwoByteStringMessageDeserializationCluster() {}
 
   void ReadNodes(MessageDeserializer* d) {
-    intptr_t count = d->ReadUnsigned();
+    const intptr_t count = d->ReadUnsigned();
     for (intptr_t i = 0; i < count; i++) {
       intptr_t length = d->ReadUnsigned();
       const uint16_t* data =
@@ -3414,6 +3481,8 @@
     case kWeakPropertyCid:
       ephemeron_cluster_ = new (Z) WeakPropertyMessageSerializationCluster();
       return ephemeron_cluster_;
+    case kWeakReferenceCid:
+      return new (Z) WeakReferenceMessageSerializationCluster();
     case kLinkedHashMapCid:
     case kImmutableLinkedHashMapCid:
       return new (Z)
@@ -3513,6 +3582,9 @@
     case kWeakPropertyCid:
       ASSERT(!is_canonical);
       return new (Z) WeakPropertyMessageDeserializationCluster();
+    case kWeakReferenceCid:
+      ASSERT(!is_canonical);
+      return new (Z) WeakReferenceMessageDeserializationCluster();
     case kLinkedHashMapCid:
     case kImmutableLinkedHashMapCid:
       return new (Z)
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index ba3ba97..e1ce95a 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -1935,6 +1935,14 @@
     object_store->set_weak_property_class(cls);
     RegisterPrivateClass(cls, Symbols::_WeakProperty(), core_lib);
 
+    cls = Class::New<WeakReference, RTN::WeakReference>(isolate_group);
+    cls.set_type_arguments_field_offset(
+        WeakReference::type_arguments_offset(),
+        RTN::WeakReference::type_arguments_offset());
+    cls.set_num_type_arguments_unsafe(1);
+    object_store->set_weak_reference_class(cls);
+    RegisterPrivateClass(cls, Symbols::_WeakReferenceImpl(), core_lib);
+
     // Pre-register the mirrors library so we can place the vm class
     // MirrorReference there rather than the core library.
     lib = Library::LookupLibrary(thread, Symbols::DartMirrors());
@@ -2498,6 +2506,8 @@
 
     cls = Class::New<WeakProperty, RTN::WeakProperty>(isolate_group);
     object_store->set_weak_property_class(cls);
+    cls = Class::New<WeakReference, RTN::WeakReference>(isolate_group);
+    object_store->set_weak_reference_class(cls);
 
     cls = Class::New<MirrorReference, RTN::MirrorReference>(isolate_group);
     cls = Class::New<UserTag, RTN::UserTag>(isolate_group);
@@ -25875,6 +25885,22 @@
   return "_WeakProperty";
 }
 
+WeakReferencePtr WeakReference::New(Heap::Space space) {
+  ASSERT(IsolateGroup::Current()->object_store()->weak_reference_class() !=
+         Class::null());
+  ObjectPtr raw =
+      Object::Allocate(WeakReference::kClassId, WeakReference::InstanceSize(),
+                       space, WeakReference::ContainsCompressedPointers());
+  return static_cast<WeakReferencePtr>(raw);
+}
+
+const char* WeakReference::ToCString() const {
+  TypeArguments& type_args = TypeArguments::Handle(GetTypeArguments());
+  String& type_args_name = String::Handle(type_args.UserVisibleName());
+  return OS::SCreate(Thread::Current()->zone(), "WeakReference%s",
+                     type_args_name.ToCString());
+}
+
 AbstractTypePtr MirrorReference::GetAbstractTypeReferent() const {
   ASSERT(Object::Handle(referent()).IsAbstractType());
   return AbstractType::Cast(Object::Handle(referent())).ptr();
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 8497df0..25d7a8e 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -12001,6 +12001,38 @@
   friend class Class;
 };
 
+class WeakReference : public Instance {
+ public:
+  ObjectPtr target() const { return untag()->target(); }
+  void set_target(const Object& target) const {
+    untag()->set_target(target.ptr());
+  }
+  static intptr_t target_offset() {
+    return OFFSET_OF(UntaggedWeakReference, target_);
+  }
+
+  static intptr_t type_arguments_offset() {
+    return OFFSET_OF(UntaggedWeakReference, type_arguments_);
+  }
+
+  static WeakReferencePtr New(Heap::Space space = Heap::kNew);
+
+  static intptr_t InstanceSize() {
+    return RoundedAllocationSize(sizeof(UntaggedWeakReference));
+  }
+
+  static void Clear(WeakReferencePtr raw_weak) {
+    ASSERT(raw_weak->untag()->next_ ==
+           CompressedWeakReferencePtr(WeakReference::null()));
+    // This action is performed by the GC. No barrier.
+    raw_weak->untag()->target_ = Object::null();
+  }
+
+ private:
+  FINAL_HEAP_OBJECT_IMPLEMENTATION(WeakReference, Instance);
+  friend class Class;
+};
+
 class MirrorReference : public Instance {
  public:
   ObjectPtr referent() const { return untag()->referent(); }
diff --git a/runtime/vm/object_graph_copy.cc b/runtime/vm/object_graph_copy.cc
index d348aec..0eeb88c 100644
--- a/runtime/vm/object_graph_copy.cc
+++ b/runtime/vm/object_graph_copy.cc
@@ -393,6 +393,9 @@
     raw_transferables_from_to_.Add(to);
   }
   void AddWeakProperty(WeakPropertyPtr from) { raw_weak_properties_.Add(from); }
+  void AddWeakReference(WeakReferencePtr from) {
+    raw_weak_references_.Add(from);
+  }
   void AddExternalTypedData(ExternalTypedDataPtr to) {
     raw_external_typed_data_to_.Add(to);
   }
@@ -410,6 +413,7 @@
   GrowableArray<ObjectPtr> raw_objects_to_rehash_;
   GrowableArray<ObjectPtr> raw_expandos_to_rehash_;
   GrowableArray<WeakPropertyPtr> raw_weak_properties_;
+  GrowableArray<WeakReferencePtr> raw_weak_references_;
   intptr_t fill_cursor_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(FastForwardMap);
@@ -450,6 +454,9 @@
   void AddWeakProperty(const WeakProperty& from) {
     weak_properties_.Add(&WeakProperty::Handle(from.ptr()));
   }
+  void AddWeakReference(const WeakReference& from) {
+    weak_references_.Add(&WeakReference::Handle(from.ptr()));
+  }
   void AddExternalTypedData(ExternalTypedDataPtr to) {
     external_typed_data_.Add(&ExternalTypedData::Handle(to));
   }
@@ -485,6 +492,7 @@
   GrowableArray<const Object*> objects_to_rehash_;
   GrowableArray<const Object*> expandos_to_rehash_;
   GrowableArray<const WeakProperty*> weak_properties_;
+  GrowableArray<const WeakReference*> weak_references_;
   intptr_t fill_cursor_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(SlowForwardMap);
@@ -740,6 +748,9 @@
   void EnqueueWeakProperty(WeakPropertyPtr from) {
     fast_forward_map_.AddWeakProperty(from);
   }
+  void EnqueueWeakReference(WeakReferencePtr from) {
+    fast_forward_map_.AddWeakReference(from);
+  }
   void EnqueueObjectToRehash(ObjectPtr to) {
     fast_forward_map_.AddObjectToRehash(to);
   }
@@ -937,6 +948,9 @@
   void EnqueueWeakProperty(const WeakProperty& from) {
     slow_forward_map_.AddWeakProperty(from);
   }
+  void EnqueueWeakReference(const WeakReference& from) {
+    slow_forward_map_.AddWeakReference(from);
+  }
   void EnqueueObjectToRehash(const Object& to) {
     slow_forward_map_.AddObjectToRehash(to);
   }
@@ -1346,9 +1360,31 @@
     Base::StoreCompressedPointerNoBarrier(
         Types::GetWeakPropertyPtr(to), OFFSET_OF(UntaggedWeakProperty, value_),
         Object::null());
+    // To satisfy some ASSERT()s in GC we'll use Object:null() explicitly here.
+    Base::StoreCompressedPointerNoBarrier(
+        Types::GetWeakPropertyPtr(to), OFFSET_OF(UntaggedWeakProperty, next_),
+        Object::null());
     Base::EnqueueWeakProperty(from);
   }
 
+  void CopyWeakReference(typename Types::WeakReference from,
+                         typename Types::WeakReference to) {
+    // We store `null` as target and let the main algorithm know that
+    // we should check reachability of the target again after the fixpoint (if
+    // it became reachable, forward the target).
+    Base::StoreCompressedPointerNoBarrier(
+        Types::GetWeakReferencePtr(to),
+        OFFSET_OF(UntaggedWeakReference, target_), Object::null());
+    // Type argument should always be copied.
+    Base::ForwardCompressedPointer(
+        from, to, OFFSET_OF(UntaggedWeakReference, type_arguments_));
+    // To satisfy some ASSERT()s in GC we'll use Object:null() explicitly here.
+    Base::StoreCompressedPointerNoBarrier(
+        Types::GetWeakReferencePtr(to), OFFSET_OF(UntaggedWeakReference, next_),
+        Object::null());
+    Base::EnqueueWeakReference(from);
+  }
+
 #define DEFINE_UNSUPPORTED(clazz)                                              \
   void Copy##clazz(typename Types::clazz from, typename Types::clazz to) {     \
     FATAL("Objects of type " #clazz " should not occur in object graphs");     \
@@ -1437,6 +1473,25 @@
         i++;
       }
     }
+    // After the fix point with [WeakProperty]s do [WeakReference]s.
+    auto& from_weak_reference = WeakReference::Handle(zone_);
+    auto& to_weak_reference = WeakReference::Handle(zone_);
+    auto& weak_reference_target = Object::Handle(zone_);
+    auto& weak_references = fast_forward_map_.raw_weak_references_;
+    for (intptr_t i = 0; i < weak_references.length(); i++) {
+      from_weak_reference = weak_references[i];
+      weak_reference_target =
+          fast_forward_map_.ForwardedObject(from_weak_reference.target());
+      if (weak_reference_target.ptr() != Marker()) {
+        to_weak_reference ^=
+            fast_forward_map_.ForwardedObject(from_weak_reference.ptr());
+
+        // The target became reachable so we'll change the forwarded
+        // [WeakReference]'s target to the new target (it is `null` at this
+        // point).
+        to_weak_reference.set_target(weak_reference_target);
+      }
+    }
     if (root_copy != Marker()) {
       ObjectPtr array;
       array = TryBuildArrayOfObjectsToRehash(
@@ -1586,6 +1641,23 @@
       }
     }
 
+    // After the fix point with [WeakProperty]s do [WeakReference]s.
+    WeakReference& weak_reference = WeakReference::Handle(Z);
+    auto& weak_references = slow_forward_map_.weak_references_;
+    for (intptr_t i = 0; i < weak_references.length(); i++) {
+      const auto& from_weak_reference = *weak_references[i];
+      to = slow_forward_map_.ForwardedObject(from_weak_reference.target());
+      if (to.ptr() != Marker()) {
+        weak_reference ^=
+            slow_forward_map_.ForwardedObject(from_weak_reference.ptr());
+
+        // The target became reachable so we'll change the forwarded
+        // [WeakReference]'s target to the new target (it is `null` at this
+        // point).
+        weak_reference.set_target(to);
+      }
+    }
+
     objects_to_rehash_ =
         BuildArrayOfObjectsToRehash(slow_forward_map_.objects_to_rehash_);
     expandos_to_rehash_ =
@@ -1779,6 +1851,7 @@
     MakeUninitializedNewSpaceObjectsGCSafe();
     HandlifyTransferables();
     HandlifyWeakProperties();
+    HandlifyWeakReferences();
     HandlifyExternalTypedData();
     HandlifyObjectsToReHash();
     HandlifyExpandosToReHash();
@@ -1816,6 +1889,10 @@
     Handlify(&fast_object_copy_.fast_forward_map_.raw_weak_properties_,
              &slow_object_copy_.slow_forward_map_.weak_properties_);
   }
+  void HandlifyWeakReferences() {
+    Handlify(&fast_object_copy_.fast_forward_map_.raw_weak_references_,
+             &slow_object_copy_.slow_forward_map_.weak_references_);
+  }
   void HandlifyExternalTypedData() {
     Handlify(&fast_object_copy_.fast_forward_map_.raw_external_typed_data_to_,
              &slow_object_copy_.slow_forward_map_.external_typed_data_);
diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc
index d24df33..210f508 100644
--- a/runtime/vm/object_service.cc
+++ b/runtime/vm/object_service.cc
@@ -1687,6 +1687,19 @@
   jsobj.AddProperty("propertyValue", value_handle);
 }
 
+void WeakReference::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  PrintSharedInstanceJSON(&jsobj, ref);
+  jsobj.AddProperty("kind", "WeakReference");
+  jsobj.AddServiceId(*this);
+  if (ref) {
+    return;
+  }
+
+  const Object& target_handle = Object::Handle(target());
+  jsobj.AddProperty("target", target_handle);
+}
+
 void MirrorReference::PrintJSONImpl(JSONStream* stream, bool ref) const {
   JSONObject jsobj(stream);
   PrintSharedInstanceJSON(&jsobj, ref);
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index 896c01b..b8eaf21 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -124,6 +124,7 @@
   RW(Class, error_class)                                                       \
   RW(Class, expando_class)                                                     \
   RW(Class, weak_property_class)                                               \
+  RW(Class, weak_reference_class)                                              \
   ARW_AR(Array, symbol_table)                                                  \
   RW(Array, canonical_types)                                                   \
   RW(Array, canonical_function_types)                                          \
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index b2dce5c..1578f69 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -3857,6 +3857,130 @@
   EXPECT(weak2.value() == Object::null());
 }
 
+static void WeakReference_PreserveOne(Thread* thread, Heap::Space space) {
+  auto& weak = WeakReference::Handle();
+  const auto& target = String::Handle(OneByteString::New("target", space));
+  {
+    HANDLESCOPE(thread);
+    ObjectStore* object_store = thread->isolate_group()->object_store();
+    const auto& type_arguments =
+        TypeArguments::Handle(object_store->type_argument_double());
+    weak ^= WeakReference::New(space);
+    weak.set_target(target);
+    weak.SetTypeArguments(type_arguments);
+  }
+  GCTestHelper::CollectAllGarbage();
+  EXPECT(weak.target() != Object::null());
+  EXPECT(weak.GetTypeArguments() != Object::null());
+}
+
+ISOLATE_UNIT_TEST_CASE(WeakReference_PreserveOne_NewSpace) {
+  WeakReference_PreserveOne(thread, Heap::kNew);
+}
+
+ISOLATE_UNIT_TEST_CASE(WeakReference_PreserveOne_OldSpace) {
+  WeakReference_PreserveOne(thread, Heap::kOld);
+}
+
+static void WeakReference_ClearOne(Thread* thread, Heap::Space space) {
+  auto& weak = WeakReference::Handle();
+  {
+    HANDLESCOPE(thread);
+    const auto& target = String::Handle(OneByteString::New("target", space));
+    ObjectStore* object_store = thread->isolate_group()->object_store();
+    const auto& type_arguments =
+        TypeArguments::Handle(object_store->type_argument_double());
+    weak ^= WeakReference::New(space);
+    weak.set_target(target);
+    weak.SetTypeArguments(type_arguments);
+  }
+  GCTestHelper::CollectAllGarbage();
+  EXPECT(weak.target() == Object::null());
+  EXPECT(weak.GetTypeArguments() != Object::null());
+}
+
+ISOLATE_UNIT_TEST_CASE(WeakReference_ClearOne_NewSpace) {
+  WeakReference_ClearOne(thread, Heap::kNew);
+}
+
+ISOLATE_UNIT_TEST_CASE(WeakReference_ClearOne_OldSpace) {
+  WeakReference_ClearOne(thread, Heap::kOld);
+}
+
+static void WeakReference_Clear_ReachableThroughWeakProperty(
+    Thread* thread,
+    Heap::Space space) {
+  auto& weak_property = WeakProperty::Handle();
+  const auto& key = String::Handle(OneByteString::New("key", space));
+  {
+    HANDLESCOPE(thread);
+    ObjectStore* object_store = thread->isolate_group()->object_store();
+    const auto& type_arguments =
+        TypeArguments::Handle(object_store->type_argument_double());
+    const auto& weak_reference =
+        WeakReference::Handle(WeakReference::New(space));
+    const auto& target = String::Handle(OneByteString::New("target", space));
+    weak_reference.set_target(target);
+    weak_reference.SetTypeArguments(type_arguments);
+
+    weak_property ^= WeakProperty::New(space);
+    weak_property.set_key(key);
+    weak_property.set_value(weak_reference);
+  }
+  GCTestHelper::CollectAllGarbage();
+  const auto& weak_reference =
+      WeakReference::CheckedHandle(Z, weak_property.value());
+  EXPECT(weak_reference.target() == Object::null());
+  EXPECT(weak_reference.GetTypeArguments() != Object::null());
+}
+
+ISOLATE_UNIT_TEST_CASE(
+    WeakReference_Clear_ReachableThroughWeakProperty_NewSpace) {
+  WeakReference_Clear_ReachableThroughWeakProperty(thread, Heap::kNew);
+}
+
+ISOLATE_UNIT_TEST_CASE(
+    WeakReference_Clear_ReachableThroughWeakProperty_OldSpace) {
+  WeakReference_Clear_ReachableThroughWeakProperty(thread, Heap::kOld);
+}
+
+static void WeakReference_Preserve_ReachableThroughWeakProperty(
+    Thread* thread,
+    Heap::Space space) {
+  auto& weak_property = WeakProperty::Handle();
+  const auto& key = String::Handle(OneByteString::New("key", space));
+  const auto& target = String::Handle(OneByteString::New("target", space));
+  {
+    HANDLESCOPE(thread);
+    ObjectStore* object_store = thread->isolate_group()->object_store();
+    const auto& type_arguments =
+        TypeArguments::Handle(object_store->type_argument_double());
+    const auto& weak_reference =
+        WeakReference::Handle(WeakReference::New(space));
+    weak_reference.set_target(target);
+    weak_reference.SetTypeArguments(type_arguments);
+
+    weak_property ^= WeakProperty::New(space);
+    weak_property.set_key(key);
+    weak_property.set_value(weak_reference);
+  }
+  GCTestHelper::CollectAllGarbage();
+  const auto& weak_reference =
+      WeakReference::CheckedHandle(Z, weak_property.value());
+  EXPECT(weak_reference.target() != Object::null());
+  EXPECT(weak_reference.GetTypeArguments() != Object::null());
+}
+
+ISOLATE_UNIT_TEST_CASE(
+    WeakReference_Preserve_ReachableThroughWeakProperty_NewSpace) {
+  WeakReference_Preserve_ReachableThroughWeakProperty(thread, Heap::kNew);
+}
+
+ISOLATE_UNIT_TEST_CASE(
+    WeakReference_Preserve_ReachableThroughWeakProperty_OldSpace) {
+  WeakReference_Preserve_ReachableThroughWeakProperty(thread, Heap::kOld);
+}
+
 ISOLATE_UNIT_TEST_CASE(MirrorReference) {
   const MirrorReference& reference =
       MirrorReference::Handle(MirrorReference::New(Object::Handle()));
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index c32aa1e..eb83d68 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -551,6 +551,7 @@
 COMPRESSED_VISITOR(StackTrace)
 COMPRESSED_VISITOR(RegExp)
 COMPRESSED_VISITOR(WeakProperty)
+COMPRESSED_VISITOR(WeakReference)
 COMPRESSED_VISITOR(MirrorReference)
 COMPRESSED_VISITOR(UserTag)
 REGULAR_VISITOR(SubtypeTestCache)
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index ff0a766..5a084c5 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -3285,6 +3285,29 @@
   friend class SlowObjectCopy;  // For OFFSET_OF
 };
 
+class UntaggedWeakReference : public UntaggedInstance {
+  RAW_HEAP_OBJECT_IMPLEMENTATION(WeakReference);
+
+  COMPRESSED_POINTER_FIELD(ObjectPtr, target)
+  VISIT_FROM(target)
+  COMPRESSED_POINTER_FIELD(TypeArgumentsPtr, type_arguments)
+  VISIT_TO(type_arguments)
+  CompressedObjectPtr* to_snapshot(Snapshot::Kind kind) { return to(); }
+
+  // Linked list is chaining all pending weak properties. Not visited by
+  // pointer visitors.
+  CompressedWeakReferencePtr next_;
+
+  friend class GCMarker;
+  template <bool>
+  friend class MarkingVisitorBase;
+  friend class Scavenger;
+  template <bool>
+  friend class ScavengerVisitorBase;
+  friend class FastObjectCopy;  // For OFFSET_OF
+  friend class SlowObjectCopy;  // For OFFSET_OF
+};
+
 // MirrorReferences are used by mirrors to hold reflectees that are VM
 // internal objects, such as libraries, classes, functions or types.
 class UntaggedMirrorReference : public UntaggedInstance {
diff --git a/runtime/vm/raw_object_fields.cc b/runtime/vm/raw_object_fields.cc
index 9fcc4d2..49bae77 100644
--- a/runtime/vm/raw_object_fields.cc
+++ b/runtime/vm/raw_object_fields.cc
@@ -193,6 +193,8 @@
   F(RegExp, external_two_byte_sticky_)                                         \
   F(WeakProperty, key_)                                                        \
   F(WeakProperty, value_)                                                      \
+  F(WeakReference, target_)                                                    \
+  F(WeakReference, type_arguments_)                                            \
   F(MirrorReference, referent_)                                                \
   F(UserTag, label_)                                                           \
   F(PointerBase, data_)                                                        \
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 6c9758a..6099df7 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -402,6 +402,7 @@
   V(_Utf8Decoder, "_Utf8Decoder")                                              \
   V(_VariableMirror, "_VariableMirror")                                        \
   V(_WeakProperty, "_WeakProperty")                                            \
+  V(_WeakReferenceImpl, "_WeakReferenceImpl")                                  \
   V(_typedDataBase, "_typedDataBase")                                          \
   V(_classRangeCheck, "_classRangeCheck")                                      \
   V(_ensureScheduleImmediate, "_ensureScheduleImmediate")                      \
diff --git a/runtime/vm/tagged_pointer.h b/runtime/vm/tagged_pointer.h
index c7c8b94..0f53fe7 100644
--- a/runtime/vm/tagged_pointer.h
+++ b/runtime/vm/tagged_pointer.h
@@ -412,6 +412,7 @@
 DEFINE_TAGGED_POINTER(StackTrace, Instance)
 DEFINE_TAGGED_POINTER(RegExp, Instance)
 DEFINE_TAGGED_POINTER(WeakProperty, Instance)
+DEFINE_TAGGED_POINTER(WeakReference, Instance)
 DEFINE_TAGGED_POINTER(MirrorReference, Instance)
 DEFINE_TAGGED_POINTER(UserTag, Instance)
 DEFINE_TAGGED_POINTER(FutureOr, Instance)
diff --git a/sdk/lib/_http/http_impl.dart b/sdk/lib/_http/http_impl.dart
index 80ee3b5..312ca7c 100644
--- a/sdk/lib/_http/http_impl.dart
+++ b/sdk/lib/_http/http_impl.dart
@@ -2723,7 +2723,8 @@
             subdomain.host.endsWith("." + domain.host)));
   }
 
-  static bool _shouldCopyHeaderOnRedirect(
+  // Only visible for testing.
+  static bool shouldCopyHeaderOnRedirect(
       String headerKey, Uri originalUrl, Uri redirectUri) {
     if (_isSubdomain(redirectUri, originalUrl)) {
       return true;
@@ -2754,7 +2755,7 @@
       for (var header in previous.headers._headers.keys) {
         if (request.headers[header] == null &&
             (!isRedirect ||
-                _shouldCopyHeaderOnRedirect(header, resolved, previous.uri))) {
+                shouldCopyHeaderOnRedirect(header, resolved, previous.uri))) {
           request.headers.set(header, previous.headers[header]!);
         }
       }
diff --git a/sdk/lib/_internal/vm/lib/expando_patch.dart b/sdk/lib/_internal/vm/lib/expando_patch.dart
index c217336..cf34b7f 100644
--- a/sdk/lib/_internal/vm/lib/expando_patch.dart
+++ b/sdk/lib/_internal/vm/lib/expando_patch.dart
@@ -173,16 +173,22 @@
   factory WeakReference(T object) = _WeakReferenceImpl<T>;
 }
 
+@pragma("vm:entry-point")
 class _WeakReferenceImpl<T extends Object> implements WeakReference<T> {
-  // TODO(http://dartbug.com/48162): Implement _WeakReference in the VM
-  // instead of reusing WeakProperty.
-  final _WeakProperty _weakProperty;
-
-  _WeakReferenceImpl(T object) : _weakProperty = _WeakProperty()..key = object {
+  _WeakReferenceImpl(T object) {
     Expando._checkType(object);
+    _target = object;
   }
 
-  T? get target => unsafeCast<T?>(_weakProperty.key);
+  @pragma("vm:recognized", "other")
+  @pragma("vm:prefer-inline")
+  @pragma("vm:external-name", "WeakReference_getTarget")
+  external T? get target;
+
+  @pragma("vm:recognized", "other")
+  @pragma("vm:prefer-inline")
+  @pragma("vm:external-name", "WeakReference_setTarget")
+  external set _target(T? value);
 }
 
 @patch
diff --git a/tests/language/type/constants_test.dart b/tests/language/type/constants_test.dart
index 560e485..2a35320 100644
--- a/tests/language/type/constants_test.dart
+++ b/tests/language/type/constants_test.dart
@@ -15,6 +15,9 @@
 
 const Type numType = num;
 
+const bool fromEnvironment =
+    const bool.fromEnvironment("foo", defaultValue: true);
+
 Type argumentType<T>() => T;
 
 void testSwitch<T extends MyType>(args) {
@@ -22,7 +25,7 @@
   for (int i = 0; i < types.length; i++) {
     switch (types[i]) {
       // Must be type literal or not override `==`.
-      case const MyType(): //# 01: compile-time error
+      case const MyType(0): //# 01: compile-time error
 
       // Must not be type variable.
       case T: //# 02: compile-time error
@@ -39,6 +42,8 @@
         throw "unreachable: num #$i";
       case MyType:
         break;
+      // Must be type literal or not override `==`.
+      case fromEnvironment ? const MyType(1) : Type: //# 07: compile-time error
       default:
         throw "unreachable: default #$i";
     }
@@ -48,7 +53,7 @@
 void testMaps<T extends MyType>(args) {
   const map = {
     // Must be type literal or not override `==`.
-    MyType(): 0, //# 04: compile-time error
+    MyType(0): 0, //# 04: compile-time error
 
     // Must not be type variable.
     T: 0, //# 05: compile-time error
@@ -61,6 +66,8 @@
     int: 1,
     String: 2,
     numType: 3,
+    // Must be type literal or not override `==`.
+    fromEnvironment ? const MyType(1) : Type: 4, //# 08: compile-time error
   };
   if (map[MyType] != 0) throw "Map Error: ${MyType} as literal";
   if (map[T] != 0) throw "Map Error: ${T} as type argument";
@@ -76,7 +83,8 @@
 // An implementation of `Type` which overrides `==`,
 // but is not the value of a constant type literal.
 class MyType implements Type {
-  const MyType();
+  final int value;
+  const MyType(this.value);
   int get hashCode => 0;
   bool operator ==(Object other) => identical(this, other);
 }
diff --git a/tests/language_2/const/switch2_test.dart b/tests/language_2/const/switch2_test.dart
index 772846e..ce881a4 100644
--- a/tests/language_2/const/switch2_test.dart
+++ b/tests/language_2/const/switch2_test.dart
@@ -13,6 +13,7 @@
   // [analyzer] COMPILE_TIME_ERROR.SWITCH_EXPRESSION_NOT_ASSIGNABLE
     case 0.0:
     //   ^
+    // [cfe] Case expression '0.0' does not have a primitive operator '=='.
     // [cfe] Type 'int' of the switch expression isn't assignable to the type 'double' of this case expression.
       print("illegal");
       break;
diff --git a/tests/language_2/switch/bad_case_test.dart b/tests/language_2/switch/bad_case_test.dart
index 3e3a340..85c88fa 100644
--- a/tests/language_2/switch/bad_case_test.dart
+++ b/tests/language_2/switch/bad_case_test.dart
@@ -34,8 +34,12 @@
 //^^^^^^
 // [analyzer] COMPILE_TIME_ERROR.CASE_EXPRESSION_TYPE_IMPLEMENTS_EQUALS
     case 3.14:
+    //   ^
+    // [cfe] Case expression '3.14' does not have a primitive operator '=='.
       return "Pi";
     case 2.71828:
+    //   ^
+    // [cfe] Case expression '2.71828' does not have a primitive operator '=='.
       return "Huh?";
   }
   return null;
diff --git a/tests/language_2/switch/case_test.dart b/tests/language_2/switch/case_test.dart
index af15ac6..fa519fd0 100644
--- a/tests/language_2/switch/case_test.dart
+++ b/tests/language_2/switch/case_test.dart
@@ -35,6 +35,8 @@
 //^^^^^^
 // [analyzer] COMPILE_TIME_ERROR.CASE_EXPRESSION_TYPE_IMPLEMENTS_EQUALS
     case const A.B(): Expect.fail("bad switch"); break;
+    //         ^
+    // [cfe] Case expression 'B {}' does not have a primitive operator '=='.
   }
 
   switch (new C()) {
@@ -59,5 +61,7 @@
     case const A.B(): Expect.fail("bad switch"); break;
     //   ^^^^^^^^^^^
     // [analyzer] COMPILE_TIME_ERROR.INCONSISTENT_CASE_EXPRESSION_TYPES
+    //         ^
+    // [cfe] Case expression 'B {}' does not have a primitive operator '=='.
   }
 }
diff --git a/tests/language_2/type/constants_test.dart b/tests/language_2/type/constants_test.dart
index ded5300..cda34ff 100644
--- a/tests/language_2/type/constants_test.dart
+++ b/tests/language_2/type/constants_test.dart
@@ -17,6 +17,9 @@
 
 const Type numType = num;
 
+const bool fromEnvironment =
+    const bool.fromEnvironment("foo", defaultValue: true);
+
 Type argumentType<T>() => T;
 
 void testSwitch<T extends MyType>(args) {
@@ -24,7 +27,7 @@
   for (int i = 0; i < types.length; i++) {
     switch (types[i]) {
       // Must be type literal or not override `==`.
-      case const MyType(): //# 01: compile-time error
+      case const MyType(0): //# 01: compile-time error
 
       // Must not be type variable.
       case T: //# 02: compile-time error
@@ -41,6 +44,8 @@
         throw "unreachable: num #$i";
       case MyType:
         break;
+      // Must be type literal or not override `==`.
+      case fromEnvironment ? const MyType(1) : Type: //# 07: compile-time error
       default:
         throw "unreachable: default #$i";
     }
@@ -50,7 +55,7 @@
 void testMaps<T extends MyType>(args) {
   const map = {
     // Must be type literal or not override `==`.
-    MyType(): 0, //# 04: compile-time error
+    MyType(0): 0, //# 04: compile-time error
 
     // Must not be type variable.
     T: 0, //# 05: compile-time error
@@ -63,6 +68,8 @@
     int: 1,
     String: 2,
     numType: 3,
+    // Must be type literal or not override `==`.
+    fromEnvironment ? const MyType(1) : Type: 4, //# 08: compile-time error
   };
   if (map[MyType] != 0) throw "Map Error: ${MyType} as literal";
   if (map[T] != 0) throw "Map Error: ${T} as type argument";
@@ -78,7 +85,8 @@
 // An implementation of `Type` which overrides `==`,
 // but is not the value of a constant type literal.
 class MyType implements Type {
-  const MyType();
+  final int value;
+  const MyType(this.value);
   int get hashCode => 0;
   bool operator ==(Object other) => identical(this, other);
 }
diff --git a/tests/lib/isolate/weak_reference_message_2_test.dart b/tests/lib/isolate/weak_reference_message_2_test.dart
new file mode 100644
index 0000000..f925185
--- /dev/null
+++ b/tests/lib/isolate/weak_reference_message_2_test.dart
@@ -0,0 +1,77 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:typed_data';
+import "dart:isolate";
+
+import "package:async_helper/async_helper.dart";
+import "package:expect/expect.dart";
+
+void main(List<String> arguments, Object? message) async {
+  if (arguments.length == 1) {
+    assert(arguments[0] == 'helper');
+    await runHelper(message as SendPort);
+  } else {
+    await runTest();
+  }
+}
+
+Future<void> runTest() async {
+  final port = ReceivePort();
+  await Isolate.spawnUri(
+    Uri.parse('weak_reference_message_2_test.dart'),
+    ['helper'],
+    port.sendPort,
+  );
+  final message = await port.first;
+
+  final weakRef1copy = message[0] as WeakReference<Uint8List>;
+  final weakRef2copy = message[1] as WeakReference<Uint8List>;
+  final weakRef3copy = message[3] as WeakReference<Uint8List>;
+  final weakRef4copy = message[5] as WeakReference<Uint8List>;
+  Expect.isNull(weakRef1copy.target);
+  Expect.equals(2, weakRef2copy.target?.length);
+  Expect.isNull(weakRef3copy.target);
+  Expect.equals(4, weakRef4copy.target?.length);
+
+  port.close();
+}
+
+Future<void> runHelper(SendPort port) async {
+  final object1 = Uint8List(1);
+  final weakRef1 = WeakReference(object1);
+  final object2 = Uint8List(2);
+  final weakRef2 = WeakReference(object2);
+  final object3 = Uint8List(3);
+  final weakRef3 = WeakReference(object3);
+  final object4 = Uint8List(4);
+  final weakRef4 = WeakReference(object4);
+
+  final key3 = Object();
+  final expando3 = Expando();
+  expando3[key3] = object3;
+  final key4 = Object();
+  final expando4 = Expando();
+  expando4[key4] = object4;
+
+  final message = <dynamic>[
+    weakRef1, // Does not have its target inluded.
+    weakRef2, // Has its target included later than itself.
+    object2,
+    weakRef3, // Does not have its target inluded.
+    expando3,
+    weakRef4, // Has its target included due to expando.
+    expando4,
+    key4,
+  ];
+  port.send(message);
+}
+
+class Nonce {
+  final int value;
+
+  Nonce(this.value);
+
+  String toString() => 'Nonce($value)';
+}
diff --git a/tests/lib_2/isolate/weak_reference_message_2_test.dart b/tests/lib_2/isolate/weak_reference_message_2_test.dart
new file mode 100644
index 0000000..bd9cb92
--- /dev/null
+++ b/tests/lib_2/isolate/weak_reference_message_2_test.dart
@@ -0,0 +1,79 @@
+// 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:typed_data';
+import "dart:isolate";
+
+import "package:async_helper/async_helper.dart";
+import "package:expect/expect.dart";
+
+void main(List<String> arguments, Object message) async {
+  if (arguments.length == 1) {
+    assert(arguments[0] == 'helper');
+    await runHelper(message as SendPort);
+  } else {
+    await runTest();
+  }
+}
+
+Future<void> runTest() async {
+  final port = ReceivePort();
+  await Isolate.spawnUri(
+    Uri.parse('weak_reference_message_2_test.dart'),
+    ['helper'],
+    port.sendPort,
+  );
+  final message = await port.first;
+
+  final weakRef1copy = message[0] as WeakReference<Uint8List>;
+  final weakRef2copy = message[1] as WeakReference<Uint8List>;
+  final weakRef3copy = message[3] as WeakReference<Uint8List>;
+  final weakRef4copy = message[5] as WeakReference<Uint8List>;
+  Expect.isNull(weakRef1copy.target);
+  Expect.equals(2, weakRef2copy.target?.length);
+  Expect.isNull(weakRef3copy.target);
+  Expect.equals(4, weakRef4copy.target?.length);
+
+  port.close();
+}
+
+Future<void> runHelper(SendPort port) async {
+  final object1 = Uint8List(1);
+  final weakRef1 = WeakReference(object1);
+  final object2 = Uint8List(2);
+  final weakRef2 = WeakReference(object2);
+  final object3 = Uint8List(3);
+  final weakRef3 = WeakReference(object3);
+  final object4 = Uint8List(4);
+  final weakRef4 = WeakReference(object4);
+
+  final key3 = Object();
+  final expando3 = Expando();
+  expando3[key3] = object3;
+  final key4 = Object();
+  final expando4 = Expando();
+  expando4[key4] = object4;
+
+  final message = <dynamic>[
+    weakRef1, // Does not have its target inluded.
+    weakRef2, // Has its target included later than itself.
+    object2,
+    weakRef3, // Does not have its target inluded.
+    expando3,
+    weakRef4, // Has its target included due to expando.
+    expando4,
+    key4,
+  ];
+  port.send(message);
+}
+
+class Nonce {
+  final int value;
+
+  Nonce(this.value);
+
+  String toString() => 'Nonce($value)';
+}
diff --git a/tests/standalone/io/http_redirect_test.dart b/tests/standalone/io/http_redirect_test.dart
index 1a19222..7ccf54d 100644
--- a/tests/standalone/io/http_redirect_test.dart
+++ b/tests/standalone/io/http_redirect_test.dart
@@ -6,6 +6,7 @@
 import "package:expect/expect.dart";
 import "dart:async";
 import "dart:io";
+import "dart:mirrors";
 
 Future<HttpServer> setupServer({Uri? targetServer}) {
   final completer = new Completer<HttpServer>();
@@ -343,6 +344,95 @@
   });
 }
 
+void testShouldCopyHeadersOnRedirect() {
+  final clientClass = reflect(HttpClient()).type;
+  final fnName = Symbol("shouldCopyHeaderOnRedirect");
+
+  shouldCopyHeaderOnRedirect(
+          String headerKey, Uri originalUrl, Uri redirectUri) =>
+      clientClass.invoke(
+          fnName, [headerKey, originalUrl, redirectUri]).reflectee as bool;
+
+  checkShouldCopyHeader(
+      String headerKey, String originalUrl, String redirectUri, bool expected) {
+    if (shouldCopyHeaderOnRedirect(
+            headerKey, Uri.parse(originalUrl), Uri.parse(redirectUri)) !=
+        expected) {
+      Expect.fail(
+          "shouldCopyHeaderOnRedirect($headerKey, $originalUrl, $redirectUri) => ${!expected}");
+    }
+  }
+
+  // Redirect on localhost.
+  checkShouldCopyHeader(
+      "authorization", "http://localhost", "http://localhost/foo", true);
+  checkShouldCopyHeader(
+      "cat", "http://localhost", "http://localhost/foo", true);
+
+  // Redirect to same IP address.
+  checkShouldCopyHeader("authorization", "http://192.168.20.20",
+      "http://192.168.20.20/foo", true);
+  checkShouldCopyHeader(
+      "cat", "http://192.168.20.20", "http://192.168.20.20/foo", true);
+
+  // Redirect to different IP address.
+  checkShouldCopyHeader(
+      "authorization", "http://192.168.20.20", "http://192.168.20.99", false);
+  checkShouldCopyHeader(
+      "cat", "http://192.168.20.20", "http://192.168.20.99", true);
+
+  // Redirect to same domain.
+  checkShouldCopyHeader(
+      "authorization", "http://foo.com", "http://foo.com/foo", true);
+  checkShouldCopyHeader("cat", "http://foo.com", "http://foo.com/foo", true);
+
+  // Redirect to same domain with explicit ports.
+  checkShouldCopyHeader(
+      "authorization", "http://foo.com", "http://foo.com:80/foo", true);
+  checkShouldCopyHeader("cat", "http://foo.com", "http://foo.com:80/foo", true);
+
+  // Redirect to subdomain.
+  checkShouldCopyHeader(
+      "authorization", "https://foo.com", "https://www.foo.com", true);
+  checkShouldCopyHeader("cat", "https://foo.com", "https://www.foo.com", true);
+
+  // Redirect to different domain.
+  checkShouldCopyHeader(
+      "authorization", "https://foo.com", "https://wwwfoo.com", false);
+  checkShouldCopyHeader("cat", "https://foo.com", "https://wwwfoo.com", true);
+
+  // Redirect to different port.
+  checkShouldCopyHeader(
+      "authorization", "http://foo.com", "http://foo.com:81", false);
+  checkShouldCopyHeader("cat", "http://foo.com", "http://foo.com:81", true);
+
+  // Redirect from secure to insecure.
+  checkShouldCopyHeader(
+      "authorization", "https://foo.com", "http://foo.com", false);
+  checkShouldCopyHeader("cat", "https://foo.com", "http://foo.com", true);
+
+  // Redirect from secure to insecure, same port.
+  checkShouldCopyHeader(
+      "authorization", "https://foo.com:8888", "http://foo.com:8888", false);
+  checkShouldCopyHeader(
+      "cat", "https://foo.com:8888", "http://foo.com:8888", true);
+
+  // Redirect from insecure to secure.
+  checkShouldCopyHeader(
+      "authorization", "http://foo.com", "https://foo.com", false);
+  checkShouldCopyHeader("cat", "http://foo.com", "https://foo.com", true);
+
+  // Redirect to subdomain, different port.
+  checkShouldCopyHeader(
+      "authorization", "https://foo.com:80", "https://www.foo.com:81", false);
+  checkShouldCopyHeader(
+      "cat", "https://foo.com:80", "https://www.foo.com:81", true);
+
+  // Different header casting:
+  checkShouldCopyHeader(
+      "AuThOrIzAtiOn", "https://foo.com", "https://bar.com", false);
+}
+
 void testCrossDomainAutoRedirectWithHeaders() {
   setupTargetServer().then((targetServer) {
     setupServer(
@@ -517,6 +607,7 @@
   testManualRedirectWithHeaders();
   testAutoRedirect();
   testAutoRedirectWithHeaders();
+  testShouldCopyHeadersOnRedirect();
   testCrossDomainAutoRedirectWithHeaders();
   testAutoRedirect301POST();
   testAutoRedirect303POST();
diff --git a/tests/standalone_2/io/http_redirect_test.dart b/tests/standalone_2/io/http_redirect_test.dart
index e851045..1d4fde8 100644
--- a/tests/standalone_2/io/http_redirect_test.dart
+++ b/tests/standalone_2/io/http_redirect_test.dart
@@ -8,6 +8,7 @@
 import "package:expect/expect.dart";
 import "dart:async";
 import "dart:io";
+import "dart:mirrors";
 
 Future<HttpServer> setupServer({Uri targetServer}) {
   Completer completer = new Completer<HttpServer>();
@@ -345,6 +346,95 @@
   });
 }
 
+void testShouldCopyHeadersOnRedirect() {
+  final clientClass = reflect(HttpClient()).type;
+  final fnName = Symbol("shouldCopyHeaderOnRedirect");
+
+  shouldCopyHeaderOnRedirect(
+          String headerKey, Uri originalUrl, Uri redirectUri) =>
+      clientClass.invoke(
+          fnName, [headerKey, originalUrl, redirectUri]).reflectee as bool;
+
+  checkShouldCopyHeader(
+      String headerKey, String originalUrl, String redirectUri, bool expected) {
+    if (shouldCopyHeaderOnRedirect(
+            headerKey, Uri.parse(originalUrl), Uri.parse(redirectUri)) !=
+        expected) {
+      Expect.fail(
+          "shouldCopyHeaderOnRedirect($headerKey, $originalUrl, $redirectUri) => ${!expected}");
+    }
+  }
+
+  // Redirect on localhost.
+  checkShouldCopyHeader(
+      "authorization", "http://localhost", "http://localhost/foo", true);
+  checkShouldCopyHeader(
+      "cat", "http://localhost", "http://localhost/foo", true);
+
+  // Redirect to same IP address.
+  checkShouldCopyHeader("authorization", "http://192.168.20.20",
+      "http://192.168.20.20/foo", true);
+  checkShouldCopyHeader(
+      "cat", "http://192.168.20.20", "http://192.168.20.20/foo", true);
+
+  // Redirect to different IP address.
+  checkShouldCopyHeader(
+      "authorization", "http://192.168.20.20", "http://192.168.20.99", false);
+  checkShouldCopyHeader(
+      "cat", "http://192.168.20.20", "http://192.168.20.99", true);
+
+  // Redirect to same domain.
+  checkShouldCopyHeader(
+      "authorization", "http://foo.com", "http://foo.com/foo", true);
+  checkShouldCopyHeader("cat", "http://foo.com", "http://foo.com/foo", true);
+
+  // Redirect to same domain with explicit ports.
+  checkShouldCopyHeader(
+      "authorization", "http://foo.com", "http://foo.com:80/foo", true);
+  checkShouldCopyHeader("cat", "http://foo.com", "http://foo.com:80/foo", true);
+
+  // Redirect to subdomain.
+  checkShouldCopyHeader(
+      "authorization", "https://foo.com", "https://www.foo.com", true);
+  checkShouldCopyHeader("cat", "https://foo.com", "https://www.foo.com", true);
+
+  // Redirect to different domain.
+  checkShouldCopyHeader(
+      "authorization", "https://foo.com", "https://wwwfoo.com", false);
+  checkShouldCopyHeader("cat", "https://foo.com", "https://wwwfoo.com", true);
+
+  // Redirect to different port.
+  checkShouldCopyHeader(
+      "authorization", "http://foo.com", "http://foo.com:81", false);
+  checkShouldCopyHeader("cat", "http://foo.com", "http://foo.com:81", true);
+
+  // Redirect from secure to insecure.
+  checkShouldCopyHeader(
+      "authorization", "https://foo.com", "http://foo.com", false);
+  checkShouldCopyHeader("cat", "https://foo.com", "http://foo.com", true);
+
+  // Redirect from secure to insecure, same port.
+  checkShouldCopyHeader(
+      "authorization", "https://foo.com:8888", "http://foo.com:8888", false);
+  checkShouldCopyHeader(
+      "cat", "https://foo.com:8888", "http://foo.com:8888", true);
+
+  // Redirect from insecure to secure.
+  checkShouldCopyHeader(
+      "authorization", "http://foo.com", "https://foo.com", false);
+  checkShouldCopyHeader("cat", "http://foo.com", "https://foo.com", true);
+
+  // Redirect to subdomain, different port.
+  checkShouldCopyHeader(
+      "authorization", "https://foo.com:80", "https://www.foo.com:81", false);
+  checkShouldCopyHeader(
+      "cat", "https://foo.com:80", "https://www.foo.com:81", true);
+
+  // Different header casting:
+  checkShouldCopyHeader(
+      "AuThOrIzAtiOn", "https://foo.com", "https://bar.com", false);
+}
+
 void testCrossDomainAutoRedirectWithHeaders() {
   setupTargetServer().then((targetServer) {
     setupServer(
@@ -519,6 +609,7 @@
   testManualRedirectWithHeaders();
   testAutoRedirect();
   testAutoRedirectWithHeaders();
+  testShouldCopyHeadersOnRedirect();
   testCrossDomainAutoRedirectWithHeaders();
   testAutoRedirect301POST();
   testAutoRedirect303POST();
diff --git a/tools/VERSION b/tools/VERSION
index 96f8bba..153a55f 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 17
 PATCH 0
-PRERELEASE 97
+PRERELEASE 98
 PRERELEASE_PATCH 0
\ No newline at end of file