Version 2.13.0-164.0.dev

Merge commit '6127386cfaeef4037c9ab7954b8debc4935e3f07' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index 80d3fe1..b78dbf0 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -11,7 +11,7 @@
     "constraint, update this by running tools/generate_package_config.dart."
   ],
   "configVersion": 2,
-  "generated": "2021-03-20T01:55:31.903271",
+  "generated": "2021-03-20T17:09:47.020685",
   "generator": "tools/generate_package_config.dart",
   "packages": [
     {
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 13057f0..143873c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -40,34 +40,6 @@
 - new lint: `use_named_constants`.
 - deprecation of `avoid_as`.
 
-### Pub
-
-* `dart pub publish` now respects `.pubignore` files with gitignore-style rules.
- `.gitignore` files in the repo are still respected if they are not
-  overridden by a `.pubignore` in the same directory.
-
-  pub no longer queries git for listing the files. This implies:
-  * Checked in files will now be ignored if they are included by a `.gitignore`
-    rule.
-  * Global ignores are no longer taken into account.
-  * Even packages that are not in git source control will have their
-    `.gitignore` files respected.
-
-* New flag `dart pub deps --json` gives a machine parsable overview of the
-  current dependencies.
-* New command: `dart pub cache clean`. Will delete everything in your current
-  pub cache.
-* Commands related to a single package now takes a `--directory` option to
-  operate on a package in the given directory instead of the working directory.
-* git dependencies with a relative repo url would previously be interpreted
-  relative to the current package, even for transitive dependencies. This now
-  fails instead.
-
-* Pub now uses a Dart library to read and write tar files.
-  This should fix several issues we had with incompatibilities between different
-  system `tar`s.
-* `PUB_HOSTED_URL` can now include a trailing slash.
-
 ## 2.12.2 - 2021-03-17
 
 This is a patch release that fixes crashes reported by Flutter 2 users (issue
diff --git a/DEPS b/DEPS
index 70d86d7..67de11a 100644
--- a/DEPS
+++ b/DEPS
@@ -45,7 +45,7 @@
   # hashes. It requires access to the dart-build-access group, which EngProd
   # has.
   "co19_rev": "fddb1dce948cec277bf3dc23b45ee95e761b89fe",
-  "co19_2_rev": "cf6eed0535e45413672bb5bb6e65df9f59846372",
+  "co19_2_rev": "6b71fed8c0f6cf396c085ba2d405d5a9af1daf45",
 
   # The internal benchmarks to use. See go/dart-benchmarks-internal
   "benchmarks_internal_rev": "076df10d9b77af337f2d8029725787155eb1cd52",
@@ -70,7 +70,7 @@
   # Revisions of /third_party/* dependencies.
   "args_rev": "eb2deca5b4489709acd001a5c7fd2df4f1eed19d",
   "async_rev": "376d418b1b535030fbe3369938d2ffdbb0340a77",
-  "bazel_worker_rev": "060c55a933d39798681a4f533b161b81dc48d77e",
+  "bazel_worker_rev": "0885637b037979afbf5bcd05fd748b309fd669c0",
   "benchmark_harness_rev": "c546dbd9f639f75cd2f75de8df2eb9f8ea15e8e7",
   "boolean_selector_rev": "665e6921ab246569420376f827bff4585dff0b14",
   "boringssl_gen_rev": "7322fc15cc065d8d2957fccce6b62a509dc4d641",
@@ -128,7 +128,7 @@
   "mockito_rev": "d39ac507483b9891165e422ec98d9fb480037c8b",
   "mustache_rev": "664737ecad027e6b96d0d1e627257efa0e46fcb1",
   "oauth2_rev": "7cd3284049fe5badbec9f2bea2afc41d14c01057",
-  "package_config_rev": "249af482de9ebabfc781bf10d6152c938e5ce45e",
+  "package_config_rev": "a84c0d45401f215fbe9384df923a38f4022a3c45",
   "path_rev": "407ab76187fade41c31e39c745b39661b710106c",
   "pedantic_rev": "df177f6ae531426aaf7bbf0121c90dc89d9c57bf",
   "platform_rev": "c20e6fa315e9f8820e51c0ae721f63aff33b8e17",
@@ -136,7 +136,7 @@
   "pool_rev": "7abe634002a1ba8a0928eded086062f1307ccfae",
   "process_rev": "56ece43b53b64c63ae51ec184b76bd5360c28d0b",
   "protobuf_rev": "0d03fd588df69e9863e2a2efc0059dee8f18d5b2",
-  "pub_rev": "255a3091fc278b04be74d246a3bec8743ef4d0b7",
+  "pub_rev": "0e657414a472e74ca5dd76ae0db50cc060251dec",
   "pub_semver_rev": "f50d80ef10c4b2fa5f4c8878036a4d9342c0cc82",
   "resource_rev": "6b79867d0becf5395e5819a75720963b8298e9a7",
   "root_certificates_rev": "7e5ec82c99677a2e5b95ce296c4d68b0d3378ed8",
diff --git a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
index 633c72f..fc66822 100644
--- a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
@@ -4184,10 +4184,13 @@
 
   @override
   Map<Type, NonPromotionReason> Function() whyNotPromoted(Expression target) {
-    ReferenceWithType<Variable, Type>? referenceWithType = _expressionReference;
-    if (referenceWithType != null) {
-      return referenceWithType.reference.getNonPromotionReasons(
-          _current.variableInfo, referenceWithType.type, typeOperations);
+    if (identical(target, _expressionWithReference)) {
+      ReferenceWithType<Variable, Type>? referenceWithType =
+          _expressionReference;
+      if (referenceWithType != null) {
+        return referenceWithType.reference.getNonPromotionReasons(
+            _current.variableInfo, referenceWithType.type, typeOperations);
+      }
     }
     return () => {};
   }
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/token.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/token.dart
index 6f92ebe..4cc7473 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/token.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/token.dart
@@ -1077,24 +1077,23 @@
   Object value();
 
   /**
-   * Compare the given [tokens] to find the token that appears first in the
+   * Compare the given tokens to find the token that appears first in the
    * source being parsed. That is, return the left-most of all of the tokens.
-   * The list must be non-`null`, but the elements of the list are allowed to be
-   * `null`. Return the token with the smallest offset, or `null` if the list is
-   * empty or if all of the elements of the list are `null`.
+   * Return the token with the smallest offset, or `null` if all of the
+   * tokens are `null`.
    */
-  static Token? lexicallyFirst(List<Token?> tokens) {
-    Token? first = null;
-    int offset = -1;
-    int length = tokens.length;
-    for (int i = 0; i < length; i++) {
-      Token? token = tokens[i];
-      if (token != null && (offset < 0 || token.offset < offset)) {
-        first = token;
-        offset = token.offset;
-      }
+  static Token? lexicallyFirst([Token? t1, Token? t2, Token? t3, Token? t4]) {
+    Token? result = t1;
+    if (result == null || t2 != null && t2.offset < result.offset) {
+      result = t2;
     }
-    return first;
+    if (result == null || t3 != null && t3.offset < result.offset) {
+      result = t3;
+    }
+    if (result == null || t4 != null && t4.offset < result.offset) {
+      result = t4;
+    }
+    return result;
   }
 }
 
diff --git a/pkg/_fe_analyzer_shared/pubspec.yaml b/pkg/_fe_analyzer_shared/pubspec.yaml
index c0066ca..e576474 100644
--- a/pkg/_fe_analyzer_shared/pubspec.yaml
+++ b/pkg/_fe_analyzer_shared/pubspec.yaml
@@ -1,5 +1,5 @@
 name: _fe_analyzer_shared
-version: 18.0.0
+version: 19.0.0
 description: Logic that is shared between the front_end and analyzer packages.
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/_fe_analyzer_shared
 
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/argument_type_not_assignable_nullability_error.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/argument_type_not_assignable_nullability_error.dart
index 1f92f0d..c40a3bb 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/argument_type_not_assignable_nullability_error.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/argument_type_not_assignable_nullability_error.dart
@@ -89,3 +89,204 @@
       /*analyzer.notPromoted(propertyNotPromoted(target: member:C7.bad, type: int?))*/ c
           . /*cfe.notPromoted(propertyNotPromoted(target: member:C7.bad, type: int?))*/ bad);
 }
+
+class C8 {
+  int? bad;
+}
+
+userDefinableBinaryOpRhs(C8 c) {
+  if (c.bad == null) return;
+  1 +
+      /*analyzer.notPromoted(propertyNotPromoted(target: member:C8.bad, type: int?))*/ c
+          . /*cfe.notPromoted(propertyNotPromoted(target: member:C8.bad, type: int?))*/ bad;
+}
+
+class C9 {
+  int? bad;
+  f(int i) {}
+}
+
+questionQuestionRhs(C9 c, int? i) {
+  // Note: "why not supported" functionality is currently not supported for the
+  // RHS of `??` because it requires more clever reasoning than we currently do:
+  // we would have to understand that the reason `i ?? c.bad` has a type of
+  // `int?` rather than `int` is because `c.bad` was not promoted.  We currently
+  // only support detecting non-promotion when the expression that had the wrong
+  // type *is* the expression that wasn't promoted.
+  if (c.bad == null) return;
+  c.f(i ?? c.bad);
+}
+
+class C10 {
+  D10? bad;
+  f(bool b) {}
+}
+
+class D10 {
+  bool operator ==(covariant D10 other) => true;
+}
+
+equalRhs(C10 c, D10 d) {
+  if (c.bad == null) return;
+  // Note: we don't report an error here because `==` always accepts `null`.
+  c.f(d == c.bad);
+  c.f(d != c.bad);
+}
+
+class C11 {
+  bool? bad;
+  f(bool b) {}
+}
+
+andOperand(C11 c, bool b) {
+  if (c.bad == null) return;
+  c.f(
+      /*analyzer.notPromoted(propertyNotPromoted(target: member:C11.bad, type: bool?))*/ c
+              . /*cfe.notPromoted(propertyNotPromoted(target: member:C11.bad, type: bool?))*/ bad &&
+          b);
+  c.f(b &&
+      /*analyzer.notPromoted(propertyNotPromoted(target: member:C11.bad, type: bool?))*/ c
+          . /*cfe.notPromoted(propertyNotPromoted(target: member:C11.bad, type: bool?))*/ bad);
+}
+
+class C12 {
+  bool? bad;
+  f(bool b) {}
+}
+
+orOperand(C12 c, bool b) {
+  if (c.bad == null) return;
+  c.f(
+      /*analyzer.notPromoted(propertyNotPromoted(target: member:C12.bad, type: bool?))*/ c
+              . /*cfe.notPromoted(propertyNotPromoted(target: member:C12.bad, type: bool?))*/ bad ||
+          b);
+  c.f(b ||
+      /*analyzer.notPromoted(propertyNotPromoted(target: member:C12.bad, type: bool?))*/ c
+          . /*cfe.notPromoted(propertyNotPromoted(target: member:C12.bad, type: bool?))*/ bad);
+}
+
+class C13 {
+  bool? bad;
+}
+
+assertStatementCondition(C13 c) {
+  if (c.bad == null) return;
+  assert(
+      /*analyzer.notPromoted(propertyNotPromoted(target: member:C13.bad, type: bool?))*/ c
+          . /*cfe.notPromoted(propertyNotPromoted(target: member:C13.bad, type: bool?))*/ bad);
+}
+
+class C14 {
+  bool? bad;
+  C14.assertInitializerCondition(C14 c)
+      : bad = c.bad!,
+        assert(
+            /*analyzer.notPromoted(propertyNotPromoted(target: member:C14.bad, type: bool?))*/ c
+                . /*cfe.notPromoted(propertyNotPromoted(target: member:C14.bad, type: bool?))*/ bad);
+}
+
+class C15 {
+  bool? bad;
+  f(bool b) {}
+}
+
+notOperand(C15 c) {
+  if (c.bad == null) return;
+  c.f(!
+      /*analyzer.notPromoted(propertyNotPromoted(target: member:C15.bad, type: bool?))*/ c
+          . /*cfe.notPromoted(propertyNotPromoted(target: member:C15.bad, type: bool?))*/ bad);
+}
+
+class C16 {
+  bool? bad;
+  f(bool b) {}
+}
+
+forLoopCondition(C16 c) {
+  if (c.bad == null) return;
+  for (;
+      /*analyzer.notPromoted(propertyNotPromoted(target: member:C16.bad, type: bool?))*/ c
+          . /*cfe.notPromoted(propertyNotPromoted(target: member:C16.bad, type: bool?))*/ bad;) {}
+  [
+    for (;
+        /*analyzer.notPromoted(propertyNotPromoted(target: member:C16.bad, type: bool?))*/ c
+            . /*cfe.notPromoted(propertyNotPromoted(target: member:C16.bad, type: bool?))*/ bad;)
+      null
+  ];
+  ({
+    for (;
+        /*analyzer.notPromoted(propertyNotPromoted(target: member:C16.bad, type: bool?))*/ c
+            . /*cfe.notPromoted(propertyNotPromoted(target: member:C16.bad, type: bool?))*/ bad;)
+      null
+  });
+  ({
+    for (;
+        /*analyzer.notPromoted(propertyNotPromoted(target: member:C16.bad, type: bool?))*/ c
+            . /*cfe.notPromoted(propertyNotPromoted(target: member:C16.bad, type: bool?))*/ bad;)
+      null: null
+  });
+}
+
+class C17 {
+  bool? bad;
+  f(int i) {}
+}
+
+conditionalExpressionCondition(C17 c) {
+  if (c.bad == null) return;
+  c.f(
+      /*analyzer.notPromoted(propertyNotPromoted(target: member:C17.bad, type: bool?))*/ c
+              . /*cfe.notPromoted(propertyNotPromoted(target: member:C17.bad, type: bool?))*/ bad
+          ? 1
+          : 2);
+}
+
+class C18 {
+  bool? bad;
+}
+
+doLoopCondition(C18 c) {
+  if (c.bad == null) return;
+  do {} while (
+      /*analyzer.notPromoted(propertyNotPromoted(target: member:C18.bad, type: bool?))*/ c
+          . /*cfe.notPromoted(propertyNotPromoted(target: member:C18.bad, type: bool?))*/ bad);
+}
+
+class C19 {
+  bool? bad;
+}
+
+ifCondition(C19 c) {
+  if (c.bad == null) return;
+  if (
+      /*analyzer.notPromoted(propertyNotPromoted(target: member:C19.bad, type: bool?))*/ c
+          . /*cfe.notPromoted(propertyNotPromoted(target: member:C19.bad, type: bool?))*/ bad) {}
+  [
+    if (
+    /*analyzer.notPromoted(propertyNotPromoted(target: member:C19.bad, type: bool?))*/ c
+        . /*cfe.notPromoted(propertyNotPromoted(target: member:C19.bad, type: bool?))*/ bad)
+      null
+  ];
+  ({
+    if (
+    /*analyzer.notPromoted(propertyNotPromoted(target: member:C19.bad, type: bool?))*/ c
+        . /*cfe.notPromoted(propertyNotPromoted(target: member:C19.bad, type: bool?))*/ bad)
+      null
+  });
+  ({
+    if (
+    /*analyzer.notPromoted(propertyNotPromoted(target: member:C19.bad, type: bool?))*/ c
+        . /*cfe.notPromoted(propertyNotPromoted(target: member:C19.bad, type: bool?))*/ bad)
+      null: null
+  });
+}
+
+class C20 {
+  bool? bad;
+}
+
+whileCondition(C20 c) {
+  if (c.bad == null) return;
+  while (/*analyzer.notPromoted(propertyNotPromoted(target: member:C20.bad, type: bool?))*/ c
+      . /*cfe.notPromoted(propertyNotPromoted(target: member:C20.bad, type: bool?))*/ bad) {}
+}
diff --git a/pkg/analysis_server/test/integration/server/bazel_changes_test.dart b/pkg/analysis_server/test/integration/server/bazel_changes_test.dart
index edca9a7..eadac35 100644
--- a/pkg/analysis_server/test/integration/server/bazel_changes_test.dart
+++ b/pkg/analysis_server/test/integration/server/bazel_changes_test.dart
@@ -13,6 +13,11 @@
 import '../support/integration_tests.dart';
 
 void main() {
+  // Skip on Windows.
+  if (Platform.isWindows) {
+    return;
+  }
+
   defineReflectiveSuite(() {
     defineReflectiveTests(BazelChangesTest);
   });
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index 8b10921..32a86f1 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,6 +1,9 @@
-## 1.3.0-dev
+## 1.3.0
 * Added `Expression.inConstantContext` to API.
 * Updated documentation comments for some getters that don't return `null`.
+* Fixed an issue with accessing `CompilationUnitElement.mixins` before `types`.
+* Implemented metadata resolution with type arguments and inference.
+* Fixed issue with metadata on enum constants.
 
 ## 1.2.0
 * Deprecated all setters in API of AST. Use `parseString()` instead.
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 9395186ea..c83a346 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -590,6 +590,7 @@
   HintCode.UNNECESSARY_NO_SUCH_METHOD,
   HintCode.UNNECESSARY_NULL_COMPARISON_FALSE,
   HintCode.UNNECESSARY_NULL_COMPARISON_TRUE,
+  HintCode.UNNECESSARY_QUESTION_MARK,
   HintCode.UNNECESSARY_TYPE_CHECK_FALSE,
   HintCode.UNNECESSARY_TYPE_CHECK_TRUE,
   HintCode.UNUSED_CATCH_CLAUSE,
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 3cec775..bbefbdd 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -80,7 +80,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 = 133;
+  static const int DATA_VERSION = 134;
 
   /// The length of the list returned by [_computeDeclaredVariablesSignature].
   static const int _declaredVariablesSignatureLength = 4;
diff --git a/pkg/analyzer/lib/src/dart/analysis/unlinked_api_signature.dart b/pkg/analyzer/lib/src/dart/analysis/unlinked_api_signature.dart
index e99dbf6..74e302c 100644
--- a/pkg/analyzer/lib/src/dart/analysis/unlinked_api_signature.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/unlinked_api_signature.dart
@@ -21,7 +21,9 @@
   static const int _kindFieldDeclaration = 2;
   static const int _kindMethodDeclaration = 3;
   static const int _nullNode = 0;
+  static const int _notNullNode = 1;
   static const int _nullToken = 0;
+  static const int _notNullToken = 1;
 
   final ApiSignature signature = ApiSignature();
 
@@ -93,6 +95,7 @@
 
   void _addNode(AstNode? node) {
     if (node != null) {
+      signature.addInt(_notNullNode);
       _addTokens(node.beginToken, node.endToken);
     } else {
       signature.addInt(_nullNode);
@@ -107,6 +110,7 @@
 
   void _addToken(Token? token) {
     if (token != null) {
+      signature.addInt(_notNullToken);
       signature.addString(token.lexeme);
     } else {
       signature.addInt(_nullToken);
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index 575cac0..e2f7ed12 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -1488,10 +1488,7 @@
 
   @override
   Token get firstTokenAfterCommentAndMetadata {
-    if (abstractKeyword != null) {
-      return abstractKeyword!;
-    }
-    return classKeyword;
+    return abstractKeyword ?? classKeyword;
   }
 
   @override
@@ -1727,10 +1724,7 @@
 
   @override
   Token get firstTokenAfterCommentAndMetadata {
-    if (abstractKeyword != null) {
-      return abstractKeyword!;
-    }
-    return typedefKeyword;
+    return abstractKeyword ?? typedefKeyword;
   }
 
   @override
@@ -2478,12 +2472,9 @@
 
   @override
   Token get firstTokenAfterCommentAndMetadata {
-    Token? leftMost =
-        Token.lexicallyFirst([externalKeyword, constKeyword, factoryKeyword]);
-    if (leftMost != null) {
-      return leftMost;
-    }
-    return _returnType.beginToken;
+    return Token.lexicallyFirst(
+            externalKeyword, constKeyword, factoryKeyword) ??
+        _returnType.beginToken;
   }
 
   @override
@@ -2810,12 +2801,7 @@
 
   @override
   Token get firstTokenAfterCommentAndMetadata {
-    if (keyword != null) {
-      return keyword!;
-    } else if (_type != null) {
-      return _type!.beginToken;
-    }
-    return _identifier.beginToken;
+    return keyword ?? _type?.beginToken ?? _identifier.beginToken;
   }
 
   @override
@@ -3938,16 +3924,9 @@
 
   @override
   Token get firstTokenAfterCommentAndMetadata {
-    if (abstractKeyword != null) {
-      return abstractKeyword!;
-    } else if (externalKeyword != null) {
-      return externalKeyword!;
-    } else if (covariantKeyword != null) {
-      return covariantKeyword!;
-    } else if (staticKeyword != null) {
-      return staticKeyword!;
-    }
-    return _fieldList.beginToken;
+    return Token.lexicallyFirst(abstractKeyword, externalKeyword,
+            covariantKeyword, staticKeyword) ??
+        _fieldList.beginToken;
   }
 
   @override
@@ -4782,14 +4761,10 @@
 
   @override
   Token get firstTokenAfterCommentAndMetadata {
-    if (externalKeyword != null) {
-      return externalKeyword!;
-    } else if (_returnType != null) {
-      return _returnType!.beginToken;
-    } else if (propertyKeyword != null) {
-      return propertyKeyword!;
-    }
-    return _name.beginToken;
+    return externalKeyword ??
+        _returnType?.beginToken ??
+        propertyKeyword ??
+        _name.beginToken;
   }
 
   @override
@@ -6906,18 +6881,10 @@
 
   @override
   Token get firstTokenAfterCommentAndMetadata {
-    if (externalKeyword != null) {
-      return externalKeyword!;
-    } else if (modifierKeyword != null) {
-      return modifierKeyword!;
-    } else if (_returnType != null) {
-      return _returnType!.beginToken;
-    } else if (propertyKeyword != null) {
-      return propertyKeyword!;
-    } else if (operatorKeyword != null) {
-      return operatorKeyword!;
-    }
-    return _name.beginToken;
+    return Token.lexicallyFirst(externalKeyword, modifierKeyword) ??
+        _returnType?.beginToken ??
+        Token.lexicallyFirst(propertyKeyword, operatorKeyword) ??
+        _name.beginToken;
   }
 
   @override
@@ -10510,14 +10477,9 @@
 
   @override
   Token get firstTokenAfterCommentAndMetadata {
-    if (lateKeyword != null) {
-      return lateKeyword!;
-    } else if (keyword != null) {
-      return keyword!;
-    } else if (_type != null) {
-      return _type!.beginToken;
-    }
-    return _variables.beginToken!;
+    return Token.lexicallyFirst(lateKeyword, keyword) ??
+        _type?.beginToken ??
+        _variables.beginToken!;
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
index 9528af0..ee8b5c1 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
@@ -2662,6 +2662,14 @@
   );
 
   /**
+   * Parameters:
+   * 0: the name of the type
+   */
+  static const HintCode UNNECESSARY_QUESTION_MARK = HintCode(
+      'UNNECESSARY_QUESTION_MARK',
+      "The '?' is unnecessary because '{0}' is nullable without it.");
+
+  /**
    * No parameters.
    */
   // #### Description
diff --git a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
index 7fd4b29..0fb7a3a 100644
--- a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
@@ -86,11 +87,13 @@
     _inferenceHelper.recordStaticType(node, staticType);
   }
 
-  void _checkNonBoolOperand(Expression operand, String operator) {
+  void _checkNonBoolOperand(Expression operand, String operator,
+      {required Map<DartType, NonPromotionReason> Function()? whyNotPromoted}) {
     _resolver.boolExpressionVerifier.checkForNonBoolExpression(
       operand,
       errorCode: CompileTimeErrorCode.NON_BOOL_OPERAND,
       arguments: [operator],
+      whyNotPromoted: whyNotPromoted,
     );
   }
 
@@ -108,6 +111,8 @@
     var right = node.rightOperand;
     right.accept(_resolver);
     right = node.rightOperand;
+    var whyNotPromotedInfo =
+        _resolver.flowAnalysis?.flow?.whyNotPromoted(right);
 
     if (!leftExtensionOverride) {
       flow?.equalityOp_end(node, right, right.typeOrThrow, notEqual: notEqual);
@@ -119,6 +124,9 @@
       promoteLeftTypeToNonNull: true,
     );
     _resolveUserDefinableType(node);
+    _resolver.checkForArgumentTypeNotAssignableForArgument(node.rightOperand,
+        promoteParameterToNullable: true,
+        whyNotPromotedInfo: whyNotPromotedInfo);
   }
 
   void _resolveIfNull(BinaryExpressionImpl node) {
@@ -154,6 +162,7 @@
     } else {
       _analyzeLeastUpperBoundTypes(node, leftType, rightType);
     }
+    _resolver.checkForArgumentTypeNotAssignableForArgument(right);
   }
 
   void _resolveLogicalAnd(BinaryExpressionImpl node) {
@@ -167,13 +176,16 @@
     flow?.logicalBinaryOp_begin();
     left.accept(_resolver);
     left = node.leftOperand;
+    var leftWhyNotPromoted = _resolver.flowAnalysis?.flow?.whyNotPromoted(left);
 
+    Map<DartType, NonPromotionReason> Function()? rightWhyNotPromoted;
     if (_resolver.flowAnalysis != null) {
       flow?.logicalBinaryOp_rightBegin(left, node, isAnd: true);
       _resolver.checkUnreachableNode(right);
 
       right.accept(_resolver);
       right = node.rightOperand;
+      rightWhyNotPromoted = _resolver.flowAnalysis!.flow?.whyNotPromoted(right);
 
       _resolver.nullSafetyDeadCodeVerifier.flowEnd(right);
       flow?.logicalBinaryOp_end(node, right, isAnd: true);
@@ -188,8 +200,8 @@
       );
     }
 
-    _checkNonBoolOperand(left, '&&');
-    _checkNonBoolOperand(right, '&&');
+    _checkNonBoolOperand(left, '&&', whyNotPromoted: leftWhyNotPromoted);
+    _checkNonBoolOperand(right, '&&', whyNotPromoted: rightWhyNotPromoted);
 
     _inferenceHelper.recordStaticType(node, _typeProvider.boolType);
   }
@@ -205,18 +217,21 @@
     flow?.logicalBinaryOp_begin();
     left.accept(_resolver);
     left = node.leftOperand;
+    var leftWhyNotPromoted = _resolver.flowAnalysis?.flow?.whyNotPromoted(left);
 
     flow?.logicalBinaryOp_rightBegin(left, node, isAnd: false);
     _resolver.checkUnreachableNode(right);
 
     right.accept(_resolver);
     right = node.rightOperand;
+    var rightWhyNotPromoted =
+        _resolver.flowAnalysis?.flow?.whyNotPromoted(right);
 
     _resolver.nullSafetyDeadCodeVerifier.flowEnd(right);
     flow?.logicalBinaryOp_end(node, right, isAnd: false);
 
-    _checkNonBoolOperand(left, '||');
-    _checkNonBoolOperand(right, '||');
+    _checkNonBoolOperand(left, '||', whyNotPromoted: leftWhyNotPromoted);
+    _checkNonBoolOperand(right, '||', whyNotPromoted: rightWhyNotPromoted);
 
     _inferenceHelper.recordStaticType(node, _typeProvider.boolType);
   }
@@ -259,8 +274,13 @@
     }
 
     right.accept(_resolver);
+    right = node.rightOperand;
+    var whyNotPromotedInfo =
+        _resolver.flowAnalysis?.flow?.whyNotPromoted(right);
 
     _resolveUserDefinableType(node);
+    _resolver.checkForArgumentTypeNotAssignableForArgument(right,
+        whyNotPromotedInfo: whyNotPromotedInfo);
   }
 
   void _resolveUserDefinableElement(
diff --git a/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart
index 7e600a4..3c44519 100644
--- a/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart
@@ -159,7 +159,10 @@
       InferenceContext.setType(condition, _resolver.typeProvider.boolType);
       condition.accept(_resolver);
       condition = forParts.condition!;
-      _resolver.boolExpressionVerifier.checkForNonBoolCondition(condition);
+      var whyNotPromoted =
+          _resolver.flowAnalysis?.flow?.whyNotPromoted(condition);
+      _resolver.boolExpressionVerifier
+          .checkForNonBoolCondition(condition, whyNotPromoted: whyNotPromoted);
     }
 
     _resolver.flowAnalysis?.for_bodyBegin(node, condition);
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 99ed1ac..3201626 100644
--- a/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
@@ -226,8 +226,10 @@
 
     operand.accept(_resolver);
     operand = node.operand;
+    var whyNotPromoted = _resolver.flowAnalysis?.flow?.whyNotPromoted(operand);
 
-    _resolver.boolExpressionVerifier.checkForNonBoolNegationExpression(operand);
+    _resolver.boolExpressionVerifier.checkForNonBoolNegationExpression(operand,
+        whyNotPromoted: whyNotPromoted);
 
     _recordStaticType(node, _typeProvider.boolType);
 
diff --git a/pkg/analyzer/lib/src/error/best_practices_verifier.dart b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
index 388384f..c2c568d 100644
--- a/pkg/analyzer/lib/src/error/best_practices_verifier.dart
+++ b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
@@ -689,6 +689,23 @@
     }
   }
 
+  @override
+  void visitTypeName(TypeName node) {
+    if (node.question != null) {
+      var name = node.name.name;
+      var type = node.typeOrThrow;
+      // Only report non-aliased, non-user-defined `Null?` and `dynamic?`. Do
+      // not report synthetic `dynamic` in place of an unresolved type.
+      if ((type.element == _nullType.element ||
+              (type.isDynamic && name == 'dynamic')) &&
+          type.aliasElement == null) {
+        _errorReporter.reportErrorForNode(
+            HintCode.UNNECESSARY_QUESTION_MARK, node, [name]);
+      }
+    }
+    super.visitTypeName(node);
+  }
+
   /// Check for the passed is expression for the unnecessary type check hint
   /// codes as well as null checks expressed using an is expression.
   ///
diff --git a/pkg/analyzer/lib/src/error/bool_expression_verifier.dart b/pkg/analyzer/lib/src/error/bool_expression_verifier.dart
index 79d5369..43d2462 100644
--- a/pkg/analyzer/lib/src/error/bool_expression_verifier.dart
+++ b/pkg/analyzer/lib/src/error/bool_expression_verifier.dart
@@ -2,55 +2,62 @@
 // 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/flow_analysis/flow_analysis.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/src/dart/ast/extensions.dart';
 import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/dart/element/type_system.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/error/nullable_dereference_verifier.dart';
+import 'package:analyzer/src/generated/resolver.dart';
 
 /// Helper for verifying expression that should be of type bool.
 class BoolExpressionVerifier {
-  final TypeSystemImpl _typeSystem;
+  final ResolverVisitor _resolver;
   final ErrorReporter _errorReporter;
   final NullableDereferenceVerifier _nullableDereferenceVerifier;
 
   final InterfaceType _boolType;
 
   BoolExpressionVerifier({
-    required TypeSystemImpl typeSystem,
+    required ResolverVisitor resolver,
     required ErrorReporter errorReporter,
     required NullableDereferenceVerifier nullableDereferenceVerifier,
-  })   : _typeSystem = typeSystem,
+  })   : _resolver = resolver,
         _errorReporter = errorReporter,
         _nullableDereferenceVerifier = nullableDereferenceVerifier,
-        _boolType = typeSystem.typeProvider.boolType;
+        _boolType = resolver.typeSystem.typeProvider.boolType;
 
   /// Check to ensure that the [condition] is of type bool, are. Otherwise an
   /// error is reported on the expression.
   ///
   /// See [CompileTimeErrorCode.NON_BOOL_CONDITION].
-  void checkForNonBoolCondition(Expression condition) {
+  void checkForNonBoolCondition(Expression condition,
+      {required Map<DartType, NonPromotionReason> Function()? whyNotPromoted}) {
     checkForNonBoolExpression(
       condition,
       errorCode: CompileTimeErrorCode.NON_BOOL_CONDITION,
+      whyNotPromoted: whyNotPromoted,
     );
   }
 
   /// Verify that the given [expression] is of type 'bool', and report
   /// [errorCode] if not, or a nullability error if its improperly nullable.
   void checkForNonBoolExpression(Expression expression,
-      {required ErrorCode errorCode, List<Object>? arguments}) {
+      {required ErrorCode errorCode,
+      List<Object>? arguments,
+      required Map<DartType, NonPromotionReason> Function()? whyNotPromoted}) {
     var type = expression.typeOrThrow;
     if (!_checkForUseOfVoidResult(expression) &&
-        !_typeSystem.isAssignableTo(type, _boolType)) {
+        !_resolver.typeSystem.isAssignableTo(type, _boolType)) {
       if (type.isDartCoreBool) {
         _nullableDereferenceVerifier.report(expression, type,
             errorCode: CompileTimeErrorCode
-                .UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION);
+                .UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION,
+            messages: _resolver.computeWhyNotPromotedMessages(
+                expression, expression, whyNotPromoted?.call()));
       } else {
         _errorReporter.reportErrorForNode(errorCode, expression, arguments);
       }
@@ -58,10 +65,12 @@
   }
 
   /// Checks to ensure that the given [expression] is assignable to bool.
-  void checkForNonBoolNegationExpression(Expression expression) {
+  void checkForNonBoolNegationExpression(Expression expression,
+      {required Map<DartType, NonPromotionReason> Function()? whyNotPromoted}) {
     checkForNonBoolExpression(
       expression,
       errorCode: CompileTimeErrorCode.NON_BOOL_NEGATION_EXPRESSION,
+      whyNotPromoted: whyNotPromoted,
     );
   }
 
diff --git a/pkg/analyzer/lib/src/generated/error_detection_helpers.dart b/pkg/analyzer/lib/src/generated/error_detection_helpers.dart
index 7ffc94c..f20e538 100644
--- a/pkg/analyzer/lib/src/generated/error_detection_helpers.dart
+++ b/pkg/analyzer/lib/src/generated/error_detection_helpers.dart
@@ -39,7 +39,7 @@
         return;
       }
 
-      checkForAssignableExpressionAtType(
+      _checkForAssignableExpressionAtType(
           expression, actualStaticType, expectedStaticType, errorCode,
           whyNotPromotedInfo: whyNotPromotedInfo);
     }
@@ -81,33 +81,99 @@
         whyNotPromotedInfo);
   }
 
-  bool checkForAssignableExpressionAtType(
-      Expression expression,
-      DartType actualStaticType,
-      DartType expectedStaticType,
-      ErrorCode errorCode,
-      {Map<DartType, NonPromotionReason> Function()? whyNotPromotedInfo}) {
-    if (!typeSystem.isAssignableTo(actualStaticType, expectedStaticType)) {
-      AstNode getErrorNode(AstNode node) {
-        if (node is CascadeExpression) {
-          return getErrorNode(node.target);
-        }
-        if (node is ParenthesizedExpression) {
-          return getErrorNode(node.expression);
-        }
-        return node;
+  /// Verify that the given constructor field [initializer] has compatible field
+  /// and initializer expression types. The [fieldElement] is the static element
+  /// from the name in the [ConstructorFieldInitializer].
+  ///
+  /// See [CompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE], and
+  /// [StaticWarningCode.FIELD_INITIALIZER_NOT_ASSIGNABLE].
+  void checkForFieldInitializerNotAssignable(
+      ConstructorFieldInitializer initializer, FieldElement fieldElement,
+      {required bool isConstConstructor}) {
+    // prepare field type
+    DartType fieldType = fieldElement.type;
+    // prepare expression type
+    Expression expression = initializer.expression;
+    // test the static type of the expression
+    DartType staticType = expression.typeOrThrow;
+    if (typeSystem.isAssignableTo(staticType, fieldType)) {
+      if (!fieldType.isVoid) {
+        checkForUseOfVoidResult(expression);
       }
-
-      errorReporter.reportErrorForNode(
-        errorCode,
-        getErrorNode(expression),
-        [actualStaticType, expectedStaticType],
-        computeWhyNotPromotedMessages(
-            expression, expression, whyNotPromotedInfo?.call()),
-      );
-      return false;
+      return;
     }
-    return true;
+    // report problem
+    if (isConstConstructor) {
+      // TODO(paulberry): this error should be based on the actual type of the
+      // constant, not the static type.  See dartbug.com/21119.
+      errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE,
+          expression,
+          [staticType, fieldType]);
+    }
+    errorReporter.reportErrorForNode(
+        CompileTimeErrorCode.FIELD_INITIALIZER_NOT_ASSIGNABLE,
+        expression,
+        [staticType, fieldType]);
+    // TODO(brianwilkerson) Define a hint corresponding to these errors and
+    // report it if appropriate.
+//        // test the propagated type of the expression
+//        Type propagatedType = expression.getPropagatedType();
+//        if (propagatedType != null && propagatedType.isAssignableTo(fieldType)) {
+//          return false;
+//        }
+//        // report problem
+//        if (isEnclosingConstructorConst) {
+//          errorReporter.reportTypeErrorForNode(
+//              CompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE,
+//              expression,
+//              propagatedType == null ? staticType : propagatedType,
+//              fieldType);
+//        } else {
+//          errorReporter.reportTypeErrorForNode(
+//              StaticWarningCode.FIELD_INITIALIZER_NOT_ASSIGNABLE,
+//              expression,
+//              propagatedType == null ? staticType : propagatedType,
+//              fieldType);
+//        }
+//        return true;
+  }
+
+  /// Verify that the given left hand side ([lhs]) and right hand side ([rhs])
+  /// represent a valid assignment.
+  ///
+  /// See [CompileTimeErrorCode.INVALID_ASSIGNMENT].
+  void checkForInvalidAssignment(Expression? lhs, Expression? rhs) {
+    if (lhs == null || rhs == null) {
+      return;
+    }
+
+    if (lhs is IndexExpression &&
+            identical(lhs.realTarget.staticType, NeverTypeImpl.instance) ||
+        lhs is PrefixedIdentifier &&
+            identical(lhs.prefix.staticType, NeverTypeImpl.instance) ||
+        lhs is PropertyAccess &&
+            identical(lhs.realTarget.staticType, NeverTypeImpl.instance)) {
+      return;
+    }
+
+    DartType leftType;
+    var parent = lhs.parent;
+    if (parent is AssignmentExpression && parent.leftHandSide == lhs) {
+      leftType = parent.writeType!;
+    } else {
+      var leftVariableElement = getVariableElement(lhs);
+      leftType = (leftVariableElement == null)
+          ? lhs.typeOrThrow
+          : leftVariableElement.type;
+    }
+
+    if (!leftType.isVoid && checkForUseOfVoidResult(rhs)) {
+      return;
+    }
+
+    _checkForAssignableExpression(
+        rhs, leftType, CompileTimeErrorCode.INVALID_ASSIGNMENT);
   }
 
   /// Check for situations where the result of a method or function is used,
@@ -148,6 +214,18 @@
       SyntacticEntity errorEntity,
       Map<DartType, NonPromotionReason>? whyNotPromoted);
 
+  /// Return the variable element represented by the given [expression], or
+  /// `null` if there is no such element.
+  VariableElement? getVariableElement(Expression? expression) {
+    if (expression is Identifier) {
+      var element = expression.staticElement;
+      if (element is VariableElement) {
+        return element;
+      }
+    }
+    return null;
+  }
+
   /// Verify that the given [expression] can be assigned to its corresponding
   /// parameters.
   ///
@@ -167,4 +245,40 @@
         expression, expectedStaticType, expression.typeOrThrow, errorCode,
         whyNotPromotedInfo: whyNotPromotedInfo);
   }
+
+  bool _checkForAssignableExpression(
+      Expression expression, DartType expectedStaticType, ErrorCode errorCode) {
+    DartType actualStaticType = expression.typeOrThrow;
+    return _checkForAssignableExpressionAtType(
+        expression, actualStaticType, expectedStaticType, errorCode);
+  }
+
+  bool _checkForAssignableExpressionAtType(
+      Expression expression,
+      DartType actualStaticType,
+      DartType expectedStaticType,
+      ErrorCode errorCode,
+      {Map<DartType, NonPromotionReason> Function()? whyNotPromotedInfo}) {
+    if (!typeSystem.isAssignableTo(actualStaticType, expectedStaticType)) {
+      AstNode getErrorNode(AstNode node) {
+        if (node is CascadeExpression) {
+          return getErrorNode(node.target);
+        }
+        if (node is ParenthesizedExpression) {
+          return getErrorNode(node.expression);
+        }
+        return node;
+      }
+
+      errorReporter.reportErrorForNode(
+        errorCode,
+        getErrorNode(expression),
+        [actualStaticType, expectedStaticType],
+        computeWhyNotPromotedMessages(
+            expression, expression, whyNotPromotedInfo?.call()),
+      );
+      return false;
+    }
+    return true;
+  }
 }
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 55a6019..0fa0cae 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -350,7 +350,7 @@
         operatorType == TokenType.QUESTION_QUESTION_EQ) {
       // Already handled in the assignment resolver.
       if (lhs is! SimpleIdentifier) {
-        _checkForInvalidAssignment(lhs, rhs);
+        checkForInvalidAssignment(lhs, rhs);
       }
     } else {
       checkForArgumentTypeNotAssignableForArgument(rhs);
@@ -388,13 +388,8 @@
     TokenType type = operator.type;
     if (type == TokenType.AMPERSAND_AMPERSAND || type == TokenType.BAR_BAR) {
       checkForUseOfVoidResult(node.rightOperand);
-    } else if (type == TokenType.EQ_EQ || type == TokenType.BANG_EQ) {
-      checkForArgumentTypeNotAssignableForArgument(node.rightOperand,
-          promoteParameterToNullable: true);
-    } else if (type != TokenType.QUESTION_QUESTION) {
-      checkForArgumentTypeNotAssignableForArgument(node.rightOperand);
     } else {
-      checkForArgumentTypeNotAssignableForArgument(node.rightOperand);
+      // Assignability checking is done by the resolver.
     }
 
     if (type == TokenType.QUESTION_QUESTION) {
@@ -552,7 +547,6 @@
       var staticElement = fieldName.staticElement;
       _checkForInvalidField(node, fieldName, staticElement);
       if (staticElement is FieldElement) {
-        _checkForFieldInitializerNotAssignable(node, staticElement);
         _checkForAbstractOrExternalFieldConstructorInitializer(
             node.fieldName, staticElement);
       }
@@ -577,7 +571,7 @@
 
   @override
   void visitDefaultFormalParameter(DefaultFormalParameter node) {
-    _checkForInvalidAssignment(node.identifier, node.defaultValue);
+    checkForInvalidAssignment(node.identifier, node.defaultValue);
     super.visitDefaultFormalParameter(node);
   }
 
@@ -1254,7 +1248,6 @@
     SimpleIdentifier nameNode = node.name;
     var initializerNode = node.initializer;
     // do checks
-    _checkForInvalidAssignment(nameNode, initializerNode);
     _checkForImplicitDynamicIdentifier(node, nameNode);
     _checkForAbstractOrExternalVariableInitializer(node);
     // visit name
@@ -1530,13 +1523,6 @@
     }
   }
 
-  bool _checkForAssignableExpression(
-      Expression expression, DartType expectedStaticType, ErrorCode errorCode) {
-    DartType actualStaticType = expression.typeOrThrow;
-    return checkForAssignableExpressionAtType(
-        expression, actualStaticType, expectedStaticType, errorCode);
-  }
-
   /// Verify that the given [expression] is not final.
   ///
   /// See [StaticWarningCode.ASSIGNMENT_TO_CONST],
@@ -2401,63 +2387,6 @@
     }
   }
 
-  /// Verify that the given constructor field [initializer] has compatible field
-  /// and initializer expression types. The [fieldElement] is the static element
-  /// from the name in the [ConstructorFieldInitializer].
-  ///
-  /// See [CompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE], and
-  /// [StaticWarningCode.FIELD_INITIALIZER_NOT_ASSIGNABLE].
-  void _checkForFieldInitializerNotAssignable(
-      ConstructorFieldInitializer initializer, FieldElement fieldElement) {
-    // prepare field type
-    DartType fieldType = fieldElement.type;
-    // prepare expression type
-    Expression expression = initializer.expression;
-    // test the static type of the expression
-    DartType staticType = expression.typeOrThrow;
-    if (typeSystem.isAssignableTo(staticType, fieldType)) {
-      if (!fieldType.isVoid) {
-        checkForUseOfVoidResult(expression);
-      }
-      return;
-    }
-    // report problem
-    if (_enclosingExecutable.isConstConstructor) {
-      // TODO(paulberry): this error should be based on the actual type of the
-      // constant, not the static type.  See dartbug.com/21119.
-      errorReporter.reportErrorForNode(
-          CompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE,
-          expression,
-          [staticType, fieldType]);
-    }
-    errorReporter.reportErrorForNode(
-        CompileTimeErrorCode.FIELD_INITIALIZER_NOT_ASSIGNABLE,
-        expression,
-        [staticType, fieldType]);
-    // TODO(brianwilkerson) Define a hint corresponding to these errors and
-    // report it if appropriate.
-//        // test the propagated type of the expression
-//        Type propagatedType = expression.getPropagatedType();
-//        if (propagatedType != null && propagatedType.isAssignableTo(fieldType)) {
-//          return false;
-//        }
-//        // report problem
-//        if (isEnclosingConstructorConst) {
-//          errorReporter.reportTypeErrorForNode(
-//              CompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE,
-//              expression,
-//              propagatedType == null ? staticType : propagatedType,
-//              fieldType);
-//        } else {
-//          errorReporter.reportTypeErrorForNode(
-//              StaticWarningCode.FIELD_INITIALIZER_NOT_ASSIGNABLE,
-//              expression,
-//              propagatedType == null ? staticType : propagatedType,
-//              fieldType);
-//        }
-//        return true;
-  }
-
   /// Verify that the given field formal [parameter] is in a constructor
   /// declaration.
   ///
@@ -2758,43 +2687,6 @@
     }
   }
 
-  /// Verify that the given left hand side ([lhs]) and right hand side ([rhs])
-  /// represent a valid assignment.
-  ///
-  /// See [CompileTimeErrorCode.INVALID_ASSIGNMENT].
-  void _checkForInvalidAssignment(Expression? lhs, Expression? rhs) {
-    if (lhs == null || rhs == null) {
-      return;
-    }
-
-    if (lhs is IndexExpression &&
-            identical(lhs.realTarget.staticType, NeverTypeImpl.instance) ||
-        lhs is PrefixedIdentifier &&
-            identical(lhs.prefix.staticType, NeverTypeImpl.instance) ||
-        lhs is PropertyAccess &&
-            identical(lhs.realTarget.staticType, NeverTypeImpl.instance)) {
-      return;
-    }
-
-    DartType leftType;
-    var parent = lhs.parent;
-    if (parent is AssignmentExpression && parent.leftHandSide == lhs) {
-      leftType = parent.writeType!;
-    } else {
-      var leftVariableElement = getVariableElement(lhs);
-      leftType = (leftVariableElement == null)
-          ? lhs.typeOrThrow
-          : leftVariableElement.type;
-    }
-
-    if (!leftType.isVoid && checkForUseOfVoidResult(rhs)) {
-      return;
-    }
-
-    _checkForAssignableExpression(
-        rhs, leftType, CompileTimeErrorCode.INVALID_ASSIGNMENT);
-  }
-
   /// Check the given [initializer] to ensure that the field being initialized
   /// is a valid field. The [fieldName] is the field name from the
   /// [ConstructorFieldInitializer]. The [staticElement] is the static element
@@ -5172,18 +5064,6 @@
 
     return fields.toList();
   }
-
-  /// Return the variable element represented by the given [expression], or
-  /// `null` if there is no such element.
-  static VariableElement? getVariableElement(Expression? expression) {
-    if (expression is Identifier) {
-      var element = expression.staticElement;
-      if (element is VariableElement) {
-        return element;
-      }
-    }
-    return null;
-  }
 }
 
 /// A record of the elements that will be declared in some scope (block), but
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index dff2a86..7490aef 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -325,7 +325,7 @@
       resolver: this,
     );
     boolExpressionVerifier = BoolExpressionVerifier(
-      typeSystem: typeSystem,
+      resolver: this,
       errorReporter: errorReporter,
       nullableDereferenceVerifier: nullableDereferenceVerifier,
     );
@@ -993,6 +993,7 @@
     boolExpressionVerifier.checkForNonBoolExpression(
       node.condition,
       errorCode: CompileTimeErrorCode.NON_BOOL_EXPRESSION,
+      whyNotPromoted: flowAnalysis?.flow?.whyNotPromoted(node.condition),
     );
     flowAnalysis?.flow?.assert_afterCondition(node.condition);
     node.message?.accept(this);
@@ -1007,6 +1008,7 @@
     boolExpressionVerifier.checkForNonBoolExpression(
       node.condition,
       errorCode: CompileTimeErrorCode.NON_BOOL_EXPRESSION,
+      whyNotPromoted: flowAnalysis?.flow?.whyNotPromoted(node.condition),
     );
     flowAnalysis?.flow?.assert_afterCondition(node.condition);
     node.message?.accept(this);
@@ -1187,7 +1189,9 @@
     // TODO(scheglov) Do we need these checks for null?
     condition.accept(this);
     condition = node.condition;
-    boolExpressionVerifier.checkForNonBoolCondition(condition);
+    var whyNotPromoted = flowAnalysis?.flow?.whyNotPromoted(condition);
+    boolExpressionVerifier.checkForNonBoolCondition(condition,
+        whyNotPromoted: whyNotPromoted);
 
     Expression thenExpression = node.thenExpression;
     InferenceContext.setTypeFromNode(thenExpression, node);
@@ -1295,6 +1299,11 @@
     node.expression.accept(this);
     node.accept(elementResolver);
     node.accept(typeAnalyzer);
+    var enclosingConstructor = enclosingFunction as ConstructorElement;
+    if (fieldElement != null) {
+      checkForFieldInitializerNotAssignable(node, fieldElement,
+          isConstConstructor: enclosingConstructor.isConst);
+    }
   }
 
   @override
@@ -1349,7 +1358,9 @@
     InferenceContext.setType(condition, typeProvider.boolType);
     condition.accept(this);
     condition = node.condition;
-    boolExpressionVerifier.checkForNonBoolCondition(condition);
+    var whyNotPromoted = flowAnalysis?.flow?.whyNotPromoted(condition);
+    boolExpressionVerifier.checkForNonBoolCondition(condition,
+        whyNotPromoted: whyNotPromoted);
 
     flowAnalysis?.flow?.doStatement_end(condition);
   }
@@ -1598,8 +1609,10 @@
     InferenceContext.setType(condition, typeProvider.boolType);
     condition.accept(this);
     condition = node.condition;
+    var whyNotPromoted = flowAnalysis?.flow?.whyNotPromoted(condition);
 
-    boolExpressionVerifier.checkForNonBoolCondition(condition);
+    boolExpressionVerifier.checkForNonBoolCondition(condition,
+        whyNotPromoted: whyNotPromoted);
 
     CollectionElement thenElement = node.thenElement;
     if (flowAnalysis != null) {
@@ -1637,8 +1650,10 @@
     InferenceContext.setType(condition, typeProvider.boolType);
     condition.accept(this);
     condition = node.condition;
+    var whyNotPromoted = flowAnalysis?.flow?.whyNotPromoted(condition);
 
-    boolExpressionVerifier.checkForNonBoolCondition(condition);
+    boolExpressionVerifier.checkForNonBoolCondition(condition,
+        whyNotPromoted: whyNotPromoted);
 
     Statement thenStatement = node.thenStatement;
     if (flowAnalysis != null) {
@@ -1837,6 +1852,10 @@
   void visitNamedExpression(NamedExpression node) {
     InferenceContext.setTypeFromNode(node.expression, node);
     super.visitNamedExpression(node);
+    // Any "why not promoted" information that flow analysis had associated with
+    // `node.expression` now needs to be forwarded to `node`, so that when
+    // `visitArgumentList` iterates through the arguments, it will find it.
+    flowAnalysis?.flow?.forwardExpression(node, node.expression);
   }
 
   @override
@@ -2141,6 +2160,7 @@
             isFinal: parent.isFinal, isLate: parent.isLate);
       }
     }
+    checkForInvalidAssignment(node.name, node.initializer);
   }
 
   @override
@@ -2168,8 +2188,11 @@
 
       flowAnalysis?.flow?.whileStatement_conditionBegin(node);
       condition.accept(this);
+      condition = node.condition;
+      var whyNotPromoted = flowAnalysis?.flow?.whyNotPromoted(condition);
 
-      boolExpressionVerifier.checkForNonBoolCondition(node.condition);
+      boolExpressionVerifier.checkForNonBoolCondition(node.condition,
+          whyNotPromoted: whyNotPromoted);
 
       Statement body = node.body;
       flowAnalysis?.flow?.whileStatement_bodyBegin(node, condition);
diff --git a/pkg/analyzer/lib/src/ignore_comments/ignore_info.dart b/pkg/analyzer/lib/src/ignore_comments/ignore_info.dart
index 507ea06..a6f0f56 100644
--- a/pkg/analyzer/lib/src/ignore_comments/ignore_info.dart
+++ b/pkg/analyzer/lib/src/ignore_comments/ignore_info.dart
@@ -209,15 +209,23 @@
 }
 
 extension on CommentToken {
+  /// The error codes currently do not contain dollar signs, so we can be a bit
+  /// more restrictive in this test.
+  static final _errorCodeNameRegExp = RegExp(r'^[a-zA-Z][_a-z0-9A-Z]*$');
+
   /// Return the diagnostic names contained in this comment, assuming that it is
   /// a correctly formatted ignore comment.
   Iterable<DiagnosticName> get diagnosticNames sync* {
+    bool isValidErrorCodeName(String text) {
+      return text.contains(_errorCodeNameRegExp);
+    }
+
     int offset = lexeme.indexOf(':') + 1;
     var names = lexeme.substring(offset).split(',');
     offset += this.offset;
     for (var name in names) {
       var trimmedName = name.trim();
-      if (trimmedName.isNotEmpty) {
+      if (trimmedName.isNotEmpty && isValidErrorCodeName(trimmedName)) {
         var innerOffset = name.indexOf(trimmedName);
         yield DiagnosticName(trimmedName.toLowerCase(), offset + innerOffset);
       }
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
index 18733e8..ab2b7b2 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
@@ -614,7 +614,7 @@
       node,
       codeOffset: codeOffset,
       codeLength: codeLength,
-      resolutionIndex: -1,
+      resolutionIndex: _readUInt30(),
       documentationTokenIndexList: documentationTokenIndexList,
     );
 
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart b/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
index 74968d8..e4ff4f3 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
@@ -534,6 +534,7 @@
 
   @override
   void visitEnumConstantDeclaration(EnumConstantDeclaration node) {
+    var resolutionIndex = _getNextResolutionIndex();
     _writeByte(Tag.EnumConstantDeclaration);
 
     _writeInformativeUint30(node.offset);
@@ -545,6 +546,7 @@
     _writeMarker(MarkerTag.EnumConstantDeclaration_declaration);
     _storeDeclaration(node);
     _writeMarker(MarkerTag.EnumConstantDeclaration_end);
+    _writeUInt30(resolutionIndex);
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/summary2/bundle_reader.dart b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
index 9f484b6..38a0e91 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
@@ -489,12 +489,6 @@
     }
     _isApplied = true;
 
-    // EnumConstantDeclaration has no separate resolution.
-    // Its metadata is resolved during EnumDeclaration resolution.
-    if (_resolutionIndex == -1) {
-      return;
-    }
-
     var localElements = <Element>[];
     var resolutionReader = LinkedResolutionReader(
       _unitReader,
diff --git a/pkg/analyzer/lib/src/task/options.dart b/pkg/analyzer/lib/src/task/options.dart
index 921b235..ac0c4a4 100644
--- a/pkg/analyzer/lib/src/task/options.dart
+++ b/pkg/analyzer/lib/src/task/options.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:collection';
-
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/error/listener.dart';
@@ -296,26 +294,14 @@
   static final String legalValueString =
       StringUtilities.printListOfQuotedNames(legalValues);
 
-  /// Lazily populated set of error codes (hashed for speedy lookup).
-  static HashSet<String>? _errorCodes;
-
-  /// Legal error code names.
-  static Set<String> get errorCodes {
-    if (_errorCodes == null) {
-      _errorCodes = HashSet<String>();
-      // Engine codes.
-      _errorCodes!.addAll(errorCodeValues.map((ErrorCode code) => code.name));
-    }
-    return _errorCodes!;
-  }
+  /// Lazily populated set of error codes.
+  static final Set<String> _errorCodes =
+      errorCodeValues.map((ErrorCode code) => code.name).toSet();
 
   /// Lazily populated set of lint codes.
-  Set<String>? _lintCodes;
-
-  Set<String> get lintCodes {
-    return _lintCodes ??= Set.from(
-        Registry.ruleRegistry.rules.map((rule) => rule.name.toUpperCase()));
-  }
+  late final Set<String> _lintCodes = Registry.ruleRegistry.rules
+      .map((rule) => rule.name.toUpperCase())
+      .toSet();
 
   @override
   void validate(ErrorReporter reporter, YamlMap options) {
@@ -327,7 +313,7 @@
           String? value;
           if (k is YamlScalar) {
             value = toUpperCase(k.value);
-            if (!errorCodes.contains(value) && !lintCodes.contains(value)) {
+            if (!_errorCodes.contains(value) && !_lintCodes.contains(value)) {
               reporter.reportErrorForSpan(
                   AnalysisOptionsWarningCode.UNRECOGNIZED_ERROR_CODE,
                   k.span,
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 8c45917..ff51f4f 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
 name: analyzer
-version: 1.3.0-dev
+version: 1.3.0
 description: This package provides a library that performs static analysis of Dart code.
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer
 
@@ -7,7 +7,7 @@
   sdk: '>=2.12.0-0 <3.0.0'
 
 dependencies:
-  _fe_analyzer_shared: ^18.0.0
+  _fe_analyzer_shared: ^19.0.0
   cli_util: ^0.3.0
   collection: ^1.15.0
   convert: ^3.0.0
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_caching_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_caching_test.dart
index 45ff977..ac0dca1 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_caching_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_caching_test.dart
@@ -22,6 +22,21 @@
     return driver.test.libraryContext.linkedCycles;
   }
 
+  test_change_factoryConstructor_addEqNothing() async {
+    await resolveTestCode(r'''
+class A {
+  factory A();
+}
+''');
+
+    driverFor(testFilePath).changeFile(testFilePath);
+    await resolveTestCode(r'''
+class A {
+  factory A() =;
+}
+''');
+  }
+
   test_change_factoryConstructor_moveStaticToken() async {
     await resolveTestCode(r'''
 class A {
diff --git a/pkg/analyzer/test/src/dart/analysis/unlinked_api_signature_test.dart b/pkg/analyzer/test/src/dart/analysis/unlinked_api_signature_test.dart
index 48bc6b5..fc8a498 100644
--- a/pkg/analyzer/test/src/dart/analysis/unlinked_api_signature_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/unlinked_api_signature_test.dart
@@ -242,6 +242,22 @@
 ''');
   }
 
+  /// The code `=;` is parsed as `= <emptyString>;`, and there was a bug that
+  /// the absence of the redirecting constructor was encoded as the same
+  /// byte sequence as the empty string. But these are different ASTs,
+  /// so they should have different signatures.
+  test_class_factoryConstructor_addEqNothing() {
+    assertNotSameSignature(r'''
+class A {
+  factory A();
+}
+''', r'''
+class A {
+  factory A() =;
+}
+''');
+  }
+
   /// The token `static` is moving from the field declaration to the factory
   /// constructor (its redirected constructor), so semantically its meaning
   /// changes. But we had a bug that we put `static` into the signature
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 9d666bb..02c71dc 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -641,6 +641,7 @@
 import 'unnecessary_non_null_assertion_test.dart'
     as unnecessary_non_null_assertion;
 import 'unnecessary_null_comparison_test.dart' as unnecessary_null_comparison;
+import 'unnecessary_question_mark_test.dart' as unnecessary_question_mark;
 import 'unnecessary_type_check_test.dart' as unnecessary_type_check;
 import 'unqualified_reference_to_non_local_static_member_test.dart'
     as unqualified_reference_to_non_local_static_member;
@@ -1104,6 +1105,7 @@
     unnecessary_no_such_method.main();
     unnecessary_non_null_assertion.main();
     unnecessary_null_comparison.main();
+    unnecessary_question_mark.main();
     unnecessary_type_check.main();
     unqualified_reference_to_non_local_static_member.main();
     unqualified_reference_to_static_member_of_extended_type.main();
diff --git a/pkg/analyzer/test/src/diagnostics/unnecessary_question_mark_test.dart b/pkg/analyzer/test/src/diagnostics/unnecessary_question_mark_test.dart
new file mode 100644
index 0000000..337484e
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/unnecessary_question_mark_test.dart
@@ -0,0 +1,52 @@
+// Copyright (c) 2021, 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/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(UnnecessaryQuestionMarkTest);
+  });
+}
+
+@reflectiveTest
+class UnnecessaryQuestionMarkTest extends PubPackageResolutionTest {
+  test_dynamic() async {
+    await assertNoErrorsInCode('''
+dynamic a;
+''');
+  }
+
+  test_dynamicQuestionMark() async {
+    await assertErrorsInCode('''
+dynamic? a;
+''', [
+      error(HintCode.UNNECESSARY_QUESTION_MARK, 0, 8),
+    ]);
+  }
+
+  test_Null() async {
+    await assertNoErrorsInCode('''
+Null a;
+''');
+  }
+
+  test_NullQuestionMark() async {
+    await assertErrorsInCode('''
+Null? a;
+''', [
+      error(HintCode.UNNECESSARY_QUESTION_MARK, 0, 5),
+    ]);
+  }
+
+  test_typeAliasQuestionMark() async {
+    await assertNoErrorsInCode('''
+typedef n = Null;
+n? a;
+''');
+  }
+}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 47c3f8b..9a6f814 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -10404,33 +10404,113 @@
   }
 
   test_metadata_enumConstantDeclaration() async {
-    var library = await checkLibrary('const a = null; enum E { @a v }');
-    checkElementText(library, r'''
+    var library = await checkLibrary('const a = 42; enum E { @a v }');
+    checkElementText(
+        library,
+        r'''
 enum E {
   synthetic final int index;
   synthetic static const List<E> values;
-  @
-        a/*location: test.dart;a?*/
   static const E v;
+    metadata
+      Annotation
+        element: self::@getter::a
+        name: SimpleIdentifier
+          staticElement: self::@getter::a
+          staticType: null
+          token: a
   String toString() {}
 }
-const dynamic a = null;
+const int a;
+  constantInitializer
+    IntegerLiteral
+      literal: 42
+      staticType: int
+''',
+        withFullyResolvedAst: true);
+  }
+
+  test_metadata_enumConstantDeclaration_instanceCreation() async {
+    var library = await checkLibrary('''
+class A {
+  final dynamic value;
+  const A(this.value);
+}
+
+enum E {
+  @A(100) a,
+  b,
+  @A(300) c,
+}
 ''');
+    checkElementText(
+        library,
+        r'''
+enum E {
+  synthetic final int index;
+  synthetic static const List<E> values;
+  static const E a;
+    metadata
+      Annotation
+        arguments: ArgumentList
+          arguments
+            IntegerLiteral
+              literal: 100
+              staticType: int
+        element: self::@class::A::@constructor::•
+        name: SimpleIdentifier
+          staticElement: self::@class::A
+          staticType: null
+          token: A
+  static const E b;
+  static const E c;
+    metadata
+      Annotation
+        arguments: ArgumentList
+          arguments
+            IntegerLiteral
+              literal: 300
+              staticType: int
+        element: self::@class::A::@constructor::•
+        name: SimpleIdentifier
+          staticElement: self::@class::A
+          staticType: null
+          token: A
+  String toString() {}
+}
+class A {
+  final dynamic value;
+  const A(dynamic this.value);
+}
+''',
+        withFullyResolvedAst: true);
   }
 
   test_metadata_enumDeclaration() async {
-    var library = await checkLibrary('const a = null; @a enum E { v }');
-    checkElementText(library, r'''
-@
-        a/*location: test.dart;a?*/
+    var library = await checkLibrary('const a = 42; @a enum E { v }');
+    checkElementText(
+        library,
+        r'''
 enum E {
   synthetic final int index;
   synthetic static const List<E> values;
   static const E v;
   String toString() {}
 }
-const dynamic a = null;
-''');
+  metadata
+    Annotation
+      element: self::@getter::a
+      name: SimpleIdentifier
+        staticElement: self::@getter::a
+        staticType: null
+        token: a
+const int a;
+  constantInitializer
+    IntegerLiteral
+      literal: 42
+      staticType: int
+''',
+        withFullyResolvedAst: true);
   }
 
   test_metadata_exportDirective() async {
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart
index dedd502..974e8a0 100644
--- a/pkg/compiler/lib/src/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load.dart
@@ -14,8 +14,7 @@
 import 'common/metrics.dart' show Metric, Metrics, CountMetric, DurationMetric;
 import 'common/tasks.dart' show CompilerTask;
 import 'common.dart';
-import 'common_elements.dart'
-    show CommonElements, ElementEnvironment, KElementEnvironment;
+import 'common_elements.dart' show CommonElements, KElementEnvironment;
 import 'compiler.dart' show Compiler;
 import 'constants/values.dart'
     show
@@ -89,13 +88,13 @@
   String get namespace => 'deferred_load';
 
   DurationMetric time = DurationMetric('time');
-  CountMetric hunkListElements = CountMetric('hunkListElements');
+  CountMetric outputUnitElements = CountMetric('outputUnitElements');
 
   @override
   Iterable<Metric> get primary => [time];
 
   @override
-  Iterable<Metric> get secondary => [hunkListElements];
+  Iterable<Metric> get secondary => [outputUnitElements];
 }
 
 /// For each deferred import, find elements and constants to be loaded when that
@@ -119,7 +118,7 @@
 
   /// A cache of the result of calling `computeImportDeferName` on the keys of
   /// this map.
-  final Map<ImportEntity, String> _importDeferName = {};
+  final Map<ImportEntity, String> importDeferName = {};
 
   /// A mapping from classes to their import set.
   Map<ClassEntity, ImportSet> _classToSet = {};
@@ -655,6 +654,7 @@
       counter++;
       importSet.unit = unit;
       _allOutputUnits.add(unit);
+      metrics.outputUnitElements.add(1);
     }
 
     // Generate an output unit for all import sets that are associated with an
@@ -669,8 +669,7 @@
     _allOutputUnits.sort();
   }
 
-  Map<String, List<OutputUnit>> _setupHunksToLoad() {
-    Map<String, List<OutputUnit>> hunksToLoad = {};
+  void _setupImportNames() {
     Set<String> usedImportNames = {};
 
     for (ImportEntity import in _allDeferredImports) {
@@ -679,38 +678,8 @@
       // Note: tools that process the json file to build multi-part initial load
       // bundles depend on the fact that makeUnique appends only digits, or a
       // period followed by digits.
-      _importDeferName[import] = makeUnique(result, usedImportNames, '.');
+      importDeferName[import] = makeUnique(result, usedImportNames, '.');
     }
-
-    // Sort the output units in descending order of the number of imports they
-    // include.
-
-    // The loading of the output units must be ordered because a superclass
-    // needs to be initialized before its subclass.
-    // But a class can only depend on another class in an output unit shared by
-    // a strict superset of the imports:
-    // By contradiction: Assume a class C in output unit shared by imports in
-    // the set S1 = (lib1,.., lib_n) depends on a class D in an output unit
-    // shared by S2 such that S2 not a superset of S1. Let lib_s be a library in
-    // S1 not in S2. lib_s must depend on C, and then in turn on D. Therefore D
-    // is not in the right output unit.
-    List<OutputUnit> sortedOutputUnits = _allOutputUnits.reversed.toList();
-
-    // For each deferred import we find out which outputUnits to load.
-    for (ImportEntity import in _allDeferredImports) {
-      // We expect to find an entry for any call to `loadLibrary`, even if
-      // there is no code to load. In that case, the entry will be an empty
-      // list.
-      hunksToLoad[_importDeferName[import]] = [];
-      for (OutputUnit outputUnit in sortedOutputUnits) {
-        if (outputUnit == _mainOutputUnit) continue;
-        if (outputUnit.imports.contains(import)) {
-          hunksToLoad[_importDeferName[import]].add(outputUnit);
-          metrics.hunkListElements.add(1);
-        }
-      }
-    }
-    return hunksToLoad;
   }
 
   /// Returns a name for a deferred import.
@@ -880,7 +849,7 @@
 
   OutputUnitData _buildResult() {
     _createOutputUnits();
-    Map<String, List<OutputUnit>> hunksToLoad = _setupHunksToLoad();
+    _setupImportNames();
     if (compiler.options.deferredGraphUri != null) {
       _dumpDeferredGraph();
     }
@@ -911,8 +880,7 @@
         localFunctionMap,
         constantMap,
         _allOutputUnits,
-        _importDeferName,
-        hunksToLoad,
+        importDeferName,
         _deferredImportDescriptions);
   }
 
@@ -1031,10 +999,10 @@
   /// The prefix this import is imported as.
   final String prefix;
 
-  final LibraryEntity _importingLibrary;
+  final LibraryEntity importingLibrary;
 
   ImportDescription.internal(
-      this.importingUri, this.prefix, this._importingLibrary);
+      this.importingUri, this.prefix, this.importingLibrary);
 
   ImportDescription(
       ImportEntity import, LibraryEntity importingLibrary, Uri mainLibraryUri)
@@ -1412,20 +1380,11 @@
   final Map<Local, OutputUnit> _localFunctionToUnit;
   final Map<ConstantValue, OutputUnit> _constantToUnit;
   final List<OutputUnit> outputUnits;
-  final Map<ImportEntity, String> _importDeferName;
-
-  /// A mapping from the name of a defer import to all the output units it
-  /// depends on in a list of lists to be loaded in the order they appear.
-  ///
-  /// For example {"lib1": [[lib1_lib2_lib3], [lib1_lib2, lib1_lib3],
-  /// [lib1]]} would mean that in order to load "lib1" first the hunk
-  /// lib1_lib2_lib2 should be loaded, then the hunks lib1_lib2 and lib1_lib3
-  /// can be loaded in parallel. And finally lib1 can be loaded.
-  final Map<String, List<OutputUnit>> hunksToLoad;
+  final Map<ImportEntity, String> importDeferName;
 
   /// Because the token-stream is forgotten later in the program, we cache a
   /// description of each deferred import.
-  final Map<ImportEntity, ImportDescription> _deferredImportDescriptions;
+  final Map<ImportEntity, ImportDescription> deferredImportDescriptions;
 
   OutputUnitData(
       this.isProgramSplit,
@@ -1436,9 +1395,8 @@
       this._localFunctionToUnit,
       this._constantToUnit,
       this.outputUnits,
-      this._importDeferName,
-      this.hunksToLoad,
-      this._deferredImportDescriptions);
+      this.importDeferName,
+      this.deferredImportDescriptions);
 
   // Creates J-world data from the K-world data.
   factory OutputUnitData.from(
@@ -1461,12 +1419,12 @@
     Map<ConstantValue, OutputUnit> constantToUnit =
         convertConstantMap(other._constantToUnit);
     Map<ImportEntity, ImportDescription> deferredImportDescriptions = {};
-    other._deferredImportDescriptions
+    other.deferredImportDescriptions
         .forEach((ImportEntity import, ImportDescription description) {
       deferredImportDescriptions[import] = ImportDescription.internal(
           description.importingUri,
           description.prefix,
-          convertLibrary(description._importingLibrary));
+          convertLibrary(description.importingLibrary));
     });
 
     return OutputUnitData(
@@ -1479,8 +1437,7 @@
         const {},
         constantToUnit,
         other.outputUnits,
-        other._importDeferName,
-        other.hunksToLoad,
+        other.importDeferName,
         deferredImportDescriptions);
   }
 
@@ -1511,11 +1468,6 @@
     });
     Map<ImportEntity, String> importDeferName =
         source.readImportMap(source.readString);
-    Map<String, List<OutputUnit>> hunksToLoad = source.readStringMap(() {
-      return source.readList(() {
-        return outputUnits[source.readInt()];
-      });
-    });
     Map<ImportEntity, ImportDescription> deferredImportDescriptions =
         source.readImportMap(() {
       String importingUri = source.readString();
@@ -1535,7 +1487,6 @@
         constantToUnit,
         outputUnits,
         importDeferName,
-        hunksToLoad,
         deferredImportDescriptions);
   }
 
@@ -1564,18 +1515,12 @@
     sink.writeConstantMap(_constantToUnit, (OutputUnit outputUnit) {
       sink.writeInt(outputUnitIndices[outputUnit]);
     });
-    sink.writeImportMap(_importDeferName, sink.writeString);
-    sink.writeStringMap(hunksToLoad, (List<OutputUnit> outputUnits) {
-      sink.writeList(
-          outputUnits,
-          (OutputUnit outputUnit) =>
-              sink.writeInt(outputUnitIndices[outputUnit]));
-    });
-    sink.writeImportMap(_deferredImportDescriptions,
+    sink.writeImportMap(importDeferName, sink.writeString);
+    sink.writeImportMap(deferredImportDescriptions,
         (ImportDescription importDescription) {
       sink.writeString(importDescription.importingUri);
       sink.writeString(importDescription.prefix);
-      sink.writeLibrary(importDescription._importingLibrary);
+      sink.writeLibrary(importDescription.importingLibrary);
     });
     sink.end(tag);
   }
@@ -1690,7 +1635,7 @@
 
   /// Returns the unique name for the given deferred [import].
   String getImportDeferName(Spannable node, ImportEntity import) {
-    String name = _importDeferName[import];
+    String name = importDeferName[import];
     if (name == null) {
       throw SpannableAssertionFailure(node, "No deferred name for $import.");
     }
@@ -1699,48 +1644,7 @@
 
   /// Returns the names associated with each deferred import in [unit].
   Iterable<String> getImportNames(OutputUnit unit) {
-    return unit.imports.map((i) => _importDeferName[i]);
-  }
-
-  /// Returns a json-style map for describing what files that are loaded by a
-  /// given deferred import.
-  /// The mapping is structured as:
-  /// library uri -> {"name": library name, "files": (prefix -> list of files)}
-  /// Where
-  ///
-  /// - <library uri> is the relative uri of the library making a deferred
-  ///   import.
-  /// - <library name> is the name of the library, or "<unnamed>" if it is
-  ///   unnamed.
-  /// - <prefix> is the `as` prefix used for a given deferred import.
-  /// - <list of files> is a list of the filenames the must be loaded when that
-  ///   import is loaded.
-  Map<String, Map<String, dynamic>> computeDeferredMap(
-      CompilerOptions options, ElementEnvironment elementEnvironment,
-      {Set<OutputUnit> omittedUnits}) {
-    omittedUnits ??= Set();
-    Map<String, Map<String, dynamic>> mapping = {};
-
-    _deferredImportDescriptions.keys.forEach((ImportEntity import) {
-      List<OutputUnit> outputUnits = hunksToLoad[_importDeferName[import]];
-      ImportDescription description = _deferredImportDescriptions[import];
-      String getName(LibraryEntity library) {
-        var name = elementEnvironment.getLibraryName(library);
-        return name == '' ? '<unnamed>' : name;
-      }
-
-      Map<String, dynamic> libraryMap = mapping.putIfAbsent(
-          description.importingUri,
-          () =>
-              {"name": getName(description._importingLibrary), "imports": {}});
-
-      List<String> partFileNames = outputUnits
-          .where((outputUnit) => !omittedUnits.contains(outputUnit))
-          .map((outputUnit) => deferredPartFileName(options, outputUnit.name))
-          .toList();
-      libraryMap["imports"][_importDeferName[import]] = partFileNames;
-    });
-    return mapping;
+    return unit.imports.map((i) => importDeferName[i]);
   }
 }
 
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index 882895c..761427f 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -651,8 +651,11 @@
       }
     }
 
-    result.deferredFiles = closedWorld.outputUnitData
-        .computeDeferredMap(compiler.options, closedWorld.elementEnvironment);
+    var fragmentsToLoad =
+        compiler.backendStrategy.emitterTask.emitter.fragmentsToLoad;
+    var fragmentMerger =
+        compiler.backendStrategy.emitterTask.emitter.fragmentMerger;
+    result.deferredFiles = fragmentMerger.computeDeferredMap(fragmentsToLoad);
     stopwatch.stop();
 
     result.program = new ProgramInfo(
diff --git a/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart b/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
index fb72825..4815c6d 100644
--- a/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
+++ b/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
@@ -5,6 +5,7 @@
 library dart2js.js_emitter.code_emitter_task;
 
 import '../common.dart';
+import '../common/metrics.dart' show Metric, Metrics, CountMetric;
 import '../common/tasks.dart' show CompilerTask;
 import '../compiler.dart' show Compiler;
 import '../constants/values.dart';
@@ -50,6 +51,9 @@
   /// Contains a list of all classes that are emitted.
   Set<ClassEntity> neededClasses;
 
+  @override
+  final _EmitterMetrics metrics = _EmitterMetrics();
+
   CodeEmitterTask(this._compiler, this._generateSourceMap)
       : super(_compiler.measurer);
 
@@ -209,6 +213,12 @@
 
   List<fragment_merger.PreFragment> get preDeferredFragmentsForTesting;
 
+  /// A map of loadId to list of [FinalizedFragments].
+  Map<String, List<fragment_merger.FinalizedFragment>> get fragmentsToLoad;
+
+  /// The [FragmentMerger] itself.
+  fragment_merger.FragmentMerger get fragmentMerger;
+
   /// Uses the [programBuilder] to generate a model of the program, emits
   /// the program, and returns the size of the generated output.
   int emitProgram(ProgramBuilder programBuilder, CodegenWorld codegenWorld);
@@ -228,3 +238,16 @@
   /// Returns the size of the code generated for a given output [unit].
   int generatedSize(OutputUnit unit);
 }
+
+class _EmitterMetrics implements Metrics {
+  @override
+  String get namespace => 'emitter';
+
+  CountMetric hunkListElements = CountMetric('hunkListElements');
+
+  @override
+  Iterable<Metric> get primary => [];
+
+  @override
+  Iterable<Metric> get secondary => [hunkListElements];
+}
diff --git a/pkg/compiler/lib/src/js_emitter/model.dart b/pkg/compiler/lib/src/js_emitter/model.dart
index 2cdfb73..dd195cf 100644
--- a/pkg/compiler/lib/src/js_emitter/model.dart
+++ b/pkg/compiler/lib/src/js_emitter/model.dart
@@ -21,9 +21,6 @@
   final bool needsNativeSupport;
   final bool hasSoftDeferredClasses;
 
-  /// A map from load id to the list of fragments that need to be loaded.
-  final Map<String, List<Fragment>> loadMap;
-
   // If this field is not `null` then its value must be emitted in the embedded
   // global `TYPE_TO_INTERCEPTOR_MAP`. The map references constants and classes.
   final js.Expression typeToInterceptorMap;
@@ -33,7 +30,7 @@
   final MetadataCollector _metadataCollector;
   final Iterable<js.TokenFinalizer> finalizers;
 
-  Program(this.fragments, this.holders, this.loadMap, this.typeToInterceptorMap,
+  Program(this.fragments, this.holders, this.typeToInterceptorMap,
       this._metadataCollector, this.finalizers,
       {this.needsNativeSupport,
       this.outputContainsConstantList,
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
index 0cd7059..947929f 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
@@ -273,8 +273,8 @@
       finalizers.add(namingFinalizer as js.TokenFinalizer);
     }
 
-    return new Program(fragments, holders, _buildLoadMap(),
-        _buildTypeToInterceptorMap(), _task.metadataCollector, finalizers,
+    return new Program(fragments, holders, _buildTypeToInterceptorMap(),
+        _task.metadataCollector, finalizers,
         needsNativeSupport: needsNativeSupport,
         outputContainsConstantList: collector.outputContainsConstantList,
         hasSoftDeferredClasses: _notSoftDeferred != null);
@@ -348,18 +348,6 @@
     }
   }
 
-  /// Builds a map from loadId to outputs-to-load.
-  Map<String, List<Fragment>> _buildLoadMap() {
-    Map<String, List<Fragment>> loadMap = <String, List<Fragment>>{};
-    _closedWorld.outputUnitData.hunksToLoad
-        .forEach((String loadId, List<OutputUnit> outputUnits) {
-      loadMap[loadId] = outputUnits
-          .map((OutputUnit unit) => _outputs[unit])
-          .toList(growable: false);
-    });
-    return loadMap;
-  }
-
   js.Expression _buildTypeToInterceptorMap() {
     InterceptorStubGenerator stubGenerator = new InterceptorStubGenerator(
         _commonElements,
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 ca28cdb..5a878fb 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
@@ -7,7 +7,6 @@
 import '../../../compiler_new.dart';
 import '../../common.dart';
 import '../../common/codegen.dart';
-import '../../common/tasks.dart';
 import '../../constants/values.dart';
 import '../../deferred_load.dart' show OutputUnit;
 import '../../dump_info.dart';
@@ -20,7 +19,7 @@
 import '../../options.dart';
 import '../../universe/codegen_world_builder.dart' show CodegenWorld;
 import '../../world.dart' show JClosedWorld;
-import '../js_emitter.dart' show Emitter, ModularEmitter;
+import '../js_emitter.dart' show CodeEmitterTask, Emitter, ModularEmitter;
 import '../model.dart';
 import '../native_emitter.dart';
 import '../program_builder/program_builder.dart' show ProgramBuilder;
@@ -150,7 +149,7 @@
   final DiagnosticReporter _reporter;
   final JClosedWorld _closedWorld;
   final RecipeEncoder _rtiRecipeEncoder;
-  final CompilerTask _task;
+  final CodeEmitterTask _task;
   ModelEmitter _emitter;
   final NativeEmitter _nativeEmitter;
 
@@ -160,6 +159,12 @@
   @override
   List<PreFragment> preDeferredFragmentsForTesting;
 
+  @override
+  Map<String, List<FinalizedFragment>> fragmentsToLoad;
+
+  @override
+  FragmentMerger fragmentMerger;
+
   EmitterImpl(
       CompilerOptions options,
       this._reporter,
@@ -201,6 +206,11 @@
     }
     return _task.measureSubtask('emit program', () {
       var size = _emitter.emitProgram(program, codegenWorld);
+      fragmentsToLoad = _emitter.fragmentsToLoad;
+      fragmentMerger = _emitter.fragmentMerger;
+      fragmentsToLoad.values.forEach((fragments) {
+        _task.metrics.hunkListElements.add(fragments.length);
+      });
       if (retainDataForTesting) {
         preDeferredFragmentsForTesting =
             _emitter.preDeferredFragmentsForTesting;
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
index 939a39f..f5f2d9a 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
@@ -730,7 +730,9 @@
   }
 
   js.Statement emitMainFragment(
-      Program program, DeferredLoadingState deferredLoadingState) {
+      Program program,
+      Map<String, List<FinalizedFragment>> fragmentsToLoad,
+      DeferredLoadingState deferredLoadingState) {
     MainFragment fragment = program.fragments.first;
 
     Iterable<Holder> nonStaticStateHolders =
@@ -778,8 +780,8 @@
       'constants': emitConstants(fragment),
       'staticNonFinalFields': emitStaticNonFinalFields(fragment),
       'lazyStatics': emitLazilyInitializedStatics(fragment),
-      'embeddedGlobalsPart1':
-          emitEmbeddedGlobalsPart1(program, deferredLoadingState),
+      'embeddedGlobalsPart1': emitEmbeddedGlobalsPart1(
+          program, fragmentsToLoad, deferredLoadingState),
       'embeddedGlobalsPart2':
           emitEmbeddedGlobalsPart2(program, deferredLoadingState),
       'typeRules': emitTypeRules(fragment),
@@ -1874,10 +1876,10 @@
   // array of hashes indexed by part.
   // [deferredLoadHashes] may have missing entries to indicate empty parts.
   void finalizeDeferredLoadingData(
-      Map<String, List<FinalizedFragment>> loadMap,
+      Map<String, List<FinalizedFragment>> fragmentsToLoad,
       Map<FinalizedFragment, String> deferredLoadHashes,
       DeferredLoadingState deferredLoadingState) {
-    if (loadMap.isEmpty) return;
+    if (fragmentsToLoad.isEmpty) return;
 
     Map<FinalizedFragment, int> fragmentIndexes = {};
     List<String> fragmentUris = [];
@@ -1885,7 +1887,8 @@
 
     List<js.Property> libraryPartsMapEntries = [];
 
-    loadMap.forEach((String loadId, List<FinalizedFragment> fragmentList) {
+    fragmentsToLoad
+        .forEach((String loadId, List<FinalizedFragment> fragmentList) {
       List<js.Expression> indexes = [];
       for (FinalizedFragment fragment in fragmentList) {
         String fragmentHash = deferredLoadHashes[fragment];
@@ -1971,10 +1974,12 @@
 
   /// Emits all embedded globals.
   js.Statement emitEmbeddedGlobalsPart1(
-      Program program, DeferredLoadingState deferredLoadingState) {
+      Program program,
+      Map<String, List<FinalizedFragment>> fragmentsToLoad,
+      DeferredLoadingState deferredLoadingState) {
     List<js.Property> globals = [];
 
-    if (program.loadMap.isNotEmpty) {
+    if (fragmentsToLoad.isNotEmpty) {
       globals
           .addAll(emitEmbeddedGlobalsForDeferredLoading(deferredLoadingState));
     }
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_merger.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_merger.dart
index 122a716..2a80113 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_merger.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_merger.dart
@@ -3,6 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:collection';
+import '../../common_elements.dart' show ElementEnvironment;
+import '../../deferred_load.dart'
+    show ImportDescription, OutputUnit, OutputUnitData, deferredPartFileName;
+import '../../elements/entities.dart';
 import '../../deferred_load.dart' show OutputUnit;
 import '../../js/js.dart' as js;
 import '../../js/size_estimator.dart';
@@ -24,6 +28,7 @@
   final List<js.Statement> nativeSupport = [];
   final Set<PreFragment> successors = {};
   final Set<PreFragment> predecessors = {};
+  FinalizedFragment finalizedFragment;
   int size = 0;
 
   PreFragment(
@@ -103,8 +108,8 @@
   }
 
   FinalizedFragment finalize(
-      Program program, Map<Fragment, FinalizedFragment> fragmentMap) {
-    FinalizedFragment finalizedFragment;
+      Program program, Map<OutputUnit, FinalizedFragment> outputUnitMap) {
+    assert(finalizedFragment == null);
     var seedFragment = fragments.first;
     var seedOutputUnit = seedFragment.outputUnit;
 
@@ -128,7 +133,7 @@
           lazyInitializers.first,
           nativeSupport.first,
           program.metadataTypesForOutputUnit(seedOutputUnit));
-      fragmentMap[seedFragment] = finalizedFragment;
+      outputUnitMap[seedOutputUnit] = finalizedFragment;
     } else {
       List<OutputUnit> outputUnits = [seedOutputUnit];
       List<Library> libraries = [];
@@ -156,8 +161,8 @@
           js.Block(lazyInitializers),
           js.Block(nativeSupport),
           program.metadataTypesForOutputUnit(seedOutputUnit));
-      for (var fragment in fragments) {
-        fragmentMap[fragment] = finalizedFragment;
+      for (var outputUnit in outputUnits) {
+        outputUnitMap[outputUnit] = finalizedFragment;
       }
     }
     return finalizedFragment;
@@ -294,28 +299,32 @@
 
 class FragmentMerger {
   final CompilerOptions _options;
+  final ElementEnvironment _elementEnvironment;
+  final OutputUnitData outputUnitData;
   int totalSize = 0;
 
-  FragmentMerger(this._options);
+  FragmentMerger(this._options, this._elementEnvironment, this.outputUnitData);
 
-  // Converts a map of (loadId, List<fragments>) to a map of
+  // Converts a map of (loadId, List<OutputUnit>) to a map of
   // (loadId, List<FinalizedFragment>).
-  static Map<String, List<FinalizedFragment>> processLoadMap(
-      Map<String, List<Fragment>> programLoadMap,
-      Map<Fragment, FinalizedFragment> fragmentMap) {
-    Map<String, List<FinalizedFragment>> loadMap = {};
-    programLoadMap.forEach((loadId, fragments) {
+  Map<String, List<FinalizedFragment>> computeFragmentsToLoad(
+      Map<String, List<OutputUnit>> outputUnitsToLoad,
+      Map<OutputUnit, FinalizedFragment> outputUnitMap,
+      Set<OutputUnit> omittedOutputUnits) {
+    Map<String, List<FinalizedFragment>> fragmentsToLoad = {};
+    outputUnitsToLoad.forEach((loadId, outputUnits) {
       Set<FinalizedFragment> unique = {};
       List<FinalizedFragment> finalizedFragments = [];
-      loadMap[loadId] = finalizedFragments;
-      for (var fragment in fragments) {
-        var finalizedFragment = fragmentMap[fragment];
+      fragmentsToLoad[loadId] = finalizedFragments;
+      for (var outputUnit in outputUnits) {
+        if (omittedOutputUnits.contains(outputUnit)) continue;
+        var finalizedFragment = outputUnitMap[outputUnit];
         if (unique.add(finalizedFragment)) {
           finalizedFragments.add(finalizedFragment);
         }
       }
     });
-    return loadMap;
+    return fragmentsToLoad;
   }
 
   /// Given a list of OutputUnits sorted by their import entites,
@@ -353,22 +362,22 @@
   }
 
   /// Attachs predecessors and successors to each PreFragment.
-  void attachDependencies(Map<Fragment, PreFragment> fragmentMap,
+  /// Expects outputUnits to be sorted.
+  void attachDependencies(
+      List<OutputUnit> outputUnits,
+      Map<Fragment, PreFragment> fragmentMap,
       List<PreFragment> preDeferredFragments) {
     // Create a map of OutputUnit to Fragment.
     Map<OutputUnit, Fragment> outputUnitMap = {};
-    List<OutputUnit> allOutputUnits = [];
     for (var preFragment in preDeferredFragments) {
       var fragment = preFragment.fragments.single;
       var outputUnit = fragment.outputUnit;
       outputUnitMap[outputUnit] = fragment;
-      allOutputUnits.add(outputUnit);
       totalSize += preFragment.size;
     }
-    allOutputUnits.sort();
 
     // Get a list of direct edges and then attach them to PreFragments.
-    var allEdges = createDirectEdges(allOutputUnits);
+    var allEdges = createDirectEdges(outputUnits);
     allEdges.forEach((outputUnit, edges) {
       var predecessor = fragmentMap[outputUnitMap[outputUnit]];
       for (var edge in edges) {
@@ -449,4 +458,79 @@
     }
     return merged;
   }
+
+  /// Computes load lists using a list of sorted OutputUnits.
+  Map<String, List<OutputUnit>> computeOutputUnitsToLoad(
+      List<OutputUnit> outputUnits) {
+    // Sort the output units in descending order of the number of imports they
+    // include.
+
+    // The loading of the output units must be ordered because a superclass
+    // needs to be initialized before its subclass.
+    // But a class can only depend on another class in an output unit shared by
+    // a strict superset of the imports:
+    // By contradiction: Assume a class C in output unit shared by imports in
+    // the set S1 = (lib1,.., lib_n) depends on a class D in an output unit
+    // shared by S2 such that S2 not a superset of S1. Let lib_s be a library in
+    // S1 not in S2. lib_s must depend on C, and then in turn on D. Therefore D
+    // is not in the right output unit.
+    List<OutputUnit> sortedOutputUnits = outputUnits.reversed.toList();
+
+    Map<String, List<OutputUnit>> outputUnitsToLoad = {};
+    for (var import in outputUnitData.deferredImportDescriptions.keys) {
+      var loadId = outputUnitData.importDeferName[import];
+      List<OutputUnit> loadList = [];
+      for (var outputUnit in sortedOutputUnits) {
+        assert(!outputUnit.isMainOutput);
+        if (outputUnit.imports.contains(import)) {
+          loadList.add(outputUnit);
+        }
+      }
+      outputUnitsToLoad[loadId] = loadList;
+    }
+    return outputUnitsToLoad;
+  }
+
+  /// Returns a json-style map for describing what files that are loaded by a
+  /// given deferred import.
+  /// The mapping is structured as:
+  /// library uri -> {"name": library name, "files": (prefix -> list of files)}
+  /// Where
+  ///
+  /// - <library uri> is the import uri of the library making a deferred
+  ///   import.
+  /// - <library name> is the name of the library, or "<unnamed>" if it is
+  ///   unnamed.
+  /// - <prefix> is the `as` prefix used for a given deferred import.
+  /// - <list of files> is a list of the filenames the must be loaded when that
+  ///   import is loaded.
+  /// TODO(joshualitt): the library name is unused and should be removed. This
+  /// will be a breaking change.
+  Map<String, Map<String, dynamic>> computeDeferredMap(
+      Map<String, List<FinalizedFragment>> fragmentsToLoad) {
+    Map<String, Map<String, dynamic>> mapping = {};
+
+    outputUnitData.deferredImportDescriptions.keys
+        .forEach((ImportEntity import) {
+      var importDeferName = outputUnitData.importDeferName[import];
+      List<FinalizedFragment> fragments = fragmentsToLoad[importDeferName];
+      ImportDescription description =
+          outputUnitData.deferredImportDescriptions[import];
+      String getName(LibraryEntity library) {
+        var name = _elementEnvironment.getLibraryName(library);
+        return name == '' ? '<unnamed>' : name;
+      }
+
+      Map<String, dynamic> libraryMap = mapping.putIfAbsent(
+          description.importingUri,
+          () => {"name": getName(description.importingLibrary), "imports": {}});
+
+      List<String> partFileNames = fragments
+          .map((fragment) =>
+              deferredPartFileName(_options, fragment.canonicalOutputUnit.name))
+          .toList();
+      libraryMap["imports"][importDeferName] = partFileNames;
+    });
+    return mapping;
+  }
 }
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 943f80e..a7c42ad 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
@@ -107,6 +107,15 @@
 
   List<PreFragment> preDeferredFragmentsForTesting;
 
+  /// A mapping from the name of a defer import to all the fragments it
+  /// depends on in a list of lists to be loaded in the order they appear.
+  ///
+  /// For example {"lib1": [[lib1_lib2_lib3], [lib1_lib2, lib1_lib3],
+  /// [lib1]]} would mean that in order to load "lib1" first the hunk
+  /// lib1_lib2_lib2 should be loaded, then the hunks lib1_lib2 and lib1_lib3
+  /// can be loaded in parallel. And fially lib1 can be loaded.
+  Map<String, List<FinalizedFragment>> fragmentsToLoad;
+
   /// For deferred loading we communicate the initializers via this global var.
   static const String deferredInitializersGlobal =
       r"$__dart_deferred_initializers__";
@@ -130,7 +139,8 @@
       RecipeEncoder rtiRecipeEncoder,
       this._shouldGenerateSourceMap)
       : _constantOrdering = new ConstantOrdering(_closedWorld.sorter),
-        fragmentMerger = FragmentMerger(_options) {
+        fragmentMerger = FragmentMerger(_options,
+            _closedWorld.elementEnvironment, _closedWorld.outputUnitData) {
     this.constantEmitter = new ConstantEmitter(
         _options,
         _namer,
@@ -213,11 +223,8 @@
         _closedWorld,
         codegenWorld);
 
-    var deferredLoadingState = new DeferredLoadingState();
-    js.Statement mainCode =
-        fragmentEmitter.emitMainFragment(program, deferredLoadingState);
-
     // In order to get size estimates, we partially emit deferred fragments.
+    List<OutputUnit> outputUnits = [];
     List<PreFragment> preDeferredFragments = [];
     Map<DeferredFragment, PreFragment> preFragmentMap = {};
     _task.measureSubtask('emit prefragments', () {
@@ -225,15 +232,23 @@
         var preFragment =
             fragmentEmitter.emitPreFragment(fragment, shouldMergeFragments);
         preFragmentMap[fragment] = preFragment;
+        outputUnits.add(fragment.outputUnit);
         preDeferredFragments.add(preFragment);
       }
     });
 
+    // Sort output units so they are in a canonical order and generate a map of
+    // loadId to list of OutputUnits to load.
+    outputUnits.sort();
+    var outputUnitsToLoad =
+        fragmentMerger.computeOutputUnitsToLoad(outputUnits);
+
     // If we are going to merge, then we attach dependencies to each PreFragment
     // and merge.
     if (shouldMergeFragments) {
       preDeferredFragments = _task.measureSubtask('merge fragments', () {
-        fragmentMerger.attachDependencies(preFragmentMap, preDeferredFragments);
+        fragmentMerger.attachDependencies(
+            outputUnits, preFragmentMap, preDeferredFragments);
         return fragmentMerger.mergeFragments(preDeferredFragments);
       });
     }
@@ -243,11 +258,12 @@
       preDeferredFragmentsForTesting = preDeferredFragments;
     }
 
-    Map<DeferredFragment, FinalizedFragment> fragmentMap = {};
+    // Finalize and emit fragments.
+    Map<OutputUnit, FinalizedFragment> outputUnitMap = {};
     Map<FinalizedFragment, js.Expression> deferredFragmentsCode = {};
     for (var preDeferredFragment in preDeferredFragments) {
       var finalizedFragment =
-          preDeferredFragment.finalize(program, fragmentMap);
+          preDeferredFragment.finalize(program, outputUnitMap);
       js.Expression fragmentCode = fragmentEmitter.emitDeferredFragment(
           finalizedFragment, program.holders);
       if (fragmentCode != null) {
@@ -257,6 +273,17 @@
       }
     }
 
+    // With all deferred fragments finalized, we can now compute a map of
+    // loadId to the files(FinalizedFragments) which need to be loaded.
+    fragmentsToLoad = fragmentMerger.computeFragmentsToLoad(
+        outputUnitsToLoad, outputUnitMap, omittedOutputUnits);
+
+    // Emit main Fragment.
+    var deferredLoadingState = new DeferredLoadingState();
+    js.Statement mainCode = fragmentEmitter.emitMainFragment(
+        program, fragmentsToLoad, deferredLoadingState);
+
+    // Count tokens and run finalizers.
     js.TokenCounter counter = new js.TokenCounter();
     deferredFragmentsCode.values.forEach(counter.countTokens);
     counter.countTokens(mainCode);
@@ -274,10 +301,8 @@
 
     // Now that we have written the deferred hunks, we can create the deferred
     // loading data.
-    Map<String, List<FinalizedFragment>> loadMap =
-        FragmentMerger.processLoadMap(program.loadMap, fragmentMap);
     fragmentEmitter.finalizeDeferredLoadingData(
-        loadMap, hunkHashes, deferredLoadingState);
+        fragmentsToLoad, hunkHashes, deferredLoadingState);
 
     _task.measureSubtask('write fragments', () {
       writeMainFragment(mainFragment, mainCode,
@@ -498,9 +523,7 @@
     // data.
     mapping["_comment"] = "This mapping shows which compiled `.js` files are "
         "needed for a given deferred library import.";
-    mapping.addAll(_closedWorld.outputUnitData.computeDeferredMap(
-        _options, _closedWorld.elementEnvironment,
-        omittedUnits: omittedOutputUnits));
+    mapping.addAll(fragmentMerger.computeDeferredMap(fragmentsToLoad));
     _outputProvider.createOutputSink(
         _options.deferredMapUri.path, '', OutputType.deferredMap)
       ..add(const JsonEncoder.withIndent("  ").convert(mapping))
diff --git a/pkg/compiler/test/analyses/dart2js_allowed.json b/pkg/compiler/test/analyses/dart2js_allowed.json
index 10ea069..3fb0668 100644
--- a/pkg/compiler/test/analyses/dart2js_allowed.json
+++ b/pkg/compiler/test/analyses/dart2js_allowed.json
@@ -45,8 +45,7 @@
   },
   "pkg/compiler/lib/src/deferred_load.dart": {
     "Dynamic access of 'memberContext'.": 1,
-    "Dynamic access of 'name'.": 1,
-    "Dynamic invocation of '[]='.": 1
+    "Dynamic access of 'name'.": 1
   },
   "pkg/compiler/lib/src/inferrer/typemasks/container_type_mask.dart": {
     "Dynamic access of 'isNullable'.": 2,
@@ -197,6 +196,9 @@
     "Dynamic invocation of '[]='.": 1,
     "Dynamic invocation of 'add'.": 1
   },
+  "pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_merger.dart": {
+    "Dynamic invocation of '[]='.": 1
+  },
   "pkg/js_ast/lib/src/builder.dart": {
     "Dynamic invocation of 'call'.": 2
   },
diff --git a/pkg/compiler/test/deferred/load_graph_segmentation_test.dart b/pkg/compiler/test/deferred/load_graph_segmentation_test.dart
index 3dc7942..660e27b 100644
--- a/pkg/compiler/test/deferred/load_graph_segmentation_test.dart
+++ b/pkg/compiler/test/deferred/load_graph_segmentation_test.dart
@@ -11,9 +11,18 @@
 import 'package:async_helper/async_helper.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/deferred_load.dart';
+import 'package:compiler/src/js_emitter/startup_emitter/fragment_merger.dart';
 import 'package:expect/expect.dart';
 import '../helpers/memory_compiler.dart';
 
+List<OutputUnit> collectOutputUnits(List<FinalizedFragment> fragments) {
+  List<OutputUnit> outputUnits = [];
+  for (var fragment in fragments) {
+    outputUnits.addAll(fragment.outputUnits);
+  }
+  return outputUnits;
+}
+
 void main() {
   asyncTest(() async {
     CompilationResult result =
@@ -59,12 +68,11 @@
     // InputElement is native, so it should be in the mainOutputUnit.
     Expect.equals(mainOutputUnit, outputUnitForClass(inputElement));
 
-    var hunksToLoad = closedWorld.outputUnitData.hunksToLoad;
-
-    var hunksLib1 = hunksToLoad["lib1"];
-    var hunksLib2 = hunksToLoad["lib2"];
-    var hunksLib4_1 = hunksToLoad["lib4_1"];
-    var hunksLib4_2 = hunksToLoad["lib4_2"];
+    var hunksToLoad = backendStrategy.emitterTask.emitter.fragmentsToLoad;
+    var hunksLib1 = collectOutputUnits(hunksToLoad["lib1"]);
+    var hunksLib2 = collectOutputUnits(hunksToLoad["lib2"]);
+    var hunksLib4_1 = collectOutputUnits(hunksToLoad["lib4_1"]);
+    var hunksLib4_2 = collectOutputUnits(hunksToLoad["lib4_2"]);
     Expect.listEquals([ou_lib1_lib2, ou_lib1], hunksLib1);
     Expect.listEquals([ou_lib1_lib2, ou_lib2], hunksLib2);
     Expect.listEquals([ou_lib4_1], hunksLib4_1);
diff --git a/pkg/compiler/test/deferred/load_mapping_test.dart b/pkg/compiler/test/deferred/load_mapping_test.dart
index b6a6821..ffb7b84 100644
--- a/pkg/compiler/test/deferred/load_mapping_test.dart
+++ b/pkg/compiler/test/deferred/load_mapping_test.dart
@@ -4,27 +4,24 @@
 
 // @dart = 2.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/src/world.dart';
-import '../helpers/memory_source_file_helper.dart';
 import '../helpers/memory_compiler.dart';
 
 void testLoadMap() async {
   var collector = new OutputCollector();
-  CompilationResult result = await runCompiler(
+  await runCompiler(
       memorySourceFiles: MEMORY_SOURCE_FILES,
       options: ['--deferred-map=deferred_map.json'],
       outputProvider: collector);
-  CompilerImpl compiler = result.compiler;
-  JClosedWorld closedWorld = compiler.backendClosedWorldForTesting;
   // Ensure a mapping file is output.
-  Expect.isNotNull(
-      collector.getOutput("deferred_map.json", OutputType.deferredMap));
+  var deferredMap =
+      collector.getOutput("deferred_map.json", OutputType.deferredMap);
+  Expect.isNotNull(deferredMap);
+  var mapping = jsonDecode(deferredMap);
 
-  Map mapping = closedWorld.outputUnitData
-      .computeDeferredMap(compiler.options, closedWorld.elementEnvironment);
   // Test structure of mapping.
   Expect.equals("<unnamed>", mapping["main.dart"]["name"]);
   Expect.equals(2, mapping["main.dart"]["imports"]["lib1"].length);
diff --git a/pkg/compiler/test/deferred_loading/data/deferred_overlapping/main.dart b/pkg/compiler/test/deferred_loading/data/deferred_overlapping/main.dart
index 58108e9..154ad59 100644
--- a/pkg/compiler/test/deferred_loading/data/deferred_overlapping/main.dart
+++ b/pkg/compiler/test/deferred_loading/data/deferred_overlapping/main.dart
@@ -31,9 +31,9 @@
 /*member: main:member_unit=main{}*/
 void main() {
   lib1.loadLibrary().then(/*closure_unit=main{}*/ (_) {
-    new lib1.C1();
+    print(new lib1.C1());
     lib2.loadLibrary().then(/*closure_unit=main{}*/ (_) {
-      new lib2.C2();
+      print(new lib2.C2());
     });
   });
 }
diff --git a/pkg/compiler/test/deferred_loading/data/lazy_types/lib.dart b/pkg/compiler/test/deferred_loading/data/lazy_types/lib.dart
index 4cd9f15..22064c8 100644
--- a/pkg/compiler/test/deferred_loading/data/lazy_types/lib.dart
+++ b/pkg/compiler/test/deferred_loading/data/lazy_types/lib.dart
@@ -16,15 +16,18 @@
     x = DateTime.now().millisecond;
   }
   /*member: Foo.method:member_unit=1{libB}*/
+  @pragma('dart2js:noInline')
   int method() => x;
 }
 
 /*member: isFoo:member_unit=3{libA, libB, libC}*/
+@pragma('dart2js:noInline')
 bool isFoo(o) {
   return o is Foo;
 }
 
 /*member: callFooMethod:member_unit=1{libB}*/
+@pragma('dart2js:noInline')
 int callFooMethod() {
   return Foo().method();
 }
@@ -33,6 +36,7 @@
 typedef int FunFunFoo(FunFoo b, int c);
 
 /*member: isFunFunFoo:member_unit=3{libA, libB, libC}*/
+@pragma('dart2js:noInline')
 bool isFunFunFoo(o) {
   return o is FunFunFoo;
 }
@@ -64,6 +68,7 @@
 class Doo<T> extends Coo<T> with Boo<T> {}
 
 /*member: createDooFunFunFoo:member_unit=2{libC}*/
+@pragma('dart2js:noInline')
 createDooFunFunFoo() => Doo<FunFunFoo>();
 
 /*class: B:
@@ -120,6 +125,7 @@
 class D3 = D2 with D1;
 
 /*member: isMega:member_unit=6{libA}*/
+@pragma('dart2js:noInline')
 bool isMega(o) {
   return o is B2 || o is C3 || o is D3;
 }
diff --git a/pkg/compiler/test/deferred_loading/data/lazy_types/main.dart b/pkg/compiler/test/deferred_loading/data/lazy_types/main.dart
index 15e8022..ce78d8a 100644
--- a/pkg/compiler/test/deferred_loading/data/lazy_types/main.dart
+++ b/pkg/compiler/test/deferred_loading/data/lazy_types/main.dart
@@ -5,15 +5,13 @@
 /*spec.library: 
  output_units=[
   f1: {units: [3{libA, libB, libC}], usedBy: [], needs: []},
-  f2: {units: [4{libA, libC}], usedBy: [], needs: []},
-  f3: {units: [6{libA}], usedBy: [], needs: []},
-  f4: {units: [5{libB, libC}], usedBy: [], needs: []},
-  f5: {units: [1{libB}], usedBy: [], needs: []},
-  f6: {units: [2{libC}], usedBy: [], needs: []}],
+  f2: {units: [6{libA}], usedBy: [], needs: []},
+  f3: {units: [1{libB}], usedBy: [], needs: []},
+  f4: {units: [2{libC}], usedBy: [], needs: []}],
  steps=[
-  libA=(f1, f2, f3),
-  libB=(f1, f4, f5),
-  libC=(f1, f4, f2, f6)]
+  libA=(f1, f2),
+  libB=(f1, f3),
+  libC=(f1, f4)]
 */
 
 /*two-frag.library: 
diff --git a/pkg/compiler/test/deferred_loading/data/type_arguments/main.dart b/pkg/compiler/test/deferred_loading/data/type_arguments/main.dart
index 13f5f03..9433a91 100644
--- a/pkg/compiler/test/deferred_loading/data/type_arguments/main.dart
+++ b/pkg/compiler/test/deferred_loading/data/type_arguments/main.dart
@@ -2,24 +2,13 @@
 // 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.
 
-/*spec.library: 
+/*library: 
  output_units=[
-  f1: {units: [3{lib1, lib3}], usedBy: [], needs: []},
-  f2: {units: [1{lib1}], usedBy: [], needs: []},
-  f3: {units: [2{lib3}], usedBy: [], needs: []}],
+  f1: {units: [1{lib1}], usedBy: [], needs: []},
+  f2: {units: [2{lib3}], usedBy: [], needs: []}],
  steps=[
-  lib1=(f1, f2),
-  lib3=(f1, f3)]
-*/
-
-/*two-frag|three-frag.library: 
- output_units=[
-  f1: {units: [3{lib1, lib3}], usedBy: [], needs: [2, 3]},
-  f2: {units: [1{lib1}], usedBy: [1], needs: []},
-  f3: {units: [2{lib3}], usedBy: [1], needs: []}],
- steps=[
-  lib1=(f1, f2),
-  lib3=(f1, f3)]
+  lib1=(f1),
+  lib3=(f2)]
 */
 
 // @dart = 2.7
diff --git a/pkg/compiler/test/deferred_loading/deferred_loading_test.dart b/pkg/compiler/test/deferred_loading/deferred_loading_test.dart
index e64d305..2e74934 100644
--- a/pkg/compiler/test/deferred_loading/deferred_loading_test.dart
+++ b/pkg/compiler/test/deferred_loading/deferred_loading_test.dart
@@ -15,7 +15,6 @@
 import 'package:compiler/src/ir/util.dart';
 import 'package:compiler/src/js_model/element_map.dart';
 import 'package:compiler/src/js_model/js_world.dart';
-import 'package:compiler/src/js_emitter/model.dart';
 import 'package:compiler/src/js_emitter/startup_emitter/fragment_merger.dart';
 import 'package:compiler/src/kernel/kernel_strategy.dart';
 import 'package:expect/expect.dart';
@@ -87,23 +86,18 @@
 }
 
 Map<String, List<PreFragment>> buildPreFragmentMap(
-    Map<String, List<Fragment>> loadMap,
+    Map<String, List<FinalizedFragment>> fragmentsToLoad,
     List<PreFragment> preDeferredFragments) {
-  Map<DeferredFragment, PreFragment> fragmentMap = {};
+  Map<FinalizedFragment, PreFragment> fragmentMap = {};
   for (var preFragment in preDeferredFragments) {
-    for (var fragment in preFragment.fragments) {
-      assert(!fragmentMap.containsKey(fragment));
-      fragmentMap[fragment] = preFragment;
-    }
+    fragmentMap[preFragment.finalizedFragment] = preFragment;
   }
-
   Map<String, List<PreFragment>> preFragmentMap = {};
-  loadMap.forEach((loadId, fragments) {
-    Set<PreFragment> preFragments = {};
+  fragmentsToLoad.forEach((loadId, fragments) {
+    List<PreFragment> preFragments = [];
     for (var fragment in fragments) {
       preFragments.add(fragmentMap[fragment]);
     }
-    assert(!preFragmentMap.containsKey(loadId));
     preFragmentMap[loadId] = preFragments.toList();
   });
   return preFragmentMap;
@@ -160,10 +154,10 @@
     ir.Library node = frontendStrategy.elementMap.getLibraryNode(library);
     List<PreFragment> preDeferredFragments = compiler
         .backendStrategy.emitterTask.emitter.preDeferredFragmentsForTesting;
-    Program program =
-        compiler.backendStrategy.emitterTask.emitter.programForTesting;
+    Map<String, List<FinalizedFragment>> fragmentsToLoad =
+        compiler.backendStrategy.emitterTask.emitter.fragmentsToLoad;
     Map<String, List<PreFragment>> preFragmentMap =
-        buildPreFragmentMap(program.loadMap, preDeferredFragments);
+        buildPreFragmentMap(fragmentsToLoad, preDeferredFragments);
     PreFragmentsIrComputer(compiler.reporter, actualMap, preFragmentMap)
         .computeForLibrary(node);
   }
@@ -208,13 +202,15 @@
       List<OutputUnit> supplied = [];
       List<int> usedBy = [];
       for (var dependent in preFragment.successors) {
-        assert(preFragmentIndices.containsKey(dependent));
-        usedBy.add(preFragmentIndices[dependent]);
+        if (preFragmentIndices.containsKey(dependent)) {
+          usedBy.add(preFragmentIndices[dependent]);
+        }
       }
 
       for (var dependency in preFragment.predecessors) {
-        assert(preFragmentIndices.containsKey(dependency));
-        needs.add(preFragmentIndices[dependency]);
+        if (preFragmentIndices.containsKey(dependency)) {
+          needs.add(preFragmentIndices[dependency]);
+        }
       }
 
       for (var fragment in preFragment.fragments) {
diff --git a/pkg/dartdev/lib/src/commands/analyze.dart b/pkg/dartdev/lib/src/commands/analyze.dart
index 95e8a37..3292669 100644
--- a/pkg/dartdev/lib/src/commands/analyze.dart
+++ b/pkg/dartdev/lib/src/commands/analyze.dart
@@ -36,7 +36,7 @@
   static final int _return = '\r'.codeUnitAt(0);
 
   AnalyzeCommand({bool verbose = false})
-      : super(cmdName, "Analyze the project's Dart code.") {
+      : super(cmdName, 'Analyze Dart code in a directory.') {
     argParser
       ..addFlag('fatal-infos',
           help: 'Treat info level issues as fatal.', negatable: false)
diff --git a/pkg/dartdev/lib/src/commands/create.dart b/pkg/dartdev/lib/src/commands/create.dart
index e8aecd4..26d6576 100644
--- a/pkg/dartdev/lib/src/commands/create.dart
+++ b/pkg/dartdev/lib/src/commands/create.dart
@@ -33,7 +33,7 @@
       stagehand.getGenerator(templateId);
 
   CreateCommand({bool verbose = false})
-      : super(cmdName, 'Create a new project.') {
+      : super(cmdName, 'Create a new Dart project.') {
     argParser.addOption(
       'template',
       allowed: legalTemplateIds,
diff --git a/pkg/dartdev/lib/src/commands/test.dart b/pkg/dartdev/lib/src/commands/test.dart
index b010f54..7261896 100644
--- a/pkg/dartdev/lib/src/commands/test.dart
+++ b/pkg/dartdev/lib/src/commands/test.dart
@@ -17,7 +17,7 @@
 class TestCommand extends DartdevCommand {
   static const String cmdName = 'test';
 
-  TestCommand() : super(cmdName, 'Run tests in this package.');
+  TestCommand() : super(cmdName, 'Run tests for a project.');
 
   // This argument parser is here solely to ensure that VM specific flags are
   // provided before any command and to provide a more consistent help message
diff --git a/pkg/dartdev/test/commands/analyze_test.dart b/pkg/dartdev/test/commands/analyze_test.dart
index 223962f..2d2ce3e 100644
--- a/pkg/dartdev/test/commands/analyze_test.dart
+++ b/pkg/dartdev/test/commands/analyze_test.dart
@@ -14,7 +14,7 @@
   group('analyze', defineAnalyze, timeout: longTimeout);
 }
 
-const String _analyzeDescriptionText = "Analyze the project's Dart code.";
+const String _analyzeDescriptionText = 'Analyze Dart code in a directory.';
 
 const String _analyzeUsageText =
     'Usage: dart analyze [arguments] [<directory>]';
diff --git a/pkg/dartdev/test/commands/migrate_test.dart b/pkg/dartdev/test/commands/migrate_test.dart
index 681d550..500d587 100644
--- a/pkg/dartdev/test/commands/migrate_test.dart
+++ b/pkg/dartdev/test/commands/migrate_test.dart
@@ -25,8 +25,8 @@
 
     expect(result.exitCode, 0);
     expect(result.stderr, isEmpty);
-    expect(result.stdout,
-        contains('Perform a null safety migration on a project or package.'));
+    expect(
+        result.stdout, contains('Perform null safety migration on a project.'));
     expect(result.stdout,
         contains('Usage: dart migrate [arguments] [project or directory]'));
   });
diff --git a/pkg/dartdev/test/commands/test_test.dart b/pkg/dartdev/test/commands/test_test.dart
index 1a85ad1..b493403 100644
--- a/pkg/dartdev/test/commands/test_test.dart
+++ b/pkg/dartdev/test/commands/test_test.dart
@@ -41,7 +41,7 @@
     final result = p.runSync(['help', 'test']);
 
     expect(result.exitCode, 0);
-    expect(result.stdout, contains(' tests in this package'));
+    expect(result.stdout, contains(' tests for a project'));
     expect(result.stderr, isEmpty);
   });
 
@@ -64,7 +64,7 @@
     expect(resultHelp.stdout, '''
 No pubspec.yaml file found - run this command in your project folder.
 
-Run tests in this package.
+Run tests for a project.
 
 Usage: dart test [arguments]
 
diff --git a/pkg/dev_compiler/lib/src/kernel/command.dart b/pkg/dev_compiler/lib/src/kernel/command.dart
index 9a30699..8ddd4dc 100644
--- a/pkg/dev_compiler/lib/src/kernel/command.dart
+++ b/pkg/dev_compiler/lib/src/kernel/command.dart
@@ -16,7 +16,6 @@
 import 'package:kernel/class_hierarchy.dart';
 import 'package:kernel/core_types.dart';
 import 'package:kernel/kernel.dart';
-import 'package:kernel/ast.dart' show NonNullableByDefaultCompiledMode;
 import 'package:kernel/target/targets.dart';
 import 'package:kernel/text/ast_to_text.dart' as kernel show Printer;
 import 'package:path/path.dart' as p;
diff --git a/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart b/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
index 2758926..03c94f7 100644
--- a/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
@@ -16,7 +16,6 @@
 import 'package:dev_compiler/src/compiler/js_names.dart' as js_ast;
 import 'package:dev_compiler/src/compiler/module_builder.dart';
 import 'package:dev_compiler/src/js_ast/js_ast.dart' as js_ast;
-import 'package:dev_compiler/src/kernel/compiler.dart';
 
 import 'package:front_end/src/api_unstable/ddc.dart';
 
diff --git a/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart b/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
index f379041..0052d2d 100644
--- a/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
+++ b/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
@@ -12,7 +12,6 @@
 import 'package:args/args.dart';
 import 'package:build_integration/file_system/multi_root.dart';
 import 'package:dev_compiler/dev_compiler.dart';
-import 'package:dev_compiler/src/compiler/module_builder.dart';
 import 'package:front_end/src/api_prototype/file_system.dart';
 import 'package:front_end/src/api_unstable/ddc.dart';
 import 'package:kernel/ast.dart' show Component, Library;
@@ -25,11 +24,7 @@
 import 'package:vm/http_filesystem.dart';
 
 import '../compiler/js_names.dart';
-import '../compiler/shared_command.dart';
 import 'command.dart';
-import 'compiler.dart';
-import 'expression_compiler.dart';
-import 'target.dart';
 
 /// The service that handles expression compilation requests from
 /// the debugger.
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_test.dart
index dabd569..bf7b39a 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_test.dart
@@ -14,7 +14,6 @@
 import 'package:cli_util/cli_util.dart';
 import 'package:dev_compiler/dev_compiler.dart';
 import 'package:dev_compiler/src/compiler/module_builder.dart';
-import 'package:dev_compiler/src/kernel/command.dart';
 import 'package:dev_compiler/src/kernel/module_metadata.dart';
 import 'package:front_end/src/api_unstable/ddc.dart' as fe;
 import 'package:front_end/src/compute_platform_binaries_location.dart' as fe;
diff --git a/pkg/nnbd_migration/lib/migration_cli.dart b/pkg/nnbd_migration/lib/migration_cli.dart
index 5705e9a..9298730 100644
--- a/pkg/nnbd_migration/lib/migration_cli.dart
+++ b/pkg/nnbd_migration/lib/migration_cli.dart
@@ -142,7 +142,7 @@
   static const String cmdName = 'migrate';
 
   static const String cmdDescription =
-      'Perform a null safety migration on a project or package.';
+      'Perform null safety migration on a project.';
 
   static const String migrationGuideLink =
       'See https://dart.dev/go/null-safety-migration for a migration guide.';
@@ -225,7 +225,7 @@
               defaultsTo: false,
               negatable: false,
               help:
-                  'Attempt to perform null safety analysis even if the package has '
+                  'Attempt to perform null safety analysis even if the project has '
                   'analysis errors.',
             )),
     MigrationCliOption(
@@ -428,7 +428,7 @@
   }
 
   void _showUsage(bool isVerbose) {
-    logger.stderr('Usage: $binaryName [options...] [<package directory>]');
+    logger.stderr('Usage: $binaryName [options...] [<project directory>]');
 
     logger.stderr('');
     logger.stderr(createParser(hide: !isVerbose).usage);
diff --git a/pkg/vm_service/lib/src/vm_service.dart b/pkg/vm_service/lib/src/vm_service.dart
index ea6a751..8b869fb 100644
--- a/pkg/vm_service/lib/src/vm_service.dart
+++ b/pkg/vm_service/lib/src/vm_service.dart
@@ -3368,7 +3368,11 @@
   /// The number of samples returned.
   int? sampleCount;
 
-  /// The timespan the set of returned samples covers, in microseconds.
+  /// The timespan the set of returned samples covers, in microseconds
+  /// (deprecated).
+  ///
+  /// Note: this property is deprecated and will always return -1. Use
+  /// `timeExtentMicros` instead.
   int? timeSpan;
 
   /// The start of the period of time in which the returned samples were
diff --git a/runtime/docs/gc.md b/runtime/docs/gc.md
index ad3c964..1780c11 100644
--- a/runtime/docs/gc.md
+++ b/runtime/docs/gc.md
@@ -1,6 +1,6 @@
 # Garbage Collection
 
-The Dart VM has a generational garbage collector with two generations. The new generation is collected by a stop-the-world semispace [scavenger](https://github.com/dart-lang/sdk/blob/master/runtime/vm/heap/scavenger.h). The old generation is collected by concurrent-[mark](https://github.com/dart-lang/sdk/blob/master/runtime/vm/heap/marker.h)-concurrent-[sweep](https://github.com/dart-lang/sdk/blob/master/runtime/vm/heap/sweeper.h) or by concurrent-mark-parallel-[compact](https://github.com/dart-lang/sdk/blob/master/runtime/vm/heap/compactor.h).
+The Dart VM has a generational garbage collector with two generations. The new generation is collected by a parallel, stop-the-world semispace [scavenger](https://github.com/dart-lang/sdk/blob/master/runtime/vm/heap/scavenger.h). The old generation is collected by concurrent-[mark](https://github.com/dart-lang/sdk/blob/master/runtime/vm/heap/marker.h)-concurrent-[sweep](https://github.com/dart-lang/sdk/blob/master/runtime/vm/heap/sweeper.h) or by concurrent-mark-parallel-[compact](https://github.com/dart-lang/sdk/blob/master/runtime/vm/heap/compactor.h).
 
 ## Object representation
 
@@ -10,7 +10,7 @@
 
 A tag of 1 has no penalty on heap object access because removing the tag can be folded into the offset used by load and store instructions.
 
-Heap objects are always allocated in double-word increments. Objects in old-space are kept at double-word alignment, and objects in new-space are kept offset from double-word alignment. This allows checking an object's age without comparing to a boundry address, avoiding restrictions on heap placement and avoiding loading the boundry from thread-local storage. Additionally, the scavenger can quickly skip over both immediates and old objects with a single branch.
+Heap objects are always allocated in double-word increments. Objects in old-space are kept at double-word alignment (address % double-word == 0), and objects in new-space are kept offset from double-word alignment (address % double-word == word). This allows checking an object's age without comparing to a boundry address, avoiding restrictions on heap placement and avoiding loading the boundry from thread-local storage. Additionally, the scavenger can quickly skip over both immediates and old objects with a single branch.
 
 | Pointer    | Referent                                |
 | ---        | ---                                     |
@@ -21,7 +21,29 @@
 
 Heap objects have a single-word header, which encodes the object's class, size, and some status flags.
 
-On 64-bit architectures, the header of heap objects also contains a 32-bit identity hash field. On 32-bit architectures, the identity hash for heap objects is kept in a side table.
+On 64-bit architectures, the header of heap objects also contains a 32-bit identity hash field. On 32-bit architectures, the identity hash for heap objects is kept in a separate hash table.
+
+## Handles
+
+The Dart VM's GC is precise and moving.
+
+A GC is said to be "precise" if when a collection happens it knows exactly what is and is not a pointer into the heap. For example, in compiled Dart code the VM tracks which stack slots contain object pointers and which contain unboxed values. This is opposed to a "conservative" collector that considers any pointer-sized value might be a pointer into the heap, though it might just be an unboxed value.
+
+In a "moving" GC, the address of an object might change, requiring pointers to that object to be updated. In the Dart VM, objects can move during a scavenge or a compaction. A moving GC must be a precise GC: if a conservative GC updates a value that is not guarenteed to be a pointer, it will corrupt execution when the value was not in fact a pointer.
+
+The VM does not know which stack slots, globals or object fields in foreign languages contain pointers into the Dart heap, including the VM's own runtime implemented in C++. For the GC to remain precise, foreign languages reference Dart objects indirectly through "handles". Handles can be thought of as pointers to pointers. They are allocated from the VM, and the GC will visit (and possibly update) the pointers contained in handles during collections.
+
+## Safepoints
+
+Any non-GC thread or task that can allocate, read or write to the heap is called a "mutator" (because it can mutate the object graph).
+
+Some phases of GC require that the heap is not being used by a mutator; we call these "[safepoint](https://github.com/dart-lang/sdk/blob/master/runtime/vm/heap/safepoint.h) operations". Examples of safepoint operations include marking roots at the beginning of concurrent marking and the entirety of a scavenge.
+
+To perform these operations, all mutators need to temporarily stop accessing the heap; we say that these mutators have reached a "safepoint". A mutator that has reached a safepoint will not resume accessing the heap (leave the safepoint) until the safepoint operation is complete. In addition to not accessing the heap, a mutator at a safepoint must not hold any pointers into the heap unless these pointers can be visited by the GC. For code in the VM runtime, this last property means holding only handles and no ObjectPtr nor UntaggedObject. Examples of places that might enter a safepoint include allocations, stack overflow checks, and transitions between compiled code and the runtime and native code.
+
+Note that a mutator can be at a safepoint without being suspended. It might be performing a long task that doesn't access the heap. It will, however, need to wait for any safepoint operation to complete in order to leave its safepoint and resume accessing the heap.
+
+Because a safepoint operation excludes execution of Dart code, it is sometimes used for non-GC tasks that requires only this property. For example, when a background compilation has completed and wants to install its result, it uses a safepoint operation to ensure no Dart execution sees the intermediate states during installation.
 
 ## Scavenge
 
@@ -29,7 +51,7 @@
 
 ## Parallel Scavenge
 
-FLAG_scavenger_tasks (default 2) workers are started on separate threads. Each worker competes to process parts of the root set (including the remembered set). When a worker copies an object to to-space, it allocates from a worker-local bump allocation region. The same worker will process the copied object. When a worker promotes an object to old-space, it allocates from a worker-local freelist, which uses bump allocation for large free blocks. The promoted object is added to a work list that implements work stealing, so some other worker may process the promoted object. After the object is evacuated, the worker using a compare-and-swap to install the forwarding pointer into the from-space object's header. If it loses the race, it un-allocates the to-space or old-space object it just allocated, and uses the winner's object to update the pointer it was processing. Workers run until all of the work set have been processed, and every worker have processed its to-space objects and local part of the promoted work list.
+FLAG_scavenger_tasks (default 2) workers are started on separate threads. Each worker competes to process parts of the root set (including the remembered set). When a worker copies an object to to-space, it allocates from a worker-local bump allocation region. The same worker will process the copied object. When a worker promotes an object to old-space, it allocates from a worker-local freelist, which uses bump allocation for large free blocks. The promoted object is added to a work list that implements work stealing, so some other worker may process the promoted object. After the object is evacuated, the worker uses a compare-and-swap to install the forwarding pointer into the from-space object's header. If it loses the race, it un-allocates the to-space or old-space object it just allocated, and uses the winner's object to update the pointer it was processing. Workers run until all of the work sets have been processed, and every worker has processed its to-space objects and its local part of the promoted work list.
 
 ## Mark-Sweep
 
@@ -45,18 +67,6 @@
 
 The Dart VM includes a sliding compactor. The forwarding table is compactly represented by dividing the heap into blocks and for each block recording its target address and the bitvector for each surviving double-word. The table is accessed in constant time by keeping heap pages aligned so the page header of any object can be accessed by masking the object.
 
-## Safepoints
-
-Any thread or task that can allocate, read or write to the heap is called a "mutator" (because it can mutate the object graph).
-
-Some phases of GC require that the heap is not being used by a mutator; we call these "[safepoint](https://github.com/dart-lang/sdk/blob/master/runtime/vm/heap/safepoint.h) operations". Examples of safepoint operations include marking roots at the beginning of concurrent marking and the entirety of a scavenge.
-
-To perform these operations, all mutators need to temporarily stop accessing the heap; we say that these mutators have reached a "safepoint". A mutator that has reached a safepoint will not resume accessing the heap (leave the safepoint) until the safepoint operation is complete. In addition to not accessing the heap, a mutator at a safepoint must not hold any pointers into the heap unless these pointers can be visited by the GC. For code in the VM runtime, this last property means holding only handles and no RawObject pointers. Examples of places that might enter a safepoint include allocations, stack overflow checks, and transitions between compiled code and the runtime and native code.
-
-Note that a mutator can be at a safepoint without being suspended. It might be performing a long task that doesn't access the heap. It will, however, need to wait for any safepoint operation to complete in order to leave its safepoint and resume accessing the heap.
-
-Because a safepoint operation excludes excution of Dart code, it is sometimes used for non-GC tasks that requires only this property. For example, when a background compilation has completed and wants to install its result, it uses a safepoint operation to ensure no Dart execution sees the intermediate states during installation.
-
 ## Concurrent Marking
 
 To reduce the time the mutator is paused for old-space GCs, we allow the mutator to continue running during most of the marking work. 
@@ -140,7 +150,7 @@
 
 For old-space objects created before marking started, in each slot the marker can see either its value at the time marking started or any subsequent value sorted in the slot. Any slot that contained a pointer continues to continue a valid pointer for the object's lifetime, so no matter which value the marker sees, it won't interpret a non-pointer as a pointer. (The one interesting case here is array truncation, where some slot in the array will become the header of a filler object. We ensure this is safe for concurrent marking by ensuring the header for the filler object looks like a Smi.) If the marker sees an old value, we may lose some precision and retain a dead object, but we remain correct because the new value has been marked by the mutator.
 
-For old-space objects created after marking started, the marker may see uninitialized values because operations on slots are not synchronized. To prevent this, during marking we allocate old-space objects black (marked) so the marker will not visit them.
+For old-space objects created after marking started, the marker may see uninitialized values because operations on slots are not synchronized. To prevent this, during marking we allocate old-space objects [black (marked)](https://en.wikipedia.org/wiki/Tracing_garbage_collection#TRI-COLOR) so the marker will not visit them.
 
 New-space objects and roots are only visited during a safepoint, and safepoints establish synchronization.
 
diff --git a/runtime/observatory/lib/src/sample_profile/sample_profile.dart b/runtime/observatory/lib/src/sample_profile/sample_profile.dart
index 06280ce..91bf3ac 100644
--- a/runtime/observatory/lib/src/sample_profile/sample_profile.dart
+++ b/runtime/observatory/lib/src/sample_profile/sample_profile.dart
@@ -784,7 +784,7 @@
   static const String _kSamples = 'samples';
   static const String _kStack = 'stack';
   static const String _kMaxStackDepth = 'maxStackDepth';
-  static const String _kTimeSpan = 'timespan';
+  static const String _kTimeSpan = 'timeExtentMicros';
   static const String _kUserTag = 'userTag';
   static const String _kVmTag = 'vmTag';
 
@@ -895,7 +895,7 @@
       samplePeriod = profile[_kSamplePeriod];
       sampleRate = (Duration.microsecondsPerSecond / samplePeriod);
       maxStackDepth = profile[_kMaxStackDepth];
-      timeSpan = profile[_kTimeSpan];
+      timeSpan = profile[_kTimeSpan] / Duration.microsecondsPerSecond;
 
       num length = 0;
 
diff --git a/runtime/observatory_2/lib/src/sample_profile/sample_profile.dart b/runtime/observatory_2/lib/src/sample_profile/sample_profile.dart
index 48667cc..8d1a385 100644
--- a/runtime/observatory_2/lib/src/sample_profile/sample_profile.dart
+++ b/runtime/observatory_2/lib/src/sample_profile/sample_profile.dart
@@ -780,7 +780,7 @@
   static const String _kSamples = 'samples';
   static const String _kStack = 'stack';
   static const String _kMaxStackDepth = 'maxStackDepth';
-  static const String _kTimeSpan = 'timespan';
+  static const String _kTimeSpan = 'timeExtentMicros';
   static const String _kUserTag = 'userTag';
   static const String _kVmTag = 'vmTag';
 
@@ -891,7 +891,7 @@
       samplePeriod = profile[_kSamplePeriod];
       sampleRate = (Duration.microsecondsPerSecond / samplePeriod);
       maxStackDepth = profile[_kMaxStackDepth];
-      timeSpan = profile[_kTimeSpan];
+      timeSpan = profile[_kTimeSpan] / Duration.microsecondsPerSecond;
 
       num length = 0;
 
diff --git a/runtime/tests/vm/dart/deopt/allocate_array_test.dart b/runtime/tests/vm/dart/deopt/allocate_array_test.dart
new file mode 100644
index 0000000..eb06336
--- /dev/null
+++ b/runtime/tests/vm/dart/deopt/allocate_array_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--disable-dart-dev --no-inline-alloc --use-slow-path --deoptimize-on-runtime-call-every=1 --deterministic --optimization-counter-threshold=1 --deoptimize-on-runtime-call-name-filter=AllocateArray
+
+main() {
+  for (int i = 0; i < 20; ++i) {
+    final list = foo(1);
+    if (list[0] != 42) throw 'a';
+  }
+}
+
+@pragma('vm:never-inline')
+List foo(int a) {
+  return List<dynamic>.filled(a, null)..[0] = 42;
+}
diff --git a/runtime/tests/vm/dart/deopt/allocate_context_test.dart b/runtime/tests/vm/dart/deopt/allocate_context_test.dart
new file mode 100644
index 0000000..c52abc0
--- /dev/null
+++ b/runtime/tests/vm/dart/deopt/allocate_context_test.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--disable-dart-dev --no-inline-alloc --use-slow-path --deoptimize-on-runtime-call-every=1 --deterministic --optimization-counter-threshold=1 --deoptimize-on-runtime-call-name-filter=AllocateContext
+
+main() {
+  for (int i = 0; i < 20; ++i) {
+    final fun = foo(1);
+    if (fun(1) != 3) throw 'a';
+    if (fun(2) != 6) throw 'b';
+  }
+}
+
+@pragma('vm:never-inline')
+int Function(int) foo(int a) {
+  int b = 1;
+  return (int c) {
+    return a++ + b++ + c;
+  };
+}
diff --git a/runtime/tests/vm/dart/deopt/allocate_object_test.dart b/runtime/tests/vm/dart/deopt/allocate_object_test.dart
new file mode 100644
index 0000000..efcd883
--- /dev/null
+++ b/runtime/tests/vm/dart/deopt/allocate_object_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--disable-dart-dev --no-inline-alloc --use-slow-path --deoptimize-on-runtime-call-every=1 --deterministic --optimization-counter-threshold=1 --deoptimize-on-runtime-call-name-filter=AllocateObject
+
+main() {
+  for (int i = 0; i < 20; ++i) {
+    final foo = bar(1);
+    if (foo.fun(1) != 3) throw 'a';
+    if (foo.fun(2) != 6) throw 'b';
+  }
+}
+
+@pragma('vm:never-inline')
+Foo bar(int a) {
+  int b = 1;
+  return Foo(a, (int c) {
+    return a++ + b++ + c++;
+  });
+}
+
+class Foo {
+  final int value;
+  final int Function(int) fun;
+  Foo(this.value, this.fun);
+}
diff --git a/runtime/tests/vm/dart/deopt/allocate_typed_data_test.dart b/runtime/tests/vm/dart/deopt/allocate_typed_data_test.dart
new file mode 100644
index 0000000..6556661
--- /dev/null
+++ b/runtime/tests/vm/dart/deopt/allocate_typed_data_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--disable-dart-dev --no-inline-alloc --use-slow-path --deoptimize-on-runtime-call-every=1 --deterministic --optimization-counter-threshold=1 --deoptimize-on-runtime-call-name-filter=AllocateTypedData
+
+import 'dart:typed_data';
+
+main() {
+  for (int i = 0; i < 20; ++i) {
+    final foo = bar(1);
+    if (foo[0] != 42) throw 'a';
+  }
+}
+
+@pragma('vm:never-inline')
+Uint32List bar(int a) {
+  return Uint32List(1)..[0] = 42;
+}
diff --git a/runtime/tests/vm/dart/deopt/clone_context_test.dart b/runtime/tests/vm/dart/deopt/clone_context_test.dart
new file mode 100644
index 0000000..5320404
--- /dev/null
+++ b/runtime/tests/vm/dart/deopt/clone_context_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--disable-dart-dev --no-inline-alloc --use-slow-path --deoptimize-on-runtime-call-every=1 --deterministic --optimization-counter-threshold=1 --deoptimize-on-runtime-call-name-filter=CloneContext
+
+main() {
+  for (int i = 0; i < 20; ++i) {
+    if (foo(1)[1]() != 2) throw 'a';
+  }
+}
+
+@pragma('vm:never-inline')
+List foo(int a) {
+  final l = <int Function()>[];
+  for (int i = 0; i < 10; ++i) {
+    l.add(() => a + i);
+  }
+  return l;
+}
diff --git a/runtime/tests/vm/dart_2/deopt/allocate_array_test.dart b/runtime/tests/vm/dart_2/deopt/allocate_array_test.dart
new file mode 100644
index 0000000..eb06336
--- /dev/null
+++ b/runtime/tests/vm/dart_2/deopt/allocate_array_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--disable-dart-dev --no-inline-alloc --use-slow-path --deoptimize-on-runtime-call-every=1 --deterministic --optimization-counter-threshold=1 --deoptimize-on-runtime-call-name-filter=AllocateArray
+
+main() {
+  for (int i = 0; i < 20; ++i) {
+    final list = foo(1);
+    if (list[0] != 42) throw 'a';
+  }
+}
+
+@pragma('vm:never-inline')
+List foo(int a) {
+  return List<dynamic>.filled(a, null)..[0] = 42;
+}
diff --git a/runtime/tests/vm/dart_2/deopt/allocate_context_test.dart b/runtime/tests/vm/dart_2/deopt/allocate_context_test.dart
new file mode 100644
index 0000000..c52abc0
--- /dev/null
+++ b/runtime/tests/vm/dart_2/deopt/allocate_context_test.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--disable-dart-dev --no-inline-alloc --use-slow-path --deoptimize-on-runtime-call-every=1 --deterministic --optimization-counter-threshold=1 --deoptimize-on-runtime-call-name-filter=AllocateContext
+
+main() {
+  for (int i = 0; i < 20; ++i) {
+    final fun = foo(1);
+    if (fun(1) != 3) throw 'a';
+    if (fun(2) != 6) throw 'b';
+  }
+}
+
+@pragma('vm:never-inline')
+int Function(int) foo(int a) {
+  int b = 1;
+  return (int c) {
+    return a++ + b++ + c;
+  };
+}
diff --git a/runtime/tests/vm/dart_2/deopt/allocate_object_test.dart b/runtime/tests/vm/dart_2/deopt/allocate_object_test.dart
new file mode 100644
index 0000000..efcd883
--- /dev/null
+++ b/runtime/tests/vm/dart_2/deopt/allocate_object_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--disable-dart-dev --no-inline-alloc --use-slow-path --deoptimize-on-runtime-call-every=1 --deterministic --optimization-counter-threshold=1 --deoptimize-on-runtime-call-name-filter=AllocateObject
+
+main() {
+  for (int i = 0; i < 20; ++i) {
+    final foo = bar(1);
+    if (foo.fun(1) != 3) throw 'a';
+    if (foo.fun(2) != 6) throw 'b';
+  }
+}
+
+@pragma('vm:never-inline')
+Foo bar(int a) {
+  int b = 1;
+  return Foo(a, (int c) {
+    return a++ + b++ + c++;
+  });
+}
+
+class Foo {
+  final int value;
+  final int Function(int) fun;
+  Foo(this.value, this.fun);
+}
diff --git a/runtime/tests/vm/dart_2/deopt/allocate_typed_data_test.dart b/runtime/tests/vm/dart_2/deopt/allocate_typed_data_test.dart
new file mode 100644
index 0000000..6556661
--- /dev/null
+++ b/runtime/tests/vm/dart_2/deopt/allocate_typed_data_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--disable-dart-dev --no-inline-alloc --use-slow-path --deoptimize-on-runtime-call-every=1 --deterministic --optimization-counter-threshold=1 --deoptimize-on-runtime-call-name-filter=AllocateTypedData
+
+import 'dart:typed_data';
+
+main() {
+  for (int i = 0; i < 20; ++i) {
+    final foo = bar(1);
+    if (foo[0] != 42) throw 'a';
+  }
+}
+
+@pragma('vm:never-inline')
+Uint32List bar(int a) {
+  return Uint32List(1)..[0] = 42;
+}
diff --git a/runtime/tests/vm/dart_2/deopt/clone_context_test.dart b/runtime/tests/vm/dart_2/deopt/clone_context_test.dart
new file mode 100644
index 0000000..5320404
--- /dev/null
+++ b/runtime/tests/vm/dart_2/deopt/clone_context_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--disable-dart-dev --no-inline-alloc --use-slow-path --deoptimize-on-runtime-call-every=1 --deterministic --optimization-counter-threshold=1 --deoptimize-on-runtime-call-name-filter=CloneContext
+
+main() {
+  for (int i = 0; i < 20; ++i) {
+    if (foo(1)[1]() != 2) throw 'a';
+  }
+}
+
+@pragma('vm:never-inline')
+List foo(int a) {
+  final l = <int Function()>[];
+  for (int i = 0; i < 10; ++i) {
+    l.add(() => a + i);
+  }
+  return l;
+}
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 9dc20b5..7a787a9 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -995,8 +995,9 @@
 
 AllocateUninitializedContextInstr::AllocateUninitializedContextInstr(
     const InstructionSource& source,
-    intptr_t num_context_variables)
-    : TemplateAllocation(source),
+    intptr_t num_context_variables,
+    intptr_t deopt_id)
+    : TemplateAllocation(source, deopt_id),
       num_context_variables_(num_context_variables) {
   // This instruction is not used in AOT for code size reasons.
   ASSERT(!CompilerState::Current().is_aot());
@@ -1019,7 +1020,7 @@
   const Code& stub = Code::ZoneHandle(
       compiler->zone(), StubCode::GetAllocationStubForTypedData(class_id()));
   compiler->GenerateStubCall(source(), stub, UntaggedPcDescriptors::kOther,
-                             locs());
+                             locs(), deopt_id());
 }
 
 bool StoreInstanceFieldInstr::IsUnboxedStore() const {
@@ -1131,7 +1132,7 @@
 }
 
 bool LoadStaticFieldInstr::AttributesEqual(Instruction* other) const {
-  ASSERT(IsFieldInitialized());
+  ASSERT(AllowsCSE());
   return field().ptr() == other->AsLoadStaticField()->field().ptr();
 }
 
@@ -5480,11 +5481,13 @@
     __ CompareRegisters(InstantiationABI::kInstantiatorTypeArgumentsReg,
                         InstantiationABI::kResultTypeArgumentsReg);
     if (!function_type_arguments()->BindsToConstant()) {
-      __ BranchIf(NOT_EQUAL, &non_null_type_args);
+      __ BranchIf(NOT_EQUAL, &non_null_type_args,
+                  compiler::AssemblerBase::kNearJump);
       __ CompareRegisters(InstantiationABI::kFunctionTypeArgumentsReg,
                           InstantiationABI::kResultTypeArgumentsReg);
     }
-    __ BranchIf(EQUAL, &type_arguments_instantiated);
+    __ BranchIf(EQUAL, &type_arguments_instantiated,
+                compiler::AssemblerBase::kNearJump);
     __ Bind(&non_null_type_args);
   }
 
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index 4d88ca8..bca05d1 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -788,7 +788,7 @@
 
   intptr_t deopt_id() const {
     ASSERT(ComputeCanDeoptimize() || ComputeCanDeoptimizeAfterCall() ||
-           CanBecomeDeoptimizationTarget() ||
+           CanBecomeDeoptimizationTarget() || MayThrow() ||
            CompilerState::Current().is_aot());
     return GetDeoptId();
   }
@@ -5522,9 +5522,7 @@
   bool calls_initializer() const { return calls_initializer_; }
   void set_calls_initializer(bool value) { calls_initializer_ = value; }
 
-  virtual bool AllowsCSE() const {
-    return field().is_final() && !FLAG_fields_may_be_reset;
-  }
+  virtual bool AllowsCSE() const { return field().is_final(); }
 
   virtual bool ComputeCanDeoptimize() const {
     return calls_initializer() && !CompilerState::Current().is_aot();
@@ -6061,6 +6059,21 @@
   // is added.
   virtual bool WillAllocateNewOrRemembered() const = 0;
 
+  virtual bool MayThrow() const {
+    // Any allocation instruction may throw an OutOfMemory error.
+    return true;
+  }
+  virtual bool ComputeCanDeoptimize() const { return false; }
+  virtual bool ComputeCanDeoptimizeAfterCall() const {
+    // We test that allocation instructions have correct deopt environment
+    // (which is needed in case OOM is thrown) by actually deoptimizing
+    // optimized code in allocation slow paths.
+    return !CompilerState::Current().is_aot();
+  }
+  virtual intptr_t NumberOfInputsConsumedBeforeCall() const {
+    return InputCount();
+  }
+
   DEFINE_INSTRUCTION_TYPE_CHECK(Allocation);
 
  private:
@@ -6070,18 +6083,16 @@
   DISALLOW_COPY_AND_ASSIGN(AllocationInstr);
 };
 
-template <intptr_t N, typename ThrowsTrait>
+template <intptr_t N>
 class TemplateAllocation : public AllocationInstr {
  public:
   explicit TemplateAllocation(const InstructionSource& source,
-                              intptr_t deopt_id = DeoptId::kNone)
+                              intptr_t deopt_id)
       : AllocationInstr(source, deopt_id), inputs_() {}
 
   virtual intptr_t InputCount() const { return N; }
   virtual Value* InputAt(intptr_t i) const { return inputs_[i]; }
 
-  virtual bool MayThrow() const { return ThrowsTrait::kCanThrow; }
-
  protected:
   EmbeddedArray<Value*, N> inputs_;
 
@@ -6096,8 +6107,9 @@
  public:
   AllocateObjectInstr(const InstructionSource& source,
                       const Class& cls,
+                      intptr_t deopt_id,
                       Value* type_arguments = nullptr)
-      : AllocationInstr(source),
+      : AllocationInstr(source, deopt_id),
         cls_(cls),
         type_arguments_(type_arguments),
         closure_function_(Function::ZoneHandle()) {
@@ -6126,10 +6138,6 @@
     return type_arguments_;
   }
 
-  virtual bool MayThrow() const { return false; }
-
-  virtual bool ComputeCanDeoptimize() const { return false; }
-
   virtual bool HasUnknownSideEffects() const { return false; }
 
   virtual bool WillAllocateNewOrRemembered() const {
@@ -6156,19 +6164,17 @@
   DISALLOW_COPY_AND_ASSIGN(AllocateObjectInstr);
 };
 
-class AllocateUninitializedContextInstr
-    : public TemplateAllocation<0, NoThrow> {
+class AllocateUninitializedContextInstr : public TemplateAllocation<0> {
  public:
   AllocateUninitializedContextInstr(const InstructionSource& source,
-                                    intptr_t num_context_variables);
+                                    intptr_t num_context_variables,
+                                    intptr_t deopt_id);
 
   DECLARE_INSTRUCTION(AllocateUninitializedContext)
   virtual CompileType ComputeType() const;
 
   intptr_t num_context_variables() const { return num_context_variables_; }
 
-  virtual bool ComputeCanDeoptimize() const { return false; }
-
   virtual bool HasUnknownSideEffects() const { return false; }
 
   virtual bool WillAllocateNewOrRemembered() const {
@@ -6290,7 +6296,7 @@
   DISALLOW_COPY_AND_ASSIGN(ArrayAllocationInstr);
 };
 
-template <intptr_t N, typename ThrowsTrait>
+template <intptr_t N>
 class TemplateArrayAllocation : public ArrayAllocationInstr {
  public:
   explicit TemplateArrayAllocation(const InstructionSource& source,
@@ -6300,8 +6306,6 @@
   virtual intptr_t InputCount() const { return N; }
   virtual Value* InputAt(intptr_t i) const { return inputs_[i]; }
 
-  virtual bool MayThrow() const { return ThrowsTrait::kCanThrow; }
-
  protected:
   EmbeddedArray<Value*, N> inputs_;
 
@@ -6309,7 +6313,7 @@
   virtual void RawSetInputAt(intptr_t i, Value* value) { inputs_[i] = value; }
 };
 
-class CreateArrayInstr : public TemplateArrayAllocation<2, Throws> {
+class CreateArrayInstr : public TemplateArrayAllocation<2> {
  public:
   CreateArrayInstr(const InstructionSource& source,
                    Value* element_type,
@@ -6328,12 +6332,6 @@
   Value* element_type() const { return inputs_[kElementTypePos]; }
   virtual Value* num_elements() const { return inputs_[kLengthPos]; }
 
-  // Throw needs environment, which is created only if instruction can
-  // deoptimize.
-  virtual bool ComputeCanDeoptimize() const {
-    return !CompilerState::Current().is_aot();
-  }
-
   virtual bool HasUnknownSideEffects() const { return false; }
 
   virtual bool WillAllocateNewOrRemembered() const {
@@ -6347,7 +6345,7 @@
   DISALLOW_COPY_AND_ASSIGN(CreateArrayInstr);
 };
 
-class AllocateTypedDataInstr : public TemplateArrayAllocation<1, Throws> {
+class AllocateTypedDataInstr : public TemplateArrayAllocation<1> {
  public:
   AllocateTypedDataInstr(const InstructionSource& source,
                          classid_t class_id,
@@ -6365,12 +6363,6 @@
   classid_t class_id() const { return class_id_; }
   virtual Value* num_elements() const { return inputs_[kLengthPos]; }
 
-  // Throw needs environment, which is created only if instruction can
-  // deoptimize.
-  virtual bool ComputeCanDeoptimize() const {
-    return !CompilerState::Current().is_aot();
-  }
-
   virtual bool HasUnknownSideEffects() const { return false; }
 
   virtual bool WillAllocateNewOrRemembered() const {
@@ -6758,11 +6750,12 @@
 
 // [AllocateContext] instruction allocates a new Context object with the space
 // for the given [context_variables].
-class AllocateContextInstr : public TemplateAllocation<0, NoThrow> {
+class AllocateContextInstr : public TemplateAllocation<0> {
  public:
   AllocateContextInstr(const InstructionSource& source,
-                       const ZoneGrowableArray<const Slot*>& context_slots)
-      : TemplateAllocation(source), context_slots_(context_slots) {}
+                       const ZoneGrowableArray<const Slot*>& context_slots,
+                       intptr_t deopt_id)
+      : TemplateAllocation(source, deopt_id), context_slots_(context_slots) {}
 
   DECLARE_INSTRUCTION(AllocateContext)
   virtual CompileType ComputeType() const;
@@ -6792,7 +6785,7 @@
 
 // [CloneContext] instruction clones the given Context object assuming that
 // it contains exactly the provided [context_variables].
-class CloneContextInstr : public TemplateDefinition<1, NoThrow> {
+class CloneContextInstr : public TemplateDefinition<1, Throws> {
  public:
   CloneContextInstr(const InstructionSource& source,
                     Value* context_value,
@@ -6814,9 +6807,16 @@
   DECLARE_INSTRUCTION(CloneContext)
   virtual CompileType ComputeType() const;
 
-  virtual bool ComputeCanDeoptimize() const {
+  virtual bool ComputeCanDeoptimize() const { return false; }
+  virtual bool ComputeCanDeoptimizeAfterCall() const {
+    // We test that allocation instructions have correct deopt environment
+    // (which is needed in case OOM is thrown) by actually deoptimizing
+    // optimized code in allocation slow paths.
     return !CompilerState::Current().is_aot();
   }
+  virtual intptr_t NumberOfInputsConsumedBeforeCall() const {
+    return InputCount();
+  }
 
   virtual bool HasUnknownSideEffects() const { return false; }
 
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index 02b811a..53ca92a 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -3487,12 +3487,17 @@
 
     compiler->SaveLiveRegisters(locs);
 
+    auto slow_path_env = compiler->SlowPathEnvironmentFor(
+        instruction(), /*num_slow_path_args=*/0);
+    ASSERT(slow_path_env != nullptr);
+
     auto object_store = compiler->isolate_group()->object_store();
     const auto& allocate_context_stub = Code::ZoneHandle(
         compiler->zone(), object_store->allocate_context_stub());
     __ LoadImmediate(R1, instruction()->num_context_variables());
     compiler->GenerateStubCall(instruction()->source(), allocate_context_stub,
-                               UntaggedPcDescriptors::kOther, locs);
+                               UntaggedPcDescriptors::kOther, locs,
+                               instruction()->deopt_id(), slow_path_env);
     ASSERT(instruction()->locs()->out(0).reg() == R0);
     compiler->RestoreLiveRegisters(instruction()->locs());
     __ b(exit_label());
@@ -3547,7 +3552,7 @@
       Code::ZoneHandle(compiler->zone(), object_store->allocate_context_stub());
   __ LoadImmediate(R1, num_context_variables());
   compiler->GenerateStubCall(source(), allocate_context_stub,
-                             UntaggedPcDescriptors::kOther, locs());
+                             UntaggedPcDescriptors::kOther, locs(), deopt_id());
 }
 
 LocationSummary* CloneContextInstr::MakeLocationSummary(Zone* zone,
@@ -3569,7 +3574,8 @@
   const auto& clone_context_stub =
       Code::ZoneHandle(compiler->zone(), object_store->clone_context_stub());
   compiler->GenerateStubCall(source(), clone_context_stub,
-                             /*kind=*/UntaggedPcDescriptors::kOther, locs());
+                             /*kind=*/UntaggedPcDescriptors::kOther, locs(),
+                             deopt_id());
 }
 
 LocationSummary* CatchBlockEntryInstr::MakeLocationSummary(Zone* zone,
@@ -7846,7 +7852,7 @@
   const Code& stub = Code::ZoneHandle(
       compiler->zone(), StubCode::GetAllocationStubForClass(cls()));
   compiler->GenerateStubCall(source(), stub, UntaggedPcDescriptors::kOther,
-                             locs());
+                             locs(), deopt_id());
 }
 
 void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index 170d8e6..8cae728 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -3062,13 +3062,18 @@
 
     compiler->SaveLiveRegisters(locs);
 
+    auto slow_path_env = compiler->SlowPathEnvironmentFor(
+        instruction(), /*num_slow_path_args=*/0);
+    ASSERT(slow_path_env != nullptr);
+
     auto object_store = compiler->isolate_group()->object_store();
     const auto& allocate_context_stub = Code::ZoneHandle(
         compiler->zone(), object_store->allocate_context_stub());
 
     __ LoadImmediate(R1, instruction()->num_context_variables());
     compiler->GenerateStubCall(instruction()->source(), allocate_context_stub,
-                               UntaggedPcDescriptors::kOther, locs);
+                               UntaggedPcDescriptors::kOther, locs,
+                               instruction()->deopt_id(), slow_path_env);
     ASSERT(instruction()->locs()->out(0).reg() == R0);
     compiler->RestoreLiveRegisters(instruction()->locs());
     __ b(exit_label());
@@ -3122,7 +3127,7 @@
       Code::ZoneHandle(compiler->zone(), object_store->allocate_context_stub());
   __ LoadImmediate(R1, num_context_variables());
   compiler->GenerateStubCall(source(), allocate_context_stub,
-                             UntaggedPcDescriptors::kOther, locs());
+                             UntaggedPcDescriptors::kOther, locs(), deopt_id());
 }
 
 LocationSummary* CloneContextInstr::MakeLocationSummary(Zone* zone,
@@ -3144,7 +3149,8 @@
   const auto& clone_context_stub =
       Code::ZoneHandle(compiler->zone(), object_store->clone_context_stub());
   compiler->GenerateStubCall(source(), clone_context_stub,
-                             /*kind=*/UntaggedPcDescriptors::kOther, locs());
+                             /*kind=*/UntaggedPcDescriptors::kOther, locs(),
+                             deopt_id());
 }
 
 LocationSummary* CatchBlockEntryInstr::MakeLocationSummary(Zone* zone,
@@ -6905,7 +6911,7 @@
   const Code& stub = Code::ZoneHandle(
       compiler->zone(), StubCode::GetAllocationStubForClass(cls()));
   compiler->GenerateStubCall(source(), stub, UntaggedPcDescriptors::kOther,
-                             locs());
+                             locs(), deopt_id());
 }
 
 void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
diff --git a/runtime/vm/compiler/backend/il_ia32.cc b/runtime/vm/compiler/backend/il_ia32.cc
index 3381064..c7c46fc 100644
--- a/runtime/vm/compiler/backend/il_ia32.cc
+++ b/runtime/vm/compiler/backend/il_ia32.cc
@@ -2812,10 +2812,15 @@
 
     compiler->SaveLiveRegisters(locs);
 
+    auto slow_path_env = compiler->SlowPathEnvironmentFor(
+        instruction(), /*num_slow_path_args=*/0);
+    ASSERT(slow_path_env != nullptr);
+
     __ movl(EDX, compiler::Immediate(instruction()->num_context_variables()));
     compiler->GenerateStubCall(instruction()->source(),
                                StubCode::AllocateContext(),
-                               UntaggedPcDescriptors::kOther, locs);
+                               UntaggedPcDescriptors::kOther, locs,
+                               instruction()->deopt_id(), slow_path_env);
     ASSERT(instruction()->locs()->out(0).reg() == EAX);
     compiler->RestoreLiveRegisters(instruction()->locs());
     __ jmp(exit_label());
@@ -2867,7 +2872,7 @@
 
   __ movl(EDX, compiler::Immediate(num_context_variables()));
   compiler->GenerateStubCall(source(), StubCode::AllocateContext(),
-                             UntaggedPcDescriptors::kOther, locs());
+                             UntaggedPcDescriptors::kOther, locs(), deopt_id());
 }
 
 LocationSummary* CloneContextInstr::MakeLocationSummary(Zone* zone,
@@ -2886,7 +2891,8 @@
   ASSERT(locs()->out(0).reg() == EAX);
 
   compiler->GenerateStubCall(source(), StubCode::CloneContext(),
-                             /*kind=*/UntaggedPcDescriptors::kOther, locs());
+                             /*kind=*/UntaggedPcDescriptors::kOther, locs(),
+                             deopt_id());
 }
 
 LocationSummary* CatchBlockEntryInstr::MakeLocationSummary(Zone* zone,
@@ -6797,7 +6803,7 @@
   const Code& stub = Code::ZoneHandle(
       compiler->zone(), StubCode::GetAllocationStubForClass(cls()));
   compiler->GenerateStubCall(source(), stub, UntaggedPcDescriptors::kOther,
-                             locs());
+                             locs(), deopt_id());
 }
 
 void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index f755d79..d3264b1 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -3145,6 +3145,10 @@
 
     compiler->SaveLiveRegisters(locs);
 
+    auto slow_path_env = compiler->SlowPathEnvironmentFor(
+        instruction(), /*num_slow_path_args=*/0);
+    ASSERT(slow_path_env != nullptr);
+
     auto object_store = compiler->isolate_group()->object_store();
     const auto& allocate_context_stub = Code::ZoneHandle(
         compiler->zone(), object_store->allocate_context_stub());
@@ -3152,8 +3156,10 @@
     __ LoadImmediate(
         R10, compiler::Immediate(instruction()->num_context_variables()));
     compiler->GenerateStubCall(instruction()->source(), allocate_context_stub,
-                               UntaggedPcDescriptors::kOther, locs);
+                               UntaggedPcDescriptors::kOther, locs,
+                               instruction()->deopt_id(), slow_path_env);
     ASSERT(instruction()->locs()->out(0).reg() == RAX);
+
     compiler->RestoreLiveRegisters(instruction()->locs());
     __ jmp(exit_label());
   }
@@ -3207,7 +3213,7 @@
 
   __ LoadImmediate(R10, compiler::Immediate(num_context_variables()));
   compiler->GenerateStubCall(source(), allocate_context_stub,
-                             UntaggedPcDescriptors::kOther, locs());
+                             UntaggedPcDescriptors::kOther, locs(), deopt_id());
 }
 
 LocationSummary* CloneContextInstr::MakeLocationSummary(Zone* zone,
@@ -3229,7 +3235,8 @@
   const auto& clone_context_stub =
       Code::ZoneHandle(compiler->zone(), object_store->clone_context_stub());
   compiler->GenerateStubCall(source(), clone_context_stub,
-                             /*kind=*/UntaggedPcDescriptors::kOther, locs());
+                             /*kind=*/UntaggedPcDescriptors::kOther, locs(),
+                             deopt_id());
 }
 
 LocationSummary* CatchBlockEntryInstr::MakeLocationSummary(Zone* zone,
@@ -7329,7 +7336,7 @@
   const Code& stub = Code::ZoneHandle(
       compiler->zone(), StubCode::GetAllocationStubForClass(cls()));
   compiler->GenerateStubCall(source(), stub, UntaggedPcDescriptors::kOther,
-                             locs());
+                             locs(), deopt_id());
 }
 
 void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
diff --git a/runtime/vm/compiler/backend/redundancy_elimination_test.cc b/runtime/vm/compiler/backend/redundancy_elimination_test.cc
index 65b6b80..c76394e 100644
--- a/runtime/vm/compiler/backend/redundancy_elimination_test.cc
+++ b/runtime/vm/compiler/backend/redundancy_elimination_test.cc
@@ -262,7 +262,7 @@
     BlockBuilder builder(H.flow_graph(), b1);
     auto& slot = Slot::Get(field, &H.flow_graph()->parsed_function());
     v0 = builder.AddDefinition(
-        new AllocateObjectInstr(InstructionSource(), cls));
+        new AllocateObjectInstr(InstructionSource(), cls, S.GetNextDeoptId()));
     v1 = builder.AddDefinition(
         new LoadFieldInstr(new Value(v0), slot, InstructionSource()));
     auto v2 = builder.AddDefinition(make_redefinition(&S, H.flow_graph(), v0));
@@ -435,9 +435,9 @@
     BlockBuilder builder(H.flow_graph(), b1);
     auto& slot = Slot::Get(field, &H.flow_graph()->parsed_function());
     v0 = builder.AddDefinition(
-        new AllocateObjectInstr(InstructionSource(), cls));
+        new AllocateObjectInstr(InstructionSource(), cls, S.GetNextDeoptId()));
     v5 = builder.AddDefinition(
-        new AllocateObjectInstr(InstructionSource(), cls));
+        new AllocateObjectInstr(InstructionSource(), cls, S.GetNextDeoptId()));
     if (!make_host_escape) {
       builder.AddInstruction(
           new StoreInstanceFieldInstr(slot, new Value(v5), new Value(v0),
diff --git a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
index 7527b84..ecdb481 100644
--- a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
+++ b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
@@ -896,8 +896,8 @@
 
 Fragment BaseFlowGraphBuilder::AllocateContext(
     const ZoneGrowableArray<const Slot*>& context_slots) {
-  AllocateContextInstr* allocate =
-      new (Z) AllocateContextInstr(InstructionSource(), context_slots);
+  AllocateContextInstr* allocate = new (Z) AllocateContextInstr(
+      InstructionSource(), context_slots, GetNextDeoptId());
   Push(allocate);
   return Fragment(allocate);
 }
@@ -906,8 +906,8 @@
     TokenPosition position,
     const Function& closure_function) {
   const Class& cls = Class::ZoneHandle(Z, IG->object_store()->closure_class());
-  AllocateObjectInstr* allocate =
-      new (Z) AllocateObjectInstr(InstructionSource(position), cls);
+  AllocateObjectInstr* allocate = new (Z)
+      AllocateObjectInstr(InstructionSource(position), cls, GetNextDeoptId());
   allocate->set_closure_function(closure_function);
   Push(allocate);
   return Fragment(allocate);
@@ -983,8 +983,8 @@
                                               intptr_t argument_count) {
   ASSERT((argument_count == 0) || (argument_count == 1));
   Value* type_arguments = (argument_count > 0) ? Pop() : nullptr;
-  AllocateObjectInstr* allocate = new (Z)
-      AllocateObjectInstr(InstructionSource(position), klass, type_arguments);
+  AllocateObjectInstr* allocate = new (Z) AllocateObjectInstr(
+      InstructionSource(position), klass, GetNextDeoptId(), type_arguments);
   Push(allocate);
   return Fragment(allocate);
 }
diff --git a/runtime/vm/compiler/jit/jit_call_specializer.cc b/runtime/vm/compiler/jit/jit_call_specializer.cc
index 40bf22e..58115df 100644
--- a/runtime/vm/compiler/jit/jit_call_specializer.cc
+++ b/runtime/vm/compiler/jit/jit_call_specializer.cc
@@ -224,8 +224,8 @@
   ASSERT(alloc->IsAllocateContext() || alloc->IsCloneContext());
 
   AllocateUninitializedContextInstr* replacement =
-      new AllocateUninitializedContextInstr(alloc->source(),
-                                            context_variables.length());
+      new AllocateUninitializedContextInstr(
+          alloc->source(), context_variables.length(), alloc->deopt_id());
   alloc->ReplaceWith(replacement, current_iterator());
 
   Instruction* cursor = replacement;
diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc
index 0ba5912..9cf5d12 100644
--- a/runtime/vm/profiler_service.cc
+++ b/runtime/vm/profiler_service.cc
@@ -1546,7 +1546,9 @@
   obj->AddProperty("maxStackDepth",
                    static_cast<intptr_t>(FLAG_max_profile_depth));
   obj->AddProperty("sampleCount", sample_count());
-  obj->AddProperty("timespan", MicrosecondsToSeconds(GetTimeSpan()));
+  // TODO(bkonyi): remove timeSpan after next major revision.
+  ASSERT(SERVICE_PROTOCOL_MAJOR_VERSION == 3);
+  obj->AddProperty64("timeSpan", -1);
   obj->AddPropertyTimeMicros("timeOriginMicros", min_time());
   obj->AddPropertyTimeMicros("timeExtentMicros", GetTimeSpan());
   obj->AddProperty64("pid", pid);
diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md
index 0da5169..e78af3e 100644
--- a/runtime/vm/service/service.md
+++ b/runtime/vm/service/service.md
@@ -1841,7 +1841,10 @@
   // The number of samples returned.
   int sampleCount;
 
-  // The timespan the set of returned samples covers, in microseconds.
+  // The timespan the set of returned samples covers, in microseconds (deprecated).
+  //
+  // Note: this property is deprecated and will always return -1. Use `timeExtentMicros`
+  // instead.
   int timeSpan;
 
   // The start of the period of time in which the returned samples were
diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc
index 609f66e..5e18589 100644
--- a/runtime/vm/timeline.cc
+++ b/runtime/vm/timeline.cc
@@ -230,6 +230,7 @@
   Timeline::stream_##name##_.set_enabled(false);
   TIMELINE_STREAM_LIST(TIMELINE_STREAM_DISABLE)
 #undef TIMELINE_STREAM_DISABLE
+  Timeline::Clear();
   delete recorder_;
   recorder_ = NULL;
   if (enabled_streams_ != NULL) {
@@ -1137,6 +1138,7 @@
 }
 
 TimelineEventFixedBufferRecorder::~TimelineEventFixedBufferRecorder() {
+  MutexLocker ml(&lock_);
   // Delete all blocks.
   for (intptr_t i = 0; i < num_blocks_; i++) {
     blocks_[i].Reset();
@@ -1333,16 +1335,7 @@
 TimelineEventEndlessRecorder::TimelineEventEndlessRecorder()
     : head_(nullptr), tail_(nullptr), block_index_(0) {}
 
-TimelineEventEndlessRecorder::~TimelineEventEndlessRecorder() {
-  TimelineEventBlock* current = head_;
-  head_ = tail_ = nullptr;
-
-  while (current != nullptr) {
-    TimelineEventBlock* next = current->next();
-    delete current;
-    current = next;
-  }
-}
+TimelineEventEndlessRecorder::~TimelineEventEndlessRecorder() {}
 
 #ifndef PRODUCT
 void TimelineEventEndlessRecorder::PrintJSON(JSONStream* js,
@@ -1424,6 +1417,7 @@
 #endif
 
 void TimelineEventEndlessRecorder::Clear() {
+  MutexLocker ml(&lock_);
   TimelineEventBlock* current = head_;
   while (current != NULL) {
     TimelineEventBlock* next = current->next();
@@ -1431,9 +1425,8 @@
     current = next;
   }
   head_ = NULL;
+  tail_ = NULL;
   block_index_ = 0;
-  OSThread* thread = OSThread::Current();
-  thread->set_timeline_block(NULL);
 }
 
 TimelineEventBlock::TimelineEventBlock(intptr_t block_index)
diff --git a/runtime/vm/timeline.h b/runtime/vm/timeline.h
index 38e739a..56a9445 100644
--- a/runtime/vm/timeline.h
+++ b/runtime/vm/timeline.h
@@ -23,7 +23,7 @@
 #if defined(__MAC_10_14) || defined (__IPHONE_12_0)
 #define HOST_OS_SUPPORTS_SIGNPOST 1
 #endif
-//signpost.h exists in macOS 10.14, iOS 12 or above
+// signpost.h exists in macOS 10.14, iOS 12 or above
 #if defined(HOST_OS_SUPPORTS_SIGNPOST)
 #include <os/signpost.h>
 #else
diff --git a/runtime/vm/timeline_test.cc b/runtime/vm/timeline_test.cc
index 70d162e..e77e460 100644
--- a/runtime/vm/timeline_test.cc
+++ b/runtime/vm/timeline_test.cc
@@ -90,11 +90,6 @@
     event->Complete();
   }
 
-  static void Clear(TimelineEventRecorder* recorder) {
-    ASSERT(recorder != NULL);
-    recorder->Clear();
-  }
-
   static void FinishBlock(TimelineEventBlock* block) { block->Finish(); }
 };
 
@@ -335,6 +330,7 @@
   event->Complete();
   EXPECT_EQ(1, recorder->CountFor(TimelineEvent::kAsyncEnd));
 
+  Timeline::Clear();
   delete recorder;
 }
 
@@ -458,7 +454,7 @@
     EXPECT(!it.HasNext());
   }
 
-  TimelineTestHelper::Clear(recorder);
+  Timeline::Clear();
   delete recorder;
 }
 
@@ -495,7 +491,7 @@
   const char* beta = strstr(js.ToCString(), "Beta");
   EXPECT(alpha < beta);
 
-  TimelineTestHelper::Clear(recorder);
+  Timeline::Clear();
   delete recorder;
 }
 
@@ -520,8 +516,9 @@
     EXPECT_EQ(10, pauses.MaxInclusiveTime("a"));
     EXPECT_EQ(10, pauses.MaxExclusiveTime("a"));
   }
-  TimelineTestHelper::Clear(recorder);
-
+  Timeline::Clear();
+  delete recorder;
+  recorder = new TimelineEventEndlessRecorder();
   // Test case.
   TimelineTestHelper::FakeDuration(recorder, "a", 0, 10);
   TimelineTestHelper::FakeDuration(recorder, "b", 0, 10);
@@ -539,7 +536,9 @@
     EXPECT_EQ(10, pauses.MaxInclusiveTime("b"));
     EXPECT_EQ(10, pauses.MaxExclusiveTime("b"));
   }
-  TimelineTestHelper::Clear(recorder);
+  Timeline::Clear();
+  delete recorder;
+  recorder = new TimelineEventEndlessRecorder();
 
   // Test case.
   TimelineTestHelper::FakeDuration(recorder, "a", 0, 10);
@@ -558,7 +557,9 @@
     EXPECT_EQ(7, pauses.MaxInclusiveTime("b"));
     EXPECT_EQ(7, pauses.MaxExclusiveTime("b"));
   }
-  TimelineTestHelper::Clear(recorder);
+  Timeline::Clear();
+  delete recorder;
+  recorder = new TimelineEventEndlessRecorder();
 
   // Test case.
   TimelineTestHelper::FakeDuration(recorder, "a", 0, 10);
@@ -586,7 +587,9 @@
     EXPECT_EQ(1, pauses.MaxInclusiveTime("b"));
     EXPECT_EQ(1, pauses.MaxExclusiveTime("b"));
   }
-  TimelineTestHelper::Clear(recorder);
+  Timeline::Clear();
+  delete recorder;
+  recorder = new TimelineEventEndlessRecorder();
 
   // Test case.
   TimelineTestHelper::FakeDuration(recorder, "a", 0, 10);
@@ -616,7 +619,9 @@
     EXPECT_EQ(5, pauses.MaxInclusiveTime("d"));
     EXPECT_EQ(5, pauses.MaxExclusiveTime("d"));
   }
-  TimelineTestHelper::Clear(recorder);
+  Timeline::Clear();
+  delete recorder;
+  recorder = new TimelineEventEndlessRecorder();
 
   // Test case.
   TimelineTestHelper::FakeDuration(recorder, "a", 0, 10);
@@ -651,7 +656,9 @@
     EXPECT_EQ(2, pauses.MaxInclusiveTime("e"));
     EXPECT_EQ(2, pauses.MaxExclusiveTime("e"));
   }
-  TimelineTestHelper::Clear(recorder);
+  Timeline::Clear();
+  delete recorder;
+  recorder = new TimelineEventEndlessRecorder();
 
   // Test case.
   TimelineTestHelper::FakeDuration(recorder, "a", 0, 10);
@@ -667,8 +674,7 @@
     EXPECT_EQ(10, pauses.MaxInclusiveTime("a"));
     EXPECT_EQ(8, pauses.MaxExclusiveTime("a"));
   }
-  TimelineTestHelper::Clear(recorder);
-
+  Timeline::Clear();
   delete recorder;
 }
 
@@ -695,7 +701,9 @@
     EXPECT_EQ(10, pauses.MaxInclusiveTime("a"));
     EXPECT_EQ(10, pauses.MaxExclusiveTime("a"));
   }
-  TimelineTestHelper::Clear(recorder);
+  Timeline::Clear();
+  delete recorder;
+  recorder = new TimelineEventEndlessRecorder();
 
   // Test case.
   TimelineTestHelper::FakeBegin(recorder, "a", 0);
@@ -717,7 +725,9 @@
     EXPECT_EQ(10, pauses.MaxInclusiveTime("b"));
     EXPECT_EQ(10, pauses.MaxExclusiveTime("b"));
   }
-  TimelineTestHelper::Clear(recorder);
+  Timeline::Clear();
+  delete recorder;
+  recorder = new TimelineEventEndlessRecorder();
 
   // Test case.
   TimelineTestHelper::FakeBegin(recorder, "a", 0);
@@ -739,7 +749,9 @@
     EXPECT_EQ(7, pauses.MaxInclusiveTime("b"));
     EXPECT_EQ(7, pauses.MaxExclusiveTime("b"));
   }
-  TimelineTestHelper::Clear(recorder);
+  Timeline::Clear();
+  delete recorder;
+  recorder = new TimelineEventEndlessRecorder();
 
   // Test case.
   TimelineTestHelper::FakeBegin(recorder, "a", 0);
@@ -772,7 +784,9 @@
     EXPECT_EQ(1, pauses.MaxInclusiveTime("b"));
     EXPECT_EQ(1, pauses.MaxExclusiveTime("b"));
   }
-  TimelineTestHelper::Clear(recorder);
+  Timeline::Clear();
+  delete recorder;
+  recorder = new TimelineEventEndlessRecorder();
 
   // Test case.
   TimelineTestHelper::FakeBegin(recorder, "a", 0);
@@ -806,7 +820,9 @@
     EXPECT_EQ(5, pauses.MaxInclusiveTime("d"));
     EXPECT_EQ(5, pauses.MaxExclusiveTime("d"));
   }
-  TimelineTestHelper::Clear(recorder);
+  Timeline::Clear();
+  delete recorder;
+  recorder = new TimelineEventEndlessRecorder();
 
   // Test case.
   TimelineTestHelper::FakeBegin(recorder, "a", 0);
@@ -846,7 +862,9 @@
     EXPECT_EQ(2, pauses.MaxInclusiveTime("e"));
     EXPECT_EQ(2, pauses.MaxExclusiveTime("e"));
   }
-  TimelineTestHelper::Clear(recorder);
+  Timeline::Clear();
+  delete recorder;
+  recorder = new TimelineEventEndlessRecorder();
 
   // Test case.
   TimelineTestHelper::FakeBegin(recorder, "a", 0);
@@ -864,7 +882,9 @@
     EXPECT_EQ(10, pauses.MaxInclusiveTime("a"));
     EXPECT_EQ(8, pauses.MaxExclusiveTime("a"));
   }
-  TimelineTestHelper::Clear(recorder);
+  Timeline::Clear();
+  delete recorder;
+  recorder = new TimelineEventEndlessRecorder();
 
   // Test case.
   TimelineTestHelper::FakeBegin(recorder, "a", 0);
@@ -878,8 +898,7 @@
     pauses.CalculatePauseTimesForThread(tid);
     EXPECT(pauses.has_error());
   }
-  TimelineTestHelper::Clear(recorder);
-
+  Timeline::Clear();
   delete recorder;
 }
 
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index 4469213..cab4c50 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -23,6 +23,7 @@
 Language/Libraries_and_Scripts/Scripts/top_level_syntax_t01: SkipByDesign # Non-JS-interop external members are not supported
 Language/Libraries_and_Scripts/top_level_syntax_t01: SkipByDesign # Non-JS-interop external members are not supported
 Language/Metadata/before*: Skip # dart:mirrors not supported https://github.com/dart-lang/co19/issues/523.
+Language/Metadata/syntax_t10: SkipByDesign # dart:mirrors is not supported
 Language/Reference/Operator_Precedence/precedence_15_unary_prefix_t08: SkipByDesign # binary '~' produces different results in JavaScript and Dart
 LanguageFeatures/Abstract-external-fields/static_analysis_external_A01_t01: SkipByDesign # Non-JS-interop external members are not supported
 LanguageFeatures/Abstract-external-fields/static_analysis_external_A01_t02: SkipByDesign # Non-JS-interop external members are not supported
diff --git a/tests/co19/co19-dartdevc.status b/tests/co19/co19-dartdevc.status
index 97c1673..f326b5f 100644
--- a/tests/co19/co19-dartdevc.status
+++ b/tests/co19/co19-dartdevc.status
@@ -72,6 +72,7 @@
 Language/Libraries_and_Scripts/Scripts/top_level_syntax_t01: SkipByDesign # External variables are not supported
 Language/Libraries_and_Scripts/top_level_syntax_t01: SkipByDesign # External variables are not supported
 Language/Metadata/before*: Skip # dart:mirrors not supported https://github.com/dart-lang/co19/issues/523.
+Language/Metadata/syntax_t10: SkipByDesign # dart:mirrors is not supported
 Language/Reference/Operator_Precedence/precedence_15_unary_prefix_t08: SkipByDesign # binary '~' produces different results in JavaScript and Dart
 Language/Types/Interface_Types/subtype_t27: Skip # Times out
 Language/Types/Interface_Types/subtype_t28: Skip # Times out
diff --git a/tests/co19/co19-kernel.status b/tests/co19/co19-kernel.status
index 98075c7..9860293b 100644
--- a/tests/co19/co19-kernel.status
+++ b/tests/co19/co19-kernel.status
@@ -13,6 +13,7 @@
 LanguageFeatures/Constant-update-2018/NewOperators_A01_t06/none: Crash
 
 [ $runtime == dart_precompiled ]
+Language/Metadata/syntax_t10: SkipByDesign # dart:mirrors is not supported
 LibTest/io/RawDatagramSocket/join_A01_t01: Skip # https://github.com/dart-lang/co19/issues/195
 LibTest/io/RawDatagramSocket/join_A01_t02: Skip # https://github.com/dart-lang/co19/issues/195
 LibTest/io/RawDatagramSocket/join_A02_t01: Skip # https://github.com/dart-lang/co19/issues/195
diff --git a/tools/VERSION b/tools/VERSION
index 4db5b67..0474ae3 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 13
 PATCH 0
-PRERELEASE 163
+PRERELEASE 164
 PRERELEASE_PATCH 0
\ No newline at end of file