Version 2.8.0-dev.8.0

Merge commit 'aadcb4418b1a7ccbb74a7cc925ad55020ce4a924' into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 44cdce0..4c6992a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,11 @@
 
 #### `dart:io`
 
+* The `Socket` class will now throw a `SocketException` if the socket has been
+  destroyed or upgraded to a secure socket upon setting or getting socket
+  options. Previously setting a socket options would be ignored and getting a
+  socket option would return `null`.
+
 ### Dart VM
 
 ### Tools
diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
index a762485..d69a1b5 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -934,6 +934,36 @@
         r"""Try removing the 'const' keyword. If you're trying to indicate that instances of the class can be constants, place the 'const' keyword on  the class' constructor(s).""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeConstConstructorLateFinalFieldCause =
+    messageConstConstructorLateFinalFieldCause;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageConstConstructorLateFinalFieldCause =
+    const MessageCode("ConstConstructorLateFinalFieldCause",
+        severity: Severity.context,
+        message: r"""Field is late, but constructor is 'const'.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeConstConstructorLateFinalFieldError =
+    messageConstConstructorLateFinalFieldError;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageConstConstructorLateFinalFieldError =
+    const MessageCode("ConstConstructorLateFinalFieldError",
+        message: r"""Constructor is marked 'const' so fields can't be late.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeConstConstructorLateFinalFieldWarning =
+    messageConstConstructorLateFinalFieldWarning;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageConstConstructorLateFinalFieldWarning =
+    const MessageCode("ConstConstructorLateFinalFieldWarning",
+        severity: Severity.warning,
+        message:
+            r"""Constructor is marked 'const' and some fields are late.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeConstConstructorNonFinalField =
     messageConstConstructorNonFinalField;
 
@@ -1656,6 +1686,27 @@
         message: r"""This is the inherited member.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeDefaultListConstructorError =
+    messageDefaultListConstructorError;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageDefaultListConstructorError = const MessageCode(
+    "DefaultListConstructorError",
+    message: r"""Can't use the default List constructor.""",
+    tip: r"""Try using List.filled instead.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeDefaultListConstructorWarning =
+    messageDefaultListConstructorWarning;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageDefaultListConstructorWarning = const MessageCode(
+    "DefaultListConstructorWarning",
+    severity: Severity.warning,
+    message: r"""Using the default List constructor.""",
+    tip: r"""Try using List.filled instead.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<Message Function(String name)>
     templateDefaultValueInRedirectingFactoryConstructor =
     const Template<Message Function(String name)>(
diff --git a/pkg/_fe_analyzer_shared/test/constants/data/type_literals.dart b/pkg/_fe_analyzer_shared/test/constants/data/type_literals.dart
index 90f7235..dd3162a 100644
--- a/pkg/_fe_analyzer_shared/test/constants/data/type_literals.dart
+++ b/pkg/_fe_analyzer_shared/test/constants/data/type_literals.dart
@@ -22,22 +22,22 @@
 main() {
   print(
       /*cfe|analyzer.TypeLiteral(dynamic Function())*/
-      /*dart2js.TypeLiteral(Typedef)*/
+      /*dart2js.TypeLiteral(()->dynamic)*/
       typedef);
 
   print(
       /*cfe|analyzer.TypeLiteral(void Function(dynamic))*/
-      /*dart2js.TypeLiteral(GenericTypedef<dynamic>)*/
+      /*dart2js.TypeLiteral((dynamic)->void)*/
       genericTypedef);
 
   print(
       /*cfe|analyzer.TypeLiteral(void Function<T>(T))*/
-      /*dart2js.TypeLiteral(GenericFunctionTypedef)*/
+      /*dart2js.TypeLiteral((0)->void)*/
       genericFunctionTypedef);
 
   print(
       /*cfe|analyzer.TypeLiteral(void Function<T>(FutureOr<T>))*/
-      /*dart2js.TypeLiteral(TypedefWithFutureOr)*/
+      /*dart2js.TypeLiteral((FutureOr<0>)->void)*/
       typedefWithFutureOr);
 
   print(
diff --git a/pkg/analysis_server/.gitignore b/pkg/analysis_server/.gitignore
new file mode 100644
index 0000000..ad1fe33
--- /dev/null
+++ b/pkg/analysis_server/.gitignore
@@ -0,0 +1,3 @@
+lib/src/edit/nnbd_migration/resources/*.js.deps
+lib/src/edit/nnbd_migration/resources/*.js.map
+lib/src/edit/nnbd_migration/resources/migration.js
diff --git a/pkg/analysis_server/lib/src/edit/fix/non_nullable_fix.dart b/pkg/analysis_server/lib/src/edit/fix/non_nullable_fix.dart
index 23f5f5d..6067254 100644
--- a/pkg/analysis_server/lib/src/edit/fix/non_nullable_fix.dart
+++ b/pkg/analysis_server/lib/src/edit/fix/non_nullable_fix.dart
@@ -233,7 +233,7 @@
     // practice, this should be cheap because typically only one path is given
     // to dartfix.
     List<String> rootParts = included
-        .map((p) => context.absolute(context.canonicalize(p)))
+        .map((p) => context.normalize(context.absolute(p)))
         .map((p) => provider.getResource(p) is File ? context.dirname(p) : p)
         .map((p) => context.split(p))
         .reduce((value, parts) {
diff --git a/pkg/analysis_server/lib/src/edit/nnbd_migration/README.md b/pkg/analysis_server/lib/src/edit/nnbd_migration/README.md
new file mode 100644
index 0000000..0b96245
--- /dev/null
+++ b/pkg/analysis_server/lib/src/edit/nnbd_migration/README.md
@@ -0,0 +1,54 @@
+# Null Safety Migration Tooling
+
+Note: the null safety migration tooling and workflow is in a very early state;
+this doc will be updated as the steps and workflow are simplified. 
+
+## Background
+
+TODO:
+
+## Building the nnbd sdk
+
+In order to run the tool currently you have to be able to build your own copy
+of the Dart SDK.
+
+To do this, run:
+
+```
+./tools/build.py -mrelease --nnbd create_sdk
+```
+
+The NNBD sdk now lives under the ReleaseX64NNBD sub-directory of your build
+directory, e.g.
+
+```
+xcodebuild/ReleaseX64NNBD/dart-sdk/
+```
+
+## Migrating a package
+
+- build a NNBD version of the SDK (see above)
+- select a package to work on
+- in that package, edit the `analysis_options.yaml` to enable the NNBD
+  experiment from the POV of the analyzer:
+```yaml
+analyzer:
+  enable-experiment:
+    - non-nullable
+```
+- run `pub get` for the package (and, verify that the
+  `.dart_tool/package_config.json` file was created) 
+
+Then, run the migration tool from the top-level of the package directory:
+
+```
+<sdk-repo>/xcodebuild/ReleaseX64/dart <sdk-repo>/pkg/dartfix/bin/dartfix.dart  upgrade sdk --sdk=<sdk-repo>/xcodebuild/ReleaseX64NNBD/dart-sdk/ .
+```
+
+The migration tool will run, print the proposed changes to the console,
+and display a url for the preview tool. Open that url from a browser to
+see a rich preview of the proposed null safety changes.
+
+## Using the tool
+
+TODO:
diff --git a/pkg/analysis_server/lib/src/edit/nnbd_migration/resources/.clang-format b/pkg/analysis_server/lib/src/edit/nnbd_migration/resources/.clang-format
new file mode 100644
index 0000000..ace8841
--- /dev/null
+++ b/pkg/analysis_server/lib/src/edit/nnbd_migration/resources/.clang-format
@@ -0,0 +1,3 @@
+# Don't format the JavaScript files in this directory.
+Language: JavaScript
+DisableFormat: true
diff --git a/pkg/analysis_server/lib/src/edit/nnbd_migration/resources/migration.js b/pkg/analysis_server/lib/src/edit/nnbd_migration/resources/migration.js
deleted file mode 100644
index a2c3c85..0000000
--- a/pkg/analysis_server/lib/src/edit/nnbd_migration/resources/migration.js
+++ /dev/null
@@ -1,526 +0,0 @@
-// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-function getOffset(location) {
-  const root = document.querySelector(".root").textContent;
-  return new URL(location, "file://" + root + "/dummy.txt")
-      .searchParams.get("offset");
-}
-
-function getLine(location) {
-  const root = document.querySelector(".root").textContent;
-  return new URL(location, "file://" + root + "/dummy.txt")
-      .searchParams.get("line");
-}
-
-// Remove highlighting from [offset].
-function removeHighlight(offset, lineNumber) {
-  if (offset != null) {
-    const anchor = document.getElementById("o" + offset);
-    if (anchor != null) {
-      anchor.classList.remove("target");
-    }
-  }
-  if (lineNumber != null) {
-    const line = document.querySelector(".line-" + lineNumber);
-    if (line != null) {
-      line.parentNode.classList.remove("highlight");
-    }
-  }
-}
-
-// Return the absolute path of [path], assuming [path] is relative to [root].
-function absolutePath(path) {
-  if (path[0] != "/") {
-      const root = document.querySelector(".root").textContent;
-      return new URL(path, window.location.href).pathname;
-  } else {
-    return path;
-  }
-}
-
-// If [path] lies within [root], return the relative path of [path] from [root].
-// Otherwise, return [path].
-function relativePath(path) {
-  const root = document.querySelector(".root").textContent + "/";
-  if (path.startsWith(root)) {
-    return path.substring(root.length);
-  } else {
-    return path;
-  }
-}
-
-// Write the contents of the Edit List, from JSON data [editListData].
-function writeEditList(editListData) {
-  const editList = document.querySelector(".edit-list .panel-content");
-  editList.innerHTML = "";
-  const p = editList.appendChild(document.createElement("p"));
-  const countElement = p.appendChild(document.createElement("strong"));
-  const editCount = editListData["editCount"];
-  countElement.appendChild(document.createTextNode(editCount));
-  if (editCount == 1) {
-    p.appendChild(document.createTextNode(
-        " edit was made to this file. Click the edit's checkbox to toggle " +
-        "its reviewed state."));
-  } else {
-    p.appendChild(document.createTextNode(
-        " edits were made to this file. Click an edit's checkbox to toggle " +
-        "its reviewed state."));
-  }
-  for (const edit of editListData["edits"]) {
-    const editP = editList.appendChild(document.createElement("p"));
-    editP.classList.add("edit");
-    const checkbox = editP.appendChild(document.createElement("input"));
-    checkbox.setAttribute("type", "checkbox");
-    checkbox.setAttribute("title", "Click to mark reviewed");
-    checkbox.setAttribute("disabled", "disabled");
-    editP.appendChild(document.createTextNode(
-        `line ${edit["line"]}: ${edit["explanation"]}. `));
-    const a = editP.appendChild(document.createElement("a"));
-    a.classList.add("edit-link");
-    const offset = edit["offset"];
-    a.dataset.offset = offset;
-    const line = edit["line"];
-    a.dataset.line = line;
-    a.appendChild(document.createTextNode("[view]"));
-    a.onclick = (event) => {
-      navigate(window.location.pathname, offset, line,
-          () => { pushState(window.location.pathname, offset, line) });
-      loadRegionExplanation(a);
-    };
-  }
-}
-
-// Load data from [data] into the .code and the .regions divs.
-function writeCodeAndRegions(data) {
-  const regions = document.querySelector(".regions");
-  const code = document.querySelector(".code");
-  regions.innerHTML = data["regions"];
-  code.innerHTML = data["navContent"];
-  writeEditList(data["editList"]);
-  highlightAllCode();
-  addClickHandlers(".code");
-  addClickHandlers(".regions");
-}
-
-// Navigate to [path] and optionally scroll [offset] into view.
-//
-// If [callback] is present, it will be called after the server response has
-// been processed, and the content has been updated on the page.
-function navigate(path, offset, lineNumber, callback) {
-  const currentOffset = getOffset(window.location.href);
-  const currentLineNumber = getLine(window.location.href);
-  removeHighlight(currentOffset, currentLineNumber);
-  if (path == window.location.pathname) {
-    // Navigating to same file; just scroll into view.
-    maybeScrollToAndHighlight(offset, lineNumber);
-    if (callback !== undefined) {
-      callback();
-    }
-  } else {
-    loadFile(path, offset, lineNumber, callback);
-  }
-}
-
-function maybeScrollIntoView(element) {
-  const rect = element.getBoundingClientRect();
-  // TODO(srawlins): Only scroll smoothly when on the same page.
-  if (rect.bottom > window.innerHeight) {
-    element.scrollIntoView({behavior: "smooth", block: "end"});
-  }
-  if (rect.top < 0) {
-    element.scrollIntoView({behavior: "smooth"});
-  }
-}
-
-// Scroll target with id [offset] into view if it is not currently in view.
-//
-// If [offset] is null, instead scroll the "unit-name" header, at the top of the
-// page, into view.
-//
-// Also add the "target" class, highlighting the target. Also add the
-// "highlight" class to the entire line on which the target lies.
-function maybeScrollToAndHighlight(offset, lineNumber) {
-  var target;
-  var line;
-  if (offset !== null) {
-    target = document.getElementById("o" + offset);
-    line = document.querySelector(".line-" + lineNumber);
-    if (target !== null) {
-      maybeScrollIntoView(target);
-      target.classList.add("target");
-    } else if (line != null) {
-      // If the target doesn't exist, but the line does, scroll that into view
-      // instead.
-      maybeScrollIntoView(line);
-    }
-    if (line != null) {
-      line.parentNode.classList.add("highlight");
-    }
-  } else {
-    // If no offset is given, this is likely a navigation link, and we need to
-    // scroll back to the top of the page.
-    target = document.getElementById("unit-name");
-    maybeScrollIntoView(target);
-  }
-}
-
-// Load the file at [path] from the server, optionally scrolling [offset] into
-// view.
-function loadFile(path, offset, lineNumber, callback) {
-  // Navigating to another file; request it, then do work with the response.
-  const xhr = new XMLHttpRequest();
-  xhr.open("GET", path + "?inline=true");
-  xhr.setRequestHeader("Content-Type", "application/json");
-  xhr.onload = function() {
-    if (xhr.status === 200) {
-      const response = JSON.parse(xhr.responseText);
-      writeCodeAndRegions(response);
-      maybeScrollToAndHighlight(offset, lineNumber);
-      updatePage(path, offset);
-      if (callback !== undefined) {
-        callback();
-      }
-    } else {
-      alert("Request failed; status of " + xhr.status);
-    }
-  };
-  xhr.onerror = function(e) {
-    alert(`Could not load ${path}; preview server might be disconnected.`);
-  };
-  xhr.send();
-}
-
-function pushState(path, offset, lineNumber) {
-  let newLocation = window.location.origin + path + "?";
-  if (offset !== null) {
-    newLocation = newLocation + "offset=" + offset + "&";
-  }
-  if (lineNumber !== null) {
-    newLocation = newLocation + "line=" + lineNumber;
-  }
-  history.pushState({}, "", newLocation);
-}
-
-// Update the heading and navigation links.
-//
-// Call this after updating page content on a navigation.
-function updatePage(path, offset) {
-  path = relativePath(path);
-  // Update page heading.
-  const unitName = document.querySelector("#unit-name");
-  unitName.textContent = path;
-  // Update navigation styles.
-  document.querySelectorAll(".nav-panel .nav-link").forEach((link) => {
-    const name = link.dataset.name;
-    if (name == path) {
-      link.classList.add("selected-file");
-    } else {
-      link.classList.remove("selected-file");
-    }
-  });
-}
-
-function highlightAllCode(_) {
-  document.querySelectorAll(".code").forEach((block) => {
-    hljs.highlightBlock(block);
-  });
-}
-
-function addArrowClickHandler(arrow) {
-  const childList = arrow.parentNode.querySelector(":scope > ul");
-  // Animating height from "auto" to "0" is not supported by CSS [1], so all we
-  // have are hacks. The `* 2` allows for events in which the list grows in
-  // height when resized, with additional text wrapping.
-  // [1] https://css-tricks.com/using-css-transitions-auto-dimensions/
-  childList.style.maxHeight = childList.offsetHeight * 2 + "px";
-  arrow.onclick = (event) => {
-    if (!childList.classList.contains("collapsed")) {
-      childList.classList.add("collapsed");
-      arrow.classList.add("collapsed");
-    } else {
-      childList.classList.remove("collapsed");
-      arrow.classList.remove("collapsed");
-    }
-  };
-}
-
-function handleNavLinkClick(event) {
-  const path = absolutePath(event.currentTarget.getAttribute("href"));
-  const offset = getOffset(event.currentTarget.getAttribute("href"));
-  const lineNumber = getLine(event.currentTarget.getAttribute("href"));
-  if (offset !== null) {
-    navigate(path, offset, lineNumber,
-        () => { pushState(path, offset, lineNumber) });
-  } else {
-    navigate(path, null, null, () => { pushState(path, null, null) });
-  }
-  event.preventDefault();
-}
-
-function handlePostLinkClick(event) {
-  // Directing the server to produce an edit; request it, then do work with
-  // the response.
-  const path = absolutePath(event.currentTarget.getAttribute("href"));
-  const xhr = new XMLHttpRequest();
-  xhr.open("POST", path);
-  xhr.setRequestHeader("Content-Type", "application/json");
-  xhr.onload = function() {
-    if (xhr.status === 200) {
-      // Likely request new navigation and file content.
-    } else {
-      alert("Request failed; status of " + xhr.status);
-    }
-  };
-  xhr.onerror = function(e) {
-    alert(`Could not load ${path}; preview server might be disconnected.`);
-  };
-  xhr.send();
-}
-
-function addClickHandlers(parentSelector) {
-  const parentElement = document.querySelector(parentSelector);
-
-  const navLinks = parentElement.querySelectorAll(".nav-link");
-  navLinks.forEach((link) => {
-    link.onclick = handleNavLinkClick;
-  });
-
-  const regions = parentElement.querySelectorAll(".region");
-  regions.forEach((region) => {
-    region.onclick = (event) => {
-      loadRegionExplanation(region);
-    };
-  });
-
-  const postLinks = parentElement.querySelectorAll(".post-link");
-  postLinks.forEach((link) => {
-    link.onclick = handlePostLinkClick;
-  });
-}
-
-function writeNavigationSubtree(parentElement, tree) {
-  const ul = parentElement.appendChild(document.createElement('ul'));
-  for (const entity of tree) {
-    const li = ul.appendChild(document.createElement('li'));
-    if (entity["type"] == "directory") {
-      li.classList.add("dir");
-      const arrow = li.appendChild(document.createElement('span'));
-      arrow.classList.add("arrow");
-      arrow.innerHTML = "&#x25BC;";
-      const icon = li.appendChild(document.createElement('span'));
-      icon.innerHTML = "&#x1F4C1;";
-      li.appendChild(document.createTextNode(entity["name"]));
-      writeNavigationSubtree(li, entity["subtree"]);
-      addArrowClickHandler(arrow);
-    } else {
-      li.innerHTML = "&#x1F4C4;";
-      const a = li.appendChild(document.createElement("a"));
-      a.classList.add("nav-link");
-      a.dataset.name = entity["path"];
-      a.setAttribute("href", entity["href"]);
-      a.appendChild(document.createTextNode(entity["name"]));
-      a.onclick = handleNavLinkClick;
-      const editCount = entity["editCount"];
-      if (editCount > 0) {
-        const editsBadge = li.appendChild(document.createElement("span"));
-        editsBadge.classList.add("edit-count");
-        const edits = editCount == 1 ? 'edit' : 'edits';
-        editsBadge.setAttribute("title", `${editCount} ${edits}`);
-        editsBadge.appendChild(document.createTextNode(editCount));
-      }
-    }
-  }
-}
-
-// Load the navigation tree into the ".nav-tree" div.
-function loadNavigationTree(region) {
-  // Request the navigation tree, then do work with the response.
-  const xhr = new XMLHttpRequest();
-  const path = "/_preview/navigationTree.json";
-  xhr.open("GET", path);
-  xhr.setRequestHeader("Content-Type", "application/json");
-  xhr.onload = function() {
-    if (xhr.status === 200) {
-      const response = JSON.parse(xhr.responseText);
-      const navTree = document.querySelector(".nav-tree");
-      navTree.innerHTML = "";
-      writeNavigationSubtree(navTree, response);
-    } else {
-      alert(`Request failed; status of ${xhr.status}`);
-    }
-  };
-  xhr.onerror = function(e) {
-    alert(`Could not load ${path}; preview server might be disconnected.`);
-  };
-  xhr.send();
-}
-
-function writeRegionExplanation(response) {
-  const editPanel = document.querySelector(".edit-panel .panel-content");
-  editPanel.innerHTML = "";
-  const regionLocation = document.createElement("p");
-  regionLocation.classList.add("region-location");
-  // Insert a zero-width space after each "/", to allow lines to wrap after each
-  // directory name.
-  const path = response["path"].replace(/\//g, "/\u200B");
-  regionLocation.appendChild(document.createTextNode(`${path} `));
-  const regionLine = regionLocation.appendChild(document.createElement("span"));
-  regionLine.appendChild(document.createTextNode(`line ${response["line"]}`));
-  regionLine.classList.add("nowrap");
-  editPanel.appendChild(regionLocation);
-  const explanation = editPanel.appendChild(document.createElement("p"));
-  explanation.appendChild(document.createTextNode(response["explanation"]));
-  const detailCount = response["details"].length;
-  if (detailCount == 0) {
-    // Having 0 details is not necessarily an expected possibility, but handling
-    // the possibility prevents awkward text, "for 0 reasons:".
-    explanation.appendChild(document.createTextNode("."));
-  } else {
-    explanation.appendChild(document.createTextNode(
-        detailCount == 1
-            ? ` for ${detailCount} reason:` : ` for ${detailCount} reasons:`));
-    const detailList = editPanel.appendChild(document.createElement("ol"));
-    for (const detail of response["details"]) {
-      const detailItem = detailList.appendChild(document.createElement("li"));
-      detailItem.appendChild(document.createTextNode(detail["description"]));
-      if (detail["link"] !== undefined) {
-        detailItem.appendChild(document.createTextNode(" ("));
-        const a = detailItem.appendChild(document.createElement("a"));
-        a.appendChild(document.createTextNode(detail["link"]["text"]));
-        a.setAttribute("href", detail["link"]["href"]);
-        a.classList.add("nav-link");
-        detailItem.appendChild(document.createTextNode(")"));
-      }
-    }
-  }
-  if (response["edits"] !== undefined) {
-    for (const edit of response["edits"]) {
-      const editParagraph = editPanel.appendChild(document.createElement("p"));
-      const a = editParagraph.appendChild(document.createElement("a"));
-      a.appendChild(document.createTextNode(edit["text"]));
-      a.setAttribute("href", edit["href"]);
-      a.classList.add("post-link");
-    }
-  }
-}
-
-// Load the explanation for [region], into the ".panel-content" div.
-function loadRegionExplanation(region) {
-  // Request the region, then do work with the response.
-  const xhr = new XMLHttpRequest();
-  const path = window.location.pathname;
-  const offset = region.dataset.offset;
-  xhr.open("GET", path + `?region=region&offset=${offset}`);
-  xhr.setRequestHeader("Content-Type", "application/json");
-  xhr.onload = function() {
-    if (xhr.status === 200) {
-      const response = JSON.parse(xhr.responseText);
-      writeRegionExplanation(response);
-      addClickHandlers(".edit-panel .panel-content");
-    } else {
-      alert(`Request failed; status of ${xhr.status}`);
-    }
-  };
-  xhr.onerror = function(e) {
-    alert(`Could not load ${path}; preview server might be disconnected.`);
-  };
-  xhr.send();
-}
-
-function debounce(fn, delay) {
-  var timeout;
-  return function() {
-    var later = function() {
-      timeout = null;
-    };
-    var callNow = !timeout;
-    clearTimeout(timeout);
-    timeout = setTimeout(later, delay);
-    if (callNow) fn.apply(this);
-	};
-};
-
-// Resize the fixed-size and fixed-position navigation and information panels.
-function resizePanels() {
-  const navInner = document.querySelector(".nav-inner");
-  const height = window.innerHeight;
-  navInner.style.height = height + "px";
-
-  const infoPanelHeight = height / 2 - 6;
-  const editPanel = document.querySelector(".edit-panel");
-  editPanel.style.height = infoPanelHeight + "px";
-
-  const editListHeight = height / 2 - 6;
-  const editList = document.querySelector(".edit-list");
-  editList.style.height = editListHeight + "px";
-}
-
-document.addEventListener("DOMContentLoaded", (event) => {
-  const path = window.location.pathname;
-  const offset = getOffset(window.location.href);
-  const lineNumber = getLine(window.location.href);
-  const root = document.querySelector(".root").textContent;
-  loadNavigationTree();
-  if (path !== "/" && path !== root) {
-    // TODO(srawlins): replaceState?
-    loadFile(path, offset, lineNumber,
-        () => { pushState(path, offset, lineNumber) });
-  }
-  resizePanels();
-});
-
-window.addEventListener("popstate", (event) => {
-  const path = window.location.pathname;
-  const offset = getOffset(window.location.href);
-  const lineNumber = getLine(window.location.href);
-  if (path.length > 1) {
-    loadFile(path, offset, lineNumber);
-  } else {
-    // Blank out the page, for the index screen.
-    writeCodeAndRegions({"regions": "", "navContent": ""});
-    updatePage("&nbsp;", null);
-  }
-});
-
-window.addEventListener("resize", (event) => {
-  debounce(resizePanels, 200)();
-});
-
-// When scrolling the page, determine whether the navigation and information
-// panels need to be fixed in place, or allowed to scroll.
-window.addEventListener("scroll", (event) => {
-  const navPanel = document.querySelector(".nav-panel");
-  const navInner = navPanel.querySelector(".nav-inner");
-  const infoPanel = document.querySelector(".info-panel");
-  const panelContainer = document.querySelector(".panel-container");
-  const innerTopOffset = navPanel.offsetTop;
-  if (window.pageYOffset > innerTopOffset) {
-    if (!navInner.classList.contains("fixed")) {
-      const navPanelWidth = navPanel.offsetWidth - 14;
-      navPanel.style.width = navPanelWidth + "px";
-      // Subtract 7px for nav-inner's padding.
-      navInner.style.width = navPanelWidth + 7 + "px";
-      navInner.classList.add("fixed");
-    }
-    if (!panelContainer.classList.contains("fixed")) {
-      const infoPanelWidth = infoPanel.offsetWidth;
-      infoPanel.style.width = infoPanelWidth + "px";
-      panelContainer.style.width = infoPanelWidth + "px";
-      panelContainer.classList.add("fixed");
-    }
-  } else {
-    if (navInner.classList.contains("fixed")) {
-      navPanel.style.width = "";
-      navInner.style.width = "";
-      navInner.classList.remove("fixed");
-    }
-    if (panelContainer.classList.contains("fixed")) {
-      infoPanel.style.width = "";
-      panelContainer.style.width = "";
-      panelContainer.classList.remove("fixed");
-    }
-  }
-  debounce(resizePanels, 200)();
-});
diff --git a/pkg/analysis_server/lib/src/edit/nnbd_migration/resources/resources.g.dart b/pkg/analysis_server/lib/src/edit/nnbd_migration/resources/resources.g.dart
index 86112bf..ea345f8 100644
--- a/pkg/analysis_server/lib/src/edit/nnbd_migration/resources/resources.g.dart
+++ b/pkg/analysis_server/lib/src/edit/nnbd_migration/resources/resources.g.dart
@@ -31,6 +31,7 @@
 }
 
 String _highlight_css;
+// highlight_css md5 is 'fb012626bafd286510d32da815dae448'
 String _highlight_css_base64 = '''
 LyoKRGF0ZTogMjQgRmV2IDIwMTUKQXV0aG9yOiBQZWRybyBPbGl2ZWlyYSA8a2FueXR1QGdtYWlsIC4g
 Y29tPgoqLwoKLmhsanMgewogIGNvbG9yOiAjYTliN2M2OwogIGJhY2tncm91bmQ6ICMyODJiMmU7CiAg
@@ -48,6 +49,7 @@
 ''';
 
 String _highlight_pack_js;
+// highlight_pack_js md5 is '9104bfe8b056f8e00da50b0ea3d6e6d4'
 String _highlight_pack_js_base64 = '''
 LyohIGhpZ2hsaWdodC5qcyB2OS4xNS4xMCB8IEJTRDMgTGljZW5zZSB8IGdpdC5pby9obGpzbGljZW5z
 ZSAqLwohZnVuY3Rpb24oZSl7dmFyIG49Im9iamVjdCI9PXR5cGVvZiB3aW5kb3cmJndpbmRvd3x8Im9i
@@ -264,327 +266,3007 @@
 ''';
 
 String _migration_js;
+// migration_dart md5 is '61fc6d8b736b7e11eb4f1945dfc64194'
 String _migration_js_base64 = '''
-Ly8gQ29weXJpZ2h0IChjKSAyMDE5LCB0aGUgRGFydCBwcm9qZWN0IGF1dGhvcnMuIFBsZWFzZSBzZWUg
-dGhlIEFVVEhPUlMgZmlsZQovLyBmb3IgZGV0YWlscy4gQWxsIHJpZ2h0cyByZXNlcnZlZC4gVXNlIG9m
-IHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYQovLyBCU0Qtc3R5bGUgbGljZW5zZSB0aGF0
-IGNhbiBiZSBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlLgoKZnVuY3Rpb24gZ2V0T2Zmc2V0KGxvY2F0
-aW9uKSB7CiAgY29uc3Qgcm9vdCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoIi5yb290IikudGV4dENv
-bnRlbnQ7CiAgcmV0dXJuIG5ldyBVUkwobG9jYXRpb24sICJmaWxlOi8vIiArIHJvb3QgKyAiL2R1bW15
-LnR4dCIpCiAgICAgIC5zZWFyY2hQYXJhbXMuZ2V0KCJvZmZzZXQiKTsKfQoKZnVuY3Rpb24gZ2V0TGlu
-ZShsb2NhdGlvbikgewogIGNvbnN0IHJvb3QgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCIucm9vdCIp
-LnRleHRDb250ZW50OwogIHJldHVybiBuZXcgVVJMKGxvY2F0aW9uLCAiZmlsZTovLyIgKyByb290ICsg
-Ii9kdW1teS50eHQiKQogICAgICAuc2VhcmNoUGFyYW1zLmdldCgibGluZSIpOwp9CgovLyBSZW1vdmUg
-aGlnaGxpZ2h0aW5nIGZyb20gW29mZnNldF0uCmZ1bmN0aW9uIHJlbW92ZUhpZ2hsaWdodChvZmZzZXQs
-IGxpbmVOdW1iZXIpIHsKICBpZiAob2Zmc2V0ICE9IG51bGwpIHsKICAgIGNvbnN0IGFuY2hvciA9IGRv
-Y3VtZW50LmdldEVsZW1lbnRCeUlkKCJvIiArIG9mZnNldCk7CiAgICBpZiAoYW5jaG9yICE9IG51bGwp
-IHsKICAgICAgYW5jaG9yLmNsYXNzTGlzdC5yZW1vdmUoInRhcmdldCIpOwogICAgfQogIH0KICBpZiAo
-bGluZU51bWJlciAhPSBudWxsKSB7CiAgICBjb25zdCBsaW5lID0gZG9jdW1lbnQucXVlcnlTZWxlY3Rv
-cigiLmxpbmUtIiArIGxpbmVOdW1iZXIpOwogICAgaWYgKGxpbmUgIT0gbnVsbCkgewogICAgICBsaW5l
-LnBhcmVudE5vZGUuY2xhc3NMaXN0LnJlbW92ZSgiaGlnaGxpZ2h0Iik7CiAgICB9CiAgfQp9CgovLyBS
-ZXR1cm4gdGhlIGFic29sdXRlIHBhdGggb2YgW3BhdGhdLCBhc3N1bWluZyBbcGF0aF0gaXMgcmVsYXRp
-dmUgdG8gW3Jvb3RdLgpmdW5jdGlvbiBhYnNvbHV0ZVBhdGgocGF0aCkgewogIGlmIChwYXRoWzBdICE9
-ICIvIikgewogICAgICBjb25zdCByb290ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcigiLnJvb3QiKS50
-ZXh0Q29udGVudDsKICAgICAgcmV0dXJuIG5ldyBVUkwocGF0aCwgd2luZG93LmxvY2F0aW9uLmhyZWYp
-LnBhdGhuYW1lOwogIH0gZWxzZSB7CiAgICByZXR1cm4gcGF0aDsKICB9Cn0KCi8vIElmIFtwYXRoXSBs
-aWVzIHdpdGhpbiBbcm9vdF0sIHJldHVybiB0aGUgcmVsYXRpdmUgcGF0aCBvZiBbcGF0aF0gZnJvbSBb
-cm9vdF0uCi8vIE90aGVyd2lzZSwgcmV0dXJuIFtwYXRoXS4KZnVuY3Rpb24gcmVsYXRpdmVQYXRoKHBh
-dGgpIHsKICBjb25zdCByb290ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcigiLnJvb3QiKS50ZXh0Q29u
-dGVudCArICIvIjsKICBpZiAocGF0aC5zdGFydHNXaXRoKHJvb3QpKSB7CiAgICByZXR1cm4gcGF0aC5z
-dWJzdHJpbmcocm9vdC5sZW5ndGgpOwogIH0gZWxzZSB7CiAgICByZXR1cm4gcGF0aDsKICB9Cn0KCi8v
-IFdyaXRlIHRoZSBjb250ZW50cyBvZiB0aGUgRWRpdCBMaXN0LCBmcm9tIEpTT04gZGF0YSBbZWRpdExp
-c3REYXRhXS4KZnVuY3Rpb24gd3JpdGVFZGl0TGlzdChlZGl0TGlzdERhdGEpIHsKICBjb25zdCBlZGl0
-TGlzdCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoIi5lZGl0LWxpc3QgLnBhbmVsLWNvbnRlbnQiKTsK
-ICBlZGl0TGlzdC5pbm5lckhUTUwgPSAiIjsKICBjb25zdCBwID0gZWRpdExpc3QuYXBwZW5kQ2hpbGQo
-ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgicCIpKTsKICBjb25zdCBjb3VudEVsZW1lbnQgPSBwLmFwcGVu
-ZENoaWxkKGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoInN0cm9uZyIpKTsKICBjb25zdCBlZGl0Q291bnQg
-PSBlZGl0TGlzdERhdGFbImVkaXRDb3VudCJdOwogIGNvdW50RWxlbWVudC5hcHBlbmRDaGlsZChkb2N1
-bWVudC5jcmVhdGVUZXh0Tm9kZShlZGl0Q291bnQpKTsKICBpZiAoZWRpdENvdW50ID09IDEpIHsKICAg
-IHAuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoCiAgICAgICAgIiBlZGl0IHdhcyBt
-YWRlIHRvIHRoaXMgZmlsZS4gQ2xpY2sgdGhlIGVkaXQncyBjaGVja2JveCB0byB0b2dnbGUgIiArCiAg
-ICAgICAgIml0cyByZXZpZXdlZCBzdGF0ZS4iKSk7CiAgfSBlbHNlIHsKICAgIHAuYXBwZW5kQ2hpbGQo
-ZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoCiAgICAgICAgIiBlZGl0cyB3ZXJlIG1hZGUgdG8gdGhpcyBm
-aWxlLiBDbGljayBhbiBlZGl0J3MgY2hlY2tib3ggdG8gdG9nZ2xlICIgKwogICAgICAgICJpdHMgcmV2
-aWV3ZWQgc3RhdGUuIikpOwogIH0KICBmb3IgKGNvbnN0IGVkaXQgb2YgZWRpdExpc3REYXRhWyJlZGl0
-cyJdKSB7CiAgICBjb25zdCBlZGl0UCA9IGVkaXRMaXN0LmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0
-ZUVsZW1lbnQoInAiKSk7CiAgICBlZGl0UC5jbGFzc0xpc3QuYWRkKCJlZGl0Iik7CiAgICBjb25zdCBj
-aGVja2JveCA9IGVkaXRQLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImlucHV0Iikp
-OwogICAgY2hlY2tib3guc2V0QXR0cmlidXRlKCJ0eXBlIiwgImNoZWNrYm94Iik7CiAgICBjaGVja2Jv
-eC5zZXRBdHRyaWJ1dGUoInRpdGxlIiwgIkNsaWNrIHRvIG1hcmsgcmV2aWV3ZWQiKTsKICAgIGNoZWNr
-Ym94LnNldEF0dHJpYnV0ZSgiZGlzYWJsZWQiLCAiZGlzYWJsZWQiKTsKICAgIGVkaXRQLmFwcGVuZENo
-aWxkKGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKAogICAgICAgIGBsaW5lICR7ZWRpdFsibGluZSJdfTog
-JHtlZGl0WyJleHBsYW5hdGlvbiJdfS4gYCkpOwogICAgY29uc3QgYSA9IGVkaXRQLmFwcGVuZENoaWxk
-KGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImEiKSk7CiAgICBhLmNsYXNzTGlzdC5hZGQoImVkaXQtbGlu
-ayIpOwogICAgY29uc3Qgb2Zmc2V0ID0gZWRpdFsib2Zmc2V0Il07CiAgICBhLmRhdGFzZXQub2Zmc2V0
-ID0gb2Zmc2V0OwogICAgY29uc3QgbGluZSA9IGVkaXRbImxpbmUiXTsKICAgIGEuZGF0YXNldC5saW5l
-ID0gbGluZTsKICAgIGEuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoIlt2aWV3XSIp
-KTsKICAgIGEub25jbGljayA9IChldmVudCkgPT4gewogICAgICBuYXZpZ2F0ZSh3aW5kb3cubG9jYXRp
-b24ucGF0aG5hbWUsIG9mZnNldCwgbGluZSwKICAgICAgICAgICgpID0+IHsgcHVzaFN0YXRlKHdpbmRv
-dy5sb2NhdGlvbi5wYXRobmFtZSwgb2Zmc2V0LCBsaW5lKSB9KTsKICAgICAgbG9hZFJlZ2lvbkV4cGxh
-bmF0aW9uKGEpOwogICAgfTsKICB9Cn0KCi8vIExvYWQgZGF0YSBmcm9tIFtkYXRhXSBpbnRvIHRoZSAu
-Y29kZSBhbmQgdGhlIC5yZWdpb25zIGRpdnMuCmZ1bmN0aW9uIHdyaXRlQ29kZUFuZFJlZ2lvbnMoZGF0
-YSkgewogIGNvbnN0IHJlZ2lvbnMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCIucmVnaW9ucyIpOwog
-IGNvbnN0IGNvZGUgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCIuY29kZSIpOwogIHJlZ2lvbnMuaW5u
-ZXJIVE1MID0gZGF0YVsicmVnaW9ucyJdOwogIGNvZGUuaW5uZXJIVE1MID0gZGF0YVsibmF2Q29udGVu
-dCJdOwogIHdyaXRlRWRpdExpc3QoZGF0YVsiZWRpdExpc3QiXSk7CiAgaGlnaGxpZ2h0QWxsQ29kZSgp
-OwogIGFkZENsaWNrSGFuZGxlcnMoIi5jb2RlIik7CiAgYWRkQ2xpY2tIYW5kbGVycygiLnJlZ2lvbnMi
-KTsKfQoKLy8gTmF2aWdhdGUgdG8gW3BhdGhdIGFuZCBvcHRpb25hbGx5IHNjcm9sbCBbb2Zmc2V0XSBp
-bnRvIHZpZXcuCi8vCi8vIElmIFtjYWxsYmFja10gaXMgcHJlc2VudCwgaXQgd2lsbCBiZSBjYWxsZWQg
-YWZ0ZXIgdGhlIHNlcnZlciByZXNwb25zZSBoYXMKLy8gYmVlbiBwcm9jZXNzZWQsIGFuZCB0aGUgY29u
-dGVudCBoYXMgYmVlbiB1cGRhdGVkIG9uIHRoZSBwYWdlLgpmdW5jdGlvbiBuYXZpZ2F0ZShwYXRoLCBv
-ZmZzZXQsIGxpbmVOdW1iZXIsIGNhbGxiYWNrKSB7CiAgY29uc3QgY3VycmVudE9mZnNldCA9IGdldE9m
-ZnNldCh3aW5kb3cubG9jYXRpb24uaHJlZik7CiAgY29uc3QgY3VycmVudExpbmVOdW1iZXIgPSBnZXRM
-aW5lKHdpbmRvdy5sb2NhdGlvbi5ocmVmKTsKICByZW1vdmVIaWdobGlnaHQoY3VycmVudE9mZnNldCwg
-Y3VycmVudExpbmVOdW1iZXIpOwogIGlmIChwYXRoID09IHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZSkg
-ewogICAgLy8gTmF2aWdhdGluZyB0byBzYW1lIGZpbGU7IGp1c3Qgc2Nyb2xsIGludG8gdmlldy4KICAg
-IG1heWJlU2Nyb2xsVG9BbmRIaWdobGlnaHQob2Zmc2V0LCBsaW5lTnVtYmVyKTsKICAgIGlmIChjYWxs
-YmFjayAhPT0gdW5kZWZpbmVkKSB7CiAgICAgIGNhbGxiYWNrKCk7CiAgICB9CiAgfSBlbHNlIHsKICAg
-IGxvYWRGaWxlKHBhdGgsIG9mZnNldCwgbGluZU51bWJlciwgY2FsbGJhY2spOwogIH0KfQoKZnVuY3Rp
-b24gbWF5YmVTY3JvbGxJbnRvVmlldyhlbGVtZW50KSB7CiAgY29uc3QgcmVjdCA9IGVsZW1lbnQuZ2V0
-Qm91bmRpbmdDbGllbnRSZWN0KCk7CiAgLy8gVE9ETyhzcmF3bGlucyk6IE9ubHkgc2Nyb2xsIHNtb290
-aGx5IHdoZW4gb24gdGhlIHNhbWUgcGFnZS4KICBpZiAocmVjdC5ib3R0b20gPiB3aW5kb3cuaW5uZXJI
-ZWlnaHQpIHsKICAgIGVsZW1lbnQuc2Nyb2xsSW50b1ZpZXcoe2JlaGF2aW9yOiAic21vb3RoIiwgYmxv
-Y2s6ICJlbmQifSk7CiAgfQogIGlmIChyZWN0LnRvcCA8IDApIHsKICAgIGVsZW1lbnQuc2Nyb2xsSW50
-b1ZpZXcoe2JlaGF2aW9yOiAic21vb3RoIn0pOwogIH0KfQoKLy8gU2Nyb2xsIHRhcmdldCB3aXRoIGlk
-IFtvZmZzZXRdIGludG8gdmlldyBpZiBpdCBpcyBub3QgY3VycmVudGx5IGluIHZpZXcuCi8vCi8vIElm
-IFtvZmZzZXRdIGlzIG51bGwsIGluc3RlYWQgc2Nyb2xsIHRoZSAidW5pdC1uYW1lIiBoZWFkZXIsIGF0
-IHRoZSB0b3Agb2YgdGhlCi8vIHBhZ2UsIGludG8gdmlldy4KLy8KLy8gQWxzbyBhZGQgdGhlICJ0YXJn
-ZXQiIGNsYXNzLCBoaWdobGlnaHRpbmcgdGhlIHRhcmdldC4gQWxzbyBhZGQgdGhlCi8vICJoaWdobGln
-aHQiIGNsYXNzIHRvIHRoZSBlbnRpcmUgbGluZSBvbiB3aGljaCB0aGUgdGFyZ2V0IGxpZXMuCmZ1bmN0
-aW9uIG1heWJlU2Nyb2xsVG9BbmRIaWdobGlnaHQob2Zmc2V0LCBsaW5lTnVtYmVyKSB7CiAgdmFyIHRh
-cmdldDsKICB2YXIgbGluZTsKICBpZiAob2Zmc2V0ICE9PSBudWxsKSB7CiAgICB0YXJnZXQgPSBkb2N1
-bWVudC5nZXRFbGVtZW50QnlJZCgibyIgKyBvZmZzZXQpOwogICAgbGluZSA9IGRvY3VtZW50LnF1ZXJ5
-U2VsZWN0b3IoIi5saW5lLSIgKyBsaW5lTnVtYmVyKTsKICAgIGlmICh0YXJnZXQgIT09IG51bGwpIHsK
-ICAgICAgbWF5YmVTY3JvbGxJbnRvVmlldyh0YXJnZXQpOwogICAgICB0YXJnZXQuY2xhc3NMaXN0LmFk
-ZCgidGFyZ2V0Iik7CiAgICB9IGVsc2UgaWYgKGxpbmUgIT0gbnVsbCkgewogICAgICAvLyBJZiB0aGUg
-dGFyZ2V0IGRvZXNuJ3QgZXhpc3QsIGJ1dCB0aGUgbGluZSBkb2VzLCBzY3JvbGwgdGhhdCBpbnRvIHZp
-ZXcKICAgICAgLy8gaW5zdGVhZC4KICAgICAgbWF5YmVTY3JvbGxJbnRvVmlldyhsaW5lKTsKICAgIH0K
-ICAgIGlmIChsaW5lICE9IG51bGwpIHsKICAgICAgbGluZS5wYXJlbnROb2RlLmNsYXNzTGlzdC5hZGQo
-ImhpZ2hsaWdodCIpOwogICAgfQogIH0gZWxzZSB7CiAgICAvLyBJZiBubyBvZmZzZXQgaXMgZ2l2ZW4s
-IHRoaXMgaXMgbGlrZWx5IGEgbmF2aWdhdGlvbiBsaW5rLCBhbmQgd2UgbmVlZCB0bwogICAgLy8gc2Ny
-b2xsIGJhY2sgdG8gdGhlIHRvcCBvZiB0aGUgcGFnZS4KICAgIHRhcmdldCA9IGRvY3VtZW50LmdldEVs
-ZW1lbnRCeUlkKCJ1bml0LW5hbWUiKTsKICAgIG1heWJlU2Nyb2xsSW50b1ZpZXcodGFyZ2V0KTsKICB9
-Cn0KCi8vIExvYWQgdGhlIGZpbGUgYXQgW3BhdGhdIGZyb20gdGhlIHNlcnZlciwgb3B0aW9uYWxseSBz
-Y3JvbGxpbmcgW29mZnNldF0gaW50bwovLyB2aWV3LgpmdW5jdGlvbiBsb2FkRmlsZShwYXRoLCBvZmZz
-ZXQsIGxpbmVOdW1iZXIsIGNhbGxiYWNrKSB7CiAgLy8gTmF2aWdhdGluZyB0byBhbm90aGVyIGZpbGU7
-IHJlcXVlc3QgaXQsIHRoZW4gZG8gd29yayB3aXRoIHRoZSByZXNwb25zZS4KICBjb25zdCB4aHIgPSBu
-ZXcgWE1MSHR0cFJlcXVlc3QoKTsKICB4aHIub3BlbigiR0VUIiwgcGF0aCArICI/aW5saW5lPXRydWUi
-KTsKICB4aHIuc2V0UmVxdWVzdEhlYWRlcigiQ29udGVudC1UeXBlIiwgImFwcGxpY2F0aW9uL2pzb24i
-KTsKICB4aHIub25sb2FkID0gZnVuY3Rpb24oKSB7CiAgICBpZiAoeGhyLnN0YXR1cyA9PT0gMjAwKSB7
-CiAgICAgIGNvbnN0IHJlc3BvbnNlID0gSlNPTi5wYXJzZSh4aHIucmVzcG9uc2VUZXh0KTsKICAgICAg
-d3JpdGVDb2RlQW5kUmVnaW9ucyhyZXNwb25zZSk7CiAgICAgIG1heWJlU2Nyb2xsVG9BbmRIaWdobGln
-aHQob2Zmc2V0LCBsaW5lTnVtYmVyKTsKICAgICAgdXBkYXRlUGFnZShwYXRoLCBvZmZzZXQpOwogICAg
-ICBpZiAoY2FsbGJhY2sgIT09IHVuZGVmaW5lZCkgewogICAgICAgIGNhbGxiYWNrKCk7CiAgICAgIH0K
-ICAgIH0gZWxzZSB7CiAgICAgIGFsZXJ0KCJSZXF1ZXN0IGZhaWxlZDsgc3RhdHVzIG9mICIgKyB4aHIu
-c3RhdHVzKTsKICAgIH0KICB9OwogIHhoci5vbmVycm9yID0gZnVuY3Rpb24oZSkgewogICAgYWxlcnQo
-YENvdWxkIG5vdCBsb2FkICR7cGF0aH07IHByZXZpZXcgc2VydmVyIG1pZ2h0IGJlIGRpc2Nvbm5lY3Rl
-ZC5gKTsKICB9OwogIHhoci5zZW5kKCk7Cn0KCmZ1bmN0aW9uIHB1c2hTdGF0ZShwYXRoLCBvZmZzZXQs
-IGxpbmVOdW1iZXIpIHsKICBsZXQgbmV3TG9jYXRpb24gPSB3aW5kb3cubG9jYXRpb24ub3JpZ2luICsg
-cGF0aCArICI/IjsKICBpZiAob2Zmc2V0ICE9PSBudWxsKSB7CiAgICBuZXdMb2NhdGlvbiA9IG5ld0xv
-Y2F0aW9uICsgIm9mZnNldD0iICsgb2Zmc2V0ICsgIiYiOwogIH0KICBpZiAobGluZU51bWJlciAhPT0g
-bnVsbCkgewogICAgbmV3TG9jYXRpb24gPSBuZXdMb2NhdGlvbiArICJsaW5lPSIgKyBsaW5lTnVtYmVy
-OwogIH0KICBoaXN0b3J5LnB1c2hTdGF0ZSh7fSwgIiIsIG5ld0xvY2F0aW9uKTsKfQoKLy8gVXBkYXRl
-IHRoZSBoZWFkaW5nIGFuZCBuYXZpZ2F0aW9uIGxpbmtzLgovLwovLyBDYWxsIHRoaXMgYWZ0ZXIgdXBk
-YXRpbmcgcGFnZSBjb250ZW50IG9uIGEgbmF2aWdhdGlvbi4KZnVuY3Rpb24gdXBkYXRlUGFnZShwYXRo
-LCBvZmZzZXQpIHsKICBwYXRoID0gcmVsYXRpdmVQYXRoKHBhdGgpOwogIC8vIFVwZGF0ZSBwYWdlIGhl
-YWRpbmcuCiAgY29uc3QgdW5pdE5hbWUgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCIjdW5pdC1uYW1l
-Iik7CiAgdW5pdE5hbWUudGV4dENvbnRlbnQgPSBwYXRoOwogIC8vIFVwZGF0ZSBuYXZpZ2F0aW9uIHN0
-eWxlcy4KICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCIubmF2LXBhbmVsIC5uYXYtbGluayIpLmZv
-ckVhY2goKGxpbmspID0+IHsKICAgIGNvbnN0IG5hbWUgPSBsaW5rLmRhdGFzZXQubmFtZTsKICAgIGlm
-IChuYW1lID09IHBhdGgpIHsKICAgICAgbGluay5jbGFzc0xpc3QuYWRkKCJzZWxlY3RlZC1maWxlIik7
-CiAgICB9IGVsc2UgewogICAgICBsaW5rLmNsYXNzTGlzdC5yZW1vdmUoInNlbGVjdGVkLWZpbGUiKTsK
-ICAgIH0KICB9KTsKfQoKZnVuY3Rpb24gaGlnaGxpZ2h0QWxsQ29kZShfKSB7CiAgZG9jdW1lbnQucXVl
-cnlTZWxlY3RvckFsbCgiLmNvZGUiKS5mb3JFYWNoKChibG9jaykgPT4gewogICAgaGxqcy5oaWdobGln
-aHRCbG9jayhibG9jayk7CiAgfSk7Cn0KCmZ1bmN0aW9uIGFkZEFycm93Q2xpY2tIYW5kbGVyKGFycm93
-KSB7CiAgY29uc3QgY2hpbGRMaXN0ID0gYXJyb3cucGFyZW50Tm9kZS5xdWVyeVNlbGVjdG9yKCI6c2Nv
-cGUgPiB1bCIpOwogIC8vIEFuaW1hdGluZyBoZWlnaHQgZnJvbSAiYXV0byIgdG8gIjAiIGlzIG5vdCBz
-dXBwb3J0ZWQgYnkgQ1NTIFsxXSwgc28gYWxsIHdlCiAgLy8gaGF2ZSBhcmUgaGFja3MuIFRoZSBgKiAy
-YCBhbGxvd3MgZm9yIGV2ZW50cyBpbiB3aGljaCB0aGUgbGlzdCBncm93cyBpbgogIC8vIGhlaWdodCB3
-aGVuIHJlc2l6ZWQsIHdpdGggYWRkaXRpb25hbCB0ZXh0IHdyYXBwaW5nLgogIC8vIFsxXSBodHRwczov
-L2Nzcy10cmlja3MuY29tL3VzaW5nLWNzcy10cmFuc2l0aW9ucy1hdXRvLWRpbWVuc2lvbnMvCiAgY2hp
-bGRMaXN0LnN0eWxlLm1heEhlaWdodCA9IGNoaWxkTGlzdC5vZmZzZXRIZWlnaHQgKiAyICsgInB4IjsK
-ICBhcnJvdy5vbmNsaWNrID0gKGV2ZW50KSA9PiB7CiAgICBpZiAoIWNoaWxkTGlzdC5jbGFzc0xpc3Qu
-Y29udGFpbnMoImNvbGxhcHNlZCIpKSB7CiAgICAgIGNoaWxkTGlzdC5jbGFzc0xpc3QuYWRkKCJjb2xs
-YXBzZWQiKTsKICAgICAgYXJyb3cuY2xhc3NMaXN0LmFkZCgiY29sbGFwc2VkIik7CiAgICB9IGVsc2Ug
-ewogICAgICBjaGlsZExpc3QuY2xhc3NMaXN0LnJlbW92ZSgiY29sbGFwc2VkIik7CiAgICAgIGFycm93
-LmNsYXNzTGlzdC5yZW1vdmUoImNvbGxhcHNlZCIpOwogICAgfQogIH07Cn0KCmZ1bmN0aW9uIGhhbmRs
-ZU5hdkxpbmtDbGljayhldmVudCkgewogIGNvbnN0IHBhdGggPSBhYnNvbHV0ZVBhdGgoZXZlbnQuY3Vy
-cmVudFRhcmdldC5nZXRBdHRyaWJ1dGUoImhyZWYiKSk7CiAgY29uc3Qgb2Zmc2V0ID0gZ2V0T2Zmc2V0
-KGV2ZW50LmN1cnJlbnRUYXJnZXQuZ2V0QXR0cmlidXRlKCJocmVmIikpOwogIGNvbnN0IGxpbmVOdW1i
-ZXIgPSBnZXRMaW5lKGV2ZW50LmN1cnJlbnRUYXJnZXQuZ2V0QXR0cmlidXRlKCJocmVmIikpOwogIGlm
-IChvZmZzZXQgIT09IG51bGwpIHsKICAgIG5hdmlnYXRlKHBhdGgsIG9mZnNldCwgbGluZU51bWJlciwK
-ICAgICAgICAoKSA9PiB7IHB1c2hTdGF0ZShwYXRoLCBvZmZzZXQsIGxpbmVOdW1iZXIpIH0pOwogIH0g
-ZWxzZSB7CiAgICBuYXZpZ2F0ZShwYXRoLCBudWxsLCBudWxsLCAoKSA9PiB7IHB1c2hTdGF0ZShwYXRo
-LCBudWxsLCBudWxsKSB9KTsKICB9CiAgZXZlbnQucHJldmVudERlZmF1bHQoKTsKfQoKZnVuY3Rpb24g
-aGFuZGxlUG9zdExpbmtDbGljayhldmVudCkgewogIC8vIERpcmVjdGluZyB0aGUgc2VydmVyIHRvIHBy
-b2R1Y2UgYW4gZWRpdDsgcmVxdWVzdCBpdCwgdGhlbiBkbyB3b3JrIHdpdGgKICAvLyB0aGUgcmVzcG9u
-c2UuCiAgY29uc3QgcGF0aCA9IGFic29sdXRlUGF0aChldmVudC5jdXJyZW50VGFyZ2V0LmdldEF0dHJp
-YnV0ZSgiaHJlZiIpKTsKICBjb25zdCB4aHIgPSBuZXcgWE1MSHR0cFJlcXVlc3QoKTsKICB4aHIub3Bl
-bigiUE9TVCIsIHBhdGgpOwogIHhoci5zZXRSZXF1ZXN0SGVhZGVyKCJDb250ZW50LVR5cGUiLCAiYXBw
-bGljYXRpb24vanNvbiIpOwogIHhoci5vbmxvYWQgPSBmdW5jdGlvbigpIHsKICAgIGlmICh4aHIuc3Rh
-dHVzID09PSAyMDApIHsKICAgICAgLy8gTGlrZWx5IHJlcXVlc3QgbmV3IG5hdmlnYXRpb24gYW5kIGZp
-bGUgY29udGVudC4KICAgIH0gZWxzZSB7CiAgICAgIGFsZXJ0KCJSZXF1ZXN0IGZhaWxlZDsgc3RhdHVz
-IG9mICIgKyB4aHIuc3RhdHVzKTsKICAgIH0KICB9OwogIHhoci5vbmVycm9yID0gZnVuY3Rpb24oZSkg
-ewogICAgYWxlcnQoYENvdWxkIG5vdCBsb2FkICR7cGF0aH07IHByZXZpZXcgc2VydmVyIG1pZ2h0IGJl
-IGRpc2Nvbm5lY3RlZC5gKTsKICB9OwogIHhoci5zZW5kKCk7Cn0KCmZ1bmN0aW9uIGFkZENsaWNrSGFu
-ZGxlcnMocGFyZW50U2VsZWN0b3IpIHsKICBjb25zdCBwYXJlbnRFbGVtZW50ID0gZG9jdW1lbnQucXVl
-cnlTZWxlY3RvcihwYXJlbnRTZWxlY3Rvcik7CgogIGNvbnN0IG5hdkxpbmtzID0gcGFyZW50RWxlbWVu
-dC5xdWVyeVNlbGVjdG9yQWxsKCIubmF2LWxpbmsiKTsKICBuYXZMaW5rcy5mb3JFYWNoKChsaW5rKSA9
-PiB7CiAgICBsaW5rLm9uY2xpY2sgPSBoYW5kbGVOYXZMaW5rQ2xpY2s7CiAgfSk7CgogIGNvbnN0IHJl
-Z2lvbnMgPSBwYXJlbnRFbGVtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoIi5yZWdpb24iKTsKICByZWdpb25z
-LmZvckVhY2goKHJlZ2lvbikgPT4gewogICAgcmVnaW9uLm9uY2xpY2sgPSAoZXZlbnQpID0+IHsKICAg
-ICAgbG9hZFJlZ2lvbkV4cGxhbmF0aW9uKHJlZ2lvbik7CiAgICB9OwogIH0pOwoKICBjb25zdCBwb3N0
-TGlua3MgPSBwYXJlbnRFbGVtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoIi5wb3N0LWxpbmsiKTsKICBwb3N0
-TGlua3MuZm9yRWFjaCgobGluaykgPT4gewogICAgbGluay5vbmNsaWNrID0gaGFuZGxlUG9zdExpbmtD
-bGljazsKICB9KTsKfQoKZnVuY3Rpb24gd3JpdGVOYXZpZ2F0aW9uU3VidHJlZShwYXJlbnRFbGVtZW50
-LCB0cmVlKSB7CiAgY29uc3QgdWwgPSBwYXJlbnRFbGVtZW50LmFwcGVuZENoaWxkKGRvY3VtZW50LmNy
-ZWF0ZUVsZW1lbnQoJ3VsJykpOwogIGZvciAoY29uc3QgZW50aXR5IG9mIHRyZWUpIHsKICAgIGNvbnN0
-IGxpID0gdWwuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnbGknKSk7CiAgICBpZiAo
-ZW50aXR5WyJ0eXBlIl0gPT0gImRpcmVjdG9yeSIpIHsKICAgICAgbGkuY2xhc3NMaXN0LmFkZCgiZGly
-Iik7CiAgICAgIGNvbnN0IGFycm93ID0gbGkuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlRWxlbWVu
-dCgnc3BhbicpKTsKICAgICAgYXJyb3cuY2xhc3NMaXN0LmFkZCgiYXJyb3ciKTsKICAgICAgYXJyb3cu
-aW5uZXJIVE1MID0gIiYjeDI1QkM7IjsKICAgICAgY29uc3QgaWNvbiA9IGxpLmFwcGVuZENoaWxkKGRv
-Y3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NwYW4nKSk7CiAgICAgIGljb24uaW5uZXJIVE1MID0gIiYjeDFG
-NEMxOyI7CiAgICAgIGxpLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKGVudGl0eVsi
-bmFtZSJdKSk7CiAgICAgIHdyaXRlTmF2aWdhdGlvblN1YnRyZWUobGksIGVudGl0eVsic3VidHJlZSJd
-KTsKICAgICAgYWRkQXJyb3dDbGlja0hhbmRsZXIoYXJyb3cpOwogICAgfSBlbHNlIHsKICAgICAgbGku
-aW5uZXJIVE1MID0gIiYjeDFGNEM0OyI7CiAgICAgIGNvbnN0IGEgPSBsaS5hcHBlbmRDaGlsZChkb2N1
-bWVudC5jcmVhdGVFbGVtZW50KCJhIikpOwogICAgICBhLmNsYXNzTGlzdC5hZGQoIm5hdi1saW5rIik7
-CiAgICAgIGEuZGF0YXNldC5uYW1lID0gZW50aXR5WyJwYXRoIl07CiAgICAgIGEuc2V0QXR0cmlidXRl
-KCJocmVmIiwgZW50aXR5WyJocmVmIl0pOwogICAgICBhLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0
-ZVRleHROb2RlKGVudGl0eVsibmFtZSJdKSk7CiAgICAgIGEub25jbGljayA9IGhhbmRsZU5hdkxpbmtD
-bGljazsKICAgICAgY29uc3QgZWRpdENvdW50ID0gZW50aXR5WyJlZGl0Q291bnQiXTsKICAgICAgaWYg
-KGVkaXRDb3VudCA+IDApIHsKICAgICAgICBjb25zdCBlZGl0c0JhZGdlID0gbGkuYXBwZW5kQ2hpbGQo
-ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic3BhbiIpKTsKICAgICAgICBlZGl0c0JhZGdlLmNsYXNzTGlz
-dC5hZGQoImVkaXQtY291bnQiKTsKICAgICAgICBjb25zdCBlZGl0cyA9IGVkaXRDb3VudCA9PSAxID8g
-J2VkaXQnIDogJ2VkaXRzJzsKICAgICAgICBlZGl0c0JhZGdlLnNldEF0dHJpYnV0ZSgidGl0bGUiLCBg
-JHtlZGl0Q291bnR9ICR7ZWRpdHN9YCk7CiAgICAgICAgZWRpdHNCYWRnZS5hcHBlbmRDaGlsZChkb2N1
-bWVudC5jcmVhdGVUZXh0Tm9kZShlZGl0Q291bnQpKTsKICAgICAgfQogICAgfQogIH0KfQoKLy8gTG9h
-ZCB0aGUgbmF2aWdhdGlvbiB0cmVlIGludG8gdGhlICIubmF2LXRyZWUiIGRpdi4KZnVuY3Rpb24gbG9h
-ZE5hdmlnYXRpb25UcmVlKHJlZ2lvbikgewogIC8vIFJlcXVlc3QgdGhlIG5hdmlnYXRpb24gdHJlZSwg
-dGhlbiBkbyB3b3JrIHdpdGggdGhlIHJlc3BvbnNlLgogIGNvbnN0IHhociA9IG5ldyBYTUxIdHRwUmVx
-dWVzdCgpOwogIGNvbnN0IHBhdGggPSAiL19wcmV2aWV3L25hdmlnYXRpb25UcmVlLmpzb24iOwogIHho
-ci5vcGVuKCJHRVQiLCBwYXRoKTsKICB4aHIuc2V0UmVxdWVzdEhlYWRlcigiQ29udGVudC1UeXBlIiwg
-ImFwcGxpY2F0aW9uL2pzb24iKTsKICB4aHIub25sb2FkID0gZnVuY3Rpb24oKSB7CiAgICBpZiAoeGhy
-LnN0YXR1cyA9PT0gMjAwKSB7CiAgICAgIGNvbnN0IHJlc3BvbnNlID0gSlNPTi5wYXJzZSh4aHIucmVz
-cG9uc2VUZXh0KTsKICAgICAgY29uc3QgbmF2VHJlZSA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoIi5u
-YXYtdHJlZSIpOwogICAgICBuYXZUcmVlLmlubmVySFRNTCA9ICIiOwogICAgICB3cml0ZU5hdmlnYXRp
-b25TdWJ0cmVlKG5hdlRyZWUsIHJlc3BvbnNlKTsKICAgIH0gZWxzZSB7CiAgICAgIGFsZXJ0KGBSZXF1
-ZXN0IGZhaWxlZDsgc3RhdHVzIG9mICR7eGhyLnN0YXR1c31gKTsKICAgIH0KICB9OwogIHhoci5vbmVy
-cm9yID0gZnVuY3Rpb24oZSkgewogICAgYWxlcnQoYENvdWxkIG5vdCBsb2FkICR7cGF0aH07IHByZXZp
-ZXcgc2VydmVyIG1pZ2h0IGJlIGRpc2Nvbm5lY3RlZC5gKTsKICB9OwogIHhoci5zZW5kKCk7Cn0KCmZ1
-bmN0aW9uIHdyaXRlUmVnaW9uRXhwbGFuYXRpb24ocmVzcG9uc2UpIHsKICBjb25zdCBlZGl0UGFuZWwg
-PSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCIuZWRpdC1wYW5lbCAucGFuZWwtY29udGVudCIpOwogIGVk
-aXRQYW5lbC5pbm5lckhUTUwgPSAiIjsKICBjb25zdCByZWdpb25Mb2NhdGlvbiA9IGRvY3VtZW50LmNy
-ZWF0ZUVsZW1lbnQoInAiKTsKICByZWdpb25Mb2NhdGlvbi5jbGFzc0xpc3QuYWRkKCJyZWdpb24tbG9j
-YXRpb24iKTsKICAvLyBJbnNlcnQgYSB6ZXJvLXdpZHRoIHNwYWNlIGFmdGVyIGVhY2ggIi8iLCB0byBh
-bGxvdyBsaW5lcyB0byB3cmFwIGFmdGVyIGVhY2gKICAvLyBkaXJlY3RvcnkgbmFtZS4KICBjb25zdCBw
-YXRoID0gcmVzcG9uc2VbInBhdGgiXS5yZXBsYWNlKC9cLy9nLCAiL1x1MjAwQiIpOwogIHJlZ2lvbkxv
-Y2F0aW9uLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKGAke3BhdGh9IGApKTsKICBj
-b25zdCByZWdpb25MaW5lID0gcmVnaW9uTG9jYXRpb24uYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRl
-RWxlbWVudCgic3BhbiIpKTsKICByZWdpb25MaW5lLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZVRl
-eHROb2RlKGBsaW5lICR7cmVzcG9uc2VbImxpbmUiXX1gKSk7CiAgcmVnaW9uTGluZS5jbGFzc0xpc3Qu
-YWRkKCJub3dyYXAiKTsKICBlZGl0UGFuZWwuYXBwZW5kQ2hpbGQocmVnaW9uTG9jYXRpb24pOwogIGNv
-bnN0IGV4cGxhbmF0aW9uID0gZWRpdFBhbmVsLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZUVsZW1l
-bnQoInAiKSk7CiAgZXhwbGFuYXRpb24uYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUo
-cmVzcG9uc2VbImV4cGxhbmF0aW9uIl0pKTsKICBjb25zdCBkZXRhaWxDb3VudCA9IHJlc3BvbnNlWyJk
-ZXRhaWxzIl0ubGVuZ3RoOwogIGlmIChkZXRhaWxDb3VudCA9PSAwKSB7CiAgICAvLyBIYXZpbmcgMCBk
-ZXRhaWxzIGlzIG5vdCBuZWNlc3NhcmlseSBhbiBleHBlY3RlZCBwb3NzaWJpbGl0eSwgYnV0IGhhbmRs
-aW5nCiAgICAvLyB0aGUgcG9zc2liaWxpdHkgcHJldmVudHMgYXdrd2FyZCB0ZXh0LCAiZm9yIDAgcmVh
-c29uczoiLgogICAgZXhwbGFuYXRpb24uYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUo
-Ii4iKSk7CiAgfSBlbHNlIHsKICAgIGV4cGxhbmF0aW9uLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0
-ZVRleHROb2RlKAogICAgICAgIGRldGFpbENvdW50ID09IDEKICAgICAgICAgICAgPyBgIGZvciAke2Rl
-dGFpbENvdW50fSByZWFzb246YCA6IGAgZm9yICR7ZGV0YWlsQ291bnR9IHJlYXNvbnM6YCkpOwogICAg
-Y29uc3QgZGV0YWlsTGlzdCA9IGVkaXRQYW5lbC5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVFbGVt
-ZW50KCJvbCIpKTsKICAgIGZvciAoY29uc3QgZGV0YWlsIG9mIHJlc3BvbnNlWyJkZXRhaWxzIl0pIHsK
-ICAgICAgY29uc3QgZGV0YWlsSXRlbSA9IGRldGFpbExpc3QuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3Jl
-YXRlRWxlbWVudCgibGkiKSk7CiAgICAgIGRldGFpbEl0ZW0uYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3Jl
-YXRlVGV4dE5vZGUoZGV0YWlsWyJkZXNjcmlwdGlvbiJdKSk7CiAgICAgIGlmIChkZXRhaWxbImxpbmsi
-XSAhPT0gdW5kZWZpbmVkKSB7CiAgICAgICAgZGV0YWlsSXRlbS5hcHBlbmRDaGlsZChkb2N1bWVudC5j
-cmVhdGVUZXh0Tm9kZSgiICgiKSk7CiAgICAgICAgY29uc3QgYSA9IGRldGFpbEl0ZW0uYXBwZW5kQ2hp
-bGQoZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiYSIpKTsKICAgICAgICBhLmFwcGVuZENoaWxkKGRvY3Vt
-ZW50LmNyZWF0ZVRleHROb2RlKGRldGFpbFsibGluayJdWyJ0ZXh0Il0pKTsKICAgICAgICBhLnNldEF0
-dHJpYnV0ZSgiaHJlZiIsIGRldGFpbFsibGluayJdWyJocmVmIl0pOwogICAgICAgIGEuY2xhc3NMaXN0
-LmFkZCgibmF2LWxpbmsiKTsKICAgICAgICBkZXRhaWxJdGVtLmFwcGVuZENoaWxkKGRvY3VtZW50LmNy
-ZWF0ZVRleHROb2RlKCIpIikpOwogICAgICB9CiAgICB9CiAgfQogIGlmIChyZXNwb25zZVsiZWRpdHMi
-XSAhPT0gdW5kZWZpbmVkKSB7CiAgICBmb3IgKGNvbnN0IGVkaXQgb2YgcmVzcG9uc2VbImVkaXRzIl0p
-IHsKICAgICAgY29uc3QgZWRpdFBhcmFncmFwaCA9IGVkaXRQYW5lbC5hcHBlbmRDaGlsZChkb2N1bWVu
-dC5jcmVhdGVFbGVtZW50KCJwIikpOwogICAgICBjb25zdCBhID0gZWRpdFBhcmFncmFwaC5hcHBlbmRD
-aGlsZChkb2N1bWVudC5jcmVhdGVFbGVtZW50KCJhIikpOwogICAgICBhLmFwcGVuZENoaWxkKGRvY3Vt
-ZW50LmNyZWF0ZVRleHROb2RlKGVkaXRbInRleHQiXSkpOwogICAgICBhLnNldEF0dHJpYnV0ZSgiaHJl
-ZiIsIGVkaXRbImhyZWYiXSk7CiAgICAgIGEuY2xhc3NMaXN0LmFkZCgicG9zdC1saW5rIik7CiAgICB9
-CiAgfQp9CgovLyBMb2FkIHRoZSBleHBsYW5hdGlvbiBmb3IgW3JlZ2lvbl0sIGludG8gdGhlICIucGFu
-ZWwtY29udGVudCIgZGl2LgpmdW5jdGlvbiBsb2FkUmVnaW9uRXhwbGFuYXRpb24ocmVnaW9uKSB7CiAg
-Ly8gUmVxdWVzdCB0aGUgcmVnaW9uLCB0aGVuIGRvIHdvcmsgd2l0aCB0aGUgcmVzcG9uc2UuCiAgY29u
-c3QgeGhyID0gbmV3IFhNTEh0dHBSZXF1ZXN0KCk7CiAgY29uc3QgcGF0aCA9IHdpbmRvdy5sb2NhdGlv
-bi5wYXRobmFtZTsKICBjb25zdCBvZmZzZXQgPSByZWdpb24uZGF0YXNldC5vZmZzZXQ7CiAgeGhyLm9w
-ZW4oIkdFVCIsIHBhdGggKyBgP3JlZ2lvbj1yZWdpb24mb2Zmc2V0PSR7b2Zmc2V0fWApOwogIHhoci5z
-ZXRSZXF1ZXN0SGVhZGVyKCJDb250ZW50LVR5cGUiLCAiYXBwbGljYXRpb24vanNvbiIpOwogIHhoci5v
-bmxvYWQgPSBmdW5jdGlvbigpIHsKICAgIGlmICh4aHIuc3RhdHVzID09PSAyMDApIHsKICAgICAgY29u
-c3QgcmVzcG9uc2UgPSBKU09OLnBhcnNlKHhoci5yZXNwb25zZVRleHQpOwogICAgICB3cml0ZVJlZ2lv
-bkV4cGxhbmF0aW9uKHJlc3BvbnNlKTsKICAgICAgYWRkQ2xpY2tIYW5kbGVycygiLmVkaXQtcGFuZWwg
-LnBhbmVsLWNvbnRlbnQiKTsKICAgIH0gZWxzZSB7CiAgICAgIGFsZXJ0KGBSZXF1ZXN0IGZhaWxlZDsg
-c3RhdHVzIG9mICR7eGhyLnN0YXR1c31gKTsKICAgIH0KICB9OwogIHhoci5vbmVycm9yID0gZnVuY3Rp
-b24oZSkgewogICAgYWxlcnQoYENvdWxkIG5vdCBsb2FkICR7cGF0aH07IHByZXZpZXcgc2VydmVyIG1p
-Z2h0IGJlIGRpc2Nvbm5lY3RlZC5gKTsKICB9OwogIHhoci5zZW5kKCk7Cn0KCmZ1bmN0aW9uIGRlYm91
-bmNlKGZuLCBkZWxheSkgewogIHZhciB0aW1lb3V0OwogIHJldHVybiBmdW5jdGlvbigpIHsKICAgIHZh
-ciBsYXRlciA9IGZ1bmN0aW9uKCkgewogICAgICB0aW1lb3V0ID0gbnVsbDsKICAgIH07CiAgICB2YXIg
-Y2FsbE5vdyA9ICF0aW1lb3V0OwogICAgY2xlYXJUaW1lb3V0KHRpbWVvdXQpOwogICAgdGltZW91dCA9
-IHNldFRpbWVvdXQobGF0ZXIsIGRlbGF5KTsKICAgIGlmIChjYWxsTm93KSBmbi5hcHBseSh0aGlzKTsK
-CX07Cn07CgovLyBSZXNpemUgdGhlIGZpeGVkLXNpemUgYW5kIGZpeGVkLXBvc2l0aW9uIG5hdmlnYXRp
-b24gYW5kIGluZm9ybWF0aW9uIHBhbmVscy4KZnVuY3Rpb24gcmVzaXplUGFuZWxzKCkgewogIGNvbnN0
-IG5hdklubmVyID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcigiLm5hdi1pbm5lciIpOwogIGNvbnN0IGhl
-aWdodCA9IHdpbmRvdy5pbm5lckhlaWdodDsKICBuYXZJbm5lci5zdHlsZS5oZWlnaHQgPSBoZWlnaHQg
-KyAicHgiOwoKICBjb25zdCBpbmZvUGFuZWxIZWlnaHQgPSBoZWlnaHQgLyAyIC0gNjsKICBjb25zdCBl
-ZGl0UGFuZWwgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCIuZWRpdC1wYW5lbCIpOwogIGVkaXRQYW5l
-bC5zdHlsZS5oZWlnaHQgPSBpbmZvUGFuZWxIZWlnaHQgKyAicHgiOwoKICBjb25zdCBlZGl0TGlzdEhl
-aWdodCA9IGhlaWdodCAvIDIgLSA2OwogIGNvbnN0IGVkaXRMaXN0ID0gZG9jdW1lbnQucXVlcnlTZWxl
-Y3RvcigiLmVkaXQtbGlzdCIpOwogIGVkaXRMaXN0LnN0eWxlLmhlaWdodCA9IGVkaXRMaXN0SGVpZ2h0
-ICsgInB4IjsKfQoKZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigiRE9NQ29udGVudExvYWRlZCIsIChl
-dmVudCkgPT4gewogIGNvbnN0IHBhdGggPSB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWU7CiAgY29uc3Qg
-b2Zmc2V0ID0gZ2V0T2Zmc2V0KHdpbmRvdy5sb2NhdGlvbi5ocmVmKTsKICBjb25zdCBsaW5lTnVtYmVy
-ID0gZ2V0TGluZSh3aW5kb3cubG9jYXRpb24uaHJlZik7CiAgY29uc3Qgcm9vdCA9IGRvY3VtZW50LnF1
-ZXJ5U2VsZWN0b3IoIi5yb290IikudGV4dENvbnRlbnQ7CiAgbG9hZE5hdmlnYXRpb25UcmVlKCk7CiAg
-aWYgKHBhdGggIT09ICIvIiAmJiBwYXRoICE9PSByb290KSB7CiAgICAvLyBUT0RPKHNyYXdsaW5zKTog
-cmVwbGFjZVN0YXRlPwogICAgbG9hZEZpbGUocGF0aCwgb2Zmc2V0LCBsaW5lTnVtYmVyLAogICAgICAg
-ICgpID0+IHsgcHVzaFN0YXRlKHBhdGgsIG9mZnNldCwgbGluZU51bWJlcikgfSk7CiAgfQogIHJlc2l6
-ZVBhbmVscygpOwp9KTsKCndpbmRvdy5hZGRFdmVudExpc3RlbmVyKCJwb3BzdGF0ZSIsIChldmVudCkg
-PT4gewogIGNvbnN0IHBhdGggPSB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWU7CiAgY29uc3Qgb2Zmc2V0
-ID0gZ2V0T2Zmc2V0KHdpbmRvdy5sb2NhdGlvbi5ocmVmKTsKICBjb25zdCBsaW5lTnVtYmVyID0gZ2V0
-TGluZSh3aW5kb3cubG9jYXRpb24uaHJlZik7CiAgaWYgKHBhdGgubGVuZ3RoID4gMSkgewogICAgbG9h
-ZEZpbGUocGF0aCwgb2Zmc2V0LCBsaW5lTnVtYmVyKTsKICB9IGVsc2UgewogICAgLy8gQmxhbmsgb3V0
-IHRoZSBwYWdlLCBmb3IgdGhlIGluZGV4IHNjcmVlbi4KICAgIHdyaXRlQ29kZUFuZFJlZ2lvbnMoeyJy
-ZWdpb25zIjogIiIsICJuYXZDb250ZW50IjogIiJ9KTsKICAgIHVwZGF0ZVBhZ2UoIiZuYnNwOyIsIG51
-bGwpOwogIH0KfSk7Cgp3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcigicmVzaXplIiwgKGV2ZW50KSA9PiB7
-CiAgZGVib3VuY2UocmVzaXplUGFuZWxzLCAyMDApKCk7Cn0pOwoKLy8gV2hlbiBzY3JvbGxpbmcgdGhl
-IHBhZ2UsIGRldGVybWluZSB3aGV0aGVyIHRoZSBuYXZpZ2F0aW9uIGFuZCBpbmZvcm1hdGlvbgovLyBw
-YW5lbHMgbmVlZCB0byBiZSBmaXhlZCBpbiBwbGFjZSwgb3IgYWxsb3dlZCB0byBzY3JvbGwuCndpbmRv
-dy5hZGRFdmVudExpc3RlbmVyKCJzY3JvbGwiLCAoZXZlbnQpID0+IHsKICBjb25zdCBuYXZQYW5lbCA9
-IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoIi5uYXYtcGFuZWwiKTsKICBjb25zdCBuYXZJbm5lciA9IG5h
-dlBhbmVsLnF1ZXJ5U2VsZWN0b3IoIi5uYXYtaW5uZXIiKTsKICBjb25zdCBpbmZvUGFuZWwgPSBkb2N1
-bWVudC5xdWVyeVNlbGVjdG9yKCIuaW5mby1wYW5lbCIpOwogIGNvbnN0IHBhbmVsQ29udGFpbmVyID0g
-ZG9jdW1lbnQucXVlcnlTZWxlY3RvcigiLnBhbmVsLWNvbnRhaW5lciIpOwogIGNvbnN0IGlubmVyVG9w
-T2Zmc2V0ID0gbmF2UGFuZWwub2Zmc2V0VG9wOwogIGlmICh3aW5kb3cucGFnZVlPZmZzZXQgPiBpbm5l
-clRvcE9mZnNldCkgewogICAgaWYgKCFuYXZJbm5lci5jbGFzc0xpc3QuY29udGFpbnMoImZpeGVkIikp
-IHsKICAgICAgY29uc3QgbmF2UGFuZWxXaWR0aCA9IG5hdlBhbmVsLm9mZnNldFdpZHRoIC0gMTQ7CiAg
-ICAgIG5hdlBhbmVsLnN0eWxlLndpZHRoID0gbmF2UGFuZWxXaWR0aCArICJweCI7CiAgICAgIC8vIFN1
-YnRyYWN0IDdweCBmb3IgbmF2LWlubmVyJ3MgcGFkZGluZy4KICAgICAgbmF2SW5uZXIuc3R5bGUud2lk
-dGggPSBuYXZQYW5lbFdpZHRoICsgNyArICJweCI7CiAgICAgIG5hdklubmVyLmNsYXNzTGlzdC5hZGQo
-ImZpeGVkIik7CiAgICB9CiAgICBpZiAoIXBhbmVsQ29udGFpbmVyLmNsYXNzTGlzdC5jb250YWlucygi
-Zml4ZWQiKSkgewogICAgICBjb25zdCBpbmZvUGFuZWxXaWR0aCA9IGluZm9QYW5lbC5vZmZzZXRXaWR0
-aDsKICAgICAgaW5mb1BhbmVsLnN0eWxlLndpZHRoID0gaW5mb1BhbmVsV2lkdGggKyAicHgiOwogICAg
-ICBwYW5lbENvbnRhaW5lci5zdHlsZS53aWR0aCA9IGluZm9QYW5lbFdpZHRoICsgInB4IjsKICAgICAg
-cGFuZWxDb250YWluZXIuY2xhc3NMaXN0LmFkZCgiZml4ZWQiKTsKICAgIH0KICB9IGVsc2UgewogICAg
-aWYgKG5hdklubmVyLmNsYXNzTGlzdC5jb250YWlucygiZml4ZWQiKSkgewogICAgICBuYXZQYW5lbC5z
-dHlsZS53aWR0aCA9ICIiOwogICAgICBuYXZJbm5lci5zdHlsZS53aWR0aCA9ICIiOwogICAgICBuYXZJ
-bm5lci5jbGFzc0xpc3QucmVtb3ZlKCJmaXhlZCIpOwogICAgfQogICAgaWYgKHBhbmVsQ29udGFpbmVy
-LmNsYXNzTGlzdC5jb250YWlucygiZml4ZWQiKSkgewogICAgICBpbmZvUGFuZWwuc3R5bGUud2lkdGgg
-PSAiIjsKICAgICAgcGFuZWxDb250YWluZXIuc3R5bGUud2lkdGggPSAiIjsKICAgICAgcGFuZWxDb250
-YWluZXIuY2xhc3NMaXN0LnJlbW92ZSgiZml4ZWQiKTsKICAgIH0KICB9CiAgZGVib3VuY2UocmVzaXpl
-UGFuZWxzLCAyMDApKCk7Cn0pOwo=
+KGZ1bmN0aW9uIGRhcnRQcm9ncmFtKCl7ZnVuY3Rpb24gY29weVByb3BlcnRpZXMoYSxiKXt2YXIgdD1P
+YmplY3Qua2V5cyhhKQpmb3IodmFyIHM9MDtzPHQubGVuZ3RoO3MrKyl7dmFyIHI9dFtzXQpiW3JdPWFb
+cl19fXZhciB6PWZ1bmN0aW9uKCl7dmFyIHQ9ZnVuY3Rpb24oKXt9CnQucHJvdG90eXBlPXtwOnt9fQp2
+YXIgcz1uZXcgdCgpCmlmKCEocy5fX3Byb3RvX18mJnMuX19wcm90b19fLnA9PT10LnByb3RvdHlwZS5w
+KSlyZXR1cm4gZmFsc2UKdHJ5e2lmKHR5cGVvZiBuYXZpZ2F0b3IhPSJ1bmRlZmluZWQiJiZ0eXBlb2Yg
+bmF2aWdhdG9yLnVzZXJBZ2VudD09InN0cmluZyImJm5hdmlnYXRvci51c2VyQWdlbnQuaW5kZXhPZigi
+Q2hyb21lLyIpPj0wKXJldHVybiB0cnVlCmlmKHR5cGVvZiB2ZXJzaW9uPT0iZnVuY3Rpb24iJiZ2ZXJz
+aW9uLmxlbmd0aD09MCl7dmFyIHI9dmVyc2lvbigpCmlmKC9eXGQrXC5cZCtcLlxkK1wuXGQrJC8udGVz
+dChyKSlyZXR1cm4gdHJ1ZX19Y2F0Y2gocSl7fXJldHVybiBmYWxzZX0oKQpmdW5jdGlvbiBzZXRGdW5j
+dGlvbk5hbWVzSWZOZWNlc3NhcnkoYSl7ZnVuY3Rpb24gdCgpe307aWYodHlwZW9mIHQubmFtZT09InN0
+cmluZyIpcmV0dXJuCmZvcih2YXIgdD0wO3Q8YS5sZW5ndGg7dCsrKXt2YXIgcz1hW3RdCnZhciByPU9i
+amVjdC5rZXlzKHMpCmZvcih2YXIgcT0wO3E8ci5sZW5ndGg7cSsrKXt2YXIgcD1yW3FdCnZhciBvPXNb
+cF0KaWYodHlwZW9mIG89PSdmdW5jdGlvbicpby5uYW1lPXB9fX1mdW5jdGlvbiBpbmhlcml0KGEsYil7
+YS5wcm90b3R5cGUuY29uc3RydWN0b3I9YQphLnByb3RvdHlwZVsiJGkiK2EubmFtZV09YQppZihiIT1u
+dWxsKXtpZih6KXthLnByb3RvdHlwZS5fX3Byb3RvX189Yi5wcm90b3R5cGUKcmV0dXJufXZhciB0PU9i
+amVjdC5jcmVhdGUoYi5wcm90b3R5cGUpCmNvcHlQcm9wZXJ0aWVzKGEucHJvdG90eXBlLHQpCmEucHJv
+dG90eXBlPXR9fWZ1bmN0aW9uIGluaGVyaXRNYW55KGEsYil7Zm9yKHZhciB0PTA7dDxiLmxlbmd0aDt0
+KyspaW5oZXJpdChiW3RdLGEpfWZ1bmN0aW9uIG1peGluKGEsYil7Y29weVByb3BlcnRpZXMoYi5wcm90
+b3R5cGUsYS5wcm90b3R5cGUpCmEucHJvdG90eXBlLmNvbnN0cnVjdG9yPWF9ZnVuY3Rpb24gbGF6eShh
+LGIsYyxkKXt2YXIgdD1hCmFbYl09dAphW2NdPWZ1bmN0aW9uKCl7YVtjXT1mdW5jdGlvbigpe0gubEco
+Yil9CnZhciBzCnZhciByPWQKdHJ5e2lmKGFbYl09PT10KXtzPWFbYl09cgpzPWFbYl09ZCgpfWVsc2Ug
+cz1hW2JdfWZpbmFsbHl7aWYocz09PXIpYVtiXT1udWxsCmFbY109ZnVuY3Rpb24oKXtyZXR1cm4gdGhp
+c1tiXX19cmV0dXJuIHN9fWZ1bmN0aW9uIG1ha2VDb25zdExpc3QoYSl7YS5pbW11dGFibGUkbGlzdD1B
+cnJheQphLmZpeGVkJGxlbmd0aD1BcnJheQpyZXR1cm4gYX1mdW5jdGlvbiBjb252ZXJ0VG9GYXN0T2Jq
+ZWN0KGEpe2Z1bmN0aW9uIHQoKXt9dC5wcm90b3R5cGU9YQpuZXcgdCgpCnJldHVybiBhfWZ1bmN0aW9u
+IGNvbnZlcnRBbGxUb0Zhc3RPYmplY3QoYSl7Zm9yKHZhciB0PTA7dDxhLmxlbmd0aDsrK3QpY29udmVy
+dFRvRmFzdE9iamVjdChhW3RdKX12YXIgeT0wCmZ1bmN0aW9uIHRlYXJPZmZHZXR0ZXIoYSxiLGMsZCxl
+KXtyZXR1cm4gZT9uZXcgRnVuY3Rpb24oImZ1bmNzIiwiYXBwbHlUcmFtcG9saW5lSW5kZXgiLCJyZWZs
+ZWN0aW9uSW5mbyIsIm5hbWUiLCJIIiwiYyIsInJldHVybiBmdW5jdGlvbiB0ZWFyT2ZmXyIrZCt5Kysr
+IihyZWNlaXZlcikgeyIrImlmIChjID09PSBudWxsKSBjID0gIisiSC5ocCIrIigiKyJ0aGlzLCBmdW5j
+cywgYXBwbHlUcmFtcG9saW5lSW5kZXgsIHJlZmxlY3Rpb25JbmZvLCBmYWxzZSwgdHJ1ZSwgbmFtZSk7
+IisicmV0dXJuIG5ldyBjKHRoaXMsIGZ1bmNzWzBdLCByZWNlaXZlciwgbmFtZSk7IisifSIpKGEsYixj
+LGQsSCxudWxsKTpuZXcgRnVuY3Rpb24oImZ1bmNzIiwiYXBwbHlUcmFtcG9saW5lSW5kZXgiLCJyZWZs
+ZWN0aW9uSW5mbyIsIm5hbWUiLCJIIiwiYyIsInJldHVybiBmdW5jdGlvbiB0ZWFyT2ZmXyIrZCt5Kysr
+IigpIHsiKyJpZiAoYyA9PT0gbnVsbCkgYyA9ICIrIkguaHAiKyIoIisidGhpcywgZnVuY3MsIGFwcGx5
+VHJhbXBvbGluZUluZGV4LCByZWZsZWN0aW9uSW5mbywgZmFsc2UsIGZhbHNlLCBuYW1lKTsiKyJyZXR1
+cm4gbmV3IGModGhpcywgZnVuY3NbMF0sIG51bGwsIG5hbWUpOyIrIn0iKShhLGIsYyxkLEgsbnVsbCl9
+ZnVuY3Rpb24gdGVhck9mZihhLGIsYyxkLGUsZil7dmFyIHQ9bnVsbApyZXR1cm4gZD9mdW5jdGlvbigp
+e2lmKHQ9PT1udWxsKXQ9SC5ocCh0aGlzLGEsYixjLHRydWUsZmFsc2UsZSkucHJvdG90eXBlCnJldHVy
+biB0fTp0ZWFyT2ZmR2V0dGVyKGEsYixjLGUsZil9dmFyIHg9MApmdW5jdGlvbiBpbnN0YWxsVGVhck9m
+ZihhLGIsYyxkLGUsZixnLGgsaSxqKXt2YXIgdD1bXQpmb3IodmFyIHM9MDtzPGgubGVuZ3RoO3MrKyl7
+dmFyIHI9aFtzXQppZih0eXBlb2Ygcj09J3N0cmluZycpcj1hW3JdCnIuJGNhbGxOYW1lPWdbc10KdC5w
+dXNoKHIpfXZhciByPXRbMF0Kci4kUj1lCnIuJEQ9Zgp2YXIgcT1pCmlmKHR5cGVvZiBxPT0ibnVtYmVy
+IilxKz14CnZhciBwPWhbMF0Kci4kc3R1Yk5hbWU9cAp2YXIgbz10ZWFyT2ZmKHQsanx8MCxxLGMscCxk
+KQphW2JdPW8KaWYoYylyLiR0ZWFyT2ZmPW99ZnVuY3Rpb24gaW5zdGFsbFN0YXRpY1RlYXJPZmYoYSxi
+LGMsZCxlLGYsZyxoKXtyZXR1cm4gaW5zdGFsbFRlYXJPZmYoYSxiLHRydWUsZmFsc2UsYyxkLGUsZixn
+LGgpfWZ1bmN0aW9uIGluc3RhbGxJbnN0YW5jZVRlYXJPZmYoYSxiLGMsZCxlLGYsZyxoLGkpe3JldHVy
+biBpbnN0YWxsVGVhck9mZihhLGIsZmFsc2UsYyxkLGUsZixnLGgsaSl9ZnVuY3Rpb24gc2V0T3JVcGRh
+dGVJbnRlcmNlcHRvcnNCeVRhZyhhKXt2YXIgdD12LmludGVyY2VwdG9yc0J5VGFnCmlmKCF0KXt2Lmlu
+dGVyY2VwdG9yc0J5VGFnPWEKcmV0dXJufWNvcHlQcm9wZXJ0aWVzKGEsdCl9ZnVuY3Rpb24gc2V0T3JV
+cGRhdGVMZWFmVGFncyhhKXt2YXIgdD12LmxlYWZUYWdzCmlmKCF0KXt2LmxlYWZUYWdzPWEKcmV0dXJu
+fWNvcHlQcm9wZXJ0aWVzKGEsdCl9ZnVuY3Rpb24gdXBkYXRlVHlwZXMoYSl7dmFyIHQ9di50eXBlcwp2
+YXIgcz10Lmxlbmd0aAp0LnB1c2guYXBwbHkodCxhKQpyZXR1cm4gc31mdW5jdGlvbiB1cGRhdGVIb2xk
+ZXIoYSxiKXtjb3B5UHJvcGVydGllcyhiLGEpCnJldHVybiBhfXZhciBodW5rSGVscGVycz1mdW5jdGlv
+bigpe3ZhciB0PWZ1bmN0aW9uKGEsYixjLGQsZSl7cmV0dXJuIGZ1bmN0aW9uKGYsZyxoLGkpe3JldHVy
+biBpbnN0YWxsSW5zdGFuY2VUZWFyT2ZmKGYsZyxhLGIsYyxkLFtoXSxpLGUpfX0scz1mdW5jdGlvbihh
+LGIsYyxkKXtyZXR1cm4gZnVuY3Rpb24oZSxmLGcsaCl7cmV0dXJuIGluc3RhbGxTdGF0aWNUZWFyT2Zm
+KGUsZixhLGIsYyxbZ10saCxkKX19CnJldHVybntpbmhlcml0OmluaGVyaXQsaW5oZXJpdE1hbnk6aW5o
+ZXJpdE1hbnksbWl4aW46bWl4aW4saW5zdGFsbFN0YXRpY1RlYXJPZmY6aW5zdGFsbFN0YXRpY1RlYXJP
+ZmYsaW5zdGFsbEluc3RhbmNlVGVhck9mZjppbnN0YWxsSW5zdGFuY2VUZWFyT2ZmLF9pbnN0YW5jZV8w
+dTp0KDAsMCxudWxsLFsiJDAiXSwwKSxfaW5zdGFuY2VfMXU6dCgwLDEsbnVsbCxbIiQxIl0sMCksX2lu
+c3RhbmNlXzJ1OnQoMCwyLG51bGwsWyIkMiJdLDApLF9pbnN0YW5jZV8waTp0KDEsMCxudWxsLFsiJDAi
+XSwwKSxfaW5zdGFuY2VfMWk6dCgxLDEsbnVsbCxbIiQxIl0sMCksX2luc3RhbmNlXzJpOnQoMSwyLG51
+bGwsWyIkMiJdLDApLF9zdGF0aWNfMDpzKDAsbnVsbCxbIiQwIl0sMCksX3N0YXRpY18xOnMoMSxudWxs
+LFsiJDEiXSwwKSxfc3RhdGljXzI6cygyLG51bGwsWyIkMiJdLDApLG1ha2VDb25zdExpc3Q6bWFrZUNv
+bnN0TGlzdCxsYXp5OmxhenksdXBkYXRlSG9sZGVyOnVwZGF0ZUhvbGRlcixjb252ZXJ0VG9GYXN0T2Jq
+ZWN0OmNvbnZlcnRUb0Zhc3RPYmplY3Qsc2V0RnVuY3Rpb25OYW1lc0lmTmVjZXNzYXJ5OnNldEZ1bmN0
+aW9uTmFtZXNJZk5lY2Vzc2FyeSx1cGRhdGVUeXBlczp1cGRhdGVUeXBlcyxzZXRPclVwZGF0ZUludGVy
+Y2VwdG9yc0J5VGFnOnNldE9yVXBkYXRlSW50ZXJjZXB0b3JzQnlUYWcsc2V0T3JVcGRhdGVMZWFmVGFn
+czpzZXRPclVwZGF0ZUxlYWZUYWdzfX0oKQpmdW5jdGlvbiBpbml0aWFsaXplRGVmZXJyZWRIdW5rKGEp
+e3g9di50eXBlcy5sZW5ndGgKYShodW5rSGVscGVycyx2LHcsJCl9ZnVuY3Rpb24gZ2V0R2xvYmFsRnJv
+bU5hbWUoYSl7Zm9yKHZhciB0PTA7dDx3Lmxlbmd0aDt0Kyspe2lmKHdbdF09PUMpY29udGludWUKaWYo
+d1t0XVthXSlyZXR1cm4gd1t0XVthXX19dmFyIEM9e30sSD17aDA6ZnVuY3Rpb24gaDAoKXt9LApmdzpm
+dW5jdGlvbihhKXt2YXIgdCxzPWFeNDgKaWYoczw9OSlyZXR1cm4gcwp0PWF8MzIKaWYoOTc8PXQmJnQ8
+PTEwMilyZXR1cm4gdC04NwpyZXR1cm4tMX0sCmhQOmZ1bmN0aW9uKCl7cmV0dXJuIG5ldyBQLmJoKCJO
+byBlbGVtZW50Iil9LApqSTpmdW5jdGlvbigpe3JldHVybiBuZXcgUC5iaCgiVG9vIG1hbnkgZWxlbWVu
+dHMiKX0sCmN5OmZ1bmN0aW9uIGN5KGEpe3RoaXMuYT1hfSwKYkM6ZnVuY3Rpb24gYkMoKXt9LAphZTpm
+dW5jdGlvbiBhZSgpe30sCmFROmZ1bmN0aW9uIGFRKGEsYixjKXt2YXIgXz10aGlzCl8uYT1hCl8uYj1i
+Cl8uYz0wCl8uZD1udWxsCl8uJHRpPWN9LAphNDpmdW5jdGlvbiBhNChhLGIsYyl7dGhpcy5hPWEKdGhp
+cy5iPWIKdGhpcy4kdGk9Y30sCmFZOmZ1bmN0aW9uIGFZKGEsYixjKXt0aGlzLmE9YQp0aGlzLmI9Ygp0
+aGlzLiR0aT1jfSwKY186ZnVuY3Rpb24gY18oYSxiLGMpe3RoaXMuYT1hCnRoaXMuYj1iCnRoaXMuJHRp
+PWN9LApWOmZ1bmN0aW9uIFYoKXt9LAphWDpmdW5jdGlvbiBhWCgpe30sCmJsOmZ1bmN0aW9uIGJsKCl7
+fSwKYmk6ZnVuY3Rpb24gYmkoYSl7dGhpcy5hPWF9LApqQzpmdW5jdGlvbigpe3Rocm93IEguYShQLk4o
+IkNhbm5vdCBtb2RpZnkgdW5tb2RpZmlhYmxlIE1hcCIpKX0sCmlZOmZ1bmN0aW9uKGEpe3ZhciB0LHM9
+SC5pWChhKQppZih0eXBlb2Ygcz09InN0cmluZyIpcmV0dXJuIHMKdD0ibWluaWZpZWQ6IithCnJldHVy
+biB0fSwKbHg6ZnVuY3Rpb24oYSxiKXt2YXIgdAppZihiIT1udWxsKXt0PWIueAppZih0IT1udWxsKXJl
+dHVybiB0fXJldHVybiB1LmFVLmMoYSl9LApiOmZ1bmN0aW9uKGEpe3ZhciB0CmlmKHR5cGVvZiBhPT0i
+c3RyaW5nIilyZXR1cm4gYQppZih0eXBlb2YgYT09Im51bWJlciIpe2lmKGEhPT0wKXJldHVybiIiK2F9
+ZWxzZSBpZighMD09PWEpcmV0dXJuInRydWUiCmVsc2UgaWYoITE9PT1hKXJldHVybiJmYWxzZSIKZWxz
+ZSBpZihhPT1udWxsKXJldHVybiJudWxsIgp0PUouYjIoYSkKaWYodHlwZW9mIHQhPSJzdHJpbmciKXRo
+cm93IEguYShILmFzKGEpKQpyZXR1cm4gdH0sCmJWOmZ1bmN0aW9uKGEpe3ZhciB0PWEuJGlkZW50aXR5
+SGFzaAppZih0PT1udWxsKXt0PU1hdGgucmFuZG9tKCkqMHgzZmZmZmZmZnwwCmEuJGlkZW50aXR5SGFz
+aD10fXJldHVybiB0fSwKaDQ6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIscSxwLG89bnVsbCxuPS9eXHMq
+WystXT8oKDB4W2EtZjAtOV0rKXwoXGQrKXwoW2EtejAtOV0rKSlccyokL2kuZXhlYyhhKQppZihuPT1u
+dWxsKXJldHVybiBvCmlmKDM+PW4ubGVuZ3RoKXJldHVybiBILmkobiwzKQp0PUgubyhuWzNdKQppZihi
+PT1udWxsKXtpZih0IT1udWxsKXJldHVybiBwYXJzZUludChhLDEwKQppZihuWzJdIT1udWxsKXJldHVy
+biBwYXJzZUludChhLDE2KQpyZXR1cm4gb31pZihiPDJ8fGI+MzYpdGhyb3cgSC5hKFAuTChiLDIsMzYs
+InJhZGl4IixvKSkKaWYoYj09PTEwJiZ0IT1udWxsKXJldHVybiBwYXJzZUludChhLDEwKQppZihiPDEw
+fHx0PT1udWxsKXtzPWI8PTEwPzQ3K2I6ODYrYgpyPW5bMV0KZm9yKHE9ci5sZW5ndGgscD0wO3A8cTsr
+K3ApaWYoKEMuYS50KHIscCl8MzIpPnMpcmV0dXJuIG99cmV0dXJuIHBhcnNlSW50KGEsYil9LAplZjpm
+dW5jdGlvbihhKXt2YXIgdD1ILmpSKGEpCnJldHVybiB0fSwKalI6ZnVuY3Rpb24oYSl7dmFyIHQscyxy
+CmlmKGEgaW5zdGFuY2VvZiBQLnQpcmV0dXJuIEguUChILmE4KGEpLG51bGwpCmlmKEouYUUoYSk9PT1D
+LlB8fHUuYWsuYyhhKSl7dD1DLnEoYSkKaWYoSC5oWCh0KSlyZXR1cm4gdApzPWEuY29uc3RydWN0b3IK
+aWYodHlwZW9mIHM9PSJmdW5jdGlvbiIpe3I9cy5uYW1lCmlmKHR5cGVvZiByPT0ic3RyaW5nIiYmSC5o
+WChyKSlyZXR1cm4gcn19cmV0dXJuIEguUChILmE4KGEpLG51bGwpfSwKaFg6ZnVuY3Rpb24oYSl7dmFy
+IHQ9YSE9PSJPYmplY3QiJiZhIT09IiIKcmV0dXJuIHR9LApoVzpmdW5jdGlvbihhKXt2YXIgdCxzLHIs
+cSxwPWEubGVuZ3RoCmlmKHA8PTUwMClyZXR1cm4gU3RyaW5nLmZyb21DaGFyQ29kZS5hcHBseShudWxs
+LGEpCmZvcih0PSIiLHM9MDtzPHA7cz1yKXtyPXMrNTAwCnE9cjxwP3I6cAp0Kz1TdHJpbmcuZnJvbUNo
+YXJDb2RlLmFwcGx5KG51bGwsYS5zbGljZShzLHEpKX1yZXR1cm4gdH0sCmtfOmZ1bmN0aW9uKGEpe3Zh
+ciB0LHMscixxPUgubihbXSx1LnQpCmZvcih0PWEubGVuZ3RoLHM9MDtzPGEubGVuZ3RoO2EubGVuZ3Ro
+PT09dHx8KDAsSC5jcikoYSksKytzKXtyPWFbc10KaWYoIUguZEoocikpdGhyb3cgSC5hKEguYXMocikp
+CmlmKHI8PTY1NTM1KUMuYi5rKHEscikKZWxzZSBpZihyPD0xMTE0MTExKXtDLmIuayhxLDU1Mjk2KyhD
+LmMuWihyLTY1NTM2LDEwKSYxMDIzKSkKQy5iLmsocSw1NjMyMCsociYxMDIzKSl9ZWxzZSB0aHJvdyBI
+LmEoSC5hcyhyKSl9cmV0dXJuIEguaFcocSl9LApoWTpmdW5jdGlvbihhKXt2YXIgdCxzLHIKZm9yKHQ9
+YS5sZW5ndGgscz0wO3M8dDsrK3Mpe3I9YVtzXQppZighSC5kSihyKSl0aHJvdyBILmEoSC5hcyhyKSkK
+aWYocjwwKXRocm93IEguYShILmFzKHIpKQppZihyPjY1NTM1KXJldHVybiBILmtfKGEpfXJldHVybiBI
+LmhXKGEpfSwKazA6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMscixxCmlmKGM8PTUwMCYmYj09PTAmJmM9
+PT1hLmxlbmd0aClyZXR1cm4gU3RyaW5nLmZyb21DaGFyQ29kZS5hcHBseShudWxsLGEpCmZvcih0PWIs
+cz0iIjt0PGM7dD1yKXtyPXQrNTAwCnE9cjxjP3I6YwpzKz1TdHJpbmcuZnJvbUNoYXJDb2RlLmFwcGx5
+KG51bGwsYS5zdWJhcnJheSh0LHEpKX1yZXR1cm4gc30sCmRfOmZ1bmN0aW9uKGEpe3ZhciB0CmlmKDA8
+PWEpe2lmKGE8PTY1NTM1KXJldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlKGEpCmlmKGE8PTExMTQxMTEp
+e3Q9YS02NTUzNgpyZXR1cm4gU3RyaW5nLmZyb21DaGFyQ29kZSgoNTUyOTZ8Qy5jLloodCwxMCkpPj4+
+MCw1NjMyMHx0JjEwMjMpfX10aHJvdyBILmEoUC5MKGEsMCwxMTE0MTExLG51bGwsbnVsbCkpfSwKYVQ6
+ZnVuY3Rpb24oYSl7aWYoYS5kYXRlPT09dm9pZCAwKWEuZGF0ZT1uZXcgRGF0ZShhLmEpCnJldHVybiBh
+LmRhdGV9LApqWjpmdW5jdGlvbihhKXt2YXIgdD1ILmFUKGEpLmdldEZ1bGxZZWFyKCkrMApyZXR1cm4g
+dH0sCmpYOmZ1bmN0aW9uKGEpe3ZhciB0PUguYVQoYSkuZ2V0TW9udGgoKSsxCnJldHVybiB0fSwKalQ6
+ZnVuY3Rpb24oYSl7dmFyIHQ9SC5hVChhKS5nZXREYXRlKCkrMApyZXR1cm4gdH0sCmpVOmZ1bmN0aW9u
+KGEpe3ZhciB0PUguYVQoYSkuZ2V0SG91cnMoKSswCnJldHVybiB0fSwKalc6ZnVuY3Rpb24oYSl7dmFy
+IHQ9SC5hVChhKS5nZXRNaW51dGVzKCkrMApyZXR1cm4gdH0sCmpZOmZ1bmN0aW9uKGEpe3ZhciB0PUgu
+YVQoYSkuZ2V0U2Vjb25kcygpKzAKcmV0dXJuIHR9LApqVjpmdW5jdGlvbihhKXt2YXIgdD1ILmFUKGEp
+LmdldE1pbGxpc2Vjb25kcygpKzAKcmV0dXJuIHR9LApiZjpmdW5jdGlvbihhLGIsYyl7dmFyIHQscyxy
+PXt9CnIuYT0wCnQ9W10Kcz1bXQpyLmE9Yi5sZW5ndGgKQy5iLkkodCxiKQpyLmI9IiIKaWYoYyE9bnVs
+bCYmYy5hIT09MCljLkEoMCxuZXcgSC5lZShyLHMsdCkpCiIiK3IuYQpyZXR1cm4gSi5qcShhLG5ldyBI
+LmNKKEMuYTAsMCx0LHMsMCkpfSwKalM6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMscixxCmlmKGIgaW5z
+dGFuY2VvZiBBcnJheSl0PWM9PW51bGx8fGMuYT09PTAKZWxzZSB0PSExCmlmKHQpe3M9YgpyPXMubGVu
+Z3RoCmlmKHI9PT0wKXtpZighIWEuJDApcmV0dXJuIGEuJDAoKX1lbHNlIGlmKHI9PT0xKXtpZighIWEu
+JDEpcmV0dXJuIGEuJDEoc1swXSl9ZWxzZSBpZihyPT09Mil7aWYoISFhLiQyKXJldHVybiBhLiQyKHNb
+MF0sc1sxXSl9ZWxzZSBpZihyPT09Myl7aWYoISFhLiQzKXJldHVybiBhLiQzKHNbMF0sc1sxXSxzWzJd
+KX1lbHNlIGlmKHI9PT00KXtpZighIWEuJDQpcmV0dXJuIGEuJDQoc1swXSxzWzFdLHNbMl0sc1szXSl9
+ZWxzZSBpZihyPT09NSlpZighIWEuJDUpcmV0dXJuIGEuJDUoc1swXSxzWzFdLHNbMl0sc1szXSxzWzRd
+KQpxPWFbIiIrIiQiK3JdCmlmKHEhPW51bGwpcmV0dXJuIHEuYXBwbHkoYSxzKX1yZXR1cm4gSC5qUShh
+LGIsYyl9LApqUTpmdW5jdGlvbihhLGIsYyl7dmFyIHQscyxyLHEscCxvLG4sbSxsLGs9YiBpbnN0YW5j
+ZW9mIEFycmF5P2I6UC5oMihiLCEwLHUueiksaj1rLmxlbmd0aCxpPWEuJFIKaWYoajxpKXJldHVybiBI
+LmJmKGEsayxjKQp0PWEuJEQKcz10PT1udWxsCnI9IXM/dCgpOm51bGwKcT1KLmFFKGEpCnA9cS4kQwpp
+Zih0eXBlb2YgcD09InN0cmluZyIpcD1xW3BdCmlmKHMpe2lmKGMhPW51bGwmJmMuYSE9PTApcmV0dXJu
+IEguYmYoYSxrLGMpCmlmKGo9PT1pKXJldHVybiBwLmFwcGx5KGEsaykKcmV0dXJuIEguYmYoYSxrLGMp
+fWlmKHIgaW5zdGFuY2VvZiBBcnJheSl7aWYoYyE9bnVsbCYmYy5hIT09MClyZXR1cm4gSC5iZihhLGss
+YykKaWYoaj5pK3IubGVuZ3RoKXJldHVybiBILmJmKGEsayxudWxsKQpDLmIuSShrLHIuc2xpY2Uoai1p
+KSkKcmV0dXJuIHAuYXBwbHkoYSxrKX1lbHNle2lmKGo+aSlyZXR1cm4gSC5iZihhLGssYykKbz1PYmpl
+Y3Qua2V5cyhyKQppZihjPT1udWxsKWZvcihzPW8ubGVuZ3RoLG49MDtuPG8ubGVuZ3RoO28ubGVuZ3Ro
+PT09c3x8KDAsSC5jcikobyksKytuKUMuYi5rKGsscltILm8ob1tuXSldKQplbHNle2ZvcihzPW8ubGVu
+Z3RoLG09MCxuPTA7bjxvLmxlbmd0aDtvLmxlbmd0aD09PXN8fCgwLEguY3IpKG8pLCsrbil7bD1ILm8o
+b1tuXSkKaWYoYy5hXyhsKSl7KyttCkMuYi5rKGssYy5qKDAsbCkpfWVsc2UgQy5iLmsoayxyW2xdKX1p
+ZihtIT09Yy5hKXJldHVybiBILmJmKGEsayxjKX1yZXR1cm4gcC5hcHBseShhLGspfX0sCmFqOmZ1bmN0
+aW9uKGEpe3Rocm93IEguYShILmFzKGEpKX0sCmk6ZnVuY3Rpb24oYSxiKXtpZihhPT1udWxsKUouYXQo
+YSkKdGhyb3cgSC5hKEguYjEoYSxiKSl9LApiMTpmdW5jdGlvbihhLGIpe3ZhciB0LHMscj0iaW5kZXgi
+CmlmKCFILmRKKGIpKXJldHVybiBuZXcgUC5hMSghMCxiLHIsbnVsbCkKdD1ILngoSi5hdChhKSkKaWYo
+IShiPDApKXtpZih0eXBlb2YgdCE9PSJudW1iZXIiKXJldHVybiBILmFqKHQpCnM9Yj49dH1lbHNlIHM9
+ITAKaWYocylyZXR1cm4gUC5lNShiLGEscixudWxsLHQpCnJldHVybiBQLmVnKGIscil9LApsbDpmdW5j
+dGlvbihhLGIsYyl7dmFyIHQ9IkludmFsaWQgdmFsdWUiCmlmKGE+YylyZXR1cm4gbmV3IFAuYVUoMCxj
+LCEwLGEsInN0YXJ0Iix0KQppZihiIT1udWxsKWlmKGI8YXx8Yj5jKXJldHVybiBuZXcgUC5hVShhLGMs
+ITAsYiwiZW5kIix0KQpyZXR1cm4gbmV3IFAuYTEoITAsYiwiZW5kIixudWxsKX0sCmFzOmZ1bmN0aW9u
+KGEpe3JldHVybiBuZXcgUC5hMSghMCxhLG51bGwsbnVsbCl9LAphOmZ1bmN0aW9uKGEpe3ZhciB0Cmlm
+KGE9PW51bGwpYT1uZXcgUC5iZCgpCnQ9bmV3IEVycm9yKCkKdC5kYXJ0RXhjZXB0aW9uPWEKaWYoImRl
+ZmluZVByb3BlcnR5IiBpbiBPYmplY3Qpe09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJtZXNzYWdlIix7
+Z2V0OkguaVd9KQp0Lm5hbWU9IiJ9ZWxzZSB0LnRvU3RyaW5nPUguaVcKcmV0dXJuIHR9LAppVzpmdW5j
+dGlvbigpe3JldHVybiBKLmIyKHRoaXMuZGFydEV4Y2VwdGlvbil9LAphazpmdW5jdGlvbihhKXt0aHJv
+dyBILmEoYSl9LApjcjpmdW5jdGlvbihhKXt0aHJvdyBILmEoUC5hdihhKSl9LAphbzpmdW5jdGlvbihh
+KXt2YXIgdCxzLHIscSxwLG8KYT1ILmxEKGEucmVwbGFjZShTdHJpbmcoe30pLCckcmVjZWl2ZXIkJykp
+CnQ9YS5tYXRjaCgvXFxcJFthLXpBLVpdK1xcXCQvZykKaWYodD09bnVsbCl0PUgubihbXSx1LnMpCnM9
+dC5pbmRleE9mKCJcXCRhcmd1bWVudHNcXCQiKQpyPXQuaW5kZXhPZigiXFwkYXJndW1lbnRzRXhwclxc
+JCIpCnE9dC5pbmRleE9mKCJcXCRleHByXFwkIikKcD10LmluZGV4T2YoIlxcJG1ldGhvZFxcJCIpCm89
+dC5pbmRleE9mKCJcXCRyZWNlaXZlclxcJCIpCnJldHVybiBuZXcgSC5laihhLnJlcGxhY2UobmV3IFJl
+Z0V4cCgnXFxcXFxcJGFyZ3VtZW50c1xcXFxcXCQnLCdnJyksJygoPzp4fFteeF0pKiknKS5yZXBsYWNl
+KG5ldyBSZWdFeHAoJ1xcXFxcXCRhcmd1bWVudHNFeHByXFxcXFxcJCcsJ2cnKSwnKCg/Onh8W154XSkq
+KScpLnJlcGxhY2UobmV3IFJlZ0V4cCgnXFxcXFxcJGV4cHJcXFxcXFwkJywnZycpLCcoKD86eHxbXnhd
+KSopJykucmVwbGFjZShuZXcgUmVnRXhwKCdcXFxcXFwkbWV0aG9kXFxcXFxcJCcsJ2cnKSwnKCg/Onh8
+W154XSkqKScpLnJlcGxhY2UobmV3IFJlZ0V4cCgnXFxcXFxcJHJlY2VpdmVyXFxcXFxcJCcsJ2cnKSwn
+KCg/Onh8W154XSkqKScpLHMscixxLHAsbyl9LAplazpmdW5jdGlvbihhKXtyZXR1cm4gZnVuY3Rpb24o
+JGV4cHIkKXt2YXIgJGFyZ3VtZW50c0V4cHIkPSckYXJndW1lbnRzJCcKdHJ5eyRleHByJC4kbWV0aG9k
+JCgkYXJndW1lbnRzRXhwciQpfWNhdGNoKHQpe3JldHVybiB0Lm1lc3NhZ2V9fShhKX0sCmkzOmZ1bmN0
+aW9uKGEpe3JldHVybiBmdW5jdGlvbigkZXhwciQpe3RyeXskZXhwciQuJG1ldGhvZCR9Y2F0Y2godCl7
+cmV0dXJuIHQubWVzc2FnZX19KGEpfSwKaFY6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gbmV3IEguY1YoYSxi
+PT1udWxsP251bGw6Yi5tZXRob2QpfSwKaDE6ZnVuY3Rpb24oYSxiKXt2YXIgdD1iPT1udWxsLHM9dD9u
+dWxsOmIubWV0aG9kCnJldHVybiBuZXcgSC5jTChhLHMsdD9udWxsOmIucmVjZWl2ZXIpfSwKUTpmdW5j
+dGlvbihhKXt2YXIgdCxzLHIscSxwLG8sbixtLGwsayxqLGksaCxnLGY9bnVsbCxlPW5ldyBILmZSKGEp
+CmlmKGE9PW51bGwpcmV0dXJuIGYKaWYodHlwZW9mIGEhPT0ib2JqZWN0IilyZXR1cm4gYQppZigiZGFy
+dEV4Y2VwdGlvbiIgaW4gYSlyZXR1cm4gZS4kMShhLmRhcnRFeGNlcHRpb24pCmVsc2UgaWYoISgibWVz
+c2FnZSIgaW4gYSkpcmV0dXJuIGEKdD1hLm1lc3NhZ2UKaWYoIm51bWJlciIgaW4gYSYmdHlwZW9mIGEu
+bnVtYmVyPT0ibnVtYmVyIil7cz1hLm51bWJlcgpyPXMmNjU1MzUKaWYoKEMuYy5aKHMsMTYpJjgxOTEp
+PT09MTApc3dpdGNoKHIpe2Nhc2UgNDM4OnJldHVybiBlLiQxKEguaDEoSC5iKHQpKyIgKEVycm9yICIr
+cisiKSIsZikpCmNhc2UgNDQ1OmNhc2UgNTAwNzpyZXR1cm4gZS4kMShILmhWKEguYih0KSsiIChFcnJv
+ciAiK3IrIikiLGYpKX19aWYoYSBpbnN0YW5jZW9mIFR5cGVFcnJvcil7cT0kLmoyKCkKcD0kLmozKCkK
+bz0kLmo0KCkKbj0kLmo1KCkKbT0kLmo4KCkKbD0kLmo5KCkKaz0kLmo3KCkKJC5qNigpCmo9JC5qYigp
+Cmk9JC5qYSgpCmg9cS5MKHQpCmlmKGghPW51bGwpcmV0dXJuIGUuJDEoSC5oMShILm8odCksaCkpCmVs
+c2V7aD1wLkwodCkKaWYoaCE9bnVsbCl7aC5tZXRob2Q9ImNhbGwiCnJldHVybiBlLiQxKEguaDEoSC5v
+KHQpLGgpKX1lbHNle2g9by5MKHQpCmlmKGg9PW51bGwpe2g9bi5MKHQpCmlmKGg9PW51bGwpe2g9bS5M
+KHQpCmlmKGg9PW51bGwpe2g9bC5MKHQpCmlmKGg9PW51bGwpe2g9ay5MKHQpCmlmKGg9PW51bGwpe2g9
+bi5MKHQpCmlmKGg9PW51bGwpe2g9ai5MKHQpCmlmKGg9PW51bGwpe2g9aS5MKHQpCmc9aCE9bnVsbH1l
+bHNlIGc9ITB9ZWxzZSBnPSEwfWVsc2UgZz0hMH1lbHNlIGc9ITB9ZWxzZSBnPSEwfWVsc2UgZz0hMH1l
+bHNlIGc9ITAKaWYoZylyZXR1cm4gZS4kMShILmhWKEgubyh0KSxoKSl9fXJldHVybiBlLiQxKG5ldyBI
+LmRhKHR5cGVvZiB0PT0ic3RyaW5nIj90OiIiKSl9aWYoYSBpbnN0YW5jZW9mIFJhbmdlRXJyb3Ipe2lm
+KHR5cGVvZiB0PT0ic3RyaW5nIiYmdC5pbmRleE9mKCJjYWxsIHN0YWNrIikhPT0tMSlyZXR1cm4gbmV3
+IFAuYlgoKQp0PWZ1bmN0aW9uKGIpe3RyeXtyZXR1cm4gU3RyaW5nKGIpfWNhdGNoKGQpe31yZXR1cm4g
+bnVsbH0oYSkKcmV0dXJuIGUuJDEobmV3IFAuYTEoITEsZixmLHR5cGVvZiB0PT0ic3RyaW5nIj90LnJl
+cGxhY2UoL15SYW5nZUVycm9yOlxzKi8sIiIpOnQpKX1pZih0eXBlb2YgSW50ZXJuYWxFcnJvcj09ImZ1
+bmN0aW9uIiYmYSBpbnN0YW5jZW9mIEludGVybmFsRXJyb3IpaWYodHlwZW9mIHQ9PSJzdHJpbmciJiZ0
+PT09InRvbyBtdWNoIHJlY3Vyc2lvbiIpcmV0dXJuIG5ldyBQLmJYKCkKcmV0dXJuIGF9LApjcDpmdW5j
+dGlvbihhKXt2YXIgdAppZihhPT1udWxsKXJldHVybiBuZXcgSC5jZyhhKQp0PWEuJGNhY2hlZFRyYWNl
+CmlmKHQhPW51bGwpcmV0dXJuIHQKcmV0dXJuIGEuJGNhY2hlZFRyYWNlPW5ldyBILmNnKGEpfSwKbG06
+ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIscT1hLmxlbmd0aApmb3IodD0wO3Q8cTt0PXIpe3M9dCsxCnI9
+cysxCmIubCgwLGFbdF0sYVtzXSl9cmV0dXJuIGJ9LApsdzpmdW5jdGlvbihhLGIsYyxkLGUsZil7dS5a
+LmIoYSkKc3dpdGNoKEgueChiKSl7Y2FzZSAwOnJldHVybiBhLiQwKCkKY2FzZSAxOnJldHVybiBhLiQx
+KGMpCmNhc2UgMjpyZXR1cm4gYS4kMihjLGQpCmNhc2UgMzpyZXR1cm4gYS4kMyhjLGQsZSkKY2FzZSA0
+OnJldHVybiBhLiQ0KGMsZCxlLGYpfXRocm93IEguYShuZXcgUC5lQSgiVW5zdXBwb3J0ZWQgbnVtYmVy
+IG9mIGFyZ3VtZW50cyBmb3Igd3JhcHBlZCBjbG9zdXJlIikpfSwKZE06ZnVuY3Rpb24oYSxiKXt2YXIg
+dAppZihhPT1udWxsKXJldHVybiBudWxsCnQ9YS4kaWRlbnRpdHkKaWYoISF0KXJldHVybiB0CnQ9ZnVu
+Y3Rpb24oYyxkLGUpe3JldHVybiBmdW5jdGlvbihmLGcsaCxpKXtyZXR1cm4gZShjLGQsZixnLGgsaSl9
+fShhLGIsSC5sdykKYS4kaWRlbnRpdHk9dApyZXR1cm4gdH0sCmpCOmZ1bmN0aW9uKGEsYixjLGQsZSxm
+LGcpe3ZhciB0LHMscixxLHAsbyxuLG0sbD1udWxsLGs9YlswXSxqPWsuJGNhbGxOYW1lLGk9ZT9PYmpl
+Y3QuY3JlYXRlKG5ldyBILmQzKCkuY29uc3RydWN0b3IucHJvdG90eXBlKTpPYmplY3QuY3JlYXRlKG5l
+dyBILmI2KGwsbCxsLGwpLmNvbnN0cnVjdG9yLnByb3RvdHlwZSkKaS4kaW5pdGlhbGl6ZT1pLmNvbnN0
+cnVjdG9yCmlmKGUpdD1mdW5jdGlvbiBzdGF0aWNfdGVhcl9vZmYoKXt0aGlzLiRpbml0aWFsaXplKCl9
+CmVsc2V7cz0kLmFtCmlmKHR5cGVvZiBzIT09Im51bWJlciIpcmV0dXJuIHMuQigpCiQuYW09cysxCnM9
+bmV3IEZ1bmN0aW9uKCJhLGIsYyxkIitzLCJ0aGlzLiRpbml0aWFsaXplKGEsYixjLGQiK3MrIikiKQp0
+PXN9aS5jb25zdHJ1Y3Rvcj10CnQucHJvdG90eXBlPWkKaWYoIWUpe3I9SC5oTChhLGssZikKci4kcmVm
+bGVjdGlvbkluZm89ZH1lbHNle2kuJHN0YXRpY19uYW1lPWcKcj1rfXE9SC5qeChkLGUsZikKaS4kUz1x
+Cmlbal09cgpmb3IocD1yLG89MTtvPGIubGVuZ3RoOysrbyl7bj1iW29dCm09bi4kY2FsbE5hbWUKaWYo
+bSE9bnVsbCl7bj1lP246SC5oTChhLG4sZikKaVttXT1ufWlmKG89PT1jKXtuLiRyZWZsZWN0aW9uSW5m
+bz1kCnA9bn19aS4kQz1wCmkuJFI9ay4kUgppLiREPWsuJEQKcmV0dXJuIHR9LApqeDpmdW5jdGlvbihh
+LGIsYyl7dmFyIHQKaWYodHlwZW9mIGE9PSJudW1iZXIiKXJldHVybiBmdW5jdGlvbihkLGUpe3JldHVy
+biBmdW5jdGlvbigpe3JldHVybiBkKGUpfX0oSC5pTCxhKQppZih0eXBlb2YgYT09InN0cmluZyIpe2lm
+KGIpdGhyb3cgSC5hKCJDYW5ub3QgY29tcHV0ZSBzaWduYXR1cmUgZm9yIHN0YXRpYyB0ZWFyb2ZmLiIp
+CnQ9Yz9ILmp2OkguanUKcmV0dXJuIGZ1bmN0aW9uKGQsZSl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJu
+IGUodGhpcyxkKX19KGEsdCl9dGhyb3cgSC5hKCJFcnJvciBpbiBmdW5jdGlvblR5cGUgb2YgdGVhcm9m
+ZiIpfSwKank6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIHQ9SC5oSwpzd2l0Y2goYj8tMTphKXtjYXNlIDA6
+cmV0dXJuIGZ1bmN0aW9uKGUsZil7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuIGYodGhpcylbZV0oKX19
+KGMsdCkKY2FzZSAxOnJldHVybiBmdW5jdGlvbihlLGYpe3JldHVybiBmdW5jdGlvbihnKXtyZXR1cm4g
+Zih0aGlzKVtlXShnKX19KGMsdCkKY2FzZSAyOnJldHVybiBmdW5jdGlvbihlLGYpe3JldHVybiBmdW5j
+dGlvbihnLGgpe3JldHVybiBmKHRoaXMpW2VdKGcsaCl9fShjLHQpCmNhc2UgMzpyZXR1cm4gZnVuY3Rp
+b24oZSxmKXtyZXR1cm4gZnVuY3Rpb24oZyxoLGkpe3JldHVybiBmKHRoaXMpW2VdKGcsaCxpKX19KGMs
+dCkKY2FzZSA0OnJldHVybiBmdW5jdGlvbihlLGYpe3JldHVybiBmdW5jdGlvbihnLGgsaSxqKXtyZXR1
+cm4gZih0aGlzKVtlXShnLGgsaSxqKX19KGMsdCkKY2FzZSA1OnJldHVybiBmdW5jdGlvbihlLGYpe3Jl
+dHVybiBmdW5jdGlvbihnLGgsaSxqLGspe3JldHVybiBmKHRoaXMpW2VdKGcsaCxpLGosayl9fShjLHQp
+CmRlZmF1bHQ6cmV0dXJuIGZ1bmN0aW9uKGUsZil7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuIGUuYXBw
+bHkoZih0aGlzKSxhcmd1bWVudHMpfX0oZCx0KX19LApoTDpmdW5jdGlvbihhLGIsYyl7dmFyIHQscyxy
+LHEscCxvLG4KaWYoYylyZXR1cm4gSC5qQShhLGIpCnQ9Yi4kc3R1Yk5hbWUKcz1iLmxlbmd0aApyPWFb
+dF0KcT1iPT1udWxsP3I9PW51bGw6Yj09PXIKcD0hcXx8cz49MjcKaWYocClyZXR1cm4gSC5qeShzLCFx
+LHQsYikKaWYocz09PTApe3E9JC5hbQppZih0eXBlb2YgcSE9PSJudW1iZXIiKXJldHVybiBxLkIoKQok
+LmFtPXErMQpvPSJzZWxmIitxCnE9InJldHVybiBmdW5jdGlvbigpe3ZhciAiK28rIiA9IHRoaXMuIgpw
+PSQuYngKcmV0dXJuIG5ldyBGdW5jdGlvbihxK0guYihwPT1udWxsPyQuYng9SC5kUygic2VsZiIpOnAp
+KyI7cmV0dXJuICIrbysiLiIrSC5iKHQpKyIoKTt9IikoKX1uPSJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2
+d3h5eiIuc3BsaXQoIiIpLnNwbGljZSgwLHMpLmpvaW4oIiwiKQpxPSQuYW0KaWYodHlwZW9mIHEhPT0i
+bnVtYmVyIilyZXR1cm4gcS5CKCkKJC5hbT1xKzEKbis9cQpxPSJyZXR1cm4gZnVuY3Rpb24oIituKyIp
+e3JldHVybiB0aGlzLiIKcD0kLmJ4CnJldHVybiBuZXcgRnVuY3Rpb24ocStILmIocD09bnVsbD8kLmJ4
+PUguZFMoInNlbGYiKTpwKSsiLiIrSC5iKHQpKyIoIituKyIpO30iKSgpfSwKano6ZnVuY3Rpb24oYSxi
+LGMsZCl7dmFyIHQ9SC5oSyxzPUguancKc3dpdGNoKGI/LTE6YSl7Y2FzZSAwOnRocm93IEguYShILmsz
+KCJJbnRlcmNlcHRlZCBmdW5jdGlvbiB3aXRoIG5vIGFyZ3VtZW50cy4iKSkKY2FzZSAxOnJldHVybiBm
+dW5jdGlvbihlLGYsZyl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuIGYodGhpcylbZV0oZyh0aGlzKSl9
+fShjLHQscykKY2FzZSAyOnJldHVybiBmdW5jdGlvbihlLGYsZyl7cmV0dXJuIGZ1bmN0aW9uKGgpe3Jl
+dHVybiBmKHRoaXMpW2VdKGcodGhpcyksaCl9fShjLHQscykKY2FzZSAzOnJldHVybiBmdW5jdGlvbihl
+LGYsZyl7cmV0dXJuIGZ1bmN0aW9uKGgsaSl7cmV0dXJuIGYodGhpcylbZV0oZyh0aGlzKSxoLGkpfX0o
+Yyx0LHMpCmNhc2UgNDpyZXR1cm4gZnVuY3Rpb24oZSxmLGcpe3JldHVybiBmdW5jdGlvbihoLGksail7
+cmV0dXJuIGYodGhpcylbZV0oZyh0aGlzKSxoLGksail9fShjLHQscykKY2FzZSA1OnJldHVybiBmdW5j
+dGlvbihlLGYsZyl7cmV0dXJuIGZ1bmN0aW9uKGgsaSxqLGspe3JldHVybiBmKHRoaXMpW2VdKGcodGhp
+cyksaCxpLGosayl9fShjLHQscykKY2FzZSA2OnJldHVybiBmdW5jdGlvbihlLGYsZyl7cmV0dXJuIGZ1
+bmN0aW9uKGgsaSxqLGssbCl7cmV0dXJuIGYodGhpcylbZV0oZyh0aGlzKSxoLGksaixrLGwpfX0oYyx0
+LHMpCmRlZmF1bHQ6cmV0dXJuIGZ1bmN0aW9uKGUsZixnLGgpe3JldHVybiBmdW5jdGlvbigpe2g9W2co
+dGhpcyldCkFycmF5LnByb3RvdHlwZS5wdXNoLmFwcGx5KGgsYXJndW1lbnRzKQpyZXR1cm4gZS5hcHBs
+eShmKHRoaXMpLGgpfX0oZCx0LHMpfX0sCmpBOmZ1bmN0aW9uKGEsYil7dmFyIHQscyxyLHEscCxvLG4s
+bT0kLmJ4CmlmKG09PW51bGwpbT0kLmJ4PUguZFMoInNlbGYiKQp0PSQuaEoKaWYodD09bnVsbCl0PSQu
+aEo9SC5kUygicmVjZWl2ZXIiKQpzPWIuJHN0dWJOYW1lCnI9Yi5sZW5ndGgKcT1hW3NdCnA9Yj09bnVs
+bD9xPT1udWxsOmI9PT1xCm89IXB8fHI+PTI4CmlmKG8pcmV0dXJuIEguanoociwhcCxzLGIpCmlmKHI9
+PT0xKXttPSJyZXR1cm4gZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy4iK0guYihtKSsiLiIrSC5iKHMpKyIo
+dGhpcy4iK0guYih0KSsiKTsiCnQ9JC5hbQppZih0eXBlb2YgdCE9PSJudW1iZXIiKXJldHVybiB0LkIo
+KQokLmFtPXQrMQpyZXR1cm4gbmV3IEZ1bmN0aW9uKG0rdCsifSIpKCl9bj0iYWJjZGVmZ2hpamtsbW5v
+cHFyc3R1dnd4eXoiLnNwbGl0KCIiKS5zcGxpY2UoMCxyLTEpLmpvaW4oIiwiKQptPSJyZXR1cm4gZnVu
+Y3Rpb24oIituKyIpe3JldHVybiB0aGlzLiIrSC5iKG0pKyIuIitILmIocykrIih0aGlzLiIrSC5iKHQp
+KyIsICIrbisiKTsiCnQ9JC5hbQppZih0eXBlb2YgdCE9PSJudW1iZXIiKXJldHVybiB0LkIoKQokLmFt
+PXQrMQpyZXR1cm4gbmV3IEZ1bmN0aW9uKG0rdCsifSIpKCl9LApocDpmdW5jdGlvbihhLGIsYyxkLGUs
+ZixnKXtyZXR1cm4gSC5qQihhLGIsYyxkLCEhZSwhIWYsZyl9LApqdTpmdW5jdGlvbihhLGIpe3JldHVy
+biBILmRGKHYudHlwZVVuaXZlcnNlLEguYTgoYS5hKSxiKX0sCmp2OmZ1bmN0aW9uKGEsYil7cmV0dXJu
+IEguZEYodi50eXBlVW5pdmVyc2UsSC5hOChhLmMpLGIpfSwKaEs6ZnVuY3Rpb24oYSl7cmV0dXJuIGEu
+YX0sCmp3OmZ1bmN0aW9uKGEpe3JldHVybiBhLmN9LApkUzpmdW5jdGlvbihhKXt2YXIgdCxzLHIscT1u
+ZXcgSC5iNigic2VsZiIsInRhcmdldCIsInJlY2VpdmVyIiwibmFtZSIpLHA9Si5qSihPYmplY3QuZ2V0
+T3duUHJvcGVydHlOYW1lcyhxKSkKZm9yKHQ9cC5sZW5ndGgscz0wO3M8dDsrK3Mpe3I9cFtzXQppZihx
+W3JdPT09YSlyZXR1cm4gcn19LApkSzpmdW5jdGlvbihhKXtpZihhPT1udWxsKUgubGcoImJvb2xlYW4g
+ZXhwcmVzc2lvbiBtdXN0IG5vdCBiZSBudWxsIikKcmV0dXJuIGF9LApsZzpmdW5jdGlvbihhKXt0aHJv
+dyBILmEobmV3IEguZGcoYSkpfSwKbEc6ZnVuY3Rpb24oYSl7dGhyb3cgSC5hKG5ldyBQLmNCKGEpKX0s
+CmszOmZ1bmN0aW9uKGEpe3JldHVybiBuZXcgSC5kMChhKX0sCmhyOmZ1bmN0aW9uKGEpe3JldHVybiB2
+LmdldElzb2xhdGVUYWcoYSl9LApuOmZ1bmN0aW9uKGEsYil7YS4kdGk9YgpyZXR1cm4gYX0sCmlKOmZ1
+bmN0aW9uKGEpe2lmKGE9PW51bGwpcmV0dXJuIG51bGwKcmV0dXJuIGEuJHRpfSwKbXY6ZnVuY3Rpb24o
+YSxiLGMpe3JldHVybiBILmlWKGFbIiRhIitILmIoYyldLEguaUooYikpfSwKaVY6ZnVuY3Rpb24oYSxi
+KXtpZihhPT1udWxsKXJldHVybiBiCmE9YS5hcHBseShudWxsLGIpCmlmKGE9PW51bGwpcmV0dXJuIG51
+bGwKaWYoQXJyYXkuaXNBcnJheShhKSlyZXR1cm4gYQppZih0eXBlb2YgYT09ImZ1bmN0aW9uIilyZXR1
+cm4gYS5hcHBseShudWxsLGIpCnJldHVybiBifSwKbXQ6ZnVuY3Rpb24oYSxiLGMpe3JldHVybiBhLmFw
+cGx5KGIsSC5pVihKLmFFKGIpWyIkYSIrSC5iKGMpXSxILmlKKGIpKSl9LAptdTpmdW5jdGlvbihhLGIs
+Yyl7T2JqZWN0LmRlZmluZVByb3BlcnR5KGEsYix7dmFsdWU6YyxlbnVtZXJhYmxlOmZhbHNlLHdyaXRh
+YmxlOnRydWUsY29uZmlndXJhYmxlOnRydWV9KX0sCmxCOmZ1bmN0aW9uKGEpe3ZhciB0LHMscixxLHA9
+SC5vKCQuaUsuJDEoYSkpLG89JC5mb1twXQppZihvIT1udWxsKXtPYmplY3QuZGVmaW5lUHJvcGVydHko
+YSx2LmRpc3BhdGNoUHJvcGVydHlOYW1lLHt2YWx1ZTpvLGVudW1lcmFibGU6ZmFsc2Usd3JpdGFibGU6
+dHJ1ZSxjb25maWd1cmFibGU6dHJ1ZX0pCnJldHVybiBvLml9dD0kLmZCW3BdCmlmKHQhPW51bGwpcmV0
+dXJuIHQKcz12LmludGVyY2VwdG9yc0J5VGFnW3BdCmlmKHM9PW51bGwpe3A9SC5vKCQuaUguJDIoYSxw
+KSkKaWYocCE9bnVsbCl7bz0kLmZvW3BdCmlmKG8hPW51bGwpe09iamVjdC5kZWZpbmVQcm9wZXJ0eShh
+LHYuZGlzcGF0Y2hQcm9wZXJ0eU5hbWUse3ZhbHVlOm8sZW51bWVyYWJsZTpmYWxzZSx3cml0YWJsZTp0
+cnVlLGNvbmZpZ3VyYWJsZTp0cnVlfSkKcmV0dXJuIG8uaX10PSQuZkJbcF0KaWYodCE9bnVsbClyZXR1
+cm4gdApzPXYuaW50ZXJjZXB0b3JzQnlUYWdbcF19fWlmKHM9PW51bGwpcmV0dXJuIG51bGwKdD1zLnBy
+b3RvdHlwZQpyPXBbMF0KaWYocj09PSIhIil7bz1ILmZPKHQpCiQuZm9bcF09bwpPYmplY3QuZGVmaW5l
+UHJvcGVydHkoYSx2LmRpc3BhdGNoUHJvcGVydHlOYW1lLHt2YWx1ZTpvLGVudW1lcmFibGU6ZmFsc2Us
+d3JpdGFibGU6dHJ1ZSxjb25maWd1cmFibGU6dHJ1ZX0pCnJldHVybiBvLml9aWYocj09PSJ+Iil7JC5m
+QltwXT10CnJldHVybiB0fWlmKHI9PT0iLSIpe3E9SC5mTyh0KQpPYmplY3QuZGVmaW5lUHJvcGVydHko
+T2JqZWN0LmdldFByb3RvdHlwZU9mKGEpLHYuZGlzcGF0Y2hQcm9wZXJ0eU5hbWUse3ZhbHVlOnEsZW51
+bWVyYWJsZTpmYWxzZSx3cml0YWJsZTp0cnVlLGNvbmZpZ3VyYWJsZTp0cnVlfSkKcmV0dXJuIHEuaX1p
+ZihyPT09IisiKXJldHVybiBILmlTKGEsdCkKaWYocj09PSIqIil0aHJvdyBILmEoUC5lbChwKSkKaWYo
+di5sZWFmVGFnc1twXT09PXRydWUpe3E9SC5mTyh0KQpPYmplY3QuZGVmaW5lUHJvcGVydHkoT2JqZWN0
+LmdldFByb3RvdHlwZU9mKGEpLHYuZGlzcGF0Y2hQcm9wZXJ0eU5hbWUse3ZhbHVlOnEsZW51bWVyYWJs
+ZTpmYWxzZSx3cml0YWJsZTp0cnVlLGNvbmZpZ3VyYWJsZTp0cnVlfSkKcmV0dXJuIHEuaX1lbHNlIHJl
+dHVybiBILmlTKGEsdCl9LAppUzpmdW5jdGlvbihhLGIpe3ZhciB0PU9iamVjdC5nZXRQcm90b3R5cGVP
+ZihhKQpPYmplY3QuZGVmaW5lUHJvcGVydHkodCx2LmRpc3BhdGNoUHJvcGVydHlOYW1lLHt2YWx1ZTpK
+Lmh2KGIsdCxudWxsLG51bGwpLGVudW1lcmFibGU6ZmFsc2Usd3JpdGFibGU6dHJ1ZSxjb25maWd1cmFi
+bGU6dHJ1ZX0pCnJldHVybiBifSwKZk86ZnVuY3Rpb24oYSl7cmV0dXJuIEouaHYoYSwhMSxudWxsLCEh
+YS4kaUopfSwKbEM6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0PWIucHJvdG90eXBlCmlmKHYubGVhZlRhZ3Nb
+YV09PT10cnVlKXJldHVybiBILmZPKHQpCmVsc2UgcmV0dXJuIEouaHYodCxjLG51bGwsbnVsbCl9LAps
+dTpmdW5jdGlvbigpe2lmKCEwPT09JC5ocylyZXR1cm4KJC5ocz0hMApILmx2KCl9LApsdjpmdW5jdGlv
+bigpe3ZhciB0LHMscixxLHAsbyxuLG0KJC5mbz1PYmplY3QuY3JlYXRlKG51bGwpCiQuZkI9T2JqZWN0
+LmNyZWF0ZShudWxsKQpILmx0KCkKdD12LmludGVyY2VwdG9yc0J5VGFnCnM9T2JqZWN0LmdldE93blBy
+b3BlcnR5TmFtZXModCkKaWYodHlwZW9mIHdpbmRvdyE9InVuZGVmaW5lZCIpe3dpbmRvdwpyPWZ1bmN0
+aW9uKCl7fQpmb3IocT0wO3E8cy5sZW5ndGg7KytxKXtwPXNbcV0Kbz0kLmlULiQxKHApCmlmKG8hPW51
+bGwpe249SC5sQyhwLHRbcF0sbykKaWYobiE9bnVsbCl7T2JqZWN0LmRlZmluZVByb3BlcnR5KG8sdi5k
+aXNwYXRjaFByb3BlcnR5TmFtZSx7dmFsdWU6bixlbnVtZXJhYmxlOmZhbHNlLHdyaXRhYmxlOnRydWUs
+Y29uZmlndXJhYmxlOnRydWV9KQpyLnByb3RvdHlwZT1vfX19fWZvcihxPTA7cTxzLmxlbmd0aDsrK3Ep
+e3A9c1txXQppZigvXltBLVphLXpfXS8udGVzdChwKSl7bT10W3BdCnRbIiEiK3BdPW0KdFsifiIrcF09
+bQp0WyItIitwXT1tCnRbIisiK3BdPW0KdFsiKiIrcF09bX19fSwKbHQ6ZnVuY3Rpb24oKXt2YXIgdCxz
+LHIscSxwLG8sbj1DLkUoKQpuPUguYnUoQy5GLEguYnUoQy5HLEguYnUoQy5yLEguYnUoQy5yLEguYnUo
+Qy5ILEguYnUoQy5JLEguYnUoQy5KKEMucSksbikpKSkpKSkKaWYodHlwZW9mIGRhcnROYXRpdmVEaXNw
+YXRjaEhvb2tzVHJhbnNmb3JtZXIhPSJ1bmRlZmluZWQiKXt0PWRhcnROYXRpdmVEaXNwYXRjaEhvb2tz
+VHJhbnNmb3JtZXIKaWYodHlwZW9mIHQ9PSJmdW5jdGlvbiIpdD1bdF0KaWYodC5jb25zdHJ1Y3Rvcj09
+QXJyYXkpZm9yKHM9MDtzPHQubGVuZ3RoOysrcyl7cj10W3NdCmlmKHR5cGVvZiByPT0iZnVuY3Rpb24i
+KW49cihuKXx8bn19cT1uLmdldFRhZwpwPW4uZ2V0VW5rbm93blRhZwpvPW4ucHJvdG90eXBlRm9yVGFn
+CiQuaUs9bmV3IEguZnkocSkKJC5pSD1uZXcgSC5meihwKQokLmlUPW5ldyBILmZBKG8pfSwKYnU6ZnVu
+Y3Rpb24oYSxiKXtyZXR1cm4gYShiKXx8Yn0sCmpNOmZ1bmN0aW9uKGEsYixjLGQsZSxmKXt2YXIgdD1i
+PyJtIjoiIixzPWM/IiI6ImkiLHI9ZD8idSI6IiIscT1lPyJzIjoiIixwPWY/ImciOiIiLG89ZnVuY3Rp
+b24oZyxoKXt0cnl7cmV0dXJuIG5ldyBSZWdFeHAoZyxoKX1jYXRjaChuKXtyZXR1cm4gbn19KGEsdCtz
+K3IrcStwKQppZihvIGluc3RhbmNlb2YgUmVnRXhwKXJldHVybiBvCnRocm93IEguYShQLkEoIklsbGVn
+YWwgUmVnRXhwIHBhdHRlcm4gKCIrU3RyaW5nKG8pKyIpIixhLG51bGwpKX0sCmxEOmZ1bmN0aW9uKGEp
+e2lmKC9bW1xde30oKSorPy5cXF4kfF0vLnRlc3QoYSkpcmV0dXJuIGEucmVwbGFjZSgvW1tcXXt9KCkq
+Kz8uXFxeJHxdL2csIlxcJCYiKQpyZXR1cm4gYX0sCmJ6OmZ1bmN0aW9uIGJ6KGEsYil7dGhpcy5hPWEK
+dGhpcy4kdGk9Yn0sCmJ5OmZ1bmN0aW9uIGJ5KCl7fSwKYUo6ZnVuY3Rpb24gYUooYSxiLGMsZCl7dmFy
+IF89dGhpcwpfLmE9YQpfLmI9YgpfLmM9YwpfLiR0aT1kfSwKY0o6ZnVuY3Rpb24gY0ooYSxiLGMsZCxl
+KXt2YXIgXz10aGlzCl8uYT1hCl8uYz1iCl8uZD1jCl8uZT1kCl8uZj1lfSwKZWU6ZnVuY3Rpb24gZWUo
+YSxiLGMpe3RoaXMuYT1hCnRoaXMuYj1iCnRoaXMuYz1jfSwKZWo6ZnVuY3Rpb24gZWooYSxiLGMsZCxl
+LGYpe3ZhciBfPXRoaXMKXy5hPWEKXy5iPWIKXy5jPWMKXy5kPWQKXy5lPWUKXy5mPWZ9LApjVjpmdW5j
+dGlvbiBjVihhLGIpe3RoaXMuYT1hCnRoaXMuYj1ifSwKY0w6ZnVuY3Rpb24gY0woYSxiLGMpe3RoaXMu
+YT1hCnRoaXMuYj1iCnRoaXMuYz1jfSwKZGE6ZnVuY3Rpb24gZGEoYSl7dGhpcy5hPWF9LApmUjpmdW5j
+dGlvbiBmUihhKXt0aGlzLmE9YX0sCmNnOmZ1bmN0aW9uIGNnKGEpe3RoaXMuYT1hCnRoaXMuYj1udWxs
+fSwKYUk6ZnVuY3Rpb24gYUkoKXt9LApkODpmdW5jdGlvbiBkOCgpe30sCmQzOmZ1bmN0aW9uIGQzKCl7
+fSwKYjY6ZnVuY3Rpb24gYjYoYSxiLGMsZCl7dmFyIF89dGhpcwpfLmE9YQpfLmI9YgpfLmM9YwpfLmQ9
+ZH0sCmQwOmZ1bmN0aW9uIGQwKGEpe3RoaXMuYT1hfSwKZGc6ZnVuY3Rpb24gZGcoYSl7dGhpcy5hPWF9
+LAphbjpmdW5jdGlvbiBhbihhKXt2YXIgXz10aGlzCl8uYT0wCl8uZj1fLmU9Xy5kPV8uYz1fLmI9bnVs
+bApfLnI9MApfLiR0aT1hfSwKZTg6ZnVuY3Rpb24gZTgoYSxiKXt2YXIgXz10aGlzCl8uYT1hCl8uYj1i
+Cl8uZD1fLmM9bnVsbH0sCmFQOmZ1bmN0aW9uIGFQKGEsYil7dGhpcy5hPWEKdGhpcy4kdGk9Yn0sCmJM
+OmZ1bmN0aW9uIGJMKGEsYixjKXt2YXIgXz10aGlzCl8uYT1hCl8uYj1iCl8uZD1fLmM9bnVsbApfLiR0
+aT1jfSwKZnk6ZnVuY3Rpb24gZnkoYSl7dGhpcy5hPWF9LApmejpmdW5jdGlvbiBmeihhKXt0aGlzLmE9
+YX0sCmZBOmZ1bmN0aW9uIGZBKGEpe3RoaXMuYT1hfSwKY0s6ZnVuY3Rpb24gY0soYSxiKXt2YXIgXz10
+aGlzCl8uYT1hCl8uYj1iCl8uZD1fLmM9bnVsbH0sCmtYOmZ1bmN0aW9uKGEpe3JldHVybiBhfSwKak86
+ZnVuY3Rpb24oYSl7cmV0dXJuIG5ldyBJbnQ4QXJyYXkoYSl9LAphcjpmdW5jdGlvbihhLGIsYyl7aWYo
+YT4+PjAhPT1hfHxhPj1jKXRocm93IEguYShILmIxKGIsYSkpfSwKa1U6ZnVuY3Rpb24oYSxiLGMpe3Zh
+ciB0CmlmKCEoYT4+PjAhPT1hKSl0PWI+Pj4wIT09Ynx8YT5ifHxiPmMKZWxzZSB0PSEwCmlmKHQpdGhy
+b3cgSC5hKEgubGwoYSxiLGMpKQpyZXR1cm4gYn0sCkM6ZnVuY3Rpb24gQygpe30sCmJROmZ1bmN0aW9u
+IGJRKCl7fSwKYVI6ZnVuY3Rpb24gYVIoKXt9LApiUjpmdW5jdGlvbiBiUigpe30sCmNQOmZ1bmN0aW9u
+IGNQKCl7fSwKY1E6ZnVuY3Rpb24gY1EoKXt9LApjUjpmdW5jdGlvbiBjUigpe30sCmNTOmZ1bmN0aW9u
+IGNTKCl7fSwKY1Q6ZnVuY3Rpb24gY1QoKXt9LApiUzpmdW5jdGlvbiBiUygpe30sCmFTOmZ1bmN0aW9u
+IGFTKCl7fSwKYzk6ZnVuY3Rpb24gYzkoKXt9LApjYTpmdW5jdGlvbiBjYSgpe30sCmNiOmZ1bmN0aW9u
+IGNiKCl7fSwKY2M6ZnVuY3Rpb24gY2MoKXt9LAppMDpmdW5jdGlvbihhLGIpe3ZhciB0PWIuZApyZXR1
+cm4gdD09bnVsbD9iLmQ9SC5mMChhLCJiRSIsW2IuUV0pOnR9LAppMTpmdW5jdGlvbihhKXt2YXIgdD1h
+LnoKaWYodD09PTZ8fHQ9PT03fHx0PT09OClyZXR1cm4gSC5pMShhLlEpCnJldHVybiB0PT09MTF8fHQ9
+PT0xMn0sCmsyOmZ1bmN0aW9uKGEpe3JldHVybiBhLmRifSwKZnA6ZnVuY3Rpb24oYSl7cmV0dXJuIEgu
+aGModi50eXBlVW5pdmVyc2UsYSl9LApsazpmdW5jdGlvbihhKXt2YXIgdD1hLiRTCmlmKHQhPW51bGwp
+e2lmKHR5cGVvZiB0PT0ibnVtYmVyIilyZXR1cm4gSC5pTCh0KQpyZXR1cm4gYS4kUygpfXJldHVybiBu
+dWxsfSwKaHQ6ZnVuY3Rpb24oYSxiKXt2YXIgdAppZihILmkxKGIpKWlmKGEgaW5zdGFuY2VvZiBILmFJ
+KXt0PUgubGsoYSkKaWYodCE9bnVsbClyZXR1cm4gdH1yZXR1cm4gSC5hOChhKX0sCmE4OmZ1bmN0aW9u
+KGEpe3ZhciB0CmlmKGEgaW5zdGFuY2VvZiBQLnQpe3Q9YS4kdGkKcmV0dXJuIHQhPW51bGw/dDpILmhs
+KGEpfWlmKEFycmF5LmlzQXJyYXkoYSkpcmV0dXJuIEguWihhKQpyZXR1cm4gSC5obChKLmFFKGEpKX0s
+Clo6ZnVuY3Rpb24oYSl7dmFyIHQ9YS4kdGkscz11LmIKaWYodD09bnVsbClyZXR1cm4gcwppZih0LmNv
+bnN0cnVjdG9yIT09cy5jb25zdHJ1Y3RvcilyZXR1cm4gcwpyZXR1cm4gdH0sCnY6ZnVuY3Rpb24oYSl7
+dmFyIHQ9YS4kdGkKcmV0dXJuIHQhPW51bGw/dDpILmhsKGEpfSwKaGw6ZnVuY3Rpb24oYSl7dmFyIHQ9
+YS5jb25zdHJ1Y3RvcixzPXQuJGNjYWNoZQppZihzIT1udWxsKXJldHVybiBzCnJldHVybiBILmwxKGEs
+dCl9LApsMTpmdW5jdGlvbihhLGIpe3ZhciB0PWEgaW5zdGFuY2VvZiBILmFJP2EuX19wcm90b19fLl9f
+cHJvdG9fXy5jb25zdHJ1Y3RvcjpiLHM9SC5rQih2LnR5cGVVbml2ZXJzZSx0Lm5hbWUpCmIuJGNjYWNo
+ZT1zCnJldHVybiBzfSwKaUw6ZnVuY3Rpb24oYSl7dmFyIHQscz1hLHI9di50eXBlcyxxPXJbc10KaWYo
+dHlwZW9mIHE9PSJzdHJpbmciKXt0PUguaGModi50eXBlVW5pdmVyc2UscSkKcltzXT10CnJldHVybiB0
+fXJldHVybiBxfSwKbDA6ZnVuY3Rpb24oYSl7dmFyIHQscz10aGlzLHI9cy56LHE9SC5rWgppZihILmNx
+KHMpKXtxPUgubDUKcy5iPXMuYT1ILmtTfWVsc2UgaWYocj09PTkpe3Q9cy5kYgppZigiZiI9PT10KXE9
+SC5kSgplbHNlIGlmKCJUIj09PXQpcT1ILml5CmVsc2UgaWYoIlUiPT09dClxPUguaXkKZWxzZSBpZigi
+YyI9PT10KXE9SC5sMwplbHNlIGlmKCJ6Ij09PXQpcT1ILmZkCmVsc2V7cj1zLlEKaWYocy5jaC5ldmVy
+eShILmNxKSl7cy54PSIkaSIrcgpxPUgubDR9fX1zLmM9cQpyZXR1cm4gcy5jKGEpfSwKa1o6ZnVuY3Rp
+b24oYSl7dmFyIHQ9dGhpcwpyZXR1cm4gSC5EKHYudHlwZVVuaXZlcnNlLEguaHQoYSx0KSxudWxsLHQs
+bnVsbCl9LApsNDpmdW5jdGlvbihhKXt2YXIgdD10aGlzLngKaWYoYSBpbnN0YW5jZW9mIFAudClyZXR1
+cm4hIWFbdF0KcmV0dXJuISFKLmFFKGEpW3RdfSwKa1k6ZnVuY3Rpb24oYSl7dmFyIHQKaWYoYT09bnVs
+bClyZXR1cm4gYQp0PXRoaXMKaWYodC5jKGEpKXJldHVybiBhCnRocm93IEguYShILmtqKEguZXkoYSxI
+Lmh0KGEsdCksSC5QKHQsbnVsbCkpKSl9LApsXzpmdW5jdGlvbihhKXt2YXIgdAppZihhPT1udWxsKXJl
+dHVybiBhCnQ9dGhpcwppZih0LmMoYSkpcmV0dXJuIGEKdGhyb3cgSC5hKEguaWcoSC5leShhLEguaHQo
+YSx0KSxILlAodCxudWxsKSkpKX0sCmRMOmZ1bmN0aW9uKGEsYixjLGQpe3ZhciB0PW51bGwKaWYoSC5E
+KHYudHlwZVVuaXZlcnNlLGEsdCxiLHQpKXJldHVybiBhCnRocm93IEguYShILmlnKCJUaGUgdHlwZSBh
+cmd1bWVudCAnIitILmIoSC5QKGEsdCkpKyInIGlzIG5vdCBhIHN1YnR5cGUgb2YgdGhlIHR5cGUgdmFy
+aWFibGUgYm91bmQgJyIrSC5iKEguUChiLHQpKSsiJyBvZiB0eXBlIHZhcmlhYmxlICciK2MrIicgaW4g
+JyIrSC5iKGQpKyInLiIpKX0sCmV5OmZ1bmN0aW9uKGEsYixjKXt2YXIgdD1QLmFNKGEpLHM9SC5QKGI9
+PW51bGw/SC5hOChhKTpiLG51bGwpCnJldHVybiB0KyI6IHR5cGUgJyIrSC5iKHMpKyInIGlzIG5vdCBh
+IHN1YnR5cGUgb2YgdHlwZSAnIitILmIoYykrIicifSwKa2o6ZnVuY3Rpb24oYSl7cmV0dXJuIG5ldyBI
+LmMxKCJDYXN0RXJyb3I6ICIrYSl9LApkajpmdW5jdGlvbihhLGIpe3JldHVybiBuZXcgSC5jMSgiQ2Fz
+dEVycm9yOiAiK0guZXkoYSxudWxsLGIpKX0sCmlnOmZ1bmN0aW9uKGEpe3JldHVybiBuZXcgSC5jaCgi
+VHlwZUVycm9yOiAiK2EpfSwKZEQ6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gbmV3IEguY2goIlR5cGVFcnJv
+cjogIitILmV5KGEsbnVsbCxiKSl9LApsNTpmdW5jdGlvbihhKXtyZXR1cm4hMH0sCmtTOmZ1bmN0aW9u
+KGEpe3JldHVybiBhfSwKZmQ6ZnVuY3Rpb24oYSl7cmV0dXJuITA9PT1hfHwhMT09PWF9LAptajpmdW5j
+dGlvbihhKXtpZighMD09PWF8fCExPT09YSlyZXR1cm4gYQppZihhPT1udWxsKXJldHVybiBhCnRocm93
+IEguYShILmRqKGEsImJvb2wiKSl9LApoZzpmdW5jdGlvbihhKXtpZighMD09PWF8fCExPT09YSlyZXR1
+cm4gYQppZihhPT1udWxsKXJldHVybiBhCnRocm93IEguYShILmREKGEsImJvb2wiKSl9LAptazpmdW5j
+dGlvbihhKXtpZih0eXBlb2YgYT09Im51bWJlciIpcmV0dXJuIGEKaWYoYT09bnVsbClyZXR1cm4gYQp0
+aHJvdyBILmEoSC5kaihhLCJkb3VibGUiKSl9LAptbzpmdW5jdGlvbihhKXtpZih0eXBlb2YgYT09Im51
+bWJlciIpcmV0dXJuIGEKaWYoYT09bnVsbClyZXR1cm4gYQp0aHJvdyBILmEoSC5kRChhLCJkb3VibGUi
+KSl9LApkSjpmdW5jdGlvbihhKXtyZXR1cm4gdHlwZW9mIGE9PSJudW1iZXIiJiZNYXRoLmZsb29yKGEp
+PT09YX0sCm1sOmZ1bmN0aW9uKGEpe2lmKHR5cGVvZiBhPT0ibnVtYmVyIiYmTWF0aC5mbG9vcihhKT09
+PWEpcmV0dXJuIGEKaWYoYT09bnVsbClyZXR1cm4gYQp0aHJvdyBILmEoSC5kaihhLCJpbnQiKSl9LAp4
+OmZ1bmN0aW9uKGEpe2lmKHR5cGVvZiBhPT0ibnVtYmVyIiYmTWF0aC5mbG9vcihhKT09PWEpcmV0dXJu
+IGEKaWYoYT09bnVsbClyZXR1cm4gYQp0aHJvdyBILmEoSC5kRChhLCJpbnQiKSl9LAppeTpmdW5jdGlv
+bihhKXtyZXR1cm4gdHlwZW9mIGE9PSJudW1iZXIifSwKbW06ZnVuY3Rpb24oYSl7aWYodHlwZW9mIGE9
+PSJudW1iZXIiKXJldHVybiBhCmlmKGE9PW51bGwpcmV0dXJuIGEKdGhyb3cgSC5hKEguZGooYSwibnVt
+IikpfSwKbXA6ZnVuY3Rpb24oYSl7aWYodHlwZW9mIGE9PSJudW1iZXIiKXJldHVybiBhCmlmKGE9PW51
+bGwpcmV0dXJuIGEKdGhyb3cgSC5hKEguZEQoYSwibnVtIikpfSwKbDM6ZnVuY3Rpb24oYSl7cmV0dXJu
+IHR5cGVvZiBhPT0ic3RyaW5nIn0sCm1uOmZ1bmN0aW9uKGEpe2lmKHR5cGVvZiBhPT0ic3RyaW5nIily
+ZXR1cm4gYQppZihhPT1udWxsKXJldHVybiBhCnRocm93IEguYShILmRqKGEsIlN0cmluZyIpKX0sCm86
+ZnVuY3Rpb24oYSl7aWYodHlwZW9mIGE9PSJzdHJpbmciKXJldHVybiBhCmlmKGE9PW51bGwpcmV0dXJu
+IGEKdGhyb3cgSC5hKEguZEQoYSwiU3RyaW5nIikpfSwKbGE6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIK
+Zm9yKHQ9IiIscz0iIixyPTA7cjxhLmxlbmd0aDsrK3Iscz0iLCAiKXQrPUMuYS5CKHMsSC5QKGFbcl0s
+YikpCnJldHVybiB0fSwKaXQ6ZnVuY3Rpb24oYTAsYTEsYTIpe3ZhciB0LHMscixxLHAsbyxuLG0sbCxr
+LGosaSxoLGcsZixlLGQsYyxiLGE9IiwgIgppZihhMiE9bnVsbCl7dD1hMi5sZW5ndGgKaWYoYTE9PW51
+bGwpe2ExPUgubihbXSx1LnMpCnM9bnVsbH1lbHNlIHM9YTEubGVuZ3RoCnI9YTEubGVuZ3RoCmZvcihx
+PXQ7cT4wOy0tcSlDLmIuayhhMSwiVCIrKHIrcSkpCmZvcihwPSI8IixvPSIiLHE9MDtxPHQ7KytxLG89
+YSl7cCs9bwpuPWExLmxlbmd0aAptPW4tMS1xCmlmKG08MClyZXR1cm4gSC5pKGExLG0pCnA9Qy5hLkIo
+cCxhMVttXSkKbD1hMltxXQppZighSC5jcShsKSlwKz1DLmEuQigiIGV4dGVuZHMgIixILlAobCxhMSkp
+fXArPSI+In1lbHNle3A9IiIKcz1udWxsfW49YTAuUQprPWEwLmNoCmo9ay5hCmk9ai5sZW5ndGgKaD1r
+LmIKZz1oLmxlbmd0aApmPWsuYwplPWYubGVuZ3RoCmQ9SC5QKG4sYTEpCmZvcihjPSIiLGI9IiIscT0w
+O3E8aTsrK3EsYj1hKWMrPUMuYS5CKGIsSC5QKGpbcV0sYTEpKQppZihnPjApe2MrPWIrIlsiCmZvcihi
+PSIiLHE9MDtxPGc7KytxLGI9YSljKz1DLmEuQihiLEguUChoW3FdLGExKSkKYys9Il0ifWlmKGU+MCl7
+Yys9YisieyIKZm9yKGI9IiIscT0wO3E8ZTtxKz0yLGI9YSljKz1DLmEuQihiLEguUChmW3ErMV0sYTEp
+KSsiICIrZltxXQpjKz0ifSJ9aWYocyE9bnVsbClhMS5sZW5ndGg9cwpyZXR1cm4gcCsiKCIrYysiKSA9
+PiAiK0guYihkKX0sClA6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIscSxwPWEuegppZihwPT09NSlyZXR1
+cm4iZXJhc2VkIgppZihwPT09MilyZXR1cm4iZHluYW1pYyIKaWYocD09PTMpcmV0dXJuInZvaWQiCmlm
+KHA9PT0xKXJldHVybiJOZXZlciIKaWYocD09PTQpcmV0dXJuImFueSIKaWYocD09PTYpcmV0dXJuIEgu
+YihILlAoYS5RLGIpKSsiKiIKaWYocD09PTcpcmV0dXJuIEguYihILlAoYS5RLGIpKSsiPyIKaWYocD09
+PTgpcmV0dXJuIkZ1dHVyZU9yPCIrSC5iKEguUChhLlEsYikpKyI+IgppZihwPT09OSl7dD1ILmxkKGEu
+USkKcz1hLmNoCnJldHVybiBzLmxlbmd0aCE9PTA/dCsoIjwiK0gubGEocyxiKSsiPiIpOnR9aWYocD09
+PTExKXJldHVybiBILml0KGEsYixudWxsKQppZihwPT09MTIpcmV0dXJuIEguaXQoYS5RLGIsYS5jaCkK
+aWYocD09PTEzKXtyPWEuUQpxPWIubGVuZ3RoCnI9cS0xLXIKaWYocjwwfHxyPj1xKXJldHVybiBILmko
+YixyKQpyZXR1cm4gYltyXX1yZXR1cm4iPyJ9LApsZDpmdW5jdGlvbihhKXt2YXIgdCxzPUguaVgoYSkK
+aWYocyE9bnVsbClyZXR1cm4gcwp0PSJtaW5pZmllZDoiK2EKcmV0dXJuIHR9LAppajpmdW5jdGlvbihh
+LGIpe3ZhciB0PWEudFJbYl0KZm9yKDt0eXBlb2YgdD09InN0cmluZyI7KXQ9YS50Ult0XQpyZXR1cm4g
+dH0sCmtCOmZ1bmN0aW9uKGEsYil7dmFyIHQscyxyLHEscCxvPWEuZVQsbj1vW2JdCmlmKG49PW51bGwp
+cmV0dXJuIEguaGMoYSxiKQplbHNlIGlmKHR5cGVvZiBuPT0ibnVtYmVyIil7dD1uCnM9SC5jaShhLDUs
+IiMiKQpyPVtdCmZvcihxPTA7cTx0OysrcSlyLnB1c2gocykKcD1ILmYwKGEsYixyKQpvW2JdPXAKcmV0
+dXJuIHB9ZWxzZSByZXR1cm4gbn0sCmt6OmZ1bmN0aW9uKGEsYil7cmV0dXJuIEguaXIoYS50UixiKX0s
+Cmt5OmZ1bmN0aW9uKGEsYil7cmV0dXJuIEguaXIoYS5lVCxiKX0sCmhjOmZ1bmN0aW9uKGEsYil7dmFy
+IHQscz1hLmVDLHI9cy5nZXQoYikKaWYociE9bnVsbClyZXR1cm4gcgp0PUguaWkoYSxudWxsLGIpCnMu
+c2V0KGIsdCkKcmV0dXJuIHR9LApkRjpmdW5jdGlvbihhLGIsYyl7dmFyIHQscyxyPWIuY3gKaWYocj09
+bnVsbClyPWIuY3g9bmV3IE1hcCgpCnQ9ci5nZXQoYykKaWYodCE9bnVsbClyZXR1cm4gdApzPUguaWko
+YSxiLGMpCnIuc2V0KGMscykKcmV0dXJuIHN9LAprQTpmdW5jdGlvbihhLGIsYyl7dmFyIHQscyxyLHE9
+Yi5jeQppZihxPT1udWxsKXE9Yi5jeT1uZXcgTWFwKCkKdD1jLmRiCnM9cS5nZXQodCkKaWYocyE9bnVs
+bClyZXR1cm4gcwpyPUguaWgoYSxiLGMuej09PTEwP2MuY2g6W2NdKQpxLnNldCh0LHIpCnJldHVybiBy
+fSwKaWk6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0PUgua3IoSC5rbihhLGIsYykpCnJldHVybiB0fSwKYnA6
+ZnVuY3Rpb24oYSxiKXt2YXIgdD1iLmRiCmEuZUMuc2V0KHQsYikKYi5hPUgua1kKYi5iPUgubF8KYi5j
+PUgubDAKcmV0dXJuIGJ9LApjaTpmdW5jdGlvbihhLGIsYyl7dmFyIHQscz1hLmVDLmdldChjKQppZihz
+IT1udWxsKXJldHVybiBzCnQ9bmV3IEguYWYobnVsbCxudWxsLG51bGwpCnQuej1iCnQuZGI9YwpyZXR1
+cm4gSC5icChhLHQpfSwKaGI6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIHQscz1hLmVDLmdldChkKQppZihz
+IT1udWxsKXJldHVybiBzCnQ9bmV3IEguYWYobnVsbCxudWxsLG51bGwpCnQuej1iCnQuUT1jCnQuZGI9
+ZApyZXR1cm4gSC5icChhLHQpfSwKa3c6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzPSIiK2IrIl4iLHI9YS5l
+Qy5nZXQocykKaWYociE9bnVsbClyZXR1cm4gcgp0PW5ldyBILmFmKG51bGwsbnVsbCxudWxsKQp0Lno9
+MTMKdC5RPWIKdC5kYj1zCnJldHVybiBILmJwKGEsdCl9LApkRTpmdW5jdGlvbihhKXt2YXIgdCxzLHIs
+cT1hLmxlbmd0aApmb3IodD0iIixzPSIiLHI9MDtyPHE7KytyLHM9IiwiKXQrPXMrYVtyXS5kYgpyZXR1
+cm4gdH0sCmt1OmZ1bmN0aW9uKGEpe3ZhciB0LHMscixxLHAsbz1hLmxlbmd0aApmb3IodD0iIixzPSIi
+LHI9MDtyPG87cis9MixzPSIsIil7cT1hW3JdCnA9YVtyKzFdLmRiCnQrPXMrcSsiOiIrcH1yZXR1cm4g
+dH0sCmYwOmZ1bmN0aW9uKGEsYixjKXt2YXIgdCxzLHI9YgppZihjLmxlbmd0aCE9PTApcis9IjwiK0gu
+ZEUoYykrIj4iCnQ9YS5lQy5nZXQocikKaWYodCE9bnVsbClyZXR1cm4gdApzPW5ldyBILmFmKG51bGws
+bnVsbCxudWxsKQpzLno9OQpzLlE9YgpzLmNoPWMKaWYoYy5sZW5ndGg+MClzLmQ9Y1swXQpzLmRiPXIK
+cmV0dXJuIEguYnAoYSxzKX0sCmloOmZ1bmN0aW9uKGEsYixjKXt2YXIgdCxzLHIscSxwCmlmKGIuej09
+PTEwKXt0PWIuUQpzPWIuY2guY29uY2F0KGMpfWVsc2V7cz1jCnQ9Yn1yPXQuZGIrIjsiKygiPCIrSC5k
+RShzKSsiPiIpCnE9YS5lQy5nZXQocikKaWYocSE9bnVsbClyZXR1cm4gcQpwPW5ldyBILmFmKG51bGws
+bnVsbCxudWxsKQpwLno9MTAKcC5RPXQKcC5jaD1zCnAuZGI9cgpyZXR1cm4gSC5icChhLHApfSwKa3Y6
+ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMscixxPWIuZGIscD1jLmEsbz1wLmxlbmd0aCxuPWMuYixtPW4u
+bGVuZ3RoLGw9Yy5jLGs9bC5sZW5ndGgsaj0iKCIrSC5kRShwKQppZihtPjApais9KG8+MD8iLCI6IiIp
+KyJbIitILmRFKG4pKyJdIgppZihrPjApais9KG8+MD8iLCI6IiIpKyJ7IitILmt1KGwpKyJ9Igp0PXEr
+KGorIikiKQpzPWEuZUMuZ2V0KHQpCmlmKHMhPW51bGwpcmV0dXJuIHMKcj1uZXcgSC5hZihudWxsLG51
+bGwsbnVsbCkKci56PTExCnIuUT1iCnIuY2g9YwpyLmRiPXQKcmV0dXJuIEguYnAoYSxyKX0sCmt4OmZ1
+bmN0aW9uKGEsYixjKXt2YXIgdCxzPWIuZGIrIjwiK0guZEUoYykrIj4iLHI9YS5lQy5nZXQocykKaWYo
+ciE9bnVsbClyZXR1cm4gcgp0PW5ldyBILmFmKG51bGwsbnVsbCxudWxsKQp0Lno9MTIKdC5RPWIKdC5j
+aD1jCnQuZGI9cwpyZXR1cm4gSC5icChhLHQpfSwKa246ZnVuY3Rpb24oYSxiLGMpe3JldHVybnt1OmEs
+ZTpiLHI6YyxzOltdLHA6MH19LAprcjpmdW5jdGlvbihhKXt2YXIgdCxzLHIscSxwLG8sbixtLGwsayxq
+LGksaCxnPWEucixmPWEucwpmb3IodD1nLmxlbmd0aCxzPTA7czx0Oyl7cj1nLmNoYXJDb2RlQXQocykK
+aWYocj49NDgmJnI8PTU3KXM9SC5rbyhzKzEscixnLGYpCmVsc2UgaWYoKCgocnwzMik+Pj4wKS05NyY2
+NTUzNSk8MjZ8fHI9PT05NXx8cj09PTM2KXM9SC5pZChhLHMsZyxmLCExKQplbHNlIGlmKHI9PT00Nilz
+PUguaWQoYSxzLGcsZiwhMCkKZWxzZXsrK3MKc3dpdGNoKHIpe2Nhc2UgNDQ6YnJlYWsKY2FzZSA1ODpi
+cmVhawpjYXNlIDU5OmYucHVzaChILmFEKGEudSxhLmUsZi5wb3AoKSkpCmJyZWFrCmNhc2UgOTQ6Zi5w
+dXNoKEgua3coYS51LGYucG9wKCkpKQpicmVhawpjYXNlIDM1OmYucHVzaChILmNpKGEudSw1LCIjIikp
+CmJyZWFrCmNhc2UgNjQ6Zi5wdXNoKEguY2koYS51LDIsIkAiKSkKYnJlYWsKY2FzZSAxMjY6Zi5wdXNo
+KEguY2koYS51LDMsIn4iKSkKYnJlYWsKY2FzZSA2MDpmLnB1c2goYS5wKQphLnA9Zi5sZW5ndGgKYnJl
+YWsKY2FzZSA2MjpxPWEudQpwPWYuc3BsaWNlKGEucCkKSC5oYShhLnUsYS5lLHApCmEucD1mLnBvcCgp
+Cm89Zi5wb3AoKQppZih0eXBlb2Ygbz09InN0cmluZyIpZi5wdXNoKEguZjAocSxvLHApKQplbHNle249
+SC5hRChxLGEuZSxvKQpzd2l0Y2gobi56KXtjYXNlIDExOmYucHVzaChILmt4KHEsbixwKSkKYnJlYWsK
+ZGVmYXVsdDpmLnB1c2goSC5paChxLG4scCkpCmJyZWFrfX1icmVhawpjYXNlIDM4Okgua3AoYSxmKQpi
+cmVhawpjYXNlIDQyOm09YS51Cmw9SC5hRChtLGEuZSxmLnBvcCgpKQpmLnB1c2goSC5oYihtLDYsbCxs
+LmRiKyIqIikpCmJyZWFrCmNhc2UgNjM6bT1hLnUKbD1ILmFEKG0sYS5lLGYucG9wKCkpCmYucHVzaChI
+LmhiKG0sNyxsLGwuZGIrIj8iKSkKYnJlYWsKY2FzZSA0NzptPWEudQpsPUguYUQobSxhLmUsZi5wb3Ao
+KSkKZi5wdXNoKEguaGIobSw4LGwsbC5kYisiLyIpKQpicmVhawpjYXNlIDQwOmYucHVzaChhLnApCmEu
+cD1mLmxlbmd0aApicmVhawpjYXNlIDQxOnE9YS51Cms9bmV3IEguZUIoKQpqPXEuc0VBCmk9cS5zRUEK
+bz1mLnBvcCgpCmlmKHR5cGVvZiBvPT0ibnVtYmVyIilzd2l0Y2gobyl7Y2FzZS0xOmo9Zi5wb3AoKQpi
+cmVhawpjYXNlLTI6aT1mLnBvcCgpCmJyZWFrCmRlZmF1bHQ6Zi5wdXNoKG8pCmJyZWFrfWVsc2UgZi5w
+dXNoKG8pCnA9Zi5zcGxpY2UoYS5wKQpILmhhKGEudSxhLmUscCkKYS5wPWYucG9wKCkKay5hPXAKay5i
+PWoKay5jPWkKZi5wdXNoKEgua3YocSxILmFEKHEsYS5lLGYucG9wKCkpLGspKQpicmVhawpjYXNlIDkx
+OmYucHVzaChhLnApCmEucD1mLmxlbmd0aApicmVhawpjYXNlIDkzOnA9Zi5zcGxpY2UoYS5wKQpILmhh
+KGEudSxhLmUscCkKYS5wPWYucG9wKCkKZi5wdXNoKHApCmYucHVzaCgtMSkKYnJlYWsKY2FzZSAxMjM6
+Zi5wdXNoKGEucCkKYS5wPWYubGVuZ3RoCmJyZWFrCmNhc2UgMTI1OnA9Zi5zcGxpY2UoYS5wKQpILmtz
+KGEudSxhLmUscCkKYS5wPWYucG9wKCkKZi5wdXNoKHApCmYucHVzaCgtMikKYnJlYWsKZGVmYXVsdDp0
+aHJvdyJCYWQgY2hhcmFjdGVyICIrcn19fWg9Zi5wb3AoKQpyZXR1cm4gSC5hRChhLnUsYS5lLGgpfSwK
+a286ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIHQscyxyPWItNDgKZm9yKHQ9Yy5sZW5ndGg7YTx0OysrYSl7
+cz1jLmNoYXJDb2RlQXQoYSkKaWYoIShzPj00OCYmczw9NTcpKWJyZWFrCnI9cioxMCsocy00OCl9ZC5w
+dXNoKHIpCnJldHVybiBhfSwKaWQ6ZnVuY3Rpb24oYSxiLGMsZCxlKXt2YXIgdCxzLHIscSxwLG8sbj1i
+KzEKZm9yKHQ9Yy5sZW5ndGg7bjx0Oysrbil7cz1jLmNoYXJDb2RlQXQobikKaWYocz09PTQ2KXtpZihl
+KWJyZWFrCmU9ITB9ZWxzZXtpZighKCgoKHN8MzIpPj4+MCktOTcmNjU1MzUpPDI2fHxzPT09OTV8fHM9
+PT0zNikpcj1zPj00OCYmczw9NTcKZWxzZSByPSEwCmlmKCFyKWJyZWFrfX1xPWMuc3Vic3RyaW5nKGIs
+bikKaWYoZSl7dD1hLnUKcD1hLmUKaWYocC56PT09MTApcD1wLlEKbz1ILmlqKHQscC5RKVtxXQppZihv
+PT1udWxsKUguYWsoJ05vICInK3ErJyIgaW4gIicrSC5rMihwKSsnIicpCmQucHVzaChILmRGKHQscCxv
+KSl9ZWxzZSBkLnB1c2gocSkKcmV0dXJuIG59LAprcDpmdW5jdGlvbihhLGIpe3ZhciB0PWIucG9wKCkK
+aWYoMD09PXQpe2IucHVzaChILmNpKGEudSwxLCIwJiIpKQpyZXR1cm59aWYoMT09PXQpe2IucHVzaChI
+LmNpKGEudSw0LCIxJiIpKQpyZXR1cm59dGhyb3cgSC5hKFAuZlkoIlVuZXhwZWN0ZWQgZXh0ZW5kZWQg
+b3BlcmF0aW9uICIrSC5iKHQpKSl9LAphRDpmdW5jdGlvbihhLGIsYyl7aWYodHlwZW9mIGM9PSJzdHJp
+bmciKXJldHVybiBILmYwKGEsYyxhLnNFQSkKZWxzZSBpZih0eXBlb2YgYz09Im51bWJlciIpcmV0dXJu
+IEgua3EoYSxiLGMpCmVsc2UgcmV0dXJuIGN9LApoYTpmdW5jdGlvbihhLGIsYyl7dmFyIHQscz1jLmxl
+bmd0aApmb3IodD0wO3Q8czsrK3QpY1t0XT1ILmFEKGEsYixjW3RdKX0sCmtzOmZ1bmN0aW9uKGEsYixj
+KXt2YXIgdCxzPWMubGVuZ3RoCmZvcih0PTE7dDxzO3QrPTIpY1t0XT1ILmFEKGEsYixjW3RdKX0sCmtx
+OmZ1bmN0aW9uKGEsYixjKXt2YXIgdCxzLHI9Yi56CmlmKHI9PT0xMCl7aWYoYz09PTApcmV0dXJuIGIu
+UQp0PWIuY2gKcz10Lmxlbmd0aAppZihjPD1zKXJldHVybiB0W2MtMV0KYy09cwpiPWIuUQpyPWIuen1l
+bHNlIGlmKGM9PT0wKXJldHVybiBiCmlmKHIhPT05KXRocm93IEguYShQLmZZKCJJbmRleGVkIGJhc2Ug
+bXVzdCBiZSBhbiBpbnRlcmZhY2UgdHlwZSIpKQp0PWIuY2gKaWYoYzw9dC5sZW5ndGgpcmV0dXJuIHRb
+Yy0xXQp0aHJvdyBILmEoUC5mWSgiQmFkIGluZGV4ICIrYysiIGZvciAiK2IuaSgwKSkpfSwKRDpmdW5j
+dGlvbihhLGIsYyxkLGUpe3ZhciB0LHMscixxLHAsbyxuLG0sbCxrCmlmKGI9PT1kKXJldHVybiEwCmlm
+KEguY3EoZCkpcmV0dXJuITAKdD1iLnoKaWYodD09PTQpcmV0dXJuITAKaWYoSC5jcShiKSlyZXR1cm4h
+MQppZihiPT09dS5QKXJldHVybiEwCnM9dD09PTEzCmlmKHMpaWYoSC5EKGEsY1tiLlFdLGMsZCxlKSly
+ZXR1cm4hMApyPWQuegppZih0PT09NilyZXR1cm4gSC5EKGEsYi5RLGMsZCxlKQppZihyPT09Nil7cT1k
+LlEKcmV0dXJuIEguRChhLGIsYyxxLGUpfWlmKHQ9PT04KXtpZighSC5EKGEsYi5RLGMsZCxlKSlyZXR1
+cm4hMQpyZXR1cm4gSC5EKGEsSC5pMChhLGIpLGMsZCxlKX1pZih0PT09Nyl7cT1ILkQoYSxiLlEsYyxk
+LGUpCnJldHVybiBxfWlmKHI9PT04KXtpZihILkQoYSxiLGMsZC5RLGUpKXJldHVybiEwCnJldHVybiBI
+LkQoYSxiLGMsSC5pMChhLGQpLGUpfWlmKHI9PT03KXtxPUguRChhLGIsYyxkLlEsZSkKcmV0dXJuIHF9
+aWYocylyZXR1cm4hMQpxPXQhPT0xMQppZigoIXF8fHQ9PT0xMikmJmQ9PT11LlopcmV0dXJuITAKaWYo
+cj09PTEyKXtpZihiPT09dS5nKXJldHVybiEwCmlmKHQhPT0xMilyZXR1cm4hMQpwPWIuY2gKbz1kLmNo
+Cm49cC5sZW5ndGgKaWYobiE9PW8ubGVuZ3RoKXJldHVybiExCmZvcihxPXUuYXYsbT0wO208bjsrK20p
+e2w9cFttXQprPW9bbV0KcS5iKGwpCnEuYihrKQppZighSC5EKGEsbCxjLGssZSl8fCFILkQoYSxrLGUs
+bCxjKSlyZXR1cm4hMX1jPWM9PW51bGw/cDpwLmNvbmNhdChjKQplPWU9PW51bGw/bzpvLmNvbmNhdChl
+KQpyZXR1cm4gSC5pdyhhLGIuUSxjLGQuUSxlKX1pZihyPT09MTEpe2lmKGI9PT11LmcpcmV0dXJuITAK
+aWYocSlyZXR1cm4hMQpyZXR1cm4gSC5pdyhhLGIsYyxkLGUpfWlmKHQ9PT05KXtpZihyIT09OSlyZXR1
+cm4hMQpyZXR1cm4gSC5sMihhLGIsYyxkLGUpfXJldHVybiExfSwKaXc6ZnVuY3Rpb24oYTAsYTEsYTIs
+YTMsYTQpe3ZhciB0LHMscixxLHAsbyxuLG0sbCxrLGosaSxoLGcsZixlLGQsYyxiLGEKaWYoIUguRChh
+MCxhMS5RLGEyLGEzLlEsYTQpKXJldHVybiExCnQ9YTEuY2gKcz1hMy5jaApyPXQuYQpxPXMuYQpwPXIu
+bGVuZ3RoCm89cS5sZW5ndGgKaWYocD5vKXJldHVybiExCm49by1wCm09dC5iCmw9cy5iCms9bS5sZW5n
+dGgKaj1sLmxlbmd0aAppZihwK2s8bytqKXJldHVybiExCmZvcihpPTA7aTxwOysraSl7aD1yW2ldCmlm
+KCFILkQoYTAscVtpXSxhNCxoLGEyKSlyZXR1cm4hMX1mb3IoaT0wO2k8bjsrK2kpe2g9bVtpXQppZigh
+SC5EKGEwLHFbcCtpXSxhNCxoLGEyKSlyZXR1cm4hMX1mb3IoaT0wO2k8ajsrK2kpe2g9bVtuK2ldCmlm
+KCFILkQoYTAsbFtpXSxhNCxoLGEyKSlyZXR1cm4hMX1nPXQuYwpmPXMuYwplPWcubGVuZ3RoCmQ9Zi5s
+ZW5ndGgKZm9yKGk9MCxjPTA7YzxkO2MrPTIpe2I9ZltjXQpkb3tpZihpPj1lKXJldHVybiExCmE9Z1tp
+XQppKz0yfXdoaWxlKGE8YikKaWYoYjxhKXJldHVybiExCmg9Z1tpLTFdCmlmKCFILkQoYTAsZltjKzFd
+LGE0LGgsYTIpKXJldHVybiExfXJldHVybiEwfSwKbDI6ZnVuY3Rpb24oYSxiLGMsZCxlKXt2YXIgdCxz
+LHIscSxwLG8sbixtLGw9Yi5RLGs9ZC5RCmlmKGw9PT1rKXt0PWIuY2gKcz1kLmNoCnI9dC5sZW5ndGgK
+Zm9yKHE9MDtxPHI7KytxKXtwPXRbcV0Kbz1zW3FdCmlmKCFILkQoYSxwLGMsbyxlKSlyZXR1cm4hMX1y
+ZXR1cm4hMH1uPUguaWooYSxsKQppZihuPT1udWxsKXJldHVybiExCm09bltrXQppZihtPT1udWxsKXJl
+dHVybiExCnI9bS5sZW5ndGgKcz1kLmNoCmZvcihxPTA7cTxyOysrcSlpZighSC5EKGEsSC5kRihhLGIs
+bVtxXSksYyxzW3FdLGUpKXJldHVybiExCnJldHVybiEwfSwKY3E6ZnVuY3Rpb24oYSl7dmFyIHQscwpp
+ZihhPT09dS5LKXJldHVybiEwCnQ9YS56CmlmKHQhPT0yKWlmKHQhPT0zKWlmKHQhPT00KWlmKHQhPT01
+KXM9dD09PTgmJkguY3EoYS5RKQplbHNlIHM9ITAKZWxzZSBzPSEwCmVsc2Ugcz0hMAplbHNlIHM9ITAK
+cmV0dXJuIHN9LAppcjpmdW5jdGlvbihhLGIpe3ZhciB0LHMscj1PYmplY3Qua2V5cyhiKSxxPXIubGVu
+Z3RoCmZvcih0PTA7dDxxOysrdCl7cz1yW3RdCmFbc109YltzXX19LAphZjpmdW5jdGlvbiBhZihhLGIs
+Yyl7dmFyIF89dGhpcwpfLmE9YQpfLmI9YgpfLmM9YwpfLnk9Xy54PV8uZD1udWxsCl8uej0wCl8uZGI9
+Xy5jeT1fLmN4PV8uY2g9Xy5RPW51bGx9LAplQjpmdW5jdGlvbiBlQigpe3RoaXMuYz10aGlzLmI9dGhp
+cy5hPW51bGx9LApkcDpmdW5jdGlvbiBkcCgpe30sCmMxOmZ1bmN0aW9uIGMxKGEpe3RoaXMuYT1hfSwK
+Y2g6ZnVuY3Rpb24gY2goYSl7dGhpcy5hPWF9LAppTTpmdW5jdGlvbihhKXtyZXR1cm4gdS5kLmMoYSl8
+fHUuQS5jKGEpfHx1LncuYyhhKXx8dS5JLmMoYSl8fHUuRi5jKGEpfHx1Lmc0LmMoYSl8fHUuZzIuYyhh
+KX0sCmlYOmZ1bmN0aW9uKGEpe3JldHVybiB2Lm1hbmdsZWRHbG9iYWxOYW1lc1thXX19LEo9ewpodjpm
+dW5jdGlvbihhLGIsYyxkKXtyZXR1cm57aTphLHA6YixlOmMseDpkfX0sCmROOmZ1bmN0aW9uKGEpe3Zh
+ciB0LHMscixxLHA9YVt2LmRpc3BhdGNoUHJvcGVydHlOYW1lXQppZihwPT1udWxsKWlmKCQuaHM9PW51
+bGwpe0gubHUoKQpwPWFbdi5kaXNwYXRjaFByb3BlcnR5TmFtZV19aWYocCE9bnVsbCl7dD1wLnAKaWYo
+ITE9PT10KXJldHVybiBwLmkKaWYoITA9PT10KXJldHVybiBhCnM9T2JqZWN0LmdldFByb3RvdHlwZU9m
+KGEpCmlmKHQ9PT1zKXJldHVybiBwLmkKaWYocC5lPT09cyl0aHJvdyBILmEoUC5lbCgiUmV0dXJuIGlu
+dGVyY2VwdG9yIGZvciAiK0guYih0KGEscCkpKSl9cj1hLmNvbnN0cnVjdG9yCnE9cj09bnVsbD9udWxs
+OnJbJC5oeSgpXQppZihxIT1udWxsKXJldHVybiBxCnE9SC5sQihhKQppZihxIT1udWxsKXJldHVybiBx
+CmlmKHR5cGVvZiBhPT0iZnVuY3Rpb24iKXJldHVybiBDLlIKdD1PYmplY3QuZ2V0UHJvdG90eXBlT2Yo
+YSkKaWYodD09bnVsbClyZXR1cm4gQy5CCmlmKHQ9PT1PYmplY3QucHJvdG90eXBlKXJldHVybiBDLkIK
+aWYodHlwZW9mIHI9PSJmdW5jdGlvbiIpe09iamVjdC5kZWZpbmVQcm9wZXJ0eShyLCQuaHkoKSx7dmFs
+dWU6Qy5uLGVudW1lcmFibGU6ZmFsc2Usd3JpdGFibGU6dHJ1ZSxjb25maWd1cmFibGU6dHJ1ZX0pCnJl
+dHVybiBDLm59cmV0dXJuIEMubn0sCmpKOmZ1bmN0aW9uKGEpe2EuZml4ZWQkbGVuZ3RoPUFycmF5CnJl
+dHVybiBhfSwKaFI6ZnVuY3Rpb24oYSl7aWYoYTwyNTYpc3dpdGNoKGEpe2Nhc2UgOTpjYXNlIDEwOmNh
+c2UgMTE6Y2FzZSAxMjpjYXNlIDEzOmNhc2UgMzI6Y2FzZSAxMzM6Y2FzZSAxNjA6cmV0dXJuITAKZGVm
+YXVsdDpyZXR1cm4hMX1zd2l0Y2goYSl7Y2FzZSA1NzYwOmNhc2UgODE5MjpjYXNlIDgxOTM6Y2FzZSA4
+MTk0OmNhc2UgODE5NTpjYXNlIDgxOTY6Y2FzZSA4MTk3OmNhc2UgODE5ODpjYXNlIDgxOTk6Y2FzZSA4
+MjAwOmNhc2UgODIwMTpjYXNlIDgyMDI6Y2FzZSA4MjMyOmNhc2UgODIzMzpjYXNlIDgyMzk6Y2FzZSA4
+Mjg3OmNhc2UgMTIyODg6Y2FzZSA2NTI3OTpyZXR1cm4hMApkZWZhdWx0OnJldHVybiExfX0sCmpLOmZ1
+bmN0aW9uKGEsYil7dmFyIHQscwpmb3IodD1hLmxlbmd0aDtiPHQ7KXtzPUMuYS50KGEsYikKaWYocyE9
+PTMyJiZzIT09MTMmJiFKLmhSKHMpKWJyZWFrOysrYn1yZXR1cm4gYn0sCmpMOmZ1bmN0aW9uKGEsYil7
+dmFyIHQscwpmb3IoO2I+MDtiPXQpe3Q9Yi0xCnM9Qy5hLnYoYSx0KQppZihzIT09MzImJnMhPT0xMyYm
+IUouaFIocykpYnJlYWt9cmV0dXJuIGJ9LAphRTpmdW5jdGlvbihhKXtpZih0eXBlb2YgYT09Im51bWJl
+ciIpe2lmKE1hdGguZmxvb3IoYSk9PWEpcmV0dXJuIEouYkkucHJvdG90eXBlCnJldHVybiBKLmNJLnBy
+b3RvdHlwZX1pZih0eXBlb2YgYT09InN0cmluZyIpcmV0dXJuIEouYXgucHJvdG90eXBlCmlmKGE9PW51
+bGwpcmV0dXJuIEouYkoucHJvdG90eXBlCmlmKHR5cGVvZiBhPT0iYm9vbGVhbiIpcmV0dXJuIEouY0gu
+cHJvdG90eXBlCmlmKGEuY29uc3RydWN0b3I9PUFycmF5KXJldHVybiBKLkYucHJvdG90eXBlCmlmKHR5
+cGVvZiBhIT0ib2JqZWN0Iil7aWYodHlwZW9mIGE9PSJmdW5jdGlvbiIpcmV0dXJuIEouYWQucHJvdG90
+eXBlCnJldHVybiBhfWlmKGEgaW5zdGFuY2VvZiBQLnQpcmV0dXJuIGEKcmV0dXJuIEouZE4oYSl9LAps
+bjpmdW5jdGlvbihhKXtpZih0eXBlb2YgYT09Im51bWJlciIpcmV0dXJuIEouYmEucHJvdG90eXBlCmlm
+KHR5cGVvZiBhPT0ic3RyaW5nIilyZXR1cm4gSi5heC5wcm90b3R5cGUKaWYoYT09bnVsbClyZXR1cm4g
+YQppZihhLmNvbnN0cnVjdG9yPT1BcnJheSlyZXR1cm4gSi5GLnByb3RvdHlwZQppZih0eXBlb2YgYSE9
+Im9iamVjdCIpe2lmKHR5cGVvZiBhPT0iZnVuY3Rpb24iKXJldHVybiBKLmFkLnByb3RvdHlwZQpyZXR1
+cm4gYX1pZihhIGluc3RhbmNlb2YgUC50KXJldHVybiBhCnJldHVybiBKLmROKGEpfSwKYV86ZnVuY3Rp
+b24oYSl7aWYodHlwZW9mIGE9PSJzdHJpbmciKXJldHVybiBKLmF4LnByb3RvdHlwZQppZihhPT1udWxs
+KXJldHVybiBhCmlmKGEuY29uc3RydWN0b3I9PUFycmF5KXJldHVybiBKLkYucHJvdG90eXBlCmlmKHR5
+cGVvZiBhIT0ib2JqZWN0Iil7aWYodHlwZW9mIGE9PSJmdW5jdGlvbiIpcmV0dXJuIEouYWQucHJvdG90
+eXBlCnJldHVybiBhfWlmKGEgaW5zdGFuY2VvZiBQLnQpcmV0dXJuIGEKcmV0dXJuIEouZE4oYSl9LApo
+cTpmdW5jdGlvbihhKXtpZihhPT1udWxsKXJldHVybiBhCmlmKGEuY29uc3RydWN0b3I9PUFycmF5KXJl
+dHVybiBKLkYucHJvdG90eXBlCmlmKHR5cGVvZiBhIT0ib2JqZWN0Iil7aWYodHlwZW9mIGE9PSJmdW5j
+dGlvbiIpcmV0dXJuIEouYWQucHJvdG90eXBlCnJldHVybiBhfWlmKGEgaW5zdGFuY2VvZiBQLnQpcmV0
+dXJuIGEKcmV0dXJuIEouZE4oYSl9LAphMDpmdW5jdGlvbihhKXtpZih0eXBlb2YgYT09InN0cmluZyIp
+cmV0dXJuIEouYXgucHJvdG90eXBlCmlmKGE9PW51bGwpcmV0dXJuIGEKaWYoIShhIGluc3RhbmNlb2Yg
+UC50KSlyZXR1cm4gSi5iay5wcm90b3R5cGUKcmV0dXJuIGF9LApFOmZ1bmN0aW9uKGEpe2lmKGE9PW51
+bGwpcmV0dXJuIGEKaWYodHlwZW9mIGEhPSJvYmplY3QiKXtpZih0eXBlb2YgYT09ImZ1bmN0aW9uIily
+ZXR1cm4gSi5hZC5wcm90b3R5cGUKcmV0dXJuIGF9aWYoYSBpbnN0YW5jZW9mIFAudClyZXR1cm4gYQpy
+ZXR1cm4gSi5kTihhKX0sCmpqOmZ1bmN0aW9uKGEsYil7aWYodHlwZW9mIGE9PSJudW1iZXIiJiZ0eXBl
+b2YgYj09Im51bWJlciIpcmV0dXJuIGErYgpyZXR1cm4gSi5sbihhKS5CKGEsYil9LApjczpmdW5jdGlv
+bihhLGIpe2lmKGE9PW51bGwpcmV0dXJuIGI9PW51bGwKaWYodHlwZW9mIGEhPSJvYmplY3QiKXJldHVy
+biBiIT1udWxsJiZhPT09YgpyZXR1cm4gSi5hRShhKS5HKGEsYil9LApmVzpmdW5jdGlvbihhLGIpe2lm
+KHR5cGVvZiBiPT09Im51bWJlciIpaWYoYS5jb25zdHJ1Y3Rvcj09QXJyYXl8fHR5cGVvZiBhPT0ic3Ry
+aW5nInx8SC5seChhLGFbdi5kaXNwYXRjaFByb3BlcnR5TmFtZV0pKWlmKGI+Pj4wPT09YiYmYjxhLmxl
+bmd0aClyZXR1cm4gYVtiXQpyZXR1cm4gSi5hXyhhKS5qKGEsYil9LApqazpmdW5jdGlvbihhKXtyZXR1
+cm4gSi5FKGEpLmJNKGEpfSwKaEQ6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gSi5hMChhKS50KGEsYil9LApq
+bDpmdW5jdGlvbihhLGIsYyxkKXtyZXR1cm4gSi5FKGEpLmI3KGEsYixjLGQpfSwKam06ZnVuY3Rpb24o
+YSxiKXtyZXR1cm4gSi5ocShhKS5PKGEsYil9LApqbjpmdW5jdGlvbihhLGIsYyxkKXtyZXR1cm4gSi5F
+KGEpLmNiKGEsYixjLGQpfSwKam86ZnVuY3Rpb24oYSl7cmV0dXJuIEouRShhKS5nYzAoYSl9LAphbDpm
+dW5jdGlvbihhKXtyZXR1cm4gSi5FKGEpLmdDKGEpfSwKYnY6ZnVuY3Rpb24oYSl7cmV0dXJuIEouYUUo
+YSkuZ3EoYSl9LAphOTpmdW5jdGlvbihhKXtyZXR1cm4gSi5ocShhKS5nRihhKX0sCmF0OmZ1bmN0aW9u
+KGEpe3JldHVybiBKLmFfKGEpLmdtKGEpfSwKZFA6ZnVuY3Rpb24oYSl7cmV0dXJuIEouRShhKS5nYUco
+YSl9LApqcDpmdW5jdGlvbihhLGIsYyl7cmV0dXJuIEouaHEoYSkuYUYoYSxiLGMpfSwKanE6ZnVuY3Rp
+b24oYSxiKXtyZXR1cm4gSi5hRShhKS5haChhLGIpfSwKaEU6ZnVuY3Rpb24oYSl7cmV0dXJuIEouRShh
+KS5jbihhKX0sCmpyOmZ1bmN0aW9uKGEsYixjLGQpe3JldHVybiBKLmEwKGEpLmEwKGEsYixjLGQpfSwK
+aEY6ZnVuY3Rpb24oYSl7cmV0dXJuIEouRShhKS5idChhKX0sCmRROmZ1bmN0aW9uKGEsYil7cmV0dXJu
+IEouRShhKS5zYWYoYSxiKX0sCmhHOmZ1bmN0aW9uKGEsYixjKXtyZXR1cm4gSi5FKGEpLmE2KGEsYixj
+KX0sCmN0OmZ1bmN0aW9uKGEsYixjKXtyZXR1cm4gSi5hMChhKS5TKGEsYixjKX0sCmpzOmZ1bmN0aW9u
+KGEsYil7cmV0dXJuIEouYTAoYSkuVShhLGIpfSwKaEg6ZnVuY3Rpb24oYSxiLGMpe3JldHVybiBKLmEw
+KGEpLm4oYSxiLGMpfSwKanQ6ZnVuY3Rpb24oYSl7cmV0dXJuIEouYTAoYSkuY3IoYSl9LApiMjpmdW5j
+dGlvbihhKXtyZXR1cm4gSi5hRShhKS5pKGEpfSwKZFI6ZnVuY3Rpb24oYSl7cmV0dXJuIEouYTAoYSku
+Y3MoYSl9LApJOmZ1bmN0aW9uIEkoKXt9LApjSDpmdW5jdGlvbiBjSCgpe30sCmJKOmZ1bmN0aW9uIGJK
+KCl7fSwKYXk6ZnVuY3Rpb24gYXkoKXt9LApjWjpmdW5jdGlvbiBjWigpe30sCmJrOmZ1bmN0aW9uIGJr
+KCl7fSwKYWQ6ZnVuY3Rpb24gYWQoKXt9LApGOmZ1bmN0aW9uIEYoYSl7dGhpcy4kdGk9YX0sCmU3OmZ1
+bmN0aW9uIGU3KGEpe3RoaXMuJHRpPWF9LAphRjpmdW5jdGlvbiBhRihhLGIsYyl7dmFyIF89dGhpcwpf
+LmE9YQpfLmI9YgpfLmM9MApfLmQ9bnVsbApfLiR0aT1jfSwKYmE6ZnVuY3Rpb24gYmEoKXt9LApiSTpm
+dW5jdGlvbiBiSSgpe30sCmNJOmZ1bmN0aW9uIGNJKCl7fSwKYXg6ZnVuY3Rpb24gYXgoKXt9fSxQPXsK
+a2Y6ZnVuY3Rpb24oKXt2YXIgdCxzLHI9e30KaWYoc2VsZi5zY2hlZHVsZUltbWVkaWF0ZSE9bnVsbCly
+ZXR1cm4gUC5saCgpCmlmKHNlbGYuTXV0YXRpb25PYnNlcnZlciE9bnVsbCYmc2VsZi5kb2N1bWVudCE9
+bnVsbCl7dD1zZWxmLmRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImRpdiIpCnM9c2VsZi5kb2N1bWVudC5j
+cmVhdGVFbGVtZW50KCJzcGFuIikKci5hPW51bGwKbmV3IHNlbGYuTXV0YXRpb25PYnNlcnZlcihILmRN
+KG5ldyBQLmV0KHIpLDEpKS5vYnNlcnZlKHQse2NoaWxkTGlzdDp0cnVlfSkKcmV0dXJuIG5ldyBQLmVz
+KHIsdCxzKX1lbHNlIGlmKHNlbGYuc2V0SW1tZWRpYXRlIT1udWxsKXJldHVybiBQLmxpKCkKcmV0dXJu
+IFAubGooKX0sCmtnOmZ1bmN0aW9uKGEpe3NlbGYuc2NoZWR1bGVJbW1lZGlhdGUoSC5kTShuZXcgUC5l
+dSh1Lk0uYihhKSksMCkpfSwKa2g6ZnVuY3Rpb24oYSl7c2VsZi5zZXRJbW1lZGlhdGUoSC5kTShuZXcg
+UC5ldih1Lk0uYihhKSksMCkpfSwKa2k6ZnVuY3Rpb24oYSl7UC5oNyhDLk0sdS5NLmIoYSkpfSwKaDc6
+ZnVuY3Rpb24oYSxiKXt2YXIgdD1DLmMuYWIoYS5hLDEwMDApCnJldHVybiBQLmt0KHQ8MD8wOnQsYil9
+LAprdDpmdW5jdGlvbihhLGIpe3ZhciB0PW5ldyBQLmRDKCkKdC5iRihhLGIpCnJldHVybiB0fSwKaTk6
+ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIKYi5hPTEKdHJ5e2EuYm4obmV3IFAuZUcoYiksbmV3IFAuZUgo
+YiksdS5QKX1jYXRjaChyKXt0PUguUShyKQpzPUguY3AocikKUC5sRihuZXcgUC5lSShiLHQscykpfX0s
+CmVGOmZ1bmN0aW9uKGEsYil7dmFyIHQscyxyCmZvcih0PXUuXztzPWEuYSxzPT09MjspYT10LmIoYS5j
+KQppZihzPj00KXtyPWIuYTkoKQpiLmE9YS5hCmIuYz1hLmMKUC5ibyhiLHIpfWVsc2V7cj11LnguYihi
+LmMpCmIuYT0yCmIuYz1hCmEuYjIocil9fSwKYm86ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIscSxwLG8s
+bixtLGwsayxqLGksaCxnLGYsZT1udWxsLGQ9e30sYz1kLmE9YQpmb3IodD11Lm4scz11Lngscj11LmM7
+ITA7KXtxPXt9CnA9Yy5hPT09OAppZihiPT1udWxsKXtpZihwKXtvPXQuYihjLmMpClAuZmUoZSxlLGMu
+YixvLmEsby5iKX1yZXR1cm59Zm9yKDtuPWIuYSxuIT1udWxsO2I9bil7Yi5hPW51bGwKUC5ibyhkLmEs
+Yil9Yz1kLmEKbT1jLmMKcS5hPXAKcS5iPW0KbD0hcAppZihsKXtrPWIuYwprPShrJjEpIT09MHx8KGsm
+MTUpPT09OH1lbHNlIGs9ITAKaWYoayl7az1iLmIKaj1rLmIKaWYocCl7aT1jLmI9PT1qCmk9IShpfHxp
+KX1lbHNlIGk9ITEKaWYoaSl7dC5iKG0pClAuZmUoZSxlLGMuYixtLmEsbS5iKQpyZXR1cm59aD0kLncK
+aWYoaCE9PWopJC53PWoKZWxzZSBoPWUKYz1iLmMKaWYoKGMmMTUpPT09OCluZXcgUC5lTihkLHEsYixw
+KS4kMCgpCmVsc2UgaWYobCl7aWYoKGMmMSkhPT0wKW5ldyBQLmVNKHEsYixtKS4kMCgpfWVsc2UgaWYo
+KGMmMikhPT0wKW5ldyBQLmVMKGQscSxiKS4kMCgpCmlmKGghPW51bGwpJC53PWgKYz1xLmIKaWYoci5j
+KGMpKXtpZihjLmE+PTQpe2c9cy5iKGsuYykKay5jPW51bGwKYj1rLmFhKGcpCmsuYT1jLmEKay5jPWMu
+YwpkLmE9Ywpjb250aW51ZX1lbHNlIFAuZUYoYyxrKQpyZXR1cm59fWY9Yi5iCmc9cy5iKGYuYykKZi5j
+PW51bGwKYj1mLmFhKGcpCmM9cS5hCmw9cS5iCmlmKCFjKXtmLiR0aS5kLmIobCkKZi5hPTQKZi5jPWx9
+ZWxzZXt0LmIobCkKZi5hPTgKZi5jPWx9ZC5hPWYKYz1mfX0sCml6OmZ1bmN0aW9uKGEsYil7dmFyIHQ9
+dS5ZCmlmKHQuYyhhKSlyZXR1cm4gdC5iKGEpCnQ9dS55CmlmKHQuYyhhKSlyZXR1cm4gdC5iKGEpCnRo
+cm93IEguYShQLmZYKGEsIm9uRXJyb3IiLCJFcnJvciBoYW5kbGVyIG11c3QgYWNjZXB0IG9uZSBPYmpl
+Y3Qgb3Igb25lIE9iamVjdCBhbmQgYSBTdGFja1RyYWNlIGFzIGFyZ3VtZW50cywgYW5kIHJldHVybiBh
+IGEgdmFsaWQgcmVzdWx0IikpfSwKbDc6ZnVuY3Rpb24oKXt2YXIgdCxzCmZvcig7dD0kLmJzLHQhPW51
+bGw7KXskLmNvPW51bGwKcz10LmIKJC5icz1zCmlmKHM9PW51bGwpJC5jbj1udWxsCnQuYS4kMCgpfX0s
+CmxjOmZ1bmN0aW9uKCl7JC5obT0hMAp0cnl7UC5sNygpfWZpbmFsbHl7JC5jbz1udWxsCiQuaG09ITEK
+aWYoJC5icyE9bnVsbCkkLmhBKCkuJDEoUC5pSSgpKX19LAppRTpmdW5jdGlvbihhKXt2YXIgdD1uZXcg
+UC5kaChhKQppZigkLmJzPT1udWxsKXskLmJzPSQuY249dAppZighJC5obSkkLmhBKCkuJDEoUC5pSSgp
+KX1lbHNlICQuY249JC5jbi5iPXR9LApsYjpmdW5jdGlvbihhKXt2YXIgdCxzLHI9JC5icwppZihyPT1u
+dWxsKXtQLmlFKGEpCiQuY289JC5jbgpyZXR1cm59dD1uZXcgUC5kaChhKQpzPSQuY28KaWYocz09bnVs
+bCl7dC5iPXIKJC5icz0kLmNvPXR9ZWxzZXt0LmI9cy5iCiQuY289cy5iPXQKaWYodC5iPT1udWxsKSQu
+Y249dH19LApsRjpmdW5jdGlvbihhKXt2YXIgdD1udWxsLHM9JC53CmlmKEMuZD09PXMpe1AuYnQodCx0
+LEMuZCxhKQpyZXR1cm59UC5idCh0LHQscyx1Lk0uYihzLmF6KGEpKSl9LAprNzpmdW5jdGlvbihhLGIp
+e3ZhciB0PSQudwppZih0PT09Qy5kKXJldHVybiBQLmg3KGEsdS5NLmIoYikpCnJldHVybiBQLmg3KGEs
+dS5NLmIodC5heihiKSkpfSwKZmU6ZnVuY3Rpb24oYSxiLGMsZCxlKXt2YXIgdD17fQp0LmE9ZApQLmxi
+KG5ldyBQLmZmKHQsZSkpfSwKaUE6ZnVuY3Rpb24oYSxiLGMsZCxlKXt2YXIgdCxzPSQudwppZihzPT09
+YylyZXR1cm4gZC4kMCgpCiQudz1jCnQ9cwp0cnl7cz1kLiQwKCkKcmV0dXJuIHN9ZmluYWxseXskLnc9
+dH19LAppQjpmdW5jdGlvbihhLGIsYyxkLGUsZixnKXt2YXIgdCxzPSQudwppZihzPT09YylyZXR1cm4g
+ZC4kMShlKQokLnc9Ywp0PXMKdHJ5e3M9ZC4kMShlKQpyZXR1cm4gc31maW5hbGx5eyQudz10fX0sCmw5
+OmZ1bmN0aW9uKGEsYixjLGQsZSxmLGcsaCxpKXt2YXIgdCxzPSQudwppZihzPT09YylyZXR1cm4gZC4k
+MihlLGYpCiQudz1jCnQ9cwp0cnl7cz1kLiQyKGUsZikKcmV0dXJuIHN9ZmluYWxseXskLnc9dH19LApi
+dDpmdW5jdGlvbihhLGIsYyxkKXt2YXIgdAp1Lk0uYihkKQp0PUMuZCE9PWMKaWYodClkPSEoIXR8fCEx
+KT9jLmF6KGQpOmMuYzEoZCx1LkgpClAuaUUoZCl9LApldDpmdW5jdGlvbiBldChhKXt0aGlzLmE9YX0s
+CmVzOmZ1bmN0aW9uIGVzKGEsYixjKXt0aGlzLmE9YQp0aGlzLmI9Ygp0aGlzLmM9Y30sCmV1OmZ1bmN0
+aW9uIGV1KGEpe3RoaXMuYT1hfSwKZXY6ZnVuY3Rpb24gZXYoYSl7dGhpcy5hPWF9LApkQzpmdW5jdGlv
+biBkQygpe3RoaXMuYj1udWxsfSwKZl86ZnVuY3Rpb24gZl8oYSxiKXt0aGlzLmE9YQp0aGlzLmI9Yn0s
+CmMyOmZ1bmN0aW9uIGMyKCl7fSwKYzA6ZnVuY3Rpb24gYzAoYSxiKXt0aGlzLmE9YQp0aGlzLiR0aT1i
+fSwKYVo6ZnVuY3Rpb24gYVooYSxiLGMsZCxlKXt2YXIgXz10aGlzCl8uYT1udWxsCl8uYj1hCl8uYz1i
+Cl8uZD1jCl8uZT1kCl8uJHRpPWV9LApTOmZ1bmN0aW9uIFMoYSxiKXt2YXIgXz10aGlzCl8uYT0wCl8u
+Yj1hCl8uYz1udWxsCl8uJHRpPWJ9LAplQzpmdW5jdGlvbiBlQyhhLGIpe3RoaXMuYT1hCnRoaXMuYj1i
+fSwKZUs6ZnVuY3Rpb24gZUsoYSxiKXt0aGlzLmE9YQp0aGlzLmI9Yn0sCmVHOmZ1bmN0aW9uIGVHKGEp
+e3RoaXMuYT1hfSwKZUg6ZnVuY3Rpb24gZUgoYSl7dGhpcy5hPWF9LAplSTpmdW5jdGlvbiBlSShhLGIs
+Yyl7dGhpcy5hPWEKdGhpcy5iPWIKdGhpcy5jPWN9LAplRTpmdW5jdGlvbiBlRShhLGIpe3RoaXMuYT1h
+CnRoaXMuYj1ifSwKZUo6ZnVuY3Rpb24gZUooYSxiKXt0aGlzLmE9YQp0aGlzLmI9Yn0sCmVEOmZ1bmN0
+aW9uIGVEKGEsYixjKXt0aGlzLmE9YQp0aGlzLmI9Ygp0aGlzLmM9Y30sCmVOOmZ1bmN0aW9uIGVOKGEs
+YixjLGQpe3ZhciBfPXRoaXMKXy5hPWEKXy5iPWIKXy5jPWMKXy5kPWR9LAplTzpmdW5jdGlvbiBlTyhh
+KXt0aGlzLmE9YX0sCmVNOmZ1bmN0aW9uIGVNKGEsYixjKXt0aGlzLmE9YQp0aGlzLmI9Ygp0aGlzLmM9
+Y30sCmVMOmZ1bmN0aW9uIGVMKGEsYixjKXt0aGlzLmE9YQp0aGlzLmI9Ygp0aGlzLmM9Y30sCmRoOmZ1
+bmN0aW9uIGRoKGEpe3RoaXMuYT1hCnRoaXMuYj1udWxsfSwKYlk6ZnVuY3Rpb24gYlkoKXt9LAplaDpm
+dW5jdGlvbiBlaChhLGIpe3RoaXMuYT1hCnRoaXMuYj1ifSwKZWk6ZnVuY3Rpb24gZWkoYSxiKXt0aGlz
+LmE9YQp0aGlzLmI9Yn0sCmQ0OmZ1bmN0aW9uIGQ0KCl7fSwKZDU6ZnVuY3Rpb24gZDUoKXt9LAphdTpm
+dW5jdGlvbiBhdShhLGIpe3RoaXMuYT1hCnRoaXMuYj1ifSwKZEc6ZnVuY3Rpb24gZEcoKXt9LApmZjpm
+dW5jdGlvbiBmZihhLGIpe3RoaXMuYT1hCnRoaXMuYj1ifSwKZHg6ZnVuY3Rpb24gZHgoKXt9LAplUjpm
+dW5jdGlvbiBlUihhLGIsYyl7dGhpcy5hPWEKdGhpcy5iPWIKdGhpcy5jPWN9LAplUTpmdW5jdGlvbiBl
+UShhLGIpe3RoaXMuYT1hCnRoaXMuYj1ifSwKZVM6ZnVuY3Rpb24gZVMoYSxiLGMpe3RoaXMuYT1hCnRo
+aXMuYj1iCnRoaXMuYz1jfSwKY086ZnVuY3Rpb24oYSxiLGMpe3JldHVybiBiLmgoIkA8MD4iKS5FKGMp
+LmgoImhTPDEsMj4iKS5iKEgubG0oYSxuZXcgSC5hbihiLmgoIkA8MD4iKS5FKGMpLmgoImFuPDEsMj4i
+KSkpKX0sCmU5OmZ1bmN0aW9uKGEsYil7cmV0dXJuIG5ldyBILmFuKGEuaCgiQDwwPiIpLkUoYikuaCgi
+YW48MSwyPiIpKX0sCmJNOmZ1bmN0aW9uKGEpe3JldHVybiBuZXcgUC5jNihhLmgoImM2PDA+IikpfSwK
+aDk6ZnVuY3Rpb24oKXt2YXIgdD1PYmplY3QuY3JlYXRlKG51bGwpCnRbIjxub24taWRlbnRpZmllci1r
+ZXk+Il09dApkZWxldGUgdFsiPG5vbi1pZGVudGlmaWVyLWtleT4iXQpyZXR1cm4gdH0sCmljOmZ1bmN0
+aW9uKGEsYixjKXt2YXIgdD1uZXcgUC5iMChhLGIsYy5oKCJiMDwwPiIpKQp0LmM9YS5lCnJldHVybiB0
+fSwKakg6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMKaWYoUC5obihhKSl7aWYoYj09PSIoIiYmYz09PSIp
+IilyZXR1cm4iKC4uLikiCnJldHVybiBiKyIuLi4iK2N9dD1ILm4oW10sdS5zKQpDLmIuaygkLlgsYSkK
+dHJ5e1AubDYoYSx0KX1maW5hbGx5e2lmKDA+PSQuWC5sZW5ndGgpcmV0dXJuIEguaSgkLlgsLTEpCiQu
+WC5wb3AoKX1zPVAuaTIoYix1LlIuYih0KSwiLCAiKStjCnJldHVybiBzLmNoYXJDb2RlQXQoMCk9PTA/
+czpzfSwKZTY6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMKaWYoUC5obihhKSlyZXR1cm4gYisiLi4uIitj
+CnQ9bmV3IFAuSChiKQpDLmIuaygkLlgsYSkKdHJ5e3M9dApzLmE9UC5pMihzLmEsYSwiLCAiKX1maW5h
+bGx5e2lmKDA+PSQuWC5sZW5ndGgpcmV0dXJuIEguaSgkLlgsLTEpCiQuWC5wb3AoKX10LmErPWMKcz10
+LmEKcmV0dXJuIHMuY2hhckNvZGVBdCgwKT09MD9zOnN9LApobjpmdW5jdGlvbihhKXt2YXIgdCxzCmZv
+cih0PSQuWC5sZW5ndGgscz0wO3M8dDsrK3MpaWYoYT09PSQuWFtzXSlyZXR1cm4hMApyZXR1cm4hMX0s
+Cmw2OmZ1bmN0aW9uKGEsYil7dmFyIHQscyxyLHEscCxvLG4sbT1hLmdGKGEpLGw9MCxrPTAKd2hpbGUo
+ITApe2lmKCEobDw4MHx8azwzKSlicmVhawppZighbS5wKCkpcmV0dXJuCnQ9SC5iKG0uZ3UoKSkKQy5i
+LmsoYix0KQpsKz10Lmxlbmd0aCsyOysra31pZighbS5wKCkpe2lmKGs8PTUpcmV0dXJuCmlmKDA+PWIu
+bGVuZ3RoKXJldHVybiBILmkoYiwtMSkKcz1iLnBvcCgpCmlmKDA+PWIubGVuZ3RoKXJldHVybiBILmko
+YiwtMSkKcj1iLnBvcCgpfWVsc2V7cT1tLmd1KCk7KytrCmlmKCFtLnAoKSl7aWYoazw9NCl7Qy5iLmso
+YixILmIocSkpCnJldHVybn1zPUguYihxKQppZigwPj1iLmxlbmd0aClyZXR1cm4gSC5pKGIsLTEpCnI9
+Yi5wb3AoKQpsKz1zLmxlbmd0aCsyfWVsc2V7cD1tLmd1KCk7KytrCmZvcig7bS5wKCk7cT1wLHA9byl7
+bz1tLmd1KCk7KytrCmlmKGs+MTAwKXt3aGlsZSghMCl7aWYoIShsPjc1JiZrPjMpKWJyZWFrCmlmKDA+
+PWIubGVuZ3RoKXJldHVybiBILmkoYiwtMSkKbC09Yi5wb3AoKS5sZW5ndGgrMjstLWt9Qy5iLmsoYiwi
+Li4uIikKcmV0dXJufX1yPUguYihxKQpzPUguYihwKQpsKz1zLmxlbmd0aCtyLmxlbmd0aCs0fX1pZihr
+PmIubGVuZ3RoKzIpe2wrPTUKbj0iLi4uIn1lbHNlIG49bnVsbAp3aGlsZSghMCl7aWYoIShsPjgwJiZi
+Lmxlbmd0aD4zKSlicmVhawppZigwPj1iLmxlbmd0aClyZXR1cm4gSC5pKGIsLTEpCmwtPWIucG9wKCku
+bGVuZ3RoKzIKaWYobj09bnVsbCl7bCs9NQpuPSIuLi4ifX1pZihuIT1udWxsKUMuYi5rKGIsbikKQy5i
+LmsoYixyKQpDLmIuayhiLHMpfSwKaFQ6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHI9UC5iTShiKQpmb3Io
+dD1hLmxlbmd0aCxzPTA7czxhLmxlbmd0aDthLmxlbmd0aD09PXR8fCgwLEguY3IpKGEpLCsrcylyLmso
+MCxiLmIoYVtzXSkpCnJldHVybiByfSwKaDM6ZnVuY3Rpb24oYSl7dmFyIHQscz17fQppZihQLmhuKGEp
+KXJldHVybiJ7Li4ufSIKdD1uZXcgUC5IKCIiKQp0cnl7Qy5iLmsoJC5YLGEpCnQuYSs9InsiCnMuYT0h
+MAphLkEoMCxuZXcgUC5lYShzLHQpKQp0LmErPSJ9In1maW5hbGx5e2lmKDA+PSQuWC5sZW5ndGgpcmV0
+dXJuIEguaSgkLlgsLTEpCiQuWC5wb3AoKX1zPXQuYQpyZXR1cm4gcy5jaGFyQ29kZUF0KDApPT0wP3M6
+c30sCmM2OmZ1bmN0aW9uIGM2KGEpe3ZhciBfPXRoaXMKXy5hPTAKXy5mPV8uZT1fLmQ9Xy5jPV8uYj1u
+dWxsCl8ucj0wCl8uJHRpPWF9LApkdTpmdW5jdGlvbiBkdShhKXt0aGlzLmE9YQp0aGlzLmM9dGhpcy5i
+PW51bGx9LApiMDpmdW5jdGlvbiBiMChhLGIsYyl7dmFyIF89dGhpcwpfLmE9YQpfLmI9YgpfLmQ9Xy5j
+PW51bGwKXy4kdGk9Y30sCmJOOmZ1bmN0aW9uIGJOKCl7fSwKbDpmdW5jdGlvbiBsKCl7fSwKYlA6ZnVu
+Y3Rpb24gYlAoKXt9LAplYTpmdW5jdGlvbiBlYShhLGIpe3RoaXMuYT1hCnRoaXMuYj1ifSwKQjpmdW5j
+dGlvbiBCKCl7fSwKY2o6ZnVuY3Rpb24gY2ooKXt9LApiYzpmdW5jdGlvbiBiYygpe30sCmF6OmZ1bmN0
+aW9uIGF6KGEsYil7dGhpcy5hPWEKdGhpcy4kdGk9Yn0sCmFXOmZ1bmN0aW9uIGFXKCl7fSwKYlc6ZnVu
+Y3Rpb24gYlcoKXt9LApjZDpmdW5jdGlvbiBjZCgpe30sCmM3OmZ1bmN0aW9uIGM3KCl7fSwKY2U6ZnVu
+Y3Rpb24gY2UoKXt9LApicTpmdW5jdGlvbiBicSgpe30sCmw4OmZ1bmN0aW9uKGEsYil7dmFyIHQscyxy
+LHEKaWYodHlwZW9mIGEhPSJzdHJpbmciKXRocm93IEguYShILmFzKGEpKQp0PW51bGwKdHJ5e3Q9SlNP
+Ti5wYXJzZShhKX1jYXRjaChyKXtzPUguUShyKQpxPVAuQShTdHJpbmcocyksbnVsbCxudWxsKQp0aHJv
+dyBILmEocSl9cT1QLmY2KHQpCnJldHVybiBxfSwKZjY6ZnVuY3Rpb24oYSl7dmFyIHQKaWYoYT09bnVs
+bClyZXR1cm4gbnVsbAppZih0eXBlb2YgYSE9Im9iamVjdCIpcmV0dXJuIGEKaWYoT2JqZWN0LmdldFBy
+b3RvdHlwZU9mKGEpIT09QXJyYXkucHJvdG90eXBlKXJldHVybiBuZXcgUC5kcyhhLE9iamVjdC5jcmVh
+dGUobnVsbCkpCmZvcih0PTA7dDxhLmxlbmd0aDsrK3QpYVt0XT1QLmY2KGFbdF0pCnJldHVybiBhfSwK
+a2E6ZnVuY3Rpb24oYSxiLGMsZCl7aWYoYiBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkpcmV0dXJuIFAua2Io
+ITEsYixjLGQpCnJldHVybiBudWxsfSwKa2I6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIHQscyxyPSQuamMo
+KQppZihyPT1udWxsKXJldHVybiBudWxsCnQ9MD09PWMKaWYodCYmITApcmV0dXJuIFAuaDgocixiKQpz
+PWIubGVuZ3RoCmQ9UC5hVihjLGQscykKaWYodCYmZD09PXMpcmV0dXJuIFAuaDgocixiKQpyZXR1cm4g
+UC5oOChyLGIuc3ViYXJyYXkoYyxkKSl9LApoODpmdW5jdGlvbihhLGIpe2lmKFAua2QoYikpcmV0dXJu
+IG51bGwKcmV0dXJuIFAua2UoYSxiKX0sCmtlOmZ1bmN0aW9uKGEsYil7dmFyIHQscwp0cnl7dD1hLmRl
+Y29kZShiKQpyZXR1cm4gdH1jYXRjaChzKXtILlEocyl9cmV0dXJuIG51bGx9LAprZDpmdW5jdGlvbihh
+KXt2YXIgdCxzPWEubGVuZ3RoLTIKZm9yKHQ9MDt0PHM7Kyt0KWlmKGFbdF09PT0yMzcpaWYoKGFbdCsx
+XSYyMjQpPT09MTYwKXJldHVybiEwCnJldHVybiExfSwKa2M6ZnVuY3Rpb24oKXt2YXIgdCxzCnRyeXt0
+PW5ldyBUZXh0RGVjb2RlcigidXRmLTgiLHtmYXRhbDp0cnVlfSkKcmV0dXJuIHR9Y2F0Y2gocyl7SC5R
+KHMpfXJldHVybiBudWxsfSwKaUQ6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMscgpmb3IodD1KLmFfKGEp
+LHM9YjtzPGM7KytzKXtyPXQuaihhLHMpCmlmKHR5cGVvZiByIT09Im51bWJlciIpcmV0dXJuIHIuUCgp
+CmlmKChyJjEyNykhPT1yKXJldHVybiBzLWJ9cmV0dXJuIGMtYn0sCmhJOmZ1bmN0aW9uKGEsYixjLGQs
+ZSxmKXtpZihDLmMuYWsoZiw0KSE9PTApdGhyb3cgSC5hKFAuQSgiSW52YWxpZCBiYXNlNjQgcGFkZGlu
+ZywgcGFkZGVkIGxlbmd0aCBtdXN0IGJlIG11bHRpcGxlIG9mIGZvdXIsIGlzICIrZixhLGMpKQppZihk
+K2UhPT1mKXRocm93IEguYShQLkEoIkludmFsaWQgYmFzZTY0IHBhZGRpbmcsICc9JyBub3QgYXQgdGhl
+IGVuZCIsYSxiKSkKaWYoZT4yKXRocm93IEguYShQLkEoIkludmFsaWQgYmFzZTY0IHBhZGRpbmcsIG1v
+cmUgdGhhbiB0d28gJz0nIGNoYXJhY3RlcnMiLGEsYikpfSwKaXg6ZnVuY3Rpb24oYSl7YS5QKDAsNjQ1
+MTIpCnJldHVybiExfSwKa1Y6ZnVuY3Rpb24oYSxiKXtyZXR1cm4oQy5jLkIoNjU1MzYsYS5QKDAsMTAy
+MykuY3YoMCwxMCkpfGImMTAyMyk+Pj4wfSwKZHM6ZnVuY3Rpb24gZHMoYSxiKXt0aGlzLmE9YQp0aGlz
+LmI9Ygp0aGlzLmM9bnVsbH0sCmR0OmZ1bmN0aW9uIGR0KGEpe3RoaXMuYT1hfSwKY3c6ZnVuY3Rpb24g
+Y3coKXt9LApjeDpmdW5jdGlvbiBjeCgpe30sCmEyOmZ1bmN0aW9uIGEyKCl7fSwKYUs6ZnVuY3Rpb24g
+YUsoKXt9LApjRTpmdW5jdGlvbiBjRSgpe30sCmNNOmZ1bmN0aW9uIGNNKCl7fSwKY046ZnVuY3Rpb24g
+Y04oYSl7dGhpcy5hPWF9LApkZDpmdW5jdGlvbiBkZCgpe30sCmRmOmZ1bmN0aW9uIGRmKCl7fSwKZjQ6
+ZnVuY3Rpb24gZjQoYSl7dGhpcy5iPTAKdGhpcy5jPWF9LApkZTpmdW5jdGlvbiBkZShhKXt0aGlzLmE9
+YX0sCmYzOmZ1bmN0aW9uIGYzKGEsYil7dmFyIF89dGhpcwpfLmE9YQpfLmI9YgpfLmM9ITAKXy5mPV8u
+ZT1fLmQ9MH0sCmRPOmZ1bmN0aW9uKGEsYixjKXt2YXIgdD1ILmg0KGEsYykKaWYodCE9bnVsbClyZXR1
+cm4gdAppZihiIT1udWxsKXJldHVybiBiLiQxKGEpCnRocm93IEguYShQLkEoYSxudWxsLG51bGwpKX0s
+CmpHOmZ1bmN0aW9uKGEpe2lmKGEgaW5zdGFuY2VvZiBILmFJKXJldHVybiBhLmkoMCkKcmV0dXJuIklu
+c3RhbmNlIG9mICciK0guYihILmVmKGEpKSsiJyJ9LApoMjpmdW5jdGlvbihhLGIsYyl7dmFyIHQscz1I
+Lm4oW10sYy5oKCJGPDA+IikpCmZvcih0PUouYTkoYSk7dC5wKCk7KUMuYi5rKHMsYy5iKHQuZ3UoKSkp
+CnJldHVybiBzfSwKaDY6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0CmlmKEFycmF5LmlzQXJyYXkoYSkpe3Uu
+dC5iKGEpCnQ9YS5sZW5ndGgKYz1QLmFWKGIsYyx0KQpyZXR1cm4gSC5oWShiPjB8fGM8dD9DLmIuYnUo
+YSxiLGMpOmEpfWlmKHUuYm0uYyhhKSlyZXR1cm4gSC5rMChhLGIsUC5hVihiLGMsYS5sZW5ndGgpKQpy
+ZXR1cm4gUC5rNShhLGIsYyl9LAprNTpmdW5jdGlvbihhLGIsYyl7dmFyIHQscyxyLHEscD1udWxsCmlm
+KGI8MCl0aHJvdyBILmEoUC5MKGIsMCxKLmF0KGEpLHAscCkpCnQ9Yz09bnVsbAppZighdCYmYzxiKXRo
+cm93IEguYShQLkwoYyxiLEouYXQoYSkscCxwKSkKcz1KLmE5KGEpCmZvcihyPTA7cjxiOysrcilpZigh
+cy5wKCkpdGhyb3cgSC5hKFAuTChiLDAscixwLHApKQpxPVtdCmlmKHQpZm9yKDtzLnAoKTspcS5wdXNo
+KHMuZ3UoKSkKZWxzZSBmb3Iocj1iO3I8YzsrK3Ipe2lmKCFzLnAoKSl0aHJvdyBILmEoUC5MKGMsYixy
+LHAscCkpCnEucHVzaChzLmd1KCkpfXJldHVybiBILmhZKHEpfSwKaV86ZnVuY3Rpb24oYSl7cmV0dXJu
+IG5ldyBILmNLKGEsSC5qTShhLCExLCEwLCExLCExLCExKSl9LAppMjpmdW5jdGlvbihhLGIsYyl7dmFy
+IHQ9Si5hOShiKQppZighdC5wKCkpcmV0dXJuIGEKaWYoYy5sZW5ndGg9PT0wKXtkbyBhKz1ILmIodC5n
+dSgpKQp3aGlsZSh0LnAoKSl9ZWxzZXthKz1ILmIodC5ndSgpKQpmb3IoO3QucCgpOylhPWErYytILmIo
+dC5ndSgpKX1yZXR1cm4gYX0sCmhVOmZ1bmN0aW9uKGEsYixjLGQpe3JldHVybiBuZXcgUC5jVShhLGIs
+YyxkKX0sCmtSOmZ1bmN0aW9uKGEsYixjLGQpe3ZhciB0LHMscixxLHAsbyxuPSIwMTIzNDU2Nzg5QUJD
+REVGIgppZihjPT09Qy5mKXt0PSQuamYoKS5iCnQ9dC50ZXN0KGIpfWVsc2UgdD0hMQppZih0KXJldHVy
+biBiCkgudihjKS5oKCJhMi5TIikuYihiKQpzPWMuZ2NhKCkuYUEoYikKZm9yKHQ9cy5sZW5ndGgscj0w
+LHE9IiI7cjx0Oysrcil7cD1zW3JdCmlmKHA8MTI4KXtvPXA+Pj40CmlmKG8+PTgpcmV0dXJuIEguaShh
+LG8pCm89KGFbb10mMTw8KHAmMTUpKSE9PTB9ZWxzZSBvPSExCmlmKG8pcSs9SC5kXyhwKQplbHNlIHE9
+ZCYmcD09PTMyP3ErIisiOnErIiUiK25bcD4+PjQmMTVdK25bcCYxNV19cmV0dXJuIHEuY2hhckNvZGVB
+dCgwKT09MD9xOnF9LApqRDpmdW5jdGlvbihhKXt2YXIgdD1NYXRoLmFicyhhKSxzPWE8MD8iLSI6IiIK
+aWYodD49MTAwMClyZXR1cm4iIithCmlmKHQ+PTEwMClyZXR1cm4gcysiMCIrdAppZih0Pj0xMClyZXR1
+cm4gcysiMDAiK3QKcmV0dXJuIHMrIjAwMCIrdH0sCmpFOmZ1bmN0aW9uKGEpe2lmKGE+PTEwMClyZXR1
+cm4iIithCmlmKGE+PTEwKXJldHVybiIwIithCnJldHVybiIwMCIrYX0sCmNDOmZ1bmN0aW9uKGEpe2lm
+KGE+PTEwKXJldHVybiIiK2EKcmV0dXJuIjAiK2F9LAphTTpmdW5jdGlvbihhKXtpZih0eXBlb2YgYT09
+Im51bWJlciJ8fEguZmQoYSl8fG51bGw9PWEpcmV0dXJuIEouYjIoYSkKaWYodHlwZW9mIGE9PSJzdHJp
+bmciKXJldHVybiBKU09OLnN0cmluZ2lmeShhKQpyZXR1cm4gUC5qRyhhKX0sCmZZOmZ1bmN0aW9uKGEp
+e3JldHVybiBuZXcgUC5idyhhKX0sCmI0OmZ1bmN0aW9uKGEpe3JldHVybiBuZXcgUC5hMSghMSxudWxs
+LG51bGwsYSl9LApmWDpmdW5jdGlvbihhLGIsYyl7cmV0dXJuIG5ldyBQLmExKCEwLGEsYixjKX0sCmVn
+OmZ1bmN0aW9uKGEsYil7cmV0dXJuIG5ldyBQLmFVKG51bGwsbnVsbCwhMCxhLGIsIlZhbHVlIG5vdCBp
+biByYW5nZSIpfSwKTDpmdW5jdGlvbihhLGIsYyxkLGUpe3JldHVybiBuZXcgUC5hVShiLGMsITAsYSxk
+LCJJbnZhbGlkIHZhbHVlIil9LAphVjpmdW5jdGlvbihhLGIsYyl7aWYoMD5hfHxhPmMpdGhyb3cgSC5h
+KFAuTChhLDAsYywic3RhcnQiLG51bGwpKQppZihiIT1udWxsKXtpZihhPmJ8fGI+Yyl0aHJvdyBILmEo
+UC5MKGIsYSxjLCJlbmQiLG51bGwpKQpyZXR1cm4gYn1yZXR1cm4gY30sCmsxOmZ1bmN0aW9uKGEsYil7
+aWYodHlwZW9mIGEhPT0ibnVtYmVyIilyZXR1cm4gYS5EKCkKaWYoYTwwKXRocm93IEguYShQLkwoYSww
+LG51bGwsYixudWxsKSl9LAplNTpmdW5jdGlvbihhLGIsYyxkLGUpe3ZhciB0PUgueChlPT1udWxsP0ou
+YXQoYik6ZSkKcmV0dXJuIG5ldyBQLmNHKHQsITAsYSxjLCJJbmRleCBvdXQgb2YgcmFuZ2UiKX0sCk46
+ZnVuY3Rpb24oYSl7cmV0dXJuIG5ldyBQLmRiKGEpfSwKZWw6ZnVuY3Rpb24oYSl7cmV0dXJuIG5ldyBQ
+LmQ5KGEpfSwKZDI6ZnVuY3Rpb24oYSl7cmV0dXJuIG5ldyBQLmJoKGEpfSwKYXY6ZnVuY3Rpb24oYSl7
+cmV0dXJuIG5ldyBQLmN6KGEpfSwKQTpmdW5jdGlvbihhLGIsYyl7cmV0dXJuIG5ldyBQLmVfKGEsYixj
+KX0sCmpOOmZ1bmN0aW9uKGEsYixjKXt2YXIgdCxzPUgubihbXSxjLmgoIkY8MD4iKSkKQy5iLnNtKHMs
+YSkKZm9yKHQ9MDt0PGE7Kyt0KUMuYi5sKHMsdCxiLiQxKHQpKQpyZXR1cm4gc30sCmk1OmZ1bmN0aW9u
+KGEpe3ZhciB0LHMscixxLHAsbyxuLG0sbCxrLGosaSxoLGcsZixlPW51bGwsZD1hLmxlbmd0aAppZihk
+Pj01KXt0PSgoSi5oRChhLDQpXjU4KSozfEMuYS50KGEsMCleMTAwfEMuYS50KGEsMSleOTd8Qy5hLnQo
+YSwyKV4xMTZ8Qy5hLnQoYSwzKV45Nyk+Pj4wCmlmKHQ9PT0wKXJldHVybiBQLmk0KGQ8ZD9DLmEubihh
+LDAsZCk6YSw1LGUpLmdicCgpCmVsc2UgaWYodD09PTMyKXJldHVybiBQLmk0KEMuYS5uKGEsNSxkKSww
+LGUpLmdicCgpfXM9bmV3IEFycmF5KDgpCnMuZml4ZWQkbGVuZ3RoPUFycmF5CnI9SC5uKHMsdS50KQpD
+LmIubChyLDAsMCkKQy5iLmwociwxLC0xKQpDLmIubChyLDIsLTEpCkMuYi5sKHIsNywtMSkKQy5iLmwo
+ciwzLDApCkMuYi5sKHIsNCwwKQpDLmIubChyLDUsZCkKQy5iLmwociw2LGQpCmlmKFAuaUMoYSwwLGQs
+MCxyKT49MTQpQy5iLmwociw3LGQpCnE9clsxXQppZih0eXBlb2YgcSE9PSJudW1iZXIiKXJldHVybiBx
+LmJyKCkKaWYocT49MClpZihQLmlDKGEsMCxxLDIwLHIpPT09MjApcls3XT1xCnM9clsyXQppZih0eXBl
+b2YgcyE9PSJudW1iZXIiKXJldHVybiBzLkIoKQpwPXMrMQpvPXJbM10Kbj1yWzRdCm09cls1XQpsPXJb
+Nl0KaWYodHlwZW9mIGwhPT0ibnVtYmVyIilyZXR1cm4gbC5EKCkKaWYodHlwZW9mIG0hPT0ibnVtYmVy
+IilyZXR1cm4gSC5haihtKQppZihsPG0pbT1sCmlmKHR5cGVvZiBuIT09Im51bWJlciIpcmV0dXJuIG4u
+RCgpCmlmKG48cCluPW0KZWxzZSBpZihuPD1xKW49cSsxCmlmKHR5cGVvZiBvIT09Im51bWJlciIpcmV0
+dXJuIG8uRCgpCmlmKG88cClvPW4Kcz1yWzddCmlmKHR5cGVvZiBzIT09Im51bWJlciIpcmV0dXJuIHMu
+RCgpCms9czwwCmlmKGspaWYocD5xKzMpe2o9ZQprPSExfWVsc2V7cz1vPjAKaWYocyYmbysxPT09bil7
+aj1lCms9ITF9ZWxzZXtpZighKG08ZCYmbT09PW4rMiYmSi5jdChhLCIuLiIsbikpKWk9bT5uKzImJkou
+Y3QoYSwiLy4uIixtLTMpCmVsc2UgaT0hMAppZihpKXtqPWUKaz0hMX1lbHNle2lmKHE9PT00KWlmKEou
+Y3QoYSwiZmlsZSIsMCkpe2lmKHA8PTApe2lmKCFDLmEuUyhhLCIvIixuKSl7aD0iZmlsZTovLy8iCnQ9
+M31lbHNle2g9ImZpbGU6Ly8iCnQ9Mn1hPWgrQy5hLm4oYSxuLGQpCnEtPTAKcz10LTAKbSs9cwpsKz1z
+CmQ9YS5sZW5ndGgKcD03Cm89NwpuPTd9ZWxzZSBpZihuPT09bSl7Zz1tKzE7KytsCmE9Qy5hLmEwKGEs
+bixtLCIvIik7KytkCm09Z31qPSJmaWxlIn1lbHNlIGlmKEMuYS5TKGEsImh0dHAiLDApKXtpZihzJiZv
+KzM9PT1uJiZDLmEuUyhhLCI4MCIsbysxKSl7Zj1uLTMKbS09MwpsLT0zCmE9Qy5hLmEwKGEsbyxuLCIi
+KQpkLT0zCm49Zn1qPSJodHRwIn1lbHNlIGo9ZQplbHNlIGlmKHE9PT01JiZKLmN0KGEsImh0dHBzIiww
+KSl7aWYocyYmbys0PT09biYmSi5jdChhLCI0NDMiLG8rMSkpe2Y9bi00Cm0tPTQKbC09NAphPUouanIo
+YSxvLG4sIiIpCmQtPTMKbj1mfWo9Imh0dHBzIn1lbHNlIGo9ZQprPSEwfX19ZWxzZSBqPWUKaWYoayl7
+cz1hLmxlbmd0aAppZihkPHMpe2E9Si5oSChhLDAsZCkKcS09MApwLT0wCm8tPTAKbi09MAptLT0wCmwt
+PTB9cmV0dXJuIG5ldyBQLmR6KGEscSxwLG8sbixtLGwsail9cmV0dXJuIFAua0MoYSwwLGQscSxwLG8s
+bixtLGwsail9LAppNzpmdW5jdGlvbihhKXt2YXIgdD11Lk4KcmV0dXJuIEMuYi5jYyhILm4oYS5zcGxp
+dCgiJiIpLHUucyksUC5lOSh0LHQpLG5ldyBQLmVxKEMuZiksdS5mKX0sCms5OmZ1bmN0aW9uKGEsYixj
+KXt2YXIgdCxzLHIscSxwLG8sbixtPW51bGwsbD0iSVB2NCBhZGRyZXNzIHNob3VsZCBjb250YWluIGV4
+YWN0bHkgNCBwYXJ0cyIsaz0iZWFjaCBwYXJ0IG11c3QgYmUgaW4gdGhlIHJhbmdlIDAuLjI1NSIsaj1u
+ZXcgUC5lbihhKSxpPW5ldyBVaW50OEFycmF5KDQpCmZvcih0PWkubGVuZ3RoLHM9YixyPXMscT0wO3M8
+YzsrK3Mpe3A9Qy5hLnYoYSxzKQppZihwIT09NDYpe2lmKChwXjQ4KT45KWouJDIoImludmFsaWQgY2hh
+cmFjdGVyIixzKX1lbHNle2lmKHE9PT0zKWouJDIobCxzKQpvPVAuZE8oQy5hLm4oYSxyLHMpLG0sbSkK
+aWYodHlwZW9mIG8hPT0ibnVtYmVyIilyZXR1cm4gby5hTSgpCmlmKG8+MjU1KWouJDIoayxyKQpuPXEr
+MQppZihxPj10KXJldHVybiBILmkoaSxxKQppW3FdPW8Kcj1zKzEKcT1ufX1pZihxIT09MylqLiQyKGws
+YykKbz1QLmRPKEMuYS5uKGEscixjKSxtLG0pCmlmKHR5cGVvZiBvIT09Im51bWJlciIpcmV0dXJuIG8u
+YU0oKQppZihvPjI1NSlqLiQyKGsscikKaWYocT49dClyZXR1cm4gSC5pKGkscSkKaVtxXT1vCnJldHVy
+biBpfSwKaTY6ZnVuY3Rpb24oYSxiLGEwKXt2YXIgdCxzLHIscSxwLG8sbixtLGwsayxqLGksaCxnLGYs
+ZSxkPW5ldyBQLmVvKGEpLGM9bmV3IFAuZXAoZCxhKQppZihhLmxlbmd0aDwyKWQuJDEoImFkZHJlc3Mg
+aXMgdG9vIHNob3J0IikKdD1ILm4oW10sdS50KQpmb3Iocz1iLHI9cyxxPSExLHA9ITE7czxhMDsrK3Mp
+e289Qy5hLnYoYSxzKQppZihvPT09NTgpe2lmKHM9PT1iKXsrK3MKaWYoQy5hLnYoYSxzKSE9PTU4KWQu
+JDIoImludmFsaWQgc3RhcnQgY29sb24uIixzKQpyPXN9aWYocz09PXIpe2lmKHEpZC4kMigib25seSBv
+bmUgd2lsZGNhcmQgYDo6YCBpcyBhbGxvd2VkIixzKQpDLmIuayh0LC0xKQpxPSEwfWVsc2UgQy5iLmso
+dCxjLiQyKHIscykpCnI9cysxfWVsc2UgaWYobz09PTQ2KXA9ITB9aWYodC5sZW5ndGg9PT0wKWQuJDEo
+InRvbyBmZXcgcGFydHMiKQpuPXI9PT1hMAptPUMuYi5nYWcodCkKaWYobiYmbSE9PS0xKWQuJDIoImV4
+cGVjdGVkIGEgcGFydCBhZnRlciBsYXN0IGA6YCIsYTApCmlmKCFuKWlmKCFwKUMuYi5rKHQsYy4kMihy
+LGEwKSkKZWxzZXtsPVAuazkoYSxyLGEwKQpDLmIuayh0LChsWzBdPDw4fGxbMV0pPj4+MCkKQy5iLmso
+dCwobFsyXTw8OHxsWzNdKT4+PjApfWlmKHEpe2lmKHQubGVuZ3RoPjcpZC4kMSgiYW4gYWRkcmVzcyB3
+aXRoIGEgd2lsZGNhcmQgbXVzdCBoYXZlIGxlc3MgdGhhbiA3IHBhcnRzIil9ZWxzZSBpZih0Lmxlbmd0
+aCE9PTgpZC4kMSgiYW4gYWRkcmVzcyB3aXRob3V0IGEgd2lsZGNhcmQgbXVzdCBjb250YWluIGV4YWN0
+bHkgOCBwYXJ0cyIpCms9bmV3IFVpbnQ4QXJyYXkoMTYpCmZvcihtPXQubGVuZ3RoLGo9ay5sZW5ndGgs
+aT05LW0scz0wLGg9MDtzPG07KytzKXtnPXRbc10KaWYoZz09PS0xKWZvcihmPTA7ZjxpOysrZil7aWYo
+aDwwfHxoPj1qKXJldHVybiBILmkoayxoKQprW2hdPTAKZT1oKzEKaWYoZT49ailyZXR1cm4gSC5pKGss
+ZSkKa1tlXT0wCmgrPTJ9ZWxzZXtlPUMuYy5aKGcsOCkKaWYoaDwwfHxoPj1qKXJldHVybiBILmkoayxo
+KQprW2hdPWUKZT1oKzEKaWYoZT49ailyZXR1cm4gSC5pKGssZSkKa1tlXT1nJjI1NQpoKz0yfX1yZXR1
+cm4ga30sCmtDOmZ1bmN0aW9uKGEsYixjLGQsZSxmLGcsaCxpLGope3ZhciB0LHMscixxLHAsbyxuLG09
+bnVsbAppZihqPT1udWxsKWlmKGQ+YilqPVAua0woYSxiLGQpCmVsc2V7aWYoZD09PWIpUC5icihhLGIs
+IkludmFsaWQgZW1wdHkgc2NoZW1lIikKaj0iIn1pZihlPmIpe3Q9ZCszCnM9dDxlP1Aua00oYSx0LGUt
+MSk6IiIKcj1QLmtIKGEsZSxmLCExKQppZih0eXBlb2YgZiE9PSJudW1iZXIiKXJldHVybiBmLkIoKQpx
+PWYrMQppZih0eXBlb2YgZyE9PSJudW1iZXIiKXJldHVybiBILmFqKGcpCnA9cTxnP1Aua0ooUC5kTyhK
+LmhIKGEscSxnKSxuZXcgUC5mMShhLGYpLG0pLGopOm19ZWxzZXtwPW0Kcj1wCnM9IiJ9bz1QLmtJKGEs
+ZyxoLG0saixyIT1udWxsKQppZih0eXBlb2YgaCE9PSJudW1iZXIiKXJldHVybiBoLkQoKQpuPWg8aT9Q
+LmtLKGEsaCsxLGksbSk6bQpyZXR1cm4gbmV3IFAuY2soaixzLHIscCxvLG4saTxjP1Aua0coYSxpKzEs
+Yyk6bSl9LAppazpmdW5jdGlvbihhKXtpZihhPT09Imh0dHAiKXJldHVybiA4MAppZihhPT09Imh0dHBz
+IilyZXR1cm4gNDQzCnJldHVybiAwfSwKYnI6ZnVuY3Rpb24oYSxiLGMpe3Rocm93IEguYShQLkEoYyxh
+LGIpKX0sCmtKOmZ1bmN0aW9uKGEsYil7aWYoYSE9bnVsbCYmYT09PVAuaWsoYikpcmV0dXJuIG51bGwK
+cmV0dXJuIGF9LAprSDpmdW5jdGlvbihhLGIsYyxkKXt2YXIgdCxzLHIscSxwLG8KaWYoYT09bnVsbCly
+ZXR1cm4gbnVsbAppZihiPT09YylyZXR1cm4iIgppZihDLmEudihhLGIpPT09OTEpe2lmKHR5cGVvZiBj
+IT09Im51bWJlciIpcmV0dXJuIGMuY3coKQp0PWMtMQppZihDLmEudihhLHQpIT09OTMpUC5icihhLGIs
+Ik1pc3NpbmcgZW5kIGBdYCB0byBtYXRjaCBgW2AgaW4gaG9zdCIpCnM9YisxCnI9UC5rRShhLHMsdCkK
+aWYodHlwZW9mIHIhPT0ibnVtYmVyIilyZXR1cm4gci5EKCkKaWYocjx0KXtxPXIrMQpwPVAuaXEoYSxD
+LmEuUyhhLCIyNSIscSk/ciszOnEsdCwiJTI1Iil9ZWxzZSBwPSIiClAuaTYoYSxzLHIpCnJldHVybiBD
+LmEubihhLGIscikudG9Mb3dlckNhc2UoKStwKyJdIn1pZih0eXBlb2YgYyE9PSJudW1iZXIiKXJldHVy
+biBILmFqKGMpCm89Ygpmb3IoO288YzsrK28paWYoQy5hLnYoYSxvKT09PTU4KXtyPUMuYS5hZShhLCIl
+IixiKQppZighKHI+PWImJnI8Yykpcj1jCmlmKHI8Yyl7cT1yKzEKcD1QLmlxKGEsQy5hLlMoYSwiMjUi
+LHEpP3IrMzpxLGMsIiUyNSIpfWVsc2UgcD0iIgpQLmk2KGEsYixyKQpyZXR1cm4iWyIrQy5hLm4oYSxi
+LHIpK3ArIl0ifXJldHVybiBQLmtPKGEsYixjKX0sCmtFOmZ1bmN0aW9uKGEsYixjKXt2YXIgdCxzPUMu
+YS5hZShhLCIlIixiKQppZihzPj1iKXtpZih0eXBlb2YgYyE9PSJudW1iZXIiKXJldHVybiBILmFqKGMp
+CnQ9czxjfWVsc2UgdD0hMQpyZXR1cm4gdD9zOmN9LAppcTpmdW5jdGlvbihhLGIsYyxkKXt2YXIgdCxz
+LHIscSxwLG8sbixtLGwsaz1kIT09IiI/bmV3IFAuSChkKTpudWxsCmlmKHR5cGVvZiBjIT09Im51bWJl
+ciIpcmV0dXJuIEguYWooYykKdD1iCnM9dApyPSEwCmZvcig7dDxjOyl7cT1DLmEudihhLHQpCmlmKHE9
+PT0zNyl7cD1QLmhlKGEsdCwhMCkKbz1wPT1udWxsCmlmKG8mJnIpe3QrPTMKY29udGludWV9aWYoaz09
+bnVsbClrPW5ldyBQLkgoIiIpCm49ay5hKz1DLmEubihhLHMsdCkKaWYobylwPUMuYS5uKGEsdCx0KzMp
+CmVsc2UgaWYocD09PSIlIilQLmJyKGEsdCwiWm9uZUlEIHNob3VsZCBub3QgY29udGFpbiAlIGFueW1v
+cmUiKQprLmE9bitwCnQrPTMKcz10CnI9ITB9ZWxzZXtpZihxPDEyNyl7bz1xPj4+NAppZihvPj04KXJl
+dHVybiBILmkoQy5rLG8pCm89KEMua1tvXSYxPDwocSYxNSkpIT09MH1lbHNlIG89ITEKaWYobyl7aWYo
+ciYmNjU8PXEmJjkwPj1xKXtpZihrPT1udWxsKWs9bmV3IFAuSCgiIikKaWYoczx0KXtrLmErPUMuYS5u
+KGEscyx0KQpzPXR9cj0hMX0rK3R9ZWxzZXtpZigocSY2NDUxMik9PT01NTI5NiYmdCsxPGMpe209Qy5h
+LnYoYSx0KzEpCmlmKChtJjY0NTEyKT09PTU2MzIwKXtxPTY1NTM2fChxJjEwMjMpPDwxMHxtJjEwMjMK
+bD0yfWVsc2UgbD0xfWVsc2UgbD0xCmlmKGs9PW51bGwpaz1uZXcgUC5IKCIiKQprLmErPUMuYS5uKGEs
+cyx0KQprLmErPVAuaGQocSkKdCs9bApzPXR9fX1pZihrPT1udWxsKXJldHVybiBDLmEubihhLGIsYykK
+aWYoczxjKWsuYSs9Qy5hLm4oYSxzLGMpCm89ay5hCnJldHVybiBvLmNoYXJDb2RlQXQoMCk9PTA/bzpv
+fSwKa086ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMscixxLHAsbyxuLG0sbCxrLGoKaWYodHlwZW9mIGMh
+PT0ibnVtYmVyIilyZXR1cm4gSC5haihjKQp0PWIKcz10CnI9bnVsbApxPSEwCmZvcig7dDxjOyl7cD1D
+LmEudihhLHQpCmlmKHA9PT0zNyl7bz1QLmhlKGEsdCwhMCkKbj1vPT1udWxsCmlmKG4mJnEpe3QrPTMK
+Y29udGludWV9aWYocj09bnVsbClyPW5ldyBQLkgoIiIpCm09Qy5hLm4oYSxzLHQpCmw9ci5hKz0hcT9t
+LnRvTG93ZXJDYXNlKCk6bQppZihuKXtvPUMuYS5uKGEsdCx0KzMpCms9M31lbHNlIGlmKG89PT0iJSIp
+e289IiUyNSIKaz0xfWVsc2Ugaz0zCnIuYT1sK28KdCs9awpzPXQKcT0hMH1lbHNle2lmKHA8MTI3KXtu
+PXA+Pj40CmlmKG4+PTgpcmV0dXJuIEguaShDLngsbikKbj0oQy54W25dJjE8PChwJjE1KSkhPT0wfWVs
+c2Ugbj0hMQppZihuKXtpZihxJiY2NTw9cCYmOTA+PXApe2lmKHI9PW51bGwpcj1uZXcgUC5IKCIiKQpp
+ZihzPHQpe3IuYSs9Qy5hLm4oYSxzLHQpCnM9dH1xPSExfSsrdH1lbHNle2lmKHA8PTkzKXtuPXA+Pj40
+CmlmKG4+PTgpcmV0dXJuIEguaShDLmgsbikKbj0oQy5oW25dJjE8PChwJjE1KSkhPT0wfWVsc2Ugbj0h
+MQppZihuKVAuYnIoYSx0LCJJbnZhbGlkIGNoYXJhY3RlciIpCmVsc2V7aWYoKHAmNjQ1MTIpPT09NTUy
+OTYmJnQrMTxjKXtqPUMuYS52KGEsdCsxKQppZigoaiY2NDUxMik9PT01NjMyMCl7cD02NTUzNnwocCYx
+MDIzKTw8MTB8aiYxMDIzCms9Mn1lbHNlIGs9MX1lbHNlIGs9MQppZihyPT1udWxsKXI9bmV3IFAuSCgi
+IikKbT1DLmEubihhLHMsdCkKci5hKz0hcT9tLnRvTG93ZXJDYXNlKCk6bQpyLmErPVAuaGQocCkKdCs9
+awpzPXR9fX19aWYocj09bnVsbClyZXR1cm4gQy5hLm4oYSxiLGMpCmlmKHM8Yyl7bT1DLmEubihhLHMs
+YykKci5hKz0hcT9tLnRvTG93ZXJDYXNlKCk6bX1uPXIuYQpyZXR1cm4gbi5jaGFyQ29kZUF0KDApPT0w
+P246bn0sCmtMOmZ1bmN0aW9uKGEsYixjKXt2YXIgdCxzLHIscQppZihiPT09YylyZXR1cm4iIgppZigh
+UC5pbShKLmEwKGEpLnQoYSxiKSkpUC5icihhLGIsIlNjaGVtZSBub3Qgc3RhcnRpbmcgd2l0aCBhbHBo
+YWJldGljIGNoYXJhY3RlciIpCmZvcih0PWIscz0hMTt0PGM7Kyt0KXtyPUMuYS50KGEsdCkKaWYocjwx
+Mjgpe3E9cj4+PjQKaWYocT49OClyZXR1cm4gSC5pKEMuaixxKQpxPShDLmpbcV0mMTw8KHImMTUpKSE9
+PTB9ZWxzZSBxPSExCmlmKCFxKVAuYnIoYSx0LCJJbGxlZ2FsIHNjaGVtZSBjaGFyYWN0ZXIiKQppZig2
+NTw9ciYmcjw9OTApcz0hMH1hPUMuYS5uKGEsYixjKQpyZXR1cm4gUC5rRChzP2EudG9Mb3dlckNhc2Uo
+KTphKX0sCmtEOmZ1bmN0aW9uKGEpe2lmKGE9PT0iaHR0cCIpcmV0dXJuImh0dHAiCmlmKGE9PT0iZmls
+ZSIpcmV0dXJuImZpbGUiCmlmKGE9PT0iaHR0cHMiKXJldHVybiJodHRwcyIKaWYoYT09PSJwYWNrYWdl
+IilyZXR1cm4icGFja2FnZSIKcmV0dXJuIGF9LAprTTpmdW5jdGlvbihhLGIsYyl7aWYoYT09bnVsbCly
+ZXR1cm4iIgpyZXR1cm4gUC5jbChhLGIsYyxDLlcsITEpfSwKa0k6ZnVuY3Rpb24oYSxiLGMsZCxlLGYp
+e3ZhciB0LHM9ZT09PSJmaWxlIixyPXN8fGYscT1hPT1udWxsCmlmKHEmJiEwKXJldHVybiBzPyIvIjoi
+Igp0PSFxP1AuY2woYSxiLGMsQy55LCEwKTpDLlEuYUYoZCxuZXcgUC5mMigpLHUuTikuVCgwLCIvIikK
+aWYodC5sZW5ndGg9PT0wKXtpZihzKXJldHVybiIvIn1lbHNlIGlmKHImJiFDLmEuSCh0LCIvIikpdD0i
+LyIrdApyZXR1cm4gUC5rTih0LGUsZil9LAprTjpmdW5jdGlvbihhLGIsYyl7dmFyIHQ9Yi5sZW5ndGg9
+PT0wCmlmKHQmJiFjJiYhQy5hLkgoYSwiLyIpKXJldHVybiBQLmtQKGEsIXR8fGMpCnJldHVybiBQLmtR
+KGEpfSwKa0s6ZnVuY3Rpb24oYSxiLGMsZCl7aWYoYSE9bnVsbClyZXR1cm4gUC5jbChhLGIsYyxDLmks
+ITApCnJldHVybiBudWxsfSwKa0c6ZnVuY3Rpb24oYSxiLGMpe2lmKGE9PW51bGwpcmV0dXJuIG51bGwK
+cmV0dXJuIFAuY2woYSxiLGMsQy5pLCEwKX0sCmhlOmZ1bmN0aW9uKGEsYixjKXt2YXIgdCxzLHIscSxw
+LG89YisyCmlmKG8+PWEubGVuZ3RoKXJldHVybiIlIgp0PUMuYS52KGEsYisxKQpzPUMuYS52KGEsbykK
+cj1ILmZ3KHQpCnE9SC5mdyhzKQppZihyPDB8fHE8MClyZXR1cm4iJSIKcD1yKjE2K3EKaWYocDwxMjcp
+e289Qy5jLloocCw0KQppZihvPj04KXJldHVybiBILmkoQy5rLG8pCm89KEMua1tvXSYxPDwocCYxNSkp
+IT09MH1lbHNlIG89ITEKaWYobylyZXR1cm4gSC5kXyhjJiY2NTw9cCYmOTA+PXA/KHB8MzIpPj4+MDpw
+KQppZih0Pj05N3x8cz49OTcpcmV0dXJuIEMuYS5uKGEsYixiKzMpLnRvVXBwZXJDYXNlKCkKcmV0dXJu
+IG51bGx9LApoZDpmdW5jdGlvbihhKXt2YXIgdCxzLHIscSxwLG8sbj0iMDEyMzQ1Njc4OUFCQ0RFRiIK
+aWYoYTwxMjgpe3Q9bmV3IEFycmF5KDMpCnQuZml4ZWQkbGVuZ3RoPUFycmF5CnM9SC5uKHQsdS50KQpD
+LmIubChzLDAsMzcpCkMuYi5sKHMsMSxDLmEudChuLGE+Pj40KSkKQy5iLmwocywyLEMuYS50KG4sYSYx
+NSkpfWVsc2V7aWYoYT4yMDQ3KWlmKGE+NjU1MzUpe3I9MjQwCnE9NH1lbHNle3I9MjI0CnE9M31lbHNl
+e3I9MTkyCnE9Mn10PW5ldyBBcnJheSgzKnEpCnQuZml4ZWQkbGVuZ3RoPUFycmF5CnM9SC5uKHQsdS50
+KQpmb3IocD0wOy0tcSxxPj0wO3I9MTI4KXtvPUMuYy5iWChhLDYqcSkmNjN8cgpDLmIubChzLHAsMzcp
+CkMuYi5sKHMscCsxLEMuYS50KG4sbz4+PjQpKQpDLmIubChzLHArMixDLmEudChuLG8mMTUpKQpwKz0z
+fX1yZXR1cm4gUC5oNihzLDAsbnVsbCl9LApjbDpmdW5jdGlvbihhLGIsYyxkLGUpe3ZhciB0PVAuaXAo
+YSxiLGMsZCxlKQpyZXR1cm4gdD09bnVsbD9DLmEubihhLGIsYyk6dH0sCmlwOmZ1bmN0aW9uKGEsYixj
+LGQsZSl7dmFyIHQscyxyLHEscCxvPW51bGwsbj0hZSxtPWIsbD1tLGs9bwp3aGlsZSghMCl7aWYodHlw
+ZW9mIG0hPT0ibnVtYmVyIilyZXR1cm4gbS5EKCkKaWYodHlwZW9mIGMhPT0ibnVtYmVyIilyZXR1cm4g
+SC5haihjKQppZighKG08YykpYnJlYWsKYyQwOnt0PUMuYS52KGEsbSkKaWYodDwxMjcpe3M9dD4+PjQK
+aWYocz49OClyZXR1cm4gSC5pKGQscykKcz0oZFtzXSYxPDwodCYxNSkpIT09MH1lbHNlIHM9ITEKaWYo
+cykrK20KZWxzZXtpZih0PT09Mzcpe3I9UC5oZShhLG0sITEpCmlmKHI9PW51bGwpe20rPTMKYnJlYWsg
+YyQwfWlmKCIlIj09PXIpe3I9IiUyNSIKcT0xfWVsc2UgcT0zfWVsc2V7aWYobilpZih0PD05Myl7cz10
+Pj4+NAppZihzPj04KXJldHVybiBILmkoQy5oLHMpCnM9KEMuaFtzXSYxPDwodCYxNSkpIT09MH1lbHNl
+IHM9ITEKZWxzZSBzPSExCmlmKHMpe1AuYnIoYSxtLCJJbnZhbGlkIGNoYXJhY3RlciIpCnE9bwpyPXF9
+ZWxzZXtpZigodCY2NDUxMik9PT01NTI5Nil7cz1tKzEKaWYoczxjKXtwPUMuYS52KGEscykKaWYoKHAm
+NjQ1MTIpPT09NTYzMjApe3Q9NjU1MzZ8KHQmMTAyMyk8PDEwfHAmMTAyMwpxPTJ9ZWxzZSBxPTF9ZWxz
+ZSBxPTF9ZWxzZSBxPTEKcj1QLmhkKHQpfX1pZihrPT1udWxsKWs9bmV3IFAuSCgiIikKay5hKz1DLmEu
+bihhLGwsbSkKay5hKz1ILmIocikKaWYodHlwZW9mIHEhPT0ibnVtYmVyIilyZXR1cm4gSC5haihxKQpt
+Kz1xCmw9bX19fWlmKGs9PW51bGwpcmV0dXJuIG8KaWYodHlwZW9mIGwhPT0ibnVtYmVyIilyZXR1cm4g
+bC5EKCkKaWYobDxjKWsuYSs9Qy5hLm4oYSxsLGMpCm49ay5hCnJldHVybiBuLmNoYXJDb2RlQXQoMCk9
+PTA/bjpufSwKaW86ZnVuY3Rpb24oYSl7aWYoQy5hLkgoYSwiLiIpKXJldHVybiEwCnJldHVybiBDLmEu
+YmYoYSwiLy4iKSE9PS0xfSwKa1E6ZnVuY3Rpb24oYSl7dmFyIHQscyxyLHEscCxvLG4KaWYoIVAuaW8o
+YSkpcmV0dXJuIGEKdD1ILm4oW10sdS5zKQpmb3Iocz1hLnNwbGl0KCIvIikscj1zLmxlbmd0aCxxPSEx
+LHA9MDtwPHI7KytwKXtvPXNbcF0KaWYoSi5jcyhvLCIuLiIpKXtuPXQubGVuZ3RoCmlmKG4hPT0wKXtp
+ZigwPj1uKXJldHVybiBILmkodCwtMSkKdC5wb3AoKQppZih0Lmxlbmd0aD09PTApQy5iLmsodCwiIil9
+cT0hMH1lbHNlIGlmKCIuIj09PW8pcT0hMAplbHNle0MuYi5rKHQsbykKcT0hMX19aWYocSlDLmIuayh0
+LCIiKQpyZXR1cm4gQy5iLlQodCwiLyIpfSwKa1A6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIscSxwLG8K
+aWYoIVAuaW8oYSkpcmV0dXJuIWI/UC5pbChhKTphCnQ9SC5uKFtdLHUucykKZm9yKHM9YS5zcGxpdCgi
+LyIpLHI9cy5sZW5ndGgscT0hMSxwPTA7cDxyOysrcCl7bz1zW3BdCmlmKCIuLiI9PT1vKWlmKHQubGVu
+Z3RoIT09MCYmQy5iLmdhZyh0KSE9PSIuLiIpe2lmKDA+PXQubGVuZ3RoKXJldHVybiBILmkodCwtMSkK
+dC5wb3AoKQpxPSEwfWVsc2V7Qy5iLmsodCwiLi4iKQpxPSExfWVsc2UgaWYoIi4iPT09bylxPSEwCmVs
+c2V7Qy5iLmsodCxvKQpxPSExfX1zPXQubGVuZ3RoCmlmKHMhPT0wKWlmKHM9PT0xKXtpZigwPj1zKXJl
+dHVybiBILmkodCwwKQpzPXRbMF0ubGVuZ3RoPT09MH1lbHNlIHM9ITEKZWxzZSBzPSEwCmlmKHMpcmV0
+dXJuIi4vIgppZihxfHxDLmIuZ2FnKHQpPT09Ii4uIilDLmIuayh0LCIiKQppZighYil7aWYoMD49dC5s
+ZW5ndGgpcmV0dXJuIEguaSh0LDApCkMuYi5sKHQsMCxQLmlsKHRbMF0pKX1yZXR1cm4gQy5iLlQodCwi
+LyIpfSwKaWw6ZnVuY3Rpb24oYSl7dmFyIHQscyxyLHE9YS5sZW5ndGgKaWYocT49MiYmUC5pbShKLmhE
+KGEsMCkpKWZvcih0PTE7dDxxOysrdCl7cz1DLmEudChhLHQpCmlmKHM9PT01OClyZXR1cm4gQy5hLm4o
+YSwwLHQpKyIlM0EiK0MuYS5VKGEsdCsxKQppZihzPD0xMjcpe3I9cz4+PjQKaWYocj49OClyZXR1cm4g
+SC5pKEMuaixyKQpyPShDLmpbcl0mMTw8KHMmMTUpKT09PTB9ZWxzZSByPSEwCmlmKHIpYnJlYWt9cmV0
+dXJuIGF9LAprRjpmdW5jdGlvbihhLGIpe3ZhciB0LHMscgpmb3IodD0wLHM9MDtzPDI7KytzKXtyPUMu
+YS50KGEsYitzKQppZig0ODw9ciYmcjw9NTcpdD10KjE2K3ItNDgKZWxzZXtyfD0zMgppZig5Nzw9ciYm
+cjw9MTAyKXQ9dCoxNityLTg3CmVsc2UgdGhyb3cgSC5hKFAuYjQoIkludmFsaWQgVVJMIGVuY29kaW5n
+IikpfX1yZXR1cm4gdH0sCmhmOmZ1bmN0aW9uKGEsYixjLGQsZSl7dmFyIHQscyxyLHEscD1iCndoaWxl
+KCEwKXtpZighKHA8Yykpe3Q9ITAKYnJlYWt9cz1DLmEudChhLHApCmlmKHM8PTEyNylpZihzIT09Mzcp
+cj1zPT09NDMKZWxzZSByPSEwCmVsc2Ugcj0hMAppZihyKXt0PSExCmJyZWFrfSsrcH1pZih0KXtpZihD
+LmYhPT1kKXI9ITEKZWxzZSByPSEwCmlmKHIpcmV0dXJuIEMuYS5uKGEsYixjKQplbHNlIHE9bmV3IEgu
+Y3koQy5hLm4oYSxiLGMpKX1lbHNle3E9SC5uKFtdLHUudCkKZm9yKHI9YS5sZW5ndGgscD1iO3A8Yzsr
+K3Ape3M9Qy5hLnQoYSxwKQppZihzPjEyNyl0aHJvdyBILmEoUC5iNCgiSWxsZWdhbCBwZXJjZW50IGVu
+Y29kaW5nIGluIFVSSSIpKQppZihzPT09Mzcpe2lmKHArMz5yKXRocm93IEguYShQLmI0KCJUcnVuY2F0
+ZWQgVVJJIikpCkMuYi5rKHEsUC5rRihhLHArMSkpCnArPTJ9ZWxzZSBpZihzPT09NDMpQy5iLmsocSwz
+MikKZWxzZSBDLmIuayhxLHMpfX11LkwuYihxKQpyZXR1cm4gbmV3IFAuZGUoITEpLmFBKHEpfSwKaW06
+ZnVuY3Rpb24oYSl7dmFyIHQ9YXwzMgpyZXR1cm4gOTc8PXQmJnQ8PTEyMn0sCmk0OmZ1bmN0aW9uKGEs
+YixjKXt2YXIgdCxzLHIscSxwLG8sbixtLGw9IkludmFsaWQgTUlNRSB0eXBlIixrPUgubihbYi0xXSx1
+LnQpCmZvcih0PWEubGVuZ3RoLHM9YixyPS0xLHE9bnVsbDtzPHQ7KytzKXtxPUMuYS50KGEscykKaWYo
+cT09PTQ0fHxxPT09NTkpYnJlYWsKaWYocT09PTQ3KXtpZihyPDApe3I9cwpjb250aW51ZX10aHJvdyBI
+LmEoUC5BKGwsYSxzKSl9fWlmKHI8MCYmcz5iKXRocm93IEguYShQLkEobCxhLHMpKQpmb3IoO3EhPT00
+NDspe0MuYi5rKGsscyk7KytzCmZvcihwPS0xO3M8dDsrK3Mpe3E9Qy5hLnQoYSxzKQppZihxPT09NjEp
+e2lmKHA8MClwPXN9ZWxzZSBpZihxPT09NTl8fHE9PT00NClicmVha31pZihwPj0wKUMuYi5rKGsscCkK
+ZWxzZXtvPUMuYi5nYWcoaykKaWYocSE9PTQ0fHxzIT09bys3fHwhQy5hLlMoYSwiYmFzZTY0IixvKzEp
+KXRocm93IEguYShQLkEoIkV4cGVjdGluZyAnPSciLGEscykpCmJyZWFrfX1DLmIuayhrLHMpCm49cysx
+CmlmKChrLmxlbmd0aCYxKT09PTEpYT1DLkQuY2soYSxuLHQpCmVsc2V7bT1QLmlwKGEsbix0LEMuaSwh
+MCkKaWYobSE9bnVsbClhPUMuYS5hMChhLG4sdCxtKX1yZXR1cm4gbmV3IFAuZW0oYSxrLGMpfSwKa1c6
+ZnVuY3Rpb24oKXt2YXIgdD0iMDEyMzQ1Njc4OUFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVm
+Z2hpamtsbW5vcHFyc3R1dnd4eXotLl9+ISQmJygpKissOz0iLHM9Ii4iLHI9IjoiLHE9Ii8iLHA9Ij8i
+LG89IiMiLG49dS5nYyxtPVAuak4oMjIsbmV3IFAuZmEoKSxuKSxsPW5ldyBQLmY5KG0pLGs9bmV3IFAu
+ZmIoKSxqPW5ldyBQLmZjKCksaT1uLmIobC4kMigwLDIyNSkpCmsuJDMoaSx0LDEpCmsuJDMoaSxzLDE0
+KQprLiQzKGksciwzNCkKay4kMyhpLHEsMykKay4kMyhpLHAsMTcyKQprLiQzKGksbywyMDUpCmk9bi5i
+KGwuJDIoMTQsMjI1KSkKay4kMyhpLHQsMSkKay4kMyhpLHMsMTUpCmsuJDMoaSxyLDM0KQprLiQzKGks
+cSwyMzQpCmsuJDMoaSxwLDE3MikKay4kMyhpLG8sMjA1KQppPW4uYihsLiQyKDE1LDIyNSkpCmsuJDMo
+aSx0LDEpCmsuJDMoaSwiJSIsMjI1KQprLiQzKGksciwzNCkKay4kMyhpLHEsOSkKay4kMyhpLHAsMTcy
+KQprLiQzKGksbywyMDUpCmk9bi5iKGwuJDIoMSwyMjUpKQprLiQzKGksdCwxKQprLiQzKGksciwzNCkK
+ay4kMyhpLHEsMTApCmsuJDMoaSxwLDE3MikKay4kMyhpLG8sMjA1KQppPW4uYihsLiQyKDIsMjM1KSkK
+ay4kMyhpLHQsMTM5KQprLiQzKGkscSwxMzEpCmsuJDMoaSxzLDE0NikKay4kMyhpLHAsMTcyKQprLiQz
+KGksbywyMDUpCmk9bi5iKGwuJDIoMywyMzUpKQprLiQzKGksdCwxMSkKay4kMyhpLHEsNjgpCmsuJDMo
+aSxzLDE4KQprLiQzKGkscCwxNzIpCmsuJDMoaSxvLDIwNSkKaT1uLmIobC4kMig0LDIyOSkpCmsuJDMo
+aSx0LDUpCmouJDMoaSwiQVoiLDIyOSkKay4kMyhpLHIsMTAyKQprLiQzKGksIkAiLDY4KQprLiQzKGks
+IlsiLDIzMikKay4kMyhpLHEsMTM4KQprLiQzKGkscCwxNzIpCmsuJDMoaSxvLDIwNSkKaT1uLmIobC4k
+Mig1LDIyOSkpCmsuJDMoaSx0LDUpCmouJDMoaSwiQVoiLDIyOSkKay4kMyhpLHIsMTAyKQprLiQzKGks
+IkAiLDY4KQprLiQzKGkscSwxMzgpCmsuJDMoaSxwLDE3MikKay4kMyhpLG8sMjA1KQppPW4uYihsLiQy
+KDYsMjMxKSkKai4kMyhpLCIxOSIsNykKay4kMyhpLCJAIiw2OCkKay4kMyhpLHEsMTM4KQprLiQzKGks
+cCwxNzIpCmsuJDMoaSxvLDIwNSkKaT1uLmIobC4kMig3LDIzMSkpCmouJDMoaSwiMDkiLDcpCmsuJDMo
+aSwiQCIsNjgpCmsuJDMoaSxxLDEzOCkKay4kMyhpLHAsMTcyKQprLiQzKGksbywyMDUpCmsuJDMobi5i
+KGwuJDIoOCw4KSksIl0iLDUpCmk9bi5iKGwuJDIoOSwyMzUpKQprLiQzKGksdCwxMSkKay4kMyhpLHMs
+MTYpCmsuJDMoaSxxLDIzNCkKay4kMyhpLHAsMTcyKQprLiQzKGksbywyMDUpCmk9bi5iKGwuJDIoMTYs
+MjM1KSkKay4kMyhpLHQsMTEpCmsuJDMoaSxzLDE3KQprLiQzKGkscSwyMzQpCmsuJDMoaSxwLDE3MikK
+ay4kMyhpLG8sMjA1KQppPW4uYihsLiQyKDE3LDIzNSkpCmsuJDMoaSx0LDExKQprLiQzKGkscSw5KQpr
+LiQzKGkscCwxNzIpCmsuJDMoaSxvLDIwNSkKaT1uLmIobC4kMigxMCwyMzUpKQprLiQzKGksdCwxMSkK
+ay4kMyhpLHMsMTgpCmsuJDMoaSxxLDIzNCkKay4kMyhpLHAsMTcyKQprLiQzKGksbywyMDUpCmk9bi5i
+KGwuJDIoMTgsMjM1KSkKay4kMyhpLHQsMTEpCmsuJDMoaSxzLDE5KQprLiQzKGkscSwyMzQpCmsuJDMo
+aSxwLDE3MikKay4kMyhpLG8sMjA1KQppPW4uYihsLiQyKDE5LDIzNSkpCmsuJDMoaSx0LDExKQprLiQz
+KGkscSwyMzQpCmsuJDMoaSxwLDE3MikKay4kMyhpLG8sMjA1KQppPW4uYihsLiQyKDExLDIzNSkpCmsu
+JDMoaSx0LDExKQprLiQzKGkscSwxMCkKay4kMyhpLHAsMTcyKQprLiQzKGksbywyMDUpCmk9bi5iKGwu
+JDIoMTIsMjM2KSkKay4kMyhpLHQsMTIpCmsuJDMoaSxwLDEyKQprLiQzKGksbywyMDUpCmk9bi5iKGwu
+JDIoMTMsMjM3KSkKay4kMyhpLHQsMTMpCmsuJDMoaSxwLDEzKQpqLiQzKG4uYihsLiQyKDIwLDI0NSkp
+LCJheiIsMjEpCmw9bi5iKGwuJDIoMjEsMjQ1KSkKai4kMyhsLCJheiIsMjEpCmouJDMobCwiMDkiLDIx
+KQprLiQzKGwsIistLiIsMjEpCnJldHVybiBtfSwKaUM6ZnVuY3Rpb24oYSxiLGMsZCxlKXt2YXIgdCxz
+LHIscSxwLG89JC5qaCgpCmZvcih0PUouYTAoYSkscz1iO3M8YzsrK3Mpe2lmKGQ8MHx8ZD49by5sZW5n
+dGgpcmV0dXJuIEguaShvLGQpCnI9b1tkXQpxPXQudChhLHMpXjk2CmlmKHE+OTUpcT0zMQppZihxPj1y
+Lmxlbmd0aClyZXR1cm4gSC5pKHIscSkKcD1yW3FdCmQ9cCYzMQpDLmIubChlLHA+Pj41LHMpfXJldHVy
+biBkfSwKZWI6ZnVuY3Rpb24gZWIoYSxiKXt0aGlzLmE9YQp0aGlzLmI9Yn0sCno6ZnVuY3Rpb24geigp
+e30sCmI3OmZ1bmN0aW9uIGI3KGEsYil7dGhpcy5hPWEKdGhpcy5iPWJ9LApUOmZ1bmN0aW9uIFQoKXt9
+LApiODpmdW5jdGlvbiBiOChhKXt0aGlzLmE9YX0sCmRYOmZ1bmN0aW9uIGRYKCl7fSwKZFk6ZnVuY3Rp
+b24gZFkoKXt9LApyOmZ1bmN0aW9uIHIoKXt9LApidzpmdW5jdGlvbiBidyhhKXt0aGlzLmE9YX0sCmJk
+OmZ1bmN0aW9uIGJkKCl7fSwKYTE6ZnVuY3Rpb24gYTEoYSxiLGMsZCl7dmFyIF89dGhpcwpfLmE9YQpf
+LmI9YgpfLmM9YwpfLmQ9ZH0sCmFVOmZ1bmN0aW9uIGFVKGEsYixjLGQsZSxmKXt2YXIgXz10aGlzCl8u
+ZT1hCl8uZj1iCl8uYT1jCl8uYj1kCl8uYz1lCl8uZD1mfSwKY0c6ZnVuY3Rpb24gY0coYSxiLGMsZCxl
+KXt2YXIgXz10aGlzCl8uZj1hCl8uYT1iCl8uYj1jCl8uYz1kCl8uZD1lfSwKY1U6ZnVuY3Rpb24gY1Uo
+YSxiLGMsZCl7dmFyIF89dGhpcwpfLmE9YQpfLmI9YgpfLmM9YwpfLmQ9ZH0sCmRiOmZ1bmN0aW9uIGRi
+KGEpe3RoaXMuYT1hfSwKZDk6ZnVuY3Rpb24gZDkoYSl7dGhpcy5hPWF9LApiaDpmdW5jdGlvbiBiaChh
+KXt0aGlzLmE9YX0sCmN6OmZ1bmN0aW9uIGN6KGEpe3RoaXMuYT1hfSwKY1c6ZnVuY3Rpb24gY1coKXt9
+LApiWDpmdW5jdGlvbiBiWCgpe30sCmNCOmZ1bmN0aW9uIGNCKGEpe3RoaXMuYT1hfSwKZUE6ZnVuY3Rp
+b24gZUEoYSl7dGhpcy5hPWF9LAplXzpmdW5jdGlvbiBlXyhhLGIsYyl7dGhpcy5hPWEKdGhpcy5iPWIK
+dGhpcy5jPWN9LAphYjpmdW5jdGlvbiBhYigpe30sCmY6ZnVuY3Rpb24gZigpe30sCmo6ZnVuY3Rpb24g
+aigpe30sClI6ZnVuY3Rpb24gUigpe30sCm06ZnVuY3Rpb24gbSgpe30sCnk6ZnVuY3Rpb24geSgpe30s
+CnA6ZnVuY3Rpb24gcCgpe30sClU6ZnVuY3Rpb24gVSgpe30sCnQ6ZnVuY3Rpb24gdCgpe30sCk06ZnVu
+Y3Rpb24gTSgpe30sCmFnOmZ1bmN0aW9uIGFnKCl7fSwKYzpmdW5jdGlvbiBjKCl7fSwKSDpmdW5jdGlv
+biBIKGEpe3RoaXMuYT1hfSwKYTY6ZnVuY3Rpb24gYTYoKXt9LAplcTpmdW5jdGlvbiBlcShhKXt0aGlz
+LmE9YX0sCmVuOmZ1bmN0aW9uIGVuKGEpe3RoaXMuYT1hfSwKZW86ZnVuY3Rpb24gZW8oYSl7dGhpcy5h
+PWF9LAplcDpmdW5jdGlvbiBlcChhLGIpe3RoaXMuYT1hCnRoaXMuYj1ifSwKY2s6ZnVuY3Rpb24gY2so
+YSxiLGMsZCxlLGYsZyl7dmFyIF89dGhpcwpfLmE9YQpfLmI9YgpfLmM9YwpfLmQ9ZApfLmU9ZQpfLmY9
+ZgpfLnI9ZwpfLlE9Xy56PV8ueT1udWxsfSwKZjE6ZnVuY3Rpb24gZjEoYSxiKXt0aGlzLmE9YQp0aGlz
+LmI9Yn0sCmYyOmZ1bmN0aW9uIGYyKCl7fSwKZW06ZnVuY3Rpb24gZW0oYSxiLGMpe3RoaXMuYT1hCnRo
+aXMuYj1iCnRoaXMuYz1jfSwKZmE6ZnVuY3Rpb24gZmEoKXt9LApmOTpmdW5jdGlvbiBmOShhKXt0aGlz
+LmE9YX0sCmZiOmZ1bmN0aW9uIGZiKCl7fSwKZmM6ZnVuY3Rpb24gZmMoKXt9LApkejpmdW5jdGlvbiBk
+eihhLGIsYyxkLGUsZixnLGgpe3ZhciBfPXRoaXMKXy5hPWEKXy5iPWIKXy5jPWMKXy5kPWQKXy5lPWUK
+Xy5mPWYKXy5yPWcKXy54PWgKXy55PW51bGx9LApkbTpmdW5jdGlvbiBkbShhLGIsYyxkLGUsZixnKXt2
+YXIgXz10aGlzCl8uYT1hCl8uYj1iCl8uYz1jCl8uZD1kCl8uZT1lCl8uZj1mCl8ucj1nCl8uUT1fLno9
+Xy55PW51bGx9LAplVjpmdW5jdGlvbiBlVigpe30sCmVYOmZ1bmN0aW9uIGVYKGEsYil7dGhpcy5hPWEK
+dGhpcy5iPWJ9LAplWTpmdW5jdGlvbiBlWShhLGIpe3RoaXMuYT1hCnRoaXMuYj1ifSwKZVc6ZnVuY3Rp
+b24gZVcoYSxiKXt0aGlzLmE9YQp0aGlzLmI9Yn0sCmNBOmZ1bmN0aW9uIGNBKCl7fSwKZFQ6ZnVuY3Rp
+b24gZFQoYSl7dGhpcy5hPWF9LApiSzpmdW5jdGlvbiBiSygpe30sCmtUOmZ1bmN0aW9uKGEsYixjLGQp
+e3ZhciB0LHMscgpILmhnKGIpCnUuai5iKGQpCmlmKEguZEsoYikpe3Q9W2NdCkMuYi5JKHQsZCkKZD10
+fXM9dS56CnI9UC5oMihKLmpwKGQsUC5seSgpLHMpLCEwLHMpCnUuWi5iKGEpCnJldHVybiBQLmhpKEgu
+alMoYSxyLG51bGwpKX0sCmhqOmZ1bmN0aW9uKGEsYixjKXt2YXIgdAp0cnl7aWYoT2JqZWN0LmlzRXh0
+ZW5zaWJsZShhKSYmIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChhLGIpKXtPYmpl
+Y3QuZGVmaW5lUHJvcGVydHkoYSxiLHt2YWx1ZTpjfSkKcmV0dXJuITB9fWNhdGNoKHQpe0guUSh0KX1y
+ZXR1cm4hMX0sCml2OmZ1bmN0aW9uKGEsYil7aWYoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0
+eS5jYWxsKGEsYikpcmV0dXJuIGFbYl0KcmV0dXJuIG51bGx9LApoaTpmdW5jdGlvbihhKXtpZihhPT1u
+dWxsfHx0eXBlb2YgYT09InN0cmluZyJ8fHR5cGVvZiBhPT0ibnVtYmVyInx8SC5mZChhKSlyZXR1cm4g
+YQppZihhIGluc3RhbmNlb2YgUC5ZKXJldHVybiBhLmEKaWYoSC5pTShhKSlyZXR1cm4gYQppZih1Lmku
+YyhhKSlyZXR1cm4gYQppZihhIGluc3RhbmNlb2YgUC5iNylyZXR1cm4gSC5hVChhKQppZih1LlouYyhh
+KSlyZXR1cm4gUC5pdShhLCIkZGFydF9qc0Z1bmN0aW9uIixuZXcgUC5mNygpKQpyZXR1cm4gUC5pdShh
+LCJfJGRhcnRfanNPYmplY3QiLG5ldyBQLmY4KCQuaEMoKSkpfSwKaXU6ZnVuY3Rpb24oYSxiLGMpe3Zh
+ciB0PVAuaXYoYSxiKQppZih0PT1udWxsKXt0PWMuJDEoYSkKUC5oaihhLGIsdCl9cmV0dXJuIHR9LApo
+aDpmdW5jdGlvbihhKXt2YXIgdCxzCmlmKGE9PW51bGx8fHR5cGVvZiBhPT0ic3RyaW5nInx8dHlwZW9m
+IGE9PSJudW1iZXIifHx0eXBlb2YgYT09ImJvb2xlYW4iKXJldHVybiBhCmVsc2UgaWYoYSBpbnN0YW5j
+ZW9mIE9iamVjdCYmSC5pTShhKSlyZXR1cm4gYQplbHNlIGlmKGEgaW5zdGFuY2VvZiBPYmplY3QmJnUu
+aS5jKGEpKXJldHVybiBhCmVsc2UgaWYoYSBpbnN0YW5jZW9mIERhdGUpe3Q9SC54KGEuZ2V0VGltZSgp
+KQppZihNYXRoLmFicyh0KTw9ODY0ZTEzKXM9ITEKZWxzZSBzPSEwCmlmKHMpSC5hayhQLmI0KCJEYXRl
+VGltZSBpcyBvdXRzaWRlIHZhbGlkIHJhbmdlOiAiK3QpKQpyZXR1cm4gbmV3IFAuYjcodCwhMSl9ZWxz
+ZSBpZihhLmNvbnN0cnVjdG9yPT09JC5oQygpKXJldHVybiBhLm8KZWxzZSByZXR1cm4gUC5pRihhKX0s
+CmlGOmZ1bmN0aW9uKGEpe2lmKHR5cGVvZiBhPT0iZnVuY3Rpb24iKXJldHVybiBQLmhrKGEsJC5mVigp
+LG5ldyBQLmZnKCkpCmlmKGEgaW5zdGFuY2VvZiBBcnJheSlyZXR1cm4gUC5oayhhLCQuaEIoKSxuZXcg
+UC5maCgpKQpyZXR1cm4gUC5oayhhLCQuaEIoKSxuZXcgUC5maSgpKX0sCmhrOmZ1bmN0aW9uKGEsYixj
+KXt2YXIgdD1QLml2KGEsYikKaWYodD09bnVsbHx8IShhIGluc3RhbmNlb2YgT2JqZWN0KSl7dD1jLiQx
+KGEpClAuaGooYSxiLHQpfXJldHVybiB0fSwKZjc6ZnVuY3Rpb24gZjcoKXt9LApmODpmdW5jdGlvbiBm
+OChhKXt0aGlzLmE9YX0sCmZnOmZ1bmN0aW9uIGZnKCl7fSwKZmg6ZnVuY3Rpb24gZmgoKXt9LApmaTpm
+dW5jdGlvbiBmaSgpe30sClk6ZnVuY3Rpb24gWShhKXt0aGlzLmE9YX0sCmJiOmZ1bmN0aW9uIGJiKGEp
+e3RoaXMuYT1hfSwKYU86ZnVuY3Rpb24gYU8oYSxiKXt0aGlzLmE9YQp0aGlzLiR0aT1ifSwKYzU6ZnVu
+Y3Rpb24gYzUoKXt9LApiZzpmdW5jdGlvbiBiZygpe30sCmN2OmZ1bmN0aW9uIGN2KGEpe3RoaXMuYT1h
+fSwKZTpmdW5jdGlvbiBlKCl7fSwKYWg6ZnVuY3Rpb24gYWgoKXt9fSxXPXsKakY6ZnVuY3Rpb24oYSxi
+LGMpe3ZhciB0PWRvY3VtZW50LmJvZHkscz0odCYmQy5wKS5LKHQsYSxiLGMpCnMudG9TdHJpbmcKdD11
+LmFjCnQ9bmV3IEguYVkobmV3IFcuTyhzKSx0LmgoInoobC5FKSIpLmIobmV3IFcuZFooKSksdC5oKCJh
+WTxsLkU+IikpCnJldHVybiB1LmguYih0LmdZKHQpKX0sCmJEOmZ1bmN0aW9uKGEpe3ZhciB0LHMscj0i
+ZWxlbWVudCB0YWcgdW5hdmFpbGFibGUiCnRyeXt0PUouRShhKQppZih0eXBlb2YgdC5nYm0oYSk9PSJz
+dHJpbmciKXI9dC5nYm0oYSl9Y2F0Y2gocyl7SC5RKHMpfXJldHVybiByfSwKZTI6ZnVuY3Rpb24oYSxi
+LGMpe3ZhciB0LHMscixxPW5ldyBQLlMoJC53LHUuYW8pLHA9bmV3IFAuYzAocSx1LkUpLG89bmV3IFhN
+TEh0dHBSZXF1ZXN0KCkKQy5PLmNsKG8sYj09bnVsbD8iR0VUIjpiLGEsITApCmMuQSgwLG5ldyBXLmUz
+KG8pKQp0PXUuYW4Kcz10LmIobmV3IFcuZTQobyxwKSkKdS5NLmIobnVsbCkKcj11LnAKVy5hQyhvLCJs
+b2FkIixzLCExLHIpClcuYUMobywiZXJyb3IiLHQuYihwLmdjNSgpKSwhMSxyKQpvLnNlbmQoKQpyZXR1
+cm4gcX0sCmVQOmZ1bmN0aW9uKGEsYil7YT01MzY4NzA5MTEmYStiCmE9NTM2ODcwOTExJmErKCg1MjQy
+ODcmYSk8PDEwKQpyZXR1cm4gYV5hPj4+Nn0sCmliOmZ1bmN0aW9uKGEsYixjLGQpe3ZhciB0PVcuZVAo
+Vy5lUChXLmVQKFcuZVAoMCxhKSxiKSxjKSxkKSxzPTUzNjg3MDkxMSZ0KygoNjcxMDg4NjMmdCk8PDMp
+CnNePXM+Pj4xMQpyZXR1cm4gNTM2ODcwOTExJnMrKCgxNjM4MyZzKTw8MTUpfSwKYUM6ZnVuY3Rpb24o
+YSxiLGMsZCxlKXt2YXIgdD1XLmxlKG5ldyBXLmV6KGMpLHUuQSkKaWYodCE9bnVsbCYmITApSi5qbChh
+LGIsdCwhMSkKcmV0dXJuIG5ldyBXLmRxKGEsYix0LCExLGUuaCgiZHE8MD4iKSl9LAppYTpmdW5jdGlv
+bihhKXt2YXIgdD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJhIikscz1uZXcgVy5keSh0LHdpbmRvdy5s
+b2NhdGlvbikKcz1uZXcgVy5iXyhzKQpzLmJEKGEpCnJldHVybiBzfSwKa2w6ZnVuY3Rpb24oYSxiLGMs
+ZCl7dS5oLmIoYSkKSC5vKGIpCkgubyhjKQp1Lk8uYihkKQpyZXR1cm4hMH0sCmttOmZ1bmN0aW9uKGEs
+YixjLGQpe3ZhciB0LHMscgp1LmguYihhKQpILm8oYikKSC5vKGMpCnQ9dS5PLmIoZCkuYQpzPXQuYQpz
+LmhyZWY9YwpyPXMuaG9zdG5hbWUKdD10LmIKaWYoIShyPT10Lmhvc3RuYW1lJiZzLnBvcnQ9PXQucG9y
+dCYmcy5wcm90b2NvbD09dC5wcm90b2NvbCkpaWYocj09PSIiKWlmKHMucG9ydD09PSIiKXt0PXMucHJv
+dG9jb2wKdD10PT09IjoifHx0PT09IiJ9ZWxzZSB0PSExCmVsc2UgdD0hMQplbHNlIHQ9ITAKcmV0dXJu
+IHR9LAppZTpmdW5jdGlvbigpe3ZhciB0PXUuTixzPVAuaFQoQy56LHQpLHI9dS5kRy5iKG5ldyBXLmVa
+KCkpLHE9SC5uKFsiVEVNUExBVEUiXSx1LnMpCnQ9bmV3IFcuZEIocyxQLmJNKHQpLFAuYk0odCksUC5i
+TSh0KSxudWxsKQp0LmJFKG51bGwsbmV3IEguYTQoQy56LHIsdS5kdikscSxudWxsKQpyZXR1cm4gdH0s
+CmlzOmZ1bmN0aW9uKGEpe3ZhciB0CmlmKGE9PW51bGwpcmV0dXJuIG51bGwKaWYoInBvc3RNZXNzYWdl
+IiBpbiBhKXt0PVcua2soYSkKcmV0dXJuIHR9ZWxzZSByZXR1cm4gdS5hUy5iKGEpfSwKa2s6ZnVuY3Rp
+b24oYSl7aWYoYT09PXdpbmRvdylyZXR1cm4gdS5jaS5iKGEpCmVsc2UgcmV0dXJuIG5ldyBXLmRsKCl9
+LApsZTpmdW5jdGlvbihhLGIpe3ZhciB0PSQudwppZih0PT09Qy5kKXJldHVybiBhCnJldHVybiB0LmMy
+KGEsYil9LApoOmZ1bmN0aW9uIGgoKXt9LApiMzpmdW5jdGlvbiBiMygpe30sCmN1OmZ1bmN0aW9uIGN1
+KCl7fSwKYjU6ZnVuY3Rpb24gYjUoKXt9LAphRzpmdW5jdGlvbiBhRygpe30sCmFIOmZ1bmN0aW9uIGFI
+KCl7fSwKYWE6ZnVuY3Rpb24gYWEoKXt9LApiQTpmdW5jdGlvbiBiQSgpe30sCmRVOmZ1bmN0aW9uIGRV
+KCl7fSwKYUw6ZnVuY3Rpb24gYUwoKXt9LApkVjpmdW5jdGlvbiBkVigpe30sCmJCOmZ1bmN0aW9uIGJC
+KCl7fSwKZFc6ZnVuY3Rpb24gZFcoKXt9LAphcTpmdW5jdGlvbiBhcShhLGIpe3RoaXMuYT1hCnRoaXMu
+JHRpPWJ9LAp1OmZ1bmN0aW9uIHUoKXt9LApkWjpmdW5jdGlvbiBkWigpe30sCmQ6ZnVuY3Rpb24gZCgp
+e30sCnE6ZnVuY3Rpb24gcSgpe30sCmI5OmZ1bmN0aW9uIGI5KCl7fSwKY0Y6ZnVuY3Rpb24gY0YoKXt9
+LAplMTpmdW5jdGlvbiBlMSgpe30sCmJGOmZ1bmN0aW9uIGJGKCl7fSwKYTM6ZnVuY3Rpb24gYTMoKXt9
+LAplMzpmdW5jdGlvbiBlMyhhKXt0aGlzLmE9YX0sCmU0OmZ1bmN0aW9uIGU0KGEsYil7dGhpcy5hPWEK
+dGhpcy5iPWJ9LApiRzpmdW5jdGlvbiBiRygpe30sCmJIOmZ1bmN0aW9uIGJIKCl7fSwKYk86ZnVuY3Rp
+b24gYk8oKXt9LApLOmZ1bmN0aW9uIEsoKXt9LApPOmZ1bmN0aW9uIE8oYSl7dGhpcy5hPWF9LAprOmZ1
+bmN0aW9uIGsoKXt9LApiVDpmdW5jdGlvbiBiVCgpe30sCmJlOmZ1bmN0aW9uIGJlKCl7fSwKYTU6ZnVu
+Y3Rpb24gYTUoKXt9LApkMTpmdW5jdGlvbiBkMSgpe30sCmJaOmZ1bmN0aW9uIGJaKCl7fSwKZDY6ZnVu
+Y3Rpb24gZDYoKXt9LApkNzpmdW5jdGlvbiBkNygpe30sCmJqOmZ1bmN0aW9uIGJqKCl7fSwKYTc6ZnVu
+Y3Rpb24gYTcoKXt9LAphQTpmdW5jdGlvbiBhQSgpe30sCmFpOmZ1bmN0aW9uIGFpKCl7fSwKYm06ZnVu
+Y3Rpb24gYm0oKXt9LApjMzpmdW5jdGlvbiBjMygpe30sCmM4OmZ1bmN0aW9uIGM4KCl7fSwKZGk6ZnVu
+Y3Rpb24gZGkoKXt9LAphcDpmdW5jdGlvbiBhcChhKXt0aGlzLmE9YX0sCmFCOmZ1bmN0aW9uIGFCKGEp
+e3RoaXMuYT1hfSwKZXc6ZnVuY3Rpb24gZXcoYSxiKXt0aGlzLmE9YQp0aGlzLmI9Yn0sCmV4OmZ1bmN0
+aW9uIGV4KGEsYil7dGhpcy5hPWEKdGhpcy5iPWJ9LApkbjpmdW5jdGlvbiBkbihhKXt0aGlzLmE9YX0s
+CmhfOmZ1bmN0aW9uIGhfKGEsYil7dGhpcy5hPWEKdGhpcy4kdGk9Yn0sCmM0OmZ1bmN0aW9uIGM0KGEs
+YixjLGQpe3ZhciBfPXRoaXMKXy5hPWEKXy5iPWIKXy5jPWMKXy4kdGk9ZH0sCmJuOmZ1bmN0aW9uIGJu
+KGEsYixjLGQpe3ZhciBfPXRoaXMKXy5hPWEKXy5iPWIKXy5jPWMKXy4kdGk9ZH0sCmRxOmZ1bmN0aW9u
+IGRxKGEsYixjLGQsZSl7dmFyIF89dGhpcwpfLmI9YQpfLmM9YgpfLmQ9YwpfLmU9ZApfLiR0aT1lfSwK
+ZXo6ZnVuY3Rpb24gZXooYSl7dGhpcy5hPWF9LApiXzpmdW5jdGlvbiBiXyhhKXt0aGlzLmE9YX0sCmFj
+OmZ1bmN0aW9uIGFjKCl7fSwKYlU6ZnVuY3Rpb24gYlUoYSl7dGhpcy5hPWF9LAplZDpmdW5jdGlvbiBl
+ZChhKXt0aGlzLmE9YX0sCmVjOmZ1bmN0aW9uIGVjKGEsYixjKXt0aGlzLmE9YQp0aGlzLmI9Ygp0aGlz
+LmM9Y30sCmNmOmZ1bmN0aW9uIGNmKCl7fSwKZVQ6ZnVuY3Rpb24gZVQoKXt9LAplVTpmdW5jdGlvbiBl
+VSgpe30sCmRCOmZ1bmN0aW9uIGRCKGEsYixjLGQsZSl7dmFyIF89dGhpcwpfLmU9YQpfLmE9YgpfLmI9
+YwpfLmM9ZApfLmQ9ZX0sCmVaOmZ1bmN0aW9uIGVaKCl7fSwKZEE6ZnVuY3Rpb24gZEEoKXt9LAphTjpm
+dW5jdGlvbiBhTihhLGIsYyl7dmFyIF89dGhpcwpfLmE9YQpfLmI9YgpfLmM9LTEKXy5kPW51bGwKXy4k
+dGk9Y30sCmRsOmZ1bmN0aW9uIGRsKCl7fSwKRzpmdW5jdGlvbiBHKCl7fSwKZHk6ZnVuY3Rpb24gZHko
+YSxiKXt0aGlzLmE9YQp0aGlzLmI9Yn0sCmNtOmZ1bmN0aW9uIGNtKGEpe3RoaXMuYT1hfSwKZjU6ZnVu
+Y3Rpb24gZjUoYSl7dGhpcy5hPWF9LApkazpmdW5jdGlvbiBkaygpe30sCmR2OmZ1bmN0aW9uIGR2KCl7
+fSwKZHc6ZnVuY3Rpb24gZHcoKXt9LApkSDpmdW5jdGlvbiBkSCgpe30sCmRJOmZ1bmN0aW9uIGRJKCl7
+fX0sTD17CmZyOmZ1bmN0aW9uKGEpe3ZhciB0PVAuaTUoYSkuZ2FKKCkuaigwLCJvZmZzZXQiKQpyZXR1
+cm4gdD09bnVsbD9udWxsOkguaDQodCxudWxsKX0sCmZxOmZ1bmN0aW9uKGEpe3ZhciB0PVAuaTUoYSku
+Z2FKKCkuaigwLCJsaW5lIikKcmV0dXJuIHQ9PW51bGw/bnVsbDpILmg0KHQsbnVsbCl9LAppRzpmdW5j
+dGlvbihhKXtpZigwPj1hLmxlbmd0aClyZXR1cm4gSC5pKGEsMCkKaWYoYVswXSE9PSIvIilyZXR1cm4g
+Si5kUihkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCIucm9vdCIpLnRleHRDb250ZW50KSsiLyIrSC5iKGEp
+CmVsc2UgcmV0dXJuIGF9LApsRTpmdW5jdGlvbihhKXt2YXIgdD1KLmpqKGRvY3VtZW50LnF1ZXJ5U2Vs
+ZWN0b3IoIi5yb290IikudGV4dENvbnRlbnQsIi8iKQppZihKLmEwKGEpLkgoYSx0KSlyZXR1cm4gQy5h
+LlUoYSx0Lmxlbmd0aCkKZWxzZSByZXR1cm4gYX0sCmxIOmZ1bmN0aW9uKGEyKXt2YXIgdCxzLHIscSxw
+LG8sbixtLGwsayxqLGksaCxnLGYsZSxkLGMsYj0iZGlzYWJsZWQiLGE9ImxpbmUiLGEwPWRvY3VtZW50
+LGExPWEwLnF1ZXJ5U2VsZWN0b3IoIi5lZGl0LWxpc3QgLnBhbmVsLWNvbnRlbnQiKQpKLmRRKGExLCIi
+KQp0PWEwLmNyZWF0ZUVsZW1lbnQoInAiKQpzPWExLmFwcGVuZENoaWxkKHQpCnQ9YTAuY3JlYXRlRWxl
+bWVudCgic3Ryb25nIikKcj1zLmFwcGVuZENoaWxkKHQpCnQ9Si5hXyhhMikKcT1ILngodC5qKGEyLCJl
+ZGl0Q291bnQiKSkKci5hcHBlbmRDaGlsZChhMC5jcmVhdGVUZXh0Tm9kZShKLmIyKHEpKSkKaWYocT09
+PTEpcy5hcHBlbmRDaGlsZChhMC5jcmVhdGVUZXh0Tm9kZSgiIGVkaXQgd2FzIG1hZGUgdG8gdGhpcyBm
+aWxlLiBDbGljayB0aGUgZWRpdCdzIGNoZWNrYm94IHRvIHRvZ2dsZSBpdHMgcmV2aWV3ZWQgc3RhdGUu
+IikpCmVsc2Ugcy5hcHBlbmRDaGlsZChhMC5jcmVhdGVUZXh0Tm9kZSgiIGVkaXRzIHdlcmUgbWFkZSB0
+byB0aGlzIGZpbGUuIENsaWNrIGFuIGVkaXQncyBjaGVja2JveCB0byB0b2dnbGUgaXRzIHJldmlld2Vk
+IHN0YXRlLiIpKQpmb3IodD1KLmE5KHUuUi5iKHQuaihhMiwiZWRpdHMiKSkpLHA9dS5hLG89dS5DLG49
+by5oKCJ+KDEpIiksbT11Lk0sbz1vLmQsbD11Lmgsaz11LmdCO3QucCgpOyl7aj10Lmd1KCkKaT1hMC5j
+cmVhdGVFbGVtZW50KCJwIikKaD1rLmIoYTEuYXBwZW5kQ2hpbGQoaSkpCmguY2xhc3NMaXN0LmFkZCgi
+ZWRpdCIpCmk9YTAuY3JlYXRlRWxlbWVudCgiaW5wdXQiKQpnPWwuYihoLmFwcGVuZENoaWxkKGkpKQpn
+LnNldEF0dHJpYnV0ZSgidHlwZSIsImNoZWNrYm94IikKZy5zZXRBdHRyaWJ1dGUoInRpdGxlIiwiQ2xp
+Y2sgdG8gbWFyayByZXZpZXdlZCIpCmcuc2V0QXR0cmlidXRlKGIsYikKaT1KLmFfKGopCmguYXBwZW5k
+Q2hpbGQoYTAuY3JlYXRlVGV4dE5vZGUoImxpbmUgIitILmIoaS5qKGosYSkpKyI6ICIrSC5iKGkuaihq
+LCJleHBsYW5hdGlvbiIpKSsiLiIpKQpmPWEwLmNyZWF0ZUVsZW1lbnQoImEiKQplPXAuYihoLmFwcGVu
+ZENoaWxkKGYpKQplLmNsYXNzTGlzdC5hZGQoImVkaXQtbGluayIpCmQ9SC54KGkuaihqLCJvZmZzZXQi
+KSkKZj1ILmIoZCkKZS5zZXRBdHRyaWJ1dGUoImRhdGEtIituZXcgVy5hQihuZXcgVy5hcChlKSkuVigi
+b2Zmc2V0IiksZikKYz1ILngoaS5qKGosYSkpCmk9SC5iKGMpCmUuc2V0QXR0cmlidXRlKCJkYXRhLSIr
+bmV3IFcuYUIobmV3IFcuYXAoZSkpLlYoYSksaSkKZS5hcHBlbmRDaGlsZChhMC5jcmVhdGVUZXh0Tm9k
+ZSgiW3ZpZXddIikpCmk9bi5iKG5ldyBMLmZVKGQsYyxlKSkKbS5iKG51bGwpClcuYUMoZSwiY2xpY2si
+LGksITEsbyl9fSwKal86ZnVuY3Rpb24oYSl7dmFyIHQ9Ii5yZWdpb25zIixzPWRvY3VtZW50LHI9cy5x
+dWVyeVNlbGVjdG9yKHQpLHE9cy5xdWVyeVNlbGVjdG9yKCIuY29kZSIpCnM9Si5hXyhhKQpKLmhHKHIs
+SC5vKHMuaihhLCJyZWdpb25zIikpLCQuaHooKSkKSi5oRyhxLEgubyhzLmooYSwibmF2Q29udGVudCIp
+KSwkLmh6KCkpCkwubEgocy5qKGEsImVkaXRMaXN0IikpCkwubHEoKQpMLmhvKCIuY29kZSIpCkwuaG8o
+dCl9LApoeDpmdW5jdGlvbihhLGIsYyxkKXt2YXIgdCxzLHI9TC5mcih3aW5kb3cubG9jYXRpb24uaHJl
+ZikscT1MLmZxKHdpbmRvdy5sb2NhdGlvbi5ocmVmKQppZihyIT1udWxsKXt0PWRvY3VtZW50LmdldEVs
+ZW1lbnRCeUlkKCJvIitILmIocikpCmlmKHQhPW51bGwpSi5hbCh0KS5NKDAsInRhcmdldCIpfWlmKHEh
+PW51bGwpe3M9ZG9jdW1lbnQucXVlcnlTZWxlY3RvcigiLmxpbmUtIitILmIocSkpCmlmKHMhPW51bGwp
+Si5hbChzLnBhcmVudEVsZW1lbnQpLk0oMCwiaGlnaGxpZ2h0Iil9aWYoYT09d2luZG93LmxvY2F0aW9u
+LnBhdGhuYW1lKXtMLmlQKGIsYykKZC4kMCgpfWVsc2UgTC5odShhLGIsYyxkKX0sCmh3OmZ1bmN0aW9u
+KGEpe3ZhciB0PWEuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkscz10LmJvdHRvbSxyPXdpbmRvdy5pbm5l
+ckhlaWdodAppZih0eXBlb2YgciE9PSJudW1iZXIiKXJldHVybiBILmFqKHIpCmlmKHM+cilKLmhGKGEp
+CmVsc2UgaWYodC50b3A8MClKLmhGKGEpfSwKaVA6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIKaWYoYSE9
+bnVsbCl7dD1kb2N1bWVudApzPXQuZ2V0RWxlbWVudEJ5SWQoIm8iK0guYihhKSkKcj10LnF1ZXJ5U2Vs
+ZWN0b3IoIi5saW5lLSIrSC5iKGIpKQppZihzIT1udWxsKXtMLmh3KHMpCkouYWwocykuaygwLCJ0YXJn
+ZXQiKX1lbHNlIGlmKHIhPW51bGwpTC5odyhyKQppZihyIT1udWxsKUouYWwodS5oLmEoci5wYXJlbnRO
+b2RlKSkuaygwLCJoaWdobGlnaHQiKX1lbHNlIEwuaHcoZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoInVu
+aXQtbmFtZSIpKX0sCmh1OmZ1bmN0aW9uKGEsYixjLGQpe3ZhciB0PXUuTgpXLmUyKEguYihhKSsiP2lu
+bGluZT10cnVlIixudWxsLFAuY08oWyJDb250ZW50LVR5cGUiLCJhcHBsaWNhdGlvbi9qc29uOyBjaGFy
+c2V0PVVURi04Il0sdCx0KSkuYTQobmV3IEwuZkMoYixjLGEsZCksdS5QKS5hZChuZXcgTC5mRChhKSl9
+LApmUTpmdW5jdGlvbihhLGIsYyl7dmFyIHQscz13aW5kb3cubG9jYXRpb24scj1DLmEuQigocyYmQy5Z
+KS5nY20ocyksYSkrIj8iCmlmKGIhPW51bGwpcis9Im9mZnNldD0iK0guYihiKSsiJiIKaWYoYyE9bnVs
+bClyKz0ibGluZT0iK0guYihjKQpzPXdpbmRvdy5oaXN0b3J5CnQ9dS56CnMudG9TdHJpbmcKcy5wdXNo
+U3RhdGUobmV3IFAuZVcoW10sW10pLmFpKFAuZTkodCx0KSksIiIscil9LAppWjpmdW5jdGlvbihhLGIp
+e3ZhciB0LHMscj17fQpyLmE9YQphPUwubEUoYSkKci5hPWEKdD1kb2N1bWVudAp0LnF1ZXJ5U2VsZWN0
+b3IoIiN1bml0LW5hbWUiKS50ZXh0Q29udGVudD1hCnM9dS5oCkguZEwocyxzLCJUIiwicXVlcnlTZWxl
+Y3RvckFsbCIpCnQ9bmV3IFcuYXEodC5xdWVyeVNlbGVjdG9yQWxsKCIubmF2LXBhbmVsIC5uYXYtbGlu
+ayIpLHUuUykKdC5BKHQsbmV3IEwuZlMocikpfSwKbHE6ZnVuY3Rpb24oKXt2YXIgdD1kb2N1bWVudCxz
+PXUuaApILmRMKHMscywiVCIsInF1ZXJ5U2VsZWN0b3JBbGwiKQp0PW5ldyBXLmFxKHQucXVlcnlTZWxl
+Y3RvckFsbCgiLmNvZGUiKSx1LlMpCnQuQSh0LG5ldyBMLmZ4KCkpfSwKbGY6ZnVuY3Rpb24oYSl7dmFy
+IHQscz11LmguYShhLnBhcmVudE5vZGUpLnF1ZXJ5U2VsZWN0b3IoIjpzY29wZSA+IHVsIikscj1zLnN0
+eWxlLHE9IiIrQy5lLmEzKHMub2Zmc2V0SGVpZ2h0KSoyKyJweCIKci5tYXhIZWlnaHQ9cQpyPUouZFAo
+YSkKcT1yLiR0aQp0PXEuaCgifigxKSIpLmIobmV3IEwuZmoocyxhKSkKdS5NLmIobnVsbCkKVy5hQyhy
+LmEsci5iLHQsITEscS5kKX0sCmxvOmZ1bmN0aW9uKGEpe3ZhciB0LHMscixxLHA9ImhyZWYiCnUuVi5i
+KGEpCnQ9dS5oLmIoVy5pcyhhLmN1cnJlbnRUYXJnZXQpKQpzPUwuaUcodC5nZXRBdHRyaWJ1dGUocCkp
+CnI9TC5mcih0LmdldEF0dHJpYnV0ZShwKSkKcT1MLmZxKHQuZ2V0QXR0cmlidXRlKHApKQppZihyIT1u
+dWxsKUwuaHgocyxyLHEsbmV3IEwuZnMocyxyLHEpKQplbHNlIEwuaHgocyxudWxsLG51bGwsbmV3IEwu
+ZnQocykpCmEucHJldmVudERlZmF1bHQoKX0sCmxwOmZ1bmN0aW9uKGEpe3ZhciB0LHM9e30scj11Lmgu
+YShXLmlzKHUuVi5iKGEpLmN1cnJlbnRUYXJnZXQpKS5nZXRBdHRyaWJ1dGUoImhyZWYiKQpzLmE9cgpy
+PUwuaUcocikKcy5hPXIKdD11Lk4KVy5lMihyLCJQT1NUIixQLmNPKFsiQ29udGVudC1UeXBlIiwiYXBw
+bGljYXRpb24vanNvbjsgY2hhcnNldD1VVEYtOCJdLHQsdCkpLmE0KG5ldyBMLmZ1KCksdS5QKS5hZChu
+ZXcgTC5mdihzKSl9LApobzpmdW5jdGlvbihhKXt2YXIgdCxzLHIscSxwPSJxdWVyeVNlbGVjdG9yQWxs
+IixvPWRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoYSksbj11LmgKby50b1N0cmluZwpILmRMKG4sbiwiVCIs
+cCkKdD11LlMKcz1uZXcgVy5hcShvLnF1ZXJ5U2VsZWN0b3JBbGwoIi5uYXYtbGluayIpLHQpCnMuQShz
+LG5ldyBMLmZsKCkpCkguZEwobixuLCJUIixwKQpyPW5ldyBXLmFxKG8ucXVlcnlTZWxlY3RvckFsbCgi
+LnJlZ2lvbiIpLHQpCnIuQShyLG5ldyBMLmZtKCkpCkguZEwobixuLCJUIixwKQpxPW5ldyBXLmFxKG8u
+cXVlcnlTZWxlY3RvckFsbCgiLnBvc3QtbGluayIpLHQpCnEuQShxLG5ldyBMLmZuKCkpfSwKajA6ZnVu
+Y3Rpb24oYSxiKXt2YXIgdCxzLHIscSxwLG8sbixtLGwsayxqLGksaD0ibmFtZSIsZz1kb2N1bWVudCxm
+PWcuY3JlYXRlRWxlbWVudCgidWwiKSxlPWEuYXBwZW5kQ2hpbGQoZikKZm9yKGY9Si5hOSh1LlIuYihi
+KSksdD11Lmgscz11Lk07Zi5wKCk7KXtyPWYuZ3UoKQpxPWcuY3JlYXRlRWxlbWVudCgibGkiKQpwPXQu
+YihlLmFwcGVuZENoaWxkKHEpKQpxPUouYV8ocikKbz1KLkUocCkKaWYoSi5jcyhxLmoociwidHlwZSIp
+LCJkaXJlY3RvcnkiKSl7by5nQyhwKS5rKDAsImRpciIpCm89Zy5jcmVhdGVFbGVtZW50KCJzcGFuIikK
+bj10LmIocC5hcHBlbmRDaGlsZChvKSkKbz1KLkUobikKby5nQyhuKS5rKDAsImFycm93IikKby5zYWYo
+biwiJiN4MjVCQzsiKQpvPWcuY3JlYXRlRWxlbWVudCgic3BhbiIpCkouZFEodC5iKHAuYXBwZW5kQ2hp
+bGQobykpLCImI3gxRjRDMTsiKQpwLmFwcGVuZENoaWxkKGcuY3JlYXRlVGV4dE5vZGUoSC5vKHEuaihy
+LGgpKSkpCkwuajAocCxxLmoociwic3VidHJlZSIpKQpMLmxmKG4pfWVsc2V7by5zYWYocCwiJiN4MUY0
+QzQ7IikKbz1nLmNyZWF0ZUVsZW1lbnQoImEiKQptPXQuYihwLmFwcGVuZENoaWxkKG8pKQpvPUouRSht
+KQpvLmdDKG0pLmsoMCwibmF2LWxpbmsiKQpsPUgubyhxLmoociwicGF0aCIpKQptLnNldEF0dHJpYnV0
+ZSgiZGF0YS0iK25ldyBXLmFCKG5ldyBXLmFwKG0pKS5WKGgpLGwpCm0uc2V0QXR0cmlidXRlKCJocmVm
+IixILm8ocS5qKHIsImhyZWYiKSkpCm0uYXBwZW5kQ2hpbGQoZy5jcmVhdGVUZXh0Tm9kZShILm8ocS5q
+KHIsaCkpKSkKbz1vLmdhRyhtKQpsPW8uJHRpCmwuaCgifigxKSIpLmIoTC5mUCgpKQpzLmIobnVsbCkK
+Vy5hQyhvLmEsby5iLEwuZlAoKSwhMSxsLmQpCms9SC54KHEuaihyLCJlZGl0Q291bnQiKSkKaWYodHlw
+ZW9mIGshPT0ibnVtYmVyIilyZXR1cm4gay5hTSgpCmlmKGs+MCl7cT1nLmNyZWF0ZUVsZW1lbnQoInNw
+YW4iKQpqPXQuYihwLmFwcGVuZENoaWxkKHEpKQpKLmFsKGopLmsoMCwiZWRpdC1jb3VudCIpCmk9az09
+PTE/ImVkaXQiOiJlZGl0cyIKai5zZXRBdHRyaWJ1dGUoInRpdGxlIiwiIitrKyIgIitpKQpqLmFwcGVu
+ZENoaWxkKGcuY3JlYXRlVGV4dE5vZGUoQy5jLmkoaykpKX19fX0sCmxBOmZ1bmN0aW9uKCl7dmFyIHQ9
+Ii9fcHJldmlldy9uYXZpZ2F0aW9uVHJlZS5qc29uIixzPXUuTgpXLmUyKHQsbnVsbCxQLmNPKFsiQ29u
+dGVudC1UeXBlIiwiYXBwbGljYXRpb24vanNvbjsgY2hhcnNldD1VVEYtOCJdLHMscykpLmE0KG5ldyBM
+LmZFKCksdS5QKS5hZChuZXcgTC5mRih0KSl9LApmSTpmdW5jdGlvbihhLGIpe3ZhciB0CndpbmRvdwp0
+PUguYihhKQppZih0eXBlb2YgY29uc29sZSE9InVuZGVmaW5lZCIpd2luZG93LmNvbnNvbGUuZXJyb3Io
+dCkKd2luZG93CnQ9SC5iKGIpCmlmKHR5cGVvZiBjb25zb2xlIT0idW5kZWZpbmVkIil3aW5kb3cuY29u
+c29sZS5lcnJvcih0KX0sCmxJOmZ1bmN0aW9uKGEwKXt2YXIgdCxzLHIscSxwLG8sbixtLGwsayxqLGks
+aCxnLGYsZSxkPSJsaW5rIixjPSJocmVmIixiPWRvY3VtZW50LGE9Yi5xdWVyeVNlbGVjdG9yKCIuZWRp
+dC1wYW5lbCAucGFuZWwtY29udGVudCIpCkouZFEoYSwiIikKdD1iLmNyZWF0ZUVsZW1lbnQoInAiKQpK
+LmFsKHQpLmsoMCwicmVnaW9uLWxvY2F0aW9uIikKcz1KLmFfKGEwKQp0LmFwcGVuZENoaWxkKGIuY3Jl
+YXRlVGV4dE5vZGUoSC5iKHMuaihhMCwicGF0aCIpKSsiICIpKQpyPWIuY3JlYXRlRWxlbWVudCgic3Bh
+biIpCnE9dS5oCnA9cS5iKHQuYXBwZW5kQ2hpbGQocikpCnAuYXBwZW5kQ2hpbGQoYi5jcmVhdGVUZXh0
+Tm9kZSgibGluZSAiK0guYihzLmooYTAsImxpbmUiKSkpKQpKLmFsKHApLmsoMCwibm93cmFwIikKYS5h
+cHBlbmRDaGlsZCh0KQpyPWIuY3JlYXRlRWxlbWVudCgicCIpCm89YS5hcHBlbmRDaGlsZChyKQpvLmFw
+cGVuZENoaWxkKGIuY3JlYXRlVGV4dE5vZGUoSC5vKHMuaihhMCwiZXhwbGFuYXRpb24iKSkpKQpuPUou
+YXQocy5qKGEwLCJkZXRhaWxzIikpCmlmKG49PT0wKW8uYXBwZW5kQ2hpbGQoYi5jcmVhdGVUZXh0Tm9k
+ZSgiLiIpKQplbHNle3I9bj09PTE/IiBmb3IgIitILmIobikrIiByZWFzb246IjoiIGZvciAiK0guYihu
+KSsiIHJlYXNvbnM6IgpvLmFwcGVuZENoaWxkKGIuY3JlYXRlVGV4dE5vZGUocikpCnI9Yi5jcmVhdGVF
+bGVtZW50KCJvbCIpCm09YS5hcHBlbmRDaGlsZChyKQpmb3Iocj1KLmE5KHUuUi5iKHMuaihhMCwiZGV0
+YWlscyIpKSksbD11LmE7ci5wKCk7KXtrPXIuZ3UoKQpqPWIuY3JlYXRlRWxlbWVudCgibGkiKQppPW0u
+YXBwZW5kQ2hpbGQoaikKaj1KLmFfKGspCmkuYXBwZW5kQ2hpbGQoYi5jcmVhdGVUZXh0Tm9kZShILm8o
+ai5qKGssImRlc2NyaXB0aW9uIikpKSkKaWYoai5qKGssZCkhPW51bGwpe2kuYXBwZW5kQ2hpbGQoYi5j
+cmVhdGVUZXh0Tm9kZSgiICgiKSkKaD1iLmNyZWF0ZUVsZW1lbnQoImEiKQpnPWwuYihpLmFwcGVuZENo
+aWxkKGgpKQpnLmFwcGVuZENoaWxkKGIuY3JlYXRlVGV4dE5vZGUoSC5vKEouZlcoai5qKGssZCksInRl
+eHQiKSkpKQpnLnNldEF0dHJpYnV0ZShjLEgubyhKLmZXKGouaihrLGQpLGMpKSkKZy5jbGFzc0xpc3Qu
+YWRkKCJuYXYtbGluayIpCmkuYXBwZW5kQ2hpbGQoYi5jcmVhdGVUZXh0Tm9kZSgiKSIpKX19fWlmKHMu
+aihhMCwiZWRpdHMiKSE9bnVsbClmb3Iocz1KLmE5KHUuUi5iKHMuaihhMCwiZWRpdHMiKSkpO3MucCgp
+Oyl7Zj1zLmd1KCkKcj1iLmNyZWF0ZUVsZW1lbnQoInAiKQplPXEuYihhLmFwcGVuZENoaWxkKHIpKQpy
+PWIuY3JlYXRlRWxlbWVudCgiYSIpCmc9cS5iKGUuYXBwZW5kQ2hpbGQocikpCnI9Si5hXyhmKQpnLmFw
+cGVuZENoaWxkKGIuY3JlYXRlVGV4dE5vZGUoSC5vKHIuaihmLCJ0ZXh0IikpKSkKZy5zZXRBdHRyaWJ1
+dGUoYyxILm8oci5qKGYsYykpKQpKLmFsKGcpLmsoMCwicG9zdC1saW5rIil9fSwKaU46ZnVuY3Rpb24o
+YSl7dmFyIHQ9d2luZG93LmxvY2F0aW9uLnBhdGhuYW1lLHM9YS5nZXRBdHRyaWJ1dGUoImRhdGEtIitu
+ZXcgVy5hQihuZXcgVy5hcChhKSkuVigib2Zmc2V0IikpLHI9dS5OClcuZTIoSC5iKHQpKyI/cmVnaW9u
+PXJlZ2lvbiZvZmZzZXQ9IitILmIocyksbnVsbCxQLmNPKFsiQ29udGVudC1UeXBlIiwiYXBwbGljYXRp
+b24vanNvbjsgY2hhcnNldD1VVEYtOCJdLHIscikpLmE0KG5ldyBMLmZHKCksdS5QKS5hZChuZXcgTC5m
+SCh0KSl9LAppVTpmdW5jdGlvbigpe3ZhciB0LHM9ZG9jdW1lbnQscj1zLnF1ZXJ5U2VsZWN0b3IoIi5u
+YXYtaW5uZXIiKSxxPXdpbmRvdy5pbm5lckhlaWdodCxwPXIuc3R5bGUsbz1ILmIocSkrInB4IgpwLmhl
+aWdodD1vCmlmKHR5cGVvZiBxIT09Im51bWJlciIpcmV0dXJuIHEuY3UoKQp0PXEvMi02CnA9cy5xdWVy
+eVNlbGVjdG9yKCIuZWRpdC1wYW5lbCIpLnN0eWxlCm89SC5iKHQpKyJweCIKcC5oZWlnaHQ9bwpzPXMu
+cXVlcnlTZWxlY3RvcigiLmVkaXQtbGlzdCIpLnN0eWxlCnA9SC5iKHQpKyJweCIKcy5oZWlnaHQ9cH0s
+CmlPOmZ1bmN0aW9uKCl7Qy5OLmFjKGRvY3VtZW50LCJET01Db250ZW50TG9hZGVkIixuZXcgTC5mSygp
+KQpDLm8uYWMod2luZG93LCJwb3BzdGF0ZSIsbmV3IEwuZkwoKSkKQy5vLmFjKHdpbmRvdywicmVzaXpl
+IixuZXcgTC5mTShuZXcgTC5jRChDLnQpKSkKQy5vLmFjKHdpbmRvdywic2Nyb2xsIixuZXcgTC5mTihu
+ZXcgTC5jRChDLnQpKSl9LApmVTpmdW5jdGlvbiBmVShhLGIsYyl7dGhpcy5hPWEKdGhpcy5iPWIKdGhp
+cy5jPWN9LApmVDpmdW5jdGlvbiBmVChhLGIpe3RoaXMuYT1hCnRoaXMuYj1ifSwKZkM6ZnVuY3Rpb24g
+ZkMoYSxiLGMsZCl7dmFyIF89dGhpcwpfLmE9YQpfLmI9YgpfLmM9YwpfLmQ9ZH0sCmZEOmZ1bmN0aW9u
+IGZEKGEpe3RoaXMuYT1hfSwKZlM6ZnVuY3Rpb24gZlMoYSl7dGhpcy5hPWF9LApmeDpmdW5jdGlvbiBm
+eCgpe30sCmZqOmZ1bmN0aW9uIGZqKGEsYil7dGhpcy5hPWEKdGhpcy5iPWJ9LApmczpmdW5jdGlvbiBm
+cyhhLGIsYyl7dGhpcy5hPWEKdGhpcy5iPWIKdGhpcy5jPWN9LApmdDpmdW5jdGlvbiBmdChhKXt0aGlz
+LmE9YX0sCmZ1OmZ1bmN0aW9uIGZ1KCl7fSwKZnY6ZnVuY3Rpb24gZnYoYSl7dGhpcy5hPWF9LApmbDpm
+dW5jdGlvbiBmbCgpe30sCmZtOmZ1bmN0aW9uIGZtKCl7fSwKZms6ZnVuY3Rpb24gZmsoYSl7dGhpcy5h
+PWF9LApmbjpmdW5jdGlvbiBmbigpe30sCmZFOmZ1bmN0aW9uIGZFKCl7fSwKZkY6ZnVuY3Rpb24gZkYo
+YSl7dGhpcy5hPWF9LApmRzpmdW5jdGlvbiBmRygpe30sCmZIOmZ1bmN0aW9uIGZIKGEpe3RoaXMuYT1h
+fSwKZks6ZnVuY3Rpb24gZksoKXt9LApmSjpmdW5jdGlvbiBmSihhLGIsYyl7dGhpcy5hPWEKdGhpcy5i
+PWIKdGhpcy5jPWN9LApmTDpmdW5jdGlvbiBmTCgpe30sCmZNOmZ1bmN0aW9uIGZNKGEpe3RoaXMuYT1h
+fSwKZk46ZnVuY3Rpb24gZk4oYSl7dGhpcy5hPWF9LAplMDpmdW5jdGlvbiBlMCgpe30sCmNEOmZ1bmN0
+aW9uIGNEKGEpe3RoaXMuYT1hCnRoaXMuYj1udWxsfSwKY1k6ZnVuY3Rpb24gY1koKXt9fQp2YXIgdz1b
+QyxILEosUCxXLExdCmh1bmtIZWxwZXJzLnNldEZ1bmN0aW9uTmFtZXNJZk5lY2Vzc2FyeSh3KQp2YXIg
+JD17fQpILmgwLnByb3RvdHlwZT17fQpKLkkucHJvdG90eXBlPXsKRzpmdW5jdGlvbihhLGIpe3JldHVy
+biBhPT09Yn0sCmdxOmZ1bmN0aW9uKGEpe3JldHVybiBILmJWKGEpfSwKaTpmdW5jdGlvbihhKXtyZXR1
+cm4iSW5zdGFuY2Ugb2YgJyIrSC5iKEguZWYoYSkpKyInIn0sCmFoOmZ1bmN0aW9uKGEsYil7dS5vLmIo
+YikKdGhyb3cgSC5hKFAuaFUoYSxiLmdiZygpLGIuZ2JqKCksYi5nYmgoKSkpfX0KSi5jSC5wcm90b3R5
+cGU9ewppOmZ1bmN0aW9uKGEpe3JldHVybiBTdHJpbmcoYSl9LApncTpmdW5jdGlvbihhKXtyZXR1cm4g
+YT81MTkwMTg6MjE4MTU5fSwKJGl6OjF9CkouYkoucHJvdG90eXBlPXsKRzpmdW5jdGlvbihhLGIpe3Jl
+dHVybiBudWxsPT1ifSwKaTpmdW5jdGlvbihhKXtyZXR1cm4ibnVsbCJ9LApncTpmdW5jdGlvbihhKXty
+ZXR1cm4gMH0sCmFoOmZ1bmN0aW9uKGEsYil7cmV0dXJuIHRoaXMuYnYoYSx1Lm8uYihiKSl9LAokaXA6
+MX0KSi5heS5wcm90b3R5cGU9ewpncTpmdW5jdGlvbihhKXtyZXR1cm4gMH0sCmk6ZnVuY3Rpb24oYSl7
+cmV0dXJuIFN0cmluZyhhKX0sCiRpaFE6MX0KSi5jWi5wcm90b3R5cGU9e30KSi5iay5wcm90b3R5cGU9
+e30KSi5hZC5wcm90b3R5cGU9ewppOmZ1bmN0aW9uKGEpe3ZhciB0PWFbJC5mVigpXQppZih0PT1udWxs
+KXJldHVybiB0aGlzLmJ5KGEpCnJldHVybiJKYXZhU2NyaXB0IGZ1bmN0aW9uIGZvciAiK0guYihKLmIy
+KHQpKX0sCiRTOmZ1bmN0aW9uKCl7cmV0dXJue2Z1bmM6MSxvcHQ6WywsLCwsLCwsLCwsLCwsLCxdfX0s
+CiRpYWI6MX0KSi5GLnByb3RvdHlwZT17Cms6ZnVuY3Rpb24oYSxiKXtILlooYSkuZC5iKGIpCmlmKCEh
+YS5maXhlZCRsZW5ndGgpSC5hayhQLk4oImFkZCIpKQphLnB1c2goYil9LApJOmZ1bmN0aW9uKGEsYil7
+dmFyIHQKSC5aKGEpLmgoImo8MT4iKS5iKGIpCmlmKCEhYS5maXhlZCRsZW5ndGgpSC5hayhQLk4oImFk
+ZEFsbCIpKQpmb3IodD1KLmE5KGIpO3QucCgpOylhLnB1c2godC5ndSgpKX0sCmFGOmZ1bmN0aW9uKGEs
+YixjKXt2YXIgdD1ILlooYSkKcmV0dXJuIG5ldyBILmE0KGEsdC5FKGMpLmgoIjEoMikiKS5iKGIpLHQu
+aCgiQDwxPiIpLkUoYykuaCgiYTQ8MSwyPiIpKX0sClQ6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzPW5ldyBB
+cnJheShhLmxlbmd0aCkKcy5maXhlZCRsZW5ndGg9QXJyYXkKZm9yKHQ9MDt0PGEubGVuZ3RoOysrdCl0
+aGlzLmwocyx0LEguYihhW3RdKSkKcmV0dXJuIHMuam9pbihiKX0sCmNjOmZ1bmN0aW9uKGEsYixjLGQp
+e3ZhciB0LHMscgpkLmIoYikKSC5aKGEpLkUoZCkuaCgiMSgxLDIpIikuYihjKQp0PWEubGVuZ3RoCmZv
+cihzPWIscj0wO3I8dDsrK3Ipe3M9Yy4kMihzLGFbcl0pCmlmKGEubGVuZ3RoIT09dCl0aHJvdyBILmEo
+UC5hdihhKSl9cmV0dXJuIHN9LApPOmZ1bmN0aW9uKGEsYil7aWYoYjwwfHxiPj1hLmxlbmd0aClyZXR1
+cm4gSC5pKGEsYikKcmV0dXJuIGFbYl19LApidTpmdW5jdGlvbihhLGIsYyl7aWYoYjwwfHxiPmEubGVu
+Z3RoKXRocm93IEguYShQLkwoYiwwLGEubGVuZ3RoLCJzdGFydCIsbnVsbCkpCmlmKGM8Ynx8Yz5hLmxl
+bmd0aCl0aHJvdyBILmEoUC5MKGMsYixhLmxlbmd0aCwiZW5kIixudWxsKSkKaWYoYj09PWMpcmV0dXJu
+IEgubihbXSxILlooYSkpCnJldHVybiBILm4oYS5zbGljZShiLGMpLEguWihhKSl9LApnYWc6ZnVuY3Rp
+b24oYSl7dmFyIHQ9YS5sZW5ndGgKaWYodD4wKXJldHVybiBhW3QtMV0KdGhyb3cgSC5hKEguaFAoKSl9
+LApiODpmdW5jdGlvbihhLGIpe3ZhciB0LHMKSC5aKGEpLmgoInooMSkiKS5iKGIpCnQ9YS5sZW5ndGgK
+Zm9yKHM9MDtzPHQ7KytzKXtpZihILmRLKGIuJDEoYVtzXSkpKXJldHVybiEwCmlmKGEubGVuZ3RoIT09
+dCl0aHJvdyBILmEoUC5hdihhKSl9cmV0dXJuITF9LAp3OmZ1bmN0aW9uKGEsYil7dmFyIHQKZm9yKHQ9
+MDt0PGEubGVuZ3RoOysrdClpZihKLmNzKGFbdF0sYikpcmV0dXJuITAKcmV0dXJuITF9LAppOmZ1bmN0
+aW9uKGEpe3JldHVybiBQLmU2KGEsIlsiLCJdIil9LApnRjpmdW5jdGlvbihhKXtyZXR1cm4gbmV3IEou
+YUYoYSxhLmxlbmd0aCxILlooYSkuaCgiYUY8MT4iKSl9LApncTpmdW5jdGlvbihhKXtyZXR1cm4gSC5i
+VihhKX0sCmdtOmZ1bmN0aW9uKGEpe3JldHVybiBhLmxlbmd0aH0sCnNtOmZ1bmN0aW9uKGEsYil7aWYo
+ISFhLmZpeGVkJGxlbmd0aClILmFrKFAuTigic2V0IGxlbmd0aCIpKQppZihiPDApdGhyb3cgSC5hKFAu
+TChiLDAsbnVsbCwibmV3TGVuZ3RoIixudWxsKSkKYS5sZW5ndGg9Yn0sCmo6ZnVuY3Rpb24oYSxiKXtI
+LngoYikKaWYoYj49YS5sZW5ndGh8fGI8MCl0aHJvdyBILmEoSC5iMShhLGIpKQpyZXR1cm4gYVtiXX0s
+Cmw6ZnVuY3Rpb24oYSxiLGMpe0guWihhKS5kLmIoYykKaWYoISFhLmltbXV0YWJsZSRsaXN0KUguYWso
+UC5OKCJpbmRleGVkIHNldCIpKQppZihiPj1hLmxlbmd0aHx8ITEpdGhyb3cgSC5hKEguYjEoYSxiKSkK
+YVtiXT1jfSwKJGlqOjEsCiRpbToxfQpKLmU3LnByb3RvdHlwZT17fQpKLmFGLnByb3RvdHlwZT17Cmd1
+OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuZH0sCnA6ZnVuY3Rpb24oKXt2YXIgdCxzPXRoaXMscj1zLmEs
+cT1yLmxlbmd0aAppZihzLmIhPT1xKXRocm93IEguYShILmNyKHIpKQp0PXMuYwppZih0Pj1xKXtzLnNh
+WChudWxsKQpyZXR1cm4hMX1zLnNhWChyW3RdKTsrK3MuYwpyZXR1cm4hMH0sCnNhWDpmdW5jdGlvbihh
+KXt0aGlzLmQ9dGhpcy4kdGkuZC5iKGEpfSwKJGlSOjF9CkouYmEucHJvdG90eXBlPXsKYm86ZnVuY3Rp
+b24oYSl7dmFyIHQKaWYoYT49LTIxNDc0ODM2NDgmJmE8PTIxNDc0ODM2NDcpcmV0dXJuIGF8MAppZihp
+c0Zpbml0ZShhKSl7dD1hPDA/TWF0aC5jZWlsKGEpOk1hdGguZmxvb3IoYSkKcmV0dXJuIHQrMH10aHJv
+dyBILmEoUC5OKCIiK2ErIi50b0ludCgpIikpfSwKYTM6ZnVuY3Rpb24oYSl7aWYoYT4wKXtpZihhIT09
+MS8wKXJldHVybiBNYXRoLnJvdW5kKGEpfWVsc2UgaWYoYT4tMS8wKXJldHVybiAwLU1hdGgucm91bmQo
+MC1hKQp0aHJvdyBILmEoUC5OKCIiK2ErIi5yb3VuZCgpIikpfSwKYTU6ZnVuY3Rpb24oYSxiKXt2YXIg
+dCxzLHIscQppZihiPDJ8fGI+MzYpdGhyb3cgSC5hKFAuTChiLDIsMzYsInJhZGl4IixudWxsKSkKdD1h
+LnRvU3RyaW5nKGIpCmlmKEMuYS52KHQsdC5sZW5ndGgtMSkhPT00MSlyZXR1cm4gdApzPS9eKFtcZGEt
+el0rKSg/OlwuKFtcZGEtel0rKSk/XChlXCsoXGQrKVwpJC8uZXhlYyh0KQppZihzPT1udWxsKUguYWso
+UC5OKCJVbmV4cGVjdGVkIHRvU3RyaW5nIHJlc3VsdDogIit0KSkKcj1zLmxlbmd0aAppZigxPj1yKXJl
+dHVybiBILmkocywxKQp0PXNbMV0KaWYoMz49cilyZXR1cm4gSC5pKHMsMykKcT0rc1szXQpyPXNbMl0K
+aWYociE9bnVsbCl7dCs9cgpxLT1yLmxlbmd0aH1yZXR1cm4gdCtDLmEuYU4oIjAiLHEpfSwKaTpmdW5j
+dGlvbihhKXtpZihhPT09MCYmMS9hPDApcmV0dXJuIi0wLjAiCmVsc2UgcmV0dXJuIiIrYX0sCmdxOmZ1
+bmN0aW9uKGEpe3ZhciB0LHMscixxLHA9YXwwCmlmKGE9PT1wKXJldHVybiA1MzY4NzA5MTEmcAp0PU1h
+dGguYWJzKGEpCnM9TWF0aC5sb2codCkvMC42OTMxNDcxODA1NTk5NDUzfDAKcj1NYXRoLnBvdygyLHMp
+CnE9dDwxP3QvcjpyL3QKcmV0dXJuIDUzNjg3MDkxMSYoKHEqOTAwNzE5OTI1NDc0MDk5MnwwKSsocSoz
+NTQyMjQzMTgxMTc2NTIxfDApKSo1OTkxOTcrcyoxMjU5fSwKQjpmdW5jdGlvbihhLGIpe2lmKHR5cGVv
+ZiBiIT0ibnVtYmVyIil0aHJvdyBILmEoSC5hcyhiKSkKcmV0dXJuIGErYn0sCmFrOmZ1bmN0aW9uKGEs
+Yil7dmFyIHQ9YSViCmlmKHQ9PT0wKXJldHVybiAwCmlmKHQ+MClyZXR1cm4gdAppZihiPDApcmV0dXJu
+IHQtYgplbHNlIHJldHVybiB0K2J9LAphYjpmdW5jdGlvbihhLGIpe3JldHVybihhfDApPT09YT9hL2J8
+MDp0aGlzLmJZKGEsYil9LApiWTpmdW5jdGlvbihhLGIpe3ZhciB0PWEvYgppZih0Pj0tMjE0NzQ4MzY0
+OCYmdDw9MjE0NzQ4MzY0NylyZXR1cm4gdHwwCmlmKHQ+MCl7aWYodCE9PTEvMClyZXR1cm4gTWF0aC5m
+bG9vcih0KX1lbHNlIGlmKHQ+LTEvMClyZXR1cm4gTWF0aC5jZWlsKHQpCnRocm93IEguYShQLk4oIlJl
+c3VsdCBvZiB0cnVuY2F0aW5nIGRpdmlzaW9uIGlzICIrSC5iKHQpKyI6ICIrSC5iKGEpKyIgfi8gIiti
+KSl9LApaOmZ1bmN0aW9uKGEsYil7dmFyIHQKaWYoYT4wKXQ9dGhpcy5iMyhhLGIpCmVsc2V7dD1iPjMx
+PzMxOmIKdD1hPj50Pj4+MH1yZXR1cm4gdH0sCmJYOmZ1bmN0aW9uKGEsYil7aWYoYjwwKXRocm93IEgu
+YShILmFzKGIpKQpyZXR1cm4gdGhpcy5iMyhhLGIpfSwKYjM6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gYj4z
+MT8wOmE+Pj5ifSwKUjpmdW5jdGlvbihhLGIpe3JldHVybihhfGIpPj4+MH0sCiRpVDoxLAokaVU6MX0K
+Si5iSS5wcm90b3R5cGU9eyRpZjoxfQpKLmNJLnByb3RvdHlwZT17fQpKLmF4LnByb3RvdHlwZT17CnY6
+ZnVuY3Rpb24oYSxiKXtpZihiPDApdGhyb3cgSC5hKEguYjEoYSxiKSkKaWYoYj49YS5sZW5ndGgpSC5h
+ayhILmIxKGEsYikpCnJldHVybiBhLmNoYXJDb2RlQXQoYil9LAp0OmZ1bmN0aW9uKGEsYil7aWYoYj49
+YS5sZW5ndGgpdGhyb3cgSC5hKEguYjEoYSxiKSkKcmV0dXJuIGEuY2hhckNvZGVBdChiKX0sCkI6ZnVu
+Y3Rpb24oYSxiKXtpZih0eXBlb2YgYiE9InN0cmluZyIpdGhyb3cgSC5hKFAuZlgoYixudWxsLG51bGwp
+KQpyZXR1cm4gYStifSwKYTA6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIHQscwpjPVAuYVYoYixjLGEubGVu
+Z3RoKQp0PWEuc3Vic3RyaW5nKDAsYikKcz1hLnN1YnN0cmluZyhjKQpyZXR1cm4gdCtkK3N9LApTOmZ1
+bmN0aW9uKGEsYixjKXt2YXIgdAppZihjPDB8fGM+YS5sZW5ndGgpdGhyb3cgSC5hKFAuTChjLDAsYS5s
+ZW5ndGgsbnVsbCxudWxsKSkKdD1jK2IubGVuZ3RoCmlmKHQ+YS5sZW5ndGgpcmV0dXJuITEKcmV0dXJu
+IGI9PT1hLnN1YnN0cmluZyhjLHQpfSwKSDpmdW5jdGlvbihhLGIpe3JldHVybiB0aGlzLlMoYSxiLDAp
+fSwKbjpmdW5jdGlvbihhLGIsYyl7aWYoIUguZEooYikpSC5hayhILmFzKGIpKQppZihjPT1udWxsKWM9
+YS5sZW5ndGgKaWYodHlwZW9mIGIhPT0ibnVtYmVyIilyZXR1cm4gYi5EKCkKaWYoYjwwKXRocm93IEgu
+YShQLmVnKGIsbnVsbCkpCmlmKGI+Yyl0aHJvdyBILmEoUC5lZyhiLG51bGwpKQppZihjPmEubGVuZ3Ro
+KXRocm93IEguYShQLmVnKGMsbnVsbCkpCnJldHVybiBhLnN1YnN0cmluZyhiLGMpfSwKVTpmdW5jdGlv
+bihhLGIpe3JldHVybiB0aGlzLm4oYSxiLG51bGwpfSwKY3I6ZnVuY3Rpb24oYSl7cmV0dXJuIGEudG9M
+b3dlckNhc2UoKX0sCmNzOmZ1bmN0aW9uKGEpe3ZhciB0LHMscixxPWEudHJpbSgpLHA9cS5sZW5ndGgK
+aWYocD09PTApcmV0dXJuIHEKaWYodGhpcy50KHEsMCk9PT0xMzMpe3Q9Si5qSyhxLDEpCmlmKHQ9PT1w
+KXJldHVybiIifWVsc2UgdD0wCnM9cC0xCnI9dGhpcy52KHEscyk9PT0xMzM/Si5qTChxLHMpOnAKaWYo
+dD09PTAmJnI9PT1wKXJldHVybiBxCnJldHVybiBxLnN1YnN0cmluZyh0LHIpfSwKYU46ZnVuY3Rpb24o
+YSxiKXt2YXIgdCxzCmlmKDA+PWIpcmV0dXJuIiIKaWYoYj09PTF8fGEubGVuZ3RoPT09MClyZXR1cm4g
+YQppZihiIT09Yj4+PjApdGhyb3cgSC5hKEMuSykKZm9yKHQ9YSxzPSIiOyEwOyl7aWYoKGImMSk9PT0x
+KXM9dCtzCmI9Yj4+PjEKaWYoYj09PTApYnJlYWsKdCs9dH1yZXR1cm4gc30sCmFlOmZ1bmN0aW9uKGEs
+YixjKXt2YXIgdAppZihjPDB8fGM+YS5sZW5ndGgpdGhyb3cgSC5hKFAuTChjLDAsYS5sZW5ndGgsbnVs
+bCxudWxsKSkKdD1hLmluZGV4T2YoYixjKQpyZXR1cm4gdH0sCmJmOmZ1bmN0aW9uKGEsYil7cmV0dXJu
+IHRoaXMuYWUoYSxiLDApfSwKaTpmdW5jdGlvbihhKXtyZXR1cm4gYX0sCmdxOmZ1bmN0aW9uKGEpe3Zh
+ciB0LHMscgpmb3IodD1hLmxlbmd0aCxzPTAscj0wO3I8dDsrK3Ipe3M9NTM2ODcwOTExJnMrYS5jaGFy
+Q29kZUF0KHIpCnM9NTM2ODcwOTExJnMrKCg1MjQyODcmcyk8PDEwKQpzXj1zPj42fXM9NTM2ODcwOTEx
+JnMrKCg2NzEwODg2MyZzKTw8MykKc149cz4+MTEKcmV0dXJuIDUzNjg3MDkxMSZzKygoMTYzODMmcyk8
+PDE1KX0sCmdtOmZ1bmN0aW9uKGEpe3JldHVybiBhLmxlbmd0aH0sCmo6ZnVuY3Rpb24oYSxiKXtILngo
+YikKaWYoYj49YS5sZW5ndGh8fCExKXRocm93IEguYShILmIxKGEsYikpCnJldHVybiBhW2JdfSwKJGlj
+WDoxLAokaWM6MX0KSC5jeS5wcm90b3R5cGU9ewpnbTpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5hLmxl
+bmd0aH0sCmo6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gQy5hLnYodGhpcy5hLEgueChiKSl9fQpILmJDLnBy
+b3RvdHlwZT17fQpILmFlLnByb3RvdHlwZT17CmdGOmZ1bmN0aW9uKGEpe3ZhciB0PXRoaXMKcmV0dXJu
+IG5ldyBILmFRKHQsdC5nbSh0KSxILnYodCkuaCgiYVE8YWUuRT4iKSl9LAphajpmdW5jdGlvbihhLGIp
+e3JldHVybiB0aGlzLmJ4KDAsSC52KHRoaXMpLmgoInooYWUuRSkiKS5iKGIpKX19CkguYVEucHJvdG90
+eXBlPXsKZ3U6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5kfSwKcDpmdW5jdGlvbigpe3ZhciB0LHM9dGhp
+cyxyPXMuYSxxPUouYV8ocikscD1xLmdtKHIpCmlmKHMuYiE9PXApdGhyb3cgSC5hKFAuYXYocikpCnQ9
+cy5jCmlmKHQ+PXApe3Muc2FRKG51bGwpCnJldHVybiExfXMuc2FRKHEuTyhyLHQpKTsrK3MuYwpyZXR1
+cm4hMH0sCnNhUTpmdW5jdGlvbihhKXt0aGlzLmQ9dGhpcy4kdGkuZC5iKGEpfSwKJGlSOjF9CkguYTQu
+cHJvdG90eXBlPXsKZ206ZnVuY3Rpb24oYSl7cmV0dXJuIEouYXQodGhpcy5hKX0sCk86ZnVuY3Rpb24o
+YSxiKXtyZXR1cm4gdGhpcy5iLiQxKEouam0odGhpcy5hLGIpKX19CkguYVkucHJvdG90eXBlPXsKZ0Y6
+ZnVuY3Rpb24oYSl7cmV0dXJuIG5ldyBILmNfKEouYTkodGhpcy5hKSx0aGlzLmIsdGhpcy4kdGkuaCgi
+Y188MT4iKSl9fQpILmNfLnByb3RvdHlwZT17CnA6ZnVuY3Rpb24oKXt2YXIgdCxzCmZvcih0PXRoaXMu
+YSxzPXRoaXMuYjt0LnAoKTspaWYoSC5kSyhzLiQxKHQuZ3UoKSkpKXJldHVybiEwCnJldHVybiExfSwK
+Z3U6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5hLmd1KCl9fQpILlYucHJvdG90eXBlPXt9CkguYVgucHJv
+dG90eXBlPXsKbDpmdW5jdGlvbihhLGIsYyl7SC52KHRoaXMpLmgoImFYLkUiKS5iKGMpCnRocm93IEgu
+YShQLk4oIkNhbm5vdCBtb2RpZnkgYW4gdW5tb2RpZmlhYmxlIGxpc3QiKSl9fQpILmJsLnByb3RvdHlw
+ZT17fQpILmJpLnByb3RvdHlwZT17CmdxOmZ1bmN0aW9uKGEpe3ZhciB0PXRoaXMuX2hhc2hDb2RlCmlm
+KHQhPW51bGwpcmV0dXJuIHQKdD01MzY4NzA5MTEmNjY0NTk3KkouYnYodGhpcy5hKQp0aGlzLl9oYXNo
+Q29kZT10CnJldHVybiB0fSwKaTpmdW5jdGlvbihhKXtyZXR1cm4nU3ltYm9sKCInK0guYih0aGlzLmEp
+KyciKSd9LApHOmZ1bmN0aW9uKGEsYil7aWYoYj09bnVsbClyZXR1cm4hMQpyZXR1cm4gYiBpbnN0YW5j
+ZW9mIEguYmkmJnRoaXMuYT09Yi5hfSwKJGlhNjoxfQpILmJ6LnByb3RvdHlwZT17fQpILmJ5LnByb3Rv
+dHlwZT17Cmk6ZnVuY3Rpb24oYSl7cmV0dXJuIFAuaDModGhpcyl9LApsOmZ1bmN0aW9uKGEsYixjKXt2
+YXIgdD1ILnYodGhpcykKdC5kLmIoYikKdC5jaFsxXS5iKGMpCnJldHVybiBILmpDKCl9LAokaXk6MX0K
+SC5hSi5wcm90b3R5cGU9ewpnbTpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5hfSwKYV86ZnVuY3Rpb24o
+YSl7aWYoIl9fcHJvdG9fXyI9PT1hKXJldHVybiExCnJldHVybiB0aGlzLmIuaGFzT3duUHJvcGVydHko
+YSl9LApqOmZ1bmN0aW9uKGEsYil7aWYoIXRoaXMuYV8oYikpcmV0dXJuIG51bGwKcmV0dXJuIHRoaXMu
+YVkoYil9LAphWTpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5iW0gubyhhKV19LApBOmZ1bmN0aW9uKGEs
+Yil7dmFyIHQscyxyLHEscD1ILnYodGhpcykKcC5oKCJ+KDEsMikiKS5iKGIpCnQ9dGhpcy5jCmZvcihz
+PXQubGVuZ3RoLHA9cC5jaFsxXSxyPTA7cjxzOysrcil7cT10W3JdCmIuJDIocSxwLmIodGhpcy5hWShx
+KSkpfX19CkguY0oucHJvdG90eXBlPXsKZ2JnOmZ1bmN0aW9uKCl7dmFyIHQ9dGhpcy5hCnJldHVybiB0
+fSwKZ2JqOmZ1bmN0aW9uKCl7dmFyIHQscyxyLHEscD10aGlzCmlmKHAuYz09PTEpcmV0dXJuIEMudwp0
+PXAuZApzPXQubGVuZ3RoLXAuZS5sZW5ndGgtcC5mCmlmKHM9PT0wKXJldHVybiBDLncKcj1bXQpmb3Io
+cT0wO3E8czsrK3Epe2lmKHE+PXQubGVuZ3RoKXJldHVybiBILmkodCxxKQpyLnB1c2godFtxXSl9ci5m
+aXhlZCRsZW5ndGg9QXJyYXkKci5pbW11dGFibGUkbGlzdD1BcnJheQpyZXR1cm4gcn0sCmdiaDpmdW5j
+dGlvbigpe3ZhciB0LHMscixxLHAsbyxuLG0sbD10aGlzCmlmKGwuYyE9PTApcmV0dXJuIEMuQQp0PWwu
+ZQpzPXQubGVuZ3RoCnI9bC5kCnE9ci5sZW5ndGgtcy1sLmYKaWYocz09PTApcmV0dXJuIEMuQQpwPW5l
+dyBILmFuKHUuQikKZm9yKG89MDtvPHM7KytvKXtpZihvPj10Lmxlbmd0aClyZXR1cm4gSC5pKHQsbykK
+bj10W29dCm09cStvCmlmKG08MHx8bT49ci5sZW5ndGgpcmV0dXJuIEguaShyLG0pCnAubCgwLG5ldyBI
+LmJpKG4pLHJbbV0pfXJldHVybiBuZXcgSC5ieihwLHUuRCl9LAokaWhPOjF9CkguZWUucHJvdG90eXBl
+PXsKJDI6ZnVuY3Rpb24oYSxiKXt2YXIgdApILm8oYSkKdD10aGlzLmEKdC5iPXQuYisiJCIrSC5iKGEp
+CkMuYi5rKHRoaXMuYixhKQpDLmIuayh0aGlzLmMsYik7Kyt0LmF9LAokUzoxOH0KSC5lai5wcm90b3R5
+cGU9ewpMOmZ1bmN0aW9uKGEpe3ZhciB0LHMscj10aGlzLHE9bmV3IFJlZ0V4cChyLmEpLmV4ZWMoYSkK
+aWYocT09bnVsbClyZXR1cm4gbnVsbAp0PU9iamVjdC5jcmVhdGUobnVsbCkKcz1yLmIKaWYocyE9PS0x
+KXQuYXJndW1lbnRzPXFbcysxXQpzPXIuYwppZihzIT09LTEpdC5hcmd1bWVudHNFeHByPXFbcysxXQpz
+PXIuZAppZihzIT09LTEpdC5leHByPXFbcysxXQpzPXIuZQppZihzIT09LTEpdC5tZXRob2Q9cVtzKzFd
+CnM9ci5mCmlmKHMhPT0tMSl0LnJlY2VpdmVyPXFbcysxXQpyZXR1cm4gdH19CkguY1YucHJvdG90eXBl
+PXsKaTpmdW5jdGlvbihhKXt2YXIgdD10aGlzLmIKaWYodD09bnVsbClyZXR1cm4iTm9TdWNoTWV0aG9k
+RXJyb3I6ICIrSC5iKHRoaXMuYSkKcmV0dXJuIk5vU3VjaE1ldGhvZEVycm9yOiBtZXRob2Qgbm90IGZv
+dW5kOiAnIit0KyInIG9uIG51bGwifX0KSC5jTC5wcm90b3R5cGU9ewppOmZ1bmN0aW9uKGEpe3ZhciB0
+LHM9dGhpcyxyPSJOb1N1Y2hNZXRob2RFcnJvcjogbWV0aG9kIG5vdCBmb3VuZDogJyIscT1zLmIKaWYo
+cT09bnVsbClyZXR1cm4iTm9TdWNoTWV0aG9kRXJyb3I6ICIrSC5iKHMuYSkKdD1zLmMKaWYodD09bnVs
+bClyZXR1cm4gcitxKyInICgiK0guYihzLmEpKyIpIgpyZXR1cm4gcitxKyInIG9uICciK3QrIicgKCIr
+SC5iKHMuYSkrIikifX0KSC5kYS5wcm90b3R5cGU9ewppOmZ1bmN0aW9uKGEpe3ZhciB0PXRoaXMuYQpy
+ZXR1cm4gdC5sZW5ndGg9PT0wPyJFcnJvciI6IkVycm9yOiAiK3R9fQpILmZSLnByb3RvdHlwZT17CiQx
+OmZ1bmN0aW9uKGEpe2lmKHUuYlUuYyhhKSlpZihhLiR0aHJvd25Kc0Vycm9yPT1udWxsKWEuJHRocm93
+bkpzRXJyb3I9dGhpcy5hCnJldHVybiBhfSwKJFM6NH0KSC5jZy5wcm90b3R5cGU9ewppOmZ1bmN0aW9u
+KGEpe3ZhciB0LHM9dGhpcy5iCmlmKHMhPW51bGwpcmV0dXJuIHMKcz10aGlzLmEKdD1zIT09bnVsbCYm
+dHlwZW9mIHM9PT0ib2JqZWN0Ij9zLnN0YWNrOm51bGwKcmV0dXJuIHRoaXMuYj10PT1udWxsPyIiOnR9
+LAokaWFnOjF9CkguYUkucHJvdG90eXBlPXsKaTpmdW5jdGlvbihhKXt2YXIgdD10aGlzLmNvbnN0cnVj
+dG9yLHM9dD09bnVsbD9udWxsOnQubmFtZQpyZXR1cm4iQ2xvc3VyZSAnIitILmlZKHM9PW51bGw/InVu
+a25vd24iOnMpKyInIn0sCiRpYWI6MSwKZ2N0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXN9LAokQzoiJDEi
+LAokUjoxLAokRDpudWxsfQpILmQ4LnByb3RvdHlwZT17fQpILmQzLnByb3RvdHlwZT17Cmk6ZnVuY3Rp
+b24oYSl7dmFyIHQ9dGhpcy4kc3RhdGljX25hbWUKaWYodD09bnVsbClyZXR1cm4iQ2xvc3VyZSBvZiB1
+bmtub3duIHN0YXRpYyBtZXRob2QiCnJldHVybiJDbG9zdXJlICciK0guaVkodCkrIicifX0KSC5iNi5w
+cm90b3R5cGU9ewpHOmZ1bmN0aW9uKGEsYil7dmFyIHQ9dGhpcwppZihiPT1udWxsKXJldHVybiExCmlm
+KHQ9PT1iKXJldHVybiEwCmlmKCEoYiBpbnN0YW5jZW9mIEguYjYpKXJldHVybiExCnJldHVybiB0LmE9
+PT1iLmEmJnQuYj09PWIuYiYmdC5jPT09Yi5jfSwKZ3E6ZnVuY3Rpb24oYSl7dmFyIHQscz10aGlzLmMK
+aWYocz09bnVsbCl0PUguYlYodGhpcy5hKQplbHNlIHQ9dHlwZW9mIHMhPT0ib2JqZWN0Ij9KLmJ2KHMp
+OkguYlYocykKcmV0dXJuKHReSC5iVih0aGlzLmIpKT4+PjB9LAppOmZ1bmN0aW9uKGEpe3ZhciB0PXRo
+aXMuYwppZih0PT1udWxsKXQ9dGhpcy5hCnJldHVybiJDbG9zdXJlICciK0guYih0aGlzLmQpKyInIG9m
+ICIrKCJJbnN0YW5jZSBvZiAnIitILmIoSC5lZih0KSkrIiciKX19CkguZDAucHJvdG90eXBlPXsKaTpm
+dW5jdGlvbihhKXtyZXR1cm4iUnVudGltZUVycm9yOiAiK0guYih0aGlzLmEpfX0KSC5kZy5wcm90b3R5
+cGU9ewppOmZ1bmN0aW9uKGEpe3JldHVybiJBc3NlcnRpb24gZmFpbGVkOiAiK1AuYU0odGhpcy5hKX19
+CkguYW4ucHJvdG90eXBlPXsKZ206ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuYX0sCmdKOmZ1bmN0aW9u
+KCl7cmV0dXJuIG5ldyBILmFQKHRoaXMsSC52KHRoaXMpLmgoImFQPDE+IikpfSwKYV86ZnVuY3Rpb24o
+YSl7dmFyIHQscwppZih0eXBlb2YgYT09InN0cmluZyIpe3Q9dGhpcy5iCmlmKHQ9PW51bGwpcmV0dXJu
+ITEKcmV0dXJuIHRoaXMuYk8odCxhKX1lbHNle3M9dGhpcy5jZihhKQpyZXR1cm4gc319LApjZjpmdW5j
+dGlvbihhKXt2YXIgdD10aGlzLmQKaWYodD09bnVsbClyZXR1cm4hMQpyZXR1cm4gdGhpcy5hRSh0aGlz
+LmF1KHQsSi5idihhKSYweDNmZmZmZmYpLGEpPj0wfSwKajpmdW5jdGlvbihhLGIpe3ZhciB0LHMscixx
+LHA9dGhpcyxvPW51bGwKaWYodHlwZW9mIGI9PSJzdHJpbmciKXt0PXAuYgppZih0PT1udWxsKXJldHVy
+biBvCnM9cC5hOCh0LGIpCnI9cz09bnVsbD9vOnMuYgpyZXR1cm4gcn1lbHNlIGlmKHR5cGVvZiBiPT0i
+bnVtYmVyIiYmKGImMHgzZmZmZmZmKT09PWIpe3E9cC5jCmlmKHE9PW51bGwpcmV0dXJuIG8Kcz1wLmE4
+KHEsYikKcj1zPT1udWxsP286cy5iCnJldHVybiByfWVsc2UgcmV0dXJuIHAuY2coYil9LApjZzpmdW5j
+dGlvbihhKXt2YXIgdCxzLHI9dGhpcy5kCmlmKHI9PW51bGwpcmV0dXJuIG51bGwKdD10aGlzLmF1KHIs
+Si5idihhKSYweDNmZmZmZmYpCnM9dGhpcy5hRSh0LGEpCmlmKHM8MClyZXR1cm4gbnVsbApyZXR1cm4g
+dFtzXS5ifSwKbDpmdW5jdGlvbihhLGIsYyl7dmFyIHQscyxyLHEscCxvLG49dGhpcyxtPUgudihuKQpt
+LmQuYihiKQptLmNoWzFdLmIoYykKaWYodHlwZW9mIGI9PSJzdHJpbmciKXt0PW4uYgpuLmFSKHQ9PW51
+bGw/bi5iPW4uYXYoKTp0LGIsYyl9ZWxzZSBpZih0eXBlb2YgYj09Im51bWJlciImJihiJjB4M2ZmZmZm
+Zik9PT1iKXtzPW4uYwpuLmFSKHM9PW51bGw/bi5jPW4uYXYoKTpzLGIsYyl9ZWxzZXtyPW4uZAppZihy
+PT1udWxsKXI9bi5kPW4uYXYoKQpxPUouYnYoYikmMHgzZmZmZmZmCnA9bi5hdShyLHEpCmlmKHA9PW51
+bGwpbi5heChyLHEsW24uYW4oYixjKV0pCmVsc2V7bz1uLmFFKHAsYikKaWYobz49MClwW29dLmI9Ywpl
+bHNlIHAucHVzaChuLmFuKGIsYykpfX19LApBOmZ1bmN0aW9uKGEsYil7dmFyIHQscyxyPXRoaXMKSC52
+KHIpLmgoIn4oMSwyKSIpLmIoYikKdD1yLmUKcz1yLnIKZm9yKDt0IT1udWxsOyl7Yi4kMih0LmEsdC5i
+KQppZihzIT09ci5yKXRocm93IEguYShQLmF2KHIpKQp0PXQuY319LAphUjpmdW5jdGlvbihhLGIsYyl7
+dmFyIHQscz10aGlzLHI9SC52KHMpCnIuZC5iKGIpCnIuY2hbMV0uYihjKQp0PXMuYTgoYSxiKQppZih0
+PT1udWxsKXMuYXgoYSxiLHMuYW4oYixjKSkKZWxzZSB0LmI9Y30sCmJHOmZ1bmN0aW9uKCl7dGhpcy5y
+PXRoaXMucisxJjY3MTA4ODYzfSwKYW46ZnVuY3Rpb24oYSxiKXt2YXIgdCxzPXRoaXMscj1ILnYocyks
+cT1uZXcgSC5lOChyLmQuYihhKSxyLmNoWzFdLmIoYikpCmlmKHMuZT09bnVsbClzLmU9cy5mPXEKZWxz
+ZXt0PXMuZgpxLmQ9dApzLmY9dC5jPXF9KytzLmEKcy5iRygpCnJldHVybiBxfSwKYUU6ZnVuY3Rpb24o
+YSxiKXt2YXIgdCxzCmlmKGE9PW51bGwpcmV0dXJuLTEKdD1hLmxlbmd0aApmb3Iocz0wO3M8dDsrK3Mp
+aWYoSi5jcyhhW3NdLmEsYikpcmV0dXJuIHMKcmV0dXJuLTF9LAppOmZ1bmN0aW9uKGEpe3JldHVybiBQ
+LmgzKHRoaXMpfSwKYTg6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gYVtiXX0sCmF1OmZ1bmN0aW9uKGEsYil7
+cmV0dXJuIGFbYl19LApheDpmdW5jdGlvbihhLGIsYyl7YVtiXT1jfSwKYlA6ZnVuY3Rpb24oYSxiKXtk
+ZWxldGUgYVtiXX0sCmJPOmZ1bmN0aW9uKGEsYil7cmV0dXJuIHRoaXMuYTgoYSxiKSE9bnVsbH0sCmF2
+OmZ1bmN0aW9uKCl7dmFyIHQ9Ijxub24taWRlbnRpZmllci1rZXk+IixzPU9iamVjdC5jcmVhdGUobnVs
+bCkKdGhpcy5heChzLHQscykKdGhpcy5iUChzLHQpCnJldHVybiBzfSwKJGloUzoxfQpILmU4LnByb3Rv
+dHlwZT17fQpILmFQLnByb3RvdHlwZT17CmdtOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLmEuYX0sCmdG
+OmZ1bmN0aW9uKGEpe3ZhciB0PXRoaXMuYSxzPW5ldyBILmJMKHQsdC5yLHRoaXMuJHRpLmgoImJMPDE+
+IikpCnMuYz10LmUKcmV0dXJuIHN9fQpILmJMLnByb3RvdHlwZT17Cmd1OmZ1bmN0aW9uKCl7cmV0dXJu
+IHRoaXMuZH0sCnA6ZnVuY3Rpb24oKXt2YXIgdD10aGlzLHM9dC5hCmlmKHQuYiE9PXMucil0aHJvdyBI
+LmEoUC5hdihzKSkKZWxzZXtzPXQuYwppZihzPT1udWxsKXt0LnNhUyhudWxsKQpyZXR1cm4hMX1lbHNl
+e3Quc2FTKHMuYSkKdC5jPXQuYy5jCnJldHVybiEwfX19LApzYVM6ZnVuY3Rpb24oYSl7dGhpcy5kPXRo
+aXMuJHRpLmQuYihhKX0sCiRpUjoxfQpILmZ5LnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3JldHVy
+biB0aGlzLmEoYSl9LAokUzo0fQpILmZ6LnByb3RvdHlwZT17CiQyOmZ1bmN0aW9uKGEsYil7cmV0dXJu
+IHRoaXMuYShhLGIpfSwKJFM6MjF9CkguZkEucHJvdG90eXBlPXsKJDE6ZnVuY3Rpb24oYSl7cmV0dXJu
+IHRoaXMuYShILm8oYSkpfSwKJFM6MjV9CkguY0sucHJvdG90eXBlPXsKaTpmdW5jdGlvbihhKXtyZXR1
+cm4iUmVnRXhwLyIrdGhpcy5hKyIvIit0aGlzLmIuZmxhZ3N9LAokaWNYOjEsCiRpaFo6MX0KSC5DLnBy
+b3RvdHlwZT17JGlDOjEsJGlXOjF9CkguYlEucHJvdG90eXBlPXsKZ206ZnVuY3Rpb24oYSl7cmV0dXJu
+IGEubGVuZ3RofSwKJGlKOjF9CkguYVIucHJvdG90eXBlPXsKajpmdW5jdGlvbihhLGIpe0gueChiKQpI
+LmFyKGIsYSxhLmxlbmd0aCkKcmV0dXJuIGFbYl19LApsOmZ1bmN0aW9uKGEsYixjKXtILmFyKGIsYSxh
+Lmxlbmd0aCkKYVtiXT1jfSwKJGlqOjEsCiRpbToxfQpILmJSLnByb3RvdHlwZT17Cmw6ZnVuY3Rpb24o
+YSxiLGMpe0guYXIoYixhLGEubGVuZ3RoKQphW2JdPWN9LAokaWo6MSwKJGltOjF9CkguY1AucHJvdG90
+eXBlPXsKajpmdW5jdGlvbihhLGIpe0gueChiKQpILmFyKGIsYSxhLmxlbmd0aCkKcmV0dXJuIGFbYl19
+fQpILmNRLnByb3RvdHlwZT17Cmo6ZnVuY3Rpb24oYSxiKXtILngoYikKSC5hcihiLGEsYS5sZW5ndGgp
+CnJldHVybiBhW2JdfX0KSC5jUi5wcm90b3R5cGU9ewpqOmZ1bmN0aW9uKGEsYil7SC54KGIpCkguYXIo
+YixhLGEubGVuZ3RoKQpyZXR1cm4gYVtiXX19CkguY1MucHJvdG90eXBlPXsKajpmdW5jdGlvbihhLGIp
+e0gueChiKQpILmFyKGIsYSxhLmxlbmd0aCkKcmV0dXJuIGFbYl19fQpILmNULnByb3RvdHlwZT17Cmo6
+ZnVuY3Rpb24oYSxiKXtILngoYikKSC5hcihiLGEsYS5sZW5ndGgpCnJldHVybiBhW2JdfX0KSC5iUy5w
+cm90b3R5cGU9ewpnbTpmdW5jdGlvbihhKXtyZXR1cm4gYS5sZW5ndGh9LApqOmZ1bmN0aW9uKGEsYil7
+SC54KGIpCkguYXIoYixhLGEubGVuZ3RoKQpyZXR1cm4gYVtiXX19CkguYVMucHJvdG90eXBlPXsKZ206
+ZnVuY3Rpb24oYSl7cmV0dXJuIGEubGVuZ3RofSwKajpmdW5jdGlvbihhLGIpe0gueChiKQpILmFyKGIs
+YSxhLmxlbmd0aCkKcmV0dXJuIGFbYl19LAokaWFTOjEsCiRpYWg6MX0KSC5jOS5wcm90b3R5cGU9e30K
+SC5jYS5wcm90b3R5cGU9e30KSC5jYi5wcm90b3R5cGU9e30KSC5jYy5wcm90b3R5cGU9e30KSC5hZi5w
+cm90b3R5cGU9ewpoOmZ1bmN0aW9uKGEpe3JldHVybiBILmRGKHYudHlwZVVuaXZlcnNlLHRoaXMsYSl9
+LApFOmZ1bmN0aW9uKGEpe3JldHVybiBILmtBKHYudHlwZVVuaXZlcnNlLHRoaXMsYSl9fQpILmVCLnBy
+b3RvdHlwZT17fQpILmRwLnByb3RvdHlwZT17Cmk6ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuYX19Ckgu
+YzEucHJvdG90eXBlPXt9CkguY2gucHJvdG90eXBlPXt9ClAuZXQucHJvdG90eXBlPXsKJDE6ZnVuY3Rp
+b24oYSl7dmFyIHQ9dGhpcy5hLHM9dC5hCnQuYT1udWxsCnMuJDAoKX0sCiRTOjExfQpQLmVzLnByb3Rv
+dHlwZT17CiQxOmZ1bmN0aW9uKGEpe3ZhciB0LHMKdGhpcy5hLmE9dS5NLmIoYSkKdD10aGlzLmIKcz10
+aGlzLmMKdC5maXJzdENoaWxkP3QucmVtb3ZlQ2hpbGQocyk6dC5hcHBlbmRDaGlsZChzKX0sCiRTOjM2
+fQpQLmV1LnByb3RvdHlwZT17CiQwOmZ1bmN0aW9uKCl7dGhpcy5hLiQwKCl9LAokQzoiJDAiLAokUjow
+LAokUzowfQpQLmV2LnByb3RvdHlwZT17CiQwOmZ1bmN0aW9uKCl7dGhpcy5hLiQwKCl9LAokQzoiJDAi
+LAokUjowLAokUzowfQpQLmRDLnByb3RvdHlwZT17CmJGOmZ1bmN0aW9uKGEsYil7aWYoc2VsZi5zZXRU
+aW1lb3V0IT1udWxsKXRoaXMuYj1zZWxmLnNldFRpbWVvdXQoSC5kTShuZXcgUC5mXyh0aGlzLGIpLDAp
+LGEpCmVsc2UgdGhyb3cgSC5hKFAuTigiYHNldFRpbWVvdXQoKWAgbm90IGZvdW5kLiIpKX0sCmM0OmZ1
+bmN0aW9uKCl7aWYoc2VsZi5zZXRUaW1lb3V0IT1udWxsKXt2YXIgdD10aGlzLmIKaWYodD09bnVsbCly
+ZXR1cm4Kc2VsZi5jbGVhclRpbWVvdXQodCkKdGhpcy5iPW51bGx9ZWxzZSB0aHJvdyBILmEoUC5OKCJD
+YW5jZWxpbmcgYSB0aW1lci4iKSl9LAokaWs2OjF9ClAuZl8ucHJvdG90eXBlPXsKJDA6ZnVuY3Rpb24o
+KXt0aGlzLmEuYj1udWxsCnRoaXMuYi4kMCgpfSwKJEM6IiQwIiwKJFI6MCwKJFM6MX0KUC5jMi5wcm90
+b3R5cGU9ewpiYTpmdW5jdGlvbihhLGIpe3ZhciB0CmlmKGE9PW51bGwpYT1uZXcgUC5iZCgpCnQ9dGhp
+cy5hCmlmKHQuYSE9PTApdGhyb3cgSC5hKFAuZDIoIkZ1dHVyZSBhbHJlYWR5IGNvbXBsZXRlZCIpKQp0
+LmJLKGEsYil9LApiOTpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5iYShhLG51bGwpfX0KUC5jMC5wcm90
+b3R5cGU9e30KUC5hWi5wcm90b3R5cGU9ewpjaTpmdW5jdGlvbihhKXtpZigodGhpcy5jJjE1KSE9PTYp
+cmV0dXJuITAKcmV0dXJuIHRoaXMuYi5iLmFLKHUuYWwuYih0aGlzLmQpLGEuYSx1LmNKLHUuSyl9LApj
+ZTpmdW5jdGlvbihhKXt2YXIgdD10aGlzLmUscz11Lnoscj11LksscT10aGlzLiR0aS5oKCIyLyIpLHA9
+dGhpcy5iLmIKaWYodS5ZLmModCkpcmV0dXJuIHEuYihwLmNvKHQsYS5hLGEuYixzLHIsdS5sKSkKZWxz
+ZSByZXR1cm4gcS5iKHAuYUsodS55LmIodCksYS5hLHMscikpfX0KUC5TLnByb3RvdHlwZT17CmJuOmZ1
+bmN0aW9uKGEsYixjKXt2YXIgdCxzLHIscT10aGlzLiR0aQpxLkUoYykuaCgiMS8oMikiKS5iKGEpCnQ9
+JC53CmlmKHQhPT1DLmQpe2MuaCgiQDwwLz4iKS5FKHEuZCkuaCgiMSgyKSIpLmIoYSkKaWYoYiE9bnVs
+bCliPVAuaXooYix0KX1zPW5ldyBQLlMoJC53LGMuaCgiUzwwPiIpKQpyPWI9PW51bGw/MTozCnRoaXMu
+YW8obmV3IFAuYVoocyxyLGEsYixxLmgoIkA8MT4iKS5FKGMpLmgoImFaPDEsMj4iKSkpCnJldHVybiBz
+fSwKYTQ6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gdGhpcy5ibihhLG51bGwsYil9LAphZDpmdW5jdGlvbihh
+KXt2YXIgdCxzLHIKdS5iZi5iKG51bGwpCnQ9dGhpcy4kdGkKcz0kLncKcj1uZXcgUC5TKHMsdCkKaWYo
+cyE9PUMuZClhPVAuaXooYSxzKQp0aGlzLmFvKG5ldyBQLmFaKHIsMixudWxsLGEsdC5oKCJAPDE+Iiku
+RSh0LmQpLmgoImFaPDEsMj4iKSkpCnJldHVybiByfSwKYW86ZnVuY3Rpb24oYSl7dmFyIHQscz10aGlz
+LHI9cy5hCmlmKHI8PTEpe2EuYT11LnguYihzLmMpCnMuYz1hfWVsc2V7aWYocj09PTIpe3Q9dS5fLmIo
+cy5jKQpyPXQuYQppZihyPDQpe3QuYW8oYSkKcmV0dXJufXMuYT1yCnMuYz10LmN9UC5idChudWxsLG51
+bGwscy5iLHUuTS5iKG5ldyBQLmVDKHMsYSkpKX19LApiMjpmdW5jdGlvbihhKXt2YXIgdCxzLHIscSxw
+LG89dGhpcyxuPXt9Cm4uYT1hCmlmKGE9PW51bGwpcmV0dXJuCnQ9by5hCmlmKHQ8PTEpe3M9dS54LmIo
+by5jKQpyPW8uYz1hCmlmKHMhPW51bGwpe2Zvcig7cT1yLmEscSE9bnVsbDtyPXEpO3IuYT1zfX1lbHNl
+e2lmKHQ9PT0yKXtwPXUuXy5iKG8uYykKdD1wLmEKaWYodDw0KXtwLmIyKGEpCnJldHVybn1vLmE9dApv
+LmM9cC5jfW4uYT1vLmFhKGEpClAuYnQobnVsbCxudWxsLG8uYix1Lk0uYihuZXcgUC5lSyhuLG8pKSl9
+fSwKYTk6ZnVuY3Rpb24oKXt2YXIgdD11LnguYih0aGlzLmMpCnRoaXMuYz1udWxsCnJldHVybiB0aGlz
+LmFhKHQpfSwKYWE6ZnVuY3Rpb24oYSl7dmFyIHQscyxyCmZvcih0PWEscz1udWxsO3QhPW51bGw7cz10
+LHQ9cil7cj10LmEKdC5hPXN9cmV0dXJuIHN9LAphVzpmdW5jdGlvbihhKXt2YXIgdCxzPXRoaXMscj1z
+LiR0aQpyLmgoIjEvIikuYihhKQppZihyLmgoImJFPDE+IikuYyhhKSlpZihyLmMoYSkpUC5lRihhLHMp
+CmVsc2UgUC5pOShhLHMpCmVsc2V7dD1zLmE5KCkKci5kLmIoYSkKcy5hPTQKcy5jPWEKUC5ibyhzLHQp
+fX0sCmFwOmZ1bmN0aW9uKGEsYil7dmFyIHQscz10aGlzCnUubC5iKGIpCnQ9cy5hOSgpCnMuYT04CnMu
+Yz1uZXcgUC5hdShhLGIpClAuYm8ocyx0KX0sCmJKOmZ1bmN0aW9uKGEpe3ZhciB0PXRoaXMscz10LiR0
+aQpzLmgoIjEvIikuYihhKQppZihzLmgoImJFPDE+IikuYyhhKSl7dC5iTChhKQpyZXR1cm59dC5hPTEK
+UC5idChudWxsLG51bGwsdC5iLHUuTS5iKG5ldyBQLmVFKHQsYSkpKX0sCmJMOmZ1bmN0aW9uKGEpe3Zh
+ciB0PXRoaXMscz10LiR0aQpzLmgoImJFPDE+IikuYihhKQppZihzLmMoYSkpe2lmKGEuZ2N6KCkpe3Qu
+YT0xClAuYnQobnVsbCxudWxsLHQuYix1Lk0uYihuZXcgUC5lSih0LGEpKSl9ZWxzZSBQLmVGKGEsdCkK
+cmV0dXJufVAuaTkoYSx0KX0sCmJLOmZ1bmN0aW9uKGEsYil7dGhpcy5hPTEKUC5idChudWxsLG51bGws
+dGhpcy5iLHUuTS5iKG5ldyBQLmVEKHRoaXMsYSxiKSkpfSwKJGliRToxfQpQLmVDLnByb3RvdHlwZT17
+CiQwOmZ1bmN0aW9uKCl7UC5ibyh0aGlzLmEsdGhpcy5iKX0sCiRTOjB9ClAuZUsucHJvdG90eXBlPXsK
+JDA6ZnVuY3Rpb24oKXtQLmJvKHRoaXMuYix0aGlzLmEuYSl9LAokUzowfQpQLmVHLnByb3RvdHlwZT17
+CiQxOmZ1bmN0aW9uKGEpe3ZhciB0PXRoaXMuYQp0LmE9MAp0LmFXKGEpfSwKJFM6MTF9ClAuZUgucHJv
+dG90eXBlPXsKJDI6ZnVuY3Rpb24oYSxiKXt1LmwuYihiKQp0aGlzLmEuYXAoYSxiKX0sCiQxOmZ1bmN0
+aW9uKGEpe3JldHVybiB0aGlzLiQyKGEsbnVsbCl9LAokQzoiJDIiLAokRDpmdW5jdGlvbigpe3JldHVy
+bltudWxsXX0sCiRTOjM3fQpQLmVJLnByb3RvdHlwZT17CiQwOmZ1bmN0aW9uKCl7dGhpcy5hLmFwKHRo
+aXMuYix0aGlzLmMpfSwKJFM6MH0KUC5lRS5wcm90b3R5cGU9ewokMDpmdW5jdGlvbigpe3ZhciB0PXRo
+aXMuYSxzPXQuJHRpLmQuYih0aGlzLmIpLHI9dC5hOSgpCnQuYT00CnQuYz1zClAuYm8odCxyKX0sCiRT
+OjB9ClAuZUoucHJvdG90eXBlPXsKJDA6ZnVuY3Rpb24oKXtQLmVGKHRoaXMuYix0aGlzLmEpfSwKJFM6
+MH0KUC5lRC5wcm90b3R5cGU9ewokMDpmdW5jdGlvbigpe3RoaXMuYS5hcCh0aGlzLmIsdGhpcy5jKX0s
+CiRTOjB9ClAuZU4ucHJvdG90eXBlPXsKJDA6ZnVuY3Rpb24oKXt2YXIgdCxzLHIscSxwLG8sbj10aGlz
+LG09bnVsbAp0cnl7cj1uLmMKbT1yLmIuYi5ibCh1LmZPLmIoci5kKSx1LnopfWNhdGNoKHEpe3Q9SC5R
+KHEpCnM9SC5jcChxKQppZihuLmQpe3I9dS5uLmIobi5hLmEuYykuYQpwPXQKcD1yPT1udWxsP3A9PW51
+bGw6cj09PXAKcj1wfWVsc2Ugcj0hMQpwPW4uYgppZihyKXAuYj11Lm4uYihuLmEuYS5jKQplbHNlIHAu
+Yj1uZXcgUC5hdSh0LHMpCnAuYT0hMApyZXR1cm59aWYodS5jLmMobSkpe2lmKG0gaW5zdGFuY2VvZiBQ
+LlMmJm0uYT49NCl7aWYobS5hPT09OCl7cj1uLmIKci5iPXUubi5iKG0uYykKci5hPSEwfXJldHVybn1v
+PW4uYS5hCnI9bi5iCnIuYj1tLmE0KG5ldyBQLmVPKG8pLHUueikKci5hPSExfX0sCiRTOjF9ClAuZU8u
+cHJvdG90eXBlPXsKJDE6ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuYX0sCiRTOjM4fQpQLmVNLnByb3Rv
+dHlwZT17CiQwOmZ1bmN0aW9uKCl7dmFyIHQscyxyLHEscCxvLG4sbT10aGlzCnRyeXtyPW0uYgpxPXIu
+JHRpCnA9cS5kCm89cC5iKG0uYykKbS5hLmI9ci5iLmIuYUsocS5oKCIyLygxKSIpLmIoci5kKSxvLHEu
+aCgiMi8iKSxwKX1jYXRjaChuKXt0PUguUShuKQpzPUguY3AobikKcj1tLmEKci5iPW5ldyBQLmF1KHQs
+cykKci5hPSEwfX0sCiRTOjF9ClAuZUwucHJvdG90eXBlPXsKJDA6ZnVuY3Rpb24oKXt2YXIgdCxzLHIs
+cSxwLG8sbixtLGw9dGhpcwp0cnl7dD11Lm4uYihsLmEuYS5jKQpxPWwuYwppZihILmRLKHEuY2kodCkp
+JiZxLmUhPW51bGwpe3A9bC5iCnAuYj1xLmNlKHQpCnAuYT0hMX19Y2F0Y2gobyl7cz1ILlEobykKcj1I
+LmNwKG8pCnE9dS5uLmIobC5hLmEuYykKcD1xLmEKbj1zCm09bC5iCmlmKHA9PW51bGw/bj09bnVsbDpw
+PT09biltLmI9cQplbHNlIG0uYj1uZXcgUC5hdShzLHIpCm0uYT0hMH19LAokUzoxfQpQLmRoLnByb3Rv
+dHlwZT17fQpQLmJZLnByb3RvdHlwZT17CmdtOmZ1bmN0aW9uKGEpe3ZhciB0LHMscj10aGlzLHE9e30s
+cD1uZXcgUC5TKCQudyx1LmZKKQpxLmE9MAp0PUgudihyKQpzPXQuaCgifigxKSIpLmIobmV3IFAuZWgo
+cSxyKSkKdS5NLmIobmV3IFAuZWkocSxwKSkKVy5hQyhyLmEsci5iLHMsITEsdC5kKQpyZXR1cm4gcH19
+ClAuZWgucHJvdG90eXBlPXsKJDE6ZnVuY3Rpb24oYSl7SC52KHRoaXMuYikuZC5iKGEpOysrdGhpcy5h
+LmF9LAokUzpmdW5jdGlvbigpe3JldHVybiBILnYodGhpcy5iKS5oKCJwKDEpIil9fQpQLmVpLnByb3Rv
+dHlwZT17CiQwOmZ1bmN0aW9uKCl7dGhpcy5iLmFXKHRoaXMuYS5hKX0sCiRTOjB9ClAuZDQucHJvdG90
+eXBlPXt9ClAuZDUucHJvdG90eXBlPXt9ClAuYXUucHJvdG90eXBlPXsKaTpmdW5jdGlvbihhKXtyZXR1
+cm4gSC5iKHRoaXMuYSl9LAokaXI6MX0KUC5kRy5wcm90b3R5cGU9eyRpaTg6MX0KUC5mZi5wcm90b3R5
+cGU9ewokMDpmdW5jdGlvbigpe3ZhciB0LHM9dGhpcy5hLHI9cy5hCnM9cj09bnVsbD9zLmE9bmV3IFAu
+YmQoKTpyCnI9dGhpcy5iCmlmKHI9PW51bGwpdGhyb3cgSC5hKHMpCnQ9SC5hKHMpCnQuc3RhY2s9ci5p
+KDApCnRocm93IHR9LAokUzowfQpQLmR4LnByb3RvdHlwZT17CmNwOmZ1bmN0aW9uKGEpe3ZhciB0LHMs
+cixxPW51bGwKdS5NLmIoYSkKdHJ5e2lmKEMuZD09PSQudyl7YS4kMCgpCnJldHVybn1QLmlBKHEscSx0
+aGlzLGEsdS5IKX1jYXRjaChyKXt0PUguUShyKQpzPUguY3AocikKUC5mZShxLHEsdGhpcyx0LHUubC5i
+KHMpKX19LApjcTpmdW5jdGlvbihhLGIsYyl7dmFyIHQscyxyLHE9bnVsbApjLmgoIn4oMCkiKS5iKGEp
+CmMuYihiKQp0cnl7aWYoQy5kPT09JC53KXthLiQxKGIpCnJldHVybn1QLmlCKHEscSx0aGlzLGEsYix1
+LkgsYyl9Y2F0Y2gocil7dD1ILlEocikKcz1ILmNwKHIpClAuZmUocSxxLHRoaXMsdCx1LmwuYihzKSl9
+fSwKYzE6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gbmV3IFAuZVIodGhpcyxiLmgoIjAoKSIpLmIoYSksYil9
+LAphejpmdW5jdGlvbihhKXtyZXR1cm4gbmV3IFAuZVEodGhpcyx1Lk0uYihhKSl9LApjMjpmdW5jdGlv
+bihhLGIpe3JldHVybiBuZXcgUC5lUyh0aGlzLGIuaCgifigwKSIpLmIoYSksYil9LApqOmZ1bmN0aW9u
+KGEsYil7cmV0dXJuIG51bGx9LApibDpmdW5jdGlvbihhLGIpe2IuaCgiMCgpIikuYihhKQppZigkLnc9
+PT1DLmQpcmV0dXJuIGEuJDAoKQpyZXR1cm4gUC5pQShudWxsLG51bGwsdGhpcyxhLGIpfSwKYUs6ZnVu
+Y3Rpb24oYSxiLGMsZCl7Yy5oKCJAPDA+IikuRShkKS5oKCIxKDIpIikuYihhKQpkLmIoYikKaWYoJC53
+PT09Qy5kKXJldHVybiBhLiQxKGIpCnJldHVybiBQLmlCKG51bGwsbnVsbCx0aGlzLGEsYixjLGQpfSwK
+Y286ZnVuY3Rpb24oYSxiLGMsZCxlLGYpe2QuaCgiQDwwPiIpLkUoZSkuRShmKS5oKCIxKDIsMykiKS5i
+KGEpCmUuYihiKQpmLmIoYykKaWYoJC53PT09Qy5kKXJldHVybiBhLiQyKGIsYykKcmV0dXJuIFAubDko
+bnVsbCxudWxsLHRoaXMsYSxiLGMsZCxlLGYpfX0KUC5lUi5wcm90b3R5cGU9ewokMDpmdW5jdGlvbigp
+e3JldHVybiB0aGlzLmEuYmwodGhpcy5iLHRoaXMuYyl9LAokUzpmdW5jdGlvbigpe3JldHVybiB0aGlz
+LmMuaCgiMCgpIil9fQpQLmVRLnByb3RvdHlwZT17CiQwOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuYS5j
+cCh0aGlzLmIpfSwKJFM6MX0KUC5lUy5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXt2YXIgdD10aGlz
+LmMKcmV0dXJuIHRoaXMuYS5jcSh0aGlzLmIsdC5iKGEpLHQpfSwKJFM6ZnVuY3Rpb24oKXtyZXR1cm4g
+dGhpcy5jLmgoIn4oMCkiKX19ClAuYzYucHJvdG90eXBlPXsKZ0Y6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhp
+cyxzPW5ldyBQLmIwKHQsdC5yLEgudih0KS5oKCJiMDwxPiIpKQpzLmM9dC5lCnJldHVybiBzfSwKZ206
+ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuYX0sCnc6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzCmlmKHR5cGVv
+ZiBiPT0ic3RyaW5nIiYmYiE9PSJfX3Byb3RvX18iKXt0PXRoaXMuYgppZih0PT1udWxsKXJldHVybiEx
+CnJldHVybiB1LkouYih0W2JdKSE9bnVsbH1lbHNle3M9dGhpcy5iTihiKQpyZXR1cm4gc319LApiTjpm
+dW5jdGlvbihhKXt2YXIgdD10aGlzLmQKaWYodD09bnVsbClyZXR1cm4hMQpyZXR1cm4gdGhpcy5hdCh0
+W3RoaXMuYXEoYSldLGEpPj0wfSwKazpmdW5jdGlvbihhLGIpe3ZhciB0LHMscj10aGlzCkgudihyKS5k
+LmIoYikKaWYodHlwZW9mIGI9PSJzdHJpbmciJiZiIT09Il9fcHJvdG9fXyIpe3Q9ci5iCnJldHVybiBy
+LmFUKHQ9PW51bGw/ci5iPVAuaDkoKTp0LGIpfWVsc2UgaWYodHlwZW9mIGI9PSJudW1iZXIiJiYoYiYx
+MDczNzQxODIzKT09PWIpe3M9ci5jCnJldHVybiByLmFUKHM9PW51bGw/ci5jPVAuaDkoKTpzLGIpfWVs
+c2UgcmV0dXJuIHIuYkgoYil9LApiSDpmdW5jdGlvbihhKXt2YXIgdCxzLHIscT10aGlzCkgudihxKS5k
+LmIoYSkKdD1xLmQKaWYodD09bnVsbCl0PXEuZD1QLmg5KCkKcz1xLmFxKGEpCnI9dFtzXQppZihyPT1u
+dWxsKXRbc109W3EuYXcoYSldCmVsc2V7aWYocS5hdChyLGEpPj0wKXJldHVybiExCnIucHVzaChxLmF3
+KGEpKX1yZXR1cm4hMH0sCk06ZnVuY3Rpb24oYSxiKXt2YXIgdAppZihiIT09Il9fcHJvdG9fXyIpcmV0
+dXJuIHRoaXMuYlUodGhpcy5iLGIpCmVsc2V7dD10aGlzLmJUKGIpCnJldHVybiB0fX0sCmJUOmZ1bmN0
+aW9uKGEpe3ZhciB0LHMscixxLHA9dGhpcyxvPXAuZAppZihvPT1udWxsKXJldHVybiExCnQ9cC5hcShh
+KQpzPW9bdF0Kcj1wLmF0KHMsYSkKaWYocjwwKXJldHVybiExCnE9cy5zcGxpY2UociwxKVswXQppZigw
+PT09cy5sZW5ndGgpZGVsZXRlIG9bdF0KcC5iNShxKQpyZXR1cm4hMH0sCmFUOmZ1bmN0aW9uKGEsYil7
+SC52KHRoaXMpLmQuYihiKQppZih1LkouYihhW2JdKSE9bnVsbClyZXR1cm4hMQphW2JdPXRoaXMuYXco
+YikKcmV0dXJuITB9LApiVTpmdW5jdGlvbihhLGIpe3ZhciB0CmlmKGE9PW51bGwpcmV0dXJuITEKdD11
+LkouYihhW2JdKQppZih0PT1udWxsKXJldHVybiExCnRoaXMuYjUodCkKZGVsZXRlIGFbYl0KcmV0dXJu
+ITB9LApiMTpmdW5jdGlvbigpe3RoaXMucj0xMDczNzQxODIzJnRoaXMucisxfSwKYXc6ZnVuY3Rpb24o
+YSl7dmFyIHQscz10aGlzLHI9bmV3IFAuZHUoSC52KHMpLmQuYihhKSkKaWYocy5lPT1udWxsKXMuZT1z
+LmY9cgplbHNle3Q9cy5mCnIuYz10CnMuZj10LmI9cn0rK3MuYQpzLmIxKCkKcmV0dXJuIHJ9LApiNTpm
+dW5jdGlvbihhKXt2YXIgdD10aGlzLHM9YS5jLHI9YS5iCmlmKHM9PW51bGwpdC5lPXIKZWxzZSBzLmI9
+cgppZihyPT1udWxsKXQuZj1zCmVsc2Ugci5jPXM7LS10LmEKdC5iMSgpfSwKYXE6ZnVuY3Rpb24oYSl7
+cmV0dXJuIEouYnYoYSkmMTA3Mzc0MTgyM30sCmF0OmZ1bmN0aW9uKGEsYil7dmFyIHQscwppZihhPT1u
+dWxsKXJldHVybi0xCnQ9YS5sZW5ndGgKZm9yKHM9MDtzPHQ7KytzKWlmKEouY3MoYVtzXS5hLGIpKXJl
+dHVybiBzCnJldHVybi0xfX0KUC5kdS5wcm90b3R5cGU9e30KUC5iMC5wcm90b3R5cGU9ewpndTpmdW5j
+dGlvbigpe3JldHVybiB0aGlzLmR9LApwOmZ1bmN0aW9uKCl7dmFyIHQ9dGhpcyxzPXQuYQppZih0LmIh
+PT1zLnIpdGhyb3cgSC5hKFAuYXYocykpCmVsc2V7cz10LmMKaWYocz09bnVsbCl7dC5zYVYobnVsbCkK
+cmV0dXJuITF9ZWxzZXt0LnNhVih0LiR0aS5kLmIocy5hKSkKdC5jPXQuYy5iCnJldHVybiEwfX19LApz
+YVY6ZnVuY3Rpb24oYSl7dGhpcy5kPXRoaXMuJHRpLmQuYihhKX0sCiRpUjoxfQpQLmJOLnByb3RvdHlw
+ZT17JGlqOjEsJGltOjF9ClAubC5wcm90b3R5cGU9ewpnRjpmdW5jdGlvbihhKXtyZXR1cm4gbmV3IEgu
+YVEoYSx0aGlzLmdtKGEpLEguYTgoYSkuaCgiYVE8bC5FPiIpKX0sCk86ZnVuY3Rpb24oYSxiKXtyZXR1
+cm4gdGhpcy5qKGEsYil9LApBOmZ1bmN0aW9uKGEsYil7dmFyIHQscwpILmE4KGEpLmgoIn4obC5FKSIp
+LmIoYikKdD10aGlzLmdtKGEpCmZvcihzPTA7czx0Oysrcyl7Yi4kMSh0aGlzLmooYSxzKSkKaWYodCE9
+PXRoaXMuZ20oYSkpdGhyb3cgSC5hKFAuYXYoYSkpfX0sCmFGOmZ1bmN0aW9uKGEsYixjKXt2YXIgdD1I
+LmE4KGEpCnJldHVybiBuZXcgSC5hNChhLHQuRShjKS5oKCIxKGwuRSkiKS5iKGIpLHQuaCgiQDxsLkU+
+IikuRShjKS5oKCJhNDwxLDI+IikpfSwKY2I6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIHQKSC5hOChhKS5o
+KCJsLkUiKS5iKGQpClAuYVYoYixjLHRoaXMuZ20oYSkpCmZvcih0PWI7dDxjOysrdCl0aGlzLmwoYSx0
+LGQpfSwKaTpmdW5jdGlvbihhKXtyZXR1cm4gUC5lNihhLCJbIiwiXSIpfX0KUC5iUC5wcm90b3R5cGU9
+e30KUC5lYS5wcm90b3R5cGU9ewokMjpmdW5jdGlvbihhLGIpe3ZhciB0LHM9dGhpcy5hCmlmKCFzLmEp
+dGhpcy5iLmErPSIsICIKcy5hPSExCnM9dGhpcy5iCnQ9cy5hKz1ILmIoYSkKcy5hPXQrIjogIgpzLmEr
+PUguYihiKX0sCiRTOjJ9ClAuQi5wcm90b3R5cGU9ewpBOmZ1bmN0aW9uKGEsYil7dmFyIHQscwpILnYo
+dGhpcykuaCgifihCLkssQi5WKSIpLmIoYikKZm9yKHQ9Si5hOSh0aGlzLmdKKCkpO3QucCgpOyl7cz10
+Lmd1KCkKYi4kMihzLHRoaXMuaigwLHMpKX19LApnbTpmdW5jdGlvbihhKXtyZXR1cm4gSi5hdCh0aGlz
+LmdKKCkpfSwKaTpmdW5jdGlvbihhKXtyZXR1cm4gUC5oMyh0aGlzKX0sCiRpeToxfQpQLmNqLnByb3Rv
+dHlwZT17Cmw6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0PUgudih0aGlzKQp0LmQuYihiKQp0LmNoWzFdLmIo
+YykKdGhyb3cgSC5hKFAuTigiQ2Fubm90IG1vZGlmeSB1bm1vZGlmaWFibGUgbWFwIikpfX0KUC5iYy5w
+cm90b3R5cGU9ewpqOmZ1bmN0aW9uKGEsYil7cmV0dXJuIHRoaXMuYS5qKDAsYil9LApsOmZ1bmN0aW9u
+KGEsYixjKXt2YXIgdD1ILnYodGhpcykKdGhpcy5hLmwoMCx0LmQuYihiKSx0LmNoWzFdLmIoYykpfSwK
+QTpmdW5jdGlvbihhLGIpe3RoaXMuYS5BKDAsSC52KHRoaXMpLmgoIn4oMSwyKSIpLmIoYikpfSwKZ206
+ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy5hCnJldHVybiB0LmdtKHQpfSwKaTpmdW5jdGlvbihhKXtyZXR1
+cm4gSi5iMih0aGlzLmEpfSwKJGl5OjF9ClAuYXoucHJvdG90eXBlPXt9ClAuYVcucHJvdG90eXBlPXsK
+aTpmdW5jdGlvbihhKXtyZXR1cm4gUC5lNih0aGlzLCJ7IiwifSIpfX0KUC5iVy5wcm90b3R5cGU9eyRp
+ajoxLCRpTToxfQpQLmNkLnByb3RvdHlwZT17Ckk6ZnVuY3Rpb24oYSxiKXt2YXIgdApmb3IodD1KLmE5
+KEgudih0aGlzKS5oKCJqPDE+IikuYihiKSk7dC5wKCk7KXRoaXMuaygwLHQuZ3UoKSl9LAppOmZ1bmN0
+aW9uKGEpe3JldHVybiBQLmU2KHRoaXMsInsiLCJ9Iil9LApUOmZ1bmN0aW9uKGEsYil7dmFyIHQscz1Q
+LmljKHRoaXMsdGhpcy5yLEgudih0aGlzKS5kKQppZighcy5wKCkpcmV0dXJuIiIKaWYoYj09PSIiKXt0
+PSIiCmRvIHQrPUguYihzLmQpCndoaWxlKHMucCgpKX1lbHNle3Q9SC5iKHMuZCkKZm9yKDtzLnAoKTsp
+dD10K2IrSC5iKHMuZCl9cmV0dXJuIHQuY2hhckNvZGVBdCgwKT09MD90OnR9LAokaWo6MSwKJGlNOjF9
+ClAuYzcucHJvdG90eXBlPXt9ClAuY2UucHJvdG90eXBlPXt9ClAuYnEucHJvdG90eXBlPXt9ClAuZHMu
+cHJvdG90eXBlPXsKajpmdW5jdGlvbihhLGIpe3ZhciB0LHM9dGhpcy5iCmlmKHM9PW51bGwpcmV0dXJu
+IHRoaXMuYy5qKDAsYikKZWxzZSBpZih0eXBlb2YgYiE9InN0cmluZyIpcmV0dXJuIG51bGwKZWxzZXt0
+PXNbYl0KcmV0dXJuIHR5cGVvZiB0PT0idW5kZWZpbmVkIj90aGlzLmJSKGIpOnR9fSwKZ206ZnVuY3Rp
+b24oYSl7cmV0dXJuIHRoaXMuYj09bnVsbD90aGlzLmMuYTp0aGlzLmExKCkubGVuZ3RofSwKZ0o6ZnVu
+Y3Rpb24oKXtpZih0aGlzLmI9PW51bGwpe3ZhciB0PXRoaXMuYwpyZXR1cm4gbmV3IEguYVAodCxILnYo
+dCkuaCgiYVA8MT4iKSl9cmV0dXJuIG5ldyBQLmR0KHRoaXMpfSwKbDpmdW5jdGlvbihhLGIsYyl7dmFy
+IHQscyxyPXRoaXMKaWYoci5iPT1udWxsKXIuYy5sKDAsYixjKQplbHNlIGlmKHIuYV8oYikpe3Q9ci5i
+CnRbYl09YwpzPXIuYQppZihzPT1udWxsP3QhPW51bGw6cyE9PXQpc1tiXT1udWxsfWVsc2Ugci5iWigp
+LmwoMCxiLGMpfSwKYV86ZnVuY3Rpb24oYSl7aWYodGhpcy5iPT1udWxsKXJldHVybiB0aGlzLmMuYV8o
+YSkKcmV0dXJuIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0aGlzLmEsYSl9LApB
+OmZ1bmN0aW9uKGEsYil7dmFyIHQscyxyLHEscD10aGlzCnUuY0EuYihiKQppZihwLmI9PW51bGwpcmV0
+dXJuIHAuYy5BKDAsYikKdD1wLmExKCkKZm9yKHM9MDtzPHQubGVuZ3RoOysrcyl7cj10W3NdCnE9cC5i
+W3JdCmlmKHR5cGVvZiBxPT0idW5kZWZpbmVkIil7cT1QLmY2KHAuYVtyXSkKcC5iW3JdPXF9Yi4kMihy
+LHEpCmlmKHQhPT1wLmMpdGhyb3cgSC5hKFAuYXYocCkpfX0sCmExOmZ1bmN0aW9uKCl7dmFyIHQ9dS5q
+LmIodGhpcy5jKQppZih0PT1udWxsKXQ9dGhpcy5jPUgubihPYmplY3Qua2V5cyh0aGlzLmEpLHUucykK
+cmV0dXJuIHR9LApiWjpmdW5jdGlvbigpe3ZhciB0LHMscixxLHAsbz10aGlzCmlmKG8uYj09bnVsbCly
+ZXR1cm4gby5jCnQ9UC5lOSh1Lk4sdS56KQpzPW8uYTEoKQpmb3Iocj0wO3E9cy5sZW5ndGgscjxxOysr
+cil7cD1zW3JdCnQubCgwLHAsby5qKDAscCkpfWlmKHE9PT0wKUMuYi5rKHMsbnVsbCkKZWxzZSBDLmIu
+c20ocywwKQpvLmE9by5iPW51bGwKcmV0dXJuIG8uYz10fSwKYlI6ZnVuY3Rpb24oYSl7dmFyIHQKaWYo
+IU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0aGlzLmEsYSkpcmV0dXJuIG51bGwK
+dD1QLmY2KHRoaXMuYVthXSkKcmV0dXJuIHRoaXMuYlthXT10fX0KUC5kdC5wcm90b3R5cGU9ewpnbTpm
+dW5jdGlvbihhKXt2YXIgdD10aGlzLmEKcmV0dXJuIHQuZ20odCl9LApPOmZ1bmN0aW9uKGEsYil7dmFy
+IHQ9dGhpcy5hCmlmKHQuYj09bnVsbCl0PXQuZ0ooKS5PKDAsYikKZWxzZXt0PXQuYTEoKQppZihiPDB8
+fGI+PXQubGVuZ3RoKXJldHVybiBILmkodCxiKQp0PXRbYl19cmV0dXJuIHR9LApnRjpmdW5jdGlvbihh
+KXt2YXIgdD10aGlzLmEKaWYodC5iPT1udWxsKXt0PXQuZ0ooKQp0PXQuZ0YodCl9ZWxzZXt0PXQuYTEo
+KQp0PW5ldyBKLmFGKHQsdC5sZW5ndGgsSC5aKHQpLmgoImFGPDE+IikpfXJldHVybiB0fX0KUC5jdy5w
+cm90b3R5cGU9ewpjazpmdW5jdGlvbihhLGEwLGExKXt2YXIgdCxzLHIscSxwLG8sbixtLGwsayxqLGks
+aCxnLGYsZSxkLGMsYj0iSW52YWxpZCBiYXNlNjQgZW5jb2RpbmcgbGVuZ3RoICIKYTE9UC5hVihhMCxh
+MSxhLmxlbmd0aCkKdD0kLmpkKCkKZm9yKHM9YTAscj1zLHE9bnVsbCxwPS0xLG89LTEsbj0wO3M8YTE7
+cz1tKXttPXMrMQpsPUMuYS50KGEscykKaWYobD09PTM3KXtrPW0rMgppZihrPD1hMSl7aj1ILmZ3KEMu
+YS50KGEsbSkpCmk9SC5mdyhDLmEudChhLG0rMSkpCmg9aioxNitpLShpJjI1NikKaWYoaD09PTM3KWg9
+LTEKbT1rfWVsc2UgaD0tMX1lbHNlIGg9bAppZigwPD1oJiZoPD0xMjcpe2lmKGg8MHx8aD49dC5sZW5n
+dGgpcmV0dXJuIEguaSh0LGgpCmc9dFtoXQppZihnPj0wKXtoPUMuYS52KCJBQkNERUZHSElKS0xNTk9Q
+UVJTVFVWV1hZWmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OSsvIixnKQppZihoPT09
+bCljb250aW51ZQpsPWh9ZWxzZXtpZihnPT09LTEpe2lmKHA8MCl7Zj1xPT1udWxsP251bGw6cS5hLmxl
+bmd0aAppZihmPT1udWxsKWY9MApwPWYrKHMtcikKbz1zfSsrbgppZihsPT09NjEpY29udGludWV9bD1o
+fWlmKGchPT0tMil7aWYocT09bnVsbClxPW5ldyBQLkgoIiIpCnEuYSs9Qy5hLm4oYSxyLHMpCnEuYSs9
+SC5kXyhsKQpyPW0KY29udGludWV9fXRocm93IEguYShQLkEoIkludmFsaWQgYmFzZTY0IGRhdGEiLGEs
+cykpfWlmKHEhPW51bGwpe2Y9cS5hKz1DLmEubihhLHIsYTEpCmU9Zi5sZW5ndGgKaWYocD49MClQLmhJ
+KGEsbyxhMSxwLG4sZSkKZWxzZXtkPUMuYy5hayhlLTEsNCkrMQppZihkPT09MSl0aHJvdyBILmEoUC5B
+KGIsYSxhMSkpCmZvcig7ZDw0Oyl7Zis9Ij0iCnEuYT1mOysrZH19Zj1xLmEKcmV0dXJuIEMuYS5hMChh
+LGEwLGExLGYuY2hhckNvZGVBdCgwKT09MD9mOmYpfWM9YTEtYTAKaWYocD49MClQLmhJKGEsbyxhMSxw
+LG4sYykKZWxzZXtkPUMuYy5hayhjLDQpCmlmKGQ9PT0xKXRocm93IEguYShQLkEoYixhLGExKSkKaWYo
+ZD4xKWE9Qy5hLmEwKGEsYTEsYTEsZD09PTI/Ij09IjoiPSIpfXJldHVybiBhfX0KUC5jeC5wcm90b3R5
+cGU9e30KUC5hMi5wcm90b3R5cGU9e30KUC5hSy5wcm90b3R5cGU9e30KUC5jRS5wcm90b3R5cGU9e30K
+UC5jTS5wcm90b3R5cGU9ewphQjpmdW5jdGlvbihhLGIsYyl7dmFyIHQKdS5lcC5iKGMpCnQ9UC5sOChi
+LHRoaXMuZ2M5KCkuYSkKcmV0dXJuIHR9LApnYzk6ZnVuY3Rpb24oKXtyZXR1cm4gQy5TfX0KUC5jTi5w
+cm90b3R5cGU9e30KUC5kZC5wcm90b3R5cGU9ewpnY2E6ZnVuY3Rpb24oKXtyZXR1cm4gQy5MfX0KUC5k
+Zi5wcm90b3R5cGU9ewphQTpmdW5jdGlvbihhKXt2YXIgdCxzLHI9UC5hVigwLG51bGwsYS5nbShhKSks
+cT1yLTAKaWYocT09PTApcmV0dXJuIG5ldyBVaW50OEFycmF5KDApCnQ9bmV3IFVpbnQ4QXJyYXkocSoz
+KQpzPW5ldyBQLmY0KHQpCmlmKHMuYlEoYSwwLHIpIT09cilzLmI2KGEudigwLHItMSksMCkKcmV0dXJu
+IG5ldyBVaW50OEFycmF5KHQuc3ViYXJyYXkoMCxILmtVKDAscy5iLHQubGVuZ3RoKSkpfX0KUC5mNC5w
+cm90b3R5cGU9ewpiNjpmdW5jdGlvbihhLGIpe3ZhciB0LHMscixxLHA9dGhpcwppZigoYiY2NDUxMik9
+PT01NjMyMClQLmtWKGEsYikKZWxzZXt0PXAuYwpzPXAuYisrCnI9Qy5jLlIoMjI0LGEuYTcoMCwxMikp
+CnE9dC5sZW5ndGgKaWYocz49cSlyZXR1cm4gSC5pKHQscykKdFtzXT1yCnI9cC5iKysKcz1DLmMuUigx
+MjgsYS5hNygwLDYpLlAoMCw2MykpCmlmKHI+PXEpcmV0dXJuIEguaSh0LHIpCnRbcl09cwpzPXAuYisr
+CnI9Qy5jLlIoMTI4LGEuUCgwLDYzKSkKaWYocz49cSlyZXR1cm4gSC5pKHQscykKdFtzXT1yCnJldHVy
+biExfX0sCmJROmZ1bmN0aW9uKGEsYixjKXt2YXIgdCxzLHIscSxwLG8sbixtPXRoaXMKaWYoYiE9PWMm
+JlAuaXgoYS52KDAsYy0xKSkpLS1jCmZvcih0PW0uYyxzPXQubGVuZ3RoLHI9YjtyPGM7KytyKXtxPWEu
+digwLHIpCmlmKHEuYnMoMCwxMjcpKXtwPW0uYgppZihwPj1zKWJyZWFrCm0uYj1wKzEKQy5hXy5sKHQs
+cCxxKX1lbHNlIGlmKFAuaXgocSkpe2lmKG0uYiszPj1zKWJyZWFrCm89cisxCmlmKG0uYjYocSxhLnYo
+MCxvKSkpcj1vfWVsc2UgaWYocS5icygwLDIwNDcpKXtwPW0uYgpuPXArMQppZihuPj1zKWJyZWFrCm0u
+Yj1uCm49Qy5jLlIoMTkyLHEuYTcoMCw2KSkKaWYocD49cylyZXR1cm4gSC5pKHQscCkKdFtwXT1uCm49
+bS5iKysKcD1DLmMuUigxMjgscS5QKDAsNjMpKQppZihuPj1zKXJldHVybiBILmkodCxuKQp0W25dPXB9
+ZWxzZXtwPW0uYgppZihwKzI+PXMpYnJlYWsKbS5iPXArMQpuPUMuYy5SKDIyNCxxLmE3KDAsMTIpKQpp
+ZihwPj1zKXJldHVybiBILmkodCxwKQp0W3BdPW4Kbj1tLmIrKwpwPUMuYy5SKDEyOCxxLmE3KDAsNiku
+UCgwLDYzKSkKaWYobj49cylyZXR1cm4gSC5pKHQsbikKdFtuXT1wCnA9bS5iKysKbj1DLmMuUigxMjgs
+cS5QKDAsNjMpKQppZihwPj1zKXJldHVybiBILmkodCxwKQp0W3BdPW59fXJldHVybiByfX0KUC5kZS5w
+cm90b3R5cGU9ewphQTpmdW5jdGlvbihhKXt2YXIgdCxzLHIscSxwLG8sbixtLGwKdS5MLmIoYSkKdD1Q
+LmthKCExLGEsMCxudWxsKQppZih0IT1udWxsKXJldHVybiB0CnM9UC5hVigwLG51bGwsSi5hdChhKSkK
+cj1QLmlEKGEsMCxzKQppZihyPjApe3E9UC5oNihhLDAscikKaWYocj09PXMpcmV0dXJuIHEKcD1uZXcg
+UC5IKHEpCm89cgpuPSExfWVsc2V7bz0wCnA9bnVsbApuPSEwfWlmKHA9PW51bGwpcD1uZXcgUC5IKCIi
+KQptPW5ldyBQLmYzKCExLHApCm0uYz1uCm0uYzYoYSxvLHMpCmlmKG0uZT4wKXtILmFrKFAuQSgiVW5m
+aW5pc2hlZCBVVEYtOCBvY3RldCBzZXF1ZW5jZSIsYSxzKSkKcC5hKz1ILmRfKDY1NTMzKQptLmY9bS5l
+PW0uZD0wfWw9cC5hCnJldHVybiBsLmNoYXJDb2RlQXQoMCk9PTA/bDpsfX0KUC5mMy5wcm90b3R5cGU9
+ewpjNjpmdW5jdGlvbihhLGIsYyl7dmFyIHQscyxyLHEscCxvLG4sbSxsLGssaixpLGg9dGhpcyxnPSJC
+YWQgVVRGLTggZW5jb2RpbmcgMHgiCnUuTC5iKGEpCnQ9aC5kCnM9aC5lCnI9aC5mCmguZj1oLmU9aC5k
+PTAKJGxhYmVsMCQwOmZvcihxPUouYV8oYSkscD1oLmIsbz1iOyEwO289ail7JGxhYmVsMSQxOmlmKHM+
+MCl7ZG97aWYobz09PWMpYnJlYWsgJGxhYmVsMCQwCm49cS5qKGEsbykKaWYodHlwZW9mIG4hPT0ibnVt
+YmVyIilyZXR1cm4gbi5QKCkKaWYoKG4mMTkyKSE9PTEyOCl7bT1QLkEoZytDLmMuYTUobiwxNiksYSxv
+KQp0aHJvdyBILmEobSl9ZWxzZXt0PSh0PDw2fG4mNjMpPj4+MDstLXM7KytvfX13aGlsZShzPjApCm09
+ci0xCmlmKG08MHx8bT49NClyZXR1cm4gSC5pKEMudSxtKQppZih0PD1DLnVbbV0pe209UC5BKCJPdmVy
+bG9uZyBlbmNvZGluZyBvZiAweCIrQy5jLmE1KHQsMTYpLGEsby1yLTEpCnRocm93IEguYShtKX1pZih0
+PjExMTQxMTEpe209UC5BKCJDaGFyYWN0ZXIgb3V0c2lkZSB2YWxpZCBVbmljb2RlIHJhbmdlOiAweCIr
+Qy5jLmE1KHQsMTYpLGEsby1yLTEpCnRocm93IEguYShtKX1pZighaC5jfHx0IT09NjUyNzkpcC5hKz1I
+LmRfKHQpCmguYz0hMX1mb3IobT1vPGM7bTspe2w9UC5pRChhLG8sYykKaWYobD4wKXtoLmM9ITEKaz1v
+K2wKcC5hKz1QLmg2KGEsbyxrKQppZihrPT09YylicmVha31lbHNlIGs9bwpqPWsrMQpuPXEuaihhLGsp
+CmlmKHR5cGVvZiBuIT09Im51bWJlciIpcmV0dXJuIG4uRCgpCmlmKG48MCl7aT1QLkEoIk5lZ2F0aXZl
+IFVURi04IGNvZGUgdW5pdDogLTB4IitDLmMuYTUoLW4sMTYpLGEsai0xKQp0aHJvdyBILmEoaSl9ZWxz
+ZXtpZigobiYyMjQpPT09MTkyKXt0PW4mMzEKcz0xCnI9MQpjb250aW51ZSAkbGFiZWwwJDB9aWYoKG4m
+MjQwKT09PTIyNCl7dD1uJjE1CnM9MgpyPTIKY29udGludWUgJGxhYmVsMCQwfWlmKChuJjI0OCk9PT0y
+NDAmJm48MjQ1KXt0PW4mNwpzPTMKcj0zCmNvbnRpbnVlICRsYWJlbDAkMH1pPVAuQShnK0MuYy5hNShu
+LDE2KSxhLGotMSkKdGhyb3cgSC5hKGkpfX1icmVhayAkbGFiZWwwJDB9aWYocz4wKXtoLmQ9dApoLmU9
+cwpoLmY9cn19fQpQLmViLnByb3RvdHlwZT17CiQyOmZ1bmN0aW9uKGEsYil7dmFyIHQscyxyCnUuZm8u
+YihhKQp0PXRoaXMuYgpzPXRoaXMuYQp0LmErPXMuYQpyPXQuYSs9SC5iKGEuYSkKdC5hPXIrIjogIgp0
+LmErPVAuYU0oYikKcy5hPSIsICJ9LAokUzoxN30KUC56LnByb3RvdHlwZT17fQpQLmI3LnByb3RvdHlw
+ZT17Ckc6ZnVuY3Rpb24oYSxiKXtpZihiPT1udWxsKXJldHVybiExCnJldHVybiBiIGluc3RhbmNlb2Yg
+UC5iNyYmdGhpcy5hPT09Yi5hJiYhMH0sCmdxOmZ1bmN0aW9uKGEpe3ZhciB0PXRoaXMuYQpyZXR1cm4o
+dF5DLmMuWih0LDMwKSkmMTA3Mzc0MTgyM30sCmk6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcyxzPVAuakQo
+SC5qWih0KSkscj1QLmNDKEgualgodCkpLHE9UC5jQyhILmpUKHQpKSxwPVAuY0MoSC5qVSh0KSksbz1Q
+LmNDKEgualcodCkpLG49UC5jQyhILmpZKHQpKSxtPVAuakUoSC5qVih0KSksbD1zKyItIityKyItIitx
+KyIgIitwKyI6IitvKyI6IituKyIuIittCnJldHVybiBsfX0KUC5ULnByb3RvdHlwZT17fQpQLmI4LnBy
+b3RvdHlwZT17Ckc6ZnVuY3Rpb24oYSxiKXtpZihiPT1udWxsKXJldHVybiExCnJldHVybiBiIGluc3Rh
+bmNlb2YgUC5iOCYmdGhpcy5hPT09Yi5hfSwKZ3E6ZnVuY3Rpb24oYSl7cmV0dXJuIEMuYy5ncSh0aGlz
+LmEpfSwKaTpmdW5jdGlvbihhKXt2YXIgdCxzLHIscT1uZXcgUC5kWSgpLHA9dGhpcy5hCmlmKHA8MCly
+ZXR1cm4iLSIrbmV3IFAuYjgoMC1wKS5pKDApCnQ9cS4kMShDLmMuYWIocCw2ZTcpJTYwKQpzPXEuJDEo
+Qy5jLmFiKHAsMWU2KSU2MCkKcj1uZXcgUC5kWCgpLiQxKHAlMWU2KQpyZXR1cm4iIitDLmMuYWIocCwz
+NmU4KSsiOiIrSC5iKHQpKyI6IitILmIocykrIi4iK0guYihyKX19ClAuZFgucHJvdG90eXBlPXsKJDE6
+ZnVuY3Rpb24oYSl7aWYoYT49MWU1KXJldHVybiIiK2EKaWYoYT49MWU0KXJldHVybiIwIithCmlmKGE+
+PTEwMDApcmV0dXJuIjAwIithCmlmKGE+PTEwMClyZXR1cm4iMDAwIithCmlmKGE+PTEwKXJldHVybiIw
+MDAwIithCnJldHVybiIwMDAwMCIrYX0sCiRTOjEyfQpQLmRZLnByb3RvdHlwZT17CiQxOmZ1bmN0aW9u
+KGEpe2lmKGE+PTEwKXJldHVybiIiK2EKcmV0dXJuIjAiK2F9LAokUzoxMn0KUC5yLnByb3RvdHlwZT17
+fQpQLmJ3LnByb3RvdHlwZT17Cmk6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy5hCmlmKHQhPW51bGwpcmV0
+dXJuIkFzc2VydGlvbiBmYWlsZWQ6ICIrUC5hTSh0KQpyZXR1cm4iQXNzZXJ0aW9uIGZhaWxlZCJ9fQpQ
+LmJkLnByb3RvdHlwZT17Cmk6ZnVuY3Rpb24oYSl7cmV0dXJuIlRocm93IG9mIG51bGwuIn19ClAuYTEu
+cHJvdG90eXBlPXsKZ2FzOmZ1bmN0aW9uKCl7cmV0dXJuIkludmFsaWQgYXJndW1lbnQiKyghdGhpcy5h
+PyIocykiOiIiKX0sCmdhcjpmdW5jdGlvbigpe3JldHVybiIifSwKaTpmdW5jdGlvbihhKXt2YXIgdCxz
+LHIscSxwPXRoaXMsbz1wLmMsbj1vIT1udWxsPyIgKCIrbysiKSI6IiIKbz1wLmQKdD1vPT1udWxsPyIi
+OiI6ICIrSC5iKG8pCnM9cC5nYXMoKStuK3QKaWYoIXAuYSlyZXR1cm4gcwpyPXAuZ2FyKCkKcT1QLmFN
+KHAuYikKcmV0dXJuIHMrcisiOiAiK3F9fQpQLmFVLnByb3RvdHlwZT17CmdhczpmdW5jdGlvbigpe3Jl
+dHVybiJSYW5nZUVycm9yIn0sCmdhcjpmdW5jdGlvbigpe3ZhciB0LHMscj10aGlzLmUKaWYocj09bnVs
+bCl7cj10aGlzLmYKdD1yIT1udWxsPyI6IE5vdCBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gIitILmIocik6
+IiJ9ZWxzZXtzPXRoaXMuZgppZihzPT1udWxsKXQ9IjogTm90IGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0
+byAiK0guYihyKQplbHNlIGlmKHM+cil0PSI6IE5vdCBpbiByYW5nZSAiK0guYihyKSsiLi4iK0guYihz
+KSsiLCBpbmNsdXNpdmUiCmVsc2UgdD1zPHI/IjogVmFsaWQgdmFsdWUgcmFuZ2UgaXMgZW1wdHkiOiI6
+IE9ubHkgdmFsaWQgdmFsdWUgaXMgIitILmIocil9cmV0dXJuIHR9fQpQLmNHLnByb3RvdHlwZT17Cmdh
+czpmdW5jdGlvbigpe3JldHVybiJSYW5nZUVycm9yIn0sCmdhcjpmdW5jdGlvbigpe3ZhciB0LHM9SC54
+KHRoaXMuYikKaWYodHlwZW9mIHMhPT0ibnVtYmVyIilyZXR1cm4gcy5EKCkKaWYoczwwKXJldHVybiI6
+IGluZGV4IG11c3Qgbm90IGJlIG5lZ2F0aXZlIgp0PXRoaXMuZgppZih0PT09MClyZXR1cm4iOiBubyBp
+bmRpY2VzIGFyZSB2YWxpZCIKcmV0dXJuIjogaW5kZXggc2hvdWxkIGJlIGxlc3MgdGhhbiAiK0guYih0
+KX0sCmdtOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLmZ9fQpQLmNVLnByb3RvdHlwZT17Cmk6ZnVuY3Rp
+b24oYSl7dmFyIHQscyxyLHEscCxvLG4sbSxsPXRoaXMsaz17fSxqPW5ldyBQLkgoIiIpCmsuYT0iIgpm
+b3IodD1sLmMscz10Lmxlbmd0aCxyPTAscT0iIixwPSIiO3I8czsrK3IscD0iLCAiKXtvPXRbcl0Kai5h
+PXErcApxPWouYSs9UC5hTShvKQprLmE9IiwgIn1sLmQuQSgwLG5ldyBQLmViKGssaikpCm49UC5hTShs
+LmEpCm09ai5pKDApCnQ9Ik5vU3VjaE1ldGhvZEVycm9yOiBtZXRob2Qgbm90IGZvdW5kOiAnIitILmIo
+bC5iLmEpKyInXG5SZWNlaXZlcjogIituKyJcbkFyZ3VtZW50czogWyIrbSsiXSIKcmV0dXJuIHR9fQpQ
+LmRiLnByb3RvdHlwZT17Cmk6ZnVuY3Rpb24oYSl7cmV0dXJuIlVuc3VwcG9ydGVkIG9wZXJhdGlvbjog
+Iit0aGlzLmF9fQpQLmQ5LnByb3RvdHlwZT17Cmk6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy5hCnJldHVy
+biB0IT1udWxsPyJVbmltcGxlbWVudGVkRXJyb3I6ICIrdDoiVW5pbXBsZW1lbnRlZEVycm9yIn19ClAu
+YmgucHJvdG90eXBlPXsKaTpmdW5jdGlvbihhKXtyZXR1cm4iQmFkIHN0YXRlOiAiK3RoaXMuYX19ClAu
+Y3oucHJvdG90eXBlPXsKaTpmdW5jdGlvbihhKXt2YXIgdD10aGlzLmEKaWYodD09bnVsbClyZXR1cm4i
+Q29uY3VycmVudCBtb2RpZmljYXRpb24gZHVyaW5nIGl0ZXJhdGlvbi4iCnJldHVybiJDb25jdXJyZW50
+IG1vZGlmaWNhdGlvbiBkdXJpbmcgaXRlcmF0aW9uOiAiK1AuYU0odCkrIi4ifX0KUC5jVy5wcm90b3R5
+cGU9ewppOmZ1bmN0aW9uKGEpe3JldHVybiJPdXQgb2YgTWVtb3J5In0sCiRpcjoxfQpQLmJYLnByb3Rv
+dHlwZT17Cmk6ZnVuY3Rpb24oYSl7cmV0dXJuIlN0YWNrIE92ZXJmbG93In0sCiRpcjoxfQpQLmNCLnBy
+b3RvdHlwZT17Cmk6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy5hCnJldHVybiB0PT1udWxsPyJSZWFkaW5n
+IHN0YXRpYyB2YXJpYWJsZSBkdXJpbmcgaXRzIGluaXRpYWxpemF0aW9uIjoiUmVhZGluZyBzdGF0aWMg
+dmFyaWFibGUgJyIrdCsiJyBkdXJpbmcgaXRzIGluaXRpYWxpemF0aW9uIn19ClAuZUEucHJvdG90eXBl
+PXsKaTpmdW5jdGlvbihhKXtyZXR1cm4iRXhjZXB0aW9uOiAiK3RoaXMuYX19ClAuZV8ucHJvdG90eXBl
+PXsKaTpmdW5jdGlvbihhKXt2YXIgdCxzLHIscSxwLG8sbixtLGwsayxqLGksaD10aGlzLmEsZz0iIiE9
+PWg/IkZvcm1hdEV4Y2VwdGlvbjogIitoOiJGb3JtYXRFeGNlcHRpb24iLGY9dGhpcy5jLGU9dGhpcy5i
+CmlmKHR5cGVvZiBlPT0ic3RyaW5nIil7aWYoZiE9bnVsbCloPWY8MHx8Zj5lLmxlbmd0aAplbHNlIGg9
+ITEKaWYoaClmPW51bGwKaWYoZj09bnVsbCl7dD1lLmxlbmd0aD43OD9DLmEubihlLDAsNzUpKyIuLi4i
+OmUKcmV0dXJuIGcrIlxuIit0fWZvcihzPTEscj0wLHE9ITEscD0wO3A8ZjsrK3Ape289Qy5hLnQoZSxw
+KQppZihvPT09MTApe2lmKHIhPT1wfHwhcSkrK3MKcj1wKzEKcT0hMX1lbHNlIGlmKG89PT0xMyl7Kytz
+CnI9cCsxCnE9ITB9fWc9cz4xP2crKCIgKGF0IGxpbmUgIitzKyIsIGNoYXJhY3RlciAiKyhmLXIrMSkr
+IilcbiIpOmcrKCIgKGF0IGNoYXJhY3RlciAiKyhmKzEpKyIpXG4iKQpuPWUubGVuZ3RoCmZvcihwPWY7
+cDxuOysrcCl7bz1DLmEudihlLHApCmlmKG89PT0xMHx8bz09PTEzKXtuPXAKYnJlYWt9fWlmKG4tcj43
+OClpZihmLXI8NzUpe209cis3NQpsPXIKaz0iIgpqPSIuLi4ifWVsc2V7aWYobi1mPDc1KXtsPW4tNzUK
+bT1uCmo9IiJ9ZWxzZXtsPWYtMzYKbT1mKzM2Cmo9Ii4uLiJ9az0iLi4uIn1lbHNle209bgpsPXIKaz0i
+IgpqPSIifWk9Qy5hLm4oZSxsLG0pCnJldHVybiBnK2sraStqKyJcbiIrQy5hLmFOKCIgIixmLWwray5s
+ZW5ndGgpKyJeXG4ifWVsc2UgcmV0dXJuIGYhPW51bGw/ZysoIiAoYXQgb2Zmc2V0ICIrSC5iKGYpKyIp
+Iik6Z319ClAuYWIucHJvdG90eXBlPXt9ClAuZi5wcm90b3R5cGU9e30KUC5qLnByb3RvdHlwZT17CmFq
+OmZ1bmN0aW9uKGEsYil7dmFyIHQ9SC52KHRoaXMpCnJldHVybiBuZXcgSC5hWSh0aGlzLHQuaCgieihq
+LkUpIikuYihiKSx0LmgoImFZPGouRT4iKSl9LApnbTpmdW5jdGlvbihhKXt2YXIgdCxzPXRoaXMuZ0Yo
+dGhpcykKZm9yKHQ9MDtzLnAoKTspKyt0CnJldHVybiB0fSwKZ1k6ZnVuY3Rpb24oYSl7dmFyIHQscz10
+aGlzLmdGKHRoaXMpCmlmKCFzLnAoKSl0aHJvdyBILmEoSC5oUCgpKQp0PXMuZ3UoKQppZihzLnAoKSl0
+aHJvdyBILmEoSC5qSSgpKQpyZXR1cm4gdH0sCk86ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIKUC5rMShi
+LCJpbmRleCIpCmZvcih0PXRoaXMuZ0YodGhpcykscz0wO3QucCgpOyl7cj10Lmd1KCkKaWYoYj09PXMp
+cmV0dXJuIHI7KytzfXRocm93IEguYShQLmU1KGIsdGhpcywiaW5kZXgiLG51bGwscykpfSwKaTpmdW5j
+dGlvbihhKXtyZXR1cm4gUC5qSCh0aGlzLCIoIiwiKSIpfX0KUC5SLnByb3RvdHlwZT17fQpQLm0ucHJv
+dG90eXBlPXskaWo6MX0KUC55LnByb3RvdHlwZT17fQpQLnAucHJvdG90eXBlPXsKZ3E6ZnVuY3Rpb24o
+YSl7cmV0dXJuIFAudC5wcm90b3R5cGUuZ3EuY2FsbCh0aGlzLHRoaXMpfSwKaTpmdW5jdGlvbihhKXty
+ZXR1cm4ibnVsbCJ9fQpQLlUucHJvdG90eXBlPXt9ClAudC5wcm90b3R5cGU9e2NvbnN0cnVjdG9yOlAu
+dCwkaXQ6MSwKRzpmdW5jdGlvbihhLGIpe3JldHVybiB0aGlzPT09Yn0sCmdxOmZ1bmN0aW9uKGEpe3Jl
+dHVybiBILmJWKHRoaXMpfSwKaTpmdW5jdGlvbihhKXtyZXR1cm4iSW5zdGFuY2Ugb2YgJyIrSC5iKEgu
+ZWYodGhpcykpKyInIn0sCmFoOmZ1bmN0aW9uKGEsYil7dS5vLmIoYikKdGhyb3cgSC5hKFAuaFUodGhp
+cyxiLmdiZygpLGIuZ2JqKCksYi5nYmgoKSkpfSwKdG9TdHJpbmc6ZnVuY3Rpb24oKXtyZXR1cm4gdGhp
+cy5pKHRoaXMpfX0KUC5NLnByb3RvdHlwZT17fQpQLmFnLnByb3RvdHlwZT17fQpQLmMucHJvdG90eXBl
+PXskaWNYOjF9ClAuSC5wcm90b3R5cGU9ewpnbTpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5hLmxlbmd0
+aH0sCmk6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy5hCnJldHVybiB0LmNoYXJDb2RlQXQoMCk9PTA/dDp0
+fSwKJGlrNDoxfQpQLmE2LnByb3RvdHlwZT17fQpQLmVxLnByb3RvdHlwZT17CiQyOmZ1bmN0aW9uKGEs
+Yil7dmFyIHQscyxyLHEKdS5mLmIoYSkKSC5vKGIpCnQ9Si5hMChiKS5iZihiLCI9IikKaWYodD09PS0x
+KXtpZihiIT09IiIpYS5sKDAsUC5oZihiLDAsYi5sZW5ndGgsdGhpcy5hLCEwKSwiIil9ZWxzZSBpZih0
+IT09MCl7cz1DLmEubihiLDAsdCkKcj1DLmEuVShiLHQrMSkKcT10aGlzLmEKYS5sKDAsUC5oZihzLDAs
+cy5sZW5ndGgscSwhMCksUC5oZihyLDAsci5sZW5ndGgscSwhMCkpfXJldHVybiBhfSwKJFM6MzV9ClAu
+ZW4ucHJvdG90eXBlPXsKJDI6ZnVuY3Rpb24oYSxiKXt0aHJvdyBILmEoUC5BKCJJbGxlZ2FsIElQdjQg
+YWRkcmVzcywgIithLHRoaXMuYSxiKSl9LAokUzoxOX0KUC5lby5wcm90b3R5cGU9ewokMjpmdW5jdGlv
+bihhLGIpe3Rocm93IEguYShQLkEoIklsbGVnYWwgSVB2NiBhZGRyZXNzLCAiK2EsdGhpcy5hLGIpKX0s
+CiQxOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLiQyKGEsbnVsbCl9LAokUzoyMH0KUC5lcC5wcm90b3R5
+cGU9ewokMjpmdW5jdGlvbihhLGIpe3ZhciB0CmlmKGItYT40KXRoaXMuYS4kMigiYW4gSVB2NiBwYXJ0
+IGNhbiBvbmx5IGNvbnRhaW4gYSBtYXhpbXVtIG9mIDQgaGV4IGRpZ2l0cyIsYSkKdD1QLmRPKEMuYS5u
+KHRoaXMuYixhLGIpLG51bGwsMTYpCmlmKHR5cGVvZiB0IT09Im51bWJlciIpcmV0dXJuIHQuRCgpCmlm
+KHQ8MHx8dD42NTUzNSl0aGlzLmEuJDIoImVhY2ggcGFydCBtdXN0IGJlIGluIHRoZSByYW5nZSBvZiBg
+MHgwLi4weEZGRkZgIixhKQpyZXR1cm4gdH0sCiRTOjI0fQpQLmNrLnByb3RvdHlwZT17CmdicTpmdW5j
+dGlvbigpe3JldHVybiB0aGlzLmJ9LApnYUQ6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy5jCmlmKHQ9PW51
+bGwpcmV0dXJuIiIKaWYoQy5hLkgodCwiWyIpKXJldHVybiBDLmEubih0LDEsdC5sZW5ndGgtMSkKcmV0
+dXJuIHR9LApnYUg6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy5kCmlmKHQ9PW51bGwpcmV0dXJuIFAuaWso
+dGhpcy5hKQpyZXR1cm4gdH0sCmdhSTpmdW5jdGlvbigpe3ZhciB0PXRoaXMuZgpyZXR1cm4gdD09bnVs
+bD8iIjp0fSwKZ2JiOmZ1bmN0aW9uKCl7dmFyIHQ9dGhpcy5yCnJldHVybiB0PT1udWxsPyIiOnR9LApn
+YUo6ZnVuY3Rpb24oKXt2YXIgdCxzPXRoaXMKaWYocy5RPT1udWxsKXt0PXMuZgpzLnNiUyhuZXcgUC5h
+eihQLmk3KHQ9PW51bGw/IiI6dCksdS5XKSl9cmV0dXJuIHMuUX0sCmdiYzpmdW5jdGlvbigpe3JldHVy
+biB0aGlzLmMhPW51bGx9LApnYmU6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5mIT1udWxsfSwKZ2JkOmZ1
+bmN0aW9uKCl7cmV0dXJuIHRoaXMuciE9bnVsbH0sCmk6ZnVuY3Rpb24oYSl7dmFyIHQscyxyLHE9dGhp
+cyxwPXEueQppZihwPT1udWxsKXtwPXEuYQp0PXAubGVuZ3RoIT09MD9wKyI6IjoiIgpzPXEuYwpyPXM9
+PW51bGwKaWYoIXJ8fHA9PT0iZmlsZSIpe3A9dCsiLy8iCnQ9cS5iCmlmKHQubGVuZ3RoIT09MClwPXAr
+dCsiQCIKaWYoIXIpcCs9cwp0PXEuZAppZih0IT1udWxsKXA9cCsiOiIrSC5iKHQpfWVsc2UgcD10CnAr
+PXEuZQp0PXEuZgppZih0IT1udWxsKXA9cCsiPyIrdAp0PXEucgppZih0IT1udWxsKXA9cCsiIyIrdApw
+PXEueT1wLmNoYXJDb2RlQXQoMCk9PTA/cDpwfXJldHVybiBwfSwKRzpmdW5jdGlvbihhLGIpe3ZhciB0
+LHMscj10aGlzCmlmKGI9PW51bGwpcmV0dXJuITEKaWYocj09PWIpcmV0dXJuITAKaWYodS5rLmMoYikp
+aWYoci5hPT09Yi5nYVAoKSlpZihyLmMhPW51bGw9PT1iLmdiYygpKWlmKHIuYj09Yi5nYnEoKSlpZihy
+LmdhRChyKT09Yi5nYUQoYikpaWYoci5nYUgocik9PWIuZ2FIKGIpKWlmKHIuZT09PWIuZ2JpKGIpKXt0
+PXIuZgpzPXQ9PW51bGwKaWYoIXM9PT1iLmdiZSgpKXtpZihzKXQ9IiIKaWYodD09PWIuZ2FJKCkpe3Q9
+ci5yCnM9dD09bnVsbAppZighcz09PWIuZ2JkKCkpe2lmKHMpdD0iIgp0PXQ9PT1iLmdiYigpfWVsc2Ug
+dD0hMX1lbHNlIHQ9ITF9ZWxzZSB0PSExfWVsc2UgdD0hMQplbHNlIHQ9ITEKZWxzZSB0PSExCmVsc2Ug
+dD0hMQplbHNlIHQ9ITEKZWxzZSB0PSExCmVsc2UgdD0hMQpyZXR1cm4gdH0sCmdxOmZ1bmN0aW9uKGEp
+e3ZhciB0PXRoaXMuegpyZXR1cm4gdD09bnVsbD90aGlzLno9Qy5hLmdxKHRoaXMuaSgwKSk6dH0sCnNi
+UzpmdW5jdGlvbihhKXt0aGlzLlE9dS5mLmIoYSl9LAokaWRjOjEsCmdhUDpmdW5jdGlvbigpe3JldHVy
+biB0aGlzLmF9LApnYmk6ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuZX19ClAuZjEucHJvdG90eXBlPXsK
+JDE6ZnVuY3Rpb24oYSl7dGhyb3cgSC5hKFAuQSgiSW52YWxpZCBwb3J0Iix0aGlzLmEsdGhpcy5iKzEp
+KX0sCiRTOjIyfQpQLmYyLnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3JldHVybiBQLmtSKEMuWCxh
+LEMuZiwhMSl9LAokUzoxM30KUC5lbS5wcm90b3R5cGU9ewpnYnA6ZnVuY3Rpb24oKXt2YXIgdCxzLHIs
+cSxwPXRoaXMsbz1udWxsLG49cC5jCmlmKG4hPW51bGwpcmV0dXJuIG4Kbj1wLmIKaWYoMD49bi5sZW5n
+dGgpcmV0dXJuIEguaShuLDApCnQ9cC5hCm49blswXSsxCnM9Qy5hLmFlKHQsIj8iLG4pCnI9dC5sZW5n
+dGgKaWYocz49MCl7cT1QLmNsKHQscysxLHIsQy5pLCExKQpyPXN9ZWxzZSBxPW8KcmV0dXJuIHAuYz1u
+ZXcgUC5kbSgiZGF0YSIsbyxvLG8sUC5jbCh0LG4scixDLnksITEpLHEsbyl9LAppOmZ1bmN0aW9uKGEp
+e3ZhciB0LHM9dGhpcy5iCmlmKDA+PXMubGVuZ3RoKXJldHVybiBILmkocywwKQp0PXRoaXMuYQpyZXR1
+cm4gc1swXT09PS0xPyJkYXRhOiIrdDp0fX0KUC5mYS5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXty
+ZXR1cm4gbmV3IFVpbnQ4QXJyYXkoOTYpfSwKJFM6NDB9ClAuZjkucHJvdG90eXBlPXsKJDI6ZnVuY3Rp
+b24oYSxiKXt2YXIgdD10aGlzLmEKaWYoYT49dC5sZW5ndGgpcmV0dXJuIEguaSh0LGEpCnQ9dFthXQpK
+LmpuKHQsMCw5NixiKQpyZXR1cm4gdH0sCiRTOjIzfQpQLmZiLnByb3RvdHlwZT17CiQzOmZ1bmN0aW9u
+KGEsYixjKXt2YXIgdCxzLHIscQpmb3IodD1iLmxlbmd0aCxzPWEubGVuZ3RoLHI9MDtyPHQ7KytyKXtx
+PUMuYS50KGIscileOTYKaWYocT49cylyZXR1cm4gSC5pKGEscSkKYVtxXT1jfX19ClAuZmMucHJvdG90
+eXBlPXsKJDM6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMscixxCmZvcih0PUMuYS50KGIsMCkscz1DLmEu
+dChiLDEpLHI9YS5sZW5ndGg7dDw9czsrK3Qpe3E9KHReOTYpPj4+MAppZihxPj1yKXJldHVybiBILmko
+YSxxKQphW3FdPWN9fX0KUC5kei5wcm90b3R5cGU9ewpnYmM6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5j
+PjB9LApnYmU6ZnVuY3Rpb24oKXt2YXIgdD10aGlzLmYKaWYodHlwZW9mIHQhPT0ibnVtYmVyIilyZXR1
+cm4gdC5EKCkKcmV0dXJuIHQ8dGhpcy5yfSwKZ2JkOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMucjx0aGlz
+LmEubGVuZ3RofSwKZ2JfOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuYj09PTQmJkMuYS5IKHRoaXMuYSwi
+aHR0cCIpfSwKZ2IwOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuYj09PTUmJkMuYS5IKHRoaXMuYSwiaHR0
+cHMiKX0sCmdhUDpmdW5jdGlvbigpe3ZhciB0LHM9dGhpcyxyPSJmaWxlIixxPSJwYWNrYWdlIixwPXMu
+YgppZihwPD0wKXJldHVybiIiCnQ9cy54CmlmKHQhPW51bGwpcmV0dXJuIHQKaWYocy5nYl8oKSlwPXMu
+eD0iaHR0cCIKZWxzZSBpZihzLmdiMCgpKXtzLng9Imh0dHBzIgpwPSJodHRwcyJ9ZWxzZSBpZihwPT09
+NCYmQy5hLkgocy5hLHIpKXtzLng9cgpwPXJ9ZWxzZSBpZihwPT09NyYmQy5hLkgocy5hLHEpKXtzLng9
+cQpwPXF9ZWxzZXtwPUMuYS5uKHMuYSwwLHApCnMueD1wfXJldHVybiBwfSwKZ2JxOmZ1bmN0aW9uKCl7
+dmFyIHQ9dGhpcy5jLHM9dGhpcy5iKzMKcmV0dXJuIHQ+cz9DLmEubih0aGlzLmEscyx0LTEpOiIifSwK
+Z2FEOmZ1bmN0aW9uKGEpe3ZhciB0PXRoaXMuYwpyZXR1cm4gdD4wP0MuYS5uKHRoaXMuYSx0LHRoaXMu
+ZCk6IiJ9LApnYUg6ZnVuY3Rpb24oYSl7dmFyIHQscyxyPXRoaXMKaWYoci5jPjApe3Q9ci5kCmlmKHR5
+cGVvZiB0IT09Im51bWJlciIpcmV0dXJuIHQuQigpCnM9ci5lCmlmKHR5cGVvZiBzIT09Im51bWJlciIp
+cmV0dXJuIEguYWoocykKcz10KzE8cwp0PXN9ZWxzZSB0PSExCmlmKHQpe3Q9ci5kCmlmKHR5cGVvZiB0
+IT09Im51bWJlciIpcmV0dXJuIHQuQigpCnJldHVybiBQLmRPKEMuYS5uKHIuYSx0KzEsci5lKSxudWxs
+LG51bGwpfWlmKHIuZ2JfKCkpcmV0dXJuIDgwCmlmKHIuZ2IwKCkpcmV0dXJuIDQ0MwpyZXR1cm4gMH0s
+CmdiaTpmdW5jdGlvbihhKXtyZXR1cm4gQy5hLm4odGhpcy5hLHRoaXMuZSx0aGlzLmYpfSwKZ2FJOmZ1
+bmN0aW9uKCl7dmFyIHQ9dGhpcy5mLHM9dGhpcy5yCmlmKHR5cGVvZiB0IT09Im51bWJlciIpcmV0dXJu
+IHQuRCgpCnJldHVybiB0PHM/Qy5hLm4odGhpcy5hLHQrMSxzKToiIn0sCmdiYjpmdW5jdGlvbigpe3Zh
+ciB0PXRoaXMucixzPXRoaXMuYQpyZXR1cm4gdDxzLmxlbmd0aD9DLmEuVShzLHQrMSk6IiJ9LApnYUo6
+ZnVuY3Rpb24oKXt2YXIgdD10aGlzLmYKaWYodHlwZW9mIHQhPT0ibnVtYmVyIilyZXR1cm4gdC5EKCkK
+aWYodD49dGhpcy5yKXJldHVybiBDLloKcmV0dXJuIG5ldyBQLmF6KFAuaTcodGhpcy5nYUkoKSksdS5X
+KX0sCmdxOmZ1bmN0aW9uKGEpe3ZhciB0PXRoaXMueQpyZXR1cm4gdD09bnVsbD90aGlzLnk9Qy5hLmdx
+KHRoaXMuYSk6dH0sCkc6ZnVuY3Rpb24oYSxiKXtpZihiPT1udWxsKXJldHVybiExCmlmKHRoaXM9PT1i
+KXJldHVybiEwCnJldHVybiB1LmsuYyhiKSYmdGhpcy5hPT09Yi5pKDApfSwKaTpmdW5jdGlvbihhKXty
+ZXR1cm4gdGhpcy5hfSwKJGlkYzoxfQpQLmRtLnByb3RvdHlwZT17fQpXLmgucHJvdG90eXBlPXt9Clcu
+YjMucHJvdG90eXBlPXsKaTpmdW5jdGlvbihhKXtyZXR1cm4gU3RyaW5nKGEpfSwKJGliMzoxfQpXLmN1
+LnByb3RvdHlwZT17Cmk6ZnVuY3Rpb24oYSl7cmV0dXJuIFN0cmluZyhhKX19ClcuYjUucHJvdG90eXBl
+PXskaWI1OjF9ClcuYUcucHJvdG90eXBlPXskaWFHOjF9ClcuYUgucHJvdG90eXBlPXskaWFIOjF9Clcu
+YWEucHJvdG90eXBlPXsKZ206ZnVuY3Rpb24oYSl7cmV0dXJuIGEubGVuZ3RofX0KVy5iQS5wcm90b3R5
+cGU9ewpnbTpmdW5jdGlvbihhKXtyZXR1cm4gYS5sZW5ndGh9fQpXLmRVLnByb3RvdHlwZT17fQpXLmFM
+LnByb3RvdHlwZT17fQpXLmRWLnByb3RvdHlwZT17Cmk6ZnVuY3Rpb24oYSl7cmV0dXJuIFN0cmluZyhh
+KX19ClcuYkIucHJvdG90eXBlPXsKaTpmdW5jdGlvbihhKXtyZXR1cm4iUmVjdGFuZ2xlICgiK0guYihh
+LmxlZnQpKyIsICIrSC5iKGEudG9wKSsiKSAiK0guYihhLndpZHRoKSsiIHggIitILmIoYS5oZWlnaHQp
+fSwKRzpmdW5jdGlvbihhLGIpe2lmKGI9PW51bGwpcmV0dXJuITEKcmV0dXJuIHUucS5jKGIpJiZhLmxl
+ZnQ9PT1iLmxlZnQmJmEudG9wPT09Yi50b3AmJmEud2lkdGg9PT1iLndpZHRoJiZhLmhlaWdodD09PWIu
+aGVpZ2h0fSwKZ3E6ZnVuY3Rpb24oYSl7cmV0dXJuIFcuaWIoQy5lLmdxKGEubGVmdCksQy5lLmdxKGEu
+dG9wKSxDLmUuZ3EoYS53aWR0aCksQy5lLmdxKGEuaGVpZ2h0KSl9LAokaWg1OjF9ClcuZFcucHJvdG90
+eXBlPXsKZ206ZnVuY3Rpb24oYSl7cmV0dXJuIGEubGVuZ3RofX0KVy5hcS5wcm90b3R5cGU9ewpnbTpm
+dW5jdGlvbihhKXtyZXR1cm4gdGhpcy5hLmxlbmd0aH0sCmo6ZnVuY3Rpb24oYSxiKXt2YXIgdApILngo
+YikKdD10aGlzLmEKaWYoYjwwfHxiPj10Lmxlbmd0aClyZXR1cm4gSC5pKHQsYikKcmV0dXJuIHRoaXMu
+JHRpLmQuYih0W2JdKX0sCmw6ZnVuY3Rpb24oYSxiLGMpe3RoaXMuJHRpLmQuYihjKQp0aHJvdyBILmEo
+UC5OKCJDYW5ub3QgbW9kaWZ5IGxpc3QiKSl9fQpXLnUucHJvdG90eXBlPXsKZ2MwOmZ1bmN0aW9uKGEp
+e3JldHVybiBuZXcgVy5hcChhKX0sCmdDOmZ1bmN0aW9uKGEpe3JldHVybiBuZXcgVy5kbihhKX0sCmk6
+ZnVuY3Rpb24oYSl7cmV0dXJuIGEubG9jYWxOYW1lfSwKYnQ6ZnVuY3Rpb24oYSl7dmFyIHQ9ISFhLnNj
+cm9sbEludG9WaWV3SWZOZWVkZWQKaWYodClhLnNjcm9sbEludG9WaWV3SWZOZWVkZWQoKQplbHNlIGEu
+c2Nyb2xsSW50b1ZpZXcoKX0sCks6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIHQscyxyLHEKaWYoYz09bnVs
+bCl7aWYoZD09bnVsbCl7dD0kLmhOCmlmKHQ9PW51bGwpe3Q9SC5uKFtdLHUuUSkKcz1uZXcgVy5iVSh0
+KQpDLmIuayh0LFcuaWEobnVsbCkpCkMuYi5rKHQsVy5pZSgpKQokLmhOPXMKZD1zfWVsc2UgZD10fXQ9
+JC5oTQppZih0PT1udWxsKXt0PW5ldyBXLmNtKGQpCiQuaE09dApjPXR9ZWxzZXt0LmE9ZApjPXR9fWVs
+c2UgaWYoZCE9bnVsbCl0aHJvdyBILmEoUC5iNCgidmFsaWRhdG9yIGNhbiBvbmx5IGJlIHBhc3NlZCBp
+ZiB0cmVlU2FuaXRpemVyIGlzIG51bGwiKSkKaWYoJC5hdz09bnVsbCl7dD1kb2N1bWVudApzPXQuaW1w
+bGVtZW50YXRpb24uY3JlYXRlSFRNTERvY3VtZW50KCIiKQokLmF3PXMKJC5mWj1zLmNyZWF0ZVJhbmdl
+KCkKcz0kLmF3LmNyZWF0ZUVsZW1lbnQoImJhc2UiKQp1LnYuYihzKQpzLmhyZWY9dC5iYXNlVVJJCiQu
+YXcuaGVhZC5hcHBlbmRDaGlsZChzKX10PSQuYXcKaWYodC5ib2R5PT1udWxsKXtzPXQuY3JlYXRlRWxl
+bWVudCgiYm9keSIpCnQuYm9keT11LlguYihzKX10PSQuYXcKaWYodS5YLmMoYSkpcj10LmJvZHkKZWxz
+ZXtyPXQuY3JlYXRlRWxlbWVudChhLnRhZ05hbWUpCiQuYXcuYm9keS5hcHBlbmRDaGlsZChyKX1pZigi
+Y3JlYXRlQ29udGV4dHVhbEZyYWdtZW50IiBpbiB3aW5kb3cuUmFuZ2UucHJvdG90eXBlJiYhQy5iLnco
+Qy5VLGEudGFnTmFtZSkpeyQuZlouc2VsZWN0Tm9kZUNvbnRlbnRzKHIpCnE9JC5mWi5jcmVhdGVDb250
+ZXh0dWFsRnJhZ21lbnQoYil9ZWxzZXtyLmlubmVySFRNTD1iCnE9JC5hdy5jcmVhdGVEb2N1bWVudEZy
+YWdtZW50KCkKZm9yKDt0PXIuZmlyc3RDaGlsZCx0IT1udWxsOylxLmFwcGVuZENoaWxkKHQpfXQ9JC5h
+dy5ib2R5CmlmKHI9PW51bGw/dCE9bnVsbDpyIT09dClKLmhFKHIpCmMuYU8ocSkKZG9jdW1lbnQuYWRv
+cHROb2RlKHEpCnJldHVybiBxfSwKYzg6ZnVuY3Rpb24oYSxiLGMpe3JldHVybiB0aGlzLksoYSxiLGMs
+bnVsbCl9LApzYWY6ZnVuY3Rpb24oYSxiKXt0aGlzLmFsKGEsYil9LAphNjpmdW5jdGlvbihhLGIsYyl7
+YS50ZXh0Q29udGVudD1udWxsCmEuYXBwZW5kQ2hpbGQodGhpcy5LKGEsYixudWxsLGMpKX0sCmFsOmZ1
+bmN0aW9uKGEsYil7cmV0dXJuIHRoaXMuYTYoYSxiLG51bGwpfSwKZ2FHOmZ1bmN0aW9uKGEpe3JldHVy
+biBuZXcgVy5ibihhLCJjbGljayIsITEsdS5DKX0sCiRpdToxLApnYm06ZnVuY3Rpb24oYSl7cmV0dXJu
+IGEudGFnTmFtZX19ClcuZFoucHJvdG90eXBlPXsKJDE6ZnVuY3Rpb24oYSl7cmV0dXJuIHUuaC5jKHUu
+Ri5iKGEpKX0sCiRTOjM5fQpXLmQucHJvdG90eXBlPXskaWQ6MX0KVy5xLnByb3RvdHlwZT17CmI3OmZ1
+bmN0aW9uKGEsYixjLGQpe3UuVS5iKGMpCmlmKGMhPW51bGwpdGhpcy5iSShhLGIsYyxkKX0sCmFjOmZ1
+bmN0aW9uKGEsYixjKXtyZXR1cm4gdGhpcy5iNyhhLGIsYyxudWxsKX0sCmJJOmZ1bmN0aW9uKGEsYixj
+LGQpe3JldHVybiBhLmFkZEV2ZW50TGlzdGVuZXIoYixILmRNKHUuVS5iKGMpLDEpLGQpfSwKJGlxOjF9
+ClcuYjkucHJvdG90eXBlPXskaWI5OjF9ClcuY0YucHJvdG90eXBlPXsKZ206ZnVuY3Rpb24oYSl7cmV0
+dXJuIGEubGVuZ3RofX0KVy5lMS5wcm90b3R5cGU9ewpnbTpmdW5jdGlvbihhKXtyZXR1cm4gYS5sZW5n
+dGh9fQpXLmJGLnByb3RvdHlwZT17fQpXLmEzLnByb3RvdHlwZT17CmNsOmZ1bmN0aW9uKGEsYixjLGQp
+e3JldHVybiBhLm9wZW4oYixjLCEwKX0sCiRpYTM6MX0KVy5lMy5wcm90b3R5cGU9ewokMjpmdW5jdGlv
+bihhLGIpe3RoaXMuYS5zZXRSZXF1ZXN0SGVhZGVyKEgubyhhKSxILm8oYikpfSwKJFM6OH0KVy5lNC5w
+cm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXt2YXIgdCxzLHIscSxwCnUucC5iKGEpCnQ9dGhpcy5hCnM9
+dC5zdGF0dXMKaWYodHlwZW9mIHMhPT0ibnVtYmVyIilyZXR1cm4gcy5icigpCnI9cz49MjAwJiZzPDMw
+MApxPXM+MzA3JiZzPDQwMApzPXJ8fHM9PT0wfHxzPT09MzA0fHxxCnA9dGhpcy5iCmlmKHMpe3AuJHRp
+LmgoIjEvIikuYih0KQpzPXAuYQppZihzLmEhPT0wKUguYWsoUC5kMigiRnV0dXJlIGFscmVhZHkgY29t
+cGxldGVkIikpCnMuYkoodCl9ZWxzZSBwLmI5KGEpfSwKJFM6MjZ9ClcuYkcucHJvdG90eXBlPXt9Clcu
+YkgucHJvdG90eXBlPXskaWJIOjF9ClcuYk8ucHJvdG90eXBlPXsKZ2NtOmZ1bmN0aW9uKGEpe2lmKCJv
+cmlnaW4iIGluIGEpcmV0dXJuIGEub3JpZ2luCnJldHVybiBILmIoYS5wcm90b2NvbCkrIi8vIitILmIo
+YS5ob3N0KX0sCmk6ZnVuY3Rpb24oYSl7cmV0dXJuIFN0cmluZyhhKX0sCiRpYk86MX0KVy5LLnByb3Rv
+dHlwZT17JGlLOjF9ClcuTy5wcm90b3R5cGU9ewpnWTpmdW5jdGlvbihhKXt2YXIgdD10aGlzLmEscz10
+LmNoaWxkTm9kZXMubGVuZ3RoCmlmKHM9PT0wKXRocm93IEguYShQLmQyKCJObyBlbGVtZW50cyIpKQpp
+ZihzPjEpdGhyb3cgSC5hKFAuZDIoIk1vcmUgdGhhbiBvbmUgZWxlbWVudCIpKQpyZXR1cm4gdC5maXJz
+dENoaWxkfSwKSTpmdW5jdGlvbihhLGIpe3ZhciB0LHMscixxCnUuZWguYihiKQp0PWIuYQpzPXRoaXMu
+YQppZih0IT09cylmb3Iocj10LmNoaWxkTm9kZXMubGVuZ3RoLHE9MDtxPHI7KytxKXMuYXBwZW5kQ2hp
+bGQodC5maXJzdENoaWxkKQpyZXR1cm59LApsOmZ1bmN0aW9uKGEsYixjKXt2YXIgdCxzCnUuRi5iKGMp
+CnQ9dGhpcy5hCnM9dC5jaGlsZE5vZGVzCmlmKGI8MHx8Yj49cy5sZW5ndGgpcmV0dXJuIEguaShzLGIp
+CnQucmVwbGFjZUNoaWxkKGMsc1tiXSl9LApnRjpmdW5jdGlvbihhKXt2YXIgdD10aGlzLmEuY2hpbGRO
+b2RlcwpyZXR1cm4gbmV3IFcuYU4odCx0Lmxlbmd0aCxILmE4KHQpLmgoImFOPGFjLkU+IikpfSwKZ206
+ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuYS5jaGlsZE5vZGVzLmxlbmd0aH0sCmo6ZnVuY3Rpb24oYSxi
+KXt2YXIgdApILngoYikKdD10aGlzLmEuY2hpbGROb2RlcwppZihiPDB8fGI+PXQubGVuZ3RoKXJldHVy
+biBILmkodCxiKQpyZXR1cm4gdFtiXX19Clcuay5wcm90b3R5cGU9ewpjbjpmdW5jdGlvbihhKXt2YXIg
+dD1hLnBhcmVudE5vZGUKaWYodCE9bnVsbCl0LnJlbW92ZUNoaWxkKGEpfSwKYk06ZnVuY3Rpb24oYSl7
+dmFyIHQKZm9yKDt0PWEuZmlyc3RDaGlsZCx0IT1udWxsOylhLnJlbW92ZUNoaWxkKHQpfSwKaTpmdW5j
+dGlvbihhKXt2YXIgdD1hLm5vZGVWYWx1ZQpyZXR1cm4gdD09bnVsbD90aGlzLmJ3KGEpOnR9LAokaWs6
+MX0KVy5iVC5wcm90b3R5cGU9ewpnbTpmdW5jdGlvbihhKXtyZXR1cm4gYS5sZW5ndGh9LApqOmZ1bmN0
+aW9uKGEsYil7SC54KGIpCmlmKGI+Pj4wIT09Ynx8Yj49YS5sZW5ndGgpdGhyb3cgSC5hKFAuZTUoYixh
+LG51bGwsbnVsbCxudWxsKSkKcmV0dXJuIGFbYl19LApsOmZ1bmN0aW9uKGEsYixjKXt1LkYuYihjKQp0
+aHJvdyBILmEoUC5OKCJDYW5ub3QgYXNzaWduIGVsZW1lbnQgb2YgaW1tdXRhYmxlIExpc3QuIikpfSwK
+TzpmdW5jdGlvbihhLGIpe2lmKGI8MHx8Yj49YS5sZW5ndGgpcmV0dXJuIEguaShhLGIpCnJldHVybiBh
+W2JdfSwKJGlKOjEsCiRpajoxLAokaW06MX0KVy5iZS5wcm90b3R5cGU9eyRpYmU6MX0KVy5hNS5wcm90
+b3R5cGU9eyRpYTU6MX0KVy5kMS5wcm90b3R5cGU9ewpnbTpmdW5jdGlvbihhKXtyZXR1cm4gYS5sZW5n
+dGh9fQpXLmJaLnByb3RvdHlwZT17Cks6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIHQscwppZigiY3JlYXRl
+Q29udGV4dHVhbEZyYWdtZW50IiBpbiB3aW5kb3cuUmFuZ2UucHJvdG90eXBlKXJldHVybiB0aGlzLmFt
+KGEsYixjLGQpCnQ9Vy5qRigiPHRhYmxlPiIrSC5iKGIpKyI8L3RhYmxlPiIsYyxkKQpzPWRvY3VtZW50
+LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKQpzLnRvU3RyaW5nCnQudG9TdHJpbmcKbmV3IFcuTyhzKS5J
+KDAsbmV3IFcuTyh0KSkKcmV0dXJuIHN9fQpXLmQ2LnByb3RvdHlwZT17Cks6ZnVuY3Rpb24oYSxiLGMs
+ZCl7dmFyIHQscyxyLHEKaWYoImNyZWF0ZUNvbnRleHR1YWxGcmFnbWVudCIgaW4gd2luZG93LlJhbmdl
+LnByb3RvdHlwZSlyZXR1cm4gdGhpcy5hbShhLGIsYyxkKQp0PWRvY3VtZW50CnM9dC5jcmVhdGVEb2N1
+bWVudEZyYWdtZW50KCkKdD1DLkMuSyh0LmNyZWF0ZUVsZW1lbnQoInRhYmxlIiksYixjLGQpCnQudG9T
+dHJpbmcKdD1uZXcgVy5PKHQpCnI9dC5nWSh0KQpyLnRvU3RyaW5nCnQ9bmV3IFcuTyhyKQpxPXQuZ1ko
+dCkKcy50b1N0cmluZwpxLnRvU3RyaW5nCm5ldyBXLk8ocykuSSgwLG5ldyBXLk8ocSkpCnJldHVybiBz
+fX0KVy5kNy5wcm90b3R5cGU9ewpLOmZ1bmN0aW9uKGEsYixjLGQpe3ZhciB0LHMscgppZigiY3JlYXRl
+Q29udGV4dHVhbEZyYWdtZW50IiBpbiB3aW5kb3cuUmFuZ2UucHJvdG90eXBlKXJldHVybiB0aGlzLmFt
+KGEsYixjLGQpCnQ9ZG9jdW1lbnQKcz10LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKQp0PUMuQy5LKHQu
+Y3JlYXRlRWxlbWVudCgidGFibGUiKSxiLGMsZCkKdC50b1N0cmluZwp0PW5ldyBXLk8odCkKcj10LmdZ
+KHQpCnMudG9TdHJpbmcKci50b1N0cmluZwpuZXcgVy5PKHMpLkkoMCxuZXcgVy5PKHIpKQpyZXR1cm4g
+c319ClcuYmoucHJvdG90eXBlPXsKYTY6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMKYS50ZXh0Q29udGVu
+dD1udWxsCnQ9YS5jb250ZW50CnQudG9TdHJpbmcKSi5qayh0KQpzPXRoaXMuSyhhLGIsbnVsbCxjKQph
+LmNvbnRlbnQuYXBwZW5kQ2hpbGQocyl9LAphbDpmdW5jdGlvbihhLGIpe3JldHVybiB0aGlzLmE2KGEs
+YixudWxsKX0sCiRpYmo6MX0KVy5hNy5wcm90b3R5cGU9e30KVy5hQS5wcm90b3R5cGU9eyRpYUE6MSwk
+aWVyOjF9ClcuYWkucHJvdG90eXBlPXskaWFpOjF9ClcuYm0ucHJvdG90eXBlPXskaWJtOjF9ClcuYzMu
+cHJvdG90eXBlPXsKaTpmdW5jdGlvbihhKXtyZXR1cm4iUmVjdGFuZ2xlICgiK0guYihhLmxlZnQpKyIs
+ICIrSC5iKGEudG9wKSsiKSAiK0guYihhLndpZHRoKSsiIHggIitILmIoYS5oZWlnaHQpfSwKRzpmdW5j
+dGlvbihhLGIpe2lmKGI9PW51bGwpcmV0dXJuITEKcmV0dXJuIHUucS5jKGIpJiZhLmxlZnQ9PT1iLmxl
+ZnQmJmEudG9wPT09Yi50b3AmJmEud2lkdGg9PT1iLndpZHRoJiZhLmhlaWdodD09PWIuaGVpZ2h0fSwK
+Z3E6ZnVuY3Rpb24oYSl7cmV0dXJuIFcuaWIoQy5lLmdxKGEubGVmdCksQy5lLmdxKGEudG9wKSxDLmUu
+Z3EoYS53aWR0aCksQy5lLmdxKGEuaGVpZ2h0KSl9fQpXLmM4LnByb3RvdHlwZT17CmdtOmZ1bmN0aW9u
+KGEpe3JldHVybiBhLmxlbmd0aH0sCmo6ZnVuY3Rpb24oYSxiKXtILngoYikKaWYoYj4+PjAhPT1ifHxi
+Pj1hLmxlbmd0aCl0aHJvdyBILmEoUC5lNShiLGEsbnVsbCxudWxsLG51bGwpKQpyZXR1cm4gYVtiXX0s
+Cmw6ZnVuY3Rpb24oYSxiLGMpe3UuRi5iKGMpCnRocm93IEguYShQLk4oIkNhbm5vdCBhc3NpZ24gZWxl
+bWVudCBvZiBpbW11dGFibGUgTGlzdC4iKSl9LApPOmZ1bmN0aW9uKGEsYil7aWYoYjwwfHxiPj1hLmxl
+bmd0aClyZXR1cm4gSC5pKGEsYikKcmV0dXJuIGFbYl19LAokaUo6MSwKJGlqOjEsCiRpbToxfQpXLmRp
+LnByb3RvdHlwZT17CkE6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIscSxwCnUudS5iKGIpCmZvcih0PXRo
+aXMuZ0ooKSxzPXQubGVuZ3RoLHI9dGhpcy5hLHE9MDtxPHQubGVuZ3RoO3QubGVuZ3RoPT09c3x8KDAs
+SC5jcikodCksKytxKXtwPXRbcV0KYi4kMihwLHIuZ2V0QXR0cmlidXRlKHApKX19LApnSjpmdW5jdGlv
+bigpe3ZhciB0LHMscixxLHA9dGhpcy5hLmF0dHJpYnV0ZXMsbz1ILm4oW10sdS5zKQpmb3IodD1wLmxl
+bmd0aCxzPXUuaDkscj0wO3I8dDsrK3Ipe2lmKHI+PXAubGVuZ3RoKXJldHVybiBILmkocCxyKQpxPXMu
+YihwW3JdKQppZihxLm5hbWVzcGFjZVVSST09bnVsbClDLmIuayhvLHEubmFtZSl9cmV0dXJuIG99fQpX
+LmFwLnByb3RvdHlwZT17Cmo6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gdGhpcy5hLmdldEF0dHJpYnV0ZShI
+Lm8oYikpfSwKbDpmdW5jdGlvbihhLGIsYyl7dGhpcy5hLnNldEF0dHJpYnV0ZShiLGMpfSwKZ206ZnVu
+Y3Rpb24oYSl7cmV0dXJuIHRoaXMuZ0ooKS5sZW5ndGh9fQpXLmFCLnByb3RvdHlwZT17Cmo6ZnVuY3Rp
+b24oYSxiKXtyZXR1cm4gdGhpcy5hLmEuZ2V0QXR0cmlidXRlKCJkYXRhLSIrdGhpcy5WKEgubyhiKSkp
+fSwKbDpmdW5jdGlvbihhLGIsYyl7dGhpcy5hLmEuc2V0QXR0cmlidXRlKCJkYXRhLSIrdGhpcy5WKGIp
+LGMpfSwKQTpmdW5jdGlvbihhLGIpe3RoaXMuYS5BKDAsbmV3IFcuZXcodGhpcyx1LnUuYihiKSkpfSwK
+Z0o6ZnVuY3Rpb24oKXt2YXIgdD1ILm4oW10sdS5zKQp0aGlzLmEuQSgwLG5ldyBXLmV4KHRoaXMsdCkp
+CnJldHVybiB0fSwKZ206ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuZ0ooKS5sZW5ndGh9LApiNDpmdW5j
+dGlvbihhKXt2YXIgdCxzLHI9SC5uKGEuc3BsaXQoIi0iKSx1LnMpCmZvcih0PTE7dDxyLmxlbmd0aDsr
+K3Qpe3M9clt0XQppZihzLmxlbmd0aD4wKUMuYi5sKHIsdCxzWzBdLnRvVXBwZXJDYXNlKCkrSi5qcyhz
+LDEpKX1yZXR1cm4gQy5iLlQociwiIil9LApWOmZ1bmN0aW9uKGEpe3ZhciB0LHMscixxLHAKZm9yKHQ9
+YS5sZW5ndGgscz0wLHI9IiI7czx0Oysrcyl7cT1hW3NdCnA9cS50b0xvd2VyQ2FzZSgpCnI9KHEhPT1w
+JiZzPjA/cisiLSI6cikrcH1yZXR1cm4gci5jaGFyQ29kZUF0KDApPT0wP3I6cn19ClcuZXcucHJvdG90
+eXBlPXsKJDI6ZnVuY3Rpb24oYSxiKXtpZihKLmEwKGEpLkgoYSwiZGF0YS0iKSl0aGlzLmIuJDIodGhp
+cy5hLmI0KEMuYS5VKGEsNSkpLGIpfSwKJFM6OH0KVy5leC5wcm90b3R5cGU9ewokMjpmdW5jdGlvbihh
+LGIpe2lmKEouYTAoYSkuSChhLCJkYXRhLSIpKUMuYi5rKHRoaXMuYix0aGlzLmEuYjQoQy5hLlUoYSw1
+KSkpfSwKJFM6OH0KVy5kbi5wcm90b3R5cGU9ewpYOmZ1bmN0aW9uKCl7dmFyIHQscyxyLHEscD1QLmJN
+KHUuTikKZm9yKHQ9dGhpcy5hLmNsYXNzTmFtZS5zcGxpdCgiICIpLHM9dC5sZW5ndGgscj0wO3I8czsr
+K3Ipe3E9Si5kUih0W3JdKQppZihxLmxlbmd0aCE9PTApcC5rKDAscSl9cmV0dXJuIHB9LAphTDpmdW5j
+dGlvbihhKXt0aGlzLmEuY2xhc3NOYW1lPXUuVC5iKGEpLlQoMCwiICIpfSwKZ206ZnVuY3Rpb24oYSl7
+cmV0dXJuIHRoaXMuYS5jbGFzc0xpc3QubGVuZ3RofSwKdzpmdW5jdGlvbihhLGIpe3ZhciB0PXRoaXMu
+YS5jbGFzc0xpc3QuY29udGFpbnMoYikKcmV0dXJuIHR9LAprOmZ1bmN0aW9uKGEsYil7dmFyIHQ9dGhp
+cy5hLmNsYXNzTGlzdCxzPXQuY29udGFpbnMoYikKdC5hZGQoYikKcmV0dXJuIXN9LApNOmZ1bmN0aW9u
+KGEsYil7dmFyIHQ9dGhpcy5hLmNsYXNzTGlzdCxzPXQuY29udGFpbnMoYikKdC5yZW1vdmUoYikKcmV0
+dXJuIHN9fQpXLmhfLnByb3RvdHlwZT17fQpXLmM0LnByb3RvdHlwZT17fQpXLmJuLnByb3RvdHlwZT17
+fQpXLmRxLnByb3RvdHlwZT17fQpXLmV6LnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3JldHVybiB0
+aGlzLmEuJDEodS5BLmIoYSkpfSwKJFM6Mjd9ClcuYl8ucHJvdG90eXBlPXsKYkQ6ZnVuY3Rpb24oYSl7
+dmFyIHQKaWYoJC5kci5hPT09MCl7Zm9yKHQ9MDt0PDI2MjsrK3QpJC5kci5sKDAsQy5UW3RdLFcubHIo
+KSkKZm9yKHQ9MDt0PDEyOysrdCkkLmRyLmwoMCxDLm1bdF0sVy5scygpKX19LApXOmZ1bmN0aW9uKGEp
+e3JldHVybiAkLmplKCkudygwLFcuYkQoYSkpfSwKTjpmdW5jdGlvbihhLGIsYyl7dmFyIHQ9JC5kci5q
+KDAsSC5iKFcuYkQoYSkpKyI6OiIrYikKaWYodD09bnVsbCl0PSQuZHIuaigwLCIqOjoiK2IpCmlmKHQ9
+PW51bGwpcmV0dXJuITEKcmV0dXJuIEguaGcodC4kNChhLGIsYyx0aGlzKSl9LAokaUc6MX0KVy5hYy5w
+cm90b3R5cGU9ewpnRjpmdW5jdGlvbihhKXtyZXR1cm4gbmV3IFcuYU4oYSx0aGlzLmdtKGEpLEguYTgo
+YSkuaCgiYU48YWMuRT4iKSl9fQpXLmJVLnByb3RvdHlwZT17Clc6ZnVuY3Rpb24oYSl7cmV0dXJuIEMu
+Yi5iOCh0aGlzLmEsbmV3IFcuZWQoYSkpfSwKTjpmdW5jdGlvbihhLGIsYyl7cmV0dXJuIEMuYi5iOCh0
+aGlzLmEsbmV3IFcuZWMoYSxiLGMpKX0sCiRpRzoxfQpXLmVkLnByb3RvdHlwZT17CiQxOmZ1bmN0aW9u
+KGEpe3JldHVybiB1LmUuYihhKS5XKHRoaXMuYSl9LAokUzoxNH0KVy5lYy5wcm90b3R5cGU9ewokMTpm
+dW5jdGlvbihhKXtyZXR1cm4gdS5lLmIoYSkuTih0aGlzLmEsdGhpcy5iLHRoaXMuYyl9LAokUzoxNH0K
+Vy5jZi5wcm90b3R5cGU9ewpiRTpmdW5jdGlvbihhLGIsYyxkKXt2YXIgdCxzLHIKdGhpcy5hLkkoMCxj
+KQp0PWIuYWooMCxuZXcgVy5lVCgpKQpzPWIuYWooMCxuZXcgVy5lVSgpKQp0aGlzLmIuSSgwLHQpCnI9
+dGhpcy5jCnIuSSgwLEMudikKci5JKDAscyl9LApXOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLmEudygw
+LFcuYkQoYSkpfSwKTjpmdW5jdGlvbihhLGIsYyl7dmFyIHQ9dGhpcyxzPVcuYkQoYSkscj10LmMKaWYo
+ci53KDAsSC5iKHMpKyI6OiIrYikpcmV0dXJuIHQuZC5jXyhjKQplbHNlIGlmKHIudygwLCIqOjoiK2Ip
+KXJldHVybiB0LmQuY18oYykKZWxzZXtyPXQuYgppZihyLncoMCxILmIocykrIjo6IitiKSlyZXR1cm4h
+MAplbHNlIGlmKHIudygwLCIqOjoiK2IpKXJldHVybiEwCmVsc2UgaWYoci53KDAsSC5iKHMpKyI6Oioi
+KSlyZXR1cm4hMAplbHNlIGlmKHIudygwLCIqOjoqIikpcmV0dXJuITB9cmV0dXJuITF9LAokaUc6MX0K
+Vy5lVC5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXtyZXR1cm4hQy5iLncoQy5tLEgubyhhKSl9LAok
+UzoxMH0KVy5lVS5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXtyZXR1cm4gQy5iLncoQy5tLEgubyhh
+KSl9LAokUzoxMH0KVy5kQi5wcm90b3R5cGU9ewpOOmZ1bmN0aW9uKGEsYixjKXtpZih0aGlzLmJDKGEs
+YixjKSlyZXR1cm4hMAppZihiPT09InRlbXBsYXRlIiYmYz09PSIiKXJldHVybiEwCmlmKGEuZ2V0QXR0
+cmlidXRlKCJ0ZW1wbGF0ZSIpPT09IiIpcmV0dXJuIHRoaXMuZS53KDAsYikKcmV0dXJuITF9fQpXLmVa
+LnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3JldHVybiJURU1QTEFURTo6IitILmIoSC5vKGEpKX0s
+CiRTOjEzfQpXLmRBLnByb3RvdHlwZT17Clc6ZnVuY3Rpb24oYSl7dmFyIHQKaWYodS5ldy5jKGEpKXJl
+dHVybiExCnQ9dS5nNy5jKGEpCmlmKHQmJlcuYkQoYSk9PT0iZm9yZWlnbk9iamVjdCIpcmV0dXJuITEK
+aWYodClyZXR1cm4hMApyZXR1cm4hMX0sCk46ZnVuY3Rpb24oYSxiLGMpe2lmKGI9PT0iaXMifHxDLmEu
+SChiLCJvbiIpKXJldHVybiExCnJldHVybiB0aGlzLlcoYSl9LAokaUc6MX0KVy5hTi5wcm90b3R5cGU9
+ewpwOmZ1bmN0aW9uKCl7dmFyIHQ9dGhpcyxzPXQuYysxLHI9dC5iCmlmKHM8cil7dC5zYVooSi5mVyh0
+LmEscykpCnQuYz1zCnJldHVybiEwfXQuc2FaKG51bGwpCnQuYz1yCnJldHVybiExfSwKZ3U6ZnVuY3Rp
+b24oKXtyZXR1cm4gdGhpcy5kfSwKc2FaOmZ1bmN0aW9uKGEpe3RoaXMuZD10aGlzLiR0aS5kLmIoYSl9
+LAokaVI6MX0KVy5kbC5wcm90b3R5cGU9eyRpcToxLCRpZXI6MX0KVy5HLnByb3RvdHlwZT17fQpXLmR5
+LnByb3RvdHlwZT17JGlrODoxfQpXLmNtLnByb3RvdHlwZT17CmFPOmZ1bmN0aW9uKGEpe25ldyBXLmY1
+KHRoaXMpLiQyKGEsbnVsbCl9LAphMjpmdW5jdGlvbihhLGIpe2lmKGI9PW51bGwpSi5oRShhKQplbHNl
+IGIucmVtb3ZlQ2hpbGQoYSl9LApiVzpmdW5jdGlvbihhLGIpe3ZhciB0LHMscixxLHAsbz0hMCxuPW51
+bGwsbT1udWxsCnRyeXtuPUouam8oYSkKbT1uLmEuZ2V0QXR0cmlidXRlKCJpcyIpCnUuaC5iKGEpCnQ9
+ZnVuY3Rpb24oYyl7aWYoIShjLmF0dHJpYnV0ZXMgaW5zdGFuY2VvZiBOYW1lZE5vZGVNYXApKXJldHVy
+biB0cnVlCnZhciBsPWMuY2hpbGROb2RlcwppZihjLmxhc3RDaGlsZCYmYy5sYXN0Q2hpbGQhPT1sW2wu
+bGVuZ3RoLTFdKXJldHVybiB0cnVlCmlmKGMuY2hpbGRyZW4paWYoIShjLmNoaWxkcmVuIGluc3RhbmNl
+b2YgSFRNTENvbGxlY3Rpb258fGMuY2hpbGRyZW4gaW5zdGFuY2VvZiBOb2RlTGlzdCkpcmV0dXJuIHRy
+dWUKdmFyIGs9MAppZihjLmNoaWxkcmVuKWs9Yy5jaGlsZHJlbi5sZW5ndGgKZm9yKHZhciBqPTA7ajxr
+O2orKyl7dmFyIGk9Yy5jaGlsZHJlbltqXQppZihpLmlkPT0nYXR0cmlidXRlcyd8fGkubmFtZT09J2F0
+dHJpYnV0ZXMnfHxpLmlkPT0nbGFzdENoaWxkJ3x8aS5uYW1lPT0nbGFzdENoaWxkJ3x8aS5pZD09J2No
+aWxkcmVuJ3x8aS5uYW1lPT0nY2hpbGRyZW4nKXJldHVybiB0cnVlfXJldHVybiBmYWxzZX0oYSkKbz1I
+LmRLKHQpPyEwOiEoYS5hdHRyaWJ1dGVzIGluc3RhbmNlb2YgTmFtZWROb2RlTWFwKX1jYXRjaChxKXtI
+LlEocSl9cz0iZWxlbWVudCB1bnByaW50YWJsZSIKdHJ5e3M9Si5iMihhKX1jYXRjaChxKXtILlEocSl9
+dHJ5e3I9Vy5iRChhKQp0aGlzLmJWKHUuaC5iKGEpLGIsbyxzLHIsdS5HLmIobiksSC5vKG0pKX1jYXRj
+aChxKXtpZihILlEocSkgaW5zdGFuY2VvZiBQLmExKXRocm93IHEKZWxzZXt0aGlzLmEyKGEsYikKd2lu
+ZG93CnA9IlJlbW92aW5nIGNvcnJ1cHRlZCBlbGVtZW50ICIrSC5iKHMpCmlmKHR5cGVvZiBjb25zb2xl
+IT0idW5kZWZpbmVkIil3aW5kb3cuY29uc29sZS53YXJuKHApfX19LApiVjpmdW5jdGlvbihhLGIsYyxk
+LGUsZixnKXt2YXIgdCxzLHIscSxwLG8sbj10aGlzCmlmKGMpe24uYTIoYSxiKQp3aW5kb3cKdD0iUmVt
+b3ZpbmcgZWxlbWVudCBkdWUgdG8gY29ycnVwdGVkIGF0dHJpYnV0ZXMgb24gPCIrZCsiPiIKaWYodHlw
+ZW9mIGNvbnNvbGUhPSJ1bmRlZmluZWQiKXdpbmRvdy5jb25zb2xlLndhcm4odCkKcmV0dXJufWlmKCFu
+LmEuVyhhKSl7bi5hMihhLGIpCndpbmRvdwp0PSJSZW1vdmluZyBkaXNhbGxvd2VkIGVsZW1lbnQgPCIr
+SC5iKGUpKyI+IGZyb20gIitILmIoYikKaWYodHlwZW9mIGNvbnNvbGUhPSJ1bmRlZmluZWQiKXdpbmRv
+dy5jb25zb2xlLndhcm4odCkKcmV0dXJufWlmKGchPW51bGwpaWYoIW4uYS5OKGEsImlzIixnKSl7bi5h
+MihhLGIpCndpbmRvdwp0PSJSZW1vdmluZyBkaXNhbGxvd2VkIHR5cGUgZXh0ZW5zaW9uIDwiK0guYihl
+KSsnIGlzPSInK2crJyI+JwppZih0eXBlb2YgY29uc29sZSE9InVuZGVmaW5lZCIpd2luZG93LmNvbnNv
+bGUud2Fybih0KQpyZXR1cm59dD1mLmdKKCkKcz1ILm4odC5zbGljZSgwKSxILloodCkuaCgiRjwxPiIp
+KQpmb3Iocj1mLmdKKCkubGVuZ3RoLTEsdD1mLmE7cj49MDstLXIpe2lmKHI+PXMubGVuZ3RoKXJldHVy
+biBILmkocyxyKQpxPXNbcl0KcD1uLmEKbz1KLmp0KHEpCkgubyhxKQppZighcC5OKGEsbyx0LmdldEF0
+dHJpYnV0ZShxKSkpe3dpbmRvdwpwPSJSZW1vdmluZyBkaXNhbGxvd2VkIGF0dHJpYnV0ZSA8IitILmIo
+ZSkrIiAiK3ErJz0iJytILmIodC5nZXRBdHRyaWJ1dGUocSkpKyciPicKaWYodHlwZW9mIGNvbnNvbGUh
+PSJ1bmRlZmluZWQiKXdpbmRvdy5jb25zb2xlLndhcm4ocCkKdC5yZW1vdmVBdHRyaWJ1dGUocSl9fWlm
+KHUuYVcuYyhhKSluLmFPKGEuY29udGVudCl9LAokaWpQOjF9ClcuZjUucHJvdG90eXBlPXsKJDI6ZnVu
+Y3Rpb24oYSxiKXt2YXIgdCxzLHIscSxwPXRoaXMuYQpzd2l0Y2goYS5ub2RlVHlwZSl7Y2FzZSAxOnAu
+YlcoYSxiKQpicmVhawpjYXNlIDg6Y2FzZSAxMTpjYXNlIDM6Y2FzZSA0OmJyZWFrCmRlZmF1bHQ6cC5h
+MihhLGIpfXQ9YS5sYXN0Q2hpbGQKZm9yKHA9dS5GO251bGwhPXQ7KXtzPW51bGwKdHJ5e3M9dC5wcmV2
+aW91c1NpYmxpbmd9Y2F0Y2gocil7SC5RKHIpCnE9cC5iKHQpCmEucmVtb3ZlQ2hpbGQocSkKdD1udWxs
+CnM9YS5sYXN0Q2hpbGR9aWYodCE9bnVsbCl0aGlzLiQyKHQsYSkKdD1wLmIocyl9fSwKJFM6Mjl9Clcu
+ZGsucHJvdG90eXBlPXt9ClcuZHYucHJvdG90eXBlPXt9ClcuZHcucHJvdG90eXBlPXt9ClcuZEgucHJv
+dG90eXBlPXt9ClcuZEkucHJvdG90eXBlPXt9ClAuZVYucHJvdG90eXBlPXsKYUM6ZnVuY3Rpb24oYSl7
+dmFyIHQscz10aGlzLmEscj1zLmxlbmd0aApmb3IodD0wO3Q8cjsrK3QpaWYoc1t0XT09PWEpcmV0dXJu
+IHQKQy5iLmsocyxhKQpDLmIuayh0aGlzLmIsbnVsbCkKcmV0dXJuIHJ9LAphaTpmdW5jdGlvbihhKXt2
+YXIgdCxzLHIscT10aGlzLHA9e30KaWYoYT09bnVsbClyZXR1cm4gYQppZihILmZkKGEpKXJldHVybiBh
+CmlmKHR5cGVvZiBhPT0ibnVtYmVyIilyZXR1cm4gYQppZih0eXBlb2YgYT09InN0cmluZyIpcmV0dXJu
+IGEKaWYoYSBpbnN0YW5jZW9mIFAuYjcpcmV0dXJuIG5ldyBEYXRlKGEuYSkKaWYodS5mdi5jKGEpKXRo
+cm93IEguYShQLmVsKCJzdHJ1Y3R1cmVkIGNsb25lIG9mIFJlZ0V4cCIpKQppZih1LmM4LmMoYSkpcmV0
+dXJuIGEKaWYodS5kLmMoYSkpcmV0dXJuIGEKaWYodS5JLmMoYSkpcmV0dXJuIGEKdD11LmRELmMoYSl8
+fCExCmlmKHQpcmV0dXJuIGEKaWYodS5HLmMoYSkpe3M9cS5hQyhhKQp0PXEuYgppZihzPj10Lmxlbmd0
+aClyZXR1cm4gSC5pKHQscykKcj1wLmE9dFtzXQppZihyIT1udWxsKXJldHVybiByCnI9e30KcC5hPXIK
+Qy5iLmwodCxzLHIpCmEuQSgwLG5ldyBQLmVYKHAscSkpCnJldHVybiBwLmF9aWYodS5qLmMoYSkpe3M9
+cS5hQyhhKQpwPXEuYgppZihzPj1wLmxlbmd0aClyZXR1cm4gSC5pKHAscykKcj1wW3NdCmlmKHIhPW51
+bGwpcmV0dXJuIHIKcmV0dXJuIHEuYzcoYSxzKX1pZih1LmVILmMoYSkpe3M9cS5hQyhhKQp0PXEuYgpp
+ZihzPj10Lmxlbmd0aClyZXR1cm4gSC5pKHQscykKcj1wLmI9dFtzXQppZihyIT1udWxsKXJldHVybiBy
+CnI9e30KcC5iPXIKQy5iLmwodCxzLHIpCnEuY2QoYSxuZXcgUC5lWShwLHEpKQpyZXR1cm4gcC5ifXRo
+cm93IEguYShQLmVsKCJzdHJ1Y3R1cmVkIGNsb25lIG9mIG90aGVyIHR5cGUiKSl9LApjNzpmdW5jdGlv
+bihhLGIpe3ZhciB0LHM9Si5hXyhhKSxyPXMuZ20oYSkscT1uZXcgQXJyYXkocikKQy5iLmwodGhpcy5i
+LGIscSkKZm9yKHQ9MDt0PHI7Kyt0KUMuYi5sKHEsdCx0aGlzLmFpKHMuaihhLHQpKSkKcmV0dXJuIHF9
+fQpQLmVYLnByb3RvdHlwZT17CiQyOmZ1bmN0aW9uKGEsYil7dGhpcy5hLmFbYV09dGhpcy5iLmFpKGIp
+fSwKJFM6Mn0KUC5lWS5wcm90b3R5cGU9ewokMjpmdW5jdGlvbihhLGIpe3RoaXMuYS5iW2FdPXRoaXMu
+Yi5haShiKX0sCiRTOjJ9ClAuZVcucHJvdG90eXBlPXsKY2Q6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIs
+cQp1LmI4LmIoYikKZm9yKHQ9T2JqZWN0LmtleXMoYSkscz10Lmxlbmd0aCxyPTA7cjxzOysrcil7cT10
+W3JdCmIuJDIocSxhW3FdKX19fQpQLmNBLnByb3RvdHlwZT17CmF5OmZ1bmN0aW9uKGEpe3ZhciB0PSQu
+ajEoKS5iCmlmKHQudGVzdChhKSlyZXR1cm4gYQp0aHJvdyBILmEoUC5mWChhLCJ2YWx1ZSIsIk5vdCBh
+IHZhbGlkIGNsYXNzIHRva2VuIikpfSwKaTpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5YKCkuVCgwLCIg
+Iil9LApnRjpmdW5jdGlvbihhKXt2YXIgdD10aGlzLlgoKQpyZXR1cm4gUC5pYyh0LHQucixILnYodCku
+ZCl9LApnbTpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5YKCkuYX0sCnc6ZnVuY3Rpb24oYSxiKXt0aGlz
+LmF5KGIpCnJldHVybiB0aGlzLlgoKS53KDAsYil9LAprOmZ1bmN0aW9uKGEsYil7dGhpcy5heShiKQpy
+ZXR1cm4gSC5oZyh0aGlzLmNqKG5ldyBQLmRUKGIpKSl9LApNOmZ1bmN0aW9uKGEsYil7dmFyIHQscwp0
+aGlzLmF5KGIpCnQ9dGhpcy5YKCkKcz10Lk0oMCxiKQp0aGlzLmFMKHQpCnJldHVybiBzfSwKY2o6ZnVu
+Y3Rpb24oYSl7dmFyIHQscwp1LmNoLmIoYSkKdD10aGlzLlgoKQpzPWEuJDEodCkKdGhpcy5hTCh0KQpy
+ZXR1cm4gc319ClAuZFQucHJvdG90eXBlPXsKJDE6ZnVuY3Rpb24oYSl7cmV0dXJuIHUuVC5iKGEpLmso
+MCx0aGlzLmEpfSwKJFM6MzB9ClAuYksucHJvdG90eXBlPXskaWJLOjF9ClAuZjcucHJvdG90eXBlPXsK
+JDE6ZnVuY3Rpb24oYSl7dmFyIHQKdS5aLmIoYSkKdD1mdW5jdGlvbihiLGMsZCl7cmV0dXJuIGZ1bmN0
+aW9uKCl7cmV0dXJuIGIoYyxkLHRoaXMsQXJyYXkucHJvdG90eXBlLnNsaWNlLmFwcGx5KGFyZ3VtZW50
+cykpfX0oUC5rVCxhLCExKQpQLmhqKHQsJC5mVigpLGEpCnJldHVybiB0fSwKJFM6NH0KUC5mOC5wcm90
+b3R5cGU9ewokMTpmdW5jdGlvbihhKXtyZXR1cm4gbmV3IHRoaXMuYShhKX0sCiRTOjR9ClAuZmcucHJv
+dG90eXBlPXsKJDE6ZnVuY3Rpb24oYSl7cmV0dXJuIG5ldyBQLmJiKGEpfSwKJFM6MzF9ClAuZmgucHJv
+dG90eXBlPXsKJDE6ZnVuY3Rpb24oYSl7cmV0dXJuIG5ldyBQLmFPKGEsdS5hbSl9LAokUzozMn0KUC5m
+aS5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXtyZXR1cm4gbmV3IFAuWShhKX0sCiRTOjMzfQpQLlku
+cHJvdG90eXBlPXsKajpmdW5jdGlvbihhLGIpe2lmKHR5cGVvZiBiIT0ic3RyaW5nIiYmdHlwZW9mIGIh
+PSJudW1iZXIiKXRocm93IEguYShQLmI0KCJwcm9wZXJ0eSBpcyBub3QgYSBTdHJpbmcgb3IgbnVtIikp
+CnJldHVybiBQLmhoKHRoaXMuYVtiXSl9LApsOmZ1bmN0aW9uKGEsYixjKXtpZih0eXBlb2YgYiE9InN0
+cmluZyImJnR5cGVvZiBiIT0ibnVtYmVyIil0aHJvdyBILmEoUC5iNCgicHJvcGVydHkgaXMgbm90IGEg
+U3RyaW5nIG9yIG51bSIpKQp0aGlzLmFbYl09UC5oaShjKX0sCkc6ZnVuY3Rpb24oYSxiKXtpZihiPT1u
+dWxsKXJldHVybiExCnJldHVybiBiIGluc3RhbmNlb2YgUC5ZJiZ0aGlzLmE9PT1iLmF9LAppOmZ1bmN0
+aW9uKGEpe3ZhciB0LHMKdHJ5e3Q9U3RyaW5nKHRoaXMuYSkKcmV0dXJuIHR9Y2F0Y2gocyl7SC5RKHMp
+CnQ9dGhpcy5iQigwKQpyZXR1cm4gdH19LApjMzpmdW5jdGlvbihhLGIpe3ZhciB0LHM9dGhpcy5hCmlm
+KGI9PW51bGwpdD1udWxsCmVsc2V7dD1ILlooYikKdD1QLmgyKG5ldyBILmE0KGIsdC5oKCJAKDEpIiku
+YihQLmx6KCkpLHQuaCgiYTQ8MSxAPiIpKSwhMCx1LnopfXJldHVybiBQLmhoKHNbYV0uYXBwbHkocyx0
+KSl9LApncTpmdW5jdGlvbihhKXtyZXR1cm4gMH19ClAuYmIucHJvdG90eXBlPXt9ClAuYU8ucHJvdG90
+eXBlPXsKYVU6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcyxzPWE8MHx8YT49dC5nbSh0KQppZihzKXRocm93
+IEguYShQLkwoYSwwLHQuZ20odCksbnVsbCxudWxsKSl9LApqOmZ1bmN0aW9uKGEsYil7aWYodHlwZW9m
+IGI9PSJudW1iZXIiJiZiPT09Qy5jLmJvKGIpKXRoaXMuYVUoSC54KGIpKQpyZXR1cm4gdGhpcy4kdGku
+ZC5iKHRoaXMuYnooMCxiKSl9LApsOmZ1bmN0aW9uKGEsYixjKXt2YXIgdAp0aGlzLiR0aS5kLmIoYykK
+dD1DLmMuYm8oYikKaWYoYj09PXQpdGhpcy5hVShiKQp0aGlzLmJBKDAsYixjKX0sCmdtOmZ1bmN0aW9u
+KGEpe3ZhciB0PXRoaXMuYS5sZW5ndGgKaWYodHlwZW9mIHQ9PT0ibnVtYmVyIiYmdD4+PjA9PT10KXJl
+dHVybiB0CnRocm93IEguYShQLmQyKCJCYWQgSnNBcnJheSBsZW5ndGgiKSl9LAokaWo6MSwKJGltOjF9
+ClAuYzUucHJvdG90eXBlPXt9ClAuYmcucHJvdG90eXBlPXskaWJnOjF9ClAuY3YucHJvdG90eXBlPXsK
+WDpmdW5jdGlvbigpe3ZhciB0LHMscixxLHA9dGhpcy5hLmdldEF0dHJpYnV0ZSgiY2xhc3MiKSxvPVAu
+Yk0odS5OKQppZihwPT1udWxsKXJldHVybiBvCmZvcih0PXAuc3BsaXQoIiAiKSxzPXQubGVuZ3RoLHI9
+MDtyPHM7KytyKXtxPUouZFIodFtyXSkKaWYocS5sZW5ndGghPT0wKW8uaygwLHEpfXJldHVybiBvfSwK
+YUw6ZnVuY3Rpb24oYSl7dGhpcy5hLnNldEF0dHJpYnV0ZSgiY2xhc3MiLGEuVCgwLCIgIikpfX0KUC5l
+LnByb3RvdHlwZT17CmdDOmZ1bmN0aW9uKGEpe3JldHVybiBuZXcgUC5jdihhKX0sCnNhZjpmdW5jdGlv
+bihhLGIpe3RoaXMuYWwoYSxiKX0sCks6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIHQscyxyLHEscCxvCmlm
+KGQ9PW51bGwpe3Q9SC5uKFtdLHUuUSkKZD1uZXcgVy5iVSh0KQpDLmIuayh0LFcuaWEobnVsbCkpCkMu
+Yi5rKHQsVy5pZSgpKQpDLmIuayh0LG5ldyBXLmRBKCkpfWM9bmV3IFcuY20oZCkKcz0nPHN2ZyB2ZXJz
+aW9uPSIxLjEiPicrSC5iKGIpKyI8L3N2Zz4iCnQ9ZG9jdW1lbnQKcj10LmJvZHkKcT0ociYmQy5wKS5j
+OChyLHMsYykKcD10LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKQpxLnRvU3RyaW5nCnQ9bmV3IFcuTyhx
+KQpvPXQuZ1kodCkKZm9yKDt0PW8uZmlyc3RDaGlsZCx0IT1udWxsOylwLmFwcGVuZENoaWxkKHQpCnJl
+dHVybiBwfSwKZ2FHOmZ1bmN0aW9uKGEpe3JldHVybiBuZXcgVy5ibihhLCJjbGljayIsITEsdS5DKX0s
+CiRpZToxfQpQLmFoLnByb3RvdHlwZT17JGlqOjEsJGltOjEsJGlXOjF9CkwuZlUucHJvdG90eXBlPXsK
+JDE6ZnVuY3Rpb24oYSl7dmFyIHQscwp1LlYuYihhKQp0PXRoaXMuYQpzPXRoaXMuYgpMLmh4KHdpbmRv
+dy5sb2NhdGlvbi5wYXRobmFtZSx0LHMsbmV3IEwuZlQodCxzKSkKTC5pTih0aGlzLmMpfSwKJFM6OX0K
+TC5mVC5wcm90b3R5cGU9ewokMDpmdW5jdGlvbigpe0wuZlEod2luZG93LmxvY2F0aW9uLnBhdGhuYW1l
+LHRoaXMuYSx0aGlzLmIpfSwKJFM6MH0KTC5mQy5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXt2YXIg
+dCxzPXRoaXMKdS5yLmIoYSkKdD1hLnN0YXR1cwppZih0PT09MjAwKXtMLmpfKEMubC5hQigwLGEucmVz
+cG9uc2VUZXh0LG51bGwpKQp0PXMuYQpMLmlQKHQscy5iKQpMLmlaKHMuYyx0KQp0PXMuZAppZih0IT1u
+dWxsKXQuJDAoKX1lbHNlIHdpbmRvdy5hbGVydCgiUmVxdWVzdCBmYWlsZWQ7IHN0YXR1cyBvZiAiK0gu
+Yih0KSl9LAokUzo1fQpMLmZELnByb3RvdHlwZT17CiQyOmZ1bmN0aW9uKGEsYil7TC5mSShhLGIpCndp
+bmRvdy5hbGVydCgiQ291bGQgbm90IGxvYWQgIitILmIodGhpcy5hKSsiOyBwcmV2aWV3IHNlcnZlciBt
+aWdodCBiZSBkaXNjb25uZWN0ZWQuIil9LAokQzoiJDIiLAokUjoyLAokUzoyfQpMLmZTLnByb3RvdHlw
+ZT17CiQxOmZ1bmN0aW9uKGEpe3ZhciB0LHM9InNlbGVjdGVkLWZpbGUiCnUuaC5iKGEpCmEudG9TdHJp
+bmcKdD1KLkUoYSkKaWYoYS5nZXRBdHRyaWJ1dGUoImRhdGEtIituZXcgVy5hQihuZXcgVy5hcChhKSku
+VigibmFtZSIpKT09dGhpcy5hLmEpdC5nQyhhKS5rKDAscykKZWxzZSB0LmdDKGEpLk0oMCxzKX0sCiRT
+OjN9CkwuZngucHJvdG90eXBlPXsKJDE6ZnVuY3Rpb24oYSl7dS5oLmIoYSkKJC5qaSgpLnRvU3RyaW5n
+CnUubS5iKCQuamcoKS5qKDAsImhsanMiKSkuYzMoImhpZ2hsaWdodEJsb2NrIixbYV0pfSwKJFM6M30K
+TC5mai5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXt2YXIgdCxzLHIscT0iY29sbGFwc2VkIgp1LlYu
+YihhKQp0PXRoaXMuYQpzPUouRSh0KQpyPXRoaXMuYgppZighcy5nQyh0KS53KDAscSkpe3MuZ0ModCku
+aygwLHEpCkouYWwocikuaygwLHEpfWVsc2V7cy5nQyh0KS5NKDAscSkKSi5hbChyKS5NKDAscSl9fSwK
+JFM6OX0KTC5mcy5wcm90b3R5cGU9ewokMDpmdW5jdGlvbigpe0wuZlEodGhpcy5hLHRoaXMuYix0aGlz
+LmMpfSwKJFM6MH0KTC5mdC5wcm90b3R5cGU9ewokMDpmdW5jdGlvbigpe0wuZlEodGhpcy5hLG51bGws
+bnVsbCl9LAokUzowfQpMLmZ1LnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3ZhciB0PXUuci5iKGEp
+LnN0YXR1cwppZih0IT09MjAwKXdpbmRvdy5hbGVydCgiUmVxdWVzdCBmYWlsZWQ7IHN0YXR1cyBvZiAi
+K0guYih0KSl9LAokUzo1fQpMLmZ2LnByb3RvdHlwZT17CiQyOmZ1bmN0aW9uKGEsYil7TC5mSShhLGIp
+CndpbmRvdy5hbGVydCgiQ291bGQgbm90IGxvYWQgIitILmIodGhpcy5hLmEpKyI7IHByZXZpZXcgc2Vy
+dmVyIG1pZ2h0IGJlIGRpc2Nvbm5lY3RlZC4iKX0sCiRDOiIkMiIsCiRSOjIsCiRTOjJ9CkwuZmwucHJv
+dG90eXBlPXsKJDE6ZnVuY3Rpb24oYSl7dmFyIHQ9Si5kUCh1LmguYihhKSkscz10LiR0aQpzLmgoIn4o
+MSkiKS5iKEwuZlAoKSkKdS5NLmIobnVsbCkKVy5hQyh0LmEsdC5iLEwuZlAoKSwhMSxzLmQpfSwKJFM6
+M30KTC5mbS5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXt2YXIgdCxzLHIKdS5oLmIoYSkKdD1KLmRQ
+KGEpCnM9dC4kdGkKcj1zLmgoIn4oMSkiKS5iKG5ldyBMLmZrKGEpKQp1Lk0uYihudWxsKQpXLmFDKHQu
+YSx0LmIsciwhMSxzLmQpfSwKJFM6M30KTC5may5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXt1LlYu
+YihhKQpMLmlOKHRoaXMuYSl9LAokUzo5fQpMLmZuLnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3Zh
+ciB0PUouZFAodS5oLmIoYSkpLHM9dC4kdGkKcy5oKCJ+KDEpIikuYihMLmlRKCkpCnUuTS5iKG51bGwp
+ClcuYUModC5hLHQuYixMLmlRKCksITEscy5kKX0sCiRTOjN9CkwuZkUucHJvdG90eXBlPXsKJDE6ZnVu
+Y3Rpb24oYSl7dmFyIHQscyxyCnUuci5iKGEpCnQ9YS5zdGF0dXMKaWYodD09PTIwMCl7cz1DLmwuYUIo
+MCxhLnJlc3BvbnNlVGV4dCxudWxsKQpyPWRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoIi5uYXYtdHJlZSIp
+CkouZFEociwiIikKTC5qMChyLHMpfWVsc2Ugd2luZG93LmFsZXJ0KCJSZXF1ZXN0IGZhaWxlZDsgc3Rh
+dHVzIG9mICIrSC5iKHQpKX0sCiRTOjV9CkwuZkYucHJvdG90eXBlPXsKJDI6ZnVuY3Rpb24oYSxiKXtM
+LmZJKGEsYikKd2luZG93LmFsZXJ0KCJDb3VsZCBub3QgbG9hZCAiK3RoaXMuYSsiOyBwcmV2aWV3IHNl
+cnZlciBtaWdodCBiZSBkaXNjb25uZWN0ZWQuIil9LAokQzoiJDIiLAokUjoyLAokUzoyfQpMLmZHLnBy
+b3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3ZhciB0CnUuci5iKGEpCnQ9YS5zdGF0dXMKaWYodD09PTIw
+MCl7TC5sSShDLmwuYUIoMCxhLnJlc3BvbnNlVGV4dCxudWxsKSkKTC5obygiLmVkaXQtcGFuZWwgLnBh
+bmVsLWNvbnRlbnQiKX1lbHNlIHdpbmRvdy5hbGVydCgiUmVxdWVzdCBmYWlsZWQ7IHN0YXR1cyBvZiAi
+K0guYih0KSl9LAokUzo1fQpMLmZILnByb3RvdHlwZT17CiQyOmZ1bmN0aW9uKGEsYil7TC5mSShhLGIp
+CndpbmRvdy5hbGVydCgiQ291bGQgbm90IGxvYWQgIitILmIodGhpcy5hKSsiOyBwcmV2aWV3IHNlcnZl
+ciBtaWdodCBiZSBkaXNjb25uZWN0ZWQuIil9LAokQzoiJDIiLAokUjoyLAokUzoyfQpMLmZLLnByb3Rv
+dHlwZT17CiQxOmZ1bmN0aW9uKGEpe3ZhciB0LHMscgp1LkEuYihhKQp0PXdpbmRvdy5sb2NhdGlvbi5w
+YXRobmFtZQpzPUwuZnIod2luZG93LmxvY2F0aW9uLmhyZWYpCnI9TC5mcSh3aW5kb3cubG9jYXRpb24u
+aHJlZikKTC5sQSgpCmlmKHQhPT0iLyImJnQhPT1KLmRSKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoIi5y
+b290IikudGV4dENvbnRlbnQpKUwuaHUodCxzLHIsbmV3IEwuZkoodCxzLHIpKQpMLmlVKCl9LAokUzo2
+fQpMLmZKLnByb3RvdHlwZT17CiQwOmZ1bmN0aW9uKCl7TC5mUSh0aGlzLmEsdGhpcy5iLHRoaXMuYyl9
+LAokUzowfQpMLmZMLnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3ZhciB0LHMscixxCnUuQS5iKGEp
+CnQ9d2luZG93LmxvY2F0aW9uLnBhdGhuYW1lCnM9TC5mcih3aW5kb3cubG9jYXRpb24uaHJlZikKcj1M
+LmZxKHdpbmRvdy5sb2NhdGlvbi5ocmVmKQppZih0Lmxlbmd0aD4xKUwuaHUodCxzLHIsbnVsbCkKZWxz
+ZXtxPXUuTgpMLmpfKFAuY08oWyJyZWdpb25zIiwiIiwibmF2Q29udGVudCIsIiJdLHEscSkpCkwuaVoo
+IiZuYnNwOyIsbnVsbCl9fSwKJFM6Nn0KTC5mTS5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXt1LkEu
+YihhKQp0aGlzLmEuYmsoTC5pUigpKX0sCiRTOjZ9CkwuZk4ucHJvdG90eXBlPXsKJDE6ZnVuY3Rpb24o
+YSl7dmFyIHQscyxyLHEscCxvLG4sbSxsLGssaj0iZml4ZWQiCnUuQS5iKGEpCnQ9ZG9jdW1lbnQKcz10
+LnF1ZXJ5U2VsZWN0b3IoIi5uYXYtcGFuZWwiKQpyPXMucXVlcnlTZWxlY3RvcigiLm5hdi1pbm5lciIp
+CnE9dC5xdWVyeVNlbGVjdG9yKCIuaW5mby1wYW5lbCIpCnA9dC5xdWVyeVNlbGVjdG9yKCIucGFuZWwt
+Y29udGFpbmVyIikKbz1DLmUuYTMocy5vZmZzZXRUb3ApCmlmKEMuZS5hMyh3aW5kb3cucGFnZVlPZmZz
+ZXQpPm8pe3Q9Si5FKHIpCmlmKCF0LmdDKHIpLncoMCxqKSl7bj1DLmUuYTMocy5vZmZzZXRXaWR0aCkt
+MTQKbT1zLnN0eWxlCmw9IiIrbisicHgiCm0ud2lkdGg9bAptPXIuc3R5bGUKbD1DLmMuaShuKzcpKyJw
+eCIKbS53aWR0aD1sCnQuZ0MocikuaygwLGopfXQ9Si5FKHApCmlmKCF0LmdDKHApLncoMCxqKSl7az1D
+LmUuYTMocS5vZmZzZXRXaWR0aCkKbT1xLnN0eWxlCmw9IiIraysicHgiCm0ud2lkdGg9bAptPXAuc3R5
+bGUKbD0iIitrKyJweCIKbS53aWR0aD1sCnQuZ0MocCkuaygwLGopfX1lbHNle3Q9Si5FKHIpCmlmKHQu
+Z0MocikudygwLGopKXttPXMuc3R5bGUKbS53aWR0aD0iIgptPXIuc3R5bGUKbS53aWR0aD0iIgp0LmdD
+KHIpLk0oMCxqKX10PUouRShwKQppZih0LmdDKHApLncoMCxqKSl7bT1xLnN0eWxlCm0ud2lkdGg9IiIK
+bT1wLnN0eWxlCm0ud2lkdGg9IiIKdC5nQyhwKS5NKDAsail9fXRoaXMuYS5iayhMLmlSKCkpfSwKJFM6
+Nn0KTC5lMC5wcm90b3R5cGU9e30KTC5jRC5wcm90b3R5cGU9ewpiazpmdW5jdGlvbihhKXt2YXIgdAp1
+Lk0uYihhKQp0PXRoaXMuYgppZih0IT1udWxsKXQuYzQoKQp0aGlzLmI9UC5rNyh0aGlzLmEsYSl9fQpM
+LmNZLnByb3RvdHlwZT17Ck46ZnVuY3Rpb24oYSxiLGMpe3JldHVybiEwfSwKVzpmdW5jdGlvbihhKXty
+ZXR1cm4hMH0sCiRpRzoxfTsoZnVuY3Rpb24gYWxpYXNlcygpe3ZhciB0PUouSS5wcm90b3R5cGUKdC5i
+dz10LmkKdC5idj10LmFoCnQ9Si5heS5wcm90b3R5cGUKdC5ieT10LmkKdD1QLmoucHJvdG90eXBlCnQu
+Yng9dC5hagp0PVAudC5wcm90b3R5cGUKdC5iQj10LmkKdD1XLnUucHJvdG90eXBlCnQuYW09dC5LCnQ9
+Vy5jZi5wcm90b3R5cGUKdC5iQz10Lk4KdD1QLlkucHJvdG90eXBlCnQuYno9dC5qCnQuYkE9dC5sfSko
+KTsoZnVuY3Rpb24gaW5zdGFsbFRlYXJPZmZzKCl7dmFyIHQ9aHVua0hlbHBlcnMuX3N0YXRpY18xLHM9
+aHVua0hlbHBlcnMuX3N0YXRpY18wLHI9aHVua0hlbHBlcnMuaW5zdGFsbEluc3RhbmNlVGVhck9mZixx
+PWh1bmtIZWxwZXJzLmluc3RhbGxTdGF0aWNUZWFyT2ZmCnQoUCwibGgiLCJrZyIsNykKdChQLCJsaSIs
+ImtoIiw3KQp0KFAsImxqIiwia2kiLDcpCnMoUCwiaUkiLCJsYyIsMSkKcihQLmMyLnByb3RvdHlwZSwi
+Z2M1IiwwLDEsbnVsbCxbIiQyIiwiJDEiXSxbImJhIiwiYjkiXSwzNCwwKQpxKFcsImxyIiw0LG51bGws
+WyIkNCJdLFsia2wiXSwxNiwwKQpxKFcsImxzIiw0LG51bGwsWyIkNCJdLFsia20iXSwxNiwwKQp0KFAs
+Imx6IiwiaGkiLDQpCnQoUCwibHkiLCJoaCIsMjgpCnQoTCwiZlAiLCJsbyIsMTUpCnQoTCwiaVEiLCJs
+cCIsMTUpCnMoTCwiaVIiLCJpVSIsMSl9KSgpOyhmdW5jdGlvbiBpbmhlcml0YW5jZSgpe3ZhciB0PWh1
+bmtIZWxwZXJzLm1peGluLHM9aHVua0hlbHBlcnMuaW5oZXJpdCxyPWh1bmtIZWxwZXJzLmluaGVyaXRN
+YW55CnMoUC50LG51bGwpCnIoUC50LFtILmgwLEouSSxKLmFGLFAuYzcsUC5qLEguYVEsUC5SLEguVixI
+LmFYLEguYmksUC5iYyxILmJ5LEguY0osSC5hSSxILmVqLFAucixILmNnLFAuQixILmU4LEguYkwsSC5j
+SyxILmFmLEguZUIsUC5kQyxQLmMyLFAuYVosUC5TLFAuZGgsUC5iWSxQLmQ0LFAuZDUsUC5hdSxQLmRH
+LFAuY2QsUC5kdSxQLmIwLFAubCxQLmNqLFAuYVcsUC5jZSxQLmEyLFAuZjQsUC5mMyxQLnosUC5iNyxQ
+LlUsUC5iOCxQLmNXLFAuYlgsUC5lQSxQLmVfLFAuYWIsUC5tLFAueSxQLnAsUC5hZyxQLmMsUC5ILFAu
+YTYsUC5jayxQLmVtLFAuZHosVy5kVSxXLmhfLFcuYl8sVy5hYyxXLmJVLFcuY2YsVy5kQSxXLmFOLFcu
+ZGwsVy5HLFcuZHksVy5jbSxQLmVWLFAuWSxQLmFoLEwuZTAsTC5jRCxMLmNZXSkKcihKLkksW0ouY0gs
+Si5iSixKLmF5LEouRixKLmJhLEouYXgsSC5DLFcucSxXLmFHLFcuZGssVy5kVixXLmJCLFcuZFcsVy5k
+LFcuZTEsVy5iSCxXLmJPLFcuZHYsVy5kSCxQLmJLXSkKcihKLmF5LFtKLmNaLEouYmssSi5hZF0pCnMo
+Si5lNyxKLkYpCnIoSi5iYSxbSi5iSSxKLmNJXSkKcyhQLmJOLFAuYzcpCnIoUC5iTixbSC5ibCxXLmFx
+LFcuT10pCnMoSC5jeSxILmJsKQpyKFAuaixbSC5iQyxILmFZXSkKcihILmJDLFtILmFlLEguYVAsUC5N
+XSkKcihILmFlLFtILmE0LFAuZHRdKQpzKEguY18sUC5SKQpzKFAuYnEsUC5iYykKcyhQLmF6LFAuYnEp
+CnMoSC5ieixQLmF6KQpzKEguYUosSC5ieSkKcihILmFJLFtILmVlLEguZlIsSC5kOCxILmZ5LEguZnos
+SC5mQSxQLmV0LFAuZXMsUC5ldSxQLmV2LFAuZl8sUC5lQyxQLmVLLFAuZUcsUC5lSCxQLmVJLFAuZUUs
+UC5lSixQLmVELFAuZU4sUC5lTyxQLmVNLFAuZUwsUC5laCxQLmVpLFAuZmYsUC5lUixQLmVRLFAuZVMs
+UC5lYSxQLmViLFAuZFgsUC5kWSxQLmVxLFAuZW4sUC5lbyxQLmVwLFAuZjEsUC5mMixQLmZhLFAuZjks
+UC5mYixQLmZjLFcuZFosVy5lMyxXLmU0LFcuZXcsVy5leCxXLmV6LFcuZWQsVy5lYyxXLmVULFcuZVUs
+Vy5lWixXLmY1LFAuZVgsUC5lWSxQLmRULFAuZjcsUC5mOCxQLmZnLFAuZmgsUC5maSxMLmZVLEwuZlQs
+TC5mQyxMLmZELEwuZlMsTC5meCxMLmZqLEwuZnMsTC5mdCxMLmZ1LEwuZnYsTC5mbCxMLmZtLEwuZmss
+TC5mbixMLmZFLEwuZkYsTC5mRyxMLmZILEwuZkssTC5mSixMLmZMLEwuZk0sTC5mTl0pCnIoUC5yLFtI
+LmNWLEguY0wsSC5kYSxILmQwLFAuYncsSC5kcCxQLmJkLFAuYTEsUC5jVSxQLmRiLFAuZDksUC5iaCxQ
+LmN6LFAuY0JdKQpyKEguZDgsW0guZDMsSC5iNl0pCnMoSC5kZyxQLmJ3KQpzKFAuYlAsUC5CKQpyKFAu
+YlAsW0guYW4sUC5kcyxXLmRpLFcuYUJdKQpzKEguYlEsSC5DKQpyKEguYlEsW0guYzksSC5jYl0pCnMo
+SC5jYSxILmM5KQpzKEguYVIsSC5jYSkKcyhILmNjLEguY2IpCnMoSC5iUixILmNjKQpyKEguYlIsW0gu
+Y1AsSC5jUSxILmNSLEguY1MsSC5jVCxILmJTLEguYVNdKQpyKEguZHAsW0guYzEsSC5jaF0pCnMoUC5j
+MCxQLmMyKQpzKFAuZHgsUC5kRykKcyhQLmM2LFAuY2QpCnMoUC5iVyxQLmNlKQpyKFAuYTIsW1AuY3cs
+UC5jRSxQLmNNXSkKcyhQLmFLLFAuZDUpCnIoUC5hSyxbUC5jeCxQLmNOLFAuZGYsUC5kZV0pCnMoUC5k
+ZCxQLmNFKQpyKFAuVSxbUC5ULFAuZl0pCnIoUC5hMSxbUC5hVSxQLmNHXSkKcyhQLmRtLFAuY2spCnIo
+Vy5xLFtXLmssVy5iRyxXLmFBLFcuYWldKQpyKFcuayxbVy51LFcuYWEsVy5hTCxXLmJtXSkKcihXLnUs
+W1cuaCxQLmVdKQpyKFcuaCxbVy5iMyxXLmN1LFcuYjUsVy5hSCxXLmNGLFcuYmUsVy5kMSxXLmJaLFcu
+ZDYsVy5kNyxXLmJqXSkKcyhXLmJBLFcuZGspCnMoVy5iOSxXLmFHKQpzKFcuYkYsVy5hTCkKcyhXLmEz
+LFcuYkcpCnIoVy5kLFtXLmE3LFcuYTVdKQpzKFcuSyxXLmE3KQpzKFcuZHcsVy5kdikKcyhXLmJULFcu
+ZHcpCnMoVy5jMyxXLmJCKQpzKFcuZEksVy5kSCkKcyhXLmM4LFcuZEkpCnMoVy5hcCxXLmRpKQpzKFAu
+Y0EsUC5iVykKcihQLmNBLFtXLmRuLFAuY3ZdKQpzKFcuYzQsUC5iWSkKcyhXLmJuLFcuYzQpCnMoVy5k
+cSxQLmQ0KQpzKFcuZEIsVy5jZikKcyhQLmVXLFAuZVYpCnIoUC5ZLFtQLmJiLFAuYzVdKQpzKFAuYU8s
+UC5jNSkKcyhQLmJnLFAuZSkKdChILmJsLEguYVgpCnQoSC5jOSxQLmwpCnQoSC5jYSxILlYpCnQoSC5j
+YixQLmwpCnQoSC5jYyxILlYpCnQoUC5jNyxQLmwpCnQoUC5jZSxQLmFXKQp0KFAuYnEsUC5jaikKdChX
+LmRrLFcuZFUpCnQoVy5kdixQLmwpCnQoVy5kdyxXLmFjKQp0KFcuZEgsUC5sKQp0KFcuZEksVy5hYykK
+dChQLmM1LFAubCl9KSgpCnZhciB2PXt0eXBlVW5pdmVyc2U6e2VDOm5ldyBNYXAoKSx0Ujp7fSxlVDp7
+fSx0UFY6e30sc0VBOltdfSxtYW5nbGVkR2xvYmFsTmFtZXM6e2Y6ImludCIsVDoiZG91YmxlIixVOiJu
+dW0iLGM6IlN0cmluZyIsejoiYm9vbCIscDoiTnVsbCIsbToiTGlzdCJ9LG1hbmdsZWROYW1lczp7fSxn
+ZXRUeXBlRnJvbU5hbWU6Z2V0R2xvYmFsRnJvbU5hbWUsbWV0YWRhdGE6W10sdHlwZXM6WyJwKCkiLCJ+
+KCkiLCJwKEAsQCkiLCJwKHUpIiwiQChAKSIsInAoYTMpIiwicChkKSIsIn4ofigpKSIsInAoYyxjKSIs
+InAoSykiLCJ6KGMpIiwicChAKSIsImMoZikiLCJjKGMpIiwieihHKSIsIn4oSykiLCJ6KHUsYyxjLGJf
+KSIsInAoYTYsQCkiLCJwKGMsQCkiLCJ+KGMsZikiLCJ+KGNbQF0pIiwiQChALGMpIiwicChjKSIsImFo
+KEAsQCkiLCJmKGYsZikiLCJAKGMpIiwicChhNSkiLCJAKGQpIiwidChAKSIsIn4oayxrKSIsInooTTxj
+PikiLCJiYihAKSIsImFPPEA+KEApIiwiWShAKSIsIn4odFthZ10pIiwieTxjLGM+KHk8YyxjPixjKSIs
+InAofigpKSIsInAoQFthZ10pIiwiUzxAPihAKSIsInooaykiLCJhaChmKSJdLGludGVyY2VwdG9yc0J5
+VGFnOm51bGwsbGVhZlRhZ3M6bnVsbH0KSC5reih2LnR5cGVVbml2ZXJzZSxKU09OLnBhcnNlKCd7ImFk
+IjoiYXkiLCJjWiI6ImF5IiwiYmsiOiJheSIsImxLIjoiZCIsImxTIjoiZCIsImxKIjoiZSIsImxUIjoi
+ZSIsIm1oIjoiYTUiLCJsTCI6ImgiLCJsViI6ImgiLCJtXyI6ImsiLCJsUiI6ImsiLCJtYyI6ImFMIiwi
+bFoiOiJLIiwibE4iOiJhNyIsImxRIjoiYWkiLCJsTSI6ImFhIiwibTAiOiJhYSIsImxYIjoiYVIiLCJs
+VyI6IkMiLCJjSCI6eyJ6IjpbXX0sImJKIjp7InAiOltdfSwiYXkiOnsiaFEiOltdLCJhYiI6W119LCJG
+Ijp7Im0iOlsiMSJdLCJqIjpbIjEiXX0sImU3Ijp7IkYiOlsiMSJdLCJtIjpbIjEiXSwiaiI6WyIxIl19
+LCJhRiI6eyJSIjpbIjEiXX0sImJhIjp7IlQiOltdLCJVIjpbXX0sImJJIjp7ImYiOltdLCJUIjpbXSwi
+VSI6W119LCJjSSI6eyJUIjpbXSwiVSI6W119LCJheCI6eyJjIjpbXSwiY1giOltdfSwiY3kiOnsiYVgi
+OlsiZiJdLCJsIjpbImYiXSwibSI6WyJmIl0sImoiOlsiZiJdLCJsLkUiOiJmIiwiYVguRSI6ImYifSwi
+YkMiOnsiaiI6WyIxIl19LCJhZSI6eyJqIjpbIjEiXX0sImFRIjp7IlIiOlsiMSJdfSwiYTQiOnsiYWUi
+OlsiMiJdLCJqIjpbIjIiXSwiYWUuRSI6IjIiLCJqLkUiOiIyIn0sImFZIjp7ImoiOlsiMSJdLCJqLkUi
+OiIxIn0sImNfIjp7IlIiOlsiMSJdfSwiYmwiOnsiYVgiOlsiMSJdLCJsIjpbIjEiXSwibSI6WyIxIl0s
+ImoiOlsiMSJdfSwiYmkiOnsiYTYiOltdfSwiYnoiOnsiYXoiOlsiMSIsIjIiXSwiYnEiOlsiMSIsIjIi
+XSwiYmMiOlsiMSIsIjIiXSwiY2oiOlsiMSIsIjIiXSwieSI6WyIxIiwiMiJdfSwiYnkiOnsieSI6WyIx
+IiwiMiJdfSwiYUoiOnsiYnkiOlsiMSIsIjIiXSwieSI6WyIxIiwiMiJdfSwiY0oiOnsiaE8iOltdfSwi
+Y1YiOnsiciI6W119LCJjTCI6eyJyIjpbXX0sImRhIjp7InIiOltdfSwiY2ciOnsiYWciOltdfSwiYUki
+OnsiYWIiOltdfSwiZDgiOnsiYWIiOltdfSwiZDMiOnsiYWIiOltdfSwiYjYiOnsiYWIiOltdfSwiZDAi
+OnsiciI6W119LCJkZyI6eyJyIjpbXX0sImFuIjp7ImhTIjpbIjEiLCIyIl0sIkIiOlsiMSIsIjIiXSwi
+eSI6WyIxIiwiMiJdLCJCLksiOiIxIiwiQi5WIjoiMiJ9LCJhUCI6eyJqIjpbIjEiXSwiai5FIjoiMSJ9
+LCJiTCI6eyJSIjpbIjEiXX0sImNLIjp7ImhaIjpbXSwiY1giOltdfSwiQyI6eyJXIjpbXX0sImJRIjp7
+IkoiOlsiQCJdLCJDIjpbXSwiVyI6W119LCJhUiI6eyJsIjpbIlQiXSwiSiI6WyJAIl0sIm0iOlsiVCJd
+LCJDIjpbXSwiViI6WyJUIl0sIlciOltdLCJqIjpbIlQiXSwibC5FIjoiVCJ9LCJiUiI6eyJsIjpbImYi
+XSwibSI6WyJmIl0sIkoiOlsiQCJdLCJDIjpbXSwiViI6WyJmIl0sIlciOltdLCJqIjpbImYiXX0sImNQ
+Ijp7ImwiOlsiZiJdLCJtIjpbImYiXSwiSiI6WyJAIl0sIkMiOltdLCJWIjpbImYiXSwiVyI6W10sImoi
+OlsiZiJdLCJsLkUiOiJmIn0sImNRIjp7ImwiOlsiZiJdLCJtIjpbImYiXSwiSiI6WyJAIl0sIkMiOltd
+LCJWIjpbImYiXSwiVyI6W10sImoiOlsiZiJdLCJsLkUiOiJmIn0sImNSIjp7ImwiOlsiZiJdLCJtIjpb
+ImYiXSwiSiI6WyJAIl0sIkMiOltdLCJWIjpbImYiXSwiVyI6W10sImoiOlsiZiJdLCJsLkUiOiJmIn0s
+ImNTIjp7ImwiOlsiZiJdLCJtIjpbImYiXSwiSiI6WyJAIl0sIkMiOltdLCJWIjpbImYiXSwiVyI6W10s
+ImoiOlsiZiJdLCJsLkUiOiJmIn0sImNUIjp7ImwiOlsiZiJdLCJtIjpbImYiXSwiSiI6WyJAIl0sIkMi
+OltdLCJWIjpbImYiXSwiVyI6W10sImoiOlsiZiJdLCJsLkUiOiJmIn0sImJTIjp7ImwiOlsiZiJdLCJt
+IjpbImYiXSwiSiI6WyJAIl0sIkMiOltdLCJWIjpbImYiXSwiVyI6W10sImoiOlsiZiJdLCJsLkUiOiJm
+In0sImFTIjp7ImFoIjpbXSwibCI6WyJmIl0sIm0iOlsiZiJdLCJKIjpbIkAiXSwiQyI6W10sIlYiOlsi
+ZiJdLCJXIjpbXSwiaiI6WyJmIl0sImwuRSI6ImYifSwiZHAiOnsiciI6W119LCJjMSI6eyJyIjpbXX0s
+ImNoIjp7InIiOltdfSwiZEMiOnsiazYiOltdfSwiYzAiOnsiYzIiOlsiMSJdfSwiUyI6eyJiRSI6WyIx
+Il19LCJhdSI6eyJyIjpbXX0sImRHIjp7Imk4IjpbXX0sImR4Ijp7Imk4IjpbXX0sImM2Ijp7ImNkIjpb
+IjEiXSwiTSI6WyIxIl0sImoiOlsiMSJdfSwiYjAiOnsiUiI6WyIxIl19LCJiTiI6eyJsIjpbIjEiXSwi
+bSI6WyIxIl0sImoiOlsiMSJdfSwiYlAiOnsiQiI6WyIxIiwiMiJdLCJ5IjpbIjEiLCIyIl19LCJCIjp7
+InkiOlsiMSIsIjIiXX0sImJjIjp7InkiOlsiMSIsIjIiXX0sImF6Ijp7ImJxIjpbIjEiLCIyIl0sImJj
+IjpbIjEiLCIyIl0sImNqIjpbIjEiLCIyIl0sInkiOlsiMSIsIjIiXX0sImJXIjp7ImFXIjpbIjEiXSwi
+TSI6WyIxIl0sImoiOlsiMSJdfSwiY2QiOnsiTSI6WyIxIl0sImoiOlsiMSJdfSwiZHMiOnsiQiI6WyJj
+IiwiQCJdLCJ5IjpbImMiLCJAIl0sIkIuSyI6ImMiLCJCLlYiOiJAIn0sImR0Ijp7ImFlIjpbImMiXSwi
+aiI6WyJjIl0sImFlLkUiOiJjIiwiai5FIjoiYyJ9LCJjdyI6eyJhMiI6WyJtPGY+IiwiYyJdLCJhMi5T
+IjoibTxmPiJ9LCJjeCI6eyJhSyI6WyJtPGY+IiwiYyJdfSwiY0UiOnsiYTIiOlsiYyIsIm08Zj4iXX0s
+ImNNIjp7ImEyIjpbInQiLCJjIl0sImEyLlMiOiJ0In0sImNOIjp7ImFLIjpbImMiLCJ0Il19LCJkZCI6
+eyJhMiI6WyJjIiwibTxmPiJdLCJhMi5TIjoiYyJ9LCJkZiI6eyJhSyI6WyJjIiwibTxmPiJdfSwiZGUi
+OnsiYUsiOlsibTxmPiIsImMiXX0sIlQiOnsiVSI6W119LCJidyI6eyJyIjpbXX0sImJkIjp7InIiOltd
+fSwiYTEiOnsiciI6W119LCJhVSI6eyJyIjpbXX0sImNHIjp7InIiOltdfSwiY1UiOnsiciI6W119LCJk
+YiI6eyJyIjpbXX0sImQ5Ijp7InIiOltdfSwiYmgiOnsiciI6W119LCJjeiI6eyJyIjpbXX0sImNXIjp7
+InIiOltdfSwiYlgiOnsiciI6W119LCJjQiI6eyJyIjpbXX0sImYiOnsiVSI6W119LCJtIjp7ImoiOlsi
+MSJdfSwiTSI6eyJqIjpbIjEiXX0sImMiOnsiY1giOltdfSwiSCI6eyJrNCI6W119LCJjayI6eyJkYyI6
+W119LCJkeiI6eyJkYyI6W119LCJkbSI6eyJkYyI6W119LCJoIjp7InUiOltdLCJrIjpbXSwicSI6W119
+LCJiMyI6eyJ1IjpbXSwiayI6W10sInEiOltdfSwiY3UiOnsidSI6W10sImsiOltdLCJxIjpbXX0sImI1
+Ijp7InUiOltdLCJrIjpbXSwicSI6W119LCJhSCI6eyJ1IjpbXSwiayI6W10sInEiOltdfSwiYWEiOnsi
+ayI6W10sInEiOltdfSwiYUwiOnsiayI6W10sInEiOltdfSwiYkIiOnsiaDUiOlsiVSJdfSwiYXEiOnsi
+bCI6WyIxIl0sIm0iOlsiMSJdLCJqIjpbIjEiXSwibC5FIjoiMSJ9LCJ1Ijp7ImsiOltdLCJxIjpbXX0s
+ImI5Ijp7ImFHIjpbXX0sImNGIjp7InUiOltdLCJrIjpbXSwicSI6W119LCJiRiI6eyJrIjpbXSwicSI6
+W119LCJhMyI6eyJxIjpbXX0sImJHIjp7InEiOltdfSwiSyI6eyJkIjpbXX0sIk8iOnsibCI6WyJrIl0s
+Im0iOlsiayJdLCJqIjpbImsiXSwibC5FIjoiayJ9LCJrIjp7InEiOltdfSwiYlQiOnsiYWMiOlsiayJd
+LCJsIjpbImsiXSwibSI6WyJrIl0sIkoiOlsiayJdLCJqIjpbImsiXSwibC5FIjoiayIsImFjLkUiOiJr
+In0sImJlIjp7InUiOltdLCJrIjpbXSwicSI6W119LCJhNSI6eyJkIjpbXX0sImQxIjp7InUiOltdLCJr
+IjpbXSwicSI6W119LCJiWiI6eyJ1IjpbXSwiayI6W10sInEiOltdfSwiZDYiOnsidSI6W10sImsiOltd
+LCJxIjpbXX0sImQ3Ijp7InUiOltdLCJrIjpbXSwicSI6W119LCJiaiI6eyJ1IjpbXSwiayI6W10sInEi
+OltdfSwiYTciOnsiZCI6W119LCJhQSI6eyJlciI6W10sInEiOltdfSwiYWkiOnsicSI6W119LCJibSI6
+eyJrIjpbXSwicSI6W119LCJjMyI6eyJoNSI6WyJVIl19LCJjOCI6eyJhYyI6WyJrIl0sImwiOlsiayJd
+LCJtIjpbImsiXSwiSiI6WyJrIl0sImoiOlsiayJdLCJsLkUiOiJrIiwiYWMuRSI6ImsifSwiZGkiOnsi
+QiI6WyJjIiwiYyJdLCJ5IjpbImMiLCJjIl19LCJhcCI6eyJCIjpbImMiLCJjIl0sInkiOlsiYyIsImMi
+XSwiQi5LIjoiYyIsIkIuViI6ImMifSwiYUIiOnsiQiI6WyJjIiwiYyJdLCJ5IjpbImMiLCJjIl0sIkIu
+SyI6ImMiLCJCLlYiOiJjIn0sImRuIjp7ImFXIjpbImMiXSwiTSI6WyJjIl0sImoiOlsiYyJdfSwiYzQi
+OnsiYlkiOlsiMSJdfSwiYm4iOnsiYzQiOlsiMSJdLCJiWSI6WyIxIl19LCJiXyI6eyJHIjpbXX0sImJV
+Ijp7IkciOltdfSwiY2YiOnsiRyI6W119LCJkQiI6eyJHIjpbXX0sImRBIjp7IkciOltdfSwiYU4iOnsi
+UiI6WyIxIl19LCJkbCI6eyJlciI6W10sInEiOltdfSwiZHkiOnsiazgiOltdfSwiY20iOnsialAiOltd
+fSwiY0EiOnsiYVciOlsiYyJdLCJNIjpbImMiXSwiaiI6WyJjIl19LCJiYiI6eyJZIjpbXX0sImFPIjp7
+ImwiOlsiMSJdLCJtIjpbIjEiXSwiWSI6W10sImoiOlsiMSJdLCJsLkUiOiIxIn0sImJnIjp7ImUiOltd
+LCJ1IjpbXSwiayI6W10sInEiOltdfSwiY3YiOnsiYVciOlsiYyJdLCJNIjpbImMiXSwiaiI6WyJjIl19
+LCJlIjp7InUiOltdLCJrIjpbXSwicSI6W119LCJhaCI6eyJtIjpbImYiXSwiVyI6W10sImoiOlsiZiJd
+fSwiY1kiOnsiRyI6W119fScpKQpILmt5KHYudHlwZVVuaXZlcnNlLEpTT04ucGFyc2UoJ3siYkMiOjEs
+ImJsIjoxLCJkNCI6MSwiZDUiOjIsImJOIjoxLCJiUCI6MiwiYlciOjEsImM3IjoxLCJjZSI6MSwiYzUi
+OjF9JykpCnZhciB1PShmdW5jdGlvbiBydGlpKCl7dmFyIHQ9SC5mcApyZXR1cm57YTp0KCJiMyIpLG46
+dCgiYXUiKSx2OnQoImI1IiksZDp0KCJhRyIpLFg6dCgiYUgiKSxEOnQoImJ6PGE2LEA+IiksaDp0KCJ1
+IiksYlU6dCgiciIpLEE6dCgiZCIpLGFTOnQoInEiKSxjODp0KCJiOSIpLFo6dCgiYWIiKSxjOnQoImJF
+PEA+Iikscjp0KCJhMyIpLEk6dCgiYkgiKSxvOnQoImhPIiksZWg6dCgiajxrPiIpLFI6dCgiajxAPiIp
+LFE6dCgiRjxHPiIpLHM6dCgiRjxjPiIpLGI6dCgiRjxAPiIpLHQ6dCgiRjxmPiIpLGVIOnQoImhRIiks
+Zzp0KCJhZCIpLGFVOnQoIko8QD4iKSxhbTp0KCJhTzxAPiIpLEI6dCgiYW48YTYsQD4iKSxtOnQoIlki
+KSx3OnQoImJLIiksajp0KCJtPEA+IiksTDp0KCJtPGY+IiksZjp0KCJ5PGMsYz4iKSxHOnQoInk8QCxA
+PiIpLGR2OnQoImE0PGMsYz4iKSxWOnQoIksiKSxkRDp0KCJDIiksYm06dCgiYVMiKSxGOnQoImsiKSxl
+OnQoIkciKSxQOnQoInAiKSxLOnQoInQiKSxnQjp0KCJiZSIpLHA6dCgiYTUiKSxxOnQoImg1PFU+Iiks
+ZnY6dCgiaFoiKSxhdjp0KCJhZiIpLGV3OnQoImJnIiksVDp0KCJNPGM+IiksbDp0KCJhZyIpLE46dCgi
+YyIpLGRHOnQoImMoYykiKSxnNzp0KCJlIiksZm86dCgiYTYiKSxhVzp0KCJiaiIpLGk6dCgiVyIpLGdj
+OnQoImFoIiksYWs6dCgiYmsiKSxXOnQoImF6PGMsYz4iKSxrOnQoImRjIiksZzQ6dCgiYUEiKSxjaTp0
+KCJlciIpLGcyOnQoImFpIiksRTp0KCJjMDxhMz4iKSxoOTp0KCJibSIpLGFjOnQoIk8iKSxDOnQoImJu
+PEs+IiksUzp0KCJhcTx1PiIpLHg6dCgiYVo8QCxAPiIpLGFvOnQoIlM8YTM+IiksXzp0KCJTPEA+Iiks
+Zko6dCgiUzxmPiIpLE86dCgiYl8iKSxKOnQoImR1IiksY0o6dCgieiIpLGFsOnQoInoodCkiKSxiZjp0
+KCJ6KEApIiksejp0KCJAIiksZk86dCgiQCgpIiksVTp0KCJAKGQpIikseTp0KCJAKHQpIiksZXA6dCgi
+QCh0LHQpIiksWTp0KCJAKHQsYWcpIiksY2g6dCgiQChNPGM+KSIpLGI4OnQoIkAoQCxAKSIpLEg6dCgi
+fiIpLE06dCgifigpIiksYW46dCgifihhNSkiKSx1OnQoIn4oYyxjKSIpLGNBOnQoIn4oYyxAKSIpfX0p
+KCk7KGZ1bmN0aW9uIGNvbnN0YW50cygpe3ZhciB0PWh1bmtIZWxwZXJzLm1ha2VDb25zdExpc3QKQy5w
+PVcuYUgucHJvdG90eXBlCkMuTj1XLmJGLnByb3RvdHlwZQpDLk89Vy5hMy5wcm90b3R5cGUKQy5QPUou
+SS5wcm90b3R5cGUKQy5iPUouRi5wcm90b3R5cGUKQy5jPUouYkkucHJvdG90eXBlCkMuUT1KLmJKLnBy
+b3RvdHlwZQpDLmU9Si5iYS5wcm90b3R5cGUKQy5hPUouYXgucHJvdG90eXBlCkMuUj1KLmFkLnByb3Rv
+dHlwZQpDLlk9Vy5iTy5wcm90b3R5cGUKQy5hXz1ILmFTLnByb3RvdHlwZQpDLkI9Si5jWi5wcm90b3R5
+cGUKQy5DPVcuYloucHJvdG90eXBlCkMubj1KLmJrLnByb3RvdHlwZQpDLm89Vy5hQS5wcm90b3R5cGUK
+Qy5hMT1uZXcgUC5jeCgpCkMuRD1uZXcgUC5jdygpCkMucT1mdW5jdGlvbiBnZXRUYWdGYWxsYmFjayhv
+KSB7CiAgdmFyIHMgPSBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwobyk7CiAgcmV0dXJuIHMu
+c3Vic3RyaW5nKDgsIHMubGVuZ3RoIC0gMSk7Cn0KQy5FPWZ1bmN0aW9uKCkgewogIHZhciB0b1N0cmlu
+Z0Z1bmN0aW9uID0gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZzsKICBmdW5jdGlvbiBnZXRUYWcobykg
+ewogICAgdmFyIHMgPSB0b1N0cmluZ0Z1bmN0aW9uLmNhbGwobyk7CiAgICByZXR1cm4gcy5zdWJzdHJp
+bmcoOCwgcy5sZW5ndGggLSAxKTsKICB9CiAgZnVuY3Rpb24gZ2V0VW5rbm93blRhZyhvYmplY3QsIHRh
+ZykgewogICAgaWYgKC9eSFRNTFtBLVpdLipFbGVtZW50JC8udGVzdCh0YWcpKSB7CiAgICAgIHZhciBu
+YW1lID0gdG9TdHJpbmdGdW5jdGlvbi5jYWxsKG9iamVjdCk7CiAgICAgIGlmIChuYW1lID09ICJbb2Jq
+ZWN0IE9iamVjdF0iKSByZXR1cm4gbnVsbDsKICAgICAgcmV0dXJuICJIVE1MRWxlbWVudCI7CiAgICB9
+CiAgfQogIGZ1bmN0aW9uIGdldFVua25vd25UYWdHZW5lcmljQnJvd3NlcihvYmplY3QsIHRhZykgewog
+ICAgaWYgKHNlbGYuSFRNTEVsZW1lbnQgJiYgb2JqZWN0IGluc3RhbmNlb2YgSFRNTEVsZW1lbnQpIHJl
+dHVybiAiSFRNTEVsZW1lbnQiOwogICAgcmV0dXJuIGdldFVua25vd25UYWcob2JqZWN0LCB0YWcpOwog
+IH0KICBmdW5jdGlvbiBwcm90b3R5cGVGb3JUYWcodGFnKSB7CiAgICBpZiAodHlwZW9mIHdpbmRvdyA9
+PSAidW5kZWZpbmVkIikgcmV0dXJuIG51bGw7CiAgICBpZiAodHlwZW9mIHdpbmRvd1t0YWddID09ICJ1
+bmRlZmluZWQiKSByZXR1cm4gbnVsbDsKICAgIHZhciBjb25zdHJ1Y3RvciA9IHdpbmRvd1t0YWddOwog
+ICAgaWYgKHR5cGVvZiBjb25zdHJ1Y3RvciAhPSAiZnVuY3Rpb24iKSByZXR1cm4gbnVsbDsKICAgIHJl
+dHVybiBjb25zdHJ1Y3Rvci5wcm90b3R5cGU7CiAgfQogIGZ1bmN0aW9uIGRpc2NyaW1pbmF0b3IodGFn
+KSB7IHJldHVybiBudWxsOyB9CiAgdmFyIGlzQnJvd3NlciA9IHR5cGVvZiBuYXZpZ2F0b3IgPT0gIm9i
+amVjdCI7CiAgcmV0dXJuIHsKICAgIGdldFRhZzogZ2V0VGFnLAogICAgZ2V0VW5rbm93blRhZzogaXNC
+cm93c2VyID8gZ2V0VW5rbm93blRhZ0dlbmVyaWNCcm93c2VyIDogZ2V0VW5rbm93blRhZywKICAgIHBy
+b3RvdHlwZUZvclRhZzogcHJvdG90eXBlRm9yVGFnLAogICAgZGlzY3JpbWluYXRvcjogZGlzY3JpbWlu
+YXRvciB9Owp9CkMuSj1mdW5jdGlvbihnZXRUYWdGYWxsYmFjaykgewogIHJldHVybiBmdW5jdGlvbiho
+b29rcykgewogICAgaWYgKHR5cGVvZiBuYXZpZ2F0b3IgIT0gIm9iamVjdCIpIHJldHVybiBob29rczsK
+ICAgIHZhciB1YSA9IG5hdmlnYXRvci51c2VyQWdlbnQ7CiAgICBpZiAodWEuaW5kZXhPZigiRHVtcFJl
+bmRlclRyZWUiKSA+PSAwKSByZXR1cm4gaG9va3M7CiAgICBpZiAodWEuaW5kZXhPZigiQ2hyb21lIikg
+Pj0gMCkgewogICAgICBmdW5jdGlvbiBjb25maXJtKHApIHsKICAgICAgICByZXR1cm4gdHlwZW9mIHdp
+bmRvdyA9PSAib2JqZWN0IiAmJiB3aW5kb3dbcF0gJiYgd2luZG93W3BdLm5hbWUgPT0gcDsKICAgICAg
+fQogICAgICBpZiAoY29uZmlybSgiV2luZG93IikgJiYgY29uZmlybSgiSFRNTEVsZW1lbnQiKSkgcmV0
+dXJuIGhvb2tzOwogICAgfQogICAgaG9va3MuZ2V0VGFnID0gZ2V0VGFnRmFsbGJhY2s7CiAgfTsKfQpD
+LkY9ZnVuY3Rpb24oaG9va3MpIHsKICBpZiAodHlwZW9mIGRhcnRFeHBlcmltZW50YWxGaXh1cEdldFRh
+ZyAhPSAiZnVuY3Rpb24iKSByZXR1cm4gaG9va3M7CiAgaG9va3MuZ2V0VGFnID0gZGFydEV4cGVyaW1l
+bnRhbEZpeHVwR2V0VGFnKGhvb2tzLmdldFRhZyk7Cn0KQy5HPWZ1bmN0aW9uKGhvb2tzKSB7CiAgdmFy
+IGdldFRhZyA9IGhvb2tzLmdldFRhZzsKICB2YXIgcHJvdG90eXBlRm9yVGFnID0gaG9va3MucHJvdG90
+eXBlRm9yVGFnOwogIGZ1bmN0aW9uIGdldFRhZ0ZpeGVkKG8pIHsKICAgIHZhciB0YWcgPSBnZXRUYWco
+byk7CiAgICBpZiAodGFnID09ICJEb2N1bWVudCIpIHsKICAgICAgaWYgKCEhby54bWxWZXJzaW9uKSBy
+ZXR1cm4gIiFEb2N1bWVudCI7CiAgICAgIHJldHVybiAiIUhUTUxEb2N1bWVudCI7CiAgICB9CiAgICBy
+ZXR1cm4gdGFnOwogIH0KICBmdW5jdGlvbiBwcm90b3R5cGVGb3JUYWdGaXhlZCh0YWcpIHsKICAgIGlm
+ICh0YWcgPT0gIkRvY3VtZW50IikgcmV0dXJuIG51bGw7CiAgICByZXR1cm4gcHJvdG90eXBlRm9yVGFn
+KHRhZyk7CiAgfQogIGhvb2tzLmdldFRhZyA9IGdldFRhZ0ZpeGVkOwogIGhvb2tzLnByb3RvdHlwZUZv
+clRhZyA9IHByb3RvdHlwZUZvclRhZ0ZpeGVkOwp9CkMuST1mdW5jdGlvbihob29rcykgewogIHZhciB1
+c2VyQWdlbnQgPSB0eXBlb2YgbmF2aWdhdG9yID09ICJvYmplY3QiID8gbmF2aWdhdG9yLnVzZXJBZ2Vu
+dCA6ICIiOwogIGlmICh1c2VyQWdlbnQuaW5kZXhPZigiRmlyZWZveCIpID09IC0xKSByZXR1cm4gaG9v
+a3M7CiAgdmFyIGdldFRhZyA9IGhvb2tzLmdldFRhZzsKICB2YXIgcXVpY2tNYXAgPSB7CiAgICAiQmVm
+b3JlVW5sb2FkRXZlbnQiOiAiRXZlbnQiLAogICAgIkRhdGFUcmFuc2ZlciI6ICJDbGlwYm9hcmQiLAog
+ICAgIkdlb0dlb2xvY2F0aW9uIjogIkdlb2xvY2F0aW9uIiwKICAgICJMb2NhdGlvbiI6ICIhTG9jYXRp
+b24iLAogICAgIldvcmtlck1lc3NhZ2VFdmVudCI6ICJNZXNzYWdlRXZlbnQiLAogICAgIlhNTERvY3Vt
+ZW50IjogIiFEb2N1bWVudCJ9OwogIGZ1bmN0aW9uIGdldFRhZ0ZpcmVmb3gobykgewogICAgdmFyIHRh
+ZyA9IGdldFRhZyhvKTsKICAgIHJldHVybiBxdWlja01hcFt0YWddIHx8IHRhZzsKICB9CiAgaG9va3Mu
+Z2V0VGFnID0gZ2V0VGFnRmlyZWZveDsKfQpDLkg9ZnVuY3Rpb24oaG9va3MpIHsKICB2YXIgdXNlckFn
+ZW50ID0gdHlwZW9mIG5hdmlnYXRvciA9PSAib2JqZWN0IiA/IG5hdmlnYXRvci51c2VyQWdlbnQgOiAi
+IjsKICBpZiAodXNlckFnZW50LmluZGV4T2YoIlRyaWRlbnQvIikgPT0gLTEpIHJldHVybiBob29rczsK
+ICB2YXIgZ2V0VGFnID0gaG9va3MuZ2V0VGFnOwogIHZhciBxdWlja01hcCA9IHsKICAgICJCZWZvcmVV
+bmxvYWRFdmVudCI6ICJFdmVudCIsCiAgICAiRGF0YVRyYW5zZmVyIjogIkNsaXBib2FyZCIsCiAgICAi
+SFRNTERERWxlbWVudCI6ICJIVE1MRWxlbWVudCIsCiAgICAiSFRNTERURWxlbWVudCI6ICJIVE1MRWxl
+bWVudCIsCiAgICAiSFRNTFBocmFzZUVsZW1lbnQiOiAiSFRNTEVsZW1lbnQiLAogICAgIlBvc2l0aW9u
+IjogIkdlb3Bvc2l0aW9uIgogIH07CiAgZnVuY3Rpb24gZ2V0VGFnSUUobykgewogICAgdmFyIHRhZyA9
+IGdldFRhZyhvKTsKICAgIHZhciBuZXdUYWcgPSBxdWlja01hcFt0YWddOwogICAgaWYgKG5ld1RhZykg
+cmV0dXJuIG5ld1RhZzsKICAgIGlmICh0YWcgPT0gIk9iamVjdCIpIHsKICAgICAgaWYgKHdpbmRvdy5E
+YXRhVmlldyAmJiAobyBpbnN0YW5jZW9mIHdpbmRvdy5EYXRhVmlldykpIHJldHVybiAiRGF0YVZpZXci
+OwogICAgfQogICAgcmV0dXJuIHRhZzsKICB9CiAgZnVuY3Rpb24gcHJvdG90eXBlRm9yVGFnSUUodGFn
+KSB7CiAgICB2YXIgY29uc3RydWN0b3IgPSB3aW5kb3dbdGFnXTsKICAgIGlmIChjb25zdHJ1Y3RvciA9
+PSBudWxsKSByZXR1cm4gbnVsbDsKICAgIHJldHVybiBjb25zdHJ1Y3Rvci5wcm90b3R5cGU7CiAgfQog
+IGhvb2tzLmdldFRhZyA9IGdldFRhZ0lFOwogIGhvb2tzLnByb3RvdHlwZUZvclRhZyA9IHByb3RvdHlw
+ZUZvclRhZ0lFOwp9CkMucj1mdW5jdGlvbihob29rcykgeyByZXR1cm4gaG9va3M7IH0KCkMubD1uZXcg
+UC5jTSgpCkMuSz1uZXcgUC5jVygpCkMuZj1uZXcgUC5kZCgpCkMuTD1uZXcgUC5kZigpCkMuZD1uZXcg
+UC5keCgpCkMuTT1uZXcgUC5iOCgwKQpDLnQ9bmV3IFAuYjgoMmU1KQpDLlM9bmV3IFAuY04obnVsbCkK
+Qy51PUgubih0KFsxMjcsMjA0Nyw2NTUzNSwxMTE0MTExXSksdS50KQpDLmg9SC5uKHQoWzAsMCwzMjc3
+NiwzMzc5MiwxLDEwMjQwLDAsMF0pLHUudCkKQy5UPUgubih0KFsiKjo6Y2xhc3MiLCIqOjpkaXIiLCIq
+OjpkcmFnZ2FibGUiLCIqOjpoaWRkZW4iLCIqOjppZCIsIio6OmluZXJ0IiwiKjo6aXRlbXByb3AiLCIq
+OjppdGVtcmVmIiwiKjo6aXRlbXNjb3BlIiwiKjo6bGFuZyIsIio6OnNwZWxsY2hlY2siLCIqOjp0aXRs
+ZSIsIio6OnRyYW5zbGF0ZSIsIkE6OmFjY2Vzc2tleSIsIkE6OmNvb3JkcyIsIkE6OmhyZWZsYW5nIiwi
+QTo6bmFtZSIsIkE6OnNoYXBlIiwiQTo6dGFiaW5kZXgiLCJBOjp0YXJnZXQiLCJBOjp0eXBlIiwiQVJF
+QTo6YWNjZXNza2V5IiwiQVJFQTo6YWx0IiwiQVJFQTo6Y29vcmRzIiwiQVJFQTo6bm9ocmVmIiwiQVJF
+QTo6c2hhcGUiLCJBUkVBOjp0YWJpbmRleCIsIkFSRUE6OnRhcmdldCIsIkFVRElPOjpjb250cm9scyIs
+IkFVRElPOjpsb29wIiwiQVVESU86Om1lZGlhZ3JvdXAiLCJBVURJTzo6bXV0ZWQiLCJBVURJTzo6cHJl
+bG9hZCIsIkJETzo6ZGlyIiwiQk9EWTo6YWxpbmsiLCJCT0RZOjpiZ2NvbG9yIiwiQk9EWTo6bGluayIs
+IkJPRFk6OnRleHQiLCJCT0RZOjp2bGluayIsIkJSOjpjbGVhciIsIkJVVFRPTjo6YWNjZXNza2V5Iiwi
+QlVUVE9OOjpkaXNhYmxlZCIsIkJVVFRPTjo6bmFtZSIsIkJVVFRPTjo6dGFiaW5kZXgiLCJCVVRUT046
+OnR5cGUiLCJCVVRUT046OnZhbHVlIiwiQ0FOVkFTOjpoZWlnaHQiLCJDQU5WQVM6OndpZHRoIiwiQ0FQ
+VElPTjo6YWxpZ24iLCJDT0w6OmFsaWduIiwiQ09MOjpjaGFyIiwiQ09MOjpjaGFyb2ZmIiwiQ09MOjpz
+cGFuIiwiQ09MOjp2YWxpZ24iLCJDT0w6OndpZHRoIiwiQ09MR1JPVVA6OmFsaWduIiwiQ09MR1JPVVA6
+OmNoYXIiLCJDT0xHUk9VUDo6Y2hhcm9mZiIsIkNPTEdST1VQOjpzcGFuIiwiQ09MR1JPVVA6OnZhbGln
+biIsIkNPTEdST1VQOjp3aWR0aCIsIkNPTU1BTkQ6OmNoZWNrZWQiLCJDT01NQU5EOjpjb21tYW5kIiwi
+Q09NTUFORDo6ZGlzYWJsZWQiLCJDT01NQU5EOjpsYWJlbCIsIkNPTU1BTkQ6OnJhZGlvZ3JvdXAiLCJD
+T01NQU5EOjp0eXBlIiwiREFUQTo6dmFsdWUiLCJERUw6OmRhdGV0aW1lIiwiREVUQUlMUzo6b3BlbiIs
+IkRJUjo6Y29tcGFjdCIsIkRJVjo6YWxpZ24iLCJETDo6Y29tcGFjdCIsIkZJRUxEU0VUOjpkaXNhYmxl
+ZCIsIkZPTlQ6OmNvbG9yIiwiRk9OVDo6ZmFjZSIsIkZPTlQ6OnNpemUiLCJGT1JNOjphY2NlcHQiLCJG
+T1JNOjphdXRvY29tcGxldGUiLCJGT1JNOjplbmN0eXBlIiwiRk9STTo6bWV0aG9kIiwiRk9STTo6bmFt
+ZSIsIkZPUk06Om5vdmFsaWRhdGUiLCJGT1JNOjp0YXJnZXQiLCJGUkFNRTo6bmFtZSIsIkgxOjphbGln
+biIsIkgyOjphbGlnbiIsIkgzOjphbGlnbiIsIkg0OjphbGlnbiIsIkg1OjphbGlnbiIsIkg2OjphbGln
+biIsIkhSOjphbGlnbiIsIkhSOjpub3NoYWRlIiwiSFI6OnNpemUiLCJIUjo6d2lkdGgiLCJIVE1MOjp2
+ZXJzaW9uIiwiSUZSQU1FOjphbGlnbiIsIklGUkFNRTo6ZnJhbWVib3JkZXIiLCJJRlJBTUU6OmhlaWdo
+dCIsIklGUkFNRTo6bWFyZ2luaGVpZ2h0IiwiSUZSQU1FOjptYXJnaW53aWR0aCIsIklGUkFNRTo6d2lk
+dGgiLCJJTUc6OmFsaWduIiwiSU1HOjphbHQiLCJJTUc6OmJvcmRlciIsIklNRzo6aGVpZ2h0IiwiSU1H
+Ojpoc3BhY2UiLCJJTUc6OmlzbWFwIiwiSU1HOjpuYW1lIiwiSU1HOjp1c2VtYXAiLCJJTUc6OnZzcGFj
+ZSIsIklNRzo6d2lkdGgiLCJJTlBVVDo6YWNjZXB0IiwiSU5QVVQ6OmFjY2Vzc2tleSIsIklOUFVUOjph
+bGlnbiIsIklOUFVUOjphbHQiLCJJTlBVVDo6YXV0b2NvbXBsZXRlIiwiSU5QVVQ6OmF1dG9mb2N1cyIs
+IklOUFVUOjpjaGVja2VkIiwiSU5QVVQ6OmRpc2FibGVkIiwiSU5QVVQ6OmlucHV0bW9kZSIsIklOUFVU
+Ojppc21hcCIsIklOUFVUOjpsaXN0IiwiSU5QVVQ6Om1heCIsIklOUFVUOjptYXhsZW5ndGgiLCJJTlBV
+VDo6bWluIiwiSU5QVVQ6Om11bHRpcGxlIiwiSU5QVVQ6Om5hbWUiLCJJTlBVVDo6cGxhY2Vob2xkZXIi
+LCJJTlBVVDo6cmVhZG9ubHkiLCJJTlBVVDo6cmVxdWlyZWQiLCJJTlBVVDo6c2l6ZSIsIklOUFVUOjpz
+dGVwIiwiSU5QVVQ6OnRhYmluZGV4IiwiSU5QVVQ6OnR5cGUiLCJJTlBVVDo6dXNlbWFwIiwiSU5QVVQ6
+OnZhbHVlIiwiSU5TOjpkYXRldGltZSIsIktFWUdFTjo6ZGlzYWJsZWQiLCJLRVlHRU46OmtleXR5cGUi
+LCJLRVlHRU46Om5hbWUiLCJMQUJFTDo6YWNjZXNza2V5IiwiTEFCRUw6OmZvciIsIkxFR0VORDo6YWNj
+ZXNza2V5IiwiTEVHRU5EOjphbGlnbiIsIkxJOjp0eXBlIiwiTEk6OnZhbHVlIiwiTElOSzo6c2l6ZXMi
+LCJNQVA6Om5hbWUiLCJNRU5VOjpjb21wYWN0IiwiTUVOVTo6bGFiZWwiLCJNRU5VOjp0eXBlIiwiTUVU
+RVI6OmhpZ2giLCJNRVRFUjo6bG93IiwiTUVURVI6Om1heCIsIk1FVEVSOjptaW4iLCJNRVRFUjo6dmFs
+dWUiLCJPQkpFQ1Q6OnR5cGVtdXN0bWF0Y2giLCJPTDo6Y29tcGFjdCIsIk9MOjpyZXZlcnNlZCIsIk9M
+OjpzdGFydCIsIk9MOjp0eXBlIiwiT1BUR1JPVVA6OmRpc2FibGVkIiwiT1BUR1JPVVA6OmxhYmVsIiwi
+T1BUSU9OOjpkaXNhYmxlZCIsIk9QVElPTjo6bGFiZWwiLCJPUFRJT046OnNlbGVjdGVkIiwiT1BUSU9O
+Ojp2YWx1ZSIsIk9VVFBVVDo6Zm9yIiwiT1VUUFVUOjpuYW1lIiwiUDo6YWxpZ24iLCJQUkU6OndpZHRo
+IiwiUFJPR1JFU1M6Om1heCIsIlBST0dSRVNTOjptaW4iLCJQUk9HUkVTUzo6dmFsdWUiLCJTRUxFQ1Q6
+OmF1dG9jb21wbGV0ZSIsIlNFTEVDVDo6ZGlzYWJsZWQiLCJTRUxFQ1Q6Om11bHRpcGxlIiwiU0VMRUNU
+OjpuYW1lIiwiU0VMRUNUOjpyZXF1aXJlZCIsIlNFTEVDVDo6c2l6ZSIsIlNFTEVDVDo6dGFiaW5kZXgi
+LCJTT1VSQ0U6OnR5cGUiLCJUQUJMRTo6YWxpZ24iLCJUQUJMRTo6Ymdjb2xvciIsIlRBQkxFOjpib3Jk
+ZXIiLCJUQUJMRTo6Y2VsbHBhZGRpbmciLCJUQUJMRTo6Y2VsbHNwYWNpbmciLCJUQUJMRTo6ZnJhbWUi
+LCJUQUJMRTo6cnVsZXMiLCJUQUJMRTo6c3VtbWFyeSIsIlRBQkxFOjp3aWR0aCIsIlRCT0RZOjphbGln
+biIsIlRCT0RZOjpjaGFyIiwiVEJPRFk6OmNoYXJvZmYiLCJUQk9EWTo6dmFsaWduIiwiVEQ6OmFiYnIi
+LCJURDo6YWxpZ24iLCJURDo6YXhpcyIsIlREOjpiZ2NvbG9yIiwiVEQ6OmNoYXIiLCJURDo6Y2hhcm9m
+ZiIsIlREOjpjb2xzcGFuIiwiVEQ6OmhlYWRlcnMiLCJURDo6aGVpZ2h0IiwiVEQ6Om5vd3JhcCIsIlRE
+Ojpyb3dzcGFuIiwiVEQ6OnNjb3BlIiwiVEQ6OnZhbGlnbiIsIlREOjp3aWR0aCIsIlRFWFRBUkVBOjph
+Y2Nlc3NrZXkiLCJURVhUQVJFQTo6YXV0b2NvbXBsZXRlIiwiVEVYVEFSRUE6OmNvbHMiLCJURVhUQVJF
+QTo6ZGlzYWJsZWQiLCJURVhUQVJFQTo6aW5wdXRtb2RlIiwiVEVYVEFSRUE6Om5hbWUiLCJURVhUQVJF
+QTo6cGxhY2Vob2xkZXIiLCJURVhUQVJFQTo6cmVhZG9ubHkiLCJURVhUQVJFQTo6cmVxdWlyZWQiLCJU
+RVhUQVJFQTo6cm93cyIsIlRFWFRBUkVBOjp0YWJpbmRleCIsIlRFWFRBUkVBOjp3cmFwIiwiVEZPT1Q6
+OmFsaWduIiwiVEZPT1Q6OmNoYXIiLCJURk9PVDo6Y2hhcm9mZiIsIlRGT09UOjp2YWxpZ24iLCJUSDo6
+YWJiciIsIlRIOjphbGlnbiIsIlRIOjpheGlzIiwiVEg6OmJnY29sb3IiLCJUSDo6Y2hhciIsIlRIOjpj
+aGFyb2ZmIiwiVEg6OmNvbHNwYW4iLCJUSDo6aGVhZGVycyIsIlRIOjpoZWlnaHQiLCJUSDo6bm93cmFw
+IiwiVEg6OnJvd3NwYW4iLCJUSDo6c2NvcGUiLCJUSDo6dmFsaWduIiwiVEg6OndpZHRoIiwiVEhFQUQ6
+OmFsaWduIiwiVEhFQUQ6OmNoYXIiLCJUSEVBRDo6Y2hhcm9mZiIsIlRIRUFEOjp2YWxpZ24iLCJUUjo6
+YWxpZ24iLCJUUjo6Ymdjb2xvciIsIlRSOjpjaGFyIiwiVFI6OmNoYXJvZmYiLCJUUjo6dmFsaWduIiwi
+VFJBQ0s6OmRlZmF1bHQiLCJUUkFDSzo6a2luZCIsIlRSQUNLOjpsYWJlbCIsIlRSQUNLOjpzcmNsYW5n
+IiwiVUw6OmNvbXBhY3QiLCJVTDo6dHlwZSIsIlZJREVPOjpjb250cm9scyIsIlZJREVPOjpoZWlnaHQi
+LCJWSURFTzo6bG9vcCIsIlZJREVPOjptZWRpYWdyb3VwIiwiVklERU86Om11dGVkIiwiVklERU86OnBy
+ZWxvYWQiLCJWSURFTzo6d2lkdGgiXSksdS5zKQpDLmk9SC5uKHQoWzAsMCw2NTQ5MCw0NTA1NSw2NTUz
+NSwzNDgxNSw2NTUzNCwxODQzMV0pLHUudCkKQy5qPUgubih0KFswLDAsMjY2MjQsMTAyMyw2NTUzNCwy
+MDQ3LDY1NTM0LDIwNDddKSx1LnQpCkMuVT1ILm4odChbIkhFQUQiLCJBUkVBIiwiQkFTRSIsIkJBU0VG
+T05UIiwiQlIiLCJDT0wiLCJDT0xHUk9VUCIsIkVNQkVEIiwiRlJBTUUiLCJGUkFNRVNFVCIsIkhSIiwi
+SU1BR0UiLCJJTUciLCJJTlBVVCIsIklTSU5ERVgiLCJMSU5LIiwiTUVUQSIsIlBBUkFNIiwiU09VUkNF
+IiwiU1RZTEUiLCJUSVRMRSIsIldCUiJdKSx1LnMpCkMudj1ILm4odChbXSksdS5zKQpDLnc9SC5uKHQo
+W10pLHUuYikKQy5XPUgubih0KFswLDAsMzI3MjIsMTIyODcsNjU1MzQsMzQ4MTUsNjU1MzQsMTg0MzFd
+KSx1LnQpCkMuaz1ILm4odChbMCwwLDI0NTc2LDEwMjMsNjU1MzQsMzQ4MTUsNjU1MzQsMTg0MzFdKSx1
+LnQpCkMueD1ILm4odChbMCwwLDMyNzU0LDExMjYzLDY1NTM0LDM0ODE1LDY1NTM0LDE4NDMxXSksdS50
+KQpDLlg9SC5uKHQoWzAsMCwzMjcyMiwxMjI4Nyw2NTUzNSwzNDgxNSw2NTUzNCwxODQzMV0pLHUudCkK
+Qy55PUgubih0KFswLDAsNjU0OTAsMTIyODcsNjU1MzUsMzQ4MTUsNjU1MzQsMTg0MzFdKSx1LnQpCkMu
+ej1ILm4odChbImJpbmQiLCJpZiIsInJlZiIsInJlcGVhdCIsInN5bnRheCJdKSx1LnMpCkMubT1ILm4o
+dChbIkE6OmhyZWYiLCJBUkVBOjpocmVmIiwiQkxPQ0tRVU9URTo6Y2l0ZSIsIkJPRFk6OmJhY2tncm91
+bmQiLCJDT01NQU5EOjppY29uIiwiREVMOjpjaXRlIiwiRk9STTo6YWN0aW9uIiwiSU1HOjpzcmMiLCJJ
+TlBVVDo6c3JjIiwiSU5TOjpjaXRlIiwiUTo6Y2l0ZSIsIlZJREVPOjpwb3N0ZXIiXSksdS5zKQpDLlo9
+bmV3IEguYUooMCx7fSxDLnYsSC5mcCgiYUo8YyxjPiIpKQpDLlY9SC5uKHQoW10pLEguZnAoIkY8YTY+
+IikpCkMuQT1uZXcgSC5hSigwLHt9LEMuVixILmZwKCJhSjxhNixAPiIpKQpDLmEwPW5ldyBILmJpKCJj
+YWxsIil9KSgpOyhmdW5jdGlvbiBzdGF0aWNGaWVsZHMoKXskLmFtPTAKJC5ieD1udWxsCiQuaEo9bnVs
+bAokLmlLPW51bGwKJC5pSD1udWxsCiQuaVQ9bnVsbAokLmZvPW51bGwKJC5mQj1udWxsCiQuaHM9bnVs
+bAokLmJzPW51bGwKJC5jbj1udWxsCiQuY289bnVsbAokLmhtPSExCiQudz1DLmQKJC5YPVtdCiQuYXc9
+bnVsbAokLmZaPW51bGwKJC5oTj1udWxsCiQuaE09bnVsbAokLmRyPVAuZTkodS5OLHUuWil9KSgpOyhm
+dW5jdGlvbiBsYXp5SW5pdGlhbGl6ZXJzKCl7dmFyIHQ9aHVua0hlbHBlcnMubGF6eQp0KCQsImxQIiwi
+ZlYiLGZ1bmN0aW9uKCl7cmV0dXJuIEguaHIoIl8kZGFydF9kYXJ0Q2xvc3VyZSIpfSkKdCgkLCJsVSIs
+Imh5IixmdW5jdGlvbigpe3JldHVybiBILmhyKCJfJGRhcnRfanMiKX0pCnQoJCwibTEiLCJqMiIsZnVu
+Y3Rpb24oKXtyZXR1cm4gSC5hbyhILmVrKHsKdG9TdHJpbmc6ZnVuY3Rpb24oKXtyZXR1cm4iJHJlY2Vp
+dmVyJCJ9fSkpfSkKdCgkLCJtMiIsImozIixmdW5jdGlvbigpe3JldHVybiBILmFvKEguZWsoeyRtZXRo
+b2QkOm51bGwsCnRvU3RyaW5nOmZ1bmN0aW9uKCl7cmV0dXJuIiRyZWNlaXZlciQifX0pKX0pCnQoJCwi
+bTMiLCJqNCIsZnVuY3Rpb24oKXtyZXR1cm4gSC5hbyhILmVrKG51bGwpKX0pCnQoJCwibTQiLCJqNSIs
+ZnVuY3Rpb24oKXtyZXR1cm4gSC5hbyhmdW5jdGlvbigpe3ZhciAkYXJndW1lbnRzRXhwciQ9JyRhcmd1
+bWVudHMkJwp0cnl7bnVsbC4kbWV0aG9kJCgkYXJndW1lbnRzRXhwciQpfWNhdGNoKHMpe3JldHVybiBz
+Lm1lc3NhZ2V9fSgpKX0pCnQoJCwibTciLCJqOCIsZnVuY3Rpb24oKXtyZXR1cm4gSC5hbyhILmVrKHZv
+aWQgMCkpfSkKdCgkLCJtOCIsImo5IixmdW5jdGlvbigpe3JldHVybiBILmFvKGZ1bmN0aW9uKCl7dmFy
+ICRhcmd1bWVudHNFeHByJD0nJGFyZ3VtZW50cyQnCnRyeXsodm9pZCAwKS4kbWV0aG9kJCgkYXJndW1l
+bnRzRXhwciQpfWNhdGNoKHMpe3JldHVybiBzLm1lc3NhZ2V9fSgpKX0pCnQoJCwibTYiLCJqNyIsZnVu
+Y3Rpb24oKXtyZXR1cm4gSC5hbyhILmkzKG51bGwpKX0pCnQoJCwibTUiLCJqNiIsZnVuY3Rpb24oKXty
+ZXR1cm4gSC5hbyhmdW5jdGlvbigpe3RyeXtudWxsLiRtZXRob2QkfWNhdGNoKHMpe3JldHVybiBzLm1l
+c3NhZ2V9fSgpKX0pCnQoJCwibWEiLCJqYiIsZnVuY3Rpb24oKXtyZXR1cm4gSC5hbyhILmkzKHZvaWQg
+MCkpfSkKdCgkLCJtOSIsImphIixmdW5jdGlvbigpe3JldHVybiBILmFvKGZ1bmN0aW9uKCl7dHJ5eyh2
+b2lkIDApLiRtZXRob2QkfWNhdGNoKHMpe3JldHVybiBzLm1lc3NhZ2V9fSgpKX0pCnQoJCwibWQiLCJo
+QSIsZnVuY3Rpb24oKXtyZXR1cm4gUC5rZigpfSkKdCgkLCJtYiIsImpjIixmdW5jdGlvbigpe3JldHVy
+biBQLmtjKCl9KQp0KCQsIm1lIiwiamQiLGZ1bmN0aW9uKCl7cmV0dXJuIEguak8oSC5rWChILm4oWy0y
+LC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0y
+LC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0xLC0yLC0yLC0y
+LC0yLC0yLDYyLC0yLDYyLC0yLDYzLDUyLDUzLDU0LDU1LDU2LDU3LDU4LDU5LDYwLDYxLC0yLC0yLC0y
+LC0xLC0yLC0yLC0yLDAsMSwyLDMsNCw1LDYsNyw4LDksMTAsMTEsMTIsMTMsMTQsMTUsMTYsMTcsMTgs
+MTksMjAsMjEsMjIsMjMsMjQsMjUsLTIsLTIsLTIsLTIsNjMsLTIsMjYsMjcsMjgsMjksMzAsMzEsMzIs
+MzMsMzQsMzUsMzYsMzcsMzgsMzksNDAsNDEsNDIsNDMsNDQsNDUsNDYsNDcsNDgsNDksNTAsNTEsLTIs
+LTIsLTIsLTIsLTJdLHUudCkpKX0pCnQoJCwibWkiLCJqZiIsZnVuY3Rpb24oKXtyZXR1cm4gUC5pXygi
+XltcXC1cXC4wLTlBLVpfYS16fl0qJCIpfSkKdCgkLCJtcyIsImpoIixmdW5jdGlvbigpe3JldHVybiBQ
+LmtXKCl9KQp0KCQsIm1nIiwiamUiLGZ1bmN0aW9uKCl7cmV0dXJuIFAuaFQoWyJBIiwiQUJCUiIsIkFD
+Uk9OWU0iLCJBRERSRVNTIiwiQVJFQSIsIkFSVElDTEUiLCJBU0lERSIsIkFVRElPIiwiQiIsIkJESSIs
+IkJETyIsIkJJRyIsIkJMT0NLUVVPVEUiLCJCUiIsIkJVVFRPTiIsIkNBTlZBUyIsIkNBUFRJT04iLCJD
+RU5URVIiLCJDSVRFIiwiQ09ERSIsIkNPTCIsIkNPTEdST1VQIiwiQ09NTUFORCIsIkRBVEEiLCJEQVRB
+TElTVCIsIkREIiwiREVMIiwiREVUQUlMUyIsIkRGTiIsIkRJUiIsIkRJViIsIkRMIiwiRFQiLCJFTSIs
+IkZJRUxEU0VUIiwiRklHQ0FQVElPTiIsIkZJR1VSRSIsIkZPTlQiLCJGT09URVIiLCJGT1JNIiwiSDEi
+LCJIMiIsIkgzIiwiSDQiLCJINSIsIkg2IiwiSEVBREVSIiwiSEdST1VQIiwiSFIiLCJJIiwiSUZSQU1F
+IiwiSU1HIiwiSU5QVVQiLCJJTlMiLCJLQkQiLCJMQUJFTCIsIkxFR0VORCIsIkxJIiwiTUFQIiwiTUFS
+SyIsIk1FTlUiLCJNRVRFUiIsIk5BViIsIk5PQlIiLCJPTCIsIk9QVEdST1VQIiwiT1BUSU9OIiwiT1VU
+UFVUIiwiUCIsIlBSRSIsIlBST0dSRVNTIiwiUSIsIlMiLCJTQU1QIiwiU0VDVElPTiIsIlNFTEVDVCIs
+IlNNQUxMIiwiU09VUkNFIiwiU1BBTiIsIlNUUklLRSIsIlNUUk9ORyIsIlNVQiIsIlNVTU1BUlkiLCJT
+VVAiLCJUQUJMRSIsIlRCT0RZIiwiVEQiLCJURVhUQVJFQSIsIlRGT09UIiwiVEgiLCJUSEVBRCIsIlRJ
+TUUiLCJUUiIsIlRSQUNLIiwiVFQiLCJVIiwiVUwiLCJWQVIiLCJWSURFTyIsIldCUiJdLHUuTil9KQp0
+KCQsImxPIiwiajEiLGZ1bmN0aW9uKCl7cmV0dXJuIFAuaV8oIl5cXFMrJCIpfSkKdCgkLCJtcSIsImpn
+IixmdW5jdGlvbigpe3JldHVybiB1Lm0uYihQLmlGKHNlbGYpKX0pCnQoJCwibWYiLCJoQiIsZnVuY3Rp
+b24oKXtyZXR1cm4gSC5ocigiXyRkYXJ0X2RhcnRPYmplY3QiKX0pCnQoJCwibXIiLCJoQyIsZnVuY3Rp
+b24oKXtyZXR1cm4gZnVuY3Rpb24gRGFydE9iamVjdChhKXt0aGlzLm89YX19KQp0KCQsIm13Iiwiamki
+LGZ1bmN0aW9uKCl7cmV0dXJuIG5ldyBMLmUwKCl9KQp0KCQsImxZIiwiaHoiLGZ1bmN0aW9uKCl7cmV0
+dXJuIG5ldyBMLmNZKCl9KX0pKCk7KGZ1bmN0aW9uIG5hdGl2ZVN1cHBvcnQoKXshZnVuY3Rpb24oKXt2
+YXIgdD1mdW5jdGlvbihhKXt2YXIgbj17fQpuW2FdPTEKcmV0dXJuIE9iamVjdC5rZXlzKGh1bmtIZWxw
+ZXJzLmNvbnZlcnRUb0Zhc3RPYmplY3QobikpWzBdfQp2LmdldElzb2xhdGVUYWc9ZnVuY3Rpb24oYSl7
+cmV0dXJuIHQoIl9fX2RhcnRfIithK3YuaXNvbGF0ZVRhZyl9CnZhciBzPSJfX19kYXJ0X2lzb2xhdGVf
+dGFnc18iCnZhciByPU9iamVjdFtzXXx8KE9iamVjdFtzXT1PYmplY3QuY3JlYXRlKG51bGwpKQp2YXIg
+cT0iX1p4WXhYIgpmb3IodmFyIHA9MDs7cCsrKXt2YXIgbz10KHErIl8iK3ArIl8iKQppZighKG8gaW4g
+cikpe3Jbb109MQp2Lmlzb2xhdGVUYWc9bwpicmVha319di5kaXNwYXRjaFByb3BlcnR5TmFtZT12Lmdl
+dElzb2xhdGVUYWcoImRpc3BhdGNoX3JlY29yZCIpfSgpCmh1bmtIZWxwZXJzLnNldE9yVXBkYXRlSW50
+ZXJjZXB0b3JzQnlUYWcoe0RPTUVycm9yOkouSSxET01JbXBsZW1lbnRhdGlvbjpKLkksTWVkaWFFcnJv
+cjpKLkksTmF2aWdhdG9yOkouSSxOYXZpZ2F0b3JDb25jdXJyZW50SGFyZHdhcmU6Si5JLE5hdmlnYXRv
+clVzZXJNZWRpYUVycm9yOkouSSxPdmVyY29uc3RyYWluZWRFcnJvcjpKLkksUG9zaXRpb25FcnJvcjpK
+LkksUmFuZ2U6Si5JLFNRTEVycm9yOkouSSxEYXRhVmlldzpILkMsQXJyYXlCdWZmZXJWaWV3OkguQyxG
+bG9hdDMyQXJyYXk6SC5hUixGbG9hdDY0QXJyYXk6SC5hUixJbnQxNkFycmF5OkguY1AsSW50MzJBcnJh
+eTpILmNRLEludDhBcnJheTpILmNSLFVpbnQxNkFycmF5OkguY1MsVWludDMyQXJyYXk6SC5jVCxVaW50
+OENsYW1wZWRBcnJheTpILmJTLENhbnZhc1BpeGVsQXJyYXk6SC5iUyxVaW50OEFycmF5OkguYVMsSFRN
+TEF1ZGlvRWxlbWVudDpXLmgsSFRNTEJSRWxlbWVudDpXLmgsSFRNTEJ1dHRvbkVsZW1lbnQ6Vy5oLEhU
+TUxDYW52YXNFbGVtZW50OlcuaCxIVE1MQ29udGVudEVsZW1lbnQ6Vy5oLEhUTUxETGlzdEVsZW1lbnQ6
+Vy5oLEhUTUxEYXRhRWxlbWVudDpXLmgsSFRNTERhdGFMaXN0RWxlbWVudDpXLmgsSFRNTERldGFpbHNF
+bGVtZW50OlcuaCxIVE1MRGlhbG9nRWxlbWVudDpXLmgsSFRNTERpdkVsZW1lbnQ6Vy5oLEhUTUxFbWJl
+ZEVsZW1lbnQ6Vy5oLEhUTUxGaWVsZFNldEVsZW1lbnQ6Vy5oLEhUTUxIUkVsZW1lbnQ6Vy5oLEhUTUxI
+ZWFkRWxlbWVudDpXLmgsSFRNTEhlYWRpbmdFbGVtZW50OlcuaCxIVE1MSHRtbEVsZW1lbnQ6Vy5oLEhU
+TUxJRnJhbWVFbGVtZW50OlcuaCxIVE1MSW1hZ2VFbGVtZW50OlcuaCxIVE1MSW5wdXRFbGVtZW50Olcu
+aCxIVE1MTElFbGVtZW50OlcuaCxIVE1MTGFiZWxFbGVtZW50OlcuaCxIVE1MTGVnZW5kRWxlbWVudDpX
+LmgsSFRNTExpbmtFbGVtZW50OlcuaCxIVE1MTWFwRWxlbWVudDpXLmgsSFRNTE1lZGlhRWxlbWVudDpX
+LmgsSFRNTE1lbnVFbGVtZW50OlcuaCxIVE1MTWV0YUVsZW1lbnQ6Vy5oLEhUTUxNZXRlckVsZW1lbnQ6
+Vy5oLEhUTUxNb2RFbGVtZW50OlcuaCxIVE1MT0xpc3RFbGVtZW50OlcuaCxIVE1MT2JqZWN0RWxlbWVu
+dDpXLmgsSFRNTE9wdEdyb3VwRWxlbWVudDpXLmgsSFRNTE9wdGlvbkVsZW1lbnQ6Vy5oLEhUTUxPdXRw
+dXRFbGVtZW50OlcuaCxIVE1MUGFyYW1FbGVtZW50OlcuaCxIVE1MUGljdHVyZUVsZW1lbnQ6Vy5oLEhU
+TUxQcmVFbGVtZW50OlcuaCxIVE1MUHJvZ3Jlc3NFbGVtZW50OlcuaCxIVE1MUXVvdGVFbGVtZW50Olcu
+aCxIVE1MU2NyaXB0RWxlbWVudDpXLmgsSFRNTFNoYWRvd0VsZW1lbnQ6Vy5oLEhUTUxTbG90RWxlbWVu
+dDpXLmgsSFRNTFNvdXJjZUVsZW1lbnQ6Vy5oLEhUTUxTcGFuRWxlbWVudDpXLmgsSFRNTFN0eWxlRWxl
+bWVudDpXLmgsSFRNTFRhYmxlQ2FwdGlvbkVsZW1lbnQ6Vy5oLEhUTUxUYWJsZUNlbGxFbGVtZW50Olcu
+aCxIVE1MVGFibGVEYXRhQ2VsbEVsZW1lbnQ6Vy5oLEhUTUxUYWJsZUhlYWRlckNlbGxFbGVtZW50Olcu
+aCxIVE1MVGFibGVDb2xFbGVtZW50OlcuaCxIVE1MVGV4dEFyZWFFbGVtZW50OlcuaCxIVE1MVGltZUVs
+ZW1lbnQ6Vy5oLEhUTUxUaXRsZUVsZW1lbnQ6Vy5oLEhUTUxUcmFja0VsZW1lbnQ6Vy5oLEhUTUxVTGlz
+dEVsZW1lbnQ6Vy5oLEhUTUxVbmtub3duRWxlbWVudDpXLmgsSFRNTFZpZGVvRWxlbWVudDpXLmgsSFRN
+TERpcmVjdG9yeUVsZW1lbnQ6Vy5oLEhUTUxGb250RWxlbWVudDpXLmgsSFRNTEZyYW1lRWxlbWVudDpX
+LmgsSFRNTEZyYW1lU2V0RWxlbWVudDpXLmgsSFRNTE1hcnF1ZWVFbGVtZW50OlcuaCxIVE1MRWxlbWVu
+dDpXLmgsSFRNTEFuY2hvckVsZW1lbnQ6Vy5iMyxIVE1MQXJlYUVsZW1lbnQ6Vy5jdSxIVE1MQmFzZUVs
+ZW1lbnQ6Vy5iNSxCbG9iOlcuYUcsSFRNTEJvZHlFbGVtZW50OlcuYUgsQ0RBVEFTZWN0aW9uOlcuYWEs
+Q2hhcmFjdGVyRGF0YTpXLmFhLENvbW1lbnQ6Vy5hYSxQcm9jZXNzaW5nSW5zdHJ1Y3Rpb246Vy5hYSxU
+ZXh0OlcuYWEsQ1NTU3R5bGVEZWNsYXJhdGlvbjpXLmJBLE1TU3R5bGVDU1NQcm9wZXJ0aWVzOlcuYkEs
+Q1NTMlByb3BlcnRpZXM6Vy5iQSxYTUxEb2N1bWVudDpXLmFMLERvY3VtZW50OlcuYUwsRE9NRXhjZXB0
+aW9uOlcuZFYsRE9NUmVjdFJlYWRPbmx5OlcuYkIsRE9NVG9rZW5MaXN0OlcuZFcsRWxlbWVudDpXLnUs
+QWJvcnRQYXltZW50RXZlbnQ6Vy5kLEFuaW1hdGlvbkV2ZW50OlcuZCxBbmltYXRpb25QbGF5YmFja0V2
+ZW50OlcuZCxBcHBsaWNhdGlvbkNhY2hlRXJyb3JFdmVudDpXLmQsQmFja2dyb3VuZEZldGNoQ2xpY2tF
+dmVudDpXLmQsQmFja2dyb3VuZEZldGNoRXZlbnQ6Vy5kLEJhY2tncm91bmRGZXRjaEZhaWxFdmVudDpX
+LmQsQmFja2dyb3VuZEZldGNoZWRFdmVudDpXLmQsQmVmb3JlSW5zdGFsbFByb21wdEV2ZW50OlcuZCxC
+ZWZvcmVVbmxvYWRFdmVudDpXLmQsQmxvYkV2ZW50OlcuZCxDYW5NYWtlUGF5bWVudEV2ZW50OlcuZCxD
+bGlwYm9hcmRFdmVudDpXLmQsQ2xvc2VFdmVudDpXLmQsQ3VzdG9tRXZlbnQ6Vy5kLERldmljZU1vdGlv
+bkV2ZW50OlcuZCxEZXZpY2VPcmllbnRhdGlvbkV2ZW50OlcuZCxFcnJvckV2ZW50OlcuZCxFeHRlbmRh
+YmxlRXZlbnQ6Vy5kLEV4dGVuZGFibGVNZXNzYWdlRXZlbnQ6Vy5kLEZldGNoRXZlbnQ6Vy5kLEZvbnRG
+YWNlU2V0TG9hZEV2ZW50OlcuZCxGb3JlaWduRmV0Y2hFdmVudDpXLmQsR2FtZXBhZEV2ZW50OlcuZCxI
+YXNoQ2hhbmdlRXZlbnQ6Vy5kLEluc3RhbGxFdmVudDpXLmQsTWVkaWFFbmNyeXB0ZWRFdmVudDpXLmQs
+TWVkaWFLZXlNZXNzYWdlRXZlbnQ6Vy5kLE1lZGlhUXVlcnlMaXN0RXZlbnQ6Vy5kLE1lZGlhU3RyZWFt
+RXZlbnQ6Vy5kLE1lZGlhU3RyZWFtVHJhY2tFdmVudDpXLmQsTWVzc2FnZUV2ZW50OlcuZCxNSURJQ29u
+bmVjdGlvbkV2ZW50OlcuZCxNSURJTWVzc2FnZUV2ZW50OlcuZCxNdXRhdGlvbkV2ZW50OlcuZCxOb3Rp
+ZmljYXRpb25FdmVudDpXLmQsUGFnZVRyYW5zaXRpb25FdmVudDpXLmQsUGF5bWVudFJlcXVlc3RFdmVu
+dDpXLmQsUGF5bWVudFJlcXVlc3RVcGRhdGVFdmVudDpXLmQsUG9wU3RhdGVFdmVudDpXLmQsUHJlc2Vu
+dGF0aW9uQ29ubmVjdGlvbkF2YWlsYWJsZUV2ZW50OlcuZCxQcmVzZW50YXRpb25Db25uZWN0aW9uQ2xv
+c2VFdmVudDpXLmQsUHJvbWlzZVJlamVjdGlvbkV2ZW50OlcuZCxQdXNoRXZlbnQ6Vy5kLFJUQ0RhdGFD
+aGFubmVsRXZlbnQ6Vy5kLFJUQ0RUTUZUb25lQ2hhbmdlRXZlbnQ6Vy5kLFJUQ1BlZXJDb25uZWN0aW9u
+SWNlRXZlbnQ6Vy5kLFJUQ1RyYWNrRXZlbnQ6Vy5kLFNlY3VyaXR5UG9saWN5VmlvbGF0aW9uRXZlbnQ6
+Vy5kLFNlbnNvckVycm9yRXZlbnQ6Vy5kLFNwZWVjaFJlY29nbml0aW9uRXJyb3I6Vy5kLFNwZWVjaFJl
+Y29nbml0aW9uRXZlbnQ6Vy5kLFNwZWVjaFN5bnRoZXNpc0V2ZW50OlcuZCxTdG9yYWdlRXZlbnQ6Vy5k
+LFN5bmNFdmVudDpXLmQsVHJhY2tFdmVudDpXLmQsVHJhbnNpdGlvbkV2ZW50OlcuZCxXZWJLaXRUcmFu
+c2l0aW9uRXZlbnQ6Vy5kLFZSRGV2aWNlRXZlbnQ6Vy5kLFZSRGlzcGxheUV2ZW50OlcuZCxWUlNlc3Np
+b25FdmVudDpXLmQsTW9qb0ludGVyZmFjZVJlcXVlc3RFdmVudDpXLmQsVVNCQ29ubmVjdGlvbkV2ZW50
+OlcuZCxJREJWZXJzaW9uQ2hhbmdlRXZlbnQ6Vy5kLEF1ZGlvUHJvY2Vzc2luZ0V2ZW50OlcuZCxPZmZs
+aW5lQXVkaW9Db21wbGV0aW9uRXZlbnQ6Vy5kLFdlYkdMQ29udGV4dEV2ZW50OlcuZCxFdmVudDpXLmQs
+SW5wdXRFdmVudDpXLmQsRXZlbnRUYXJnZXQ6Vy5xLEZpbGU6Vy5iOSxIVE1MRm9ybUVsZW1lbnQ6Vy5j
+RixIaXN0b3J5OlcuZTEsSFRNTERvY3VtZW50OlcuYkYsWE1MSHR0cFJlcXVlc3Q6Vy5hMyxYTUxIdHRw
+UmVxdWVzdEV2ZW50VGFyZ2V0OlcuYkcsSW1hZ2VEYXRhOlcuYkgsTG9jYXRpb246Vy5iTyxNb3VzZUV2
+ZW50OlcuSyxEcmFnRXZlbnQ6Vy5LLFBvaW50ZXJFdmVudDpXLkssV2hlZWxFdmVudDpXLkssRG9jdW1l
+bnRGcmFnbWVudDpXLmssU2hhZG93Um9vdDpXLmssRG9jdW1lbnRUeXBlOlcuayxOb2RlOlcuayxOb2Rl
+TGlzdDpXLmJULFJhZGlvTm9kZUxpc3Q6Vy5iVCxIVE1MUGFyYWdyYXBoRWxlbWVudDpXLmJlLFByb2dy
+ZXNzRXZlbnQ6Vy5hNSxSZXNvdXJjZVByb2dyZXNzRXZlbnQ6Vy5hNSxIVE1MU2VsZWN0RWxlbWVudDpX
+LmQxLEhUTUxUYWJsZUVsZW1lbnQ6Vy5iWixIVE1MVGFibGVSb3dFbGVtZW50OlcuZDYsSFRNTFRhYmxl
+U2VjdGlvbkVsZW1lbnQ6Vy5kNyxIVE1MVGVtcGxhdGVFbGVtZW50OlcuYmosQ29tcG9zaXRpb25FdmVu
+dDpXLmE3LEZvY3VzRXZlbnQ6Vy5hNyxLZXlib2FyZEV2ZW50OlcuYTcsVGV4dEV2ZW50OlcuYTcsVG91
+Y2hFdmVudDpXLmE3LFVJRXZlbnQ6Vy5hNyxXaW5kb3c6Vy5hQSxET01XaW5kb3c6Vy5hQSxEZWRpY2F0
+ZWRXb3JrZXJHbG9iYWxTY29wZTpXLmFpLFNlcnZpY2VXb3JrZXJHbG9iYWxTY29wZTpXLmFpLFNoYXJl
+ZFdvcmtlckdsb2JhbFNjb3BlOlcuYWksV29ya2VyR2xvYmFsU2NvcGU6Vy5haSxBdHRyOlcuYm0sQ2xp
+ZW50UmVjdDpXLmMzLERPTVJlY3Q6Vy5jMyxOYW1lZE5vZGVNYXA6Vy5jOCxNb3pOYW1lZEF0dHJNYXA6
+Vy5jOCxJREJLZXlSYW5nZTpQLmJLLFNWR1NjcmlwdEVsZW1lbnQ6UC5iZyxTVkdBRWxlbWVudDpQLmUs
+U1ZHQW5pbWF0ZUVsZW1lbnQ6UC5lLFNWR0FuaW1hdGVNb3Rpb25FbGVtZW50OlAuZSxTVkdBbmltYXRl
+VHJhbnNmb3JtRWxlbWVudDpQLmUsU1ZHQW5pbWF0aW9uRWxlbWVudDpQLmUsU1ZHQ2lyY2xlRWxlbWVu
+dDpQLmUsU1ZHQ2xpcFBhdGhFbGVtZW50OlAuZSxTVkdEZWZzRWxlbWVudDpQLmUsU1ZHRGVzY0VsZW1l
+bnQ6UC5lLFNWR0Rpc2NhcmRFbGVtZW50OlAuZSxTVkdFbGxpcHNlRWxlbWVudDpQLmUsU1ZHRkVCbGVu
+ZEVsZW1lbnQ6UC5lLFNWR0ZFQ29sb3JNYXRyaXhFbGVtZW50OlAuZSxTVkdGRUNvbXBvbmVudFRyYW5z
+ZmVyRWxlbWVudDpQLmUsU1ZHRkVDb21wb3NpdGVFbGVtZW50OlAuZSxTVkdGRUNvbnZvbHZlTWF0cml4
+RWxlbWVudDpQLmUsU1ZHRkVEaWZmdXNlTGlnaHRpbmdFbGVtZW50OlAuZSxTVkdGRURpc3BsYWNlbWVu
+dE1hcEVsZW1lbnQ6UC5lLFNWR0ZFRGlzdGFudExpZ2h0RWxlbWVudDpQLmUsU1ZHRkVGbG9vZEVsZW1l
+bnQ6UC5lLFNWR0ZFRnVuY0FFbGVtZW50OlAuZSxTVkdGRUZ1bmNCRWxlbWVudDpQLmUsU1ZHRkVGdW5j
+R0VsZW1lbnQ6UC5lLFNWR0ZFRnVuY1JFbGVtZW50OlAuZSxTVkdGRUdhdXNzaWFuQmx1ckVsZW1lbnQ6
+UC5lLFNWR0ZFSW1hZ2VFbGVtZW50OlAuZSxTVkdGRU1lcmdlRWxlbWVudDpQLmUsU1ZHRkVNZXJnZU5v
+ZGVFbGVtZW50OlAuZSxTVkdGRU1vcnBob2xvZ3lFbGVtZW50OlAuZSxTVkdGRU9mZnNldEVsZW1lbnQ6
+UC5lLFNWR0ZFUG9pbnRMaWdodEVsZW1lbnQ6UC5lLFNWR0ZFU3BlY3VsYXJMaWdodGluZ0VsZW1lbnQ6
+UC5lLFNWR0ZFU3BvdExpZ2h0RWxlbWVudDpQLmUsU1ZHRkVUaWxlRWxlbWVudDpQLmUsU1ZHRkVUdXJi
+dWxlbmNlRWxlbWVudDpQLmUsU1ZHRmlsdGVyRWxlbWVudDpQLmUsU1ZHRm9yZWlnbk9iamVjdEVsZW1l
+bnQ6UC5lLFNWR0dFbGVtZW50OlAuZSxTVkdHZW9tZXRyeUVsZW1lbnQ6UC5lLFNWR0dyYXBoaWNzRWxl
+bWVudDpQLmUsU1ZHSW1hZ2VFbGVtZW50OlAuZSxTVkdMaW5lRWxlbWVudDpQLmUsU1ZHTGluZWFyR3Jh
+ZGllbnRFbGVtZW50OlAuZSxTVkdNYXJrZXJFbGVtZW50OlAuZSxTVkdNYXNrRWxlbWVudDpQLmUsU1ZH
+TWV0YWRhdGFFbGVtZW50OlAuZSxTVkdQYXRoRWxlbWVudDpQLmUsU1ZHUGF0dGVybkVsZW1lbnQ6UC5l
+LFNWR1BvbHlnb25FbGVtZW50OlAuZSxTVkdQb2x5bGluZUVsZW1lbnQ6UC5lLFNWR1JhZGlhbEdyYWRp
+ZW50RWxlbWVudDpQLmUsU1ZHUmVjdEVsZW1lbnQ6UC5lLFNWR1NldEVsZW1lbnQ6UC5lLFNWR1N0b3BF
+bGVtZW50OlAuZSxTVkdTdHlsZUVsZW1lbnQ6UC5lLFNWR1NWR0VsZW1lbnQ6UC5lLFNWR1N3aXRjaEVs
+ZW1lbnQ6UC5lLFNWR1N5bWJvbEVsZW1lbnQ6UC5lLFNWR1RTcGFuRWxlbWVudDpQLmUsU1ZHVGV4dENv
+bnRlbnRFbGVtZW50OlAuZSxTVkdUZXh0RWxlbWVudDpQLmUsU1ZHVGV4dFBhdGhFbGVtZW50OlAuZSxT
+VkdUZXh0UG9zaXRpb25pbmdFbGVtZW50OlAuZSxTVkdUaXRsZUVsZW1lbnQ6UC5lLFNWR1VzZUVsZW1l
+bnQ6UC5lLFNWR1ZpZXdFbGVtZW50OlAuZSxTVkdHcmFkaWVudEVsZW1lbnQ6UC5lLFNWR0NvbXBvbmVu
+dFRyYW5zZmVyRnVuY3Rpb25FbGVtZW50OlAuZSxTVkdGRURyb3BTaGFkb3dFbGVtZW50OlAuZSxTVkdN
+UGF0aEVsZW1lbnQ6UC5lLFNWR0VsZW1lbnQ6UC5lfSkKaHVua0hlbHBlcnMuc2V0T3JVcGRhdGVMZWFm
+VGFncyh7RE9NRXJyb3I6dHJ1ZSxET01JbXBsZW1lbnRhdGlvbjp0cnVlLE1lZGlhRXJyb3I6dHJ1ZSxO
+YXZpZ2F0b3I6dHJ1ZSxOYXZpZ2F0b3JDb25jdXJyZW50SGFyZHdhcmU6dHJ1ZSxOYXZpZ2F0b3JVc2Vy
+TWVkaWFFcnJvcjp0cnVlLE92ZXJjb25zdHJhaW5lZEVycm9yOnRydWUsUG9zaXRpb25FcnJvcjp0cnVl
+LFJhbmdlOnRydWUsU1FMRXJyb3I6dHJ1ZSxEYXRhVmlldzp0cnVlLEFycmF5QnVmZmVyVmlldzpmYWxz
+ZSxGbG9hdDMyQXJyYXk6dHJ1ZSxGbG9hdDY0QXJyYXk6dHJ1ZSxJbnQxNkFycmF5OnRydWUsSW50MzJB
+cnJheTp0cnVlLEludDhBcnJheTp0cnVlLFVpbnQxNkFycmF5OnRydWUsVWludDMyQXJyYXk6dHJ1ZSxV
+aW50OENsYW1wZWRBcnJheTp0cnVlLENhbnZhc1BpeGVsQXJyYXk6dHJ1ZSxVaW50OEFycmF5OmZhbHNl
+LEhUTUxBdWRpb0VsZW1lbnQ6dHJ1ZSxIVE1MQlJFbGVtZW50OnRydWUsSFRNTEJ1dHRvbkVsZW1lbnQ6
+dHJ1ZSxIVE1MQ2FudmFzRWxlbWVudDp0cnVlLEhUTUxDb250ZW50RWxlbWVudDp0cnVlLEhUTUxETGlz
+dEVsZW1lbnQ6dHJ1ZSxIVE1MRGF0YUVsZW1lbnQ6dHJ1ZSxIVE1MRGF0YUxpc3RFbGVtZW50OnRydWUs
+SFRNTERldGFpbHNFbGVtZW50OnRydWUsSFRNTERpYWxvZ0VsZW1lbnQ6dHJ1ZSxIVE1MRGl2RWxlbWVu
+dDp0cnVlLEhUTUxFbWJlZEVsZW1lbnQ6dHJ1ZSxIVE1MRmllbGRTZXRFbGVtZW50OnRydWUsSFRNTEhS
+RWxlbWVudDp0cnVlLEhUTUxIZWFkRWxlbWVudDp0cnVlLEhUTUxIZWFkaW5nRWxlbWVudDp0cnVlLEhU
+TUxIdG1sRWxlbWVudDp0cnVlLEhUTUxJRnJhbWVFbGVtZW50OnRydWUsSFRNTEltYWdlRWxlbWVudDp0
+cnVlLEhUTUxJbnB1dEVsZW1lbnQ6dHJ1ZSxIVE1MTElFbGVtZW50OnRydWUsSFRNTExhYmVsRWxlbWVu
+dDp0cnVlLEhUTUxMZWdlbmRFbGVtZW50OnRydWUsSFRNTExpbmtFbGVtZW50OnRydWUsSFRNTE1hcEVs
+ZW1lbnQ6dHJ1ZSxIVE1MTWVkaWFFbGVtZW50OnRydWUsSFRNTE1lbnVFbGVtZW50OnRydWUsSFRNTE1l
+dGFFbGVtZW50OnRydWUsSFRNTE1ldGVyRWxlbWVudDp0cnVlLEhUTUxNb2RFbGVtZW50OnRydWUsSFRN
+TE9MaXN0RWxlbWVudDp0cnVlLEhUTUxPYmplY3RFbGVtZW50OnRydWUsSFRNTE9wdEdyb3VwRWxlbWVu
+dDp0cnVlLEhUTUxPcHRpb25FbGVtZW50OnRydWUsSFRNTE91dHB1dEVsZW1lbnQ6dHJ1ZSxIVE1MUGFy
+YW1FbGVtZW50OnRydWUsSFRNTFBpY3R1cmVFbGVtZW50OnRydWUsSFRNTFByZUVsZW1lbnQ6dHJ1ZSxI
+VE1MUHJvZ3Jlc3NFbGVtZW50OnRydWUsSFRNTFF1b3RlRWxlbWVudDp0cnVlLEhUTUxTY3JpcHRFbGVt
+ZW50OnRydWUsSFRNTFNoYWRvd0VsZW1lbnQ6dHJ1ZSxIVE1MU2xvdEVsZW1lbnQ6dHJ1ZSxIVE1MU291
+cmNlRWxlbWVudDp0cnVlLEhUTUxTcGFuRWxlbWVudDp0cnVlLEhUTUxTdHlsZUVsZW1lbnQ6dHJ1ZSxI
+VE1MVGFibGVDYXB0aW9uRWxlbWVudDp0cnVlLEhUTUxUYWJsZUNlbGxFbGVtZW50OnRydWUsSFRNTFRh
+YmxlRGF0YUNlbGxFbGVtZW50OnRydWUsSFRNTFRhYmxlSGVhZGVyQ2VsbEVsZW1lbnQ6dHJ1ZSxIVE1M
+VGFibGVDb2xFbGVtZW50OnRydWUsSFRNTFRleHRBcmVhRWxlbWVudDp0cnVlLEhUTUxUaW1lRWxlbWVu
+dDp0cnVlLEhUTUxUaXRsZUVsZW1lbnQ6dHJ1ZSxIVE1MVHJhY2tFbGVtZW50OnRydWUsSFRNTFVMaXN0
+RWxlbWVudDp0cnVlLEhUTUxVbmtub3duRWxlbWVudDp0cnVlLEhUTUxWaWRlb0VsZW1lbnQ6dHJ1ZSxI
+VE1MRGlyZWN0b3J5RWxlbWVudDp0cnVlLEhUTUxGb250RWxlbWVudDp0cnVlLEhUTUxGcmFtZUVsZW1l
+bnQ6dHJ1ZSxIVE1MRnJhbWVTZXRFbGVtZW50OnRydWUsSFRNTE1hcnF1ZWVFbGVtZW50OnRydWUsSFRN
+TEVsZW1lbnQ6ZmFsc2UsSFRNTEFuY2hvckVsZW1lbnQ6dHJ1ZSxIVE1MQXJlYUVsZW1lbnQ6dHJ1ZSxI
+VE1MQmFzZUVsZW1lbnQ6dHJ1ZSxCbG9iOmZhbHNlLEhUTUxCb2R5RWxlbWVudDp0cnVlLENEQVRBU2Vj
+dGlvbjp0cnVlLENoYXJhY3RlckRhdGE6dHJ1ZSxDb21tZW50OnRydWUsUHJvY2Vzc2luZ0luc3RydWN0
+aW9uOnRydWUsVGV4dDp0cnVlLENTU1N0eWxlRGVjbGFyYXRpb246dHJ1ZSxNU1N0eWxlQ1NTUHJvcGVy
+dGllczp0cnVlLENTUzJQcm9wZXJ0aWVzOnRydWUsWE1MRG9jdW1lbnQ6dHJ1ZSxEb2N1bWVudDpmYWxz
+ZSxET01FeGNlcHRpb246dHJ1ZSxET01SZWN0UmVhZE9ubHk6ZmFsc2UsRE9NVG9rZW5MaXN0OnRydWUs
+RWxlbWVudDpmYWxzZSxBYm9ydFBheW1lbnRFdmVudDp0cnVlLEFuaW1hdGlvbkV2ZW50OnRydWUsQW5p
+bWF0aW9uUGxheWJhY2tFdmVudDp0cnVlLEFwcGxpY2F0aW9uQ2FjaGVFcnJvckV2ZW50OnRydWUsQmFj
+a2dyb3VuZEZldGNoQ2xpY2tFdmVudDp0cnVlLEJhY2tncm91bmRGZXRjaEV2ZW50OnRydWUsQmFja2dy
+b3VuZEZldGNoRmFpbEV2ZW50OnRydWUsQmFja2dyb3VuZEZldGNoZWRFdmVudDp0cnVlLEJlZm9yZUlu
+c3RhbGxQcm9tcHRFdmVudDp0cnVlLEJlZm9yZVVubG9hZEV2ZW50OnRydWUsQmxvYkV2ZW50OnRydWUs
+Q2FuTWFrZVBheW1lbnRFdmVudDp0cnVlLENsaXBib2FyZEV2ZW50OnRydWUsQ2xvc2VFdmVudDp0cnVl
+LEN1c3RvbUV2ZW50OnRydWUsRGV2aWNlTW90aW9uRXZlbnQ6dHJ1ZSxEZXZpY2VPcmllbnRhdGlvbkV2
+ZW50OnRydWUsRXJyb3JFdmVudDp0cnVlLEV4dGVuZGFibGVFdmVudDp0cnVlLEV4dGVuZGFibGVNZXNz
+YWdlRXZlbnQ6dHJ1ZSxGZXRjaEV2ZW50OnRydWUsRm9udEZhY2VTZXRMb2FkRXZlbnQ6dHJ1ZSxGb3Jl
+aWduRmV0Y2hFdmVudDp0cnVlLEdhbWVwYWRFdmVudDp0cnVlLEhhc2hDaGFuZ2VFdmVudDp0cnVlLElu
+c3RhbGxFdmVudDp0cnVlLE1lZGlhRW5jcnlwdGVkRXZlbnQ6dHJ1ZSxNZWRpYUtleU1lc3NhZ2VFdmVu
+dDp0cnVlLE1lZGlhUXVlcnlMaXN0RXZlbnQ6dHJ1ZSxNZWRpYVN0cmVhbUV2ZW50OnRydWUsTWVkaWFT
+dHJlYW1UcmFja0V2ZW50OnRydWUsTWVzc2FnZUV2ZW50OnRydWUsTUlESUNvbm5lY3Rpb25FdmVudDp0
+cnVlLE1JRElNZXNzYWdlRXZlbnQ6dHJ1ZSxNdXRhdGlvbkV2ZW50OnRydWUsTm90aWZpY2F0aW9uRXZl
+bnQ6dHJ1ZSxQYWdlVHJhbnNpdGlvbkV2ZW50OnRydWUsUGF5bWVudFJlcXVlc3RFdmVudDp0cnVlLFBh
+eW1lbnRSZXF1ZXN0VXBkYXRlRXZlbnQ6dHJ1ZSxQb3BTdGF0ZUV2ZW50OnRydWUsUHJlc2VudGF0aW9u
+Q29ubmVjdGlvbkF2YWlsYWJsZUV2ZW50OnRydWUsUHJlc2VudGF0aW9uQ29ubmVjdGlvbkNsb3NlRXZl
+bnQ6dHJ1ZSxQcm9taXNlUmVqZWN0aW9uRXZlbnQ6dHJ1ZSxQdXNoRXZlbnQ6dHJ1ZSxSVENEYXRhQ2hh
+bm5lbEV2ZW50OnRydWUsUlRDRFRNRlRvbmVDaGFuZ2VFdmVudDp0cnVlLFJUQ1BlZXJDb25uZWN0aW9u
+SWNlRXZlbnQ6dHJ1ZSxSVENUcmFja0V2ZW50OnRydWUsU2VjdXJpdHlQb2xpY3lWaW9sYXRpb25FdmVu
+dDp0cnVlLFNlbnNvckVycm9yRXZlbnQ6dHJ1ZSxTcGVlY2hSZWNvZ25pdGlvbkVycm9yOnRydWUsU3Bl
+ZWNoUmVjb2duaXRpb25FdmVudDp0cnVlLFNwZWVjaFN5bnRoZXNpc0V2ZW50OnRydWUsU3RvcmFnZUV2
+ZW50OnRydWUsU3luY0V2ZW50OnRydWUsVHJhY2tFdmVudDp0cnVlLFRyYW5zaXRpb25FdmVudDp0cnVl
+LFdlYktpdFRyYW5zaXRpb25FdmVudDp0cnVlLFZSRGV2aWNlRXZlbnQ6dHJ1ZSxWUkRpc3BsYXlFdmVu
+dDp0cnVlLFZSU2Vzc2lvbkV2ZW50OnRydWUsTW9qb0ludGVyZmFjZVJlcXVlc3RFdmVudDp0cnVlLFVT
+QkNvbm5lY3Rpb25FdmVudDp0cnVlLElEQlZlcnNpb25DaGFuZ2VFdmVudDp0cnVlLEF1ZGlvUHJvY2Vz
+c2luZ0V2ZW50OnRydWUsT2ZmbGluZUF1ZGlvQ29tcGxldGlvbkV2ZW50OnRydWUsV2ViR0xDb250ZXh0
+RXZlbnQ6dHJ1ZSxFdmVudDpmYWxzZSxJbnB1dEV2ZW50OmZhbHNlLEV2ZW50VGFyZ2V0OmZhbHNlLEZp
+bGU6dHJ1ZSxIVE1MRm9ybUVsZW1lbnQ6dHJ1ZSxIaXN0b3J5OnRydWUsSFRNTERvY3VtZW50OnRydWUs
+WE1MSHR0cFJlcXVlc3Q6dHJ1ZSxYTUxIdHRwUmVxdWVzdEV2ZW50VGFyZ2V0OmZhbHNlLEltYWdlRGF0
+YTp0cnVlLExvY2F0aW9uOnRydWUsTW91c2VFdmVudDp0cnVlLERyYWdFdmVudDp0cnVlLFBvaW50ZXJF
+dmVudDp0cnVlLFdoZWVsRXZlbnQ6dHJ1ZSxEb2N1bWVudEZyYWdtZW50OnRydWUsU2hhZG93Um9vdDp0
+cnVlLERvY3VtZW50VHlwZTp0cnVlLE5vZGU6ZmFsc2UsTm9kZUxpc3Q6dHJ1ZSxSYWRpb05vZGVMaXN0
+OnRydWUsSFRNTFBhcmFncmFwaEVsZW1lbnQ6dHJ1ZSxQcm9ncmVzc0V2ZW50OnRydWUsUmVzb3VyY2VQ
+cm9ncmVzc0V2ZW50OnRydWUsSFRNTFNlbGVjdEVsZW1lbnQ6dHJ1ZSxIVE1MVGFibGVFbGVtZW50OnRy
+dWUsSFRNTFRhYmxlUm93RWxlbWVudDp0cnVlLEhUTUxUYWJsZVNlY3Rpb25FbGVtZW50OnRydWUsSFRN
+TFRlbXBsYXRlRWxlbWVudDp0cnVlLENvbXBvc2l0aW9uRXZlbnQ6dHJ1ZSxGb2N1c0V2ZW50OnRydWUs
+S2V5Ym9hcmRFdmVudDp0cnVlLFRleHRFdmVudDp0cnVlLFRvdWNoRXZlbnQ6dHJ1ZSxVSUV2ZW50OmZh
+bHNlLFdpbmRvdzp0cnVlLERPTVdpbmRvdzp0cnVlLERlZGljYXRlZFdvcmtlckdsb2JhbFNjb3BlOnRy
+dWUsU2VydmljZVdvcmtlckdsb2JhbFNjb3BlOnRydWUsU2hhcmVkV29ya2VyR2xvYmFsU2NvcGU6dHJ1
+ZSxXb3JrZXJHbG9iYWxTY29wZTp0cnVlLEF0dHI6dHJ1ZSxDbGllbnRSZWN0OnRydWUsRE9NUmVjdDp0
+cnVlLE5hbWVkTm9kZU1hcDp0cnVlLE1vek5hbWVkQXR0ck1hcDp0cnVlLElEQktleVJhbmdlOnRydWUs
+U1ZHU2NyaXB0RWxlbWVudDp0cnVlLFNWR0FFbGVtZW50OnRydWUsU1ZHQW5pbWF0ZUVsZW1lbnQ6dHJ1
+ZSxTVkdBbmltYXRlTW90aW9uRWxlbWVudDp0cnVlLFNWR0FuaW1hdGVUcmFuc2Zvcm1FbGVtZW50OnRy
+dWUsU1ZHQW5pbWF0aW9uRWxlbWVudDp0cnVlLFNWR0NpcmNsZUVsZW1lbnQ6dHJ1ZSxTVkdDbGlwUGF0
+aEVsZW1lbnQ6dHJ1ZSxTVkdEZWZzRWxlbWVudDp0cnVlLFNWR0Rlc2NFbGVtZW50OnRydWUsU1ZHRGlz
+Y2FyZEVsZW1lbnQ6dHJ1ZSxTVkdFbGxpcHNlRWxlbWVudDp0cnVlLFNWR0ZFQmxlbmRFbGVtZW50OnRy
+dWUsU1ZHRkVDb2xvck1hdHJpeEVsZW1lbnQ6dHJ1ZSxTVkdGRUNvbXBvbmVudFRyYW5zZmVyRWxlbWVu
+dDp0cnVlLFNWR0ZFQ29tcG9zaXRlRWxlbWVudDp0cnVlLFNWR0ZFQ29udm9sdmVNYXRyaXhFbGVtZW50
+OnRydWUsU1ZHRkVEaWZmdXNlTGlnaHRpbmdFbGVtZW50OnRydWUsU1ZHRkVEaXNwbGFjZW1lbnRNYXBF
+bGVtZW50OnRydWUsU1ZHRkVEaXN0YW50TGlnaHRFbGVtZW50OnRydWUsU1ZHRkVGbG9vZEVsZW1lbnQ6
+dHJ1ZSxTVkdGRUZ1bmNBRWxlbWVudDp0cnVlLFNWR0ZFRnVuY0JFbGVtZW50OnRydWUsU1ZHRkVGdW5j
+R0VsZW1lbnQ6dHJ1ZSxTVkdGRUZ1bmNSRWxlbWVudDp0cnVlLFNWR0ZFR2F1c3NpYW5CbHVyRWxlbWVu
+dDp0cnVlLFNWR0ZFSW1hZ2VFbGVtZW50OnRydWUsU1ZHRkVNZXJnZUVsZW1lbnQ6dHJ1ZSxTVkdGRU1l
+cmdlTm9kZUVsZW1lbnQ6dHJ1ZSxTVkdGRU1vcnBob2xvZ3lFbGVtZW50OnRydWUsU1ZHRkVPZmZzZXRF
+bGVtZW50OnRydWUsU1ZHRkVQb2ludExpZ2h0RWxlbWVudDp0cnVlLFNWR0ZFU3BlY3VsYXJMaWdodGlu
+Z0VsZW1lbnQ6dHJ1ZSxTVkdGRVNwb3RMaWdodEVsZW1lbnQ6dHJ1ZSxTVkdGRVRpbGVFbGVtZW50OnRy
+dWUsU1ZHRkVUdXJidWxlbmNlRWxlbWVudDp0cnVlLFNWR0ZpbHRlckVsZW1lbnQ6dHJ1ZSxTVkdGb3Jl
+aWduT2JqZWN0RWxlbWVudDp0cnVlLFNWR0dFbGVtZW50OnRydWUsU1ZHR2VvbWV0cnlFbGVtZW50OnRy
+dWUsU1ZHR3JhcGhpY3NFbGVtZW50OnRydWUsU1ZHSW1hZ2VFbGVtZW50OnRydWUsU1ZHTGluZUVsZW1l
+bnQ6dHJ1ZSxTVkdMaW5lYXJHcmFkaWVudEVsZW1lbnQ6dHJ1ZSxTVkdNYXJrZXJFbGVtZW50OnRydWUs
+U1ZHTWFza0VsZW1lbnQ6dHJ1ZSxTVkdNZXRhZGF0YUVsZW1lbnQ6dHJ1ZSxTVkdQYXRoRWxlbWVudDp0
+cnVlLFNWR1BhdHRlcm5FbGVtZW50OnRydWUsU1ZHUG9seWdvbkVsZW1lbnQ6dHJ1ZSxTVkdQb2x5bGlu
+ZUVsZW1lbnQ6dHJ1ZSxTVkdSYWRpYWxHcmFkaWVudEVsZW1lbnQ6dHJ1ZSxTVkdSZWN0RWxlbWVudDp0
+cnVlLFNWR1NldEVsZW1lbnQ6dHJ1ZSxTVkdTdG9wRWxlbWVudDp0cnVlLFNWR1N0eWxlRWxlbWVudDp0
+cnVlLFNWR1NWR0VsZW1lbnQ6dHJ1ZSxTVkdTd2l0Y2hFbGVtZW50OnRydWUsU1ZHU3ltYm9sRWxlbWVu
+dDp0cnVlLFNWR1RTcGFuRWxlbWVudDp0cnVlLFNWR1RleHRDb250ZW50RWxlbWVudDp0cnVlLFNWR1Rl
+eHRFbGVtZW50OnRydWUsU1ZHVGV4dFBhdGhFbGVtZW50OnRydWUsU1ZHVGV4dFBvc2l0aW9uaW5nRWxl
+bWVudDp0cnVlLFNWR1RpdGxlRWxlbWVudDp0cnVlLFNWR1VzZUVsZW1lbnQ6dHJ1ZSxTVkdWaWV3RWxl
+bWVudDp0cnVlLFNWR0dyYWRpZW50RWxlbWVudDp0cnVlLFNWR0NvbXBvbmVudFRyYW5zZmVyRnVuY3Rp
+b25FbGVtZW50OnRydWUsU1ZHRkVEcm9wU2hhZG93RWxlbWVudDp0cnVlLFNWR01QYXRoRWxlbWVudDp0
+cnVlLFNWR0VsZW1lbnQ6ZmFsc2V9KQpILmJRLiRuYXRpdmVTdXBlcmNsYXNzVGFnPSJBcnJheUJ1ZmZl
+clZpZXciCkguYzkuJG5hdGl2ZVN1cGVyY2xhc3NUYWc9IkFycmF5QnVmZmVyVmlldyIKSC5jYS4kbmF0
+aXZlU3VwZXJjbGFzc1RhZz0iQXJyYXlCdWZmZXJWaWV3IgpILmFSLiRuYXRpdmVTdXBlcmNsYXNzVGFn
+PSJBcnJheUJ1ZmZlclZpZXciCkguY2IuJG5hdGl2ZVN1cGVyY2xhc3NUYWc9IkFycmF5QnVmZmVyVmll
+dyIKSC5jYy4kbmF0aXZlU3VwZXJjbGFzc1RhZz0iQXJyYXlCdWZmZXJWaWV3IgpILmJSLiRuYXRpdmVT
+dXBlcmNsYXNzVGFnPSJBcnJheUJ1ZmZlclZpZXcifSkoKQpjb252ZXJ0QWxsVG9GYXN0T2JqZWN0KHcp
+CmNvbnZlcnRUb0Zhc3RPYmplY3QoJCk7KGZ1bmN0aW9uKGEpe2lmKHR5cGVvZiBkb2N1bWVudD09PSJ1
+bmRlZmluZWQiKXthKG51bGwpCnJldHVybn1pZih0eXBlb2YgZG9jdW1lbnQuY3VycmVudFNjcmlwdCE9
+J3VuZGVmaW5lZCcpe2EoZG9jdW1lbnQuY3VycmVudFNjcmlwdCkKcmV0dXJufXZhciB0PWRvY3VtZW50
+LnNjcmlwdHMKZnVuY3Rpb24gb25Mb2FkKGIpe2Zvcih2YXIgcj0wO3I8dC5sZW5ndGg7KytyKXRbcl0u
+cmVtb3ZlRXZlbnRMaXN0ZW5lcigibG9hZCIsb25Mb2FkLGZhbHNlKQphKGIudGFyZ2V0KX1mb3IodmFy
+IHM9MDtzPHQubGVuZ3RoOysrcyl0W3NdLmFkZEV2ZW50TGlzdGVuZXIoImxvYWQiLG9uTG9hZCxmYWxz
+ZSl9KShmdW5jdGlvbihhKXt2LmN1cnJlbnRTY3JpcHQ9YQppZih0eXBlb2YgZGFydE1haW5SdW5uZXI9
+PT0iZnVuY3Rpb24iKWRhcnRNYWluUnVubmVyKEwuaU8sW10pCmVsc2UgTC5pTyhbXSl9KX0pKCkKLy8j
+IHNvdXJjZU1hcHBpbmdVUkw9bWlncmF0aW9uLmpzLm1hcAo=
 ''';
 
 String _migration_css;
+// migration_css md5 is 'f17223177bb502d5077cd5157c4d0b38'
 String _migration_css_base64 = '''
 LyogQ29weXJpZ2h0IChjKSAyMDE5LCB0aGUgRGFydCBwcm9qZWN0IGF1dGhvcnMuIFBsZWFzZSBzZWUg
 dGhlIEFVVEhPUlMgZmlsZSAgKi8KLyogZm9yIGRldGFpbHMuIEFsbCByaWdodHMgcmVzZXJ2ZWQuIFVz
diff --git a/pkg/analysis_server/lib/src/edit/nnbd_migration/web/migration.dart b/pkg/analysis_server/lib/src/edit/nnbd_migration/web/migration.dart
new file mode 100644
index 0000000..8d5c9f5
--- /dev/null
+++ b/pkg/analysis_server/lib/src/edit/nnbd_migration/web/migration.dart
@@ -0,0 +1,605 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:html';
+import 'dart:js';
+
+//  TODO(devoncarew): Remove this is a follow-up.
+// ignore_for_file: prefer_single_quotes
+
+// TODO(devoncarew): Fix the issue where we can't load source maps.
+
+// TODO(devoncarew): Include a favicon.
+
+String get rootPath => querySelector(".root").text.trim();
+
+int getOffset(String location) {
+  String str = Uri.parse(location).queryParameters['offset'];
+  return str == null ? null : int.tryParse(str);
+}
+
+int getLine(String location) {
+  String str = Uri.parse(location).queryParameters['line'];
+  return str == null ? null : int.tryParse(str);
+}
+
+/// Remove highlighting from [offset].
+void removeHighlight(int offset, int lineNumber) {
+  if (offset != null) {
+    var anchor = document.getElementById("o$offset");
+    if (anchor != null) {
+      anchor.classes.remove("target");
+    }
+  }
+  if (lineNumber != null) {
+    var line = document.querySelector(".line-$lineNumber");
+    if (line != null) {
+      line.parent.classes.remove("highlight");
+    }
+  }
+}
+
+/// Return the absolute path of [path], assuming [path] is relative to [root].
+String absolutePath(String path) {
+  if (path[0] != "/") {
+    return '$rootPath/$path';
+  } else {
+    return path;
+  }
+}
+
+/// If [path] lies within [root], return the relative path of [path] from [root].
+/// Otherwise, return [path].
+String relativePath(String path) {
+  var root = querySelector(".root").text + "/";
+  if (path.startsWith(root)) {
+    return path.substring(root.length);
+  } else {
+    return path;
+  }
+}
+
+/// Write the contents of the Edit List, from JSON data [editListData].
+void writeEditList(dynamic editListData) {
+  var editList = document.querySelector(".edit-list .panel-content");
+  editList.innerHtml = "";
+  var p = editList.append(document.createElement("p"));
+  var countElement = p.append(document.createElement("strong"));
+  int editCount = editListData["editCount"];
+  countElement.append(Text(editCount.toString()));
+  if (editCount == 1) {
+    p.append(
+        Text(" edit was made to this file. Click the edit's checkbox to toggle "
+            "its reviewed state."));
+  } else {
+    p.append(Text(
+        " edits were made to this file. Click an edit's checkbox to toggle "
+        "its reviewed state."));
+  }
+  for (var edit in editListData["edits"]) {
+    ParagraphElement editP = editList.append(document.createElement("p"));
+    editP.classes.add("edit");
+    Element checkbox = editP.append(document.createElement("input"));
+    checkbox.setAttribute("type", "checkbox");
+    checkbox.setAttribute("title", "Click to mark reviewed");
+    checkbox.setAttribute("disabled", "disabled");
+    editP.append(Text('line ${edit["line"]}: ${edit["explanation"]}.'));
+    AnchorElement a = editP.append(document.createElement("a"));
+    a.classes.add("edit-link");
+    int offset = edit["offset"];
+    a.dataset['offset'] = '$offset';
+    int line = edit["line"];
+    a.dataset['line'] = '$line';
+    a.append(Text("[view]"));
+    a.onClick.listen((MouseEvent event) {
+      navigate(window.location.pathname, offset, line, callback: () {
+        pushState(window.location.pathname, offset, line);
+      });
+      loadRegionExplanation(a);
+    });
+  }
+}
+
+/// Load data from [data] into the .code and the .regions divs.
+void writeCodeAndRegions(dynamic data) {
+  var regions = document.querySelector(".regions");
+  var code = document.querySelector(".code");
+  PermissiveNodeValidator.setInnerHtml(regions, data["regions"]);
+  PermissiveNodeValidator.setInnerHtml(code, data["navContent"]);
+  writeEditList(data["editList"]);
+  highlightAllCode();
+  addClickHandlers(".code");
+  addClickHandlers(".regions");
+}
+
+/// Navigate to [path] and optionally scroll [offset] into view.
+///
+/// If [callback] is present, it will be called after the server response has
+/// been processed, and the content has been updated on the page.
+void navigate(
+  String path,
+  int offset,
+  int lineNumber, {
+  VoidCallback callback,
+}) {
+  int currentOffset = getOffset(window.location.href);
+  int currentLineNumber = getLine(window.location.href);
+  removeHighlight(currentOffset, currentLineNumber);
+  if (path == window.location.pathname) {
+    // Navigating to same file; just scroll into view.
+    maybeScrollToAndHighlight(offset, lineNumber);
+    if (callback != null) {
+      callback();
+    }
+  } else {
+    loadFile(path, offset, lineNumber, callback: callback);
+  }
+}
+
+void maybeScrollIntoView(Element element) {
+  Rectangle rect = element.getBoundingClientRect();
+  if (rect.bottom > window.innerHeight) {
+    element.scrollIntoView();
+  } else if (rect.top < 0) {
+    element.scrollIntoView();
+  }
+}
+
+/// Scroll target with id [offset] into view if it is not currently in view.
+///
+/// If [offset] is null, instead scroll the "unit-name" header, at the top of the
+/// page, into view.
+///
+/// Also add the "target" class, highlighting the target. Also add the
+/// "highlight" class to the entire line on which the target lies.
+void maybeScrollToAndHighlight(int offset, int lineNumber) {
+  Element target;
+  Element line;
+
+  if (offset != null) {
+    target = document.getElementById("o$offset");
+    line = document.querySelector(".line-$lineNumber");
+    if (target != null) {
+      maybeScrollIntoView(target);
+      target.classes.add("target");
+    } else if (line != null) {
+      // If the target doesn't exist, but the line does, scroll that into view
+      // instead.
+      maybeScrollIntoView(line);
+    }
+    if (line != null) {
+      (line.parentNode as Element).classes.add("highlight");
+    }
+  } else {
+    // If no offset is given, this is likely a navigation link, and we need to
+    // scroll back to the top of the page.
+    target = document.getElementById("unit-name");
+    maybeScrollIntoView(target);
+  }
+}
+
+/// Load the file at [path] from the server, optionally scrolling [offset] into
+/// view.
+void loadFile(
+  String path,
+  int offset,
+  int lineNumber, {
+  VoidCallback callback,
+}) {
+  // Navigating to another file; request it, then do work with the response.
+  HttpRequest.request(
+    "$path?inline=true",
+    requestHeaders: {'Content-Type': 'application/json; charset=UTF-8'},
+  ).then((HttpRequest xhr) {
+    if (xhr.status == 200) {
+      var response = jsonDecode(xhr.responseText);
+      writeCodeAndRegions(response);
+      maybeScrollToAndHighlight(offset, lineNumber);
+      updatePage(path, offset);
+      if (callback != null) {
+        callback();
+      }
+    } else {
+      window.alert("Request failed; status of ${xhr.status}");
+    }
+  }).catchError((e, st) {
+    logError(e, st);
+
+    window.alert('Could not load $path; preview server might be disconnected.');
+  });
+}
+
+void pushState(String path, int offset, int lineNumber) {
+  var newLocation = window.location.origin + path + "?";
+  if (offset != null) {
+    newLocation = newLocation + "offset=$offset&";
+  }
+  if (lineNumber != null) {
+    newLocation = newLocation + "line=$lineNumber";
+  }
+  window.history.pushState({}, "", newLocation);
+}
+
+/// Update the heading and navigation links.
+///
+/// Call this after updating page content on a navigation.
+void updatePage(String path, int offset) {
+  path = relativePath(path);
+  // Update page heading.
+  Element unitName = document.querySelector("#unit-name");
+  unitName.text = path;
+  // Update navigation styles.
+  document.querySelectorAll(".nav-panel .nav-link").forEach((Element link) {
+    var name = link.dataset['name'];
+    if (name == path) {
+      link.classes.add("selected-file");
+    } else {
+      link.classes.remove("selected-file");
+    }
+  });
+}
+
+void highlightAllCode() {
+  document.querySelectorAll(".code").forEach((Element block) {
+    hljs.highlightBlock(block);
+  });
+}
+
+void addArrowClickHandler(Element arrow) {
+  Element childList =
+      (arrow.parentNode as Element).querySelector(":scope > ul");
+  // Animating height from "auto" to "0" is not supported by CSS [1], so all we
+  // have are hacks. The `* 2` allows for events in which the list grows in
+  // height when resized, with additional text wrapping.
+  // [1] https://css-tricks.com/using-css-transitions-auto-dimensions/
+  childList.style.maxHeight = "${childList.offsetHeight * 2}px";
+  arrow.onClick.listen((MouseEvent event) {
+    if (!childList.classes.contains("collapsed")) {
+      childList.classes.add("collapsed");
+      arrow.classes.add("collapsed");
+    } else {
+      childList.classes.remove("collapsed");
+      arrow.classes.remove("collapsed");
+    }
+  });
+}
+
+void handleNavLinkClick(MouseEvent event) {
+  Element target = event.currentTarget;
+
+  var path = absolutePath(target.getAttribute("href"));
+  int offset = getOffset(target.getAttribute("href"));
+  int lineNumber = getLine(target.getAttribute("href"));
+
+  if (offset != null) {
+    navigate(path, offset, lineNumber, callback: () {
+      pushState(path, offset, lineNumber);
+    });
+  } else {
+    navigate(path, null, null, callback: () {
+      pushState(path, null, null);
+    });
+  }
+  event.preventDefault();
+}
+
+void handlePostLinkClick(MouseEvent event) {
+  String path = (event.currentTarget as Element).getAttribute("href");
+  path = absolutePath(path);
+
+  // Directing the server to produce an edit; request it, then do work with the
+  // response.
+  HttpRequest.request(
+    path,
+    method: 'POST',
+    requestHeaders: {'Content-Type': 'application/json; charset=UTF-8'},
+  ).then((HttpRequest xhr) {
+    if (xhr.status == 200) {
+      // Likely request new navigation and file content.
+    } else {
+      window.alert("Request failed; status of ${xhr.status}");
+    }
+  }).catchError((e, st) {
+    logError(e, st);
+
+    window.alert('Could not load $path; preview server might be disconnected.');
+  });
+}
+
+void addClickHandlers(String parentSelector) {
+  Element parentElement = document.querySelector(parentSelector);
+
+  var navLinks = parentElement.querySelectorAll(".nav-link");
+  navLinks.forEach((link) {
+    link.onClick.listen(handleNavLinkClick);
+  });
+
+  var regions = parentElement.querySelectorAll(".region");
+  regions.forEach((Element region) {
+    region.onClick.listen((event) {
+      loadRegionExplanation(region);
+    });
+  });
+
+  var postLinks = parentElement.querySelectorAll(".post-link");
+  postLinks.forEach((link) {
+    link.onClick.listen(handlePostLinkClick);
+  });
+}
+
+void writeNavigationSubtree(Element parentElement, dynamic tree) {
+  var ul = parentElement.append(document.createElement('ul'));
+  for (var entity in tree) {
+    Element li = ul.append(document.createElement('li'));
+    if (entity["type"] == "directory") {
+      li.classes.add("dir");
+      Element arrow = li.append(document.createElement('span'));
+      arrow.classes.add("arrow");
+      arrow.innerHtml = "&#x25BC;";
+      Element icon = li.append(document.createElement('span'));
+      icon.innerHtml = "&#x1F4C1;";
+      li.append(Text(entity["name"]));
+      writeNavigationSubtree(li, entity["subtree"]);
+      addArrowClickHandler(arrow);
+    } else {
+      li.innerHtml = "&#x1F4C4;";
+      Element a = li.append(document.createElement("a"));
+      a.classes.add("nav-link");
+      a.dataset['name'] = entity["path"];
+      a.setAttribute("href", entity["href"]);
+      a.append(Text(entity["name"]));
+      a.onClick.listen(handleNavLinkClick);
+      int editCount = entity["editCount"];
+      if (editCount > 0) {
+        Element editsBadge = li.append(document.createElement("span"));
+        editsBadge.classes.add("edit-count");
+        var edits = editCount == 1 ? 'edit' : 'edits';
+        editsBadge.setAttribute("title", '$editCount $edits');
+        editsBadge.append(Text(editCount.toString()));
+      }
+    }
+  }
+}
+
+/// Load the navigation tree into the ".nav-tree" div.
+void loadNavigationTree() {
+  String path = "/_preview/navigationTree.json";
+
+  // Request the navigation tree, then do work with the response.
+  HttpRequest.request(
+    path,
+    requestHeaders: {'Content-Type': 'application/json; charset=UTF-8'},
+  ).then((HttpRequest xhr) {
+    if (xhr.status == 200) {
+      dynamic response = jsonDecode(xhr.responseText);
+      var navTree = document.querySelector(".nav-tree");
+      navTree.innerHtml = "";
+      writeNavigationSubtree(navTree, response);
+    } else {
+      window.alert('Request failed; status of ${xhr.status}');
+    }
+  }).catchError((e, st) {
+    logError(e, st);
+
+    window.alert('Could not load $path; preview server might be disconnected.');
+  });
+}
+
+void logError(e, st) {
+  window.console.error('$e');
+  window.console.error('$st');
+}
+
+void writeRegionExplanation(dynamic response) {
+  var editPanel = document.querySelector(".edit-panel .panel-content");
+  editPanel.innerHtml = "";
+  var regionLocation = document.createElement("p");
+  regionLocation.classes.add("region-location");
+  // Insert a zero-width space after each "/", to allow lines to wrap after each
+  // directory name.
+  // TODO(devoncarew): Handle the following regex (to improve layout).
+  //var path = response["path"].replace(/\//g, "/\u200B");
+  var path = response["path"];
+  regionLocation.append(Text('$path '));
+  Element regionLine = regionLocation.append(document.createElement("span"));
+  regionLine.append(Text('line ${response["line"]}'));
+  regionLine.classes.add("nowrap");
+  editPanel.append(regionLocation);
+  var explanation = editPanel.append(document.createElement("p"));
+  explanation.append(Text(response["explanation"]));
+  var detailCount = response["details"].length;
+  if (detailCount == 0) {
+    // Having 0 details is not necessarily an expected possibility, but handling
+    // the possibility prevents awkward text, "for 0 reasons:".
+    explanation.append(Text("."));
+  } else {
+    explanation.append(Text(detailCount == 1
+        ? ' for $detailCount reason:'
+        : ' for $detailCount reasons:'));
+    var detailList = editPanel.append(document.createElement("ol"));
+    for (var detail in response["details"]) {
+      var detailItem = detailList.append(document.createElement("li"));
+      detailItem.append(Text(detail["description"]));
+      if (detail["link"] != null) {
+        detailItem.append(Text(" ("));
+        AnchorElement a = detailItem.append(document.createElement("a"));
+        a.append(Text(detail["link"]["text"]));
+        a.setAttribute("href", detail["link"]["href"]);
+        a.classes.add("nav-link");
+        detailItem.append(Text(")"));
+      }
+    }
+  }
+  if (response["edits"] != null) {
+    for (var edit in response["edits"]) {
+      Element editParagraph = editPanel.append(document.createElement("p"));
+      Element a = editParagraph.append(document.createElement("a"));
+      a.append(Text(edit["text"]));
+      a.setAttribute("href", edit["href"]);
+      a.classes.add("post-link");
+    }
+  }
+}
+
+/// Load the explanation for [region], into the ".panel-content" div.
+void loadRegionExplanation(Element region) {
+  String path = window.location.pathname;
+  String offset = region.dataset['offset'];
+
+  // Request the region, then do work with the response.
+  HttpRequest.request(
+    '$path?region=region&offset=$offset',
+    requestHeaders: {'Content-Type': 'application/json; charset=UTF-8'},
+  ).then((HttpRequest xhr) {
+    if (xhr.status == 200) {
+      var response = jsonDecode(xhr.responseText);
+      writeRegionExplanation(response);
+      addClickHandlers(".edit-panel .panel-content");
+    } else {
+      window.alert('Request failed; status of ${xhr.status}');
+    }
+  }).catchError((e, st) {
+    logError(e, st);
+
+    window.alert('Could not load $path; preview server might be disconnected.');
+  });
+}
+
+/// Resize the fixed-size and fixed-position navigation and information panels.
+void resizePanels() {
+  var navInner = document.querySelector(".nav-inner");
+  var height = window.innerHeight;
+  navInner.style.height = "${height}px";
+
+  var infoPanelHeight = height / 2 - 6;
+  var editPanel = document.querySelector(".edit-panel");
+  editPanel.style.height = "${infoPanelHeight}px";
+
+  var editListHeight = height / 2 - 6;
+  var editList = document.querySelector(".edit-list");
+  editList.style.height = "${editListHeight}px";
+}
+
+void main() {
+  document.addEventListener("DOMContentLoaded", (event) {
+    String path = window.location.pathname;
+    int offset = getOffset(window.location.href);
+    int lineNumber = getLine(window.location.href);
+    loadNavigationTree();
+    if (path != "/" && path != rootPath) {
+      // TODO(srawlins): replaceState?
+      loadFile(path, offset, lineNumber, callback: () {
+        pushState(path, offset, lineNumber);
+      });
+    }
+    resizePanels();
+  });
+
+  window.addEventListener("popstate", (event) {
+    var path = window.location.pathname;
+    int offset = getOffset(window.location.href);
+    var lineNumber = getLine(window.location.href);
+    if (path.length > 1) {
+      loadFile(path, offset, lineNumber);
+    } else {
+      // Blank out the page, for the index screen.
+      writeCodeAndRegions({"regions": "", "navContent": ""});
+      updatePage("&nbsp;", null);
+    }
+  });
+
+  final Debouncer resizeDebouncer =
+      Debouncer(const Duration(milliseconds: 200));
+  window.addEventListener("resize", (event) {
+    resizeDebouncer.run(resizePanels);
+  });
+
+  final Debouncer scrollDebouncer =
+      Debouncer(const Duration(milliseconds: 200));
+
+  // When scrolling the page, determine whether the navigation and information
+  // panels need to be fixed in place, or allowed to scroll.
+  window.addEventListener("scroll", (event) {
+    var navPanel = document.querySelector(".nav-panel");
+    var navInner = navPanel.querySelector(".nav-inner");
+    var infoPanel = document.querySelector(".info-panel");
+    var panelContainer = document.querySelector(".panel-container");
+    var innerTopOffset = navPanel.offsetTop;
+    if (window.pageYOffset > innerTopOffset) {
+      if (!navInner.classes.contains("fixed")) {
+        var navPanelWidth = navPanel.offsetWidth - 14;
+        navPanel.style.width = "${navPanelWidth}px";
+        // Subtract 7px for nav-inner's padding.
+        navInner.style.width = (navPanelWidth + 7).toString() + "px";
+        navInner.classes.add("fixed");
+      }
+      if (!panelContainer.classes.contains("fixed")) {
+        var infoPanelWidth = infoPanel.offsetWidth;
+        infoPanel.style.width = "${infoPanelWidth}px";
+        panelContainer.style.width = "${infoPanelWidth}px";
+        panelContainer.classes.add("fixed");
+      }
+    } else {
+      if (navInner.classes.contains("fixed")) {
+        navPanel.style.width = "";
+        navInner.style.width = "";
+        navInner.classes.remove("fixed");
+      }
+      if (panelContainer.classes.contains("fixed")) {
+        infoPanel.style.width = "";
+        panelContainer.style.width = "";
+        panelContainer.classes.remove("fixed");
+      }
+    }
+    scrollDebouncer.run(resizePanels);
+  });
+}
+
+final HighlightJs hljs = HighlightJs._();
+
+/// A small wrapper around the JavaScript highlight.js APIs.
+class HighlightJs {
+  static JsObject get _hljs => context['hljs'];
+
+  HighlightJs._();
+
+  void highlightBlock(Element block) {
+    _hljs.callMethod('highlightBlock', [block]);
+  }
+}
+
+/// A utility class to debounce an action at the given duration.
+class Debouncer {
+  final Duration duration;
+  Timer _timer;
+
+  Debouncer(this.duration);
+
+  void run(VoidCallback action) {
+    if (_timer != null) {
+      _timer.cancel();
+    }
+    _timer = Timer(duration, action);
+  }
+}
+
+class PermissiveNodeValidator implements NodeValidator {
+  static PermissiveNodeValidator instance = PermissiveNodeValidator();
+
+  static void setInnerHtml(Element element, String html) {
+    element.setInnerHtml(html, validator: instance);
+  }
+
+  @override
+  bool allowsAttribute(Element element, String attributeName, String value) {
+    return true;
+  }
+
+  @override
+  bool allowsElement(Element element) {
+    return true;
+  }
+}
diff --git a/pkg/analysis_server/lib/src/plugin/plugin_manager.dart b/pkg/analysis_server/lib/src/plugin/plugin_manager.dart
index 7b170e9..74ed4ea 100644
--- a/pkg/analysis_server/lib/src/plugin/plugin_manager.dart
+++ b/pkg/analysis_server/lib/src/plugin/plugin_manager.dart
@@ -569,7 +569,12 @@
       plugin.removeContextRoot(contextRoot);
       if (plugin is DiscoveredPluginInfo && plugin.contextRoots.isEmpty) {
         _pluginMap.remove(plugin.path);
-        plugin.stop();
+        try {
+          plugin.stop();
+        } catch (e, st) {
+          AnalysisEngine.instance.instrumentationService
+              .logException(SilentException('Issue stopping a plugin', e, st));
+        }
       }
     }
   }
diff --git a/pkg/analysis_server/lib/src/protocol_server.dart b/pkg/analysis_server/lib/src/protocol_server.dart
index e5b3c4d..592c9ca 100644
--- a/pkg/analysis_server/lib/src/protocol_server.dart
+++ b/pkg/analysis_server/lib/src/protocol_server.dart
@@ -62,7 +62,7 @@
     if (element.kind == engine.ElementKind.SETTER) {
       return null;
     } else {
-      return element.returnType?.toString();
+      return element.returnType?.getDisplayString(withNullability: false);
     }
   } else if (element is engine.VariableElement) {
     engine.DartType type = element.type;
@@ -70,7 +70,8 @@
         ? type.getDisplayString(withNullability: false)
         : 'dynamic';
   } else if (element is engine.FunctionTypeAliasElement) {
-    return element.function.returnType.toString();
+    var returnType = element.function.returnType;
+    return returnType.getDisplayString(withNullability: false);
   } else {
     return null;
   }
diff --git a/pkg/analysis_server/lib/src/search/type_hierarchy.dart b/pkg/analysis_server/lib/src/search/type_hierarchy.dart
index 8ed15b2..4224a77 100644
--- a/pkg/analysis_server/lib/src/search/type_hierarchy.dart
+++ b/pkg/analysis_server/lib/src/search/type_hierarchy.dart
@@ -119,8 +119,10 @@
     {
       String displayName;
       if (typeArguments != null && typeArguments.isNotEmpty) {
-        displayName =
-            classElement.displayName + '<' + typeArguments.join(', ') + '>';
+        var typeArgumentsStr = typeArguments
+            .map((type) => type.getDisplayString(withNullability: false))
+            .join(', ');
+        displayName = classElement.displayName + '<' + typeArgumentsStr + '>';
       }
       ExecutableElement memberElement = _findMemberElement(classElement);
       item = TypeHierarchyItem(convertElement(classElement),
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart b/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart
index 86147e9..6a490e5 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart
@@ -332,7 +332,7 @@
   if (type == null) {
     return DYNAMIC;
   }
-  return type.toString();
+  return type.getDisplayString(withNullability: false);
 }
 
 /// TODO(pq): fix to use getDefaultStringParameterValue()
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_contains.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_contains.dart
new file mode 100644
index 0000000..05c2c9e
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_contains.dart
@@ -0,0 +1,140 @@
+// Copyright (c) 2020, 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:analysis_server/src/services/correction/dart/abstract_producer.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
+import 'package:analyzer_plugin/utilities/range_factory.dart';
+
+class ConvertToContains extends CorrectionProducer {
+  @override
+  Future<void> compute(DartChangeBuilder builder) async {
+    var comparison = node.thisOrAncestorOfType<BinaryExpression>();
+    if (comparison == null) {
+      return;
+    }
+    var leftOperand = comparison.leftOperand;
+    var rightOperand = comparison.rightOperand;
+    if (leftOperand is MethodInvocation && isInteger(rightOperand)) {
+      var value = integerValue(rightOperand);
+      var methodName = leftOperand.methodName;
+      var deletionRange = range.endEnd(leftOperand, rightOperand);
+      var notOffset = -1;
+      var style = negationStyle(comparison.operator.type, value);
+      if (style == NegationStyle.none) {
+        return;
+      } else if (style == NegationStyle.negated) {
+        notOffset = leftOperand.offset;
+      }
+
+      await builder.addFileEdit(file, (DartFileEditBuilder builder) {
+        if (notOffset > 0) {
+          builder.addSimpleInsertion(notOffset, '!');
+        }
+        builder.addSimpleReplacement(range.node(methodName), 'contains');
+        builder.addDeletion(deletionRange);
+      });
+    } else if (isInteger(leftOperand) && rightOperand is MethodInvocation) {
+      var value = integerValue(leftOperand);
+      var methodName = rightOperand.methodName;
+      var deletionRange = range.startStart(leftOperand, rightOperand);
+      var notOffset = -1;
+      var style =
+          negationStyle(invertedTokenType(comparison.operator.type), value);
+      if (style == NegationStyle.none) {
+        return;
+      } else if (style == NegationStyle.negated) {
+        notOffset = rightOperand.offset;
+      }
+
+      await builder.addFileEdit(file, (DartFileEditBuilder builder) {
+        builder.addDeletion(deletionRange);
+        if (notOffset > 0) {
+          builder.addSimpleInsertion(notOffset, '!');
+        }
+        builder.addSimpleReplacement(range.node(methodName), 'contains');
+      });
+    }
+  }
+
+  /// Return the value of the given [expression], given that [isInteger]
+  /// returned `true`.
+  int integerValue(Expression expression) {
+    if (expression is IntegerLiteral) {
+      return expression.value;
+    } else if (expression is PrefixExpression &&
+        expression.operator.type == TokenType.MINUS) {
+      var operand = expression.operand;
+      if (operand is IntegerLiteral) {
+        return -(operand.value);
+      }
+    }
+    throw StateError('invalid integer value');
+  }
+
+  TokenType invertedTokenType(TokenType type) {
+    switch (type) {
+      case TokenType.LT_EQ:
+        return TokenType.GT_EQ;
+      case TokenType.LT:
+        return TokenType.GT;
+      case TokenType.GT:
+        return TokenType.LT;
+      case TokenType.GT_EQ:
+        return TokenType.LT_EQ;
+      default:
+        return type;
+    }
+  }
+
+  /// Return `true` if the given [expression] is a literal integer, possibly
+  /// prefixed by a negation operator.
+  bool isInteger(Expression expression) {
+    return (expression is IntegerLiteral) ||
+        (expression is PrefixExpression &&
+            expression.operator.type == TokenType.MINUS &&
+            expression.operand is IntegerLiteral);
+  }
+
+  NegationStyle negationStyle(TokenType type, int value) {
+    if (value == -1) {
+      if (type == TokenType.EQ_EQ || type == TokenType.LT_EQ) {
+        // `indexOf == -1` is the same as `!contains`
+        // `indexOf <= -1` is the same as `!contains`
+        return NegationStyle.negated;
+      } else if (type == TokenType.BANG_EQ || type == TokenType.GT) {
+        // `indexOf != -1` is the same as `contains`
+        // `indexOf > -1` is the same as `contains`
+        return NegationStyle.positive;
+      } else if (type == TokenType.LT || type == TokenType.GT_EQ) {
+        // `indexOf < -1` is always false
+        // `indexOf >= -1` is always true
+        return NegationStyle.none;
+      }
+    } else if (value == 0) {
+      if (type == TokenType.GT_EQ) {
+        // `indexOf >= 0` is the same as `contains`
+        return NegationStyle.positive;
+      } else if (type == TokenType.LT) {
+        // `indexOf < 0` is the same as `!contains`
+        return NegationStyle.negated;
+      }
+      // Any other comparison with zero should not have been flagged, so we
+      // should never reach this point.
+      return NegationStyle.none;
+    } else if (value < -1) {
+      // 'indexOf' is always >= -1, so comparing with lesser values makes
+      // no sense.
+      return NegationStyle.none;
+    }
+    // Comparison with any value greater than zero should not have been flagged,
+    // so we should never reach this point.
+    return NegationStyle.none;
+  }
+}
+
+/// An indication of whether the `contains` test should be negated, not negated,
+/// or whether neither is appropriate and the code should be left unchanged.
+enum NegationStyle { none, negated, positive }
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index 5fb30cd..1a286ce 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -188,6 +188,8 @@
       FixKind('CONVERT_FLUTTER_CHILDREN', 50, 'Convert to child:');
   static const CONVERT_INTO_EXPRESSION_BODY =
       FixKind('CONVERT_INTO_EXPRESSION_BODY', 50, 'Convert to expression body');
+  static const CONVERT_TO_CONTAINS =
+      FixKind('CONVERT_TO_CONTAINS', 50, "Convert to using 'contains'");
   static const CONVERT_TO_FOR_ELEMENT =
       FixKind('CONVERT_TO_FOR_ELEMENT', 50, "Convert to a 'for' element");
   static const CONVERT_TO_GENERIC_FUNCTION_SYNTAX = FixKind(
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index cba9fee..305248b 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -12,6 +12,7 @@
 import 'package:analysis_server/src/services/completion/dart/utilities.dart';
 import 'package:analysis_server/src/services/correction/base_processor.dart';
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
+import 'package:analysis_server/src/services/correction/dart/convert_to_contains.dart';
 import 'package:analysis_server/src/services/correction/dart/convert_to_list_literal.dart';
 import 'package:analysis_server/src/services/correction/dart/convert_to_map_literal.dart';
 import 'package:analysis_server/src/services/correction/dart/convert_to_null_aware.dart';
@@ -1426,7 +1427,7 @@
               changeBuilder,
               DartFixKind.CHANGE_TYPE_ANNOTATION,
               args: [
-                typeNode.type,
+                typeNode.type.getDisplayString(withNullability: false),
                 newType.getDisplayString(withNullability: false),
               ],
             );
@@ -4723,6 +4724,11 @@
           ConvertToSetLiteral(),
           DartFixKind.CONVERT_TO_SET_LITERAL,
         );
+      } else if (name == LintNames.prefer_contains) {
+        await compute(
+          ConvertToContains(),
+          DartFixKind.CONVERT_TO_CONTAINS,
+        );
       } else if (name == LintNames.prefer_iterable_whereType) {
         await compute(
           ConvertToWhereType(),
diff --git a/pkg/analysis_server/lib/src/services/linter/lint_names.dart b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
index ca6dce2..366d8f4 100644
--- a/pkg/analysis_server/lib/src/services/linter/lint_names.dart
+++ b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
@@ -40,6 +40,7 @@
   static const String prefer_collection_literals = 'prefer_collection_literals';
   static const String prefer_conditional_assignment =
       'prefer_conditional_assignment';
+  static const String prefer_contains = 'prefer_contains';
   static const String prefer_const_constructors = 'prefer_const_constructors';
   static const String prefer_const_declarations = 'prefer_const_declarations';
   static const String prefer_equal_for_default_values =
diff --git a/pkg/analysis_server/test/analysis_abstract.dart b/pkg/analysis_server/test/analysis_abstract.dart
index c800360..a65abc2 100644
--- a/pkg/analysis_server/test/analysis_abstract.dart
+++ b/pkg/analysis_server/test/analysis_abstract.dart
@@ -131,7 +131,7 @@
   }
 
   /**
-   * Creates a project `/project`.
+   * Creates a project [projectPath].
    */
   void createProject({Map<String, String> packageRoots}) {
     newFolder(projectPath);
@@ -148,7 +148,7 @@
   }
 
   /**
-   * Returns the offset of [search] in [testCode].
+   * Returns the offset of [search] in the file at the given [path].
    * Fails if not found.
    */
   int findFileOffset(String path, String search) {
diff --git a/pkg/analysis_server/test/client/completion_driver_test.dart b/pkg/analysis_server/test/client/completion_driver_test.dart
new file mode 100644
index 0000000..7b89151
--- /dev/null
+++ b/pkg/analysis_server/test/client/completion_driver_test.dart
@@ -0,0 +1,107 @@
+// Copyright (c) 2020, 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_plugin/protocol/protocol_common.dart';
+import 'package:meta/meta.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
+
+import '../services/completion/dart/completion_contributor_util.dart';
+import 'impl/completion_driver.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(BasicCompletionTest);
+  });
+}
+
+abstract class AbstractCompletionDriverTest with ResourceProviderMixin {
+  CompletionDriver driver;
+
+  Map<String, String> packageRoots;
+
+  List<CompletionSuggestion> suggestions;
+
+  bool get supportsAvailableDeclarations;
+
+  String addTestFile(String content, {int offset}) =>
+      driver.addTestFile(content, offset: offset);
+
+  Future<List<CompletionSuggestion>> getSuggestions() async {
+    suggestions = await driver.getSuggestions();
+    return suggestions;
+  }
+
+  @mustCallSuper
+  void setUp() {
+    driver = CompletionDriver(
+        supportsAvailableDeclarations: supportsAvailableDeclarations,
+        resourceProvider: resourceProvider);
+    driver.createProject(packageRoots: packageRoots);
+  }
+
+  SuggestionMatcher suggestionHas(
+          {@required String completion,
+          ElementKind element,
+          CompletionSuggestionKind kind}) =>
+      (CompletionSuggestion s) {
+        if (s.completion == completion) {
+          if (element != null && s.element?.kind != element) {
+            return false;
+          }
+          if (kind != null && s.kind != kind) {
+            return false;
+          }
+          return true;
+        }
+        return false;
+      };
+
+  CompletionSuggestion suggestionWith(
+      {@required String completion,
+      ElementKind element,
+      CompletionSuggestionKind kind}) {
+    final matches = suggestions.where(
+        suggestionHas(completion: completion, element: element, kind: kind));
+    expect(matches, hasLength(1));
+    return matches.first;
+  }
+}
+
+@reflectiveTest
+class BasicCompletionTest extends AbstractCompletionDriverTest {
+  @override
+  bool get supportsAvailableDeclarations => false;
+
+  /// Duplicates (and potentially replaces DeprecatedMemberRelevanceTest.
+  Future<void> test_deprecated_member_relevance() async {
+    addTestFile('''
+class A {
+  void a1() { }
+  @deprecated
+  void a2() { }
+}
+
+void main() {
+  var a = A();
+  a.^
+}
+''');
+
+    await getSuggestions();
+    expect(
+        suggestionWith(
+                completion: 'a2',
+                element: ElementKind.METHOD,
+                kind: CompletionSuggestionKind.INVOCATION)
+            .relevance,
+        lessThan(suggestionWith(
+                completion: 'a1',
+                element: ElementKind.METHOD,
+                kind: CompletionSuggestionKind.INVOCATION)
+            .relevance));
+  }
+}
diff --git a/pkg/analysis_server/test/client/impl/abstract_client.dart b/pkg/analysis_server/test/client/impl/abstract_client.dart
new file mode 100644
index 0000000..d938063
--- /dev/null
+++ b/pkg/analysis_server/test/client/impl/abstract_client.dart
@@ -0,0 +1,141 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:analysis_server/protocol/protocol.dart';
+import 'package:analysis_server/protocol/protocol_generated.dart'
+    hide AnalysisOptions;
+import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analysis_server/src/domain_analysis.dart';
+import 'package:analysis_server/src/utilities/mocks.dart';
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/instrumentation/instrumentation.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/sdk.dart';
+import 'package:analyzer/src/test_utilities/mock_sdk.dart';
+import 'package:matcher/matcher.dart';
+import 'package:meta/meta.dart';
+
+import '../../mocks.dart';
+
+abstract class AbstractClient {
+  final MockServerChannel serverChannel;
+  final TestPluginManager pluginManager;
+  AnalysisServer server;
+
+  final List<GeneralAnalysisService> generalServices =
+      <GeneralAnalysisService>[];
+  final Map<AnalysisService, List<String>> analysisSubscriptions = {};
+
+  final String projectPath;
+  final String testFolder;
+  final String testFile;
+  String testCode;
+
+  AbstractClient({
+    @required this.projectPath,
+    @required this.testFolder,
+    @required this.testFile,
+    @required String sdkPath,
+  })  : serverChannel = MockServerChannel(),
+        pluginManager = TestPluginManager() {
+    server = createAnalysisServer(sdkPath);
+    var notificationStream = serverChannel.notificationController.stream;
+    notificationStream.listen((Notification notification) {
+      processNotification(notification);
+    });
+  }
+
+  AnalysisDomainHandler get analysisHandler => server.handlers
+      .singleWhere((handler) => handler is AnalysisDomainHandler);
+
+  AnalysisOptions get analysisOptions => testDiver.analysisOptions;
+
+  ResourceProvider get resourceProvider;
+
+  AnalysisDriver get testDiver => server.getAnalysisDriver(testFile);
+
+  void addAnalysisOptionsFile(String content) {
+    newFile(
+        resourceProvider.pathContext.join(projectPath, 'analysis_options.yaml'),
+        content);
+  }
+
+  void addAnalysisSubscription(AnalysisService service, String file) {
+    // add file to subscription
+    var files = analysisSubscriptions[service];
+    if (files == null) {
+      files = <String>[];
+      analysisSubscriptions[service] = files;
+    }
+    files.add(file);
+    // set subscriptions
+    var request =
+        AnalysisSetSubscriptionsParams(analysisSubscriptions).toRequest('0');
+    handleSuccessfulRequest(request);
+  }
+
+  void addGeneralAnalysisSubscription(GeneralAnalysisService service) {
+    generalServices.add(service);
+    var request =
+        AnalysisSetGeneralSubscriptionsParams(generalServices).toRequest('0');
+    handleSuccessfulRequest(request);
+  }
+
+  String addTestFile(String content) {
+    newFile(testFile, content);
+    testCode = content;
+    return testFile;
+  }
+
+  void assertValidId(String id) {
+    expect(id, isNotNull);
+    expect(id.isNotEmpty, isTrue);
+  }
+
+  /// Create an analysis server with the given [sdkPath].
+  AnalysisServer createAnalysisServer(String sdkPath) {
+    MockSdk(resourceProvider: resourceProvider);
+    var options = AnalysisServerOptions();
+    return AnalysisServer(serverChannel, resourceProvider, options,
+        DartSdkManager(sdkPath, true), InstrumentationService.NULL_SERVICE);
+  }
+
+  /// Create a project at [projectPath].
+  void createProject({Map<String, String> packageRoots}) {
+    newFolder(projectPath);
+    var request = AnalysisSetAnalysisRootsParams([projectPath], [],
+            packageRoots: packageRoots)
+        .toRequest('0');
+    handleSuccessfulRequest(request, handler: analysisHandler);
+  }
+
+  void expect(actual, matcher, {String reason});
+
+  /// Validate that the given [request] is handled successfully.
+  Response handleSuccessfulRequest(Request request, {RequestHandler handler}) {
+    handler ??= analysisHandler;
+    var response = handler.handleRequest(request);
+    expect(response, isResponseSuccess(request.id));
+    return response;
+  }
+
+  File newFile(String path, String content, [int stamp]);
+
+  Folder newFolder(String path);
+
+  void processNotification(Notification notification);
+
+  /// Returns a [Future] that completes when the server's analysis is complete.
+  Future waitForTasksFinished() => server.onAnalysisComplete;
+
+  /// Completes with a successful [Response] for the given [request].
+  /// Otherwise fails.
+  Future<Response> waitResponse(Request request,
+      {bool throwOnError = true}) async {
+    return serverChannel.sendRequest(request, throwOnError: throwOnError);
+  }
+}
diff --git a/pkg/analysis_server/test/client/impl/completion_driver.dart b/pkg/analysis_server/test/client/impl/completion_driver.dart
new file mode 100644
index 0000000..8a6415e
--- /dev/null
+++ b/pkg/analysis_server/test/client/impl/completion_driver.dart
@@ -0,0 +1,105 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:analysis_server/protocol/protocol.dart';
+import 'package:analysis_server/protocol/protocol_constants.dart';
+import 'package:analysis_server/protocol/protocol_generated.dart'
+    hide AnalysisOptions;
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/memory_file_system.dart';
+import 'package:analyzer_plugin/protocol/protocol_common.dart';
+import 'package:matcher/matcher.dart';
+import 'package:meta/meta.dart';
+
+import '../../constants.dart';
+import 'abstract_client.dart';
+import 'expect_mixin.dart';
+
+class CompletionDriver extends AbstractClient with ExpectMixin {
+  final bool supportsAvailableDeclarations;
+  final MemoryResourceProvider _resourceProvider;
+
+  Map<String, Completer<void>> receivedSuggestionsCompleters = {};
+  List<CompletionSuggestion> suggestions = [];
+  bool suggestionsDone = false;
+  Map<String, List<CompletionSuggestion>> allSuggestions = {};
+
+  String completionId;
+  int completionOffset;
+  int replacementOffset;
+  int replacementLength;
+
+  CompletionDriver({
+    @required this.supportsAvailableDeclarations,
+    @required MemoryResourceProvider resourceProvider,
+  })  : _resourceProvider = resourceProvider,
+        super(
+            projectPath: resourceProvider.convertPath('/project'),
+            testFolder: resourceProvider.convertPath('/project/bin'),
+            testFile: resourceProvider.convertPath('/project/bin/test.dart'),
+            sdkPath: resourceProvider.convertPath('/sdk'));
+
+  @override
+  MemoryResourceProvider get resourceProvider => _resourceProvider;
+
+  @override
+  String addTestFile(String content, {int offset}) {
+    completionOffset = content.indexOf('^');
+    if (offset != null) {
+      expect(completionOffset, -1, reason: 'cannot supply offset and ^');
+      completionOffset = offset;
+      return super.addTestFile(content);
+    }
+    expect(completionOffset, isNot(equals(-1)), reason: 'missing ^');
+    int nextOffset = content.indexOf('^', completionOffset + 1);
+    expect(nextOffset, equals(-1), reason: 'too many ^');
+    return super.addTestFile(content.substring(0, completionOffset) +
+        content.substring(completionOffset + 1));
+  }
+
+  Future<List<CompletionSuggestion>> getSuggestions() async {
+    await waitForTasksFinished();
+
+    var request = CompletionGetSuggestionsParams(testFile, completionOffset)
+        .toRequest('0');
+    var response = await waitResponse(request);
+    var result = CompletionGetSuggestionsResult.fromResponse(response);
+    completionId = result.id;
+    assertValidId(completionId);
+    await _getResultsCompleter(completionId).future;
+    expect(suggestionsDone, isTrue);
+    return suggestions;
+  }
+
+  @override
+  File newFile(String path, String content, [int stamp]) =>
+      resourceProvider.newFile(path, content, stamp);
+
+  @override
+  Folder newFolder(String path) => resourceProvider.newFolder(path);
+
+  @override
+  Future<void> processNotification(Notification notification) async {
+    if (notification.event == COMPLETION_RESULTS) {
+      var params = CompletionResultsParams.fromNotification(notification);
+      var id = params.id;
+      assertValidId(id);
+      replacementOffset = params.replacementOffset;
+      replacementLength = params.replacementLength;
+      suggestionsDone = params.isLast;
+      expect(suggestionsDone, isNotNull);
+      suggestions = params.results;
+      expect(allSuggestions.containsKey(id), isFalse);
+      allSuggestions[id] = params.results;
+      _getResultsCompleter(id).complete(null);
+    } else if (notification.event == SERVER_NOTIFICATION_ERROR) {
+      throw Exception('server error: ${notification.toJson()}');
+    }
+  }
+
+  Completer<void> _getResultsCompleter(String id) =>
+      receivedSuggestionsCompleters.putIfAbsent(id, () => Completer<void>());
+}
diff --git a/pkg/analysis_server/test/client/impl/expect_mixin.dart b/pkg/analysis_server/test/client/impl/expect_mixin.dart
new file mode 100644
index 0000000..abbfe42
--- /dev/null
+++ b/pkg/analysis_server/test/client/impl/expect_mixin.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2020, 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:matcher/matcher.dart';
+
+typedef _Predicate<T> = bool Function(T value);
+
+/// Lightweight expect that can be run outside of a test context.
+class ExpectMixin {
+  void expect(actual, matcher, {String reason}) {
+    matcher = _wrapMatcher(matcher);
+    var matchState = {};
+    try {
+      if ((matcher as Matcher).matches(actual, matchState)) {
+        return;
+      }
+    } catch (e, trace) {
+      reason ??= '$e at $trace';
+    }
+    throw Exception(reason);
+  }
+
+  static Matcher _wrapMatcher(x) {
+    if (x is Matcher) {
+      return x;
+    } else if (x is _Predicate<Object>) {
+      // x is already a predicate that can handle anything
+      return predicate(x);
+    } else if (x is _Predicate<Null>) {
+      // x is a unary predicate, but expects a specific type
+      // so wrap it.
+      // ignore: unnecessary_lambdas
+      return predicate((a) => (x as dynamic)(a));
+    } else {
+      return equals(x);
+    }
+  }
+}
diff --git a/pkg/analysis_server/test/client/test_all.dart b/pkg/analysis_server/test/client/test_all.dart
new file mode 100644
index 0000000..417c4d3
--- /dev/null
+++ b/pkg/analysis_server/test/client/test_all.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2020, 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:test_reflective_loader/test_reflective_loader.dart';
+
+import 'completion_driver_test.dart' as completion_driver;
+
+void main() {
+  defineReflectiveSuite(() {
+    completion_driver.main();
+  });
+}
diff --git a/pkg/analysis_server/test/mock_packages/flutter/lib/foundation.dart b/pkg/analysis_server/test/mock_packages/flutter/lib/foundation.dart
index 5cf9392..fecb726 100644
--- a/pkg/analysis_server/test/mock_packages/flutter/lib/foundation.dart
+++ b/pkg/analysis_server/test/mock_packages/flutter/lib/foundation.dart
@@ -11,4 +11,5 @@
         required,
         visibleForTesting;
 
+export 'src/foundation/diagnostics.dart';
 export 'src/foundation/key.dart';
diff --git a/pkg/analysis_server/test/mock_packages/flutter/lib/src/foundation/diagnostics.dart b/pkg/analysis_server/test/mock_packages/flutter/lib/src/foundation/diagnostics.dart
new file mode 100644
index 0000000..b624146
--- /dev/null
+++ b/pkg/analysis_server/test/mock_packages/flutter/lib/src/foundation/diagnostics.dart
@@ -0,0 +1,15 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+abstract class Diagnosticable {}
+
+class DiagnosticPropertiesBuilder {
+  void add(DiagnosticsNode property) {}
+}
+
+abstract class DiagnosticsNode {}
+
+class DiagnosticsProperty<T> extends DiagnosticsNode {
+  DiagnosticsProperty(String name, T value);
+}
diff --git a/pkg/analysis_server/test/mock_packages/flutter/lib/src/widgets/framework.dart b/pkg/analysis_server/test/mock_packages/flutter/lib/src/widgets/framework.dart
index ac48179..a52fa57 100644
--- a/pkg/analysis_server/test/mock_packages/flutter/lib/src/widgets/framework.dart
+++ b/pkg/analysis_server/test/mock_packages/flutter/lib/src/widgets/framework.dart
@@ -41,6 +41,8 @@
   final Key key;
 
   const Widget({this.key});
+
+  void debugFillProperties(DiagnosticPropertiesBuilder properties) {}
 }
 
 abstract class SingleChildRenderObjectWidget extends RenderObjectWidget {
diff --git a/pkg/analysis_server/test/src/edit/fix/non_nullable_fix_test.dart b/pkg/analysis_server/test/src/edit/fix/non_nullable_fix_test.dart
index a485d89..8f688fd 100644
--- a/pkg/analysis_server/test/src/edit/fix/non_nullable_fix_test.dart
+++ b/pkg/analysis_server/test/src/edit/fix/non_nullable_fix_test.dart
@@ -30,13 +30,6 @@
 
   String get nextRequestId => (++requestId).toString();
 
-  /// On Windows, canonicalization results in changing a drive letter to be
-  /// lowercase. When a path is canonicalized in [NonNullableFix], and asserted
-  /// on in a test below, the expected path below also needs to be
-  /// canonicalized.
-  String canonicalizeAndConvertPath(String p) =>
-      convertPath(context.canonicalize(p));
-
   Future<EditDartfixResult> performFix({List<String> included}) async {
     final id = nextRequestId;
     final params = EditDartfixParams(included);
@@ -80,7 +73,7 @@
 
   Future<void> test_included_multipleRelativeDirectories() async {
     NonNullableFix fix = NonNullableFix(listener, included: ['lib', 'test']);
-    expect(fix.includedRoot, equals(canonicalizeAndConvertPath('/project')));
+    expect(fix.includedRoot, equals(convertPath('/project')));
   }
 
   Future<void> test_included_multipleRelativeDirectories_nonCanonical() async {
@@ -88,8 +81,7 @@
       convertPath('../project2/lib'),
       convertPath('../project2/lib/src')
     ]);
-    expect(
-        fix.includedRoot, equals(canonicalizeAndConvertPath('/project2/lib')));
+    expect(fix.includedRoot, equals(convertPath('/project2/lib')));
   }
 
   Future<void>
@@ -98,13 +90,13 @@
       convertPath('../project2/lib'),
       convertPath('../project/lib')
     ]);
-    expect(fix.includedRoot, equals(canonicalizeAndConvertPath('/')));
+    expect(fix.includedRoot, equals(convertPath('/')));
   }
 
   Future<void>
       test_included_multipleRelativeDirectories_subAndSuperDirectories() async {
     NonNullableFix fix = NonNullableFix(listener, included: ['lib', '.']);
-    expect(fix.includedRoot, equals(canonicalizeAndConvertPath('/project')));
+    expect(fix.includedRoot, equals(convertPath('/project')));
   }
 
   Future<void> test_included_multipleRelativeFiles() async {
@@ -112,14 +104,13 @@
       convertPath('lib/lib1.dart'),
       convertPath('test/test.dart')
     ]);
-    expect(fix.includedRoot, equals(canonicalizeAndConvertPath('/project')));
+    expect(fix.includedRoot, equals(convertPath('/project')));
   }
 
   Future<void> test_included_multipleRelativeFiles_sameDirectory() async {
     NonNullableFix fix = NonNullableFix(listener,
         included: [convertPath('lib/lib1.dart'), convertPath('lib/lib2.dart')]);
-    expect(
-        fix.includedRoot, equals(canonicalizeAndConvertPath('/project/lib')));
+    expect(fix.includedRoot, equals(convertPath('/project/lib')));
   }
 
   Future<void> test_included_multipleRelativeFilesAndDirectories() async {
@@ -128,25 +119,23 @@
       convertPath('lib/src'),
       convertPath('../project/lib/src/lib3.dart')
     ]);
-    expect(
-        fix.includedRoot, equals(canonicalizeAndConvertPath('/project/lib')));
+    expect(fix.includedRoot, equals(convertPath('/project/lib')));
   }
 
   Future<void> test_included_singleAbsoluteDirectory() async {
     NonNullableFix fix =
         NonNullableFix(listener, included: [convertPath('/project')]);
-    expect(fix.includedRoot, equals(canonicalizeAndConvertPath('/project')));
+    expect(fix.includedRoot, equals(convertPath('/project')));
   }
 
   Future<void> test_included_singleAbsoluteFile() async {
     NonNullableFix fix = NonNullableFix(listener,
         included: [convertPath('/project/bin/bin.dart')]);
-    expect(
-        fix.includedRoot, equals(canonicalizeAndConvertPath('/project/bin')));
+    expect(fix.includedRoot, equals(convertPath('/project/bin')));
   }
 
   Future<void> test_included_singleRelativeDirectory() async {
     NonNullableFix fix = NonNullableFix(listener, included: ['.']);
-    expect(fix.includedRoot, equals(canonicalizeAndConvertPath('/project')));
+    expect(fix.includedRoot, equals(convertPath('/project')));
   }
 }
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_await_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_await_test.dart
index f075f8f..b54c20d 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_await_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_await_test.dart
@@ -25,14 +25,14 @@
 
   Future<void> test_intLiteral() async {
     await resolveTestUnit('''
-Future doSomething() => new Future();
+Future doSomething() => new Future.value('');
 
 void main() async {
-  doSomething()/*LINT*/;
+  doSomething();
 }
 ''');
     await assertHasFix('''
-Future doSomething() => new Future();
+Future doSomething() => new Future.value('');
 
 void main() async {
   await doSomething();
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_const_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_const_test.dart
index 189e3a8..f384b72 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_const_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_const_test.dart
@@ -23,13 +23,28 @@
   @override
   String get lintCode => LintNames.prefer_const_constructors;
 
-  Future<void> test_basic() async {
+  Future<void> test_new() async {
     await resolveTestUnit('''
 class C {
   const C();
 }
 main() {
-  var c = C/*LINT*/();
+  var c = new C();
+  print(c);
+}
+''');
+    // handled by REPLACE_NEW_WITH_CONST
+    await assertNoFix();
+  }
+
+  Future<void> test_noKeyword() async {
+    await resolveTestUnit('''
+class C {
+  const C();
+}
+main() {
+  var c = C();
+  print(c);
 }
 ''');
     await assertHasFix('''
@@ -38,20 +53,8 @@
 }
 main() {
   var c = const C();
+  print(c);
 }
 ''');
   }
-
-  Future<void> test_not_present() async {
-    await resolveTestUnit('''
-class C {
-  const C();
-}
-main() {
-  var c = new C/*LINT*/();
-}
-''');
-    // handled by REPLACE_NEW_WITH_CONST
-    await assertNoFix();
-  }
 }
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_curly_braces_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_curly_braces_test.dart
index 267ee17..ab16f8e 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_curly_braces_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_curly_braces_test.dart
@@ -24,10 +24,11 @@
   String get lintCode => LintNames.curly_braces_in_flow_control_structures;
 
   // More coverage in the `use_curly_braces_test.dart` assist test.
+
   Future<void> test_do_block() async {
     await resolveTestUnit('''
 main() {
-  do /*LINT*/print(0); while (true);
+  do print(0); while (true);
 }
 ''');
     await assertHasFix('''
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_diagnostic_property_reference_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_diagnostic_property_reference_test.dart
index ac5dd64..e094001 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_diagnostic_property_reference_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_diagnostic_property_reference_test.dart
@@ -4,6 +4,7 @@
 
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -23,12 +24,21 @@
   @override
   String get lintCode => LintNames.diagnostic_describe_all_properties;
 
-  Future<void> test_boolField_debugFillProperties() async {
+  @override
+  void setUp() {
+    super.setUp();
+    addFlutterPackage();
+  }
+
+  Future<void> test_boolField() async {
     await resolveTestUnit('''
-class Absorber extends Widget {
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
   bool get absorbing => _absorbing;
   bool _absorbing;
-  bool /*LINT*/ignoringSemantics;
+  bool ignoringSemantics;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
     super.debugFillProperties(properties);
@@ -37,7 +47,10 @@
 }
 ''');
     await assertHasFix('''
-class Absorber extends Widget {
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
   bool get absorbing => _absorbing;
   bool _absorbing;
   bool ignoringSemantics;
@@ -51,17 +64,23 @@
 ''');
   }
 
-  Future<void> test_boolField_debugFillProperties_empty() async {
+  Future<void> test_boolField_empty() async {
     await resolveTestUnit('''
-class Absorber extends Widget {
-  bool /*LINT*/ignoringSemantics;
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
+  bool ignoringSemantics;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
   }
 }
 ''');
     await assertHasFix('''
-class Absorber extends Widget {
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
   bool ignoringSemantics;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
@@ -71,18 +90,23 @@
 ''');
   }
 
-  Future<void>
-      test_boolField_debugFillProperties_empty_customParamName() async {
+  Future<void> test_boolField_empty_customParamName() async {
     await resolveTestUnit('''
-class Absorber extends Widget {
-  bool /*LINT*/ignoringSemantics;
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
+  bool ignoringSemantics;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder props) {
   }
 }
 ''');
     await assertHasFix('''
-class Absorber extends Widget {
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
   bool ignoringSemantics;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder props) {
@@ -92,10 +116,13 @@
 ''');
   }
 
-  Future<void> test_boolGetter_debugFillProperties() async {
+  Future<void> test_boolGetter() async {
     await resolveTestUnit('''
-class Absorber extends Widget {
-  bool get /*LINT*/absorbing => _absorbing;
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
+  bool get absorbing => _absorbing;
   bool _absorbing;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
@@ -104,7 +131,10 @@
 }
 ''');
     await assertHasFix('''
-class Absorber extends Widget {
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
   bool get absorbing => _absorbing;
   bool _absorbing;
   @override
@@ -116,12 +146,14 @@
 ''');
   }
 
-  Future<void> test_colorField_debugFillProperties() async {
-    addFlutterPackage();
+  Future<void> test_colorField() async {
     await resolveTestUnit('''
+import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
-class A extends Widget {
-  Color /*LINT*/field;
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
+  Color field;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
     super.debugFillProperties(properties);
@@ -129,8 +161,11 @@
 }
 ''');
     await assertHasFix('''
+import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
-class A extends Widget {
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
   Color field;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
@@ -141,10 +176,13 @@
 ''');
   }
 
-  Future<void> test_doubleField_debugFillProperties() async {
+  Future<void> test_doubleField() async {
     await resolveTestUnit('''
-class A extends Widget {
-  double /*LINT*/field;
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
+  double field;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
     super.debugFillProperties(properties);
@@ -152,7 +190,10 @@
 }
 ''');
     await assertHasFix('''
-class A extends Widget {
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
   double field;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
@@ -163,10 +204,13 @@
 ''');
   }
 
-  Future<void> test_dynamicField_debugFillProperties() async {
+  Future<void> test_dynamicField() async {
     await resolveTestUnit('''
-class A extends Widget {
-  dynamic /*LINT*/field;
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
+  dynamic field;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
     super.debugFillProperties(properties);
@@ -174,7 +218,10 @@
 }
 ''');
     await assertHasFix('''
-class A extends Widget {
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
   dynamic field;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
@@ -185,20 +232,25 @@
 ''');
   }
 
-  Future<void> test_enumField_debugFillProperties() async {
+  Future<void> test_enumField() async {
     await resolveTestUnit('''
-enum Foo {bar}
-class A extends Widget {
-  Foo /*LINT*/field;
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
+  Foo field;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
     super.debugFillProperties(properties);
   }
 }
+enum Foo {bar}
 ''');
     await assertHasFix('''
-enum Foo {bar}
-class A extends Widget {
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
   Foo field;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
@@ -206,30 +258,31 @@
     properties.add(EnumProperty<Foo>('field', field));
   }
 }
+enum Foo {bar}
 ''');
   }
 
-  Future<void> test_functionField_debugFillProperties() async {
-    addFlutterPackage();
+  Future<void> test_functionField() async {
     await resolveTestUnit('''
+import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
 
-typedef ValueChanged<T> = void Function(T value);
-
-class A extends Widget {
-  ValueChanged<double> /*LINT*/onChanged;
+class C extends Widget implements Diagnosticable {
+  ValueChanged<double> onChanged;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
     super.debugFillProperties(properties);
   }
 }
+typedef ValueChanged<T> = void Function(T value);
 ''');
     await assertHasFix('''
+import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
 
-typedef ValueChanged<T> = void Function(T value);
-
-class A extends Widget {
+class C extends Widget implements Diagnosticable {
   ValueChanged<double> onChanged;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
@@ -237,13 +290,17 @@
     properties.add(ObjectFlagProperty<ValueChanged<double>>.has('onChanged', onChanged));
   }
 }
+typedef ValueChanged<T> = void Function(T value);
 ''');
   }
 
-  Future<void> test_intField_debugFillProperties() async {
+  Future<void> test_intField() async {
     await resolveTestUnit('''
-class A extends Widget {
-  int /*LINT*/field;
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
+  int field;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
     super.debugFillProperties(properties);
@@ -251,7 +308,10 @@
 }
 ''');
     await assertHasFix('''
-class A extends Widget {
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
   int field;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
@@ -262,10 +322,13 @@
 ''');
   }
 
-  Future<void> test_iterableField_debugFillProperties() async {
+  Future<void> test_iterableField() async {
     await resolveTestUnit('''
-class A extends Widget {
-  Iterable<String> /*LINT*/field;
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
+  Iterable<String> field;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
     super.debugFillProperties(properties);
@@ -273,7 +336,10 @@
 }
 ''');
     await assertHasFix('''
-class A extends Widget {
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
   Iterable<String> field;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
@@ -284,10 +350,13 @@
 ''');
   }
 
-  Future<void> test_listField_debugFillProperties() async {
+  Future<void> test_listField() async {
     await resolveTestUnit('''
-class A extends Widget {
-  List<List<String>> /*LINT*/field;
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
+  List<List<String>> field;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
     super.debugFillProperties(properties);
@@ -295,7 +364,10 @@
 }
 ''');
     await assertHasFix('''
-class A extends Widget {
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
   List<List<String>> field;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
@@ -306,12 +378,15 @@
 ''');
   }
 
-  Future<void> test_matrix4Field_debugFillProperties() async {
+  Future<void> test_matrix4Field() async {
     addVectorMathPackage();
     await resolveTestUnit('''
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
 import 'package:vector_math/vector_math_64.dart';
-class A extends Widget {
-  Matrix4 /*LINT*/field;
+
+class C extends Widget implements Diagnosticable {
+  Matrix4 field;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
     super.debugFillProperties(properties);
@@ -319,8 +394,11 @@
 }
 ''');
     await assertHasFix('''
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
 import 'package:vector_math/vector_math_64.dart';
-class A extends Widget {
+
+class C extends Widget implements Diagnosticable {
   Matrix4 field;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
@@ -331,10 +409,13 @@
 ''');
   }
 
-  Future<void> test_objectField_debugFillProperties() async {
+  Future<void> test_objectField() async {
     await resolveTestUnit('''
-class A extends Widget {
-  Object /*LINT*/field;
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
+  Object field;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
     super.debugFillProperties(properties);
@@ -342,7 +423,10 @@
 }
 ''');
     await assertHasFix('''
-class A extends Widget {
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
   Object field;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
@@ -353,10 +437,13 @@
 ''');
   }
 
-  Future<void> test_stringField_debugFillProperties() async {
+  Future<void> test_stringField() async {
     await resolveTestUnit('''
-class A extends Widget {
-  String /*LINT*/field;
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
+  String field;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
     super.debugFillProperties(properties);
@@ -364,7 +451,10 @@
 }
 ''');
     await assertHasFix('''
-class A extends Widget {
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
   String field;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
@@ -377,12 +467,18 @@
 
   Future<void> test_stringField_noDebugFillProperties() async {
     await resolveTestUnit('''
-class A extends Widget {
-  String /*LINT*/field;
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
+  String field;
 }
 ''');
     await assertHasFix('''
-class A extends Widget {
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
   String field;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
@@ -393,10 +489,13 @@
 ''');
   }
 
-  Future<void> test_typeOutOfScopeField_debugFillProperties() async {
+  Future<void> test_typeOutOfScopeField() async {
     await resolveTestUnit('''
-class A extends Widget {
-  ClassNotInScope<bool> /*LINT*/onChanged;
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
+  ClassNotInScope<bool> onChanged;
 
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
@@ -405,7 +504,10 @@
 }
 ''');
     await assertHasFix('''
-class A extends Widget {
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
   ClassNotInScope<bool> onChanged;
 
   @override
@@ -414,13 +516,18 @@
     properties.add(DiagnosticsProperty<ClassNotInScope<bool>>('onChanged', onChanged));
   }
 }
-''');
+''',
+        errorFilter: (error) =>
+            error.errorCode != CompileTimeErrorCode.UNDEFINED_CLASS);
   }
 
-  Future<void> test_typeOutOfScopeGetter_debugFillProperties() async {
+  Future<void> test_typeOutOfScopeGetter() async {
     await resolveTestUnit('''
-class A extends Widget {
-  ClassNotInScope<bool> get /*LINT*/onChanged => null;
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
+  ClassNotInScope<bool> get onChanged => null;
 
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
@@ -429,7 +536,10 @@
 }
 ''');
     await assertHasFix('''
-class A extends Widget {
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
   ClassNotInScope<bool> get onChanged => null;
 
   @override
@@ -438,13 +548,18 @@
     properties.add(DiagnosticsProperty<ClassNotInScope<bool>>('onChanged', onChanged));
   }
 }
-''');
+''',
+        errorFilter: (error) =>
+            error.errorCode != CompileTimeErrorCode.UNDEFINED_CLASS);
   }
 
-  Future<void> test_varField_debugFillProperties() async {
+  Future<void> test_varField() async {
     await resolveTestUnit('''
-class A extends Widget {
-  var /*LINT*/field;
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
+  var field;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
     super.debugFillProperties(properties);
@@ -452,7 +567,10 @@
 }
 ''');
     await assertHasFix('''
-class A extends Widget {
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+class C extends Widget implements Diagnosticable {
   var field;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_override_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_override_test.dart
index 4113925..1205817 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_override_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_override_test.dart
@@ -25,15 +25,15 @@
 
   Future<void> test_field() async {
     await resolveTestUnit('''
-class abstract Test {
+abstract class Test {
   int get t;
 }
 class Sub extends Test {
-  int /*LINT*/t = 42;
+  int t = 42;
 }
 ''');
     await assertHasFix('''
-class abstract Test {
+abstract class Test {
   int get t;
 }
 class Sub extends Test {
@@ -49,7 +49,7 @@
   int get t => null;
 }
 class Sub extends Test {
-  int get /*LINT*/t => null;
+  int get t => null;
 }
 ''');
     await assertHasFix('''
@@ -69,7 +69,7 @@
   void t() { }
 }
 class Sub extends Test {
-  void /*LINT*/t() { }
+  void t() { }
 }
 ''');
     await assertHasFix('''
@@ -90,7 +90,7 @@
 }
 class Sub extends Test {
   /// Doc comment.
-  void /*LINT*/t() { }
+  void t() { }
 }
 ''');
     await assertHasFix('''
@@ -114,7 +114,7 @@
   /**
    * Doc comment.
    */
-  void /*LINT*/t() { }
+  void t() { }
 }
 ''');
     await assertHasFix('''
@@ -139,8 +139,9 @@
 class Sub extends Test {
   /// Doc comment.
   @foo
-  void /*LINT*/t() { }
+  void t() { }
 }
+const foo = '';
 ''');
     await assertHasFix('''
 class Test {
@@ -152,6 +153,7 @@
   @foo
   void t() { }
 }
+const foo = '';
 ''');
   }
 
@@ -162,7 +164,7 @@
 }
 class Sub extends Test {
   // Non-doc comment.
-  void /*LINT*/t() { }
+  void t() { }
 }
 ''');
     await assertHasFix('''
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_required_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_required_test.dart
index 8eccd35..b9ecdf2 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_required_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_required_test.dart
@@ -25,7 +25,7 @@
 
   Future<void> test_withAssert() async {
     await resolveTestUnit('''
-void function({String /*LINT*/param}) {
+void function({String param}) {
   assert(param != null);
 }
 ''');
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_return_type_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_return_type_test.dart
index dc6e266..614490f 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_return_type_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_return_type_test.dart
@@ -27,9 +27,10 @@
     await resolveTestUnit('''
 class A {
   void m() {
-    /*LINT*/f() {
+    f() {
       return '';
     }
+    f();
   }
 }
 ''');
@@ -39,6 +40,7 @@
     String f() {
       return '';
     }
+    f();
   }
 }
 ''');
@@ -48,7 +50,8 @@
     await resolveTestUnit('''
 class A {
   void m() {
-    /*LINT*/f() => '';
+    f() => '';
+    f();
   }
 }
 ''');
@@ -56,6 +59,7 @@
 class A {
   void m() {
     String f() => '';
+    f();
   }
 }
 ''');
@@ -64,7 +68,7 @@
   Future<void> test_method_block_noReturn() async {
     await resolveTestUnit('''
 class A {
-  /*LINT*/m() {
+  m() {
   }
 }
 ''');
@@ -74,7 +78,7 @@
   Future<void> test_method_block_returnDynamic() async {
     await resolveTestUnit('''
 class A {
-  /*LINT*/m(p) {
+  m(p) {
     return p;
   }
 }
@@ -85,7 +89,7 @@
   Future<void> test_method_block_returnNoValue() async {
     await resolveTestUnit('''
 class A {
-  /*LINT*/m() {
+  m() {
     return;
   }
 }
@@ -102,7 +106,7 @@
   Future<void> test_method_block_singleReturn() async {
     await resolveTestUnit('''
 class A {
-  /*LINT*/m() {
+  m() {
     return '';
   }
 }
@@ -119,7 +123,7 @@
   Future<void> test_method_expression() async {
     await resolveTestUnit('''
 class A {
-  /*LINT*/m() => '';
+  m() => '';
 }
 ''');
     await assertHasFix('''
@@ -131,7 +135,7 @@
 
   Future<void> test_topLevelFunction_block() async {
     await resolveTestUnit('''
-/*LINT*/f() {
+f() {
   return '';
 }
 ''');
@@ -144,7 +148,7 @@
 
   Future<void> test_topLevelFunction_expression() async {
     await resolveTestUnit('''
-/*LINT*/f() => '';
+f() => '';
 ''');
     await assertHasFix('''
 String f() => '';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_type_annotation_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_type_annotation_test.dart
index 5eacfec..4322e01 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_type_annotation_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_type_annotation_test.dart
@@ -25,10 +25,11 @@
   String get lintCode => LintNames.always_specify_types;
 
   // More coverage in the `add_type_annotation_test.dart` assist test.
+
   Future<void> test_do_block() async {
     await resolveTestUnit('''
 class A {
-  /*LINT*/final f = 0;
+  final f = 0;
 }
 ''');
     await assertHasFix('''
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_documentation_into_line_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_documentation_into_line_test.dart
index 2dccc30..4e8edc0 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/convert_documentation_into_line_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_documentation_into_line_test.dart
@@ -28,7 +28,7 @@
     await resolveTestUnit('''
 class A {
   /**
-   * /*LINT*/AAAAAAA [int] AAAAAAA
+   * AAAAAAA [int] AAAAAAA
    * BBBBBBBB BBBB BBBB
    * CCC [A] CCCCCCCCCCC
    */
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_into_expression_body_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_into_expression_body_test.dart
index 832ea45..97f56dd 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/convert_into_expression_body_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_into_expression_body_test.dart
@@ -28,7 +28,7 @@
     await resolveTestUnit('''
 class A {
   mmm() async { 
-    return 42; /*LINT*/
+    return 42;
   }
 }
 ''');
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_contains_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_contains_test.dart
new file mode 100644
index 0000000..f72cb3a
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_contains_test.dart
@@ -0,0 +1,217 @@
+// Copyright (c) 2020, 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:analysis_server/src/services/correction/fix.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ConvertToContainsTest);
+  });
+}
+
+@reflectiveTest
+class ConvertToContainsTest extends FixProcessorLintTest {
+  @override
+  FixKind get kind => DartFixKind.CONVERT_TO_CONTAINS;
+
+  @override
+  String get lintCode => LintNames.prefer_contains;
+
+  Future<void> test_left_bangEq_minusOne() async {
+    await resolveTestUnit('''
+bool f(List<int> list, int value) {
+  return -1 != list.indexOf(value);
+}
+''');
+    await assertHasFix('''
+bool f(List<int> list, int value) {
+  return list.contains(value);
+}
+''');
+  }
+
+  Future<void> test_left_eqEq_minusOne() async {
+    await resolveTestUnit('''
+bool f(List<int> list, int value) {
+  return -1 == list.indexOf(value);
+}
+''');
+    await assertHasFix('''
+bool f(List<int> list, int value) {
+  return !list.contains(value);
+}
+''');
+  }
+
+  Future<void> test_left_gt_minusOne() async {
+    await resolveTestUnit('''
+bool f(List<int> list, int value) {
+  return -1 > list.indexOf(value);
+}
+''');
+    await assertNoFix();
+  }
+
+  Future<void> test_left_gt_zero() async {
+    await resolveTestUnit('''
+bool f(List<int> list, int value) {
+  return 0 > list.indexOf(value);
+}
+''');
+    await assertHasFix('''
+bool f(List<int> list, int value) {
+  return !list.contains(value);
+}
+''');
+  }
+
+  Future<void> test_left_gtEq_minusOne() async {
+    await resolveTestUnit('''
+bool f(List<int> list, int value) {
+  return -1 >= list.indexOf(value);
+}
+''');
+    await assertHasFix('''
+bool f(List<int> list, int value) {
+  return !list.contains(value);
+}
+''');
+  }
+
+  Future<void> test_left_lt_minusOne() async {
+    await resolveTestUnit('''
+bool f(List<int> list, int value) {
+  return -1 < list.indexOf(value);
+}
+''');
+    await assertHasFix('''
+bool f(List<int> list, int value) {
+  return list.contains(value);
+}
+''');
+  }
+
+  Future<void> test_left_ltEq_minusOne() async {
+    await resolveTestUnit('''
+bool f(List<int> list, int value) {
+  return -1 <= list.indexOf(value);
+}
+''');
+    await assertNoFix();
+  }
+
+  Future<void> test_left_ltEq_zero() async {
+    await resolveTestUnit('''
+bool f(List<int> list, int value) {
+  return 0 <= list.indexOf(value);
+}
+''');
+    await assertHasFix('''
+bool f(List<int> list, int value) {
+  return list.contains(value);
+}
+''');
+  }
+
+  Future<void> test_right_bangEq_minusOne() async {
+    await resolveTestUnit('''
+bool f(List<int> list, int value) {
+  return list.indexOf(value) != -1;
+}
+''');
+    await assertHasFix('''
+bool f(List<int> list, int value) {
+  return list.contains(value);
+}
+''');
+  }
+
+  Future<void> test_right_eqEq_minusOne() async {
+    await resolveTestUnit('''
+bool f(List<int> list, int value) {
+  return list.indexOf(value) == -1;
+}
+''');
+    await assertHasFix('''
+bool f(List<int> list, int value) {
+  return !list.contains(value);
+}
+''');
+  }
+
+  Future<void> test_right_gt_minusOne() async {
+    await resolveTestUnit('''
+bool f(List<int> list, int value) {
+  return list.indexOf(value) > -1;
+}
+''');
+    await assertHasFix('''
+bool f(List<int> list, int value) {
+  return list.contains(value);
+}
+''');
+  }
+
+  Future<void> test_right_gtEq_minusOne() async {
+    await resolveTestUnit('''
+bool f(List<int> list, int value) {
+  return list.indexOf(value) >= -1;
+}
+''');
+    await assertNoFix();
+  }
+
+  Future<void> test_right_gtEq_zero() async {
+    await resolveTestUnit('''
+bool f(List<int> list, int value) {
+  return list.indexOf(value) >= 0;
+}
+''');
+    await assertHasFix('''
+bool f(List<int> list, int value) {
+  return list.contains(value);
+}
+''');
+  }
+
+  Future<void> test_right_lt_minusOne() async {
+    await resolveTestUnit('''
+bool f(List<int> list, int value) {
+  return list.indexOf(value) < -1;
+}
+''');
+    await assertNoFix();
+  }
+
+  Future<void> test_right_lt_zero() async {
+    await resolveTestUnit('''
+bool f(List<int> list, int value) {
+  return list.indexOf(value) < 0;
+}
+''');
+    await assertHasFix('''
+bool f(List<int> list, int value) {
+  return !list.contains(value);
+}
+''');
+  }
+
+  Future<void> test_right_ltEq_minusOne() async {
+    await resolveTestUnit('''
+bool f(List<int> list, int value) {
+  return list.indexOf(value) <= -1;
+}
+''');
+    await assertHasFix('''
+bool f(List<int> list, int value) {
+  return !list.contains(value);
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_for_element_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_for_element_test.dart
index 76ae348..2457d3b 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/convert_to_for_element_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_for_element_test.dart
@@ -29,7 +29,7 @@
     await resolveTestUnit('''
 f(Iterable<int> i) {
   var k = 3;
-  return Map.fromIterable/*LINT*/(i, key: (k) => k * 2, value: (v) => k);
+  return Map.fromIterable(i, key: (k) => k * 2, value: (v) => k);
 }
 ''');
     await assertHasFix('''
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_generic_function_syntax_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_generic_function_syntax_test.dart
index fd4e744..f56da24 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/convert_to_generic_function_syntax_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_generic_function_syntax_test.dart
@@ -26,14 +26,14 @@
 
   Future<void> test_functionTypeAlias_noParameterTypes() async {
     await resolveTestUnit('''
-typedef String /*LINT*/F(x);
+typedef String F(x);
 ''');
     await assertNoFix();
   }
 
   Future<void> test_functionTypeAlias_noReturnType_noTypeParameters() async {
     await resolveTestUnit('''
-typedef String /*LINT*/F(int x);
+typedef String F(int x);
 ''');
     await assertHasFix('''
 typedef F = String Function(int x);
@@ -42,7 +42,7 @@
 
   Future<void> test_functionTypeAlias_noReturnType_typeParameters() async {
     await resolveTestUnit('''
-typedef /*LINT*/F<P, R>(P x);
+typedef F<P, R>(P x);
 ''');
     await assertHasFix('''
 typedef F<P, R> = Function(P x);
@@ -51,7 +51,7 @@
 
   Future<void> test_functionTypeAlias_returnType_noTypeParameters() async {
     await resolveTestUnit('''
-typedef String /*LINT*/F(int x);
+typedef String F(int x);
 ''');
     await assertHasFix('''
 typedef F = String Function(int x);
@@ -60,7 +60,7 @@
 
   Future<void> test_functionTypeAlias_returnType_typeParameters() async {
     await resolveTestUnit('''
-typedef R /*LINT*/F<P, R>(P x);
+typedef R F<P, R>(P x);
 ''');
     await assertHasFix('''
 typedef F<P, R> = R Function(P x);
@@ -78,14 +78,14 @@
 
   Future<void> test_functionTypedParameter_noParameterTypes() async {
     await resolveTestUnit('''
-g(String /*LINT*/f(x)) {}
+g(String f(x)) {}
 ''');
     await assertNoFix();
   }
 
   Future<void> test_functionTypedParameter_returnType() async {
     await resolveTestUnit('''
-g(String /*LINT*/f(int x)) {}
+g(String f(int x)) {}
 ''');
     await assertHasFix('''
 g(String Function(int x) f) {}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_if_element_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_if_element_test.dart
index b4a8b0d..cb36355 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/convert_to_if_element_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_if_element_test.dart
@@ -28,7 +28,7 @@
   Future<void> test_conditional_list() async {
     await resolveTestUnit('''
 f(bool b) {
-  return ['a', b /*LINT*/? 'c' : 'd', 'e'];
+  return ['a', b ? 'c' : 'd', 'e'];
 }
 ''');
     await assertHasFix('''
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_if_null_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_if_null_test.dart
index feac4bd..ba18148 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/convert_to_if_null_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_if_null_test.dart
@@ -26,7 +26,7 @@
   Future<void> test_equalEqual() async {
     await resolveTestUnit('''
 void f(String s) {
-  print(/*LINT*/s == null ? 'default' : s);
+  print(s == null ? 'default' : s);
 }
 ''');
     await assertHasFix('''
@@ -39,7 +39,7 @@
   Future<void> test_notEqual() async {
     await resolveTestUnit('''
 void f(String s) {
-  print(/*LINT*/s != null ? s : 'default');
+  print(s != null ? s : 'default');
 }
 ''');
     await assertHasFix('''
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_int_literal_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_int_literal_test.dart
index 76a903e..e451086 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/convert_to_int_literal_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_int_literal_test.dart
@@ -26,7 +26,7 @@
   /// More coverage in the `convert_to_int_literal_test.dart` assist test.
   Future<void> test_decimal() async {
     await resolveTestUnit('''
-const double myDouble = /*LINT*/42.0;
+const double myDouble = 42.0;
 ''');
     await assertHasFix('''
 const double myDouble = 42;
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_list_literal_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_list_literal_test.dart
index d3af501..65f833c 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/convert_to_list_literal_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_list_literal_test.dart
@@ -25,7 +25,7 @@
 
   Future<void> test_default_declaredType() async {
     await resolveTestUnit('''
-List l = /*LINT*/List();
+List l = List();
 ''');
     await assertHasFix('''
 List l = [];
@@ -34,7 +34,7 @@
 
   Future<void> test_default_minimal() async {
     await resolveTestUnit('''
-var l = /*LINT*/List();
+var l = List();
 ''');
     await assertHasFix('''
 var l = [];
@@ -43,23 +43,16 @@
 
   Future<void> test_default_newKeyword() async {
     await resolveTestUnit('''
-var l = /*LINT*/new List();
+var l = new List();
 ''');
     await assertHasFix('''
 var l = [];
 ''');
   }
 
-  Future<void> test_default_tooManyArguments() async {
-    await resolveTestUnit('''
-var l = /*LINT*/List(5);
-''');
-    await assertNoFix();
-  }
-
   Future<void> test_default_typeArg() async {
     await resolveTestUnit('''
-var l = /*LINT*/List<int>();
+var l = List<int>();
 ''');
     await assertHasFix('''
 var l = <int>[];
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_map_literal_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_map_literal_test.dart
index 1287453..16926a1 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/convert_to_map_literal_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_map_literal_test.dart
@@ -25,7 +25,7 @@
 
   Future<void> test_default_declaredType() async {
     await resolveTestUnit('''
-Map m = /*LINT*/Map();
+Map m = Map();
 ''');
     await assertHasFix('''
 Map m = {};
@@ -35,7 +35,7 @@
   Future<void> test_default_linkedHashMap() async {
     await resolveTestUnit('''
 import 'dart:collection';
-var m = /*LINT*/LinkedHashMap();
+var m = LinkedHashMap();
 ''');
     await assertHasFix('''
 import 'dart:collection';
@@ -45,7 +45,7 @@
 
   Future<void> test_default_minimal() async {
     await resolveTestUnit('''
-var m = /*LINT*/Map();
+var m = Map();
 ''');
     await assertHasFix('''
 var m = {};
@@ -54,7 +54,7 @@
 
   Future<void> test_default_newKeyword() async {
     await resolveTestUnit('''
-var m = /*LINT*/new Map();
+var m = new Map();
 ''');
     await assertHasFix('''
 var m = {};
@@ -63,7 +63,7 @@
 
   Future<void> test_default_typeArg() async {
     await resolveTestUnit('''
-var m = /*LINT*/Map<String, int>();
+var m = Map<String, int>();
 ''');
     await assertHasFix('''
 var m = <String, int>{};
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_relative_import_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_relative_import_test.dart
index f1ccd9a..471432f 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/convert_to_relative_import_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_relative_import_test.dart
@@ -4,6 +4,7 @@
 
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -24,14 +25,18 @@
   String get lintCode => LintNames.prefer_relative_imports;
 
   Future<void> test_relativeImport() async {
-    addSource('/home/test/lib/foo.dart', '');
+    addSource('/home/test/lib/foo.dart', '''
+class C {}
+''');
     testFile = convertPath('/home/test/lib/src/test.dart');
     await resolveTestUnit('''
-import /*LINT*/'package:test/foo.dart';
+import 'package:test/foo.dart';
+C c;
 ''');
 
     await assertHasFix('''
 import '../foo.dart';
+C c;
 ''');
   }
 
@@ -40,7 +45,7 @@
     addSource('/home/test1/lib/foo.dart', '');
     testFile = convertPath('/home/test2/lib/bar.dart');
     await resolveTestUnit('''
-import /*LINT*/'package:test1/foo.dart';
+import 'package:test1/foo.dart';
 ''');
 
     await assertNoFix();
@@ -50,47 +55,61 @@
     addSource('/home/test/lib/foo.dart', '');
     testFile = convertPath('/home/test/lib/bar.dart');
     await resolveTestUnit('''
-import /*LINT*/'package:test/foo';
+import 'package:test/foo';
 ''');
 
     await assertHasFix('''
 import 'foo';
-''');
+''',
+        errorFilter: (error) =>
+            error.errorCode != CompileTimeErrorCode.URI_DOES_NOT_EXIST);
   }
 
   Future<void> test_relativeImportRespectQuoteStyle() async {
-    addSource('/home/test/lib/foo.dart', '');
+    addSource('/home/test/lib/foo.dart', '''
+class C {}
+''');
     testFile = convertPath('/home/test/lib/bar.dart');
     await resolveTestUnit('''
-import /*LINT*/"package:test/foo.dart";
+import "package:test/foo.dart";
+C c;
 ''');
 
     await assertHasFix('''
 import "foo.dart";
+C c;
 ''');
   }
 
   Future<void> test_relativeImportSameDirectory() async {
-    addSource('/home/test/lib/foo.dart', '');
+    addSource('/home/test/lib/foo.dart', '''
+class C {}
+''');
     testFile = convertPath('/home/test/lib/bar.dart');
     await resolveTestUnit('''
-import /*LINT*/'package:test/foo.dart';
+import 'package:test/foo.dart';
+C c;
 ''');
 
     await assertHasFix('''
 import 'foo.dart';
+C c;
 ''');
   }
 
   Future<void> test_relativeImportSubDirectory() async {
-    addSource('/home/test/lib/baz/foo.dart', '');
+    addSource('/home/test/lib/baz/foo.dart', '''
+class C {}
+''');
     testFile = convertPath('/home/test/lib/test.dart');
     await resolveTestUnit('''
-import /*LINT*/'package:test/baz/foo.dart';
+import 'package:test/baz/foo.dart';
+C c;
 ''');
 
     await assertHasFix('''
 import 'baz/foo.dart';
+C c;
 ''');
   }
 }
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_set_literal_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_set_literal_test.dart
index 553d2a0..3f55c70 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/convert_to_set_literal_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_set_literal_test.dart
@@ -25,7 +25,7 @@
 
   Future<void> test_default_declaredType() async {
     await resolveTestUnit('''
-Set s = /*LINT*/Set();
+Set s = Set();
 ''');
     await assertHasFix('''
 Set s = {};
@@ -34,7 +34,7 @@
 
   Future<void> test_default_minimal() async {
     await resolveTestUnit('''
-var s = /*LINT*/Set();
+var s = Set();
 ''');
     await assertHasFix('''
 var s = <dynamic>{};
@@ -43,7 +43,7 @@
 
   Future<void> test_default_newKeyword() async {
     await resolveTestUnit('''
-var s = /*LINT*/new Set();
+var s = new Set();
 ''');
     await assertHasFix('''
 var s = <dynamic>{};
@@ -52,7 +52,7 @@
 
   Future<void> test_default_typeArg() async {
     await resolveTestUnit('''
-var s = /*LINT*/Set<int>();
+var s = Set<int>();
 ''');
     await assertHasFix('''
 var s = <int>{};
@@ -65,7 +65,7 @@
     await resolveTestUnit('''
 import 'dart:collection';
 
-var s = /*LINT*/LinkedHashSet<int>();
+var s = LinkedHashSet<int>();
 ''');
     await assertHasFix('''
 import 'dart:collection';
@@ -76,7 +76,7 @@
 
   Future<void> test_from_empty() async {
     await resolveTestUnit('''
-var s = /*LINT*/Set.from([]);
+var s = Set.from([]);
 ''');
     await assertHasFix('''
 var s = <dynamic>{};
@@ -89,7 +89,7 @@
     // type.
     await resolveTestUnit('''
 void f(Set<int> s) {}
-var s = f(/*LINT*/Set.from([]));
+var s = f(Set.from([]));
 ''');
     await assertHasFix('''
 void f(Set<int> s) {}
@@ -99,7 +99,7 @@
 
   Future<void> test_from_newKeyword() async {
     await resolveTestUnit('''
-var s = /*LINT*/new Set.from([2, 3]);
+var s = new Set.from([2, 3]);
 ''');
     await assertHasFix('''
 var s = {2, 3};
@@ -108,7 +108,7 @@
 
   Future<void> test_from_noKeyword_declaredType() async {
     await resolveTestUnit('''
-Set s = /*LINT*/Set.from([2, 3]);
+Set s = Set.from([2, 3]);
 ''');
     await assertHasFix('''
 Set s = {2, 3};
@@ -117,7 +117,7 @@
 
   Future<void> test_from_noKeyword_typeArg_onConstructor() async {
     await resolveTestUnit('''
-var s = /*LINT*/Set<int>.from([2, 3]);
+var s = Set<int>.from([2, 3]);
 ''');
     await assertHasFix('''
 var s = <int>{2, 3};
@@ -126,7 +126,7 @@
 
   Future<void> test_from_noKeyword_typeArg_onConstructorAndLiteral() async {
     await resolveTestUnit('''
-var s = /*LINT*/Set<int>.from(<num>[2, 3]);
+var s = Set<int>.from(<num>[2, 3]);
 ''');
     await assertHasFix('''
 var s = <int>{2, 3};
@@ -135,7 +135,7 @@
 
   Future<void> test_from_noKeyword_typeArg_onLiteral() async {
     await resolveTestUnit('''
-var s = /*LINT*/Set.from(<int>[2, 3]);
+var s = Set.from(<int>[2, 3]);
 ''');
     await assertHasFix('''
 var s = <int>{2, 3};
@@ -144,24 +144,16 @@
 
   Future<void> test_from_nonEmpty() async {
     await resolveTestUnit('''
-var s = /*LINT*/Set.from([2, 3]);
+var s = Set.from([2, 3]);
 ''');
     await assertHasFix('''
 var s = {2, 3};
 ''');
   }
 
-  Future<void> test_from_notALiteral() async {
-    await resolveTestUnit('''
-var l = [1];
-Set s = /*LINT*/new Set.from(l);
-''');
-    await assertNoFix();
-  }
-
   Future<void> test_from_trailingComma() async {
     await resolveTestUnit('''
-var s = /*LINT*/Set.from([2, 3,]);
+var s = Set.from([2, 3,]);
 ''');
     await assertHasFix('''
 var s = {2, 3,};
@@ -170,7 +162,7 @@
 
   Future<void> test_toSet_empty() async {
     await resolveTestUnit('''
-var s = /*LINT*/[].toSet();
+var s = [].toSet();
 ''');
     await assertHasFix('''
 var s = <dynamic>{};
@@ -179,7 +171,7 @@
 
   Future<void> test_toSet_empty_typeArg() async {
     await resolveTestUnit('''
-var s = /*LINT*/<int>[].toSet();
+var s = <int>[].toSet();
 ''');
     await assertHasFix('''
 var s = <int>{};
@@ -188,7 +180,7 @@
 
   Future<void> test_toSet_nonEmpty() async {
     await resolveTestUnit('''
-var s = /*LINT*/[2, 3].toSet();
+var s = [2, 3].toSet();
 ''');
     await assertHasFix('''
 var s = {2, 3};
@@ -197,18 +189,10 @@
 
   Future<void> test_toSet_nonEmpty_typeArg() async {
     await resolveTestUnit('''
-var s = /*LINT*/<int>[2, 3].toSet();
+var s = <int>[2, 3].toSet();
 ''');
     await assertHasFix('''
 var s = <int>{2, 3};
 ''');
   }
-
-  Future<void> test_toSet_notALiteral() async {
-    await resolveTestUnit('''
-var l = [];
-var s = /*LINT*/l.toSet();
-''');
-    await assertNoFix();
-  }
 }
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_single_quoted_string_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_single_quoted_string_test.dart
index 5899c01..18f6af1 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/convert_to_single_quoted_string_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_single_quoted_string_test.dart
@@ -27,7 +27,7 @@
   Future<void> test_one_simple() async {
     await resolveTestUnit('''
 main() {
-  print(/*LINT*/"abc");
+  print("abc");
 }
 ''');
     await assertHasFix('''
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_spread_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_spread_test.dart
index 089c9db..bcf9a8e 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/convert_to_spread_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_spread_test.dart
@@ -28,7 +28,7 @@
     await resolveTestUnit('''
 f() {
   var ints = [1, 2, 3];
-  print(['a']../*LINT*/addAll(ints.map((i) => i.toString()))..addAll(['c']));
+  print(['a']..addAll(ints.map((i) => i.toString()))..addAll(['c']));
 }
 ''');
     await assertHasFix('''
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_where_type_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_where_type_test.dart
index 847c04a..e843e15 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/convert_to_where_type_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_where_type_test.dart
@@ -26,7 +26,7 @@
   Future<void> test_default_declaredType() async {
     await resolveTestUnit('''
 Iterable<C> f(List<Object> list) {
-  return list./*LINT*/where((e) => e is C);
+  return list.where((e) => e is C);
 }
 class C {}
 ''');
diff --git a/pkg/analysis_server/test/src/services/correction/fix/create_method_test.dart b/pkg/analysis_server/test/src/services/correction/fix/create_method_test.dart
index fd279c4..2216ee1 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/create_method_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/create_method_test.dart
@@ -31,7 +31,7 @@
     await resolveTestUnit('''
 class C {
   @override
-  int get /*LINT*/hashCode => 13;
+  int get hashCode => 13;
 }
 ''');
     await assertHasFix('''
@@ -52,7 +52,7 @@
     await resolveTestUnit('''
 class C {
   @override
-  bool operator /*LINT*/==(Object other) => false;
+  bool operator ==(Object other) => false;
 }
 ''');
     await assertHasFix('''
diff --git a/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart b/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart
index 7d8cbb1..6ed206e 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart
@@ -37,13 +37,19 @@
   Future<void> resolveTestUnit(String code) async {
     lintOffset = code.indexOf(lintMarker);
     if (lintOffset < 0) {
-      fail("Missing '$lintMarker' marker");
+      return super.resolveTestUnit(code);
     }
     var endOffset = lintOffset + lintMarker.length;
     code = code.substring(0, lintOffset) + code.substring(endOffset);
     return super.resolveTestUnit(code);
   }
 
+  @override
+  void setUp() {
+    super.setUp();
+    createAnalysisOptionsFile(lints: [lintCode]);
+  }
+
   /// Find the error that is to be fixed by computing the errors in the file,
   /// using the [errorFilter] to filter out errors that should be ignored, and
   /// expecting that there is a single remaining error. The error filter should
@@ -52,6 +58,9 @@
   Future<AnalysisError> _findErrorToFix(
       bool Function(AnalysisError) errorFilter,
       {int length}) async {
+    if (lintOffset < 0) {
+      return super._findErrorToFix(errorFilter, length: 0);
+    }
     return AnalysisError(
         testSource, lintOffset, length ?? 0, LintCode(lintCode, '<ignored>'));
   }
@@ -185,8 +194,8 @@
         }
       }
       if (actualNumberOfFixesForKind != expectedNumberOfFixesForKind) {
-        fail(
-            "Expected $expectedNumberOfFixesForKind fixes of kind $kind, but found $actualNumberOfFixesForKind:\n${fixes.join('\n')}");
+        fail('Expected $expectedNumberOfFixesForKind fixes of kind $kind,'
+            ' but found $actualNumberOfFixesForKind:\n${fixes.join('\n')}');
       }
     }
 
@@ -197,8 +206,13 @@
           return fix;
         }
       }
-      fail(
-          'Expected to find fix $kind with name $matchFixMessage in\n${fixes.join('\n')}');
+      if (fixes.isEmpty) {
+        fail('Expected to find fix $kind with name $matchFixMessage'
+            ' but there were no fixes.');
+      } else {
+        fail('Expected to find fix $kind with name $matchFixMessage'
+            ' in\n${fixes.join('\n')}');
+      }
     }
 
     // Assert that none of the fixes are a fix-all fix.
diff --git a/pkg/analysis_server/test/src/services/correction/fix/inline_invocation_test.dart b/pkg/analysis_server/test/src/services/correction/fix/inline_invocation_test.dart
index e895e79..82168ee 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/inline_invocation_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/inline_invocation_test.dart
@@ -26,7 +26,7 @@
   /// More coverage in the `inline_invocation_test.dart` assist test.
   Future<void> test_add_emptyTarget() async {
     await resolveTestUnit('''
-var l = []../*LINT*/add('a')..add('b');
+var l = []..add('a')..add('b');
 ''');
     await assertHasFix('''
 var l = ['a']..add('b');
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_argument_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_argument_test.dart
index 0ebd9c2..f324585 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_argument_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_argument_test.dart
@@ -28,7 +28,7 @@
 void f({bool valWithDefault = true, bool val}) {}
 
 void main() {
-  f(valWithDefault: /*LINT*/true);
+  f(valWithDefault: true);
 }
 ''');
     await assertHasFix('''
@@ -45,14 +45,14 @@
 void f({bool valWithDefault = true, bool val}) {}
 
 void main() {
-  f(valWithDefault: /*LINT*/true, false);
+  f(valWithDefault: true, val: false);
 }
 ''');
     await assertHasFix('''
 void f({bool valWithDefault = true, bool val}) {}
 
 void main() {
-  f(false);
+  f(val: false);
 }
 ''');
   }
@@ -62,7 +62,7 @@
 void g(int x, [int y = 0]) {}
 
 void main() {
-  g(1, /*LINT*/0);
+  g(1, 0);
 }
 ''');
     await assertHasFix('''
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_await_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_await_test.dart
index a0e4787..a9857ed 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_await_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_await_test.dart
@@ -26,7 +26,7 @@
   Future<void> test_intLiteral() async {
     await resolveTestUnit('''
 bad() async {
-  print(/*LINT*/await 23);
+  print(await 23);
 }
 ''');
     await assertHasFix('''
@@ -39,7 +39,7 @@
   Future<void> test_stringLiteral() async {
     await resolveTestUnit('''
 bad() async {
-  print(/*LINT*/await 'hola');
+  print(await 'hola');
 }
 ''');
     await assertHasFix('''
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_duplicate_case_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_duplicate_case_test.dart
index d8c9b4e..2317c0f 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_duplicate_case_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_duplicate_case_test.dart
@@ -31,9 +31,9 @@
       print('a');
       break;
     case 2:
-    case 2 /*LINT*/:
+    case 2:
     default:
-      print('?);
+      print('?');
   }
 }
 ''');
@@ -45,7 +45,7 @@
       break;
     case 2:
     default:
-      print('?);
+      print('?');
   }
 }
 ''');
@@ -62,11 +62,11 @@
     case 'b':
       print('b');
       break;
-    case 'a' /*LINT*/:
+    case 'a' :
       print('a');
       break;
     default:
-      print('?);
+      print('?');
   }
 }
 ''');
@@ -81,7 +81,7 @@
       print('b');
       break;
     default:
-      print('?);
+      print('?');
   }
 }
 ''');
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_empty_catch_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_empty_catch_test.dart
index bfff423..5d83554 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_empty_catch_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_empty_catch_test.dart
@@ -28,7 +28,7 @@
 void foo() {
   try {
     1;
-  } catch (e) {/*LINT*/
+  } catch (e) {
   } finally {
     2;
   }
@@ -48,7 +48,7 @@
   Future<void> test_singleCatch_finally_sameLine() async {
     await resolveTestUnit('''
 void foo() {
-  try {} catch (e) {/*LINT*/} finally {}
+  try {} catch (e) {} finally {}
 }
 ''');
     await assertHasFix('''
@@ -64,7 +64,7 @@
     await resolveTestUnit('''
 void foo() {
   try {
-  } catch (e) {/*LINT*/}
+  } catch (e) {}
 }
 ''');
     await assertNoFix();
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_empty_constructor_body_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_empty_constructor_body_test.dart
index fc57229..3a1a413 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_empty_constructor_body_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_empty_constructor_body_test.dart
@@ -26,7 +26,7 @@
   Future<void> test_empty() async {
     await resolveTestUnit('''
 class C {
-  C() {/*LINT*/}
+  C() {}
 }
 ''');
     await assertHasFix('''
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_empty_else_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_empty_else_test.dart
index 14fb311..907e83a 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_empty_else_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_empty_else_test.dart
@@ -29,7 +29,7 @@
   if (cond) {
     //
   }
-  else /*LINT*/;
+  else ;
 }
 ''');
     await assertHasFix('''
@@ -46,7 +46,7 @@
 void foo(bool cond) {
   if (cond) {
     //
-  } else /*LINT*/;
+  } else ;
 }
 ''');
     await assertHasFix('''
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_empty_statement_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_empty_statement_test.dart
index 211a7c3..c7f0fe8 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_empty_statement_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_empty_statement_test.dart
@@ -27,7 +27,7 @@
     await resolveTestUnit('''
 void foo() {
   while(true) {
-    /*LINT*/;
+    ;
   }
 }
 ''');
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_if_null_operator_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_if_null_operator_test.dart
index 3feb40a..17c760d 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_if_null_operator_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_if_null_operator_test.dart
@@ -26,7 +26,7 @@
   Future<void> test_left() async {
     await resolveTestUnit('''
 var a = '';
-var b = /*LINT*/null ?? a;
+var b = null ?? a;
 ''');
     await assertHasFix('''
 var a = '';
@@ -37,7 +37,7 @@
   Future<void> test_right() async {
     await resolveTestUnit('''
 var a = '';
-var b = /*LINT*/a ?? null;
+var b = a ?? null;
 ''');
     await assertHasFix('''
 var a = '';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_initializer_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_initializer_test.dart
index 25f3bd5..fe01b6d 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_initializer_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_initializer_test.dart
@@ -26,7 +26,7 @@
   Future<void> test_field() async {
     await resolveTestUnit('''
 class Test {
-  int /*LINT*/x = null;
+  int x = null;
 }
 ''');
     await assertHasFix('''
@@ -39,7 +39,7 @@
   Future<void> test_forLoop() async {
     await resolveTestUnit('''
 void f() {
-  for (var /*LINT*/i = null; i != null; i++) {
+  for (var i = null; i != null; i++) {
   }
 }
 ''');
@@ -53,7 +53,7 @@
 
   Future<void> test_listOfVariableDeclarations() async {
     await resolveTestUnit('''
-String a = 'a', /*LINT*/b = null, c = 'c';
+String a = 'a', b = null, c = 'c';
 ''');
     await assertHasFix('''
 String a = 'a', b, c = 'c';
@@ -62,7 +62,7 @@
 
   Future<void> test_parameter_optionalNamed() async {
     await resolveTestUnit('''
-void f({String /*LINT*/s = null}) {}
+void f({String s = null}) {}
 ''');
     await assertHasFix('''
 void f({String s}) {}
@@ -71,7 +71,7 @@
 
   Future<void> test_parameter_optionalPositional() async {
     await resolveTestUnit('''
-void f([String /*LINT*/s = null]) {}
+void f([String s = null]) {}
 ''');
     await assertHasFix('''
 void f([String s]) {}
@@ -80,7 +80,7 @@
 
   Future<void> test_topLevel() async {
     await resolveTestUnit('''
-var /*LINT*/x = null;
+var x = null;
 ''');
     await assertHasFix('''
 var x;
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_interpolation_braces_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_interpolation_braces_test.dart
index fcb23eb..46cc0ea 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_interpolation_braces_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_interpolation_braces_test.dart
@@ -27,7 +27,7 @@
     await resolveTestUnit(r'''
 main() {
   var v = 42;
-  print('v: /*LINT*/${ v}');
+  print('v: ${ v}');
 }
 ''');
     await assertHasFix(r'''
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_method_declaration_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_method_declaration_test.dart
index fd19334..cd3e80c 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_method_declaration_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_method_declaration_test.dart
@@ -26,17 +26,19 @@
   Future<void> test_getter() async {
     await resolveTestUnit('''
 class A {
-  int x;
+  int foo;
 }
+
 class B extends A {
   @override
-  int get /*LINT*/x => super.x;
+  int get foo => super.foo;
 }
 ''');
     await assertHasFix('''
 class A {
-  int x;
+  int foo;
 }
+
 class B extends A {
 }
 ''');
@@ -45,8 +47,85 @@
   Future<void> test_method() async {
     await resolveTestUnit('''
 class A {
+  int foo() => 0;
+}
+
+class B extends A {
   @override
-  String /*LINT*/toString() => super.toString();
+  int foo() => super.foo();
+}
+''');
+    await assertHasFix('''
+class A {
+  int foo() => 0;
+}
+
+class B extends A {
+}
+''');
+  }
+
+  @FailingTest(issue: 'https://github.com/dart-lang/linter/issues/1997')
+  Future<void> test_method_generic() async {
+    await resolveTestUnit('''
+class A<T> {
+  T foo() {
+    throw 42;
+  }
+}
+
+class B extends A<int> {
+  @override
+  int foo() => super.foo();
+}
+''');
+    await assertHasFix('''
+class A<T> {
+  T foo() {
+    throw 42;
+  }
+}
+
+class B extends A<int> {
+}
+''');
+  }
+
+  @FailingTest(issue: 'https://github.com/dart-lang/linter/issues/1997')
+  Future<void> test_method_nullSafety_optIn_fromOptOut() async {
+    createAnalysisOptionsFile(
+      experiments: ['non-nullable'],
+      lints: [lintCode],
+    );
+    newFile('/home/test/lib/a.dart', content: r'''
+class A {
+  int foo() => 0;
+}
+''');
+    await resolveTestUnit('''
+// @dart = 2.7
+import 'a.dart';
+
+class B extends A {
+  @override
+  int foo() => super.foo();
+}
+''');
+    await assertHasFix('''
+// @dart = 2.7
+import 'a.dart';
+
+class B extends A {
+}
+''');
+  }
+
+  /// TODO(scheglov) This test will fail with NNBD SDK.
+  Future<void> test_method_toString() async {
+    await resolveTestUnit('''
+class A {
+  @override
+  String toString() => super.toString();
 }
 ''');
     await assertHasFix('''
@@ -58,19 +137,21 @@
   Future<void> test_setter() async {
     await resolveTestUnit('''
 class A {
-  int x;
+  int foo;
 }
+
 class B extends A {
   @override
-  set /*LINT*/x(int other) {
-    this.x = other;
+  set /*LINT*/foo(int value) {
+    super.foo = value;
   }
 }
 ''');
     await assertHasFix('''
 class A {
-  int x;
+  int foo;
 }
+
 class B extends A {
 }
 ''');
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_operator_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_operator_test.dart
index 1568cf3..62c35d6 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_operator_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_operator_test.dart
@@ -25,7 +25,7 @@
 
   Future<void> test_plus() async {
     await resolveTestUnit('''
-var s = 'a' /*LINT*/+ 'b';
+var s = 'a' + 'b';
 ''');
     await assertHasFix('''
 var s = 'a' 'b';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_this_expression_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_this_expression_test.dart
index ad30634..a9e07f1 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_this_expression_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_this_expression_test.dart
@@ -27,7 +27,7 @@
     await resolveTestUnit('''
 class A {
   int x;
-  A(int x) : /*LINT*/this.x = x;
+  A(int x) : this.x = x;
 }
 ''');
     await assertHasFix('''
@@ -42,7 +42,7 @@
     await resolveTestUnit('''
 class A {
   void foo() {
-    /*LINT*/this.foo();
+    this.foo();
   }
 }
 ''');
@@ -59,7 +59,7 @@
     await resolveTestUnit('''
 class A {
   void foo() {
-    /*LINT*/this?.foo();
+    this?.foo();
   }
 }
 ''');
@@ -72,21 +72,12 @@
 ''');
   }
 
-  Future<void> test_notAThisExpression() async {
-    await resolveTestUnit('''
-void foo() {
-  final /*LINT*/this.id;
-}
-''');
-    await assertNoFix();
-  }
-
   Future<void> test_propertyAccess_oneCharacterOperator() async {
     await resolveTestUnit('''
 class A {
   int x;
   void foo() {
-    /*LINT*/this.x = 2;
+    this.x = 2;
   }
 }
 ''');
@@ -105,7 +96,7 @@
 class A {
   int x;
   void foo() {
-    /*LINT*/this?.x = 2;
+    this?.x = 2;
   }
 }
 ''');
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_type_annotation_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_type_annotation_test.dart
index 3e99462..b83f7d0 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_type_annotation_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_type_annotation_test.dart
@@ -25,7 +25,7 @@
 
   Future<void> test_insideFunctionTypedFormalParameter() async {
     await resolveTestUnit('''
-bad(void foo(/*LINT*/dynamic x)) {
+bad(void foo(dynamic x)) {
   return null;
 }
 ''');
@@ -38,7 +38,7 @@
 
   Future<void> test_namedParameter() async {
     await resolveTestUnit('''
-bad({/*LINT*/dynamic defaultValue}) {
+bad({dynamic defaultValue}) {
   return null;
 }
 ''');
@@ -51,7 +51,7 @@
 
   Future<void> test_normalParameter() async {
     await resolveTestUnit('''
-bad(/*LINT*/dynamic defaultValue) {
+bad(dynamic defaultValue) {
   return null;
 }
 ''');
@@ -64,7 +64,7 @@
 
   Future<void> test_optionalParameter() async {
     await resolveTestUnit('''
-bad([/*LINT*/dynamic defaultValue]) {
+bad([dynamic defaultValue]) {
   return null;
 }
 ''');
@@ -83,7 +83,7 @@
 
   Future<void> test_void() async {
     await resolveTestUnit('''
-/*LINT*/void set speed2(int ms) {}
+void set speed2(int ms) {}
 ''');
     await assertHasFix('''
 set speed2(int ms) {}
@@ -98,40 +98,28 @@
 
   Future<void> test_namedParameter() async {
     await resolveTestUnit('''
-var x = ({/*LINT*/Future<int> defaultValue}) {
-  return null;
-};
+var x = ({Future<int> defaultValue}) => null;
 ''');
     await assertHasFix('''
-var x = ({defaultValue}) {
-  return null;
-};
+var x = ({defaultValue}) => null;
 ''');
   }
 
   Future<void> test_normalParameter() async {
     await resolveTestUnit('''
-var x = (/*LINT*/Future<int> defaultValue) {
-  return null;
-};
+var x = (Future<int> defaultValue) => null;
 ''');
     await assertHasFix('''
-var x = (defaultValue) {
-  return null;
-};
+var x = (defaultValue) => null;
 ''');
   }
 
   Future<void> test_optionalParameter() async {
     await resolveTestUnit('''
-var x = ([/*LINT*/Future<int> defaultValue]) {
-  return null;
-};
+var x = ([Future<int> defaultValue]) => null;
 ''');
     await assertHasFix('''
-var x = ([defaultValue]) {
-  return null;
-};
+var x = ([defaultValue]) => null;
 ''');
   }
 }
@@ -151,7 +139,7 @@
     await resolveTestUnit('''
 class C {
   int f;
-  C(/*LINT*/int this.f);
+  C(int this.f);
 }
 ''');
     await assertHasFix('''
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_const_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_const_test.dart
index 7146abd..f9a1dbf 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_const_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_const_test.dart
@@ -23,36 +23,23 @@
   @override
   String get lintCode => LintNames.unnecessary_const;
 
-  Future<void> test_constConstructor() async {
-    await resolveTestUnit('''
-class A { const A(); }
-m(){
-  const a = /*LINT*/const A();
-}
-''');
-    await assertHasFix('''
-class A { const A(); }
-m(){
-  const a = A();
-}
-''');
-  }
-
   Future<void> test_instanceCreation() async {
     await resolveTestUnit('''
-const list = /*LINT*/const List();
+class C { const C(); }
+const c = const C();
 ''');
     await assertHasFix('''
-const list = List();
-''', length: 5);
+class C { const C(); }
+const c = C();
+''');
   }
 
   Future<void> test_typedLiteral() async {
     await resolveTestUnit('''
-const list = /*LINT*/const [];
+const list = const [];
 ''');
     await assertHasFix('''
 const list = [];
-''', length: 5);
+''');
   }
 }
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_new_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_new_test.dart
index d416ab8..c00dcb2 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_new_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_new_test.dart
@@ -26,14 +26,16 @@
   Future<void> test_constructor() async {
     await resolveTestUnit('''
 class A { A(); }
-m(){
-  final a = /*LINT*/new A();
+f() {
+  final a = new A();
+  print(a);
 }
 ''');
     await assertHasFix('''
 class A { A(); }
-m(){
+f() {
   final a = A();
+  print(a);
 }
 ''');
   }
diff --git a/pkg/analysis_server/test/src/services/correction/fix/rename_to_camel_case_test.dart b/pkg/analysis_server/test/src/services/correction/fix/rename_to_camel_case_test.dart
index 47d4102..e44d68d 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/rename_to_camel_case_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/rename_to_camel_case_test.dart
@@ -26,7 +26,7 @@
   Future<void> test_localVariable() async {
     await resolveTestUnit('''
 main() {
-  int /*LINT*/my_integer_variable = 42;
+  int my_integer_variable = 42;
   int foo;
   print(my_integer_variable);
   print(foo);
@@ -45,7 +45,7 @@
   Future<void> test_parameter_closure() async {
     await resolveTestUnit('''
 main() {
-  [0, 1, 2].forEach((/*LINT*/my_integer_variable) {
+  [0, 1, 2].forEach((my_integer_variable) {
     print(my_integer_variable);
   });
 }
@@ -61,7 +61,7 @@
 
   Future<void> test_parameter_function() async {
     await resolveTestUnit('''
-main(int /*LINT*/my_integer_variable) {
+main(int my_integer_variable) {
   print(my_integer_variable);
 }
 ''');
@@ -75,7 +75,7 @@
   Future<void> test_parameter_method() async {
     await resolveTestUnit('''
 class A {
-  main(int /*LINT*/my_integer_variable) {
+  main(int my_integer_variable) {
     print(my_integer_variable);
   }
 }
@@ -91,7 +91,7 @@
 
   Future<void> test_parameter_optionalNamed() async {
     await resolveTestUnit('''
-foo({int /*LINT*/my_integer_variable}) {
+foo({int my_integer_variable}) {
   print(my_integer_variable);
 }
 ''');
@@ -100,7 +100,7 @@
 
   Future<void> test_parameter_optionalPositional() async {
     await resolveTestUnit('''
-main([int /*LINT*/my_integer_variable]) {
+main([int my_integer_variable]) {
   print(my_integer_variable);
 }
 ''');
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_colon_with_equals_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_colon_with_equals_test.dart
index c7e3e59..698a9ed 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_colon_with_equals_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_colon_with_equals_test.dart
@@ -25,14 +25,10 @@
 
   Future<void> test_method() async {
     await resolveTestUnit('''
-void f1({int a}) { }    
-
-f1({a/*LINT*/: 1}) => null;
+void f({int a: 1}) => null;
 ''');
     await assertHasFix('''
-void f1({int a}) { }    
-
-f1({a = 1}) => null;
+void f({int a = 1}) => null;
 ''');
   }
 }
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_final_with_const_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_final_with_const_test.dart
index 60ea7bc..164990c 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_final_with_const_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_final_with_const_test.dart
@@ -25,7 +25,7 @@
 
   Future<void> test_method() async {
     await resolveTestUnit('''
-/*LINT*/final int a = 1;
+final int a = 1;
 ''');
     await assertHasFix('''
 const int a = 1;
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_new_with_const_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_new_with_const_test.dart
index 95d3073..4573b3a 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_new_with_const_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_new_with_const_test.dart
@@ -23,13 +23,14 @@
   @override
   String get lintCode => LintNames.prefer_const_constructors;
 
-  Future<void> test_basic() async {
+  Future<void> test_new() async {
     await resolveTestUnit('''
 class C {
   const C();
 }
 main() {
-  var c = new C/*LINT*/();
+  var c = new C();
+  print(c);
 }
 ''');
     await assertHasFix('''
@@ -38,17 +39,19 @@
 }
 main() {
   var c = const C();
+  print(c);
 }
 ''');
   }
 
-  Future<void> test_not_present() async {
+  Future<void> test_noKeyword() async {
     await resolveTestUnit('''
 class C {
   const C();
 }
 main() {
-  var c = C/*LINT*/();
+  var c = C();
+  print(c);
 }
 ''');
     // handled by ADD_CONST
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_null_with_closure_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_null_with_closure_test.dart
index 4c6024c..d974b43 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_null_with_closure_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_null_with_closure_test.dart
@@ -25,7 +25,6 @@
 
   /// Currently failing since the LINT annotation is tagging the ArgumentList
   /// where the fix (and lint) expect a NullLiteral.
-  /// todo (pq): re-write FixProcessorLintTest to run the actual lints.
   @failingTest
   Future<void> test_null_closure_literal() async {
     await resolveTestUnit('''
@@ -45,12 +44,12 @@
   Future<void> test_null_closure_named_expression() async {
     await resolveTestUnit('''
 main() {
-  [1, 3, 5].firstWhere((e) => e.isOdd, orElse: /*LINT*/null);
+  [1, 3, 5].firstWhere((e) => e.isEven, orElse: null);
 }
 ''');
     await assertHasFix('''
 main() {
-  [1, 3, 5].firstWhere((e) => e.isOdd, orElse: () => null);
+  [1, 3, 5].firstWhere((e) => e.isEven, orElse: () => null);
 }
 ''');
   }
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_with_brackets_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_with_brackets_test.dart
index 1d5ddaf..d265a95 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_with_brackets_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_with_brackets_test.dart
@@ -25,15 +25,15 @@
 
   Future<void> test_outOfBlock_otherLine() async {
     await resolveTestUnit('''
-void foo() {
-  while(true)
-  /*LINT*/;
+void f(bool c) {
+  while(c)
+  ;
   print('hi');
 }
 ''');
     await assertHasFix('''
-void foo() {
-  while(true) {}
+void f(bool c) {
+  while(c) {}
   print('hi');
 }
 ''');
@@ -41,14 +41,14 @@
 
   Future<void> test_outOfBlock_sameLine() async {
     await resolveTestUnit('''
-void foo() {
-  while(true)/*LINT*/;
+void f(bool c) {
+  while(c);
   print('hi');
 }
 ''');
     await assertHasFix('''
-void foo() {
-  while(true) {}
+void f(bool c) {
+  while(c) {}
   print('hi');
 }
 ''');
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_with_conditional_assignment_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_with_conditional_assignment_test.dart
index c54e29a..881c3c8f 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_with_conditional_assignment_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_with_conditional_assignment_test.dart
@@ -29,11 +29,12 @@
   String _fullName;
   void foo() {
     print('hi');
-    /*LINT*/if (_fullName == null) {
+    if (_fullName == null) {
       _fullName = getFullUserName(this);
     }
     print('hi');
   }
+  String getFullUserName(Person p) => '';
 }
 ''');
     await assertHasFix('''
@@ -44,6 +45,7 @@
     _fullName ??= getFullUserName(this);
     print('hi');
   }
+  String getFullUserName(Person p) => '';
 }
 ''');
   }
@@ -53,10 +55,11 @@
 class Person {
   String _fullName;
   void foo() {
-    /*LINT*/if (_fullName == null) {
+    if (_fullName == null) {
       _fullName = getFullUserName(this);
     }
   }
+  String getFullUserName(Person p) => '';
 }
 ''');
     await assertHasFix('''
@@ -65,6 +68,7 @@
   void foo() {
     _fullName ??= getFullUserName(this);
   }
+  String getFullUserName(Person p) => '';
 }
 ''');
   }
@@ -74,9 +78,10 @@
 class Person {
   String _fullName;
   void foo() {
-    /*LINT*/if (_fullName == null)
+    if (_fullName == null)
       _fullName = getFullUserName(this);
   }
+  String getFullUserName(Person p) => '';
 }
 ''');
     await assertHasFix('''
@@ -85,6 +90,7 @@
   void foo() {
     _fullName ??= getFullUserName(this);
   }
+  String getFullUserName(Person p) => '';
 }
 ''');
   }
@@ -94,10 +100,11 @@
 class Person {
   String _fullName;
   void foo() {
-    /*LINT*/if (_fullName == null) {{
+    if (_fullName == null) {{
       _fullName = getFullUserName(this);
     }}
   }
+  String getFullUserName(Person p) => '';
 }
 ''');
     await assertHasFix('''
@@ -106,6 +113,7 @@
   void foo() {
     _fullName ??= getFullUserName(this);
   }
+  String getFullUserName(Person p) => '';
 }
 ''');
   }
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_with_identifier_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_with_identifier_test.dart
index 5a5b9c3..259bf0d 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_with_identifier_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_with_identifier_test.dart
@@ -25,7 +25,7 @@
 
   Future<void> test_functionTypedFormalParameter() async {
     await resolveTestUnit('''
-var functionWithFunction = (/*LINT*/int f(int x)) => f(0);
+var functionWithFunction = (int f(int x)) => f(0);
 ''');
     await assertHasFix('''
 var functionWithFunction = (f) => f(0);
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_with_is_empty_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_with_is_empty_test.dart
index 1ecf23e..815abe6 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_with_is_empty_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_with_is_empty_test.dart
@@ -26,7 +26,7 @@
   Future<void> test_constantOnLeft_equal() async {
     await resolveTestUnit('''
 f(List c) {
-  if (/*LINT*/0 == c.length) {}
+  if (0 == c.length) {}
 }
 ''');
     await assertHasFix('''
@@ -39,7 +39,7 @@
   Future<void> test_constantOnLeft_greaterThan() async {
     await resolveTestUnit('''
 f(List c) {
-  if (/*LINT*/1 > c.length) {}
+  if (1 > c.length) {}
 }
 ''');
     await assertHasFix('''
@@ -52,7 +52,7 @@
   Future<void> test_constantOnLeft_greaterThanOrEqual() async {
     await resolveTestUnit('''
 f(List c) {
-  if (/*LINT*/0 >= c.length) {}
+  if (0 >= c.length) {}
 }
 ''');
     await assertHasFix('''
@@ -65,7 +65,7 @@
   Future<void> test_constantOnRight_equal() async {
     await resolveTestUnit('''
 f(List c) {
-  if (/*LINT*/c.length == 0) {}
+  if (c.length == 0) {}
 }
 ''');
     await assertHasFix('''
@@ -78,7 +78,7 @@
   Future<void> test_constantOnRight_lessThan() async {
     await resolveTestUnit('''
 f(List c) {
-  if (/*LINT*/c.length < 1) {}
+  if (c.length < 1) {}
 }
 ''');
     await assertHasFix('''
@@ -91,7 +91,7 @@
   Future<void> test_constantOnRight_lessThanOrEqual() async {
     await resolveTestUnit('''
 f(List c) {
-  if (/*LINT*/c.length <= 0) {}
+  if (c.length <= 0) {}
 }
 ''');
     await assertHasFix('''
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_with_is_not_empty_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_with_is_not_empty_test.dart
index c26dbb6..67d0e67 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_with_is_not_empty_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_with_is_not_empty_test.dart
@@ -26,7 +26,7 @@
   Future<void> test_constantOnLeft_lessThanOrEqual() async {
     await resolveTestUnit('''
 f(List c) {
-  if (/*LINT*/1 <= c.length) {}
+  if (1 <= c.length) {}
 }
 ''');
     await assertHasFix('''
@@ -39,7 +39,7 @@
   Future<void> test_constantOnLeft_notEqual() async {
     await resolveTestUnit('''
 f(List c) {
-  if (/*LINT*/0 != c.length) {}
+  if (0 != c.length) {}
 }
 ''');
     await assertHasFix('''
@@ -52,7 +52,7 @@
   Future<void> test_constantOnRight_greaterThanOrEqual() async {
     await resolveTestUnit('''
 f(List c) {
-  if (/*LINT*/c.length >= 1) {}
+  if (c.length >= 1) {}
 }
 ''');
     await assertHasFix('''
@@ -65,7 +65,7 @@
   Future<void> test_constantOnRight_notEqual() async {
     await resolveTestUnit('''
 f(List c) {
-  if (/*LINT*/c.length != 0) {}
+  if (c.length != 0) {}
 }
 ''');
     await assertHasFix('''
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_with_tear_off_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_with_tear_off_test.dart
index 2199104..cf9cc3d 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_with_tear_off_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_with_tear_off_test.dart
@@ -25,12 +25,12 @@
 
   Future<void> test_function_oneParameter() async {
     await resolveTestUnit('''
-final x = /*LINT*/(name) {
+Function f() => (name) {
   print(name);
 };
 ''');
     await assertHasFix('''
-final x = print;
+Function f() => print;
 ''');
   }
 
@@ -38,7 +38,7 @@
     await resolveTestUnit('''
 void foo(){}
 Function finalVar() {
-  return /*LINT*/() {
+  return () {
     foo();
   };
 }
@@ -56,7 +56,7 @@
 void foo() {
   bool isPair(int a) => a % 2 == 0;
   final finalList = <int>[];
-  finalList.where(/*LINT*/(number) =>
+  finalList.where((number) =>
     isPair(number));
 }
 ''');
@@ -71,24 +71,26 @@
 
   Future<void> test_method_oneParameter() async {
     await resolveTestUnit('''
-var a = /*LINT*/(x) => finalList.remove(x);
+final l = <int>[];
+var a = (x) => l.indexOf(x);
 ''');
     await assertHasFix('''
-var a = finalList.remove;
+final l = <int>[];
+var a = l.indexOf;
 ''');
   }
 
   Future<void> test_method_zeroParameter() async {
     await resolveTestUnit('''
-final Object a;
+final Object a = '';
 Function finalVar() {
-  return /*LINT*/() {
+  return () {
     return a.toString();
   };
 }
 ''');
     await assertHasFix('''
-final Object a;
+final Object a = '';
 Function finalVar() {
   return a.toString;
 }
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_with_var_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_with_var_test.dart
index b1b2d9c..08fa570 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_with_var_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_with_var_test.dart
@@ -26,7 +26,7 @@
   Future<void> test_for() async {
     await resolveTestUnit('''
 void f(List<int> list) {
-  for (/*LINT*/int i = 0; i < list.length; i++) {
+  for (int i = 0; i < list.length; i++) {
     print(i);
   }
 }
@@ -43,7 +43,7 @@
   Future<void> test_forEach() async {
     await resolveTestUnit('''
 void f(List<int> list) {
-  for (/*LINT*/int i in list) {
+  for (int i in list) {
     print(i);
   }
 }
@@ -60,7 +60,7 @@
   Future<void> test_generic_instanceCreation_withArguments() async {
     await resolveTestUnit('''
 C<int> f() {
-  /*LINT*/C<int> c = C<int>();
+  C<int> c = C<int>();
   return c;
 }
 class C<T> {}
@@ -77,7 +77,7 @@
   Future<void> test_generic_instanceCreation_withoutArguments() async {
     await resolveTestUnit('''
 C<int> f() {
-  /*LINT*/C<int> c = C();
+  C<int> c = C();
   return c;
 }
 class C<T> {}
@@ -94,7 +94,7 @@
   Future<void> test_generic_listLiteral() async {
     await resolveTestUnit('''
 List f() {
-  /*LINT*/List<int> l = [];
+  List<int> l = [];
   return l;
 }
 ''');
@@ -109,7 +109,7 @@
   Future<void> test_generic_mapLiteral() async {
     await resolveTestUnit('''
 Map f() {
-  /*LINT*/Map<String, int> m = {};
+  Map<String, int> m = {};
   return m;
 }
 ''');
@@ -124,7 +124,7 @@
   Future<void> test_generic_setLiteral() async {
     await resolveTestUnit('''
 Set f() {
-  /*LINT*/Set<int> s = {};
+  Set<int> s = {};
   return s;
 }
 ''');
@@ -139,7 +139,7 @@
   Future<void> test_generic_setLiteral_ambiguous() async {
     await resolveTestUnit('''
 Set f() {
-  /*LINT*/Set s = {};
+  Set s = {};
   return s;
 }
 ''');
@@ -149,7 +149,7 @@
   Future<void> test_simple() async {
     await resolveTestUnit('''
 String f() {
-  /*LINT*/String s = '';
+  String s = '';
   return s;
 }
 ''');
diff --git a/pkg/analysis_server/test/src/services/correction/fix/sort_child_property_last_test.dart b/pkg/analysis_server/test/src/services/correction/fix/sort_child_property_last_test.dart
index 035a6cf..8da5969 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/sort_child_property_last_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/sort_child_property_last_test.dart
@@ -30,7 +30,7 @@
 import 'package:flutter/material.dart';
 main() {
   Column(
-    /*LINT*/children: <Widget>[
+    children: <Widget>[
       Text('aaa'),
       Text('bbbbbb'),
       Text('ccccccccc'),
diff --git a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
index cb1657b..b2647d3 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
@@ -41,6 +41,7 @@
 import 'convert_flutter_child_test.dart' as convert_flutter_child;
 import 'convert_flutter_children_test.dart' as convert_flutter_children;
 import 'convert_into_expression_body_test.dart' as convert_into_expression_body;
+import 'convert_to_contains_test.dart' as convert_to_contains;
 import 'convert_to_for_element_test.dart' as convert_to_for_element;
 import 'convert_to_generic_function_syntax_test.dart'
     as convert_to_generic_function_syntax;
@@ -180,6 +181,7 @@
     convert_flutter_child.main();
     convert_flutter_children.main();
     convert_into_expression_body.main();
+    convert_to_contains.main();
     convert_to_for_element.main();
     convert_to_generic_function_syntax.main();
     convert_to_if_element.main();
diff --git a/pkg/analysis_server/test/src/services/correction/fix/use_is_not_empty_test.dart b/pkg/analysis_server/test/src/services/correction/fix/use_is_not_empty_test.dart
index b413b49..14cdc4b 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/use_is_not_empty_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/use_is_not_empty_test.dart
@@ -25,13 +25,13 @@
 
   Future<void> test_notIsEmpty() async {
     await resolveTestUnit('''
-f(c) {
-  if (/*LINT*/!c.isEmpty) {}
+f(List<int> l) {
+  if (!l.isEmpty) {}
 }
 ''');
     await assertHasFix('''
-f(c) {
-  if (c.isNotEmpty) {}
+f(List<int> l) {
+  if (l.isNotEmpty) {}
 }
 ''');
   }
diff --git a/pkg/analysis_server/test/src/services/correction/fix/use_rethrow_test.dart b/pkg/analysis_server/test/src/services/correction/fix/use_rethrow_test.dart
index 9a4eb7a..4d8c8a10 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/use_rethrow_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/use_rethrow_test.dart
@@ -27,7 +27,7 @@
     await resolveTestUnit('''
 void bad1() {
   try {} catch (e) {
-    throw/*LINT*/ e;
+    throw e;
   }
 }
 ''');
diff --git a/pkg/analysis_server/test/test_all.dart b/pkg/analysis_server/test/test_all.dart
index 9ed34eb..0f8d453 100644
--- a/pkg/analysis_server/test/test_all.dart
+++ b/pkg/analysis_server/test/test_all.dart
@@ -9,6 +9,7 @@
 import 'analysis_server_test.dart' as analysis_server;
 import 'benchmarks_test.dart' as benchmarks;
 import 'channel/test_all.dart' as channel;
+import 'client/test_all.dart' as client;
 import 'completion_test.dart' as completion;
 import 'context_manager_test.dart' as context_manager;
 import 'domain_analysis_test.dart' as domain_analysis;
@@ -35,6 +36,7 @@
     analysis_server.main();
     benchmarks.main();
     channel.main();
+    client.main();
     completion.main();
     context_manager.main();
     domain_analysis.main();
diff --git a/pkg/analysis_server/tool/completion_metrics/completion_metrics.dart b/pkg/analysis_server/tool/completion_metrics/completion_metrics.dart
index e3cbbcb..913e94d 100644
--- a/pkg/analysis_server/tool/completion_metrics/completion_metrics.dart
+++ b/pkg/analysis_server/tool/completion_metrics/completion_metrics.dart
@@ -28,33 +28,39 @@
 // TODO(jwren) have the analysis root and verbose option be configurable via a
 //  command line UX
 Future<void> main() async {
-  await CompletionMetricsComputer('', true).computeCompletionMetrics();
+  await CompletionCoverageMetrics('').compute();
+//  await RelevanceAnalyzerMetrics('', [RHSOfAsExpression()]).compute();
 }
 
 /// This is the main metrics computer class for code completions. After the
 /// object is constructed, [computeCompletionMetrics] is executed to do analysis
 /// and print a summary of the metrics gathered from the completion tests.
-class CompletionMetricsComputer {
-  /// The analysis root path that this CompletionMetrics class will be computed.
+abstract class AbstractCompletionMetricsComputer {
   final String _rootPath;
 
-  /// When enabled, expected, but missing completion tokens will be printed to
-  /// stdout.
-  final bool _verbose;
+  String _currentFilePath;
 
-  final RelevanceAnalyzer _relevanceAnalyzer = null;
+  ResolvedUnitResult _resolvedUnitResult;
 
-  CompletionMetricsComputer(this._rootPath, this._verbose);
+  final CompletionPerformance _performance = CompletionPerformance();
 
-  Future computeCompletionMetrics() async {
-    int includedCount = 0;
-    int notIncludedCount = 0;
-    var completionMissedTokenCounter = Counter('missing completion counter');
-    var completionKindCounter = Counter('completion kind counter');
-    var completionElementKindCounter =
-        Counter('completion element kind counter');
-    var mRRComputer = MeanReciprocalRankComputer();
+  AbstractCompletionMetricsComputer(this._rootPath);
 
+  /// The path to the current file.
+  String get currentFilePath => _currentFilePath;
+
+  /// If the concrete class has this getter return true, then when
+  /// [forEachExpectedCompletion] is called, the [List] of
+  /// [CompletionSuggestion]s will be passed.
+  bool get doComputeCompletionsFromAnalysisServer;
+
+  /// The current [ResolvedUnitResult].
+  ResolvedUnitResult get resolvedUnitResult => _resolvedUnitResult;
+
+  /// The analysis root path that this CompletionMetrics class will be computed.
+  String get rootPath => _rootPath;
+
+  void compute() async {
     print('Analyzing root: \"$_rootPath\"');
 
     if (!io.Directory(_rootPath).existsSync()) {
@@ -68,21 +74,27 @@
     );
 
     for (var context in collection.contexts) {
+      // Set the DeclarationsTracker, only call doWork to build up the available
+      // suggestions if doComputeCompletionsFromAnalysisServer is true.
       var declarationsTracker = DeclarationsTracker(
           MemoryByteStore(), PhysicalResourceProvider.INSTANCE);
       declarationsTracker.addContext(context);
-
-      while (declarationsTracker.hasWork) {
-        declarationsTracker.doWork();
+      if (doComputeCompletionsFromAnalysisServer) {
+        while (declarationsTracker.hasWork) {
+          declarationsTracker.doWork();
+        }
       }
 
+      // Loop through each file, resolve the file and call
+      // forEachExpectedCompletion
       for (var filePath in context.contextRoot.analyzedFiles()) {
         if (AnalysisEngine.isDartFileName(filePath)) {
+          _currentFilePath = filePath;
           try {
-            final resolvedUnitResult =
+            _resolvedUnitResult =
                 await context.currentSession.getResolvedUnit(filePath);
 
-            var error = _getFirstErrorOrNull(resolvedUnitResult);
+            var error = getFirstErrorOrNull(resolvedUnitResult);
             if (error != null) {
               print('File $filePath skipped due to errors such as:');
               print('  ${error.toString()}');
@@ -96,39 +108,15 @@
             resolvedUnitResult.unit.accept(visitor);
 
             for (var expectedCompletion in visitor.expectedCompletions) {
-              var suggestions = await _computeCompletionSuggestions(
-                  resolvedUnitResult,
-                  expectedCompletion.offset,
-                  declarationsTracker);
-
-              var place =
-                  _placementInSuggestionList(suggestions, expectedCompletion);
-
-              mRRComputer.addReciprocalRank(place);
-
-              _relevanceAnalyzer?.report(expectedCompletion);
-
-              if (place.denominator != 0) {
-                includedCount++;
-              } else {
-                notIncludedCount++;
-
-                completionMissedTokenCounter
-                    .count(expectedCompletion.completion);
-                completionKindCounter.count(expectedCompletion.kind.toString());
-                completionElementKindCounter
-                    .count(expectedCompletion.elementKind.toString());
-
-                if (_verbose) {
-                  // The format "/file/path/foo.dart:3:4" makes for easier input
-                  // with the Files dialog in IntelliJ
-                  print(
-                      '$filePath:${expectedCompletion.lineNumber}:${expectedCompletion.columnNumber}');
-                  print(
-                      '\tdid not include the expected completion: \"${expectedCompletion.completion}\", completion kind: ${expectedCompletion.kind.toString()}, element kind: ${expectedCompletion.elementKind.toString()}');
-                  print('');
-                }
-              }
+              // Call forEachExpectedCompletion, passing in the computed
+              // suggestions only if doComputeCompletionsFromAnalysisServer is
+              // true:
+              forEachExpectedCompletion(
+                  expectedCompletion,
+                  doComputeCompletionsFromAnalysisServer
+                      ? await _computeCompletionSuggestions(resolvedUnitResult,
+                          expectedCompletion.offset, declarationsTracker)
+                      : null);
             }
           } catch (e) {
             print('Exception caught analyzing: $filePath');
@@ -137,41 +125,18 @@
         }
       }
     }
-
-    final totalCompletionCount = includedCount + notIncludedCount;
-    final percentIncluded = includedCount / totalCompletionCount;
-    final percentNotIncluded = 1 - percentIncluded;
-
-    completionMissedTokenCounter.printCounterValues();
-    print('');
-
-    completionKindCounter.printCounterValues();
-    print('');
-
-    completionElementKindCounter.printCounterValues();
-    print('');
-
-    mRRComputer.printMean();
-    print('');
-
-    print('Summary for $_rootPath:');
-    print('Total number of completion tests   = $totalCompletionCount');
-    print(
-        'Number of successful completions   = $includedCount (${printPercentage(percentIncluded)})');
-    print(
-        'Number of unsuccessful completions = $notIncludedCount (${printPercentage(percentNotIncluded)})');
-
-    includedCount = 0;
-    notIncludedCount = 0;
-    completionMissedTokenCounter.clear();
-    completionKindCounter.clear();
-    completionElementKindCounter.clear();
-    mRRComputer.clear();
-
-    _relevanceAnalyzer?.printData();
-    _relevanceAnalyzer?.clear();
+    printAndClearComputers();
   }
 
+  /// Overridden by each subclass, this method gathers some set of data from
+  /// each [ExpectedCompletion], and each [CompletionSuggestion] list (if
+  /// [doComputeCompletionsFromAnalysisServer] is set to true.)
+  void forEachExpectedCompletion(ExpectedCompletion expectedCompletion,
+      List<CompletionSuggestion> suggestions);
+
+  /// This method is called to print a summary of the data collected.
+  void printAndClearComputers();
+
   Future<List<CompletionSuggestion>> _computeCompletionSuggestions(
       ResolvedUnitResult resolvedUnitResult, int offset,
       [DeclarationsTracker declarationsTracker]) async {
@@ -214,7 +179,7 @@
 
   /// Given some [ResolvedUnitResult] return the first error of high severity
   /// if such an error exists, null otherwise.
-  err.AnalysisError _getFirstErrorOrNull(
+  static err.AnalysisError getFirstErrorOrNull(
       ResolvedUnitResult resolvedUnitResult) {
     for (var error in resolvedUnitResult.errors) {
       if (error.severity == Severity.error) {
@@ -224,7 +189,7 @@
     return null;
   }
 
-  Place _placementInSuggestionList(List<CompletionSuggestion> suggestions,
+  static Place placementInSuggestionList(List<CompletionSuggestion> suggestions,
       ExpectedCompletion expectedCompletion) {
     var placeCounter = 1;
     for (var completionSuggestion in suggestions) {
@@ -236,3 +201,115 @@
     return Place.none();
   }
 }
+
+class CompletionCoverageMetrics extends AbstractCompletionMetricsComputer {
+  int includedCount = 0;
+  int notIncludedCount = 0;
+  var completionMissedTokenCounter = Counter('missing completion counter');
+  var completionKindCounter = Counter('completion kind counter');
+  var completionElementKindCounter = Counter('completion element kind counter');
+  var mRRComputer = MeanReciprocalRankComputer();
+
+  CompletionCoverageMetrics(String rootPath) : super(rootPath);
+
+  @override
+  bool get doComputeCompletionsFromAnalysisServer => true;
+
+  @override
+  void forEachExpectedCompletion(ExpectedCompletion expectedCompletion,
+      List<CompletionSuggestion> suggestions) {
+    assert(suggestions != null);
+
+    var place = AbstractCompletionMetricsComputer.placementInSuggestionList(
+        suggestions, expectedCompletion);
+
+    mRRComputer.addRank(place.rank);
+
+    if (place.denominator != 0) {
+      includedCount++;
+    } else {
+      notIncludedCount++;
+
+      completionMissedTokenCounter.count(expectedCompletion.completion);
+      completionKindCounter.count(expectedCompletion.kind.toString());
+      completionElementKindCounter
+          .count(expectedCompletion.elementKind.toString());
+
+      // The format "/file/path/foo.dart:3:4" makes for easier input
+      // with the Files dialog in IntelliJ
+      print(
+          '$currentFilePath:${expectedCompletion.lineNumber}:${expectedCompletion.columnNumber}');
+      print(
+          '\tdid not include the expected completion: \"${expectedCompletion.completion}\", completion kind: ${expectedCompletion.kind.toString()}, element kind: ${expectedCompletion.elementKind.toString()}');
+      print('');
+    }
+  }
+
+  @override
+  void printAndClearComputers() {
+    final totalCompletionCount = includedCount + notIncludedCount;
+    final percentIncluded = includedCount / totalCompletionCount;
+    final percentNotIncluded = 1 - percentIncluded;
+
+    completionMissedTokenCounter.printCounterValues();
+    print('');
+
+    completionKindCounter.printCounterValues();
+    print('');
+
+    completionElementKindCounter.printCounterValues();
+    print('');
+
+    mRRComputer.printMean();
+    print('');
+
+    print('Summary for $_rootPath:');
+    print('Total number of completion tests   = $totalCompletionCount');
+    print(
+        'Number of successful completions   = $includedCount (${printPercentage(percentIncluded)})');
+    print(
+        'Number of unsuccessful completions = $notIncludedCount (${printPercentage(percentNotIncluded)})');
+
+    includedCount = 0;
+    notIncludedCount = 0;
+    completionMissedTokenCounter.clear();
+    completionKindCounter.clear();
+    completionElementKindCounter.clear();
+    mRRComputer.clear();
+  }
+}
+
+class RelevanceAnalyzerMetrics extends AbstractCompletionMetricsComputer {
+  /// A non-null list of [RelevanceAnalyzer]s to execute when computing the
+  /// completion metrics.
+  final List<RelevanceAnalyzer> _relevanceAnalyzers;
+
+  RelevanceAnalyzerMetrics(String rootPath, this._relevanceAnalyzers)
+      : assert(_relevanceAnalyzers.isNotEmpty),
+        super(rootPath);
+
+  @override
+  bool get doComputeCompletionsFromAnalysisServer => false;
+
+  List<RelevanceAnalyzer> get relevanceAnalyzers => _relevanceAnalyzers;
+
+  @override
+  void forEachExpectedCompletion(ExpectedCompletion expectedCompletion,
+      List<CompletionSuggestion> suggestions) async {
+    assert(suggestions == null);
+    var dartCompletionRequest = await DartCompletionRequestImpl.from(
+        CompletionRequestImpl(
+            resolvedUnitResult, expectedCompletion.offset, _performance));
+
+    _relevanceAnalyzers.forEach((analyzer) =>
+        analyzer.report(expectedCompletion, dartCompletionRequest));
+  }
+
+  @override
+  void printAndClearComputers() {
+    print('\nRelevance Analysis (count: ${_relevanceAnalyzers.length}):');
+    _relevanceAnalyzers.forEach((analyzer) => analyzer
+      ..printData()
+      ..clear());
+  }
+}
diff --git a/pkg/analysis_server/tool/completion_metrics/metrics_util.dart b/pkg/analysis_server/tool/completion_metrics/metrics_util.dart
index 30450de..7552187 100644
--- a/pkg/analysis_server/tool/completion_metrics/metrics_util.dart
+++ b/pkg/analysis_server/tool/completion_metrics/metrics_util.dart
@@ -50,39 +50,45 @@
 
   void printCounterValues() {
     print('Counts for \'$name\':');
-    _buckets.forEach((id, count) =>
-        print('[$id] $count (${printPercentage(count / _totalCount, 2)})'));
+    if (totalCount > 0) {
+      _buckets.forEach((id, count) =>
+          print('[$id] $count (${printPercentage(count / _totalCount, 2)})'));
+    } else {
+      print('<no counts>');
+    }
   }
 }
 
 /// A computer for the mean reciprocal rank,
 /// https://en.wikipedia.org/wiki/Mean_reciprocal_rank.
 class MeanReciprocalRankComputer {
-  final List<double> _ranks = [];
+  final List<int> ranks = [];
   MeanReciprocalRankComputer();
 
-  double get mean {
+  double get mrr {
+    if (ranks.isEmpty) {
+      return 0;
+    }
+
     double sum = 0;
-    _ranks.forEach((rank) {
-      sum += rank;
+    ranks.forEach((rank) {
+      sum += rank != 0 ? (1 / rank) : 0;
     });
-    return rankCount == 0 ? 0 : sum / rankCount;
+    return sum / rankCount;
   }
 
-  int get rankCount => _ranks.length;
+  int get rankCount => ranks.length;
 
-  int get ranks => _ranks.length;
-
-  void addReciprocalRank(Place place) {
-    _ranks.add(place.reciprocalRank);
+  void addRank(int rank) {
+    ranks.add(rank);
   }
 
-  void clear() => _ranks.clear();
+  void clear() => ranks.clear();
 
   void printMean() {
-    var mrr = mean;
-    print('Mean Reciprocal Rank    = ${mrr.toStringAsFixed(5)}');
-    print('Harmonic Mean (inverse) = ${(1 / mrr).toStringAsFixed(1)}');
+    var mrrVal = mrr;
+    print('Mean Reciprocal Rank    = ${mrrVal.toStringAsFixed(5)}');
+    print('Harmonic Mean (inverse) = ${(1 / mrrVal).toStringAsFixed(2)}');
   }
 }
 
@@ -110,7 +116,7 @@
 
   int get numerator => _numerator;
 
-  double get reciprocalRank => denominator == 0 ? 0 : numerator / denominator;
+  int get rank => _numerator;
 
   @override
   bool operator ==(dynamic other) =>
diff --git a/pkg/analysis_server/tool/completion_metrics/relevance_analyzers.dart b/pkg/analysis_server/tool/completion_metrics/relevance_analyzers.dart
index ff8fc20..aab8b2c 100644
--- a/pkg/analysis_server/tool/completion_metrics/relevance_analyzers.dart
+++ b/pkg/analysis_server/tool/completion_metrics/relevance_analyzers.dart
@@ -2,11 +2,19 @@
 // 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:analysis_server/src/provisional/completion/dart/completion_dart.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 
 import 'metrics_util.dart';
 import 'visitors.dart';
 
+/// Concrete instances of [RelevanceAnalyzer]s are intended to assist in the
+/// collection of data around the best relevances for completions in specific
+/// locations in the AST.  Concrete classes override [isApplicable], which
+/// accepts an [ExpectedCompletion], the objects created by
+/// [ExpectedCompletionsVisitor], as well as a [DartCompletionRequest], the same
+/// object used in the [DartCompletionManager] to identify which completions and
+/// relevances a user should see when using code completion.
 abstract class RelevanceAnalyzer {
   final String _name;
   final Counter _counter;
@@ -18,24 +26,30 @@
 
   void clear() => _counter.clear();
 
-  bool isApplicable(ExpectedCompletion expectedCompletion);
+  bool isApplicable(ExpectedCompletion expectedCompletion,
+      DartCompletionRequest dartCompletionRequest);
 
   void printData() {
     _counter.printCounterValues();
+    print('');
   }
 
-  void report(ExpectedCompletion expectedCompletion) {
-    if (isApplicable(expectedCompletion)) {
+  void report(ExpectedCompletion expectedCompletion,
+      DartCompletionRequest dartCompletionRequest) {
+    if (isApplicable(expectedCompletion, dartCompletionRequest)) {
       _counter.count(expectedCompletion.elementKind.toString());
     }
   }
 }
 
+/// This [RelevanceAnalyzer] gathers data on the right hand side of an
+/// [AsExpression].
 class RHSOfAsExpression extends RelevanceAnalyzer {
   RHSOfAsExpression() : super('RHS Of AsExpression');
 
   @override
-  bool isApplicable(ExpectedCompletion expectedCompletion) {
+  bool isApplicable(ExpectedCompletion expectedCompletion,
+      DartCompletionRequest dartCompletionRequest) {
     var entity = expectedCompletion.syntacticEntity;
     if (entity is AstNode) {
       var asExpression = entity.thisOrAncestorOfType<AsExpression>();
diff --git a/pkg/analysis_server/tool/nnbd_migration/check_generated_test.dart b/pkg/analysis_server/tool/nnbd_migration/check_generated_test.dart
new file mode 100644
index 0000000..228656c
--- /dev/null
+++ b/pkg/analysis_server/tool/nnbd_migration/check_generated_test.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2020, 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 'generate_resources.dart' as generate_resources;
+
+/// Validate that the
+/// pkg/analysis_server/lib/src/edit/nnbd_migration/resources/resources.g.dart
+/// file was regenerated after changing upstream dependencies.
+void main() async {
+  generate_resources.main(['--verify']);
+}
diff --git a/pkg/analysis_server/tool/nnbd_migration/generate_resources.dart b/pkg/analysis_server/tool/nnbd_migration/generate_resources.dart
index 7e8fc56..7b0d82e 100644
--- a/pkg/analysis_server/tool/nnbd_migration/generate_resources.dart
+++ b/pkg/analysis_server/tool/nnbd_migration/generate_resources.dart
@@ -10,9 +10,21 @@
 import 'dart:io';
 import 'dart:math' as math;
 
+import 'package:crypto/crypto.dart';
 import 'package:path/path.dart' as path;
 
-void main(List<String> args) {
+void main(List<String> args) async {
+  if (args.isEmpty) {
+    // this is valid
+  } else if (args.length != 1 || args.first != '--verify') {
+    fail('''
+usage: dart pkg/analysis_server/tool/nnbd_migration/generate_resources.dart [--verify]
+
+Run with no args to generate web resources for the NNBD migration preview tool.
+Run with '--verify' to validate that the web resource have been regenerated.
+''');
+  }
+
   if (FileSystemEntity.isFileSync(
       path.join('tool', 'nnbd_migration', 'generate_resources.dart'))) {
     // We're running from the project root - cd up two directories.
@@ -22,17 +34,84 @@
     fail('Please run this tool from the root of the sdk repo.');
   }
 
-  Directory resourceDir = Directory(path.join('pkg', 'analysis_server', 'lib',
-      'src', 'edit', 'nnbd_migration', 'resources'));
+  bool verify = args.isNotEmpty && args.first == '--verify';
 
+  if (verify) {
+    verifyResourcesGDartGenerated();
+  } else {
+    await compileWebFrontEnd();
+
+    createResourcesGDart();
+  }
+}
+
+final Directory resourceDir = Directory(path.join('pkg', 'analysis_server',
+    'lib', 'src', 'edit', 'nnbd_migration', 'resources'));
+final File resourcesFile = File(path.join('pkg', 'analysis_server', 'lib',
+    'src', 'edit', 'nnbd_migration', 'resources', 'resources.g.dart'));
+
+final File dartSources = File(path.join('pkg', 'analysis_server', 'lib', 'src',
+    'edit', 'nnbd_migration', 'web', 'migration.dart'));
+final javascriptOutput = File(path.join('pkg', 'analysis_server', 'lib', 'src',
+    'edit', 'nnbd_migration', 'resources', 'migration.js'));
+
+void verifyResourcesGDartGenerated() {
+  print('Verifying that ${path.basename(resourcesFile.path)} is up-to-date...');
+
+  // Find the hashes for the last generated version of resources.g.dart.
+  Map<String, String> resourceHashes = {};
+  // highlight_css md5 is 'fb012626bafd286510d32da815dae448'
+  RegExp hashPattern = RegExp(r"// (\S+) md5 is '(\S+)'");
+  for (RegExpMatch match
+      in hashPattern.allMatches(resourcesFile.readAsStringSync())) {
+    resourceHashes[match.group(1)] = match.group(2);
+  }
+
+  // For all resources (modulo compiled JS ones), verify the hash.
+  for (FileSystemEntity entity in resourceDir.listSync()) {
+    String name = path.basename(entity.path);
+    if (!name.endsWith('.js') && !name.endsWith('.css')) {
+      continue;
+    }
+
+    if (name == 'migration.js') {
+      // skip the compiled js
+      continue;
+    }
+
+    String key = name.replaceAll('.', '_');
+    if (!resourceHashes.containsKey(key)) {
+      failGenerate('No entry on resources.g.dart for $name');
+    } else {
+      String hash = md5String((entity as File).readAsStringSync());
+      if (hash != resourceHashes[key]) {
+        failGenerate('$name not up to date in resources.g.dart');
+      }
+    }
+  }
+
+  // verify the compiled dart code
+  StringBuffer sourceCode = StringBuffer();
+  for (FileSystemEntity entity in dartSources.parent.listSync()) {
+    if (entity.path.endsWith('.dart')) {
+      sourceCode.write((entity as File).readAsStringSync());
+    }
+  }
+  String hash = md5String(sourceCode.toString());
+  if (hash != resourceHashes['migration_dart']) {
+    failGenerate('Compiled javascript not up to date in resources.g.dart');
+  }
+
+  print('Generated resources up to date.');
+}
+
+void createResourcesGDart() {
   String content = generateResourceFile(resourceDir.listSync().where((entity) {
     String name = path.basename(entity.path);
     return entity is File && (name.endsWith('.js') || name.endsWith('.css'));
   }).cast<File>());
 
   // write the content
-  File resourcesFile = File(path.join('pkg', 'analysis_server', 'lib', 'src',
-      'edit', 'nnbd_migration', 'resources', 'resources.g.dart'));
   resourcesFile.writeAsStringSync(content);
 }
 
@@ -74,6 +153,21 @@
 
     buf.writeln();
     buf.writeln('String _$name;');
+    if (name == path.basename(javascriptOutput.path).replaceAll('.', '_')) {
+      // Write out the crc for the dart code.
+      StringBuffer sourceCode = StringBuffer();
+      // collect the dart source code
+      for (FileSystemEntity entity in dartSources.parent.listSync()) {
+        if (entity.path.endsWith('.dart')) {
+          sourceCode.write((entity as File).readAsStringSync());
+        }
+      }
+      buf.writeln(
+          "// migration_dart md5 is '${md5String(sourceCode.toString())}'");
+    } else {
+      // highlight_css md5 is 'fb012626bafd286510d32da815dae448'
+      buf.writeln("// $name md5 is '${md5String(source)}'");
+    }
     buf.writeln('String _${name}_base64 = $delimiter');
     buf.writeln(base64Encode(source.codeUnits));
     buf.writeln('$delimiter;');
@@ -82,11 +176,14 @@
   return buf.toString();
 }
 
+String md5String(String str) {
+  return md5.convert(str.codeUnits).toString();
+}
+
 String base64Encode(List<int> bytes) {
   String encoded = base64.encode(bytes);
 
-  // Logic to cut lines into 80-character chunks
-  // – makes for prettier source code
+  // Logic to cut lines into 80-character chunks.
   var lines = <String>[];
   var index = 0;
 
@@ -99,7 +196,36 @@
   return lines.join('\n');
 }
 
+void compileWebFrontEnd() async {
+  String sdkBinDir = path.dirname(Platform.resolvedExecutable);
+  String dart2jsPath = path.join(sdkBinDir, 'dart2js');
+
+  // dart2js -m -o output source
+  Process process = await Process.start(
+      dart2jsPath, ['-m', '-o', javascriptOutput.path, dartSources.path]);
+  process.stdout.listen((List<int> data) => stdout.add(data));
+  process.stderr.listen((List<int> data) => stderr.add(data));
+  int exitCode = await process.exitCode;
+
+  if (exitCode != 0) {
+    fail('Failed compiling ${dartSources.path}.');
+  }
+}
+
 void fail(String message) {
   stderr.writeln(message);
   exit(1);
 }
+
+/// Fail the script, and print out a message indicating how to regenerate the
+/// resources file.
+void failGenerate(String message) {
+  stderr.writeln('$message.');
+  stderr.writeln();
+  stderr.writeln('''
+To re-generate lib/src/edit/nnbd_migration/resources/resources.g.dart, run:
+
+  dart pkg/analysis_server/tool/nnbd_migration/generate_resources.dart
+''');
+  exit(1);
+}
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index 17ab10b..743a14a 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -4,6 +4,9 @@
   feature, type arguments derived from type parameter bounds cannot be used as
   is, and might require erasing nullability, when the element is instantiated
   from a legacy library. Use `TypeSystem.instantiateToBounds2()` instead.
+* Deprecated `DeclaredVariables.getBool/getInt/getString()`. These methods
+  are used internally for constants computation, and should not be used by
+  clients.
 
 ## 0.39.4
 * Deprecated `DartType.name`, use `element` or `getDisplayString()` instead.
diff --git a/pkg/analyzer/lib/dart/analysis/declared_variables.dart b/pkg/analyzer/lib/dart/analysis/declared_variables.dart
index c33e45a..2b80e7b 100644
--- a/pkg/analyzer/lib/dart/analysis/declared_variables.dart
+++ b/pkg/analyzer/lib/dart/analysis/declared_variables.dart
@@ -4,7 +4,8 @@
 
 import 'package:analyzer/dart/constant/value.dart';
 import 'package:analyzer/dart/element/type_provider.dart';
-import 'package:analyzer/src/dart/constant/value.dart';
+import 'package:analyzer/src/dart/constant/from_environment_evaluator.dart';
+import 'package:analyzer/src/generated/type_system.dart';
 
 /// An object used to provide access to the values of variables that have been
 /// defined on the command line using the `-D` option.
@@ -49,35 +50,18 @@
   /// DartObject representing "unknown" is returned. If the value cannot be
   /// parsed as a boolean, a DartObject representing 'null' is returned. The
   /// [typeProvider] is the type provider used to find the type 'bool'.
+  @Deprecated("Clients don't need this functionality")
   DartObject getBool(TypeProvider typeProvider, String name) {
-    String value = _declaredVariables[name];
-    if (value == null) {
-      return DartObjectImpl(typeProvider.boolType, BoolState.UNKNOWN_VALUE);
-    }
-    if (value == "true") {
-      return DartObjectImpl(typeProvider.boolType, BoolState.TRUE_STATE);
-    } else if (value == "false") {
-      return DartObjectImpl(typeProvider.boolType, BoolState.FALSE_STATE);
-    }
-    return DartObjectImpl(typeProvider.nullType, NullState.NULL_STATE);
+    return _evaluator(typeProvider).getBool(name);
   }
 
   /// Return the value of the variable with the given [name] interpreted as an
   /// integer value. If the variable is not defined (or [name] is `null`), a
   /// DartObject representing "unknown" is returned. If the value cannot be
   /// parsed as an integer, a DartObject representing 'null' is returned.
+  @Deprecated("Clients don't need this functionality")
   DartObject getInt(TypeProvider typeProvider, String name) {
-    String value = _declaredVariables[name];
-    if (value == null) {
-      return DartObjectImpl(typeProvider.intType, IntState.UNKNOWN_VALUE);
-    }
-    int bigInteger;
-    try {
-      bigInteger = int.parse(value);
-    } on FormatException {
-      return DartObjectImpl(typeProvider.nullType, NullState.NULL_STATE);
-    }
-    return DartObjectImpl(typeProvider.intType, IntState(bigInteger));
+    return _evaluator(typeProvider).getInt(name);
   }
 
   /// Return the value of the variable with the given [name] interpreted as a
@@ -86,11 +70,18 @@
   /// variable is not defined (or [name] is `null`), a DartObject representing
   /// "unknown" is returned. The [typeProvider] is the type provider used to
   /// find the type 'String'.
+  @Deprecated("Clients don't need this functionality")
   DartObject getString(TypeProvider typeProvider, String name) {
-    String value = _declaredVariables[name];
-    if (value == null) {
-      return DartObjectImpl(typeProvider.stringType, StringState.UNKNOWN_VALUE);
-    }
-    return DartObjectImpl(typeProvider.stringType, StringState(value));
+    return _evaluator(typeProvider).getString(name);
+  }
+
+  FromEnvironmentEvaluator _evaluator(TypeProvider typeProvider) {
+    var typeSystem = TypeSystemImpl(
+      implicitCasts: false,
+      isNonNullableByDefault: false,
+      strictInference: false,
+      typeProvider: typeProvider,
+    );
+    return FromEnvironmentEvaluator(typeSystem, this);
   }
 }
diff --git a/pkg/analyzer/lib/dart/element/type_provider.dart b/pkg/analyzer/lib/dart/element/type_provider.dart
index 24178c1..385d302 100644
--- a/pkg/analyzer/lib/dart/element/type_provider.dart
+++ b/pkg/analyzer/lib/dart/element/type_provider.dart
@@ -111,6 +111,7 @@
   ClassElement get nullElement;
 
   /// Return a [DartObjectImpl] representing the `null` object.
+  @deprecated
   DartObjectImpl get nullObject;
 
   /// Return the type representing the built-in type 'Null'.
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 89511e8..38cec6e 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -303,6 +303,7 @@
   CompileTimeErrorCode.SUPER_IN_EXTENSION,
   CompileTimeErrorCode.SUPER_IN_INVALID_CONTEXT,
   CompileTimeErrorCode.SUPER_IN_REDIRECTING_CONSTRUCTOR,
+  CompileTimeErrorCode.SWITCH_CASE_COMPLETES_NORMALLY,
   CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF,
   CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS,
   // ignore: deprecated_member_use_from_same_package
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index eb287f4..a41e3dc 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -236,7 +236,7 @@
   void _computeConstantErrors(
       ErrorReporter errorReporter, CompilationUnit unit) {
     ConstantVerifier constantVerifier = ConstantVerifier(
-        errorReporter, _libraryElement, _typeProvider, _declaredVariables,
+        errorReporter, _libraryElement, _declaredVariables,
         featureSet: unit.featureSet, forAnalysisDriver: true);
     unit.accept(constantVerifier);
   }
diff --git a/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart b/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
index 974a65f..19c32b4 100644
--- a/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
+++ b/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
@@ -11,7 +11,6 @@
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/dart/element/type_provider.dart';
-import 'package:analyzer/dart/element/type_system.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/src/dart/ast/utilities.dart';
@@ -22,6 +21,7 @@
 import 'package:analyzer/src/diagnostic/diagnostic_factory.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/type_system.dart';
 
 /// Instances of the class `ConstantVerifier` traverse an AST structure looking
 /// for additional errors and warnings not covered by the parser and resolver.
@@ -31,6 +31,9 @@
   /// The error reporter by which errors will be reported.
   final ErrorReporter _errorReporter;
 
+  /// The type operations.
+  final TypeSystemImpl _typeSystem;
+
   /// The type provider used to access the known types.
   final TypeProvider _typeProvider;
 
@@ -51,7 +54,7 @@
 
   /// Initialize a newly created constant verifier.
   ConstantVerifier(ErrorReporter errorReporter, LibraryElement currentLibrary,
-      TypeProvider typeProvider, DeclaredVariables declaredVariables,
+      DeclaredVariables declaredVariables,
       // TODO(brianwilkerson) Remove the unused parameter `forAnalysisDriver`.
       {bool forAnalysisDriver,
       // TODO(paulberry): make [featureSet] a required parameter.
@@ -59,9 +62,9 @@
       : this._(
             errorReporter,
             currentLibrary,
-            typeProvider,
-            declaredVariables,
             currentLibrary.typeSystem,
+            currentLibrary.typeProvider,
+            declaredVariables,
             featureSet ??
                 (currentLibrary.context.analysisOptions as AnalysisOptionsImpl)
                     .contextFeatures);
@@ -69,16 +72,16 @@
   ConstantVerifier._(
       this._errorReporter,
       this._currentLibrary,
+      this._typeSystem,
       this._typeProvider,
       this.declaredVariables,
-      TypeSystem typeSystem,
       FeatureSet featureSet)
       : _constantUpdate2018Enabled =
             featureSet.isEnabled(Feature.constant_update_2018),
         _intType = _typeProvider.intType,
         _evaluationEngine = ConstantEvaluationEngine(
             _typeProvider, declaredVariables,
-            typeSystem: typeSystem, experimentStatus: featureSet);
+            typeSystem: _typeSystem, experimentStatus: featureSet);
 
   @override
   void visitAnnotation(Annotation node) {
@@ -515,7 +518,11 @@
         Expression defaultValue = parameter.defaultValue;
         DartObjectImpl result;
         if (defaultValue == null) {
-          result = DartObjectImpl(_typeProvider.nullType, NullState.NULL_STATE);
+          result = DartObjectImpl(
+            _typeSystem,
+            _typeProvider.nullType,
+            NullState.NULL_STATE,
+          );
         } else {
           result = _validate(
               defaultValue, CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE);
diff --git a/pkg/analyzer/lib/src/dart/constant/evaluation.dart b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
index d577938..6e0cf47 100644
--- a/pkg/analyzer/lib/src/dart/constant/evaluation.dart
+++ b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
@@ -18,6 +18,7 @@
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/src/dart/analysis/experiments.dart';
+import 'package:analyzer/src/dart/constant/from_environment_evaluator.dart';
 import 'package:analyzer/src/dart/constant/potentially_constant.dart';
 import 'package:analyzer/src/dart/constant/utilities.dart';
 import 'package:analyzer/src/dart/constant/value.dart';
@@ -67,8 +68,9 @@
   /// exact value is unknown.
   final TypeSystem typeSystem;
 
-  /// The set of variables declared on the command line using '-D'.
-  final DeclaredVariables _declaredVariables;
+  /// The helper for evaluating variables declared on the command line
+  /// using '-D', and represented as [DeclaredVariables].
+  FromEnvironmentEvaluator _fromEnvironmentEvaluator;
 
   /// Return the object representing the state of active experiments.
   final ExperimentStatus experimentStatus;
@@ -78,11 +80,12 @@
   final ConstantEvaluationValidator validator;
 
   /// Initialize a newly created [ConstantEvaluationEngine].  The [typeProvider]
-  /// is used to access known types.  [_declaredVariables] is the set of
+  /// is used to access known types.  [_fromEnvironmentEvaluator] is the set of
   /// variables declared on the command line using '-D'.  The [validator], if
   /// given, is used to verify correct dependency analysis when running unit
   /// tests.
-  ConstantEvaluationEngine(TypeProvider typeProvider, this._declaredVariables,
+  ConstantEvaluationEngine(
+      TypeProvider typeProvider, DeclaredVariables declaredVariables,
       {ConstantEvaluationValidator validator,
       ExperimentStatus experimentStatus,
       TypeSystem typeSystem,
@@ -97,12 +100,25 @@
               strictInference: false,
               typeProvider: typeProvider,
             ),
-        experimentStatus = experimentStatus ?? ExperimentStatus();
+        experimentStatus = experimentStatus ?? ExperimentStatus() {
+    _fromEnvironmentEvaluator = FromEnvironmentEvaluator(
+      typeSystem,
+      declaredVariables,
+    );
+  }
 
   bool get _isNonNullableByDefault {
     return (typeSystem as TypeSystemImpl).isNonNullableByDefault;
   }
 
+  DartObjectImpl get _nullObject {
+    return DartObjectImpl(
+      typeSystem,
+      typeProvider.nullType,
+      NullState.NULL_STATE,
+    );
+  }
+
   /// Check that the arguments to a call to fromEnvironment() are correct. The
   /// [arguments] are the AST nodes of the arguments. The [argumentValues] are
   /// the values of the unnamed arguments. The [namedArgumentValues] are the
@@ -190,8 +206,7 @@
           constant.evaluationResult =
               EvaluationResultImpl(dartObject, errorListener.errors);
         } else {
-          constant.evaluationResult =
-              EvaluationResultImpl(typeProvider.nullObject);
+          constant.evaluationResult = EvaluationResultImpl(_nullObject);
         }
       }
     } else if (constant is VariableElementImpl) {
@@ -297,8 +312,9 @@
     if (constant is ConstructorElement) {
       constant = (constant as ConstructorElement).declaration;
     }
-    if (constant is VariableElementImpl) {
-      Expression initializer = constant.constantInitializer;
+    if (constant is VariableElement) {
+      VariableElementImpl declaration = constant.declaration;
+      Expression initializer = declaration.constantInitializer;
       if (initializer != null) {
         initializer.accept(referenceFinder);
       }
@@ -460,7 +476,10 @@
       // in this case, as well as other cases involving constant expression
       // circularities (e.g. "compile-time constant expression depends on
       // itself")
-      return DartObjectImpl.validWithUnknownValue(constructor.returnType);
+      return DartObjectImpl.validWithUnknownValue(
+        typeSystem,
+        constructor.returnType,
+      );
     }
 
     int argumentCount = arguments.length;
@@ -509,27 +528,41 @@
         if (definingClass == typeProvider.boolType) {
           DartObject valueFromEnvironment;
           valueFromEnvironment =
-              _declaredVariables.getBool(typeProvider, variableName);
+              _fromEnvironmentEvaluator.getBool(variableName);
           return computeValueFromEnvironment(
-              valueFromEnvironment,
-              DartObjectImpl(typeProvider.boolType, BoolState.FALSE_STATE),
-              namedValues);
+            valueFromEnvironment,
+            DartObjectImpl(
+              typeSystem,
+              typeProvider.boolType,
+              BoolState.FALSE_STATE,
+            ),
+            namedValues,
+          );
         } else if (definingClass == typeProvider.intType) {
           DartObject valueFromEnvironment;
-          valueFromEnvironment =
-              _declaredVariables.getInt(typeProvider, variableName);
+          valueFromEnvironment = _fromEnvironmentEvaluator.getInt(variableName);
           return computeValueFromEnvironment(
-              valueFromEnvironment,
-              DartObjectImpl(typeProvider.nullType, NullState.NULL_STATE),
-              namedValues);
+            valueFromEnvironment,
+            DartObjectImpl(
+              typeSystem,
+              typeProvider.nullType,
+              NullState.NULL_STATE,
+            ),
+            namedValues,
+          );
         } else if (definingClass == typeProvider.stringType) {
           DartObject valueFromEnvironment;
           valueFromEnvironment =
-              _declaredVariables.getString(typeProvider, variableName);
+              _fromEnvironmentEvaluator.getString(variableName);
           return computeValueFromEnvironment(
-              valueFromEnvironment,
-              DartObjectImpl(typeProvider.nullType, NullState.NULL_STATE),
-              namedValues);
+            valueFromEnvironment,
+            DartObjectImpl(
+              typeSystem,
+              typeProvider.nullType,
+              NullState.NULL_STATE,
+            ),
+            namedValues,
+          );
         }
       } else if (constructor.name == "" &&
           definingClass == typeProvider.symbolType &&
@@ -540,7 +573,11 @@
           return null;
         }
         String argumentValue = argumentValues[0].toStringValue();
-        return DartObjectImpl(definingClass, SymbolState(argumentValue));
+        return DartObjectImpl(
+          typeSystem,
+          definingClass,
+          SymbolState(argumentValue),
+        );
       }
       // Either it's an external const factory constructor that we can't
       // emulate, or an error occurred (a cycle, or a const constructor trying
@@ -548,7 +585,7 @@
       // In the former case, the best we can do is consider it an unknown value.
       // In the latter case, the error has already been reported, so considering
       // it an unknown value will suppress further errors.
-      return DartObjectImpl.validWithUnknownValue(definingClass);
+      return DartObjectImpl.validWithUnknownValue(typeSystem, definingClass);
     }
     ConstructorElementImpl constructorBase = constructor.declaration;
     validator.beforeGetConstantInitializers(constructorBase);
@@ -560,7 +597,7 @@
       // const instance using a non-const constructor, or the node we're
       // visiting is involved in a cycle).  The error has already been reported,
       // so consider it an unknown value to suppress further errors.
-      return DartObjectImpl.validWithUnknownValue(definingClass);
+      return DartObjectImpl.validWithUnknownValue(typeSystem, definingClass);
     }
 
     var fieldMap = HashMap<String, DartObjectImpl>();
@@ -639,7 +676,7 @@
         EvaluationResultImpl evaluationResult = baseParameter.evaluationResult;
         if (evaluationResult == null) {
           // No default was provided, so the default value is null.
-          argumentValue = typeProvider.nullObject;
+          argumentValue = _nullObject;
         } else if (evaluationResult.value != null) {
           argumentValue = evaluationResult.value;
         }
@@ -775,7 +812,10 @@
           CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, node);
     }
     return DartObjectImpl(
-        definingClass, GenericState(fieldMap, invocation: invocation));
+      typeSystem,
+      definingClass,
+      GenericState(fieldMap, invocation: invocation),
+    );
   }
 
   void evaluateSuperConstructorCall(
@@ -1105,8 +1145,13 @@
   }
 
   @override
-  DartObjectImpl visitBooleanLiteral(BooleanLiteral node) =>
-      DartObjectImpl(_typeProvider.boolType, BoolState.from(node.value));
+  DartObjectImpl visitBooleanLiteral(BooleanLiteral node) {
+    return DartObjectImpl(
+      typeSystem,
+      _typeProvider.boolType,
+      BoolState.from(node.value),
+    );
+  }
 
   @override
   DartObjectImpl visitConditionalExpression(ConditionalExpression node) {
@@ -1164,12 +1209,19 @@
     ParameterizedType thenType = thenResult.type;
     ParameterizedType elseType = elseResult.type;
     return DartObjectImpl.validWithUnknownValue(
-        typeSystem.leastUpperBound(thenType, elseType) as ParameterizedType);
+      typeSystem,
+      typeSystem.leastUpperBound(thenType, elseType) as ParameterizedType,
+    );
   }
 
   @override
-  DartObjectImpl visitDoubleLiteral(DoubleLiteral node) =>
-      DartObjectImpl(_typeProvider.doubleType, DoubleState(node.value));
+  DartObjectImpl visitDoubleLiteral(DoubleLiteral node) {
+    return DartObjectImpl(
+      typeSystem,
+      _typeProvider.doubleType,
+      DoubleState(node.value),
+    );
+  }
 
   @override
   DartObjectImpl visitInstanceCreationExpression(
@@ -1194,9 +1246,16 @@
   DartObjectImpl visitIntegerLiteral(IntegerLiteral node) {
     if (node.staticType == _typeProvider.doubleType) {
       return DartObjectImpl(
-          _typeProvider.doubleType, DoubleState(node.value?.toDouble()));
+        typeSystem,
+        _typeProvider.doubleType,
+        DoubleState(node.value?.toDouble()),
+      );
     }
-    return DartObjectImpl(_typeProvider.intType, IntState(node.value));
+    return DartObjectImpl(
+      typeSystem,
+      _typeProvider.intType,
+      IntState(node.value),
+    );
   }
 
   @override
@@ -1210,8 +1269,13 @@
   }
 
   @override
-  DartObjectImpl visitInterpolationString(InterpolationString node) =>
-      DartObjectImpl(_typeProvider.stringType, StringState(node.value));
+  DartObjectImpl visitInterpolationString(InterpolationString node) {
+    return DartObjectImpl(
+      typeSystem,
+      _typeProvider.stringType,
+      StringState(node.value),
+    );
+  }
 
   @override
   DartObjectImpl visitIsExpression(IsExpression node) {
@@ -1246,7 +1310,7 @@
             ? nodeType.typeArguments[0]
             : _typeProvider.dynamicType;
     InterfaceType listType = _typeProvider.listType2(elementType);
-    return DartObjectImpl(listType, ListState(list));
+    return DartObjectImpl(typeSystem, listType, ListState(list));
   }
 
   @override
@@ -1286,7 +1350,9 @@
   }
 
   @override
-  DartObjectImpl visitNullLiteral(NullLiteral node) => _typeProvider.nullObject;
+  DartObjectImpl visitNullLiteral(NullLiteral node) {
+    return evaluationEngine._nullObject;
+  }
 
   @override
   DartObjectImpl visitParenthesizedExpression(ParenthesizedExpression node) =>
@@ -1302,7 +1368,7 @@
         prefixElement is! ExtensionElement) {
       DartObjectImpl prefixResult = prefixNode.accept(this);
       if (_isStringLength(prefixResult, node.identifier)) {
-        return prefixResult.stringLength(_typeProvider);
+        return prefixResult.stringLength(typeSystem);
       }
     }
     // importPrefix.CONST
@@ -1342,7 +1408,7 @@
     if (node.target != null) {
       DartObjectImpl prefixResult = node.target.accept(this);
       if (_isStringLength(prefixResult, node.propertyName)) {
-        return prefixResult.stringLength(_typeProvider);
+        return prefixResult.stringLength(typeSystem);
       }
     }
     return _getConstantValue(node, node.propertyName.staticElement);
@@ -1382,7 +1448,7 @@
         }
       }
       InterfaceType mapType = _typeProvider.mapType2(keyType, valueType);
-      return DartObjectImpl(mapType, MapState(map));
+      return DartObjectImpl(typeSystem, mapType, MapState(map));
     } else {
       if (!node.isConst) {
         _errorReporter.reportErrorForNode(
@@ -1403,7 +1469,7 @@
               ? nodeType.typeArguments[0]
               : _typeProvider.dynamicType;
       InterfaceType setType = _typeProvider.setType2(elementType);
-      return DartObjectImpl(setType, SetState(set));
+      return DartObjectImpl(typeSystem, setType, SetState(set));
     }
   }
 
@@ -1417,8 +1483,13 @@
   }
 
   @override
-  DartObjectImpl visitSimpleStringLiteral(SimpleStringLiteral node) =>
-      DartObjectImpl(_typeProvider.stringType, StringState(node.value));
+  DartObjectImpl visitSimpleStringLiteral(SimpleStringLiteral node) {
+    return DartObjectImpl(
+      typeSystem,
+      _typeProvider.stringType,
+      StringState(node.value),
+    );
+  }
 
   @override
   DartObjectImpl visitStringInterpolation(StringInterpolation node) {
@@ -1447,7 +1518,10 @@
       buffer.write(components[i].lexeme);
     }
     return DartObjectImpl(
-        _typeProvider.symbolType, SymbolState(buffer.toString()));
+      typeSystem,
+      _typeProvider.symbolType,
+      SymbolState(buffer.toString()),
+    );
   }
 
   @override
@@ -1456,7 +1530,11 @@
     if (_hasTypeParameterReference(type)) {
       return super.visitTypeName(node);
     }
-    return DartObjectImpl(_typeProvider.typeType, TypeState(type));
+    return DartObjectImpl(
+      typeSystem,
+      _typeProvider.typeType,
+      TypeState(type),
+    );
   }
 
   /// Add the entries produced by evaluating the given collection [element] to
@@ -1626,7 +1704,11 @@
       ExecutableElement function = element;
       if (function.isStatic) {
         var functionType = node.staticType;
-        return DartObjectImpl(functionType, FunctionState(function));
+        return DartObjectImpl(
+          typeSystem,
+          functionType,
+          FunctionState(function),
+        );
       }
     } else if (variableElement is ClassElement) {
       var type = variableElement.instantiate(
@@ -1635,9 +1717,14 @@
             .toList(),
         nullabilitySuffix: NullabilitySuffix.star,
       );
-      return DartObjectImpl(_typeProvider.typeType, TypeState(type));
+      return DartObjectImpl(
+        typeSystem,
+        _typeProvider.typeType,
+        TypeState(type),
+      );
     } else if (variableElement is DynamicElementImpl) {
       return DartObjectImpl(
+        typeSystem,
         _typeProvider.typeType,
         TypeState(_typeProvider.dynamicType),
       );
@@ -1648,9 +1735,14 @@
             .toList(),
         nullabilitySuffix: NullabilitySuffix.star,
       );
-      return DartObjectImpl(_typeProvider.typeType, TypeState(type));
+      return DartObjectImpl(
+        typeSystem,
+        _typeProvider.typeType,
+        TypeState(type),
+      );
     } else if (variableElement is NeverElementImpl) {
       return DartObjectImpl(
+        typeSystem,
         _typeProvider.typeType,
         TypeState(_typeProvider.neverType),
       );
@@ -1693,7 +1785,7 @@
     if (expressionValue != null) {
       return expressionValue;
     }
-    return _typeProvider.nullObject;
+    return evaluationEngine._nullObject;
   }
 
   /// Return `true` if the [type] has a type parameter reference, so is not
@@ -1720,10 +1812,6 @@
 
   DartObjectComputer(this._errorReporter, this._evaluationEngine);
 
-  /// Convenience getter to gain access to the [evaluationEngine]'s type
-  /// provider.
-  TypeProvider get _typeProvider => _evaluationEngine.typeProvider;
-
   /// Convenience getter to gain access to the [evaluationEngine]'s type system.
   TypeSystem get _typeSystem => _evaluationEngine.typeSystem;
 
@@ -1731,7 +1819,7 @@
       DartObjectImpl rightOperand) {
     if (leftOperand != null && rightOperand != null) {
       try {
-        return leftOperand.add(_typeProvider, rightOperand);
+        return leftOperand.add(_typeSystem, rightOperand);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
         return null;
@@ -1747,7 +1835,7 @@
       AstNode node, DartObjectImpl evaluationResult) {
     if (evaluationResult != null) {
       try {
-        return evaluationResult.convertToBool(_typeProvider);
+        return evaluationResult.convertToBool(_typeSystem);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -1758,7 +1846,7 @@
   DartObjectImpl bitNot(Expression node, DartObjectImpl evaluationResult) {
     if (evaluationResult != null) {
       try {
-        return evaluationResult.bitNot(_typeProvider);
+        return evaluationResult.bitNot(_typeSystem);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -1770,7 +1858,7 @@
       AsExpression node, DartObjectImpl expression, DartObjectImpl type) {
     if (expression != null && type != null) {
       try {
-        return expression.castToType(_typeProvider, _typeSystem, type);
+        return expression.castToType(_typeSystem, type);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -1782,7 +1870,7 @@
       DartObjectImpl rightOperand) {
     if (leftOperand != null && rightOperand != null) {
       try {
-        return leftOperand.concatenate(_typeProvider, rightOperand);
+        return leftOperand.concatenate(_typeSystem, rightOperand);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -1794,7 +1882,7 @@
       DartObjectImpl rightOperand) {
     if (leftOperand != null && rightOperand != null) {
       try {
-        return leftOperand.divide(_typeProvider, rightOperand);
+        return leftOperand.divide(_typeSystem, rightOperand);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -1806,7 +1894,7 @@
       DartObjectImpl rightOperand, bool allowBool) {
     if (leftOperand != null && rightOperand != null) {
       try {
-        return leftOperand.eagerAnd(_typeProvider, rightOperand, allowBool);
+        return leftOperand.eagerAnd(_typeSystem, rightOperand, allowBool);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -1818,7 +1906,7 @@
       DartObjectImpl rightOperand, bool allowBool) {
     if (leftOperand != null && rightOperand != null) {
       try {
-        return leftOperand.eagerOr(_typeProvider, rightOperand, allowBool);
+        return leftOperand.eagerOr(_typeSystem, rightOperand, allowBool);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -1841,7 +1929,7 @@
       DartObjectImpl rightOperand, bool allowBool) {
     if (leftOperand != null && rightOperand != null) {
       try {
-        return leftOperand.eagerXor(_typeProvider, rightOperand, allowBool);
+        return leftOperand.eagerXor(_typeSystem, rightOperand, allowBool);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -1853,7 +1941,7 @@
       DartObjectImpl rightOperand) {
     if (leftOperand != null && rightOperand != null) {
       try {
-        return leftOperand.equalEqual(_typeProvider, rightOperand);
+        return leftOperand.equalEqual(_typeSystem, rightOperand);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -1865,7 +1953,7 @@
       DartObjectImpl rightOperand) {
     if (leftOperand != null && rightOperand != null) {
       try {
-        return leftOperand.greaterThan(_typeProvider, rightOperand);
+        return leftOperand.greaterThan(_typeSystem, rightOperand);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -1877,7 +1965,7 @@
       DartObjectImpl leftOperand, DartObjectImpl rightOperand) {
     if (leftOperand != null && rightOperand != null) {
       try {
-        return leftOperand.greaterThanOrEqual(_typeProvider, rightOperand);
+        return leftOperand.greaterThanOrEqual(_typeSystem, rightOperand);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -1889,7 +1977,7 @@
       DartObjectImpl leftOperand, DartObjectImpl rightOperand) {
     if (leftOperand != null && rightOperand != null) {
       try {
-        return leftOperand.integerDivide(_typeProvider, rightOperand);
+        return leftOperand.integerDivide(_typeSystem, rightOperand);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -1901,7 +1989,7 @@
       DartObjectImpl rightOperand) {
     if (leftOperand != null && rightOperand != null) {
       try {
-        return leftOperand.isIdentical(_typeProvider, rightOperand);
+        return leftOperand.isIdentical2(_typeSystem, rightOperand);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -1913,7 +2001,7 @@
       DartObjectImpl Function() rightOperandComputer) {
     if (leftOperand != null) {
       try {
-        return leftOperand.lazyAnd(_typeProvider, rightOperandComputer);
+        return leftOperand.lazyAnd(_typeSystem, rightOperandComputer);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -1925,7 +2013,7 @@
       DartObjectImpl rightOperand) {
     if (leftOperand != null && rightOperand != null) {
       try {
-        return leftOperand.lazyEqualEqual(_typeProvider, rightOperand);
+        return leftOperand.lazyEqualEqual(_typeSystem, rightOperand);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -1937,7 +2025,7 @@
       DartObjectImpl Function() rightOperandComputer) {
     if (leftOperand != null) {
       try {
-        return leftOperand.lazyOr(_typeProvider, rightOperandComputer);
+        return leftOperand.lazyOr(_typeSystem, rightOperandComputer);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -1962,7 +2050,7 @@
       DartObjectImpl rightOperand) {
     if (leftOperand != null && rightOperand != null) {
       try {
-        return leftOperand.lessThan(_typeProvider, rightOperand);
+        return leftOperand.lessThan(_typeSystem, rightOperand);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -1974,7 +2062,7 @@
       DartObjectImpl leftOperand, DartObjectImpl rightOperand) {
     if (leftOperand != null && rightOperand != null) {
       try {
-        return leftOperand.lessThanOrEqual(_typeProvider, rightOperand);
+        return leftOperand.lessThanOrEqual(_typeSystem, rightOperand);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -1985,7 +2073,7 @@
   DartObjectImpl logicalNot(Expression node, DartObjectImpl evaluationResult) {
     if (evaluationResult != null) {
       try {
-        return evaluationResult.logicalNot(_typeProvider);
+        return evaluationResult.logicalNot(_typeSystem);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -1997,7 +2085,7 @@
       DartObjectImpl leftOperand, DartObjectImpl rightOperand) {
     if (leftOperand != null && rightOperand != null) {
       try {
-        return leftOperand.logicalShiftRight(_typeProvider, rightOperand);
+        return leftOperand.logicalShiftRight(_typeSystem, rightOperand);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -2009,7 +2097,7 @@
       DartObjectImpl rightOperand) {
     if (leftOperand != null && rightOperand != null) {
       try {
-        return leftOperand.minus(_typeProvider, rightOperand);
+        return leftOperand.minus(_typeSystem, rightOperand);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -2020,7 +2108,7 @@
   DartObjectImpl negated(Expression node, DartObjectImpl evaluationResult) {
     if (evaluationResult != null) {
       try {
-        return evaluationResult.negated(_typeProvider);
+        return evaluationResult.negated(_typeSystem);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -2032,7 +2120,7 @@
       DartObjectImpl rightOperand) {
     if (leftOperand != null && rightOperand != null) {
       try {
-        return leftOperand.notEqual(_typeProvider, rightOperand);
+        return leftOperand.notEqual(_typeSystem, rightOperand);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -2044,7 +2132,7 @@
       AstNode node, DartObjectImpl evaluationResult) {
     if (evaluationResult != null) {
       try {
-        return evaluationResult.performToString(_typeProvider);
+        return evaluationResult.performToString(_typeSystem);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -2056,7 +2144,7 @@
       DartObjectImpl rightOperand) {
     if (leftOperand != null && rightOperand != null) {
       try {
-        return leftOperand.remainder(_typeProvider, rightOperand);
+        return leftOperand.remainder(_typeSystem, rightOperand);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -2068,7 +2156,7 @@
       DartObjectImpl rightOperand) {
     if (leftOperand != null && rightOperand != null) {
       try {
-        return leftOperand.shiftLeft(_typeProvider, rightOperand);
+        return leftOperand.shiftLeft(_typeSystem, rightOperand);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -2080,7 +2168,7 @@
       DartObjectImpl rightOperand) {
     if (leftOperand != null && rightOperand != null) {
       try {
-        return leftOperand.shiftRight(_typeProvider, rightOperand);
+        return leftOperand.shiftRight(_typeSystem, rightOperand);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -2096,7 +2184,7 @@
     if (evaluationResult.value != null) {
       try {
         return EvaluationResultImpl(
-            evaluationResult.value.stringLength(_typeProvider));
+            evaluationResult.value.stringLength(_typeSystem));
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -2108,7 +2196,7 @@
       DartObjectImpl rightOperand) {
     if (leftOperand != null && rightOperand != null) {
       try {
-        return leftOperand.times(_typeProvider, rightOperand);
+        return leftOperand.times(_typeSystem, rightOperand);
       } on EvaluationException catch (exception) {
         _errorReporter.reportErrorForNode(exception.errorCode, node);
       }
@@ -2120,10 +2208,9 @@
       IsExpression node, DartObjectImpl expression, DartObjectImpl type) {
     if (expression != null && type != null) {
       try {
-        DartObjectImpl result =
-            expression.hasType(_typeProvider, _typeSystem, type);
+        DartObjectImpl result = expression.hasType(_typeSystem, type);
         if (node.notOperator != null) {
-          return result.logicalNot(_typeProvider);
+          return result.logicalNot(_typeSystem);
         }
         return result;
       } on EvaluationException catch (exception) {
diff --git a/pkg/analyzer/lib/src/dart/constant/from_environment_evaluator.dart b/pkg/analyzer/lib/src/dart/constant/from_environment_evaluator.dart
new file mode 100644
index 0000000..92534ce
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/constant/from_environment_evaluator.dart
@@ -0,0 +1,99 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/dart/analysis/declared_variables.dart';
+import 'package:analyzer/dart/constant/value.dart';
+import 'package:analyzer/src/dart/constant/value.dart';
+import 'package:analyzer/src/generated/type_system.dart';
+
+class FromEnvironmentEvaluator {
+  final TypeSystemImpl _typeSystem;
+  final DeclaredVariables _declaredVariables;
+
+  FromEnvironmentEvaluator(this._typeSystem, this._declaredVariables);
+
+  /// Return the value of the variable with the given [name] interpreted as a
+  /// 'boolean' value. If the variable is not defined (or [name] is `null`), a
+  /// DartObject representing "unknown" is returned. If the value cannot be
+  /// parsed as a boolean, a DartObject representing 'null' is returned.
+  DartObject getBool(String name) {
+    String value = _declaredVariables.get(name);
+    if (value == null) {
+      return DartObjectImpl(
+        _typeSystem,
+        _typeSystem.typeProvider.boolType,
+        BoolState.UNKNOWN_VALUE,
+      );
+    }
+    if (value == "true") {
+      return DartObjectImpl(
+        _typeSystem,
+        _typeSystem.typeProvider.boolType,
+        BoolState.TRUE_STATE,
+      );
+    } else if (value == "false") {
+      return DartObjectImpl(
+        _typeSystem,
+        _typeSystem.typeProvider.boolType,
+        BoolState.FALSE_STATE,
+      );
+    }
+    return DartObjectImpl(
+      _typeSystem,
+      _typeSystem.typeProvider.nullType,
+      NullState.NULL_STATE,
+    );
+  }
+
+  /// Return the value of the variable with the given [name] interpreted as an
+  /// integer value. If the variable is not defined (or [name] is `null`), a
+  /// DartObject representing "unknown" is returned. If the value cannot be
+  /// parsed as an integer, a DartObject representing 'null' is returned.
+  DartObject getInt(String name) {
+    String value = _declaredVariables.get(name);
+    if (value == null) {
+      return DartObjectImpl(
+        _typeSystem,
+        _typeSystem.typeProvider.intType,
+        IntState.UNKNOWN_VALUE,
+      );
+    }
+    int bigInteger;
+    try {
+      bigInteger = int.parse(value);
+    } on FormatException {
+      return DartObjectImpl(
+        _typeSystem,
+        _typeSystem.typeProvider.nullType,
+        NullState.NULL_STATE,
+      );
+    }
+    return DartObjectImpl(
+      _typeSystem,
+      _typeSystem.typeProvider.intType,
+      IntState(bigInteger),
+    );
+  }
+
+  /// Return the value of the variable with the given [name] interpreted as a
+  /// String value, or `null` if the variable is not defined. Return the value
+  /// of the variable with the given name interpreted as a String value. If the
+  /// variable is not defined (or [name] is `null`), a DartObject representing
+  /// "unknown" is returned.
+  DartObject getString(String name) {
+    String value = _declaredVariables.get(name);
+    if (value == null) {
+      return DartObjectImpl(
+        _typeSystem,
+        _typeSystem.typeProvider.stringType,
+        StringState.UNKNOWN_VALUE,
+      );
+    }
+    return DartObjectImpl(
+      _typeSystem,
+      _typeSystem.typeProvider.stringType,
+      StringState(value),
+    );
+  }
+}
diff --git a/pkg/analyzer/lib/src/dart/constant/value.dart b/pkg/analyzer/lib/src/dart/constant/value.dart
index 04dc28d..726e1ea 100644
--- a/pkg/analyzer/lib/src/dart/constant/value.dart
+++ b/pkg/analyzer/lib/src/dart/constant/value.dart
@@ -9,9 +9,9 @@
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/dart/element/type_provider.dart';
-import 'package:analyzer/dart/element/type_system.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/type_system.dart';
 import 'package:analyzer/src/generated/utilities_general.dart';
 
 /// The state of an object representing a boolean value.
@@ -146,6 +146,8 @@
 
 /// A representation of an instance of a Dart class.
 class DartObjectImpl implements DartObject {
+  final TypeSystemImpl _typeSystem;
+
   @override
   final ParameterizedType type;
 
@@ -153,22 +155,25 @@
   final InstanceState _state;
 
   /// Initialize a newly created object to have the given [type] and [_state].
-  DartObjectImpl(this.type, this._state);
+  DartObjectImpl(this._typeSystem, this.type, this._state);
 
   /// Create an object to represent an unknown value.
-  factory DartObjectImpl.validWithUnknownValue(ParameterizedType type) {
+  factory DartObjectImpl.validWithUnknownValue(
+    TypeSystemImpl typeSystem,
+    ParameterizedType type,
+  ) {
     if (type.element.library.isDartCore) {
       if (type.isDartCoreBool) {
-        return DartObjectImpl(type, BoolState.UNKNOWN_VALUE);
+        return DartObjectImpl(typeSystem, type, BoolState.UNKNOWN_VALUE);
       } else if (type.isDartCoreDouble) {
-        return DartObjectImpl(type, DoubleState.UNKNOWN_VALUE);
+        return DartObjectImpl(typeSystem, type, DoubleState.UNKNOWN_VALUE);
       } else if (type.isDartCoreInt) {
-        return DartObjectImpl(type, IntState.UNKNOWN_VALUE);
+        return DartObjectImpl(typeSystem, type, IntState.UNKNOWN_VALUE);
       } else if (type.isDartCoreString) {
-        return DartObjectImpl(type, StringState.UNKNOWN_VALUE);
+        return DartObjectImpl(typeSystem, type, StringState.UNKNOWN_VALUE);
       }
     }
-    return DartObjectImpl(type, GenericState.UNKNOWN_VALUE);
+    return DartObjectImpl(typeSystem, type, GenericState.UNKNOWN_VALUE);
   }
 
   Map<String, DartObjectImpl> get fields => _state.fields;
@@ -202,41 +207,57 @@
   @override
   bool operator ==(Object object) {
     if (object is DartObjectImpl) {
-      return type == object.type && _state == object._state;
+      return _typeSystem.runtimeTypesEqual(type, object.type) &&
+          _state == object._state;
     }
     return false;
   }
 
   /// Return the result of invoking the '+' operator on this object with the
-  /// given [rightOperand]. The [typeProvider] is the type provider used to find
-  /// known types.
+  /// given [rightOperand].
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
-  DartObjectImpl add(TypeProvider typeProvider, DartObjectImpl rightOperand) {
+  DartObjectImpl add(TypeSystemImpl typeSystem, DartObjectImpl rightOperand) {
     InstanceState result = _state.add(rightOperand._state);
     if (result is IntState) {
-      return DartObjectImpl(typeProvider.intType, result);
+      return DartObjectImpl(
+        typeSystem,
+        typeSystem.typeProvider.intType,
+        result,
+      );
     } else if (result is DoubleState) {
-      return DartObjectImpl(typeProvider.doubleType, result);
+      return DartObjectImpl(
+        typeSystem,
+        typeSystem.typeProvider.doubleType,
+        result,
+      );
     } else if (result is StringState) {
-      return DartObjectImpl(typeProvider.stringType, result);
+      return DartObjectImpl(
+        typeSystem,
+        typeSystem.typeProvider.stringType,
+        result,
+      );
     }
     // We should never get here.
     throw StateError("add returned a ${result.runtimeType}");
   }
 
-  /// Return the result of invoking the '~' operator on this object. The
-  /// [typeProvider] is the type provider used to find known types.
+  /// Return the result of invoking the '~' operator on this object.
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
-  DartObjectImpl bitNot(TypeProvider typeProvider) =>
-      DartObjectImpl(typeProvider.intType, _state.bitNot());
+  DartObjectImpl bitNot(TypeSystemImpl typeSystem) {
+    return DartObjectImpl(
+      typeSystem,
+      typeSystem.typeProvider.intType,
+      _state.bitNot(),
+    );
+  }
 
   /// Return the result of casting this object to the given [castType].
-  DartObjectImpl castToType(TypeProvider typeProvider, TypeSystem typeSystem,
-      DartObjectImpl castType) {
+  DartObjectImpl castToType(
+      TypeSystemImpl typeSystem, DartObjectImpl castType) {
     _assertType(castType);
     if (isNull) {
       return this;
@@ -249,119 +270,147 @@
   }
 
   /// Return the result of invoking the ' ' operator on this object with the
-  /// [rightOperand]. The [typeProvider] is the type provider used to find known
-  /// types.
+  /// [rightOperand].
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
   DartObjectImpl concatenate(
-          TypeProvider typeProvider, DartObjectImpl rightOperand) =>
-      DartObjectImpl(
-          typeProvider.stringType, _state.concatenate(rightOperand._state));
+      TypeSystemImpl typeSystem, DartObjectImpl rightOperand) {
+    return DartObjectImpl(
+      typeSystem,
+      typeSystem.typeProvider.stringType,
+      _state.concatenate(rightOperand._state),
+    );
+  }
 
-  /// Return the result of applying boolean conversion to this object. The
-  /// [typeProvider] is the type provider used to find known types.
+  /// Return the result of applying boolean conversion to this object.
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
-  DartObjectImpl convertToBool(TypeProvider typeProvider) {
-    InterfaceType boolType = typeProvider.boolType;
+  DartObjectImpl convertToBool(TypeSystemImpl typeSystem) {
+    InterfaceType boolType = typeSystem.typeProvider.boolType;
     if (identical(type, boolType)) {
       return this;
     }
-    return DartObjectImpl(boolType, _state.convertToBool());
+    return DartObjectImpl(typeSystem, boolType, _state.convertToBool());
   }
 
   /// Return the result of invoking the '/' operator on this object with the
-  /// [rightOperand]. The [typeProvider] is the type provider used to find known
-  /// types.
+  /// [rightOperand].
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for
   /// an object of this kind.
   DartObjectImpl divide(
-      TypeProvider typeProvider, DartObjectImpl rightOperand) {
+      TypeSystemImpl typeSystem, DartObjectImpl rightOperand) {
     InstanceState result = _state.divide(rightOperand._state);
     if (result is IntState) {
-      return DartObjectImpl(typeProvider.intType, result);
+      return DartObjectImpl(
+        typeSystem,
+        typeSystem.typeProvider.intType,
+        result,
+      );
     } else if (result is DoubleState) {
-      return DartObjectImpl(typeProvider.doubleType, result);
+      return DartObjectImpl(
+        typeSystem,
+        typeSystem.typeProvider.doubleType,
+        result,
+      );
     }
     // We should never get here.
     throw StateError("divide returned a ${result.runtimeType}");
   }
 
   /// Return the result of invoking the '&' operator on this object with the
-  /// [rightOperand]. The [typeProvider] is the type provider used to find known
-  /// types.
+  /// [rightOperand].
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
   DartObjectImpl eagerAnd(
-      TypeProvider typeProvider, DartObjectImpl rightOperand, bool allowBool) {
+      TypeSystemImpl typeSystem, DartObjectImpl rightOperand, bool allowBool) {
     if (allowBool && isBool && rightOperand.isBool) {
       return DartObjectImpl(
-          typeProvider.boolType, _state.logicalAnd(rightOperand._state));
+        typeSystem,
+        typeSystem.typeProvider.boolType,
+        _state.logicalAnd(rightOperand._state),
+      );
     } else if (isInt && rightOperand.isInt) {
       return DartObjectImpl(
-          typeProvider.intType, _state.bitAnd(rightOperand._state));
+        typeSystem,
+        typeSystem.typeProvider.intType,
+        _state.bitAnd(rightOperand._state),
+      );
     }
     throw EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_INT);
   }
 
   /// Return the result of invoking the '|' operator on this object with the
-  /// [rightOperand]. The [typeProvider] is the type provider used to find known
-  /// types.
+  /// [rightOperand].
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
   DartObjectImpl eagerOr(
-      TypeProvider typeProvider, DartObjectImpl rightOperand, bool allowBool) {
+      TypeSystemImpl typeSystem, DartObjectImpl rightOperand, bool allowBool) {
     if (allowBool && isBool && rightOperand.isBool) {
       return DartObjectImpl(
-          typeProvider.boolType, _state.logicalOr(rightOperand._state));
+        typeSystem,
+        typeSystem.typeProvider.boolType,
+        _state.logicalOr(rightOperand._state),
+      );
     } else if (isInt && rightOperand.isInt) {
       return DartObjectImpl(
-          typeProvider.intType, _state.bitOr(rightOperand._state));
+        typeSystem,
+        typeSystem.typeProvider.intType,
+        _state.bitOr(rightOperand._state),
+      );
     }
     throw EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_INT);
   }
 
   /// Return the result of invoking the '^' operator on this object with the
-  /// [rightOperand]. The [typeProvider] is the type provider used to find known
-  /// types.
+  /// [rightOperand].
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
   DartObjectImpl eagerXor(
-      TypeProvider typeProvider, DartObjectImpl rightOperand, bool allowBool) {
+      TypeSystemImpl typeSystem, DartObjectImpl rightOperand, bool allowBool) {
     if (allowBool && isBool && rightOperand.isBool) {
       return DartObjectImpl(
-          typeProvider.boolType, _state.logicalXor(rightOperand._state));
+        typeSystem,
+        typeSystem.typeProvider.boolType,
+        _state.logicalXor(rightOperand._state),
+      );
     } else if (isInt && rightOperand.isInt) {
       return DartObjectImpl(
-          typeProvider.intType, _state.bitXor(rightOperand._state));
+        typeSystem,
+        typeSystem.typeProvider.intType,
+        _state.bitXor(rightOperand._state),
+      );
     }
     throw EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_INT);
   }
 
   /// Return the result of invoking the '==' operator on this object with the
-  /// [rightOperand]. The [typeProvider] is the type provider used to find known
-  /// types.
+  /// [rightOperand].
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
   DartObjectImpl equalEqual(
-      TypeProvider typeProvider, DartObjectImpl rightOperand) {
+      TypeSystemImpl typeSystem, DartObjectImpl rightOperand) {
     if (isNull || rightOperand.isNull) {
       return DartObjectImpl(
-          typeProvider.boolType,
-          isNull && rightOperand.isNull
-              ? BoolState.TRUE_STATE
-              : BoolState.FALSE_STATE);
+        typeSystem,
+        typeSystem.typeProvider.boolType,
+        isNull && rightOperand.isNull
+            ? BoolState.TRUE_STATE
+            : BoolState.FALSE_STATE,
+      );
     }
     if (isBoolNumStringOrNull) {
       return DartObjectImpl(
-          typeProvider.boolType, _state.equalEqual(rightOperand._state));
+        typeSystem,
+        typeSystem.typeProvider.boolType,
+        _state.equalEqual(rightOperand._state),
+      );
     }
     throw EvaluationException(
         CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING);
@@ -387,38 +436,43 @@
   }
 
   /// Return the result of invoking the '&gt;' operator on this object with the
-  /// [rightOperand]. The [typeProvider] is the type provider used to find known
-  /// types.
+  /// [rightOperand].
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
   DartObjectImpl greaterThan(
-          TypeProvider typeProvider, DartObjectImpl rightOperand) =>
-      DartObjectImpl(
-          typeProvider.boolType, _state.greaterThan(rightOperand._state));
+      TypeSystemImpl typeSystem, DartObjectImpl rightOperand) {
+    return DartObjectImpl(
+      typeSystem,
+      typeSystem.typeProvider.boolType,
+      _state.greaterThan(rightOperand._state),
+    );
+  }
 
   /// Return the result of invoking the '&gt;=' operator on this object with the
-  /// [rightOperand]. The [typeProvider] is the type provider used to find known
-  /// types.
+  /// [rightOperand].
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
   DartObjectImpl greaterThanOrEqual(
-          TypeProvider typeProvider, DartObjectImpl rightOperand) =>
-      DartObjectImpl(typeProvider.boolType,
-          _state.greaterThanOrEqual(rightOperand._state));
+      TypeSystemImpl typeSystem, DartObjectImpl rightOperand) {
+    return DartObjectImpl(
+      typeSystem,
+      typeSystem.typeProvider.boolType,
+      _state.greaterThanOrEqual(rightOperand._state),
+    );
+  }
 
   /// Return the result of testing whether this object has the given
   /// [testedType].
-  DartObjectImpl hasType(TypeProvider typeProvider, TypeSystem typeSystem,
-      DartObjectImpl testedType) {
+  DartObjectImpl hasType(TypeSystemImpl typeSystem, DartObjectImpl testedType) {
     _assertType(testedType);
     DartType typeType = (testedType._state as TypeState)._type;
     BoolState state;
     if (isNull) {
-      if (typeType == typeProvider.objectType ||
-          typeType == typeProvider.dynamicType ||
-          typeType == typeProvider.nullType) {
+      if (typeType == typeSystem.typeProvider.objectType ||
+          typeType == typeSystem.typeProvider.dynamicType ||
+          typeType == typeSystem.typeProvider.nullType) {
         state = BoolState.TRUE_STATE;
       } else {
         state = BoolState.FALSE_STATE;
@@ -426,232 +480,310 @@
     } else {
       state = BoolState.from(typeSystem.isSubtypeOf(type, typeType));
     }
-    return DartObjectImpl(typeProvider.boolType, state);
+    return DartObjectImpl(typeSystem, typeSystem.typeProvider.boolType, state);
   }
 
   /// Return the result of invoking the '~/' operator on this object with the
-  /// [rightOperand]. The [typeProvider] is the type provider used to find known
-  /// types.
+  /// [rightOperand].
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
   DartObjectImpl integerDivide(
-          TypeProvider typeProvider, DartObjectImpl rightOperand) =>
-      DartObjectImpl(
-          typeProvider.intType, _state.integerDivide(rightOperand._state));
+      TypeSystemImpl typeSystem, DartObjectImpl rightOperand) {
+    return DartObjectImpl(
+      typeSystem,
+      typeSystem.typeProvider.intType,
+      _state.integerDivide(rightOperand._state),
+    );
+  }
 
   /// Return the result of invoking the identical function on this object with
   /// the [rightOperand]. The [typeProvider] is the type provider used to find
   /// known types.
+  @Deprecated('Use isIdentical2() instead')
   DartObjectImpl isIdentical(
       TypeProvider typeProvider, DartObjectImpl rightOperand) {
+    var typeSystem = TypeSystemImpl(
+      implicitCasts: false,
+      isNonNullableByDefault: false,
+      strictInference: false,
+      typeProvider: typeProvider,
+    );
+    return isIdentical2(typeSystem, rightOperand);
+  }
+
+  /// Return the result of invoking the identical function on this object with
+  /// the [rightOperand].
+  DartObjectImpl isIdentical2(
+      TypeSystemImpl typeSystem, DartObjectImpl rightOperand) {
     return DartObjectImpl(
-        typeProvider.boolType, _state.isIdentical(rightOperand._state));
+      typeSystem,
+      typeSystem.typeProvider.boolType,
+      _state.isIdentical(rightOperand._state),
+    );
   }
 
   /// Return the result of invoking the '&&' operator on this object with the
-  /// [rightOperand]. The [typeProvider] is the type provider used to find known
-  /// types.
+  /// [rightOperand].
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
-  DartObjectImpl lazyAnd(TypeProvider typeProvider,
-          DartObjectImpl Function() rightOperandComputer) =>
-      DartObjectImpl(typeProvider.boolType,
-          _state.lazyAnd(() => rightOperandComputer()?._state));
+  DartObjectImpl lazyAnd(TypeSystemImpl typeSystem,
+      DartObjectImpl Function() rightOperandComputer) {
+    return DartObjectImpl(
+      typeSystem,
+      typeSystem.typeProvider.boolType,
+      _state.lazyAnd(() => rightOperandComputer()?._state),
+    );
+  }
 
   /// Return the result of invoking the '==' operator on this object with the
-  /// [rightOperand]. The [typeProvider] is the type provider used to find known
-  /// types.
+  /// [rightOperand].
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
   DartObjectImpl lazyEqualEqual(
-      TypeProvider typeProvider, DartObjectImpl rightOperand) {
+      TypeSystemImpl typeSystem, DartObjectImpl rightOperand) {
     if (isNull || rightOperand.isNull) {
       return DartObjectImpl(
-          typeProvider.boolType,
-          isNull && rightOperand.isNull
-              ? BoolState.TRUE_STATE
-              : BoolState.FALSE_STATE);
+        typeSystem,
+        typeSystem.typeProvider.boolType,
+        isNull && rightOperand.isNull
+            ? BoolState.TRUE_STATE
+            : BoolState.FALSE_STATE,
+      );
     }
     if (isBoolNumStringOrNull) {
       return DartObjectImpl(
-          typeProvider.boolType, _state.lazyEqualEqual(rightOperand._state));
+        typeSystem,
+        typeSystem.typeProvider.boolType,
+        _state.lazyEqualEqual(rightOperand._state),
+      );
     }
     throw EvaluationException(
         CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING);
   }
 
   /// Return the result of invoking the '||' operator on this object with the
-  /// [rightOperand]. The [typeProvider] is the type provider used to find known
-  /// types.
+  /// [rightOperand].
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
-  DartObjectImpl lazyOr(TypeProvider typeProvider,
+  DartObjectImpl lazyOr(TypeSystemImpl typeSystem,
           DartObjectImpl Function() rightOperandComputer) =>
-      DartObjectImpl(typeProvider.boolType,
-          _state.lazyOr(() => rightOperandComputer()?._state));
+      DartObjectImpl(
+        typeSystem,
+        typeSystem.typeProvider.boolType,
+        _state.lazyOr(() => rightOperandComputer()?._state),
+      );
 
   /// Return the result of invoking the '&lt;' operator on this object with the
-  /// [rightOperand]. The [typeProvider] is the type provider used to find known
-  /// types.
+  /// [rightOperand].
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
   DartObjectImpl lessThan(
-          TypeProvider typeProvider, DartObjectImpl rightOperand) =>
-      DartObjectImpl(
-          typeProvider.boolType, _state.lessThan(rightOperand._state));
+      TypeSystemImpl typeSystem, DartObjectImpl rightOperand) {
+    return DartObjectImpl(
+      typeSystem,
+      typeSystem.typeProvider.boolType,
+      _state.lessThan(rightOperand._state),
+    );
+  }
 
   /// Return the result of invoking the '&lt;=' operator on this object with the
-  /// [rightOperand]. The [typeProvider] is the type provider used to find known
-  /// types.
+  /// [rightOperand].
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
   DartObjectImpl lessThanOrEqual(
-          TypeProvider typeProvider, DartObjectImpl rightOperand) =>
-      DartObjectImpl(
-          typeProvider.boolType, _state.lessThanOrEqual(rightOperand._state));
+      TypeSystemImpl typeSystem, DartObjectImpl rightOperand) {
+    return DartObjectImpl(
+      typeSystem,
+      typeSystem.typeProvider.boolType,
+      _state.lessThanOrEqual(rightOperand._state),
+    );
+  }
 
-  /// Return the result of invoking the '!' operator on this object. The
-  /// [typeProvider] is the type provider used to find known types.
+  /// Return the result of invoking the '!' operator on this object.
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
-  DartObjectImpl logicalNot(TypeProvider typeProvider) =>
-      DartObjectImpl(typeProvider.boolType, _state.logicalNot());
+  DartObjectImpl logicalNot(TypeSystemImpl typeSystem) {
+    return DartObjectImpl(
+      typeSystem,
+      typeSystem.typeProvider.boolType,
+      _state.logicalNot(),
+    );
+  }
 
   /// Return the result of invoking the '&gt;&gt;&gt;' operator on this object
-  /// with the [rightOperand]. The [typeProvider] is the type provider used to
-  /// find known types.
+  /// with the [rightOperand].
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
   DartObjectImpl logicalShiftRight(
-          TypeProvider typeProvider, DartObjectImpl rightOperand) =>
-      DartObjectImpl(
-          typeProvider.intType, _state.logicalShiftRight(rightOperand._state));
+      TypeSystemImpl typeSystem, DartObjectImpl rightOperand) {
+    return DartObjectImpl(
+      typeSystem,
+      typeSystem.typeProvider.intType,
+      _state.logicalShiftRight(rightOperand._state),
+    );
+  }
 
   /// Return the result of invoking the '-' operator on this object with the
-  /// [rightOperand]. The [typeProvider] is the type provider used to find known
-  /// types.
+  /// [rightOperand].
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
-  DartObjectImpl minus(TypeProvider typeProvider, DartObjectImpl rightOperand) {
+  DartObjectImpl minus(TypeSystemImpl typeSystem, DartObjectImpl rightOperand) {
     InstanceState result = _state.minus(rightOperand._state);
     if (result is IntState) {
-      return DartObjectImpl(typeProvider.intType, result);
+      return DartObjectImpl(
+        typeSystem,
+        typeSystem.typeProvider.intType,
+        result,
+      );
     } else if (result is DoubleState) {
-      return DartObjectImpl(typeProvider.doubleType, result);
+      return DartObjectImpl(
+        typeSystem,
+        typeSystem.typeProvider.doubleType,
+        result,
+      );
     }
     // We should never get here.
     throw StateError("minus returned a ${result.runtimeType}");
   }
 
-  /// Return the result of invoking the '-' operator on this object. The
-  /// [typeProvider] is the type provider used to find known types.
+  /// Return the result of invoking the '-' operator on this object.
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
-  DartObjectImpl negated(TypeProvider typeProvider) {
+  DartObjectImpl negated(TypeSystemImpl typeSystem) {
     InstanceState result = _state.negated();
     if (result is IntState) {
-      return DartObjectImpl(typeProvider.intType, result);
+      return DartObjectImpl(
+        typeSystem,
+        typeSystem.typeProvider.intType,
+        result,
+      );
     } else if (result is DoubleState) {
-      return DartObjectImpl(typeProvider.doubleType, result);
+      return DartObjectImpl(
+        typeSystem,
+        typeSystem.typeProvider.doubleType,
+        result,
+      );
     }
     // We should never get here.
     throw StateError("negated returned a ${result.runtimeType}");
   }
 
   /// Return the result of invoking the '!=' operator on this object with the
-  /// [rightOperand]. The [typeProvider] is the type provider used to find known
-  /// types.
+  /// [rightOperand].
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
   DartObjectImpl notEqual(
-      TypeProvider typeProvider, DartObjectImpl rightOperand) {
-    return equalEqual(typeProvider, rightOperand).logicalNot(typeProvider);
+      TypeSystemImpl typeSystem, DartObjectImpl rightOperand) {
+    return equalEqual(typeSystem, rightOperand).logicalNot(typeSystem);
   }
 
-  /// Return the result of converting this object to a 'String'. The
-  /// [typeProvider] is the type provider used to find known types.
+  /// Return the result of converting this object to a 'String'.
   ///
   /// Throws an [EvaluationException] if the object cannot be converted to a
   /// 'String'.
-  DartObjectImpl performToString(TypeProvider typeProvider) {
-    InterfaceType stringType = typeProvider.stringType;
+  DartObjectImpl performToString(TypeSystemImpl typeSystem) {
+    InterfaceType stringType = typeSystem.typeProvider.stringType;
     if (identical(type, stringType)) {
       return this;
     }
-    return DartObjectImpl(stringType, _state.convertToString());
+    return DartObjectImpl(typeSystem, stringType, _state.convertToString());
   }
 
   /// Return the result of invoking the '%' operator on this object with the
-  /// [rightOperand]. The [typeProvider] is the type provider used to find known
-  /// types.
+  /// [rightOperand].
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
   DartObjectImpl remainder(
-      TypeProvider typeProvider, DartObjectImpl rightOperand) {
+      TypeSystemImpl typeSystem, DartObjectImpl rightOperand) {
     InstanceState result = _state.remainder(rightOperand._state);
     if (result is IntState) {
-      return DartObjectImpl(typeProvider.intType, result);
+      return DartObjectImpl(
+        typeSystem,
+        typeSystem.typeProvider.intType,
+        result,
+      );
     } else if (result is DoubleState) {
-      return DartObjectImpl(typeProvider.doubleType, result);
+      return DartObjectImpl(
+        typeSystem,
+        typeSystem.typeProvider.doubleType,
+        result,
+      );
     }
     // We should never get here.
     throw StateError("remainder returned a ${result.runtimeType}");
   }
 
   /// Return the result of invoking the '&lt;&lt;' operator on this object with
-  /// the [rightOperand]. The [typeProvider] is the type provider used to find
-  /// known types.
+  /// the [rightOperand].
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
   DartObjectImpl shiftLeft(
-          TypeProvider typeProvider, DartObjectImpl rightOperand) =>
-      DartObjectImpl(
-          typeProvider.intType, _state.shiftLeft(rightOperand._state));
+      TypeSystemImpl typeSystem, DartObjectImpl rightOperand) {
+    return DartObjectImpl(
+      typeSystem,
+      typeSystem.typeProvider.intType,
+      _state.shiftLeft(rightOperand._state),
+    );
+  }
 
   /// Return the result of invoking the '&gt;&gt;' operator on this object with
-  /// the [rightOperand]. The [typeProvider] is the type provider used to find
-  /// known types.
+  /// the [rightOperand].
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
   DartObjectImpl shiftRight(
-          TypeProvider typeProvider, DartObjectImpl rightOperand) =>
-      DartObjectImpl(
-          typeProvider.intType, _state.shiftRight(rightOperand._state));
+      TypeSystemImpl typeSystem, DartObjectImpl rightOperand) {
+    return DartObjectImpl(
+      typeSystem,
+      typeSystem.typeProvider.intType,
+      _state.shiftRight(rightOperand._state),
+    );
+  }
 
-  /// Return the result of invoking the 'length' getter on this object. The
-  /// [typeProvider] is the type provider used to find known types.
+  /// Return the result of invoking the 'length' getter on this object.
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
-  DartObjectImpl stringLength(TypeProvider typeProvider) =>
-      DartObjectImpl(typeProvider.intType, _state.stringLength());
+  DartObjectImpl stringLength(TypeSystemImpl typeSystem) {
+    return DartObjectImpl(
+      typeSystem,
+      typeSystem.typeProvider.intType,
+      _state.stringLength(),
+    );
+  }
 
   /// Return the result of invoking the '*' operator on this object with the
-  /// [rightOperand]. The [typeProvider] is the type provider used to find known
-  /// types.
+  /// [rightOperand].
   ///
   /// Throws an [EvaluationException] if the operator is not appropriate for an
   /// object of this kind.
-  DartObjectImpl times(TypeProvider typeProvider, DartObjectImpl rightOperand) {
+  DartObjectImpl times(TypeSystemImpl typeSystem, DartObjectImpl rightOperand) {
     InstanceState result = _state.times(rightOperand._state);
     if (result is IntState) {
-      return DartObjectImpl(typeProvider.intType, result);
+      return DartObjectImpl(
+        typeSystem,
+        typeSystem.typeProvider.intType,
+        result,
+      );
     } else if (result is DoubleState) {
-      return DartObjectImpl(typeProvider.doubleType, result);
+      return DartObjectImpl(
+        typeSystem,
+        typeSystem.typeProvider.doubleType,
+        result,
+      );
     }
     // We should never get here.
     throw StateError("times returned a ${result.runtimeType}");
@@ -2550,5 +2682,7 @@
   }
 
   @override
-  String toString() => _type?.toString() ?? "-unknown-";
+  String toString() {
+    return _type?.getDisplayString(withNullability: true) ?? '-unknown-';
+  }
 }
diff --git a/pkg/analyzer/lib/src/dart/element/display_string_builder.dart b/pkg/analyzer/lib/src/dart/element/display_string_builder.dart
index 1130ad4..c49b8af 100644
--- a/pkg/analyzer/lib/src/dart/element/display_string_builder.dart
+++ b/pkg/analyzer/lib/src/dart/element/display_string_builder.dart
@@ -8,6 +8,7 @@
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type_algebra.dart';
+import 'package:analyzer/src/generated/element_type_provider.dart';
 import 'package:meta/meta.dart';
 
 class ElementDisplayStringBuilder {
@@ -394,6 +395,8 @@
       var newTypeParameter = TypeParameterElementImpl(name, -1);
       newTypeParameter.bound = typeParameter.bound;
       newTypeParameters.add(newTypeParameter);
+      ElementTypeProvider.current
+          .freshTypeParameterCreated(newTypeParameter, typeParameter);
     }
 
     return replaceTypeParameters(type, newTypeParameters);
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 0e75695..f17b1be 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -21,6 +21,7 @@
 import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/dart/resolver/variance.dart';
 import 'package:analyzer/src/generated/constant.dart' show EvaluationResultImpl;
+import 'package:analyzer/src/generated/element_type_provider.dart';
 import 'package:analyzer/src/generated/engine.dart'
     show AnalysisContext, AnalysisOptionsImpl;
 import 'package:analyzer/src/generated/java_engine.dart';
@@ -1824,9 +1825,17 @@
   EvaluationResultImpl get evaluationResult {
     if (_evaluationResult == null) {
       Map<String, DartObjectImpl> fieldMap = <String, DartObjectImpl>{
-        name: DartObjectImpl(library.typeProvider.intType, IntState(_index))
+        name: DartObjectImpl(
+          library.typeSystem,
+          library.typeProvider.intType,
+          IntState(_index),
+        )
       };
-      DartObjectImpl value = DartObjectImpl(type, GenericState(fieldMap));
+      DartObjectImpl value = DartObjectImpl(
+        library.typeSystem,
+        type,
+        GenericState(fieldMap),
+      );
       _evaluationResult = EvaluationResultImpl(value);
     }
     return _evaluationResult;
@@ -1849,7 +1858,10 @@
   }
 
   @override
-  InterfaceType get type => _enum.thisType;
+  InterfaceType get type => ElementTypeProvider.current.getFieldType(this);
+
+  @override
+  InterfaceType get typeInternal => _enum.thisType;
 }
 
 /// The synthetic `values` field of an enum.
@@ -1868,8 +1880,13 @@
           constantValues.add(field.evaluationResult.value);
         }
       }
-      _evaluationResult =
-          EvaluationResultImpl(DartObjectImpl(type, ListState(constantValues)));
+      _evaluationResult = EvaluationResultImpl(
+        DartObjectImpl(
+          library.typeSystem,
+          type,
+          ListState(constantValues),
+        ),
+      );
     }
     return _evaluationResult;
   }
@@ -1878,7 +1895,10 @@
   String get name => 'values';
 
   @override
-  InterfaceType get type {
+  InterfaceType get type => ElementTypeProvider.current.getFieldType(this);
+
+  @override
+  InterfaceType get typeInternal {
     if (_type == null) {
       return _type = library.typeProvider.listType2(_enum.thisType);
     }
@@ -2137,7 +2157,16 @@
   }
 
   @override
-  DartType get returnType {
+  DartType get returnType =>
+      ElementTypeProvider.current.getExecutableReturnType(this);
+
+  @override
+  set returnType(DartType returnType) {
+    assert(false);
+  }
+
+  @override
+  DartType get returnTypeInternal {
     if (_returnType != null) return _returnType;
 
     InterfaceTypeImpl classThisType = enclosingElement.thisType;
@@ -2149,12 +2178,15 @@
   }
 
   @override
-  set returnType(DartType returnType) {
+  FunctionType get type => ElementTypeProvider.current.getExecutableType(this);
+
+  @override
+  set type(FunctionType type) {
     assert(false);
   }
 
   @override
-  FunctionType get type {
+  FunctionType get typeInternal {
     // TODO(scheglov) Remove "element" in the breaking changes branch.
     return _type ??= FunctionTypeImpl(
       typeFormals: typeParameters,
@@ -2166,11 +2198,6 @@
   }
 
   @override
-  set type(FunctionType type) {
-    assert(false);
-  }
-
-  @override
   T accept<T>(ElementVisitor<T> visitor) =>
       visitor.visitConstructorElement(this);
 
@@ -3152,6 +3179,22 @@
   }
 }
 
+/// Abstract base class for elements whose type is guaranteed to be a function
+/// type.
+abstract class ElementImplWithFunctionType implements Element {
+  /// Gets the element's return type, without going through the indirection of
+  /// [ElementTypeProvider].
+  ///
+  /// In most cases, the element's `returnType` getter should be used instead.
+  DartType get returnTypeInternal;
+
+  /// Gets the element's type, without going through the indirection of
+  /// [ElementTypeProvider].
+  ///
+  /// In most cases, the element's `type` getter should be used instead.
+  FunctionType get typeInternal;
+}
+
 /// A concrete implementation of an [ElementLocation].
 class ElementLocationImpl implements ElementLocation {
   /// The character used to separate components in the encoded form.
@@ -3521,7 +3564,7 @@
 /// A base class for concrete implementations of an [ExecutableElement].
 abstract class ExecutableElementImpl extends ElementImpl
     with TypeParameterizedElementMixin
-    implements ExecutableElement {
+    implements ExecutableElement, ElementImplWithFunctionType {
   /// A list containing all of the parameters defined by this executable
   /// element.
   List<ParameterElement> _parameters;
@@ -3660,7 +3703,23 @@
   }
 
   @override
-  List<ParameterElement> get parameters {
+  List<ParameterElement> get parameters =>
+      ElementTypeProvider.current.getExecutableParameters(this);
+
+  /// Set the parameters defined by this executable element to the given
+  /// [parameters].
+  set parameters(List<ParameterElement> parameters) {
+    for (ParameterElement parameter in parameters) {
+      (parameter as ParameterElementImpl).enclosingElement = this;
+    }
+    this._parameters = parameters;
+  }
+
+  /// Gets the element's parameters, without going through the indirection of
+  /// [ElementTypeProvider].
+  ///
+  /// In most cases, the [parameters] getter should be used instead.
+  List<ParameterElement> get parametersInternal {
     if (_parameters != null) return _parameters;
 
     if (linkedNode != null) {
@@ -3678,25 +3737,9 @@
     return _parameters ??= const <ParameterElement>[];
   }
 
-  /// Set the parameters defined by this executable element to the given
-  /// [parameters].
-  set parameters(List<ParameterElement> parameters) {
-    for (ParameterElement parameter in parameters) {
-      (parameter as ParameterElementImpl).enclosingElement = this;
-    }
-    this._parameters = parameters;
-  }
-
   @override
-  DartType get returnType {
-    if (_returnType != null) return _returnType;
-
-    if (linkedNode != null) {
-      var context = enclosingUnit.linkedContext;
-      return _returnType = context.getReturnType(linkedNode);
-    }
-    return _returnType;
-  }
+  DartType get returnType =>
+      ElementTypeProvider.current.getExecutableReturnType(this);
 
   set returnType(DartType returnType) {
     if (linkedNode != null) {
@@ -3714,7 +3757,25 @@
   }
 
   @override
-  FunctionType get type {
+  DartType get returnTypeInternal {
+    if (_returnType != null) return _returnType;
+
+    if (linkedNode != null) {
+      var context = enclosingUnit.linkedContext;
+      return _returnType = context.getReturnType(linkedNode);
+    }
+    return _returnType;
+  }
+
+  @override
+  FunctionType get type => ElementTypeProvider.current.getExecutableType(this);
+
+  set type(FunctionType type) {
+    _type = type;
+  }
+
+  @override
+  FunctionType get typeInternal {
     if (_type != null) return _type;
 
     // TODO(scheglov) Remove "element" in the breaking changes branch.
@@ -3727,10 +3788,6 @@
     );
   }
 
-  set type(FunctionType type) {
-    _type = type;
-  }
-
   /// Set the type parameters defined by this executable element to the given
   /// [typeParameters].
   set typeParameters(List<TypeParameterElement> typeParameters) {
@@ -4398,7 +4455,10 @@
 /// Clients may not extend, implement or mix-in this class.
 class GenericFunctionTypeElementImpl extends ElementImpl
     with TypeParameterizedElementMixin
-    implements GenericFunctionTypeElement, FunctionTypedElementImpl {
+    implements
+        GenericFunctionTypeElement,
+        FunctionTypedElementImpl,
+        ElementImplWithFunctionType {
   /// The declared return type of the function.
   DartType _returnType;
 
@@ -4468,15 +4528,8 @@
   }
 
   @override
-  DartType get returnType {
-    if (_returnType == null) {
-      if (linkedNode != null) {
-        var context = enclosingUnit.linkedContext;
-        return _returnType = context.getReturnType(linkedNode);
-      }
-    }
-    return _returnType;
-  }
+  DartType get returnType =>
+      ElementTypeProvider.current.getExecutableReturnType(this);
 
   /// Set the return type defined by this function type element to the given
   /// [returnType].
@@ -4486,7 +4539,27 @@
   }
 
   @override
-  FunctionType get type {
+  DartType get returnTypeInternal {
+    if (_returnType == null) {
+      if (linkedNode != null) {
+        var context = enclosingUnit.linkedContext;
+        return _returnType = context.getReturnType(linkedNode);
+      }
+    }
+    return _returnType;
+  }
+
+  @override
+  FunctionType get type => ElementTypeProvider.current.getExecutableType(this);
+
+  /// Set the function type defined by this function type element to the given
+  /// [type].
+  set type(FunctionType type) {
+    _type = type;
+  }
+
+  @override
+  FunctionType get typeInternal {
     if (_type != null) return _type;
 
     // TODO(scheglov) Remove "element" in the breaking changes branch.
@@ -4500,12 +4573,6 @@
     );
   }
 
-  /// Set the function type defined by this function type element to the given
-  /// [type].
-  set type(FunctionType type) {
-    _type = type;
-  }
-
   @override
   List<TypeParameterElement> get typeParameters {
     if (linkedNode != null) {
@@ -4550,7 +4617,7 @@
 /// Clients may not extend, implement or mix-in this class.
 class GenericTypeAliasElementImpl extends ElementImpl
     with TypeParameterizedElementMixin
-    implements GenericTypeAliasElement {
+    implements GenericTypeAliasElement, ElementImplWithFunctionType {
   /// The element representing the generic function type.
   GenericFunctionTypeElementImpl _function;
 
@@ -4685,7 +4752,11 @@
       function?.parameters ?? const <ParameterElement>[];
 
   @override
-  DartType get returnType {
+  DartType get returnType =>
+      ElementTypeProvider.current.getExecutableReturnType(this);
+
+  @override
+  DartType get returnTypeInternal {
     if (function == null) {
       return DynamicTypeImpl.instance;
     }
@@ -4694,7 +4765,15 @@
 
   @override
   @deprecated
-  FunctionType get type {
+  FunctionType get type => ElementTypeProvider.current.getExecutableType(this);
+
+  set type(FunctionType type) {
+    _type = type;
+  }
+
+  @override
+  @deprecated
+  FunctionType get typeInternal {
     _type ??= FunctionTypeImpl.synthetic(
       function.returnType,
       typeParameters,
@@ -4710,10 +4789,6 @@
     return _type;
   }
 
-  set type(FunctionType type) {
-    _type = type;
-  }
-
   /// Set the type parameters defined for this type to the given
   /// [typeParameters].
   set typeParameters(List<TypeParameterElement> typeParameters) {
@@ -5761,7 +5836,7 @@
   @override
   String get name {
     String name = super.name;
-    if (name == '-' && parameters.isEmpty) {
+    if (name == '-' && parametersInternal.isEmpty) {
       return 'unary-';
     }
     return super.name;
@@ -6300,6 +6375,9 @@
   }
 
   @override
+  DartType get type => ElementTypeProvider.current.getVariableType(this);
+
+  @override
   set type(DartType type) {
     if (linkedNode != null) {
       return linkedContext.setVariableType(linkedNode, type);
@@ -6567,14 +6645,7 @@
   }
 
   @override
-  DartType get type {
-    if (linkedNode != null) {
-      if (_type != null) return _type;
-      var context = enclosingUnit.linkedContext;
-      return _type = context.getType(linkedNode);
-    }
-    return super.type;
-  }
+  DartType get type => ElementTypeProvider.current.getVariableType(this);
 
   @override
   TopLevelInferenceError get typeInferenceError {
@@ -6587,6 +6658,16 @@
   }
 
   @override
+  DartType get typeInternal {
+    if (linkedNode != null) {
+      if (_type != null) return _type;
+      var context = enclosingUnit.linkedContext;
+      return _type = context.getType(linkedNode);
+    }
+    return super.typeInternal;
+  }
+
+  @override
   List<TypeParameterElement> get typeParameters {
     if (_typeParameters != null) return _typeParameters;
 
@@ -6738,12 +6819,15 @@
   }
 
   @override
-  DartType get type => setter.variable.type;
+  DartType get type => ElementTypeProvider.current.getVariableType(this);
 
   @override
   set type(DartType type) {
     assert(false); // Should never be called.
   }
+
+  @override
+  DartType get typeInternal => setter.variable.type;
 }
 
 /// A mixin that provides a common implementation for methods defined in
@@ -6999,7 +7083,8 @@
   bool get isGetter => true;
 
   @override
-  DartType get returnType => variable.type;
+  DartType get returnType =>
+      ElementTypeProvider.current.getExecutableReturnType(this);
 
   @override
   set returnType(DartType returnType) {
@@ -7007,7 +7092,18 @@
   }
 
   @override
-  FunctionType get type {
+  DartType get returnTypeInternal => variable.type;
+
+  @override
+  FunctionType get type => ElementTypeProvider.current.getExecutableType(this);
+
+  @override
+  set type(FunctionType type) {
+    assert(false); // Should never be called.
+  }
+
+  @override
+  FunctionType get typeInternal {
     if (_type != null) return _type;
 
     // TODO(scheglov) Remove "element" in the breaking changes branch.
@@ -7028,11 +7124,6 @@
 
     return type;
   }
-
-  @override
-  set type(FunctionType type) {
-    assert(false); // Should never be called.
-  }
 }
 
 /// Implicit setter for a [PropertyInducingElementImpl].
@@ -7051,14 +7142,19 @@
   bool get isSetter => true;
 
   @override
-  List<ParameterElement> get parameters {
+  List<ParameterElement> get parameters =>
+      ElementTypeProvider.current.getExecutableParameters(this);
+
+  @override
+  List<ParameterElement> get parametersInternal {
     return _parameters ??= <ParameterElement>[
       ParameterElementImpl_ofImplicitSetter(this)
     ];
   }
 
   @override
-  DartType get returnType => VoidTypeImpl.instance;
+  DartType get returnType =>
+      ElementTypeProvider.current.getExecutableReturnType(this);
 
   @override
   set returnType(DartType returnType) {
@@ -7066,7 +7162,18 @@
   }
 
   @override
-  FunctionType get type {
+  DartType get returnTypeInternal => VoidTypeImpl.instance;
+
+  @override
+  FunctionType get type => ElementTypeProvider.current.getExecutableType(this);
+
+  @override
+  set type(FunctionType type) {
+    assert(false); // Should never be called.
+  }
+
+  @override
+  FunctionType get typeInternal {
     if (_type != null) return _type;
 
     // TODO(scheglov) Remove "element" in the breaking changes branch.
@@ -7087,11 +7194,6 @@
 
     return type;
   }
-
-  @override
-  set type(FunctionType type) {
-    assert(false); // Should never be called.
-  }
 }
 
 /// A concrete implementation of a [PropertyInducingElement].
@@ -7127,7 +7229,10 @@
   }
 
   @override
-  DartType get type {
+  DartType get type => ElementTypeProvider.current.getFieldType(this);
+
+  @override
+  DartType get typeInternal {
     if (linkedNode != null) {
       if (_type != null) return _type;
       return _type = linkedContext.getType(linkedNode);
@@ -7144,7 +7249,7 @@
         _type = DynamicTypeImpl.instance;
       }
     }
-    return super.type;
+    return super.typeInternal;
   }
 }
 
@@ -7315,7 +7420,13 @@
   }
 
   @override
-  DartType get bound {
+  DartType get bound => ElementTypeProvider.current.getTypeParameterBound(this);
+
+  set bound(DartType bound) {
+    _bound = bound;
+  }
+
+  DartType get boundInternal {
     if (_bound != null) return _bound;
 
     if (linkedNode != null) {
@@ -7326,10 +7437,6 @@
     return _bound;
   }
 
-  set bound(DartType bound) {
-    _bound = bound;
-  }
-
   @override
   int get codeLength {
     if (linkedNode != null) {
@@ -7654,7 +7761,7 @@
   bool get isStatic => hasModifier(Modifier.STATIC);
 
   @override
-  DartType get type => _type;
+  DartType get type => ElementTypeProvider.current.getVariableType(this);
 
   set type(DartType type) {
     if (linkedNode != null) {
@@ -7670,6 +7777,12 @@
     return null;
   }
 
+  /// Gets the element's type, without going through the indirection of
+  /// [ElementTypeProvider].
+  ///
+  /// In most cases, the element's `returnType` getter should be used instead.
+  DartType get typeInternal => _type;
+
   @override
   void appendTo(ElementDisplayStringBuilder builder) {
     builder.writeVariableElement(this);
diff --git a/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart b/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
index a1c0d48..4688c44 100644
--- a/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
+++ b/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
@@ -6,6 +6,7 @@
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/dart/element/type_system.dart';
 import 'package:analyzer/src/dart/element/member.dart';
+import 'package:analyzer/src/error/correct_override.dart';
 import 'package:analyzer/src/generated/type_system.dart' show TypeSystemImpl;
 import 'package:analyzer/src/generated/utilities_general.dart';
 import 'package:meta/meta.dart';
@@ -416,10 +417,13 @@
       ExecutableElement validOverride;
       for (var i = candidates.length - 1; i >= 0; i--) {
         validOverride = candidates[i];
+        var overrideHelper = CorrectOverrideHelper(
+          typeSystem: typeSystem,
+          thisMember: validOverride,
+        );
         for (var j = 0; j < candidates.length; j++) {
           var candidate = candidates[j];
-          if (!typeSystem.isOverrideSubtypeOf(
-              validOverride.type, candidate.type)) {
+          if (!overrideHelper.isCorrectOverrideOf(superMember: candidate)) {
             validOverride = null;
             break;
           }
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index b0af87b..d240f68 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -15,6 +15,7 @@
 import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
 import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/dart/element/type_algebra.dart';
+import 'package:analyzer/src/generated/element_type_provider.dart';
 import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine;
 import 'package:analyzer/src/generated/type_system.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
@@ -583,6 +584,7 @@
       TypeParameterElement p2 = params2[i];
       TypeParameterElementImpl pFresh =
           TypeParameterElementImpl.synthetic(p2.name);
+      ElementTypeProvider.current.freshTypeParameterCreated(pFresh, p2);
 
       DartType variableFresh = pFresh.instantiate(
         nullabilitySuffix: NullabilitySuffix.none,
@@ -1956,8 +1958,8 @@
       List<DartType> argumentTypes, List<DartType> parameterTypes);
 
   @override
-  String toString({bool withNullability = false}) {
-    return getDisplayString(withNullability: withNullability);
+  String toString() {
+    return getDisplayString(withNullability: false);
   }
 
   /**
diff --git a/pkg/analyzer/lib/src/dart/element/type_algebra.dart b/pkg/analyzer/lib/src/dart/element/type_algebra.dart
index f1653a6..5c4bda6 100644
--- a/pkg/analyzer/lib/src/dart/element/type_algebra.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_algebra.dart
@@ -147,7 +147,7 @@
 }
 
 abstract class Substitution {
-  static const Substitution empty = _NullSubstitution.instance;
+  static const MapSubstitution empty = _NullSubstitution.instance;
 
   const Substitution();
 
diff --git a/pkg/analyzer/lib/src/dart/element/type_provider.dart b/pkg/analyzer/lib/src/dart/element/type_provider.dart
index 40524cf..0d151526 100644
--- a/pkg/analyzer/lib/src/dart/element/type_provider.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_provider.dart
@@ -8,6 +8,7 @@
 import 'package:analyzer/dart/element/type_provider.dart';
 import 'package:analyzer/src/dart/constant/value.dart';
 import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/generated/type_system.dart';
 import 'package:meta/meta.dart';
 
 /// Provide common functionality shared by the various TypeProvider
@@ -363,10 +364,20 @@
     return _nullElement ??= _getClassElement(_coreLibrary, 'Null');
   }
 
+  @deprecated
   @override
   DartObjectImpl get nullObject {
     if (_nullObject == null) {
-      _nullObject = DartObjectImpl(nullType, NullState.NULL_STATE);
+      _nullObject = DartObjectImpl(
+        TypeSystemImpl(
+          implicitCasts: false,
+          isNonNullableByDefault: false,
+          strictInference: false,
+          typeProvider: this,
+        ),
+        nullType,
+        NullState.NULL_STATE,
+      );
     }
     return _nullObject;
   }
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
index a6a834e..5580f75 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
@@ -1127,7 +1127,8 @@
       'MUST_BE_IMMUTABLE',
       "This class (or a class that this class inherits from) is marked as "
           "'@immutable', but one or more of its instance fields aren't final: "
-          "{0}");
+          "{0}",
+      hasPublishedDocs: true);
 
   /**
    * Parameters:
@@ -1180,7 +1181,8 @@
   static const HintCode MUST_CALL_SUPER = HintCode(
       'MUST_CALL_SUPER',
       "This method overrides a method annotated as '@mustCallSuper' in '{0}', "
-          "but doesn't invoke the overridden method.");
+          "but doesn't invoke the overridden method.",
+      hasPublishedDocs: true);
 
   /**
    * Generate a hint for non-const instance creation using a constructor
@@ -2116,7 +2118,8 @@
   static const HintCode UNDEFINED_HIDDEN_NAME = HintCode(
       'UNDEFINED_HIDDEN_NAME',
       "The library '{0}' doesn't export a member with the hidden name '{1}'.",
-      correction: "Try removing the name from the list of hidden members.");
+      correction: "Try removing the name from the list of hidden members.",
+      hasPublishedDocs: true);
 
   /**
    * Parameters:
@@ -2151,7 +2154,8 @@
   // ```
   static const HintCode UNDEFINED_SHOWN_NAME = HintCode('UNDEFINED_SHOWN_NAME',
       "The library '{0}' doesn't export a member with the shown name '{1}'.",
-      correction: "Try removing the name from the list of shown members.");
+      correction: "Try removing the name from the list of shown members.",
+      hasPublishedDocs: true);
 
   /**
    * No parameters.
@@ -2187,7 +2191,7 @@
   // ```
   static const HintCode UNNECESSARY_CAST = HintCode(
       'UNNECESSARY_CAST', "Unnecessary cast.",
-      correction: "Try removing the cast.");
+      correction: "Try removing the cast.", hasPublishedDocs: true);
 
   /**
    * Unnecessary `noSuchMethod` declaration.
@@ -2256,7 +2260,8 @@
       // TODO(brianwilkerson) Split this error code so that we can differentiate
       // between removing the catch clause and replacing the catch clause with
       // an on clause.
-      correction: "Try removing the catch clause.");
+      correction: "Try removing the catch clause.",
+      hasPublishedDocs: true);
 
   /**
    * Parameters:
@@ -2298,7 +2303,8 @@
   // ```
   static const HintCode UNUSED_CATCH_STACK = HintCode('UNUSED_CATCH_STACK',
       "The stack trace variable '{0}' isn't used and can be removed.",
-      correction: "Try removing the stack trace variable, or using it.");
+      correction: "Try removing the stack trace variable, or using it.",
+      hasPublishedDocs: true);
 
   /**
    * Parameters:
@@ -2438,7 +2444,8 @@
   static const HintCode UNUSED_LABEL =
       HintCode('UNUSED_LABEL', "The label '{0}' isn't used.",
           correction: "Try removing the label, or "
-              "using it in either a 'break' or 'continue' statement.");
+              "using it in either a 'break' or 'continue' statement.",
+          hasPublishedDocs: true);
 
   /**
    * Parameters:
@@ -2503,7 +2510,8 @@
   // ```
   static const HintCode UNUSED_SHOWN_NAME = HintCode(
       'UNUSED_SHOWN_NAME', "The name {0} is shown, but isn’t used.",
-      correction: "Try removing the name from the list of shown members.");
+      correction: "Try removing the name from the list of shown members.",
+      hasPublishedDocs: true);
 
   /**
    * Initialize a newly created error code to have the given [name]. The message
diff --git a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
index a9cb1f3..56a67ea 100644
--- a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
@@ -17,7 +17,6 @@
 import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/error/nullable_dereference_verifier.dart';
-import 'package:analyzer/src/generated/element_type_provider.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/type_system.dart';
 import 'package:analyzer/src/task/strong/checker.dart';
@@ -27,7 +26,6 @@
 class AssignmentExpressionResolver {
   final ResolverVisitor _resolver;
   final FlowAnalysisHelper _flowAnalysis;
-  final ElementTypeProvider _elementTypeProvider;
   final TypePropertyResolver _typePropertyResolver;
   final InvocationInferenceHelper _inferenceHelper;
   final AssignmentExpressionShared _assignmentShared;
@@ -35,10 +33,8 @@
   AssignmentExpressionResolver({
     @required ResolverVisitor resolver,
     @required FlowAnalysisHelper flowAnalysis,
-    @required ElementTypeProvider elementTypeProvider,
   })  : _resolver = resolver,
         _flowAnalysis = flowAnalysis,
-        _elementTypeProvider = elementTypeProvider,
         _typePropertyResolver = resolver.typePropertyResolver,
         _inferenceHelper = resolver.inferenceHelper,
         _assignmentShared = AssignmentExpressionShared(
@@ -88,6 +84,116 @@
             : node.staticType);
   }
 
+  /**
+   * Set the static type of [node] to be the least upper bound of the static
+   * types of subexpressions [expr1] and [expr2].
+   *
+   * TODO(scheglov) this is duplicate
+   */
+  void _analyzeLeastUpperBound(
+      Expression node, Expression expr1, Expression expr2,
+      {bool read = false}) {
+    DartType staticType1 = _getExpressionType(expr1, read: read);
+    DartType staticType2 = _getExpressionType(expr2, read: read);
+
+    _analyzeLeastUpperBoundTypes(node, staticType1, staticType2);
+  }
+
+  /**
+   * Set the static type of [node] to be the least upper bound of the static
+   * types [staticType1] and [staticType2].
+   *
+   * TODO(scheglov) this is duplicate
+   */
+  void _analyzeLeastUpperBoundTypes(
+      Expression node, DartType staticType1, DartType staticType2) {
+    if (staticType1 == null) {
+      // TODO(brianwilkerson) Determine whether this can still happen.
+      staticType1 = DynamicTypeImpl.instance;
+    }
+
+    if (staticType2 == null) {
+      // TODO(brianwilkerson) Determine whether this can still happen.
+      staticType2 = DynamicTypeImpl.instance;
+    }
+
+    DartType staticType =
+        _typeSystem.getLeastUpperBound(staticType1, staticType2) ??
+            DynamicTypeImpl.instance;
+
+    staticType = _resolver.toLegacyTypeIfOptOut(staticType);
+
+    _inferenceHelper.recordStaticType(node, staticType);
+  }
+
+  /**
+   * Gets the definite type of expression, which can be used in cases where
+   * the most precise type is desired, for example computing the least upper
+   * bound.
+   *
+   * See [getExpressionType] for more information. Without strong mode, this is
+   * equivalent to [_getStaticType].
+   *
+   * TODO(scheglov) this is duplicate
+   */
+  DartType _getExpressionType(Expression expr, {bool read = false}) =>
+      getExpressionType(expr, _typeSystem, _typeProvider, read: read);
+
+  /**
+   * Return the static type of the given [expression] that is to be used for
+   * type analysis.
+   *
+   * TODO(scheglov) this is duplicate
+   */
+  DartType _getStaticType1(Expression expression, {bool read = false}) {
+    if (expression is NullLiteral) {
+      return _typeProvider.nullType;
+    }
+    DartType type = read ? getReadType(expression) : expression.staticType;
+    return _resolveTypeParameter(type);
+  }
+
+  /**
+   * Return the static type of the given [expression].
+   *
+   * TODO(scheglov) this is duplicate
+   */
+  DartType _getStaticType2(Expression expression, {bool read = false}) {
+    DartType type;
+    if (read) {
+      type = getReadType(expression);
+    } else {
+      if (expression is SimpleIdentifier && expression.inSetterContext()) {
+        var element = expression.staticElement;
+        if (element is PromotableElement) {
+          // We're writing to the element so ignore promotions.
+          type = element.type;
+        } else {
+          type = expression.staticType;
+        }
+      } else {
+        type = expression.staticType;
+      }
+    }
+    if (type == null) {
+      // TODO(brianwilkerson) Determine the conditions for which the static type
+      // is null.
+      return DynamicTypeImpl.instance;
+    }
+    return type;
+  }
+
+  /// Return the non-nullable variant of the [type] if NNBD is enabled, otherwise
+  /// return the type itself.
+  ///
+  /// TODO(scheglov) this is duplicate
+  DartType _nonNullable(DartType type) {
+    if (_isNonNullableByDefault) {
+      return _typeSystem.promoteToNonNull(type);
+    }
+    return type;
+  }
+
   void _resolve1(AssignmentExpressionImpl node) {
     Token operator = node.operator;
     TokenType operatorType = operator.type;
@@ -140,48 +246,6 @@
     }
   }
 
-  /**
-   * Return `true` if we should report an error for the lookup [result] on
-   * the [type].
-   *
-   * TODO(scheglov) this is duplicate
-   */
-  bool _shouldReportInvalidMember(DartType type, ResolutionResult result) {
-    if (result.isNone && type != null && !type.isDynamic) {
-      if (_typeSystem.isNonNullableByDefault &&
-          _typeSystem.isPotentiallyNullable(type)) {
-        return false;
-      }
-      return true;
-    }
-    return false;
-  }
-
-  /**
-   * Return the static type of the given [expression] that is to be used for
-   * type analysis.
-   *
-   * TODO(scheglov) this is duplicate
-   */
-  DartType _getStaticType1(Expression expression, {bool read = false}) {
-    if (expression is NullLiteral) {
-      return _typeProvider.nullType;
-    }
-    DartType type = read
-        ? getReadType(expression, elementTypeProvider: _elementTypeProvider)
-        : expression.staticType;
-    return _resolveTypeParameter(type);
-  }
-
-  /**
-   * If the given [type] is a type parameter, resolve it to the type that should
-   * be used when looking up members. Otherwise, return the original type.
-   *
-   * TODO(scheglov) this is duplicate
-   */
-  DartType _resolveTypeParameter(DartType type) =>
-      type?.resolveToBound(_typeProvider.objectType);
-
   void _resolve2(AssignmentExpressionImpl node) {
     TokenType operator = node.operator.type;
     if (operator == TokenType.EQ) {
@@ -219,9 +283,7 @@
       }
 
       var operatorElement = node.staticElement;
-      var type =
-          _elementTypeProvider.safeExecutableReturnType(operatorElement) ??
-              DynamicTypeImpl.instance;
+      var type = operatorElement?.returnType ?? DynamicTypeImpl.instance;
       type = _typeSystem.refineBinaryExpressionType(
         leftReadType,
         operator,
@@ -242,101 +304,30 @@
     _resolver.nullShortingTermination(node);
   }
 
-  /// Return the non-nullable variant of the [type] if NNBD is enabled, otherwise
-  /// return the type itself.
-  ///
-  /// TODO(scheglov) this is duplicate
-  DartType _nonNullable(DartType type) {
-    if (_isNonNullableByDefault) {
-      return _typeSystem.promoteToNonNull(type);
-    }
-    return type;
-  }
-
   /**
-   * Set the static type of [node] to be the least upper bound of the static
-   * types of subexpressions [expr1] and [expr2].
+   * If the given [type] is a type parameter, resolve it to the type that should
+   * be used when looking up members. Otherwise, return the original type.
    *
    * TODO(scheglov) this is duplicate
    */
-  void _analyzeLeastUpperBound(
-      Expression node, Expression expr1, Expression expr2,
-      {bool read = false}) {
-    DartType staticType1 = _getExpressionType(expr1, read: read);
-    DartType staticType2 = _getExpressionType(expr2, read: read);
-
-    _analyzeLeastUpperBoundTypes(node, staticType1, staticType2);
-  }
+  DartType _resolveTypeParameter(DartType type) =>
+      type?.resolveToBound(_typeProvider.objectType);
 
   /**
-   * Gets the definite type of expression, which can be used in cases where
-   * the most precise type is desired, for example computing the least upper
-   * bound.
-   *
-   * See [getExpressionType] for more information. Without strong mode, this is
-   * equivalent to [_getStaticType].
+   * Return `true` if we should report an error for the lookup [result] on
+   * the [type].
    *
    * TODO(scheglov) this is duplicate
    */
-  DartType _getExpressionType(Expression expr, {bool read = false}) =>
-      getExpressionType(expr, _typeSystem, _typeProvider,
-          read: read, elementTypeProvider: _elementTypeProvider);
-
-  /**
-   * Set the static type of [node] to be the least upper bound of the static
-   * types [staticType1] and [staticType2].
-   *
-   * TODO(scheglov) this is duplicate
-   */
-  void _analyzeLeastUpperBoundTypes(
-      Expression node, DartType staticType1, DartType staticType2) {
-    if (staticType1 == null) {
-      // TODO(brianwilkerson) Determine whether this can still happen.
-      staticType1 = DynamicTypeImpl.instance;
-    }
-
-    if (staticType2 == null) {
-      // TODO(brianwilkerson) Determine whether this can still happen.
-      staticType2 = DynamicTypeImpl.instance;
-    }
-
-    DartType staticType =
-        _typeSystem.getLeastUpperBound(staticType1, staticType2) ??
-            DynamicTypeImpl.instance;
-
-    staticType = _resolver.toLegacyTypeIfOptOut(staticType);
-
-    _inferenceHelper.recordStaticType(node, staticType);
-  }
-
-  /**
-   * Return the static type of the given [expression].
-   *
-   * TODO(scheglov) this is duplicate
-   */
-  DartType _getStaticType2(Expression expression, {bool read = false}) {
-    DartType type;
-    if (read) {
-      type = getReadType(expression, elementTypeProvider: _elementTypeProvider);
-    } else {
-      if (expression is SimpleIdentifier && expression.inSetterContext()) {
-        var element = expression.staticElement;
-        if (element is PromotableElement) {
-          // We're writing to the element so ignore promotions.
-          type = _elementTypeProvider.getVariableType(element);
-        } else {
-          type = expression.staticType;
-        }
-      } else {
-        type = expression.staticType;
+  bool _shouldReportInvalidMember(DartType type, ResolutionResult result) {
+    if (result.isNone && type != null && !type.isDynamic) {
+      if (_typeSystem.isNonNullableByDefault &&
+          _typeSystem.isPotentiallyNullable(type)) {
+        return false;
       }
+      return true;
     }
-    if (type == null) {
-      // TODO(brianwilkerson) Determine the conditions for which the static type
-      // is null.
-      return DynamicTypeImpl.instance;
-    }
-    return type;
+    return false;
   }
 }
 
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 98b53f2..a0db802 100644
--- a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
@@ -15,7 +15,6 @@
 import 'package:analyzer/src/dart/resolver/resolution_result.dart';
 import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
 import 'package:analyzer/src/error/codes.dart';
-import 'package:analyzer/src/generated/element_type_provider.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/type_promotion_manager.dart';
 import 'package:analyzer/src/generated/type_system.dart';
@@ -27,7 +26,6 @@
   final ResolverVisitor _resolver;
   final TypePromotionManager _promoteManager;
   final FlowAnalysisHelper _flowAnalysis;
-  final ElementTypeProvider _elementTypeProvider;
   final TypePropertyResolver _typePropertyResolver;
   final InvocationInferenceHelper _inferenceHelper;
 
@@ -35,11 +33,9 @@
     @required ResolverVisitor resolver,
     @required TypePromotionManager promoteManager,
     @required FlowAnalysisHelper flowAnalysis,
-    @required ElementTypeProvider elementTypeProvider,
   })  : _resolver = resolver,
         _promoteManager = promoteManager,
         _flowAnalysis = flowAnalysis,
-        _elementTypeProvider = elementTypeProvider,
         _typePropertyResolver = resolver.typePropertyResolver,
         _inferenceHelper = resolver.inferenceHelper;
 
@@ -119,8 +115,7 @@
   ///
   /// TODO(scheglov) this is duplicate
   DartType _getExpressionType(Expression expr, {bool read = false}) =>
-      getExpressionType(expr, _typeSystem, _typeProvider,
-          read: read, elementTypeProvider: _elementTypeProvider);
+      getExpressionType(expr, _typeSystem, _typeProvider, read: read);
 
   /// Return the static type of the given [expression] that is to be used for
   /// type analysis.
@@ -130,9 +125,7 @@
     if (expression is NullLiteral) {
       return _typeProvider.nullType;
     }
-    DartType type = read
-        ? getReadType(expression, elementTypeProvider: _elementTypeProvider)
-        : expression.staticType;
+    DartType type = read ? getReadType(expression) : expression.staticType;
     return _resolveTypeParameter(type);
   }
 
@@ -200,8 +193,7 @@
     );
 
     node.staticElement = result.getter;
-    node.staticInvokeType =
-        _elementTypeProvider.safeExecutableType(result.getter);
+    node.staticInvokeType = result.getter?.type;
     if (_shouldReportInvalidMember(leftType, result)) {
       if (leftOperand is SuperExpression) {
         _errorReporter.reportErrorForToken(
@@ -351,8 +343,7 @@
       // If this is a user-defined operator, set the right operand context
       // using the operator method's parameter type.
       var rightParam = invokeType.parameters[0];
-      InferenceContext.setType(
-          right, _elementTypeProvider.getVariableType(rightParam));
+      InferenceContext.setType(right, rightParam.type);
     }
 
     // TODO(scheglov) Do we need these checks for null?
diff --git a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
index 92bcc0b..f682667 100644
--- a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
@@ -10,7 +10,6 @@
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/dart/element/type_system.dart';
 import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/element_type_provider.dart';
 import 'package:analyzer/src/generated/migration.dart';
 import 'package:analyzer/src/generated/type_system.dart' show TypeSystemImpl;
 import 'package:analyzer/src/generated/variable_type_provider.dart';
@@ -292,12 +291,6 @@
       : super(typeSystem, false);
 
   @override
-  LocalVariableTypeProvider get localVariableTypeProvider {
-    return _LocalVariableTypeProvider(this,
-        elementTypeProvider: migrationResolutionHooks);
-  }
-
-  @override
   void topLevelDeclaration_enter(
       Declaration node, FormalParameterList parameters, FunctionBody body) {
     super.topLevelDeclaration_enter(node, parameters, body);
@@ -558,11 +551,7 @@
 class _LocalVariableTypeProvider implements LocalVariableTypeProvider {
   final FlowAnalysisHelper _manager;
 
-  final ElementTypeProvider _elementTypeProvider;
-
-  _LocalVariableTypeProvider(this._manager,
-      {ElementTypeProvider elementTypeProvider = const ElementTypeProvider()})
-      : _elementTypeProvider = elementTypeProvider;
+  _LocalVariableTypeProvider(this._manager);
 
   @override
   DartType getType(SimpleIdentifier node) {
@@ -571,6 +560,6 @@
       var promotedType = _manager.flow?.variableRead(node, variable);
       if (promotedType != null) return promotedType;
     }
-    return _elementTypeProvider.getVariableType(variable);
+    return variable.type;
   }
 }
diff --git a/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart
index 1db222a..8f7dd08 100644
--- a/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart
@@ -13,22 +13,18 @@
 import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/error/nullable_dereference_verifier.dart';
-import 'package:analyzer/src/generated/element_type_provider.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:meta/meta.dart';
 
 /// Helper for resolving [FunctionExpressionInvocation]s.
 class FunctionExpressionInvocationResolver {
   final ResolverVisitor _resolver;
-  final ElementTypeProvider _elementTypeProvider;
   final TypePropertyResolver _typePropertyResolver;
   final InvocationInferenceHelper _inferenceHelper;
 
   FunctionExpressionInvocationResolver({
     @required ResolverVisitor resolver,
-    @required ElementTypeProvider elementTypeProvider,
   })  : _resolver = resolver,
-        _elementTypeProvider = elementTypeProvider,
         _typePropertyResolver = resolver.typePropertyResolver,
         _inferenceHelper = resolver.inferenceHelper;
 
@@ -112,7 +108,7 @@
       );
     }
 
-    var rawType = _elementTypeProvider.getExecutableType(callElement);
+    var rawType = callElement.type;
     _resolve(node, rawType);
   }
 
@@ -136,7 +132,7 @@
     }
 
     node.staticElement = callElement;
-    var rawType = _elementTypeProvider.getExecutableType(callElement);
+    var rawType = callElement.type;
     _resolve(node, rawType);
   }
 
diff --git a/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart b/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
index 9ac8a76..779d22a 100644
--- a/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
@@ -13,35 +13,34 @@
 import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
 import 'package:analyzer/src/error/codes.dart';
-import 'package:analyzer/src/generated/element_type_provider.dart';
 import 'package:analyzer/src/generated/migration.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:meta/meta.dart';
 
 class InvocationInferenceHelper {
   final ResolverVisitor _resolver;
-  final ElementTypeProvider _elementTypeProvider;
   final ErrorReporter _errorReporter;
   final FlowAnalysisHelper _flowAnalysis;
   final TypeSystemImpl _typeSystem;
   final TypeProviderImpl _typeProvider;
+  final MigrationResolutionHooks _migrationResolutionHooks;
 
   List<DartType> _typeArgumentTypes;
   FunctionType _invokeType;
 
-  InvocationInferenceHelper({
-    @required ResolverVisitor resolver,
-    @required LibraryElementImpl definingLibrary,
-    @required ElementTypeProvider elementTypeProvider,
-    @required ErrorReporter errorReporter,
-    @required FlowAnalysisHelper flowAnalysis,
-    @required TypeSystemImpl typeSystem,
-  })  : _resolver = resolver,
-        _elementTypeProvider = elementTypeProvider,
+  InvocationInferenceHelper(
+      {@required ResolverVisitor resolver,
+      @required LibraryElementImpl definingLibrary,
+      @required ErrorReporter errorReporter,
+      @required FlowAnalysisHelper flowAnalysis,
+      @required TypeSystemImpl typeSystem,
+      @required MigrationResolutionHooks migrationResolutionHooks})
+      : _resolver = resolver,
         _errorReporter = errorReporter,
         _typeSystem = typeSystem,
         _typeProvider = typeSystem.typeProvider,
-        _flowAnalysis = flowAnalysis;
+        _flowAnalysis = flowAnalysis,
+        _migrationResolutionHooks = migrationResolutionHooks;
 
   /// Compute the return type of the method or function represented by the given
   /// type that is being invoked.
@@ -191,8 +190,7 @@
       return false;
     }
     inferredElement = _resolver.toLegacyElement(inferredElement);
-    DartType inferredType =
-        _elementTypeProvider.getExecutableType(inferredElement);
+    DartType inferredType = inferredElement.type;
     if (inferredType is FunctionType) {
       DartType returnType = inferredType.returnType;
       if (inferredType.parameters.isEmpty &&
@@ -213,10 +211,9 @@
   ///
   /// TODO(scheglov) this is duplication
   void recordStaticType(Expression expression, DartType type) {
-    var elementTypeProvider = this._elementTypeProvider;
-    if (elementTypeProvider is MigrationResolutionHooks) {
+    if (_migrationResolutionHooks != null) {
       // TODO(scheglov) type cannot be null
-      type = elementTypeProvider.modifyExpressionType(
+      type = _migrationResolutionHooks.modifyExpressionType(
         expression,
         type ?? DynamicTypeImpl.instance,
       );
diff --git a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
index d59be4a..115f447 100644
--- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -14,7 +14,6 @@
 import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
 import 'package:analyzer/src/dart/resolver/scope.dart';
 import 'package:analyzer/src/error/codes.dart';
-import 'package:analyzer/src/generated/element_type_provider.dart';
 import 'package:analyzer/src/generated/migratable_ast_info_provider.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/super_context.dart';
@@ -52,7 +51,6 @@
   /// Helper for extension method resolution.
   final ExtensionMemberResolver _extensionResolver;
 
-  final ElementTypeProvider _elementTypeProvider;
   final InvocationInferenceHelper _inferenceHelper;
 
   final MigratableAstInfoProvider _migratableAstInfoProvider;
@@ -65,7 +63,6 @@
 
   MethodInvocationResolver(
     this._resolver,
-    this._elementTypeProvider,
     this._migratableAstInfoProvider, {
     @required InvocationInferenceHelper inferenceHelper,
   })  : _typeType = _resolver.typeProvider.typeType,
@@ -339,8 +336,7 @@
       getter = _resolver.toLegacyElement(getter);
       nameNode.staticElement = getter;
       _reportStaticAccessToInstanceMember(getter, nameNode);
-      _rewriteAsFunctionExpressionInvocation(
-          node, _elementTypeProvider.getExecutableReturnType(getter));
+      _rewriteAsFunctionExpressionInvocation(node, getter.returnType);
       return;
     }
 
@@ -349,7 +345,7 @@
       method = _resolver.toLegacyElement(method);
       nameNode.staticElement = method;
       _reportStaticAccessToInstanceMember(method, nameNode);
-      _setResolution(node, _elementTypeProvider.getExecutableType(method));
+      _setResolution(node, method.type);
       return;
     }
 
@@ -392,11 +388,10 @@
     nameNode.staticElement = member;
 
     if (member is PropertyAccessorElement) {
-      return _rewriteAsFunctionExpressionInvocation(
-          node, _elementTypeProvider.getExecutableReturnType(member));
+      return _rewriteAsFunctionExpressionInvocation(node, member.returnType);
     }
 
-    _setResolution(node, _elementTypeProvider.getExecutableType(member));
+    _setResolution(node, member.type);
   }
 
   void _resolveReceiverDynamic(MethodInvocation node, String name) {
@@ -459,7 +454,7 @@
         methodName.staticElement = objectMember;
         _setResolution(
           node,
-          _elementTypeProvider.getExecutableType(objectMember),
+          objectMember.type,
         );
       } else {
         _setDynamicResolution(node);
@@ -503,12 +498,10 @@
         element = multiply.conflictingElements[0];
       }
       if (element is PropertyAccessorElement) {
-        return _rewriteAsFunctionExpressionInvocation(
-            node, _elementTypeProvider.getExecutableReturnType(element));
+        return _rewriteAsFunctionExpressionInvocation(node, element.returnType);
       }
       if (element is ExecutableElement) {
-        return _setResolution(
-            node, _elementTypeProvider.getExecutableType(element));
+        return _setResolution(node, element.type);
       }
       if (element is VariableElement) {
         var targetType = _localVariableTypeProvider.getType(nameNode);
@@ -553,8 +546,7 @@
         element = _resolver.toLegacyElement(element);
         if (element is ExecutableElement) {
           nameNode.staticElement = element;
-          return _setResolution(
-              node, _elementTypeProvider.getExecutableType(element));
+          return _setResolution(node, element.type);
         }
       }
     }
@@ -572,13 +564,11 @@
     }
 
     if (element is PropertyAccessorElement) {
-      return _rewriteAsFunctionExpressionInvocation(
-          node, _elementTypeProvider.getExecutableReturnType(element));
+      return _rewriteAsFunctionExpressionInvocation(node, element.returnType);
     }
 
     if (element is ExecutableElement) {
-      return _setResolution(
-          node, _elementTypeProvider.getExecutableType(element));
+      return _setResolution(node, element.type);
     }
 
     _reportUndefinedFunction(node, prefixedName);
@@ -603,10 +593,9 @@
     if (target != null) {
       nameNode.staticElement = target;
       if (target is PropertyAccessorElement) {
-        return _rewriteAsFunctionExpressionInvocation(
-            node, _elementTypeProvider.getExecutableReturnType(target));
+        return _rewriteAsFunctionExpressionInvocation(node, target.returnType);
       }
-      _setResolution(node, _elementTypeProvider.getExecutableType(target));
+      _setResolution(node, target.type);
       return;
     }
 
@@ -616,7 +605,7 @@
     target = _inheritance.getInherited(receiverType, _currentName);
     if (target != null) {
       nameNode.staticElement = target;
-      _setResolution(node, _elementTypeProvider.getExecutableType(target));
+      _setResolution(node, target.type);
 
       _resolver.errorReporter.reportErrorForNode(
           CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE,
@@ -667,11 +656,9 @@
       }
 
       if (target is PropertyAccessorElement) {
-        return _rewriteAsFunctionExpressionInvocation(
-            node, _elementTypeProvider.getExecutableReturnType(target));
+        return _rewriteAsFunctionExpressionInvocation(node, target.returnType);
       }
-      return _setResolution(
-          node, _elementTypeProvider.getExecutableType(target));
+      return _setResolution(node, target.type);
     }
 
     _setDynamicResolution(node);
@@ -702,9 +689,9 @@
         nameNode.staticElement = element;
         if (element is PropertyAccessorElement) {
           return _rewriteAsFunctionExpressionInvocation(
-              node, _elementTypeProvider.getExecutableReturnType(element));
+              node, element.returnType);
         }
-        _setResolution(node, _elementTypeProvider.getExecutableType(element));
+        _setResolution(node, element.type);
       } else {
         _reportInvocationOfNonFunction(node);
       }
diff --git a/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
index 36866f7..687889f 100644
--- a/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
@@ -15,7 +15,6 @@
 import 'package:analyzer/src/dart/resolver/resolution_result.dart';
 import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
 import 'package:analyzer/src/error/codes.dart';
-import 'package:analyzer/src/generated/element_type_provider.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/type_system.dart';
 import 'package:analyzer/src/task/strong/checker.dart';
@@ -25,7 +24,6 @@
 class PostfixExpressionResolver {
   final ResolverVisitor _resolver;
   final FlowAnalysisHelper _flowAnalysis;
-  final ElementTypeProvider _elementTypeProvider;
   final TypePropertyResolver _typePropertyResolver;
   final InvocationInferenceHelper _inferenceHelper;
   final AssignmentExpressionShared _assignmentShared;
@@ -33,10 +31,8 @@
   PostfixExpressionResolver({
     @required ResolverVisitor resolver,
     @required FlowAnalysisHelper flowAnalysis,
-    @required ElementTypeProvider elementTypeProvider,
   })  : _resolver = resolver,
         _flowAnalysis = flowAnalysis,
-        _elementTypeProvider = elementTypeProvider,
         _typePropertyResolver = resolver.typePropertyResolver,
         _inferenceHelper = resolver.inferenceHelper,
         _assignmentShared = AssignmentExpressionShared(
@@ -60,7 +56,6 @@
 
     var receiverType = getReadType(
       node.operand,
-      elementTypeProvider: _elementTypeProvider,
     );
 
     _assignmentShared.checkLateFinalAlreadyAssigned(node.operand);
@@ -97,17 +92,15 @@
       // This is a function invocation expression disguised as something else.
       // We are invoking a getter and then invoking the returned function.
       //
-      FunctionType propertyType =
-          _elementTypeProvider.getExecutableType(element);
+      FunctionType propertyType = element.type;
       if (propertyType != null) {
         return _resolver.inferenceHelper.computeInvokeReturnType(
             propertyType.returnType,
             isNullAware: false);
       }
     } else if (element is ExecutableElement) {
-      return _resolver.inferenceHelper.computeInvokeReturnType(
-          _elementTypeProvider.getExecutableType(element),
-          isNullAware: false);
+      return _resolver.inferenceHelper
+          .computeInvokeReturnType(element.type, isNullAware: false);
     }
     return DynamicTypeImpl.instance;
   }
@@ -128,7 +121,7 @@
     if (node is SimpleIdentifier) {
       var element = node.staticElement;
       if (element is PromotableElement) {
-        return _elementTypeProvider.getVariableType(element);
+        return element.type;
       }
     }
     return node.staticType;
@@ -213,7 +206,6 @@
 
     var operandType = getReadType(
       operand,
-      elementTypeProvider: _elementTypeProvider,
     );
 
     var type = _typeSystem.promoteToNonNull(operandType);
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 7281a90..d985231 100644
--- a/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
@@ -16,7 +16,6 @@
 import 'package:analyzer/src/dart/resolver/resolution_result.dart';
 import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
 import 'package:analyzer/src/error/codes.dart';
-import 'package:analyzer/src/generated/element_type_provider.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/type_system.dart';
 import 'package:analyzer/src/task/strong/checker.dart';
@@ -26,7 +25,6 @@
 class PrefixExpressionResolver {
   final ResolverVisitor _resolver;
   final FlowAnalysisHelper _flowAnalysis;
-  final ElementTypeProvider _elementTypeProvider;
   final TypePropertyResolver _typePropertyResolver;
   final InvocationInferenceHelper _inferenceHelper;
   final AssignmentExpressionShared _assignmentShared;
@@ -34,10 +32,8 @@
   PrefixExpressionResolver({
     @required ResolverVisitor resolver,
     @required FlowAnalysisHelper flowAnalysis,
-    @required ElementTypeProvider elementTypeProvider,
   })  : _resolver = resolver,
         _flowAnalysis = flowAnalysis,
-        _elementTypeProvider = elementTypeProvider,
         _typePropertyResolver = resolver.typePropertyResolver,
         _inferenceHelper = resolver.inferenceHelper,
         _assignmentShared = AssignmentExpressionShared(
@@ -96,17 +92,15 @@
       // This is a function invocation expression disguised as something else.
       // We are invoking a getter and then invoking the returned function.
       //
-      FunctionType propertyType =
-          _elementTypeProvider.getExecutableType(element);
+      FunctionType propertyType = element.type;
       if (propertyType != null) {
         return _resolver.inferenceHelper.computeInvokeReturnType(
             propertyType.returnType,
             isNullAware: false);
       }
     } else if (element is ExecutableElement) {
-      return _resolver.inferenceHelper.computeInvokeReturnType(
-          _elementTypeProvider.getExecutableType(element),
-          isNullAware: false);
+      return _resolver.inferenceHelper
+          .computeInvokeReturnType(element.type, isNullAware: false);
     }
     return DynamicTypeImpl.instance;
   }
@@ -134,7 +128,6 @@
     if (read) {
       var type = getReadType(
         expression,
-        elementTypeProvider: _elementTypeProvider,
       );
       return _resolveTypeParameter(type);
     } else {
@@ -142,7 +135,7 @@
         var element = expression.staticElement;
         if (element is PromotableElement) {
           // We're writing to the element so ignore promotions.
-          return _elementTypeProvider.getVariableType(element);
+          return element.type;
         } else {
           return expression.staticType;
         }
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index a371761..70fc7dc 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -107,7 +107,8 @@
       CheckedModeCompileTimeErrorCode(
           'VARIABLE_TYPE_MISMATCH',
           "A value of type '{0}' can't be assigned to a variable of type "
-              "'{1}'.");
+              "'{1}'.",
+          hasPublishedDocs: true);
 
   /**
    * Initialize a newly created error code to have the given [name]. The message
@@ -553,7 +554,8 @@
   static const CompileTimeErrorCode BUILT_IN_IDENTIFIER_AS_TYPE =
       CompileTimeErrorCode('BUILT_IN_IDENTIFIER_AS_TYPE',
           "The built-in identifier '{0}' can't be used as a type.",
-          correction: "Try correcting the name to match an existing type.");
+          correction: "Try correcting the name to match an existing type.",
+          hasPublishedDocs: true);
 
   /**
    * 16.33 Identifier Reference: It is a compile-time error if a built-in
@@ -852,7 +854,8 @@
       CompileTimeErrorCode('CONST_CONSTRUCTOR_WITH_NON_FINAL_FIELD',
           "Can't define a const constructor for a class with non-final fields.",
           correction: "Try making all of the fields final, or "
-              "removing the keyword 'const' from the constructor.");
+              "removing the keyword 'const' from the constructor.",
+          hasPublishedDocs: true);
 
   /**
    * 12.12.2 Const: It is a compile-time error if <i>T</i> is a deferred type.
@@ -1048,7 +1051,8 @@
   static const CompileTimeErrorCode CONST_INSTANCE_FIELD = CompileTimeErrorCode(
       'CONST_INSTANCE_FIELD', "Only static fields can be declared as const.",
       correction: "Try declaring the field as final, or adding the keyword "
-          "'static'.");
+          "'static'.",
+      hasPublishedDocs: true);
 
   /**
    * 12.8 Maps: It is a compile-time error if the key of an entry in a constant
@@ -1219,7 +1223,8 @@
   static const CompileTimeErrorCode CONST_WITH_NON_CONST = CompileTimeErrorCode(
       'CONST_WITH_NON_CONST',
       "The constructor being called isn't a const constructor.",
-      correction: "Try removing 'const' from the constructor invocation.");
+      correction: "Try removing 'const' from the constructor invocation.",
+      hasPublishedDocs: true);
 
   /**
    * No parameters.
@@ -1589,7 +1594,8 @@
           "The argument for the named parameter '{0}' was already specified.",
           correction: "Try removing one of the named arguments, or "
               "correcting one of the names to reference a different named "
-              "parameter.");
+              "parameter.",
+          hasPublishedDocs: true);
 
   /**
    * No parameters.
@@ -2469,7 +2475,8 @@
   // ```
   static const CompileTimeErrorCode IMPLEMENTS_REPEATED = CompileTimeErrorCode(
       'IMPLEMENTS_REPEATED', "'{0}' can only be implemented once.",
-      correction: "Try removing all but one occurrence of the class name.");
+      correction: "Try removing all but one occurrence of the class name.",
+      hasPublishedDocs: true);
 
   /**
    * 7.10 Superinterfaces: It is a compile-time error if the superclass of a
@@ -2665,7 +2672,8 @@
       CompileTimeErrorCode('INITIALIZER_FOR_NON_EXISTENT_FIELD',
           "'{0}' isn't a field in the enclosing class.",
           correction: "Try correcting the name to match an existing field, or "
-              "defining a field named '{0}'.");
+              "defining a field named '{0}'.",
+          hasPublishedDocs: true);
 
   /**
    * 7.6.1 Generative Constructors: Let <i>k</i> be a generative constructor. It
@@ -2825,7 +2833,8 @@
   static const CompileTimeErrorCode INSTANCE_MEMBER_ACCESS_FROM_FACTORY =
       CompileTimeErrorCode('INSTANCE_MEMBER_ACCESS_FROM_FACTORY',
           "Instance members can't be accessed from a factory constructor.",
-          correction: "Try removing the reference to the instance member.");
+          correction: "Try removing the reference to the instance member.",
+          hasPublishedDocs: true);
 
   /**
    * No parameters.
@@ -2881,7 +2890,8 @@
       CompileTimeErrorCode('INSTANCE_MEMBER_ACCESS_FROM_STATIC',
           "Instance members can't be accessed from a static method.",
           correction: "Try removing the reference to the instance member, or "
-              "removing the keyword 'static' from the method.");
+              "removing the keyword 'static' from the method.",
+          hasPublishedDocs: true);
 
   /**
    * Enum proposal: It is also a compile-time error to explicitly instantiate an
@@ -3090,7 +3100,8 @@
       CompileTimeErrorCode(
           'INVALID_FACTORY_NAME_NOT_A_CLASS',
           "The name of a factory constructor must be the same as the name of "
-              "the immediately enclosing class.");
+              "the immediately enclosing class.",
+          hasPublishedDocs: true);
 
   static const CompileTimeErrorCode INVALID_INLINE_FUNCTION_TYPE =
       CompileTimeErrorCode(
@@ -3220,7 +3231,8 @@
   // ```
   static const CompileTimeErrorCode INVALID_REFERENCE_TO_THIS =
       CompileTimeErrorCode('INVALID_REFERENCE_TO_THIS',
-          "Invalid reference to 'this' expression.");
+          "Invalid reference to 'this' expression.",
+          hasPublishedDocs: true);
 
   /**
    * 12.6 Lists: It is a compile time error if the type argument of a constant
@@ -3295,8 +3307,9 @@
   // #### Common fixes
   //
   // Replace the invalid URI with a valid URI.
-  static const CompileTimeErrorCode INVALID_URI =
-      CompileTimeErrorCode('INVALID_URI', "Invalid URI syntax: '{0}'.");
+  static const CompileTimeErrorCode INVALID_URI = CompileTimeErrorCode(
+      'INVALID_URI', "Invalid URI syntax: '{0}'.",
+      hasPublishedDocs: true);
 
   /**
    * Parameters:
@@ -3733,7 +3746,8 @@
   // class C {}
   // ```
   static const CompileTimeErrorCode MIXIN_OF_NON_CLASS = CompileTimeErrorCode(
-      'MIXIN_OF_NON_CLASS', "Classes can only mix in mixins and classes.");
+      'MIXIN_OF_NON_CLASS', "Classes can only mix in mixins and classes.",
+      hasPublishedDocs: true);
 
   /**
    * 9 Mixins: It is a compile-time error if a declared or derived mixin refers
@@ -3854,7 +3868,8 @@
   static const CompileTimeErrorCode NO_ANNOTATION_CONSTRUCTOR_ARGUMENTS =
       CompileTimeErrorCode('NO_ANNOTATION_CONSTRUCTOR_ARGUMENTS',
           "Annotation creation must have arguments.",
-          correction: "Try adding an empty argument list.");
+          correction: "Try adding an empty argument list.",
+          hasPublishedDocs: true);
 
   /**
    * Parameters:
@@ -4285,7 +4300,8 @@
   static const CompileTimeErrorCode NON_CONSTANT_SET_ELEMENT =
       CompileTimeErrorCode('NON_CONSTANT_SET_ELEMENT',
           "The values in a const set literal must be constants.",
-          correction: "Try removing the keyword 'const' from the set literal.");
+          correction: "Try removing the keyword 'const' from the set literal.",
+          hasPublishedDocs: true);
 
   /**
    * This error code is no longer being generated. It should be removed when the
@@ -4644,7 +4660,8 @@
   static const CompileTimeErrorCode PART_OF_NON_PART = CompileTimeErrorCode(
       'PART_OF_NON_PART',
       "The included part '{0}' must have a part-of directive.",
-      correction: "Try adding a part-of directive to '{0}'.");
+      correction: "Try adding a part-of directive to '{0}'.",
+      hasPublishedDocs: true);
 
   /// Parts: It is a static warning if the referenced part declaration
   /// <i>p</i> names a library that does not have a library tag.
@@ -5076,8 +5093,9 @@
   //
   // Rewrite the code to not use `super`.
   static const CompileTimeErrorCode SUPER_IN_INVALID_CONTEXT =
-      CompileTimeErrorCode('SUPER_IN_INVALID_CONTEXT',
-          "Invalid context for 'super' invocation.");
+      CompileTimeErrorCode(
+          'SUPER_IN_INVALID_CONTEXT', "Invalid context for 'super' invocation.",
+          hasPublishedDocs: true);
 
   /**
    * 7.6.1 Generative Constructors: A generative constructor may be redirecting,
@@ -5096,6 +5114,16 @@
       CompileTimeErrorCode('SUPER_INITIALIZER_IN_OBJECT',
           "The class 'Object' can't invoke a constructor from a superclass.");
 
+  /// It is an error if any case of a switch statement except the last case
+  /// (the default case if present) may complete normally. The previous
+  /// syntactic restriction requiring the last statement of each case to be
+  /// one of an enumerated list of statements (break, continue, return,
+  /// throw, or rethrow) is removed.
+  static const CompileTimeErrorCode SWITCH_CASE_COMPLETES_NORMALLY =
+      CompileTimeErrorCode('SWITCH_CASE_COMPLETES_NORMALLY',
+          "The 'case' should not complete normally.",
+          correction: "Try adding 'break', or 'return', etc.");
+
   /**
    * Parameters:
    * 0: the name of the type used in the instance creation that should be
@@ -5299,7 +5327,8 @@
       CompileTimeErrorCode('UNDEFINED_CONSTRUCTOR_IN_INITIALIZER',
           "The class '{0}' doesn't have a constructor named '{1}'.",
           correction: "Try defining a constructor named '{1}' in '{0}', or "
-              "invoking a different constructor.");
+              "invoking a different constructor.",
+          hasPublishedDocs: true);
 
   /**
    * Parameters:
@@ -5951,7 +5980,8 @@
   // ```
   static const CompileTimeErrorCode WRONG_NUMBER_OF_PARAMETERS_FOR_SETTER =
       CompileTimeErrorCode('WRONG_NUMBER_OF_PARAMETERS_FOR_SETTER',
-          "Setters must declare exactly one required positional parameter.");
+          "Setters must declare exactly one required positional parameter.",
+          hasPublishedDocs: true);
 
   /**
    * Let `C` be a generic class that declares a formal type parameter `X`, and
@@ -6201,7 +6231,8 @@
   static const StaticTypeWarningCode INSTANCE_ACCESS_TO_STATIC_MEMBER =
       StaticTypeWarningCode('INSTANCE_ACCESS_TO_STATIC_MEMBER',
           "Static {1} '{0}' can't be accessed through an instance.",
-          correction: "Try using the class '{2}' to access the {1}.");
+          correction: "Try using the class '{2}' to access the {1}.",
+          hasPublishedDocs: true);
 
   /**
    * Parameters:
@@ -6338,7 +6369,8 @@
       StaticTypeWarningCode(
           'INVOCATION_OF_NON_FUNCTION_EXPRESSION',
           "The expression doesn't evaluate to a function, so it can't be "
-              "invoked.");
+              "invoked.",
+          hasPublishedDocs: true);
 
   /**
    * No parameters.
@@ -6407,7 +6439,7 @@
   static const StaticTypeWarningCode NON_BOOL_EXPRESSION =
       StaticTypeWarningCode('NON_BOOL_EXPRESSION',
           "The expression in an assert must be of type 'bool'.",
-          correction: "Try changing the expression.");
+          correction: "Try changing the expression.", hasPublishedDocs: true);
 
   /**
    * No parameters.
@@ -6438,7 +6470,8 @@
   static const StaticTypeWarningCode NON_BOOL_NEGATION_EXPRESSION =
       StaticTypeWarningCode('NON_BOOL_NEGATION_EXPRESSION',
           "A negation operand must have a static type of 'bool'.",
-          correction: "Try changing the operand to the '!' operator.");
+          correction: "Try changing the operand to the '!' operator.",
+          hasPublishedDocs: true);
 
   /**
    * Parameters:
@@ -6469,7 +6502,8 @@
   // ```
   static const StaticTypeWarningCode NON_BOOL_OPERAND = StaticTypeWarningCode(
       'NON_BOOL_OPERAND',
-      "The operands of the operator '{0}' must be assignable to 'bool'.");
+      "The operands of the operator '{0}' must be assignable to 'bool'.",
+      hasPublishedDocs: true);
 
   /**
    * Parameters:
@@ -6554,7 +6588,8 @@
       StaticTypeWarningCode(
           'RETURN_OF_INVALID_TYPE_FROM_CLOSURE',
           "The return type '{0}' isn't a '{1}', as required by the closure's "
-              "context.");
+              "context.",
+          hasPublishedDocs: true);
 
   /**
    * Parameters:
@@ -7134,7 +7169,8 @@
   // ```
   static const StaticTypeWarningCode FOR_IN_OF_INVALID_TYPE =
       StaticTypeWarningCode('FOR_IN_OF_INVALID_TYPE',
-          "The type '{0}' used in the 'for' loop must implement {1}.");
+          "The type '{0}' used in the 'for' loop must implement {1}.",
+          hasPublishedDocs: true);
 
   /**
    * 17.6.2 For-in. It the iterable expression does not implement Iterable with
@@ -7381,7 +7417,8 @@
   static const StaticWarningCode ASSIGNMENT_TO_FINAL = StaticWarningCode(
       'ASSIGNMENT_TO_FINAL',
       "'{0}' can't be used as a setter because it's final.",
-      correction: "Try finding a different setter, or making '{0}' non-final.");
+      correction: "Try finding a different setter, or making '{0}' non-final.",
+      hasPublishedDocs: true);
 
   /**
    * No parameters.
@@ -7419,7 +7456,8 @@
   static const StaticWarningCode ASSIGNMENT_TO_FINAL_LOCAL = StaticWarningCode(
       'ASSIGNMENT_TO_FINAL_LOCAL',
       "The final variable '{0}' can only be set once.",
-      correction: "Try making '{0}' non-final.");
+      correction: "Try making '{0}' non-final.",
+      hasPublishedDocs: true);
 
   /**
    * No parameters.
@@ -7520,7 +7558,8 @@
   //
   // Rewrite the code so that there isn't an assignment to a method.
   static const StaticWarningCode ASSIGNMENT_TO_METHOD = StaticWarningCode(
-      'ASSIGNMENT_TO_METHOD', "Methods can't be assigned a value.");
+      'ASSIGNMENT_TO_METHOD', "Methods can't be assigned a value.",
+      hasPublishedDocs: true);
 
   /**
    * 12.18 Assignment: It is as static warning if an assignment of the form
@@ -7576,7 +7615,8 @@
       'CASE_BLOCK_NOT_TERMINATED',
       "The last statement of the 'case' should be 'break', 'continue', "
           "'rethrow', 'return', or 'throw'.",
-      correction: "Try adding one of the required statements.");
+      correction: "Try adding one of the required statements.",
+      hasPublishedDocs: true);
 
   /**
    * No parameters.
@@ -8025,7 +8065,8 @@
   // create an instance of the concrete subclass.
   static const StaticWarningCode INSTANTIATE_ABSTRACT_CLASS = StaticWarningCode(
       'INSTANTIATE_ABSTRACT_CLASS', "Abstract classes can't be instantiated.",
-      correction: "Try creating an instance of a concrete subtype.");
+      correction: "Try creating an instance of a concrete subtype.",
+      hasPublishedDocs: true);
 
   /**
    * 7.1 Instance Methods: It is a static warning if an instance method
@@ -8158,7 +8199,8 @@
       StaticWarningCode(
           'MAP_KEY_TYPE_NOT_ASSIGNABLE',
           "The element type '{0}' can't be assigned to the map key type "
-              "'{1}'.");
+              "'{1}'.",
+          hasPublishedDocs: true);
 
   /**
    * Parameters:
@@ -8198,7 +8240,8 @@
       StaticWarningCode(
           'MAP_VALUE_TYPE_NOT_ASSIGNABLE',
           "The element type '{0}' can't be assigned to the map value type "
-              "'{1}'.");
+              "'{1}'.",
+          hasPublishedDocs: true);
 
   /**
    * Parameters:
@@ -8267,7 +8310,8 @@
       StaticWarningCode(
           'MISSING_ENUM_CONSTANT_IN_SWITCH', "Missing case clause for '{0}'.",
           correction: "Try adding a case clause for the missing constant, or "
-              "adding a default clause.");
+              "adding a default clause.",
+          hasPublishedDocs: true);
 
   @Deprecated('No longer an error in the spec and no longer generated')
   static const StaticWarningCode MIXED_RETURN_TYPES = StaticWarningCode(
@@ -8360,7 +8404,8 @@
       StaticWarningCode('NEW_WITH_UNDEFINED_CONSTRUCTOR_DEFAULT',
           "The class '{0}' doesn't have a default constructor.",
           correction:
-              "Try using one of the named constructors defined in '{0}'.");
+              "Try using one of the named constructors defined in '{0}'.",
+          hasPublishedDocs: true);
 
   /**
    * Parameters:
@@ -8543,7 +8588,8 @@
       'NON_TYPE_IN_CATCH_CLAUSE',
       "The name '{0}' isn't a type and can't be used in an on-catch "
           "clause.",
-      correction: "Try correcting the name to match an existing class.");
+      correction: "Try correcting the name to match an existing class.",
+      hasPublishedDocs: true);
 
   /**
    * 7.1.1 Operators: It is a static warning if the return type of the
@@ -8685,7 +8731,8 @@
           'REDIRECT_TO_INVALID_FUNCTION_TYPE',
           "The redirected constructor '{0}' has incompatible parameters with "
               "'{1}'.",
-          correction: "Try redirecting to a different constructor.");
+          correction: "Try redirecting to a different constructor.",
+          hasPublishedDocs: true);
 
   /**
    * Parameters:
@@ -8747,7 +8794,8 @@
           'REDIRECT_TO_INVALID_RETURN_TYPE',
           "The return type '{0}' of the redirected constructor isn't "
               "assignable to '{1}'.",
-          correction: "Try redirecting to a different constructor.");
+          correction: "Try redirecting to a different constructor.",
+          hasPublishedDocs: true);
 
   @Deprecated('Use CompileTimeErrorCode.REDIRECT_TO_MISSING_CONSTRUCTOR')
   static const CompileTimeErrorCode REDIRECT_TO_MISSING_CONSTRUCTOR =
@@ -8786,7 +8834,8 @@
   // }
   // ```
   static const StaticWarningCode RETURN_WITHOUT_VALUE = StaticWarningCode(
-      'RETURN_WITHOUT_VALUE', "The  return value is missing after 'return'.");
+      'RETURN_WITHOUT_VALUE', "The  return value is missing after 'return'.",
+      hasPublishedDocs: true);
 
   /**
    * Parameters:
@@ -8851,7 +8900,8 @@
   // ```
   static const StaticWarningCode STATIC_ACCESS_TO_INSTANCE_MEMBER =
       StaticWarningCode('STATIC_ACCESS_TO_INSTANCE_MEMBER',
-          "Instance member '{0}' can't be accessed using static access.");
+          "Instance member '{0}' can't be accessed using static access.",
+          hasPublishedDocs: true);
 
   /**
    * 13.9 Switch: It is a static warning if the type of <i>e</i> may not be
@@ -9089,7 +9139,8 @@
       correction:
           "Try checking to see if you're using the correct API; there might "
           "be a function or call that returns void you didn't expect. Also "
-          "check type parameters and variables which might also be void.");
+          "check type parameters and variables which might also be void.",
+      hasPublishedDocs: true);
 
   @override
   final ErrorSeverity errorSeverity;
diff --git a/pkg/analyzer/lib/src/error/correct_override.dart b/pkg/analyzer/lib/src/error/correct_override.dart
index a737b71..7e0a016 100644
--- a/pkg/analyzer/lib/src/error/correct_override.dart
+++ b/pkg/analyzer/lib/src/error/correct_override.dart
@@ -17,7 +17,6 @@
 
 class CorrectOverrideHelper {
   final TypeSystemImpl _typeSystem;
-  final ErrorReporter _errorReporter;
 
   final ExecutableElement _thisMember;
   FunctionType _thisTypeForSubtype;
@@ -28,10 +27,8 @@
 
   CorrectOverrideHelper({
     @required TypeSystemImpl typeSystem,
-    @required ErrorReporter errorReporter,
     @required ExecutableElement thisMember,
   })  : _typeSystem = typeSystem,
-        _errorReporter = errorReporter,
         _thisMember = thisMember {
     _computeThisTypeForSubtype();
   }
@@ -89,11 +86,22 @@
   /// error.
   void verify({
     @required ExecutableElement superMember,
+    @required ErrorReporter errorReporter,
     @required AstNode errorNode,
   }) {
     var isCorrect = isCorrectOverrideOf(superMember: superMember);
     if (!isCorrect) {
-      _reportInvalidOverride(errorNode, _thisMember, superMember);
+      errorReporter.reportErrorForNode(
+        CompileTimeErrorCode.INVALID_OVERRIDE,
+        errorNode,
+        [
+          _thisMember.name,
+          _thisMember.enclosingElement.name,
+          _thisMember.type,
+          superMember.enclosingElement.name,
+          superMember.type,
+        ],
+      );
     }
   }
 
@@ -162,24 +170,6 @@
     _superSubstitution = Substitution.fromPairs(superParameters, newTypes);
   }
 
-  void _reportInvalidOverride(
-    AstNode node,
-    ExecutableElement member,
-    ExecutableElement superMember,
-  ) {
-    _errorReporter.reportErrorForNode(
-      CompileTimeErrorCode.INVALID_OVERRIDE,
-      node,
-      [
-        member.name,
-        member.enclosingElement.name,
-        member.type,
-        superMember.enclosingElement.name,
-        superMember.type,
-      ],
-    );
-  }
-
   /// Return an element of [parameters] that corresponds for the [proto],
   /// or `null` if no such parameter exist.
   static ParameterElement _correspondingParameter(
diff --git a/pkg/analyzer/lib/src/error/dead_code_verifier.dart b/pkg/analyzer/lib/src/error/dead_code_verifier.dart
index ca5e9f7..98834a1 100644
--- a/pkg/analyzer/lib/src/error/dead_code_verifier.dart
+++ b/pkg/analyzer/lib/src/error/dead_code_verifier.dart
@@ -448,12 +448,13 @@
   /// is not a constant boolean value.
   EvaluationResultImpl _getConstantBooleanValue(Expression expression) {
     if (expression is BooleanLiteral) {
-      if (expression.value) {
-        return EvaluationResultImpl(DartObjectImpl(null, BoolState.from(true)));
-      } else {
-        return EvaluationResultImpl(
-            DartObjectImpl(null, BoolState.from(false)));
-      }
+      return EvaluationResultImpl(
+        DartObjectImpl(
+          _typeSystem,
+          _typeSystem.typeProvider.boolType,
+          BoolState.from(expression.value),
+        ),
+      );
     }
 
     // Don't consider situations where we could evaluate to a constant boolean
diff --git a/pkg/analyzer/lib/src/error/inheritance_override.dart b/pkg/analyzer/lib/src/error/inheritance_override.dart
index 9d4da67..0e3b487 100644
--- a/pkg/analyzer/lib/src/error/inheritance_override.dart
+++ b/pkg/analyzer/lib/src/error/inheritance_override.dart
@@ -233,10 +233,10 @@
         //  overriding method. The classNameNode is always wrong.
         CorrectOverrideHelper(
           typeSystem: typeSystem,
-          errorReporter: reporter,
           thisMember: concreteElement,
         ).verify(
           superMember: interfaceElement,
+          errorReporter: reporter,
           errorNode: classNameNode,
         );
       }
@@ -272,7 +272,6 @@
     var name = Name(libraryUri, member.name);
     var correctOverrideHelper = CorrectOverrideHelper(
       typeSystem: typeSystem,
-      errorReporter: reporter,
       thisMember: member,
     );
 
@@ -290,6 +289,7 @@
 
       correctOverrideHelper.verify(
         superMember: superMember,
+        errorReporter: reporter,
         errorNode: node,
       );
 
@@ -601,7 +601,10 @@
     } else {
       var candidatesStr = conflict.candidates.map((candidate) {
         var className = candidate.enclosingElement.name;
-        return '$className.${name.name} (${candidate.displayName})';
+        var typeStr = candidate.type.getDisplayString(
+          withNullability: typeSystem.isNonNullableByDefault,
+        );
+        return '$className.${name.name} ($typeStr)';
       }).join(', ');
 
       reporter.reportErrorForNode(
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index 03abc79..0e5fab1 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -20,7 +20,6 @@
 import 'package:analyzer/src/dart/resolver/resolution_result.dart';
 import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
 import 'package:analyzer/src/error/codes.dart';
-import 'package:analyzer/src/generated/element_type_provider.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/migratable_ast_info_provider.dart';
 import 'package:analyzer/src/generated/resolver.dart';
@@ -119,26 +118,21 @@
 
   MethodInvocationResolver _methodInvocationResolver;
 
-  final ElementTypeProvider _elementTypeProvider;
-
   /**
    * Initialize a newly created visitor to work for the given [_resolver] to
    * resolve the nodes in a compilation unit.
    */
   ElementResolver(this._resolver,
       {this.reportConstEvaluationErrors = true,
-      ElementTypeProvider elementTypeProvider = const ElementTypeProvider(),
       MigratableAstInfoProvider migratableAstInfoProvider =
           const MigratableAstInfoProvider()})
       : _definingLibrary = _resolver.definingLibrary,
         _extensionResolver = _resolver.extensionResolver,
-        _typePropertyResolver = _resolver.typePropertyResolver,
-        _elementTypeProvider = elementTypeProvider {
+        _typePropertyResolver = _resolver.typePropertyResolver {
     _dynamicType = _typeProvider.dynamicType;
     _typeType = _typeProvider.typeType;
     _methodInvocationResolver = MethodInvocationResolver(
       _resolver,
-      elementTypeProvider,
       migratableAstInfoProvider,
       inferenceHelper: _resolver.inferenceHelper,
     );
@@ -959,9 +953,7 @@
     if (expression is NullLiteral) {
       return _typeProvider.nullType;
     }
-    DartType type = read
-        ? getReadType(expression, elementTypeProvider: _elementTypeProvider)
-        : expression.staticType;
+    DartType type = read ? getReadType(expression) : expression.staticType;
     return _resolveTypeParameter(type);
   }
 
@@ -1220,8 +1212,7 @@
     if (executableElement == null) {
       return null;
     }
-    List<ParameterElement> parameters =
-        _elementTypeProvider.getExecutableParameters(executableElement);
+    List<ParameterElement> parameters = executableElement.parameters;
     return _resolveArgumentsToParameters(argumentList, parameters);
   }
 
diff --git a/pkg/analyzer/lib/src/generated/element_type_provider.dart b/pkg/analyzer/lib/src/generated/element_type_provider.dart
index 7d74e36..6eb52b0 100644
--- a/pkg/analyzer/lib/src/generated/element_type_provider.dart
+++ b/pkg/analyzer/lib/src/generated/element_type_provider.dart
@@ -4,6 +4,7 @@
 
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/element.dart';
 
 /// Abstraction layer allowing the mechanism for looking up the types of
 /// elements to be customized.
@@ -13,54 +14,52 @@
 ///
 /// This base class implementation gets types directly from the elements; for
 /// other behaviors, create a class that extends or implements this class.
+///
+/// Getters in the ElementImpl classes are automatically wired into this
+/// indirection mechanism, so it should be transparent to clients, as well as
+/// most analyzer internal code.
 class ElementTypeProvider {
+  /// The [ElementTypeProvider] currently in use.  Change this value to cause
+  /// element types to be looked up in a different way.
+  static ElementTypeProvider current = const ElementTypeProvider();
+
   const ElementTypeProvider();
 
+  /// Notifies the [ElementTypeProvider] that a fresh type parameter element has
+  /// been created.  If the [ElementTypeProvider] is storing additional
+  /// information about type parameter elements, this gives it an opportunity to
+  /// copy that information.
+  void freshTypeParameterCreated(TypeParameterElement newTypeParameter,
+      TypeParameterElement oldTypeParameter) {}
+
   /// Queries the parameters of an executable element's signature.
   ///
   /// Equivalent to `getExecutableType(...).parameters`.
-  List<ParameterElement> getExecutableParameters(ExecutableElement element) =>
-      element.parameters;
+  List<ParameterElement> getExecutableParameters(
+          ExecutableElementImpl element) =>
+      element.parametersInternal;
 
   /// Queries the return type of an executable element.
   ///
   /// Equivalent to `getExecutableType(...).returnType`.
-  DartType getExecutableReturnType(FunctionTypedElement element) =>
-      element.returnType;
+  DartType getExecutableReturnType(ElementImplWithFunctionType element) =>
+      element.returnTypeInternal;
 
   /// Queries the full type of an executable element.
   ///
   /// Guaranteed to be a function type.
-  FunctionType getExecutableType(FunctionTypedElement element) => element.type;
+  FunctionType getExecutableType(ElementImplWithFunctionType element) =>
+      element.typeInternal;
 
   /// Queries the type of a field.
-  DartType getFieldType(FieldElement element) => element.type;
+  DartType getFieldType(PropertyInducingElementImpl element) =>
+      element.typeInternal;
+
+  /// Queries the bound of a type parameter.
+  DartType getTypeParameterBound(TypeParameterElementImpl element) =>
+      element.boundInternal;
 
   /// Queries the type of a variable element.
-  DartType getVariableType(VariableElement variable) => variable.type;
-}
-
-/// Extension providing additional convenience functions based on
-/// [ElementTypeProvider].  This is an extension so that these methods don't
-/// need to be replicated when [ElementTypeProvider] is overridden.
-extension E on ElementTypeProvider {
-  /// Null-aware version of [ElementTypeProvider.getExecutableParameters].
-  List<ParameterElement> safeExecutableParameters(ExecutableElement element) =>
-      element == null ? null : getExecutableParameters(element);
-
-  /// Null-aware version of [ElementTypeProvider.getExecutableReturnType].
-  DartType safeExecutableReturnType(FunctionTypedElement element) =>
-      element == null ? null : getExecutableReturnType(element);
-
-  /// Null-aware version of [ElementTypeProvider.getExecutableType].
-  FunctionType safeExecutableType(ExecutableElement element) =>
-      element == null ? null : getExecutableType(element);
-
-  /// Null-aware version of [ElementTypeProvider.getFieldType].
-  DartType safeFieldType(FieldElement element) =>
-      element == null ? null : getFieldType(element);
-
-  /// Null-aware version of [ElementTypeProvider.getVariableType].
-  DartType safeVariableType(VariableElement variable) =>
-      variable == null ? null : getVariableType(variable);
+  DartType getVariableType(VariableElementImpl variable) =>
+      variable.typeInternal;
 }
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index f070892..96a2965 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -1885,6 +1885,8 @@
    * See [StaticWarningCode.CASE_BLOCK_NOT_TERMINATED].
    */
   void _checkForCaseBlocksNotTerminated(SwitchStatement statement) {
+    if (_isNonNullableByDefault) return;
+
     NodeList<SwitchMember> members = statement.members;
     int lastMember = members.length - 1;
     for (int i = 0; i < lastMember; i++) {
@@ -3576,7 +3578,6 @@
       if (mixinMember != null) {
         var isCorrect = CorrectOverrideHelper(
           typeSystem: _typeSystem,
-          errorReporter: _errorReporter,
           thisMember: superMember,
         ).isCorrectOverrideOf(
           superMember: mixinMember,
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 90fa793..f2b0528 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -39,7 +39,6 @@
 import 'package:analyzer/src/error/nullable_dereference_verifier.dart';
 import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/element_resolver.dart';
-import 'package:analyzer/src/generated/element_type_provider.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/migratable_ast_info_provider.dart';
 import 'package:analyzer/src/generated/migration.dart';
@@ -197,8 +196,6 @@
    */
   final FeatureSet _featureSet;
 
-  final ElementTypeProvider _elementTypeProvider;
-
   final MigratableAstInfoProvider _migratableAstInfoProvider;
 
   /// Helper for checking expression that should have the `bool` type.
@@ -314,8 +311,8 @@
             propagateTypes,
             reportConstEvaluationErrors,
             flowAnalysisHelper,
-            const ElementTypeProvider(),
-            const MigratableAstInfoProvider());
+            const MigratableAstInfoProvider(),
+            null);
 
   ResolverVisitor._(
       this.inheritance,
@@ -329,8 +326,8 @@
       bool propagateTypes,
       reportConstEvaluationErrors,
       this._flowAnalysis,
-      this._elementTypeProvider,
-      this._migratableAstInfoProvider)
+      this._migratableAstInfoProvider,
+      MigrationResolutionHooks migrationResolutionHooks)
       : _featureSet = featureSet,
         super(definingLibrary, source, typeProvider, errorListener,
             nameScope: nameScope) {
@@ -350,50 +347,39 @@
     this.extensionResolver = ExtensionMemberResolver(this);
     this.typePropertyResolver = TypePropertyResolver(this);
     this.inferenceHelper = InvocationInferenceHelper(
-      resolver: this,
-      definingLibrary: definingLibrary,
-      elementTypeProvider: _elementTypeProvider,
-      flowAnalysis: _flowAnalysis,
-      errorReporter: errorReporter,
-      typeSystem: typeSystem,
-    );
+        resolver: this,
+        definingLibrary: definingLibrary,
+        flowAnalysis: _flowAnalysis,
+        errorReporter: errorReporter,
+        typeSystem: typeSystem,
+        migrationResolutionHooks: migrationResolutionHooks);
     this._assignmentExpressionResolver = AssignmentExpressionResolver(
       resolver: this,
       flowAnalysis: _flowAnalysis,
-      elementTypeProvider: _elementTypeProvider,
     );
     this._binaryExpressionResolver = BinaryExpressionResolver(
       resolver: this,
       promoteManager: _promoteManager,
       flowAnalysis: _flowAnalysis,
-      elementTypeProvider: _elementTypeProvider,
     );
     this._functionExpressionInvocationResolver =
         FunctionExpressionInvocationResolver(
       resolver: this,
-      elementTypeProvider: _elementTypeProvider,
     );
     this._postfixExpressionResolver = PostfixExpressionResolver(
       resolver: this,
       flowAnalysis: _flowAnalysis,
-      elementTypeProvider: _elementTypeProvider,
     );
     this._prefixExpressionResolver = PrefixExpressionResolver(
       resolver: this,
       flowAnalysis: _flowAnalysis,
-      elementTypeProvider: _elementTypeProvider,
     );
     this.elementResolver = ElementResolver(this,
         reportConstEvaluationErrors: reportConstEvaluationErrors,
-        elementTypeProvider: _elementTypeProvider,
         migratableAstInfoProvider: _migratableAstInfoProvider);
     this.inferenceContext = InferenceContext._(this);
     this.typeAnalyzer = StaticTypeAnalyzer(
-      this,
-      featureSet,
-      _flowAnalysis,
-      elementTypeProvider: _elementTypeProvider,
-    );
+        this, featureSet, _flowAnalysis, migrationResolutionHooks);
   }
 
   /// Return the element representing the function containing the current node,
@@ -571,8 +557,7 @@
     node.constructorName?.accept(this);
     Element element = node.element;
     if (element is ExecutableElement) {
-      InferenceContext.setType(
-          node.arguments, _elementTypeProvider.getExecutableType(element));
+      InferenceContext.setType(node.arguments, element.type);
     }
     node.arguments?.accept(this);
     node.accept(elementResolver);
@@ -833,8 +818,7 @@
       _flowAnalysis?.executableDeclaration_enter(node, node.parameters, false);
       _promoteManager.enterFunctionBody(node.body);
       _enclosingFunction = node.declaredElement;
-      FunctionType type =
-          _elementTypeProvider.getExecutableType(_enclosingFunction);
+      FunctionType type = _enclosingFunction.type;
       InferenceContext.setType(node.body, type.returnType);
       super.visitConstructorDeclaration(node);
     } finally {
@@ -867,8 +851,7 @@
     // to be visited in the context of the constructor field initializer node.
     //
     FieldElement fieldElement = enclosingClass.getField(node.fieldName.name);
-    InferenceContext.setType(
-        node.expression, _elementTypeProvider.safeFieldType(fieldElement));
+    InferenceContext.setType(node.expression, fieldElement?.type);
     node.expression?.accept(this);
     node.accept(elementResolver);
     node.accept(typeAnalyzer);
@@ -898,8 +881,7 @@
 
   @override
   void visitDefaultFormalParameter(DefaultFormalParameter node) {
-    InferenceContext.setType(node.defaultValue,
-        _elementTypeProvider.safeVariableType(node.declaredElement));
+    InferenceContext.setType(node.defaultValue, node.declaredElement?.type);
     super.visitDefaultFormalParameter(node);
     ParameterElement element = node.declaredElement;
 
@@ -1072,12 +1054,11 @@
         identifier?.accept(this);
         identifierElement = identifier?.staticElement;
         if (identifierElement is VariableElement) {
-          valueType = _elementTypeProvider.getVariableType(identifierElement);
+          valueType = identifierElement.type;
         } else if (identifierElement is PropertyAccessorElement) {
-          var parameters =
-              _elementTypeProvider.getExecutableParameters(identifierElement);
+          var parameters = identifierElement.parameters;
           if (parameters.isNotEmpty) {
-            valueType = _elementTypeProvider.getVariableType(parameters[0]);
+            valueType = parameters[0].type;
           }
         }
       }
@@ -1169,12 +1150,11 @@
       if (identifier != null) {
         identifierElement = identifier.staticElement;
         if (identifierElement is VariableElement) {
-          valueType = _elementTypeProvider.getVariableType(identifierElement);
+          valueType = identifierElement.type;
         } else if (identifierElement is PropertyAccessorElement) {
-          var parameters =
-              _elementTypeProvider.getExecutableParameters(identifierElement);
+          var parameters = identifierElement.parameters;
           if (parameters.isNotEmpty) {
-            valueType = _elementTypeProvider.getVariableType(parameters[0]);
+            valueType = parameters[0].type;
           }
         }
       }
@@ -1243,8 +1223,8 @@
       }
       _promoteManager.enterFunctionBody(node.functionExpression.body);
       _enclosingFunction = functionName.staticElement as ExecutableElement;
-      InferenceContext.setType(node.functionExpression,
-          _elementTypeProvider.getExecutableType(_enclosingFunction));
+      InferenceContext.setType(
+          node.functionExpression, _enclosingFunction.type);
       super.visitFunctionDeclaration(node);
     } finally {
       if (_flowAnalysis != null) {
@@ -1427,11 +1407,10 @@
     node.accept(elementResolver);
     var method = node.staticElement;
     if (method != null) {
-      var parameters = _elementTypeProvider.getExecutableParameters(method);
+      var parameters = method.parameters;
       if (parameters.isNotEmpty) {
         var indexParam = parameters[0];
-        InferenceContext.setType(
-            node.index, _elementTypeProvider.getVariableType(indexParam));
+        InferenceContext.setType(node.index, indexParam.type);
       }
     }
     node.index?.accept(this);
@@ -1475,7 +1454,7 @@
       _promoteManager.enterFunctionBody(node.body);
       _enclosingFunction = node.declaredElement;
       DartType returnType = _computeReturnOrYieldType(
-        _elementTypeProvider.safeExecutableReturnType(_enclosingFunction),
+        _enclosingFunction?.returnType,
       );
       InferenceContext.setType(node.body, returnType);
       super.visitMethodDeclaration(node);
@@ -1606,8 +1585,7 @@
     // invocation.
     //
     node.accept(elementResolver);
-    InferenceContext.setType(node.argumentList,
-        _elementTypeProvider.safeExecutableType(node.staticElement));
+    InferenceContext.setType(node.argumentList, node.staticElement?.type);
     node.argumentList?.accept(this);
     node.accept(typeAnalyzer);
   }
@@ -1679,8 +1657,7 @@
     // invocation.
     //
     node.accept(elementResolver);
-    InferenceContext.setType(node.argumentList,
-        _elementTypeProvider.safeExecutableType(node.staticElement));
+    InferenceContext.setType(node.argumentList, node.staticElement?.type);
     node.argumentList?.accept(this);
     node.accept(typeAnalyzer);
   }
@@ -1692,6 +1669,17 @@
     InferenceContext.setType(
         node.expression, _enclosingSwitchStatementExpressionType);
     super.visitSwitchCase(node);
+
+    var flow = _flowAnalysis?.flow;
+    if (flow != null && flow.isReachable) {
+      var switchStatement = node.parent as SwitchStatement;
+      if (switchStatement.members.last != node && node.statements.isNotEmpty) {
+        errorReporter.reportErrorForToken(
+          CompileTimeErrorCode.SWITCH_CASE_COMPLETES_NORMALLY,
+          node.keyword,
+        );
+      }
+    }
   }
 
   @override
@@ -1818,8 +1806,7 @@
     _flowAnalysis?.variableDeclarationList(node);
     for (VariableDeclaration decl in node.variables) {
       VariableElement variableElement = decl.declaredElement;
-      InferenceContext.setType(
-          decl, _elementTypeProvider.safeVariableType(variableElement));
+      InferenceContext.setType(decl, variableElement?.type);
     }
     super.visitVariableDeclarationList(node);
   }
@@ -2031,7 +2018,7 @@
     }
 
     if (inferred == null) {
-      var type = _elementTypeProvider.safeExecutableType(originalElement);
+      var type = originalElement?.type;
       type = toLegacyTypeIfOptOut(type);
       InferenceContext.setType(node.argumentList, type);
     }
@@ -2142,6 +2129,8 @@
 /// Override of [ResolverVisitorForMigration] that invokes methods of
 /// [MigrationResolutionHooks] when appropriate.
 class ResolverVisitorForMigration extends ResolverVisitor {
+  final MigrationResolutionHooks _migrationResolutionHooks;
+
   ResolverVisitorForMigration(
       InheritanceManager3 inheritanceManager,
       LibraryElement definingLibrary,
@@ -2151,7 +2140,8 @@
       TypeSystem typeSystem,
       FeatureSet featureSet,
       MigrationResolutionHooks migrationResolutionHooks)
-      : super._(
+      : _migrationResolutionHooks = migrationResolutionHooks,
+        super._(
             inheritanceManager,
             definingLibrary,
             source,
@@ -2170,8 +2160,7 @@
   @override
   void visitIfElement(IfElement node) {
     var conditionalKnownValue =
-        (_elementTypeProvider as MigrationResolutionHooks)
-            .getConditionalKnownValue(node);
+        _migrationResolutionHooks.getConditionalKnownValue(node);
     if (conditionalKnownValue == null) {
       super.visitIfElement(node);
       return;
@@ -2184,8 +2173,7 @@
   @override
   void visitIfStatement(IfStatement node) {
     var conditionalKnownValue =
-        (_elementTypeProvider as MigrationResolutionHooks)
-            .getConditionalKnownValue(node);
+        _migrationResolutionHooks.getConditionalKnownValue(node);
     if (conditionalKnownValue == null) {
       super.visitIfStatement(node);
       return;
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 295cb6f..d9047b9 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -15,7 +15,6 @@
 import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
 import 'package:analyzer/src/error/codes.dart';
-import 'package:analyzer/src/generated/element_type_provider.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/migration.dart';
 import 'package:analyzer/src/generated/resolver.dart';
@@ -43,6 +42,8 @@
    */
   final FeatureSet _featureSet;
 
+  final MigrationResolutionHooks _migrationResolutionHooks;
+
   /**
    * The object providing access to the types defined by the language.
    */
@@ -76,8 +77,6 @@
 
   final FlowAnalysisHelper _flowAnalysis;
 
-  final ElementTypeProvider _elementTypeProvider;
-
   /**
    * Initialize a newly created static type analyzer to analyze types for the
    * [_resolver] based on the
@@ -85,8 +84,7 @@
    * @param resolver the resolver driving this participant
    */
   StaticTypeAnalyzer(this._resolver, this._featureSet, this._flowAnalysis,
-      {ElementTypeProvider elementTypeProvider = const ElementTypeProvider()})
-      : _elementTypeProvider = elementTypeProvider {
+      this._migrationResolutionHooks) {
     _typeProvider = _resolver.typeProvider;
     _typeSystem = _resolver.typeSystem;
     _dynamicType = _typeProvider.dynamicType;
@@ -138,13 +136,13 @@
     var classElement = constructor.enclosingElement;
     var typeParameters = classElement.typeParameters;
     if (typeParameters.isEmpty) {
-      return _elementTypeProvider.getExecutableType(constructor);
+      return constructor.type;
     }
 
     return FunctionTypeImpl(
       typeFormals: typeParameters,
-      parameters: _elementTypeProvider.getExecutableParameters(constructor),
-      returnType: _elementTypeProvider.getExecutableReturnType(constructor),
+      parameters: constructor.parameters,
+      returnType: constructor.returnType,
       nullabilitySuffix: NullabilitySuffix.star,
     );
   }
@@ -161,9 +159,7 @@
       void inferType(ParameterElementImpl p, DartType inferredType) {
         // Check that there is no declared type, and that we have not already
         // inferred a type in some fashion.
-        if (p.hasImplicitType &&
-            (_elementTypeProvider.getVariableType(p) == null ||
-                _elementTypeProvider.getVariableType(p).isDynamic)) {
+        if (p.hasImplicitType && (p.type == null || p.type.isDynamic)) {
           inferredType = _typeSystem.greatestClosure(inferredType);
           if (inferredType.isDartCoreNull) {
             inferredType = _typeProvider.objectType;
@@ -182,8 +178,7 @@
         Iterator<ParameterElement> fnPositional =
             functionType.parameters.where((p) => p.isPositional).iterator;
         while (positional.moveNext() && fnPositional.moveNext()) {
-          inferType(positional.current,
-              _elementTypeProvider.getVariableType(fnPositional.current));
+          inferType(positional.current, fnPositional.current.type);
         }
       }
 
@@ -299,8 +294,7 @@
       functionElement.returnType =
           _computeStaticReturnTypeOfFunctionDeclaration(node);
     }
-    _recordStaticType(
-        function, _elementTypeProvider.getExecutableType(functionElement));
+    _recordStaticType(function, functionElement.type);
   }
 
   /**
@@ -355,14 +349,12 @@
     } else {
       DartType type;
       if (node.inSetterContext()) {
-        var parameters =
-            _elementTypeProvider.safeExecutableParameters(node.staticElement);
+        var parameters = node.staticElement?.parameters;
         if (parameters?.length == 2) {
-          type = _elementTypeProvider.getVariableType(parameters[1]);
+          type = parameters[1].type;
         }
       } else {
-        type =
-            _elementTypeProvider.safeExecutableReturnType(node.staticElement);
+        type = node.staticElement?.returnType;
       }
 
       type ??= _dynamicType;
@@ -493,13 +485,13 @@
       }
       return;
     } else if (staticElement is MethodElement) {
-      staticType = _elementTypeProvider.getExecutableType(staticElement);
+      staticType = staticElement.type;
     } else if (staticElement is PropertyAccessorElement) {
       staticType = _getTypeOfProperty(staticElement);
     } else if (staticElement is ExecutableElement) {
-      staticType = _elementTypeProvider.getExecutableType(staticElement);
+      staticType = staticElement.type;
     } else if (staticElement is VariableElement) {
-      staticType = _elementTypeProvider.getVariableType(staticElement);
+      staticType = staticElement.type;
     }
 
     staticType = _inferTearOff(node, node.identifier, staticType);
@@ -556,7 +548,7 @@
     Element staticElement = propertyName.staticElement;
     DartType staticType = _dynamicType;
     if (staticElement is MethodElement) {
-      staticType = _elementTypeProvider.getExecutableType(staticElement);
+      staticType = staticElement.type;
     } else if (staticElement is PropertyAccessorElement) {
       staticType = _getTypeOfProperty(staticElement);
     } else {
@@ -642,11 +634,11 @@
       }
       return;
     } else if (element is MethodElement) {
-      staticType = _elementTypeProvider.getExecutableType(element);
+      staticType = element.type;
     } else if (element is PropertyAccessorElement) {
       staticType = _getTypeOfProperty(element);
     } else if (element is ExecutableElement) {
-      staticType = _elementTypeProvider.getExecutableType(element);
+      staticType = element.type;
     } else if (element is TypeParameterElement) {
       staticType = _nonNullable(_typeProvider.typeType);
     } else if (element is VariableElement) {
@@ -820,8 +812,7 @@
    * equivalent to [_getStaticType].
    */
   DartType _getExpressionType(Expression expr, {bool read = false}) =>
-      getExpressionType(expr, _typeSystem, _typeProvider,
-          read: read, elementTypeProvider: _elementTypeProvider);
+      getExpressionType(expr, _typeSystem, _typeProvider, read: read);
 
   /**
    * Return the static type of the given [expression].
@@ -829,13 +820,13 @@
   DartType _getStaticType(Expression expression, {bool read = false}) {
     DartType type;
     if (read) {
-      type = getReadType(expression, elementTypeProvider: _elementTypeProvider);
+      type = getReadType(expression);
     } else {
       if (expression is SimpleIdentifier && expression.inSetterContext()) {
         var element = expression.staticElement;
         if (element is PromotableElement) {
           // We're writing to the element so ignore promotions.
-          type = _elementTypeProvider.getVariableType(element);
+          type = element.type;
         } else {
           type = expression.staticType;
         }
@@ -871,8 +862,7 @@
    * @return the type that should be recorded for a node that resolved to the given accessor
    */
   DartType _getTypeOfProperty(PropertyAccessorElement accessor) {
-    FunctionType functionType =
-        _elementTypeProvider.getExecutableType(accessor);
+    FunctionType functionType = accessor.type;
     if (functionType == null) {
       // TODO(brianwilkerson) Report this internal error. This happens when we
       // are analyzing a reference to a property before we have analyzed the
@@ -887,7 +877,7 @@
       }
       PropertyAccessorElement getter = accessor.variable.getter;
       if (getter != null) {
-        functionType = _elementTypeProvider.getExecutableType(getter);
+        functionType = getter.type;
         if (functionType != null) {
           return functionType.returnType;
         }
@@ -938,8 +928,7 @@
         node.constructorName,
         isConst: node.isConst);
 
-    if (inferred != null &&
-        inferred != _elementTypeProvider.getExecutableType(originalElement)) {
+    if (inferred != null && inferred != originalElement.type) {
       inferred = _resolver.toLegacyTypeIfOptOut(inferred);
       // Fix up the parameter elements based on inferred method.
       arguments.correspondingStaticParameters =
@@ -972,8 +961,7 @@
 
     computedType = _computeReturnTypeOfFunction(body, computedType);
     functionElement.returnType = computedType;
-    _recordStaticType(
-        node, _elementTypeProvider.getExecutableType(functionElement));
+    _recordStaticType(node, functionElement.type);
   }
 
   /**
@@ -1028,8 +1016,7 @@
       return false;
     }
     inferredElement = _resolver.toLegacyElement(inferredElement);
-    DartType inferredType =
-        _elementTypeProvider.getExecutableReturnType(inferredElement);
+    DartType inferredType = inferredElement.returnType;
     if (nodeType != null &&
         nodeType.isDynamic &&
         inferredType is InterfaceType &&
@@ -1109,9 +1096,8 @@
    * @param type the static type of the node
    */
   void _recordStaticType(Expression expression, DartType type) {
-    var elementTypeProvider = this._elementTypeProvider;
-    if (elementTypeProvider is MigrationResolutionHooks) {
-      type = elementTypeProvider.modifyExpressionType(
+    if (_migrationResolutionHooks != null) {
+      type = _migrationResolutionHooks.modifyExpressionType(
           expression, type ?? _dynamicType);
     }
 
diff --git a/pkg/analyzer/lib/src/generated/testing/element_factory.dart b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
index f63784d..2fe0eb0 100644
--- a/pkg/analyzer/lib/src/generated/testing/element_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
@@ -18,6 +18,7 @@
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/testing/ast_test_factory.dart';
+import 'package:analyzer/src/generated/type_system.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
 import 'package:meta/meta.dart';
 import 'package:path/path.dart';
@@ -153,8 +154,15 @@
           [List<DartType> argumentTypes]) =>
       constructorElement(definingClass, name, false, argumentTypes);
 
+  @deprecated
   static EnumElementImpl enumElement(TypeProvider typeProvider, String enumName,
       [List<String> constantNames]) {
+    var typeSystem = TypeSystemImpl(
+      implicitCasts: false,
+      isNonNullableByDefault: false,
+      strictInference: false,
+      typeProvider: typeProvider,
+    );
     //
     // Build the enum.
     //
@@ -198,10 +206,12 @@
         constantElement.type = enumType;
         Map<String, DartObjectImpl> fieldMap =
             HashMap<String, DartObjectImpl>();
-        fieldMap[indexFieldName] = DartObjectImpl(intType, IntState(i));
+        fieldMap[indexFieldName] =
+            DartObjectImpl(typeSystem, intType, IntState(i));
         fieldMap[nameFieldName] =
-            DartObjectImpl(stringType, StringState(constantName));
-        DartObjectImpl value = DartObjectImpl(enumType, GenericState(fieldMap));
+            DartObjectImpl(typeSystem, stringType, StringState(constantName));
+        DartObjectImpl value =
+            DartObjectImpl(typeSystem, enumType, GenericState(fieldMap));
         constantElement.evaluationResult = EvaluationResultImpl(value);
         fields.add(constantElement);
       }
diff --git a/pkg/analyzer/lib/src/generated/type_system.dart b/pkg/analyzer/lib/src/generated/type_system.dart
index ed9acc4..96177bd 100644
--- a/pkg/analyzer/lib/src/generated/type_system.dart
+++ b/pkg/analyzer/lib/src/generated/type_system.dart
@@ -1215,26 +1215,6 @@
     return false;
   }
 
-  @override
-  bool isOverrideSubtypeOf(FunctionType f1, FunctionType f2) {
-    return FunctionTypeImpl.relate(f1, f2, isSubtypeOf,
-        parameterRelation: isOverrideSubtypeOfParameter,
-        // Type parameter bounds are invariant.
-        boundsRelation: (t1, t2, p1, p2) =>
-            isSubtypeOf(t1, t2) && isSubtypeOf(t2, t1));
-  }
-
-  /// Check that parameter [p2] is a subtype of [p1], given that we are
-  /// checking `f1 <: f2` where `p1` is a parameter of `f1` and `p2` is a
-  /// parameter of `f2`.
-  ///
-  /// Parameters are contravariant, so we must check `p2 <: p1` to
-  /// determine if `f1 <: f2`. This is used by [isOverrideSubtypeOf].
-  bool isOverrideSubtypeOfParameter(ParameterElement p1, ParameterElement p2) {
-    return isSubtypeOf(p2.type, p1.type) ||
-        p1.isCovariant && isSubtypeOf(p1.type, p2.type);
-  }
-
   /// Check if [_T0] is a subtype of [_T1].
   ///
   /// Implements:
@@ -1528,13 +1508,6 @@
     return NormalizeHelper(this).normalize(T);
   }
 
-  /// Return `true` if runtime types [T1] and [T2] are equal.
-  ///
-  /// nnbd/feature-specification.md#runtime-type-equality-operator
-  bool runtimeTypesEqual(DartType T1, DartType T2) {
-    return RuntimeTypeEqualityHelper(this).equal(T1, T2);
-  }
-
   @override
   DartType refineBinaryExpressionType(DartType leftType, TokenType operator,
       DartType rightType, DartType currentType) {
@@ -1570,6 +1543,13 @@
         .refineBinaryExpressionType(leftType, operator, rightType, currentType);
   }
 
+  /// Return `true` if runtime types [T1] and [T2] are equal.
+  ///
+  /// nnbd/feature-specification.md#runtime-type-equality-operator
+  bool runtimeTypesEqual(DartType T1, DartType T2) {
+    return RuntimeTypeEqualityHelper(this).equal(T1, T2);
+  }
+
   DartType toLegacyType(DartType type) {
     if (isNonNullableByDefault) return type;
     return NullabilityEliminator.perform(typeProvider, type);
@@ -3462,13 +3442,6 @@
     return false;
   }
 
-  /// Check that [f1] is a subtype of [f2] for a member override.
-  ///
-  /// This is different from the normal function subtyping in two ways:
-  /// - we know the function types are strict arrows,
-  /// - it allows opt-in covariant parameters.
-  bool isOverrideSubtypeOf(FunctionType f1, FunctionType f2);
-
   @override
   bool isPotentiallyNonNullable(DartType type) => !isNullable(type);
 
@@ -3585,8 +3558,12 @@
           );
         }
       } else {
+        // Note: we need to use `element.declaration` because `element` might
+        // itself be a TypeParameterMember (due to a previous promotion), and
+        // you can't create a TypeParameterMember wrapping a
+        // TypeParameterMember.
         return TypeParameterTypeImpl(
-          TypeParameterMember(element, null, promotedBound),
+          TypeParameterMember(element.declaration, null, promotedBound),
           nullabilitySuffix: NullabilitySuffix.none,
         );
       }
diff --git a/pkg/analyzer/lib/src/lint/linter.dart b/pkg/analyzer/lib/src/lint/linter.dart
index c81f36c..ccd0f72 100644
--- a/pkg/analyzer/lib/src/lint/linter.dart
+++ b/pkg/analyzer/lib/src/lint/linter.dart
@@ -441,7 +441,6 @@
       ConstantVerifier(
         errorReporter,
         libraryElement,
-        typeProvider,
         declaredVariables,
         featureSet: currentUnit.unit.featureSet,
       ),
diff --git a/pkg/analyzer/lib/src/summary2/function_type_builder.dart b/pkg/analyzer/lib/src/summary2/function_type_builder.dart
index 9ecafe6..4114f26 100644
--- a/pkg/analyzer/lib/src/summary2/function_type_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/function_type_builder.dart
@@ -91,7 +91,7 @@
   }
 
   @override
-  String toString({bool withNullability = false}) {
+  String toString() {
     var buffer = StringBuffer();
 
     if (typeFormals.isNotEmpty) {
diff --git a/pkg/analyzer/lib/src/summary2/named_type_builder.dart b/pkg/analyzer/lib/src/summary2/named_type_builder.dart
index 62ec33b..ebd18e5 100644
--- a/pkg/analyzer/lib/src/summary2/named_type_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/named_type_builder.dart
@@ -114,7 +114,7 @@
   }
 
   @override
-  String toString({bool withNullability = false}) {
+  String toString() {
     var buffer = StringBuffer();
     buffer.write(element.displayName);
     if (arguments.isNotEmpty) {
diff --git a/pkg/analyzer/lib/src/summary2/top_level_inference.dart b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
index bda48e5..ee81b9b 100644
--- a/pkg/analyzer/lib/src/summary2/top_level_inference.dart
+++ b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
@@ -9,6 +9,7 @@
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/resolver/scope.dart';
+import 'package:analyzer/src/generated/element_type_provider.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/summary/format.dart';
 import 'package:analyzer/src/summary/idl.dart';
@@ -199,7 +200,8 @@
   }
 }
 
-class _FunctionElementForLink_Initializer implements FunctionElementImpl {
+class _FunctionElementForLink_Initializer
+    implements FunctionElementImpl, ElementImplWithFunctionType {
   final _VariableInferenceNode _node;
 
   @override
@@ -208,7 +210,11 @@
   _FunctionElementForLink_Initializer(this._node);
 
   @override
-  DartType get returnType {
+  DartType get returnType =>
+      ElementTypeProvider.current.getExecutableReturnType(this);
+
+  @override
+  DartType get returnTypeInternal {
     if (!_node.isEvaluated) {
       _node._walker.walk(_node);
     }
diff --git a/pkg/analyzer/lib/src/task/strong/checker.dart b/pkg/analyzer/lib/src/task/strong/checker.dart
index ed6e25c..cf73b01 100644
--- a/pkg/analyzer/lib/src/task/strong/checker.dart
+++ b/pkg/analyzer/lib/src/task/strong/checker.dart
@@ -17,7 +17,6 @@
 import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/error/codes.dart' show StrongModeCode;
-import 'package:analyzer/src/generated/element_type_provider.dart';
 import 'package:analyzer/src/generated/type_system.dart';
 import 'package:analyzer/src/summary/idl.dart';
 
@@ -25,11 +24,10 @@
 /// gets the known static type of the expression.
 DartType getExpressionType(
     Expression expression, TypeSystemImpl typeSystem, TypeProvider typeProvider,
-    {bool read = false,
-    ElementTypeProvider elementTypeProvider = const ElementTypeProvider()}) {
+    {bool read = false}) {
   DartType type;
   if (read) {
-    type = getReadType(expression, elementTypeProvider: elementTypeProvider);
+    type = getReadType(expression);
   } else {
     type = expression.staticType;
   }
@@ -37,13 +35,12 @@
   return type;
 }
 
-DartType getReadType(Expression expression,
-    {ElementTypeProvider elementTypeProvider = const ElementTypeProvider()}) {
+DartType getReadType(Expression expression) {
   if (expression is IndexExpression) {
     var staticElement = expression.auxiliaryElements?.staticElement;
     return staticElement == null
         ? DynamicTypeImpl.instance
-        : elementTypeProvider.getExecutableReturnType(staticElement);
+        : staticElement.returnType;
   }
   {
     Element setter;
@@ -57,7 +54,7 @@
     if (setter is PropertyAccessorElement && setter.isSetter) {
       var getter = setter.variable.getter;
       if (getter != null) {
-        var type = elementTypeProvider.getExecutableReturnType(getter);
+        var type = getter.returnType;
         // The return type might be `null` when we perform top-level inference.
         // The first stage collects references to build the dependency graph.
         // TODO(scheglov) Maybe preliminary set types to `dynamic`?
@@ -71,7 +68,7 @@
       var staticElement = aux.staticElement;
       return staticElement == null
           ? DynamicTypeImpl.instance
-          : elementTypeProvider.getExecutableReturnType(staticElement);
+          : staticElement.returnType;
     }
   }
   return expression.staticType;
diff --git a/pkg/analyzer/test/dart/analysis/declared_variables_test.dart b/pkg/analyzer/test/dart/analysis/declared_variables_test.dart
deleted file mode 100644
index 0bdd537..0000000
--- a/pkg/analyzer/test/dart/analysis/declared_variables_test.dart
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:analyzer/dart/analysis/declared_variables.dart';
-import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/generated/constant.dart';
-import 'package:analyzer/src/generated/testing/test_type_provider.dart';
-import 'package:test/test.dart';
-import 'package:test_reflective_loader/test_reflective_loader.dart';
-
-main() {
-  defineReflectiveSuite(() {
-    defineReflectiveTests(DeclaredVariablesTest);
-  });
-}
-
-@reflectiveTest
-class DeclaredVariablesTest {
-  void test_getBool_false() {
-    TestTypeProvider typeProvider = TestTypeProvider();
-    String variableName = "var";
-    DeclaredVariables variables =
-        DeclaredVariables.fromMap({variableName: 'false'});
-    DartObject object = variables.getBool(typeProvider, variableName);
-    expect(object, isNotNull);
-    expect(object.toBoolValue(), false);
-  }
-
-  void test_getBool_invalid() {
-    TestTypeProvider typeProvider = TestTypeProvider();
-    String variableName = "var";
-    DeclaredVariables variables =
-        DeclaredVariables.fromMap({variableName: 'not true'});
-    _assertNullDartObject(
-        typeProvider, variables.getBool(typeProvider, variableName));
-  }
-
-  void test_getBool_true() {
-    TestTypeProvider typeProvider = TestTypeProvider();
-    String variableName = "var";
-    DeclaredVariables variables =
-        DeclaredVariables.fromMap({variableName: 'true'});
-    DartObject object = variables.getBool(typeProvider, variableName);
-    expect(object, isNotNull);
-    expect(object.toBoolValue(), true);
-  }
-
-  void test_getBool_undefined() {
-    TestTypeProvider typeProvider = TestTypeProvider();
-    String variableName = "var";
-    DeclaredVariables variables = DeclaredVariables();
-    _assertUnknownDartObject(
-        typeProvider.boolType, variables.getBool(typeProvider, variableName));
-  }
-
-  void test_getInt_invalid() {
-    TestTypeProvider typeProvider = TestTypeProvider();
-    String variableName = "var";
-    DeclaredVariables variables =
-        DeclaredVariables.fromMap({variableName: 'four score and seven years'});
-    _assertNullDartObject(
-        typeProvider, variables.getInt(typeProvider, variableName));
-  }
-
-  void test_getInt_undefined() {
-    TestTypeProvider typeProvider = TestTypeProvider();
-    String variableName = "var";
-    DeclaredVariables variables = DeclaredVariables();
-    _assertUnknownDartObject(
-        typeProvider.intType, variables.getInt(typeProvider, variableName));
-  }
-
-  void test_getInt_valid() {
-    TestTypeProvider typeProvider = TestTypeProvider();
-    String variableName = "var";
-    DeclaredVariables variables =
-        DeclaredVariables.fromMap({variableName: '23'});
-    DartObject object = variables.getInt(typeProvider, variableName);
-    expect(object, isNotNull);
-    expect(object.toIntValue(), 23);
-  }
-
-  void test_getString_defined() {
-    TestTypeProvider typeProvider = TestTypeProvider();
-    String variableName = "var";
-    String value = "value";
-    DeclaredVariables variables =
-        DeclaredVariables.fromMap({variableName: value});
-    DartObject object = variables.getString(typeProvider, variableName);
-    expect(object, isNotNull);
-    expect(object.toStringValue(), value);
-  }
-
-  void test_getString_undefined() {
-    TestTypeProvider typeProvider = TestTypeProvider();
-    String variableName = "var";
-    DeclaredVariables variables = DeclaredVariables();
-    _assertUnknownDartObject(typeProvider.stringType,
-        variables.getString(typeProvider, variableName));
-  }
-
-  void _assertNullDartObject(TestTypeProvider typeProvider, DartObject result) {
-    expect(result.type, typeProvider.nullType);
-  }
-
-  void _assertUnknownDartObject(DartType expectedType, DartObject result) {
-    expect((result as DartObjectImpl).isUnknown, isTrue);
-    expect(result.type, expectedType);
-  }
-}
diff --git a/pkg/analyzer/test/dart/analysis/from_environment_evaluator_test.dart b/pkg/analyzer/test/dart/analysis/from_environment_evaluator_test.dart
new file mode 100644
index 0000000..3204b56
--- /dev/null
+++ b/pkg/analyzer/test/dart/analysis/from_environment_evaluator_test.dart
@@ -0,0 +1,144 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/dart/analysis/declared_variables.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/dart/element/type_provider.dart';
+import 'package:analyzer/src/dart/constant/from_environment_evaluator.dart';
+import 'package:analyzer/src/generated/constant.dart';
+import 'package:analyzer/src/generated/type_system.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../../generated/test_analysis_context.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(FromEnvironmentEvaluatorTest);
+  });
+}
+
+@reflectiveTest
+class FromEnvironmentEvaluatorTest {
+  TypeProvider typeProvider;
+  TypeSystemImpl typeSystem;
+
+  void setUp() {
+    var analysisContext = TestAnalysisContext();
+    typeProvider = analysisContext.typeProviderLegacy;
+    typeSystem = analysisContext.typeSystemLegacy;
+  }
+
+  void test_getBool_false() {
+    String variableName = "var";
+    var variables = FromEnvironmentEvaluator(
+      typeSystem,
+      DeclaredVariables.fromMap({variableName: 'false'}),
+    );
+    DartObject object = variables.getBool(variableName);
+    expect(object, isNotNull);
+    expect(object.toBoolValue(), false);
+  }
+
+  void test_getBool_invalid() {
+    String variableName = "var";
+    var variables = FromEnvironmentEvaluator(
+      typeSystem,
+      DeclaredVariables.fromMap({variableName: 'not true'}),
+    );
+    _assertNullDartObject(
+      variables.getBool(variableName),
+    );
+  }
+
+  void test_getBool_true() {
+    String variableName = "var";
+    var variables = FromEnvironmentEvaluator(
+      typeSystem,
+      DeclaredVariables.fromMap({variableName: 'true'}),
+    );
+    DartObject object = variables.getBool(variableName);
+    expect(object, isNotNull);
+    expect(object.toBoolValue(), true);
+  }
+
+  void test_getBool_undefined() {
+    String variableName = "var";
+    var variables = FromEnvironmentEvaluator(
+      typeSystem,
+      DeclaredVariables(),
+    );
+    _assertUnknownDartObject(
+      typeProvider.boolType,
+      variables.getBool(variableName),
+    );
+  }
+
+  void test_getInt_invalid() {
+    String variableName = "var";
+    var variables = FromEnvironmentEvaluator(
+      typeSystem,
+      DeclaredVariables.fromMap({variableName: 'four score and seven years'}),
+    );
+    _assertNullDartObject(
+      variables.getInt(variableName),
+    );
+  }
+
+  void test_getInt_undefined() {
+    String variableName = "var";
+    var variables = FromEnvironmentEvaluator(
+      typeSystem,
+      DeclaredVariables(),
+    );
+    _assertUnknownDartObject(
+      typeProvider.intType,
+      variables.getInt(variableName),
+    );
+  }
+
+  void test_getInt_valid() {
+    String variableName = "var";
+    var variables = FromEnvironmentEvaluator(
+      typeSystem,
+      DeclaredVariables.fromMap({variableName: '23'}),
+    );
+    DartObject object = variables.getInt(variableName);
+    expect(object, isNotNull);
+    expect(object.toIntValue(), 23);
+  }
+
+  void test_getString_defined() {
+    String variableName = "var";
+    String value = "value";
+    var variables = FromEnvironmentEvaluator(
+      typeSystem,
+      DeclaredVariables.fromMap({variableName: value}),
+    );
+    DartObject object = variables.getString(variableName);
+    expect(object, isNotNull);
+    expect(object.toStringValue(), value);
+  }
+
+  void test_getString_undefined() {
+    String variableName = "var";
+    var variables = FromEnvironmentEvaluator(
+      typeSystem,
+      DeclaredVariables(),
+    );
+    _assertUnknownDartObject(
+      typeProvider.stringType,
+      variables.getString(variableName),
+    );
+  }
+
+  void _assertNullDartObject(DartObject result) {
+    expect(result.type, typeProvider.nullType);
+  }
+
+  void _assertUnknownDartObject(DartType expectedType, DartObject result) {
+    expect((result as DartObjectImpl).isUnknown, isTrue);
+    expect(result.type, expectedType);
+  }
+}
diff --git a/pkg/analyzer/test/dart/analysis/test_all.dart b/pkg/analyzer/test/dart/analysis/test_all.dart
index 44f950b..a7e9797 100644
--- a/pkg/analyzer/test/dart/analysis/test_all.dart
+++ b/pkg/analyzer/test/dart/analysis/test_all.dart
@@ -4,7 +4,7 @@
 
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import 'declared_variables_test.dart' as declared_variables;
+import 'from_environment_evaluator_test.dart' as declared_variables;
 import 'utilities_test.dart' as utilities;
 
 main() {
diff --git a/pkg/analyzer/test/generated/compile_time_error_code.dart b/pkg/analyzer/test/generated/compile_time_error_code.dart
index 89db9fe..410f60f 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code.dart
@@ -192,29 +192,6 @@
     ]);
   }
 
-  test_caseExpressionTypeImplementsEquals() async {
-    await assertErrorsInCode(r'''
-class IntWrapper {
-  final int value;
-  const IntWrapper(this.value);
-  bool operator ==(Object x) {
-    return x is IntWrapper && x.value == value;
-  }
-  get hashCode => value;
-}
-
-f(var a) {
-  switch(a) {
-    case(const IntWrapper(1)) : return 1;
-    default: return 0;
-  }
-}
-''', [
-      error(
-          CompileTimeErrorCode.CASE_EXPRESSION_TYPE_IMPLEMENTS_EQUALS, 194, 6),
-    ]);
-  }
-
   test_conflictingGenericInterfaces_hierarchyLoop() async {
     // There is no interface conflict here, but there is a loop in the class
     // hierarchy leading to a finite set of implemented types; this loop
diff --git a/pkg/analyzer/test/generated/element_resolver_test.dart b/pkg/analyzer/test/generated/element_resolver_test.dart
index 5deef1f..ad07280 100644
--- a/pkg/analyzer/test/generated/element_resolver_test.dart
+++ b/pkg/analyzer/test/generated/element_resolver_test.dart
@@ -555,27 +555,6 @@
     _listener.assertNoErrors();
   }
 
-  test_visitEnumDeclaration() async {
-    CompilationUnitElementImpl compilationUnitElement =
-        ElementFactory.compilationUnit('foo.dart');
-    EnumElementImpl enumElement =
-        ElementFactory.enumElement(_typeProvider, ('E'));
-    compilationUnitElement.enums = <ClassElement>[enumElement];
-    EnumDeclaration enumNode = AstTestFactory.enumDeclaration2('E', []);
-    Annotation annotationNode =
-        AstTestFactory.annotation(AstTestFactory.identifier3('a'));
-    annotationNode.element = ElementFactory.classElement2('A');
-    annotationNode.elementAnnotation =
-        ElementAnnotationImpl(compilationUnitElement);
-    enumNode.metadata.add(annotationNode);
-    enumNode.name.staticElement = enumElement;
-    List<ElementAnnotation> metadata = <ElementAnnotation>[
-      annotationNode.elementAnnotation
-    ];
-    _resolveNode(enumNode);
-    expect(metadata[0].element, annotationNode.element);
-  }
-
   test_visitExportDirective_noCombinators() async {
     ExportDirective directive = AstTestFactory.exportDirective2(null);
     directive.element = ElementFactory.exportFor(
diff --git a/pkg/analyzer/test/generated/non_error_resolver_test.dart b/pkg/analyzer/test/generated/non_error_resolver_test.dart
index 11645ae..1ec4a8f 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_test.dart
@@ -700,105 +700,6 @@
     ]);
   }
 
-  test_caseBlockNotTerminated() async {
-    await assertNoErrorsInCode(r'''
-f(int p) {
-  for (int i = 0; i < 10; i++) {
-    switch (p) {
-      case 0:
-        break;
-      case 1:
-        continue;
-      case 2:
-        return;
-      case 3:
-        throw new Object();
-      case 4:
-      case 5:
-        return;
-      case 6:
-      default:
-        return;
-    }
-  }
-}
-''');
-  }
-
-  test_caseBlockNotTerminated_lastCase() async {
-    await assertNoErrorsInCode(r'''
-f(int p) {
-  switch (p) {
-    case 0:
-      p = p + 1;
-  }
-}
-''');
-  }
-
-  test_caseExpressionTypeImplementsEquals() async {
-    await assertNoErrorsInCode(r'''
-print(p) {}
-
-abstract class B {
-  final id;
-  const B(this.id);
-  String toString() => 'C($id)';
-  /** Equality is identity equality, the id isn't used. */
-  bool operator==(Object other);
-  }
-
-class C extends B {
-  const C(id) : super(id);
-}
-
-void doSwitch(c) {
-  switch (c) {
-  case const C(0): print('Switch: 0'); break;
-  case const C(1): print('Switch: 1'); break;
-  }
-}
-''');
-  }
-
-  test_caseExpressionTypeImplementsEquals_int() async {
-    await assertNoErrorsInCode(r'''
-f(int i) {
-  switch(i) {
-    case(1) : return 1;
-    default: return 0;
-  }
-}
-''');
-  }
-
-  test_caseExpressionTypeImplementsEquals_Object() async {
-    await assertNoErrorsInCode(r'''
-class IntWrapper {
-  final int value;
-  const IntWrapper(this.value);
-}
-
-f(IntWrapper intWrapper) {
-  switch(intWrapper) {
-    case(const IntWrapper(1)) : return 1;
-    default: return 0;
-  }
-}
-''');
-  }
-
-  test_caseExpressionTypeImplementsEquals_String() async {
-    await assertNoErrorsInCode(r'''
-f(String s) {
-  switch(s) {
-    case('1') : return 1;
-    default: return 0;
-  }
-}
-''');
-  }
-
   test_class_type_alias_documentationComment() async {
     await assertNoErrorsInCode('''
 /**
diff --git a/pkg/analyzer/test/id_tests/type_promotion_test.dart b/pkg/analyzer/test/id_tests/type_promotion_test.dart
index ed67d91..e0779a3 100644
--- a/pkg/analyzer/test/id_tests/type_promotion_test.dart
+++ b/pkg/analyzer/test/id_tests/type_promotion_test.dart
@@ -92,7 +92,7 @@
   @override
   bool isEmpty(DartType actualData) => actualData == null;
 
-  String _typeToString(TypeImpl type) {
-    return type.toString(withNullability: true);
+  String _typeToString(DartType type) {
+    return type.getDisplayString(withNullability: true);
   }
 }
diff --git a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
index 9854564..640f482 100644
--- a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
+++ b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
@@ -159,7 +159,7 @@
 const a = b;
 const b = 3;''');
     var environment = <String, DartObjectImpl>{
-      'b': DartObjectImpl(typeProvider.intType, IntState(6)),
+      'b': DartObjectImpl(typeSystem, typeProvider.intType, IntState(6)),
     };
     var result = _evaluateConstant('a', lexicalEnvironment: environment);
     expect(result.type, typeProvider.intType);
@@ -171,7 +171,7 @@
 const a = b;
 const b = 3;''');
     var environment = <String, DartObjectImpl>{
-      'c': DartObjectImpl(typeProvider.intType, IntState(6)),
+      'c': DartObjectImpl(typeSystem, typeProvider.intType, IntState(6)),
     };
     var result = _evaluateConstant('a', lexicalEnvironment: environment);
     expect(result.type, typeProvider.intType);
diff --git a/pkg/analyzer/test/src/dart/constant/value_test.dart b/pkg/analyzer/test/src/dart/constant/value_test.dart
index a1910d2..6018be7 100644
--- a/pkg/analyzer/test/src/dart/constant/value_test.dart
+++ b/pkg/analyzer/test/src/dart/constant/value_test.dart
@@ -5,10 +5,12 @@
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/dart/element/type_provider.dart';
 import 'package:analyzer/src/generated/constant.dart';
-import 'package:analyzer/src/generated/testing/test_type_provider.dart';
+import 'package:analyzer/src/generated/type_system.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
+import '../../../generated/test_analysis_context.dart';
+
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(DartObjectImplTest);
@@ -22,7 +24,14 @@
 
 @reflectiveTest
 class DartObjectImplTest {
-  final TypeProvider _typeProvider = TestTypeProvider();
+  TypeProvider _typeProvider;
+  TypeSystemImpl _typeSystem;
+
+  void setUp() {
+    var analysisContext = TestAnalysisContext();
+    _typeProvider = analysisContext.typeProviderLegacy;
+    _typeSystem = analysisContext.typeSystemLegacy;
+  }
 
   void test_add_knownDouble_knownDouble() {
     _assertAdd(_doubleValue(3.0), _doubleValue(1.0), _doubleValue(2.0));
@@ -1360,8 +1369,15 @@
   }
 
   void test_shiftLeft_knownInt_tooLarge() {
-    _assertShiftLeft(_intValue(null), _intValue(6),
-        DartObjectImpl(_typeProvider.intType, IntState(LONG_MAX_VALUE)));
+    _assertShiftLeft(
+      _intValue(null),
+      _intValue(6),
+      DartObjectImpl(
+        _typeSystem,
+        _typeProvider.intType,
+        IntState(LONG_MAX_VALUE),
+      ),
+    );
   }
 
   void test_shiftLeft_knownInt_unknownInt() {
@@ -1393,8 +1409,15 @@
   }
 
   void test_shiftRight_knownInt_tooLarge() {
-    _assertShiftRight(_intValue(null), _intValue(48),
-        DartObjectImpl(_typeProvider.intType, IntState(LONG_MAX_VALUE)));
+    _assertShiftRight(
+      _intValue(null),
+      _intValue(48),
+      DartObjectImpl(
+        _typeSystem,
+        _typeProvider.intType,
+        IntState(LONG_MAX_VALUE),
+      ),
+    );
   }
 
   void test_shiftRight_knownInt_unknownInt() {
@@ -1488,10 +1511,10 @@
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
       expect(() {
-        left.add(_typeProvider, right);
+        left.add(_typeSystem, right);
       }, throwsEvaluationException);
     } else {
-      DartObjectImpl result = left.add(_typeProvider, right);
+      DartObjectImpl result = left.add(_typeSystem, right);
       expect(result, isNotNull);
       expect(result, expected);
     }
@@ -1504,10 +1527,10 @@
   void _assertBitNot(DartObjectImpl expected, DartObjectImpl operand) {
     if (expected == null) {
       expect(() {
-        operand.bitNot(_typeProvider);
+        operand.bitNot(_typeSystem);
       }, throwsEvaluationException);
     } else {
-      DartObjectImpl result = operand.bitNot(_typeProvider);
+      DartObjectImpl result = operand.bitNot(_typeSystem);
       expect(result, isNotNull);
       expect(result, expected);
     }
@@ -1522,10 +1545,10 @@
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
       expect(() {
-        left.concatenate(_typeProvider, right);
+        left.concatenate(_typeSystem, right);
       }, throwsEvaluationException);
     } else {
-      DartObjectImpl result = left.concatenate(_typeProvider, right);
+      DartObjectImpl result = left.concatenate(_typeSystem, right);
       expect(result, isNotNull);
       expect(result, expected);
     }
@@ -1540,10 +1563,10 @@
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
       expect(() {
-        left.divide(_typeProvider, right);
+        left.divide(_typeSystem, right);
       }, throwsEvaluationException);
     } else {
-      DartObjectImpl result = left.divide(_typeProvider, right);
+      DartObjectImpl result = left.divide(_typeSystem, right);
       expect(result, isNotNull);
       expect(result, expected);
     }
@@ -1558,10 +1581,10 @@
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
       expect(() {
-        left.eagerAnd(_typeProvider, right, false);
+        left.eagerAnd(_typeSystem, right, false);
       }, throwsEvaluationException);
     } else {
-      DartObjectImpl result = left.eagerAnd(_typeProvider, right, false);
+      DartObjectImpl result = left.eagerAnd(_typeSystem, right, false);
       expect(result, isNotNull);
       expect(result, expected);
     }
@@ -1576,10 +1599,10 @@
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
       expect(() {
-        left.eagerOr(_typeProvider, right, false);
+        left.eagerOr(_typeSystem, right, false);
       }, throwsEvaluationException);
     } else {
-      DartObjectImpl result = left.eagerOr(_typeProvider, right, false);
+      DartObjectImpl result = left.eagerOr(_typeSystem, right, false);
       expect(result, isNotNull);
       expect(result, expected);
     }
@@ -1594,10 +1617,10 @@
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
       expect(() {
-        left.eagerXor(_typeProvider, right, false);
+        left.eagerXor(_typeSystem, right, false);
       }, throwsEvaluationException);
     } else {
-      DartObjectImpl result = left.eagerXor(_typeProvider, right, false);
+      DartObjectImpl result = left.eagerXor(_typeSystem, right, false);
       expect(result, isNotNull);
       expect(result, expected);
     }
@@ -1612,10 +1635,10 @@
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
       expect(() {
-        left.equalEqual(_typeProvider, right);
+        left.equalEqual(_typeSystem, right);
       }, throwsEvaluationException);
     } else {
-      DartObjectImpl result = left.equalEqual(_typeProvider, right);
+      DartObjectImpl result = left.equalEqual(_typeSystem, right);
       expect(result, isNotNull);
       expect(result, expected);
     }
@@ -1630,10 +1653,10 @@
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
       expect(() {
-        left.greaterThan(_typeProvider, right);
+        left.greaterThan(_typeSystem, right);
       }, throwsEvaluationException);
     } else {
-      DartObjectImpl result = left.greaterThan(_typeProvider, right);
+      DartObjectImpl result = left.greaterThan(_typeSystem, right);
       expect(result, isNotNull);
       expect(result, expected);
     }
@@ -1648,10 +1671,10 @@
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
       expect(() {
-        left.greaterThanOrEqual(_typeProvider, right);
+        left.greaterThanOrEqual(_typeSystem, right);
       }, throwsEvaluationException);
     } else {
-      DartObjectImpl result = left.greaterThanOrEqual(_typeProvider, right);
+      DartObjectImpl result = left.greaterThanOrEqual(_typeSystem, right);
       expect(result, isNotNull);
       expect(result, expected);
     }
@@ -1663,7 +1686,7 @@
    */
   void _assertIdentical(
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
-    DartObjectImpl result = left.isIdentical(_typeProvider, right);
+    DartObjectImpl result = left.isIdentical2(_typeSystem, right);
     expect(result, isNotNull);
     expect(result, expected);
   }
@@ -1681,10 +1704,10 @@
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
       expect(() {
-        left.integerDivide(_typeProvider, right);
+        left.integerDivide(_typeSystem, right);
       }, throwsEvaluationException);
     } else {
-      DartObjectImpl result = left.integerDivide(_typeProvider, right);
+      DartObjectImpl result = left.integerDivide(_typeSystem, right);
       expect(result, isNotNull);
       expect(result, expected);
     }
@@ -1699,10 +1722,10 @@
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
       expect(() {
-        left.lazyAnd(_typeProvider, () => right);
+        left.lazyAnd(_typeSystem, () => right);
       }, throwsEvaluationException);
     } else {
-      DartObjectImpl result = left.lazyAnd(_typeProvider, () => right);
+      DartObjectImpl result = left.lazyAnd(_typeSystem, () => right);
       expect(result, isNotNull);
       expect(result, expected);
     }
@@ -1717,10 +1740,10 @@
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
       expect(() {
-        left.lazyOr(_typeProvider, () => right);
+        left.lazyOr(_typeSystem, () => right);
       }, throwsEvaluationException);
     } else {
-      DartObjectImpl result = left.lazyOr(_typeProvider, () => right);
+      DartObjectImpl result = left.lazyOr(_typeSystem, () => right);
       expect(result, isNotNull);
       expect(result, expected);
     }
@@ -1735,10 +1758,10 @@
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
       expect(() {
-        left.lessThan(_typeProvider, right);
+        left.lessThan(_typeSystem, right);
       }, throwsEvaluationException);
     } else {
-      DartObjectImpl result = left.lessThan(_typeProvider, right);
+      DartObjectImpl result = left.lessThan(_typeSystem, right);
       expect(result, isNotNull);
       expect(result, expected);
     }
@@ -1753,10 +1776,10 @@
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
       expect(() {
-        left.lessThanOrEqual(_typeProvider, right);
+        left.lessThanOrEqual(_typeSystem, right);
       }, throwsEvaluationException);
     } else {
-      DartObjectImpl result = left.lessThanOrEqual(_typeProvider, right);
+      DartObjectImpl result = left.lessThanOrEqual(_typeSystem, right);
       expect(result, isNotNull);
       expect(result, expected);
     }
@@ -1769,10 +1792,10 @@
   void _assertLogicalNot(DartObjectImpl expected, DartObjectImpl operand) {
     if (expected == null) {
       expect(() {
-        operand.logicalNot(_typeProvider);
+        operand.logicalNot(_typeSystem);
       }, throwsEvaluationException);
     } else {
-      DartObjectImpl result = operand.logicalNot(_typeProvider);
+      DartObjectImpl result = operand.logicalNot(_typeSystem);
       expect(result, isNotNull);
       expect(result, expected);
     }
@@ -1787,10 +1810,10 @@
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
       expect(() {
-        left.minus(_typeProvider, right);
+        left.minus(_typeSystem, right);
       }, throwsEvaluationException);
     } else {
-      DartObjectImpl result = left.minus(_typeProvider, right);
+      DartObjectImpl result = left.minus(_typeSystem, right);
       expect(result, isNotNull);
       expect(result, expected);
     }
@@ -1803,10 +1826,10 @@
   void _assertNegated(DartObjectImpl expected, DartObjectImpl operand) {
     if (expected == null) {
       expect(() {
-        operand.negated(_typeProvider);
+        operand.negated(_typeSystem);
       }, throwsEvaluationException);
     } else {
-      DartObjectImpl result = operand.negated(_typeProvider);
+      DartObjectImpl result = operand.negated(_typeSystem);
       expect(result, isNotNull);
       expect(result, expected);
     }
@@ -1821,10 +1844,10 @@
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
       expect(() {
-        left.notEqual(_typeProvider, right);
+        left.notEqual(_typeSystem, right);
       }, throwsEvaluationException);
     } else {
-      DartObjectImpl result = left.notEqual(_typeProvider, right);
+      DartObjectImpl result = left.notEqual(_typeSystem, right);
       expect(result, isNotNull);
       expect(result, expected);
     }
@@ -1837,10 +1860,10 @@
   void _assertPerformToString(DartObjectImpl expected, DartObjectImpl operand) {
     if (expected == null) {
       expect(() {
-        operand.performToString(_typeProvider);
+        operand.performToString(_typeSystem);
       }, throwsEvaluationException);
     } else {
-      DartObjectImpl result = operand.performToString(_typeProvider);
+      DartObjectImpl result = operand.performToString(_typeSystem);
       expect(result, isNotNull);
       expect(result, expected);
     }
@@ -1855,10 +1878,10 @@
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
       expect(() {
-        left.remainder(_typeProvider, right);
+        left.remainder(_typeSystem, right);
       }, throwsEvaluationException);
     } else {
-      DartObjectImpl result = left.remainder(_typeProvider, right);
+      DartObjectImpl result = left.remainder(_typeSystem, right);
       expect(result, isNotNull);
       expect(result, expected);
     }
@@ -1873,10 +1896,10 @@
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
       expect(() {
-        left.shiftLeft(_typeProvider, right);
+        left.shiftLeft(_typeSystem, right);
       }, throwsEvaluationException);
     } else {
-      DartObjectImpl result = left.shiftLeft(_typeProvider, right);
+      DartObjectImpl result = left.shiftLeft(_typeSystem, right);
       expect(result, isNotNull);
       expect(result, expected);
     }
@@ -1891,10 +1914,10 @@
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
       expect(() {
-        left.shiftRight(_typeProvider, right);
+        left.shiftRight(_typeSystem, right);
       }, throwsEvaluationException);
     } else {
-      DartObjectImpl result = left.shiftRight(_typeProvider, right);
+      DartObjectImpl result = left.shiftRight(_typeSystem, right);
       expect(result, isNotNull);
       expect(result, expected);
     }
@@ -1907,10 +1930,10 @@
   void _assertStringLength(DartObjectImpl expected, DartObjectImpl operand) {
     if (expected == null) {
       expect(() {
-        operand.stringLength(_typeProvider);
+        operand.stringLength(_typeSystem);
       }, throwsEvaluationException);
     } else {
-      DartObjectImpl result = operand.stringLength(_typeProvider);
+      DartObjectImpl result = operand.stringLength(_typeSystem);
       expect(result, isNotNull);
       expect(result, expected);
     }
@@ -1925,10 +1948,10 @@
       DartObjectImpl expected, DartObjectImpl left, DartObjectImpl right) {
     if (expected == null) {
       expect(() {
-        left.times(_typeProvider, right);
+        left.times(_typeSystem, right);
       }, throwsEvaluationException);
     } else {
-      DartObjectImpl result = left.times(_typeProvider, right);
+      DartObjectImpl result = left.times(_typeSystem, right);
       expect(result, isNotNull);
       expect(result, expected);
     }
@@ -1936,11 +1959,23 @@
 
   DartObjectImpl _boolValue(bool value) {
     if (value == null) {
-      return DartObjectImpl(_typeProvider.boolType, BoolState.UNKNOWN_VALUE);
+      return DartObjectImpl(
+        _typeSystem,
+        _typeProvider.boolType,
+        BoolState.UNKNOWN_VALUE,
+      );
     } else if (identical(value, false)) {
-      return DartObjectImpl(_typeProvider.boolType, BoolState.FALSE_STATE);
+      return DartObjectImpl(
+        _typeSystem,
+        _typeProvider.boolType,
+        BoolState.FALSE_STATE,
+      );
     } else if (identical(value, true)) {
-      return DartObjectImpl(_typeProvider.boolType, BoolState.TRUE_STATE);
+      return DartObjectImpl(
+        _typeSystem,
+        _typeProvider.boolType,
+        BoolState.TRUE_STATE,
+      );
     }
     fail("Invalid boolean value used in test");
   }
@@ -1948,17 +1983,32 @@
   DartObjectImpl _doubleValue(double value) {
     if (value == null) {
       return DartObjectImpl(
-          _typeProvider.doubleType, DoubleState.UNKNOWN_VALUE);
+        _typeSystem,
+        _typeProvider.doubleType,
+        DoubleState.UNKNOWN_VALUE,
+      );
     } else {
-      return DartObjectImpl(_typeProvider.doubleType, DoubleState(value));
+      return DartObjectImpl(
+        _typeSystem,
+        _typeProvider.doubleType,
+        DoubleState(value),
+      );
     }
   }
 
   DartObjectImpl _intValue(int value) {
     if (value == null) {
-      return DartObjectImpl(_typeProvider.intType, IntState.UNKNOWN_VALUE);
+      return DartObjectImpl(
+        _typeSystem,
+        _typeProvider.intType,
+        IntState.UNKNOWN_VALUE,
+      );
     } else {
-      return DartObjectImpl(_typeProvider.intType, IntState(value));
+      return DartObjectImpl(
+        _typeSystem,
+        _typeProvider.intType,
+        IntState(value),
+      );
     }
   }
 
@@ -1967,6 +2017,7 @@
     List<DartObjectImpl> elements,
   ) {
     return DartObjectImpl(
+      _typeSystem,
       _typeProvider.listType2(elementType),
       ListState(elements),
     );
@@ -1981,29 +2032,49 @@
       map[keyElementPairs[i++]] = keyElementPairs[i++];
     }
     return DartObjectImpl(
+      _typeSystem,
       _typeProvider.mapType2(keyType, valueType),
       MapState(map),
     );
   }
 
   DartObjectImpl _nullValue() {
-    return DartObjectImpl(_typeProvider.nullType, NullState.NULL_STATE);
+    return DartObjectImpl(
+      _typeSystem,
+      _typeProvider.nullType,
+      NullState.NULL_STATE,
+    );
   }
 
   DartObjectImpl _setValue(DartType type, Set<DartObjectImpl> elements) {
-    return DartObjectImpl(type, SetState(elements ?? <DartObjectImpl>{}));
+    return DartObjectImpl(
+      _typeSystem,
+      type,
+      SetState(elements ?? <DartObjectImpl>{}),
+    );
   }
 
   DartObjectImpl _stringValue(String value) {
     if (value == null) {
       return DartObjectImpl(
-          _typeProvider.stringType, StringState.UNKNOWN_VALUE);
+        _typeSystem,
+        _typeProvider.stringType,
+        StringState.UNKNOWN_VALUE,
+      );
     } else {
-      return DartObjectImpl(_typeProvider.stringType, StringState(value));
+      return DartObjectImpl(
+        _typeSystem,
+        _typeProvider.stringType,
+        StringState(value),
+      );
     }
   }
 
   DartObjectImpl _symbolValue(String value) {
-    return DartObjectImpl(_typeProvider.symbolType, SymbolState(value));
+    return DartObjectImpl(
+      _typeSystem,
+      _typeProvider.symbolType,
+      SymbolState(value),
+    );
   }
 }
diff --git a/pkg/analyzer/test/src/dart/element/element_test.dart b/pkg/analyzer/test/src/dart/element/element_test.dart
index a1ed2a6..32d8e11 100644
--- a/pkg/analyzer/test/src/dart/element/element_test.dart
+++ b/pkg/analyzer/test/src/dart/element/element_test.dart
@@ -223,20 +223,6 @@
     expect(classA.hasStaticMember, isTrue);
   }
 
-  void test_isEnum() {
-    String firstConst = "A";
-    String secondConst = "B";
-    EnumElementImpl enumE = ElementFactory.enumElement(
-        TestTypeProvider(), "E", [firstConst, secondConst]);
-
-    // E is an enum
-    expect(enumE.isEnum, true);
-
-    // A and B are static members
-    expect(enumE.getField(firstConst).isEnumConstant, true);
-    expect(enumE.getField(secondConst).isEnumConstant, true);
-  }
-
   void test_lookUpConcreteMethod_declared() {
     // class A {
     //   m() {}
@@ -867,28 +853,6 @@
 
 @reflectiveTest
 class CompilationUnitElementImplTest {
-  void test_getEnum_declared() {
-    TestTypeProvider typeProvider = TestTypeProvider();
-    CompilationUnitElementImpl unit =
-        ElementFactory.compilationUnit("/lib.dart");
-    String enumName = "E";
-    ClassElement enumElement =
-        ElementFactory.enumElement(typeProvider, enumName);
-    unit.enums = <ClassElement>[enumElement];
-    expect(unit.getEnum(enumName), same(enumElement));
-  }
-
-  void test_getEnum_undeclared() {
-    TestTypeProvider typeProvider = TestTypeProvider();
-    CompilationUnitElementImpl unit =
-        ElementFactory.compilationUnit("/lib.dart");
-    String enumName = "E";
-    ClassElement enumElement =
-        ElementFactory.enumElement(typeProvider, enumName);
-    unit.enums = <ClassElement>[enumElement];
-    expect(unit.getEnum("${enumName}x"), isNull);
-  }
-
   void test_getType_declared() {
     CompilationUnitElementImpl unit =
         ElementFactory.compilationUnit("/lib.dart");
diff --git a/pkg/analyzer/test/src/dart/resolution/constant_test.dart b/pkg/analyzer/test/src/dart/resolution/constant_test.dart
index 510112c..37f27e4 100644
--- a/pkg/analyzer/test/src/dart/resolution/constant_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/constant_test.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:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer/src/dart/element/element.dart';
@@ -232,4 +233,66 @@
       'List<Never Function(Object?)>',
     );
   }
+
+  test_field_optIn_fromOptOut() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  static const foo = 42;
+}
+''');
+
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+const bar = A.foo;
+''');
+
+    var bar = findElement.topVar('bar');
+    _assertIntValue(bar, 42);
+  }
+
+  test_topLevelVariable_optIn_fromOptOut() async {
+    newFile('/test/lib/a.dart', content: r'''
+const foo = 42;
+''');
+
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+const bar = foo;
+''');
+
+    var bar = findElement.topVar('bar');
+    assertType(bar.type, 'int*');
+    _assertIntValue(bar, 42);
+  }
+
+  test_topLevelVariable_optOut2() async {
+    newFile('/test/lib/a.dart', content: r'''
+const a = 42;
+''');
+
+    newFile('/test/lib/b.dart', content: r'''
+import 'a.dart';
+
+const b = a;
+''');
+
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'b.dart';
+
+const c = b;
+''');
+
+    var c = findElement.topVar('c');
+    assertType(c.type, 'int*');
+    _assertIntValue(c, 42);
+  }
+
+  void _assertIntValue(VariableElement element, int value) {
+    expect(element.constantValue.toIntValue(), value);
+  }
 }
diff --git a/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart
index 74fb1e9..92a1b1c 100644
--- a/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart
@@ -2,8 +2,10 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer/src/generated/engine.dart';
+import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import 'driver_resolution.dart';
@@ -175,10 +177,40 @@
 }
 ''');
 
+    var postfixExpression = findNode.postfix('x!');
     assertPostfixExpression(
-      findNode.postfix('x!'),
+      postfixExpression,
       element: null,
       type: 'T',
     );
+    expect(
+        postfixExpression.staticType,
+        TypeMatcher<TypeParameterType>().having(
+            (t) => t.bound.getDisplayString(withNullability: true),
+            'bound',
+            'Object'));
+  }
+
+  test_nullCheck_typeParameter_already_promoted() async {
+    await assertNoErrorsInCode('''
+f<T>(T? x) {
+  if (x is num?) {
+    x!;
+  }
+}
+''');
+
+    var postfixExpression = findNode.postfix('x!');
+    assertPostfixExpression(
+      postfixExpression,
+      element: null,
+      type: 'T',
+    );
+    expect(
+        postfixExpression.staticType,
+        TypeMatcher<TypeParameterType>().having(
+            (t) => t.bound.getDisplayString(withNullability: true),
+            'bound',
+            'num'));
   }
 }
diff --git a/pkg/analyzer/test/src/dart/resolution/resolution.dart b/pkg/analyzer/test/src/dart/resolution/resolution.dart
index 459660e..73c651d 100644
--- a/pkg/analyzer/test/src/dart/resolution/resolution.dart
+++ b/pkg/analyzer/test/src/dart/resolution/resolution.dart
@@ -17,6 +17,7 @@
 import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type_algebra.dart';
+import 'package:analyzer/src/generated/type_system.dart';
 import 'package:analyzer/src/test_utilities/find_element.dart';
 import 'package:analyzer/src/test_utilities/find_node.dart';
 import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
@@ -80,6 +81,8 @@
 
   TypeProvider get typeProvider => result.typeProvider;
 
+  TypeSystemImpl get typeSystem => result.typeSystem;
+
   /// Whether `DartType.toString()` with nullability should be asked.
   bool get typeToStringWithNullability => false;
 
diff --git a/pkg/analyzer/test/src/diagnostics/case_block_not_terminated_test.dart b/pkg/analyzer/test/src/diagnostics/case_block_not_terminated_test.dart
index 6594b74..3c52f06 100644
--- a/pkg/analyzer/test/src/diagnostics/case_block_not_terminated_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/case_block_not_terminated_test.dart
@@ -15,17 +15,96 @@
 
 @reflectiveTest
 class CaseBlockNotTerminatedTest extends DriverResolutionTest {
-  test_caseBlockNotTerminated() async {
-    await assertErrorsInCode('''
-f(int p) {
-  switch (p) {
+  test_lastCase() async {
+    await assertNoErrorsInCode(r'''
+f(int a) {
+  switch (a) {
     case 0:
-      f(p);
-    case 1:
-      break;
+      print(0);
+  }
+}
+''');
+  }
+
+  test_notTerminated() async {
+    await assertErrorsInCode('''
+void f(int a) {
+  switch (a) {
+    case 0:
+      print(0);
+    default:
+      return;
   }
 }''', [
-      error(StaticWarningCode.CASE_BLOCK_NOT_TERMINATED, 30, 4),
+      error(StaticWarningCode.CASE_BLOCK_NOT_TERMINATED, 35, 4),
     ]);
   }
+
+  test_terminated_break() async {
+    await assertNoErrorsInCode(r'''
+void f(int a) {
+  switch (a) {
+    case 0:
+      break;
+    default:
+      return;
+  }
+}
+''');
+  }
+
+  test_terminated_continue_loop() async {
+    await assertNoErrorsInCode(r'''
+void f(int a) {
+  while (true) {
+    switch (a) {
+      case 0:
+        continue;
+      default:
+        return;
+    }
+  }
+}
+''');
+  }
+
+  test_terminated_return() async {
+    await assertNoErrorsInCode(r'''
+void f(int a) {
+  switch (a) {
+    case 0:
+      return;
+    default:
+      return;
+  }
+}
+''');
+  }
+
+  test_terminated_return2() async {
+    await assertNoErrorsInCode(r'''
+void f(int a) {
+  switch (a) {
+    case 0:
+    case 1:
+      return;
+    default:
+      return;
+  }
+}
+''');
+  }
+
+  test_terminated_throw() async {
+    await assertNoErrorsInCode(r'''
+void f(int a) {
+  switch (a) {
+    case 0:
+      throw 42;
+    default:
+      return;
+  }
+}
+''');
+  }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/case_expression_type_implements_equals_test.dart b/pkg/analyzer/test/src/diagnostics/case_expression_type_implements_equals_test.dart
new file mode 100644
index 0000000..989da35
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/case_expression_type_implements_equals_test.dart
@@ -0,0 +1,103 @@
+// Copyright (c) 2020, 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/driver_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(CaseExpressionTypeImplementsEqualsTest);
+  });
+}
+
+@reflectiveTest
+class CaseExpressionTypeImplementsEqualsTest extends DriverResolutionTest {
+  test_declares() async {
+    await assertNoErrorsInCode(r'''
+print(p) {}
+
+abstract class B {
+  final id;
+  const B(this.id);
+  String toString() => 'C($id)';
+  /** Equality is identity equality, the id isn't used. */
+  bool operator==(Object other);
+  }
+
+class C extends B {
+  const C(id) : super(id);
+}
+
+void doSwitch(c) {
+  switch (c) {
+  case const C(0): print('Switch: 0'); break;
+  case const C(1): print('Switch: 1'); break;
+  }
+}
+''');
+  }
+
+  test_implements() async {
+    await assertErrorsInCode(r'''
+class IntWrapper {
+  final int value;
+  const IntWrapper(this.value);
+  bool operator ==(Object x) {
+    return x is IntWrapper && x.value == value;
+  }
+  get hashCode => value;
+}
+
+f(var a) {
+  switch(a) {
+    case(const IntWrapper(1)) : return 1;
+    default: return 0;
+  }
+}
+''', [
+      error(
+          CompileTimeErrorCode.CASE_EXPRESSION_TYPE_IMPLEMENTS_EQUALS, 194, 6),
+    ]);
+  }
+
+  test_int() async {
+    await assertNoErrorsInCode(r'''
+f(int i) {
+  switch(i) {
+    case(1) : return 1;
+    default: return 0;
+  }
+}
+''');
+  }
+
+  test_Object() async {
+    await assertNoErrorsInCode(r'''
+class IntWrapper {
+  final int value;
+  const IntWrapper(this.value);
+}
+
+f(IntWrapper intWrapper) {
+  switch(intWrapper) {
+    case(const IntWrapper(1)) : return 1;
+    default: return 0;
+  }
+}
+''');
+  }
+
+  test_String() async {
+    await assertNoErrorsInCode(r'''
+f(String s) {
+  switch(s) {
+    case('1') : return 1;
+    default: return 0;
+  }
+}
+''');
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_override_different_default_values_positional_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_override_different_default_values_positional_test.dart
index 07cfc59..944b726 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_override_different_default_values_positional_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_override_different_default_values_positional_test.dart
@@ -2,7 +2,9 @@
 // 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/dart/analysis/experiments.dart';
 import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../dart/resolution/driver_resolution.dart';
@@ -10,6 +12,9 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(InvalidOverrideDifferentDefaultValuesPositionalTest);
+    defineReflectiveTests(
+      InvalidOverrideDifferentDefaultValuesPositionalWithNnbdTest,
+    );
   });
 }
 
@@ -186,3 +191,49 @@
     ]);
   }
 }
+
+@reflectiveTest
+class InvalidOverrideDifferentDefaultValuesPositionalWithNnbdTest
+    extends InvalidOverrideDifferentDefaultValuesPositionalTest {
+  @override
+  AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+    ..enabledExperiments = [EnableString.non_nullable]
+    ..implicitCasts = false;
+
+  @override
+  bool get typeToStringWithNullability => true;
+
+  test_equal_optIn_extends_optOut() async {
+    newFile('/test/lib/a.dart', content: r'''
+// @dart = 2.7
+class A {
+  void foo([int a = 0]) {}
+}
+''');
+
+    await assertNoErrorsInCode(r'''
+import 'a.dart';
+
+class B extends A {
+  void foo([int a = 0]) {}
+}
+''');
+  }
+
+  test_equal_optOut_extends_optIn() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  void foo([int a = 0]) {}
+}
+''');
+
+    await assertNoErrorsInCode(r'''
+// @dart = 2.7
+import 'a.dart';
+
+class B extends A {
+  void foo([int a = 0]) {}
+}
+''');
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/non_null_opt_out_test.dart b/pkg/analyzer/test/src/diagnostics/non_null_opt_out_test.dart
index 398f6bc..3893cf2 100644
--- a/pkg/analyzer/test/src/diagnostics/non_null_opt_out_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/non_null_opt_out_test.dart
@@ -334,40 +334,6 @@
     _assertLegacyMember(element, _import_a.method('+'));
   }
 
-  test_const_field() async {
-    newFile('/test/lib/a.dart', content: r'''
-class A {
-  static const foo = 42;
-}
-''');
-    await assertNoErrorsInCode(r'''
-// @dart = 2.5
-import 'a.dart';
-
-const bar = A.foo;
-''');
-
-    var bar = findElement.topVar('bar');
-    assertType(bar.type, 'int*');
-    expect(bar.constantValue.toIntValue(), 42);
-  }
-
-  test_const_topLevelVariable() async {
-    newFile('/test/lib/a.dart', content: r'''
-const foo = 42;
-''');
-    await assertNoErrorsInCode(r'''
-// @dart = 2.5
-import 'a.dart';
-
-const bar = foo;
-''');
-
-    var bar = findElement.topVar('bar');
-    assertType(bar.type, 'int*');
-    expect(bar.constantValue.toIntValue(), 42);
-  }
-
   test_functionExpressionInvocation() async {
     newFile('/test/lib/a.dart', content: r'''
 int Function(int, int?)? foo;
diff --git a/pkg/analyzer/test/src/diagnostics/switch_case_completes_normally_test.dart b/pkg/analyzer/test/src/diagnostics/switch_case_completes_normally_test.dart
new file mode 100644
index 0000000..dd4d6ca
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/switch_case_completes_normally_test.dart
@@ -0,0 +1,162 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/dart/analysis/features.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(SwitchCaseCompletesNormallyTest);
+  });
+}
+
+@reflectiveTest
+class SwitchCaseCompletesNormallyTest extends DriverResolutionTest {
+  @override
+  AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+    ..contextFeatures = FeatureSet.forTesting(
+        sdkVersion: '2.7.0', additionalFeatures: [Feature.non_nullable]);
+
+  test_break() async {
+    await assertNoErrorsInCode(r'''
+void f(int a) {
+  switch (a) {
+    case 0:
+      break;
+    default:
+      return;
+  }
+}
+''');
+  }
+
+  test_completes() async {
+    await assertErrorsInCode('''
+void f(int a) {
+  switch (a) {
+    case 0:
+      print(0);
+    default:
+      return;
+  }
+}''', [
+      error(CompileTimeErrorCode.SWITCH_CASE_COMPLETES_NORMALLY, 35, 4),
+    ]);
+  }
+
+  test_continue_loop() async {
+    await assertNoErrorsInCode(r'''
+void f(int a) {
+  while (true) {
+    switch (a) {
+      case 0:
+        continue;
+      default:
+        return;
+    }
+  }
+}
+''');
+  }
+
+  test_for_whatever() async {
+    await assertNoErrorsInCode(r'''
+void f(int a) {
+  switch (a) {
+    case 0:
+      for (;;) {
+        print(0);
+      }
+    default:
+      return;
+  }
+}
+''');
+  }
+
+  test_lastCase() async {
+    await assertNoErrorsInCode(r'''
+f(int a) {
+  switch (a) {
+    case 0:
+      print(0);
+  }
+}
+''');
+  }
+
+  test_methodInvocation_never() async {
+    await assertNoErrorsInCode(r'''
+void f(int a) {
+  switch (a) {
+    case 0:
+      neverCompletes();
+    default:
+      return;
+  }
+}
+
+Never neverCompletes() {}
+''');
+  }
+
+  test_return() async {
+    await assertNoErrorsInCode(r'''
+void f(int a) {
+  switch (a) {
+    case 0:
+      return;
+    default:
+      return;
+  }
+}
+''');
+  }
+
+  test_return2() async {
+    await assertNoErrorsInCode(r'''
+void f(int a) {
+  switch (a) {
+    case 0:
+    case 1:
+      return;
+    default:
+      return;
+  }
+}
+''');
+  }
+
+  test_throw() async {
+    await assertNoErrorsInCode(r'''
+void f(int a) {
+  switch (a) {
+    case 0:
+      throw 42;
+    default:
+      return;
+  }
+}
+''');
+  }
+
+  test_while_true() async {
+    await assertNoErrorsInCode(r'''
+void f(int a) {
+  switch (a) {
+    case 0:
+      while (true) {
+        print(0);
+      }
+    default:
+      return;
+  }
+}
+''');
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 5879733..7411a24 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -31,6 +31,8 @@
     as builtin_as_extension_name;
 import 'can_be_null_after_null_aware_test.dart' as can_be_null_after_null_aware;
 import 'case_block_not_terminated_test.dart' as case_block_not_terminated;
+import 'case_expression_type_implements_equals_test.dart'
+    as case_expression_type_implements_equals;
 import 'cast_to_non_type_test.dart' as cast_to_non_type;
 import 'concrete_class_with_abstract_member_test.dart'
     as concrete_class_with_abstract_member;
@@ -410,6 +412,8 @@
 import 'super_in_redirecting_constructor_test.dart'
     as super_in_redirecting_constructor;
 import 'super_initializer_in_object_test.dart' as super_initializer_in_object;
+import 'switch_case_completes_normally_test.dart'
+    as switch_case_completes_normally;
 import 'switch_expression_not_assignable_test.dart'
     as switch_expression_not_assignable;
 import 'todo_test.dart' as todo_test;
@@ -508,6 +512,7 @@
     builtin_as_extension_name.main();
     can_be_null_after_null_aware.main();
     case_block_not_terminated.main();
+    case_expression_type_implements_equals.main();
     cast_to_non_type.main();
     concrete_class_with_abstract_member.main();
     conflicting_generic_interfaces.main();
@@ -761,6 +766,7 @@
     super_in_invalid_context.main();
     super_in_redirecting_constructor.main();
     super_initializer_in_object.main();
+    switch_case_completes_normally.main();
     switch_expression_not_assignable.main();
     todo_test.main();
     top_level_instance_getter.main();
diff --git a/pkg/analyzer_plugin/lib/src/utilities/completion/suggestion_builder.dart b/pkg/analyzer_plugin/lib/src/utilities/completion/suggestion_builder.dart
index e605603..27a22ee 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/completion/suggestion_builder.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/completion/suggestion_builder.dart
@@ -134,7 +134,7 @@
       if (element.kind == ElementKind.SETTER) {
         return null;
       } else {
-        return element.returnType?.toString();
+        return element.returnType?.getDisplayString(withNullability: false);
       }
     } else if (element is VariableElement) {
       DartType type = element.type;
@@ -142,7 +142,8 @@
           ? type.getDisplayString(withNullability: false)
           : 'dynamic';
     } else if (element is FunctionTypeAliasElement) {
-      return element.function.returnType.toString();
+      var returnType = element.function.returnType;
+      return returnType.getDisplayString(withNullability: false);
     } else {
       return null;
     }
diff --git a/pkg/analyzer_plugin/lib/utilities/analyzer_converter.dart b/pkg/analyzer_plugin/lib/utilities/analyzer_converter.dart
index 6c20347..701f320 100644
--- a/pkg/analyzer_plugin/lib/utilities/analyzer_converter.dart
+++ b/pkg/analyzer_plugin/lib/utilities/analyzer_converter.dart
@@ -256,14 +256,15 @@
       if (element.kind == analyzer.ElementKind.SETTER) {
         return null;
       }
-      return element.returnType?.toString();
+      return element.returnType?.getDisplayString(withNullability: false);
     } else if (element is analyzer.VariableElement) {
       analyzer.DartType type = element.type;
       return type != null
           ? type.getDisplayString(withNullability: false)
           : 'dynamic';
     } else if (element is analyzer.FunctionTypeAliasElement) {
-      return element.function.returnType.toString();
+      var returnType = element.function.returnType;
+      return returnType.getDisplayString(withNullability: false);
     }
     return null;
   }
diff --git a/pkg/analyzer_plugin/test/src/utilities/completion/completion_target_test.dart b/pkg/analyzer_plugin/test/src/utilities/completion/completion_target_test.dart
index 2a780d3..380166e 100644
--- a/pkg/analyzer_plugin/test/src/utilities/completion/completion_target_test.dart
+++ b/pkg/analyzer_plugin/test/src/utilities/completion/completion_target_test.dart
@@ -1000,11 +1000,12 @@
 
   static String _executableStr(ExecutableElement element) {
     var executableStr = _executableNameStr(element);
-
-    return '$executableStr: ${element.type}';
+    var typeStr = element.type.getDisplayString(withNullability: false);
+    return '$executableStr: $typeStr';
   }
 
   static String _parameterStr(ParameterElement element) {
-    return '${element.name}: ${element.type}';
+    var typeStr = element.type.getDisplayString(withNullability: false);
+    return '${element.name}: $typeStr';
   }
 }
diff --git a/pkg/compiler/lib/src/common/codegen.dart b/pkg/compiler/lib/src/common/codegen.dart
index 992fbe3..44e3980 100644
--- a/pkg/compiler/lib/src/common/codegen.dart
+++ b/pkg/compiler/lib/src/common/codegen.dart
@@ -676,13 +676,6 @@
         break;
       case ModularNameKind.globalPropertyNameForType:
       case ModularNameKind.runtimeTypeName:
-        bool dataIsClassEntity = source.readBool();
-        if (dataIsClassEntity) {
-          data = source.readClass();
-        } else {
-          data = source.readTypedef();
-        }
-        break;
       case ModularNameKind.className:
       case ModularNameKind.operatorIs:
       case ModularNameKind.substitution:
@@ -730,13 +723,6 @@
         break;
       case ModularNameKind.globalPropertyNameForType:
       case ModularNameKind.runtimeTypeName:
-        sink.writeBool(data is ClassEntity);
-        if (data is ClassEntity) {
-          sink.writeClass(data);
-        } else {
-          sink.writeTypedef(data);
-        }
-        break;
       case ModularNameKind.className:
       case ModularNameKind.operatorIs:
       case ModularNameKind.substitution:
@@ -868,12 +854,7 @@
         data = source.readClass();
         break;
       case ModularExpressionKind.globalObjectForType:
-        bool dataIsClassEntity = source.readBool();
-        if (dataIsClassEntity) {
-          data = source.readClass();
-        } else {
-          data = source.readTypedef();
-        }
+        data = source.readClass();
         break;
       case ModularExpressionKind.globalObjectForMember:
         data = source.readMember();
@@ -900,12 +881,7 @@
         sink.writeClass(data);
         break;
       case ModularExpressionKind.globalObjectForType:
-        sink.writeBool(data is ClassEntity);
-        if (data is ClassEntity) {
-          sink.writeClass(data);
-        } else {
-          sink.writeTypedef(data);
-        }
+        sink.writeClass(data);
         break;
       case ModularExpressionKind.globalObjectForMember:
         sink.writeMember(data);
diff --git a/pkg/compiler/lib/src/common_elements.dart b/pkg/compiler/lib/src/common_elements.dart
index 9ddd6dd..78e3d71 100644
--- a/pkg/compiler/lib/src/common_elements.dart
+++ b/pkg/compiler/lib/src/common_elements.dart
@@ -2335,13 +2335,6 @@
   /// Returns the type of [field].
   DartType getFieldType(FieldEntity field);
 
-  /// Returns the 'unaliased' type of [type]. For typedefs this is the function
-  /// type it is an alias of, for other types it is the type itself.
-  ///
-  /// Use this during resolution to ensure that the alias has been computed.
-  // TODO(johnniwinther): Remove this when the resolver is removed.
-  DartType getUnaliasedType(DartType type);
-
   /// Returns `true` if [cls] is a Dart enum class.
   bool isEnumClass(ClassEntity cls);
 }
diff --git a/pkg/compiler/lib/src/constants/values.dart b/pkg/compiler/lib/src/constants/values.dart
index 76c3302..fab1045 100644
--- a/pkg/compiler/lib/src/constants/values.dart
+++ b/pkg/compiler/lib/src/constants/values.dart
@@ -540,11 +540,11 @@
   @override
   bool operator ==(other) {
     return other is TypeConstantValue &&
-        representedType.unaliased == other.representedType.unaliased;
+        representedType == other.representedType;
   }
 
   @override
-  int get hashCode => representedType.unaliased.hashCode * 13;
+  int get hashCode => representedType.hashCode * 13;
 
   @override
   List<ConstantValue> getDependencies() => const <ConstantValue>[];
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart
index 42aa893..7083e91 100644
--- a/pkg/compiler/lib/src/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load.dart
@@ -173,10 +173,6 @@
   Iterable<ImportEntity> memberImportsTo(
       MemberEntity element, LibraryEntity library);
 
-  /// Returns every [ImportEntity] that imports [element] into [library].
-  Iterable<ImportEntity> typedefImportsTo(
-      TypedefEntity element, LibraryEntity library);
-
   /// Collects all direct dependencies of [element].
   ///
   /// The collected dependent elements and constants are are added to
@@ -558,10 +554,6 @@
         var imports = classImportsTo(type.element, library);
         _fixDependencyInfo(
             info, imports, "Class (in constant) ", type.element.name, context);
-      } else if (type is TypedefType) {
-        var imports = typedefImportsTo(type.element, library);
-        _fixDependencyInfo(
-            info, imports, "Typedef ", type.element.name, context);
       }
     }
   }
@@ -1697,12 +1689,6 @@
   }
 
   @override
-  void visitTypedefType(TypedefType type, Null argument) {
-    visitList(type.typeArguments);
-    visit(type.unaliased);
-  }
-
-  @override
   void visitInterfaceType(InterfaceType type, Null argument) {
     visitList(type.typeArguments);
     // TODO(sigmund): when we are able to split classes from types in our
diff --git a/pkg/compiler/lib/src/elements/entities.dart b/pkg/compiler/lib/src/elements/entities.dart
index 9ca42c6..bad2d7c 100644
--- a/pkg/compiler/lib/src/elements/entities.dart
+++ b/pkg/compiler/lib/src/elements/entities.dart
@@ -75,11 +75,6 @@
   bool get isAbstract;
 }
 
-abstract class TypedefEntity extends Entity {
-  /// The library in which the typedef was declared.
-  LibraryEntity get library;
-}
-
 abstract class TypeVariableEntity extends Entity {
   /// The class or generic method that declared this type variable.
   Entity get typeDeclaration;
diff --git a/pkg/compiler/lib/src/elements/indexed.dart b/pkg/compiler/lib/src/elements/indexed.dart
index 6a6afc4..781d600 100644
--- a/pkg/compiler/lib/src/elements/indexed.dart
+++ b/pkg/compiler/lib/src/elements/indexed.dart
@@ -45,11 +45,6 @@
   int get typeVariableIndex => _index;
 }
 
-abstract class IndexedTypedef extends _Indexed implements TypedefEntity {
-  /// Typedef index used for fast lookup in [KernelToElementMapBase].
-  int get typedefIndex => _index;
-}
-
 abstract class IndexedLocal extends _Indexed implements Local {
   int get localIndex => _index;
 }
diff --git a/pkg/compiler/lib/src/elements/types.dart b/pkg/compiler/lib/src/elements/types.dart
index efc2f70..008cda1 100644
--- a/pkg/compiler/lib/src/elements/types.dart
+++ b/pkg/compiler/lib/src/elements/types.dart
@@ -25,16 +25,6 @@
 abstract class DartType {
   const DartType();
 
-  /// Returns the unaliased type of this type.
-  ///
-  /// The unaliased type of a typedef'd type is the unaliased type to which its
-  /// name is bound. The unaliased version of any other type is the type itself.
-  ///
-  /// For example, the unaliased type of `typedef A Func<A,B>(B b)` is the
-  /// function type `(B) -> A` and the unaliased type of `Func<int,String>`
-  /// is the function type `(String) -> int`.
-  DartType get unaliased => this;
-
   /// Is `true` if this type is a top type.
   bool _isTop(bool isLegacy) => false;
 
@@ -292,68 +282,6 @@
   }
 }
 
-class TypedefType extends DartType {
-  final TypedefEntity element;
-  final List<DartType> typeArguments;
-  @override
-  final FunctionType unaliased;
-
-  TypedefType(this.element, this.typeArguments, this.unaliased);
-
-  @override
-  bool _isTop(bool isLegacy) => unaliased._isTop(isLegacy);
-
-  @override
-  bool get containsTypeVariables =>
-      typeArguments.any((type) => type.containsTypeVariables);
-
-  @override
-  void forEachTypeVariable(f(TypeVariableType variable)) {
-    typeArguments.forEach((type) => type.forEachTypeVariable(f));
-  }
-
-  @override
-  bool _treatAsRaw(bool isLegacy) {
-    for (DartType type in typeArguments) {
-      if (!type._isTop(isLegacy)) return false;
-    }
-    return true;
-  }
-
-  @override
-  R accept<R, A>(DartTypeVisitor<R, A> visitor, A argument) =>
-      visitor.visitTypedefType(this, argument);
-
-  @override
-  int get hashCode {
-    int hash = element.hashCode;
-    for (DartType argument in typeArguments) {
-      int argumentHash = argument != null ? argument.hashCode : 0;
-      hash = 17 * hash + 3 * argumentHash;
-    }
-    return hash;
-  }
-
-  @override
-  bool operator ==(other) {
-    if (identical(this, other)) return true;
-    if (other is! TypedefType) return false;
-    return _equalsInternal(other, null);
-  }
-
-  @override
-  bool _equals(DartType other, _Assumptions assumptions) {
-    if (identical(this, other)) return true;
-    if (other is! TypedefType) return false;
-    return _equalsInternal(other, assumptions);
-  }
-
-  bool _equalsInternal(TypedefType other, _Assumptions assumptions) {
-    return identical(element, other.element) &&
-        _equalTypes(typeArguments, other.typeArguments, assumptions);
-  }
-}
-
 class TypeVariableType extends DartType {
   final TypeVariableEntity element;
 
@@ -752,8 +680,6 @@
 
   R visitInterfaceType(covariant InterfaceType type, A argument) => null;
 
-  R visitTypedefType(covariant TypedefType type, A argument) => null;
-
   R visitDynamicType(covariant DynamicType type, A argument) => null;
 
   R visitErasedType(covariant ErasedType type, A argument) => null;
@@ -1013,22 +939,6 @@
   }
 
   @override
-  DartType visitTypedefType(covariant TypedefType type, A argument) {
-    DartType probe = _map[type];
-    if (probe != null) return probe;
-
-    List<DartType> newTypeArguments = _substTypes(type.typeArguments, argument);
-    FunctionType newUnaliased = visit(type.unaliased, argument);
-    // Create a new type only if necessary.
-    if (identical(type.typeArguments, newTypeArguments) &&
-        identical(type.unaliased, newUnaliased)) {
-      return _mapped(type, type);
-    }
-    return _mapped(
-        type, TypedefType(type.element, newTypeArguments, newUnaliased));
-  }
-
-  @override
   DartType visitDynamicType(covariant DynamicType type, A argument) => type;
 
   @override
@@ -1107,7 +1017,6 @@
   bool handleFreeFunctionTypeVariable(FunctionTypeVariable type) => false;
   bool handleFunctionType(FunctionType type) => false;
   bool handleInterfaceType(InterfaceType type) => false;
-  bool handleTypedefType(TypedefType type) => false;
   bool handleDynamicType(DynamicType type) => false;
   bool handleErasedType(ErasedType type) => false;
   bool handleAnyType(AnyType type) => false;
@@ -1173,13 +1082,6 @@
   }
 
   @override
-  bool visitTypedefType(TypedefType type, List<FunctionTypeVariable> bindings) {
-    if (handleTypedefType(type)) return true;
-    if (_visitAll(type.typeArguments, bindings)) return true;
-    return visit(type.unaliased, bindings);
-  }
-
-  @override
   bool visitDynamicType(
           DynamicType type, List<FunctionTypeVariable> bindings) =>
       handleDynamicType(type);
@@ -1452,12 +1354,6 @@
     _optionalTypeArguments(type.typeArguments);
   }
 
-  @override
-  void visitTypedefType(covariant TypedefType type, _) {
-    _identifier(type.element.name);
-    _optionalTypeArguments(type.typeArguments);
-  }
-
   void _optionalTypeArguments(List<DartType> types) {
     if (types.isNotEmpty) {
       _token('<');
@@ -1519,9 +1415,6 @@
     /// See also [_isSubtype] in `dart:_rti`.
     bool _isSubtype(DartType s, Set<FunctionTypeVariable> sEnv, DartType t,
         Set<FunctionTypeVariable> tEnv) {
-      s = s.unaliased;
-      t = t.unaliased;
-
       // Reflexivity:
       if (s == t) return true;
       if (s is FunctionTypeVariable &&
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
index 5dbcf12..5685069 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
@@ -2262,7 +2262,7 @@
     otherType = abstractValueDomain.createNonNullSubtype(annotation.element);
   } else if (annotation is VoidType) {
     return type;
-  } else if (annotation is TypedefType || annotation is FunctionType) {
+  } else if (annotation is FunctionType) {
     otherType = closedWorld.abstractValueDomain.functionType;
   } else if (annotation is FutureOrType) {
     // TODO(johnniwinther): Narrow FutureOr types.
diff --git a/pkg/compiler/lib/src/inferrer/type_system.dart b/pkg/compiler/lib/src/inferrer/type_system.dart
index cec794d..43c0f1d 100644
--- a/pkg/compiler/lib/src/inferrer/type_system.dart
+++ b/pkg/compiler/lib/src/inferrer/type_system.dart
@@ -335,7 +335,7 @@
         otherType =
             _abstractValueDomain.createNonNullSubtype(interface.element);
       }
-    } else if (annotation is TypedefType || annotation is FunctionType) {
+    } else if (annotation is FunctionType) {
       otherType = functionType.type;
     } else if (annotation is FutureOrType) {
       // TODO(johnniwinther): Support narrowing of FutureOr.
diff --git a/pkg/compiler/lib/src/ir/constants.dart b/pkg/compiler/lib/src/ir/constants.dart
index 04a9deb..768b8e1 100644
--- a/pkg/compiler/lib/src/ir/constants.dart
+++ b/pkg/compiler/lib/src/ir/constants.dart
@@ -23,6 +23,8 @@
       bool enableTripleShift = false,
       bool supportReevaluationForTesting: false})
       : _supportReevaluationForTesting = supportReevaluationForTesting,
+        // TODO(johnniwinther,sigmund): Pass evaluation mode for nnbd
+        //  strong/weak mode.
         super(
             const Dart2jsConstantsBackend(supportsUnevaluatedConstants: false),
             environment,
diff --git a/pkg/compiler/lib/src/ir/element_map.dart b/pkg/compiler/lib/src/ir/element_map.dart
index f521fac..22d2571 100644
--- a/pkg/compiler/lib/src/ir/element_map.dart
+++ b/pkg/compiler/lib/src/ir/element_map.dart
@@ -42,9 +42,6 @@
   /// Returns the [FunctionType] of the [node].
   FunctionType getFunctionType(ir.FunctionNode node);
 
-  /// Returns the [TypedefType] corresponding to raw type of the typedef [node].
-  TypedefType getTypedefType(ir.Typedef node);
-
   /// Return the [InterfaceType] corresponding to the [cls] with the given
   /// [typeArguments].
   InterfaceType createInterfaceType(
diff --git a/pkg/compiler/lib/src/ir/visitors.dart b/pkg/compiler/lib/src/ir/visitors.dart
index f111636..9ab1eb4 100644
--- a/pkg/compiler/lib/src/ir/visitors.dart
+++ b/pkg/compiler/lib/src/ir/visitors.dart
@@ -173,13 +173,7 @@
 
   @override
   ConstantValue visitTypeLiteralConstant(ir.TypeLiteralConstant node) {
-    DartType type;
-    if (node.type is ir.FunctionType) {
-      ir.FunctionType functionType = node.type;
-      type = elementMap.getTypedefType(functionType.typedef);
-    } else {
-      type = elementMap.getDartType(node.type);
-    }
+    DartType type = elementMap.getDartType(node.type);
     return constant_system.createType(elementMap.commonElements, type);
   }
 
diff --git a/pkg/compiler/lib/src/js_backend/checked_mode_helpers.dart b/pkg/compiler/lib/src/js_backend/checked_mode_helpers.dart
index 966e8a7..5790e10 100644
--- a/pkg/compiler/lib/src/js_backend/checked_mode_helpers.dart
+++ b/pkg/compiler/lib/src/js_backend/checked_mode_helpers.dart
@@ -203,8 +203,6 @@
   String getCheckedModeHelperNameInternal(
       DartType type, CommonElements commonElements,
       {bool typeCast, bool nativeCheckOnly}) {
-    assert(type is! TypedefType);
-
     DartTypes dartTypes = commonElements.dartTypes;
 
     if (type is TypeVariableType) {
diff --git a/pkg/compiler/lib/src/js_backend/constant_emitter.dart b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
index 9a89069..7833ded 100644
--- a/pkg/compiler/lib/src/js_backend/constant_emitter.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
@@ -371,7 +371,7 @@
 
   @override
   jsAst.Expression visitType(TypeConstantValue constant, [_]) {
-    DartType type = constant.representedType.unaliased;
+    DartType type = constant.representedType;
 
     if (_options.useNewRti) {
       assert(!type.containsTypeVariables);
diff --git a/pkg/compiler/lib/src/js_backend/impact_transformer.dart b/pkg/compiler/lib/src/js_backend/impact_transformer.dart
index 5ccffe9..aadb8fd 100644
--- a/pkg/compiler/lib/src/js_backend/impact_transformer.dart
+++ b/pkg/compiler/lib/src/js_backend/impact_transformer.dart
@@ -329,7 +329,6 @@
       _backendUsageBuilder.processBackendImpact(impact);
     }
 
-    type = _elementEnvironment.getUnaliasedType(type);
     registerImpact(_impacts.typeCheck);
 
     if (!_dartTypes.treatAsRawType(type) ||
@@ -381,7 +380,6 @@
   void onIsCheckForCodegen(DartType type, TransformedWorldImpact transformed) {
     if (type is DynamicType) return;
     if (type is VoidType) return;
-    type = type.unaliased;
     _impacts.typeCheck.registerImpact(transformed, _elementEnvironment);
 
     if (!_closedWorld.dartTypes.treatAsRawType(type) ||
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index 506b9da..3268416 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -1433,17 +1433,11 @@
   }
 
   String globalObjectForType(Entity element) {
-    if (element is TypedefEntity) {
-      return globalObjectForLibrary(element.library);
-    }
     return globalObjectForClass(element);
   }
 
   @override
   jsAst.VariableUse readGlobalObjectForType(Entity element) {
-    if (element is TypedefEntity) {
-      return readGlobalObjectForLibrary(element.library);
-    }
     return readGlobalObjectForClass(element);
   }
 
@@ -1619,10 +1613,6 @@
 
   String getTypeRepresentationForTypeConstant(DartType type) {
     if (type is DynamicType) return "dynamic";
-    if (type is TypedefType) {
-      return uniqueNameForTypeConstantElement(
-          type.element.library, type.element);
-    }
     if (type is FutureOrType) {
       return "FutureOr<dynamic>";
     }
@@ -1897,8 +1887,6 @@
     String name;
     if (type is InterfaceType) {
       name = type.element.name;
-    } else if (type is TypedefType) {
-      name = type.element.name;
     }
     if (name == null) {
       // e.g. DartType 'dynamic' has no element.
@@ -2172,11 +2160,6 @@
   }
 
   @override
-  visitTypedefType(TypedefType type, _) {
-    sb.write(type.element.name);
-  }
-
-  @override
   visitTypeVariableType(TypeVariableType type, _) {
     sb.write(type.element.name);
   }
@@ -2581,8 +2564,6 @@
         return asName(fixedNames.operatorSignature);
       case JsGetName.RTI_NAME:
         return asName(fixedNames.rtiName);
-      case JsGetName.TYPEDEF_TAG:
-        return asName(rtiTags.typedefTag);
       case JsGetName.FUNCTION_TYPE_TAG:
         return asName(rtiTags.functionTypeTag);
       case JsGetName.FUNCTION_TYPE_GENERIC_BOUNDS_TAG:
diff --git a/pkg/compiler/lib/src/js_backend/resolution_listener.dart b/pkg/compiler/lib/src/js_backend/resolution_listener.dart
index dc68980..f9244e9 100644
--- a/pkg/compiler/lib/src/js_backend/resolution_listener.dart
+++ b/pkg/compiler/lib/src/js_backend/resolution_listener.dart
@@ -270,7 +270,7 @@
           ..addAll(functionType.optionalParameterTypes)
           ..addAll(functionType.namedParameterTypes);
         for (var type in allParameterTypes) {
-          if (type is FunctionType || type is TypedefType) {
+          if (type is FunctionType) {
             var closureConverter = _commonElements.closureConverter;
             worldImpact.registerStaticUse(
                 new StaticUse.implicitInvoke(closureConverter));
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart
index e397bab..f0f376a 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart
@@ -27,7 +27,6 @@
 import 'runtime_types_resolution.dart';
 
 typedef jsAst.Expression OnVariableCallback(TypeVariableType variable);
-typedef bool ShouldEncodeTypedefCallback(TypedefType variable);
 
 /// Interface for the needed runtime type checks.
 abstract class RuntimeTypesChecks {
@@ -499,8 +498,7 @@
   /// Returns a [jsAst.Expression] representing the given [type]. Type variables
   /// are replaced by the [jsAst.Expression] returned by [onVariable].
   jsAst.Expression getTypeRepresentation(
-      ModularEmitter emitter, DartType type, OnVariableCallback onVariable,
-      [ShouldEncodeTypedefCallback shouldEncodeTypedef]);
+      ModularEmitter emitter, DartType type, OnVariableCallback onVariable);
 
   jsAst.Expression getJsInteropTypeArguments(int count);
 
@@ -832,8 +830,8 @@
 
   RuntimeTypesEncoderImpl(this.rtiTags, NativeBasicData nativeData,
       this._elementEnvironment, this.commonElements, this._rtiNeed)
-      : _representationGenerator = new TypeRepresentationGenerator(
-            commonElements.dartTypes, rtiTags, nativeData);
+      : _representationGenerator =
+            new TypeRepresentationGenerator(rtiTags, nativeData);
 
   /// Returns the JavaScript template to determine at runtime if a type object
   /// is a function type.
@@ -870,10 +868,9 @@
 
   @override
   jsAst.Expression getTypeRepresentation(
-      ModularEmitter emitter, DartType type, OnVariableCallback onVariable,
-      [ShouldEncodeTypedefCallback shouldEncodeTypedef]) {
+      ModularEmitter emitter, DartType type, OnVariableCallback onVariable) {
     return _representationGenerator.getTypeRepresentation(
-        emitter, type, onVariable, shouldEncodeTypedef);
+        emitter, type, onVariable);
   }
 
   String getTypeVariableName(TypeVariableType type) {
@@ -946,8 +943,6 @@
 class RuntimeTypeTags {
   const RuntimeTypeTags();
 
-  String get typedefTag => r'typedef';
-
   String get functionTypeTag => r'func';
 
   String get functionTypeVoidReturnTag => r'v';
@@ -969,31 +964,21 @@
 
 class TypeRepresentationGenerator
     implements DartTypeVisitor<jsAst.Expression, ModularEmitter> {
-  final DartTypes _dartTypes;
   final RuntimeTypeTags _rtiTags;
   final NativeBasicData _nativeData;
 
   OnVariableCallback onVariable;
-  ShouldEncodeTypedefCallback shouldEncodeTypedef;
-  Map<TypeVariableType, jsAst.Expression> typedefBindings;
   List<FunctionTypeVariable> functionTypeVariables = <FunctionTypeVariable>[];
 
-  TypeRepresentationGenerator(this._dartTypes, this._rtiTags, this._nativeData);
+  TypeRepresentationGenerator(this._rtiTags, this._nativeData);
 
   /// Creates a type representation for [type]. [onVariable] is called to
   /// provide the type representation for type variables.
   jsAst.Expression getTypeRepresentation(
-      ModularEmitter emitter,
-      DartType type,
-      OnVariableCallback onVariable,
-      ShouldEncodeTypedefCallback encodeTypedef) {
-    assert(typedefBindings == null);
+      ModularEmitter emitter, DartType type, OnVariableCallback onVariable) {
     this.onVariable = onVariable;
-    this.shouldEncodeTypedef =
-        (encodeTypedef != null) ? encodeTypedef : (TypedefType type) => false;
     jsAst.Expression representation = visit(type, emitter);
     this.onVariable = null;
-    this.shouldEncodeTypedef = null;
     assert(functionTypeVariables.isEmpty);
     return representation;
   }
@@ -1016,10 +1001,6 @@
   @override
   jsAst.Expression visitTypeVariableType(
       TypeVariableType type, ModularEmitter emitter) {
-    if (typedefBindings != null) {
-      assert(typedefBindings[type] != null);
-      return typedefBindings[type];
-    }
     return onVariable(type);
   }
 
@@ -1205,61 +1186,6 @@
   }
 
   @override
-  jsAst.Expression visitTypedefType(TypedefType type, ModularEmitter emitter) {
-    bool shouldEncode = shouldEncodeTypedef(type);
-    DartType unaliasedType = type.unaliased;
-
-    var oldBindings = typedefBindings;
-    if (typedefBindings == null) {
-      // First level typedef - capture arguments for re-use within typedef body.
-      //
-      // The type `Map<T, Foo<Set<T>>>` contains one type variable referenced
-      // twice, so there are two inputs into the HTypeInfoExpression
-      // instruction.
-      //
-      // If Foo is a typedef, T can be reused, e.g.
-      //
-      //     typedef E Foo<E>(E a, E b);
-      //
-      // As the typedef is expanded (to (Set<T>, Set<T>) => Set<T>) it should
-      // not consume additional types from the to-level input.  We prevent this
-      // by capturing the types and using the captured type expressions inside
-      // the typedef expansion.
-      //
-      // TODO(sra): We should make the type subexpression Foo<...> be a second
-      // HTypeInfoExpression, with Set<T> as its input (a third
-      // HTypeInfoExpression). This would share all the Set<T> subexpressions
-      // instead of duplicating them. This would require HTypeInfoExpression
-      // inputs to correspond to type variables AND typedefs.
-      typedefBindings = <TypeVariableType, jsAst.Expression>{};
-      type.forEachTypeVariable((TypeVariableType variable) {
-        typedefBindings[variable] = onVariable(variable);
-      });
-    }
-
-    jsAst.Expression finish(jsAst.Expression result) {
-      typedefBindings = oldBindings;
-      return result;
-    }
-
-    if (shouldEncode) {
-      jsAst.ObjectInitializer initializer = visit(unaliasedType, emitter);
-      // We have to encode the aliased type.
-      jsAst.Expression name = getJavaScriptClassName(type.element, emitter);
-      jsAst.Expression encodedTypedef = _dartTypes.treatAsRawType(type)
-          ? name
-          : visitList(type.typeArguments, emitter, head: name);
-
-      // Add it to the function-type object.
-      jsAst.LiteralString tag = js.string(_rtiTags.typedefTag);
-      initializer.properties.add(new jsAst.Property(tag, encodedTypedef));
-      return finish(initializer);
-    } else {
-      return finish(visit(unaliasedType, emitter));
-    }
-  }
-
-  @override
   jsAst.Expression visitFutureOrType(
       FutureOrType type, ModularEmitter emitter) {
     List<jsAst.Property> properties = <jsAst.Property>[];
@@ -1338,11 +1264,6 @@
   }
 
   @override
-  void visitTypedefType(TypedefType type, _) {
-    collect(type.unaliased);
-  }
-
-  @override
   void visitInterfaceType(InterfaceType type, _) {
     addClass(type.element);
     collectAll(type.typeArguments);
@@ -1455,11 +1376,6 @@
   }
 
   @override
-  visitTypedefType(TypedefType type, TypeVisitorState state) {
-    visitType(type.unaliased, state);
-  }
-
-  @override
   visitFunctionTypeVariable(FunctionTypeVariable type, TypeVisitorState state) {
     if (_visitedFunctionTypeVariables.add(type)) {
       visitType(type.bound, state);
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types_new.dart b/pkg/compiler/lib/src/js_backend/runtime_types_new.dart
index 65a5eab..2aa30b4 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types_new.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types_new.dart
@@ -420,11 +420,6 @@
   }
 
   @override
-  void visitTypedefType(TypedefType type, _) {
-    visit(type.unaliased, _);
-  }
-
-  @override
   void visitFutureOrType(FutureOrType type, _) {
     visit(type.typeArgument, _);
     _emitCode(Recipe.wrapFutureOr);
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types_resolution.dart b/pkg/compiler/lib/src/js_backend/runtime_types_resolution.dart
index 4f62071..f89cbd0 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types_resolution.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types_resolution.dart
@@ -601,7 +601,7 @@
         InterfaceType instance = types.asInstanceOf(type, cls);
         if (instance != null) {
           for (DartType argument in instance.typeArguments) {
-            addImplicitCheck(argument.unaliased);
+            addImplicitCheck(argument);
           }
         }
       }
diff --git a/pkg/compiler/lib/src/js_backend/type_reference.dart b/pkg/compiler/lib/src/js_backend/type_reference.dart
index e6be8f9..9e99b0b 100644
--- a/pkg/compiler/lib/src/js_backend/type_reference.dart
+++ b/pkg/compiler/lib/src/js_backend/type_reference.dart
@@ -772,11 +772,6 @@
     return false;
   }
 
-  @override
-  void visitTypedefType(covariant TypedefType type, _) {
-    throw StateError('Typedefs should be elided $type');
-  }
-
   /// Returns `true` for types which print as a single identifier.
   static bool _isSimple(DartType type) {
     return type is DynamicType ||
diff --git a/pkg/compiler/lib/src/js_emitter/constant_ordering.dart b/pkg/compiler/lib/src/js_emitter/constant_ordering.dart
index e7158dd..4c5afba 100644
--- a/pkg/compiler/lib/src/js_emitter/constant_ordering.dart
+++ b/pkg/compiler/lib/src/js_emitter/constant_ordering.dart
@@ -5,8 +5,7 @@
 library dart2js.js_emitter.constant_ordering;
 
 import '../constants/values.dart';
-import '../elements/entities.dart'
-    show ClassEntity, FieldEntity, MemberEntity, TypedefEntity;
+import '../elements/entities.dart' show ClassEntity, FieldEntity, MemberEntity;
 import '../elements/types.dart';
 import 'sorter.dart' show Sorter;
 
@@ -58,12 +57,6 @@
     return _sorter.compareMembersByLocation(a, b);
   }
 
-  int compareTypedefs(TypedefEntity a, TypedefEntity b) {
-    int r = a.name.compareTo(b.name);
-    if (r != 0) return r;
-    return _sorter.compareTypedefsByLocation(a, b);
-  }
-
   int compareDartTypes(DartType a, DartType b) {
     return _dartTypeOrdering.compare(a, b);
   }
@@ -211,7 +204,7 @@
   @override
   int visitInterfaceType(InterfaceType type, _) => 1;
   @override
-  int visitTypedefType(TypedefType type, _) => 2;
+  int visitFunctionTypeVariable(FunctionTypeVariable type, _) => 2;
   @override
   int visitTypeVariableType(TypeVariableType type, _) => 3;
   @override
@@ -230,15 +223,13 @@
   int visitNullableType(NullableType type, _) => 10;
   @override
   int visitFutureOrType(FutureOrType type, _) => 11;
-  @override
-  int visitFunctionTypeVariable(FunctionTypeVariable type, _) =>
-      throw new UnsupportedError(
-          'FunctionTypeVariable unsupported in constant.');
 }
 
 class _DartTypeOrdering extends DartTypeVisitor<int, DartType> {
   final _ConstantOrdering _constantOrdering;
   DartType _root;
+  List<FunctionTypeVariable> _leftFunctionTypeVariables = [];
+  List<FunctionTypeVariable> _rightFunctionTypeVariables = [];
   _DartTypeOrdering(this._constantOrdering);
 
   int compare(DartType a, DartType b) {
@@ -284,20 +275,45 @@
   }
 
   @override
+  int visitFunctionTypeVariable(covariant FunctionTypeVariable type,
+      covariant FunctionTypeVariable other) {
+    int leftIndex = _leftFunctionTypeVariables.indexOf(type);
+    int rightIndex = _rightFunctionTypeVariables.indexOf(other);
+    assert(leftIndex != -1);
+    assert(rightIndex != -1);
+    int r = leftIndex.compareTo(rightIndex);
+    if (r != 0) return r;
+    return compare(type.bound, other.bound);
+  }
+
+  @override
   int visitFunctionType(
       covariant FunctionType type, covariant FunctionType other) {
+    int leftLength = _leftFunctionTypeVariables.length;
+    int rightLength = _rightFunctionTypeVariables.length;
+    _leftFunctionTypeVariables.addAll(type.typeVariables);
+    _rightFunctionTypeVariables.addAll(other.typeVariables);
     int r = _compareTypeArguments(type.parameterTypes, other.parameterTypes);
-    if (r != 0) return r;
-    r = _compareTypeArguments(
-        type.optionalParameterTypes, other.optionalParameterTypes);
-    if (r != 0) return r;
-    r = _ConstantOrdering.compareLists((String a, String b) => a.compareTo(b),
-        type.namedParameters, other.namedParameters);
-    if (r != 0) return r;
-    r = _compareTypeArguments(
-        type.namedParameterTypes, other.namedParameterTypes);
-    if (r != 0) return r;
-    return compare(type.returnType, other.returnType);
+    if (r == 0) {
+      r = _compareTypeArguments(
+          type.optionalParameterTypes, other.optionalParameterTypes);
+    }
+    if (r == 0) {
+      r = _ConstantOrdering.compareLists((String a, String b) => a.compareTo(b),
+          type.namedParameters, other.namedParameters);
+    }
+    if (r == 0) {
+      r = _compareTypeArguments(
+          type.namedParameterTypes, other.namedParameterTypes);
+    }
+    if (r == 0) {
+      r = compare(type.returnType, other.returnType);
+    }
+    _leftFunctionTypeVariables.removeRange(
+        leftLength, _leftFunctionTypeVariables.length);
+    _rightFunctionTypeVariables.removeRange(
+        rightLength, _rightFunctionTypeVariables.length);
+    return r;
   }
 
   @override
@@ -309,14 +325,6 @@
   }
 
   @override
-  int visitTypedefType(
-      covariant TypedefType type, covariant TypedefType other) {
-    int r = _constantOrdering.compareTypedefs(type.element, other.element);
-    if (r != 0) return r;
-    return _compareTypeArguments(type.typeArguments, other.typeArguments);
-  }
-
-  @override
   int visitDynamicType(
       covariant DynamicType type, covariant DynamicType other) {
     throw new UnsupportedError('Unreachable');
diff --git a/pkg/compiler/lib/src/js_emitter/metadata_collector.dart b/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
index 4d14230..ed33fbe 100644
--- a/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
+++ b/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
@@ -181,8 +181,6 @@
           "Type representation for type variable $variable in "
           "$type is not supported.");
       return jsAst.LiteralNull();
-    }, (TypedefType typedef) {
-      return false;
     });
 
     if (representation is jsAst.LiteralString) {
diff --git a/pkg/compiler/lib/src/js_emitter/native_emitter.dart b/pkg/compiler/lib/src/js_emitter/native_emitter.dart
index 5a30e74..7b73e7f 100644
--- a/pkg/compiler/lib/src/js_emitter/native_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/native_emitter.dart
@@ -285,7 +285,6 @@
       // parameter that was not provided for this stub.
       for (jsAst.Parameter stubParameter in stubParameters) {
         if (stubParameter.name == name) {
-          type = type.unaliased;
           if (type is FunctionType) {
             closureConverter ??= _emitterTask.emitter
                 .staticFunctionAccess(_commonElements.closureConverter);
diff --git a/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
index 7cfe426..8ebbf99 100644
--- a/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
@@ -352,11 +352,6 @@
   bool visitAnyType(AnyType type, OutputUnit argument) => true;
 
   @override
-  bool visitTypedefType(TypedefType type, OutputUnit argument) {
-    return visit(type.unaliased, argument);
-  }
-
-  @override
   bool visitInterfaceType(InterfaceType type, OutputUnit argument) {
     if (_outputUnitData.outputUnitForClass(type.element) != argument) {
       return false;
diff --git a/pkg/compiler/lib/src/js_emitter/sorter.dart b/pkg/compiler/lib/src/js_emitter/sorter.dart
index 5048bb4..0de3e33 100644
--- a/pkg/compiler/lib/src/js_emitter/sorter.dart
+++ b/pkg/compiler/lib/src/js_emitter/sorter.dart
@@ -14,14 +14,10 @@
   /// Returns a sorted list of [classes].
   Iterable<ClassEntity> sortClasses(Iterable<ClassEntity> classes);
 
-  /// Returns a sorted list of [typedefs].
-  Iterable<TypedefEntity> sortTypedefs(Iterable<TypedefEntity> typedefs);
-
   /// Returns a sorted list of [members].
   Iterable<T> sortMembers<T extends MemberEntity>(Iterable<T> members);
 
   int compareLibrariesByLocation(LibraryEntity a, LibraryEntity b);
   int compareClassesByLocation(ClassEntity a, ClassEntity b);
-  int compareTypedefsByLocation(TypedefEntity a, TypedefEntity b);
   int compareMembersByLocation(MemberEntity a, MemberEntity b);
 }
diff --git a/pkg/compiler/lib/src/js_model/element_map.dart b/pkg/compiler/lib/src/js_model/element_map.dart
index a1f7f95..4da915f 100644
--- a/pkg/compiler/lib/src/js_model/element_map.dart
+++ b/pkg/compiler/lib/src/js_model/element_map.dart
@@ -74,9 +74,6 @@
   /// Returns the [ClassEntity] corresponding to the class [node].
   ClassEntity getClass(ir.Class node);
 
-  /// Returns the [TypedefType] corresponding to raw type of the typedef [node].
-  TypedefType getTypedefType(ir.Typedef node);
-
   /// Returns the super [MemberEntity] for a super invocation, get or set of
   /// [name] from the member [context].
   MemberEntity getSuperMember(MemberEntity context, ir.Name name,
diff --git a/pkg/compiler/lib/src/js_model/element_map_impl.dart b/pkg/compiler/lib/src/js_model/element_map_impl.dart
index dcbbbf2..2ce9ead 100644
--- a/pkg/compiler/lib/src/js_model/element_map_impl.dart
+++ b/pkg/compiler/lib/src/js_model/element_map_impl.dart
@@ -65,12 +65,10 @@
   /// [JsKernelToElementMap] object in a debugging data stream.
   static const String libraryTag = 'libraries';
   static const String classTag = 'classes';
-  static const String typedefTag = 'typedefs';
   static const String memberTag = 'members';
   static const String typeVariableTag = 'type-variables';
   static const String libraryDataTag = 'library-data';
   static const String classDataTag = 'class-data';
-  static const String typedefDataTag = 'typedef-data';
   static const String memberDataTag = 'member-data';
   static const String typeVariableDataTag = 'type-variable-data';
   static const String nestedClosuresTag = 'nested-closures';
@@ -100,12 +98,9 @@
       new EntityDataMap<IndexedMember, JMemberData>();
   final EntityDataMap<IndexedTypeVariable, JTypeVariableData> typeVariables =
       new EntityDataMap<IndexedTypeVariable, JTypeVariableData>();
-  final EntityDataMap<IndexedTypedef, JTypedefData> typedefs =
-      new EntityDataMap<IndexedTypedef, JTypedefData>();
 
   final Map<ir.Library, IndexedLibrary> libraryMap = {};
   final Map<ir.Class, IndexedClass> classMap = {};
-  final Map<ir.Typedef, IndexedTypedef> typedefMap = {};
 
   /// Map from [ir.TypeParameter] nodes to the corresponding
   /// [TypeVariableEntity].
@@ -179,25 +174,6 @@
       assert(newClass.classIndex == oldClass.classIndex);
       libraries.getEnv(newClass.library).registerClass(newClass.name, newEnv);
     }
-    for (int typedefIndex = 0;
-        typedefIndex < _elementMap.typedefs.length;
-        typedefIndex++) {
-      IndexedTypedef oldTypedef = _elementMap.typedefs.getEntity(typedefIndex);
-      KTypedefData data = _elementMap.typedefs.getData(oldTypedef);
-      IndexedLibrary oldLibrary = oldTypedef.library;
-      LibraryEntity newLibrary = libraries.getEntity(oldLibrary.libraryIndex);
-      IndexedTypedef newTypedef = new JTypedef(newLibrary, oldTypedef.name);
-      typedefMap[data.node] = typedefs.register(
-          newTypedef,
-          new JTypedefData(
-              data.node,
-              new TypedefType(
-                  newTypedef,
-                  new List<DartType>.filled(
-                      data.node.typeParameters.length, DynamicType()),
-                  getDartType(data.node.type))));
-      assert(newTypedef.typedefIndex == oldTypedef.typedefIndex);
-    }
 
     for (int memberIndex = 0;
         memberIndex < _elementMap.members.length;
@@ -350,15 +326,6 @@
     }
     source.end(classTag);
 
-    source.begin(typedefTag);
-    int typedefCount = source.readInt();
-    for (int i = 0; i < typedefCount; i++) {
-      int index = source.readInt();
-      JTypedef typedef = new JTypedef.readFromDataSource(source);
-      entityLookup.registerTypedef(index, typedef);
-    }
-    source.end(typedefTag);
-
     source.begin(memberTag);
     int memberCount = source.readInt();
     for (int i = 0; i < memberCount; i++) {
@@ -402,14 +369,6 @@
     });
     source.end(classDataTag);
 
-    source.begin(typedefDataTag);
-    entityLookup.forEachTypedef((int index, JTypedef typedef) {
-      JTypedefData data = new JTypedefData.readFromDataSource(source);
-      typedefMap[data.node] = typedefs.registerByIndex(index, typedef, data);
-      assert(index == typedef.typedefIndex);
-    });
-    source.end(typedefDataTag);
-
     source.begin(memberDataTag);
     entityLookup.forEachMember((int index, IndexedMember member) {
       JMemberData data = new JMemberData.readFromDataSource(source);
@@ -469,7 +428,6 @@
     libraries.close();
     classes.close();
     members.close();
-    typedefs.close();
     typeVariables.close();
     return length;
   }
@@ -495,14 +453,6 @@
     });
     sink.end(classTag);
 
-    sink.begin(typedefTag);
-    sink.writeInt(typedefs.size);
-    typedefs.forEach((JTypedef typedef, _) {
-      sink.writeInt(typedef.typedefIndex);
-      typedef.writeToDataSink(sink);
-    });
-    sink.end(typedefTag);
-
     sink.begin(memberTag);
     sink.writeInt(members.size);
     members.forEach((JMember member, _) {
@@ -534,12 +484,6 @@
     });
     sink.end(classDataTag);
 
-    sink.begin(typedefDataTag);
-    typedefs.forEach((_, JTypedefData data) {
-      data.writeToDataSink(sink);
-    });
-    sink.end(typedefDataTag);
-
     sink.begin(memberDataTag);
     members.forEach((_, JMemberData data) {
       data.writeToDataSink(sink);
@@ -823,12 +767,6 @@
   }
 
   @override
-  TypedefType getTypedefType(ir.Typedef node) {
-    IndexedTypedef typedef = getTypedefInternal(node);
-    return typedefs.getData(typedef).rawType;
-  }
-
-  @override
   MemberEntity getMember(ir.Member node) {
     if (node is ir.Field) {
       return getFieldInternal(node);
@@ -1677,12 +1615,6 @@
     return typeVariable;
   }
 
-  TypedefEntity getTypedefInternal(ir.Typedef node) {
-    TypedefEntity typedef = typedefMap[node];
-    assert(typedef != null, "No typedef entity for $node");
-    return typedef;
-  }
-
   @override
   FunctionEntity getConstructorBody(ir.Constructor node) {
     ConstructorEntity constructor = getConstructor(node);
@@ -2351,9 +2283,6 @@
   }
 
   @override
-  DartType getUnaliasedType(DartType type) => type;
-
-  @override
   ConstructorEntity lookupConstructor(ClassEntity cls, String name,
       {bool required: false}) {
     ConstructorEntity constructor = elementMap.lookupConstructor(cls, name);
@@ -2552,7 +2481,6 @@
 class _EntityLookup implements EntityLookup {
   final Map<int, JLibrary> _libraries = {};
   final Map<int, JClass> _classes = {};
-  final Map<int, JTypedef> _typedefs = {};
   final Map<int, JMember> _members = {};
   final Map<int, JTypeVariable> _typeVariables = {};
 
@@ -2568,12 +2496,6 @@
     _classes[index] = cls;
   }
 
-  void registerTypedef(int index, JTypedef typedef) {
-    assert(!_typedefs.containsKey(index),
-        "Typedef for index $index has already been defined.");
-    _typedefs[index] = typedef;
-  }
-
   void registerMember(int index, JMember member) {
     assert(!_members.containsKey(index),
         "Member for index $index has already been defined.");
@@ -2594,10 +2516,6 @@
     _classes.forEach(f);
   }
 
-  void forEachTypedef(void f(int index, JTypedef typedef)) {
-    _typedefs.forEach(f);
-  }
-
   void forEachMember(void f(int index, JMember member)) {
     _members.forEach(f);
   }
@@ -2621,13 +2539,6 @@
   }
 
   @override
-  IndexedTypedef getTypedefByIndex(int index) {
-    IndexedTypedef typedef = _typedefs[index];
-    assert(typedef != null, "No typedef found for index $index");
-    return typedef;
-  }
-
-  @override
   IndexedMember getMemberByIndex(int index) {
     IndexedMember member = _members[index];
     assert(member != null, "No member found for index $index");
@@ -2659,11 +2570,6 @@
   }
 
   @override
-  IndexedTypedef getTypedefByIndex(int index) {
-    return _elementMap.typedefs.getEntity(index);
-  }
-
-  @override
   IndexedClass getClassByIndex(int index) {
     return _elementMap.classes.getEntity(index);
   }
diff --git a/pkg/compiler/lib/src/js_model/elements.dart b/pkg/compiler/lib/src/js_model/elements.dart
index 2818e69..89b4467 100644
--- a/pkg/compiler/lib/src/js_model/elements.dart
+++ b/pkg/compiler/lib/src/js_model/elements.dart
@@ -102,40 +102,6 @@
   String toString() => '${jsElementPrefix}class($name)';
 }
 
-class JTypedef extends IndexedTypedef {
-  /// Tag used for identifying serialized [JTypedef] objects in a
-  /// debugging data stream.
-  static const String tag = 'typedef';
-
-  @override
-  final JLibrary library;
-
-  @override
-  final String name;
-
-  JTypedef(this.library, this.name);
-
-  /// Deserializes a [JTypedef] object from [source].
-  factory JTypedef.readFromDataSource(DataSource source) {
-    source.begin(tag);
-    JLibrary library = source.readLibrary();
-    String name = source.readString();
-    source.end(tag);
-    return new JTypedef(library, name);
-  }
-
-  /// Serializes this [JTypedef] to [sink].
-  void writeToDataSink(DataSink sink) {
-    sink.begin(tag);
-    sink.writeLibrary(library);
-    sink.writeString(name);
-    sink.end(tag);
-  }
-
-  @override
-  String toString() => '${jsElementPrefix}typedef($name)';
-}
-
 /// Enum used for identifying [JMember] subclasses in serialization.
 enum JMemberKind {
   generativeConstructor,
@@ -787,7 +753,7 @@
 }
 
 /// Enum used for identifying [JTypeVariable] variants in serialization.
-enum JTypeVariableKind { cls, member, typedef, local }
+enum JTypeVariableKind { cls, member, local }
 
 class JTypeVariable extends IndexedTypeVariable {
   /// Tag used for identifying serialized [JTypeVariable] objects in a
@@ -815,9 +781,6 @@
       case JTypeVariableKind.member:
         typeDeclaration = source.readMember();
         break;
-      case JTypeVariableKind.typedef:
-        typeDeclaration = source.readTypedef();
-        break;
       case JTypeVariableKind.local:
         // Type variables declared by local functions don't point to their
         // declaration, since the corresponding closure call methods is created
@@ -842,10 +805,6 @@
       IndexedMember member = typeDeclaration;
       sink.writeEnum(JTypeVariableKind.member);
       sink.writeMember(member);
-    } else if (typeDeclaration is IndexedTypedef) {
-      IndexedTypedef typedef = typeDeclaration;
-      sink.writeEnum(JTypeVariableKind.typedef);
-      sink.writeTypedef(typedef);
     } else if (typeDeclaration == null) {
       sink.writeEnum(JTypeVariableKind.local);
     } else {
diff --git a/pkg/compiler/lib/src/js_model/env.dart b/pkg/compiler/lib/src/js_model/env.dart
index 98e0b84..0bb8445 100644
--- a/pkg/compiler/lib/src/js_model/env.dart
+++ b/pkg/compiler/lib/src/js_model/env.dart
@@ -1014,32 +1014,6 @@
   }
 }
 
-class JTypedefData {
-  /// Tag used for identifying serialized [JTypedefData] objects in
-  /// a debugging data stream.
-  static const String tag = 'typedef-data';
-
-  final ir.Typedef node;
-  final TypedefType rawType;
-
-  JTypedefData(this.node, this.rawType);
-
-  factory JTypedefData.readFromDataSource(DataSource source) {
-    source.begin(tag);
-    ir.Typedef node = source.readTypedefNode();
-    TypedefType rawType = source.readDartType();
-    source.end(tag);
-    return new JTypedefData(node, rawType);
-  }
-
-  void writeToDataSink(DataSink sink) {
-    sink.begin(tag);
-    sink.writeTypedefNode(node);
-    sink.writeDartType(rawType);
-    sink.end(tag);
-  }
-}
-
 class JTypeVariableData {
   /// Tag used for identifying serialized [JTypeVariableData] objects in
   /// a debugging data stream.
diff --git a/pkg/compiler/lib/src/js_model/js_world.dart b/pkg/compiler/lib/src/js_model/js_world.dart
index 0b2a816..bb9a5ca 100644
--- a/pkg/compiler/lib/src/js_model/js_world.dart
+++ b/pkg/compiler/lib/src/js_model/js_world.dart
@@ -644,13 +644,6 @@
   }
 
   @override
-  Iterable<TypedefEntity> sortTypedefs(Iterable<TypedefEntity> typedefs) {
-    // TODO(redemption): Support this.
-    assert(typedefs.isEmpty);
-    return typedefs;
-  }
-
-  @override
   int compareLibrariesByLocation(LibraryEntity a, LibraryEntity b) {
     return _compareLibraries(a, b);
   }
@@ -666,13 +659,6 @@
   }
 
   @override
-  int compareTypedefsByLocation(TypedefEntity a, TypedefEntity b) {
-    // TODO(redemption): Support this.
-    failedAt(a, 'KernelSorter.compareTypedefsByLocation unimplemented');
-    return 0;
-  }
-
-  @override
   int compareMembersByLocation(MemberEntity a, MemberEntity b) {
     int r = _compareLibraries(a.library, b.library);
     if (r != 0) return r;
diff --git a/pkg/compiler/lib/src/js_model/js_world_builder.dart b/pkg/compiler/lib/src/js_model/js_world_builder.dart
index 0eec8fd..1ff938b 100644
--- a/pkg/compiler/lib/src/js_model/js_world_builder.dart
+++ b/pkg/compiler/lib/src/js_model/js_world_builder.dart
@@ -683,7 +683,6 @@
   Entity toBackendEntity(Entity entity) {
     if (entity is ClassEntity) return toBackendClass(entity);
     if (entity is MemberEntity) return toBackendMember(entity);
-    if (entity is TypedefEntity) return toBackendTypedef(entity);
     if (entity is TypeVariableEntity) {
       return toBackendTypeVariable(entity);
     }
@@ -706,10 +705,6 @@
     return _backend.members.getEntity(member.memberIndex);
   }
 
-  TypedefEntity toBackendTypedef(covariant IndexedTypedef typedef) {
-    return _backend.typedefs.getEntity(typedef.typedefIndex);
-  }
-
   TypeVariableEntity toBackendTypeVariable(TypeVariableEntity typeVariable) {
     if (typeVariable is KLocalTypeVariable) {
       failedAt(
@@ -792,14 +787,6 @@
   }
 
   @override
-  DartType visitTypedefType(TypedefType type, _EntityConverter converter) {
-    return new TypedefType(
-        converter(type.element),
-        visitList(type.typeArguments, converter),
-        visit(type.unaliased, converter));
-  }
-
-  @override
   DartType visitTypeVariableType(
       TypeVariableType type, _EntityConverter converter) {
     return new TypeVariableType(converter(type.element));
diff --git a/pkg/compiler/lib/src/kernel/deferred_load.dart b/pkg/compiler/lib/src/kernel/deferred_load.dart
index 09c383c..9ca9bcf 100644
--- a/pkg/compiler/lib/src/kernel/deferred_load.dart
+++ b/pkg/compiler/lib/src/kernel/deferred_load.dart
@@ -48,13 +48,6 @@
   }
 
   @override
-  Iterable<ImportEntity> typedefImportsTo(
-      TypedefEntity element, LibraryEntity library) {
-    ir.Typedef node = _elementMap.getTypedefNode(element);
-    return _findImportsTo(node, node.name, node.enclosingLibrary, library);
-  }
-
-  @override
   Iterable<ImportEntity> memberImportsTo(
       Entity element, LibraryEntity library) {
     ir.Member node = _elementMap.getMemberNode(element);
diff --git a/pkg/compiler/lib/src/kernel/element_map.dart b/pkg/compiler/lib/src/kernel/element_map.dart
index a9ef438..34664e7 100644
--- a/pkg/compiler/lib/src/kernel/element_map.dart
+++ b/pkg/compiler/lib/src/kernel/element_map.dart
@@ -81,9 +81,6 @@
   /// Returns the [ClassEntity] corresponding to the class [node].
   ClassEntity getClass(ir.Class node);
 
-  /// Returns the [TypedefType] corresponding to raw type of the typedef [node].
-  TypedefType getTypedefType(ir.Typedef node);
-
   /// Returns the super [MemberEntity] for a super invocation, get or set of
   /// [name] from the member [context].
   MemberEntity getSuperMember(MemberEntity context, ir.Name name,
@@ -174,9 +171,6 @@
   /// Returns the [ir.Library] corresponding to [library].
   ir.Library getLibraryNode(LibraryEntity library);
 
-  /// Returns the node that defines [typedef].
-  ir.Typedef getTypedefNode(covariant TypedefEntity typedef);
-
   /// Returns the defining node for [member].
   ir.Member getMemberNode(covariant MemberEntity member);
 
diff --git a/pkg/compiler/lib/src/kernel/element_map_impl.dart b/pkg/compiler/lib/src/kernel/element_map_impl.dart
index d2559b7..cd66278 100644
--- a/pkg/compiler/lib/src/kernel/element_map_impl.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart
@@ -87,8 +87,6 @@
       new EntityDataMap<IndexedMember, KMemberData>();
   final EntityDataMap<IndexedTypeVariable, KTypeVariableData> typeVariables =
       new EntityDataMap<IndexedTypeVariable, KTypeVariableData>();
-  final EntityDataMap<IndexedTypedef, KTypedefData> typedefs =
-      new EntityDataMap<IndexedTypedef, KTypedefData>();
 
   /// Set to `true` before creating the J-World from the K-World to assert that
   /// no entities are created late.
@@ -96,7 +94,6 @@
 
   final Map<ir.Library, IndexedLibrary> libraryMap = {};
   final Map<ir.Class, IndexedClass> classMap = {};
-  final Map<ir.Typedef, IndexedTypedef> typedefMap = {};
 
   /// Map from [ir.TypeParameter] nodes to the corresponding
   /// [TypeVariableEntity].
@@ -390,12 +387,6 @@
   }
 
   @override
-  TypedefType getTypedefType(ir.Typedef node) {
-    IndexedTypedef typedef = getTypedefInternal(node);
-    return typedefs.getData(typedef).rawType;
-  }
-
-  @override
   MemberEntity getMember(ir.Member node) {
     if (node is ir.Field) {
       return getFieldInternal(node);
@@ -760,10 +751,6 @@
     return classes.getData(cls).node;
   }
 
-  ir.Typedef _getTypedefNode(covariant IndexedTypedef typedef) {
-    return typedefs.getData(typedef).node;
-  }
-
   @override
   ImportEntity getImport(ir.LibraryDependency node) {
     if (node == null) return null;
@@ -1172,25 +1159,6 @@
     return classes.register(cls, new KClassDataImpl(node), classEnv);
   }
 
-  TypedefEntity getTypedefInternal(ir.Typedef node) {
-    return typedefMap[node] ??= _getTypedefCreate(node);
-  }
-
-  TypedefEntity _getTypedefCreate(ir.Typedef node) {
-    assert(
-        !envIsClosed,
-        "Environment of $this is closed. Trying to create "
-        "typedef for $node.");
-    IndexedLibrary library = getLibraryInternal(node.enclosingLibrary);
-    IndexedTypedef typedef = createTypedef(library, node.name);
-    TypedefType typedefType = new TypedefType(
-        typedef,
-        new List<DartType>.filled(node.typeParameters.length, DynamicType()),
-        getDartType(node.type));
-    return typedefs.register(
-        typedef, new KTypedefData(node, typedef, typedefType));
-  }
-
   TypeVariableEntity getTypeVariableInternal(ir.TypeParameter node) {
     return typeVariableMap[node] ??= _getTypeVariableCreate(node);
   }
@@ -1505,11 +1473,6 @@
   }
 
   @override
-  ir.Typedef getTypedefNode(TypedefEntity typedef) {
-    return _getTypedefNode(typedef);
-  }
-
-  @override
   ForeignKind getForeignKind(ir.StaticInvocation node) {
     if (commonElements.isForeignHelper(getMember(node.target))) {
       switch (node.target.name.name) {
@@ -1585,10 +1548,6 @@
     return new KClass(library, name, isAbstract: isAbstract);
   }
 
-  IndexedTypedef createTypedef(LibraryEntity library, String name) {
-    return new KTypedef(library, name);
-  }
-
   TypeVariableEntity createTypeVariable(
       Entity typeDeclaration, String name, int index) {
     return new KTypeVariable(typeDeclaration, name, index);
@@ -1741,9 +1700,6 @@
   }
 
   @override
-  DartType getUnaliasedType(DartType type) => type;
-
-  @override
   ConstructorEntity lookupConstructor(ClassEntity cls, String name,
       {bool required: false}) {
     ConstructorEntity constructor = elementMap.lookupConstructor(cls, name);
diff --git a/pkg/compiler/lib/src/kernel/env.dart b/pkg/compiler/lib/src/kernel/env.dart
index 2f7b040..899632f 100644
--- a/pkg/compiler/lib/src/kernel/env.dart
+++ b/pkg/compiler/lib/src/kernel/env.dart
@@ -881,14 +881,6 @@
   }
 }
 
-class KTypedefData {
-  final ir.Typedef node;
-  final TypedefEntity element;
-  final TypedefType rawType;
-
-  KTypedefData(this.node, this.element, this.rawType);
-}
-
 class KTypeVariableData {
   final ir.TypeParameter node;
   DartType _bound;
diff --git a/pkg/compiler/lib/src/kernel/kelements.dart b/pkg/compiler/lib/src/kernel/kelements.dart
index 3062fc2..277a33c 100644
--- a/pkg/compiler/lib/src/kernel/kelements.dart
+++ b/pkg/compiler/lib/src/kernel/kelements.dart
@@ -42,19 +42,6 @@
   String toString() => '${kElementPrefix}class($name)';
 }
 
-class KTypedef extends IndexedTypedef {
-  @override
-  final KLibrary library;
-
-  @override
-  final String name;
-
-  KTypedef(this.library, this.name);
-
-  @override
-  String toString() => '${kElementPrefix}typedef($name)';
-}
-
 abstract class KMember extends IndexedMember {
   @override
   final KLibrary library;
diff --git a/pkg/compiler/lib/src/kernel/kernel_impact.dart b/pkg/compiler/lib/src/kernel/kernel_impact.dart
index 1a75ffd..a7decd7 100644
--- a/pkg/compiler/lib/src/kernel/kernel_impact.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_impact.dart
@@ -790,12 +790,6 @@
     ImportEntity deferredImport = elementMap.getImport(import);
     impactBuilder.registerTypeUse(
         new TypeUse.typeLiteral(elementMap.getDartType(type), deferredImport));
-    if (type is ir.FunctionType) {
-      assert(type.typedef != null);
-      // TODO(johnniwinther): Can we avoid the typedef type altogether?
-      // We need to ensure that the typedef is live.
-      elementMap.getTypedefType(type.typedef);
-    }
   }
 
   @override
diff --git a/pkg/compiler/lib/src/native/behavior.dart b/pkg/compiler/lib/src/native/behavior.dart
index e02b89d..c95f069 100644
--- a/pkg/compiler/lib/src/native/behavior.dart
+++ b/pkg/compiler/lib/src/native/behavior.dart
@@ -777,7 +777,6 @@
   /// Models the behavior of having instances of [type] escape from Dart code
   /// into native code.
   void _escape(DartType type, bool isJsInterop) {
-    type = elementEnvironment.getUnaliasedType(type);
     if (type is FunctionType) {
       FunctionType functionType = type;
       // A function might be called from native code, passing us novel
@@ -796,7 +795,6 @@
   /// We assume that JS-interop APIs cannot instantiate Dart types or
   /// non-JSInterop native types.
   void _capture(DartType type, bool isJsInterop) {
-    type = elementEnvironment.getUnaliasedType(type);
     if (type is FunctionType) {
       FunctionType functionType = type;
       _capture(functionType.returnType, isJsInterop);
diff --git a/pkg/compiler/lib/src/serialization/abstract_sink.dart b/pkg/compiler/lib/src/serialization/abstract_sink.dart
index 3a096fd..0aad205 100644
--- a/pkg/compiler/lib/src/serialization/abstract_sink.dart
+++ b/pkg/compiler/lib/src/serialization/abstract_sink.dart
@@ -401,11 +401,6 @@
   }
 
   @override
-  void writeTypedef(IndexedTypedef value) {
-    _entityWriter.writeTypedefToDataSink(this, value);
-  }
-
-  @override
   void writeMember(IndexedMember value) {
     _entityWriter.writeMemberToDataSink(this, value);
   }
diff --git a/pkg/compiler/lib/src/serialization/abstract_source.dart b/pkg/compiler/lib/src/serialization/abstract_source.dart
index 51cd928..5a455ed 100644
--- a/pkg/compiler/lib/src/serialization/abstract_source.dart
+++ b/pkg/compiler/lib/src/serialization/abstract_source.dart
@@ -131,11 +131,6 @@
   }
 
   @override
-  IndexedTypedef readTypedef() {
-    return _entityReader.readTypedefFromDataSource(this, entityLookup);
-  }
-
-  @override
   IndexedMember readMember() {
     return _entityReader.readMemberFromDataSource(this, entityLookup);
   }
@@ -235,11 +230,6 @@
         IndexedClass cls = readClass();
         List<DartType> typeArguments = _readDartTypes(functionTypeVariables);
         return new InterfaceType(cls, typeArguments);
-      case DartTypeKind.typedef:
-        IndexedTypedef typedef = readTypedef();
-        List<DartType> typeArguments = _readDartTypes(functionTypeVariables);
-        DartType unaliased = _readDartType(functionTypeVariables);
-        return new TypedefType(typedef, typeArguments, unaliased);
       case DartTypeKind.dynamicType:
         return DynamicType();
       case DartTypeKind.erasedType:
diff --git a/pkg/compiler/lib/src/serialization/helpers.dart b/pkg/compiler/lib/src/serialization/helpers.dart
index 8d73694..3e6d621 100644
--- a/pkg/compiler/lib/src/serialization/helpers.dart
+++ b/pkg/compiler/lib/src/serialization/helpers.dart
@@ -97,7 +97,6 @@
   functionTypeVariable,
   functionType,
   interfaceType,
-  typedef,
   dynamicType,
   erasedType,
   anyType,
@@ -200,15 +199,6 @@
   }
 
   @override
-  void visitTypedefType(covariant TypedefType type,
-      List<FunctionTypeVariable> functionTypeVariables) {
-    _sink.writeEnum(DartTypeKind.typedef);
-    _sink.writeTypedef(type.element);
-    visitTypes(type.typeArguments, functionTypeVariables);
-    _sink._writeDartType(type.unaliased, functionTypeVariables);
-  }
-
-  @override
   void visitDynamicType(covariant DynamicType type,
       List<FunctionTypeVariable> functionTypeVariables) {
     _sink.writeEnum(DartTypeKind.dynamicType);
diff --git a/pkg/compiler/lib/src/serialization/serialization.dart b/pkg/compiler/lib/src/serialization/serialization.dart
index 7c37416..6663884 100644
--- a/pkg/compiler/lib/src/serialization/serialization.dart
+++ b/pkg/compiler/lib/src/serialization/serialization.dart
@@ -301,9 +301,6 @@
   void writeClassMap<V>(Map<ClassEntity, V> map, void f(V value),
       {bool allowNull: false});
 
-  /// Writes a reference to the indexed typedef [value] to this data sink.
-  void writeTypedef(IndexedTypedef value);
-
   /// Writes a reference to the indexed member [value] to this data sink.
   void writeMember(IndexedMember value);
 
@@ -721,9 +718,6 @@
   Map<K, V> readClassMap<K extends ClassEntity, V>(V f(),
       {bool emptyAsNull: false});
 
-  /// Reads a reference to an indexed typedef from this data source.
-  IndexedTypedef readTypedef();
-
   /// Reads a reference to an indexed member from this data source.
   IndexedMember readMember();
 
@@ -857,9 +851,6 @@
   /// Returns the indexed class corresponding to [index].
   IndexedClass getClassByIndex(int index);
 
-  /// Returns the indexed typedef corresponding to [index].
-  IndexedTypedef getTypedefByIndex(int index);
-
   /// Returns the indexed member corresponding to [index].
   IndexedMember getMemberByIndex(int index);
 
@@ -881,11 +872,6 @@
     return entityLookup.getClassByIndex(source.readInt());
   }
 
-  IndexedTypedef readTypedefFromDataSource(
-      DataSource source, EntityLookup entityLookup) {
-    return entityLookup.getTypedefByIndex(source.readInt());
-  }
-
   IndexedMember readMemberFromDataSource(
       DataSource source, EntityLookup entityLookup) {
     return entityLookup.getMemberByIndex(source.readInt());
@@ -909,10 +895,6 @@
     sink.writeInt(value.classIndex);
   }
 
-  void writeTypedefToDataSink(DataSink sink, IndexedTypedef value) {
-    sink.writeInt(value.typedefIndex);
-  }
-
   void writeMemberToDataSink(DataSink sink, IndexedMember value) {
     sink.writeInt(value.memberIndex);
   }
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 87c7c5a..162f2b1 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -2425,16 +2425,10 @@
 
     StaticType operandType = _getStaticType(operand);
     DartType type = _elementMap.getDartType(node.type);
-    if (_elementMap.types.isSubtype(operandType.type, type)) {
+    if (!node.isCovarianceCheck &&
+        _elementMap.types.isSubtype(operandType.type, type)) {
       // Skip unneeded casts.
-      if (operand is! ir.PropertyGet) {
-        // TODO(johnniwinther): Support property get. Currently CFE inserts
-        // a seemingly unnecessary cast on tearoffs that contain type variables
-        // in contravariant positions. Since these casts are not marked we
-        // cannot easily detect when we actually need the cast. See test
-        // `language_2/instantiate_tearoff_after_contravariance_check_test`.
-        return;
-      }
+      return;
     }
 
     SourceInformation sourceInformation =
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 0bef2b6..6727238 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -3216,7 +3216,6 @@
   void visitTypeConversion(HTypeConversion node) {
     assert(node.isTypeCheck || node.isCastCheck);
     DartType type = node.typeExpression;
-    assert(type is! TypedefType);
     assert(type is! DynamicType);
     assert(type is! VoidType);
     if (type is FunctionType) {
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index 0dbb1eb..321de33 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -1405,7 +1405,6 @@
 
   HInstruction convertType(JClosedWorld closedWorld, DartType type, int kind) {
     if (type == null) return this;
-    type = type.unaliased;
     // Only the builder knows how to create [HTypeConversion]
     // instructions with generics. It has the generic type context
     // available.
@@ -3687,7 +3686,6 @@
       HInstruction input, SourceInformation sourceInformation)
       : checkedType = type,
         super(<HInstruction>[input], type) {
-    assert(typeExpression == null || typeExpression is! TypedefType);
     this.sourceElement = input.sourceElement;
     this.sourceInformation = sourceInformation;
   }
@@ -3696,7 +3694,6 @@
       AbstractValue type, HInstruction input, HInstruction typeRepresentation)
       : checkedType = type,
         super(<HInstruction>[input, typeRepresentation], type) {
-    assert(typeExpression is! TypedefType);
     sourceElement = input.sourceElement;
   }
 
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index c9a80b9..9cc56f6 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -902,7 +902,7 @@
       // @Native methods have conversion code for function arguments. Rather
       // than insert that code at the inlined call site, call the target on the
       // interceptor.
-      if (parameterType.unaliased is FunctionType) return true;
+      if (parameterType is FunctionType) return true;
     }
 
     if (!_closedWorld.annotationsData
@@ -1167,8 +1167,6 @@
 
     if (!node.isRawCheck) {
       return node;
-    } else if (type is TypedefType) {
-      return node;
     } else if (type is FunctionType) {
       return node;
     } else if (type is FutureOrType) {
@@ -1523,8 +1521,8 @@
 
       if (!_closedWorld.dartTypes.treatAsRawType(fieldType) ||
           fieldType is TypeVariableType ||
-          fieldType.unaliased is FunctionType ||
-          fieldType.unaliased is FutureOrType) {
+          fieldType is FunctionType ||
+          fieldType is FutureOrType) {
         // We cannot generate the correct type representation here, so don't
         // inline this access.
         // TODO(sra): If the input is such that we don't need a type check, we
@@ -3266,8 +3264,6 @@
     DartType type = instruction.typeExpression;
     if (!instruction.isRawCheck) {
       return;
-    } else if (type is TypedefType) {
-      return;
     } else if (type is FutureOrType) {
       return;
     }
diff --git a/pkg/compiler/lib/src/ssa/type_builder.dart b/pkg/compiler/lib/src/ssa/type_builder.dart
index 86b26e8..89bec4e 100644
--- a/pkg/compiler/lib/src/ssa/type_builder.dart
+++ b/pkg/compiler/lib/src/ssa/type_builder.dart
@@ -52,7 +52,6 @@
   AbstractValue trustTypeMask(DartType type) {
     if (type == null) return null;
     type = builder.localsHandler.substInContext(type);
-    type = type.unaliased;
     if (type is DynamicType) return null;
     if (type is! InterfaceType) return null;
     if (type == _closedWorld.commonElements.objectType) return null;
@@ -255,7 +254,6 @@
       return analyzeTypeArgumentNewRti(argument, sourceElement,
           sourceInformation: sourceInformation);
     }
-    argument = argument.unaliased;
     if (argument is DynamicType) {
       // Represent [dynamic] as [null].
       return builder.graph.addConstantNull(_closedWorld);
@@ -285,8 +283,6 @@
   HInstruction analyzeTypeArgumentNewRti(
       DartType argument, MemberEntity sourceElement,
       {SourceInformation sourceInformation}) {
-    argument = argument.unaliased;
-
     if (!argument.containsTypeVariables) {
       HInstruction rti =
           HLoadType.type(argument, _abstractValueDomain.dynamicType)
@@ -432,7 +428,6 @@
     }
 
     if (type == null) return original;
-    type = type.unaliased;
     if (type is InterfaceType && !_closedWorld.dartTypes.treatAsRawType(type)) {
       InterfaceType interfaceType = type;
       AbstractValue subtype =
@@ -471,8 +466,6 @@
   HInstruction buildAsCheck(HInstruction original, DartType type,
       {bool isTypeError, SourceInformation sourceInformation}) {
     if (type == null) return original;
-    type = type.unaliased;
-
     if (type is DynamicType) return original;
     if (type is VoidType) return original;
     if (type == _closedWorld.commonElements.objectType) return original;
diff --git a/pkg/compiler/lib/src/universe/codegen_world_builder.dart b/pkg/compiler/lib/src/universe/codegen_world_builder.dart
index 59b416e..e234deb 100644
--- a/pkg/compiler/lib/src/universe/codegen_world_builder.dart
+++ b/pkg/compiler/lib/src/universe/codegen_world_builder.dart
@@ -322,7 +322,7 @@
   }
 
   void registerIsCheck(covariant DartType type) {
-    _isChecks.add(type.unaliased);
+    _isChecks.add(type);
   }
 
   void registerNamedTypeVariableNewRti(TypeVariableType type) {
diff --git a/pkg/compiler/lib/src/universe/resolution_world_builder.dart b/pkg/compiler/lib/src/universe/resolution_world_builder.dart
index d0e72c0..6e23c07 100644
--- a/pkg/compiler/lib/src/universe/resolution_world_builder.dart
+++ b/pkg/compiler/lib/src/universe/resolution_world_builder.dart
@@ -89,8 +89,7 @@
   void registerProcessedMember(MemberEntity member);
   Iterable<MemberEntity> get processedMembers;
 
-  /// Registers that [type] is checked in this world builder. The unaliased type
-  /// is returned.
+  /// Registers that [type] is checked in this world builder.
   void registerIsCheck(DartType type);
 
   void registerNamedTypeVariableNewRti(TypeVariableType typeVariable);
diff --git a/pkg/dartdev/lib/src/commands/format.dart b/pkg/dartdev/lib/src/commands/format.dart
index 32f0206..99a8066 100644
--- a/pkg/dartdev/lib/src/commands/format.dart
+++ b/pkg/dartdev/lib/src/commands/format.dart
@@ -9,17 +9,52 @@
 
 class FormatCommand extends DartdevCommand {
   FormatCommand({bool verbose = false})
-      : super('format', 'Format one or more Dart files.') {
-    // TODO(jwren) add all options and flags
+      : super(
+          'format',
+          'Idiomatically formats Dart source code.',
+        ) {
+    // TODO(jwren) When https://github.com/dart-lang/dart_style/issues/889
+    //  is resolved, have dart_style provide the ArgParser, instead of creating
+    // one here.
+    argParser
+      ..addFlag('dry-run',
+          abbr: 'n',
+          help: 'Show which files would be modified but make no changes.')
+      ..addFlag('set-exit-if-changed',
+          help: 'Return exit code 1 if there are any formatting changes.')
+      ..addFlag('machine',
+          abbr: 'm', help: 'Produce machine-readable JSON output.')
+      ..addOption('line-length',
+          abbr: 'l',
+          help:
+              'Wrap lines longer than this length. Defaults to 80 characters.',
+          defaultsTo: '80');
   }
 
   @override
   FutureOr<int> run() async {
-    // TODO(jwren) implement verbose in dart_style
-    // dartfmt doesn't have '-v' or '--verbose', so remove from the argument list
-    var args = List.from(argResults.arguments)
+    // TODO(jwren) The verbose flag was added to dartfmt in version 1.3.4 with
+    // https://github.com/dart-lang/dart_style/pull/887, this version is rolled
+    // into the dart sdk build, we can remove the removal of '-v' and
+    // '--verbose':
+    List<String> args = List.from(argResults.arguments)
       ..remove('-v')
       ..remove('--verbose');
+
+    // By printing and returning if there are no arguments, this changes the
+    // default unix-pipe behavior of dartfmt:
+    if (args.isEmpty) {
+      printUsage();
+      return 0;
+    }
+
+    // By always adding '--overwrite', the default behavior of dartfmt by
+    // is changed to have the UX of 'flutter format *'.  The flag is not added
+    // if 'dry-run' has been passed as they are not compatible.
+    if (!argResults['dry-run']) {
+      args.add('--overwrite');
+    }
+
     var process = await startProcess(sdk.dartfmt, args);
     routeToStdout(process);
     return process.exitCode;
diff --git a/pkg/dartdev/lib/src/core.dart b/pkg/dartdev/lib/src/core.dart
index 8e0e3d8..9640904 100644
--- a/pkg/dartdev/lib/src/core.dart
+++ b/pkg/dartdev/lib/src/core.dart
@@ -33,6 +33,15 @@
   return Process.start(executable, arguments, workingDirectory: cwd);
 }
 
+ProcessResult runSync(
+  String executable,
+  List<String> arguments, {
+  String cwd,
+}) {
+  log.trace('$executable ${arguments.join(' ')}');
+  return Process.runSync(executable, arguments, workingDirectory: cwd);
+}
+
 void routeToStdout(
   Process process, {
   bool logToTrace = false,
diff --git a/pkg/dartdev/test/commands/flag_test.dart b/pkg/dartdev/test/commands/flag_test.dart
index 809f3e9..190173b 100644
--- a/pkg/dartdev/test/commands/flag_test.dart
+++ b/pkg/dartdev/test/commands/flag_test.dart
@@ -22,6 +22,7 @@
     var result = p.runSync('--help');
 
     expect(result.exitCode, 0);
+    expect(result.stderr, isEmpty);
     expect(result.stdout, contains(DartdevRunner.dartdevDescription));
     expect(result.stdout, contains('Usage: dartdev <command> [arguments]'));
     expect(result.stdout, contains('Global options:'));
diff --git a/pkg/dartdev/test/commands/format_test.dart b/pkg/dartdev/test/commands/format_test.dart
index ce18d50..0c076ec 100644
--- a/pkg/dartdev/test/commands/format_test.dart
+++ b/pkg/dartdev/test/commands/format_test.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'dart:io';
+
 import 'package:test/test.dart';
 
 import '../utils.dart';
@@ -15,13 +17,65 @@
 
   tearDown(() => p?.dispose());
 
+  test('implicit --help', () {
+    p = project();
+    var result = p.runSync('format');
+    expect(result.exitCode, 0);
+    expect(result.stderr, isEmpty);
+    expect(result.stdout, contains('Idiomatically formats Dart source code.'));
+    expect(result.stdout, contains('Usage: dartdev format [arguments]'));
+  });
+
   test('--help', () {
     p = project();
     var result = p.runSync('format', ['--help']);
     expect(result.exitCode, 0);
-    expect(result.stdout, contains('Format one or more Dart files.'));
+    expect(result.stderr, isEmpty);
+    expect(result.stdout, contains('Idiomatically formats Dart source code.'));
     expect(result.stdout, contains('Usage: dartdev format [arguments]'));
-    expect(
-        result.stdout, contains('Run "dartdev help" to see global options.'));
+  });
+
+  test('unchanged', () {
+    p = project(mainSrc: 'int get foo => 1;\n');
+    ProcessResult result = p.runSync('format', [p.relativeFilePath]);
+    expect(result.exitCode, 0);
+    expect(result.stderr, isEmpty);
+    expect(result.stdout, startsWith('Unchanged ${p.relativeFilePath}'));
+  });
+
+  test('formatted', () {
+    p = project(mainSrc: 'int get foo =>       1;\n');
+    ProcessResult result = p.runSync('format', [p.relativeFilePath]);
+    expect(result.exitCode, 0);
+    expect(result.stderr, isEmpty);
+    expect(result.stdout, startsWith('Formatted ${p.relativeFilePath}'));
+  });
+
+  test('dry-run changes', () {
+    p = project(mainSrc: 'int get foo =>       1;\n');
+    ProcessResult result =
+        p.runSync('format', ['--dry-run', p.relativeFilePath]);
+    expect(result.exitCode, 0);
+    expect(result.stderr, isEmpty);
+    expect(result.stdout, startsWith(p.relativeFilePath));
+  });
+
+  test('dry-run no changes', () {
+    p = project(mainSrc: 'int get foo => 1;\n');
+    ProcessResult result =
+        p.runSync('format', ['--dry-run', p.relativeFilePath]);
+    expect(result.exitCode, 0);
+    expect(result.stderr, isEmpty);
+    expect(result.stdout, isEmpty);
+  });
+
+  test('unknown file', () {
+    p = project(mainSrc: 'int get foo => 1;\n');
+    var unknownFilePath = p.relativeFilePath + '-unknown-file.dart';
+    ProcessResult result = p.runSync('format', [unknownFilePath]);
+    expect(result.exitCode, 0);
+    expect(result.stderr,
+        startsWith('No file or directory found at "${unknownFilePath}".'));
+    expect(result.stdout, isEmpty);
   });
 }
diff --git a/pkg/dartdev/test/utils.dart b/pkg/dartdev/test/utils.dart
index ac4189a..abd3b18 100644
--- a/pkg/dartdev/test/utils.dart
+++ b/pkg/dartdev/test/utils.dart
@@ -15,10 +15,12 @@
 
   String get name => defaultProjectName;
 
+  String get relativeFilePath => 'lib/main.dart';
+
   TestProject({String mainSrc}) {
     dir = Directory.systemTemp.createTempSync('dartdev');
     if (mainSrc != null) {
-      file('lib/main.dart', mainSrc);
+      file(relativeFilePath, mainSrc);
     }
     file('pubspec.yaml', 'name: $name\ndev_dependencies:\n  test: any\n');
   }
diff --git a/pkg/dev_compiler/analysis_options.yaml b/pkg/dev_compiler/analysis_options.yaml
index e4c5083..649b03d 100644
--- a/pkg/dev_compiler/analysis_options.yaml
+++ b/pkg/dev_compiler/analysis_options.yaml
@@ -21,14 +21,17 @@
     - annotate_overrides
     - avoid_null_checks_in_equality_operators
     - camel_case_extensions
+    - omit_local_variable_types
     - prefer_adjacent_string_concatenation
     - prefer_collection_literals
     - prefer_conditional_assignment
     - prefer_final_fields
     - prefer_for_elements_to_map_fromIterable
+    - prefer_generic_function_type_aliases
     - prefer_if_null_operators
     - prefer_single_quotes
     - prefer_spread_collections
+    - use_function_type_syntax_for_parameters
     # Not enforced by pedantic at any version.
     - directives_ordering
     - prefer_null_aware_operators
diff --git a/pkg/dev_compiler/lib/src/compiler/js_metalet.dart b/pkg/dev_compiler/lib/src/compiler/js_metalet.dart
index 4f569a1..8941bb0 100644
--- a/pkg/dev_compiler/lib/src/compiler/js_metalet.dart
+++ b/pkg/dev_compiler/lib/src/compiler/js_metalet.dart
@@ -216,7 +216,7 @@
       // Since this is let*, subsequent variables can refer to previous ones,
       // so we need to substitute here.
       init = _substitute(init, substitutions);
-      int n = counter.counts[variable];
+      var n = counter.counts[variable];
       if (n == 1) {
         // Replace interpolated exprs with their value, if it only occurs once.
         substitutions[variable] = init;
@@ -330,7 +330,7 @@
   @override
   void visitInterpolatedExpression(InterpolatedExpression node) {
     if (node is MetaLetVariable) {
-      int n = counts[node];
+      var n = counts[node];
       counts[node] = n == null ? 1 : n + 1;
     }
   }
diff --git a/pkg/dev_compiler/lib/src/compiler/js_names.dart b/pkg/dev_compiler/lib/src/compiler/js_names.dart
index 0e3192c..647f6fb 100644
--- a/pkg/dev_compiler/lib/src/compiler/js_names.dart
+++ b/pkg/dev_compiler/lib/src/compiler/js_names.dart
@@ -245,7 +245,7 @@
       // TODO(jmesserly): what's the most readable scheme here? Maybe 1-letter
       // names in some cases?
       candidate = name == 'function' ? 'func' : '${name}\$';
-      for (int i = 0;
+      for (var i = 0;
           scopes.any((scope) => scope.used.contains(candidate));
           i++) {
         candidate = '${name}\$$i';
@@ -415,7 +415,7 @@
 
   // Escape any invalid characters
   StringBuffer buffer;
-  for (int i = 0; i < name.length; i++) {
+  for (var i = 0; i < name.length; i++) {
     var ch = name[i];
     var needsEscape = ch == r'$' || invalidCharInIdentifier.hasMatch(ch);
     if (needsEscape && buffer == null) {
diff --git a/pkg/dev_compiler/lib/src/compiler/shared_command.dart b/pkg/dev_compiler/lib/src/compiler/shared_command.dart
index d668402..37b4771 100644
--- a/pkg/dev_compiler/lib/src/compiler/shared_command.dart
+++ b/pkg/dev_compiler/lib/src/compiler/shared_command.dart
@@ -242,7 +242,7 @@
   });
 
   String optionName(int prefixLength, String arg) {
-    int equalsOffset = arg.lastIndexOf('=');
+    var equalsOffset = arg.lastIndexOf('=');
     if (equalsOffset < 0) {
       return arg.substring(prefixLength);
     }
@@ -287,7 +287,7 @@
     source = source.replaceAll('\\', '/');
   }
 
-  Uri result = Uri.base.resolve(source);
+  var result = Uri.base.resolve(source);
   if (windows && result.scheme.length == 1) {
     // Assume c: or similar --- interpret as file path.
     return Uri.file(source, windows: true);
@@ -364,7 +364,7 @@
     return p.toUri(sourcePath).path;
   }
 
-  for (int i = 0; i < list.length; i++) {
+  for (var i = 0; i < list.length; i++) {
     list[i] = makeRelative(list[i] as String);
   }
   map['sources'] = list;
@@ -480,10 +480,10 @@
     if (args.isEmpty) return ParsedArguments._(args);
 
     var newArgs = <String>[];
-    bool isWorker = false;
-    bool isBatch = false;
-    bool reuseResult = false;
-    bool useIncrementalCompiler = false;
+    var isWorker = false;
+    var isBatch = false;
+    var reuseResult = false;
+    var useIncrementalCompiler = false;
 
     Iterable<String> argsToParse = args;
 
diff --git a/pkg/dev_compiler/lib/src/js_ast/builder.dart b/pkg/dev_compiler/lib/src/js_ast/builder.dart
index 9b2105f..cf9c5c2 100644
--- a/pkg/dev_compiler/lib/src/js_ast/builder.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/builder.dart
@@ -4,7 +4,7 @@
 
 // ignore_for_file: slash_for_doc_comments, unnecessary_new
 // ignore_for_file: always_declare_return_types, prefer_single_quotes
-// ignore_for_file: prefer_collection_literals
+// ignore_for_file: prefer_collection_literals, omit_local_variable_types
 
 // Utilities for building JS ASTs at runtime.  Contains a builder class
 // and a parser that parses part of the language.
diff --git a/pkg/dev_compiler/lib/src/js_ast/nodes.dart b/pkg/dev_compiler/lib/src/js_ast/nodes.dart
index bed1271..14db172 100644
--- a/pkg/dev_compiler/lib/src/js_ast/nodes.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/nodes.dart
@@ -5,6 +5,7 @@
 // ignore_for_file: slash_for_doc_comments, prefer_single_quotes
 // ignore_for_file: always_declare_return_types, prefer_final_fields
 // ignore_for_file: always_require_non_null_named_parameters
+// ignore_for_file: omit_local_variable_types
 
 part of js_ast;
 
diff --git a/pkg/dev_compiler/lib/src/js_ast/printer.dart b/pkg/dev_compiler/lib/src/js_ast/printer.dart
index df80ee1..c7891b4 100644
--- a/pkg/dev_compiler/lib/src/js_ast/printer.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/printer.dart
@@ -4,7 +4,9 @@
 
 // ignore_for_file: slash_for_doc_comments, unnecessary_const
 // ignore_for_file: always_declare_return_types, prefer_single_quotes
-// ignore_for_file: prefer_collection_literals, prefer_final_fields
+// ignore_for_file: prefer_collection_literals, omit_local_variable_types
+// ignore_for_file: prefer_generic_function_type_aliases, prefer_final_fields
+// ignore_for_file: use_function_type_syntax_for_parameters
 
 part of js_ast;
 
diff --git a/pkg/dev_compiler/lib/src/js_ast/source_map_printer.dart b/pkg/dev_compiler/lib/src/js_ast/source_map_printer.dart
index 867e905..6acee34 100644
--- a/pkg/dev_compiler/lib/src/js_ast/source_map_printer.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/source_map_printer.dart
@@ -2,7 +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.
 
-// ignore_for_file: always_declare_return_types
+// ignore_for_file: always_declare_return_types, omit_local_variable_types
 
 import 'package:source_maps/source_maps.dart' hide Printer;
 import 'package:source_span/source_span.dart' show SourceLocation;
diff --git a/pkg/dev_compiler/lib/src/js_ast/template.dart b/pkg/dev_compiler/lib/src/js_ast/template.dart
index 733b786..73d840b 100644
--- a/pkg/dev_compiler/lib/src/js_ast/template.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/template.dart
@@ -2,8 +2,9 @@
 // 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.
 
-// ignore_for_file: slash_for_doc_comments, prefer_single_quotes
+// ignore_for_file: slash_for_doc_comments, omit_local_variable_types
 // ignore_for_file: always_declare_return_types, prefer_collection_literals
+// ignore_for_file: prefer_single_quotes, prefer_generic_function_type_aliases
 
 part of js_ast;
 
diff --git a/pkg/dev_compiler/lib/src/kernel/command.dart b/pkg/dev_compiler/lib/src/kernel/command.dart
index 080d830..b7524cc 100644
--- a/pkg/dev_compiler/lib/src/kernel/command.dart
+++ b/pkg/dev_compiler/lib/src/kernel/command.dart
@@ -250,7 +250,7 @@
   var experiments = fe.parseExperimentalFlags(options.experiments,
       onError: stderr.writeln, onWarning: print);
 
-  bool trackWidgetCreation =
+  var trackWidgetCreation =
       argResults['track-widget-creation'] as bool ?? false;
 
   var compileSdk = argResults['compile-sdk'] == true;
@@ -258,8 +258,8 @@
   List<Component> doneInputSummaries;
   fe.IncrementalCompiler incrementalCompiler;
   fe.WorkerInputComponent cachedSdkInput;
-  bool recordUsedInputs = argResults['used-inputs-file'] != null;
-  List<Uri> inputSummaries = summaryModules.keys.toList();
+  var recordUsedInputs = argResults['used-inputs-file'] != null;
+  var inputSummaries = summaryModules.keys.toList();
   if (!useIncrementalCompiler) {
     compilerState = await fe.initializeCompiler(
         oldCompilerState,
@@ -285,7 +285,7 @@
       if (!compileSdk) {
         inputDigests[sourcePathToUri(sdkSummaryPath)] = const [0];
       }
-      for (Uri uri in summaryModules.keys) {
+      for (var uri in summaryModules.keys) {
         inputDigests[uri] = const [0];
       }
     }
@@ -329,7 +329,7 @@
     result = await fe.compile(compilerState, inputs, diagnosticMessageHandler);
   } else {
     compilerState.options.onDiagnostic = diagnosticMessageHandler;
-    Component incrementalComponent = await incrementalCompiler.computeDelta(
+    var incrementalComponent = await incrementalCompiler.computeDelta(
         entryPoints: inputs, fullComponent: true);
     result = fe.DdcResult(incrementalComponent, cachedSdkInput.component,
         doneInputSummaries, incrementalCompiler.userCode.loader.hierarchy);
@@ -341,10 +341,10 @@
   }
 
   var component = result.component;
-  Set<Library> librariesFromDill = result.computeLibrariesFromDill();
-  Component compiledLibraries =
+  var librariesFromDill = result.computeLibrariesFromDill();
+  var compiledLibraries =
       Component(nameRoot: component.root, uriToSource: component.uriToSource);
-  for (Library lib in component.libraries) {
+  for (var lib in component.libraries) {
     if (!librariesFromDill.contains(lib)) compiledLibraries.libraries.add(lib);
   }
 
@@ -383,7 +383,7 @@
           'the --summarize-text option is not supported.');
       return CompilerResult(64);
     }
-    StringBuffer sb = StringBuffer();
+    var sb = StringBuffer();
     kernel.Printer(sb).writeComponentFile(component);
     outFiles.add(File(outPaths.first + '.txt').writeAsString(sb.toString()));
   }
@@ -429,14 +429,13 @@
   }
 
   if (recordUsedInputs) {
-    Set<Uri> usedOutlines = <Uri>{};
+    var usedOutlines = <Uri>{};
     if (useIncrementalCompiler) {
       compilerState.incrementalCompiler
           .updateNeededDillLibrariesWithHierarchy(result.classHierarchy, null);
-      for (Library lib
-          in compilerState.incrementalCompiler.neededDillLibraries) {
+      for (var lib in compilerState.incrementalCompiler.neededDillLibraries) {
         if (lib.importUri.scheme == 'dart') continue;
-        Uri uri = compilerState.libraryToInputDill[lib.importUri];
+        var uri = compilerState.libraryToInputDill[lib.importUri];
         if (uri == null) {
           throw StateError('Library ${lib.importUri} was recorded as used, '
               'but was not in the list of known libraries.');
@@ -602,7 +601,7 @@
 /// and removes them from [args] so the result can be parsed normally.
 Map<String, String> parseAndRemoveDeclaredVariables(List<String> args) {
   var declaredVariables = <String, String>{};
-  for (int i = 0; i < args.length;) {
+  for (var i = 0; i < args.length;) {
     var arg = args[i];
     if (arg.startsWith('-D') && arg.length > 2) {
       var rest = arg.substring(2);
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index f46dcd5..3e73acb 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -861,7 +861,7 @@
       body.add(_emitClassStatement(c, className, baseClass, []));
 
       var m = c.mixedInType.asInterfaceType;
-      bool deferMixin = shouldDefer(m);
+      var deferMixin = shouldDefer(m);
       var mixinBody = deferMixin ? deferredSupertypes : body;
       var mixinClass = deferMixin ? emitDeferredType(m) : emitClassRef(m);
       var classExpr = deferMixin ? getBaseClass(0) : className;
@@ -893,7 +893,7 @@
     // classes lack required synthetic members, such as constructors.
     //
     // Also, we need to generate one extra level of nesting for alias classes.
-    for (int i = 0; i < mixins.length; i++) {
+    for (var i = 0; i < mixins.length; i++) {
       var m = mixins[i];
       var mixinName =
           getLocalClassName(superclass) + '_' + getLocalClassName(m.classNode);
@@ -1636,8 +1636,8 @@
     var virtualFields = _classProperties.virtualFields;
 
     var jsMethods = <js_ast.Method>[];
-    bool hasJsPeer = _extensionTypes.isNativeClass(c);
-    bool hasIterator = false;
+    var hasJsPeer = _extensionTypes.isNativeClass(c);
+    var hasIterator = false;
 
     if (c == _coreTypes.objectClass) {
       // Dart does not use ES6 constructors.
@@ -1778,7 +1778,7 @@
   }
 
   js_ast.Fun _emitNativeFunctionBody(Procedure node) {
-    String name = _annotationName(node, isJSAnnotation) ?? node.name.name;
+    var name = _annotationName(node, isJSAnnotation) ?? node.name.name;
     if (node.isGetter) {
       return js_ast.Fun([], js.block('{ return this.#; }', [name]));
     } else if (node.isSetter) {
@@ -2142,7 +2142,8 @@
     })));
   }
 
-  List<js_ast.Statement> _withLetScope(List<js_ast.Statement> visitBody()) {
+  List<js_ast.Statement> _withLetScope(
+      List<js_ast.Statement> Function() visitBody) {
     var savedLetVariables = _letVariables;
     _letVariables = [];
 
@@ -2154,7 +2155,8 @@
     return body;
   }
 
-  js_ast.ArrowFun _arrowFunctionWithLetScope(js_ast.Expression visitBody()) {
+  js_ast.ArrowFun _arrowFunctionWithLetScope(
+      js_ast.Expression Function() visitBody) {
     var savedLetVariables = _letVariables;
     _letVariables = [];
 
@@ -2242,7 +2244,7 @@
         if (parts.length < 2) return propertyName(runtimeName);
 
         js_ast.Expression result = _emitIdentifier(parts[0]);
-        for (int i = 1; i < parts.length; i++) {
+        for (var i = 1; i < parts.length; i++) {
           result = js_ast.PropertyAccess(result, propertyName(parts[i]));
         }
         return result;
@@ -2874,7 +2876,7 @@
   js_ast.ArrayInitializer _emitTypeNames(List<DartType> types,
       List<VariableDeclaration> parameters, Member member) {
     var result = <js_ast.Expression>[];
-    for (int i = 0; i < types.length; ++i) {
+    for (var i = 0; i < types.length; ++i) {
       var type = _emitType(types[i]);
       if (parameters != null) {
         type = _emitAnnotatedResult(type, parameters[i].annotations, member);
@@ -2918,7 +2920,7 @@
     // potentially mutated in Kernel. For now we assume all parameters are.
     super.enterFunction(name, formals, () => true);
 
-    js_ast.Block block =
+    var block =
         isSync ? _emitSyncFunctionBody(f) : _emitGeneratorFunctionBody(f, name);
 
     block = super.exitFunction(name, formals, block);
@@ -2986,7 +2988,7 @@
   js_ast.Expression _emitGeneratorFunctionExpression(
       FunctionNode function, String name) {
     js_ast.Expression emitGeneratorFn(
-        List<js_ast.Parameter> getParameters(js_ast.Block jsBody)) {
+        List<js_ast.Parameter> Function(js_ast.Block jsBody) getParameters) {
       var savedController = _asyncStarController;
       _asyncStarController = function.asyncMarker == AsyncMarker.AsyncStar
           ? _emitTemporaryId('stream')
@@ -3148,7 +3150,7 @@
   }
 
   List<js_ast.Statement> _withCurrentFunction(
-      FunctionNode fn, List<js_ast.Statement> action()) {
+      FunctionNode fn, List<js_ast.Statement> Function() action) {
     var savedFunction = _currentFunction;
     _currentFunction = fn;
     _nullableInference.enterFunction(fn);
@@ -3160,7 +3162,7 @@
     return result;
   }
 
-  T _superDisallowed<T>(T action()) {
+  T _superDisallowed<T>(T Function() action) {
     var savedSuperAllowed = _superAllowed;
     _superAllowed = false;
     var result = action();
@@ -3578,7 +3580,8 @@
     return body;
   }
 
-  T _translateLoop<T extends js_ast.Statement>(Statement node, T action()) {
+  T _translateLoop<T extends js_ast.Statement>(
+      Statement node, T Function() action) {
     List<LabeledStatement> savedBreakTargets;
     if (_currentBreakTargets.isNotEmpty &&
         _effectiveTargets[_currentBreakTargets.first] != node) {
@@ -4214,7 +4217,7 @@
       Arguments arguments, InvocationExpression node) {
     var name = node.name.name;
     if (isOperatorMethodName(name) && arguments.named.isEmpty) {
-      int argLength = arguments.positional.length;
+      var argLength = arguments.positional.length;
       if (argLength == 0) {
         return _emitUnaryOperator(receiver, target, node);
       } else if (argLength == 1) {
@@ -4226,7 +4229,7 @@
     var jsReceiver = _visitExpression(receiver);
     var args = _emitArgumentList(arguments, target: target);
 
-    bool isCallingDynamicField = target is Member &&
+    var isCallingDynamicField = target is Member &&
         target.hasGetter &&
         _isDynamicOrFunction(target.getterType);
     if (name == 'call') {
@@ -4363,7 +4366,7 @@
       var left = getInvocationReceiver(parent);
       var right = parent.arguments.positional[0];
       if (left != null && op == '==') {
-        const int MAX = 0x7fffffff;
+        const MAX = 0x7fffffff;
         if (_asIntInRange(right, 0, MAX) != null) return uncoerced;
         if (_asIntInRange(left, 0, MAX) != null) return uncoerced;
       } else if (left != null && op == '>>') {
@@ -4415,7 +4418,7 @@
       if (parent.name.name == '&' && parent.arguments.positional.length == 1) {
         var left = getInvocationReceiver(parent);
         var right = parent.arguments.positional[0];
-        final int MAX = (1 << width) - 1;
+        final MAX = (1 << width) - 1;
         if (left != null) {
           if (_asIntInRange(right, 0, MAX) != null) return true;
           if (_asIntInRange(left, 0, MAX) != null) return true;
@@ -4429,7 +4432,7 @@
   /// Determines if the result of evaluating [expr] will be an non-negative
   /// value that fits in 31 bits.
   bool _is31BitUnsigned(Expression expr) {
-    const int MAX = 32; // Includes larger and negative values.
+    const MAX = 32; // Includes larger and negative values.
     /// Determines how many bits are required to hold result of evaluation
     /// [expr].  [depth] is used to bound exploration of huge expressions.
     int bitWidth(Expression expr, int depth) {
@@ -4451,20 +4454,20 @@
               return max(bitWidth(left, depth), bitWidth(right, depth));
 
             case '>>':
-              int shiftValue = _asIntInRange(right, 0, 31);
+              var shiftValue = _asIntInRange(right, 0, 31);
               if (shiftValue != null) {
-                int leftWidth = bitWidth(left, depth);
+                var leftWidth = bitWidth(left, depth);
                 return leftWidth == MAX ? MAX : max(0, leftWidth - shiftValue);
               }
               return MAX;
 
             case '<<':
-              int leftWidth = bitWidth(left, depth);
-              int shiftValue = _asIntInRange(right, 0, 31);
+              var leftWidth = bitWidth(left, depth);
+              var shiftValue = _asIntInRange(right, 0, 31);
               if (shiftValue != null) {
                 return min(MAX, leftWidth + shiftValue);
               }
-              int rightWidth = bitWidth(right, depth);
+              var rightWidth = bitWidth(right, depth);
               if (rightWidth <= 5) {
                 // e.g.  `1 << (x & 7)` has a rightWidth of 3, so shifts by up to
                 // (1 << 3) - 1 == 7 bits.
@@ -4476,7 +4479,7 @@
           }
         }
       }
-      int value = _asIntInRange(expr, 0, 0x7fffffff);
+      var value = _asIntInRange(expr, 0, 0x7fffffff);
       if (value != null) return value.bitLength;
       return MAX;
     }
@@ -4551,7 +4554,7 @@
                 : bitwise('# ^ #');
 
           case '>>':
-            int shiftCount = _asIntInRange(right, 0, 31);
+            var shiftCount = _asIntInRange(right, 0, 31);
             if (_is31BitUnsigned(left) && shiftCount != null) {
               return binary('# >> #');
             }
@@ -5181,7 +5184,7 @@
 
   @override
   js_ast.Expression visitAsExpression(AsExpression node) {
-    Expression fromExpr = node.operand;
+    var fromExpr = node.operand;
     var to = node.type;
     var jsFrom = _visitExpression(fromExpr);
     var from = fromExpr.getStaticType(_staticTypeContext);
@@ -5357,14 +5360,14 @@
   }
 
   js_ast.ArrowFun _emitArrowFunction(FunctionExpression node) {
-    js_ast.Fun f = _emitFunction(node.function, null);
+    var f = _emitFunction(node.function, null);
     js_ast.Node body = f.body;
 
     // Simplify `=> { return e; }` to `=> e`
     if (body is js_ast.Block) {
       var block = body as js_ast.Block;
       if (block.statements.length == 1) {
-        js_ast.Statement s = block.statements[0];
+        var s = block.statements[0];
         if (s is js_ast.Block) {
           block = s as js_ast.Block;
           s = block.statements.length == 1 ? block.statements[0] : null;
@@ -5501,7 +5504,7 @@
   /// string, this returns the string value.
   ///
   /// Calls [findAnnotation] followed by [getNameFromAnnotation].
-  String _annotationName(NamedNode node, bool test(Expression value)) {
+  String _annotationName(NamedNode node, bool Function(Expression) test) {
     return _constants.getFieldValueFromAnnotation(
         findAnnotation(node, test), 'name') as String;
   }
@@ -5570,8 +5573,8 @@
     // Emit the constant as an integer, if possible.
     if (value.isFinite) {
       var intValue = value.toInt();
-      const int _MIN_INT32 = -0x80000000;
-      const int _MAX_INT32 = 0x7FFFFFFF;
+      const _MIN_INT32 = -0x80000000;
+      const _MAX_INT32 = 0x7FFFFFFF;
       if (intValue.toDouble() == value &&
           intValue >= _MIN_INT32 &&
           intValue <= _MAX_INT32) {
diff --git a/pkg/dev_compiler/lib/src/kernel/constants.dart b/pkg/dev_compiler/lib/src/kernel/constants.dart
index 2059f37..69ba4a5 100644
--- a/pkg/dev_compiler/lib/src/kernel/constants.dart
+++ b/pkg/dev_compiler/lib/src/kernel/constants.dart
@@ -101,7 +101,7 @@
 
   @override
   bool shouldInlineConstant(ConstantExpression initializer) {
-    Constant constant = initializer.constant;
+    var constant = initializer.constant;
     if (constant is StringConstant) {
       // Only inline small string constants, not large ones.
       // (The upper bound value is arbitrary.)
diff --git a/pkg/dev_compiler/lib/src/kernel/js_typerep.dart b/pkg/dev_compiler/lib/src/kernel/js_typerep.dart
index 7c4cba7..e9ea6e4 100644
--- a/pkg/dev_compiler/lib/src/kernel/js_typerep.dart
+++ b/pkg/dev_compiler/lib/src/kernel/js_typerep.dart
@@ -66,7 +66,7 @@
   /// returns the corresponding class in `dart:_interceptors`:
   /// `JSBool`, `JSString`, and `JSNumber` respectively, otherwise null.
   Class getImplementationClass(DartType t) {
-    JSType rep = typeFor(t);
+    var rep = typeFor(t);
     // Number, String, and Bool are final
     if (rep == JSType.jsNumber) return _jsNumber;
     if (rep == JSType.jsBoolean) return _jsBool;
diff --git a/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart b/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
index 6f2fe52..03e4d95 100644
--- a/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
+++ b/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
@@ -67,7 +67,7 @@
 ///
 ///    (v) => v.type.name == 'Deprecated' && v.type.element.library.isDartCore
 ///
-Expression findAnnotation(TreeNode node, bool test(Expression value)) {
+Expression findAnnotation(TreeNode node, bool Function(Expression) test) {
   List<Expression> annotations;
   if (node is Class) {
     annotations = node.annotations;
diff --git a/pkg/dev_compiler/lib/src/kernel/native_types.dart b/pkg/dev_compiler/lib/src/kernel/native_types.dart
index 162c50b..bf340b1 100644
--- a/pkg/dev_compiler/lib/src/kernel/native_types.dart
+++ b/pkg/dev_compiler/lib/src/kernel/native_types.dart
@@ -74,7 +74,7 @@
     if (_extensibleTypes.contains(c) || _nativeTypes.contains(c)) {
       return;
     }
-    bool isNative = mustBeNative || _isNative(c);
+    var isNative = mustBeNative || _isNative(c);
     if (isNative) {
       _nativeTypes.add(c);
     } else {
diff --git a/pkg/dev_compiler/lib/src/kernel/target.dart b/pkg/dev_compiler/lib/src/kernel/target.dart
index 5ab0178..8295e95 100644
--- a/pkg/dev_compiler/lib/src/kernel/target.dart
+++ b/pkg/dev_compiler/lib/src/kernel/target.dart
@@ -102,7 +102,7 @@
     // Multi-root scheme used by modular test framework.
     if (uri.scheme == 'dev-dart-app') return true;
 
-    String scriptName = uri.path;
+    var scriptName = uri.path;
     return scriptName.contains('tests/compiler/dartdevc_native');
   }
 
@@ -135,7 +135,7 @@
       Map<String, String> environmentDefines,
       DiagnosticReporter diagnosticReporter,
       ReferenceFromIndex referenceFromIndex,
-      {void logger(String msg),
+      {void Function(String msg) logger,
       ChangedStructureNotifier changedStructureNotifier}) {
     for (var library in libraries) {
       _CovarianceTransformer(library).transform();
@@ -151,7 +151,7 @@
       CoreTypes coreTypes,
       List<Library> libraries,
       DiagnosticReporter diagnosticReporter,
-      {void logger(String msg),
+      {void Function(String msg) logger,
       ChangedStructureNotifier changedStructureNotifier}) {
     if (flags.trackWidgetCreation) {
       _widgetTracker ??= WidgetCreatorTracker();
diff --git a/pkg/dev_compiler/lib/src/kernel/type_table.dart b/pkg/dev_compiler/lib/src/kernel/type_table.dart
index bb751d1..0c704de 100644
--- a/pkg/dev_compiler/lib/src/kernel/type_table.dart
+++ b/pkg/dev_compiler/lib/src/kernel/type_table.dart
@@ -120,7 +120,7 @@
   js_ast.Statement _dischargeType(DartType t) {
     var name = _names.remove(t);
     if (name != null) {
-      js_ast.Expression init = _defs.remove(t);
+      var init = _defs.remove(t);
       assert(init != null);
       // TODO(vsm): Change back to `let`.
       // See https://github.com/dart-lang/sdk/issues/40380.
diff --git a/pkg/dev_compiler/test/modular_suite.dart b/pkg/dev_compiler/test/modular_suite.dart
index e76144a..b6aa6d5 100644
--- a/pkg/dev_compiler/test/modular_suite.dart
+++ b/pkg/dev_compiler/test/modular_suite.dart
@@ -64,11 +64,11 @@
     //
     // Files in packages are defined in terms of `package:` URIs, while
     // non-package URIs are defined using the `dart-dev-app` scheme.
-    String rootScheme = module.isSdk ? 'dev-dart-sdk' : 'dev-dart-app';
+    var rootScheme = module.isSdk ? 'dev-dart-sdk' : 'dev-dart-app';
     String sourceToImportUri(Uri relativeUri) =>
         _sourceToImportUri(module, rootScheme, relativeUri);
 
-    Set<Module> transitiveDependencies = computeTransitiveDependencies(module);
+    var transitiveDependencies = computeTransitiveDependencies(module);
     await _createPackagesFile(module, root, transitiveDependencies);
 
     List<String> sources;
@@ -82,10 +82,10 @@
       extraArgs = ['--packages-file', '$rootScheme:/.packages'];
     }
 
-    Module sdkModule =
+    var sdkModule =
         module.isSdk ? module : module.dependencies.firstWhere((m) => m.isSdk);
 
-    List<String> args = [
+    var args = [
       _kernelWorkerScript,
       '--summary-only',
       '--target',
@@ -141,10 +141,10 @@
       List<String> flags) async {
     if (_options.verbose) print('\nstep: ddk on $module');
 
-    Set<Module> transitiveDependencies = computeTransitiveDependencies(module);
+    var transitiveDependencies = computeTransitiveDependencies(module);
     await _createPackagesFile(module, root, transitiveDependencies);
 
-    String rootScheme = module.isSdk ? 'dev-dart-sdk' : 'dev-dart-app';
+    var rootScheme = module.isSdk ? 'dev-dart-sdk' : 'dev-dart-app';
     List<String> sources;
     List<String> extraArgs;
     if (module.isSdk) {
@@ -152,7 +152,7 @@
       extraArgs = ['--compile-sdk'];
       assert(transitiveDependencies.isEmpty);
     } else {
-      Module sdkModule = module.dependencies.firstWhere((m) => m.isSdk);
+      var sdkModule = module.dependencies.firstWhere((m) => m.isSdk);
       sources = module.sources
           .map((relativeUri) =>
               _sourceToImportUri(module, rootScheme, relativeUri))
@@ -165,9 +165,9 @@
       ];
     }
 
-    Uri output = toUri(module, jsId);
+    var output = toUri(module, jsId);
 
-    List<String> args = [
+    var args = [
       '--packages=${sdkRoot.toFilePath()}/.packages',
       _dartdevcScript,
       '--kernel',
@@ -236,7 +236,7 @@
     var wrapper =
         root.resolveUri(toUri(module, jsId)).toFilePath() + '.wrapper.js';
     await File(wrapper).writeAsString(runjs);
-    List<String> d8Args = ['--module', wrapper];
+    var d8Args = ['--module', wrapper];
     var result = await _runProcess(
         sdkRoot.resolve(_d8executable).toFilePath(), d8Args, root.toFilePath());
 
@@ -301,7 +301,7 @@
   if (module.isPackage) {
     packagesContents.write('${module.name}:${module.packageBase}\n');
   }
-  for (Module dependency in transitiveDependencies) {
+  for (var dependency in transitiveDependencies) {
     if (dependency.isPackage) {
       packagesContents.write('${dependency.name}:unused\n');
     }
@@ -326,9 +326,9 @@
 Future<void> _resolveScripts() async {
   Future<String> resolve(
       String sdkSourcePath, String relativeSnapshotPath) async {
-    String result = sdkRoot.resolve(sdkSourcePath).toFilePath();
+    var result = sdkRoot.resolve(sdkSourcePath).toFilePath();
     if (_options.useSdk) {
-      String snapshot = Uri.file(Platform.resolvedExecutable)
+      var snapshot = Uri.file(Platform.resolvedExecutable)
           .resolve(relativeSnapshotPath)
           .toFilePath();
       if (await File(snapshot).exists()) {
diff --git a/pkg/dev_compiler/test/modular_suite_nnbd.dart b/pkg/dev_compiler/test/modular_suite_nnbd.dart
index 716d3db..4f1b317 100644
--- a/pkg/dev_compiler/test/modular_suite_nnbd.dart
+++ b/pkg/dev_compiler/test/modular_suite_nnbd.dart
@@ -64,11 +64,11 @@
     //
     // Files in packages are defined in terms of `package:` URIs, while
     // non-package URIs are defined using the `dart-dev-app` scheme.
-    String rootScheme = module.isSdk ? 'dev-dart-sdk' : 'dev-dart-app';
+    var rootScheme = module.isSdk ? 'dev-dart-sdk' : 'dev-dart-app';
     String sourceToImportUri(Uri relativeUri) =>
         _sourceToImportUri(module, rootScheme, relativeUri);
 
-    Set<Module> transitiveDependencies = computeTransitiveDependencies(module);
+    var transitiveDependencies = computeTransitiveDependencies(module);
     await _createPackagesFile(module, root, transitiveDependencies);
 
     List<String> sources;
@@ -85,10 +85,10 @@
       extraArgs = ['--packages-file', '$rootScheme:/.packages'];
     }
 
-    Module sdkModule =
+    var sdkModule =
         module.isSdk ? module : module.dependencies.firstWhere((m) => m.isSdk);
 
-    List<String> args = [
+    var args = [
       _kernelWorkerScript,
       '--summary-only',
       '--target',
@@ -144,10 +144,10 @@
       List<String> flags) async {
     if (_options.verbose) print('\nstep: ddk on $module');
 
-    Set<Module> transitiveDependencies = computeTransitiveDependencies(module);
+    var transitiveDependencies = computeTransitiveDependencies(module);
     await _createPackagesFile(module, root, transitiveDependencies);
 
-    String rootScheme = module.isSdk ? 'dev-dart-sdk' : 'dev-dart-app';
+    var rootScheme = module.isSdk ? 'dev-dart-sdk' : 'dev-dart-app';
     List<String> sources;
     List<String> extraArgs;
     if (module.isSdk) {
@@ -160,7 +160,7 @@
       ];
       assert(transitiveDependencies.isEmpty);
     } else {
-      Module sdkModule = module.dependencies.firstWhere((m) => m.isSdk);
+      var sdkModule = module.dependencies.firstWhere((m) => m.isSdk);
       sources = module.sources
           .map((relativeUri) =>
               _sourceToImportUri(module, rootScheme, relativeUri))
@@ -173,9 +173,9 @@
       ];
     }
 
-    Uri output = toUri(module, jsId);
+    var output = toUri(module, jsId);
 
-    List<String> args = [
+    var args = [
       '--packages=${sdkRoot.toFilePath()}/.packages',
       _dartdevcScript,
       '--kernel',
@@ -245,7 +245,7 @@
     var wrapper =
         root.resolveUri(toUri(module, jsId)).toFilePath() + '.wrapper.js';
     await File(wrapper).writeAsString(runjs);
-    List<String> d8Args = ['--module', wrapper];
+    var d8Args = ['--module', wrapper];
     var result = await _runProcess(
         sdkRoot.resolve(_d8executable).toFilePath(), d8Args, root.toFilePath());
 
@@ -310,7 +310,7 @@
   if (module.isPackage) {
     packagesContents.write('${module.name}:${module.packageBase}\n');
   }
-  for (Module dependency in transitiveDependencies) {
+  for (var dependency in transitiveDependencies) {
     if (dependency.isPackage) {
       packagesContents.write('${dependency.name}:unused\n');
     }
@@ -335,9 +335,9 @@
 Future<void> _resolveScripts() async {
   Future<String> resolve(
       String sdkSourcePath, String relativeSnapshotPath) async {
-    String result = sdkRoot.resolve(sdkSourcePath).toFilePath();
+    var result = sdkRoot.resolve(sdkSourcePath).toFilePath();
     if (_options.useSdk) {
-      String snapshot = Uri.file(Platform.resolvedExecutable)
+      var snapshot = Uri.file(Platform.resolvedExecutable)
           .resolve(relativeSnapshotPath)
           .toFilePath();
       if (await File(snapshot).exists()) {
diff --git a/pkg/dev_compiler/test/nullable_inference_test.dart b/pkg/dev_compiler/test/nullable_inference_test.dart
index 2b1d6e0..683a872 100644
--- a/pkg/dev_compiler/test/nullable_inference_test.dart
+++ b/pkg/dev_compiler/test/nullable_inference_test.dart
@@ -498,7 +498,7 @@
       // against the underlying constant value instead.
       .map((e) {
         if (e is ConstantExpression) {
-          Constant c = e.constant;
+          var c = e.constant;
           if (c is DoubleConstant &&
               c.value.isFinite &&
               c.value.truncateToDouble() == c.value) {
@@ -669,10 +669,10 @@
       experiments: const {},
       environmentDefines: const {});
   if (!identical(oldCompilerState, _compilerState)) inference = null;
-  fe.DdcResult result =
+  var result =
       await fe.compile(_compilerState, [mainUri], diagnosticMessageHandler);
   expect(succeeded, true);
 
-  Set<Library> librariesFromDill = result.computeLibrariesFromDill();
+  var librariesFromDill = result.computeLibrariesFromDill();
   return CompileResult(result.component, librariesFromDill);
 }
diff --git a/pkg/dev_compiler/test/sourcemap/common.dart b/pkg/dev_compiler/test/sourcemap/common.dart
index bd3f485..3abc7ec 100644
--- a/pkg/dev_compiler/test/sourcemap/common.dart
+++ b/pkg/dev_compiler/test/sourcemap/common.dart
@@ -28,7 +28,7 @@
       return null;
     }
 
-    Data data = cleanupHelper.remove(description);
+    var data = cleanupHelper.remove(description);
     data?.outDir?.deleteSync(recursive: true);
     return null;
   }
@@ -44,7 +44,7 @@
 
   @override
   Future<Result<Data>> run(TestDescription input, ChainContext context) async {
-    Data data = Data()..uri = input.uri;
+    var data = Data()..uri = input.uri;
     if (context is ChainContextWithCleanupHelper) {
       context.cleanupHelper[input] = data;
     }
@@ -75,7 +75,7 @@
   @override
   Future<Result<Data>> run(Data data, ChainContext context) async {
     var outWrapperPath = p.join(data.outDir.path, 'wrapper.js');
-    ProcessResult runResult =
+    var runResult =
         runD8AndStep(data.outDir.path, data.code, ['--module', outWrapperPath]);
     data.d8Output = (runResult.stdout as String).split('\n');
     return pass(data);
@@ -101,7 +101,7 @@
   var outerDir = sdkRoot.path;
   for (var outDir in const ['out/ReleaseX64', 'xcodebuild/ReleaseX64']) {
     var tryPath = p.join(outerDir, outDir, relative);
-    File file = File(tryPath);
+    var file = File(tryPath);
     if (file.existsSync()) return file;
   }
   throw "Couldn't find $relative. Try building more targets.";
diff --git a/pkg/dev_compiler/test/sourcemap/ddc_common.dart b/pkg/dev_compiler/test/sourcemap/ddc_common.dart
index b7680de..7ea70ee 100644
--- a/pkg/dev_compiler/test/sourcemap/ddc_common.dart
+++ b/pkg/dev_compiler/test/sourcemap/ddc_common.dart
@@ -66,8 +66,8 @@
   @override
   Future<Result<Data>> run(Data data, ChainContext context) async {
     data.outDir = await Directory.systemTemp.createTemp('stacktrace-test');
-    String code = await File.fromUri(data.uri).readAsString();
-    Test test = processTestCode(code, knownMarkers);
+    var code = await File.fromUri(data.uri).readAsString();
+    var test = processTestCode(code, knownMarkers);
     await testStackTrace(test, marker, _compile,
         jsPreambles: _getPreambles,
         useJsMethodNamesOnAbsence: true,
@@ -98,10 +98,10 @@
   String _convertName(String name) {
     if (name == null) return null;
     // Hack for DDC naming scheme.
-    String result = name;
+    var result = name;
     if (result.startsWith('new ')) result = result.substring(4);
     if (result.startsWith('Object.')) result = result.substring(7);
-    String inputName =
+    var inputName =
         INPUT_FILE_NAME.substring(0, INPUT_FILE_NAME.indexOf('.') + 1);
     if (result.startsWith(inputName)) {
       result = result.substring(inputName.length);
@@ -113,10 +113,10 @@
 Directory _cachedDdcDir;
 Directory getDdcDir() {
   Directory search() {
-    Directory dir = File.fromUri(Platform.script).parent;
-    Uri dirUrl = dir.uri;
+    var dir = File.fromUri(Platform.script).parent;
+    var dirUrl = dir.uri;
     if (dirUrl.pathSegments.contains('dev_compiler')) {
-      for (int i = dirUrl.pathSegments.length - 2; i >= 0; --i) {
+      for (var i = dirUrl.pathSegments.length - 2; i >= 0; --i) {
         // Directory uri ends in empty string
         if (dirUrl.pathSegments[i] == 'dev_compiler') break;
         dir = dir.parent;
@@ -164,7 +164,7 @@
     String outputFilename, Uri outDir) {
   // For debugging via HTML, Chrome and ./pkg/test_runner/bin/http_server.dart.
   var sdkFile = File(p.relative(sdkJsFile.path, from: sdkRoot.path));
-  String jsRootDart = '/root_dart/${sdkFile.uri}';
+  var jsRootDart = '/root_dart/${sdkFile.uri}';
   File.fromUri(outputFile.resolve('$outputFilename.html.js')).writeAsStringSync(
       jsContent.replaceFirst("from 'dart_sdk.js'", "from '$jsRootDart'"));
   File.fromUri(outputFile.resolve('$outputFilename.html.html'))
diff --git a/pkg/dev_compiler/test/sourcemap/sourcemaps_ddk_suite.dart b/pkg/dev_compiler/test/sourcemap/sourcemaps_ddk_suite.dart
index 39ccc98..e2c3059 100644
--- a/pkg/dev_compiler/test/sourcemap/sourcemaps_ddk_suite.dart
+++ b/pkg/dev_compiler/test/sourcemap/sourcemaps_ddk_suite.dart
@@ -50,15 +50,15 @@
 
   @override
   Future<Null> run(Uri inputFile, Uri outputFile, Uri outWrapperFile) async {
-    Uri outDir = outputFile.resolve('.');
-    String outputFilename = outputFile.pathSegments.last;
+    var outDir = outputFile.resolve('.');
+    var outputFilename = outputFile.pathSegments.last;
 
-    File sdkJsFile = findInOutDir('gen/utils/dartdevc/kernel/es6/dart_sdk.js');
+    var sdkJsFile = findInOutDir('gen/utils/dartdevc/kernel/es6/dart_sdk.js');
     var jsSdkPath = sdkJsFile.uri;
 
-    File ddcSdkSummary = findInOutDir('ddc_sdk.dill');
+    var ddcSdkSummary = findInOutDir('ddc_sdk.dill');
 
-    List<String> args = <String>[
+    var args = <String>[
       "--packages=${sdkRoot.uri.resolve(".packages").toFilePath()}",
       '--modules=es6',
       '--dart-sdk-summary=${ddcSdkSummary.path}',
@@ -67,7 +67,7 @@
       inputFile.toFilePath()
     ];
 
-    bool succeeded = false;
+    var succeeded = false;
     try {
       var result = await compile(args, compilerState: context.compilerState);
       context.compilerState =
diff --git a/pkg/dev_compiler/test/sourcemap/testfiles/hello_class_call.dart b/pkg/dev_compiler/test/sourcemap/testfiles/hello_class_call.dart
index 53a6943..05bdd91 100644
--- a/pkg/dev_compiler/test/sourcemap/testfiles/hello_class_call.dart
+++ b/pkg/dev_compiler/test/sourcemap/testfiles/hello_class_call.dart
@@ -4,7 +4,7 @@
 
 void main() {
   /*bl*/
-  Foo foo = Foo();
+  var foo = Foo();
   foo.foo();
   /*nbb:0:1*/
 }
diff --git a/pkg/dev_compiler/test/sourcemap/testfiles/next_through_assign_call_test.dart b/pkg/dev_compiler/test/sourcemap/testfiles/next_through_assign_call_test.dart
index b4941e7..b46fd9a 100644
--- a/pkg/dev_compiler/test/sourcemap/testfiles/next_through_assign_call_test.dart
+++ b/pkg/dev_compiler/test/sourcemap/testfiles/next_through_assign_call_test.dart
@@ -11,7 +11,7 @@
   /*bc:3*/ print(b);
   a = /*bc:4*/ foo();
   /*bc:5*/ print(a);
-  int d = /*bc:6*/ foo();
+  var d = /*bc:6*/ foo();
   /*bc:7*/ print(d);
   int e = /*bc:8*/ foo(), f, g = /*bc:9*/ foo();
   /*bc:10*/ print(e);
diff --git a/pkg/dev_compiler/test/sourcemap/testfiles/next_through_assign_int_test.dart b/pkg/dev_compiler/test/sourcemap/testfiles/next_through_assign_int_test.dart
index 5a4452e..7a80ef3 100644
--- a/pkg/dev_compiler/test/sourcemap/testfiles/next_through_assign_int_test.dart
+++ b/pkg/dev_compiler/test/sourcemap/testfiles/next_through_assign_int_test.dart
@@ -12,7 +12,7 @@
   /*s:3*/ print(b);
   /*s:4*/ a = 42;
   /*s:5*/ print(a);
-  int d = /*s:6*/ 42;
+  var d = /*s:6*/ 42;
   /*s:7*/ print(d);
   int e = /*s:8*/ 41, f, g = /*s:9*/ 42;
   /*s:10*/ print(e);
diff --git a/pkg/dev_compiler/test/sourcemap/testfiles/next_through_for_each_loop_test.dart b/pkg/dev_compiler/test/sourcemap/testfiles/next_through_for_each_loop_test.dart
index d240819..20c74c1 100644
--- a/pkg/dev_compiler/test/sourcemap/testfiles/next_through_for_each_loop_test.dart
+++ b/pkg/dev_compiler/test/sourcemap/testfiles/next_through_for_each_loop_test.dart
@@ -4,10 +4,10 @@
 
 /*Debugger:stepOver*/
 void main() {
-  /*bl*/ /*sl:1*/ List<int> data = [1, 2, 3];
+  /*bl*/ /*sl:1*/ var data = [1, 2, 3];
   for (
       // comment forcing formatting
-      /*sl:3*/ /*sl:5*/ /*sl:7*/ /*sl:8*/ int datapoint
+      /*sl:3*/ /*sl:5*/ /*sl:7*/ /*sl:8*/ var datapoint
       // comment forcing formatting
       in
       // comment forcing formatting
diff --git a/pkg/dev_compiler/test/sourcemap/testfiles/next_through_for_loop_with_break_and_continue_test.dart b/pkg/dev_compiler/test/sourcemap/testfiles/next_through_for_loop_with_break_and_continue_test.dart
index f562c22..a3e6148 100644
--- a/pkg/dev_compiler/test/sourcemap/testfiles/next_through_for_loop_with_break_and_continue_test.dart
+++ b/pkg/dev_compiler/test/sourcemap/testfiles/next_through_for_loop_with_break_and_continue_test.dart
@@ -4,8 +4,8 @@
 
 /*Debugger:stepOver*/
 void main() {
-  /*bl*/ /*sl:1*/ int count = 0;
-  for (/*sl:2*/ int i = 0;
+  /*bl*/ /*sl:1*/ var count = 0;
+  for (/*sl:2*/ var i = 0;
       /*sl:3*/ /*sl:8*/ /*sl:13*/ /*sl:17*/ /*nbb:18:21*/ i < 42;
       /*sl:7*/ /*sl:12*/ /*sl:16*/ /*nbb:17:21*/ ++i) {
     /*sl:4*/ /*sl:9*/ /*sl:14*/ /*sl:18*/ /*nbb:19:21*/ if (i == 2) {
diff --git a/pkg/dev_compiler/test/sourcemap/testfiles/next_through_is_and_as_test.dart b/pkg/dev_compiler/test/sourcemap/testfiles/next_through_is_and_as_test.dart
index 45de474..93c9cde 100644
--- a/pkg/dev_compiler/test/sourcemap/testfiles/next_through_is_and_as_test.dart
+++ b/pkg/dev_compiler/test/sourcemap/testfiles/next_through_is_and_as_test.dart
@@ -20,7 +20,7 @@
   /*bc:9*/ if (hex is int) {
     /*bc:10*/ print('hex is int');
     // ignore: unnecessary_cast
-    int x = /*bc:11*/ hex as int;
+    var x = /*bc:11*/ hex as int;
     /*bc:12*/ if (x.isEven) {
       /*bc:13*/ print("it's even even!");
     } else {
diff --git a/pkg/dev_compiler/test/sourcemap/testfiles/next_through_operator_bracket_on_super_test.dart b/pkg/dev_compiler/test/sourcemap/testfiles/next_through_operator_bracket_on_super_test.dart
index 801b41e..4bdda3d 100644
--- a/pkg/dev_compiler/test/sourcemap/testfiles/next_through_operator_bracket_on_super_test.dart
+++ b/pkg/dev_compiler/test/sourcemap/testfiles/next_through_operator_bracket_on_super_test.dart
@@ -22,7 +22,7 @@
 }
 
 void main() {
-  Class3 c = Class3();
+  var c = Class3();
   c[42];
   c.code();
 }
diff --git a/pkg/dev_compiler/test/sourcemap/testfiles/next_through_operator_bracket_on_this_test.dart b/pkg/dev_compiler/test/sourcemap/testfiles/next_through_operator_bracket_on_this_test.dart
index d6c74bf..30d90f5 100644
--- a/pkg/dev_compiler/test/sourcemap/testfiles/next_through_operator_bracket_on_this_test.dart
+++ b/pkg/dev_compiler/test/sourcemap/testfiles/next_through_operator_bracket_on_this_test.dart
@@ -14,7 +14,7 @@
 }
 
 void main() {
-  Class2 c = Class2();
+  var c = Class2();
   c[42];
   c.code();
 }
diff --git a/pkg/dev_compiler/test/sourcemap/testfiles/next_through_operator_bracket_test.dart b/pkg/dev_compiler/test/sourcemap/testfiles/next_through_operator_bracket_test.dart
index 23c41eb..3171aba 100644
--- a/pkg/dev_compiler/test/sourcemap/testfiles/next_through_operator_bracket_test.dart
+++ b/pkg/dev_compiler/test/sourcemap/testfiles/next_through_operator_bracket_test.dart
@@ -14,7 +14,7 @@
 }
 
 void main() {
-  /*bl*/ /*sl:1*/ Class2 c = Class2();
+  /*bl*/ /*sl:1*/ var c = Class2();
   c /*sl:2*/ [42];
   c /*sl:3*/ .code();
 }
diff --git a/pkg/dev_compiler/test/sourcemap/testfiles/next_through_yield.dart b/pkg/dev_compiler/test/sourcemap/testfiles/next_through_yield.dart
index 882e28c..c141ab5 100644
--- a/pkg/dev_compiler/test/sourcemap/testfiles/next_through_yield.dart
+++ b/pkg/dev_compiler/test/sourcemap/testfiles/next_through_yield.dart
@@ -5,14 +5,14 @@
 /*Debugger:stepOver*/
 
 void main() {
-  for (int i in naturalsTo(2)) {
+  for (var i in naturalsTo(2)) {
     print(i);
   }
 }
 
 Iterable<int> naturalsTo(int n) sync* {
   /*bl*/
-  /*sl:1*/ int k = 0;
+  /*sl:1*/ var k = 0;
   /*sl:2*/ /*sl:4*/ /*sl:6*/ while (k < n) {
     yield /*bc:3*/ /*bc:5*/ foo(++k);
   }
diff --git a/pkg/dev_compiler/test/sourcemap/testfiles/no_mapping_on_class_constructor_line.dart b/pkg/dev_compiler/test/sourcemap/testfiles/no_mapping_on_class_constructor_line.dart
index 1806b0f..b5d935b 100644
--- a/pkg/dev_compiler/test/sourcemap/testfiles/no_mapping_on_class_constructor_line.dart
+++ b/pkg/dev_compiler/test/sourcemap/testfiles/no_mapping_on_class_constructor_line.dart
@@ -4,7 +4,7 @@
 
 void main() {
   // ignore: unused_local_variable
-  Foo foo = Foo();
+  var foo = Foo();
 }
 
 class Foo {
diff --git a/pkg/dev_compiler/test/sourcemap/testfiles/no_mapping_on_class_function_line.dart b/pkg/dev_compiler/test/sourcemap/testfiles/no_mapping_on_class_function_line.dart
index 6ec8512..8b3b281 100644
--- a/pkg/dev_compiler/test/sourcemap/testfiles/no_mapping_on_class_function_line.dart
+++ b/pkg/dev_compiler/test/sourcemap/testfiles/no_mapping_on_class_function_line.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 void main() {
-  Foo foo = Foo();
+  var foo = Foo();
   foo.foo();
 }
 
diff --git a/pkg/dev_compiler/test/sourcemap/testfiles/no_mapping_on_class_line.dart b/pkg/dev_compiler/test/sourcemap/testfiles/no_mapping_on_class_line.dart
index db93e37..f7943d6 100644
--- a/pkg/dev_compiler/test/sourcemap/testfiles/no_mapping_on_class_line.dart
+++ b/pkg/dev_compiler/test/sourcemap/testfiles/no_mapping_on_class_line.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 void main() {
-  Foo foo = Foo();
+  var foo = Foo();
   foo.foo();
 }
 
diff --git a/pkg/dev_compiler/test/sourcemap/testfiles/no_mapping_on_class_named_constructor_line.dart b/pkg/dev_compiler/test/sourcemap/testfiles/no_mapping_on_class_named_constructor_line.dart
index f4851ac..9c71302 100644
--- a/pkg/dev_compiler/test/sourcemap/testfiles/no_mapping_on_class_named_constructor_line.dart
+++ b/pkg/dev_compiler/test/sourcemap/testfiles/no_mapping_on_class_named_constructor_line.dart
@@ -4,7 +4,7 @@
 
 void main() {
   // ignore: unused_local_variable
-  Foo foo = Foo.named();
+  var foo = Foo.named();
 }
 
 class Foo {
diff --git a/pkg/dev_compiler/test/sourcemap/testfiles/printing_class_fields.dart b/pkg/dev_compiler/test/sourcemap/testfiles/printing_class_fields.dart
index 223bc0e..58fe7ef 100644
--- a/pkg/dev_compiler/test/sourcemap/testfiles/printing_class_fields.dart
+++ b/pkg/dev_compiler/test/sourcemap/testfiles/printing_class_fields.dart
@@ -5,7 +5,7 @@
 /*Debugger:stepOver*/
 void main() {
   /*bl*/
-  /*sl:1*/ Foo foo = Foo(1, 2);
+  /*sl:1*/ var foo = Foo(1, 2);
   /*sl:2*/ print(foo.x);
   /*sl:3*/ print(foo.y);
   /*sl:4*/ print(foo.z);
diff --git a/pkg/dev_compiler/test/sourcemap/testfiles/printing_class_fields_step_into.dart b/pkg/dev_compiler/test/sourcemap/testfiles/printing_class_fields_step_into.dart
index 9dd8d22..2b7406d 100644
--- a/pkg/dev_compiler/test/sourcemap/testfiles/printing_class_fields_step_into.dart
+++ b/pkg/dev_compiler/test/sourcemap/testfiles/printing_class_fields_step_into.dart
@@ -5,7 +5,7 @@
 /*nb*/
 void main() {
   /*bl*/
-  Foo foo = /*sl:1*/ Foo(1, 2);
+  var foo = /*sl:1*/ Foo(1, 2);
   /*s:5*/ print(foo.x);
   /*s:6*/ print(foo.y);
   /*s:7*/ print(foo.z);
diff --git a/pkg/dev_compiler/test/sourcemap/testfiles/step_through_property_get_test.dart b/pkg/dev_compiler/test/sourcemap/testfiles/step_through_property_get_test.dart
index c1f08b1..4bec5db 100644
--- a/pkg/dev_compiler/test/sourcemap/testfiles/step_through_property_get_test.dart
+++ b/pkg/dev_compiler/test/sourcemap/testfiles/step_through_property_get_test.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 void main() {
-  Bar bar = Bar();
+  var bar = Bar();
   bar.doStuff();
 }
 
diff --git a/pkg/dev_compiler/test/sourcemap/testfiles/step_through_sync_star.dart b/pkg/dev_compiler/test/sourcemap/testfiles/step_through_sync_star.dart
index 36768c1..4ce057b 100644
--- a/pkg/dev_compiler/test/sourcemap/testfiles/step_through_sync_star.dart
+++ b/pkg/dev_compiler/test/sourcemap/testfiles/step_through_sync_star.dart
@@ -5,13 +5,13 @@
 void main() {
   /* bl */
   /*sl:1*/ var iterator = naturalsTo(2);
-  for (int /*bc:3*/ /*bc:8*/ /*bc:12*/ i in /*bc:2*/ iterator) {
+  for (var /*bc:3*/ /*bc:8*/ /*bc:12*/ i in /*bc:2*/ iterator) {
     /*bc:7*/ /*bc:11*/ print(i);
   }
 }
 
 Iterable<int> naturalsTo(int n) sync* {
-  /*sl:4*/ int k = 0;
+  /*sl:4*/ var k = 0;
   /*sl:5*/ /*sl:9*/ /*sl:13*/ while (k < n) {
     /*nbb:0:6*/ /*sl:6*/ /*sl:10*/ yield ++k;
   }
diff --git a/pkg/dev_compiler/test/worker/worker_test.dart b/pkg/dev_compiler/test/worker/worker_test.dart
index 69ec023..4a650da 100644
--- a/pkg/dev_compiler/test/worker/worker_test.dart
+++ b/pkg/dev_compiler/test/worker/worker_test.dart
@@ -17,7 +17,7 @@
 File file(String path) => File(join(tmp.path, joinAll(path.split('/'))));
 
 void main() {
-  List<String> baseArgs = [];
+  var baseArgs = <String>[];
   final binDir = dirname(Platform.resolvedExecutable);
   // Note, the bots use the dart binary in the top-level build directory.
   // On windows, this is a .bat file.
diff --git a/pkg/dev_compiler/tool/check_nnbd_sdk.dart b/pkg/dev_compiler/tool/check_nnbd_sdk.dart
index 9b52d5f..1dc3bde 100644
--- a/pkg/dev_compiler/tool/check_nnbd_sdk.dart
+++ b/pkg/dev_compiler/tool/check_nnbd_sdk.dart
@@ -31,7 +31,7 @@
   var sdkDir = baseUri.resolve('sdk/').toFilePath();
   print('Generating a patched sdk at ${baseUri.path}');
 
-  Uri librariesJson = args['libraries'] != null
+  var librariesJson = args['libraries'] != null
       ? resolveInputUri(args['libraries'] as String)
       : Platform.script.resolve('../../../sdk_nnbd/lib/libraries.json');
   var target = args['target'] as String;
@@ -112,9 +112,9 @@
       var toAdd = <String>[];
       var toRemove = <String>[];
       var goldenList = golden.trim().split('\n');
-      int i = 0, j = 0;
+      var i = 0, j = 0;
       for (; i < errorList.length && j < goldenList.length;) {
-        int compare = errorList[i].compareTo(goldenList[j]);
+        var compare = errorList[i].compareTo(goldenList[j]);
         if (compare == 0) {
           i++;
           j++;
diff --git a/pkg/dev_compiler/tool/dart2js_nnbd_sdk_error_golden.txt b/pkg/dev_compiler/tool/dart2js_nnbd_sdk_error_golden.txt
index 62cba23..65bb306 100644
--- a/pkg/dev_compiler/tool/dart2js_nnbd_sdk_error_golden.txt
+++ b/pkg/dev_compiler/tool/dart2js_nnbd_sdk_error_golden.txt
@@ -1,13 +1,13 @@
-ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1655|7|5|Superinterfaces don't have a valid override for '&': int.& (&), JSNumber.& (&).
-ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1655|7|5|Superinterfaces don't have a valid override for '<<': int.<< (<<), JSNumber.<< (<<).
-ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1655|7|5|Superinterfaces don't have a valid override for '>>': int.>> (>>), JSNumber.>> (>>).
-ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1655|7|5|Superinterfaces don't have a valid override for '\|': int.\| (\|), JSNumber.\| (\|).
-ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1655|7|5|Superinterfaces don't have a valid override for '^': int.^ (^), JSNumber.^ (^).
+ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1655|7|5|Superinterfaces don't have a valid override for '&': int.& (int Function(int)), JSNumber.& (num Function(num)).
+ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1655|7|5|Superinterfaces don't have a valid override for '<<': int.<< (int Function(int)), JSNumber.<< (num Function(num)).
+ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1655|7|5|Superinterfaces don't have a valid override for '>>': int.>> (int Function(int)), JSNumber.>> (num Function(num)).
+ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1655|7|5|Superinterfaces don't have a valid override for '\|': int.\| (int Function(int)), JSNumber.\| (num Function(num)).
+ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1655|7|5|Superinterfaces don't have a valid override for '^': int.^ (int Function(int)), JSNumber.^ (num Function(num)).
 ERROR|COMPILE_TIME_ERROR|INVALID_OVERRIDE|lib/_internal/js_runtime/lib/interceptors.dart|1153|7|14|'JSArray.[]=' ('void Function(int, E)') isn't a valid override of 'JSMutableIndexable.[]=' ('void Function(int, dynamic)').
 ERROR|COMPILE_TIME_ERROR|INVALID_OVERRIDE|lib/_internal/js_runtime/lib/interceptors.dart|1155|7|12|'JSArray.[]=' ('void Function(int, E)') isn't a valid override of 'JSMutableIndexable.[]=' ('void Function(int, dynamic)').
 ERROR|COMPILE_TIME_ERROR|INVALID_OVERRIDE|lib/_internal/js_runtime/lib/interceptors.dart|1157|7|17|'JSArray.[]=' ('void Function(int, E)') isn't a valid override of 'JSMutableIndexable.[]=' ('void Function(int, dynamic)').
-ERROR|COMPILE_TIME_ERROR|INVALID_OVERRIDE|lib/_internal/js_runtime/lib/native_typed_data.dart|708|17|3|'NativeTypedArrayOfDouble.[]=' ('void Function(int, double)') isn't a valid override of 'JSMutableIndexable.[]=' ('void Function(int, dynamic)').
-ERROR|COMPILE_TIME_ERROR|INVALID_OVERRIDE|lib/_internal/js_runtime/lib/native_typed_data.dart|729|17|3|'NativeTypedArrayOfInt.[]=' ('void Function(int, int)') isn't a valid override of 'JSMutableIndexable.[]=' ('void Function(int, dynamic)').
+ERROR|COMPILE_TIME_ERROR|INVALID_OVERRIDE|lib/_internal/js_runtime/lib/native_typed_data.dart|703|17|3|'NativeTypedArrayOfDouble.[]=' ('void Function(int, double)') isn't a valid override of 'JSMutableIndexable.[]=' ('void Function(int*, dynamic)*').
+ERROR|COMPILE_TIME_ERROR|INVALID_OVERRIDE|lib/_internal/js_runtime/lib/native_typed_data.dart|724|17|3|'NativeTypedArrayOfInt.[]=' ('void Function(int, int)') isn't a valid override of 'JSMutableIndexable.[]=' ('void Function(int*, dynamic)*').
 ERROR|COMPILE_TIME_ERROR|INVALID_OVERRIDE|lib/js/js.dart|351|17|3|'JsArray.[]=' ('void Function(dynamic, E)') isn't a valid override of 'JsObject.[]=' ('void Function(dynamic, dynamic)').
 ERROR|STATIC_TYPE_WARNING|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1672|28|1|The operator '&' isn't defined for the type 'JSInt'.
 ERROR|STATIC_TYPE_WARNING|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1674|27|1|The operator '&' isn't defined for the type 'JSInt'.
@@ -97,8 +97,3 @@
 ERROR|STATIC_WARNING|FINAL_NOT_INITIALIZED_CONSTRUCTOR|lib/svg/dart2js/svg_dart2js.dart|881|3|24|All final variables must be initialized, but 'diffuseConstant', 'height', and 8 others are not.
 ERROR|STATIC_WARNING|FINAL_NOT_INITIALIZED_CONSTRUCTOR|lib/svg/dart2js/svg_dart2js.dart|934|3|24|All final variables must be initialized, but 'height', 'in1', and 8 others are not.
 ERROR|STATIC_WARNING|FINAL_NOT_INITIALIZED_CONSTRUCTOR|lib/svg/dart2js/svg_dart2js.dart|996|3|21|All final variables must be initialized, but 'azimuth' and 'elevation' are not.
-ERROR|STATIC_WARNING|FINAL_NOT_INITIALIZED|lib/_internal/js_runtime/lib/native_typed_data.dart|31|13|13|The final variable 'lengthInBytes' must be initialized.
-ERROR|STATIC_WARNING|FINAL_NOT_INITIALIZED|lib/_internal/js_runtime/lib/native_typed_data.dart|320|20|6|The final variable 'buffer' must be initialized.
-ERROR|STATIC_WARNING|FINAL_NOT_INITIALIZED|lib/_internal/js_runtime/lib/native_typed_data.dart|324|13|13|The final variable 'lengthInBytes' must be initialized.
-ERROR|STATIC_WARNING|FINAL_NOT_INITIALIZED|lib/_internal/js_runtime/lib/native_typed_data.dart|328|13|13|The final variable 'offsetInBytes' must be initialized.
-ERROR|STATIC_WARNING|FINAL_NOT_INITIALIZED|lib/_internal/js_runtime/lib/native_typed_data.dart|333|13|18|The final variable 'elementSizeInBytes' must be initialized.
diff --git a/pkg/dev_compiler/tool/dartdevc_nnbd_sdk_error_golden.txt b/pkg/dev_compiler/tool/dartdevc_nnbd_sdk_error_golden.txt
index 7ac9295..2aae401 100644
--- a/pkg/dev_compiler/tool/dartdevc_nnbd_sdk_error_golden.txt
+++ b/pkg/dev_compiler/tool/dartdevc_nnbd_sdk_error_golden.txt
@@ -7,9 +7,10 @@
 ERROR|COMPILE_TIME_ERROR|INVALID_OVERRIDE|lib/html/dart2js/html_dart2js.dart|19361|11|18|'InputElement.selectionDirection' ('String? Function()') isn't a valid override of 'TextInputElementBase.selectionDirection' ('String Function()').
 ERROR|COMPILE_TIME_ERROR|INVALID_OVERRIDE|lib/html/dart2js/html_dart2js.dart|19363|8|12|'InputElement.selectionEnd' ('int? Function()') isn't a valid override of 'TextInputElementBase.selectionEnd' ('int Function()').
 ERROR|COMPILE_TIME_ERROR|INVALID_OVERRIDE|lib/html/dart2js/html_dart2js.dart|19365|8|14|'InputElement.selectionStart' ('int? Function()') isn't a valid override of 'TextInputElementBase.selectionStart' ('int Function()').
-ERROR|COMPILE_TIME_ERROR|INVALID_OVERRIDE|lib/html/dart2js/html_dart2js.dart|33119|19|6|'Window.opener' ('WindowBase? Function()') isn't a valid override of 'WindowBase.opener' ('WindowBase Function()').
-ERROR|COMPILE_TIME_ERROR|INVALID_OVERRIDE|lib/html/dart2js/html_dart2js.dart|33191|19|6|'Window.parent' ('WindowBase? Function()') isn't a valid override of 'WindowBase.parent' ('WindowBase Function()').
-ERROR|COMPILE_TIME_ERROR|INVALID_OVERRIDE|lib/html/dart2js/html_dart2js.dart|33378|19|3|'Window.top' ('WindowBase? Function()') isn't a valid override of 'WindowBase.top' ('WindowBase Function()').
+ERROR|COMPILE_TIME_ERROR|INVALID_OVERRIDE|lib/html/dart2js/html_dart2js.dart|34277|7|18|'_WrappedEvent._selector' ('String? Function()') isn't a valid override of 'Event._selector' ('String Function()').
+ERROR|COMPILE_TIME_ERROR|INVALID_OVERRIDE|lib/html/dart2js/html_dart2js.dart|34300|29|9|'_BeforeUnloadEventStreamProvider.forTarget' ('Stream<BeforeUnloadEvent> Function(EventTarget, {bool useCapture})') isn't a valid override of 'EventStreamProvider.forTarget' ('Stream<BeforeUnloadEvent> Function(EventTarget?, {bool useCapture})').
+ERROR|COMPILE_TIME_ERROR|INVALID_OVERRIDE|lib/html/dart2js/html_dart2js.dart|40984|7|8|'_WrappedEvent._selector' ('String? Function()') isn't a valid override of 'Event._selector' ('String Function()').
+ERROR|COMPILE_TIME_ERROR|INVALID_OVERRIDE|lib/html/dart2js/html_dart2js.dart|41230|11|9|'_WrappedEvent._selector' ('String? Function()') isn't a valid override of 'Event._selector' ('String Function()').
 ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|10275|15|10|The parameter 'extendsTag' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
 ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|10281|49|13|The parameter 'typeExtension' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
 ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|10298|15|13|The parameter 'typeExtension' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
@@ -105,28 +106,7 @@
 ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|32371|19|13|The parameter 'relatedTarget' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
 ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|32606|52|7|The parameter 'options' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
 ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|34231|25|16|The parameter 'creationCallback' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
-ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|39886|35|9|The parameter 'uriPolicy' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
-ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|39899|31|9|The parameter 'uriPolicy' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
-ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|39940|34|7|The parameter 'tagName' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
-ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|39958|30|9|The parameter 'uriPolicy' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
-ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|39977|18|9|The parameter 'uriPolicy' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
-ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|39979|24|13|The parameter 'uriAttributes' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
-ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|40002|18|9|The parameter 'uriPolicy' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
-ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|40003|24|10|The parameter 'attributes' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
-ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|40004|24|13|The parameter 'uriAttributes' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
-ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|40020|18|9|The parameter 'uriPolicy' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
-ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|40021|24|10|The parameter 'attributes' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
-ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|40022|24|13|The parameter 'uriAttributes' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
-ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|40139|25|15|The parameter 'allowedElements' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
-ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|40140|24|17|The parameter 'allowedAttributes' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
-ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|40141|24|20|The parameter 'allowedUriAttributes' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
-ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|40667|69|7|The parameter 'options' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
-ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|40882|17|10|The parameter 'useCapture' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
-ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|40895|17|10|The parameter 'useCapture' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
-ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|41038|15|4|The parameter 'view' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
-ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|41048|19|13|The parameter 'currentTarget' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
 ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|4113|63|8|The parameter 'priority' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
-ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|41377|36|9|The parameter 'uriPolicy' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
 ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|5292|63|8|The parameter 'priority' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
 ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/html/dart2js/html_dart2js.dart|8836|60|6|The parameter 'detail' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
 ERROR|COMPILE_TIME_ERROR|MISSING_DEFAULT_VALUE_FOR_PARAMETER|lib/indexed_db/dart2js/indexed_db_dart2js.dart|234|21|3|The parameter 'key' can't have a value of 'null' because of its type, so it must either be a required parameter or have a default value.
@@ -157,11 +137,6 @@
 ERROR|COMPILE_TIME_ERROR|NOT_ASSIGNED_POTENTIALLY_NON_NULLABLE_LOCAL_VARIABLE|lib/html/dart2js/html_dart2js.dart|16899|13|10|The non-nullable local variable 'controller' must be assigned before it can be used.
 ERROR|COMPILE_TIME_ERROR|NOT_ASSIGNED_POTENTIALLY_NON_NULLABLE_LOCAL_VARIABLE|lib/html/dart2js/html_dart2js.dart|16903|18|7|The non-nullable local variable 'watchId' must be assigned before it can be used.
 ERROR|COMPILE_TIME_ERROR|NOT_ASSIGNED_POTENTIALLY_NON_NULLABLE_LOCAL_VARIABLE|lib/html/dart2js/html_dart2js.dart|16904|23|7|The non-nullable local variable 'watchId' must be assigned before it can be used.
-ERROR|COMPILE_TIME_ERROR|NOT_ASSIGNED_POTENTIALLY_NON_NULLABLE_LOCAL_VARIABLE|lib/html/dart2js/html_dart2js.dart|40689|60|4|The non-nullable local variable 'type' must be assigned before it can be used.
-ERROR|COMPILE_TIME_ERROR|NOT_ASSIGNED_POTENTIALLY_NON_NULLABLE_LOCAL_VARIABLE|lib/html/dart2js/html_dart2js.dart|40691|29|4|The non-nullable local variable 'type' must be assigned before it can be used.
-ERROR|COMPILE_TIME_ERROR|NOT_ASSIGNED_POTENTIALLY_NON_NULLABLE_LOCAL_VARIABLE|lib/html/dart2js/html_dart2js.dart|40696|58|4|The non-nullable local variable 'type' must be assigned before it can be used.
-ERROR|COMPILE_TIME_ERROR|NOT_ASSIGNED_POTENTIALLY_NON_NULLABLE_LOCAL_VARIABLE|lib/html/dart2js/html_dart2js.dart|40698|31|4|The non-nullable local variable 'type' must be assigned before it can be used.
-ERROR|COMPILE_TIME_ERROR|NOT_ASSIGNED_POTENTIALLY_NON_NULLABLE_LOCAL_VARIABLE|lib/html/dart2js/html_dart2js.dart|40707|29|4|The non-nullable local variable 'type' must be assigned before it can be used.
 ERROR|COMPILE_TIME_ERROR|NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|115|3|11|Non-nullable instance field 'nonce' must be initialized.
 ERROR|COMPILE_TIME_ERROR|NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|12627|3|7|Non-nullable instance field '_defaultSanitizer' must be initialized.
 ERROR|COMPILE_TIME_ERROR|NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|12627|3|7|Non-nullable instance field '_defaultValidator' must be initialized.
@@ -169,21 +144,6 @@
 ERROR|COMPILE_TIME_ERROR|NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|12627|3|7|Non-nullable instance field '_parseRange' must be initialized.
 ERROR|COMPILE_TIME_ERROR|NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|12627|3|7|Non-nullable instance field 'innerText' must be initialized.
 ERROR|COMPILE_TIME_ERROR|NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|34280|3|18|Non-nullable instance field '_returnValue' must be initialized.
-ERROR|COMPILE_TIME_ERROR|NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|36952|3|19|Non-nullable instance field '_elementList' must be initialized.
-ERROR|COMPILE_TIME_ERROR|NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|37563|3|9|Non-nullable instance field '_unit' must be initialized.
-ERROR|COMPILE_TIME_ERROR|NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|37563|3|9|Non-nullable instance field '_value' must be initialized.
-ERROR|COMPILE_TIME_ERROR|NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|37923|3|22|Non-nullable instance field '_streamController' must be initialized.
-ERROR|COMPILE_TIME_ERROR|NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|37923|3|22|Non-nullable instance field '_type' must be initialized.
-ERROR|COMPILE_TIME_ERROR|NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|37977|3|11|Non-nullable instance field '_controller' must be initialized.
-ERROR|COMPILE_TIME_ERROR|NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|39520|3|21|Non-nullable instance field '_stream' must be initialized.
-ERROR|COMPILE_TIME_ERROR|NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|40430|3|21|Non-nullable instance field '_current' must be initialized.
-ERROR|COMPILE_TIME_ERROR|NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|40456|3|25|Non-nullable instance field '_current' must be initialized.
-ERROR|COMPILE_TIME_ERROR|NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|41028|3|8|Non-nullable instance field '_currentTarget' must be initialized.
-ERROR|COMPILE_TIME_ERROR|NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|41028|3|8|Non-nullable instance field '_parent' must be initialized.
-ERROR|COMPILE_TIME_ERROR|NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|41028|3|8|Non-nullable instance field '_shadowAltKey' must be initialized.
-ERROR|COMPILE_TIME_ERROR|NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|41028|3|8|Non-nullable instance field '_shadowCharCode' must be initialized.
-ERROR|COMPILE_TIME_ERROR|NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|41028|3|8|Non-nullable instance field '_shadowKeyCode' must be initialized.
-ERROR|COMPILE_TIME_ERROR|NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|41218|3|13|Non-nullable instance field '_selector' must be initialized.
 ERROR|COMPILE_TIME_ERROR|NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|5283|3|23|Non-nullable instance field '_elementCssStyleDeclarationSetIterable' must be initialized.
 ERROR|COMPILE_TIME_ERROR|NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD|lib/html/dart2js/html_dart2js.dart|19472|8|9|Non-nullable instance field 'autofocus' must be initialized.
 ERROR|COMPILE_TIME_ERROR|NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD|lib/html/dart2js/html_dart2js.dart|19474|8|8|Non-nullable instance field 'disabled' must be initialized.
@@ -209,7 +169,6 @@
 ERROR|COMPILE_TIME_ERROR|NOT_INITIALIZED_NON_NULLABLE_VARIABLE|lib/html/dart2js/html_dart2js.dart|13533|16|11|The non-nullable variable '_parseRange' must be initialized.
 ERROR|COMPILE_TIME_ERROR|NOT_INITIALIZED_NON_NULLABLE_VARIABLE|lib/html/dart2js/html_dart2js.dart|13534|31|17|The non-nullable variable '_defaultValidator' must be initialized.
 ERROR|COMPILE_TIME_ERROR|NOT_INITIALIZED_NON_NULLABLE_VARIABLE|lib/html/dart2js/html_dart2js.dart|13535|35|17|The non-nullable variable '_defaultSanitizer' must be initialized.
-ERROR|STATIC_TYPE_WARNING|FOR_IN_OF_INVALID_ELEMENT_TYPE|lib/html/dart2js/html_dart2js.dart|37442|26|8|The type 'Iterable<Object>' used in the 'for' loop must implement Iterable with a type argument that can be assigned to 'String'.
 ERROR|STATIC_TYPE_WARNING|INVALID_ASSIGNMENT|lib/html/dart2js/html_dart2js.dart|11762|22|27|A value of type 'Element?' can't be assigned to a variable of type 'Element'.
 ERROR|STATIC_TYPE_WARNING|INVALID_ASSIGNMENT|lib/html/dart2js/html_dart2js.dart|11768|22|26|A value of type 'Element?' can't be assigned to a variable of type 'Element'.
 ERROR|STATIC_TYPE_WARNING|INVALID_ASSIGNMENT|lib/html/dart2js/html_dart2js.dart|12817|25|10|A value of type 'String?' can't be assigned to a variable of type 'String'.
@@ -238,20 +197,6 @@
 ERROR|STATIC_TYPE_WARNING|INVALID_ASSIGNMENT|lib/html/dart2js/html_dart2js.dart|30311|19|34|A value of type 'Event' can't be assigned to a variable of type 'TextEvent'.
 ERROR|STATIC_TYPE_WARNING|INVALID_ASSIGNMENT|lib/html/dart2js/html_dart2js.dart|31182|17|32|A value of type 'Event' can't be assigned to a variable of type 'UIEvent'.
 ERROR|STATIC_TYPE_WARNING|INVALID_ASSIGNMENT|lib/html/dart2js/html_dart2js.dart|3239|26|41|A value of type 'Event' can't be assigned to a variable of type 'CompositionEvent'.
-ERROR|STATIC_TYPE_WARNING|INVALID_ASSIGNMENT|lib/html/dart2js/html_dart2js.dart|36328|20|13|A value of type 'Node' can't be assigned to a variable of type '_Attr'.
-ERROR|STATIC_TYPE_WARNING|INVALID_ASSIGNMENT|lib/html/dart2js/html_dart2js.dart|36341|20|13|A value of type 'Node' can't be assigned to a variable of type '_Attr'.
-ERROR|STATIC_TYPE_WARNING|INVALID_ASSIGNMENT|lib/html/dart2js/html_dart2js.dart|37843|15|4|A value of type 'Null' can't be assigned to a variable of type 'EventTarget'.
-ERROR|STATIC_TYPE_WARNING|INVALID_ASSIGNMENT|lib/html/dart2js/html_dart2js.dart|37844|15|4|A value of type 'Null' can't be assigned to a variable of type 'dynamic Function(Event)'.
-ERROR|STATIC_TYPE_WARNING|INVALID_ASSIGNMENT|lib/html/dart2js/html_dart2js.dart|37856|15|95|A value of type 'void Function(Event)?' can't be assigned to a variable of type 'dynamic Function(Event)'.
-ERROR|STATIC_TYPE_WARNING|INVALID_ASSIGNMENT|lib/html/dart2js/html_dart2js.dart|39773|26|38|A value of type 'int?' can't be assigned to a variable of type 'int'.
-ERROR|STATIC_TYPE_WARNING|INVALID_ASSIGNMENT|lib/html/dart2js/html_dart2js.dart|39782|30|4|A value of type 'Null' can't be assigned to a variable of type 'KeyboardEvent'.
-ERROR|STATIC_TYPE_WARNING|INVALID_ASSIGNMENT|lib/html/dart2js/html_dart2js.dart|40442|16|4|A value of type 'Null' can't be assigned to a variable of type 'T'.
-ERROR|STATIC_TYPE_WARNING|INVALID_ASSIGNMENT|lib/html/dart2js/html_dart2js.dart|40467|16|4|A value of type 'Null' can't be assigned to a variable of type 'T'.
-ERROR|STATIC_TYPE_WARNING|INVALID_ASSIGNMENT|lib/html/dart2js/html_dart2js.dart|40844|28|4|A value of type 'Null' can't be assigned to a variable of type 'List<dynamic>'.
-ERROR|STATIC_TYPE_WARNING|INVALID_ASSIGNMENT|lib/html/dart2js/html_dart2js.dart|41033|22|21|A value of type 'EventTarget?' can't be assigned to a variable of type 'EventTarget'.
-ERROR|STATIC_TYPE_WARNING|INVALID_ASSIGNMENT|lib/html/dart2js/html_dart2js.dart|41268|29|18|A value of type 'EventTarget' can't be assigned to a variable of type 'Element'.
-ERROR|STATIC_TYPE_WARNING|INVALID_ASSIGNMENT|lib/html/dart2js/html_dart2js.dart|41269|22|11|A value of type 'EventTarget' can't be assigned to a variable of type 'Element'.
-ERROR|STATIC_TYPE_WARNING|INVALID_ASSIGNMENT|lib/html/dart2js/html_dart2js.dart|41273|16|13|A value of type 'Element?' can't be assigned to a variable of type 'Element'.
 ERROR|STATIC_TYPE_WARNING|INVALID_ASSIGNMENT|lib/html/dart2js/html_dart2js.dart|8837|27|36|A value of type 'Event' can't be assigned to a variable of type 'CustomEvent'.
 ERROR|STATIC_TYPE_WARNING|INVALID_ASSIGNMENT|lib/svg/dart2js/svg_dart2js.dart|3138|31|16|A value of type 'Node' can't be assigned to a variable of type 'SvgElement'.
 ERROR|STATIC_TYPE_WARNING|INVALID_ASSIGNMENT|lib/svg/dart2js/svg_dart2js.dart|3145|31|16|A value of type 'Node' can't be assigned to a variable of type 'SvgElement'.
@@ -277,28 +222,8 @@
 ERROR|STATIC_TYPE_WARNING|RETURN_OF_INVALID_TYPE|lib/html/dart2js/html_dart2js.dart|29916|45|18|A value of type 'HtmlElement' can't be returned from method 'insertCell' because it has a return type of 'TableCellElement'.
 ERROR|STATIC_TYPE_WARNING|RETURN_OF_INVALID_TYPE|lib/html/dart2js/html_dart2js.dart|29979|43|17|A value of type 'HtmlElement' can't be returned from method 'insertRow' because it has a return type of 'TableRowElement'.
 ERROR|STATIC_TYPE_WARNING|RETURN_OF_INVALID_TYPE|lib/html/dart2js/html_dart2js.dart|35143|12|4|A value of type 'Null' can't be returned from method 'intersection' because it has a return type of 'Rectangle<num>'.
-ERROR|STATIC_TYPE_WARNING|RETURN_OF_INVALID_TYPE|lib/html/dart2js/html_dart2js.dart|36307|12|9|A value of type 'String?' can't be returned from method 'putIfAbsent' because it has a return type of 'String'.
-ERROR|STATIC_TYPE_WARNING|RETURN_OF_INVALID_TYPE|lib/html/dart2js/html_dart2js.dart|37188|12|4|A value of type 'Null' can't be returned from method 'intersection' because it has a return type of 'Rectangle<num>'.
-ERROR|STATIC_TYPE_WARNING|RETURN_OF_INVALID_TYPE|lib/html/dart2js/html_dart2js.dart|37839|27|4|A value of type 'Null' can't be returned from method 'cancel' because it has a return type of 'Future<dynamic>'.
-ERROR|STATIC_TYPE_WARNING|RETURN_OF_INVALID_TYPE|lib/html/dart2js/html_dart2js.dart|37845|12|4|A value of type 'Null' can't be returned from method 'cancel' because it has a return type of 'Future<dynamic>'.
-ERROR|STATIC_TYPE_WARNING|RETURN_OF_INVALID_TYPE|lib/html/dart2js/html_dart2js.dart|40338|31|12|A value of type 'Node' can't be returned from method '[]' because it has a return type of 'E'.
-ERROR|STATIC_TYPE_WARNING|RETURN_OF_INVALID_TYPE|lib/html/dart2js/html_dart2js.dart|40360|28|21|A value of type 'Node' can't be returned from method 'removeAt' because it has a return type of 'E'.
-ERROR|STATIC_TYPE_WARNING|RETURN_OF_INVALID_TYPE|lib/html/dart2js/html_dart2js.dart|40485|7|68|A value of type 'MemoryInfo?' can't be returned from function 'memory' because it has a return type of 'MemoryInfo'.
-ERROR|STATIC_TYPE_WARNING|RETURN_OF_INVALID_TYPE|lib/html/dart2js/html_dart2js.dart|40565|27|4|A value of type 'Null' can't be returned from function '_convertNativeToDart_Window' because it has a return type of 'WindowBase'.
-ERROR|STATIC_TYPE_WARNING|RETURN_OF_INVALID_TYPE|lib/html/dart2js/html_dart2js.dart|40571|12|4|A value of type 'Null' can't be returned from function '_convertNativeToDart_EventTarget' because it has a return type of 'EventTarget'.
-ERROR|STATIC_TYPE_WARNING|RETURN_OF_INVALID_TYPE|lib/html/dart2js/html_dart2js.dart|40582|12|4|A value of type 'Null' can't be returned from function '_convertNativeToDart_EventTarget' because it has a return type of 'EventTarget'.
-ERROR|STATIC_TYPE_WARNING|RETURN_OF_INVALID_TYPE|lib/html/dart2js/html_dart2js.dart|41149|22|12|A value of type 'WindowBase?' can't be returned from function 'view' because it has a return type of 'Window'.
-ERROR|STATIC_TYPE_WARNING|RETURN_OF_INVALID_TYPE|lib/html/dart2js/html_dart2js.dart|41226|36|21|A value of type 'EventTarget?' can't be returned from function 'currentTarget' because it has a return type of 'EventTarget'.
-ERROR|STATIC_TYPE_WARNING|RETURN_OF_INVALID_TYPE|lib/html/dart2js/html_dart2js.dart|41234|29|14|A value of type 'EventTarget?' can't be returned from function 'target' because it has a return type of 'EventTarget'.
-ERROR|STATIC_TYPE_WARNING|RETURN_OF_INVALID_TYPE|lib/html/dart2js/html_dart2js.dart|41236|27|17|A value of type 'num' can't be returned from function 'timeStamp' because it has a return type of 'double'.
-ERROR|STATIC_TYPE_WARNING|RETURN_OF_INVALID_TYPE|lib/html/dart2js/html_dart2js.dart|41288|26|12|A value of type 'List<EventTarget>' can't be returned from function 'path' because it has a return type of 'List<Node>'.
-ERROR|STATIC_TYPE_WARNING|RETURN_OF_INVALID_TYPE|lib/html/dart2js/html_dart2js.dart|41301|32|4|A value of type 'Null' can't be returned from function '_wrapZone' because it has a return type of 'void Function(T)'.
-ERROR|STATIC_TYPE_WARNING|RETURN_OF_INVALID_TYPE|lib/html/dart2js/html_dart2js.dart|41308|32|4|A value of type 'Null' can't be returned from function '_wrapBinaryZone' because it has a return type of 'void Function(T1, T2)'.
 ERROR|STATIC_TYPE_WARNING|RETURN_OF_INVALID_TYPE|lib/svg/dart2js/svg_dart2js.dart|3107|7|59|A value of type 'Element' can't be returned from function 'tag' because it has a return type of 'SvgElement'.
-ERROR|STATIC_TYPE_WARNING|RETURN_OF_INVALID_TYPE|lib/svg/dart2js/svg_dart2js.dart|33|12|4|A value of type 'Element' can't be returned from method 'createSvgElement_tag' because it has a return type of 'SvgElement'.
 ERROR|STATIC_TYPE_WARNING|RETURN_OF_INVALID_TYPE|lib/web_audio/dart2js/web_audio_dart2js.dart|249|14|59|A value of type 'Future<dynamic>' can't be returned from method 'decodeAudioData' because it has a return type of 'Future<AudioBuffer>'.
-ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/_internal/js_dev_runtime/private/interceptors.dart|689|52|1|The argument type 'Object?' can't be assigned to the parameter type 'Comparable<dynamic>'.
-ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/_internal/js_dev_runtime/private/interceptors.dart|689|55|1|The argument type 'Object?' can't be assigned to the parameter type 'Comparable<dynamic>'.
 ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|13066|60|4|The argument type 'Null' can't be assigned to the parameter type 'String'.
 ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|13498|40|24|The argument type 'Element?' can't be assigned to the parameter type 'Element'.
 ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|16933|48|13|The argument type 'void Function(PositionError)?' can't be assigned to the parameter type 'void Function(PositionError)'.
@@ -320,35 +245,14 @@
 ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|31084|57|4|The argument type 'Null' can't be assigned to the parameter type 'NodeFilter'.
 ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|34222|13|3|The argument type 'num' can't be assigned to the parameter type 'int'.
 ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|34222|18|3|The argument type 'num' can't be assigned to the parameter type 'int'.
-ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|36319|14|5|The argument type 'String?' can't be assigned to the parameter type 'String'.
-ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|36374|35|3|The argument type 'Object?' can't be assigned to the parameter type 'String'.
-ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|36378|34|3|The argument type 'Object?' can't be assigned to the parameter type 'String'.
-ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|36422|49|3|The argument type 'Object?' can't be assigned to the parameter type 'String'.
-ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|36426|48|3|The argument type 'Object?' can't be assigned to the parameter type 'String'.
-ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|36485|66|3|The argument type 'Object?' can't be assigned to the parameter type 'String'.
-ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|36487|57|3|The argument type 'Object?' can't be assigned to the parameter type 'String'.
-ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|36496|59|3|The argument type 'Object?' can't be assigned to the parameter type 'String'.
-ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|37348|32|5|The argument type 'Object?' can't be assigned to the parameter type 'Object'.
-ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|37368|26|8|The argument type 'Iterable<Object?>' can't be assigned to the parameter type 'Iterable<Object>'.
-ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|37736|40|6|The argument type 'void Function(T)?' can't be assigned to the parameter type 'void Function(T)'.
-ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|39946|34|4|The argument type 'Null' can't be assigned to the parameter type 'UriPolicy'.
-ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|39990|36|5|The argument type 'Iterable<String>?' can't be assigned to the parameter type 'Iterable<String>'.
-ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|39990|43|8|The argument type 'Iterable<String>?' can't be assigned to the parameter type 'Iterable<String>'.
-ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|40016|40|5|The argument type 'Iterable<String>?' can't be assigned to the parameter type 'Iterable<String>'.
-ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|40016|47|8|The argument type 'Iterable<String>?' can't be assigned to the parameter type 'Iterable<String>'.
-ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|40112|37|4|The argument type 'Null' can't be assigned to the parameter type 'UriPolicy'.
-ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|40233|15|4|The argument type 'Null' can't be assigned to the parameter type 'UriPolicy'.
-ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|40350|44|1|The argument type 'Node' can't be assigned to the parameter type 'E'.
-ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|40350|47|1|The argument type 'Node' can't be assigned to the parameter type 'E'.
-ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|40353|65|7|The argument type 'Object' can't be assigned to the parameter type 'Node'.
-ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|40356|25|7|The argument type 'Object' can't be assigned to the parameter type 'Node'.
-ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|41540|16|4|The argument type 'Null' can't be assigned to the parameter type 'Node'.
+ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|36378|34|14|The argument type 'String?' can't be assigned to the parameter type 'String'.
+ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|36426|48|14|The argument type 'String?' can't be assigned to the parameter type 'String'.
+ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|37894|45|7|The argument type 'dynamic Function(Event)?' can't be assigned to the parameter type 'dynamic Function(Event)'.
+ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|37900|48|7|The argument type 'dynamic Function(Event)?' can't be assigned to the parameter type 'dynamic Function(Event)'.
 ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|9520|41|15|The argument type 'void Function(Entry)?' can't be assigned to the parameter type 'void Function(Entry)'.
 ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|9564|36|15|The argument type 'void Function(Entry)?' can't be assigned to the parameter type 'void Function(Entry)'.
 ERROR|STATIC_WARNING|ARGUMENT_TYPE_NOT_ASSIGNABLE|lib/svg/dart2js/svg_dart2js.dart|3172|26|15|The argument type 'Node?' can't be assigned to the parameter type 'Node'.
 ERROR|STATIC_WARNING|FIELD_INITIALIZER_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|11629|26|17|The initializer type 'List<Node>' can't be assigned to the field type 'HtmlCollection'.
-ERROR|STATIC_WARNING|FIELD_INITIALIZER_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|37832|19|95|The initializer type 'void Function(Event)?' can't be assigned to the field type 'dynamic Function(Event)'.
-ERROR|STATIC_WARNING|FIELD_INITIALIZER_NOT_ASSIGNABLE|lib/html/dart2js/html_dart2js.dart|39513|19|4|The initializer type 'Null' can't be assigned to the field type 'EventTarget'.
 ERROR|STATIC_WARNING|FINAL_NOT_INITIALIZED_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|12627|3|7|All final variables must be initialized, but '_firstElementChild', '_lastElementChild', and 8 others are not.
 ERROR|STATIC_WARNING|FINAL_NOT_INITIALIZED_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|15934|3|15|All final variables must be initialized, but 'form' is not.
 ERROR|STATIC_WARNING|FINAL_NOT_INITIALIZED_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|18791|3|13|All final variables must be initialized, but '_get_contentWindow' is not.
@@ -365,7 +269,6 @@
 ERROR|STATIC_WARNING|FINAL_NOT_INITIALIZED_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|27859|3|13|All final variables must be initialized, but 'form' is not.
 ERROR|STATIC_WARNING|FINAL_NOT_INITIALIZED_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|29564|3|12|All final variables must be initialized, but 'sheet' is not.
 ERROR|STATIC_WARNING|FINAL_NOT_INITIALIZED_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|30135|3|15|All final variables must be initialized, but 'form' is not.
-ERROR|STATIC_WARNING|FINAL_NOT_INITIALIZED_CONSTRUCTOR|lib/html/dart2js/html_dart2js.dart|41028|3|8|All final variables must be initialized, but 'sourceCapabilities' is not.
 ERROR|STATIC_WARNING|FINAL_NOT_INITIALIZED_CONSTRUCTOR|lib/svg/dart2js/svg_dart2js.dart|3043|3|12|All final variables must be initialized, but 'sheet' is not.
 ERROR|STATIC_WARNING|FINAL_NOT_INITIALIZED_CONSTRUCTOR|lib/svg/dart2js/svg_dart2js.dart|3392|3|10|All final variables must be initialized, but 'ownerSvgElement' and 'viewportElement' are not.
 ERROR|STATIC_WARNING|GETTER_NOT_SUBTYPE_SETTER_TYPES|lib/html/dart2js/html_dart2js.dart|33119|19|6|The return type of getter 'opener' is 'WindowBase?' which isn't a subtype of the type 'Window' of its setter 'opener'.
@@ -374,14 +277,5 @@
 ERROR|STATIC_WARNING|UNCHECKED_USE_OF_NULLABLE_VALUE|lib/html/dart2js/html_dart2js.dart|23368|7|10|The expression is nullable and must be null-checked before it can be used.
 ERROR|STATIC_WARNING|UNCHECKED_USE_OF_NULLABLE_VALUE|lib/html/dart2js/html_dart2js.dart|34260|9|24|The expression is nullable and must be null-checked before it can be used.
 ERROR|STATIC_WARNING|UNCHECKED_USE_OF_NULLABLE_VALUE|lib/html/dart2js/html_dart2js.dart|34274|9|24|The expression is nullable and must be null-checked before it can be used.
-ERROR|STATIC_WARNING|UNCHECKED_USE_OF_NULLABLE_VALUE|lib/html/dart2js/html_dart2js.dart|40350|36|7|The expression is nullable and must be null-checked before it can be used.
 ERROR|STATIC_WARNING|UNCHECKED_USE_OF_NULLABLE_VALUE|lib/svg/dart2js/svg_dart2js.dart|3116|26|14|The expression is nullable and must be null-checked before it can be used.
-WARNING|STATIC_WARNING|INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_NAMED|lib/html/html_common/html_common_dart2js.dart|224|24|19|Parameters can't override default values, this method overrides 'Iterable.toList' where 'growable' has a different value.
-WARNING|STATIC_WARNING|INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_NAMED|lib/html/html_common/html_common_dart2js.dart|224|24|19|Parameters can't override default values, this method overrides 'SetMixin.toList' where 'growable' has a different value.
-WARNING|STATIC_WARNING|INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_POSITIONAL|lib/html/html_common/html_common_dart2js.dart|90|16|21|Parameters can't override default values, this method overrides 'Iterable.join' where this positional parameter has a different value.
-WARNING|STATIC_WARNING|INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_POSITIONAL|lib/html/html_common/html_common_dart2js.dart|90|16|21|Parameters can't override default values, this method overrides 'SetMixin.join' where this positional parameter has a different value.
-WARNING|STATIC_WARNING|INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_POSITIONAL|lib/html/html_common/html_common_dart2js.dart|962|8|17|Parameters can't override default values, this method overrides 'List.setRange' where this positional parameter has a different value.
-WARNING|STATIC_WARNING|INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_POSITIONAL|lib/html/html_common/html_common_dart2js.dart|962|8|17|Parameters can't override default values, this method overrides 'ListMixin.setRange' where this positional parameter has a different value.
-WARNING|STATIC_WARNING|UNNECESSARY_NULL_AWARE_CALL|lib/html/dart2js/html_dart2js.dart|39984|9|2|The target expression can't be null, and so '?.' isn't necessary.
-WARNING|STATIC_WARNING|UNNECESSARY_NULL_AWARE_CALL|lib/html/dart2js/html_dart2js.dart|40008|9|2|The target expression can't be null, and so '?.' isn't necessary.
-WARNING|STATIC_WARNING|UNNECESSARY_NULL_AWARE_CALL|lib/html/dart2js/html_dart2js.dart|40010|9|2|The target expression can't be null, and so '?.' isn't necessary.
+WARNING|STATIC_WARNING|UNNECESSARY_NON_NULL_ASSERTION|lib/html/dart2js/html_dart2js.dart|37453|33|1|The '!' will have no effect because the target expression cannot be null.
diff --git a/pkg/dev_compiler/tool/kernel_sdk.dart b/pkg/dev_compiler/tool/kernel_sdk.dart
index 9481d7d..3708675 100755
--- a/pkg/dev_compiler/tool/kernel_sdk.dart
+++ b/pkg/dev_compiler/tool/kernel_sdk.dart
@@ -57,16 +57,16 @@
     }
   }
 
-  String customScheme = 'org-dartlang-sdk';
+  var customScheme = 'org-dartlang-sdk';
   var fileSystem = MultiRootFileSystem(
       customScheme, [Uri.base], StandardFileSystem.instance);
-  Uri sdkRoot = Uri.parse('$customScheme:/');
-  Uri packagesFileUri = sdkRoot
+  var sdkRoot = Uri.parse('$customScheme:/');
+  var packagesFileUri = sdkRoot
       .resolve(p.relative(Uri.file(packagesPath).path, from: Uri.base.path));
   if (packagesFileUri.scheme != customScheme) {
     throw 'packagesPath has to be under ${Uri.base}';
   }
-  Uri librariesSpecificationUri = sdkRoot
+  var librariesSpecificationUri = sdkRoot
       .resolve(p.relative(Uri.file(librarySpecPath).path, from: Uri.base.path));
   if (librariesSpecificationUri.scheme != customScheme) {
     throw 'librarySpecPath has to be under ${Uri.base}';
diff --git a/pkg/dev_compiler/tool/patch_sdk.dart b/pkg/dev_compiler/tool/patch_sdk.dart
index 3dcb32b..3ef4057 100755
--- a/pkg/dev_compiler/tool/patch_sdk.dart
+++ b/pkg/dev_compiler/tool/patch_sdk.dart
@@ -166,7 +166,7 @@
   var patchFinder = PatchFinder.parseAndVisit(patchContents, useNnbd: useNnbd);
 
   // Merge `external` declarations with the corresponding `@patch` code.
-  bool failed = false;
+  var failed = false;
   for (var partContent in partsContents) {
     var partEdits = StringEditBuffer(partContent);
     var partUnit = _parseString(partContent, useNnbd: useNnbd).unit;
@@ -207,20 +207,20 @@
 
     // To patch a library, we must have a library directive
     var libDir = unit.directives.first as LibraryDirective;
-    int importPos = unit.directives
+    var importPos = unit.directives
         .lastWhere((d) => d is ImportDirective, orElse: () => libDir)
         .end;
     for (var d in patch.unit.directives.whereType<ImportDirective>()) {
       _merge(d, importPos);
     }
 
-    int partPos = unit.directives.last.end;
+    var partPos = unit.directives.last.end;
     for (var d in patch.unit.directives.whereType<PartDirective>()) {
       _merge(d, partPos);
     }
 
     // Merge declarations from the patch
-    int declPos = edits.original.length;
+    var declPos = edits.original.length;
     for (var d in patch.mergeDeclarations) {
       _merge(d, declPos);
     }
@@ -274,8 +274,8 @@
       return;
     }
 
-    Annotation patchMeta = patchNode.metadata.lastWhere(_isPatchAnnotation);
-    int start = patchMeta.endToken.next.offset;
+    var patchMeta = patchNode.metadata.lastWhere(_isPatchAnnotation);
+    var start = patchMeta.endToken.next.offset;
     var code = patch.contents.substring(start, patchNode.end);
 
     // Const factory constructors can't be legally parsed from the patch file,
@@ -416,7 +416,7 @@
     // Sort edits by start location.
     _edits.sort();
 
-    int consumed = 0;
+    var consumed = 0;
     for (var edit in _edits) {
       if (consumed > edit.begin) {
         sb = StringBuffer();
@@ -460,7 +460,7 @@
 
   @override
   int compareTo(_StringEdit other) {
-    int diff = begin - other.begin;
+    var diff = begin - other.begin;
     if (diff != 0) return diff;
     return end - other.end;
   }
@@ -489,7 +489,7 @@
 }
 
 String relativizeLibraryUri(Uri libRoot, Uri uri, bool useNnbd) {
-  String relativePath = relativizeUri(libRoot, uri, isWindows);
+  var relativePath = relativizeUri(libRoot, uri, isWindows);
   // During the nnbd-migration we may have paths that reach out into the
   // non-nnbd directory.
   if (relativePath.startsWith('..')) {
diff --git a/pkg/dev_compiler/web/stack_trace_mapper.dart b/pkg/dev_compiler/web/stack_trace_mapper.dart
index e10e6f3..a4daaa9 100644
--- a/pkg/dev_compiler/web/stack_trace_mapper.dart
+++ b/pkg/dev_compiler/web/stack_trace_mapper.dart
@@ -30,7 +30,7 @@
 
 import 'source_map_stack_trace.dart';
 
-typedef void ReadyCallback();
+typedef ReadyCallback = void Function();
 
 /// Global object DDC uses to see if a stack trace utility has been registered.
 @JS(r'$dartStackTraceUtility')
@@ -39,9 +39,9 @@
 @JS(r'$dartLoader.rootDirectories')
 external List get rootDirectories;
 
-typedef String StackTraceMapper(String stackTrace);
-typedef dynamic SourceMapProvider(String modulePath);
-typedef void SetSourceMapProvider(SourceMapProvider provider);
+typedef StackTraceMapper = String Function(String stackTrace);
+typedef SourceMapProvider = dynamic Function(String modulePath);
+typedef SetSourceMapProvider = void Function(SourceMapProvider);
 
 @JS()
 @anonymous
diff --git a/pkg/front_end/lib/src/api_prototype/constant_evaluator.dart b/pkg/front_end/lib/src/api_prototype/constant_evaluator.dart
index 5eeb2a6..98dd0ab 100644
--- a/pkg/front_end/lib/src/api_prototype/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/api_prototype/constant_evaluator.dart
@@ -9,6 +9,7 @@
         ConstantEvaluator,
         ConstantsTransformer,
         ErrorReporter,
+        EvaluationMode,
         EvaluationEnvironment,
         SimpleErrorReporter,
         transformComponent,
diff --git a/pkg/front_end/lib/src/fasta/builder/builder.dart b/pkg/front_end/lib/src/fasta/builder/builder.dart
index b297897..709c4cfcc 100644
--- a/pkg/front_end/lib/src/fasta/builder/builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/builder.dart
@@ -178,6 +178,8 @@
 
   bool get isRegularMethod;
 
+  bool get isOperator;
+
   bool get isSetter;
 
   bool get isStatic;
@@ -265,6 +267,9 @@
   bool get isRegularMethod => false;
 
   @override
+  bool get isOperator => false;
+
+  @override
   bool get isSetter => false;
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/builder/class_builder.dart b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
index 6dd7e15..e6bd782 100644
--- a/pkg/front_end/lib/src/fasta/builder/class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
@@ -80,6 +80,7 @@
 import 'builder.dart';
 import 'constructor_reference_builder.dart';
 import 'declaration_builder.dart';
+import 'field_builder.dart';
 import 'function_builder.dart';
 import 'library_builder.dart';
 import 'member_builder.dart';
@@ -788,10 +789,6 @@
     }
 
     // Check in members.
-    for (Field field in cls.fields) {
-      checkVarianceInField(field, typeEnvironment, cls.typeParameters);
-      library.checkBoundsInField(field, typeEnvironment);
-    }
     for (Procedure procedure in cls.procedures) {
       checkVarianceInFunction(procedure, typeEnvironment, cls.typeParameters);
       library.checkBoundsInFunctionNode(
@@ -810,8 +807,15 @@
           namedParameters: redirecting.namedParameters);
     }
 
-    // Check initializers.
     forEach((String name, Builder builder) {
+      // Check fields.
+      if (builder is FieldBuilder) {
+        checkVarianceInField(
+            builder.field, typeEnvironment, cls.typeParameters);
+        library.checkTypesInField(builder, typeEnvironment);
+      }
+
+      // Check initializers.
       if (builder is FunctionBuilder &&
           !builder.isAbstract &&
           builder.formals != null) {
diff --git a/pkg/front_end/lib/src/fasta/builder/field_builder.dart b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
index 571ef94..6dbdd64 100644
--- a/pkg/front_end/lib/src/fasta/builder/field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
@@ -931,22 +931,6 @@
   }
 }
 
-mixin LateWithInitializer on AbstractLateFieldEncoding {
-  @override
-  Statement _createGetterBody(
-      CoreTypes coreTypes, String name, Expression initializer) {
-    assert(_type != null, "Type has not been computed for field $name.");
-    return late_lowering.createGetterWithInitializer(
-        fileOffset, name, _type, initializer,
-        createVariableRead: _createFieldRead,
-        createVariableWrite: (Expression value) =>
-            _createFieldSet(_field, value),
-        createIsSetRead: () => _createFieldGet(_lateIsSetField),
-        createIsSetWrite: (Expression value) =>
-            _createFieldSet(_lateIsSetField, value));
-  }
-}
-
 mixin LateWithoutInitializer on AbstractLateFieldEncoding {
   @override
   Statement _createGetterBody(
@@ -975,7 +959,7 @@
 }
 
 class LateFieldWithInitializerEncoding extends AbstractLateFieldEncoding
-    with NonFinalLate, LateWithInitializer {
+    with NonFinalLate {
   LateFieldWithInitializerEncoding(
       String name,
       Uri fileUri,
@@ -987,6 +971,20 @@
       Procedure setterReferenceFrom)
       : super(name, fileUri, charOffset, charEndOffset, referenceFrom,
             lateIsSetReferenceFrom, getterReferenceFrom, setterReferenceFrom);
+
+  @override
+  Statement _createGetterBody(
+      CoreTypes coreTypes, String name, Expression initializer) {
+    assert(_type != null, "Type has not been computed for field $name.");
+    return late_lowering.createGetterWithInitializer(
+        fileOffset, name, _type, initializer,
+        createVariableRead: _createFieldRead,
+        createVariableWrite: (Expression value) =>
+            _createFieldSet(_field, value),
+        createIsSetRead: () => _createFieldGet(_lateIsSetField),
+        createIsSetWrite: (Expression value) =>
+            _createFieldSet(_lateIsSetField, value));
+  }
 }
 
 class LateFinalFieldWithoutInitializerEncoding extends AbstractLateFieldEncoding
@@ -1019,8 +1017,7 @@
   }
 }
 
-class LateFinalFieldWithInitializerEncoding extends AbstractLateFieldEncoding
-    with LateWithInitializer {
+class LateFinalFieldWithInitializerEncoding extends AbstractLateFieldEncoding {
   LateFinalFieldWithInitializerEncoding(
       String name,
       Uri fileUri,
@@ -1032,6 +1029,19 @@
       Procedure setterReferenceFrom)
       : super(name, fileUri, charOffset, charEndOffset, referenceFrom,
             lateIsSetReferenceFrom, getterReferenceFrom, setterReferenceFrom);
+  @override
+  Statement _createGetterBody(
+      CoreTypes coreTypes, String name, Expression initializer) {
+    assert(_type != null, "Type has not been computed for field $name.");
+    return late_lowering.createGetterWithInitializerWithRecheck(
+        coreTypes, fileOffset, name, _type, 'Field', initializer,
+        createVariableRead: _createFieldRead,
+        createVariableWrite: (Expression value) =>
+            _createFieldSet(_field, value),
+        createIsSetRead: () => _createFieldGet(_lateIsSetField),
+        createIsSetWrite: (Expression value) =>
+            _createFieldSet(_lateIsSetField, value));
+  }
 
   @override
   Procedure _createSetter(
diff --git a/pkg/front_end/lib/src/fasta/builder/library_builder.dart b/pkg/front_end/lib/src/fasta/builder/library_builder.dart
index 3e7315d..1f05a75 100644
--- a/pkg/front_end/lib/src/fasta/builder/library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/library_builder.dart
@@ -80,7 +80,7 @@
   /// Returns the import uri for the library.
   ///
   /// This is the canonical uri for the library, for instance 'dart:core'.
-  Uri get uri;
+  Uri get importUri;
 
   Iterator<Builder> get iterator;
 
@@ -254,7 +254,7 @@
   int get modifiers => 0;
 
   @override
-  Uri get uri;
+  Uri get importUri;
 
   @override
   Iterator<Builder> get iterator {
@@ -354,7 +354,7 @@
     }
     throw internalProblem(
         templateInternalProblemConstructorNotFound.withArguments(
-            "$className.$constructorName", uri),
+            "$className.$constructorName", importUri),
         -1,
         null);
   }
diff --git a/pkg/front_end/lib/src/fasta/builder/type_variable_builder.dart b/pkg/front_end/lib/src/fasta/builder/type_variable_builder.dart
index 1e5c652..c34ef54 100644
--- a/pkg/front_end/lib/src/fasta/builder/type_variable_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/type_variable_builder.dart
@@ -103,7 +103,7 @@
       } else {
         library.addProblem(
             templateInternalProblemUnfinishedTypeVariable.withArguments(
-                name, library?.uri),
+                name, library?.importUri),
             parameter.fileOffset,
             name.length,
             fileUri);
diff --git a/pkg/front_end/lib/src/fasta/builder_graph.dart b/pkg/front_end/lib/src/fasta/builder_graph.dart
index f917b93..79539fd 100644
--- a/pkg/front_end/lib/src/fasta/builder_graph.dart
+++ b/pkg/front_end/lib/src/fasta/builder_graph.dart
@@ -36,20 +36,20 @@
       for (Import import in library.imports) {
         // 'imported' can be null for fake imports, such as dart-ext:.
         if (import.imported != null) {
-          Uri uri = import.imported.uri;
+          Uri uri = import.imported.importUri;
           if (builders.containsKey(uri)) {
             yield uri;
           }
         }
       }
       for (Export export in library.exports) {
-        Uri uri = export.exported.uri;
+        Uri uri = export.exported.importUri;
         if (builders.containsKey(uri)) {
           yield uri;
         }
       }
       for (SourceLibraryBuilder part in library.parts) {
-        Uri uri = part.uri;
+        Uri uri = part.importUri;
         if (builders.containsKey(uri)) {
           yield uri;
         }
@@ -65,7 +65,7 @@
 
       // Parts
       for (LibraryPart part in library.library.parts) {
-        Uri uri = getPartUri(library.uri, part);
+        Uri uri = getPartUri(library.importUri, part);
         if (builders.containsKey(uri)) {
           yield uri;
         }
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart
index fa463de..562615e 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart
@@ -139,7 +139,7 @@
   void setLanguageVersion(int major, int minor,
       {int offset: 0, int length, bool explicit}) {}
 
-  Uri get uri => library.importUri;
+  Uri get importUri => library.importUri;
 
   Uri get fileUri => library.fileUri;
 
diff --git a/pkg/front_end/lib/src/fasta/fasta_codes_cfe_generated.dart b/pkg/front_end/lib/src/fasta/fasta_codes_cfe_generated.dart
index 4af16f1..5edb792 100644
--- a/pkg/front_end/lib/src/fasta/fasta_codes_cfe_generated.dart
+++ b/pkg/front_end/lib/src/fasta/fasta_codes_cfe_generated.dart
@@ -702,6 +702,156 @@
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<
         Message Function(
+            String name, DartType _type, bool isNonNullableByDefault)>
+    templateFieldNonNullableNotInitializedByConstructorError = const Template<
+            Message Function(
+                String name, DartType _type, bool isNonNullableByDefault)>(
+        messageTemplate:
+            r"""This constructor should initialize field '#name' because its type '#type' doesn't allow null.""",
+        withArguments:
+            _withArgumentsFieldNonNullableNotInitializedByConstructorError);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<
+        Message Function(
+            String name, DartType _type, bool isNonNullableByDefault)>
+    codeFieldNonNullableNotInitializedByConstructorError = const Code<
+        Message Function(
+            String name, DartType _type, bool isNonNullableByDefault)>(
+  "FieldNonNullableNotInitializedByConstructorError",
+  templateFieldNonNullableNotInitializedByConstructorError,
+);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsFieldNonNullableNotInitializedByConstructorError(
+    String name, DartType _type, bool isNonNullableByDefault) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  TypeLabeler labeler = new TypeLabeler(isNonNullableByDefault);
+  List<Object> typeParts = labeler.labelType(_type);
+  String type = typeParts.join();
+  return new Message(codeFieldNonNullableNotInitializedByConstructorError,
+      message:
+          """This constructor should initialize field '${name}' because its type '${type}' doesn't allow null.""" +
+              labeler.originMessages,
+      arguments: {'name': name, 'type': _type});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+        Message Function(
+            String name, DartType _type, bool isNonNullableByDefault)>
+    templateFieldNonNullableNotInitializedByConstructorWarning = const Template<
+            Message Function(
+                String name, DartType _type, bool isNonNullableByDefault)>(
+        messageTemplate:
+            r"""This constructor doesn't initialize field '#name' and its type '#type' doesn't allow null.""",
+        withArguments:
+            _withArgumentsFieldNonNullableNotInitializedByConstructorWarning);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<
+        Message Function(
+            String name, DartType _type, bool isNonNullableByDefault)>
+    codeFieldNonNullableNotInitializedByConstructorWarning = const Code<
+            Message Function(
+                String name, DartType _type, bool isNonNullableByDefault)>(
+        "FieldNonNullableNotInitializedByConstructorWarning",
+        templateFieldNonNullableNotInitializedByConstructorWarning,
+        severity: Severity.warning);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsFieldNonNullableNotInitializedByConstructorWarning(
+    String name, DartType _type, bool isNonNullableByDefault) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  TypeLabeler labeler = new TypeLabeler(isNonNullableByDefault);
+  List<Object> typeParts = labeler.labelType(_type);
+  String type = typeParts.join();
+  return new Message(codeFieldNonNullableNotInitializedByConstructorWarning,
+      message:
+          """This constructor doesn't initialize field '${name}' and its type '${type}' doesn't allow null.""" +
+              labeler.originMessages,
+      arguments: {'name': name, 'type': _type});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+        Message Function(
+            String name, DartType _type, bool isNonNullableByDefault)>
+    templateFieldNonNullableWithoutInitializerError = const Template<
+            Message Function(
+                String name, DartType _type, bool isNonNullableByDefault)>(
+        messageTemplate:
+            r"""Field '#name' should be initialized because its type '#type' doesn't allow null.""",
+        withArguments: _withArgumentsFieldNonNullableWithoutInitializerError);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<
+        Message Function(
+            String name, DartType _type, bool isNonNullableByDefault)>
+    codeFieldNonNullableWithoutInitializerError = const Code<
+        Message Function(
+            String name, DartType _type, bool isNonNullableByDefault)>(
+  "FieldNonNullableWithoutInitializerError",
+  templateFieldNonNullableWithoutInitializerError,
+);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsFieldNonNullableWithoutInitializerError(
+    String name, DartType _type, bool isNonNullableByDefault) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  TypeLabeler labeler = new TypeLabeler(isNonNullableByDefault);
+  List<Object> typeParts = labeler.labelType(_type);
+  String type = typeParts.join();
+  return new Message(codeFieldNonNullableWithoutInitializerError,
+      message:
+          """Field '${name}' should be initialized because its type '${type}' doesn't allow null.""" +
+              labeler.originMessages,
+      arguments: {'name': name, 'type': _type});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+        Message Function(
+            String name, DartType _type, bool isNonNullableByDefault)>
+    templateFieldNonNullableWithoutInitializerWarning = const Template<
+            Message Function(
+                String name, DartType _type, bool isNonNullableByDefault)>(
+        messageTemplate:
+            r"""Field '#name' isn't initialized and its type '#type' doesn't allow null.""",
+        withArguments: _withArgumentsFieldNonNullableWithoutInitializerWarning);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<
+        Message Function(
+            String name, DartType _type, bool isNonNullableByDefault)>
+    codeFieldNonNullableWithoutInitializerWarning = const Code<
+            Message Function(
+                String name, DartType _type, bool isNonNullableByDefault)>(
+        "FieldNonNullableWithoutInitializerWarning",
+        templateFieldNonNullableWithoutInitializerWarning,
+        severity: Severity.warning);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsFieldNonNullableWithoutInitializerWarning(
+    String name, DartType _type, bool isNonNullableByDefault) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  TypeLabeler labeler = new TypeLabeler(isNonNullableByDefault);
+  List<Object> typeParts = labeler.labelType(_type);
+  String type = typeParts.join();
+  return new Message(codeFieldNonNullableWithoutInitializerWarning,
+      message:
+          """Field '${name}' isn't initialized and its type '${type}' doesn't allow null.""" +
+              labeler.originMessages,
+      arguments: {'name': name, 'type': _type});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+        Message Function(
             DartType _type, DartType _type2, bool isNonNullableByDefault)>
     templateForInLoopElementTypeNotAssignable = const Template<
             Message Function(
@@ -1373,6 +1523,42 @@
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<
         Message Function(
+            String string, DartType _type, bool isNonNullableByDefault)>
+    templateInternalProblemUnsupportedNullability = const Template<
+            Message Function(
+                String string, DartType _type, bool isNonNullableByDefault)>(
+        messageTemplate:
+            r"""Unsupported nullability value '#string' on type '#type'.""",
+        withArguments: _withArgumentsInternalProblemUnsupportedNullability);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<
+        Message Function(
+            String string, DartType _type, bool isNonNullableByDefault)>
+    codeInternalProblemUnsupportedNullability = const Code<
+            Message Function(
+                String string, DartType _type, bool isNonNullableByDefault)>(
+        "InternalProblemUnsupportedNullability",
+        templateInternalProblemUnsupportedNullability,
+        severity: Severity.internalProblem);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsInternalProblemUnsupportedNullability(
+    String string, DartType _type, bool isNonNullableByDefault) {
+  if (string.isEmpty) throw 'No string provided';
+  TypeLabeler labeler = new TypeLabeler(isNonNullableByDefault);
+  List<Object> typeParts = labeler.labelType(_type);
+  String type = typeParts.join();
+  return new Message(codeInternalProblemUnsupportedNullability,
+      message:
+          """Unsupported nullability value '${string}' on type '${type}'.""" +
+              labeler.originMessages,
+      arguments: {'string': string, 'type': _type});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+        Message Function(
             DartType _type, DartType _type2, bool isNonNullableByDefault)>
     templateInvalidAssignmentError = const Template<
             Message Function(
diff --git a/pkg/front_end/lib/src/fasta/incremental_compiler.dart b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
index dad13e9..8599429 100644
--- a/pkg/front_end/lib/src/fasta/incremental_compiler.dart
+++ b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
@@ -438,8 +438,9 @@
           }
           assert(
               !map.containsKey(name),
-              "Unexpected double-entry for $name in ${builder.uri} "
-              "(org from ${entry.key.uri}): $childBuilder and ${map[name]}");
+              "Unexpected double-entry for $name in ${builder.importUri} "
+              "(org from ${entry.key.importUri}): $childBuilder and "
+              "${map[name]}");
           map[name] = childBuilder;
         }
       }
@@ -460,7 +461,7 @@
         new Map<LibraryBuilder, List<SourceLibraryBuilder>>.identity();
     if (experimentalInvalidation != null) {
       for (LibraryBuilder library in experimentalInvalidation.rebuildBodies) {
-        LibraryBuilder newBuilder = userCode.loader.read(library.uri, -1,
+        LibraryBuilder newBuilder = userCode.loader.read(library.importUri, -1,
             accessor: userCode.loader.first,
             fileUri: library.fileUri,
             referencesFrom: library.library);
@@ -471,7 +472,7 @@
           // overwrite correctly, but the library itself should  not be
           // over written as the library for parts are temporary "fake"
           // libraries.
-          Uri partUri = getPartUri(library.uri, part);
+          Uri partUri = getPartUri(library.importUri, part);
           Uri fileUri =
               getPartFileUri(library.library.fileUri, part, uriTranslator);
           LibraryBuilder newPartBuilder = userCode.loader.read(partUri, -1,
@@ -583,8 +584,9 @@
 
     // Re-use the libraries we've deemed re-usable.
     for (LibraryBuilder library in reusedLibraries) {
-      userCode.loader.builders[library.uri] = library;
-      if (library.uri.scheme == "dart" && library.uri.path == "core") {
+      userCode.loader.builders[library.importUri] = library;
+      if (library.importUri.scheme == "dart" &&
+          library.importUri.path == "core") {
         userCode.loader.coreLibrary = library;
       }
     }
@@ -597,8 +599,8 @@
     bool wasFirstSet = false;
     if (experimentalInvalidation != null) {
       for (LibraryBuilder library in experimentalInvalidation.rebuildBodies) {
-        if (library.uri == firstEntryPointImportUri) {
-          userCode.loader.read(library.uri, -1,
+        if (library.importUri == firstEntryPointImportUri) {
+          userCode.loader.read(library.importUri, -1,
               accessor: userCode.loader.first,
               fileUri: library.fileUri,
               referencesFrom: library.library);
@@ -688,8 +690,9 @@
       for (DillLibraryBuilder library
           in oldDillLoadedData.loader.builders.values) {
         library.loader = dillLoadedData.loader;
-        dillLoadedData.loader.builders[library.uri] = library;
-        if (library.uri.scheme == "dart" && library.uri.path == "core") {
+        dillLoadedData.loader.builders[library.importUri] = library;
+        if (library.importUri.scheme == "dart" &&
+            library.importUri.path == "core") {
           dillLoadedData.loader.coreLibrary = library;
         }
       }
@@ -715,10 +718,10 @@
       incrementalSerializer?.invalidate(builder.fileUri);
 
       LibraryBuilder dillBuilder =
-          dillLoadedData.loader.builders.remove(builder.uri);
+          dillLoadedData.loader.builders.remove(builder.importUri);
       if (dillBuilder != null) {
         removedDillBuilders = true;
-        userBuilders?.remove(builder.uri);
+        userBuilders?.remove(builder.importUri);
       }
 
       // Remove component problems for libraries we don't reuse.
@@ -820,7 +823,7 @@
       if (builder.isPart) continue;
       if (builder.isPatch) continue;
       if (rebuildBodies.contains(builder)) continue;
-      if (!seenUris.add(builder.uri)) continue;
+      if (!seenUris.add(builder.importUri)) continue;
       reusedResult.reusedLibraries.add(builder);
       originalNotReusedLibraries.add(builder);
     }
@@ -919,7 +922,7 @@
       userBuilders = <Uri, LibraryBuilder>{};
       platformBuilders = <LibraryBuilder>[];
       dillLoadedData.loader.builders.forEach((uri, builder) {
-        if (builder.uri.scheme == "dart") {
+        if (builder.importUri.scheme == "dart") {
           platformBuilders.add(builder);
         } else {
           userBuilders[uri] = builder;
@@ -1076,7 +1079,7 @@
         userBuilders = <Uri, LibraryBuilder>{};
         platformBuilders = <LibraryBuilder>[];
         dillLoadedData.loader.builders.forEach((uri, builder) {
-          if (builder.uri.scheme == "dart") {
+          if (builder.importUri.scheme == "dart") {
             platformBuilders.add(builder);
           } else {
             userBuilders[uri] = builder;
@@ -1189,12 +1192,13 @@
     List<Uri> worklist = new List<Uri>();
     worklist.addAll(entries);
     for (LibraryBuilder libraryBuilder in reusedLibraries) {
-      if (libraryBuilder.uri.scheme == "dart" && !libraryBuilder.isSynthetic) {
+      if (libraryBuilder.importUri.scheme == "dart" &&
+          !libraryBuilder.isSynthetic) {
         continue;
       }
       Library lib = libraryBuilder.library;
-      potentiallyReferencedLibraries[libraryBuilder.uri] = lib;
-      libraryMap[libraryBuilder.uri] = lib;
+      potentiallyReferencedLibraries[libraryBuilder.importUri] = lib;
+      libraryMap[libraryBuilder.importUri] = lib;
     }
 
     LibraryGraph graph = new LibraryGraph(libraryMap);
@@ -1542,7 +1546,7 @@
     List<LibraryBuilder> reusedLibraries = <LibraryBuilder>[];
     for (int i = 0; i < platformBuilders.length; i++) {
       LibraryBuilder builder = platformBuilders[i];
-      if (!seenUris.add(builder.uri)) continue;
+      if (!seenUris.add(builder.importUri)) continue;
       reusedLibraries.add(builder);
     }
     if (userCode == null && userBuilders == null) {
@@ -1587,7 +1591,7 @@
 
     addBuilderAndInvalidateUris(Uri uri, LibraryBuilder libraryBuilder) {
       if (uri.scheme == "dart" && !libraryBuilder.isSynthetic) {
-        if (seenUris.add(libraryBuilder.uri)) {
+        if (seenUris.add(libraryBuilder.importUri)) {
           reusedLibraries.add(libraryBuilder);
         }
         return;
@@ -1598,14 +1602,14 @@
       }
       if (libraryBuilder is SourceLibraryBuilder) {
         for (LibraryBuilder part in libraryBuilder.parts) {
-          if (isInvalidated(part.uri, part.fileUri)) {
-            invalidatedImportUris.add(part.uri);
-            builders[part.uri] = part;
+          if (isInvalidated(part.importUri, part.fileUri)) {
+            invalidatedImportUris.add(part.importUri);
+            builders[part.importUri] = part;
           }
         }
       } else if (libraryBuilder is DillLibraryBuilder) {
         for (LibraryPart part in libraryBuilder.library.parts) {
-          Uri partUri = getPartUri(libraryBuilder.uri, part);
+          Uri partUri = getPartUri(libraryBuilder.importUri, part);
           Uri fileUri = getPartFileUri(
               libraryBuilder.library.fileUri, part, uriTranslator);
 
@@ -1651,8 +1655,8 @@
       // [current] is null if the corresponding key (URI) has already been
       // removed.
       if (current != null) {
-        Set<Uri> s = directDependencies[current.uri];
-        if (current.uri != removed) {
+        Set<Uri> s = directDependencies[current.importUri];
+        if (current.importUri != removed) {
           if (s == null) {
             s = directDependencies[removed];
           } else {
@@ -1676,7 +1680,7 @@
       // TODO(jensj/ahe): This line can probably go away once
       // https://dart-review.googlesource.com/47442 lands.
       if (builder.isPatch) continue;
-      if (!seenUris.add(builder.uri)) continue;
+      if (!seenUris.add(builder.importUri)) continue;
       reusedLibraries.add(builder);
     }
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index 39f4308..9276e54 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -344,12 +344,13 @@
         classBuilder =
             declarationBuilder is ClassBuilder ? declarationBuilder : null,
         enableNative = libraryBuilder.loader.target.backendTarget
-            .enableNative(libraryBuilder.uri),
+            .enableNative(libraryBuilder.importUri),
         stringExpectedAfterNative = libraryBuilder
             .loader.target.backendTarget.nativeExtensionExpectsString,
-        ignoreMainInGetMainClosure = libraryBuilder.uri.scheme == 'dart' &&
-            (libraryBuilder.uri.path == "_builtin" ||
-                libraryBuilder.uri.path == "ui"),
+        ignoreMainInGetMainClosure =
+            libraryBuilder.importUri.scheme == 'dart' &&
+                (libraryBuilder.importUri.path == "_builtin" ||
+                    libraryBuilder.importUri.path == "ui"),
         needsImplicitSuperInitializer = declarationBuilder is ClassBuilder &&
             coreTypes?.objectClass != declarationBuilder.cls,
         typePromoter = typeInferrer?.typePromoter,
diff --git a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart b/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
index 441fc5b..889090f 100644
--- a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
@@ -2553,7 +2553,7 @@
           debug?.log("Combined Member Signature: "
               "${fullName(bestSoFar)} !<: ${fullName(candidate)}");
 
-          String uri = '${classBuilder.library.uri}';
+          String uri = '${classBuilder.library.importUri}';
           if (uri == 'dart:js' &&
                   classBuilder.fileUri.pathSegments.last == 'js.dart' ||
               uri == 'dart:_interceptors' &&
diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
index 430f0f2..645e2b95 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -27,9 +27,9 @@
 import 'package:kernel/clone.dart';
 import 'package:kernel/core_types.dart';
 import 'package:kernel/kernel.dart';
+import 'package:kernel/src/legacy_erasure.dart';
 import 'package:kernel/type_algebra.dart';
 import 'package:kernel/type_environment.dart';
-
 import 'package:kernel/target/targets.dart';
 
 import '../fasta_codes.dart'
@@ -68,8 +68,12 @@
 
 part 'constant_collection_builders.dart';
 
-Component transformComponent(Component component, ConstantsBackend backend,
-    Map<String, String> environmentDefines, ErrorReporter errorReporter,
+Component transformComponent(
+    Component component,
+    ConstantsBackend backend,
+    Map<String, String> environmentDefines,
+    ErrorReporter errorReporter,
+    EvaluationMode evaluationMode,
     {bool keepFields: true,
     bool evaluateAnnotations: true,
     bool desugarSets: false,
@@ -84,7 +88,7 @@
       new TypeEnvironment(coreTypes, hierarchy);
 
   transformLibraries(component.libraries, backend, environmentDefines,
-      typeEnvironment, errorReporter,
+      typeEnvironment, errorReporter, evaluationMode,
       keepFields: keepFields,
       desugarSets: desugarSets,
       enableTripleShift: enableTripleShift,
@@ -99,6 +103,7 @@
     Map<String, String> environmentDefines,
     TypeEnvironment typeEnvironment,
     ErrorReporter errorReporter,
+    EvaluationMode evaluationMode,
     {bool keepFields: true,
     bool evaluateAnnotations: true,
     bool desugarSets: false,
@@ -113,12 +118,19 @@
       enableTripleShift,
       errorOnUnevaluatedConstant,
       typeEnvironment,
-      errorReporter);
+      errorReporter,
+      evaluationMode);
   for (final Library library in libraries) {
     constantsTransformer.convertLibrary(library);
   }
 }
 
+enum EvaluationMode {
+  legacy,
+  weak,
+  strong,
+}
+
 class ConstantsTransformer extends Transformer {
   final ConstantsBackend backend;
   final ConstantEvaluator constantEvaluator;
@@ -141,12 +153,14 @@
       this.enableTripleShift,
       this.errorOnUnevaluatedConstant,
       this.typeEnvironment,
-      ErrorReporter errorReporter)
+      ErrorReporter errorReporter,
+      EvaluationMode evaluationMode)
       : constantEvaluator = new ConstantEvaluator(
             backend, environmentDefines, typeEnvironment, errorReporter,
             desugarSets: desugarSets,
             enableTripleShift: enableTripleShift,
-            errorOnUnevaluatedConstant: errorOnUnevaluatedConstant);
+            errorOnUnevaluatedConstant: errorOnUnevaluatedConstant,
+            evaluationMode: evaluationMode);
 
   // Transform the library/class members:
 
@@ -519,6 +533,7 @@
   final TypeEnvironment typeEnvironment;
   StaticTypeContext _staticTypeContext;
   final ErrorReporter errorReporter;
+  final EvaluationMode evaluationMode;
 
   final bool desugarSets;
   final Field unmodifiableSetMap;
@@ -559,7 +574,8 @@
       this.errorReporter,
       {this.desugarSets = false,
       this.enableTripleShift = false,
-      this.errorOnUnevaluatedConstant = false})
+      this.errorOnUnevaluatedConstant = false,
+      this.evaluationMode: EvaluationMode.legacy})
       : numberSemantics = backend.numberSemantics,
         coreTypes = typeEnvironment.coreTypes,
         canonicalizationCache = <Constant, Constant>{},
@@ -591,6 +607,32 @@
     };
   }
 
+  DartType convertType(DartType type) {
+    switch (evaluationMode) {
+      case EvaluationMode.legacy:
+      case EvaluationMode.strong:
+        return type;
+      case EvaluationMode.weak:
+        return legacyErasure(coreTypes, type);
+    }
+    throw new UnsupportedError(
+        "Unexpected evaluation mode: ${evaluationMode}.");
+  }
+
+  List<DartType> convertTypes(List<DartType> types) {
+    switch (evaluationMode) {
+      case EvaluationMode.legacy:
+      case EvaluationMode.strong:
+        return types;
+      case EvaluationMode.weak:
+        return types
+            .map((DartType type) => legacyErasure(coreTypes, type))
+            .toList();
+    }
+    throw new UnsupportedError(
+        "Unexpected evaluation mode: ${evaluationMode}.");
+  }
+
   Uri getFileUri(TreeNode node) {
     while (node != null && node is! FileUriNode) {
       node = node.parent;
@@ -834,7 +876,7 @@
 
   @override
   Constant visitTypeLiteral(TypeLiteral node) {
-    final DartType type = evaluateDartType(node, node.type);
+    final DartType type = evaluateDartType(node, convertType(node.type));
     return canonicalize(new TypeLiteralConstant(type));
   }
 
@@ -860,7 +902,7 @@
       return reportInvalid(node, "Non-constant list literal");
     }
     final ListConstantBuilder builder =
-        new ListConstantBuilder(node, node.typeArgument, this);
+        new ListConstantBuilder(node, convertType(node.typeArgument), this);
     for (Expression element in node.expressions) {
       builder.add(element);
     }
@@ -870,7 +912,7 @@
   @override
   Constant visitListConcatenation(ListConcatenation node) {
     final ListConstantBuilder builder =
-        new ListConstantBuilder(node, node.typeArgument, this);
+        new ListConstantBuilder(node, convertType(node.typeArgument), this);
     for (Expression list in node.lists) {
       builder.addSpread(list);
     }
@@ -883,7 +925,7 @@
       return reportInvalid(node, "Non-constant set literal");
     }
     final SetConstantBuilder builder =
-        new SetConstantBuilder(node, node.typeArgument, this);
+        new SetConstantBuilder(node, convertType(node.typeArgument), this);
     for (Expression element in node.expressions) {
       builder.add(element);
     }
@@ -893,7 +935,7 @@
   @override
   Constant visitSetConcatenation(SetConcatenation node) {
     final SetConstantBuilder builder =
-        new SetConstantBuilder(node, node.typeArgument, this);
+        new SetConstantBuilder(node, convertType(node.typeArgument), this);
     for (Expression set_ in node.sets) {
       builder.addSpread(set_);
     }
@@ -905,8 +947,8 @@
     if (!node.isConst) {
       return reportInvalid(node, "Non-constant map literal");
     }
-    final MapConstantBuilder builder =
-        new MapConstantBuilder(node, node.keyType, node.valueType, this);
+    final MapConstantBuilder builder = new MapConstantBuilder(
+        node, convertType(node.keyType), convertType(node.valueType), this);
     for (MapEntry element in node.entries) {
       builder.add(element);
     }
@@ -915,8 +957,8 @@
 
   @override
   Constant visitMapConcatenation(MapConcatenation node) {
-    final MapConstantBuilder builder =
-        new MapConstantBuilder(node, node.keyType, node.valueType, this);
+    final MapConstantBuilder builder = new MapConstantBuilder(
+        node, convertType(node.keyType), convertType(node.valueType), this);
     for (Expression map in node.maps) {
       builder.addSpread(map);
     }
@@ -972,7 +1014,7 @@
     }
 
     final List<DartType> typeArguments =
-        evaluateTypeArguments(node, node.arguments);
+        convertTypes(evaluateTypeArguments(node, node.arguments));
 
     // Fill in any missing type arguments with "dynamic".
     for (int i = typeArguments.length; i < klass.typeParameters.length; i++) {
@@ -1016,7 +1058,8 @@
 
   @override
   Constant visitInstanceCreation(InstanceCreation node) {
-    return withNewInstanceBuilder(node.classNode, node.typeArguments, () {
+    return withNewInstanceBuilder(
+        node.classNode, convertTypes(node.typeArguments), () {
       for (AssertStatement statement in node.asserts) {
         checkAssert(statement);
       }
@@ -1859,7 +1902,7 @@
       if (node.typeArguments.length ==
           constant.procedure.function.typeParameters.length) {
         final List<DartType> typeArguments =
-            evaluateDartTypes(node, node.typeArguments);
+            convertTypes(evaluateDartTypes(node, node.typeArguments));
         return canonicalize(
             new PartialInstantiationConstant(constant, typeArguments));
       }
diff --git a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
index 6f25949..be297da 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
@@ -17,7 +17,6 @@
 import '../builder/builder.dart';
 import '../builder/declaration_builder.dart';
 import '../builder/extension_builder.dart';
-import '../builder/function_builder.dart';
 import '../builder/invalid_type_declaration_builder.dart';
 import '../builder/member_builder.dart';
 import '../builder/named_type_builder.dart';
@@ -1558,7 +1557,7 @@
         assert(!getterBuilder.isStatic);
         readTarget = getterBuilder.readTarget;
         invokeTarget = getterBuilder.invokeTarget;
-      } else if (getterBuilder is FunctionBuilder && getterBuilder.isOperator) {
+      } else if (getterBuilder.isOperator) {
         assert(!getterBuilder.isStatic);
         invokeTarget = getterBuilder.invokeTarget;
       }
@@ -1860,13 +1859,13 @@
         MemberBuilder procedureBuilder = getterBuilder;
         readTarget = procedureBuilder.readTarget;
         invokeTarget = procedureBuilder.invokeTarget;
-      } else if (getterBuilder is FunctionBuilder && getterBuilder.isOperator) {
+      } else if (getterBuilder.isOperator) {
         assert(!getterBuilder.isStatic);
         MemberBuilder memberBuilder = getterBuilder;
         invokeTarget = memberBuilder.invokeTarget;
       } else {
         return unhandled(
-            "${getterBuilder.runtimeType}",
+            "$getterBuilder (${getterBuilder.runtimeType})",
             "InstanceExtensionAccessGenerator.fromBuilder",
             offsetForToken(token),
             helper.uri);
@@ -1883,7 +1882,7 @@
         writeTarget = memberBuilder.writeTarget;
       } else {
         return unhandled(
-            "${setterBuilder.runtimeType}",
+            "$setterBuilder (${setterBuilder.runtimeType})",
             "InstanceExtensionAccessGenerator.fromBuilder",
             offsetForToken(token),
             helper.uri);
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index c5e3e53..a96fb3e 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -718,6 +718,7 @@
             computeConstructorReturnType(node.target, inferrer.coreTypes),
         isConst: node.isConst);
     node.hasBeenInferred = true;
+    Expression resultNode = node;
     if (!inferrer.isTopLevel) {
       SourceLibraryBuilder library = inferrer.library;
       if (!hadExplicitTypeArguments) {
@@ -726,8 +727,19 @@
             inferred: true);
       }
     }
+    if (inferrer.isNonNullableByDefault && inferrer.performNnbdChecks) {
+      if (node.target == inferrer.coreTypes.listDefaultConstructor) {
+        if (inferrer.nnbdStrongMode) {
+          resultNode = inferrer.helper.wrapInProblem(
+              node, messageDefaultListConstructorError, noLength);
+        } else {
+          inferrer.library.addProblem(messageDefaultListConstructorWarning,
+              node.fileOffset, noLength, inferrer.library.fileUri);
+        }
+      }
+    }
     return new ExpressionInferenceResult(
-        result.inferredType, result.applyResult(node));
+        result.inferredType, result.applyResult(resultNode));
   }
 
   @override
@@ -2361,10 +2373,8 @@
   @override
   ExpressionInferenceResult visitNullCheck(
       NullCheck node, DartType typeContext) {
-    // TODO(johnniwinther): Should the typeContext for the operand be
-    //  `Nullable(typeContext)`?
-    ExpressionInferenceResult operandResult =
-        inferrer.inferExpression(node.operand, typeContext, true);
+    ExpressionInferenceResult operandResult = inferrer.inferExpression(
+        node.operand, inferrer.computeNullable(typeContext), true);
     node.operand = operandResult.expression..parent = node;
     // TODO(johnniwinther): Check that the inferred type is potentially
     //  nullable.
@@ -5283,8 +5293,9 @@
       initializerResult = inferrer.inferExpression(node.initializer,
           declaredType, !inferrer.isTopLevel || node.isImplicitlyTyped,
           isVoidAllowed: true);
-      inferredType =
-          inferrer.inferDeclarationType(initializerResult.inferredType);
+      inferredType = inferrer.inferDeclarationType(
+          initializerResult.inferredType,
+          forSyntheticVariable: node.name == null);
       inferrer.flowAnalysis.initialize(node);
     } else {
       inferredType = const DynamicType();
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
index 292505e..abf58ad 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -22,6 +22,7 @@
         Initializer,
         InterfaceType,
         InvalidInitializer,
+        InvalidType,
         Library,
         Name,
         NamedExpression,
@@ -84,10 +85,17 @@
 import '../messages.dart'
     show
         FormattedMessage,
+        messageConstConstructorLateFinalFieldCause,
+        messageConstConstructorLateFinalFieldError,
+        messageConstConstructorLateFinalFieldWarning,
         messageConstConstructorNonFinalField,
         messageConstConstructorNonFinalFieldCause,
         messageConstConstructorRedirectionToNonConst,
         noLength,
+        templateFieldNonNullableNotInitializedByConstructorError,
+        templateFieldNonNullableNotInitializedByConstructorWarning,
+        templateFieldNonNullableWithoutInitializerError,
+        templateFieldNonNullableWithoutInitializerWarning,
         templateFinalFieldNotInitialized,
         templateFinalFieldNotInitializedByConstructor,
         templateInferredPackageUri,
@@ -108,7 +116,8 @@
 
 import '../uri_translator.dart' show UriTranslator;
 
-import 'constant_evaluator.dart' as constants show transformLibraries;
+import 'constant_evaluator.dart' as constants
+    show EvaluationMode, transformLibraries;
 
 import 'kernel_constants.dart' show KernelConstantErrorReporter;
 
@@ -309,6 +318,7 @@
       loader.addNoSuchMethodForwarders(myClasses);
       loader.checkMixins(myClasses);
       loader.buildOutlineExpressions(loader.coreTypes);
+      _updateDelayedParameterTypes();
       installAllComponentProblems(loader.allComponentProblems);
       loader.allComponentProblems.clear();
       return component;
@@ -441,6 +451,17 @@
     ticker.logMs("Installed synthetic constructors");
   }
 
+  List<DelayedParameterType> _delayedParameterTypes = <DelayedParameterType>[];
+
+  /// Update the type of parameters cloned from parameters with inferred
+  /// parameter types.
+  void _updateDelayedParameterTypes() {
+    for (DelayedParameterType delayedParameterType in _delayedParameterTypes) {
+      delayedParameterType.updateType();
+    }
+    _delayedParameterTypes.clear();
+  }
+
   ClassBuilder get objectClassBuilder => objectType.declaration;
 
   Class get objectClass => objectClassBuilder.cls;
@@ -556,6 +577,9 @@
           isFinal: formal.isFinal, isConst: formal.isConst);
       if (formal.type != null) {
         copy.type = substitute(formal.type, substitutionMap);
+      } else {
+        _delayedParameterTypes
+            .add(new DelayedParameterType(formal, copy, substitutionMap));
       }
       return copy;
     }
@@ -701,15 +725,25 @@
     /// Quotes below are from [Dart Programming Language Specification, 4th
     /// Edition](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-408.pdf):
     List<Field> uninitializedFields = <Field>[];
-    List<Field> nonFinalFields = <Field>[];
     for (Field field in cls.fields) {
-      if (field.isInstanceMember && !field.isFinal) {
-        nonFinalFields.add(field);
-      }
       if (field.initializer == null) {
         uninitializedFields.add(field);
       }
     }
+    List<FieldBuilder> nonFinalFields = <FieldBuilder>[];
+    List<FieldBuilder> lateFinalFields = <FieldBuilder>[];
+    builder.forEach((String name, Builder fieldBuilder) {
+      if (fieldBuilder is FieldBuilder) {
+        if (fieldBuilder.isDeclarationInstanceMember && !fieldBuilder.isFinal) {
+          nonFinalFields.add(fieldBuilder);
+        }
+        if (fieldBuilder.isDeclarationInstanceMember &&
+            fieldBuilder.isLate &&
+            fieldBuilder.isFinal) {
+          lateFinalFields.add(fieldBuilder);
+        }
+      }
+    });
     Map<Constructor, Set<Field>> constructorInitializedFields =
         <Constructor, Set<Field>>{};
     Constructor superTarget;
@@ -786,10 +820,35 @@
               constructor.fileOffset, noLength,
               context: nonFinalFields
                   .map((field) => messageConstConstructorNonFinalFieldCause
-                      .withLocation(field.fileUri, field.fileOffset, noLength))
+                      .withLocation(field.fileUri, field.charOffset, noLength))
                   .toList());
           nonFinalFields.clear();
         }
+        SourceLibraryBuilder library = builder.library;
+        if (library.isNonNullableByDefault &&
+            library.loader.performNnbdChecks) {
+          if (constructor.isConst && lateFinalFields.isNotEmpty) {
+            if (library.loader.nnbdStrongMode) {
+              builder.addProblem(messageConstConstructorLateFinalFieldError,
+                  constructor.fileOffset, noLength,
+                  context: lateFinalFields
+                      .map((field) => messageConstConstructorLateFinalFieldCause
+                          .withLocation(
+                              field.fileUri, field.charOffset, noLength))
+                      .toList());
+              lateFinalFields.clear();
+            } else {
+              builder.addProblem(messageConstConstructorLateFinalFieldWarning,
+                  constructor.fileOffset, noLength,
+                  context: lateFinalFields
+                      .map((field) => messageConstConstructorLateFinalFieldCause
+                          .withLocation(
+                              field.fileUri, field.charOffset, noLength))
+                      .toList());
+              lateFinalFields.clear();
+            }
+          }
+        }
       }
     }
     Set<Field> initializedFields;
@@ -826,6 +885,30 @@
                   field.name.name.length,
                   field.fileUri);
             }
+          } else if (field.type is! InvalidType &&
+              field.type.isPotentiallyNonNullable &&
+              (cls.constructors.isNotEmpty || cls.isMixinDeclaration)) {
+            SourceLibraryBuilder library = builder.library;
+            if (library.isNonNullableByDefault &&
+                library.loader.performNnbdChecks) {
+              if (library.loader.nnbdStrongMode) {
+                library.addProblem(
+                    templateFieldNonNullableWithoutInitializerError
+                        .withArguments(field.name.name, field.type,
+                            library.isNonNullableByDefault),
+                    field.fileOffset,
+                    field.name.name.length,
+                    library.fileUri);
+              } else {
+                library.addProblem(
+                    templateFieldNonNullableWithoutInitializerWarning
+                        .withArguments(field.name.name, field.type,
+                            library.isNonNullableByDefault),
+                    field.fileOffset,
+                    field.name.name.length,
+                    library.fileUri);
+              }
+            }
           }
         }
       }
@@ -855,6 +938,29 @@
                       .withLocation(field.fileUri, field.fileOffset,
                           field.name.name.length)
                 ]);
+          } else if (field.type is! InvalidType &&
+              field.type.isPotentiallyNonNullable) {
+            SourceLibraryBuilder library = builder.library;
+            if (library.isNonNullableByDefault &&
+                library.loader.performNnbdChecks) {
+              if (library.loader.nnbdStrongMode) {
+                library.addProblem(
+                    templateFieldNonNullableNotInitializedByConstructorError
+                        .withArguments(field.name.name, field.type,
+                            library.isNonNullableByDefault),
+                    field.fileOffset,
+                    field.name.name.length,
+                    library.fileUri);
+              } else {
+                library.addProblem(
+                    templateFieldNonNullableNotInitializedByConstructorWarning
+                        .withArguments(field.name.name, field.type,
+                            library.isNonNullableByDefault),
+                    field.fileOffset,
+                    field.name.name.length,
+                    library.fileUri);
+              }
+            }
           }
         }
       }
@@ -873,12 +979,24 @@
 
     TypeEnvironment environment =
         new TypeEnvironment(loader.coreTypes, loader.hierarchy);
+    constants.EvaluationMode evaluationMode;
+    if (enableNonNullable) {
+      if (loader.nnbdStrongMode) {
+        evaluationMode = constants.EvaluationMode.strong;
+      } else {
+        evaluationMode = constants.EvaluationMode.weak;
+      }
+    } else {
+      evaluationMode = constants.EvaluationMode.legacy;
+    }
+
     constants.transformLibraries(
         loader.libraries,
         backendTarget.constantsBackend(loader.coreTypes),
         environmentDefines,
         environment,
         new KernelConstantErrorReporter(loader),
+        evaluationMode,
         desugarSets: !backendTarget.supportsSetLiterals,
         enableTripleShift: enableTripleShift,
         errorOnUnevaluatedConstant: errorOnUnevaluatedConstant);
@@ -925,8 +1043,8 @@
 
   @override
   void readPatchFiles(SourceLibraryBuilder library) {
-    assert(library.uri.scheme == "dart");
-    List<Uri> patches = uriTranslator.getDartPatches(library.uri.path);
+    assert(library.importUri.scheme == "dart");
+    List<Uri> patches = uriTranslator.getDartPatches(library.importUri.path);
     if (patches != null) {
       SourceLibraryBuilder first;
       for (Uri patch in patches) {
@@ -940,7 +1058,7 @@
               origin: library, fileUri: patch, accessor: library);
           first.parts.add(part);
           first.partOffsets.add(-1);
-          part.partOfUri = first.uri;
+          part.partOfUri = first.importUri;
         }
       }
     }
@@ -979,3 +1097,21 @@
     loader.addProblem(message, charOffset, noLength, fileUri, context: context);
   }
 }
+
+/// Data for updating cloned parameters of parameters with inferred parameter
+/// types.
+///
+/// The type of [source] is not declared so the type of [target] needs to be
+/// updated when the type of [source] has been inferred.
+class DelayedParameterType {
+  final VariableDeclaration source;
+  final VariableDeclaration target;
+  final Map<TypeParameter, DartType> substitutionMap;
+
+  DelayedParameterType(this.source, this.target, this.substitutionMap);
+
+  void updateType() {
+    assert(source.type != null, "No type computed for $source.");
+    target.type = substitute(source.type, substitutionMap);
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart b/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart
index ca339e3..171e1fd 100644
--- a/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart
@@ -7,6 +7,14 @@
 
 import '../names.dart';
 
+/// Creates the body for the synthesized getter used to encode the lowering
+/// of a late non-final field with an initializer or a late local with an
+/// initializer.
+///
+/// Late final field needs to detect writes during initialization and therefore
+/// uses [createGetterWithInitializerWithRecheck] instead. Late final locals
+/// cannot have writes during initialization since they are not in scope in
+/// their own initializer.
 Statement createGetterWithInitializer(
     int fileOffset, String name, DartType type, Expression initializer,
     {Expression createVariableRead({bool needsPromotion}),
@@ -73,6 +81,129 @@
   }
 }
 
+/// Creates the body for the synthesized getter used to encode the lowering
+/// of a late final field with an initializer.
+///
+/// A late final field needs to detect writes during initialization for
+/// which a `LateInitializationError` should be thrown. Late final locals
+/// cannot have writes during initialization since they are not in scope in
+/// their own initializer.
+Statement createGetterWithInitializerWithRecheck(
+    CoreTypes coreTypes,
+    int fileOffset,
+    String name,
+    DartType type,
+    String variableKindName,
+    Expression initializer,
+    {Expression createVariableRead({bool needsPromotion}),
+    Expression createVariableWrite(Expression value),
+    Expression createIsSetRead(),
+    Expression createIsSetWrite(Expression value)}) {
+  Expression exception = new Throw(new ConstructorInvocation(
+      coreTypes.lateInitializationErrorConstructor,
+      new Arguments(<Expression>[
+        new StringLiteral(
+            "$variableKindName '${name}' has been assigned during "
+            "initialization.")
+          ..fileOffset = fileOffset
+      ])
+        ..fileOffset = fileOffset)
+    ..fileOffset = fileOffset)
+    ..fileOffset = fileOffset;
+  VariableDeclaration temp =
+      new VariableDeclaration.forValue(initializer, type: type)
+        ..fileOffset = fileOffset;
+  if (type.isPotentiallyNullable) {
+    // Generate:
+    //
+    //    if (!_#isSet#field) {
+    //      var temp = <init>;
+    //      if (_#isSet#field) throw '...'
+    //      _#isSet#field = true
+    //      _#field = temp;
+    //    }
+    //    return _#field;
+    return new Block(<Statement>[
+      new IfStatement(
+          new Not(createIsSetRead()..fileOffset = fileOffset)
+            ..fileOffset = fileOffset,
+          new Block(<Statement>[
+            temp,
+            new IfStatement(
+                createIsSetRead()..fileOffset = fileOffset,
+                new ExpressionStatement(exception)..fileOffset = fileOffset,
+                null)
+              ..fileOffset = fileOffset,
+            new ExpressionStatement(
+                createIsSetWrite(new BoolLiteral(true)..fileOffset = fileOffset)
+                  ..fileOffset = fileOffset)
+              ..fileOffset = fileOffset,
+            new ExpressionStatement(
+                createVariableWrite(
+                    new VariableGet(temp)..fileOffset = fileOffset)
+                  ..fileOffset = fileOffset)
+              ..fileOffset = fileOffset,
+          ]),
+          null)
+        ..fileOffset = fileOffset,
+      new ReturnStatement(
+          // If [type] is a type variable with undetermined nullability we need
+          // to create a read of the field that is promoted to the type variable
+          // type.
+          createVariableRead(needsPromotion: type.isPotentiallyNonNullable))
+        ..fileOffset = fileOffset
+    ])
+      ..fileOffset = fileOffset;
+  } else {
+    // Generate:
+    //
+    //    return let #1 = _#field in #1 == null
+    //        ? let #2 = <init> in _#field == null ? _#field = #2 : throw '...'
+    //        : #1;
+    VariableDeclaration variable = new VariableDeclaration.forValue(
+        createVariableRead(needsPromotion: false)..fileOffset = fileOffset,
+        type: type.withNullability(Nullability.nullable))
+      ..fileOffset = fileOffset;
+    return new ReturnStatement(
+        new Let(
+            variable,
+            new ConditionalExpression(
+                new MethodInvocation(
+                    new VariableGet(variable)..fileOffset = fileOffset,
+                    equalsName,
+                    new Arguments(<Expression>[
+                      new NullLiteral()..fileOffset = fileOffset
+                    ])
+                      ..fileOffset = fileOffset)
+                  ..fileOffset = fileOffset,
+                new Let(
+                    temp,
+                    new ConditionalExpression(
+                        new MethodInvocation(
+                            createVariableRead(needsPromotion: false)
+                              ..fileOffset = fileOffset,
+                            equalsName,
+                            new Arguments(<Expression>[
+                              new NullLiteral()..fileOffset = fileOffset
+                            ])
+                              ..fileOffset = fileOffset)
+                          ..fileOffset = fileOffset,
+                        createVariableWrite(
+                            new VariableGet(temp)..fileOffset = fileOffset)
+                          ..fileOffset = fileOffset,
+                        exception,
+                        type)
+                      ..fileOffset = fileOffset),
+                new VariableGet(variable, type)..fileOffset = fileOffset,
+                type)
+              ..fileOffset = fileOffset)
+          ..fileOffset = fileOffset)
+      ..fileOffset = fileOffset;
+  }
+}
+
+/// Creates the body for the synthesized getter used to encode the lowering
+/// of a late field or local without an initializer.
 Statement createGetterBodyWithoutInitializer(CoreTypes coreTypes,
     int fileOffset, String name, DartType type, String variableKindName,
     {Expression createVariableRead({bool needsPromotion}),
@@ -129,6 +260,8 @@
   }
 }
 
+/// Creates the body for the synthesized setter used to encode the lowering
+/// of a non-final late field or local.
 Statement createSetterBody(
     int fileOffset, String name, VariableDeclaration parameter, DartType type,
     {bool shouldReturnValue,
@@ -169,6 +302,8 @@
   }
 }
 
+/// Creates the body for the synthesized setter used to encode the lowering
+/// of a final late field or local.
 Statement createSetterBodyFinal(
     CoreTypes coreTypes,
     int fileOffset,
diff --git a/pkg/front_end/lib/src/fasta/loader.dart b/pkg/front_end/lib/src/fasta/loader.dart
index fcb1cb7..b879ee9 100644
--- a/pkg/front_end/lib/src/fasta/loader.dart
+++ b/pkg/front_end/lib/src/fasta/loader.dart
@@ -202,7 +202,8 @@
       if (coreLibrary == library) {
         target.loadExtraRequiredLibraries(this);
       }
-      if (target.backendTarget.mayDefineRestrictedType(origin?.uri ?? uri)) {
+      if (target.backendTarget
+          .mayDefineRestrictedType(origin?.importUri ?? uri)) {
         library.mayImplementRestrictedTypes = true;
       }
       if (uri.scheme == "dart") {
@@ -220,7 +221,7 @@
       if (!accessor.isPatch &&
           !accessor.isPart &&
           !target.backendTarget
-              .allowPlatformPrivateLibraryAccess(accessor.uri, uri)) {
+              .allowPlatformPrivateLibraryAccess(accessor.importUri, uri)) {
         accessor.addProblem(messagePlatformPrivateLibraryAccess, charOffset,
             noLength, accessor.fileUri);
       }
@@ -243,7 +244,7 @@
     assert(coreLibrary != null);
     for (LibraryBuilder library in builders.values) {
       if (library.loader == this) {
-        currentUriForCrashReporting = library.uri;
+        currentUriForCrashReporting = library.importUri;
         await buildBody(library);
       }
     }
@@ -255,7 +256,7 @@
     ensureCoreLibrary();
     while (unparsedLibraries.isNotEmpty) {
       LibraryBuilder library = unparsedLibraries.removeFirst();
-      currentUriForCrashReporting = library.uri;
+      currentUriForCrashReporting = library.importUri;
       await buildOutline(library);
     }
     currentUriForCrashReporting = null;
diff --git a/pkg/front_end/lib/src/fasta/source/diet_listener.dart b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
index f561749..e0516e5 100644
--- a/pkg/front_end/lib/src/fasta/source/diet_listener.dart
+++ b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
@@ -117,7 +117,7 @@
         uri = library.fileUri,
         memberScope = library.scope,
         enableNative =
-            library.loader.target.backendTarget.enableNative(library.uri),
+            library.loader.target.backendTarget.enableNative(library.importUri),
         stringExpectedAfterNative =
             library.loader.target.backendTarget.nativeExtensionExpectsString;
 
diff --git a/pkg/front_end/lib/src/fasta/source/outline_builder.dart b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
index f79ddbe..ae16b95 100644
--- a/pkg/front_end/lib/src/fasta/source/outline_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
@@ -114,7 +114,7 @@
   OutlineBuilder(SourceLibraryBuilder library)
       : libraryBuilder = library,
         enableNative =
-            library.loader.target.backendTarget.enableNative(library.uri),
+            library.loader.target.backendTarget.enableNative(library.importUri),
         stringExpectedAfterNative =
             library.loader.target.backendTarget.nativeExtensionExpectsString;
 
diff --git a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
index 6940aaa..ea4acbe 100644
--- a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
@@ -37,6 +37,8 @@
 import 'package:kernel/type_algebra.dart' as type_algebra
     show getSubstitutionMap;
 
+import 'package:kernel/type_environment.dart';
+
 import '../builder/builder.dart';
 
 import '../builder/class_builder.dart';
@@ -426,8 +428,9 @@
     library.forwardersOrigins.add(procedure);
   }
 
-  void addNoSuchMethodForwarderGetterForField(Member noSuchMethod,
-      KernelTarget target, Field field, ClassHierarchy hierarchy) {
+  void addNoSuchMethodForwarderGetterForField(
+      Field field, Member noSuchMethod, KernelTarget target) {
+    ClassHierarchy hierarchy = target.loader.hierarchy;
     Substitution substitution = Substitution.fromSupertype(
         hierarchy.getClassAsInstanceOf(cls, field.enclosingClass));
 
@@ -453,8 +456,9 @@
     getter.parent = cls;
   }
 
-  void addNoSuchMethodForwarderSetterForField(Member noSuchMethod,
-      KernelTarget target, Field field, ClassHierarchy hierarchy) {
+  void addNoSuchMethodForwarderSetterForField(
+      Field field, Member noSuchMethod, KernelTarget target) {
+    ClassHierarchy hierarchy = target.loader.hierarchy;
     Substitution substitution = Substitution.fromSupertype(
         hierarchy.getClassAsInstanceOf(cls, field.enclosingClass));
 
@@ -484,128 +488,212 @@
     setter.parent = cls;
   }
 
-  /// Adds noSuchMethod forwarding stubs to this class. Returns `true` if the
-  /// class was modified.
-  bool addNoSuchMethodForwarders(
-      KernelTarget target, ClassHierarchy hierarchy) {
-    if (cls.isAbstract) return false;
+  bool _addMissingNoSuchMethodForwarders(
+      KernelTarget target, Set<Member> existingForwarders,
+      {bool forSetters}) {
+    assert(forSetters != null);
 
-    Set<Name> existingForwardersNames = new Set<Name>();
-    Set<Name> existingSetterForwardersNames = new Set<Name>();
-    Class leastConcreteSuperclass = cls.superclass;
-    while (
-        leastConcreteSuperclass != null && leastConcreteSuperclass.isAbstract) {
-      leastConcreteSuperclass = leastConcreteSuperclass.superclass;
-    }
-    if (leastConcreteSuperclass != null) {
-      bool superHasUserDefinedNoSuchMethod = hasUserDefinedNoSuchMethod(
-          leastConcreteSuperclass, hierarchy, target.objectClass);
-      List<Member> concrete =
-          hierarchy.getDispatchTargets(leastConcreteSuperclass);
-      for (Member member
-          in hierarchy.getInterfaceMembers(leastConcreteSuperclass)) {
-        if ((superHasUserDefinedNoSuchMethod ||
-                leastConcreteSuperclass.enclosingLibrary.compareTo(
-                            member.enclosingClass.enclosingLibrary) !=
-                        0 &&
-                    member.name.isPrivate) &&
-            ClassHierarchy.findMemberByName(concrete, member.name) == null) {
-          existingForwardersNames.add(member.name);
-        }
-      }
+    ClassHierarchy hierarchy = target.loader.hierarchy;
+    TypeEnvironment typeEnvironment =
+        target.loader.typeInferenceEngine.typeSchemaEnvironment;
 
-      List<Member> concreteSetters =
-          hierarchy.getDispatchTargets(leastConcreteSuperclass, setters: true);
-      for (Member member in hierarchy
-          .getInterfaceMembers(leastConcreteSuperclass, setters: true)) {
-        if (ClassHierarchy.findMemberByName(concreteSetters, member.name) ==
-            null) {
-          existingSetterForwardersNames.add(member.name);
-        }
-      }
-    }
+    List<Member> allMembers =
+        hierarchy.getInterfaceMembers(cls, setters: forSetters);
+    List<Member> concreteMembers =
+        hierarchy.getDispatchTargets(cls, setters: forSetters);
+    List<Member> declaredMembers =
+        hierarchy.getDeclaredMembers(cls, setters: forSetters);
 
     Member noSuchMethod = ClassHierarchy.findMemberByName(
         hierarchy.getInterfaceMembers(cls), noSuchMethodName);
-
-    List<Member> concrete = hierarchy.getDispatchTargets(cls);
-    List<Member> declared = hierarchy.getDeclaredMembers(cls);
-
     bool clsHasUserDefinedNoSuchMethod =
         hasUserDefinedNoSuchMethod(cls, hierarchy, target.objectClass);
+
     bool changed = false;
-    for (Member member in hierarchy.getInterfaceMembers(cls)) {
-      // We generate a noSuchMethod forwarder for [member] in [cls] if the
-      // following three conditions are satisfied simultaneously:
-      // 1) There is a user-defined noSuchMethod in [cls] or [member] is private
-      //    and the enclosing library of [member] is different from that of
-      //    [cls].
-      // 2) There is no implementation of [member] in [cls].
-      // 3) The superclass of [cls] has no forwarder for [member].
-      if (member is Procedure &&
-          (clsHasUserDefinedNoSuchMethod ||
-              cls.enclosingLibrary
-                          .compareTo(member.enclosingClass.enclosingLibrary) !=
-                      0 &&
-                  member.name.isPrivate) &&
-          ClassHierarchy.findMemberByName(concrete, member.name) == null &&
-          !existingForwardersNames.contains(member.name)) {
-        if (ClassHierarchy.findMemberByName(declared, member.name) != null) {
-          transformProcedureToNoSuchMethodForwarder(
-              noSuchMethod, target, member);
-        } else {
-          addNoSuchMethodForwarderForProcedure(
-              noSuchMethod, target, member, hierarchy);
-        }
-        existingForwardersNames.add(member.name);
-        changed = true;
-        continue;
-      }
 
-      if (member is Field &&
-          ClassHierarchy.findMemberByName(concrete, member.name) == null &&
-          !existingForwardersNames.contains(member.name)) {
-        addNoSuchMethodForwarderGetterForField(
-            noSuchMethod, target, member, hierarchy);
-        existingForwardersNames.add(member.name);
-        changed = true;
-      }
+    // It's possible to have multiple abstract members with the same name -- as
+    // long as there's one with function type that's a subtype of function types
+    // of all other members.  Such member is called "best" in the code below.
+    // Members with the same name are put into groups, and "best" is searched
+    // for in each group.
+    Map<Name, List<Member>> sameNameMembers = {};
+    for (Member member in allMembers) {
+      (sameNameMembers[member.name] ??= []).add(member);
     }
+    for (Name name in sameNameMembers.keys) {
+      List<Member> members = sameNameMembers[name];
+      assert(members.isNotEmpty);
+      List<DartType> memberTypes = [];
 
-    List<Member> concreteSetters =
-        hierarchy.getDispatchTargets(cls, setters: true);
-    List<Member> declaredSetters =
-        hierarchy.getDeclaredMembers(cls, setters: true);
-    for (Member member in hierarchy.getInterfaceMembers(cls, setters: true)) {
-      if (member is Procedure &&
-          ClassHierarchy.findMemberByName(concreteSetters, member.name) ==
-              null &&
-          !existingSetterForwardersNames.contains(member.name)) {
-        if (ClassHierarchy.findMemberByName(declaredSetters, member.name) !=
-            null) {
-          transformProcedureToNoSuchMethodForwarder(
-              noSuchMethod, target, member);
-        } else {
-          addNoSuchMethodForwarderForProcedure(
-              noSuchMethod, target, member, hierarchy);
+      // The most specific member has the type that is subtype of the types of
+      // all other members.
+      Member bestSoFar = members.first;
+      DartType bestSoFarType =
+          forSetters ? bestSoFar.setterType : bestSoFar.getterType;
+      bestSoFarType = Substitution.fromSupertype(
+              hierarchy.getClassAsInstanceOf(cls, bestSoFar.enclosingClass))
+          .substituteType(bestSoFarType);
+      for (int i = 1; i < members.length; ++i) {
+        Member candidate = members[i];
+        DartType candidateType =
+            forSetters ? candidate.setterType : candidate.getterType;
+        Substitution substitution = Substitution.fromSupertype(
+            hierarchy.getClassAsInstanceOf(cls, candidate.enclosingClass));
+        candidateType = substitution.substituteType(candidateType);
+        memberTypes.add(candidateType);
+        bool isMoreSpecific = forSetters
+            ? typeEnvironment.isSubtypeOf(bestSoFarType, candidateType,
+                SubtypeCheckMode.withNullabilities)
+            : typeEnvironment.isSubtypeOf(candidateType, bestSoFarType,
+                SubtypeCheckMode.withNullabilities);
+        if (isMoreSpecific) {
+          bestSoFar = candidate;
+          bestSoFarType = candidateType;
         }
-        existingSetterForwardersNames.add(member.name);
-        changed = true;
       }
-      if (member is Field &&
-          ClassHierarchy.findMemberByName(concreteSetters, member.name) ==
-              null &&
-          !existingSetterForwardersNames.contains(member.name)) {
-        addNoSuchMethodForwarderSetterForField(
-            noSuchMethod, target, member, hierarchy);
-        existingSetterForwardersNames.add(member.name);
-        changed = true;
+      // Since isSubtypeOf isn't a linear order on types, we need to check once
+      // again that the found member is indeed the most specific one.
+      bool isActuallyBestSoFar = true;
+      for (DartType memberType in memberTypes) {
+        bool isMoreSpecific = forSetters
+            ? typeEnvironment.isSubtypeOf(
+                memberType, bestSoFarType, SubtypeCheckMode.withNullabilities)
+            : typeEnvironment.isSubtypeOf(
+                bestSoFarType, memberType, SubtypeCheckMode.withNullabilities);
+        if (!isMoreSpecific) {
+          isActuallyBestSoFar = false;
+          break;
+        }
+      }
+      if (!isActuallyBestSoFar) {
+        // It's a member conflict that is reported elsewhere.
+      } else {
+        Member member = bestSoFar;
+
+        if (_isForwarderRequired(
+                clsHasUserDefinedNoSuchMethod, member, cls, concreteMembers,
+                isPatch: member.fileUri != member.enclosingClass.fileUri) &&
+            !existingForwarders.contains(member)) {
+          if (member is Procedure) {
+            // If there's a declared member with such name, then it's abstract
+            // -- transform it into a noSuchMethod forwarder.
+            if (ClassHierarchy.findMemberByName(declaredMembers, member.name) !=
+                null) {
+              transformProcedureToNoSuchMethodForwarder(
+                  noSuchMethod, target, member);
+            } else {
+              addNoSuchMethodForwarderForProcedure(
+                  noSuchMethod, target, member, hierarchy);
+            }
+            changed = true;
+          } else if (member is Field) {
+            // Current class isn't abstract, so it can't have an abstract field
+            // with the same name -- just insert the forwarder.
+            if (forSetters) {
+              addNoSuchMethodForwarderSetterForField(
+                  member, noSuchMethod, target);
+            } else {
+              addNoSuchMethodForwarderGetterForField(
+                  member, noSuchMethod, target);
+            }
+            changed = true;
+          } else {
+            return unhandled(
+                "${member.runtimeType}",
+                "addNoSuchMethodForwarders",
+                cls.fileOffset,
+                cls.enclosingLibrary.fileUri);
+          }
+        }
       }
     }
 
     return changed;
   }
 
+  /// Adds noSuchMethod forwarding stubs to this class.
+  ///
+  /// Returns `true` if the class was modified.
+  bool addNoSuchMethodForwarders(
+      KernelTarget target, ClassHierarchy hierarchy) {
+    // Don't install forwarders in superclasses.
+    if (cls.isAbstract) return false;
+
+    // Compute signatures of existing noSuchMethod forwarders in superclasses.
+    Set<Member> existingForwarders = new Set<Member>.identity();
+    Set<Member> existingSetterForwarders = new Set<Member>.identity();
+    {
+      Class nearestConcreteSuperclass = cls.superclass;
+      while (nearestConcreteSuperclass != null &&
+          nearestConcreteSuperclass.isAbstract) {
+        nearestConcreteSuperclass = nearestConcreteSuperclass.superclass;
+      }
+      if (nearestConcreteSuperclass != null) {
+        bool superHasUserDefinedNoSuchMethod = hasUserDefinedNoSuchMethod(
+            nearestConcreteSuperclass, hierarchy, target.objectClass);
+        {
+          List<Member> concrete =
+              hierarchy.getDispatchTargets(nearestConcreteSuperclass);
+          for (Member member
+              in hierarchy.getInterfaceMembers(nearestConcreteSuperclass)) {
+            if (_isForwarderRequired(superHasUserDefinedNoSuchMethod, member,
+                nearestConcreteSuperclass, concrete,
+                isPatch: member.fileUri != member.enclosingClass.fileUri)) {
+              existingForwarders.add(member);
+            }
+          }
+        }
+
+        {
+          List<Member> concreteSetters = hierarchy
+              .getDispatchTargets(nearestConcreteSuperclass, setters: true);
+          for (Member member in hierarchy
+              .getInterfaceMembers(nearestConcreteSuperclass, setters: true)) {
+            if (_isForwarderRequired(superHasUserDefinedNoSuchMethod, member,
+                nearestConcreteSuperclass, concreteSetters)) {
+              existingSetterForwarders.add(member);
+            }
+          }
+        }
+      }
+    }
+
+    bool changed = false;
+
+    // Install noSuchMethod forwarders for methods and getters.
+    changed = _addMissingNoSuchMethodForwarders(target, existingForwarders,
+            forSetters: false) ||
+        changed;
+
+    // Install noSuchMethod forwarders for setters.
+    changed = _addMissingNoSuchMethodForwarders(
+            target, existingSetterForwarders,
+            forSetters: true) ||
+        changed;
+
+    return changed;
+  }
+
+  /// Tells if a noSuchMethod forwarder is required for [member] in [cls].
+  bool _isForwarderRequired(bool hasUserDefinedNoSuchMethod, Member member,
+      Class cls, List<Member> concreteMembers,
+      {bool isPatch = false}) {
+    // A noSuchMethod forwarder is allowed for an abstract member if the class
+    // has a user-defined noSuchMethod or if the member is private and is
+    // defined in a different library.  Private members in patches are assumed
+    // to be visible only to patches, so they are treated as if they were from
+    // another library.
+    bool isForwarderAllowed = hasUserDefinedNoSuchMethod ||
+        (member.name.isPrivate &&
+            cls.enclosingLibrary.compareTo(member.enclosingLibrary) != 0) ||
+        (member.name.isPrivate && isPatch);
+    // A noSuchMethod forwarder is required if it's allowed and if there's no
+    // concrete implementation or a forwarder already.
+    bool isForwarderRequired = isForwarderAllowed &&
+        ClassHierarchy.findMemberByName(concreteMembers, member.name) == null;
+    return isForwarderRequired;
+  }
+
   void addRedirectingConstructor(ProcedureBuilder constructorBuilder,
       SourceLibraryBuilder library, Field referenceFrom) {
     // Add a new synthetic field to this class for representing factory
diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
index 0c4dfb2..dc904d8 100644
--- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
@@ -27,6 +27,7 @@
         FunctionNode,
         FunctionType,
         InterfaceType,
+        InvalidType,
         Library,
         LibraryDependency,
         LibraryPart,
@@ -617,7 +618,9 @@
         context: [
           templateConstructorWithWrongNameContext
               .withArguments(currentTypeParameterScopeBuilder.name)
-              .withLocation(uri, currentTypeParameterScopeBuilder.charOffset,
+              .withLocation(
+                  importUri,
+                  currentTypeParameterScopeBuilder.charOffset,
                   currentTypeParameterScopeBuilder.name.length)
         ]);
 
@@ -640,8 +643,9 @@
       }
     }
 
-    LibraryBuilder exportedLibrary = loader
-        .read(resolve(this.uri, uri, uriOffset), charOffset, accessor: this);
+    LibraryBuilder exportedLibrary = loader.read(
+        resolve(this.importUri, uri, uriOffset), charOffset,
+        accessor: this);
     exportedLibrary.addExporter(this, combinators, charOffset);
     exports.add(new Export(this, exportedLibrary, combinators, charOffset));
   }
@@ -657,8 +661,8 @@
 
     if (imported == null) {
       LibraryBuilder coreLibrary = loader.read(
-          resolve(
-              this.uri, new Uri(scheme: "dart", path: "core").toString(), -1),
+          resolve(this.importUri,
+              new Uri(scheme: "dart", path: "core").toString(), -1),
           -1);
       imported = coreLibrary
           .loader.builders[new Uri(scheme: 'dart', path: dottedName)];
@@ -694,8 +698,8 @@
     if (uri.startsWith(nativeExtensionScheme)) {
       String strippedUri = uri.substring(nativeExtensionScheme.length);
       if (strippedUri.startsWith("package")) {
-        resolvedUri = resolve(
-            this.uri, strippedUri, uriOffset + nativeExtensionScheme.length);
+        resolvedUri = resolve(this.importUri, strippedUri,
+            uriOffset + nativeExtensionScheme.length);
         resolvedUri = loader.target.translateUri(resolvedUri);
         nativePath = resolvedUri.toString();
       } else {
@@ -703,7 +707,7 @@
         nativePath = uri;
       }
     } else {
-      resolvedUri = resolve(this.uri, uri, uriOffset);
+      resolvedUri = resolve(this.importUri, uri, uriOffset);
       builder = loader.read(resolvedUri, uriOffset, accessor: this);
     }
 
@@ -715,7 +719,7 @@
   void addPart(List<MetadataBuilder> metadata, String uri, int charOffset) {
     Uri resolvedUri;
     Uri newFileUri;
-    resolvedUri = resolve(this.uri, uri, charOffset, isPart: true);
+    resolvedUri = resolve(this.importUri, uri, charOffset, isPart: true);
     newFileUri = resolve(fileUri, uri, charOffset);
     // TODO(johnniwinther): Add a LibraryPartBuilder instead of using
     // [LibraryBuilder] to represent both libraries and parts.
@@ -733,7 +737,7 @@
       List<MetadataBuilder> metadata, String name, String uri, int uriOffset) {
     partOfName = name;
     if (uri != null) {
-      partOfUri = resolve(this.uri, uri, uriOffset);
+      partOfUri = resolve(this.importUri, uri, uriOffset);
       Uri newFileUri = resolve(fileUri, uri, uriOffset);
       LibraryBuilder library = loader.read(partOfUri, uriOffset,
           fileUri: newFileUri, accessor: this);
@@ -958,7 +962,7 @@
   /// (../kernel/kernel_mixin_application_builder.dart)).
   void addImplementationBuilder(
       String name, Builder declaration, int charOffset) {
-    assert(canAddImplementationBuilders, "$uri");
+    assert(canAddImplementationBuilders, "$importUri");
     implementationBuilders
         .add(new ImplementationInfo(name, declaration, charOffset));
   }
@@ -976,7 +980,7 @@
       }
       for (SourceLibraryBuilder part in parts) {
         // Mark this part as used so we don't report it as orphaned.
-        usedParts.add(part.uri);
+        usedParts.add(part.importUri);
       }
     }
     parts.clear();
@@ -1012,7 +1016,7 @@
           if (isPatch) {
             usedParts.add(part.fileUri);
           } else {
-            usedParts.add(part.uri);
+            usedParts.add(part.importUri);
           }
           includePart(part, usedParts, partOffset);
         }
@@ -1026,12 +1030,12 @@
   bool includePart(
       SourceLibraryBuilder part, Set<Uri> usedParts, int partOffset) {
     if (part.partOfUri != null) {
-      if (uriIsValid(part.partOfUri) && part.partOfUri != uri) {
+      if (uriIsValid(part.partOfUri) && part.partOfUri != importUri) {
         // This is an error, but the part is not removed from the list of parts,
         // so that metadata annotations can be associated with it.
         addProblem(
             templatePartOfUriMismatch.withArguments(
-                part.fileUri, uri, part.partOfUri),
+                part.fileUri, importUri, part.partOfUri),
             partOffset,
             noLength,
             fileUri);
@@ -1313,7 +1317,7 @@
   @override
   SourceLibraryBuilder get origin => actualOrigin ?? this;
 
-  Uri get uri => library.importUri;
+  Uri get importUri => library.importUri;
 
   void addSyntheticDeclarationOfDynamic() {
     addBuilder(
@@ -2406,7 +2410,7 @@
       modifiers |= initializingFormalMask;
     }
     FormalParameterBuilder formal = new FormalParameterBuilder(
-        metadata, modifiers, type, name, this, charOffset, uri)
+        metadata, modifiers, type, name, this, charOffset, importUri)
       ..initializerToken = initializerToken
       ..hasDeclaredInitializer = (initializerToken != null);
     return formal;
@@ -2955,8 +2959,8 @@
   }
 
   void exportMemberFromPatch(String name, Builder member) {
-    if (uri.scheme != "dart" || !uri.path.startsWith("_")) {
-      addProblem(templatePatchInjectionFailed.withArguments(name, uri),
+    if (importUri.scheme != "dart" || !importUri.path.startsWith("_")) {
+      addProblem(templatePatchInjectionFailed.withArguments(name, importUri),
           member.charOffset, noLength, member.fileUri);
     }
     // Platform-private libraries, such as "dart:_internal" have special
@@ -3057,10 +3061,45 @@
     addProblem(message, fileOffset, noLength, fileUri, context: context);
   }
 
-  void checkBoundsInField(Field field, TypeEnvironment typeEnvironment) {
-    checkBoundsInType(
-        field.type, typeEnvironment, field.fileUri, field.fileOffset,
+  void checkTypesInField(
+      FieldBuilder fieldBuilder, TypeEnvironment typeEnvironment) {
+    // Check the bounds in the field's type.
+    checkBoundsInType(fieldBuilder.field.type, typeEnvironment,
+        fieldBuilder.fileUri, fieldBuilder.field.fileOffset,
         allowSuperBounded: true);
+
+    // Check that the field has an initializer if its type is potentially
+    // non-nullable.
+    if (isNonNullableByDefault && loader.performNnbdChecks) {
+      // Only static and top-level fields are checked here.  Instance fields are
+      // checked elsewhere.
+      DartType fieldType = fieldBuilder.field.type;
+      if (!fieldBuilder.isDeclarationInstanceMember &&
+          !fieldBuilder.field.isLate &&
+          fieldType is! InvalidType &&
+          fieldType.isPotentiallyNonNullable &&
+          !fieldBuilder.hasInitializer) {
+        if (loader.nnbdStrongMode) {
+          addProblem(
+              templateFieldNonNullableWithoutInitializerError.withArguments(
+                  fieldBuilder.name,
+                  fieldBuilder.field.type,
+                  isNonNullableByDefault),
+              fieldBuilder.charOffset,
+              fieldBuilder.name.length,
+              fileUri);
+        } else {
+          addProblem(
+              templateFieldNonNullableWithoutInitializerWarning.withArguments(
+                  fieldBuilder.name,
+                  fieldBuilder.field.type,
+                  isNonNullableByDefault),
+              fieldBuilder.charOffset,
+              fieldBuilder.name.length,
+              fileUri);
+        }
+      }
+    }
   }
 
   void checkInitializersInFormals(List<FormalParameterBuilder> formals) {
@@ -3334,7 +3373,7 @@
     while (iterator.moveNext()) {
       Builder declaration = iterator.current;
       if (declaration is FieldBuilder) {
-        checkBoundsInField(declaration.field, typeEnvironment);
+        checkTypesInField(declaration, typeEnvironment);
       } else if (declaration is ProcedureBuilder) {
         checkBoundsInFunctionNode(declaration.procedure.function,
             typeEnvironment, declaration.fileUri);
@@ -3683,7 +3722,7 @@
 Uri computeLibraryUri(Builder declaration) {
   Builder current = declaration;
   do {
-    if (current is LibraryBuilder) return current.uri;
+    if (current is LibraryBuilder) return current.importUri;
     current = current.parent;
   } while (current != null);
   return unhandled("no library parent", "${declaration.runtimeType}",
diff --git a/pkg/front_end/lib/src/fasta/source/source_loader.dart b/pkg/front_end/lib/src/fasta/source/source_loader.dart
index 087edf8..9a79867 100644
--- a/pkg/front_end/lib/src/fasta/source/source_loader.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -20,6 +20,7 @@
     show
         ErrorToken,
         LanguageVersionToken,
+        Scanner,
         ScannerConfiguration,
         ScannerResult,
         Token,
@@ -205,16 +206,17 @@
     if (bytes == null) {
       // Error recovery.
       if (uri.scheme == untranslatableUriScheme) {
-        Message message = templateUntranslatableUri.withArguments(library.uri);
+        Message message =
+            templateUntranslatableUri.withArguments(library.importUri);
         library.addProblemAtAccessors(message);
-        bytes = synthesizeSourceForMissingFile(library.uri, null);
+        bytes = synthesizeSourceForMissingFile(library.importUri, null);
       } else if (!uri.hasScheme) {
         return internalProblem(
             templateInternalProblemUriMissingScheme.withArguments(uri),
             -1,
-            library.uri);
+            library.importUri);
       } else if (uri.scheme == SourceLibraryBuilder.MALFORMED_URI_SCHEME) {
-        bytes = synthesizeSourceForMissingFile(library.uri, null);
+        bytes = synthesizeSourceForMissingFile(library.importUri, null);
       }
       if (bytes != null) {
         Uint8List zeroTerminatedBytes = new Uint8List(bytes.length + 1);
@@ -233,7 +235,7 @@
       } on FileSystemException catch (e) {
         Message message = templateCantReadFile.withArguments(uri, e.message);
         library.addProblemAtAccessors(message);
-        rawBytes = synthesizeSourceForMissingFile(library.uri, message);
+        rawBytes = synthesizeSourceForMissingFile(library.importUri, message);
       }
       Uint8List zeroTerminatedBytes = new Uint8List(rawBytes.length + 1);
       zeroTerminatedBytes.setRange(0, rawBytes.length, rawBytes);
@@ -247,15 +249,20 @@
         configuration: new ScannerConfiguration(
             enableTripleShift: target.enableTripleShift,
             enableExtensionMethods: target.enableExtensionMethods,
-            enableNonNullable: target.enableNonNullable),
-        languageVersionChanged: (_, LanguageVersionToken version) {
+            enableNonNullable: library.isNonNullableByDefault),
+        languageVersionChanged:
+            (Scanner scanner, LanguageVersionToken version) {
       library.setLanguageVersion(version.major, version.minor,
           offset: version.offset, length: version.length, explicit: true);
+      scanner.configuration = new ScannerConfiguration(
+          enableTripleShift: target.enableTripleShift,
+          enableExtensionMethods: target.enableExtensionMethods,
+          enableNonNullable: library.isNonNullableByDefault);
     });
     Token token = result.tokens;
     if (!suppressLexicalErrors) {
       List<int> source = getSource(bytes);
-      Uri importUri = library.uri;
+      Uri importUri = library.importUri;
       if (library.isPatch) {
         // For patch files we create a "fake" import uri.
         // We cannot use the import uri from the patched library because
@@ -879,7 +886,7 @@
     builders.forEach((Uri uri, LibraryBuilder libraryBuilder) {
       if (!libraryBuilder.isPatch &&
           (libraryBuilder.loader == this ||
-              libraryBuilder.uri.scheme == "dart" ||
+              libraryBuilder.importUri.scheme == "dart" ||
               libraryBuilder == this.first)) {
         if (libraries.add(libraryBuilder.library)) {
           workList.add(libraryBuilder.library);
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart b/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart
index c43f4c3..d2dbbc0 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart
@@ -55,23 +55,56 @@
 }
 
 /// Returns [type] in which all promoted type variables have been replace with
-/// their unpromoted equivalents.
-DartType demoteType(DartType type) {
-  return type.accept(const _TypeVariableDemotion()) ?? type;
+/// their unpromoted equivalents, and, if [library] is non-nullable by default,
+/// replaces all legacy types with their non-nullable equivalents.
+DartType demoteTypeInLibrary(DartType type, Library library) {
+  if (library.isNonNullableByDefault) {
+    return type.accept(const _DemotionNonNullification()) ?? type;
+  } else {
+    return type
+            .accept(const _DemotionNonNullification(nonNullifyTypes: false)) ??
+        type;
+  }
 }
 
-/// Visitor that replaces all promoted type variables the type variable itself.
+/// Returns [type] in which all legacy types have been replaced with
+/// non-nullable types.
+DartType nonNullifyInLibrary(DartType type, Library library) {
+  if (library.isNonNullableByDefault) {
+    return type.accept(
+            const _DemotionNonNullification(demoteTypeVariables: false)) ??
+        type;
+  }
+  return type;
+}
+
+/// Visitor that replaces all promoted type variables the type variable itself
+/// and/or replaces all legacy types with non-nullable types.
 ///
 /// The visitor returns `null` if the type wasn't changed.
-class _TypeVariableDemotion extends ReplacementVisitor {
-  const _TypeVariableDemotion();
+class _DemotionNonNullification extends ReplacementVisitor {
+  final bool demoteTypeVariables;
+  final bool nonNullifyTypes;
+
+  const _DemotionNonNullification(
+      {this.demoteTypeVariables: true, this.nonNullifyTypes: true})
+      : assert(demoteTypeVariables || nonNullifyTypes);
+
+  @override
+  Nullability visitNullability(DartType node) {
+    if (nonNullifyTypes && node.nullability == Nullability.legacy) {
+      return Nullability.nonNullable;
+    }
+    return null;
+  }
 
   @override
   DartType visitTypeParameterType(TypeParameterType node) {
-    if (node.promotedBound != null) {
+    Nullability newNullability = visitNullability(node);
+    if (demoteTypeVariables && node.promotedBound != null) {
       return new TypeParameterType(
-          node.parameter, node.typeParameterTypeNullability);
+          node.parameter, newNullability ?? node.typeParameterTypeNullability);
     }
-    return node;
+    return createTypeParameterType(node, newNullability);
   }
 }
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index 91e493c..72cebf9 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -48,7 +48,7 @@
 
 import '../names.dart';
 
-import '../problems.dart' show unexpected, unhandled;
+import '../problems.dart' show internalProblem, unexpected, unhandled;
 
 import '../source/source_library_builder.dart' show SourceLibraryBuilder;
 
@@ -356,7 +356,7 @@
           returnExpressionTypes[i]);
     }
 
-    return inferredType;
+    return demoteTypeInLibrary(inferredType, inferrer.library.library);
   }
 
   DartType _wrapAsyncOrGenerator(
@@ -541,6 +541,10 @@
           ? const NeverType(Nullability.nonNullable)
           : type;
     }
+    if (type is TypeParameterType && type.promotedBound != null) {
+      return new TypeParameterType(type.parameter, Nullability.nonNullable,
+          computeNonNullable(type.promotedBound));
+    }
     return type.withNullability(library.nonNullable);
   }
 
@@ -1047,6 +1051,24 @@
       target = new ObjectAccessTarget.interfaceMember(interfaceMember);
     } else if (receiverType is DynamicType) {
       target = const ObjectAccessTarget.dynamic();
+    } else if (receiverType is NeverType) {
+      switch (receiverType.nullability) {
+        case Nullability.nonNullable:
+          target = const ObjectAccessTarget.never();
+          break;
+        case Nullability.nullable:
+        case Nullability.legacy:
+          // Never? and Never* are equivalent to Null.
+          return findInterfaceMember(coreTypes.nullType, name, fileOffset);
+        case Nullability.undetermined:
+          return internalProblem(
+              templateInternalProblemUnsupportedNullability.withArguments(
+                  "${receiverType.nullability}",
+                  receiverType,
+                  isNonNullableByDefault),
+              fileOffset,
+              library.fileUri);
+      }
     } else if (receiverType is InvalidType) {
       target = const ObjectAccessTarget.invalid();
     } else if (receiverType is InterfaceType &&
@@ -1150,7 +1172,8 @@
                         thisBuilder.kind,
                         inferredTypeArguments)
                     : const ObjectAccessTarget.missing(),
-                isPlatform: extensionBuilder.library.uri.scheme == 'dart');
+                isPlatform:
+                    extensionBuilder.library.importUri.scheme == 'dart');
             if (noneMoreSpecific.isNotEmpty) {
               bool isMostSpecific = true;
               for (ExtensionAccessCandidate other in noneMoreSpecific) {
@@ -1351,6 +1374,8 @@
       case ObjectAccessTargetKind.invalid:
       case ObjectAccessTargetKind.missing:
         return const DynamicType();
+      case ObjectAccessTargetKind.never:
+        return const NeverType(Nullability.nonNullable);
       case ObjectAccessTargetKind.instanceMember:
         return getGetterTypeForMemberTarget(target.member, receiverType);
       case ObjectAccessTargetKind.extensionMember:
@@ -1451,6 +1476,7 @@
         return _getFunctionType(receiverType);
       case ObjectAccessTargetKind.unresolved:
       case ObjectAccessTargetKind.dynamic:
+      case ObjectAccessTargetKind.never:
       case ObjectAccessTargetKind.invalid:
       case ObjectAccessTargetKind.missing:
         return unknownFunction;
@@ -1514,6 +1540,8 @@
             throw unhandled('$target', 'getFunctionType', null, null);
         }
         break;
+      case ObjectAccessTargetKind.never:
+        return const NeverType(Nullability.nonNullable);
       case ObjectAccessTargetKind.callFunction:
       case ObjectAccessTargetKind.unresolved:
       case ObjectAccessTargetKind.dynamic:
@@ -1551,6 +1579,7 @@
       case ObjectAccessTargetKind.callFunction:
       case ObjectAccessTargetKind.unresolved:
       case ObjectAccessTargetKind.dynamic:
+      case ObjectAccessTargetKind.never:
       case ObjectAccessTargetKind.invalid:
       case ObjectAccessTargetKind.missing:
         break;
@@ -1609,6 +1638,7 @@
       case ObjectAccessTargetKind.callFunction:
       case ObjectAccessTargetKind.unresolved:
       case ObjectAccessTargetKind.dynamic:
+      case ObjectAccessTargetKind.never:
       case ObjectAccessTargetKind.invalid:
       case ObjectAccessTargetKind.missing:
         break;
@@ -1664,6 +1694,7 @@
       case ObjectAccessTargetKind.callFunction:
       case ObjectAccessTargetKind.unresolved:
       case ObjectAccessTargetKind.dynamic:
+      case ObjectAccessTargetKind.never:
       case ObjectAccessTargetKind.invalid:
       case ObjectAccessTargetKind.missing:
         break;
@@ -1718,6 +1749,7 @@
     switch (target.kind) {
       case ObjectAccessTargetKind.unresolved:
       case ObjectAccessTargetKind.dynamic:
+      case ObjectAccessTargetKind.never:
       case ObjectAccessTargetKind.invalid:
       case ObjectAccessTargetKind.missing:
         return const DynamicType();
@@ -1840,7 +1872,8 @@
   }
 
   /// Modifies a type as appropriate when inferring a declared variable's type.
-  DartType inferDeclarationType(DartType initializerType) {
+  DartType inferDeclarationType(DartType initializerType,
+      {bool forSyntheticVariable: false}) {
     if (initializerType is BottomType ||
         (initializerType is InterfaceType &&
             initializerType.classNode == coreTypes.nullClass)) {
@@ -1850,7 +1883,11 @@
       // not spec'ed anywhere.
       return const DynamicType();
     }
-    return demoteType(initializerType);
+    if (forSyntheticVariable) {
+      return nonNullifyInLibrary(initializerType, library.library);
+    } else {
+      return demoteTypeInLibrary(initializerType, library.library);
+    }
   }
 
   void inferSyntheticVariable(VariableDeclarationImpl variable) {
@@ -1860,7 +1897,8 @@
         variable.initializer, const UnknownType(), true,
         isVoidAllowed: true);
     variable.initializer = result.expression..parent = variable;
-    DartType inferredType = inferDeclarationType(result.inferredType);
+    DartType inferredType =
+        inferDeclarationType(result.inferredType, forSyntheticVariable: true);
     instrumentation?.record(uriForInstrumentation, variable.fileOffset, 'type',
         new InstrumentationValueForType(inferredType));
     variable.type = inferredType;
@@ -1881,7 +1919,8 @@
       variable.initializer = result.expression..parent = variable;
       nullAwareGuards = const Link<NullAwareGuard>();
     }
-    DartType inferredType = inferDeclarationType(result.inferredType);
+    DartType inferredType =
+        inferDeclarationType(result.inferredType, forSyntheticVariable: true);
     instrumentation?.record(uriForInstrumentation, variable.fileOffset, 'type',
         new InstrumentationValueForType(inferredType));
     variable.type = inferredType;
@@ -2482,7 +2521,7 @@
         }
         instrumentation?.record(uriForInstrumentation, formal.fileOffset,
             'type', new InstrumentationValueForType(inferredType));
-        formal.type = inferredType;
+        formal.type = demoteTypeInLibrary(inferredType, library.library);
       }
 
       if (isNonNullableByDefault && performNnbdChecks) {
@@ -2502,7 +2541,7 @@
                         formal.name, formal.type, isNonNullableByDefault),
                 formal.fileOffset,
                 formal.name.length,
-                library.uri);
+                library.importUri);
           } else {
             library.addProblem(
                 templateOptionalNonNullableWithoutInitializerWarning
@@ -2510,7 +2549,7 @@
                         formal.name, formal.type, isNonNullableByDefault),
                 formal.fileOffset,
                 formal.name.length,
-                library.uri);
+                library.importUri);
           }
         }
       }
@@ -2526,14 +2565,14 @@
                     .withArguments(formal.name),
                 formal.fileOffset,
                 formal.name.length,
-                library.uri);
+                library.importUri);
           } else {
             library.addProblem(
                 templateRequiredNamedParameterHasDefaultValueWarning
                     .withArguments(formal.name),
                 formal.fileOffset,
                 formal.name.length,
-                library.uri);
+                library.importUri);
           }
         }
       }
@@ -2639,6 +2678,25 @@
         nullAwareGuards);
   }
 
+  ExpressionInferenceResult _inferNeverInvocation(
+      int fileOffset,
+      Link<NullAwareGuard> nullAwareGuards,
+      Expression receiver,
+      NeverType receiverType,
+      Name name,
+      Arguments arguments,
+      DartType typeContext) {
+    InvocationInferenceResult result = inferInvocation(
+        typeContext, fileOffset, unknownFunction, arguments, name,
+        receiverType: receiverType);
+    assert(name != equalsName);
+    return createNullAwareExpressionInferenceResult(
+        result.inferredType,
+        result.applyResult(new MethodInvocation(receiver, name, arguments)
+          ..fileOffset = fileOffset),
+        nullAwareGuards);
+  }
+
   ExpressionInferenceResult _inferMissingInvocation(
       int fileOffset,
       Link<NullAwareGuard> nullAwareGuards,
@@ -3034,6 +3092,9 @@
       case ObjectAccessTargetKind.unresolved:
         return _inferDynamicInvocation(fileOffset, nullAwareGuards, receiver,
             name, arguments, typeContext);
+      case ObjectAccessTargetKind.never:
+        return _inferNeverInvocation(fileOffset, nullAwareGuards, receiver,
+            receiverType, name, arguments, typeContext);
     }
     return unhandled(
         '$target', 'inferMethodInvocation', fileOffset, uriForInstrumentation);
@@ -3919,6 +3980,7 @@
   callFunction,
   extensionMember,
   dynamic,
+  never,
   invalid,
   missing,
   // TODO(johnniwinther): Remove this.
@@ -3960,6 +4022,10 @@
   const ObjectAccessTarget.dynamic()
       : this.internal(ObjectAccessTargetKind.dynamic, null);
 
+  /// Creates an access on a receiver of type Never with no known target.
+  const ObjectAccessTarget.never()
+      : this.internal(ObjectAccessTargetKind.never, null);
+
   /// Creates an access with no target due to an invalid receiver type.
   ///
   /// This is not in itself an error but a consequence of another error.
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart b/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart
index 3b0d487..789301a 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart
@@ -204,6 +204,7 @@
       List<DartType> inferredTypes,
       Library clientLibrary,
       {bool isConst: false}) {
+    assert((formalTypes?.length ?? 0) == (actualTypes?.length ?? 0));
     if (typeParametersToInfer.isEmpty) {
       return;
     }
@@ -236,7 +237,7 @@
         downwardsInferPhase: formalTypes == null);
 
     for (int i = 0; i < inferredTypes.length; i++) {
-      inferredTypes[i] = demoteType(inferredTypes[i]);
+      inferredTypes[i] = demoteTypeInLibrary(inferredTypes[i], clientLibrary);
     }
   }
 
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index e7fbe16..4ea9e45 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -72,6 +72,10 @@
 ConstAndFinal/part_wrapped_declaration3: Fail
 ConstAndFinal/part_wrapped_declaration4: Fail
 ConstConstructorInSubclassOfMixinApplication/example: Fail
+ConstConstructorLateFinalFieldError/analyzerCode: Fail
+ConstConstructorLateFinalFieldError/example: Fail
+ConstConstructorLateFinalFieldWarning/analyzerCode: Fail
+ConstConstructorLateFinalFieldWarning/example: Fail
 ConstConstructorNonFinalField/example: Fail
 ConstConstructorRedirectionToNonConst/analyzerCode: Fail # The analyzer doesn't report this error.
 ConstEvalCircularity/example: Fail
@@ -135,6 +139,10 @@
 CyclicClassHierarchy/script1: Fail # We report an error for each class involved in the cycle.
 CyclicClassHierarchy/script2: Fail # We report an error for each class involved in the cycle.
 CyclicTypedef/example: Fail
+DefaultListConstructorError/analyzerCode: Fail
+DefaultListConstructorError/example: Fail
+DefaultListConstructorWarning/analyzerCode: Fail
+DefaultListConstructorWarning/example: Fail
 DeferredAfterPrefix/example: Fail
 DeferredExtensionImport/analyzerCode: Fail
 DeferredExtensionImport/part_wrapped_script: Fail
@@ -292,6 +300,14 @@
 FieldInitializedOutsideDeclaringClass/script1: Fail
 FieldInitializerOutsideConstructor/part_wrapped_script1: Fail
 FieldInitializerOutsideConstructor/script1: Fail
+FieldNonNullableNotInitializedByConstructorError/analyzerCode: Fail
+FieldNonNullableNotInitializedByConstructorError/example: Fail
+FieldNonNullableNotInitializedByConstructorWarning/analyzerCode: Fail
+FieldNonNullableNotInitializedByConstructorWarning/example: Fail
+FieldNonNullableWithoutInitializerError/analyzerCode: Fail
+FieldNonNullableWithoutInitializerError/example: Fail
+FieldNonNullableWithoutInitializerWarning/analyzerCode: Fail
+FieldNonNullableWithoutInitializerWarning/example: Fail
 FinalAndCovariant/part_wrapped_script2: Fail
 FinalAndCovariant/script2: Fail
 FinalFieldWithoutInitializer/example: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 1ff32f8..b81fef3 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -1704,6 +1704,10 @@
   template: "Unfinished type variable '#name' found in non-source library '#uri'."
   severity: INTERNAL_PROBLEM
 
+InternalProblemUnsupportedNullability:
+  template: "Unsupported nullability value '#string' on type '#type'."
+  severity: INTERNAL_PROBLEM
+
 LocalDefinitionHidesExport:
   template: "Local definition of '#name' hides export from '#uri'."
   severity: IGNORED
@@ -2727,6 +2731,17 @@
   template: "Field isn't final, but constructor is 'const'."
   severity: CONTEXT
 
+ConstConstructorLateFinalFieldError:
+  template: "Constructor is marked 'const' so fields can't be late."
+
+ConstConstructorLateFinalFieldWarning:
+  template: "Constructor is marked 'const' and some fields are late."
+  severity: WARNING
+
+ConstConstructorLateFinalFieldCause:
+  template: "Field is late, but constructor is 'const'."
+  severity: CONTEXT
+
 ConstConstructorRedirectionToNonConst:
   template: "A constant constructor can't call a non-constant constructor."
   script:
@@ -3833,6 +3848,20 @@
   template: "Optional parameter '#name' doesn't have a default value and its type '#type' doesn't allow null."
   severity: WARNING
 
+FieldNonNullableWithoutInitializerError:
+  template: "Field '#name' should be initialized because its type '#type' doesn't allow null."
+
+FieldNonNullableWithoutInitializerWarning:
+  template: "Field '#name' isn't initialized and its type '#type' doesn't allow null."
+  severity: WARNING
+
+FieldNonNullableNotInitializedByConstructorError:
+  template: "This constructor should initialize field '#name' because its type '#type' doesn't allow null."
+
+FieldNonNullableNotInitializedByConstructorWarning:
+  template: "This constructor doesn't initialize field '#name' and its type '#type' doesn't allow null."
+  severity: WARNING
+
 NonNullableOptOut:
   template: "Null safety features are disabled for this library."
   tip: "Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`."
@@ -3868,3 +3897,12 @@
 JsInteropIndexNotSupported:
   template: "JS interop classes do not support [] and []= operator methods."
   tip: "Try replacing with a normal method."
+
+DefaultListConstructorError:
+  template: "Can't use the default List constructor."
+  tip: "Try using List.filled instead."
+
+DefaultListConstructorWarning:
+  template: "Using the default List constructor."
+  tip: "Try using List.filled instead."
+  severity: WARNING
diff --git a/pkg/front_end/parser_testcases/non-nnbd/issue_40288.dart b/pkg/front_end/parser_testcases/non-nnbd/issue_40288.dart
new file mode 100644
index 0000000..59cb3c5
--- /dev/null
+++ b/pkg/front_end/parser_testcases/non-nnbd/issue_40288.dart
@@ -0,0 +1,12 @@
+class late {
+  int get g => 1;
+}
+
+class required {
+  int get g => 2;
+}
+
+class C {
+  late l = late();
+  required r = required();
+}
diff --git a/pkg/front_end/parser_testcases/non-nnbd/issue_40288.dart.expect b/pkg/front_end/parser_testcases/non-nnbd/issue_40288.dart.expect
new file mode 100644
index 0000000..fa5b46a
--- /dev/null
+++ b/pkg/front_end/parser_testcases/non-nnbd/issue_40288.dart.expect
@@ -0,0 +1,111 @@
+beginCompilationUnit(class)
+  beginMetadataStar(class)
+  endMetadataStar(0)
+  beginClassOrNamedMixinApplicationPrelude(class)
+    handleIdentifier(late, classOrMixinDeclaration)
+    handleNoTypeVariables({)
+    beginClassDeclaration(class, null, late)
+      handleNoType(late)
+      handleClassExtends(null)
+      handleClassNoWithClause()
+      handleClassOrMixinImplements(null, 0)
+      handleClassHeader(class, class, null)
+      beginClassOrMixinBody(DeclarationKind.Class, {)
+        beginMetadataStar(int)
+        endMetadataStar(0)
+        beginMember()
+          beginMethod(null, null, null, null, get, g)
+            handleIdentifier(int, typeReference)
+            handleNoTypeArguments(get)
+            handleType(int, null)
+            handleIdentifier(g, methodDeclaration)
+            handleNoTypeVariables(=>)
+            handleNoFormalParameters(=>, MemberKind.NonStaticMethod)
+            handleNoInitializers()
+            handleAsyncModifier(null, null)
+            handleLiteralInt(1)
+            handleExpressionFunctionBody(=>, ;)
+          endClassMethod(get, int, =>, null, ;)
+        endMember()
+      endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+    endClassDeclaration(class, })
+  endTopLevelDeclaration(class)
+  beginMetadataStar(class)
+  endMetadataStar(0)
+  beginClassOrNamedMixinApplicationPrelude(class)
+    handleIdentifier(required, classOrMixinDeclaration)
+    handleNoTypeVariables({)
+    beginClassDeclaration(class, null, required)
+      handleNoType(required)
+      handleClassExtends(null)
+      handleClassNoWithClause()
+      handleClassOrMixinImplements(null, 0)
+      handleClassHeader(class, class, null)
+      beginClassOrMixinBody(DeclarationKind.Class, {)
+        beginMetadataStar(int)
+        endMetadataStar(0)
+        beginMember()
+          beginMethod(null, null, null, null, get, g)
+            handleIdentifier(int, typeReference)
+            handleNoTypeArguments(get)
+            handleType(int, null)
+            handleIdentifier(g, methodDeclaration)
+            handleNoTypeVariables(=>)
+            handleNoFormalParameters(=>, MemberKind.NonStaticMethod)
+            handleNoInitializers()
+            handleAsyncModifier(null, null)
+            handleLiteralInt(2)
+            handleExpressionFunctionBody(=>, ;)
+          endClassMethod(get, int, =>, null, ;)
+        endMember()
+      endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+    endClassDeclaration(class, })
+  endTopLevelDeclaration(class)
+  beginMetadataStar(class)
+  endMetadataStar(0)
+  beginClassOrNamedMixinApplicationPrelude(class)
+    handleIdentifier(C, classOrMixinDeclaration)
+    handleNoTypeVariables({)
+    beginClassDeclaration(class, null, C)
+      handleNoType(C)
+      handleClassExtends(null)
+      handleClassNoWithClause()
+      handleClassOrMixinImplements(null, 0)
+      handleClassHeader(class, class, null)
+      beginClassOrMixinBody(DeclarationKind.Class, {)
+        beginMetadataStar(late)
+        endMetadataStar(0)
+        beginMember()
+          handleIdentifier(late, typeReference)
+          handleNoTypeArguments(l)
+          handleType(late, null)
+          handleIdentifier(l, fieldDeclaration)
+          beginFieldInitializer(=)
+            handleIdentifier(late, expression)
+            handleNoTypeArguments(()
+            beginArguments(()
+            endArguments(0, (, ))
+            handleSend(late, ;)
+          endFieldInitializer(=, ;)
+        endClassFields(null, null, null, null, 1, late, ;)
+      endMember()
+      beginMetadataStar(required)
+      endMetadataStar(0)
+      beginMember()
+        handleIdentifier(required, typeReference)
+        handleNoTypeArguments(r)
+        handleType(required, null)
+        handleIdentifier(r, fieldDeclaration)
+        beginFieldInitializer(=)
+          handleIdentifier(required, expression)
+          handleNoTypeArguments(()
+          beginArguments(()
+          endArguments(0, (, ))
+          handleSend(required, ;)
+        endFieldInitializer(=, ;)
+      endClassFields(null, null, null, null, 1, required, ;)
+    endMember()
+  endClassOrMixinBody(DeclarationKind.Class, 2, {, })
+endClassDeclaration(class, })
+endTopLevelDeclaration()
+endCompilationUnit(3, )
diff --git a/pkg/front_end/parser_testcases/non-nnbd/issue_40288.dart.intertwined.expect b/pkg/front_end/parser_testcases/non-nnbd/issue_40288.dart.intertwined.expect
new file mode 100644
index 0000000..ceb712e
--- /dev/null
+++ b/pkg/front_end/parser_testcases/non-nnbd/issue_40288.dart.intertwined.expect
@@ -0,0 +1,228 @@
+parseUnit(class)
+  skipErrorTokens(class)
+  listener: beginCompilationUnit(class)
+  syntheticPreviousToken(class)
+  parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+    parseMetadataStar()
+      listener: beginMetadataStar(class)
+      listener: endMetadataStar(0)
+    parseTopLevelKeywordDeclaration(, class, Instance of 'DirectiveContext')
+      parseClassDeclarationModifiers(, class)
+      parseClassOrNamedMixinApplication(null, class)
+        listener: beginClassOrNamedMixinApplicationPrelude(class)
+        ensureIdentifier(class, classOrMixinDeclaration)
+          listener: handleIdentifier(late, classOrMixinDeclaration)
+        listener: handleNoTypeVariables({)
+        listener: beginClassDeclaration(class, null, late)
+        parseClass(late, class, class, late)
+          parseClassHeaderOpt(late, class, class)
+            parseClassExtendsOpt(late)
+              listener: handleNoType(late)
+              listener: handleClassExtends(null)
+            parseWithClauseOpt(late)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(late)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassOrMixinOrExtensionBody(late, DeclarationKind.Class, late)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, int)
+            parseClassOrMixinOrExtensionMemberImpl({, DeclarationKind.Class, late)
+              parseMetadataStar({)
+                listener: beginMetadataStar(int)
+                listener: endMetadataStar(0)
+              listener: beginMember()
+              parseMethod({, null, null, null, null, null, {, Instance of 'SimpleType', get, g, DeclarationKind.Class, late)
+                listener: beginMethod(null, null, null, null, get, g)
+                listener: handleIdentifier(int, typeReference)
+                listener: handleNoTypeArguments(get)
+                listener: handleType(int, null)
+                ensureIdentifier(get, methodDeclaration)
+                  listener: handleIdentifier(g, methodDeclaration)
+                listener: handleNoTypeVariables(=>)
+                parseGetterOrFormalParameters(g, g, true, MemberKind.NonStaticMethod)
+                  listener: handleNoFormalParameters(=>, MemberKind.NonStaticMethod)
+                parseInitializersOpt(g)
+                  listener: handleNoInitializers()
+                parseAsyncModifierOpt(g)
+                  listener: handleAsyncModifier(null, null)
+                  inPlainSync()
+                inPlainSync()
+                inPlainSync()
+                parseFunctionBody(g, false, true)
+                  parseExpressionFunctionBody(=>, false)
+                    parseExpression(=>)
+                      parsePrecedenceExpression(=>, 1, true)
+                        parseUnaryExpression(=>, true)
+                          parsePrimary(=>, expression)
+                            parseLiteralInt(=>)
+                              listener: handleLiteralInt(1)
+                    ensureSemicolon(1)
+                    listener: handleExpressionFunctionBody(=>, ;)
+                    inGenerator()
+                listener: endClassMethod(get, int, =>, null, ;)
+              listener: endMember()
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+          listener: endClassDeclaration(class, })
+  listener: endTopLevelDeclaration(class)
+  parseTopLevelDeclarationImpl(}, Instance of 'DirectiveContext')
+    parseMetadataStar(})
+      listener: beginMetadataStar(class)
+      listener: endMetadataStar(0)
+    parseTopLevelKeywordDeclaration(}, class, Instance of 'DirectiveContext')
+      parseClassDeclarationModifiers(}, class)
+      parseClassOrNamedMixinApplication(null, class)
+        listener: beginClassOrNamedMixinApplicationPrelude(class)
+        ensureIdentifier(class, classOrMixinDeclaration)
+          listener: handleIdentifier(required, classOrMixinDeclaration)
+        listener: handleNoTypeVariables({)
+        listener: beginClassDeclaration(class, null, required)
+        parseClass(required, class, class, required)
+          parseClassHeaderOpt(required, class, class)
+            parseClassExtendsOpt(required)
+              listener: handleNoType(required)
+              listener: handleClassExtends(null)
+            parseWithClauseOpt(required)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(required)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassOrMixinOrExtensionBody(required, DeclarationKind.Class, required)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, int)
+            parseClassOrMixinOrExtensionMemberImpl({, DeclarationKind.Class, required)
+              parseMetadataStar({)
+                listener: beginMetadataStar(int)
+                listener: endMetadataStar(0)
+              listener: beginMember()
+              parseMethod({, null, null, null, null, null, {, Instance of 'SimpleType', get, g, DeclarationKind.Class, required)
+                listener: beginMethod(null, null, null, null, get, g)
+                listener: handleIdentifier(int, typeReference)
+                listener: handleNoTypeArguments(get)
+                listener: handleType(int, null)
+                ensureIdentifier(get, methodDeclaration)
+                  listener: handleIdentifier(g, methodDeclaration)
+                listener: handleNoTypeVariables(=>)
+                parseGetterOrFormalParameters(g, g, true, MemberKind.NonStaticMethod)
+                  listener: handleNoFormalParameters(=>, MemberKind.NonStaticMethod)
+                parseInitializersOpt(g)
+                  listener: handleNoInitializers()
+                parseAsyncModifierOpt(g)
+                  listener: handleAsyncModifier(null, null)
+                  inPlainSync()
+                inPlainSync()
+                inPlainSync()
+                parseFunctionBody(g, false, true)
+                  parseExpressionFunctionBody(=>, false)
+                    parseExpression(=>)
+                      parsePrecedenceExpression(=>, 1, true)
+                        parseUnaryExpression(=>, true)
+                          parsePrimary(=>, expression)
+                            parseLiteralInt(=>)
+                              listener: handleLiteralInt(2)
+                    ensureSemicolon(2)
+                    listener: handleExpressionFunctionBody(=>, ;)
+                    inGenerator()
+                listener: endClassMethod(get, int, =>, null, ;)
+              listener: endMember()
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+          listener: endClassDeclaration(class, })
+  listener: endTopLevelDeclaration(class)
+  parseTopLevelDeclarationImpl(}, Instance of 'DirectiveContext')
+    parseMetadataStar(})
+      listener: beginMetadataStar(class)
+      listener: endMetadataStar(0)
+    parseTopLevelKeywordDeclaration(}, class, Instance of 'DirectiveContext')
+      parseClassDeclarationModifiers(}, class)
+      parseClassOrNamedMixinApplication(null, class)
+        listener: beginClassOrNamedMixinApplicationPrelude(class)
+        ensureIdentifier(class, classOrMixinDeclaration)
+          listener: handleIdentifier(C, classOrMixinDeclaration)
+        listener: handleNoTypeVariables({)
+        listener: beginClassDeclaration(class, null, C)
+        parseClass(C, class, class, C)
+          parseClassHeaderOpt(C, class, class)
+            parseClassExtendsOpt(C)
+              listener: handleNoType(C)
+              listener: handleClassExtends(null)
+            parseWithClauseOpt(C)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(C)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassOrMixinOrExtensionBody(C, DeclarationKind.Class, C)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, late)
+            parseClassOrMixinOrExtensionMemberImpl({, DeclarationKind.Class, C)
+              parseMetadataStar({)
+                listener: beginMetadataStar(late)
+                listener: endMetadataStar(0)
+              listener: beginMember()
+              parseFields({, null, null, null, null, null, {, Instance of 'SimpleType', l, DeclarationKind.Class)
+                listener: handleIdentifier(late, typeReference)
+                listener: handleNoTypeArguments(l)
+                listener: handleType(late, null)
+                ensureIdentifier(late, fieldDeclaration)
+                  listener: handleIdentifier(l, fieldDeclaration)
+                parseFieldInitializerOpt(l, l, null, null, DeclarationKind.Class)
+                  listener: beginFieldInitializer(=)
+                  parseExpression(=)
+                    parsePrecedenceExpression(=, 1, true)
+                      parseUnaryExpression(=, true)
+                        parsePrimary(=, expression)
+                          parseSendOrFunctionLiteral(=, expression)
+                            looksLikeFunctionBody(;)
+                            parseSend(=, expression)
+                              ensureIdentifier(=, expression)
+                                listener: handleIdentifier(late, expression)
+                              listener: handleNoTypeArguments(()
+                              parseArgumentsOpt(late)
+                                parseArguments(late)
+                                  parseArgumentsRest(()
+                                    listener: beginArguments(()
+                                    listener: endArguments(0, (, ))
+                              listener: handleSend(late, ;)
+                  listener: endFieldInitializer(=, ;)
+                listener: endClassFields(null, null, null, null, 1, late, ;)
+              listener: endMember()
+            notEofOrValue(}, required)
+            parseClassOrMixinOrExtensionMemberImpl(;, DeclarationKind.Class, C)
+              parseMetadataStar(;)
+                listener: beginMetadataStar(required)
+                listener: endMetadataStar(0)
+              listener: beginMember()
+              parseFields(;, null, null, null, null, null, ;, Instance of 'SimpleType', r, DeclarationKind.Class)
+                listener: handleIdentifier(required, typeReference)
+                listener: handleNoTypeArguments(r)
+                listener: handleType(required, null)
+                ensureIdentifier(required, fieldDeclaration)
+                  listener: handleIdentifier(r, fieldDeclaration)
+                parseFieldInitializerOpt(r, r, null, null, DeclarationKind.Class)
+                  listener: beginFieldInitializer(=)
+                  parseExpression(=)
+                    parsePrecedenceExpression(=, 1, true)
+                      parseUnaryExpression(=, true)
+                        parsePrimary(=, expression)
+                          parseSendOrFunctionLiteral(=, expression)
+                            looksLikeFunctionBody(;)
+                            parseSend(=, expression)
+                              ensureIdentifier(=, expression)
+                                listener: handleIdentifier(required, expression)
+                              listener: handleNoTypeArguments(()
+                              parseArgumentsOpt(required)
+                                parseArguments(required)
+                                  parseArgumentsRest(()
+                                    listener: beginArguments(()
+                                    listener: endArguments(0, (, ))
+                              listener: handleSend(required, ;)
+                  listener: endFieldInitializer(=, ;)
+                listener: endClassFields(null, null, null, null, 1, required, ;)
+              listener: endMember()
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 2, {, })
+          listener: endClassDeclaration(class, })
+  listener: endTopLevelDeclaration()
+  reportAllErrorTokens(class)
+  listener: endCompilationUnit(3, )
diff --git a/pkg/front_end/parser_testcases/non-nnbd/issue_40288.dart.parser.expect b/pkg/front_end/parser_testcases/non-nnbd/issue_40288.dart.parser.expect
new file mode 100644
index 0000000..ffd3e65
--- /dev/null
+++ b/pkg/front_end/parser_testcases/non-nnbd/issue_40288.dart.parser.expect
@@ -0,0 +1,27 @@
+class late {
+int get g => 1;
+}
+
+class required {
+int get g => 2;
+}
+
+class C {
+late l = late();
+required r = required();
+}
+
+
+class[KeywordToken] late[StringToken] {[BeginToken]
+int[StringToken] get[KeywordToken] g[StringToken] =>[SimpleToken] 1[StringToken];[SimpleToken]
+}[SimpleToken]
+
+class[KeywordToken] required[StringToken] {[BeginToken]
+int[StringToken] get[KeywordToken] g[StringToken] =>[SimpleToken] 2[StringToken];[SimpleToken]
+}[SimpleToken]
+
+class[KeywordToken] C[StringToken] {[BeginToken]
+late[StringToken] l[StringToken] =[SimpleToken] late[StringToken]([BeginToken])[SimpleToken];[SimpleToken]
+required[StringToken] r[StringToken] =[SimpleToken] required[StringToken]([BeginToken])[SimpleToken];[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/non-nnbd/issue_40288.dart.scanner.expect b/pkg/front_end/parser_testcases/non-nnbd/issue_40288.dart.scanner.expect
new file mode 100644
index 0000000..ffd3e65
--- /dev/null
+++ b/pkg/front_end/parser_testcases/non-nnbd/issue_40288.dart.scanner.expect
@@ -0,0 +1,27 @@
+class late {
+int get g => 1;
+}
+
+class required {
+int get g => 2;
+}
+
+class C {
+late l = late();
+required r = required();
+}
+
+
+class[KeywordToken] late[StringToken] {[BeginToken]
+int[StringToken] get[KeywordToken] g[StringToken] =>[SimpleToken] 1[StringToken];[SimpleToken]
+}[SimpleToken]
+
+class[KeywordToken] required[StringToken] {[BeginToken]
+int[StringToken] get[KeywordToken] g[StringToken] =>[SimpleToken] 2[StringToken];[SimpleToken]
+}[SimpleToken]
+
+class[KeywordToken] C[StringToken] {[BeginToken]
+late[StringToken] l[StringToken] =[SimpleToken] late[StringToken]([BeginToken])[SimpleToken];[SimpleToken]
+required[StringToken] r[StringToken] =[SimpleToken] required[StringToken]([BeginToken])[SimpleToken];[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/non-nnbd/issue_40288_prime.dart b/pkg/front_end/parser_testcases/non-nnbd/issue_40288_prime.dart
new file mode 100644
index 0000000..0c6b0e6
--- /dev/null
+++ b/pkg/front_end/parser_testcases/non-nnbd/issue_40288_prime.dart
@@ -0,0 +1,12 @@
+class Xlate {
+  int get g => 1;
+}
+
+class Xrequired {
+  int get g => 2;
+}
+
+class C {
+  Xlate l = Xlate();
+  Xrequired r = Xrequired();
+}
diff --git a/pkg/front_end/parser_testcases/non-nnbd/issue_40288_prime.dart.expect b/pkg/front_end/parser_testcases/non-nnbd/issue_40288_prime.dart.expect
new file mode 100644
index 0000000..7d97c5e
--- /dev/null
+++ b/pkg/front_end/parser_testcases/non-nnbd/issue_40288_prime.dart.expect
@@ -0,0 +1,111 @@
+beginCompilationUnit(class)
+  beginMetadataStar(class)
+  endMetadataStar(0)
+  beginClassOrNamedMixinApplicationPrelude(class)
+    handleIdentifier(Xlate, classOrMixinDeclaration)
+    handleNoTypeVariables({)
+    beginClassDeclaration(class, null, Xlate)
+      handleNoType(Xlate)
+      handleClassExtends(null)
+      handleClassNoWithClause()
+      handleClassOrMixinImplements(null, 0)
+      handleClassHeader(class, class, null)
+      beginClassOrMixinBody(DeclarationKind.Class, {)
+        beginMetadataStar(int)
+        endMetadataStar(0)
+        beginMember()
+          beginMethod(null, null, null, null, get, g)
+            handleIdentifier(int, typeReference)
+            handleNoTypeArguments(get)
+            handleType(int, null)
+            handleIdentifier(g, methodDeclaration)
+            handleNoTypeVariables(=>)
+            handleNoFormalParameters(=>, MemberKind.NonStaticMethod)
+            handleNoInitializers()
+            handleAsyncModifier(null, null)
+            handleLiteralInt(1)
+            handleExpressionFunctionBody(=>, ;)
+          endClassMethod(get, int, =>, null, ;)
+        endMember()
+      endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+    endClassDeclaration(class, })
+  endTopLevelDeclaration(class)
+  beginMetadataStar(class)
+  endMetadataStar(0)
+  beginClassOrNamedMixinApplicationPrelude(class)
+    handleIdentifier(Xrequired, classOrMixinDeclaration)
+    handleNoTypeVariables({)
+    beginClassDeclaration(class, null, Xrequired)
+      handleNoType(Xrequired)
+      handleClassExtends(null)
+      handleClassNoWithClause()
+      handleClassOrMixinImplements(null, 0)
+      handleClassHeader(class, class, null)
+      beginClassOrMixinBody(DeclarationKind.Class, {)
+        beginMetadataStar(int)
+        endMetadataStar(0)
+        beginMember()
+          beginMethod(null, null, null, null, get, g)
+            handleIdentifier(int, typeReference)
+            handleNoTypeArguments(get)
+            handleType(int, null)
+            handleIdentifier(g, methodDeclaration)
+            handleNoTypeVariables(=>)
+            handleNoFormalParameters(=>, MemberKind.NonStaticMethod)
+            handleNoInitializers()
+            handleAsyncModifier(null, null)
+            handleLiteralInt(2)
+            handleExpressionFunctionBody(=>, ;)
+          endClassMethod(get, int, =>, null, ;)
+        endMember()
+      endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+    endClassDeclaration(class, })
+  endTopLevelDeclaration(class)
+  beginMetadataStar(class)
+  endMetadataStar(0)
+  beginClassOrNamedMixinApplicationPrelude(class)
+    handleIdentifier(C, classOrMixinDeclaration)
+    handleNoTypeVariables({)
+    beginClassDeclaration(class, null, C)
+      handleNoType(C)
+      handleClassExtends(null)
+      handleClassNoWithClause()
+      handleClassOrMixinImplements(null, 0)
+      handleClassHeader(class, class, null)
+      beginClassOrMixinBody(DeclarationKind.Class, {)
+        beginMetadataStar(Xlate)
+        endMetadataStar(0)
+        beginMember()
+          handleIdentifier(Xlate, typeReference)
+          handleNoTypeArguments(l)
+          handleType(Xlate, null)
+          handleIdentifier(l, fieldDeclaration)
+          beginFieldInitializer(=)
+            handleIdentifier(Xlate, expression)
+            handleNoTypeArguments(()
+            beginArguments(()
+            endArguments(0, (, ))
+            handleSend(Xlate, ;)
+          endFieldInitializer(=, ;)
+        endClassFields(null, null, null, null, 1, Xlate, ;)
+      endMember()
+      beginMetadataStar(Xrequired)
+      endMetadataStar(0)
+      beginMember()
+        handleIdentifier(Xrequired, typeReference)
+        handleNoTypeArguments(r)
+        handleType(Xrequired, null)
+        handleIdentifier(r, fieldDeclaration)
+        beginFieldInitializer(=)
+          handleIdentifier(Xrequired, expression)
+          handleNoTypeArguments(()
+          beginArguments(()
+          endArguments(0, (, ))
+          handleSend(Xrequired, ;)
+        endFieldInitializer(=, ;)
+      endClassFields(null, null, null, null, 1, Xrequired, ;)
+    endMember()
+  endClassOrMixinBody(DeclarationKind.Class, 2, {, })
+endClassDeclaration(class, })
+endTopLevelDeclaration()
+endCompilationUnit(3, )
diff --git a/pkg/front_end/parser_testcases/non-nnbd/issue_40288_prime.dart.intertwined.expect b/pkg/front_end/parser_testcases/non-nnbd/issue_40288_prime.dart.intertwined.expect
new file mode 100644
index 0000000..319b1ae
--- /dev/null
+++ b/pkg/front_end/parser_testcases/non-nnbd/issue_40288_prime.dart.intertwined.expect
@@ -0,0 +1,228 @@
+parseUnit(class)
+  skipErrorTokens(class)
+  listener: beginCompilationUnit(class)
+  syntheticPreviousToken(class)
+  parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+    parseMetadataStar()
+      listener: beginMetadataStar(class)
+      listener: endMetadataStar(0)
+    parseTopLevelKeywordDeclaration(, class, Instance of 'DirectiveContext')
+      parseClassDeclarationModifiers(, class)
+      parseClassOrNamedMixinApplication(null, class)
+        listener: beginClassOrNamedMixinApplicationPrelude(class)
+        ensureIdentifier(class, classOrMixinDeclaration)
+          listener: handleIdentifier(Xlate, classOrMixinDeclaration)
+        listener: handleNoTypeVariables({)
+        listener: beginClassDeclaration(class, null, Xlate)
+        parseClass(Xlate, class, class, Xlate)
+          parseClassHeaderOpt(Xlate, class, class)
+            parseClassExtendsOpt(Xlate)
+              listener: handleNoType(Xlate)
+              listener: handleClassExtends(null)
+            parseWithClauseOpt(Xlate)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(Xlate)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassOrMixinOrExtensionBody(Xlate, DeclarationKind.Class, Xlate)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, int)
+            parseClassOrMixinOrExtensionMemberImpl({, DeclarationKind.Class, Xlate)
+              parseMetadataStar({)
+                listener: beginMetadataStar(int)
+                listener: endMetadataStar(0)
+              listener: beginMember()
+              parseMethod({, null, null, null, null, null, {, Instance of 'SimpleType', get, g, DeclarationKind.Class, Xlate)
+                listener: beginMethod(null, null, null, null, get, g)
+                listener: handleIdentifier(int, typeReference)
+                listener: handleNoTypeArguments(get)
+                listener: handleType(int, null)
+                ensureIdentifier(get, methodDeclaration)
+                  listener: handleIdentifier(g, methodDeclaration)
+                listener: handleNoTypeVariables(=>)
+                parseGetterOrFormalParameters(g, g, true, MemberKind.NonStaticMethod)
+                  listener: handleNoFormalParameters(=>, MemberKind.NonStaticMethod)
+                parseInitializersOpt(g)
+                  listener: handleNoInitializers()
+                parseAsyncModifierOpt(g)
+                  listener: handleAsyncModifier(null, null)
+                  inPlainSync()
+                inPlainSync()
+                inPlainSync()
+                parseFunctionBody(g, false, true)
+                  parseExpressionFunctionBody(=>, false)
+                    parseExpression(=>)
+                      parsePrecedenceExpression(=>, 1, true)
+                        parseUnaryExpression(=>, true)
+                          parsePrimary(=>, expression)
+                            parseLiteralInt(=>)
+                              listener: handleLiteralInt(1)
+                    ensureSemicolon(1)
+                    listener: handleExpressionFunctionBody(=>, ;)
+                    inGenerator()
+                listener: endClassMethod(get, int, =>, null, ;)
+              listener: endMember()
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+          listener: endClassDeclaration(class, })
+  listener: endTopLevelDeclaration(class)
+  parseTopLevelDeclarationImpl(}, Instance of 'DirectiveContext')
+    parseMetadataStar(})
+      listener: beginMetadataStar(class)
+      listener: endMetadataStar(0)
+    parseTopLevelKeywordDeclaration(}, class, Instance of 'DirectiveContext')
+      parseClassDeclarationModifiers(}, class)
+      parseClassOrNamedMixinApplication(null, class)
+        listener: beginClassOrNamedMixinApplicationPrelude(class)
+        ensureIdentifier(class, classOrMixinDeclaration)
+          listener: handleIdentifier(Xrequired, classOrMixinDeclaration)
+        listener: handleNoTypeVariables({)
+        listener: beginClassDeclaration(class, null, Xrequired)
+        parseClass(Xrequired, class, class, Xrequired)
+          parseClassHeaderOpt(Xrequired, class, class)
+            parseClassExtendsOpt(Xrequired)
+              listener: handleNoType(Xrequired)
+              listener: handleClassExtends(null)
+            parseWithClauseOpt(Xrequired)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(Xrequired)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassOrMixinOrExtensionBody(Xrequired, DeclarationKind.Class, Xrequired)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, int)
+            parseClassOrMixinOrExtensionMemberImpl({, DeclarationKind.Class, Xrequired)
+              parseMetadataStar({)
+                listener: beginMetadataStar(int)
+                listener: endMetadataStar(0)
+              listener: beginMember()
+              parseMethod({, null, null, null, null, null, {, Instance of 'SimpleType', get, g, DeclarationKind.Class, Xrequired)
+                listener: beginMethod(null, null, null, null, get, g)
+                listener: handleIdentifier(int, typeReference)
+                listener: handleNoTypeArguments(get)
+                listener: handleType(int, null)
+                ensureIdentifier(get, methodDeclaration)
+                  listener: handleIdentifier(g, methodDeclaration)
+                listener: handleNoTypeVariables(=>)
+                parseGetterOrFormalParameters(g, g, true, MemberKind.NonStaticMethod)
+                  listener: handleNoFormalParameters(=>, MemberKind.NonStaticMethod)
+                parseInitializersOpt(g)
+                  listener: handleNoInitializers()
+                parseAsyncModifierOpt(g)
+                  listener: handleAsyncModifier(null, null)
+                  inPlainSync()
+                inPlainSync()
+                inPlainSync()
+                parseFunctionBody(g, false, true)
+                  parseExpressionFunctionBody(=>, false)
+                    parseExpression(=>)
+                      parsePrecedenceExpression(=>, 1, true)
+                        parseUnaryExpression(=>, true)
+                          parsePrimary(=>, expression)
+                            parseLiteralInt(=>)
+                              listener: handleLiteralInt(2)
+                    ensureSemicolon(2)
+                    listener: handleExpressionFunctionBody(=>, ;)
+                    inGenerator()
+                listener: endClassMethod(get, int, =>, null, ;)
+              listener: endMember()
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+          listener: endClassDeclaration(class, })
+  listener: endTopLevelDeclaration(class)
+  parseTopLevelDeclarationImpl(}, Instance of 'DirectiveContext')
+    parseMetadataStar(})
+      listener: beginMetadataStar(class)
+      listener: endMetadataStar(0)
+    parseTopLevelKeywordDeclaration(}, class, Instance of 'DirectiveContext')
+      parseClassDeclarationModifiers(}, class)
+      parseClassOrNamedMixinApplication(null, class)
+        listener: beginClassOrNamedMixinApplicationPrelude(class)
+        ensureIdentifier(class, classOrMixinDeclaration)
+          listener: handleIdentifier(C, classOrMixinDeclaration)
+        listener: handleNoTypeVariables({)
+        listener: beginClassDeclaration(class, null, C)
+        parseClass(C, class, class, C)
+          parseClassHeaderOpt(C, class, class)
+            parseClassExtendsOpt(C)
+              listener: handleNoType(C)
+              listener: handleClassExtends(null)
+            parseWithClauseOpt(C)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(C)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassOrMixinOrExtensionBody(C, DeclarationKind.Class, C)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, Xlate)
+            parseClassOrMixinOrExtensionMemberImpl({, DeclarationKind.Class, C)
+              parseMetadataStar({)
+                listener: beginMetadataStar(Xlate)
+                listener: endMetadataStar(0)
+              listener: beginMember()
+              parseFields({, null, null, null, null, null, {, Instance of 'SimpleType', l, DeclarationKind.Class)
+                listener: handleIdentifier(Xlate, typeReference)
+                listener: handleNoTypeArguments(l)
+                listener: handleType(Xlate, null)
+                ensureIdentifier(Xlate, fieldDeclaration)
+                  listener: handleIdentifier(l, fieldDeclaration)
+                parseFieldInitializerOpt(l, l, null, null, DeclarationKind.Class)
+                  listener: beginFieldInitializer(=)
+                  parseExpression(=)
+                    parsePrecedenceExpression(=, 1, true)
+                      parseUnaryExpression(=, true)
+                        parsePrimary(=, expression)
+                          parseSendOrFunctionLiteral(=, expression)
+                            looksLikeFunctionBody(;)
+                            parseSend(=, expression)
+                              ensureIdentifier(=, expression)
+                                listener: handleIdentifier(Xlate, expression)
+                              listener: handleNoTypeArguments(()
+                              parseArgumentsOpt(Xlate)
+                                parseArguments(Xlate)
+                                  parseArgumentsRest(()
+                                    listener: beginArguments(()
+                                    listener: endArguments(0, (, ))
+                              listener: handleSend(Xlate, ;)
+                  listener: endFieldInitializer(=, ;)
+                listener: endClassFields(null, null, null, null, 1, Xlate, ;)
+              listener: endMember()
+            notEofOrValue(}, Xrequired)
+            parseClassOrMixinOrExtensionMemberImpl(;, DeclarationKind.Class, C)
+              parseMetadataStar(;)
+                listener: beginMetadataStar(Xrequired)
+                listener: endMetadataStar(0)
+              listener: beginMember()
+              parseFields(;, null, null, null, null, null, ;, Instance of 'SimpleType', r, DeclarationKind.Class)
+                listener: handleIdentifier(Xrequired, typeReference)
+                listener: handleNoTypeArguments(r)
+                listener: handleType(Xrequired, null)
+                ensureIdentifier(Xrequired, fieldDeclaration)
+                  listener: handleIdentifier(r, fieldDeclaration)
+                parseFieldInitializerOpt(r, r, null, null, DeclarationKind.Class)
+                  listener: beginFieldInitializer(=)
+                  parseExpression(=)
+                    parsePrecedenceExpression(=, 1, true)
+                      parseUnaryExpression(=, true)
+                        parsePrimary(=, expression)
+                          parseSendOrFunctionLiteral(=, expression)
+                            looksLikeFunctionBody(;)
+                            parseSend(=, expression)
+                              ensureIdentifier(=, expression)
+                                listener: handleIdentifier(Xrequired, expression)
+                              listener: handleNoTypeArguments(()
+                              parseArgumentsOpt(Xrequired)
+                                parseArguments(Xrequired)
+                                  parseArgumentsRest(()
+                                    listener: beginArguments(()
+                                    listener: endArguments(0, (, ))
+                              listener: handleSend(Xrequired, ;)
+                  listener: endFieldInitializer(=, ;)
+                listener: endClassFields(null, null, null, null, 1, Xrequired, ;)
+              listener: endMember()
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 2, {, })
+          listener: endClassDeclaration(class, })
+  listener: endTopLevelDeclaration()
+  reportAllErrorTokens(class)
+  listener: endCompilationUnit(3, )
diff --git a/pkg/front_end/parser_testcases/non-nnbd/issue_40288_prime.dart.parser.expect b/pkg/front_end/parser_testcases/non-nnbd/issue_40288_prime.dart.parser.expect
new file mode 100644
index 0000000..85eeb05
--- /dev/null
+++ b/pkg/front_end/parser_testcases/non-nnbd/issue_40288_prime.dart.parser.expect
@@ -0,0 +1,27 @@
+class Xlate {
+int get g => 1;
+}
+
+class Xrequired {
+int get g => 2;
+}
+
+class C {
+Xlate l = Xlate();
+Xrequired r = Xrequired();
+}
+
+
+class[KeywordToken] Xlate[StringToken] {[BeginToken]
+int[StringToken] get[KeywordToken] g[StringToken] =>[SimpleToken] 1[StringToken];[SimpleToken]
+}[SimpleToken]
+
+class[KeywordToken] Xrequired[StringToken] {[BeginToken]
+int[StringToken] get[KeywordToken] g[StringToken] =>[SimpleToken] 2[StringToken];[SimpleToken]
+}[SimpleToken]
+
+class[KeywordToken] C[StringToken] {[BeginToken]
+Xlate[StringToken] l[StringToken] =[SimpleToken] Xlate[StringToken]([BeginToken])[SimpleToken];[SimpleToken]
+Xrequired[StringToken] r[StringToken] =[SimpleToken] Xrequired[StringToken]([BeginToken])[SimpleToken];[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/non-nnbd/issue_40288_prime.dart.scanner.expect b/pkg/front_end/parser_testcases/non-nnbd/issue_40288_prime.dart.scanner.expect
new file mode 100644
index 0000000..85eeb05
--- /dev/null
+++ b/pkg/front_end/parser_testcases/non-nnbd/issue_40288_prime.dart.scanner.expect
@@ -0,0 +1,27 @@
+class Xlate {
+int get g => 1;
+}
+
+class Xrequired {
+int get g => 2;
+}
+
+class C {
+Xlate l = Xlate();
+Xrequired r = Xrequired();
+}
+
+
+class[KeywordToken] Xlate[StringToken] {[BeginToken]
+int[StringToken] get[KeywordToken] g[StringToken] =>[SimpleToken] 1[StringToken];[SimpleToken]
+}[SimpleToken]
+
+class[KeywordToken] Xrequired[StringToken] {[BeginToken]
+int[StringToken] get[KeywordToken] g[StringToken] =>[SimpleToken] 2[StringToken];[SimpleToken]
+}[SimpleToken]
+
+class[KeywordToken] C[StringToken] {[BeginToken]
+Xlate[StringToken] l[StringToken] =[SimpleToken] Xlate[StringToken]([BeginToken])[SimpleToken];[SimpleToken]
+Xrequired[StringToken] r[StringToken] =[SimpleToken] Xrequired[StringToken]([BeginToken])[SimpleToken];[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/test/fasta/type_inference/type_schema_environment_nnbd_test.dart b/pkg/front_end/test/fasta/type_inference/type_schema_environment_nnbd_test.dart
index 661ed9a..14828d3 100644
--- a/pkg/front_end/test/fasta/type_inference/type_schema_environment_nnbd_test.dart
+++ b/pkg/front_end/test/fasta/type_inference/type_schema_environment_nnbd_test.dart
@@ -562,30 +562,78 @@
           listClassThisType,
           [T.parameter],
           [T, T],
-          [coreTypes.intLegacyRawType, coreTypes.doubleLegacyRawType],
+          [coreTypes.intNonNullableRawType, coreTypes.doubleNonNullableRawType],
           null,
           inferredTypes,
           testLib);
-      expect(inferredTypes[0], coreTypes.numLegacyRawType);
+      expect(inferredTypes[0], coreTypes.numNonNullableRawType);
     }
     {
       // Test an instantiation of [1, 2.0] with a context of List<Object>.  This
       // should infer as List<Object> during downwards inference.
       List<DartType> inferredTypes = <DartType>[new UnknownType()];
       TypeParameterType T = listClassThisType.typeArguments[0];
-      env.inferGenericFunctionOrType(listClassThisType, [T.parameter], null,
-          null, _list(coreTypes.objectLegacyRawType), inferredTypes, testLib);
-      expect(inferredTypes[0], coreTypes.objectLegacyRawType);
+      env.inferGenericFunctionOrType(
+          listClassThisType,
+          [T.parameter],
+          null,
+          null,
+          _list(coreTypes.objectNonNullableRawType),
+          inferredTypes,
+          testLib);
+      expect(inferredTypes[0], coreTypes.objectNonNullableRawType);
       // And upwards inference should preserve the type.
       env.inferGenericFunctionOrType(
           listClassThisType,
           [T.parameter],
           [T, T],
-          [coreTypes.intLegacyRawType, coreTypes.doubleLegacyRawType],
-          _list(coreTypes.objectLegacyRawType),
+          [coreTypes.intNonNullableRawType, coreTypes.doubleNonNullableRawType],
+          _list(coreTypes.objectNonNullableRawType),
           inferredTypes,
           testLib);
-      expect(inferredTypes[0], coreTypes.objectLegacyRawType);
+      expect(inferredTypes[0], coreTypes.objectNonNullableRawType);
+    }
+    {
+      // Test an instantiation of [1, 2.0, null] with no context.  This should
+      // infer as List<?> during downwards inference.
+      List<DartType> inferredTypes = <DartType>[new UnknownType()];
+      TypeParameterType T = listClassThisType.typeArguments[0];
+      env.inferGenericFunctionOrType(listClassThisType, [T.parameter], null,
+          null, null, inferredTypes, testLib);
+      expect(inferredTypes[0], new UnknownType());
+      // And upwards inference should refine it to List<num?>.
+      env.inferGenericFunctionOrType(
+          listClassThisType,
+          [T.parameter],
+          [T, T, T],
+          [
+            coreTypes.intNonNullableRawType,
+            coreTypes.doubleNonNullableRawType,
+            coreTypes.nullType
+          ],
+          null,
+          inferredTypes,
+          testLib);
+      expect(inferredTypes[0], coreTypes.numNullableRawType);
+    }
+    {
+      // Test an instantiation of legacy [1, 2.0] with no context.
+      // This should infer as List<?> during downwards inference.
+      List<DartType> inferredTypes = <DartType>[new UnknownType()];
+      TypeParameterType T = listClassThisType.typeArguments[0];
+      env.inferGenericFunctionOrType(listClassThisType, [T.parameter], null,
+          null, null, inferredTypes, testLib);
+      expect(inferredTypes[0], new UnknownType());
+      // And upwards inference should refine it to List<num!>.
+      env.inferGenericFunctionOrType(
+          listClassThisType,
+          [T.parameter],
+          [T, T],
+          [coreTypes.intLegacyRawType, coreTypes.doubleLegacyRawType],
+          null,
+          inferredTypes,
+          testLib);
+      expect(inferredTypes[0], coreTypes.numNonNullableRawType);
     }
   }
 
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 9cad39e..6dce68e 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -654,6 +654,8 @@
 nullable2
 nullable3
 nullary
+nullification
+nullify
 nulls
 o
 oauth
@@ -796,6 +798,7 @@
 recalculation
 recall
 received
+recheck
 recompiled
 recompiling
 recompute
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index 26cf233..f577286 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -392,6 +392,7 @@
 cased
 cases
 casting
+cat
 catch
 catches
 categories
@@ -903,6 +904,7 @@
 easier
 easiest
 easily
+eat
 edge
 edges
 edit
@@ -1118,6 +1120,7 @@
 few
 fewer
 field
+field's
 fieldname
 fields
 figure
@@ -1159,6 +1162,7 @@
 flattened
 flexibility
 flexible
+float
 flow
 flow's
 flush
@@ -1172,6 +1176,7 @@
 followed
 following
 follows
+food
 for
 force
 forced
@@ -1334,6 +1339,7 @@
 how
 however
 http
+hungry
 hybrid
 idea
 ideally
@@ -1906,6 +1912,7 @@
 notifies
 now
 null
+nullability
 nullable
 num
 number
@@ -2218,6 +2225,7 @@
 promotions
 propagate
 propagating
+propagation
 proper
 properly
 properties
diff --git a/pkg/front_end/test/spell_checking_list_messages.txt b/pkg/front_end/test/spell_checking_list_messages.txt
index 31322a38..358ed80 100644
--- a/pkg/front_end/test/spell_checking_list_messages.txt
+++ b/pkg/front_end/test/spell_checking_list_messages.txt
@@ -9,6 +9,7 @@
 # Comments on a line by itself will be considered a header of the file and
 # automatic tools might move it to the top of the file.
 
+JS
 argument(s)
 assigning
 b
@@ -18,9 +19,9 @@
 constructor(s)
 count.#count
 d
-dart_runner
-dart:ffi
 dart2js_server
+dart:ffi
+dart_runner
 dartbug.com
 dname
 e.g
@@ -32,8 +33,8 @@
 h
 interop
 libraries.json
+list.filled
 loadlibrary
-JS
 name.#name
 name.stack
 native('native
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index 468adfa..8422fa5 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -37,6 +37,7 @@
 b1x
 b2x
 ba
+baba
 backed
 bailout
 bash
@@ -341,6 +342,7 @@
 reflective
 regenerate
 regressions
+reify
 reload
 remap
 remaps
@@ -446,6 +448,8 @@
 worlds
 ws
 x's
+xlate
+xrequired
 xxx
 y's
 year
diff --git a/pkg/front_end/test/static_types/data/null_check.dart b/pkg/front_end/test/static_types/data/null_check.dart
new file mode 100644
index 0000000..fd4dfe2
--- /dev/null
+++ b/pkg/front_end/test/static_types/data/null_check.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/*library: nnbd=true*/
+
+abstract class A {
+  T foo<T>();
+  String bar() => /*invoke: String?*/ foo/*<String?>*/()!;
+}
+
+main() {}
diff --git a/pkg/front_end/test/static_types/data/promoted_access.dart b/pkg/front_end/test/static_types/data/promoted_access.dart
index 1d9e4cb..3e87292 100644
--- a/pkg/front_end/test/static_types/data/promoted_access.dart
+++ b/pkg/front_end/test/static_types/data/promoted_access.dart
@@ -6,11 +6,17 @@
 /*cfe:nnbd.library: nnbd=true*/
 
 class Class<T> {
+  var property;
+
   method(T o) {
     if (/*cfe.T*/ /*cfe:nnbd.T%*/ o is Class) {
       /*cfe.T & Class<dynamic>*/
       /*cfe:nnbd.T! & Class<dynamic>!*/
       o. /*invoke: dynamic*/ method(/*Null*/ null);
+      /*cfe.T & Class<dynamic>*/ /*cfe:nnbd.T! & Class<dynamic>!*/ o
+          ?. /*invoke: dynamic*/ method(/*Null*/ null);
+      /*cfe.T & Class<dynamic>*/ /*cfe:nnbd.T! & Class<dynamic>!*/ o
+          ?. /*dynamic*/ property;
     }
   }
 }
@@ -20,6 +26,10 @@
     /*cfe.T & Class<dynamic>*/
     /*cfe:nnbd.T! & Class<dynamic>!*/
     o. /*invoke: dynamic*/ method(/*Null*/ null);
+    /*cfe.T & Class<dynamic>*/ /*cfe:nnbd.T! & Class<dynamic>!*/ o
+        ?. /*invoke: dynamic*/ method(/*Null*/ null);
+    /*cfe.T & Class<dynamic>*/ /*cfe:nnbd.T! & Class<dynamic>!*/ o
+        ?. /*dynamic*/ property;
   }
 }
 
diff --git a/pkg/front_end/test/static_types/static_type_test.dart b/pkg/front_end/test/static_types/static_type_test.dart
index e49079f..3f64311f 100644
--- a/pkg/front_end/test/static_types/static_type_test.dart
+++ b/pkg/front_end/test/static_types/static_type_test.dart
@@ -28,6 +28,7 @@
           'from_opt_in',
           'from_opt_out',
           'if_null.dart',
+          'null_check.dart',
         ]
       });
 }
diff --git a/pkg/front_end/testcases/extensions/issue39938/issue39938.dart b/pkg/front_end/testcases/extensions/issue39938/issue39938.dart
new file mode 100644
index 0000000..5a39748
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue39938/issue39938.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2020, 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 'issue39938_lib.dart';
+
+main() {
+  expect(true, true + true);
+  expect(true, true + false);
+  expect(true, false + true);
+  expect(false, false + false);
+  expect(true, Extension(true) + true);
+  expect(true, Extension(true) + false);
+  expect(true, Extension(false) + true);
+  expect(false, Extension(false) + false);
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual.';
+}
diff --git a/pkg/front_end/testcases/extensions/issue39938/issue39938_lib.dart b/pkg/front_end/testcases/extensions/issue39938/issue39938_lib.dart
new file mode 100644
index 0000000..8f2588e
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue39938/issue39938_lib.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2020, 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.
+
+extension Extension on bool {
+  bool operator +(bool other) => this | other;
+}
diff --git a/pkg/front_end/testcases/extensions/issue39938/issue39938_lib.dart.outline.expect b/pkg/front_end/testcases/extensions/issue39938/issue39938_lib.dart.outline.expect
new file mode 100644
index 0000000..b84871b
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue39938/issue39938_lib.dart.outline.expect
@@ -0,0 +1,19 @@
+library;
+import self as self;
+
+import "org-dartlang-testcase:///issue39938_lib.dart";
+
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
+
+library;
+import self as self2;
+import "dart:core" as core;
+
+extension Extension on core::bool* {
+  operator + = self2::Extension|+;
+}
+static method Extension|+(final core::bool* #this, core::bool* other) → core::bool*
+  ;
diff --git a/pkg/front_end/testcases/extensions/issue39938/issue39938_lib.dart.strong.expect b/pkg/front_end/testcases/extensions/issue39938/issue39938_lib.dart.strong.expect
new file mode 100644
index 0000000..e321b2b
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue39938/issue39938_lib.dart.strong.expect
@@ -0,0 +1,31 @@
+library;
+import self as self;
+import "issue39938_lib.dart" as iss;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///issue39938_lib.dart";
+
+static method main() → dynamic {
+  self::expect(true, iss::Extension|+(true, true));
+  self::expect(true, iss::Extension|+(true, false));
+  self::expect(true, iss::Extension|+(false, true));
+  self::expect(false, iss::Extension|+(false, false));
+  self::expect(true, iss::Extension|+(true, true));
+  self::expect(true, iss::Extension|+(true, false));
+  self::expect(true, iss::Extension|+(false, true));
+  self::expect(false, iss::Extension|+(false, false));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}.";
+}
+
+library;
+import self as iss;
+import "dart:core" as core;
+
+extension Extension on core::bool* {
+  operator + = iss::Extension|+;
+}
+static method Extension|+(final core::bool* #this, core::bool* other) → core::bool*
+  return #this.{core::bool::|}(other);
diff --git a/pkg/front_end/testcases/extensions/issue39938/issue39938_lib.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/issue39938/issue39938_lib.dart.strong.transformed.expect
new file mode 100644
index 0000000..e321b2b
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue39938/issue39938_lib.dart.strong.transformed.expect
@@ -0,0 +1,31 @@
+library;
+import self as self;
+import "issue39938_lib.dart" as iss;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///issue39938_lib.dart";
+
+static method main() → dynamic {
+  self::expect(true, iss::Extension|+(true, true));
+  self::expect(true, iss::Extension|+(true, false));
+  self::expect(true, iss::Extension|+(false, true));
+  self::expect(false, iss::Extension|+(false, false));
+  self::expect(true, iss::Extension|+(true, true));
+  self::expect(true, iss::Extension|+(true, false));
+  self::expect(true, iss::Extension|+(false, true));
+  self::expect(false, iss::Extension|+(false, false));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}.";
+}
+
+library;
+import self as iss;
+import "dart:core" as core;
+
+extension Extension on core::bool* {
+  operator + = iss::Extension|+;
+}
+static method Extension|+(final core::bool* #this, core::bool* other) → core::bool*
+  return #this.{core::bool::|}(other);
diff --git a/pkg/front_end/testcases/extensions/issue39938/link.options b/pkg/front_end/testcases/extensions/issue39938/link.options
new file mode 100644
index 0000000..73fb531
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue39938/link.options
@@ -0,0 +1 @@
+issue39938_lib.dart
\ No newline at end of file
diff --git a/pkg/front_end/testcases/general/abstract_members.dart.outline.expect b/pkg/front_end/testcases/general/abstract_members.dart.outline.expect
index 841c0e0..3500568 100644
--- a/pkg/front_end/testcases/general/abstract_members.dart.outline.expect
+++ b/pkg/front_end/testcases/general/abstract_members.dart.outline.expect
@@ -185,14 +185,6 @@
     ;
   method cMethod() → dynamic
     ;
-  no-such-method-forwarder get interfaceMethod1() → dynamic
-    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod1, 1, const <core::Type*>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{}))) as{TypeError,ForDynamic} dynamic;
-  no-such-method-forwarder set property3(dynamic _) → void
-    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#property3=, 2, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{})));
-  no-such-method-forwarder set interfaceMethod1(dynamic value) → void
-    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod1=, 2, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{})));
-  no-such-method-forwarder set property1(dynamic _) → void
-    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#property1=, 2, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{})));
 }
 class MyMock1 extends self::B {
   synthetic constructor •() → self::MyMock1*
@@ -225,16 +217,6 @@
   synthetic constructor •() → self::MyMock3*
     ;
   abstract method noSuchMethod(core::Invocation* _) → dynamic;
-  no-such-method-forwarder get interfaceMethod1() → dynamic
-    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod1, 1, const <core::Type*>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{}))) as{TypeError,ForDynamic} dynamic;
-  no-such-method-forwarder set property3(dynamic _) → void
-    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#property3=, 2, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{})));
-  no-such-method-forwarder set interfaceMethod1(dynamic value) → void
-    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod1=, 2, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{})));
-  no-such-method-forwarder set property1(dynamic _) → void
-    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#property1=, 2, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{})));
-  no-such-method-forwarder set property2(dynamic _) → void
-    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#property2=, 2, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{})));
 }
 class C extends core::Object {
   synthetic constructor •() → self::C*
diff --git a/pkg/front_end/testcases/general/abstract_members.dart.strong.expect b/pkg/front_end/testcases/general/abstract_members.dart.strong.expect
index 3192669..333da0b 100644
--- a/pkg/front_end/testcases/general/abstract_members.dart.strong.expect
+++ b/pkg/front_end/testcases/general/abstract_members.dart.strong.expect
@@ -181,14 +181,6 @@
   method aMethod() → dynamic {}
   method bMethod() → dynamic {}
   method cMethod() → dynamic {}
-  no-such-method-forwarder get interfaceMethod1() → dynamic
-    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 1, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4))) as{TypeError,ForDynamic} dynamic;
-  no-such-method-forwarder set property3(dynamic _) → void
-    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C5, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
-  no-such-method-forwarder set interfaceMethod1(dynamic value) → void
-    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C6, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
-  no-such-method-forwarder set property1(dynamic _) → void
-    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C7, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
 }
 class MyMock1 extends self::B {
   synthetic constructor •() → self::MyMock1*
@@ -197,19 +189,19 @@
   method noSuchMethod(core::Invocation* _) → dynamic
     return null;
   no-such-method-forwarder method interfaceMethod2() → void
-    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C8, 0, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
-  no-such-method-forwarder method abstractMethod() → dynamic
-    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C9, 0, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4))) as{TypeError,ForDynamic} dynamic;
-  no-such-method-forwarder method interfaceMethod1() → void
     return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 0, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
+  no-such-method-forwarder method abstractMethod() → dynamic
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C5, 0, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4))) as{TypeError,ForDynamic} dynamic;
+  no-such-method-forwarder method interfaceMethod1() → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C6, 0, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
   no-such-method-forwarder method interfaceMethod3() → void
-    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C10, 0, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C7, 0, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
   no-such-method-forwarder set property3(dynamic _) → void
-    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C5, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C8, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
   no-such-method-forwarder set interfaceMethod1(dynamic value) → void
-    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C6, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C9, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
   no-such-method-forwarder set property1(dynamic _) → void
-    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C7, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C10, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
   no-such-method-forwarder set property2(dynamic _) → void
     return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C11, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
 }
@@ -224,16 +216,6 @@
     : super self::B::•()
     ;
   abstract method noSuchMethod(core::Invocation* _) → dynamic;
-  no-such-method-forwarder get interfaceMethod1() → dynamic
-    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 1, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4))) as{TypeError,ForDynamic} dynamic;
-  no-such-method-forwarder set property3(dynamic _) → void
-    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#C5, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
-  no-such-method-forwarder set interfaceMethod1(dynamic value) → void
-    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#C6, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
-  no-such-method-forwarder set property1(dynamic _) → void
-    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#C7, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
-  no-such-method-forwarder set property2(dynamic _) → void
-    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#C11, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
 }
 class C extends core::Object {
   synthetic constructor •() → self::C*
@@ -296,15 +278,15 @@
 static method main() → dynamic {}
 
 constants  {
-  #C1 = #interfaceMethod1
+  #C1 = #interfaceMethod2
   #C2 = <core::Type*>[]
   #C3 = <dynamic>[]
   #C4 = core::_ImmutableMap<core::Symbol*, dynamic> {_kvPairs:#C3}
-  #C5 = #property3=
-  #C6 = #interfaceMethod1=
-  #C7 = #property1=
-  #C8 = #interfaceMethod2
-  #C9 = #abstractMethod
-  #C10 = #interfaceMethod3
+  #C5 = #abstractMethod
+  #C6 = #interfaceMethod1
+  #C7 = #interfaceMethod3
+  #C8 = #property3=
+  #C9 = #interfaceMethod1=
+  #C10 = #property1=
   #C11 = #property2=
 }
diff --git a/pkg/front_end/testcases/general/demote_closure_types.dart b/pkg/front_end/testcases/general/demote_closure_types.dart
new file mode 100644
index 0000000..d472317
--- /dev/null
+++ b/pkg/front_end/testcases/general/demote_closure_types.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2020, 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.
+
+method<T>(T a, T b) {
+  if (a is String) {
+    var f = () => a;
+    String s = f();
+  }
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/general/demote_closure_types.dart.outline.expect b/pkg/front_end/testcases/general/demote_closure_types.dart.outline.expect
new file mode 100644
index 0000000..3854c37
--- /dev/null
+++ b/pkg/front_end/testcases/general/demote_closure_types.dart.outline.expect
@@ -0,0 +1,8 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method method<T extends core::Object* = dynamic>(self::method::T* a, self::method::T* b) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/general/demote_closure_types.dart.strong.expect b/pkg/front_end/testcases/general/demote_closure_types.dart.strong.expect
new file mode 100644
index 0000000..dde2e96
--- /dev/null
+++ b/pkg/front_end/testcases/general/demote_closure_types.dart.strong.expect
@@ -0,0 +1,20 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/demote_closure_types.dart:8:17: Error: A value of type 'T' can't be assigned to a variable of type 'String'.
+//     String s = f();
+//                 ^
+//
+import self as self;
+import "dart:core" as core;
+
+static method method<T extends core::Object* = dynamic>(self::method::T* a, self::method::T* b) → dynamic {
+  if(a is core::String*) {
+    () →* self::method::T* f = () → self::method::T* => a{self::method::T* & core::String* /* '*' & '*' = '*' */};
+    core::String* s = let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/general/demote_closure_types.dart:8:17: Error: A value of type 'T' can't be assigned to a variable of type 'String'.
+    String s = f();
+                ^" in f.call() as{TypeError} core::String*;
+  }
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/general/demote_closure_types.dart.strong.transformed.expect b/pkg/front_end/testcases/general/demote_closure_types.dart.strong.transformed.expect
new file mode 100644
index 0000000..dde2e96
--- /dev/null
+++ b/pkg/front_end/testcases/general/demote_closure_types.dart.strong.transformed.expect
@@ -0,0 +1,20 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/demote_closure_types.dart:8:17: Error: A value of type 'T' can't be assigned to a variable of type 'String'.
+//     String s = f();
+//                 ^
+//
+import self as self;
+import "dart:core" as core;
+
+static method method<T extends core::Object* = dynamic>(self::method::T* a, self::method::T* b) → dynamic {
+  if(a is core::String*) {
+    () →* self::method::T* f = () → self::method::T* => a{self::method::T* & core::String* /* '*' & '*' = '*' */};
+    core::String* s = let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/general/demote_closure_types.dart:8:17: Error: A value of type 'T' can't be assigned to a variable of type 'String'.
+    String s = f();
+                ^" in f.call() as{TypeError} core::String*;
+  }
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/general/issue40428.dart b/pkg/front_end/testcases/general/issue40428.dart
new file mode 100644
index 0000000..f24cb23
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue40428.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2020, 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.
+
+abstract class SuperClass1 {
+  final String value;
+
+  SuperClass1(this.value);
+}
+
+abstract class SuperClass2 {
+  final String value;
+
+  SuperClass2(String i) : value = i;
+}
+
+class Mixin {}
+
+class NamedMixin1 = SuperClass1 with Mixin;
+class NamedMixin2 = SuperClass2 with Mixin;
+
+void main() {
+  new NamedMixin1('');
+  new NamedMixin2('');
+}
+
+errors() {
+  new NamedMixin1(0);
+  new NamedMixin2(0);
+}
diff --git a/pkg/front_end/testcases/general/issue40428.dart.outline.expect b/pkg/front_end/testcases/general/issue40428.dart.outline.expect
new file mode 100644
index 0000000..e371403
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue40428.dart.outline.expect
@@ -0,0 +1,32 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+abstract class SuperClass1 extends core::Object {
+  final field core::String* value;
+  constructor •(core::String* value) → self::SuperClass1*
+    ;
+}
+abstract class SuperClass2 extends core::Object {
+  final field core::String* value;
+  constructor •(core::String* i) → self::SuperClass2*
+    ;
+}
+class Mixin extends core::Object {
+  synthetic constructor •() → self::Mixin*
+    ;
+}
+class NamedMixin1 = self::SuperClass1 with self::Mixin {
+  synthetic constructor •(core::String* value) → self::NamedMixin1*
+    : super self::SuperClass1::•(value)
+    ;
+}
+class NamedMixin2 = self::SuperClass2 with self::Mixin {
+  synthetic constructor •(core::String* i) → self::NamedMixin2*
+    : super self::SuperClass2::•(i)
+    ;
+}
+static method main() → void
+  ;
+static method errors() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/general/issue40428.dart.strong.expect b/pkg/front_end/testcases/general/issue40428.dart.strong.expect
new file mode 100644
index 0000000..ce0aa76
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue40428.dart.strong.expect
@@ -0,0 +1,54 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/issue40428.dart:28:19: Error: The argument type 'int' can't be assigned to the parameter type 'String'.
+//   new NamedMixin1(0);
+//                   ^
+//
+// pkg/front_end/testcases/general/issue40428.dart:29:19: Error: The argument type 'int' can't be assigned to the parameter type 'String'.
+//   new NamedMixin2(0);
+//                   ^
+//
+import self as self;
+import "dart:core" as core;
+
+abstract class SuperClass1 extends core::Object {
+  final field core::String* value;
+  constructor •(core::String* value) → self::SuperClass1*
+    : self::SuperClass1::value = value, super core::Object::•()
+    ;
+}
+abstract class SuperClass2 extends core::Object {
+  final field core::String* value;
+  constructor •(core::String* i) → self::SuperClass2*
+    : self::SuperClass2::value = i, super core::Object::•()
+    ;
+}
+class Mixin extends core::Object {
+  synthetic constructor •() → self::Mixin*
+    : super core::Object::•()
+    ;
+}
+class NamedMixin1 = self::SuperClass1 with self::Mixin {
+  synthetic constructor •(core::String* value) → self::NamedMixin1*
+    : super self::SuperClass1::•(value)
+    ;
+}
+class NamedMixin2 = self::SuperClass2 with self::Mixin {
+  synthetic constructor •(core::String* i) → self::NamedMixin2*
+    : super self::SuperClass2::•(i)
+    ;
+}
+static method main() → void {
+  new self::NamedMixin1::•("");
+  new self::NamedMixin2::•("");
+}
+static method errors() → dynamic {
+  new self::NamedMixin1::•(let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/general/issue40428.dart:28:19: Error: The argument type 'int' can't be assigned to the parameter type 'String'.
+  new NamedMixin1(0);
+                  ^" in 0 as{TypeError} core::String*);
+  new self::NamedMixin2::•(let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/general/issue40428.dart:29:19: Error: The argument type 'int' can't be assigned to the parameter type 'String'.
+  new NamedMixin2(0);
+                  ^" in 0 as{TypeError} core::String*);
+}
diff --git a/pkg/front_end/testcases/general/issue40428.dart.strong.transformed.expect b/pkg/front_end/testcases/general/issue40428.dart.strong.transformed.expect
new file mode 100644
index 0000000..11cf476
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue40428.dart.strong.transformed.expect
@@ -0,0 +1,54 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/issue40428.dart:28:19: Error: The argument type 'int' can't be assigned to the parameter type 'String'.
+//   new NamedMixin1(0);
+//                   ^
+//
+// pkg/front_end/testcases/general/issue40428.dart:29:19: Error: The argument type 'int' can't be assigned to the parameter type 'String'.
+//   new NamedMixin2(0);
+//                   ^
+//
+import self as self;
+import "dart:core" as core;
+
+abstract class SuperClass1 extends core::Object {
+  final field core::String* value;
+  constructor •(core::String* value) → self::SuperClass1*
+    : self::SuperClass1::value = value, super core::Object::•()
+    ;
+}
+abstract class SuperClass2 extends core::Object {
+  final field core::String* value;
+  constructor •(core::String* i) → self::SuperClass2*
+    : self::SuperClass2::value = i, super core::Object::•()
+    ;
+}
+class Mixin extends core::Object {
+  synthetic constructor •() → self::Mixin*
+    : super core::Object::•()
+    ;
+}
+class NamedMixin1 extends self::SuperClass1 implements self::Mixin {
+  synthetic constructor •(core::String* value) → self::NamedMixin1*
+    : super self::SuperClass1::•(value)
+    ;
+}
+class NamedMixin2 extends self::SuperClass2 implements self::Mixin {
+  synthetic constructor •(core::String* i) → self::NamedMixin2*
+    : super self::SuperClass2::•(i)
+    ;
+}
+static method main() → void {
+  new self::NamedMixin1::•("");
+  new self::NamedMixin2::•("");
+}
+static method errors() → dynamic {
+  new self::NamedMixin1::•(let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/general/issue40428.dart:28:19: Error: The argument type 'int' can't be assigned to the parameter type 'String'.
+  new NamedMixin1(0);
+                  ^" in 0 as{TypeError} core::String*);
+  new self::NamedMixin2::•(let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/general/issue40428.dart:29:19: Error: The argument type 'int' can't be assigned to the parameter type 'String'.
+  new NamedMixin2(0);
+                  ^" in 0 as{TypeError} core::String*);
+}
diff --git a/pkg/front_end/testcases/general/mixin_application_inferred_parameter_type.dart b/pkg/front_end/testcases/general/mixin_application_inferred_parameter_type.dart
index 6ed8c68..ae79ed2 100644
--- a/pkg/front_end/testcases/general/mixin_application_inferred_parameter_type.dart
+++ b/pkg/front_end/testcases/general/mixin_application_inferred_parameter_type.dart
@@ -13,8 +13,9 @@
 class Class = Super with Mixin;
 
 main() {
-  // TODO(johnniwinther): The parameter is created before the super constructor
-  //  parameter type is inferred. Set up a way to propagate the inferred type
-  //  to its use sites.
+  new Class(0);
+}
+
+error() {
   new Class('');
 }
diff --git a/pkg/front_end/testcases/general/mixin_application_inferred_parameter_type.dart.outline.expect b/pkg/front_end/testcases/general/mixin_application_inferred_parameter_type.dart.outline.expect
index 275d510..eb95af0 100644
--- a/pkg/front_end/testcases/general/mixin_application_inferred_parameter_type.dart.outline.expect
+++ b/pkg/front_end/testcases/general/mixin_application_inferred_parameter_type.dart.outline.expect
@@ -12,9 +12,11 @@
     ;
 }
 class Class = self::Super with self::Mixin {
-  synthetic constructor •(dynamic field) → self::Class*
+  synthetic constructor •(core::int* field) → self::Class*
     : super self::Super::•(field)
     ;
 }
 static method main() → dynamic
   ;
+static method error() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/general/mixin_application_inferred_parameter_type.dart.strong.expect b/pkg/front_end/testcases/general/mixin_application_inferred_parameter_type.dart.strong.expect
index db0dcf5..577e4e4 100644
--- a/pkg/front_end/testcases/general/mixin_application_inferred_parameter_type.dart.strong.expect
+++ b/pkg/front_end/testcases/general/mixin_application_inferred_parameter_type.dart.strong.expect
@@ -1,4 +1,11 @@
 library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/mixin_application_inferred_parameter_type.dart:20:13: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+//   new Class('');
+//             ^
+//
 import self as self;
 import "dart:core" as core;
 
@@ -14,10 +21,15 @@
     ;
 }
 class Class = self::Super with self::Mixin {
-  synthetic constructor •(dynamic field) → self::Class*
+  synthetic constructor •(core::int* field) → self::Class*
     : super self::Super::•(field)
     ;
 }
 static method main() → dynamic {
-  new self::Class::•("");
+  new self::Class::•(0);
+}
+static method error() → dynamic {
+  new self::Class::•(let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/general/mixin_application_inferred_parameter_type.dart:20:13: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+  new Class('');
+            ^" in "" as{TypeError} core::int*);
 }
diff --git a/pkg/front_end/testcases/general/mixin_application_inferred_parameter_type.dart.strong.transformed.expect b/pkg/front_end/testcases/general/mixin_application_inferred_parameter_type.dart.strong.transformed.expect
index 174f790..44d03d0 100644
--- a/pkg/front_end/testcases/general/mixin_application_inferred_parameter_type.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/mixin_application_inferred_parameter_type.dart.strong.transformed.expect
@@ -1,4 +1,11 @@
 library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/mixin_application_inferred_parameter_type.dart:20:13: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+//   new Class('');
+//             ^
+//
 import self as self;
 import "dart:core" as core;
 
@@ -14,10 +21,15 @@
     ;
 }
 class Class extends self::Super implements self::Mixin {
-  synthetic constructor •(dynamic field) → self::Class*
+  synthetic constructor •(core::int* field) → self::Class*
     : super self::Super::•(field)
     ;
 }
 static method main() → dynamic {
-  new self::Class::•("");
+  new self::Class::•(0);
+}
+static method error() → dynamic {
+  new self::Class::•(let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/general/mixin_application_inferred_parameter_type.dart:20:13: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+  new Class('');
+            ^" in "" as{TypeError} core::int*);
 }
diff --git a/pkg/front_end/testcases/general/promoted_null_aware_access.dart b/pkg/front_end/testcases/general/promoted_null_aware_access.dart
new file mode 100644
index 0000000..12d7b83
--- /dev/null
+++ b/pkg/front_end/testcases/general/promoted_null_aware_access.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2020, 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.
+
+method<T>(T o) {
+  if (o is String) {
+    o?.length;
+  }
+}
+
+main() {
+  method("");
+}
diff --git a/pkg/front_end/testcases/general/promoted_null_aware_access.dart.outline.expect b/pkg/front_end/testcases/general/promoted_null_aware_access.dart.outline.expect
new file mode 100644
index 0000000..fa1074a
--- /dev/null
+++ b/pkg/front_end/testcases/general/promoted_null_aware_access.dart.outline.expect
@@ -0,0 +1,8 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method method<T extends core::Object* = dynamic>(self::method::T* o) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/general/promoted_null_aware_access.dart.strong.expect b/pkg/front_end/testcases/general/promoted_null_aware_access.dart.strong.expect
new file mode 100644
index 0000000..b7c4248
--- /dev/null
+++ b/pkg/front_end/testcases/general/promoted_null_aware_access.dart.strong.expect
@@ -0,0 +1,12 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method method<T extends core::Object* = dynamic>(self::method::T* o) → dynamic {
+  if(o is core::String*) {
+    let final self::method::T* & core::String* /* '*' & '*' = '*' */ #t1 = o{self::method::T* & core::String* /* '*' & '*' = '*' */} in #t1.{core::String::==}(null) ?{core::int*} null : #t1.{core::String::length};
+  }
+}
+static method main() → dynamic {
+  self::method<core::String*>("");
+}
diff --git a/pkg/front_end/testcases/general/promoted_null_aware_access.dart.strong.transformed.expect b/pkg/front_end/testcases/general/promoted_null_aware_access.dart.strong.transformed.expect
new file mode 100644
index 0000000..b7c4248
--- /dev/null
+++ b/pkg/front_end/testcases/general/promoted_null_aware_access.dart.strong.transformed.expect
@@ -0,0 +1,12 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method method<T extends core::Object* = dynamic>(self::method::T* o) → dynamic {
+  if(o is core::String*) {
+    let final self::method::T* & core::String* /* '*' & '*' = '*' */ #t1 = o{self::method::T* & core::String* /* '*' & '*' = '*' */} in #t1.{core::String::==}(null) ?{core::int*} null : #t1.{core::String::length};
+  }
+}
+static method main() → dynamic {
+  self::method<core::String*>("");
+}
diff --git a/pkg/front_end/testcases/general/well_boundness_checks_in_outline.dart b/pkg/front_end/testcases/general/well_boundness_checks_in_outline.dart
new file mode 100644
index 0000000..37dc716
--- /dev/null
+++ b/pkg/front_end/testcases/general/well_boundness_checks_in_outline.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2020, 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.
+
+class A<X extends int> {}
+
+class B {
+  A<num> fieldOfA; // Error.
+  static A<num> staticFieldOfA; // Error.
+}
+
+extension E<X extends A<num>> // Error.
+    on A {
+  static A<num> fieldOfE; // Error.
+  A<num> fooOfE() => null; // Error.
+  void barOfE(A<num> a) {} // Error.
+  void bazOfE<Y extends A<num>>() {} // Error.
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/general/well_boundness_checks_in_outline.dart.outline.expect b/pkg/front_end/testcases/general/well_boundness_checks_in_outline.dart.outline.expect
new file mode 100644
index 0000000..b2736df
--- /dev/null
+++ b/pkg/front_end/testcases/general/well_boundness_checks_in_outline.dart.outline.expect
@@ -0,0 +1,57 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/well_boundness_checks_in_outline.dart:8:10: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'A'.
+// Try changing type arguments so that they conform to the bounds.
+//   A<num> fieldOfA; // Error.
+//          ^
+// pkg/front_end/testcases/general/well_boundness_checks_in_outline.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
+// class A<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/general/well_boundness_checks_in_outline.dart:9:17: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'A'.
+// Try changing type arguments so that they conform to the bounds.
+//   static A<num> staticFieldOfA; // Error.
+//                 ^
+// pkg/front_end/testcases/general/well_boundness_checks_in_outline.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
+// class A<X extends int> {}
+//         ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A<X extends core::int* = core::int*> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X*>*
+    ;
+}
+class B extends core::Object {
+  field self::A<core::num*>* fieldOfA;
+  static field self::A<core::num*>* staticFieldOfA;
+  synthetic constructor •() → self::B*
+    ;
+}
+extension E<X extends self::A<core::num*>* = dynamic> on self::A<core::int*>* {
+  static field fieldOfE = self::E|fieldOfE;
+  method fooOfE = self::E|fooOfE;
+  tearoff fooOfE = self::E|get#fooOfE;
+  method barOfE = self::E|barOfE;
+  tearoff barOfE = self::E|get#barOfE;
+  method bazOfE = self::E|bazOfE;
+  tearoff bazOfE = self::E|get#bazOfE;
+}
+static field self::A<core::num*>* E|fieldOfE;
+static method E|fooOfE<X extends self::A<core::num*>* = dynamic>(final self::A<core::int*>* #this) → self::A<core::num*>*
+  ;
+static method E|get#fooOfE<X extends self::A<core::num*>* = dynamic>(final self::A<core::int*>* #this) → () →* self::A<core::num*>*
+  return () → self::A<core::num*>* => self::E|fooOfE<self::E|get#fooOfE::X*>(#this);
+static method E|barOfE<X extends self::A<core::num*>* = dynamic>(final self::A<core::int*>* #this, self::A<core::num*>* a) → void
+  ;
+static method E|get#barOfE<X extends self::A<core::num*>* = dynamic>(final self::A<core::int*>* #this) → (self::A<core::num*>*) →* void
+  return (self::A<core::num*>* a) → void => self::E|barOfE<self::E|get#barOfE::X*>(#this, a);
+static method E|bazOfE<X extends self::A<core::num*>* = dynamic, Y extends self::A<core::num*>* = dynamic>(final self::A<core::int*>* #this) → void
+  ;
+static method E|get#bazOfE<X extends self::A<core::num*>* = dynamic>(final self::A<core::int*>* #this) → <Y extends self::A<core::num*>* = dynamic>() →* void
+  return <Y extends self::A<core::num*>* = dynamic>() → void => self::E|bazOfE<self::E|get#bazOfE::X*, Y*>(#this);
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/general/well_boundness_checks_in_outline.dart.strong.expect b/pkg/front_end/testcases/general/well_boundness_checks_in_outline.dart.strong.expect
new file mode 100644
index 0000000..7929082
--- /dev/null
+++ b/pkg/front_end/testcases/general/well_boundness_checks_in_outline.dart.strong.expect
@@ -0,0 +1,56 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/well_boundness_checks_in_outline.dart:8:10: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'A'.
+// Try changing type arguments so that they conform to the bounds.
+//   A<num> fieldOfA; // Error.
+//          ^
+// pkg/front_end/testcases/general/well_boundness_checks_in_outline.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
+// class A<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/general/well_boundness_checks_in_outline.dart:9:17: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'A'.
+// Try changing type arguments so that they conform to the bounds.
+//   static A<num> staticFieldOfA; // Error.
+//                 ^
+// pkg/front_end/testcases/general/well_boundness_checks_in_outline.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
+// class A<X extends int> {}
+//         ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A<X extends core::int* = core::int*> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X*>*
+    : super core::Object::•()
+    ;
+}
+class B extends core::Object {
+  field self::A<core::num*>* fieldOfA = null;
+  static field self::A<core::num*>* staticFieldOfA = null;
+  synthetic constructor •() → self::B*
+    : super core::Object::•()
+    ;
+}
+extension E<X extends self::A<core::num*>* = dynamic> on self::A<core::int*>* {
+  static field fieldOfE = self::E|fieldOfE;
+  method fooOfE = self::E|fooOfE;
+  tearoff fooOfE = self::E|get#fooOfE;
+  method barOfE = self::E|barOfE;
+  tearoff barOfE = self::E|get#barOfE;
+  method bazOfE = self::E|bazOfE;
+  tearoff bazOfE = self::E|get#bazOfE;
+}
+static field self::A<core::num*>* E|fieldOfE;
+static method E|fooOfE<X extends self::A<core::num*>* = dynamic>(final self::A<core::int*>* #this) → self::A<core::num*>*
+  return null;
+static method E|get#fooOfE<X extends self::A<core::num*>* = dynamic>(final self::A<core::int*>* #this) → () →* self::A<core::num*>*
+  return () → self::A<core::num*>* => self::E|fooOfE<self::E|get#fooOfE::X*>(#this);
+static method E|barOfE<X extends self::A<core::num*>* = dynamic>(final self::A<core::int*>* #this, self::A<core::num*>* a) → void {}
+static method E|get#barOfE<X extends self::A<core::num*>* = dynamic>(final self::A<core::int*>* #this) → (self::A<core::num*>*) →* void
+  return (self::A<core::num*>* a) → void => self::E|barOfE<self::E|get#barOfE::X*>(#this, a);
+static method E|bazOfE<X extends self::A<core::num*>* = dynamic, Y extends self::A<core::num*>* = dynamic>(final self::A<core::int*>* #this) → void {}
+static method E|get#bazOfE<X extends self::A<core::num*>* = dynamic>(final self::A<core::int*>* #this) → <Y extends self::A<core::num*>* = dynamic>() →* void
+  return <Y extends self::A<core::num*>* = dynamic>() → void => self::E|bazOfE<self::E|get#bazOfE::X*, Y*>(#this);
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/general/well_boundness_checks_in_outline.dart.strong.transformed.expect b/pkg/front_end/testcases/general/well_boundness_checks_in_outline.dart.strong.transformed.expect
new file mode 100644
index 0000000..7929082
--- /dev/null
+++ b/pkg/front_end/testcases/general/well_boundness_checks_in_outline.dart.strong.transformed.expect
@@ -0,0 +1,56 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/well_boundness_checks_in_outline.dart:8:10: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'A'.
+// Try changing type arguments so that they conform to the bounds.
+//   A<num> fieldOfA; // Error.
+//          ^
+// pkg/front_end/testcases/general/well_boundness_checks_in_outline.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
+// class A<X extends int> {}
+//         ^
+//
+// pkg/front_end/testcases/general/well_boundness_checks_in_outline.dart:9:17: Error: Type argument 'num' doesn't conform to the bound 'int' of the type variable 'X' on 'A'.
+// Try changing type arguments so that they conform to the bounds.
+//   static A<num> staticFieldOfA; // Error.
+//                 ^
+// pkg/front_end/testcases/general/well_boundness_checks_in_outline.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
+// class A<X extends int> {}
+//         ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A<X extends core::int* = core::int*> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X*>*
+    : super core::Object::•()
+    ;
+}
+class B extends core::Object {
+  field self::A<core::num*>* fieldOfA = null;
+  static field self::A<core::num*>* staticFieldOfA = null;
+  synthetic constructor •() → self::B*
+    : super core::Object::•()
+    ;
+}
+extension E<X extends self::A<core::num*>* = dynamic> on self::A<core::int*>* {
+  static field fieldOfE = self::E|fieldOfE;
+  method fooOfE = self::E|fooOfE;
+  tearoff fooOfE = self::E|get#fooOfE;
+  method barOfE = self::E|barOfE;
+  tearoff barOfE = self::E|get#barOfE;
+  method bazOfE = self::E|bazOfE;
+  tearoff bazOfE = self::E|get#bazOfE;
+}
+static field self::A<core::num*>* E|fieldOfE;
+static method E|fooOfE<X extends self::A<core::num*>* = dynamic>(final self::A<core::int*>* #this) → self::A<core::num*>*
+  return null;
+static method E|get#fooOfE<X extends self::A<core::num*>* = dynamic>(final self::A<core::int*>* #this) → () →* self::A<core::num*>*
+  return () → self::A<core::num*>* => self::E|fooOfE<self::E|get#fooOfE::X*>(#this);
+static method E|barOfE<X extends self::A<core::num*>* = dynamic>(final self::A<core::int*>* #this, self::A<core::num*>* a) → void {}
+static method E|get#barOfE<X extends self::A<core::num*>* = dynamic>(final self::A<core::int*>* #this) → (self::A<core::num*>*) →* void
+  return (self::A<core::num*>* a) → void => self::E|barOfE<self::E|get#barOfE::X*>(#this, a);
+static method E|bazOfE<X extends self::A<core::num*>* = dynamic, Y extends self::A<core::num*>* = dynamic>(final self::A<core::int*>* #this) → void {}
+static method E|get#bazOfE<X extends self::A<core::num*>* = dynamic>(final self::A<core::int*>* #this) → <Y extends self::A<core::num*>* = dynamic>() →* void
+  return <Y extends self::A<core::num*>* = dynamic>() → void => self::E|bazOfE<self::E|get#bazOfE::X*, Y*>(#this);
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/abstract_members.dart.outline.expect b/pkg/front_end/testcases/general_nnbd_opt_out/abstract_members.dart.outline.expect
index 0f02aec..046136a 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/abstract_members.dart.outline.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/abstract_members.dart.outline.expect
@@ -185,14 +185,6 @@
     ;
   method cMethod() → dynamic
     ;
-  no-such-method-forwarder get interfaceMethod1() → dynamic
-    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod1, 1, const <core::Type*>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{}))) as{TypeError,ForDynamic} dynamic;
-  no-such-method-forwarder set property3(dynamic _) → void
-    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#property3=, 2, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{})));
-  no-such-method-forwarder set interfaceMethod1(dynamic value) → void
-    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod1=, 2, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{})));
-  no-such-method-forwarder set property1(dynamic _) → void
-    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#property1=, 2, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{})));
 }
 class MyMock1 extends self::B {
   synthetic constructor •() → self::MyMock1*
@@ -225,16 +217,6 @@
   synthetic constructor •() → self::MyMock3*
     ;
   abstract method noSuchMethod(core::Invocation* _) → dynamic;
-  no-such-method-forwarder get interfaceMethod1() → dynamic
-    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod1, 1, const <core::Type*>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{}))) as{TypeError,ForDynamic} dynamic;
-  no-such-method-forwarder set property3(dynamic _) → void
-    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#property3=, 2, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{})));
-  no-such-method-forwarder set interfaceMethod1(dynamic value) → void
-    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#interfaceMethod1=, 2, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{})));
-  no-such-method-forwarder set property1(dynamic _) → void
-    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#property1=, 2, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{})));
-  no-such-method-forwarder set property2(dynamic _) → void
-    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#property2=, 2, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{})));
 }
 class C extends core::Object {
   synthetic constructor •() → self::C*
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/abstract_members.dart.strong.expect b/pkg/front_end/testcases/general_nnbd_opt_out/abstract_members.dart.strong.expect
index 4d04d03..b43d627 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/abstract_members.dart.strong.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/abstract_members.dart.strong.expect
@@ -181,14 +181,6 @@
   method aMethod() → dynamic {}
   method bMethod() → dynamic {}
   method cMethod() → dynamic {}
-  no-such-method-forwarder get interfaceMethod1() → dynamic
-    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 1, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4))) as{TypeError,ForDynamic} dynamic;
-  no-such-method-forwarder set property3(dynamic _) → void
-    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C5, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
-  no-such-method-forwarder set interfaceMethod1(dynamic value) → void
-    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C6, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
-  no-such-method-forwarder set property1(dynamic _) → void
-    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C7, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
 }
 class MyMock1 extends self::B {
   synthetic constructor •() → self::MyMock1*
@@ -197,19 +189,19 @@
   method noSuchMethod(core::Invocation* _) → dynamic
     return null;
   no-such-method-forwarder method interfaceMethod2() → void
-    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C8, 0, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
-  no-such-method-forwarder method abstractMethod() → dynamic
-    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C9, 0, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4))) as{TypeError,ForDynamic} dynamic;
-  no-such-method-forwarder method interfaceMethod1() → void
     return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 0, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
+  no-such-method-forwarder method abstractMethod() → dynamic
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C5, 0, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4))) as{TypeError,ForDynamic} dynamic;
+  no-such-method-forwarder method interfaceMethod1() → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C6, 0, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
   no-such-method-forwarder method interfaceMethod3() → void
-    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C10, 0, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C7, 0, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
   no-such-method-forwarder set property3(dynamic _) → void
-    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C5, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C8, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
   no-such-method-forwarder set interfaceMethod1(dynamic value) → void
-    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C6, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C9, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
   no-such-method-forwarder set property1(dynamic _) → void
-    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C7, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C10, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
   no-such-method-forwarder set property2(dynamic _) → void
     return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C11, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
 }
@@ -224,16 +216,6 @@
     : super self::B::•()
     ;
   abstract method noSuchMethod(core::Invocation* _) → dynamic;
-  no-such-method-forwarder get interfaceMethod1() → dynamic
-    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 1, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4))) as{TypeError,ForDynamic} dynamic;
-  no-such-method-forwarder set property3(dynamic _) → void
-    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#C5, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
-  no-such-method-forwarder set interfaceMethod1(dynamic value) → void
-    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#C6, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
-  no-such-method-forwarder set property1(dynamic _) → void
-    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#C7, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
-  no-such-method-forwarder set property2(dynamic _) → void
-    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#C11, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
 }
 class C extends core::Object {
   synthetic constructor •() → self::C*
@@ -296,15 +278,15 @@
 static method main() → dynamic {}
 
 constants  {
-  #C1 = #interfaceMethod1
+  #C1 = #interfaceMethod2
   #C2 = <core::Type*>[]
   #C3 = <dynamic>[]
   #C4 = core::_ImmutableMap<core::Symbol*, dynamic> {_kvPairs:#C3}
-  #C5 = #property3=
-  #C6 = #interfaceMethod1=
-  #C7 = #property1=
-  #C8 = #interfaceMethod2
-  #C9 = #abstractMethod
-  #C10 = #interfaceMethod3
+  #C5 = #abstractMethod
+  #C6 = #interfaceMethod1
+  #C7 = #interfaceMethod3
+  #C8 = #property3=
+  #C9 = #interfaceMethod1=
+  #C10 = #property1=
   #C11 = #property2=
 }
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/abstract_members.dart.weak.expect b/pkg/front_end/testcases/general_nnbd_opt_out/abstract_members.dart.weak.expect
index 4d04d03..b43d627 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/abstract_members.dart.weak.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/abstract_members.dart.weak.expect
@@ -181,14 +181,6 @@
   method aMethod() → dynamic {}
   method bMethod() → dynamic {}
   method cMethod() → dynamic {}
-  no-such-method-forwarder get interfaceMethod1() → dynamic
-    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 1, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4))) as{TypeError,ForDynamic} dynamic;
-  no-such-method-forwarder set property3(dynamic _) → void
-    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C5, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
-  no-such-method-forwarder set interfaceMethod1(dynamic value) → void
-    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C6, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
-  no-such-method-forwarder set property1(dynamic _) → void
-    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C7, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
 }
 class MyMock1 extends self::B {
   synthetic constructor •() → self::MyMock1*
@@ -197,19 +189,19 @@
   method noSuchMethod(core::Invocation* _) → dynamic
     return null;
   no-such-method-forwarder method interfaceMethod2() → void
-    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C8, 0, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
-  no-such-method-forwarder method abstractMethod() → dynamic
-    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C9, 0, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4))) as{TypeError,ForDynamic} dynamic;
-  no-such-method-forwarder method interfaceMethod1() → void
     return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 0, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
+  no-such-method-forwarder method abstractMethod() → dynamic
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C5, 0, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4))) as{TypeError,ForDynamic} dynamic;
+  no-such-method-forwarder method interfaceMethod1() → void
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C6, 0, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
   no-such-method-forwarder method interfaceMethod3() → void
-    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C10, 0, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C7, 0, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
   no-such-method-forwarder set property3(dynamic _) → void
-    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C5, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C8, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
   no-such-method-forwarder set interfaceMethod1(dynamic value) → void
-    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C6, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C9, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
   no-such-method-forwarder set property1(dynamic _) → void
-    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C7, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
+    return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C10, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
   no-such-method-forwarder set property2(dynamic _) → void
     return this.{self::MyMock1::noSuchMethod}(new core::_InvocationMirror::_withType(#C11, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
 }
@@ -224,16 +216,6 @@
     : super self::B::•()
     ;
   abstract method noSuchMethod(core::Invocation* _) → dynamic;
-  no-such-method-forwarder get interfaceMethod1() → dynamic
-    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 1, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4))) as{TypeError,ForDynamic} dynamic;
-  no-such-method-forwarder set property3(dynamic _) → void
-    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#C5, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
-  no-such-method-forwarder set interfaceMethod1(dynamic value) → void
-    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#C6, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
-  no-such-method-forwarder set property1(dynamic _) → void
-    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#C7, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
-  no-such-method-forwarder set property2(dynamic _) → void
-    return this.{self::MyMock3::noSuchMethod}(new core::_InvocationMirror::_withType(#C11, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[_]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
 }
 class C extends core::Object {
   synthetic constructor •() → self::C*
@@ -296,15 +278,15 @@
 static method main() → dynamic {}
 
 constants  {
-  #C1 = #interfaceMethod1
+  #C1 = #interfaceMethod2
   #C2 = <core::Type*>[]
   #C3 = <dynamic>[]
   #C4 = core::_ImmutableMap<core::Symbol*, dynamic> {_kvPairs:#C3}
-  #C5 = #property3=
-  #C6 = #interfaceMethod1=
-  #C7 = #property1=
-  #C8 = #interfaceMethod2
-  #C9 = #abstractMethod
-  #C10 = #interfaceMethod3
+  #C5 = #abstractMethod
+  #C6 = #interfaceMethod1
+  #C7 = #interfaceMethod3
+  #C8 = #property3=
+  #C9 = #interfaceMethod1=
+  #C10 = #property1=
   #C11 = #property2=
 }
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/external.dart b/pkg/front_end/testcases/general_nnbd_opt_out/external.dart
index 54ce8a7..ae5fa13 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/external.dart
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/external.dart
@@ -1,6 +1,9 @@
 // Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
+
+// @dart=2.6
+
 import 'dart:isolate';
 
 var subscription;
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart b/pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart
index 4f11955..eaec508 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart
@@ -15,8 +15,9 @@
 class Class = Super with Mixin;
 
 main() {
-  // TODO(johnniwinther): The parameter is created before the super constructor
-  //  parameter type is inferred. Set up a way to propagate the inferred type
-  //  to its use sites.
+  new Class(0);
+}
+
+error() {
   new Class('');
 }
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart.outline.expect b/pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart.outline.expect
index 275d510..eb95af0 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart.outline.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart.outline.expect
@@ -12,9 +12,11 @@
     ;
 }
 class Class = self::Super with self::Mixin {
-  synthetic constructor •(dynamic field) → self::Class*
+  synthetic constructor •(core::int* field) → self::Class*
     : super self::Super::•(field)
     ;
 }
 static method main() → dynamic
   ;
+static method error() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart.strong.expect b/pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart.strong.expect
index db0dcf5..5f066ca 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart.strong.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart.strong.expect
@@ -1,4 +1,11 @@
 library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart:22:13: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+//   new Class('');
+//             ^
+//
 import self as self;
 import "dart:core" as core;
 
@@ -14,10 +21,15 @@
     ;
 }
 class Class = self::Super with self::Mixin {
-  synthetic constructor •(dynamic field) → self::Class*
+  synthetic constructor •(core::int* field) → self::Class*
     : super self::Super::•(field)
     ;
 }
 static method main() → dynamic {
-  new self::Class::•("");
+  new self::Class::•(0);
+}
+static method error() → dynamic {
+  new self::Class::•(let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart:22:13: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+  new Class('');
+            ^" in "" as{TypeError} core::int*);
 }
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart.strong.transformed.expect b/pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart.strong.transformed.expect
index 174f790..e797e4f 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart.strong.transformed.expect
@@ -1,4 +1,11 @@
 library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart:22:13: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+//   new Class('');
+//             ^
+//
 import self as self;
 import "dart:core" as core;
 
@@ -14,10 +21,15 @@
     ;
 }
 class Class extends self::Super implements self::Mixin {
-  synthetic constructor •(dynamic field) → self::Class*
+  synthetic constructor •(core::int* field) → self::Class*
     : super self::Super::•(field)
     ;
 }
 static method main() → dynamic {
-  new self::Class::•("");
+  new self::Class::•(0);
+}
+static method error() → dynamic {
+  new self::Class::•(let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart:22:13: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+  new Class('');
+            ^" in "" as{TypeError} core::int*);
 }
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart.weak.expect b/pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart.weak.expect
index db0dcf5..5f066ca 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart.weak.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart.weak.expect
@@ -1,4 +1,11 @@
 library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart:22:13: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+//   new Class('');
+//             ^
+//
 import self as self;
 import "dart:core" as core;
 
@@ -14,10 +21,15 @@
     ;
 }
 class Class = self::Super with self::Mixin {
-  synthetic constructor •(dynamic field) → self::Class*
+  synthetic constructor •(core::int* field) → self::Class*
     : super self::Super::•(field)
     ;
 }
 static method main() → dynamic {
-  new self::Class::•("");
+  new self::Class::•(0);
+}
+static method error() → dynamic {
+  new self::Class::•(let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart:22:13: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+  new Class('');
+            ^" in "" as{TypeError} core::int*);
 }
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart.weak.transformed.expect b/pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart.weak.transformed.expect
index 174f790..e797e4f 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart.weak.transformed.expect
@@ -1,4 +1,11 @@
 library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart:22:13: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+//   new Class('');
+//             ^
+//
 import self as self;
 import "dart:core" as core;
 
@@ -14,10 +21,15 @@
     ;
 }
 class Class extends self::Super implements self::Mixin {
-  synthetic constructor •(dynamic field) → self::Class*
+  synthetic constructor •(core::int* field) → self::Class*
     : super self::Super::•(field)
     ;
 }
 static method main() → dynamic {
-  new self::Class::•("");
+  new self::Class::•(0);
+}
+static method error() → dynamic {
+  new self::Class::•(let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/general_nnbd_opt_out/mixin_application_inferred_parameter_type.dart:22:13: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+  new Class('');
+            ^" in "" as{TypeError} core::int*);
 }
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_29.yaml.world.1.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_29.yaml.world.1.expect
index 400b523..c1312ba 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_29.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_29.yaml.world.1.expect
@@ -40,19 +40,22 @@
     }
     get field7() → dart.core::int? {
       if(!this.{main::C::_#C#field7#isSet}) {
+        final dart.core::int? #t3 = 42;
+        if(this.{main::C::_#C#field7#isSet})
+          throw new dart._internal::LateInitializationErrorImpl::•("Field 'field7' has been assigned during initialization.");
         this.{main::C::_#C#field7#isSet} = true;
-        this.{main::C::_#C#field7} = 42;
+        this.{main::C::_#C#field7} = #t3;
       }
       return this.{main::C::_#C#field7};
     }
     get field8() → dart.core::int?
       return this.{main::C::_#C#field8#isSet} ?{dart.core::int?} this.{main::C::_#C#field8} : throw new dart._internal::LateInitializationErrorImpl::•("Field 'field8' has not been initialized.");
-    set field8(dart.core::int? #t3) → void
+    set field8(dart.core::int? #t4) → void
       if(this.{main::C::_#C#field8#isSet})
         throw new dart._internal::LateInitializationErrorImpl::•("Field 'field8' has already been initialized.");
       else {
         this.{main::C::_#C#field8#isSet} = true;
-        this.{main::C::_#C#field8} = #t3;
+        this.{main::C::_#C#field8} = #t4;
       }
     static get field9() → dart.core::int? {
       if(!main::C::_#field9#isSet) {
@@ -61,31 +64,34 @@
       }
       return main::C::_#field9;
     }
-    static set field9(dart.core::int? #t4) → void {
+    static set field9(dart.core::int? #t5) → void {
       main::C::_#field9#isSet = true;
-      main::C::_#field9 = #t4;
+      main::C::_#field9 = #t5;
     }
     static get field10() → dart.core::int?
       return main::C::_#field10#isSet ?{dart.core::int?} main::C::_#field10 : throw new dart._internal::LateInitializationErrorImpl::•("Field 'field10' has not been initialized.");
-    static set field10(dart.core::int? #t5) → void {
+    static set field10(dart.core::int? #t6) → void {
       main::C::_#field10#isSet = true;
-      main::C::_#field10 = #t5;
+      main::C::_#field10 = #t6;
     }
     static get field11() → dart.core::int? {
       if(!main::C::_#field11#isSet) {
+        final dart.core::int? #t7 = 42;
+        if(main::C::_#field11#isSet)
+          throw new dart._internal::LateInitializationErrorImpl::•("Field 'field11' has been assigned during initialization.");
         main::C::_#field11#isSet = true;
-        main::C::_#field11 = 42;
+        main::C::_#field11 = #t7;
       }
       return main::C::_#field11;
     }
     static get field12() → dart.core::int?
       return main::C::_#field12#isSet ?{dart.core::int?} main::C::_#field12 : throw new dart._internal::LateInitializationErrorImpl::•("Field 'field12' has not been initialized.");
-    static set field12(dart.core::int? #t6) → void
+    static set field12(dart.core::int? #t8) → void
       if(main::C::_#field12#isSet)
         throw new dart._internal::LateInitializationErrorImpl::•("Field 'field12' has already been initialized.");
       else {
         main::C::_#field12#isSet = true;
-        main::C::_#field12 = #t6;
+        main::C::_#field12 = #t8;
       }
   }
   static field dart.core::int? _#field1 = null;
@@ -103,31 +109,34 @@
     }
     return main::_#field1;
   }
-  static set field1(dart.core::int? #t7) → void {
+  static set field1(dart.core::int? #t9) → void {
     main::_#field1#isSet = true;
-    main::_#field1 = #t7;
+    main::_#field1 = #t9;
   }
   static get field2() → dart.core::int?
     return main::_#field2#isSet ?{dart.core::int?} main::_#field2 : throw new dart._internal::LateInitializationErrorImpl::•("Field 'field2' has not been initialized.");
-  static set field2(dart.core::int? #t8) → void {
+  static set field2(dart.core::int? #t10) → void {
     main::_#field2#isSet = true;
-    main::_#field2 = #t8;
+    main::_#field2 = #t10;
   }
   static get field3() → dart.core::int? {
     if(!main::_#field3#isSet) {
+      final dart.core::int? #t11 = 42;
+      if(main::_#field3#isSet)
+        throw new dart._internal::LateInitializationErrorImpl::•("Field 'field3' has been assigned during initialization.");
       main::_#field3#isSet = true;
-      main::_#field3 = 42;
+      main::_#field3 = #t11;
     }
     return main::_#field3;
   }
   static get field4() → dart.core::int?
     return main::_#field4#isSet ?{dart.core::int?} main::_#field4 : throw new dart._internal::LateInitializationErrorImpl::•("Field 'field4' has not been initialized.");
-  static set field4(dart.core::int? #t9) → void
+  static set field4(dart.core::int? #t12) → void
     if(main::_#field4#isSet)
       throw new dart._internal::LateInitializationErrorImpl::•("Field 'field4' has already been initialized.");
     else {
       main::_#field4#isSet = true;
-      main::_#field4 = #t9;
+      main::_#field4 = #t12;
     }
   static method main() → dynamic {
     main::field1 = 43;
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_29.yaml.world.2.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_29.yaml.world.2.expect
index 47dca35..fcb2736 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_29.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_29.yaml.world.2.expect
@@ -40,19 +40,22 @@
     }
     get field7() → dart.core::int? {
       if(!this.{main::C::_#C#field7#isSet}) {
+        final dart.core::int? #t3 = 42;
+        if(this.{main::C::_#C#field7#isSet})
+          throw new dart._internal::LateInitializationErrorImpl::•("Field 'field7' has been assigned during initialization.");
         this.{main::C::_#C#field7#isSet} = true;
-        this.{main::C::_#C#field7} = 42;
+        this.{main::C::_#C#field7} = #t3;
       }
       return this.{main::C::_#C#field7};
     }
     get field8() → dart.core::int?
       return this.{main::C::_#C#field8#isSet} ?{dart.core::int?} this.{main::C::_#C#field8} : throw new dart._internal::LateInitializationErrorImpl::•("Field 'field8' has not been initialized.");
-    set field8(dart.core::int? #t3) → void
+    set field8(dart.core::int? #t4) → void
       if(this.{main::C::_#C#field8#isSet})
         throw new dart._internal::LateInitializationErrorImpl::•("Field 'field8' has already been initialized.");
       else {
         this.{main::C::_#C#field8#isSet} = true;
-        this.{main::C::_#C#field8} = #t3;
+        this.{main::C::_#C#field8} = #t4;
       }
     static get field9() → dart.core::int? {
       if(!main::C::_#field9#isSet) {
@@ -61,31 +64,34 @@
       }
       return main::C::_#field9;
     }
-    static set field9(dart.core::int? #t4) → void {
+    static set field9(dart.core::int? #t5) → void {
       main::C::_#field9#isSet = true;
-      main::C::_#field9 = #t4;
+      main::C::_#field9 = #t5;
     }
     static get field10() → dart.core::int?
       return main::C::_#field10#isSet ?{dart.core::int?} main::C::_#field10 : throw new dart._internal::LateInitializationErrorImpl::•("Field 'field10' has not been initialized.");
-    static set field10(dart.core::int? #t5) → void {
+    static set field10(dart.core::int? #t6) → void {
       main::C::_#field10#isSet = true;
-      main::C::_#field10 = #t5;
+      main::C::_#field10 = #t6;
     }
     static get field11() → dart.core::int? {
       if(!main::C::_#field11#isSet) {
+        final dart.core::int? #t7 = 42;
+        if(main::C::_#field11#isSet)
+          throw new dart._internal::LateInitializationErrorImpl::•("Field 'field11' has been assigned during initialization.");
         main::C::_#field11#isSet = true;
-        main::C::_#field11 = 42;
+        main::C::_#field11 = #t7;
       }
       return main::C::_#field11;
     }
     static get field12() → dart.core::int?
       return main::C::_#field12#isSet ?{dart.core::int?} main::C::_#field12 : throw new dart._internal::LateInitializationErrorImpl::•("Field 'field12' has not been initialized.");
-    static set field12(dart.core::int? #t6) → void
+    static set field12(dart.core::int? #t8) → void
       if(main::C::_#field12#isSet)
         throw new dart._internal::LateInitializationErrorImpl::•("Field 'field12' has already been initialized.");
       else {
         main::C::_#field12#isSet = true;
-        main::C::_#field12 = #t6;
+        main::C::_#field12 = #t8;
       }
   }
   static field dart.core::int? _#field1 = null;
@@ -103,31 +109,34 @@
     }
     return main::_#field1;
   }
-  static set field1(dart.core::int? #t7) → void {
+  static set field1(dart.core::int? #t9) → void {
     main::_#field1#isSet = true;
-    main::_#field1 = #t7;
+    main::_#field1 = #t9;
   }
   static get field2() → dart.core::int?
     return main::_#field2#isSet ?{dart.core::int?} main::_#field2 : throw new dart._internal::LateInitializationErrorImpl::•("Field 'field2' has not been initialized.");
-  static set field2(dart.core::int? #t8) → void {
+  static set field2(dart.core::int? #t10) → void {
     main::_#field2#isSet = true;
-    main::_#field2 = #t8;
+    main::_#field2 = #t10;
   }
   static get field3() → dart.core::int? {
     if(!main::_#field3#isSet) {
+      final dart.core::int? #t11 = 42;
+      if(main::_#field3#isSet)
+        throw new dart._internal::LateInitializationErrorImpl::•("Field 'field3' has been assigned during initialization.");
       main::_#field3#isSet = true;
-      main::_#field3 = 42;
+      main::_#field3 = #t11;
     }
     return main::_#field3;
   }
   static get field4() → dart.core::int?
     return main::_#field4#isSet ?{dart.core::int?} main::_#field4 : throw new dart._internal::LateInitializationErrorImpl::•("Field 'field4' has not been initialized.");
-  static set field4(dart.core::int? #t9) → void
+  static set field4(dart.core::int? #t12) → void
     if(main::_#field4#isSet)
       throw new dart._internal::LateInitializationErrorImpl::•("Field 'field4' has already been initialized.");
     else {
       main::_#field4#isSet = true;
-      main::_#field4 = #t9;
+      main::_#field4 = #t12;
     }
   static method main() → dynamic {
     main::field1 = 44;
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_31.yaml.world.1.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_31.yaml.world.1.expect
index 0bbc1ed..0bb5760 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_31.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_31.yaml.world.1.expect
@@ -58,19 +58,22 @@
   }
   static get field3() → dart.core::int? {
     if(!main::_#field3#isSet) {
+      final dart.core::int? #t3 = 42;
+      if(main::_#field3#isSet)
+        throw new dart._internal::LateInitializationErrorImpl::•("Field 'field3' has been assigned during initialization.");
       main::_#field3#isSet = true;
-      main::_#field3 = 42;
+      main::_#field3 = #t3;
     }
     return main::_#field3;
   }
   static get field4() → dart.core::int?
     return main::_#field4#isSet ?{dart.core::int?} main::_#field4 : throw new dart._internal::LateInitializationErrorImpl::•("Field 'field4' has not been initialized.");
-  static set field4(dart.core::int? #t3) → void
+  static set field4(dart.core::int? #t4) → void
     if(main::_#field4#isSet)
       throw new dart._internal::LateInitializationErrorImpl::•("Field 'field4' has already been initialized.");
     else {
       main::_#field4#isSet = true;
-      main::_#field4 = #t3;
+      main::_#field4 = #t4;
     }
   static get _extension#0|field5() → dart.core::int? {
     if(!main::_#_extension#0|field5#isSet) {
@@ -79,31 +82,34 @@
     }
     return main::_#_extension#0|field5;
   }
-  static set _extension#0|field5(dart.core::int? #t4) → void {
+  static set _extension#0|field5(dart.core::int? #t5) → void {
     main::_#_extension#0|field5#isSet = true;
-    main::_#_extension#0|field5 = #t4;
+    main::_#_extension#0|field5 = #t5;
   }
   static get _extension#0|field6() → dart.core::int?
     return main::_#_extension#0|field6#isSet ?{dart.core::int?} main::_#_extension#0|field6 : throw new dart._internal::LateInitializationErrorImpl::•("Field 'field6' has not been initialized.");
-  static set _extension#0|field6(dart.core::int? #t5) → void {
+  static set _extension#0|field6(dart.core::int? #t6) → void {
     main::_#_extension#0|field6#isSet = true;
-    main::_#_extension#0|field6 = #t5;
+    main::_#_extension#0|field6 = #t6;
   }
   static get _extension#0|field7() → dart.core::int? {
     if(!main::_#_extension#0|field7#isSet) {
+      final dart.core::int? #t7 = 42;
+      if(main::_#_extension#0|field7#isSet)
+        throw new dart._internal::LateInitializationErrorImpl::•("Field 'field7' has been assigned during initialization.");
       main::_#_extension#0|field7#isSet = true;
-      main::_#_extension#0|field7 = 42;
+      main::_#_extension#0|field7 = #t7;
     }
     return main::_#_extension#0|field7;
   }
   static get _extension#0|field8() → dart.core::int?
     return main::_#_extension#0|field8#isSet ?{dart.core::int?} main::_#_extension#0|field8 : throw new dart._internal::LateInitializationErrorImpl::•("Field 'field8' has not been initialized.");
-  static set _extension#0|field8(dart.core::int? #t6) → void
+  static set _extension#0|field8(dart.core::int? #t8) → void
     if(main::_#_extension#0|field8#isSet)
       throw new dart._internal::LateInitializationErrorImpl::•("Field 'field8' has already been initialized.");
     else {
       main::_#_extension#0|field8#isSet = true;
-      main::_#_extension#0|field8 = #t6;
+      main::_#_extension#0|field8 = #t8;
     }
   static method main() → dynamic {
     main::field1 = 43;
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_31.yaml.world.2.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_31.yaml.world.2.expect
index 5363796..fdf6f59 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_31.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_31.yaml.world.2.expect
@@ -58,19 +58,22 @@
   }
   static get field3() → dart.core::int? {
     if(!main::_#field3#isSet) {
+      final dart.core::int? #t3 = 42;
+      if(main::_#field3#isSet)
+        throw new dart._internal::LateInitializationErrorImpl::•("Field 'field3' has been assigned during initialization.");
       main::_#field3#isSet = true;
-      main::_#field3 = 42;
+      main::_#field3 = #t3;
     }
     return main::_#field3;
   }
   static get field4() → dart.core::int?
     return main::_#field4#isSet ?{dart.core::int?} main::_#field4 : throw new dart._internal::LateInitializationErrorImpl::•("Field 'field4' has not been initialized.");
-  static set field4(dart.core::int? #t3) → void
+  static set field4(dart.core::int? #t4) → void
     if(main::_#field4#isSet)
       throw new dart._internal::LateInitializationErrorImpl::•("Field 'field4' has already been initialized.");
     else {
       main::_#field4#isSet = true;
-      main::_#field4 = #t3;
+      main::_#field4 = #t4;
     }
   static get _extension#0|field5() → dart.core::int? {
     if(!main::_#_extension#0|field5#isSet) {
@@ -79,31 +82,34 @@
     }
     return main::_#_extension#0|field5;
   }
-  static set _extension#0|field5(dart.core::int? #t4) → void {
+  static set _extension#0|field5(dart.core::int? #t5) → void {
     main::_#_extension#0|field5#isSet = true;
-    main::_#_extension#0|field5 = #t4;
+    main::_#_extension#0|field5 = #t5;
   }
   static get _extension#0|field6() → dart.core::int?
     return main::_#_extension#0|field6#isSet ?{dart.core::int?} main::_#_extension#0|field6 : throw new dart._internal::LateInitializationErrorImpl::•("Field 'field6' has not been initialized.");
-  static set _extension#0|field6(dart.core::int? #t5) → void {
+  static set _extension#0|field6(dart.core::int? #t6) → void {
     main::_#_extension#0|field6#isSet = true;
-    main::_#_extension#0|field6 = #t5;
+    main::_#_extension#0|field6 = #t6;
   }
   static get _extension#0|field7() → dart.core::int? {
     if(!main::_#_extension#0|field7#isSet) {
+      final dart.core::int? #t7 = 42;
+      if(main::_#_extension#0|field7#isSet)
+        throw new dart._internal::LateInitializationErrorImpl::•("Field 'field7' has been assigned during initialization.");
       main::_#_extension#0|field7#isSet = true;
-      main::_#_extension#0|field7 = 42;
+      main::_#_extension#0|field7 = #t7;
     }
     return main::_#_extension#0|field7;
   }
   static get _extension#0|field8() → dart.core::int?
     return main::_#_extension#0|field8#isSet ?{dart.core::int?} main::_#_extension#0|field8 : throw new dart._internal::LateInitializationErrorImpl::•("Field 'field8' has not been initialized.");
-  static set _extension#0|field8(dart.core::int? #t6) → void
+  static set _extension#0|field8(dart.core::int? #t8) → void
     if(main::_#_extension#0|field8#isSet)
       throw new dart._internal::LateInitializationErrorImpl::•("Field 'field8' has already been initialized.");
     else {
       main::_#_extension#0|field8#isSet = true;
-      main::_#_extension#0|field8 = #t6;
+      main::_#_extension#0|field8 = #t8;
     }
   static method main() → dynamic {
     main::field1 = 44;
diff --git a/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart b/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart
new file mode 100644
index 0000000..d444b164
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2020, 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.
+
+int nonNullableTopLevelFieldReads = 0;
+
+late final int nonNullableTopLevelField =
+    nonNullableTopLevelFieldReads++ == 0 ? nonNullableTopLevelField + 1 : 0;
+
+int nullableTopLevelFieldReads = 0;
+
+late final int? nullableTopLevelField =
+    nullableTopLevelFieldReads++ == 0 ? nullableTopLevelField.hashCode : 0;
+
+class Class {
+  static int nonNullableStaticFieldReads = 0;
+
+  static late final int nonNullableStaticField =
+      nonNullableStaticFieldReads++ == 0 ? nonNullableStaticField + 1 : 0;
+
+  static int nullableStaticFieldReads = 0;
+
+  static late final int? nullableStaticField =
+      nullableStaticFieldReads++ == 0 ? nullableStaticField.hashCode : 0;
+
+  int nonNullableInstanceFieldReads = 0;
+
+  late final int nonNullableInstanceField =
+      nonNullableInstanceFieldReads++ == 0 ? nonNullableInstanceField + 1 : 0;
+
+  int nullableInstanceFieldReads = 0;
+
+  late final int? nullableInstanceField =
+      nullableInstanceFieldReads++ == 0 ? nullableInstanceField.hashCode : 0;
+}
+
+void main() {
+  throws(() => nonNullableTopLevelField, "Read nonNullableTopLevelField");
+  throws(() => nullableTopLevelField, "Read nullableTopLevelField");
+  throws(() => Class.nonNullableStaticField, "Read nonNullableStaticField");
+  throws(() => Class.nullableStaticField, "Read nullableStaticField");
+  throws(() => new Class().nonNullableInstanceField,
+      "Read nonNullableInstanceField");
+  throws(() => new Class().nullableInstanceField, "Read nullableInstanceField");
+}
+
+throws(f(), String message) {
+  dynamic value;
+  try {
+    value = f();
+  } on LateInitializationError catch (e) {
+    print(e);
+    return;
+  }
+  throw '$message: $value';
+}
diff --git a/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.outline.expect b/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.outline.expect
new file mode 100644
index 0000000..baafca82
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.outline.expect
@@ -0,0 +1,33 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  static field core::int nonNullableStaticFieldReads;
+  static field core::int? _#nonNullableStaticField;
+  static field core::int nullableStaticFieldReads;
+  static field core::int? _#nullableStaticField;
+  static field core::bool _#nullableStaticField#isSet;
+  field core::int nonNullableInstanceFieldReads;
+  field core::int? _#Class#nonNullableInstanceField;
+  field core::int nullableInstanceFieldReads;
+  field core::int? _#Class#nullableInstanceField;
+  field core::bool _#Class#nullableInstanceField#isSet;
+  synthetic constructor •() → self::Class
+    ;
+  static get nonNullableStaticField() → core::int;
+  static get nullableStaticField() → core::int?;
+  get nonNullableInstanceField() → core::int;
+  get nullableInstanceField() → core::int?;
+}
+static field core::int nonNullableTopLevelFieldReads;
+static field core::int? _#nonNullableTopLevelField;
+static field core::int nullableTopLevelFieldReads;
+static field core::int? _#nullableTopLevelField;
+static field core::bool _#nullableTopLevelField#isSet;
+static get nonNullableTopLevelField() → core::int;
+static get nullableTopLevelField() → core::int?;
+static method main() → void
+  ;
+static method throws(() → dynamic f, core::String message) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.strong.expect b/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.strong.expect
new file mode 100644
index 0000000..461a137
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.strong.expect
@@ -0,0 +1,80 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+class Class extends core::Object {
+  static field core::int nonNullableStaticFieldReads = 0;
+  static field core::int? _#nonNullableStaticField = null;
+  static field core::int nullableStaticFieldReads = 0;
+  static field core::int? _#nullableStaticField = null;
+  static field core::bool _#nullableStaticField#isSet = false;
+  field core::int nonNullableInstanceFieldReads = 0;
+  field core::int? _#Class#nonNullableInstanceField = null;
+  field core::int nullableInstanceFieldReads = 0;
+  field core::int? _#Class#nullableInstanceField = null;
+  field core::bool _#Class#nullableInstanceField#isSet = false;
+  synthetic constructor •() → self::Class
+    : super core::Object::•()
+    ;
+  static get nonNullableStaticField() → core::int
+    return let final core::int? #t1 = self::Class::_#nonNullableStaticField in #t1.==(null) ?{core::int} let final core::int #t2 = (let final core::int #t3 = self::Class::nonNullableStaticFieldReads in let final core::int #t4 = self::Class::nonNullableStaticFieldReads = #t3.{core::num::+}(1) in #t3).{core::num::==}(0) ?{core::int} self::Class::nonNullableStaticField.{core::num::+}(1) : 0 in self::Class::_#nonNullableStaticField.==(null) ?{core::int} self::Class::_#nonNullableStaticField = #t2 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticField' has been assigned during initialization.") : #t1{core::int};
+  static get nullableStaticField() → core::int? {
+    if(!self::Class::_#nullableStaticField#isSet) {
+      final core::int? #t5 = (let final core::int #t6 = self::Class::nullableStaticFieldReads in let final core::int #t7 = self::Class::nullableStaticFieldReads = #t6.{core::num::+}(1) in #t6).{core::num::==}(0) ?{core::int*} self::Class::nullableStaticField.{core::num::hashCode} : 0;
+      if(self::Class::_#nullableStaticField#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'nullableStaticField' has been assigned during initialization.");
+      self::Class::_#nullableStaticField#isSet = true;
+      self::Class::_#nullableStaticField = #t5;
+    }
+    return self::Class::_#nullableStaticField;
+  }
+  get nonNullableInstanceField() → core::int
+    return let final core::int? #t8 = this.{self::Class::_#Class#nonNullableInstanceField} in #t8.==(null) ?{core::int} let final core::int #t9 = (let final core::int #t10 = this.{self::Class::nonNullableInstanceFieldReads} in let final core::int #t11 = this.{self::Class::nonNullableInstanceFieldReads} = #t10.{core::num::+}(1) in #t10).{core::num::==}(0) ?{core::int} this.{self::Class::nonNullableInstanceField}.{core::num::+}(1) : 0 in this.{self::Class::_#Class#nonNullableInstanceField}.==(null) ?{core::int} this.{self::Class::_#Class#nonNullableInstanceField} = #t9 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableInstanceField' has been assigned during initialization.") : #t8{core::int};
+  get nullableInstanceField() → core::int? {
+    if(!this.{self::Class::_#Class#nullableInstanceField#isSet}) {
+      final core::int? #t12 = (let final core::int #t13 = this.{self::Class::nullableInstanceFieldReads} in let final core::int #t14 = this.{self::Class::nullableInstanceFieldReads} = #t13.{core::num::+}(1) in #t13).{core::num::==}(0) ?{core::int*} this.{self::Class::nullableInstanceField}.{core::num::hashCode} : 0;
+      if(this.{self::Class::_#Class#nullableInstanceField#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'nullableInstanceField' has been assigned during initialization.");
+      this.{self::Class::_#Class#nullableInstanceField#isSet} = true;
+      this.{self::Class::_#Class#nullableInstanceField} = #t12;
+    }
+    return this.{self::Class::_#Class#nullableInstanceField};
+  }
+}
+static field core::int nonNullableTopLevelFieldReads = 0;
+static field core::int? _#nonNullableTopLevelField = null;
+static field core::int nullableTopLevelFieldReads = 0;
+static field core::int? _#nullableTopLevelField = null;
+static field core::bool _#nullableTopLevelField#isSet = false;
+static get nonNullableTopLevelField() → core::int
+  return let final core::int? #t15 = self::_#nonNullableTopLevelField in #t15.==(null) ?{core::int} let final core::int #t16 = (let final core::int #t17 = self::nonNullableTopLevelFieldReads in let final core::int #t18 = self::nonNullableTopLevelFieldReads = #t17.{core::num::+}(1) in #t17).{core::num::==}(0) ?{core::int} self::nonNullableTopLevelField.{core::num::+}(1) : 0 in self::_#nonNullableTopLevelField.==(null) ?{core::int} self::_#nonNullableTopLevelField = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has been assigned during initialization.") : #t15{core::int};
+static get nullableTopLevelField() → core::int? {
+  if(!self::_#nullableTopLevelField#isSet) {
+    final core::int? #t19 = (let final core::int #t20 = self::nullableTopLevelFieldReads in let final core::int #t21 = self::nullableTopLevelFieldReads = #t20.{core::num::+}(1) in #t20).{core::num::==}(0) ?{core::int*} self::nullableTopLevelField.{core::num::hashCode} : 0;
+    if(self::_#nullableTopLevelField#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'nullableTopLevelField' has been assigned during initialization.");
+    self::_#nullableTopLevelField#isSet = true;
+    self::_#nullableTopLevelField = #t19;
+  }
+  return self::_#nullableTopLevelField;
+}
+static method main() → void {
+  self::throws(() → core::int => self::nonNullableTopLevelField, "Read nonNullableTopLevelField");
+  self::throws(() → core::int? => self::nullableTopLevelField, "Read nullableTopLevelField");
+  self::throws(() → core::int => self::Class::nonNullableStaticField, "Read nonNullableStaticField");
+  self::throws(() → core::int? => self::Class::nullableStaticField, "Read nullableStaticField");
+  self::throws(() → core::int => new self::Class::•().{self::Class::nonNullableInstanceField}, "Read nonNullableInstanceField");
+  self::throws(() → core::int? => new self::Class::•().{self::Class::nullableInstanceField}, "Read nullableInstanceField");
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on core::LateInitializationError catch(final core::LateInitializationError e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.strong.transformed.expect
new file mode 100644
index 0000000..461a137
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.strong.transformed.expect
@@ -0,0 +1,80 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+class Class extends core::Object {
+  static field core::int nonNullableStaticFieldReads = 0;
+  static field core::int? _#nonNullableStaticField = null;
+  static field core::int nullableStaticFieldReads = 0;
+  static field core::int? _#nullableStaticField = null;
+  static field core::bool _#nullableStaticField#isSet = false;
+  field core::int nonNullableInstanceFieldReads = 0;
+  field core::int? _#Class#nonNullableInstanceField = null;
+  field core::int nullableInstanceFieldReads = 0;
+  field core::int? _#Class#nullableInstanceField = null;
+  field core::bool _#Class#nullableInstanceField#isSet = false;
+  synthetic constructor •() → self::Class
+    : super core::Object::•()
+    ;
+  static get nonNullableStaticField() → core::int
+    return let final core::int? #t1 = self::Class::_#nonNullableStaticField in #t1.==(null) ?{core::int} let final core::int #t2 = (let final core::int #t3 = self::Class::nonNullableStaticFieldReads in let final core::int #t4 = self::Class::nonNullableStaticFieldReads = #t3.{core::num::+}(1) in #t3).{core::num::==}(0) ?{core::int} self::Class::nonNullableStaticField.{core::num::+}(1) : 0 in self::Class::_#nonNullableStaticField.==(null) ?{core::int} self::Class::_#nonNullableStaticField = #t2 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticField' has been assigned during initialization.") : #t1{core::int};
+  static get nullableStaticField() → core::int? {
+    if(!self::Class::_#nullableStaticField#isSet) {
+      final core::int? #t5 = (let final core::int #t6 = self::Class::nullableStaticFieldReads in let final core::int #t7 = self::Class::nullableStaticFieldReads = #t6.{core::num::+}(1) in #t6).{core::num::==}(0) ?{core::int*} self::Class::nullableStaticField.{core::num::hashCode} : 0;
+      if(self::Class::_#nullableStaticField#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'nullableStaticField' has been assigned during initialization.");
+      self::Class::_#nullableStaticField#isSet = true;
+      self::Class::_#nullableStaticField = #t5;
+    }
+    return self::Class::_#nullableStaticField;
+  }
+  get nonNullableInstanceField() → core::int
+    return let final core::int? #t8 = this.{self::Class::_#Class#nonNullableInstanceField} in #t8.==(null) ?{core::int} let final core::int #t9 = (let final core::int #t10 = this.{self::Class::nonNullableInstanceFieldReads} in let final core::int #t11 = this.{self::Class::nonNullableInstanceFieldReads} = #t10.{core::num::+}(1) in #t10).{core::num::==}(0) ?{core::int} this.{self::Class::nonNullableInstanceField}.{core::num::+}(1) : 0 in this.{self::Class::_#Class#nonNullableInstanceField}.==(null) ?{core::int} this.{self::Class::_#Class#nonNullableInstanceField} = #t9 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableInstanceField' has been assigned during initialization.") : #t8{core::int};
+  get nullableInstanceField() → core::int? {
+    if(!this.{self::Class::_#Class#nullableInstanceField#isSet}) {
+      final core::int? #t12 = (let final core::int #t13 = this.{self::Class::nullableInstanceFieldReads} in let final core::int #t14 = this.{self::Class::nullableInstanceFieldReads} = #t13.{core::num::+}(1) in #t13).{core::num::==}(0) ?{core::int*} this.{self::Class::nullableInstanceField}.{core::num::hashCode} : 0;
+      if(this.{self::Class::_#Class#nullableInstanceField#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'nullableInstanceField' has been assigned during initialization.");
+      this.{self::Class::_#Class#nullableInstanceField#isSet} = true;
+      this.{self::Class::_#Class#nullableInstanceField} = #t12;
+    }
+    return this.{self::Class::_#Class#nullableInstanceField};
+  }
+}
+static field core::int nonNullableTopLevelFieldReads = 0;
+static field core::int? _#nonNullableTopLevelField = null;
+static field core::int nullableTopLevelFieldReads = 0;
+static field core::int? _#nullableTopLevelField = null;
+static field core::bool _#nullableTopLevelField#isSet = false;
+static get nonNullableTopLevelField() → core::int
+  return let final core::int? #t15 = self::_#nonNullableTopLevelField in #t15.==(null) ?{core::int} let final core::int #t16 = (let final core::int #t17 = self::nonNullableTopLevelFieldReads in let final core::int #t18 = self::nonNullableTopLevelFieldReads = #t17.{core::num::+}(1) in #t17).{core::num::==}(0) ?{core::int} self::nonNullableTopLevelField.{core::num::+}(1) : 0 in self::_#nonNullableTopLevelField.==(null) ?{core::int} self::_#nonNullableTopLevelField = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has been assigned during initialization.") : #t15{core::int};
+static get nullableTopLevelField() → core::int? {
+  if(!self::_#nullableTopLevelField#isSet) {
+    final core::int? #t19 = (let final core::int #t20 = self::nullableTopLevelFieldReads in let final core::int #t21 = self::nullableTopLevelFieldReads = #t20.{core::num::+}(1) in #t20).{core::num::==}(0) ?{core::int*} self::nullableTopLevelField.{core::num::hashCode} : 0;
+    if(self::_#nullableTopLevelField#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'nullableTopLevelField' has been assigned during initialization.");
+    self::_#nullableTopLevelField#isSet = true;
+    self::_#nullableTopLevelField = #t19;
+  }
+  return self::_#nullableTopLevelField;
+}
+static method main() → void {
+  self::throws(() → core::int => self::nonNullableTopLevelField, "Read nonNullableTopLevelField");
+  self::throws(() → core::int? => self::nullableTopLevelField, "Read nullableTopLevelField");
+  self::throws(() → core::int => self::Class::nonNullableStaticField, "Read nonNullableStaticField");
+  self::throws(() → core::int? => self::Class::nullableStaticField, "Read nullableStaticField");
+  self::throws(() → core::int => new self::Class::•().{self::Class::nonNullableInstanceField}, "Read nonNullableInstanceField");
+  self::throws(() → core::int? => new self::Class::•().{self::Class::nullableInstanceField}, "Read nullableInstanceField");
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on core::LateInitializationError catch(final core::LateInitializationError e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.weak.expect b/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.weak.expect
new file mode 100644
index 0000000..461a137
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.weak.expect
@@ -0,0 +1,80 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+class Class extends core::Object {
+  static field core::int nonNullableStaticFieldReads = 0;
+  static field core::int? _#nonNullableStaticField = null;
+  static field core::int nullableStaticFieldReads = 0;
+  static field core::int? _#nullableStaticField = null;
+  static field core::bool _#nullableStaticField#isSet = false;
+  field core::int nonNullableInstanceFieldReads = 0;
+  field core::int? _#Class#nonNullableInstanceField = null;
+  field core::int nullableInstanceFieldReads = 0;
+  field core::int? _#Class#nullableInstanceField = null;
+  field core::bool _#Class#nullableInstanceField#isSet = false;
+  synthetic constructor •() → self::Class
+    : super core::Object::•()
+    ;
+  static get nonNullableStaticField() → core::int
+    return let final core::int? #t1 = self::Class::_#nonNullableStaticField in #t1.==(null) ?{core::int} let final core::int #t2 = (let final core::int #t3 = self::Class::nonNullableStaticFieldReads in let final core::int #t4 = self::Class::nonNullableStaticFieldReads = #t3.{core::num::+}(1) in #t3).{core::num::==}(0) ?{core::int} self::Class::nonNullableStaticField.{core::num::+}(1) : 0 in self::Class::_#nonNullableStaticField.==(null) ?{core::int} self::Class::_#nonNullableStaticField = #t2 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticField' has been assigned during initialization.") : #t1{core::int};
+  static get nullableStaticField() → core::int? {
+    if(!self::Class::_#nullableStaticField#isSet) {
+      final core::int? #t5 = (let final core::int #t6 = self::Class::nullableStaticFieldReads in let final core::int #t7 = self::Class::nullableStaticFieldReads = #t6.{core::num::+}(1) in #t6).{core::num::==}(0) ?{core::int*} self::Class::nullableStaticField.{core::num::hashCode} : 0;
+      if(self::Class::_#nullableStaticField#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'nullableStaticField' has been assigned during initialization.");
+      self::Class::_#nullableStaticField#isSet = true;
+      self::Class::_#nullableStaticField = #t5;
+    }
+    return self::Class::_#nullableStaticField;
+  }
+  get nonNullableInstanceField() → core::int
+    return let final core::int? #t8 = this.{self::Class::_#Class#nonNullableInstanceField} in #t8.==(null) ?{core::int} let final core::int #t9 = (let final core::int #t10 = this.{self::Class::nonNullableInstanceFieldReads} in let final core::int #t11 = this.{self::Class::nonNullableInstanceFieldReads} = #t10.{core::num::+}(1) in #t10).{core::num::==}(0) ?{core::int} this.{self::Class::nonNullableInstanceField}.{core::num::+}(1) : 0 in this.{self::Class::_#Class#nonNullableInstanceField}.==(null) ?{core::int} this.{self::Class::_#Class#nonNullableInstanceField} = #t9 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableInstanceField' has been assigned during initialization.") : #t8{core::int};
+  get nullableInstanceField() → core::int? {
+    if(!this.{self::Class::_#Class#nullableInstanceField#isSet}) {
+      final core::int? #t12 = (let final core::int #t13 = this.{self::Class::nullableInstanceFieldReads} in let final core::int #t14 = this.{self::Class::nullableInstanceFieldReads} = #t13.{core::num::+}(1) in #t13).{core::num::==}(0) ?{core::int*} this.{self::Class::nullableInstanceField}.{core::num::hashCode} : 0;
+      if(this.{self::Class::_#Class#nullableInstanceField#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'nullableInstanceField' has been assigned during initialization.");
+      this.{self::Class::_#Class#nullableInstanceField#isSet} = true;
+      this.{self::Class::_#Class#nullableInstanceField} = #t12;
+    }
+    return this.{self::Class::_#Class#nullableInstanceField};
+  }
+}
+static field core::int nonNullableTopLevelFieldReads = 0;
+static field core::int? _#nonNullableTopLevelField = null;
+static field core::int nullableTopLevelFieldReads = 0;
+static field core::int? _#nullableTopLevelField = null;
+static field core::bool _#nullableTopLevelField#isSet = false;
+static get nonNullableTopLevelField() → core::int
+  return let final core::int? #t15 = self::_#nonNullableTopLevelField in #t15.==(null) ?{core::int} let final core::int #t16 = (let final core::int #t17 = self::nonNullableTopLevelFieldReads in let final core::int #t18 = self::nonNullableTopLevelFieldReads = #t17.{core::num::+}(1) in #t17).{core::num::==}(0) ?{core::int} self::nonNullableTopLevelField.{core::num::+}(1) : 0 in self::_#nonNullableTopLevelField.==(null) ?{core::int} self::_#nonNullableTopLevelField = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has been assigned during initialization.") : #t15{core::int};
+static get nullableTopLevelField() → core::int? {
+  if(!self::_#nullableTopLevelField#isSet) {
+    final core::int? #t19 = (let final core::int #t20 = self::nullableTopLevelFieldReads in let final core::int #t21 = self::nullableTopLevelFieldReads = #t20.{core::num::+}(1) in #t20).{core::num::==}(0) ?{core::int*} self::nullableTopLevelField.{core::num::hashCode} : 0;
+    if(self::_#nullableTopLevelField#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'nullableTopLevelField' has been assigned during initialization.");
+    self::_#nullableTopLevelField#isSet = true;
+    self::_#nullableTopLevelField = #t19;
+  }
+  return self::_#nullableTopLevelField;
+}
+static method main() → void {
+  self::throws(() → core::int => self::nonNullableTopLevelField, "Read nonNullableTopLevelField");
+  self::throws(() → core::int? => self::nullableTopLevelField, "Read nullableTopLevelField");
+  self::throws(() → core::int => self::Class::nonNullableStaticField, "Read nonNullableStaticField");
+  self::throws(() → core::int? => self::Class::nullableStaticField, "Read nullableStaticField");
+  self::throws(() → core::int => new self::Class::•().{self::Class::nonNullableInstanceField}, "Read nonNullableInstanceField");
+  self::throws(() → core::int? => new self::Class::•().{self::Class::nullableInstanceField}, "Read nullableInstanceField");
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on core::LateInitializationError catch(final core::LateInitializationError e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.weak.transformed.expect
new file mode 100644
index 0000000..461a137
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.weak.transformed.expect
@@ -0,0 +1,80 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+class Class extends core::Object {
+  static field core::int nonNullableStaticFieldReads = 0;
+  static field core::int? _#nonNullableStaticField = null;
+  static field core::int nullableStaticFieldReads = 0;
+  static field core::int? _#nullableStaticField = null;
+  static field core::bool _#nullableStaticField#isSet = false;
+  field core::int nonNullableInstanceFieldReads = 0;
+  field core::int? _#Class#nonNullableInstanceField = null;
+  field core::int nullableInstanceFieldReads = 0;
+  field core::int? _#Class#nullableInstanceField = null;
+  field core::bool _#Class#nullableInstanceField#isSet = false;
+  synthetic constructor •() → self::Class
+    : super core::Object::•()
+    ;
+  static get nonNullableStaticField() → core::int
+    return let final core::int? #t1 = self::Class::_#nonNullableStaticField in #t1.==(null) ?{core::int} let final core::int #t2 = (let final core::int #t3 = self::Class::nonNullableStaticFieldReads in let final core::int #t4 = self::Class::nonNullableStaticFieldReads = #t3.{core::num::+}(1) in #t3).{core::num::==}(0) ?{core::int} self::Class::nonNullableStaticField.{core::num::+}(1) : 0 in self::Class::_#nonNullableStaticField.==(null) ?{core::int} self::Class::_#nonNullableStaticField = #t2 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticField' has been assigned during initialization.") : #t1{core::int};
+  static get nullableStaticField() → core::int? {
+    if(!self::Class::_#nullableStaticField#isSet) {
+      final core::int? #t5 = (let final core::int #t6 = self::Class::nullableStaticFieldReads in let final core::int #t7 = self::Class::nullableStaticFieldReads = #t6.{core::num::+}(1) in #t6).{core::num::==}(0) ?{core::int*} self::Class::nullableStaticField.{core::num::hashCode} : 0;
+      if(self::Class::_#nullableStaticField#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'nullableStaticField' has been assigned during initialization.");
+      self::Class::_#nullableStaticField#isSet = true;
+      self::Class::_#nullableStaticField = #t5;
+    }
+    return self::Class::_#nullableStaticField;
+  }
+  get nonNullableInstanceField() → core::int
+    return let final core::int? #t8 = this.{self::Class::_#Class#nonNullableInstanceField} in #t8.==(null) ?{core::int} let final core::int #t9 = (let final core::int #t10 = this.{self::Class::nonNullableInstanceFieldReads} in let final core::int #t11 = this.{self::Class::nonNullableInstanceFieldReads} = #t10.{core::num::+}(1) in #t10).{core::num::==}(0) ?{core::int} this.{self::Class::nonNullableInstanceField}.{core::num::+}(1) : 0 in this.{self::Class::_#Class#nonNullableInstanceField}.==(null) ?{core::int} this.{self::Class::_#Class#nonNullableInstanceField} = #t9 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableInstanceField' has been assigned during initialization.") : #t8{core::int};
+  get nullableInstanceField() → core::int? {
+    if(!this.{self::Class::_#Class#nullableInstanceField#isSet}) {
+      final core::int? #t12 = (let final core::int #t13 = this.{self::Class::nullableInstanceFieldReads} in let final core::int #t14 = this.{self::Class::nullableInstanceFieldReads} = #t13.{core::num::+}(1) in #t13).{core::num::==}(0) ?{core::int*} this.{self::Class::nullableInstanceField}.{core::num::hashCode} : 0;
+      if(this.{self::Class::_#Class#nullableInstanceField#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'nullableInstanceField' has been assigned during initialization.");
+      this.{self::Class::_#Class#nullableInstanceField#isSet} = true;
+      this.{self::Class::_#Class#nullableInstanceField} = #t12;
+    }
+    return this.{self::Class::_#Class#nullableInstanceField};
+  }
+}
+static field core::int nonNullableTopLevelFieldReads = 0;
+static field core::int? _#nonNullableTopLevelField = null;
+static field core::int nullableTopLevelFieldReads = 0;
+static field core::int? _#nullableTopLevelField = null;
+static field core::bool _#nullableTopLevelField#isSet = false;
+static get nonNullableTopLevelField() → core::int
+  return let final core::int? #t15 = self::_#nonNullableTopLevelField in #t15.==(null) ?{core::int} let final core::int #t16 = (let final core::int #t17 = self::nonNullableTopLevelFieldReads in let final core::int #t18 = self::nonNullableTopLevelFieldReads = #t17.{core::num::+}(1) in #t17).{core::num::==}(0) ?{core::int} self::nonNullableTopLevelField.{core::num::+}(1) : 0 in self::_#nonNullableTopLevelField.==(null) ?{core::int} self::_#nonNullableTopLevelField = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has been assigned during initialization.") : #t15{core::int};
+static get nullableTopLevelField() → core::int? {
+  if(!self::_#nullableTopLevelField#isSet) {
+    final core::int? #t19 = (let final core::int #t20 = self::nullableTopLevelFieldReads in let final core::int #t21 = self::nullableTopLevelFieldReads = #t20.{core::num::+}(1) in #t20).{core::num::==}(0) ?{core::int*} self::nullableTopLevelField.{core::num::hashCode} : 0;
+    if(self::_#nullableTopLevelField#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'nullableTopLevelField' has been assigned during initialization.");
+    self::_#nullableTopLevelField#isSet = true;
+    self::_#nullableTopLevelField = #t19;
+  }
+  return self::_#nullableTopLevelField;
+}
+static method main() → void {
+  self::throws(() → core::int => self::nonNullableTopLevelField, "Read nonNullableTopLevelField");
+  self::throws(() → core::int? => self::nullableTopLevelField, "Read nullableTopLevelField");
+  self::throws(() → core::int => self::Class::nonNullableStaticField, "Read nonNullableStaticField");
+  self::throws(() → core::int? => self::Class::nullableStaticField, "Read nullableStaticField");
+  self::throws(() → core::int => new self::Class::•().{self::Class::nonNullableInstanceField}, "Read nonNullableInstanceField");
+  self::throws(() → core::int? => new self::Class::•().{self::Class::nullableInstanceField}, "Read nullableInstanceField");
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on core::LateInitializationError catch(final core::LateInitializationError e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.strong.expect
index a6e79a5..9c3f037 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.strong.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.strong.expect
@@ -1,6 +1,7 @@
 library;
 import self as self;
 import "dart:core" as core;
+import "dart:_internal" as _in;
 
 class Class<T extends core::Object? = dynamic> extends core::Object {
   static field core::int? lateStaticField1Init = null;
@@ -20,12 +21,12 @@
     return self::Class::lateStaticField1Init = value;
   }
   static get lateStaticField1() → core::int
-    return let final core::int? #t1 = self::Class::_#lateStaticField1 in #t1.==(null) ?{core::int} self::Class::_#lateStaticField1 = self::Class::initLateStaticField1(87) : #t1{core::int};
+    return let final core::int? #t1 = self::Class::_#lateStaticField1 in #t1.==(null) ?{core::int} let final core::int #t2 = self::Class::initLateStaticField1(87) in self::Class::_#lateStaticField1.==(null) ?{core::int} self::Class::_#lateStaticField1 = #t2 : throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField1' has been assigned during initialization.") : #t1{core::int};
   static method initLateStaticField2(core::int value) → core::int {
     return self::Class::lateStaticField2Init = value;
   }
   static get lateStaticField2() → core::int
-    return let final core::int? #t2 = self::Class::_#lateStaticField2 in #t2.==(null) ?{core::int} self::Class::_#lateStaticField2 = self::Class::initLateStaticField2(42) : #t2{core::int};
+    return let final core::int? #t3 = self::Class::_#lateStaticField2 in #t3.==(null) ?{core::int} let final core::int #t4 = self::Class::initLateStaticField2(42) in self::Class::_#lateStaticField2.==(null) ?{core::int} self::Class::_#lateStaticField2 = #t4 : throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField2' has been assigned during initialization.") : #t3{core::int};
   static method staticMethod() → dynamic {
     self::expect(null, self::Class::lateStaticField2Init);
     self::expect(42, self::Class::lateStaticField2);
@@ -35,16 +36,19 @@
     return this.{self::Class::lateInstanceFieldInit} = value;
   }
   get lateInstanceField() → core::int
-    return let final core::int? #t3 = this.{self::Class::_#Class#lateInstanceField} in #t3.==(null) ?{core::int} this.{self::Class::_#Class#lateInstanceField} = this.{self::Class::initLateInstanceField}(16) : #t3{core::int};
+    return let final core::int? #t5 = this.{self::Class::_#Class#lateInstanceField} in #t5.==(null) ?{core::int} let final core::int #t6 = this.{self::Class::initLateInstanceField}(16) in this.{self::Class::_#Class#lateInstanceField}.==(null) ?{core::int} this.{self::Class::_#Class#lateInstanceField} = #t6 : throw new _in::LateInitializationErrorImpl::•("Field 'lateInstanceField' has been assigned during initialization.") : #t5{core::int};
   method initLateGenericField(generic-covariant-impl self::Class::T% value) → self::Class::T% {
     return this.{self::Class::lateGenericFieldInit} = value;
   }
   get lateGenericField() → self::Class::T% {
     if(!this.{self::Class::_#Class#lateGenericField#isSet}) {
+      final self::Class::T% #t7 = this.{self::Class::initLateGenericField}(this.{self::Class::field});
+      if(this.{self::Class::_#Class#lateGenericField#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'lateGenericField' has been assigned during initialization.");
       this.{self::Class::_#Class#lateGenericField#isSet} = true;
-      this.{self::Class::_#Class#lateGenericField} = this.{self::Class::initLateGenericField}(this.{self::Class::field});
+      this.{self::Class::_#Class#lateGenericField} = #t7;
     }
-    return let final self::Class::T? #t4 = this.{self::Class::_#Class#lateGenericField} in #t4{self::Class::T%};
+    return let final self::Class::T? #t8 = this.{self::Class::_#Class#lateGenericField} in #t8{self::Class::T%};
   }
   method instanceMethod() → dynamic {
     self::expect(null, this.{self::Class::lateInstanceFieldInit});
@@ -76,17 +80,17 @@
   return self::lateTopLevelField1Init = value;
 }
 static get lateTopLevelField1() → core::int
-  return let final core::int? #t5 = self::_#lateTopLevelField1 in #t5.==(null) ?{core::int} self::_#lateTopLevelField1 = self::initLateTopLevelField1(123) : #t5{core::int};
+  return let final core::int? #t9 = self::_#lateTopLevelField1 in #t9.==(null) ?{core::int} let final core::int #t10 = self::initLateTopLevelField1(123) in self::_#lateTopLevelField1.==(null) ?{core::int} self::_#lateTopLevelField1 = #t10 : throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField1' has been assigned during initialization.") : #t9{core::int};
 static method Extension|initLateExtensionField1(core::int value) → core::int {
   return self::Extension|lateExtensionField1Init = value;
 }
 static get Extension|lateExtensionField1() → core::int
-  return let final core::int? #t6 = self::_#Extension|lateExtensionField1 in #t6.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = self::Extension|initLateExtensionField1(87) : #t6{core::int};
+  return let final core::int? #t11 = self::_#Extension|lateExtensionField1 in #t11.==(null) ?{core::int} let final core::int #t12 = self::Extension|initLateExtensionField1(87) in self::_#Extension|lateExtensionField1.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = #t12 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has been assigned during initialization.") : #t11{core::int};
 static method Extension|initLateExtensionField2(core::int value) → core::int {
   return self::Extension|lateExtensionField2Init = value;
 }
 static get Extension|lateExtensionField2() → core::int
-  return let final core::int? #t7 = self::_#Extension|lateExtensionField2 in #t7.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = self::Extension|initLateExtensionField2(42) : #t7{core::int};
+  return let final core::int? #t13 = self::_#Extension|lateExtensionField2 in #t13.==(null) ?{core::int} let final core::int #t14 = self::Extension|initLateExtensionField2(42) in self::_#Extension|lateExtensionField2.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = #t14 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has been assigned during initialization.") : #t13{core::int};
 static method Extension|staticMethod() → dynamic {
   self::expect(null, self::Extension|lateExtensionField2Init);
   self::expect(42, self::Extension|lateExtensionField2);
diff --git a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.strong.transformed.expect
index a6e79a5..9c3f037 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.strong.transformed.expect
@@ -1,6 +1,7 @@
 library;
 import self as self;
 import "dart:core" as core;
+import "dart:_internal" as _in;
 
 class Class<T extends core::Object? = dynamic> extends core::Object {
   static field core::int? lateStaticField1Init = null;
@@ -20,12 +21,12 @@
     return self::Class::lateStaticField1Init = value;
   }
   static get lateStaticField1() → core::int
-    return let final core::int? #t1 = self::Class::_#lateStaticField1 in #t1.==(null) ?{core::int} self::Class::_#lateStaticField1 = self::Class::initLateStaticField1(87) : #t1{core::int};
+    return let final core::int? #t1 = self::Class::_#lateStaticField1 in #t1.==(null) ?{core::int} let final core::int #t2 = self::Class::initLateStaticField1(87) in self::Class::_#lateStaticField1.==(null) ?{core::int} self::Class::_#lateStaticField1 = #t2 : throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField1' has been assigned during initialization.") : #t1{core::int};
   static method initLateStaticField2(core::int value) → core::int {
     return self::Class::lateStaticField2Init = value;
   }
   static get lateStaticField2() → core::int
-    return let final core::int? #t2 = self::Class::_#lateStaticField2 in #t2.==(null) ?{core::int} self::Class::_#lateStaticField2 = self::Class::initLateStaticField2(42) : #t2{core::int};
+    return let final core::int? #t3 = self::Class::_#lateStaticField2 in #t3.==(null) ?{core::int} let final core::int #t4 = self::Class::initLateStaticField2(42) in self::Class::_#lateStaticField2.==(null) ?{core::int} self::Class::_#lateStaticField2 = #t4 : throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField2' has been assigned during initialization.") : #t3{core::int};
   static method staticMethod() → dynamic {
     self::expect(null, self::Class::lateStaticField2Init);
     self::expect(42, self::Class::lateStaticField2);
@@ -35,16 +36,19 @@
     return this.{self::Class::lateInstanceFieldInit} = value;
   }
   get lateInstanceField() → core::int
-    return let final core::int? #t3 = this.{self::Class::_#Class#lateInstanceField} in #t3.==(null) ?{core::int} this.{self::Class::_#Class#lateInstanceField} = this.{self::Class::initLateInstanceField}(16) : #t3{core::int};
+    return let final core::int? #t5 = this.{self::Class::_#Class#lateInstanceField} in #t5.==(null) ?{core::int} let final core::int #t6 = this.{self::Class::initLateInstanceField}(16) in this.{self::Class::_#Class#lateInstanceField}.==(null) ?{core::int} this.{self::Class::_#Class#lateInstanceField} = #t6 : throw new _in::LateInitializationErrorImpl::•("Field 'lateInstanceField' has been assigned during initialization.") : #t5{core::int};
   method initLateGenericField(generic-covariant-impl self::Class::T% value) → self::Class::T% {
     return this.{self::Class::lateGenericFieldInit} = value;
   }
   get lateGenericField() → self::Class::T% {
     if(!this.{self::Class::_#Class#lateGenericField#isSet}) {
+      final self::Class::T% #t7 = this.{self::Class::initLateGenericField}(this.{self::Class::field});
+      if(this.{self::Class::_#Class#lateGenericField#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'lateGenericField' has been assigned during initialization.");
       this.{self::Class::_#Class#lateGenericField#isSet} = true;
-      this.{self::Class::_#Class#lateGenericField} = this.{self::Class::initLateGenericField}(this.{self::Class::field});
+      this.{self::Class::_#Class#lateGenericField} = #t7;
     }
-    return let final self::Class::T? #t4 = this.{self::Class::_#Class#lateGenericField} in #t4{self::Class::T%};
+    return let final self::Class::T? #t8 = this.{self::Class::_#Class#lateGenericField} in #t8{self::Class::T%};
   }
   method instanceMethod() → dynamic {
     self::expect(null, this.{self::Class::lateInstanceFieldInit});
@@ -76,17 +80,17 @@
   return self::lateTopLevelField1Init = value;
 }
 static get lateTopLevelField1() → core::int
-  return let final core::int? #t5 = self::_#lateTopLevelField1 in #t5.==(null) ?{core::int} self::_#lateTopLevelField1 = self::initLateTopLevelField1(123) : #t5{core::int};
+  return let final core::int? #t9 = self::_#lateTopLevelField1 in #t9.==(null) ?{core::int} let final core::int #t10 = self::initLateTopLevelField1(123) in self::_#lateTopLevelField1.==(null) ?{core::int} self::_#lateTopLevelField1 = #t10 : throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField1' has been assigned during initialization.") : #t9{core::int};
 static method Extension|initLateExtensionField1(core::int value) → core::int {
   return self::Extension|lateExtensionField1Init = value;
 }
 static get Extension|lateExtensionField1() → core::int
-  return let final core::int? #t6 = self::_#Extension|lateExtensionField1 in #t6.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = self::Extension|initLateExtensionField1(87) : #t6{core::int};
+  return let final core::int? #t11 = self::_#Extension|lateExtensionField1 in #t11.==(null) ?{core::int} let final core::int #t12 = self::Extension|initLateExtensionField1(87) in self::_#Extension|lateExtensionField1.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = #t12 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has been assigned during initialization.") : #t11{core::int};
 static method Extension|initLateExtensionField2(core::int value) → core::int {
   return self::Extension|lateExtensionField2Init = value;
 }
 static get Extension|lateExtensionField2() → core::int
-  return let final core::int? #t7 = self::_#Extension|lateExtensionField2 in #t7.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = self::Extension|initLateExtensionField2(42) : #t7{core::int};
+  return let final core::int? #t13 = self::_#Extension|lateExtensionField2 in #t13.==(null) ?{core::int} let final core::int #t14 = self::Extension|initLateExtensionField2(42) in self::_#Extension|lateExtensionField2.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = #t14 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has been assigned during initialization.") : #t13{core::int};
 static method Extension|staticMethod() → dynamic {
   self::expect(null, self::Extension|lateExtensionField2Init);
   self::expect(42, self::Extension|lateExtensionField2);
diff --git a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.expect b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.expect
index a6e79a5..9c3f037 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.expect
@@ -1,6 +1,7 @@
 library;
 import self as self;
 import "dart:core" as core;
+import "dart:_internal" as _in;
 
 class Class<T extends core::Object? = dynamic> extends core::Object {
   static field core::int? lateStaticField1Init = null;
@@ -20,12 +21,12 @@
     return self::Class::lateStaticField1Init = value;
   }
   static get lateStaticField1() → core::int
-    return let final core::int? #t1 = self::Class::_#lateStaticField1 in #t1.==(null) ?{core::int} self::Class::_#lateStaticField1 = self::Class::initLateStaticField1(87) : #t1{core::int};
+    return let final core::int? #t1 = self::Class::_#lateStaticField1 in #t1.==(null) ?{core::int} let final core::int #t2 = self::Class::initLateStaticField1(87) in self::Class::_#lateStaticField1.==(null) ?{core::int} self::Class::_#lateStaticField1 = #t2 : throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField1' has been assigned during initialization.") : #t1{core::int};
   static method initLateStaticField2(core::int value) → core::int {
     return self::Class::lateStaticField2Init = value;
   }
   static get lateStaticField2() → core::int
-    return let final core::int? #t2 = self::Class::_#lateStaticField2 in #t2.==(null) ?{core::int} self::Class::_#lateStaticField2 = self::Class::initLateStaticField2(42) : #t2{core::int};
+    return let final core::int? #t3 = self::Class::_#lateStaticField2 in #t3.==(null) ?{core::int} let final core::int #t4 = self::Class::initLateStaticField2(42) in self::Class::_#lateStaticField2.==(null) ?{core::int} self::Class::_#lateStaticField2 = #t4 : throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField2' has been assigned during initialization.") : #t3{core::int};
   static method staticMethod() → dynamic {
     self::expect(null, self::Class::lateStaticField2Init);
     self::expect(42, self::Class::lateStaticField2);
@@ -35,16 +36,19 @@
     return this.{self::Class::lateInstanceFieldInit} = value;
   }
   get lateInstanceField() → core::int
-    return let final core::int? #t3 = this.{self::Class::_#Class#lateInstanceField} in #t3.==(null) ?{core::int} this.{self::Class::_#Class#lateInstanceField} = this.{self::Class::initLateInstanceField}(16) : #t3{core::int};
+    return let final core::int? #t5 = this.{self::Class::_#Class#lateInstanceField} in #t5.==(null) ?{core::int} let final core::int #t6 = this.{self::Class::initLateInstanceField}(16) in this.{self::Class::_#Class#lateInstanceField}.==(null) ?{core::int} this.{self::Class::_#Class#lateInstanceField} = #t6 : throw new _in::LateInitializationErrorImpl::•("Field 'lateInstanceField' has been assigned during initialization.") : #t5{core::int};
   method initLateGenericField(generic-covariant-impl self::Class::T% value) → self::Class::T% {
     return this.{self::Class::lateGenericFieldInit} = value;
   }
   get lateGenericField() → self::Class::T% {
     if(!this.{self::Class::_#Class#lateGenericField#isSet}) {
+      final self::Class::T% #t7 = this.{self::Class::initLateGenericField}(this.{self::Class::field});
+      if(this.{self::Class::_#Class#lateGenericField#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'lateGenericField' has been assigned during initialization.");
       this.{self::Class::_#Class#lateGenericField#isSet} = true;
-      this.{self::Class::_#Class#lateGenericField} = this.{self::Class::initLateGenericField}(this.{self::Class::field});
+      this.{self::Class::_#Class#lateGenericField} = #t7;
     }
-    return let final self::Class::T? #t4 = this.{self::Class::_#Class#lateGenericField} in #t4{self::Class::T%};
+    return let final self::Class::T? #t8 = this.{self::Class::_#Class#lateGenericField} in #t8{self::Class::T%};
   }
   method instanceMethod() → dynamic {
     self::expect(null, this.{self::Class::lateInstanceFieldInit});
@@ -76,17 +80,17 @@
   return self::lateTopLevelField1Init = value;
 }
 static get lateTopLevelField1() → core::int
-  return let final core::int? #t5 = self::_#lateTopLevelField1 in #t5.==(null) ?{core::int} self::_#lateTopLevelField1 = self::initLateTopLevelField1(123) : #t5{core::int};
+  return let final core::int? #t9 = self::_#lateTopLevelField1 in #t9.==(null) ?{core::int} let final core::int #t10 = self::initLateTopLevelField1(123) in self::_#lateTopLevelField1.==(null) ?{core::int} self::_#lateTopLevelField1 = #t10 : throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField1' has been assigned during initialization.") : #t9{core::int};
 static method Extension|initLateExtensionField1(core::int value) → core::int {
   return self::Extension|lateExtensionField1Init = value;
 }
 static get Extension|lateExtensionField1() → core::int
-  return let final core::int? #t6 = self::_#Extension|lateExtensionField1 in #t6.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = self::Extension|initLateExtensionField1(87) : #t6{core::int};
+  return let final core::int? #t11 = self::_#Extension|lateExtensionField1 in #t11.==(null) ?{core::int} let final core::int #t12 = self::Extension|initLateExtensionField1(87) in self::_#Extension|lateExtensionField1.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = #t12 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has been assigned during initialization.") : #t11{core::int};
 static method Extension|initLateExtensionField2(core::int value) → core::int {
   return self::Extension|lateExtensionField2Init = value;
 }
 static get Extension|lateExtensionField2() → core::int
-  return let final core::int? #t7 = self::_#Extension|lateExtensionField2 in #t7.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = self::Extension|initLateExtensionField2(42) : #t7{core::int};
+  return let final core::int? #t13 = self::_#Extension|lateExtensionField2 in #t13.==(null) ?{core::int} let final core::int #t14 = self::Extension|initLateExtensionField2(42) in self::_#Extension|lateExtensionField2.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = #t14 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has been assigned during initialization.") : #t13{core::int};
 static method Extension|staticMethod() → dynamic {
   self::expect(null, self::Extension|lateExtensionField2Init);
   self::expect(42, self::Extension|lateExtensionField2);
diff --git a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.transformed.expect
index a6e79a5..9c3f037 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.transformed.expect
@@ -1,6 +1,7 @@
 library;
 import self as self;
 import "dart:core" as core;
+import "dart:_internal" as _in;
 
 class Class<T extends core::Object? = dynamic> extends core::Object {
   static field core::int? lateStaticField1Init = null;
@@ -20,12 +21,12 @@
     return self::Class::lateStaticField1Init = value;
   }
   static get lateStaticField1() → core::int
-    return let final core::int? #t1 = self::Class::_#lateStaticField1 in #t1.==(null) ?{core::int} self::Class::_#lateStaticField1 = self::Class::initLateStaticField1(87) : #t1{core::int};
+    return let final core::int? #t1 = self::Class::_#lateStaticField1 in #t1.==(null) ?{core::int} let final core::int #t2 = self::Class::initLateStaticField1(87) in self::Class::_#lateStaticField1.==(null) ?{core::int} self::Class::_#lateStaticField1 = #t2 : throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField1' has been assigned during initialization.") : #t1{core::int};
   static method initLateStaticField2(core::int value) → core::int {
     return self::Class::lateStaticField2Init = value;
   }
   static get lateStaticField2() → core::int
-    return let final core::int? #t2 = self::Class::_#lateStaticField2 in #t2.==(null) ?{core::int} self::Class::_#lateStaticField2 = self::Class::initLateStaticField2(42) : #t2{core::int};
+    return let final core::int? #t3 = self::Class::_#lateStaticField2 in #t3.==(null) ?{core::int} let final core::int #t4 = self::Class::initLateStaticField2(42) in self::Class::_#lateStaticField2.==(null) ?{core::int} self::Class::_#lateStaticField2 = #t4 : throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField2' has been assigned during initialization.") : #t3{core::int};
   static method staticMethod() → dynamic {
     self::expect(null, self::Class::lateStaticField2Init);
     self::expect(42, self::Class::lateStaticField2);
@@ -35,16 +36,19 @@
     return this.{self::Class::lateInstanceFieldInit} = value;
   }
   get lateInstanceField() → core::int
-    return let final core::int? #t3 = this.{self::Class::_#Class#lateInstanceField} in #t3.==(null) ?{core::int} this.{self::Class::_#Class#lateInstanceField} = this.{self::Class::initLateInstanceField}(16) : #t3{core::int};
+    return let final core::int? #t5 = this.{self::Class::_#Class#lateInstanceField} in #t5.==(null) ?{core::int} let final core::int #t6 = this.{self::Class::initLateInstanceField}(16) in this.{self::Class::_#Class#lateInstanceField}.==(null) ?{core::int} this.{self::Class::_#Class#lateInstanceField} = #t6 : throw new _in::LateInitializationErrorImpl::•("Field 'lateInstanceField' has been assigned during initialization.") : #t5{core::int};
   method initLateGenericField(generic-covariant-impl self::Class::T% value) → self::Class::T% {
     return this.{self::Class::lateGenericFieldInit} = value;
   }
   get lateGenericField() → self::Class::T% {
     if(!this.{self::Class::_#Class#lateGenericField#isSet}) {
+      final self::Class::T% #t7 = this.{self::Class::initLateGenericField}(this.{self::Class::field});
+      if(this.{self::Class::_#Class#lateGenericField#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'lateGenericField' has been assigned during initialization.");
       this.{self::Class::_#Class#lateGenericField#isSet} = true;
-      this.{self::Class::_#Class#lateGenericField} = this.{self::Class::initLateGenericField}(this.{self::Class::field});
+      this.{self::Class::_#Class#lateGenericField} = #t7;
     }
-    return let final self::Class::T? #t4 = this.{self::Class::_#Class#lateGenericField} in #t4{self::Class::T%};
+    return let final self::Class::T? #t8 = this.{self::Class::_#Class#lateGenericField} in #t8{self::Class::T%};
   }
   method instanceMethod() → dynamic {
     self::expect(null, this.{self::Class::lateInstanceFieldInit});
@@ -76,17 +80,17 @@
   return self::lateTopLevelField1Init = value;
 }
 static get lateTopLevelField1() → core::int
-  return let final core::int? #t5 = self::_#lateTopLevelField1 in #t5.==(null) ?{core::int} self::_#lateTopLevelField1 = self::initLateTopLevelField1(123) : #t5{core::int};
+  return let final core::int? #t9 = self::_#lateTopLevelField1 in #t9.==(null) ?{core::int} let final core::int #t10 = self::initLateTopLevelField1(123) in self::_#lateTopLevelField1.==(null) ?{core::int} self::_#lateTopLevelField1 = #t10 : throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField1' has been assigned during initialization.") : #t9{core::int};
 static method Extension|initLateExtensionField1(core::int value) → core::int {
   return self::Extension|lateExtensionField1Init = value;
 }
 static get Extension|lateExtensionField1() → core::int
-  return let final core::int? #t6 = self::_#Extension|lateExtensionField1 in #t6.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = self::Extension|initLateExtensionField1(87) : #t6{core::int};
+  return let final core::int? #t11 = self::_#Extension|lateExtensionField1 in #t11.==(null) ?{core::int} let final core::int #t12 = self::Extension|initLateExtensionField1(87) in self::_#Extension|lateExtensionField1.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = #t12 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has been assigned during initialization.") : #t11{core::int};
 static method Extension|initLateExtensionField2(core::int value) → core::int {
   return self::Extension|lateExtensionField2Init = value;
 }
 static get Extension|lateExtensionField2() → core::int
-  return let final core::int? #t7 = self::_#Extension|lateExtensionField2 in #t7.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = self::Extension|initLateExtensionField2(42) : #t7{core::int};
+  return let final core::int? #t13 = self::_#Extension|lateExtensionField2 in #t13.==(null) ?{core::int} let final core::int #t14 = self::Extension|initLateExtensionField2(42) in self::_#Extension|lateExtensionField2.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = #t14 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has been assigned during initialization.") : #t13{core::int};
 static method Extension|staticMethod() → dynamic {
   self::expect(null, self::Extension|lateExtensionField2Init);
   self::expect(42, self::Extension|lateExtensionField2);
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.strong.expect
index 6c91c6d..49d7ba3 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.strong.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.strong.expect
@@ -1,6 +1,7 @@
 library;
 import self as self;
 import "dart:core" as core;
+import "dart:_internal" as _in;
 
 class Class<T extends core::Object? = dynamic> extends core::Object {
   static field core::int? lateStaticField1Init = null;
@@ -24,8 +25,11 @@
   }
   static get lateStaticField1() → core::int? {
     if(!self::Class::_#lateStaticField1#isSet) {
+      final core::int? #t1 = self::Class::initLateStaticField1(87);
+      if(self::Class::_#lateStaticField1#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField1' has been assigned during initialization.");
       self::Class::_#lateStaticField1#isSet = true;
-      self::Class::_#lateStaticField1 = self::Class::initLateStaticField1(87);
+      self::Class::_#lateStaticField1 = #t1;
     }
     return self::Class::_#lateStaticField1;
   }
@@ -34,8 +38,11 @@
   }
   static get lateStaticField2() → core::int? {
     if(!self::Class::_#lateStaticField2#isSet) {
+      final core::int? #t2 = self::Class::initLateStaticField2(42);
+      if(self::Class::_#lateStaticField2#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField2' has been assigned during initialization.");
       self::Class::_#lateStaticField2#isSet = true;
-      self::Class::_#lateStaticField2 = self::Class::initLateStaticField2(42);
+      self::Class::_#lateStaticField2 = #t2;
     }
     return self::Class::_#lateStaticField2;
   }
@@ -49,8 +56,11 @@
   }
   get lateInstanceField() → core::int? {
     if(!this.{self::Class::_#Class#lateInstanceField#isSet}) {
+      final core::int? #t3 = this.{self::Class::initLateInstanceField}(16);
+      if(this.{self::Class::_#Class#lateInstanceField#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'lateInstanceField' has been assigned during initialization.");
       this.{self::Class::_#Class#lateInstanceField#isSet} = true;
-      this.{self::Class::_#Class#lateInstanceField} = this.{self::Class::initLateInstanceField}(16);
+      this.{self::Class::_#Class#lateInstanceField} = #t3;
     }
     return this.{self::Class::_#Class#lateInstanceField};
   }
@@ -59,8 +69,11 @@
   }
   get lateGenericInstanceField() → self::Class::T? {
     if(!this.{self::Class::_#Class#lateGenericInstanceField#isSet}) {
+      final self::Class::T? #t4 = this.{self::Class::initLateGenericInstanceField}(this.{self::Class::field});
+      if(this.{self::Class::_#Class#lateGenericInstanceField#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'lateGenericInstanceField' has been assigned during initialization.");
       this.{self::Class::_#Class#lateGenericInstanceField#isSet} = true;
-      this.{self::Class::_#Class#lateGenericInstanceField} = this.{self::Class::initLateGenericInstanceField}(this.{self::Class::field});
+      this.{self::Class::_#Class#lateGenericInstanceField} = #t4;
     }
     return this.{self::Class::_#Class#lateGenericInstanceField};
   }
@@ -100,8 +113,11 @@
 }
 static get lateTopLevelField1() → core::int? {
   if(!self::_#lateTopLevelField1#isSet) {
+    final core::int? #t5 = self::initLateTopLevelField1(123);
+    if(self::_#lateTopLevelField1#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField1' has been assigned during initialization.");
     self::_#lateTopLevelField1#isSet = true;
-    self::_#lateTopLevelField1 = self::initLateTopLevelField1(123);
+    self::_#lateTopLevelField1 = #t5;
   }
   return self::_#lateTopLevelField1;
 }
@@ -110,8 +126,11 @@
 }
 static get Extension|lateExtensionField1() → core::int? {
   if(!self::_#Extension|lateExtensionField1#isSet) {
+    final core::int? #t6 = self::Extension|initLateExtensionField1(87);
+    if(self::_#Extension|lateExtensionField1#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has been assigned during initialization.");
     self::_#Extension|lateExtensionField1#isSet = true;
-    self::_#Extension|lateExtensionField1 = self::Extension|initLateExtensionField1(87);
+    self::_#Extension|lateExtensionField1 = #t6;
   }
   return self::_#Extension|lateExtensionField1;
 }
@@ -120,8 +139,11 @@
 }
 static get Extension|lateExtensionField2() → core::int? {
   if(!self::_#Extension|lateExtensionField2#isSet) {
+    final core::int? #t7 = self::Extension|initLateExtensionField2(42);
+    if(self::_#Extension|lateExtensionField2#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has been assigned during initialization.");
     self::_#Extension|lateExtensionField2#isSet = true;
-    self::_#Extension|lateExtensionField2 = self::Extension|initLateExtensionField2(42);
+    self::_#Extension|lateExtensionField2 = #t7;
   }
   return self::_#Extension|lateExtensionField2;
 }
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.strong.transformed.expect
index 6c91c6d..49d7ba3 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.strong.transformed.expect
@@ -1,6 +1,7 @@
 library;
 import self as self;
 import "dart:core" as core;
+import "dart:_internal" as _in;
 
 class Class<T extends core::Object? = dynamic> extends core::Object {
   static field core::int? lateStaticField1Init = null;
@@ -24,8 +25,11 @@
   }
   static get lateStaticField1() → core::int? {
     if(!self::Class::_#lateStaticField1#isSet) {
+      final core::int? #t1 = self::Class::initLateStaticField1(87);
+      if(self::Class::_#lateStaticField1#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField1' has been assigned during initialization.");
       self::Class::_#lateStaticField1#isSet = true;
-      self::Class::_#lateStaticField1 = self::Class::initLateStaticField1(87);
+      self::Class::_#lateStaticField1 = #t1;
     }
     return self::Class::_#lateStaticField1;
   }
@@ -34,8 +38,11 @@
   }
   static get lateStaticField2() → core::int? {
     if(!self::Class::_#lateStaticField2#isSet) {
+      final core::int? #t2 = self::Class::initLateStaticField2(42);
+      if(self::Class::_#lateStaticField2#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField2' has been assigned during initialization.");
       self::Class::_#lateStaticField2#isSet = true;
-      self::Class::_#lateStaticField2 = self::Class::initLateStaticField2(42);
+      self::Class::_#lateStaticField2 = #t2;
     }
     return self::Class::_#lateStaticField2;
   }
@@ -49,8 +56,11 @@
   }
   get lateInstanceField() → core::int? {
     if(!this.{self::Class::_#Class#lateInstanceField#isSet}) {
+      final core::int? #t3 = this.{self::Class::initLateInstanceField}(16);
+      if(this.{self::Class::_#Class#lateInstanceField#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'lateInstanceField' has been assigned during initialization.");
       this.{self::Class::_#Class#lateInstanceField#isSet} = true;
-      this.{self::Class::_#Class#lateInstanceField} = this.{self::Class::initLateInstanceField}(16);
+      this.{self::Class::_#Class#lateInstanceField} = #t3;
     }
     return this.{self::Class::_#Class#lateInstanceField};
   }
@@ -59,8 +69,11 @@
   }
   get lateGenericInstanceField() → self::Class::T? {
     if(!this.{self::Class::_#Class#lateGenericInstanceField#isSet}) {
+      final self::Class::T? #t4 = this.{self::Class::initLateGenericInstanceField}(this.{self::Class::field});
+      if(this.{self::Class::_#Class#lateGenericInstanceField#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'lateGenericInstanceField' has been assigned during initialization.");
       this.{self::Class::_#Class#lateGenericInstanceField#isSet} = true;
-      this.{self::Class::_#Class#lateGenericInstanceField} = this.{self::Class::initLateGenericInstanceField}(this.{self::Class::field});
+      this.{self::Class::_#Class#lateGenericInstanceField} = #t4;
     }
     return this.{self::Class::_#Class#lateGenericInstanceField};
   }
@@ -100,8 +113,11 @@
 }
 static get lateTopLevelField1() → core::int? {
   if(!self::_#lateTopLevelField1#isSet) {
+    final core::int? #t5 = self::initLateTopLevelField1(123);
+    if(self::_#lateTopLevelField1#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField1' has been assigned during initialization.");
     self::_#lateTopLevelField1#isSet = true;
-    self::_#lateTopLevelField1 = self::initLateTopLevelField1(123);
+    self::_#lateTopLevelField1 = #t5;
   }
   return self::_#lateTopLevelField1;
 }
@@ -110,8 +126,11 @@
 }
 static get Extension|lateExtensionField1() → core::int? {
   if(!self::_#Extension|lateExtensionField1#isSet) {
+    final core::int? #t6 = self::Extension|initLateExtensionField1(87);
+    if(self::_#Extension|lateExtensionField1#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has been assigned during initialization.");
     self::_#Extension|lateExtensionField1#isSet = true;
-    self::_#Extension|lateExtensionField1 = self::Extension|initLateExtensionField1(87);
+    self::_#Extension|lateExtensionField1 = #t6;
   }
   return self::_#Extension|lateExtensionField1;
 }
@@ -120,8 +139,11 @@
 }
 static get Extension|lateExtensionField2() → core::int? {
   if(!self::_#Extension|lateExtensionField2#isSet) {
+    final core::int? #t7 = self::Extension|initLateExtensionField2(42);
+    if(self::_#Extension|lateExtensionField2#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has been assigned during initialization.");
     self::_#Extension|lateExtensionField2#isSet = true;
-    self::_#Extension|lateExtensionField2 = self::Extension|initLateExtensionField2(42);
+    self::_#Extension|lateExtensionField2 = #t7;
   }
   return self::_#Extension|lateExtensionField2;
 }
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.weak.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.weak.expect
index 6c91c6d..49d7ba3 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.weak.expect
@@ -1,6 +1,7 @@
 library;
 import self as self;
 import "dart:core" as core;
+import "dart:_internal" as _in;
 
 class Class<T extends core::Object? = dynamic> extends core::Object {
   static field core::int? lateStaticField1Init = null;
@@ -24,8 +25,11 @@
   }
   static get lateStaticField1() → core::int? {
     if(!self::Class::_#lateStaticField1#isSet) {
+      final core::int? #t1 = self::Class::initLateStaticField1(87);
+      if(self::Class::_#lateStaticField1#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField1' has been assigned during initialization.");
       self::Class::_#lateStaticField1#isSet = true;
-      self::Class::_#lateStaticField1 = self::Class::initLateStaticField1(87);
+      self::Class::_#lateStaticField1 = #t1;
     }
     return self::Class::_#lateStaticField1;
   }
@@ -34,8 +38,11 @@
   }
   static get lateStaticField2() → core::int? {
     if(!self::Class::_#lateStaticField2#isSet) {
+      final core::int? #t2 = self::Class::initLateStaticField2(42);
+      if(self::Class::_#lateStaticField2#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField2' has been assigned during initialization.");
       self::Class::_#lateStaticField2#isSet = true;
-      self::Class::_#lateStaticField2 = self::Class::initLateStaticField2(42);
+      self::Class::_#lateStaticField2 = #t2;
     }
     return self::Class::_#lateStaticField2;
   }
@@ -49,8 +56,11 @@
   }
   get lateInstanceField() → core::int? {
     if(!this.{self::Class::_#Class#lateInstanceField#isSet}) {
+      final core::int? #t3 = this.{self::Class::initLateInstanceField}(16);
+      if(this.{self::Class::_#Class#lateInstanceField#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'lateInstanceField' has been assigned during initialization.");
       this.{self::Class::_#Class#lateInstanceField#isSet} = true;
-      this.{self::Class::_#Class#lateInstanceField} = this.{self::Class::initLateInstanceField}(16);
+      this.{self::Class::_#Class#lateInstanceField} = #t3;
     }
     return this.{self::Class::_#Class#lateInstanceField};
   }
@@ -59,8 +69,11 @@
   }
   get lateGenericInstanceField() → self::Class::T? {
     if(!this.{self::Class::_#Class#lateGenericInstanceField#isSet}) {
+      final self::Class::T? #t4 = this.{self::Class::initLateGenericInstanceField}(this.{self::Class::field});
+      if(this.{self::Class::_#Class#lateGenericInstanceField#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'lateGenericInstanceField' has been assigned during initialization.");
       this.{self::Class::_#Class#lateGenericInstanceField#isSet} = true;
-      this.{self::Class::_#Class#lateGenericInstanceField} = this.{self::Class::initLateGenericInstanceField}(this.{self::Class::field});
+      this.{self::Class::_#Class#lateGenericInstanceField} = #t4;
     }
     return this.{self::Class::_#Class#lateGenericInstanceField};
   }
@@ -100,8 +113,11 @@
 }
 static get lateTopLevelField1() → core::int? {
   if(!self::_#lateTopLevelField1#isSet) {
+    final core::int? #t5 = self::initLateTopLevelField1(123);
+    if(self::_#lateTopLevelField1#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField1' has been assigned during initialization.");
     self::_#lateTopLevelField1#isSet = true;
-    self::_#lateTopLevelField1 = self::initLateTopLevelField1(123);
+    self::_#lateTopLevelField1 = #t5;
   }
   return self::_#lateTopLevelField1;
 }
@@ -110,8 +126,11 @@
 }
 static get Extension|lateExtensionField1() → core::int? {
   if(!self::_#Extension|lateExtensionField1#isSet) {
+    final core::int? #t6 = self::Extension|initLateExtensionField1(87);
+    if(self::_#Extension|lateExtensionField1#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has been assigned during initialization.");
     self::_#Extension|lateExtensionField1#isSet = true;
-    self::_#Extension|lateExtensionField1 = self::Extension|initLateExtensionField1(87);
+    self::_#Extension|lateExtensionField1 = #t6;
   }
   return self::_#Extension|lateExtensionField1;
 }
@@ -120,8 +139,11 @@
 }
 static get Extension|lateExtensionField2() → core::int? {
   if(!self::_#Extension|lateExtensionField2#isSet) {
+    final core::int? #t7 = self::Extension|initLateExtensionField2(42);
+    if(self::_#Extension|lateExtensionField2#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has been assigned during initialization.");
     self::_#Extension|lateExtensionField2#isSet = true;
-    self::_#Extension|lateExtensionField2 = self::Extension|initLateExtensionField2(42);
+    self::_#Extension|lateExtensionField2 = #t7;
   }
   return self::_#Extension|lateExtensionField2;
 }
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.weak.transformed.expect
index 6c91c6d..49d7ba3 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.weak.transformed.expect
@@ -1,6 +1,7 @@
 library;
 import self as self;
 import "dart:core" as core;
+import "dart:_internal" as _in;
 
 class Class<T extends core::Object? = dynamic> extends core::Object {
   static field core::int? lateStaticField1Init = null;
@@ -24,8 +25,11 @@
   }
   static get lateStaticField1() → core::int? {
     if(!self::Class::_#lateStaticField1#isSet) {
+      final core::int? #t1 = self::Class::initLateStaticField1(87);
+      if(self::Class::_#lateStaticField1#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField1' has been assigned during initialization.");
       self::Class::_#lateStaticField1#isSet = true;
-      self::Class::_#lateStaticField1 = self::Class::initLateStaticField1(87);
+      self::Class::_#lateStaticField1 = #t1;
     }
     return self::Class::_#lateStaticField1;
   }
@@ -34,8 +38,11 @@
   }
   static get lateStaticField2() → core::int? {
     if(!self::Class::_#lateStaticField2#isSet) {
+      final core::int? #t2 = self::Class::initLateStaticField2(42);
+      if(self::Class::_#lateStaticField2#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField2' has been assigned during initialization.");
       self::Class::_#lateStaticField2#isSet = true;
-      self::Class::_#lateStaticField2 = self::Class::initLateStaticField2(42);
+      self::Class::_#lateStaticField2 = #t2;
     }
     return self::Class::_#lateStaticField2;
   }
@@ -49,8 +56,11 @@
   }
   get lateInstanceField() → core::int? {
     if(!this.{self::Class::_#Class#lateInstanceField#isSet}) {
+      final core::int? #t3 = this.{self::Class::initLateInstanceField}(16);
+      if(this.{self::Class::_#Class#lateInstanceField#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'lateInstanceField' has been assigned during initialization.");
       this.{self::Class::_#Class#lateInstanceField#isSet} = true;
-      this.{self::Class::_#Class#lateInstanceField} = this.{self::Class::initLateInstanceField}(16);
+      this.{self::Class::_#Class#lateInstanceField} = #t3;
     }
     return this.{self::Class::_#Class#lateInstanceField};
   }
@@ -59,8 +69,11 @@
   }
   get lateGenericInstanceField() → self::Class::T? {
     if(!this.{self::Class::_#Class#lateGenericInstanceField#isSet}) {
+      final self::Class::T? #t4 = this.{self::Class::initLateGenericInstanceField}(this.{self::Class::field});
+      if(this.{self::Class::_#Class#lateGenericInstanceField#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'lateGenericInstanceField' has been assigned during initialization.");
       this.{self::Class::_#Class#lateGenericInstanceField#isSet} = true;
-      this.{self::Class::_#Class#lateGenericInstanceField} = this.{self::Class::initLateGenericInstanceField}(this.{self::Class::field});
+      this.{self::Class::_#Class#lateGenericInstanceField} = #t4;
     }
     return this.{self::Class::_#Class#lateGenericInstanceField};
   }
@@ -100,8 +113,11 @@
 }
 static get lateTopLevelField1() → core::int? {
   if(!self::_#lateTopLevelField1#isSet) {
+    final core::int? #t5 = self::initLateTopLevelField1(123);
+    if(self::_#lateTopLevelField1#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField1' has been assigned during initialization.");
     self::_#lateTopLevelField1#isSet = true;
-    self::_#lateTopLevelField1 = self::initLateTopLevelField1(123);
+    self::_#lateTopLevelField1 = #t5;
   }
   return self::_#lateTopLevelField1;
 }
@@ -110,8 +126,11 @@
 }
 static get Extension|lateExtensionField1() → core::int? {
   if(!self::_#Extension|lateExtensionField1#isSet) {
+    final core::int? #t6 = self::Extension|initLateExtensionField1(87);
+    if(self::_#Extension|lateExtensionField1#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has been assigned during initialization.");
     self::_#Extension|lateExtensionField1#isSet = true;
-    self::_#Extension|lateExtensionField1 = self::Extension|initLateExtensionField1(87);
+    self::_#Extension|lateExtensionField1 = #t6;
   }
   return self::_#Extension|lateExtensionField1;
 }
@@ -120,8 +139,11 @@
 }
 static get Extension|lateExtensionField2() → core::int? {
   if(!self::_#Extension|lateExtensionField2#isSet) {
+    final core::int? #t7 = self::Extension|initLateExtensionField2(42);
+    if(self::_#Extension|lateExtensionField2#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has been assigned during initialization.");
     self::_#Extension|lateExtensionField2#isSet = true;
-    self::_#Extension|lateExtensionField2 = self::Extension|initLateExtensionField2(42);
+    self::_#Extension|lateExtensionField2 = #t7;
   }
   return self::_#Extension|lateExtensionField2;
 }
diff --git a/pkg/front_end/testcases/late_lowering/later.dart b/pkg/front_end/testcases/late_lowering/later.dart
new file mode 100644
index 0000000..4ae2c96
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/later.dart
@@ -0,0 +1,59 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// @dart=2.7
+
+// This test checks for compile-time errors and their absence for some use cases
+// of late fields and variables.
+
+class A {
+  int a = 42;
+  late int b = (this.a * 2) >> 1; // Not an error.
+
+  foo(late int x) {} // Error.
+}
+
+bar(late int x) {} // Error.
+
+baz() {
+  try {
+    throw "baz";
+  } on dynamic catch (late e, late t) {} // Error.
+  for (late int i = 0; i < 10; ++i) { // Error.
+    print("baz");
+  }
+  for (late String s in ["baz"]) { // Error.
+    print(s);
+  }
+  [for (late int i = 0; i < 10; ++i) i]; // Error.
+}
+
+hest() async {
+  await for (late String s in new Stream.fromIterable(["hest"])) { // Error.
+    print(s);
+  }
+  return "hest";
+}
+
+fisk() async {
+  late String s1 = await hest(); // Error.
+  late String s2 = '${fisk}${await hest()}${fisk}'; // Error.
+  late Function f = () async => await hest(); // Not an error.
+}
+
+class B {
+  late final int x = 42;
+
+  const B(); // Error: B has late final fields.
+}
+
+class C {
+  late final int x;
+
+  initVars() {
+    x = 42; // Ok: [x] doesn't have an initializer.
+  }
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/late_lowering/later.dart.outline.expect b/pkg/front_end/testcases/late_lowering/later.dart.outline.expect
new file mode 100644
index 0000000..25da1db
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/later.dart.outline.expect
@@ -0,0 +1,55 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/late_lowering/later.dart:14:7: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+//   foo(late int x) {} // Error.
+//       ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:17:5: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// bar(late int x) {} // Error.
+//     ^^^^
+//
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+class A extends core::Object {
+  field core::int a;
+  field core::int? _#A#b;
+  synthetic constructor •() → self::A
+    ;
+  get b() → core::int;
+  set b(core::int #t1) → void;
+  method foo(core::int x) → dynamic
+    ;
+}
+class B extends core::Object {
+  field core::int? _#B#x = null;
+  const constructor •() → self::B
+    : super core::Object::•()
+    ;
+  get x() → core::int
+    return let final core::int? #t2 = this.{self::B::_#B#x} in #t2.==(null) ?{core::int} let final core::int #t3 = 42 in this.{self::B::_#B#x}.==(null) ?{core::int} this.{self::B::_#B#x} = #t3 : throw new _in::LateInitializationErrorImpl::•("Field 'x' has been assigned during initialization.") : #t2{core::int};
+}
+class C extends core::Object {
+  field core::int? _#C#x;
+  synthetic constructor •() → self::C
+    ;
+  get x() → core::int;
+  set x(core::int #t4) → void;
+  method initVars() → dynamic
+    ;
+}
+static method bar(core::int x) → dynamic
+  ;
+static method baz() → dynamic
+  ;
+static method hest() → dynamic
+  ;
+static method fisk() → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/late_lowering/later.dart.strong.expect b/pkg/front_end/testcases/late_lowering/later.dart.strong.expect
new file mode 100644
index 0000000..1b470d9
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/later.dart.strong.expect
@@ -0,0 +1,164 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/late_lowering/later.dart:14:7: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+//   foo(late int x) {} // Error.
+//       ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:17:5: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// bar(late int x) {} // Error.
+//     ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:22:28: Error: 'catch' must be followed by '(identifier)' or '(identifier, identifier)'.
+// No types are needed, the first is given by 'on', the second is always 'StackTrace'.
+//   } on dynamic catch (late e, late t) {} // Error.
+//                            ^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:22:31: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+//   } on dynamic catch (late e, late t) {} // Error.
+//                               ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:22:36: Error: 'catch' must be followed by '(identifier)' or '(identifier, identifier)'.
+// No types are needed, the first is given by 'on', the second is always 'StackTrace'.
+//   } on dynamic catch (late e, late t) {} // Error.
+//                                    ^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:23:8: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+//   for (late int i = 0; i < 10; ++i) { // Error.
+//        ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:26:8: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+//   for (late String s in ["baz"]) { // Error.
+//        ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:29:9: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+//   [for (late int i = 0; i < 10; ++i) i]; // Error.
+//         ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:33:14: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+//   await for (late String s in new Stream.fromIterable(["hest"])) { // Error.
+//              ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:40:20: Error: `await` expressions are not supported in late local initializers.
+//   late String s1 = await hest(); // Error.
+//                    ^^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:41:30: Error: `await` expressions are not supported in late local initializers.
+//   late String s2 = '${fisk}${await hest()}${fisk}'; // Error.
+//                              ^^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:48:9: Error: Constructor is marked 'const' so fields can't be late.
+//   const B(); // Error: B has late final fields.
+//         ^
+// pkg/front_end/testcases/late_lowering/later.dart:46:18: Context: Field is late, but constructor is 'const'.
+//   late final int x = 42;
+//                  ^
+//
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+import "dart:async" as asy;
+
+class A extends core::Object {
+  field core::int a = 42;
+  field core::int? _#A#b = null;
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  get b() → core::int
+    return let final core::int? #t1 = this.{self::A::_#A#b} in #t1.==(null) ?{core::int} this.{self::A::_#A#b} = this.{self::A::a}.{core::num::*}(2).{core::int::>>}(1) : #t1{core::int};
+  set b(core::int #t2) → void
+    this.{self::A::_#A#b} = #t2;
+  method foo(core::int x) → dynamic {}
+}
+class B extends core::Object {
+  field core::int? _#B#x = null;
+  const constructor •() → self::B
+    : super core::Object::•()
+    ;
+  get x() → core::int
+    return let final core::int? #t3 = this.{self::B::_#B#x} in #t3.==(null) ?{core::int} let final core::int #t4 = 42 in this.{self::B::_#B#x}.==(null) ?{core::int} this.{self::B::_#B#x} = #t4 : throw new _in::LateInitializationErrorImpl::•("Field 'x' has been assigned during initialization.") : #t3{core::int};
+}
+class C extends core::Object {
+  field core::int? _#C#x = null;
+  synthetic constructor •() → self::C
+    : super core::Object::•()
+    ;
+  get x() → core::int
+    return let final core::int? #t5 = this.{self::C::_#C#x} in #t5.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'x' has not been initialized.") : #t5{core::int};
+  set x(core::int #t6) → void
+    if(this.{self::C::_#C#x}.==(null))
+      this.{self::C::_#C#x} = #t6;
+    else
+      throw new _in::LateInitializationErrorImpl::•("Field 'x' has already been initialized.");
+  method initVars() → dynamic {
+    this.{self::C::x} = 42;
+  }
+}
+static method bar(core::int x) → dynamic {}
+static method baz() → dynamic {
+  {
+    {
+      invalid-expression "pkg/front_end/testcases/late_lowering/later.dart:22:36: Error: 'catch' must be followed by '(identifier)' or '(identifier, identifier)'.
+No types are needed, the first is given by 'on', the second is always 'StackTrace'.
+  } on dynamic catch (late e, late t) {} // Error.
+                                   ^";
+    }
+    try {
+      throw "baz";
+    }
+    on dynamic catch(final dynamic late, final core::StackTrace e) {
+    }
+  }
+  for (core::int i = 0; i.{core::num::<}(10); i = i.{core::num::+}(1)) {
+    core::print("baz");
+  }
+  for (core::String s in <core::String>["baz"]) {
+    core::print(s);
+  }
+  block {
+    final core::List<core::int> #t7 = <core::int>[];
+    for (core::int i = 0; i.{core::num::<}(10); i = i.{core::num::+}(1))
+      #t7.{core::List::add}(i);
+  } =>#t7;
+}
+static method hest() → dynamic async {
+  await for (core::String s in asy::Stream::fromIterable<core::String>(<core::String>["hest"])) {
+    core::print(s);
+  }
+  return "hest";
+}
+static method fisk() → dynamic async {
+  core::String? s1;
+  function #s1#get() → core::String
+    return let final core::String? #t8 = s1 in #t8.==(null) ?{core::String} s1 = invalid-expression "pkg/front_end/testcases/late_lowering/later.dart:40:20: Error: `await` expressions are not supported in late local initializers.
+  late String s1 = await hest(); // Error.
+                   ^^^^^" as{TypeError,ForDynamic,ForNonNullableByDefault} core::String : #t8{core::String};
+  function #s1#set(core::String #t9) → dynamic
+    return s1 = #t9;
+  core::String? s2;
+  function #s2#get() → core::String
+    return let final core::String? #t10 = s2 in #t10.==(null) ?{core::String} s2 = "${#C1}${invalid-expression "pkg/front_end/testcases/late_lowering/later.dart:41:30: Error: `await` expressions are not supported in late local initializers.
+  late String s2 = '\${fisk}\${await hest()}\${fisk}'; // Error.
+                             ^^^^^"}${#C1}" : #t10{core::String};
+  function #s2#set(core::String #t11) → dynamic
+    return s2 = #t11;
+  core::Function? f;
+  function #f#get() → core::Function
+    return let final core::Function? #t12 = f in #t12.==(null) ?{core::Function} f = () → asy::Future<dynamic> async => await self::hest() : #t12{core::Function};
+  function #f#set(core::Function #t13) → dynamic
+    return f = #t13;
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = tearoff self::fisk
+}
diff --git a/pkg/front_end/testcases/late_lowering/later.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/later.dart.strong.transformed.expect
new file mode 100644
index 0000000..d54ab7b
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/later.dart.strong.transformed.expect
@@ -0,0 +1,270 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/late_lowering/later.dart:14:7: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+//   foo(late int x) {} // Error.
+//       ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:17:5: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// bar(late int x) {} // Error.
+//     ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:22:28: Error: 'catch' must be followed by '(identifier)' or '(identifier, identifier)'.
+// No types are needed, the first is given by 'on', the second is always 'StackTrace'.
+//   } on dynamic catch (late e, late t) {} // Error.
+//                            ^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:22:31: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+//   } on dynamic catch (late e, late t) {} // Error.
+//                               ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:22:36: Error: 'catch' must be followed by '(identifier)' or '(identifier, identifier)'.
+// No types are needed, the first is given by 'on', the second is always 'StackTrace'.
+//   } on dynamic catch (late e, late t) {} // Error.
+//                                    ^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:23:8: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+//   for (late int i = 0; i < 10; ++i) { // Error.
+//        ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:26:8: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+//   for (late String s in ["baz"]) { // Error.
+//        ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:29:9: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+//   [for (late int i = 0; i < 10; ++i) i]; // Error.
+//         ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:33:14: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+//   await for (late String s in new Stream.fromIterable(["hest"])) { // Error.
+//              ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:40:20: Error: `await` expressions are not supported in late local initializers.
+//   late String s1 = await hest(); // Error.
+//                    ^^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:41:30: Error: `await` expressions are not supported in late local initializers.
+//   late String s2 = '${fisk}${await hest()}${fisk}'; // Error.
+//                              ^^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:48:9: Error: Constructor is marked 'const' so fields can't be late.
+//   const B(); // Error: B has late final fields.
+//         ^
+// pkg/front_end/testcases/late_lowering/later.dart:46:18: Context: Field is late, but constructor is 'const'.
+//   late final int x = 42;
+//                  ^
+//
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+import "dart:async" as asy;
+
+class A extends core::Object {
+  field core::int a = 42;
+  field core::int? _#A#b = null;
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  get b() → core::int
+    return let final core::int? #t1 = this.{self::A::_#A#b} in #t1.==(null) ?{core::int} this.{self::A::_#A#b} = this.{self::A::a}.{core::num::*}(2).{core::int::>>}(1) : #t1{core::int};
+  set b(core::int #t2) → void
+    this.{self::A::_#A#b} = #t2;
+  method foo(core::int x) → dynamic {}
+}
+class B extends core::Object {
+  field core::int? _#B#x = null;
+  const constructor •() → self::B
+    : super core::Object::•()
+    ;
+  get x() → core::int
+    return let final core::int? #t3 = this.{self::B::_#B#x} in #t3.==(null) ?{core::int} let final core::int #t4 = 42 in this.{self::B::_#B#x}.==(null) ?{core::int} this.{self::B::_#B#x} = #t4 : throw new _in::LateInitializationErrorImpl::•("Field 'x' has been assigned during initialization.") : #t3{core::int};
+}
+class C extends core::Object {
+  field core::int? _#C#x = null;
+  synthetic constructor •() → self::C
+    : super core::Object::•()
+    ;
+  get x() → core::int
+    return let final core::int? #t5 = this.{self::C::_#C#x} in #t5.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'x' has not been initialized.") : #t5{core::int};
+  set x(core::int #t6) → void
+    if(this.{self::C::_#C#x}.==(null))
+      this.{self::C::_#C#x} = #t6;
+    else
+      throw new _in::LateInitializationErrorImpl::•("Field 'x' has already been initialized.");
+  method initVars() → dynamic {
+    this.{self::C::x} = 42;
+  }
+}
+static method bar(core::int x) → dynamic {}
+static method baz() → dynamic {
+  {
+    {
+      invalid-expression "pkg/front_end/testcases/late_lowering/later.dart:22:36: Error: 'catch' must be followed by '(identifier)' or '(identifier, identifier)'.
+No types are needed, the first is given by 'on', the second is always 'StackTrace'.
+  } on dynamic catch (late e, late t) {} // Error.
+                                   ^";
+    }
+    try {
+      throw "baz";
+    }
+    on dynamic catch(final dynamic late, final core::StackTrace e) {
+    }
+  }
+  for (core::int i = 0; i.{core::num::<}(10); i = i.{core::num::+}(1)) {
+    core::print("baz");
+  }
+  {
+    core::Iterator<core::String*>* :sync-for-iterator = _in::unsafeCast<core::Iterable<core::String*>*>(<core::String>["baz"]).{core::Iterable::iterator};
+    for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+      core::String s = :sync-for-iterator.{core::Iterator::current};
+      {
+        core::print(s);
+      }
+    }
+  }
+  block {
+    final core::List<core::int> #t7 = <core::int>[];
+    for (core::int i = 0; i.{core::num::<}(10); i = i.{core::num::+}(1))
+      #t7.{core::List::add}(i);
+  } =>#t7;
+}
+static method hest() → dynamic /* originally async */ {
+  final asy::_AsyncAwaitCompleter<dynamic> :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
+  asy::FutureOr<dynamic>? :return_value;
+  dynamic :async_stack_trace;
+  dynamic :async_op_then;
+  dynamic :async_op_error;
+  core::int :await_jump_var = 0;
+  dynamic :await_ctx_var;
+  dynamic :saved_try_context_var0;
+  dynamic :saved_try_context_var1;
+  dynamic :exception0;
+  dynamic :stack_trace0;
+  function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+    try {
+      #L1:
+      {
+        {
+          dynamic :stream = asy::Stream::fromIterable<core::String>(<core::String>["hest"]);
+          asy::_asyncStarListenHelper(:stream, :async_op);
+          asy::_StreamIterator<core::String>? :for-iterator = new asy::_StreamIterator::•<core::String>(:stream);
+          try
+            #L2:
+            while (true) {
+              dynamic #t8 = asy::_asyncStarMoveNextHelper(:stream);
+              [yield] let dynamic #t9 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
+              if(_in::unsafeCast<core::bool*>(:result)) {
+                core::String s = :for-iterator.{asy::_StreamIterator::current};
+                {
+                  core::print(s);
+                }
+              }
+              else
+                break #L2;
+            }
+          finally
+            if(!:for-iterator.{asy::_StreamIterator::_subscription}.{core::Object::==}(null)) {
+              [yield] let dynamic #t10 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::cancel}(), :async_op_then, :async_op_error, :async_op) in null;
+              :result;
+            }
+        }
+        :return_value = "hest";
+        break #L1;
+      }
+      asy::_completeOnAsyncReturn(:async_completer, :return_value);
+      return;
+    }
+    on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+      :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+    }
+  :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+  :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+  :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+  :async_completer.start(:async_op);
+  return :async_completer.{asy::Completer::future};
+}
+static method fisk() → dynamic /* originally async */ {
+  final asy::_AsyncAwaitCompleter<dynamic> :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
+  asy::FutureOr<dynamic>? :return_value;
+  dynamic :async_stack_trace;
+  dynamic :async_op_then;
+  dynamic :async_op_error;
+  core::int :await_jump_var = 0;
+  dynamic :await_ctx_var;
+  function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+    try {
+      #L3:
+      {
+        core::String? s1;
+        function #s1#get() → core::String
+          return let final core::String? #t11 = s1 in #t11.==(null) ?{core::String} s1 = invalid-expression "pkg/front_end/testcases/late_lowering/later.dart:40:20: Error: `await` expressions are not supported in late local initializers.
+  late String s1 = await hest(); // Error.
+                   ^^^^^" as{TypeError,ForDynamic,ForNonNullableByDefault} core::String : #t11{core::String};
+        function #s1#set(core::String #t12) → dynamic
+          return s1 = #t12;
+        core::String? s2;
+        function #s2#get() → core::String
+          return let final core::String? #t13 = s2 in #t13.==(null) ?{core::String} s2 = "${#C1}${invalid-expression "pkg/front_end/testcases/late_lowering/later.dart:41:30: Error: `await` expressions are not supported in late local initializers.
+  late String s2 = '\${fisk}\${await hest()}\${fisk}'; // Error.
+                             ^^^^^"}${#C1}" : #t13{core::String};
+        function #s2#set(core::String #t14) → dynamic
+          return s2 = #t14;
+        core::Function? f;
+        function #f#get() → core::Function
+          return let final core::Function? #t15 = f in #t15.==(null) ?{core::Function} f = () → asy::Future<dynamic> /* originally async */ {
+            final asy::_AsyncAwaitCompleter<dynamic> :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
+            asy::FutureOr<dynamic>? :return_value;
+            dynamic :async_stack_trace;
+            dynamic :async_op_then;
+            dynamic :async_op_error;
+            core::int :await_jump_var = 0;
+            dynamic :await_ctx_var;
+            dynamic :saved_try_context_var0;
+            function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+              try {
+                #L4:
+                {
+                  [yield] let dynamic #t16 = asy::_awaitHelper(self::hest(), :async_op_then, :async_op_error, :async_op) in null;
+                  :return_value = :result;
+                  break #L4;
+                }
+                asy::_completeOnAsyncReturn(:async_completer, :return_value);
+                return;
+              }
+              on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+                :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+              }
+            :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+            :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+            :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+            :async_completer.start(:async_op);
+            return :async_completer.{asy::Completer::future};
+          } : #t15{core::Function};
+        function #f#set(core::Function #t17) → dynamic
+          return f = #t17;
+      }
+      asy::_completeOnAsyncReturn(:async_completer, :return_value);
+      return;
+    }
+    on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+      :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+    }
+  :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+  :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+  :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+  :async_completer.start(:async_op);
+  return :async_completer.{asy::Completer::future};
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = tearoff self::fisk
+}
diff --git a/pkg/front_end/testcases/late_lowering/later.dart.weak.expect b/pkg/front_end/testcases/late_lowering/later.dart.weak.expect
new file mode 100644
index 0000000..f7e7212
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/later.dart.weak.expect
@@ -0,0 +1,164 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/late_lowering/later.dart:14:7: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+//   foo(late int x) {} // Error.
+//       ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:17:5: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// bar(late int x) {} // Error.
+//     ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:22:28: Error: 'catch' must be followed by '(identifier)' or '(identifier, identifier)'.
+// No types are needed, the first is given by 'on', the second is always 'StackTrace'.
+//   } on dynamic catch (late e, late t) {} // Error.
+//                            ^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:22:31: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+//   } on dynamic catch (late e, late t) {} // Error.
+//                               ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:22:36: Error: 'catch' must be followed by '(identifier)' or '(identifier, identifier)'.
+// No types are needed, the first is given by 'on', the second is always 'StackTrace'.
+//   } on dynamic catch (late e, late t) {} // Error.
+//                                    ^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:23:8: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+//   for (late int i = 0; i < 10; ++i) { // Error.
+//        ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:26:8: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+//   for (late String s in ["baz"]) { // Error.
+//        ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:29:9: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+//   [for (late int i = 0; i < 10; ++i) i]; // Error.
+//         ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:33:14: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+//   await for (late String s in new Stream.fromIterable(["hest"])) { // Error.
+//              ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:40:20: Error: `await` expressions are not supported in late local initializers.
+//   late String s1 = await hest(); // Error.
+//                    ^^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:41:30: Error: `await` expressions are not supported in late local initializers.
+//   late String s2 = '${fisk}${await hest()}${fisk}'; // Error.
+//                              ^^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:48:9: Warning: Constructor is marked 'const' and some fields are late.
+//   const B(); // Error: B has late final fields.
+//         ^
+// pkg/front_end/testcases/late_lowering/later.dart:46:18: Context: Field is late, but constructor is 'const'.
+//   late final int x = 42;
+//                  ^
+//
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+import "dart:async" as asy;
+
+class A extends core::Object {
+  field core::int a = 42;
+  field core::int? _#A#b = null;
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  get b() → core::int
+    return let final core::int? #t1 = this.{self::A::_#A#b} in #t1.==(null) ?{core::int} this.{self::A::_#A#b} = this.{self::A::a}.{core::num::*}(2).{core::int::>>}(1) : #t1{core::int};
+  set b(core::int #t2) → void
+    this.{self::A::_#A#b} = #t2;
+  method foo(core::int x) → dynamic {}
+}
+class B extends core::Object {
+  field core::int? _#B#x = null;
+  const constructor •() → self::B
+    : super core::Object::•()
+    ;
+  get x() → core::int
+    return let final core::int? #t3 = this.{self::B::_#B#x} in #t3.==(null) ?{core::int} let final core::int #t4 = 42 in this.{self::B::_#B#x}.==(null) ?{core::int} this.{self::B::_#B#x} = #t4 : throw new _in::LateInitializationErrorImpl::•("Field 'x' has been assigned during initialization.") : #t3{core::int};
+}
+class C extends core::Object {
+  field core::int? _#C#x = null;
+  synthetic constructor •() → self::C
+    : super core::Object::•()
+    ;
+  get x() → core::int
+    return let final core::int? #t5 = this.{self::C::_#C#x} in #t5.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'x' has not been initialized.") : #t5{core::int};
+  set x(core::int #t6) → void
+    if(this.{self::C::_#C#x}.==(null))
+      this.{self::C::_#C#x} = #t6;
+    else
+      throw new _in::LateInitializationErrorImpl::•("Field 'x' has already been initialized.");
+  method initVars() → dynamic {
+    this.{self::C::x} = 42;
+  }
+}
+static method bar(core::int x) → dynamic {}
+static method baz() → dynamic {
+  {
+    {
+      invalid-expression "pkg/front_end/testcases/late_lowering/later.dart:22:36: Error: 'catch' must be followed by '(identifier)' or '(identifier, identifier)'.
+No types are needed, the first is given by 'on', the second is always 'StackTrace'.
+  } on dynamic catch (late e, late t) {} // Error.
+                                   ^";
+    }
+    try {
+      throw "baz";
+    }
+    on dynamic catch(final dynamic late, final core::StackTrace e) {
+    }
+  }
+  for (core::int i = 0; i.{core::num::<}(10); i = i.{core::num::+}(1)) {
+    core::print("baz");
+  }
+  for (core::String s in <core::String>["baz"]) {
+    core::print(s);
+  }
+  block {
+    final core::List<core::int> #t7 = <core::int>[];
+    for (core::int i = 0; i.{core::num::<}(10); i = i.{core::num::+}(1))
+      #t7.{core::List::add}(i);
+  } =>#t7;
+}
+static method hest() → dynamic async {
+  await for (core::String s in asy::Stream::fromIterable<core::String>(<core::String>["hest"])) {
+    core::print(s);
+  }
+  return "hest";
+}
+static method fisk() → dynamic async {
+  core::String? s1;
+  function #s1#get() → core::String
+    return let final core::String? #t8 = s1 in #t8.==(null) ?{core::String} s1 = invalid-expression "pkg/front_end/testcases/late_lowering/later.dart:40:20: Error: `await` expressions are not supported in late local initializers.
+  late String s1 = await hest(); // Error.
+                   ^^^^^" as{TypeError,ForDynamic,ForNonNullableByDefault} core::String : #t8{core::String};
+  function #s1#set(core::String #t9) → dynamic
+    return s1 = #t9;
+  core::String? s2;
+  function #s2#get() → core::String
+    return let final core::String? #t10 = s2 in #t10.==(null) ?{core::String} s2 = "${#C1}${invalid-expression "pkg/front_end/testcases/late_lowering/later.dart:41:30: Error: `await` expressions are not supported in late local initializers.
+  late String s2 = '\${fisk}\${await hest()}\${fisk}'; // Error.
+                             ^^^^^"}${#C1}" : #t10{core::String};
+  function #s2#set(core::String #t11) → dynamic
+    return s2 = #t11;
+  core::Function? f;
+  function #f#get() → core::Function
+    return let final core::Function? #t12 = f in #t12.==(null) ?{core::Function} f = () → asy::Future<dynamic> async => await self::hest() : #t12{core::Function};
+  function #f#set(core::Function #t13) → dynamic
+    return f = #t13;
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = tearoff self::fisk
+}
diff --git a/pkg/front_end/testcases/late_lowering/later.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/later.dart.weak.transformed.expect
new file mode 100644
index 0000000..3ae52e7
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/later.dart.weak.transformed.expect
@@ -0,0 +1,270 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/late_lowering/later.dart:14:7: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+//   foo(late int x) {} // Error.
+//       ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:17:5: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// bar(late int x) {} // Error.
+//     ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:22:28: Error: 'catch' must be followed by '(identifier)' or '(identifier, identifier)'.
+// No types are needed, the first is given by 'on', the second is always 'StackTrace'.
+//   } on dynamic catch (late e, late t) {} // Error.
+//                            ^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:22:31: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+//   } on dynamic catch (late e, late t) {} // Error.
+//                               ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:22:36: Error: 'catch' must be followed by '(identifier)' or '(identifier, identifier)'.
+// No types are needed, the first is given by 'on', the second is always 'StackTrace'.
+//   } on dynamic catch (late e, late t) {} // Error.
+//                                    ^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:23:8: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+//   for (late int i = 0; i < 10; ++i) { // Error.
+//        ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:26:8: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+//   for (late String s in ["baz"]) { // Error.
+//        ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:29:9: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+//   [for (late int i = 0; i < 10; ++i) i]; // Error.
+//         ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:33:14: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+//   await for (late String s in new Stream.fromIterable(["hest"])) { // Error.
+//              ^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:40:20: Error: `await` expressions are not supported in late local initializers.
+//   late String s1 = await hest(); // Error.
+//                    ^^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:41:30: Error: `await` expressions are not supported in late local initializers.
+//   late String s2 = '${fisk}${await hest()}${fisk}'; // Error.
+//                              ^^^^^
+//
+// pkg/front_end/testcases/late_lowering/later.dart:48:9: Warning: Constructor is marked 'const' and some fields are late.
+//   const B(); // Error: B has late final fields.
+//         ^
+// pkg/front_end/testcases/late_lowering/later.dart:46:18: Context: Field is late, but constructor is 'const'.
+//   late final int x = 42;
+//                  ^
+//
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+import "dart:async" as asy;
+
+class A extends core::Object {
+  field core::int a = 42;
+  field core::int? _#A#b = null;
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  get b() → core::int
+    return let final core::int? #t1 = this.{self::A::_#A#b} in #t1.==(null) ?{core::int} this.{self::A::_#A#b} = this.{self::A::a}.{core::num::*}(2).{core::int::>>}(1) : #t1{core::int};
+  set b(core::int #t2) → void
+    this.{self::A::_#A#b} = #t2;
+  method foo(core::int x) → dynamic {}
+}
+class B extends core::Object {
+  field core::int? _#B#x = null;
+  const constructor •() → self::B
+    : super core::Object::•()
+    ;
+  get x() → core::int
+    return let final core::int? #t3 = this.{self::B::_#B#x} in #t3.==(null) ?{core::int} let final core::int #t4 = 42 in this.{self::B::_#B#x}.==(null) ?{core::int} this.{self::B::_#B#x} = #t4 : throw new _in::LateInitializationErrorImpl::•("Field 'x' has been assigned during initialization.") : #t3{core::int};
+}
+class C extends core::Object {
+  field core::int? _#C#x = null;
+  synthetic constructor •() → self::C
+    : super core::Object::•()
+    ;
+  get x() → core::int
+    return let final core::int? #t5 = this.{self::C::_#C#x} in #t5.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'x' has not been initialized.") : #t5{core::int};
+  set x(core::int #t6) → void
+    if(this.{self::C::_#C#x}.==(null))
+      this.{self::C::_#C#x} = #t6;
+    else
+      throw new _in::LateInitializationErrorImpl::•("Field 'x' has already been initialized.");
+  method initVars() → dynamic {
+    this.{self::C::x} = 42;
+  }
+}
+static method bar(core::int x) → dynamic {}
+static method baz() → dynamic {
+  {
+    {
+      invalid-expression "pkg/front_end/testcases/late_lowering/later.dart:22:36: Error: 'catch' must be followed by '(identifier)' or '(identifier, identifier)'.
+No types are needed, the first is given by 'on', the second is always 'StackTrace'.
+  } on dynamic catch (late e, late t) {} // Error.
+                                   ^";
+    }
+    try {
+      throw "baz";
+    }
+    on dynamic catch(final dynamic late, final core::StackTrace e) {
+    }
+  }
+  for (core::int i = 0; i.{core::num::<}(10); i = i.{core::num::+}(1)) {
+    core::print("baz");
+  }
+  {
+    core::Iterator<core::String*>* :sync-for-iterator = _in::unsafeCast<core::Iterable<core::String*>*>(<core::String>["baz"]).{core::Iterable::iterator};
+    for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+      core::String s = :sync-for-iterator.{core::Iterator::current};
+      {
+        core::print(s);
+      }
+    }
+  }
+  block {
+    final core::List<core::int> #t7 = <core::int>[];
+    for (core::int i = 0; i.{core::num::<}(10); i = i.{core::num::+}(1))
+      #t7.{core::List::add}(i);
+  } =>#t7;
+}
+static method hest() → dynamic /* originally async */ {
+  final asy::_AsyncAwaitCompleter<dynamic> :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
+  asy::FutureOr<dynamic>? :return_value;
+  dynamic :async_stack_trace;
+  dynamic :async_op_then;
+  dynamic :async_op_error;
+  core::int :await_jump_var = 0;
+  dynamic :await_ctx_var;
+  dynamic :saved_try_context_var0;
+  dynamic :saved_try_context_var1;
+  dynamic :exception0;
+  dynamic :stack_trace0;
+  function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+    try {
+      #L1:
+      {
+        {
+          dynamic :stream = asy::Stream::fromIterable<core::String>(<core::String>["hest"]);
+          asy::_asyncStarListenHelper(:stream, :async_op);
+          asy::_StreamIterator<core::String>? :for-iterator = new asy::_StreamIterator::•<core::String>(:stream);
+          try
+            #L2:
+            while (true) {
+              dynamic #t8 = asy::_asyncStarMoveNextHelper(:stream);
+              [yield] let dynamic #t9 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
+              if(_in::unsafeCast<core::bool*>(:result)) {
+                core::String s = :for-iterator.{asy::_StreamIterator::current};
+                {
+                  core::print(s);
+                }
+              }
+              else
+                break #L2;
+            }
+          finally
+            if(!:for-iterator.{asy::_StreamIterator::_subscription}.{core::Object::==}(null)) {
+              [yield] let dynamic #t10 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::cancel}(), :async_op_then, :async_op_error, :async_op) in null;
+              :result;
+            }
+        }
+        :return_value = "hest";
+        break #L1;
+      }
+      asy::_completeOnAsyncReturn(:async_completer, :return_value);
+      return;
+    }
+    on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+      :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+    }
+  :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+  :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+  :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+  :async_completer.start(:async_op);
+  return :async_completer.{asy::Completer::future};
+}
+static method fisk() → dynamic /* originally async */ {
+  final asy::_AsyncAwaitCompleter<dynamic> :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
+  asy::FutureOr<dynamic>? :return_value;
+  dynamic :async_stack_trace;
+  dynamic :async_op_then;
+  dynamic :async_op_error;
+  core::int :await_jump_var = 0;
+  dynamic :await_ctx_var;
+  function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+    try {
+      #L3:
+      {
+        core::String? s1;
+        function #s1#get() → core::String
+          return let final core::String? #t11 = s1 in #t11.==(null) ?{core::String} s1 = invalid-expression "pkg/front_end/testcases/late_lowering/later.dart:40:20: Error: `await` expressions are not supported in late local initializers.
+  late String s1 = await hest(); // Error.
+                   ^^^^^" as{TypeError,ForDynamic,ForNonNullableByDefault} core::String : #t11{core::String};
+        function #s1#set(core::String #t12) → dynamic
+          return s1 = #t12;
+        core::String? s2;
+        function #s2#get() → core::String
+          return let final core::String? #t13 = s2 in #t13.==(null) ?{core::String} s2 = "${#C1}${invalid-expression "pkg/front_end/testcases/late_lowering/later.dart:41:30: Error: `await` expressions are not supported in late local initializers.
+  late String s2 = '\${fisk}\${await hest()}\${fisk}'; // Error.
+                             ^^^^^"}${#C1}" : #t13{core::String};
+        function #s2#set(core::String #t14) → dynamic
+          return s2 = #t14;
+        core::Function? f;
+        function #f#get() → core::Function
+          return let final core::Function? #t15 = f in #t15.==(null) ?{core::Function} f = () → asy::Future<dynamic> /* originally async */ {
+            final asy::_AsyncAwaitCompleter<dynamic> :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
+            asy::FutureOr<dynamic>? :return_value;
+            dynamic :async_stack_trace;
+            dynamic :async_op_then;
+            dynamic :async_op_error;
+            core::int :await_jump_var = 0;
+            dynamic :await_ctx_var;
+            dynamic :saved_try_context_var0;
+            function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+              try {
+                #L4:
+                {
+                  [yield] let dynamic #t16 = asy::_awaitHelper(self::hest(), :async_op_then, :async_op_error, :async_op) in null;
+                  :return_value = :result;
+                  break #L4;
+                }
+                asy::_completeOnAsyncReturn(:async_completer, :return_value);
+                return;
+              }
+              on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+                :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+              }
+            :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+            :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+            :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+            :async_completer.start(:async_op);
+            return :async_completer.{asy::Completer::future};
+          } : #t15{core::Function};
+        function #f#set(core::Function #t17) → dynamic
+          return f = #t17;
+      }
+      asy::_completeOnAsyncReturn(:async_completer, :return_value);
+      return;
+    }
+    on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+      :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+    }
+  :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+  :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+  :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+  :async_completer.start(:async_op);
+  return :async_completer.{asy::Completer::future};
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = tearoff self::fisk
+}
diff --git a/pkg/front_end/testcases/late_lowering/override.dart.strong.expect b/pkg/front_end/testcases/late_lowering/override.dart.strong.expect
index 8e6d857..2fb9901 100644
--- a/pkg/front_end/testcases/late_lowering/override.dart.strong.expect
+++ b/pkg/front_end/testcases/late_lowering/override.dart.strong.expect
@@ -58,7 +58,7 @@
     else
       throw new _in::LateInitializationErrorImpl::•("Field 'field3' has already been initialized.");
   get field4() → core::int
-    return let final core::int? #t15 = this.{self::SubClass::_#SubClass#field4} in #t15.==(null) ?{core::int} this.{self::SubClass::_#SubClass#field4} = 0 : #t15{core::int};
+    return let final core::int? #t15 = this.{self::SubClass::_#SubClass#field4} in #t15.==(null) ?{core::int} let final core::int #t16 = 0 in this.{self::SubClass::_#SubClass#field4}.==(null) ?{core::int} this.{self::SubClass::_#SubClass#field4} = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'field4' has been assigned during initialization.") : #t15{core::int};
   get directField1() → core::int
     return super.{self::Class::field1};
   set directField1(core::int value) → void {
diff --git a/pkg/front_end/testcases/late_lowering/override.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/override.dart.strong.transformed.expect
index 8e6d857..2fb9901 100644
--- a/pkg/front_end/testcases/late_lowering/override.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/override.dart.strong.transformed.expect
@@ -58,7 +58,7 @@
     else
       throw new _in::LateInitializationErrorImpl::•("Field 'field3' has already been initialized.");
   get field4() → core::int
-    return let final core::int? #t15 = this.{self::SubClass::_#SubClass#field4} in #t15.==(null) ?{core::int} this.{self::SubClass::_#SubClass#field4} = 0 : #t15{core::int};
+    return let final core::int? #t15 = this.{self::SubClass::_#SubClass#field4} in #t15.==(null) ?{core::int} let final core::int #t16 = 0 in this.{self::SubClass::_#SubClass#field4}.==(null) ?{core::int} this.{self::SubClass::_#SubClass#field4} = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'field4' has been assigned during initialization.") : #t15{core::int};
   get directField1() → core::int
     return super.{self::Class::field1};
   set directField1(core::int value) → void {
diff --git a/pkg/front_end/testcases/late_lowering/override.dart.weak.expect b/pkg/front_end/testcases/late_lowering/override.dart.weak.expect
index 8e6d857..2fb9901 100644
--- a/pkg/front_end/testcases/late_lowering/override.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/override.dart.weak.expect
@@ -58,7 +58,7 @@
     else
       throw new _in::LateInitializationErrorImpl::•("Field 'field3' has already been initialized.");
   get field4() → core::int
-    return let final core::int? #t15 = this.{self::SubClass::_#SubClass#field4} in #t15.==(null) ?{core::int} this.{self::SubClass::_#SubClass#field4} = 0 : #t15{core::int};
+    return let final core::int? #t15 = this.{self::SubClass::_#SubClass#field4} in #t15.==(null) ?{core::int} let final core::int #t16 = 0 in this.{self::SubClass::_#SubClass#field4}.==(null) ?{core::int} this.{self::SubClass::_#SubClass#field4} = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'field4' has been assigned during initialization.") : #t15{core::int};
   get directField1() → core::int
     return super.{self::Class::field1};
   set directField1(core::int value) → void {
diff --git a/pkg/front_end/testcases/late_lowering/override.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/override.dart.weak.transformed.expect
index 8e6d857..2fb9901 100644
--- a/pkg/front_end/testcases/late_lowering/override.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/override.dart.weak.transformed.expect
@@ -58,7 +58,7 @@
     else
       throw new _in::LateInitializationErrorImpl::•("Field 'field3' has already been initialized.");
   get field4() → core::int
-    return let final core::int? #t15 = this.{self::SubClass::_#SubClass#field4} in #t15.==(null) ?{core::int} this.{self::SubClass::_#SubClass#field4} = 0 : #t15{core::int};
+    return let final core::int? #t15 = this.{self::SubClass::_#SubClass#field4} in #t15.==(null) ?{core::int} let final core::int #t16 = 0 in this.{self::SubClass::_#SubClass#field4}.==(null) ?{core::int} this.{self::SubClass::_#SubClass#field4} = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'field4' has been assigned during initialization.") : #t15{core::int};
   get directField1() → core::int
     return super.{self::Class::field1};
   set directField1(core::int value) → void {
diff --git a/pkg/front_end/testcases/late_lowering/test.options b/pkg/front_end/testcases/late_lowering/test.options
index 707afaf..0b0b221 100644
--- a/pkg/front_end/testcases/late_lowering/test.options
+++ b/pkg/front_end/testcases/late_lowering/test.options
@@ -1,2 +1,3 @@
 --enable-experiment=non-nullable
---force-late-lowering
\ No newline at end of file
+--force-late-lowering
+--force-nnbd-checks
diff --git a/pkg/front_end/testcases/nnbd/constants.dart b/pkg/front_end/testcases/nnbd/constants.dart
new file mode 100644
index 0000000..0a32e64
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/constants.dart
@@ -0,0 +1,94 @@
+// Copyright (c) 2020, 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 'constants_lib.dart' as lib;
+
+typedef F1<T> = T Function(T);
+typedef F2 = T Function<T>(T);
+
+const objectTypeLiteral = Object;
+const int Function(int) partialInstantiation = lib.id;
+const instance = const lib.Class<int>(0);
+const functionTypeLiteral = F1;
+const genericFunctionTypeLiteral = F2;
+const listLiteral = <int>[0];
+const setLiteral = <int>{0};
+const mapLiteral = <int, String>{0: 'foo'};
+const listConcatenation = <int>[...listLiteral];
+const setConcatenation = <int>{...setLiteral};
+const mapConcatenation = <int, String>{...mapLiteral};
+
+const objectTypeLiteralIdentical =
+    identical(objectTypeLiteral, lib.objectTypeLiteral);
+const partialInstantiationIdentical =
+    identical(partialInstantiation, lib.partialInstantiation);
+const instanceIdentical = identical(instance, lib.instance);
+const functionTypeLiteralIdentical =
+    identical(functionTypeLiteral, lib.functionTypeLiteral);
+const genericFunctionTypeLiteralIdentical =
+    identical(genericFunctionTypeLiteral, lib.genericFunctionTypeLiteral);
+const listLiteralIdentical = identical(listLiteral, lib.listLiteral);
+const setLiteralIdentical = identical(setLiteral, lib.setLiteral);
+const mapLiteralIdentical = identical(mapLiteral, lib.mapLiteral);
+const listConcatenationIdentical =
+    identical(listConcatenation, lib.listConcatenation);
+const setConcatenationIdentical =
+    identical(setConcatenation, lib.setConcatenation);
+const mapConcatenationIdentical =
+    identical(mapConcatenation, lib.mapConcatenation);
+
+final bool inStrongMode = _inStrongMode();
+
+bool _inStrongMode() {
+  var f = (String? s) {
+    s.length; // This will be an invalid expression in strong mode.
+  };
+  try {
+    f("foo");
+  } catch (e) {
+    print('Running in strong mode.');
+    return true;
+  }
+  print('Running in weak mode.');
+  return false;
+}
+
+main() {
+  test(objectTypeLiteral, lib.objectTypeLiteral);
+  test(partialInstantiation, lib.partialInstantiation);
+  test(instance, lib.instance);
+  test(functionTypeLiteral, lib.functionTypeLiteral);
+  test(genericFunctionTypeLiteral, lib.genericFunctionTypeLiteral);
+  test(listLiteral, lib.listLiteral);
+  test(setLiteral, lib.setLiteral);
+  test(mapLiteral, lib.mapLiteral);
+  test(listConcatenation, lib.listConcatenation);
+  test(setConcatenation, lib.setConcatenation);
+  test(mapConcatenation, lib.mapConcatenation);
+
+  test(true, objectTypeLiteralIdentical);
+  test(true, partialInstantiationIdentical);
+  test(true, instanceIdentical);
+  test(true, functionTypeLiteralIdentical);
+  test(true, genericFunctionTypeLiteralIdentical);
+  test(true, listLiteralIdentical);
+  test(true, setLiteralIdentical);
+  test(true, mapLiteralIdentical);
+  test(true, listConcatenationIdentical);
+  test(true, setConcatenationIdentical);
+  test(true, mapConcatenationIdentical);
+}
+
+test(expected, actual) {
+  print('test($expected, $actual)');
+  if (inStrongMode) {
+    if (identical(expected, actual)) {
+      throw 'Unexpected identical for $expected and $actual';
+    }
+  } else {
+    if (!identical(expected, actual)) {
+      throw 'Expected $expected, actual $actual';
+    }
+  }
+}
diff --git a/pkg/front_end/testcases/nnbd/constants.dart.outline.expect b/pkg/front_end/testcases/nnbd/constants.dart.outline.expect
new file mode 100644
index 0000000..ff2d865
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/constants.dart.outline.expect
@@ -0,0 +1,65 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "constants_lib.dart" as con;
+
+import "org-dartlang-testcase:///constants_lib.dart" as lib;
+
+typedef F1<invariant T extends core::Object? = dynamic> = (T%) → T%;
+typedef F2 = <T extends core::Object? = dynamic>(T%) → T%;
+static const field core::Type objectTypeLiteral = core::Object;
+static const field (core::int) → core::int partialInstantiation = con::id<core::int>;
+static const field con::Class<core::int> instance = const con::Class::•<core::int>(0);
+static const field core::Type functionTypeLiteral = (dynamic) → dynamic;
+static const field core::Type genericFunctionTypeLiteral = <T extends core::Object? = dynamic>(T%) → T%;
+static const field core::List<core::int> listLiteral = const <core::int>[0];
+static const field core::Set<core::int> setLiteral = const <core::int>{0};
+static const field core::Map<core::int, core::String> mapLiteral = const <core::int, core::String>{0: "foo"};
+static const field core::List<core::int> listConcatenation = self::listLiteral;
+static const field core::Set<core::int> setConcatenation = self::setLiteral;
+static const field core::Map<core::int, core::String> mapConcatenation = self::mapLiteral;
+static const field core::bool objectTypeLiteralIdentical = core::identical(self::objectTypeLiteral, con::objectTypeLiteral);
+static const field core::bool partialInstantiationIdentical = core::identical(self::partialInstantiation, con::partialInstantiation);
+static const field core::bool instanceIdentical = core::identical(self::instance, con::instance);
+static const field core::bool functionTypeLiteralIdentical = core::identical(self::functionTypeLiteral, con::functionTypeLiteral);
+static const field core::bool genericFunctionTypeLiteralIdentical = core::identical(self::genericFunctionTypeLiteral, con::genericFunctionTypeLiteral);
+static const field core::bool listLiteralIdentical = core::identical(self::listLiteral, con::listLiteral);
+static const field core::bool setLiteralIdentical = core::identical(self::setLiteral, con::setLiteral);
+static const field core::bool mapLiteralIdentical = core::identical(self::mapLiteral, con::mapLiteral);
+static const field core::bool listConcatenationIdentical = core::identical(self::listConcatenation, con::listConcatenation);
+static const field core::bool setConcatenationIdentical = core::identical(self::setConcatenation, con::setConcatenation);
+static const field core::bool mapConcatenationIdentical = core::identical(self::mapConcatenation, con::mapConcatenation);
+static final field core::bool inStrongMode;
+static method _inStrongMode() → core::bool
+  ;
+static method main() → dynamic
+  ;
+static method test(dynamic expected, dynamic actual) → dynamic
+  ;
+
+library;
+import self as con;
+import "dart:core" as core;
+
+typedef F1<invariant T extends core::Object* = dynamic> = (T*) →* T*;
+typedef F2 = <T extends core::Object* = dynamic>(T*) →* T*;
+class Class<T extends core::Object* = dynamic> extends core::Object {
+  final field con::Class::T* field;
+  const constructor •(con::Class::T* field) → con::Class<con::Class::T*>*
+    : con::Class::field = field, super core::Object::•()
+    ;
+}
+static const field core::Type* objectTypeLiteral = core::Object*;
+static const field (core::Object*, core::Object*) →* core::bool* c2 = core::identical;
+static const field (core::int*) →* core::int* partialInstantiation = con::id<core::int*>;
+static const field con::Class<core::int*>* instance = const con::Class::•<core::int*>(0);
+static const field core::Type* functionTypeLiteral = (dynamic) →* dynamic;
+static const field core::Type* genericFunctionTypeLiteral = <T extends core::Object* = dynamic>(T*) →* T*;
+static const field core::List<core::int*>* listLiteral = const <core::int*>[0];
+static const field core::Set<core::int*>* setLiteral = const <core::int*>{0};
+static const field core::Map<core::int*, core::String*>* mapLiteral = const <core::int*, core::String*>{0: "foo"};
+static const field core::List<core::int*>* listConcatenation = con::listLiteral;
+static const field core::Set<core::int*>* setConcatenation = con::setLiteral;
+static const field core::Map<core::int*, core::String*>* mapConcatenation = con::mapLiteral;
+static method id<T extends core::Object* = dynamic>(con::id::T* t) → con::id::T*
+  ;
diff --git a/pkg/front_end/testcases/nnbd/constants.dart.strong.expect b/pkg/front_end/testcases/nnbd/constants.dart.strong.expect
new file mode 100644
index 0000000..c787b65
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/constants.dart.strong.expect
@@ -0,0 +1,150 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/constants.dart:45:7: Error: Property 'length' cannot be accessed on 'String?' because it is potentially null.
+// Try accessing using ?. instead.
+//     s.length; // This will be an invalid expression in strong mode.
+//       ^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+import "constants_lib.dart" as con;
+
+import "org-dartlang-testcase:///constants_lib.dart" as lib;
+
+typedef F1<invariant T extends core::Object? = dynamic> = (T%) → T%;
+typedef F2 = <T extends core::Object? = dynamic>(T%) → T%;
+static const field core::Type objectTypeLiteral = #C1;
+static const field (core::int) → core::int partialInstantiation = #C3;
+static const field con::Class<core::int> instance = #C5;
+static const field core::Type functionTypeLiteral = #C6;
+static const field core::Type genericFunctionTypeLiteral = #C7;
+static const field core::List<core::int> listLiteral = #C8;
+static const field core::Set<core::int> setLiteral = #C12;
+static const field core::Map<core::int, core::String> mapLiteral = #C15;
+static const field core::List<core::int> listConcatenation = #C8;
+static const field core::Set<core::int> setConcatenation = #C12;
+static const field core::Map<core::int, core::String> mapConcatenation = #C15;
+static const field core::bool objectTypeLiteralIdentical = #C16;
+static const field core::bool partialInstantiationIdentical = #C16;
+static const field core::bool instanceIdentical = #C16;
+static const field core::bool functionTypeLiteralIdentical = #C16;
+static const field core::bool genericFunctionTypeLiteralIdentical = #C16;
+static const field core::bool listLiteralIdentical = #C16;
+static const field core::bool setLiteralIdentical = #C16;
+static const field core::bool mapLiteralIdentical = #C16;
+static const field core::bool listConcatenationIdentical = #C16;
+static const field core::bool setConcatenationIdentical = #C16;
+static const field core::bool mapConcatenationIdentical = #C16;
+static final field core::bool inStrongMode = self::_inStrongMode();
+static method _inStrongMode() → core::bool {
+  (core::String?) → core::Null? f = (core::String? s) → core::Null? {
+    let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/constants.dart:45:7: Error: Property 'length' cannot be accessed on 'String?' because it is potentially null.
+Try accessing using ?. instead.
+    s.length; // This will be an invalid expression in strong mode.
+      ^^^^^^" in s.{core::String::length};
+  };
+  try {
+    f.call("foo");
+  }
+  on dynamic catch(final dynamic e) {
+    core::print("Running in strong mode.");
+    return true;
+  }
+  core::print("Running in weak mode.");
+  return false;
+}
+static method main() → dynamic {
+  self::test(#C1, #C17);
+  self::test(#C3, #C18);
+  self::test(#C5, #C19);
+  self::test(#C6, #C20);
+  self::test(#C7, #C21);
+  self::test(#C8, #C22);
+  self::test(#C12, #C24);
+  self::test(#C15, #C25);
+  self::test(#C8, #C22);
+  self::test(#C12, #C24);
+  self::test(#C15, #C25);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+}
+static method test(dynamic expected, dynamic actual) → dynamic {
+  core::print("test(${expected}, ${actual})");
+  if(self::inStrongMode) {
+    if(core::identical(expected, actual)) {
+      throw "Unexpected identical for ${expected} and ${actual}";
+    }
+  }
+  else {
+    if(!core::identical(expected, actual)) {
+      throw "Expected ${expected}, actual ${actual}";
+    }
+  }
+}
+
+library;
+import self as con;
+import "dart:core" as core;
+
+typedef F1<invariant T extends core::Object* = dynamic> = (T*) →* T*;
+typedef F2 = <T extends core::Object* = dynamic>(T*) →* T*;
+class Class<T extends core::Object* = dynamic> extends core::Object {
+  final field con::Class::T* field;
+  const constructor •(con::Class::T* field) → con::Class<con::Class::T*>*
+    : con::Class::field = field, super core::Object::•()
+    ;
+}
+static const field core::Type* objectTypeLiteral = #C17;
+static const field (core::Object*, core::Object*) →* core::bool* c2 = #C26;
+static const field (core::int*) →* core::int* partialInstantiation = #C18;
+static const field con::Class<core::int*>* instance = #C19;
+static const field core::Type* functionTypeLiteral = #C20;
+static const field core::Type* genericFunctionTypeLiteral = #C21;
+static const field core::List<core::int*>* listLiteral = #C22;
+static const field core::Set<core::int*>* setLiteral = #C24;
+static const field core::Map<core::int*, core::String*>* mapLiteral = #C25;
+static const field core::List<core::int*>* listConcatenation = #C22;
+static const field core::Set<core::int*>* setConcatenation = #C24;
+static const field core::Map<core::int*, core::String*>* mapConcatenation = #C25;
+static method id<T extends core::Object* = dynamic>(con::id::T* t) → con::id::T*
+  return t;
+
+constants  {
+  #C1 = TypeLiteralConstant(dart.core::Object)
+  #C2 = tearoff con::id
+  #C3 = partial-instantiation con::id <core::int>
+  #C4 = 0
+  #C5 = con::Class<core::int> {field:#C4}
+  #C6 = TypeLiteralConstant((dynamic) → dynamic)
+  #C7 = TypeLiteralConstant(<T extends dart.core::Object? = dynamic>(T%) → T%)
+  #C8 = <core::int>[#C4]
+  #C9 = null
+  #C10 = <dynamic>[#C4, #C9]
+  #C11 = core::_ImmutableMap<core::int, core::Null?> {_kvPairs:#C10}
+  #C12 = col::_UnmodifiableSet<core::int> {_map:#C11}
+  #C13 = "foo"
+  #C14 = <dynamic>[#C4, #C13]
+  #C15 = core::_ImmutableMap<core::int, core::String> {_kvPairs:#C14}
+  #C16 = false
+  #C17 = TypeLiteralConstant(dart.core::Object*)
+  #C18 = partial-instantiation con::id <core::int*>
+  #C19 = con::Class<core::int*> {field:#C4}
+  #C20 = TypeLiteralConstant((dynamic) →* dynamic)
+  #C21 = TypeLiteralConstant(<T extends dart.core::Object* = dynamic>(T*) →* T*)
+  #C22 = <core::int*>[#C4]
+  #C23 = core::_ImmutableMap<core::int*, core::Null?> {_kvPairs:#C10}
+  #C24 = col::_UnmodifiableSet<core::int*> {_map:#C23}
+  #C25 = core::_ImmutableMap<core::int*, core::String*> {_kvPairs:#C14}
+  #C26 = tearoff core::identical
+}
diff --git a/pkg/front_end/testcases/nnbd/constants.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/constants.dart.strong.transformed.expect
new file mode 100644
index 0000000..c787b65
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/constants.dart.strong.transformed.expect
@@ -0,0 +1,150 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/constants.dart:45:7: Error: Property 'length' cannot be accessed on 'String?' because it is potentially null.
+// Try accessing using ?. instead.
+//     s.length; // This will be an invalid expression in strong mode.
+//       ^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+import "constants_lib.dart" as con;
+
+import "org-dartlang-testcase:///constants_lib.dart" as lib;
+
+typedef F1<invariant T extends core::Object? = dynamic> = (T%) → T%;
+typedef F2 = <T extends core::Object? = dynamic>(T%) → T%;
+static const field core::Type objectTypeLiteral = #C1;
+static const field (core::int) → core::int partialInstantiation = #C3;
+static const field con::Class<core::int> instance = #C5;
+static const field core::Type functionTypeLiteral = #C6;
+static const field core::Type genericFunctionTypeLiteral = #C7;
+static const field core::List<core::int> listLiteral = #C8;
+static const field core::Set<core::int> setLiteral = #C12;
+static const field core::Map<core::int, core::String> mapLiteral = #C15;
+static const field core::List<core::int> listConcatenation = #C8;
+static const field core::Set<core::int> setConcatenation = #C12;
+static const field core::Map<core::int, core::String> mapConcatenation = #C15;
+static const field core::bool objectTypeLiteralIdentical = #C16;
+static const field core::bool partialInstantiationIdentical = #C16;
+static const field core::bool instanceIdentical = #C16;
+static const field core::bool functionTypeLiteralIdentical = #C16;
+static const field core::bool genericFunctionTypeLiteralIdentical = #C16;
+static const field core::bool listLiteralIdentical = #C16;
+static const field core::bool setLiteralIdentical = #C16;
+static const field core::bool mapLiteralIdentical = #C16;
+static const field core::bool listConcatenationIdentical = #C16;
+static const field core::bool setConcatenationIdentical = #C16;
+static const field core::bool mapConcatenationIdentical = #C16;
+static final field core::bool inStrongMode = self::_inStrongMode();
+static method _inStrongMode() → core::bool {
+  (core::String?) → core::Null? f = (core::String? s) → core::Null? {
+    let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/constants.dart:45:7: Error: Property 'length' cannot be accessed on 'String?' because it is potentially null.
+Try accessing using ?. instead.
+    s.length; // This will be an invalid expression in strong mode.
+      ^^^^^^" in s.{core::String::length};
+  };
+  try {
+    f.call("foo");
+  }
+  on dynamic catch(final dynamic e) {
+    core::print("Running in strong mode.");
+    return true;
+  }
+  core::print("Running in weak mode.");
+  return false;
+}
+static method main() → dynamic {
+  self::test(#C1, #C17);
+  self::test(#C3, #C18);
+  self::test(#C5, #C19);
+  self::test(#C6, #C20);
+  self::test(#C7, #C21);
+  self::test(#C8, #C22);
+  self::test(#C12, #C24);
+  self::test(#C15, #C25);
+  self::test(#C8, #C22);
+  self::test(#C12, #C24);
+  self::test(#C15, #C25);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+}
+static method test(dynamic expected, dynamic actual) → dynamic {
+  core::print("test(${expected}, ${actual})");
+  if(self::inStrongMode) {
+    if(core::identical(expected, actual)) {
+      throw "Unexpected identical for ${expected} and ${actual}";
+    }
+  }
+  else {
+    if(!core::identical(expected, actual)) {
+      throw "Expected ${expected}, actual ${actual}";
+    }
+  }
+}
+
+library;
+import self as con;
+import "dart:core" as core;
+
+typedef F1<invariant T extends core::Object* = dynamic> = (T*) →* T*;
+typedef F2 = <T extends core::Object* = dynamic>(T*) →* T*;
+class Class<T extends core::Object* = dynamic> extends core::Object {
+  final field con::Class::T* field;
+  const constructor •(con::Class::T* field) → con::Class<con::Class::T*>*
+    : con::Class::field = field, super core::Object::•()
+    ;
+}
+static const field core::Type* objectTypeLiteral = #C17;
+static const field (core::Object*, core::Object*) →* core::bool* c2 = #C26;
+static const field (core::int*) →* core::int* partialInstantiation = #C18;
+static const field con::Class<core::int*>* instance = #C19;
+static const field core::Type* functionTypeLiteral = #C20;
+static const field core::Type* genericFunctionTypeLiteral = #C21;
+static const field core::List<core::int*>* listLiteral = #C22;
+static const field core::Set<core::int*>* setLiteral = #C24;
+static const field core::Map<core::int*, core::String*>* mapLiteral = #C25;
+static const field core::List<core::int*>* listConcatenation = #C22;
+static const field core::Set<core::int*>* setConcatenation = #C24;
+static const field core::Map<core::int*, core::String*>* mapConcatenation = #C25;
+static method id<T extends core::Object* = dynamic>(con::id::T* t) → con::id::T*
+  return t;
+
+constants  {
+  #C1 = TypeLiteralConstant(dart.core::Object)
+  #C2 = tearoff con::id
+  #C3 = partial-instantiation con::id <core::int>
+  #C4 = 0
+  #C5 = con::Class<core::int> {field:#C4}
+  #C6 = TypeLiteralConstant((dynamic) → dynamic)
+  #C7 = TypeLiteralConstant(<T extends dart.core::Object? = dynamic>(T%) → T%)
+  #C8 = <core::int>[#C4]
+  #C9 = null
+  #C10 = <dynamic>[#C4, #C9]
+  #C11 = core::_ImmutableMap<core::int, core::Null?> {_kvPairs:#C10}
+  #C12 = col::_UnmodifiableSet<core::int> {_map:#C11}
+  #C13 = "foo"
+  #C14 = <dynamic>[#C4, #C13]
+  #C15 = core::_ImmutableMap<core::int, core::String> {_kvPairs:#C14}
+  #C16 = false
+  #C17 = TypeLiteralConstant(dart.core::Object*)
+  #C18 = partial-instantiation con::id <core::int*>
+  #C19 = con::Class<core::int*> {field:#C4}
+  #C20 = TypeLiteralConstant((dynamic) →* dynamic)
+  #C21 = TypeLiteralConstant(<T extends dart.core::Object* = dynamic>(T*) →* T*)
+  #C22 = <core::int*>[#C4]
+  #C23 = core::_ImmutableMap<core::int*, core::Null?> {_kvPairs:#C10}
+  #C24 = col::_UnmodifiableSet<core::int*> {_map:#C23}
+  #C25 = core::_ImmutableMap<core::int*, core::String*> {_kvPairs:#C14}
+  #C26 = tearoff core::identical
+}
diff --git a/pkg/front_end/testcases/nnbd/constants.dart.weak.expect b/pkg/front_end/testcases/nnbd/constants.dart.weak.expect
new file mode 100644
index 0000000..fdb1f8e
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/constants.dart.weak.expect
@@ -0,0 +1,138 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/constants.dart:45:7: Warning: Property 'length' is accessed on 'String?' which is potentially null.
+// Try accessing using ?. instead.
+//     s.length; // This will be an invalid expression in strong mode.
+//       ^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+import "constants_lib.dart" as con;
+
+import "org-dartlang-testcase:///constants_lib.dart" as lib;
+
+typedef F1<invariant T extends core::Object? = dynamic> = (T%) → T%;
+typedef F2 = <T extends core::Object? = dynamic>(T%) → T%;
+static const field core::Type objectTypeLiteral = #C1;
+static const field (core::int) → core::int partialInstantiation = #C3;
+static const field con::Class<core::int> instance = #C5;
+static const field core::Type functionTypeLiteral = #C6;
+static const field core::Type genericFunctionTypeLiteral = #C7;
+static const field core::List<core::int> listLiteral = #C8;
+static const field core::Set<core::int> setLiteral = #C12;
+static const field core::Map<core::int, core::String> mapLiteral = #C15;
+static const field core::List<core::int> listConcatenation = #C8;
+static const field core::Set<core::int> setConcatenation = #C12;
+static const field core::Map<core::int, core::String> mapConcatenation = #C15;
+static const field core::bool objectTypeLiteralIdentical = #C16;
+static const field core::bool partialInstantiationIdentical = #C16;
+static const field core::bool instanceIdentical = #C16;
+static const field core::bool functionTypeLiteralIdentical = #C16;
+static const field core::bool genericFunctionTypeLiteralIdentical = #C16;
+static const field core::bool listLiteralIdentical = #C16;
+static const field core::bool setLiteralIdentical = #C16;
+static const field core::bool mapLiteralIdentical = #C16;
+static const field core::bool listConcatenationIdentical = #C16;
+static const field core::bool setConcatenationIdentical = #C16;
+static const field core::bool mapConcatenationIdentical = #C16;
+static final field core::bool inStrongMode = self::_inStrongMode();
+static method _inStrongMode() → core::bool {
+  (core::String?) → core::Null? f = (core::String? s) → core::Null? {
+    s.{core::String::length};
+  };
+  try {
+    f.call("foo");
+  }
+  on dynamic catch(final dynamic e) {
+    core::print("Running in strong mode.");
+    return true;
+  }
+  core::print("Running in weak mode.");
+  return false;
+}
+static method main() → dynamic {
+  self::test(#C1, #C1);
+  self::test(#C3, #C3);
+  self::test(#C5, #C5);
+  self::test(#C6, #C6);
+  self::test(#C7, #C7);
+  self::test(#C8, #C8);
+  self::test(#C12, #C12);
+  self::test(#C15, #C15);
+  self::test(#C8, #C8);
+  self::test(#C12, #C12);
+  self::test(#C15, #C15);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+}
+static method test(dynamic expected, dynamic actual) → dynamic {
+  core::print("test(${expected}, ${actual})");
+  if(self::inStrongMode) {
+    if(core::identical(expected, actual)) {
+      throw "Unexpected identical for ${expected} and ${actual}";
+    }
+  }
+  else {
+    if(!core::identical(expected, actual)) {
+      throw "Expected ${expected}, actual ${actual}";
+    }
+  }
+}
+
+library;
+import self as con;
+import "dart:core" as core;
+
+typedef F1<invariant T extends core::Object* = dynamic> = (T*) →* T*;
+typedef F2 = <T extends core::Object* = dynamic>(T*) →* T*;
+class Class<T extends core::Object* = dynamic> extends core::Object {
+  final field con::Class::T* field;
+  const constructor •(con::Class::T* field) → con::Class<con::Class::T*>*
+    : con::Class::field = field, super core::Object::•()
+    ;
+}
+static const field core::Type* objectTypeLiteral = #C1;
+static const field (core::Object*, core::Object*) →* core::bool* c2 = #C17;
+static const field (core::int*) →* core::int* partialInstantiation = #C3;
+static const field con::Class<core::int*>* instance = #C5;
+static const field core::Type* functionTypeLiteral = #C6;
+static const field core::Type* genericFunctionTypeLiteral = #C7;
+static const field core::List<core::int*>* listLiteral = #C8;
+static const field core::Set<core::int*>* setLiteral = #C12;
+static const field core::Map<core::int*, core::String*>* mapLiteral = #C15;
+static const field core::List<core::int*>* listConcatenation = #C8;
+static const field core::Set<core::int*>* setConcatenation = #C12;
+static const field core::Map<core::int*, core::String*>* mapConcatenation = #C15;
+static method id<T extends core::Object* = dynamic>(con::id::T* t) → con::id::T*
+  return t;
+
+constants  {
+  #C1 = TypeLiteralConstant(dart.core::Object*)
+  #C2 = tearoff con::id
+  #C3 = partial-instantiation con::id <core::int*>
+  #C4 = 0
+  #C5 = con::Class<core::int*> {field:#C4}
+  #C6 = TypeLiteralConstant((dynamic) →* dynamic)
+  #C7 = TypeLiteralConstant(<T extends dart.core::Object* = dynamic>(T*) →* T*)
+  #C8 = <core::int*>[#C4]
+  #C9 = null
+  #C10 = <dynamic>[#C4, #C9]
+  #C11 = core::_ImmutableMap<core::int*, core::Null?> {_kvPairs:#C10}
+  #C12 = col::_UnmodifiableSet<core::int*> {_map:#C11}
+  #C13 = "foo"
+  #C14 = <dynamic>[#C4, #C13]
+  #C15 = core::_ImmutableMap<core::int*, core::String*> {_kvPairs:#C14}
+  #C16 = true
+  #C17 = tearoff core::identical
+}
diff --git a/pkg/front_end/testcases/nnbd/constants.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/constants.dart.weak.transformed.expect
new file mode 100644
index 0000000..fdb1f8e
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/constants.dart.weak.transformed.expect
@@ -0,0 +1,138 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/constants.dart:45:7: Warning: Property 'length' is accessed on 'String?' which is potentially null.
+// Try accessing using ?. instead.
+//     s.length; // This will be an invalid expression in strong mode.
+//       ^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+import "constants_lib.dart" as con;
+
+import "org-dartlang-testcase:///constants_lib.dart" as lib;
+
+typedef F1<invariant T extends core::Object? = dynamic> = (T%) → T%;
+typedef F2 = <T extends core::Object? = dynamic>(T%) → T%;
+static const field core::Type objectTypeLiteral = #C1;
+static const field (core::int) → core::int partialInstantiation = #C3;
+static const field con::Class<core::int> instance = #C5;
+static const field core::Type functionTypeLiteral = #C6;
+static const field core::Type genericFunctionTypeLiteral = #C7;
+static const field core::List<core::int> listLiteral = #C8;
+static const field core::Set<core::int> setLiteral = #C12;
+static const field core::Map<core::int, core::String> mapLiteral = #C15;
+static const field core::List<core::int> listConcatenation = #C8;
+static const field core::Set<core::int> setConcatenation = #C12;
+static const field core::Map<core::int, core::String> mapConcatenation = #C15;
+static const field core::bool objectTypeLiteralIdentical = #C16;
+static const field core::bool partialInstantiationIdentical = #C16;
+static const field core::bool instanceIdentical = #C16;
+static const field core::bool functionTypeLiteralIdentical = #C16;
+static const field core::bool genericFunctionTypeLiteralIdentical = #C16;
+static const field core::bool listLiteralIdentical = #C16;
+static const field core::bool setLiteralIdentical = #C16;
+static const field core::bool mapLiteralIdentical = #C16;
+static const field core::bool listConcatenationIdentical = #C16;
+static const field core::bool setConcatenationIdentical = #C16;
+static const field core::bool mapConcatenationIdentical = #C16;
+static final field core::bool inStrongMode = self::_inStrongMode();
+static method _inStrongMode() → core::bool {
+  (core::String?) → core::Null? f = (core::String? s) → core::Null? {
+    s.{core::String::length};
+  };
+  try {
+    f.call("foo");
+  }
+  on dynamic catch(final dynamic e) {
+    core::print("Running in strong mode.");
+    return true;
+  }
+  core::print("Running in weak mode.");
+  return false;
+}
+static method main() → dynamic {
+  self::test(#C1, #C1);
+  self::test(#C3, #C3);
+  self::test(#C5, #C5);
+  self::test(#C6, #C6);
+  self::test(#C7, #C7);
+  self::test(#C8, #C8);
+  self::test(#C12, #C12);
+  self::test(#C15, #C15);
+  self::test(#C8, #C8);
+  self::test(#C12, #C12);
+  self::test(#C15, #C15);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+  self::test(true, #C16);
+}
+static method test(dynamic expected, dynamic actual) → dynamic {
+  core::print("test(${expected}, ${actual})");
+  if(self::inStrongMode) {
+    if(core::identical(expected, actual)) {
+      throw "Unexpected identical for ${expected} and ${actual}";
+    }
+  }
+  else {
+    if(!core::identical(expected, actual)) {
+      throw "Expected ${expected}, actual ${actual}";
+    }
+  }
+}
+
+library;
+import self as con;
+import "dart:core" as core;
+
+typedef F1<invariant T extends core::Object* = dynamic> = (T*) →* T*;
+typedef F2 = <T extends core::Object* = dynamic>(T*) →* T*;
+class Class<T extends core::Object* = dynamic> extends core::Object {
+  final field con::Class::T* field;
+  const constructor •(con::Class::T* field) → con::Class<con::Class::T*>*
+    : con::Class::field = field, super core::Object::•()
+    ;
+}
+static const field core::Type* objectTypeLiteral = #C1;
+static const field (core::Object*, core::Object*) →* core::bool* c2 = #C17;
+static const field (core::int*) →* core::int* partialInstantiation = #C3;
+static const field con::Class<core::int*>* instance = #C5;
+static const field core::Type* functionTypeLiteral = #C6;
+static const field core::Type* genericFunctionTypeLiteral = #C7;
+static const field core::List<core::int*>* listLiteral = #C8;
+static const field core::Set<core::int*>* setLiteral = #C12;
+static const field core::Map<core::int*, core::String*>* mapLiteral = #C15;
+static const field core::List<core::int*>* listConcatenation = #C8;
+static const field core::Set<core::int*>* setConcatenation = #C12;
+static const field core::Map<core::int*, core::String*>* mapConcatenation = #C15;
+static method id<T extends core::Object* = dynamic>(con::id::T* t) → con::id::T*
+  return t;
+
+constants  {
+  #C1 = TypeLiteralConstant(dart.core::Object*)
+  #C2 = tearoff con::id
+  #C3 = partial-instantiation con::id <core::int*>
+  #C4 = 0
+  #C5 = con::Class<core::int*> {field:#C4}
+  #C6 = TypeLiteralConstant((dynamic) →* dynamic)
+  #C7 = TypeLiteralConstant(<T extends dart.core::Object* = dynamic>(T*) →* T*)
+  #C8 = <core::int*>[#C4]
+  #C9 = null
+  #C10 = <dynamic>[#C4, #C9]
+  #C11 = core::_ImmutableMap<core::int*, core::Null?> {_kvPairs:#C10}
+  #C12 = col::_UnmodifiableSet<core::int*> {_map:#C11}
+  #C13 = "foo"
+  #C14 = <dynamic>[#C4, #C13]
+  #C15 = core::_ImmutableMap<core::int*, core::String*> {_kvPairs:#C14}
+  #C16 = true
+  #C17 = tearoff core::identical
+}
diff --git a/pkg/front_end/testcases/nnbd/constants_lib.dart b/pkg/front_end/testcases/nnbd/constants_lib.dart
new file mode 100644
index 0000000..afa7bf1
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/constants_lib.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// @dart=2.6
+
+class Class<T> {
+  final T field;
+
+  const Class(this.field);
+}
+
+T id<T>(T t) => t;
+
+typedef F1<T> = T Function(T);
+typedef F2 = T Function<T>(T);
+
+const objectTypeLiteral = Object;
+const c2 = identical;
+const int Function(int) partialInstantiation = id;
+const instance = const Class<int>(0);
+const functionTypeLiteral = F1;
+const genericFunctionTypeLiteral = F2;
+const listLiteral = <int>[0];
+const setLiteral = <int>{0};
+const mapLiteral = <int, String>{0: 'foo'};
+const listConcatenation = <int>[...listLiteral];
+const setConcatenation = <int>{...setLiteral};
+const mapConcatenation = <int, String>{...mapLiteral};
diff --git a/pkg/front_end/testcases/nnbd/demote_closure_types.dart b/pkg/front_end/testcases/nnbd/demote_closure_types.dart
new file mode 100644
index 0000000..d472317
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/demote_closure_types.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2020, 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.
+
+method<T>(T a, T b) {
+  if (a is String) {
+    var f = () => a;
+    String s = f();
+  }
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/demote_closure_types.dart.outline.expect b/pkg/front_end/testcases/nnbd/demote_closure_types.dart.outline.expect
new file mode 100644
index 0000000..c33f97f
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/demote_closure_types.dart.outline.expect
@@ -0,0 +1,8 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method method<T extends core::Object? = dynamic>(self::method::T% a, self::method::T% b) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/nnbd/demote_closure_types.dart.strong.expect b/pkg/front_end/testcases/nnbd/demote_closure_types.dart.strong.expect
new file mode 100644
index 0000000..3dac54e
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/demote_closure_types.dart.strong.expect
@@ -0,0 +1,20 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/demote_closure_types.dart:8:17: Error: A value of type 'T' can't be assigned to a variable of type 'String'.
+//     String s = f();
+//                 ^
+//
+import self as self;
+import "dart:core" as core;
+
+static method method<T extends core::Object? = dynamic>(self::method::T% a, self::method::T% b) → dynamic {
+  if(a is{ForNonNullableByDefault} core::String) {
+    () → self::method::T% f = () → self::method::T% => a{self::method::T% & core::String /* '%' & '!' = '!' */};
+    core::String s = let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/demote_closure_types.dart:8:17: Error: A value of type 'T' can't be assigned to a variable of type 'String'.
+    String s = f();
+                ^" in f.call() as{TypeError,ForNonNullableByDefault} core::String;
+  }
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/demote_closure_types.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/demote_closure_types.dart.strong.transformed.expect
new file mode 100644
index 0000000..3dac54e
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/demote_closure_types.dart.strong.transformed.expect
@@ -0,0 +1,20 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/demote_closure_types.dart:8:17: Error: A value of type 'T' can't be assigned to a variable of type 'String'.
+//     String s = f();
+//                 ^
+//
+import self as self;
+import "dart:core" as core;
+
+static method method<T extends core::Object? = dynamic>(self::method::T% a, self::method::T% b) → dynamic {
+  if(a is{ForNonNullableByDefault} core::String) {
+    () → self::method::T% f = () → self::method::T% => a{self::method::T% & core::String /* '%' & '!' = '!' */};
+    core::String s = let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/demote_closure_types.dart:8:17: Error: A value of type 'T' can't be assigned to a variable of type 'String'.
+    String s = f();
+                ^" in f.call() as{TypeError,ForNonNullableByDefault} core::String;
+  }
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/demote_closure_types.dart.weak.expect b/pkg/front_end/testcases/nnbd/demote_closure_types.dart.weak.expect
new file mode 100644
index 0000000..3dac54e
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/demote_closure_types.dart.weak.expect
@@ -0,0 +1,20 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/demote_closure_types.dart:8:17: Error: A value of type 'T' can't be assigned to a variable of type 'String'.
+//     String s = f();
+//                 ^
+//
+import self as self;
+import "dart:core" as core;
+
+static method method<T extends core::Object? = dynamic>(self::method::T% a, self::method::T% b) → dynamic {
+  if(a is{ForNonNullableByDefault} core::String) {
+    () → self::method::T% f = () → self::method::T% => a{self::method::T% & core::String /* '%' & '!' = '!' */};
+    core::String s = let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/demote_closure_types.dart:8:17: Error: A value of type 'T' can't be assigned to a variable of type 'String'.
+    String s = f();
+                ^" in f.call() as{TypeError,ForNonNullableByDefault} core::String;
+  }
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/demote_closure_types.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/demote_closure_types.dart.weak.transformed.expect
new file mode 100644
index 0000000..3dac54e
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/demote_closure_types.dart.weak.transformed.expect
@@ -0,0 +1,20 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/demote_closure_types.dart:8:17: Error: A value of type 'T' can't be assigned to a variable of type 'String'.
+//     String s = f();
+//                 ^
+//
+import self as self;
+import "dart:core" as core;
+
+static method method<T extends core::Object? = dynamic>(self::method::T% a, self::method::T% b) → dynamic {
+  if(a is{ForNonNullableByDefault} core::String) {
+    () → self::method::T% f = () → self::method::T% => a{self::method::T% & core::String /* '%' & '!' = '!' */};
+    core::String s = let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/demote_closure_types.dart:8:17: Error: A value of type 'T' can't be assigned to a variable of type 'String'.
+    String s = f();
+                ^" in f.call() as{TypeError,ForNonNullableByDefault} core::String;
+  }
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/infer_from_opt_in.dart b/pkg/front_end/testcases/nnbd/infer_from_opt_in.dart
new file mode 100644
index 0000000..3810516
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/infer_from_opt_in.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2020, 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 'infer_from_opt_in_lib.dart';
+
+reify<T>(T arg) => T;
+
+main() {
+  Foo x = new Foo();
+  var y = new Foo();
+  var z = () => createFoo();
+  callback((x) => x);
+  print(reify(x));
+  print(reify(y));
+  print(reify(z));
+}
diff --git a/pkg/front_end/testcases/nnbd/infer_from_opt_in.dart.outline.expect b/pkg/front_end/testcases/nnbd/infer_from_opt_in.dart.outline.expect
new file mode 100644
index 0000000..4706d9d
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/infer_from_opt_in.dart.outline.expect
@@ -0,0 +1,23 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///infer_from_opt_in_lib.dart";
+
+static method reify<T extends core::Object? = dynamic>(self::reify::T% arg) → dynamic
+  ;
+static method main() → dynamic
+  ;
+
+library;
+import self as self2;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  synthetic constructor •() → self2::Foo
+    ;
+}
+static method createFoo() → self2::Foo
+  ;
+static method callback((self2::Foo?) → self2::Foo? f) → void
+  ;
diff --git a/pkg/front_end/testcases/nnbd/infer_from_opt_in.dart.strong.expect b/pkg/front_end/testcases/nnbd/infer_from_opt_in.dart.strong.expect
new file mode 100644
index 0000000..840dfca
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/infer_from_opt_in.dart.strong.expect
@@ -0,0 +1,31 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "infer_from_opt_in_lib.dart" as inf;
+
+import "org-dartlang-testcase:///infer_from_opt_in_lib.dart";
+
+static method reify<T extends core::Object? = dynamic>(self::reify::T% arg) → dynamic
+  return self::reify::T%;
+static method main() → dynamic {
+  inf::Foo x = new inf::Foo::•();
+  inf::Foo y = new inf::Foo::•();
+  () → inf::Foo z = () → inf::Foo => inf::createFoo();
+  inf::callback((inf::Foo? x) → inf::Foo? => x);
+  core::print(self::reify<inf::Foo>(x));
+  core::print(self::reify<inf::Foo>(y));
+  core::print(self::reify<() → inf::Foo>(z));
+}
+
+library;
+import self as inf;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  synthetic constructor •() → inf::Foo
+    : super core::Object::•()
+    ;
+}
+static method createFoo() → inf::Foo
+  return new inf::Foo::•();
+static method callback((inf::Foo?) → inf::Foo? f) → void {}
diff --git a/pkg/front_end/testcases/nnbd/infer_from_opt_in.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/infer_from_opt_in.dart.strong.transformed.expect
new file mode 100644
index 0000000..840dfca
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/infer_from_opt_in.dart.strong.transformed.expect
@@ -0,0 +1,31 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "infer_from_opt_in_lib.dart" as inf;
+
+import "org-dartlang-testcase:///infer_from_opt_in_lib.dart";
+
+static method reify<T extends core::Object? = dynamic>(self::reify::T% arg) → dynamic
+  return self::reify::T%;
+static method main() → dynamic {
+  inf::Foo x = new inf::Foo::•();
+  inf::Foo y = new inf::Foo::•();
+  () → inf::Foo z = () → inf::Foo => inf::createFoo();
+  inf::callback((inf::Foo? x) → inf::Foo? => x);
+  core::print(self::reify<inf::Foo>(x));
+  core::print(self::reify<inf::Foo>(y));
+  core::print(self::reify<() → inf::Foo>(z));
+}
+
+library;
+import self as inf;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  synthetic constructor •() → inf::Foo
+    : super core::Object::•()
+    ;
+}
+static method createFoo() → inf::Foo
+  return new inf::Foo::•();
+static method callback((inf::Foo?) → inf::Foo? f) → void {}
diff --git a/pkg/front_end/testcases/nnbd/infer_from_opt_in.dart.weak.expect b/pkg/front_end/testcases/nnbd/infer_from_opt_in.dart.weak.expect
new file mode 100644
index 0000000..840dfca
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/infer_from_opt_in.dart.weak.expect
@@ -0,0 +1,31 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "infer_from_opt_in_lib.dart" as inf;
+
+import "org-dartlang-testcase:///infer_from_opt_in_lib.dart";
+
+static method reify<T extends core::Object? = dynamic>(self::reify::T% arg) → dynamic
+  return self::reify::T%;
+static method main() → dynamic {
+  inf::Foo x = new inf::Foo::•();
+  inf::Foo y = new inf::Foo::•();
+  () → inf::Foo z = () → inf::Foo => inf::createFoo();
+  inf::callback((inf::Foo? x) → inf::Foo? => x);
+  core::print(self::reify<inf::Foo>(x));
+  core::print(self::reify<inf::Foo>(y));
+  core::print(self::reify<() → inf::Foo>(z));
+}
+
+library;
+import self as inf;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  synthetic constructor •() → inf::Foo
+    : super core::Object::•()
+    ;
+}
+static method createFoo() → inf::Foo
+  return new inf::Foo::•();
+static method callback((inf::Foo?) → inf::Foo? f) → void {}
diff --git a/pkg/front_end/testcases/nnbd/infer_from_opt_in.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/infer_from_opt_in.dart.weak.transformed.expect
new file mode 100644
index 0000000..840dfca
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/infer_from_opt_in.dart.weak.transformed.expect
@@ -0,0 +1,31 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "infer_from_opt_in_lib.dart" as inf;
+
+import "org-dartlang-testcase:///infer_from_opt_in_lib.dart";
+
+static method reify<T extends core::Object? = dynamic>(self::reify::T% arg) → dynamic
+  return self::reify::T%;
+static method main() → dynamic {
+  inf::Foo x = new inf::Foo::•();
+  inf::Foo y = new inf::Foo::•();
+  () → inf::Foo z = () → inf::Foo => inf::createFoo();
+  inf::callback((inf::Foo? x) → inf::Foo? => x);
+  core::print(self::reify<inf::Foo>(x));
+  core::print(self::reify<inf::Foo>(y));
+  core::print(self::reify<() → inf::Foo>(z));
+}
+
+library;
+import self as inf;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  synthetic constructor •() → inf::Foo
+    : super core::Object::•()
+    ;
+}
+static method createFoo() → inf::Foo
+  return new inf::Foo::•();
+static method callback((inf::Foo?) → inf::Foo? f) → void {}
diff --git a/pkg/front_end/testcases/nnbd/infer_from_opt_in_lib.dart b/pkg/front_end/testcases/nnbd/infer_from_opt_in_lib.dart
new file mode 100644
index 0000000..746d4e9
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/infer_from_opt_in_lib.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2020, 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.
+
+class Foo {}
+
+Foo createFoo() => new Foo();
+
+void callback(Foo? Function(Foo?) f) {}
diff --git a/pkg/front_end/testcases/nnbd/infer_from_opt_out.dart b/pkg/front_end/testcases/nnbd/infer_from_opt_out.dart
new file mode 100644
index 0000000..97e9a88
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/infer_from_opt_out.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2020, 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 'infer_from_opt_out_lib.dart';
+
+reify<T>(T arg) => T;
+
+main() {
+  Foo x = new Foo();
+  var y = new Foo();
+  var z = () => createFoo();
+  callback((x) => x);
+  print(reify(x));
+  print(reify(y));
+  print(reify(z));
+}
diff --git a/pkg/front_end/testcases/nnbd/infer_from_opt_out.dart.outline.expect b/pkg/front_end/testcases/nnbd/infer_from_opt_out.dart.outline.expect
new file mode 100644
index 0000000..d160bcf
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/infer_from_opt_out.dart.outline.expect
@@ -0,0 +1,23 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///infer_from_opt_out_lib.dart";
+
+static method reify<T extends core::Object? = dynamic>(self::reify::T% arg) → dynamic
+  ;
+static method main() → dynamic
+  ;
+
+library;
+import self as self2;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  synthetic constructor •() → self2::Foo*
+    ;
+}
+static method createFoo() → self2::Foo*
+  ;
+static method callback((self2::Foo*) →* self2::Foo* f) → void
+  ;
diff --git a/pkg/front_end/testcases/nnbd/infer_from_opt_out.dart.strong.expect b/pkg/front_end/testcases/nnbd/infer_from_opt_out.dart.strong.expect
new file mode 100644
index 0000000..b217fb1
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/infer_from_opt_out.dart.strong.expect
@@ -0,0 +1,31 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "infer_from_opt_out_lib.dart" as inf;
+
+import "org-dartlang-testcase:///infer_from_opt_out_lib.dart";
+
+static method reify<T extends core::Object? = dynamic>(self::reify::T% arg) → dynamic
+  return self::reify::T%;
+static method main() → dynamic {
+  inf::Foo x = new inf::Foo::•();
+  inf::Foo y = new inf::Foo::•();
+  () → inf::Foo z = () → inf::Foo => inf::createFoo();
+  inf::callback((inf::Foo x) → inf::Foo => x);
+  core::print(self::reify<inf::Foo>(x));
+  core::print(self::reify<inf::Foo>(y));
+  core::print(self::reify<() → inf::Foo>(z));
+}
+
+library;
+import self as inf;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  synthetic constructor •() → inf::Foo*
+    : super core::Object::•()
+    ;
+}
+static method createFoo() → inf::Foo*
+  return new inf::Foo::•();
+static method callback((inf::Foo*) →* inf::Foo* f) → void {}
diff --git a/pkg/front_end/testcases/nnbd/infer_from_opt_out.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/infer_from_opt_out.dart.strong.transformed.expect
new file mode 100644
index 0000000..b217fb1
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/infer_from_opt_out.dart.strong.transformed.expect
@@ -0,0 +1,31 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "infer_from_opt_out_lib.dart" as inf;
+
+import "org-dartlang-testcase:///infer_from_opt_out_lib.dart";
+
+static method reify<T extends core::Object? = dynamic>(self::reify::T% arg) → dynamic
+  return self::reify::T%;
+static method main() → dynamic {
+  inf::Foo x = new inf::Foo::•();
+  inf::Foo y = new inf::Foo::•();
+  () → inf::Foo z = () → inf::Foo => inf::createFoo();
+  inf::callback((inf::Foo x) → inf::Foo => x);
+  core::print(self::reify<inf::Foo>(x));
+  core::print(self::reify<inf::Foo>(y));
+  core::print(self::reify<() → inf::Foo>(z));
+}
+
+library;
+import self as inf;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  synthetic constructor •() → inf::Foo*
+    : super core::Object::•()
+    ;
+}
+static method createFoo() → inf::Foo*
+  return new inf::Foo::•();
+static method callback((inf::Foo*) →* inf::Foo* f) → void {}
diff --git a/pkg/front_end/testcases/nnbd/infer_from_opt_out.dart.weak.expect b/pkg/front_end/testcases/nnbd/infer_from_opt_out.dart.weak.expect
new file mode 100644
index 0000000..b217fb1
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/infer_from_opt_out.dart.weak.expect
@@ -0,0 +1,31 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "infer_from_opt_out_lib.dart" as inf;
+
+import "org-dartlang-testcase:///infer_from_opt_out_lib.dart";
+
+static method reify<T extends core::Object? = dynamic>(self::reify::T% arg) → dynamic
+  return self::reify::T%;
+static method main() → dynamic {
+  inf::Foo x = new inf::Foo::•();
+  inf::Foo y = new inf::Foo::•();
+  () → inf::Foo z = () → inf::Foo => inf::createFoo();
+  inf::callback((inf::Foo x) → inf::Foo => x);
+  core::print(self::reify<inf::Foo>(x));
+  core::print(self::reify<inf::Foo>(y));
+  core::print(self::reify<() → inf::Foo>(z));
+}
+
+library;
+import self as inf;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  synthetic constructor •() → inf::Foo*
+    : super core::Object::•()
+    ;
+}
+static method createFoo() → inf::Foo*
+  return new inf::Foo::•();
+static method callback((inf::Foo*) →* inf::Foo* f) → void {}
diff --git a/pkg/front_end/testcases/nnbd/infer_from_opt_out.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/infer_from_opt_out.dart.weak.transformed.expect
new file mode 100644
index 0000000..b217fb1
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/infer_from_opt_out.dart.weak.transformed.expect
@@ -0,0 +1,31 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "infer_from_opt_out_lib.dart" as inf;
+
+import "org-dartlang-testcase:///infer_from_opt_out_lib.dart";
+
+static method reify<T extends core::Object? = dynamic>(self::reify::T% arg) → dynamic
+  return self::reify::T%;
+static method main() → dynamic {
+  inf::Foo x = new inf::Foo::•();
+  inf::Foo y = new inf::Foo::•();
+  () → inf::Foo z = () → inf::Foo => inf::createFoo();
+  inf::callback((inf::Foo x) → inf::Foo => x);
+  core::print(self::reify<inf::Foo>(x));
+  core::print(self::reify<inf::Foo>(y));
+  core::print(self::reify<() → inf::Foo>(z));
+}
+
+library;
+import self as inf;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  synthetic constructor •() → inf::Foo*
+    : super core::Object::•()
+    ;
+}
+static method createFoo() → inf::Foo*
+  return new inf::Foo::•();
+static method callback((inf::Foo*) →* inf::Foo* f) → void {}
diff --git a/pkg/front_end/testcases/nnbd/infer_from_opt_out_lib.dart b/pkg/front_end/testcases/nnbd/infer_from_opt_out_lib.dart
new file mode 100644
index 0000000..397c4dc
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/infer_from_opt_out_lib.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// @dart = 2.6
+class Foo {}
+
+Foo createFoo() => new Foo();
+
+void callback(Foo Function(Foo) f) {}
diff --git a/pkg/front_end/testcases/nnbd/issue_39286_2.dart b/pkg/front_end/testcases/nnbd/issue_39286_2.dart
index b241823..739ab6d 100644
--- a/pkg/front_end/testcases/nnbd/issue_39286_2.dart
+++ b/pkg/front_end/testcases/nnbd/issue_39286_2.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 class C {
-  int y;
+  int y = 42;
   D? f() => new D();
   C h() => this;
 }
diff --git a/pkg/front_end/testcases/nnbd/issue_39286_2.dart.strong.expect b/pkg/front_end/testcases/nnbd/issue_39286_2.dart.strong.expect
index 32274dd..57d21df 100644
--- a/pkg/front_end/testcases/nnbd/issue_39286_2.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/issue_39286_2.dart.strong.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 class C extends core::Object {
-  field core::int y = null;
+  field core::int y = 42;
   synthetic constructor •() → self::C
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/nnbd/issue_39286_2.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/issue_39286_2.dart.strong.transformed.expect
index 32274dd..57d21df 100644
--- a/pkg/front_end/testcases/nnbd/issue_39286_2.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/issue_39286_2.dart.strong.transformed.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 class C extends core::Object {
-  field core::int y = null;
+  field core::int y = 42;
   synthetic constructor •() → self::C
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/nnbd/issue_39286_2.dart.weak.expect b/pkg/front_end/testcases/nnbd/issue_39286_2.dart.weak.expect
index 32274dd..57d21df 100644
--- a/pkg/front_end/testcases/nnbd/issue_39286_2.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/issue_39286_2.dart.weak.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 class C extends core::Object {
-  field core::int y = null;
+  field core::int y = 42;
   synthetic constructor •() → self::C
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/nnbd/issue_39286_2.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/issue_39286_2.dart.weak.transformed.expect
index 32274dd..57d21df 100644
--- a/pkg/front_end/testcases/nnbd/issue_39286_2.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/issue_39286_2.dart.weak.transformed.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 class C extends core::Object {
-  field core::int y = null;
+  field core::int y = 42;
   synthetic constructor •() → self::C
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/nnbd/later.dart.strong.expect b/pkg/front_end/testcases/nnbd/later.dart.strong.expect
index 3327046..e96accc 100644
--- a/pkg/front_end/testcases/nnbd/later.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/later.dart.strong.expect
@@ -55,6 +55,13 @@
 //   late String s2 = '${fisk}${await hest()}${fisk}';
 //                              ^^^^^
 //
+// pkg/front_end/testcases/nnbd/later.dart:46:9: Error: Constructor is marked 'const' so fields can't be late.
+//   const B();
+//         ^
+// pkg/front_end/testcases/nnbd/later.dart:44:18: Context: Field is late, but constructor is 'const'.
+//   late final int x = 42;
+//                  ^
+//
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
@@ -110,7 +117,7 @@
   } =>#t1;
 }
 static method hest() → dynamic async {
-  await for (core::String s in asy::Stream::fromIterable<core::String>(<core::String*>["hest"])) {
+  await for (core::String s in asy::Stream::fromIterable<core::String>(<core::String>["hest"])) {
     core::print(s);
   }
   return "hest";
diff --git a/pkg/front_end/testcases/nnbd/later.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/later.dart.strong.transformed.expect
index f87102a..982ee0c 100644
--- a/pkg/front_end/testcases/nnbd/later.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/later.dart.strong.transformed.expect
@@ -55,6 +55,13 @@
 //   late String s2 = '${fisk}${await hest()}${fisk}';
 //                              ^^^^^
 //
+// pkg/front_end/testcases/nnbd/later.dart:46:9: Error: Constructor is marked 'const' so fields can't be late.
+//   const B();
+//         ^
+// pkg/front_end/testcases/nnbd/later.dart:44:18: Context: Field is late, but constructor is 'const'.
+//   late final int x = 42;
+//                  ^
+//
 import self as self;
 import "dart:core" as core;
 import "dart:_internal" as _in;
@@ -133,7 +140,7 @@
       #L1:
       {
         {
-          dynamic :stream = asy::Stream::fromIterable<core::String>(<core::String*>["hest"]);
+          dynamic :stream = asy::Stream::fromIterable<core::String>(<core::String>["hest"]);
           asy::_asyncStarListenHelper(:stream, :async_op);
           asy::_StreamIterator<core::String>? :for-iterator = new asy::_StreamIterator::•<core::String>(:stream);
           try
diff --git a/pkg/front_end/testcases/nnbd/later.dart.weak.expect b/pkg/front_end/testcases/nnbd/later.dart.weak.expect
index 3327046..09e7b68 100644
--- a/pkg/front_end/testcases/nnbd/later.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/later.dart.weak.expect
@@ -55,6 +55,13 @@
 //   late String s2 = '${fisk}${await hest()}${fisk}';
 //                              ^^^^^
 //
+// pkg/front_end/testcases/nnbd/later.dart:46:9: Warning: Constructor is marked 'const' and some fields are late.
+//   const B();
+//         ^
+// pkg/front_end/testcases/nnbd/later.dart:44:18: Context: Field is late, but constructor is 'const'.
+//   late final int x = 42;
+//                  ^
+//
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
@@ -110,7 +117,7 @@
   } =>#t1;
 }
 static method hest() → dynamic async {
-  await for (core::String s in asy::Stream::fromIterable<core::String>(<core::String*>["hest"])) {
+  await for (core::String s in asy::Stream::fromIterable<core::String>(<core::String>["hest"])) {
     core::print(s);
   }
   return "hest";
diff --git a/pkg/front_end/testcases/nnbd/later.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/later.dart.weak.transformed.expect
index f87102a..c96bcbb 100644
--- a/pkg/front_end/testcases/nnbd/later.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/later.dart.weak.transformed.expect
@@ -55,6 +55,13 @@
 //   late String s2 = '${fisk}${await hest()}${fisk}';
 //                              ^^^^^
 //
+// pkg/front_end/testcases/nnbd/later.dart:46:9: Warning: Constructor is marked 'const' and some fields are late.
+//   const B();
+//         ^
+// pkg/front_end/testcases/nnbd/later.dart:44:18: Context: Field is late, but constructor is 'const'.
+//   late final int x = 42;
+//                  ^
+//
 import self as self;
 import "dart:core" as core;
 import "dart:_internal" as _in;
@@ -133,7 +140,7 @@
       #L1:
       {
         {
-          dynamic :stream = asy::Stream::fromIterable<core::String>(<core::String*>["hest"]);
+          dynamic :stream = asy::Stream::fromIterable<core::String>(<core::String>["hest"]);
           asy::_asyncStarListenHelper(:stream, :async_op);
           asy::_StreamIterator<core::String>? :for-iterator = new asy::_StreamIterator::•<core::String>(:stream);
           try
diff --git a/pkg/front_end/testcases/nnbd/list_constructor.dart b/pkg/front_end/testcases/nnbd/list_constructor.dart
index 95543ad..dd7dbce 100644
--- a/pkg/front_end/testcases/nnbd/list_constructor.dart
+++ b/pkg/front_end/testcases/nnbd/list_constructor.dart
@@ -8,6 +8,7 @@
 foo<T extends Object?>() {
   new List<T>(42);
   new List<int?>(42);
+  new List<int>(42);
 }
 
 main() {}
diff --git a/pkg/front_end/testcases/nnbd/list_constructor.dart.strong.expect b/pkg/front_end/testcases/nnbd/list_constructor.dart.strong.expect
index 638b5be..788fdeb 100644
--- a/pkg/front_end/testcases/nnbd/list_constructor.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/list_constructor.dart.strong.expect
@@ -1,9 +1,37 @@
 library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/list_constructor.dart:9:7: Error: Can't use the default List constructor.
+// Try using List.filled instead.
+//   new List<T>(42);
+//       ^
+//
+// pkg/front_end/testcases/nnbd/list_constructor.dart:10:7: Error: Can't use the default List constructor.
+// Try using List.filled instead.
+//   new List<int?>(42);
+//       ^
+//
+// pkg/front_end/testcases/nnbd/list_constructor.dart:11:7: Error: Can't use the default List constructor.
+// Try using List.filled instead.
+//   new List<int>(42);
+//       ^
+//
 import self as self;
 import "dart:core" as core;
 
 static method foo<T extends core::Object? = core::Object?>() → dynamic {
-  core::List::•<self::foo::T%>(42);
-  core::List::•<core::int?>(42);
+  let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/list_constructor.dart:9:7: Error: Can't use the default List constructor.
+Try using List.filled instead.
+  new List<T>(42);
+      ^" in core::List::•<self::foo::T%>(42);
+  let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/nnbd/list_constructor.dart:10:7: Error: Can't use the default List constructor.
+Try using List.filled instead.
+  new List<int?>(42);
+      ^" in core::List::•<core::int?>(42);
+  let final<BottomType> #t3 = invalid-expression "pkg/front_end/testcases/nnbd/list_constructor.dart:11:7: Error: Can't use the default List constructor.
+Try using List.filled instead.
+  new List<int>(42);
+      ^" in core::List::•<core::int>(42);
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/list_constructor.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/list_constructor.dart.strong.transformed.expect
index 1f48f90..64a625b 100644
--- a/pkg/front_end/testcases/nnbd/list_constructor.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/list_constructor.dart.strong.transformed.expect
@@ -1,9 +1,37 @@
 library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/list_constructor.dart:9:7: Error: Can't use the default List constructor.
+// Try using List.filled instead.
+//   new List<T>(42);
+//       ^
+//
+// pkg/front_end/testcases/nnbd/list_constructor.dart:10:7: Error: Can't use the default List constructor.
+// Try using List.filled instead.
+//   new List<int?>(42);
+//       ^
+//
+// pkg/front_end/testcases/nnbd/list_constructor.dart:11:7: Error: Can't use the default List constructor.
+// Try using List.filled instead.
+//   new List<int>(42);
+//       ^
+//
 import self as self;
 import "dart:core" as core;
 
 static method foo<T extends core::Object? = core::Object?>() → dynamic {
-  core::_List::•<self::foo::T%>(42);
-  core::_List::•<core::int?>(42);
+  let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/list_constructor.dart:9:7: Error: Can't use the default List constructor.
+Try using List.filled instead.
+  new List<T>(42);
+      ^" in core::_List::•<self::foo::T%>(42);
+  let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/nnbd/list_constructor.dart:10:7: Error: Can't use the default List constructor.
+Try using List.filled instead.
+  new List<int?>(42);
+      ^" in core::_List::•<core::int?>(42);
+  let final<BottomType> #t3 = invalid-expression "pkg/front_end/testcases/nnbd/list_constructor.dart:11:7: Error: Can't use the default List constructor.
+Try using List.filled instead.
+  new List<int>(42);
+      ^" in core::_List::•<core::int>(42);
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/list_constructor.dart.weak.expect b/pkg/front_end/testcases/nnbd/list_constructor.dart.weak.expect
index 638b5be..e72bdc9 100644
--- a/pkg/front_end/testcases/nnbd/list_constructor.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/list_constructor.dart.weak.expect
@@ -1,9 +1,28 @@
 library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/list_constructor.dart:9:7: Warning: Using the default List constructor.
+// Try using List.filled instead.
+//   new List<T>(42);
+//       ^
+//
+// pkg/front_end/testcases/nnbd/list_constructor.dart:10:7: Warning: Using the default List constructor.
+// Try using List.filled instead.
+//   new List<int?>(42);
+//       ^
+//
+// pkg/front_end/testcases/nnbd/list_constructor.dart:11:7: Warning: Using the default List constructor.
+// Try using List.filled instead.
+//   new List<int>(42);
+//       ^
+//
 import self as self;
 import "dart:core" as core;
 
 static method foo<T extends core::Object? = core::Object?>() → dynamic {
   core::List::•<self::foo::T%>(42);
   core::List::•<core::int?>(42);
+  core::List::•<core::int>(42);
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/list_constructor.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/list_constructor.dart.weak.transformed.expect
index 1f48f90..eda5511 100644
--- a/pkg/front_end/testcases/nnbd/list_constructor.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/list_constructor.dart.weak.transformed.expect
@@ -1,9 +1,28 @@
 library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/list_constructor.dart:9:7: Warning: Using the default List constructor.
+// Try using List.filled instead.
+//   new List<T>(42);
+//       ^
+//
+// pkg/front_end/testcases/nnbd/list_constructor.dart:10:7: Warning: Using the default List constructor.
+// Try using List.filled instead.
+//   new List<int?>(42);
+//       ^
+//
+// pkg/front_end/testcases/nnbd/list_constructor.dart:11:7: Warning: Using the default List constructor.
+// Try using List.filled instead.
+//   new List<int>(42);
+//       ^
+//
 import self as self;
 import "dart:core" as core;
 
 static method foo<T extends core::Object? = core::Object?>() → dynamic {
   core::_List::•<self::foo::T%>(42);
   core::_List::•<core::int?>(42);
+  core::_List::•<core::int>(42);
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart b/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart
index 439fe5f..2bc2765 100644
--- a/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart
+++ b/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart
@@ -3,12 +3,12 @@
 // BSD-style license that can be found in the LICENSE file.
 
 void foo({required String s}) {}
-void Function({required String s}) g;
+void Function({required String s}) g = ({required String s}) {};
 
 class A {
   A({required int x});
   foo({required int y}) {}
-  void Function({required String s}) f;
+  void Function({required String s}) f = ({required String s}) {};
 }
 
 bar() {
diff --git a/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.strong.expect b/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.strong.expect
index f8923db..46eca1c 100644
--- a/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.strong.expect
@@ -32,13 +32,13 @@
 import "dart:core" as core;
 
 class A extends core::Object {
-  field ({required s: core::String}) → void f = null;
+  field ({required s: core::String}) → void f = ({required core::String s = #C1}) → core::Null? {};
   constructor •({required core::int x = #C1}) → self::A
     : super core::Object::•()
     ;
   method foo({required core::int y = #C1}) → dynamic {}
 }
-static field ({required s: core::String}) → void g;
+static field ({required s: core::String}) → void g = ({required core::String s = #C1}) → core::Null? {};
 static method foo({required core::String s = #C1}) → void {}
 static method bar() → dynamic {
   invalid-expression "pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:15:6: Error: Required named parameter 's' must be provided.
diff --git a/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.strong.transformed.expect
index f8923db..46eca1c 100644
--- a/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.strong.transformed.expect
@@ -32,13 +32,13 @@
 import "dart:core" as core;
 
 class A extends core::Object {
-  field ({required s: core::String}) → void f = null;
+  field ({required s: core::String}) → void f = ({required core::String s = #C1}) → core::Null? {};
   constructor •({required core::int x = #C1}) → self::A
     : super core::Object::•()
     ;
   method foo({required core::int y = #C1}) → dynamic {}
 }
-static field ({required s: core::String}) → void g;
+static field ({required s: core::String}) → void g = ({required core::String s = #C1}) → core::Null? {};
 static method foo({required core::String s = #C1}) → void {}
 static method bar() → dynamic {
   invalid-expression "pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart:15:6: Error: Required named parameter 's' must be provided.
diff --git a/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.weak.expect b/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.weak.expect
index b6243a6..de95e8d 100644
--- a/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.weak.expect
@@ -26,13 +26,13 @@
 import "dart:core" as core;
 
 class A extends core::Object {
-  field ({required s: core::String}) → void f = null;
+  field ({required s: core::String}) → void f = ({required core::String s = #C1}) → core::Null? {};
   constructor •({required core::int x = #C1}) → self::A
     : super core::Object::•()
     ;
   method foo({required core::int y = #C1}) → dynamic {}
 }
-static field ({required s: core::String}) → void g;
+static field ({required s: core::String}) → void g = ({required core::String s = #C1}) → core::Null? {};
 static method foo({required core::String s = #C1}) → void {}
 static method bar() → dynamic {
   self::foo();
diff --git a/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.weak.transformed.expect
index b6243a6..de95e8d 100644
--- a/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/missing_required_named_parameter.dart.weak.transformed.expect
@@ -26,13 +26,13 @@
 import "dart:core" as core;
 
 class A extends core::Object {
-  field ({required s: core::String}) → void f = null;
+  field ({required s: core::String}) → void f = ({required core::String s = #C1}) → core::Null? {};
   constructor •({required core::int x = #C1}) → self::A
     : super core::Object::•()
     ;
   method foo({required core::int y = #C1}) → dynamic {}
 }
-static field ({required s: core::String}) → void g;
+static field ({required s: core::String}) → void g = ({required core::String s = #C1}) → core::Null? {};
 static method foo({required core::String s = #C1}) → void {}
 static method bar() → dynamic {
   self::foo();
diff --git a/pkg/front_end/testcases/nnbd/never_receiver.dart b/pkg/front_end/testcases/nnbd/never_receiver.dart
new file mode 100644
index 0000000..61af20a
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/never_receiver.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2020, 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.
+
+foo(Never x, Never? y) {
+  var local0 = y.toString(); // Not an error.
+  var local1 = y.hashCode; // Not an error.
+
+  x.foo(); // Not an error.
+  x.bar; // Not an error.
+  x.baz = 42; // Not an error.
+  x(); // Not an error.
+  x[42]; // Not an error.
+  x[42] = 42; // Not an error.
+  x++; // Not an error.
+  x += 1; // Not an error.
+  y?.foo(); // Not an error.
+  y?.bar; // Not an error.
+  y?.baz = 42; // Not an error.
+  y?.call(); // Not an error.
+  y?.[42]; // Not an error.
+  y?.[42] = 42; // Not an error.
+
+  y.foo(); // Error.
+  y.bar; // Error.
+  y.baz = 42; // Error.
+  y(); // Error.
+  y++; // Error.
+  y += 1; // Error.
+  y[42]; // Error.
+  y[42] = 42; // Error.
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/never_receiver.dart.outline.expect b/pkg/front_end/testcases/nnbd/never_receiver.dart.outline.expect
new file mode 100644
index 0000000..95bf118
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/never_receiver.dart.outline.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+
+static method foo(Neverx, Never? y) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/nnbd/never_receiver.dart.strong.expect b/pkg/front_end/testcases/nnbd/never_receiver.dart.strong.expect
new file mode 100644
index 0000000..3ec8d1f
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/never_receiver.dart.strong.expect
@@ -0,0 +1,146 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:24:5: Error: The method 'foo' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing method, or defining a method named 'foo'.
+//   y.foo(); // Error.
+//     ^^^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:25:5: Error: The getter 'bar' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'bar'.
+//   y.bar; // Error.
+//     ^^^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:25:5: Error: Property 'bar' cannot be accessed on 'Never' because it is potentially null.
+// Try accessing using ?. instead.
+//   y.bar; // Error.
+//     ^^^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:26:5: Error: The setter 'baz' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'baz'.
+//   y.baz = 42; // Error.
+//     ^^^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:26:5: Error: Property 'baz' cannot be accessed on 'Never' because it is potentially null.
+// Try accessing using ?. instead.
+//   y.baz = 42; // Error.
+//     ^^^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:27:4: Error: The method 'call' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing method, or defining a method named 'call'.
+//   y(); // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:27:4: Error: Can't use an expression of type 'Never' as a function because it's potentially null.
+// Try calling using ?.call instead.
+//   y(); // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:28:4: Error: The method '+' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing method, or defining a method named '+'.
+//   y++; // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:28:4: Error: Operator '+' cannot be called on 'Never' because it is potentially null.
+//   y++; // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:29:5: Error: The method '+' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing method, or defining a method named '+'.
+//   y += 1; // Error.
+//     ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:29:5: Error: Operator '+' cannot be called on 'Never' because it is potentially null.
+//   y += 1; // Error.
+//     ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:30:4: Error: The method '[]' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing method, or defining a method named '[]'.
+//   y[42]; // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:30:4: Error: Operator '[]' cannot be called on 'Never' because it is potentially null.
+//   y[42]; // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:31:4: Error: The method '[]=' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing method, or defining a method named '[]='.
+//   y[42] = 42; // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:31:4: Error: Operator '[]=' cannot be called on 'Never' because it is potentially null.
+//   y[42] = 42; // Error.
+//    ^
+//
+import self as self;
+import "dart:core" as core;
+
+static method foo(Neverx, Never? y) → dynamic {
+  core::String local0 = y.{core::Object::toString}();
+  core::int local1 = y.{core::Object::hashCode};
+  x.foo();
+  x.bar;
+  x.baz = 42;
+  x.call();
+  x.[](42);
+  x.[]=(42, 42);
+  x = x.+(1);
+  x = x.+(1);
+  let finalNever? #t1 = y in #t1.{core::Object::==}(null) ?{dynamic} null : #t1{Never}.foo();
+  let finalNever? #t2 = y in #t2.{core::Object::==}(null) ?{core::Null?} null : #t2{Never}.bar;
+  let finalNever? #t3 = y in #t3.{core::Object::==}(null) ?{core::int?} null : #t3{Never}.baz = 42;
+  let finalNever? #t4 = y in #t4.{core::Object::==}(null) ?{dynamic} null : #t4{Never}.call();
+  let finalNever? #t5 = y in #t5.{core::Object::==}(null) ?{core::Null?} null : #t5{Never}.[](42);
+  let finalNever? #t6 = y in #t6.{core::Object::==}(null) ?{core::int?} null : #t6{Never}.[]=(42, 42);
+  invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:24:5: Error: The method 'foo' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing method, or defining a method named 'foo'.
+  y.foo(); // Error.
+    ^^^";
+  let final<BottomType> #t7 = invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:25:5: Error: Property 'bar' cannot be accessed on 'Never' because it is potentially null.
+Try accessing using ?. instead.
+  y.bar; // Error.
+    ^^^" in invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:25:5: Error: The getter 'bar' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'bar'.
+  y.bar; // Error.
+    ^^^";
+  let final<BottomType> #t8 = invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:26:5: Error: Property 'baz' cannot be accessed on 'Never' because it is potentially null.
+Try accessing using ?. instead.
+  y.baz = 42; // Error.
+    ^^^" in invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:26:5: Error: The setter 'baz' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'baz'.
+  y.baz = 42; // Error.
+    ^^^";
+  let final<BottomType> #t9 = invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:27:4: Error: Can't use an expression of type 'Never' as a function because it's potentially null.
+Try calling using ?.call instead.
+  y(); // Error.
+   ^" in invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:27:4: Error: The method 'call' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing method, or defining a method named 'call'.
+  y(); // Error.
+   ^";
+  y = (let final<BottomType> #t10 = invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:28:4: Error: Operator '+' cannot be called on 'Never' because it is potentially null.
+  y++; // Error.
+   ^" in invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:28:4: Error: The method '+' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing method, or defining a method named '+'.
+  y++; // Error.
+   ^") as{TypeError,ForDynamic,ForNonNullableByDefault} Never?;
+  y = (let final<BottomType> #t11 = invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:29:5: Error: Operator '+' cannot be called on 'Never' because it is potentially null.
+  y += 1; // Error.
+    ^" in invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:29:5: Error: The method '+' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing method, or defining a method named '+'.
+  y += 1; // Error.
+    ^") as{TypeError,ForDynamic,ForNonNullableByDefault} Never?;
+  let final<BottomType> #t12 = invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:30:4: Error: Operator '[]' cannot be called on 'Never' because it is potentially null.
+  y[42]; // Error.
+   ^" in invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:30:4: Error: The method '[]' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing method, or defining a method named '[]'.
+  y[42]; // Error.
+   ^";
+  let final<BottomType> #t13 = invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:31:4: Error: Operator '[]=' cannot be called on 'Never' because it is potentially null.
+  y[42] = 42; // Error.
+   ^" in invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:31:4: Error: The method '[]=' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing method, or defining a method named '[]='.
+  y[42] = 42; // Error.
+   ^";
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/never_receiver.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/never_receiver.dart.strong.transformed.expect
new file mode 100644
index 0000000..3ec8d1f
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/never_receiver.dart.strong.transformed.expect
@@ -0,0 +1,146 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:24:5: Error: The method 'foo' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing method, or defining a method named 'foo'.
+//   y.foo(); // Error.
+//     ^^^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:25:5: Error: The getter 'bar' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'bar'.
+//   y.bar; // Error.
+//     ^^^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:25:5: Error: Property 'bar' cannot be accessed on 'Never' because it is potentially null.
+// Try accessing using ?. instead.
+//   y.bar; // Error.
+//     ^^^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:26:5: Error: The setter 'baz' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'baz'.
+//   y.baz = 42; // Error.
+//     ^^^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:26:5: Error: Property 'baz' cannot be accessed on 'Never' because it is potentially null.
+// Try accessing using ?. instead.
+//   y.baz = 42; // Error.
+//     ^^^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:27:4: Error: The method 'call' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing method, or defining a method named 'call'.
+//   y(); // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:27:4: Error: Can't use an expression of type 'Never' as a function because it's potentially null.
+// Try calling using ?.call instead.
+//   y(); // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:28:4: Error: The method '+' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing method, or defining a method named '+'.
+//   y++; // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:28:4: Error: Operator '+' cannot be called on 'Never' because it is potentially null.
+//   y++; // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:29:5: Error: The method '+' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing method, or defining a method named '+'.
+//   y += 1; // Error.
+//     ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:29:5: Error: Operator '+' cannot be called on 'Never' because it is potentially null.
+//   y += 1; // Error.
+//     ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:30:4: Error: The method '[]' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing method, or defining a method named '[]'.
+//   y[42]; // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:30:4: Error: Operator '[]' cannot be called on 'Never' because it is potentially null.
+//   y[42]; // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:31:4: Error: The method '[]=' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing method, or defining a method named '[]='.
+//   y[42] = 42; // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:31:4: Error: Operator '[]=' cannot be called on 'Never' because it is potentially null.
+//   y[42] = 42; // Error.
+//    ^
+//
+import self as self;
+import "dart:core" as core;
+
+static method foo(Neverx, Never? y) → dynamic {
+  core::String local0 = y.{core::Object::toString}();
+  core::int local1 = y.{core::Object::hashCode};
+  x.foo();
+  x.bar;
+  x.baz = 42;
+  x.call();
+  x.[](42);
+  x.[]=(42, 42);
+  x = x.+(1);
+  x = x.+(1);
+  let finalNever? #t1 = y in #t1.{core::Object::==}(null) ?{dynamic} null : #t1{Never}.foo();
+  let finalNever? #t2 = y in #t2.{core::Object::==}(null) ?{core::Null?} null : #t2{Never}.bar;
+  let finalNever? #t3 = y in #t3.{core::Object::==}(null) ?{core::int?} null : #t3{Never}.baz = 42;
+  let finalNever? #t4 = y in #t4.{core::Object::==}(null) ?{dynamic} null : #t4{Never}.call();
+  let finalNever? #t5 = y in #t5.{core::Object::==}(null) ?{core::Null?} null : #t5{Never}.[](42);
+  let finalNever? #t6 = y in #t6.{core::Object::==}(null) ?{core::int?} null : #t6{Never}.[]=(42, 42);
+  invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:24:5: Error: The method 'foo' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing method, or defining a method named 'foo'.
+  y.foo(); // Error.
+    ^^^";
+  let final<BottomType> #t7 = invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:25:5: Error: Property 'bar' cannot be accessed on 'Never' because it is potentially null.
+Try accessing using ?. instead.
+  y.bar; // Error.
+    ^^^" in invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:25:5: Error: The getter 'bar' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'bar'.
+  y.bar; // Error.
+    ^^^";
+  let final<BottomType> #t8 = invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:26:5: Error: Property 'baz' cannot be accessed on 'Never' because it is potentially null.
+Try accessing using ?. instead.
+  y.baz = 42; // Error.
+    ^^^" in invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:26:5: Error: The setter 'baz' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'baz'.
+  y.baz = 42; // Error.
+    ^^^";
+  let final<BottomType> #t9 = invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:27:4: Error: Can't use an expression of type 'Never' as a function because it's potentially null.
+Try calling using ?.call instead.
+  y(); // Error.
+   ^" in invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:27:4: Error: The method 'call' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing method, or defining a method named 'call'.
+  y(); // Error.
+   ^";
+  y = (let final<BottomType> #t10 = invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:28:4: Error: Operator '+' cannot be called on 'Never' because it is potentially null.
+  y++; // Error.
+   ^" in invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:28:4: Error: The method '+' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing method, or defining a method named '+'.
+  y++; // Error.
+   ^") as{TypeError,ForDynamic,ForNonNullableByDefault} Never?;
+  y = (let final<BottomType> #t11 = invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:29:5: Error: Operator '+' cannot be called on 'Never' because it is potentially null.
+  y += 1; // Error.
+    ^" in invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:29:5: Error: The method '+' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing method, or defining a method named '+'.
+  y += 1; // Error.
+    ^") as{TypeError,ForDynamic,ForNonNullableByDefault} Never?;
+  let final<BottomType> #t12 = invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:30:4: Error: Operator '[]' cannot be called on 'Never' because it is potentially null.
+  y[42]; // Error.
+   ^" in invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:30:4: Error: The method '[]' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing method, or defining a method named '[]'.
+  y[42]; // Error.
+   ^";
+  let final<BottomType> #t13 = invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:31:4: Error: Operator '[]=' cannot be called on 'Never' because it is potentially null.
+  y[42] = 42; // Error.
+   ^" in invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:31:4: Error: The method '[]=' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing method, or defining a method named '[]='.
+  y[42] = 42; // Error.
+   ^";
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/never_receiver.dart.weak.expect b/pkg/front_end/testcases/nnbd/never_receiver.dart.weak.expect
new file mode 100644
index 0000000..d147c4e
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/never_receiver.dart.weak.expect
@@ -0,0 +1,139 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:24:5: Error: The method 'foo' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing method, or defining a method named 'foo'.
+//   y.foo(); // Error.
+//     ^^^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:24:5: Warning: Method 'foo' is called on 'Never' which is potentially null.
+// Try calling using ?. instead.
+//   y.foo(); // Error.
+//     ^^^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:25:5: Error: The getter 'bar' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'bar'.
+//   y.bar; // Error.
+//     ^^^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:25:5: Warning: Property 'bar' is accessed on 'Never' which is potentially null.
+// Try accessing using ?. instead.
+//   y.bar; // Error.
+//     ^^^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:26:5: Error: The setter 'baz' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'baz'.
+//   y.baz = 42; // Error.
+//     ^^^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:26:5: Warning: Property 'baz' is accessed on 'Never' which is potentially null.
+// Try accessing using ?. instead.
+//   y.baz = 42; // Error.
+//     ^^^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:27:4: Error: The method 'call' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing method, or defining a method named 'call'.
+//   y(); // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:27:4: Warning: Method 'call' is called on 'Never' which is potentially null.
+// Try calling using ?. instead.
+//   y(); // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:27:4: Warning: Expression of type 'Never' is used as a function, but it's potentially null.
+// Try calling using ?.call instead.
+//   y(); // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:28:4: Error: The method '+' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing method, or defining a method named '+'.
+//   y++; // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:28:4: Warning: Operator '+' is called on 'Never' which is potentially null.
+//   y++; // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:29:5: Error: The method '+' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing method, or defining a method named '+'.
+//   y += 1; // Error.
+//     ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:29:5: Warning: Operator '+' is called on 'Never' which is potentially null.
+//   y += 1; // Error.
+//     ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:30:4: Error: The method '[]' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing method, or defining a method named '[]'.
+//   y[42]; // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:30:4: Warning: Operator '[]' is called on 'Never' which is potentially null.
+//   y[42]; // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:31:4: Error: The method '[]=' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing method, or defining a method named '[]='.
+//   y[42] = 42; // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:31:4: Warning: Operator '[]=' is called on 'Never' which is potentially null.
+//   y[42] = 42; // Error.
+//    ^
+//
+import self as self;
+import "dart:core" as core;
+
+static method foo(Neverx, Never? y) → dynamic {
+  core::String local0 = y.{core::Object::toString}();
+  core::int local1 = y.{core::Object::hashCode};
+  x.foo();
+  x.bar;
+  x.baz = 42;
+  x.call();
+  x.[](42);
+  x.[]=(42, 42);
+  x = x.+(1);
+  x = x.+(1);
+  let finalNever? #t1 = y in #t1.{core::Object::==}(null) ?{dynamic} null : #t1{Never}.foo();
+  let finalNever? #t2 = y in #t2.{core::Object::==}(null) ?{core::Null?} null : #t2{Never}.bar;
+  let finalNever? #t3 = y in #t3.{core::Object::==}(null) ?{core::int?} null : #t3{Never}.baz = 42;
+  let finalNever? #t4 = y in #t4.{core::Object::==}(null) ?{dynamic} null : #t4{Never}.call();
+  let finalNever? #t5 = y in #t5.{core::Object::==}(null) ?{core::Null?} null : #t5{Never}.[](42);
+  let finalNever? #t6 = y in #t6.{core::Object::==}(null) ?{core::int?} null : #t6{Never}.[]=(42, 42);
+  invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:24:5: Error: The method 'foo' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing method, or defining a method named 'foo'.
+  y.foo(); // Error.
+    ^^^";
+  invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:25:5: Error: The getter 'bar' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'bar'.
+  y.bar; // Error.
+    ^^^";
+  invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:26:5: Error: The setter 'baz' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'baz'.
+  y.baz = 42; // Error.
+    ^^^";
+  invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:27:4: Error: The method 'call' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing method, or defining a method named 'call'.
+  y(); // Error.
+   ^";
+  y = invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:28:4: Error: The method '+' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing method, or defining a method named '+'.
+  y++; // Error.
+   ^" as{TypeError,ForDynamic,ForNonNullableByDefault} Never?;
+  y = invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:29:5: Error: The method '+' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing method, or defining a method named '+'.
+  y += 1; // Error.
+    ^" as{TypeError,ForDynamic,ForNonNullableByDefault} Never?;
+  invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:30:4: Error: The method '[]' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing method, or defining a method named '[]'.
+  y[42]; // Error.
+   ^";
+  invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:31:4: Error: The method '[]=' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing method, or defining a method named '[]='.
+  y[42] = 42; // Error.
+   ^";
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/never_receiver.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/never_receiver.dart.weak.transformed.expect
new file mode 100644
index 0000000..d147c4e
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/never_receiver.dart.weak.transformed.expect
@@ -0,0 +1,139 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:24:5: Error: The method 'foo' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing method, or defining a method named 'foo'.
+//   y.foo(); // Error.
+//     ^^^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:24:5: Warning: Method 'foo' is called on 'Never' which is potentially null.
+// Try calling using ?. instead.
+//   y.foo(); // Error.
+//     ^^^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:25:5: Error: The getter 'bar' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'bar'.
+//   y.bar; // Error.
+//     ^^^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:25:5: Warning: Property 'bar' is accessed on 'Never' which is potentially null.
+// Try accessing using ?. instead.
+//   y.bar; // Error.
+//     ^^^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:26:5: Error: The setter 'baz' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'baz'.
+//   y.baz = 42; // Error.
+//     ^^^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:26:5: Warning: Property 'baz' is accessed on 'Never' which is potentially null.
+// Try accessing using ?. instead.
+//   y.baz = 42; // Error.
+//     ^^^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:27:4: Error: The method 'call' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing method, or defining a method named 'call'.
+//   y(); // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:27:4: Warning: Method 'call' is called on 'Never' which is potentially null.
+// Try calling using ?. instead.
+//   y(); // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:27:4: Warning: Expression of type 'Never' is used as a function, but it's potentially null.
+// Try calling using ?.call instead.
+//   y(); // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:28:4: Error: The method '+' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing method, or defining a method named '+'.
+//   y++; // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:28:4: Warning: Operator '+' is called on 'Never' which is potentially null.
+//   y++; // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:29:5: Error: The method '+' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing method, or defining a method named '+'.
+//   y += 1; // Error.
+//     ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:29:5: Warning: Operator '+' is called on 'Never' which is potentially null.
+//   y += 1; // Error.
+//     ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:30:4: Error: The method '[]' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing method, or defining a method named '[]'.
+//   y[42]; // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:30:4: Warning: Operator '[]' is called on 'Never' which is potentially null.
+//   y[42]; // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:31:4: Error: The method '[]=' isn't defined for the class 'Never'.
+// Try correcting the name to the name of an existing method, or defining a method named '[]='.
+//   y[42] = 42; // Error.
+//    ^
+//
+// pkg/front_end/testcases/nnbd/never_receiver.dart:31:4: Warning: Operator '[]=' is called on 'Never' which is potentially null.
+//   y[42] = 42; // Error.
+//    ^
+//
+import self as self;
+import "dart:core" as core;
+
+static method foo(Neverx, Never? y) → dynamic {
+  core::String local0 = y.{core::Object::toString}();
+  core::int local1 = y.{core::Object::hashCode};
+  x.foo();
+  x.bar;
+  x.baz = 42;
+  x.call();
+  x.[](42);
+  x.[]=(42, 42);
+  x = x.+(1);
+  x = x.+(1);
+  let finalNever? #t1 = y in #t1.{core::Object::==}(null) ?{dynamic} null : #t1{Never}.foo();
+  let finalNever? #t2 = y in #t2.{core::Object::==}(null) ?{core::Null?} null : #t2{Never}.bar;
+  let finalNever? #t3 = y in #t3.{core::Object::==}(null) ?{core::int?} null : #t3{Never}.baz = 42;
+  let finalNever? #t4 = y in #t4.{core::Object::==}(null) ?{dynamic} null : #t4{Never}.call();
+  let finalNever? #t5 = y in #t5.{core::Object::==}(null) ?{core::Null?} null : #t5{Never}.[](42);
+  let finalNever? #t6 = y in #t6.{core::Object::==}(null) ?{core::int?} null : #t6{Never}.[]=(42, 42);
+  invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:24:5: Error: The method 'foo' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing method, or defining a method named 'foo'.
+  y.foo(); // Error.
+    ^^^";
+  invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:25:5: Error: The getter 'bar' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'bar'.
+  y.bar; // Error.
+    ^^^";
+  invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:26:5: Error: The setter 'baz' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'baz'.
+  y.baz = 42; // Error.
+    ^^^";
+  invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:27:4: Error: The method 'call' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing method, or defining a method named 'call'.
+  y(); // Error.
+   ^";
+  y = invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:28:4: Error: The method '+' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing method, or defining a method named '+'.
+  y++; // Error.
+   ^" as{TypeError,ForDynamic,ForNonNullableByDefault} Never?;
+  y = invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:29:5: Error: The method '+' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing method, or defining a method named '+'.
+  y += 1; // Error.
+    ^" as{TypeError,ForDynamic,ForNonNullableByDefault} Never?;
+  invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:30:4: Error: The method '[]' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing method, or defining a method named '[]'.
+  y[42]; // Error.
+   ^";
+  invalid-expression "pkg/front_end/testcases/nnbd/never_receiver.dart:31:4: Error: The method '[]=' isn't defined for the class 'Never'.
+Try correcting the name to the name of an existing method, or defining a method named '[]='.
+  y[42] = 42; // Error.
+   ^";
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version.dart b/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version.dart
new file mode 100644
index 0000000..28c90f7
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version.dart
@@ -0,0 +1,19 @@
+// @dart=2.4
+
+class late {
+  int get g => 1;
+}
+
+class required {
+  int get g => 2;
+}
+
+class C {
+  late l = late();
+  required r = required();
+}
+
+main() {
+  if (new C().l.g != 1) throw "Expected 1";
+  if (new C().r.g != 2) throw "Expected 2";
+}
diff --git a/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version.dart.outline.expect b/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version.dart.outline.expect
new file mode 100644
index 0000000..0929ee6
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version.dart.outline.expect
@@ -0,0 +1,24 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class late extends core::Object {
+  synthetic constructor •() → self::late*
+    ;
+  get g() → core::int*
+    ;
+}
+class required extends core::Object {
+  synthetic constructor •() → self::required*
+    ;
+  get g() → core::int*
+    ;
+}
+class C extends core::Object {
+  field self::late* l;
+  field self::required* r;
+  synthetic constructor •() → self::C*
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version.dart.strong.expect b/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version.dart.strong.expect
new file mode 100644
index 0000000..46f8c11
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version.dart.strong.expect
@@ -0,0 +1,31 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class late extends core::Object {
+  synthetic constructor •() → self::late*
+    : super core::Object::•()
+    ;
+  get g() → core::int*
+    return 1;
+}
+class required extends core::Object {
+  synthetic constructor •() → self::required*
+    : super core::Object::•()
+    ;
+  get g() → core::int*
+    return 2;
+}
+class C extends core::Object {
+  field self::late* l = new self::late::•();
+  field self::required* r = new self::required::•();
+  synthetic constructor •() → self::C*
+    : super core::Object::•()
+    ;
+}
+static method main() → dynamic {
+  if(!new self::C::•().{self::C::l}.{self::late::g}.{core::num::==}(1))
+    throw "Expected 1";
+  if(!new self::C::•().{self::C::r}.{self::required::g}.{core::num::==}(2))
+    throw "Expected 2";
+}
diff --git a/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version.dart.strong.transformed.expect
new file mode 100644
index 0000000..46f8c11
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version.dart.strong.transformed.expect
@@ -0,0 +1,31 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class late extends core::Object {
+  synthetic constructor •() → self::late*
+    : super core::Object::•()
+    ;
+  get g() → core::int*
+    return 1;
+}
+class required extends core::Object {
+  synthetic constructor •() → self::required*
+    : super core::Object::•()
+    ;
+  get g() → core::int*
+    return 2;
+}
+class C extends core::Object {
+  field self::late* l = new self::late::•();
+  field self::required* r = new self::required::•();
+  synthetic constructor •() → self::C*
+    : super core::Object::•()
+    ;
+}
+static method main() → dynamic {
+  if(!new self::C::•().{self::C::l}.{self::late::g}.{core::num::==}(1))
+    throw "Expected 1";
+  if(!new self::C::•().{self::C::r}.{self::required::g}.{core::num::==}(2))
+    throw "Expected 2";
+}
diff --git a/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version.dart.weak.expect b/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version.dart.weak.expect
new file mode 100644
index 0000000..46f8c11
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version.dart.weak.expect
@@ -0,0 +1,31 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class late extends core::Object {
+  synthetic constructor •() → self::late*
+    : super core::Object::•()
+    ;
+  get g() → core::int*
+    return 1;
+}
+class required extends core::Object {
+  synthetic constructor •() → self::required*
+    : super core::Object::•()
+    ;
+  get g() → core::int*
+    return 2;
+}
+class C extends core::Object {
+  field self::late* l = new self::late::•();
+  field self::required* r = new self::required::•();
+  synthetic constructor •() → self::C*
+    : super core::Object::•()
+    ;
+}
+static method main() → dynamic {
+  if(!new self::C::•().{self::C::l}.{self::late::g}.{core::num::==}(1))
+    throw "Expected 1";
+  if(!new self::C::•().{self::C::r}.{self::required::g}.{core::num::==}(2))
+    throw "Expected 2";
+}
diff --git a/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version.dart.weak.transformed.expect
new file mode 100644
index 0000000..46f8c11
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version.dart.weak.transformed.expect
@@ -0,0 +1,31 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class late extends core::Object {
+  synthetic constructor •() → self::late*
+    : super core::Object::•()
+    ;
+  get g() → core::int*
+    return 1;
+}
+class required extends core::Object {
+  synthetic constructor •() → self::required*
+    : super core::Object::•()
+    ;
+  get g() → core::int*
+    return 2;
+}
+class C extends core::Object {
+  field self::late* l = new self::late::•();
+  field self::required* r = new self::required::•();
+  synthetic constructor •() → self::C*
+    : super core::Object::•()
+    ;
+}
+static method main() → dynamic {
+  if(!new self::C::•().{self::C::l}.{self::late::g}.{core::num::==}(1))
+    throw "Expected 1";
+  if(!new self::C::•().{self::C::r}.{self::required::g}.{core::num::==}(2))
+    throw "Expected 2";
+}
diff --git a/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version_try_to_trick.dart b/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version_try_to_trick.dart
new file mode 100644
index 0000000..dae41d7
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version_try_to_trick.dart
@@ -0,0 +1,20 @@
+// @dart=2.4
+// @dart=2.8
+
+class late {
+  int get g => 1;
+}
+
+class required {
+  int get g => 2;
+}
+
+class C {
+  late l = late();
+  required r = required();
+}
+
+main() {
+  if (new C().l.g != 1) throw "Expected 1";
+  if (new C().r.g != 2) throw "Expected 2";
+}
diff --git a/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version_try_to_trick.dart.outline.expect b/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version_try_to_trick.dart.outline.expect
new file mode 100644
index 0000000..0929ee6
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version_try_to_trick.dart.outline.expect
@@ -0,0 +1,24 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class late extends core::Object {
+  synthetic constructor •() → self::late*
+    ;
+  get g() → core::int*
+    ;
+}
+class required extends core::Object {
+  synthetic constructor •() → self::required*
+    ;
+  get g() → core::int*
+    ;
+}
+class C extends core::Object {
+  field self::late* l;
+  field self::required* r;
+  synthetic constructor •() → self::C*
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version_try_to_trick.dart.strong.expect b/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version_try_to_trick.dart.strong.expect
new file mode 100644
index 0000000..46f8c11
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version_try_to_trick.dart.strong.expect
@@ -0,0 +1,31 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class late extends core::Object {
+  synthetic constructor •() → self::late*
+    : super core::Object::•()
+    ;
+  get g() → core::int*
+    return 1;
+}
+class required extends core::Object {
+  synthetic constructor •() → self::required*
+    : super core::Object::•()
+    ;
+  get g() → core::int*
+    return 2;
+}
+class C extends core::Object {
+  field self::late* l = new self::late::•();
+  field self::required* r = new self::required::•();
+  synthetic constructor •() → self::C*
+    : super core::Object::•()
+    ;
+}
+static method main() → dynamic {
+  if(!new self::C::•().{self::C::l}.{self::late::g}.{core::num::==}(1))
+    throw "Expected 1";
+  if(!new self::C::•().{self::C::r}.{self::required::g}.{core::num::==}(2))
+    throw "Expected 2";
+}
diff --git a/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version_try_to_trick.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version_try_to_trick.dart.strong.transformed.expect
new file mode 100644
index 0000000..46f8c11
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version_try_to_trick.dart.strong.transformed.expect
@@ -0,0 +1,31 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class late extends core::Object {
+  synthetic constructor •() → self::late*
+    : super core::Object::•()
+    ;
+  get g() → core::int*
+    return 1;
+}
+class required extends core::Object {
+  synthetic constructor •() → self::required*
+    : super core::Object::•()
+    ;
+  get g() → core::int*
+    return 2;
+}
+class C extends core::Object {
+  field self::late* l = new self::late::•();
+  field self::required* r = new self::required::•();
+  synthetic constructor •() → self::C*
+    : super core::Object::•()
+    ;
+}
+static method main() → dynamic {
+  if(!new self::C::•().{self::C::l}.{self::late::g}.{core::num::==}(1))
+    throw "Expected 1";
+  if(!new self::C::•().{self::C::r}.{self::required::g}.{core::num::==}(2))
+    throw "Expected 2";
+}
diff --git a/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version_try_to_trick.dart.weak.expect b/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version_try_to_trick.dart.weak.expect
new file mode 100644
index 0000000..46f8c11
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version_try_to_trick.dart.weak.expect
@@ -0,0 +1,31 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class late extends core::Object {
+  synthetic constructor •() → self::late*
+    : super core::Object::•()
+    ;
+  get g() → core::int*
+    return 1;
+}
+class required extends core::Object {
+  synthetic constructor •() → self::required*
+    : super core::Object::•()
+    ;
+  get g() → core::int*
+    return 2;
+}
+class C extends core::Object {
+  field self::late* l = new self::late::•();
+  field self::required* r = new self::required::•();
+  synthetic constructor •() → self::C*
+    : super core::Object::•()
+    ;
+}
+static method main() → dynamic {
+  if(!new self::C::•().{self::C::l}.{self::late::g}.{core::num::==}(1))
+    throw "Expected 1";
+  if(!new self::C::•().{self::C::r}.{self::required::g}.{core::num::==}(2))
+    throw "Expected 2";
+}
diff --git a/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version_try_to_trick.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version_try_to_trick.dart.weak.transformed.expect
new file mode 100644
index 0000000..46f8c11
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/nnbd_opt_out_language_version_try_to_trick.dart.weak.transformed.expect
@@ -0,0 +1,31 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class late extends core::Object {
+  synthetic constructor •() → self::late*
+    : super core::Object::•()
+    ;
+  get g() → core::int*
+    return 1;
+}
+class required extends core::Object {
+  synthetic constructor •() → self::required*
+    : super core::Object::•()
+    ;
+  get g() → core::int*
+    return 2;
+}
+class C extends core::Object {
+  field self::late* l = new self::late::•();
+  field self::required* r = new self::required::•();
+  synthetic constructor •() → self::C*
+    : super core::Object::•()
+    ;
+}
+static method main() → dynamic {
+  if(!new self::C::•().{self::C::l}.{self::late::g}.{core::num::==}(1))
+    throw "Expected 1";
+  if(!new self::C::•().{self::C::r}.{self::required::g}.{core::num::==}(2))
+    throw "Expected 2";
+}
diff --git a/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart
new file mode 100644
index 0000000..29a117e
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart
@@ -0,0 +1,81 @@
+// Copyright (c) 2020, 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.
+
+class Foo {}
+
+int topLevelField; // Error.
+
+class A {
+  static int staticFieldOfA; // Error.
+  int fieldOfA; // Error.
+  A.foo();
+  A.bar(this.fieldOfA);
+}
+
+class B<X extends Object?, Y extends Object> {
+  X fieldOfB; // Error.
+  Y fieldOfB2; // Error.
+  B.foo();
+  B.bar(this.fieldOfB, this.fieldOfB2);
+}
+
+mixin M {
+  static int staticFieldOfM; // Error.
+  int fieldOfM; // Error.
+}
+
+mixin N<X extends Object?, Y extends Object> {
+  X fieldOfN; // Error.
+  Y fieldOfN2; // Error.
+}
+
+extension P on Foo {
+  static int staticFieldOfE; // Error.
+}
+
+int? nullableTopLevelField; // Not an error.
+late int lateTopLevelField; // Not an error.
+int topLevelFieldWithInitializer = 42; // Not an error.
+
+class C<X extends Object?, Y extends Object> {
+  static int? staticFieldOfX; // Not an error.
+  static int staticFieldOfXInitialized = 42; // Not an error.
+  X? fieldOfX; // Not an error.
+  int? fieldOfX2; // Not an error.
+  dynamic fieldOfX3; // Not an error.
+  Null fieldOfX4; // Not an error.
+  int Function()? fieldOfX5; // Not an error.
+  Y? fieldOfX6; // Not an error.
+  static late int lateStaticFieldOfC; // Not an error.
+  late int fieldOfC7; // Not an error.
+  late X fieldOfC8; // Not an error.
+  late Y fieldOfC9; // Not an error.
+  int fieldOfC10; // Not an error.
+
+  C.foo(this.fieldOfC10);
+  C.bar(this.fieldOfC10);
+}
+
+mixin L<X extends Object?, Y extends Object> {
+  static int? staticFieldOfL; // Not an error.
+  static int staticFieldOfLInitialized = 42; // Not an error
+  X? fieldOfL; // Not an error.
+  int? fieldOfL2; // Not an error.
+  dynamic fieldOfL3; // Not an error.
+  Null fieldOfL4; // Not an error.
+  int Function()? fieldOfL5; // Not an error.
+  Y? fieldOfL6; // Not an error.
+  static late int lateStaticFieldOfM; // Not an error.
+  late int fieldOfM7; // Not an error.
+  late X fieldOfM8; // Not an error.
+  late Y fieldOfM9; // Not an error.
+}
+
+extension Q on Foo {
+  static int? staticFieldOfQ; // Not an error.
+  static late int lateStaticFieldOfQ; // Not an error.
+  static int staticFieldOfQInitialized = 42; // Not an error.
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.outline.expect b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.outline.expect
new file mode 100644
index 0000000..56810f6
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.outline.expect
@@ -0,0 +1,98 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:7:5: Error: Field 'topLevelField' should be initialized because its type 'int' doesn't allow null.
+// int topLevelField; // Error.
+//     ^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:10:14: Error: Field 'staticFieldOfA' should be initialized because its type 'int' doesn't allow null.
+//   static int staticFieldOfA; // Error.
+//              ^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:24:14: Error: Field 'staticFieldOfM' should be initialized because its type 'int' doesn't allow null.
+//   static int staticFieldOfM; // Error.
+//              ^^^^^^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  synthetic constructor •() → self::Foo
+    ;
+}
+class A extends core::Object {
+  static field core::int staticFieldOfA;
+  field core::int fieldOfA;
+  constructor foo() → self::A
+    ;
+  constructor bar(core::int fieldOfA) → self::A
+    ;
+}
+class B<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+  generic-covariant-impl field self::B::X% fieldOfB;
+  generic-covariant-impl field self::B::Y fieldOfB2;
+  constructor foo() → self::B<self::B::X%, self::B::Y>
+    ;
+  constructor bar(self::B::X% fieldOfB, self::B::Y fieldOfB2) → self::B<self::B::X%, self::B::Y>
+    ;
+}
+abstract class M extends core::Object {
+  static field core::int staticFieldOfM;
+  field core::int fieldOfM;
+}
+abstract class N<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+  generic-covariant-impl field self::N::X% fieldOfN;
+  generic-covariant-impl field self::N::Y fieldOfN2;
+}
+class C<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+  static field core::int? staticFieldOfX;
+  static field core::int staticFieldOfXInitialized;
+  generic-covariant-impl field self::C::X? fieldOfX;
+  field core::int? fieldOfX2;
+  field dynamic fieldOfX3;
+  field core::Null? fieldOfX4;
+  field () →? core::int fieldOfX5;
+  generic-covariant-impl field self::C::Y? fieldOfX6;
+  late static field core::int lateStaticFieldOfC;
+  late field core::int fieldOfC7;
+  late generic-covariant-impl field self::C::X% fieldOfC8;
+  late generic-covariant-impl field self::C::Y fieldOfC9;
+  field core::int fieldOfC10;
+  constructor foo(core::int fieldOfC10) → self::C<self::C::X%, self::C::Y>
+    ;
+  constructor bar(core::int fieldOfC10) → self::C<self::C::X%, self::C::Y>
+    ;
+}
+abstract class L<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+  static field core::int? staticFieldOfL;
+  static field core::int staticFieldOfLInitialized;
+  generic-covariant-impl field self::L::X? fieldOfL;
+  field core::int? fieldOfL2;
+  field dynamic fieldOfL3;
+  field core::Null? fieldOfL4;
+  field () →? core::int fieldOfL5;
+  generic-covariant-impl field self::L::Y? fieldOfL6;
+  late static field core::int lateStaticFieldOfM;
+  late field core::int fieldOfM7;
+  late generic-covariant-impl field self::L::X% fieldOfM8;
+  late generic-covariant-impl field self::L::Y fieldOfM9;
+}
+extension P on self::Foo {
+  static field staticFieldOfE = self::P|staticFieldOfE;
+}
+extension Q on self::Foo {
+  static field staticFieldOfQ = self::Q|staticFieldOfQ;
+  static field lateStaticFieldOfQ = self::Q|lateStaticFieldOfQ;
+  static field staticFieldOfQInitialized = self::Q|staticFieldOfQInitialized;
+}
+static field core::int topLevelField;
+static field core::int P|staticFieldOfE;
+static field core::int? nullableTopLevelField;
+late static field core::int lateTopLevelField;
+static field core::int topLevelFieldWithInitializer;
+static field core::int? Q|staticFieldOfQ;
+late static field core::int Q|lateStaticFieldOfQ;
+static field core::int Q|staticFieldOfQInitialized;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.strong.expect b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.strong.expect
new file mode 100644
index 0000000..90d9ea5
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.strong.expect
@@ -0,0 +1,128 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:7:5: Error: Field 'topLevelField' should be initialized because its type 'int' doesn't allow null.
+// int topLevelField; // Error.
+//     ^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:10:14: Error: Field 'staticFieldOfA' should be initialized because its type 'int' doesn't allow null.
+//   static int staticFieldOfA; // Error.
+//              ^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:24:14: Error: Field 'staticFieldOfM' should be initialized because its type 'int' doesn't allow null.
+//   static int staticFieldOfM; // Error.
+//              ^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:11:7: Error: This constructor should initialize field 'fieldOfA' because its type 'int' doesn't allow null.
+//   int fieldOfA; // Error.
+//       ^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:17:5: Error: This constructor should initialize field 'fieldOfB' because its type 'X' doesn't allow null.
+//   X fieldOfB; // Error.
+//     ^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:18:5: Error: This constructor should initialize field 'fieldOfB2' because its type 'Y' doesn't allow null.
+//   Y fieldOfB2; // Error.
+//     ^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:25:7: Error: Field 'fieldOfM' should be initialized because its type 'int' doesn't allow null.
+//   int fieldOfM; // Error.
+//       ^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:29:5: Error: Field 'fieldOfN' should be initialized because its type 'X' doesn't allow null.
+//   X fieldOfN; // Error.
+//     ^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:30:5: Error: Field 'fieldOfN2' should be initialized because its type 'Y' doesn't allow null.
+//   Y fieldOfN2; // Error.
+//     ^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  synthetic constructor •() → self::Foo
+    : super core::Object::•()
+    ;
+}
+class A extends core::Object {
+  static field core::int staticFieldOfA = null;
+  field core::int fieldOfA;
+  constructor foo() → self::A
+    : self::A::fieldOfA = null, super core::Object::•()
+    ;
+  constructor bar(core::int fieldOfA) → self::A
+    : self::A::fieldOfA = fieldOfA, super core::Object::•()
+    ;
+}
+class B<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+  generic-covariant-impl field self::B::X% fieldOfB;
+  generic-covariant-impl field self::B::Y fieldOfB2;
+  constructor foo() → self::B<self::B::X%, self::B::Y>
+    : self::B::fieldOfB2 = null, self::B::fieldOfB = null, super core::Object::•()
+    ;
+  constructor bar(self::B::X% fieldOfB, self::B::Y fieldOfB2) → self::B<self::B::X%, self::B::Y>
+    : self::B::fieldOfB = fieldOfB, self::B::fieldOfB2 = fieldOfB2, super core::Object::•()
+    ;
+}
+abstract class M extends core::Object {
+  static field core::int staticFieldOfM = null;
+  field core::int fieldOfM = null;
+}
+abstract class N<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+  generic-covariant-impl field self::N::X% fieldOfN = null;
+  generic-covariant-impl field self::N::Y fieldOfN2 = null;
+}
+class C<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+  static field core::int? staticFieldOfX = null;
+  static field core::int staticFieldOfXInitialized = 42;
+  generic-covariant-impl field self::C::X? fieldOfX = null;
+  field core::int? fieldOfX2 = null;
+  field dynamic fieldOfX3 = null;
+  field core::Null? fieldOfX4 = null;
+  field () →? core::int fieldOfX5 = null;
+  generic-covariant-impl field self::C::Y? fieldOfX6 = null;
+  late static field core::int lateStaticFieldOfC;
+  late field core::int fieldOfC7;
+  late generic-covariant-impl field self::C::X% fieldOfC8;
+  late generic-covariant-impl field self::C::Y fieldOfC9;
+  field core::int fieldOfC10;
+  constructor foo(core::int fieldOfC10) → self::C<self::C::X%, self::C::Y>
+    : self::C::fieldOfC10 = fieldOfC10, super core::Object::•()
+    ;
+  constructor bar(core::int fieldOfC10) → self::C<self::C::X%, self::C::Y>
+    : self::C::fieldOfC10 = fieldOfC10, super core::Object::•()
+    ;
+}
+abstract class L<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+  static field core::int? staticFieldOfL = null;
+  static field core::int staticFieldOfLInitialized = 42;
+  generic-covariant-impl field self::L::X? fieldOfL = null;
+  field core::int? fieldOfL2 = null;
+  field dynamic fieldOfL3 = null;
+  field core::Null? fieldOfL4 = null;
+  field () →? core::int fieldOfL5 = null;
+  generic-covariant-impl field self::L::Y? fieldOfL6 = null;
+  late static field core::int lateStaticFieldOfM;
+  late field core::int fieldOfM7;
+  late generic-covariant-impl field self::L::X% fieldOfM8;
+  late generic-covariant-impl field self::L::Y fieldOfM9;
+}
+extension P on self::Foo {
+  static field staticFieldOfE = self::P|staticFieldOfE;
+}
+extension Q on self::Foo {
+  static field staticFieldOfQ = self::Q|staticFieldOfQ;
+  static field lateStaticFieldOfQ = self::Q|lateStaticFieldOfQ;
+  static field staticFieldOfQInitialized = self::Q|staticFieldOfQInitialized;
+}
+static field core::int topLevelField;
+static field core::int P|staticFieldOfE;
+static field core::int? nullableTopLevelField;
+late static field core::int lateTopLevelField;
+static field core::int topLevelFieldWithInitializer = 42;
+static field core::int? Q|staticFieldOfQ;
+late static field core::int Q|lateStaticFieldOfQ;
+static field core::int Q|staticFieldOfQInitialized = 42;
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.strong.transformed.expect
new file mode 100644
index 0000000..90d9ea5
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.strong.transformed.expect
@@ -0,0 +1,128 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:7:5: Error: Field 'topLevelField' should be initialized because its type 'int' doesn't allow null.
+// int topLevelField; // Error.
+//     ^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:10:14: Error: Field 'staticFieldOfA' should be initialized because its type 'int' doesn't allow null.
+//   static int staticFieldOfA; // Error.
+//              ^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:24:14: Error: Field 'staticFieldOfM' should be initialized because its type 'int' doesn't allow null.
+//   static int staticFieldOfM; // Error.
+//              ^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:11:7: Error: This constructor should initialize field 'fieldOfA' because its type 'int' doesn't allow null.
+//   int fieldOfA; // Error.
+//       ^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:17:5: Error: This constructor should initialize field 'fieldOfB' because its type 'X' doesn't allow null.
+//   X fieldOfB; // Error.
+//     ^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:18:5: Error: This constructor should initialize field 'fieldOfB2' because its type 'Y' doesn't allow null.
+//   Y fieldOfB2; // Error.
+//     ^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:25:7: Error: Field 'fieldOfM' should be initialized because its type 'int' doesn't allow null.
+//   int fieldOfM; // Error.
+//       ^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:29:5: Error: Field 'fieldOfN' should be initialized because its type 'X' doesn't allow null.
+//   X fieldOfN; // Error.
+//     ^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:30:5: Error: Field 'fieldOfN2' should be initialized because its type 'Y' doesn't allow null.
+//   Y fieldOfN2; // Error.
+//     ^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  synthetic constructor •() → self::Foo
+    : super core::Object::•()
+    ;
+}
+class A extends core::Object {
+  static field core::int staticFieldOfA = null;
+  field core::int fieldOfA;
+  constructor foo() → self::A
+    : self::A::fieldOfA = null, super core::Object::•()
+    ;
+  constructor bar(core::int fieldOfA) → self::A
+    : self::A::fieldOfA = fieldOfA, super core::Object::•()
+    ;
+}
+class B<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+  generic-covariant-impl field self::B::X% fieldOfB;
+  generic-covariant-impl field self::B::Y fieldOfB2;
+  constructor foo() → self::B<self::B::X%, self::B::Y>
+    : self::B::fieldOfB2 = null, self::B::fieldOfB = null, super core::Object::•()
+    ;
+  constructor bar(self::B::X% fieldOfB, self::B::Y fieldOfB2) → self::B<self::B::X%, self::B::Y>
+    : self::B::fieldOfB = fieldOfB, self::B::fieldOfB2 = fieldOfB2, super core::Object::•()
+    ;
+}
+abstract class M extends core::Object {
+  static field core::int staticFieldOfM = null;
+  field core::int fieldOfM = null;
+}
+abstract class N<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+  generic-covariant-impl field self::N::X% fieldOfN = null;
+  generic-covariant-impl field self::N::Y fieldOfN2 = null;
+}
+class C<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+  static field core::int? staticFieldOfX = null;
+  static field core::int staticFieldOfXInitialized = 42;
+  generic-covariant-impl field self::C::X? fieldOfX = null;
+  field core::int? fieldOfX2 = null;
+  field dynamic fieldOfX3 = null;
+  field core::Null? fieldOfX4 = null;
+  field () →? core::int fieldOfX5 = null;
+  generic-covariant-impl field self::C::Y? fieldOfX6 = null;
+  late static field core::int lateStaticFieldOfC;
+  late field core::int fieldOfC7;
+  late generic-covariant-impl field self::C::X% fieldOfC8;
+  late generic-covariant-impl field self::C::Y fieldOfC9;
+  field core::int fieldOfC10;
+  constructor foo(core::int fieldOfC10) → self::C<self::C::X%, self::C::Y>
+    : self::C::fieldOfC10 = fieldOfC10, super core::Object::•()
+    ;
+  constructor bar(core::int fieldOfC10) → self::C<self::C::X%, self::C::Y>
+    : self::C::fieldOfC10 = fieldOfC10, super core::Object::•()
+    ;
+}
+abstract class L<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+  static field core::int? staticFieldOfL = null;
+  static field core::int staticFieldOfLInitialized = 42;
+  generic-covariant-impl field self::L::X? fieldOfL = null;
+  field core::int? fieldOfL2 = null;
+  field dynamic fieldOfL3 = null;
+  field core::Null? fieldOfL4 = null;
+  field () →? core::int fieldOfL5 = null;
+  generic-covariant-impl field self::L::Y? fieldOfL6 = null;
+  late static field core::int lateStaticFieldOfM;
+  late field core::int fieldOfM7;
+  late generic-covariant-impl field self::L::X% fieldOfM8;
+  late generic-covariant-impl field self::L::Y fieldOfM9;
+}
+extension P on self::Foo {
+  static field staticFieldOfE = self::P|staticFieldOfE;
+}
+extension Q on self::Foo {
+  static field staticFieldOfQ = self::Q|staticFieldOfQ;
+  static field lateStaticFieldOfQ = self::Q|lateStaticFieldOfQ;
+  static field staticFieldOfQInitialized = self::Q|staticFieldOfQInitialized;
+}
+static field core::int topLevelField;
+static field core::int P|staticFieldOfE;
+static field core::int? nullableTopLevelField;
+late static field core::int lateTopLevelField;
+static field core::int topLevelFieldWithInitializer = 42;
+static field core::int? Q|staticFieldOfQ;
+late static field core::int Q|lateStaticFieldOfQ;
+static field core::int Q|staticFieldOfQInitialized = 42;
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.weak.expect b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.weak.expect
new file mode 100644
index 0000000..29e2dde
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.weak.expect
@@ -0,0 +1,128 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:7:5: Warning: Field 'topLevelField' isn't initialized and its type 'int' doesn't allow null.
+// int topLevelField; // Error.
+//     ^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:10:14: Warning: Field 'staticFieldOfA' isn't initialized and its type 'int' doesn't allow null.
+//   static int staticFieldOfA; // Error.
+//              ^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:24:14: Warning: Field 'staticFieldOfM' isn't initialized and its type 'int' doesn't allow null.
+//   static int staticFieldOfM; // Error.
+//              ^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:11:7: Warning: This constructor doesn't initialize field 'fieldOfA' and its type 'int' doesn't allow null.
+//   int fieldOfA; // Error.
+//       ^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:17:5: Warning: This constructor doesn't initialize field 'fieldOfB' and its type 'X' doesn't allow null.
+//   X fieldOfB; // Error.
+//     ^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:18:5: Warning: This constructor doesn't initialize field 'fieldOfB2' and its type 'Y' doesn't allow null.
+//   Y fieldOfB2; // Error.
+//     ^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:25:7: Warning: Field 'fieldOfM' isn't initialized and its type 'int' doesn't allow null.
+//   int fieldOfM; // Error.
+//       ^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:29:5: Warning: Field 'fieldOfN' isn't initialized and its type 'X' doesn't allow null.
+//   X fieldOfN; // Error.
+//     ^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:30:5: Warning: Field 'fieldOfN2' isn't initialized and its type 'Y' doesn't allow null.
+//   Y fieldOfN2; // Error.
+//     ^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  synthetic constructor •() → self::Foo
+    : super core::Object::•()
+    ;
+}
+class A extends core::Object {
+  static field core::int staticFieldOfA = null;
+  field core::int fieldOfA;
+  constructor foo() → self::A
+    : self::A::fieldOfA = null, super core::Object::•()
+    ;
+  constructor bar(core::int fieldOfA) → self::A
+    : self::A::fieldOfA = fieldOfA, super core::Object::•()
+    ;
+}
+class B<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+  generic-covariant-impl field self::B::X% fieldOfB;
+  generic-covariant-impl field self::B::Y fieldOfB2;
+  constructor foo() → self::B<self::B::X%, self::B::Y>
+    : self::B::fieldOfB2 = null, self::B::fieldOfB = null, super core::Object::•()
+    ;
+  constructor bar(self::B::X% fieldOfB, self::B::Y fieldOfB2) → self::B<self::B::X%, self::B::Y>
+    : self::B::fieldOfB = fieldOfB, self::B::fieldOfB2 = fieldOfB2, super core::Object::•()
+    ;
+}
+abstract class M extends core::Object {
+  static field core::int staticFieldOfM = null;
+  field core::int fieldOfM = null;
+}
+abstract class N<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+  generic-covariant-impl field self::N::X% fieldOfN = null;
+  generic-covariant-impl field self::N::Y fieldOfN2 = null;
+}
+class C<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+  static field core::int? staticFieldOfX = null;
+  static field core::int staticFieldOfXInitialized = 42;
+  generic-covariant-impl field self::C::X? fieldOfX = null;
+  field core::int? fieldOfX2 = null;
+  field dynamic fieldOfX3 = null;
+  field core::Null? fieldOfX4 = null;
+  field () →? core::int fieldOfX5 = null;
+  generic-covariant-impl field self::C::Y? fieldOfX6 = null;
+  late static field core::int lateStaticFieldOfC;
+  late field core::int fieldOfC7;
+  late generic-covariant-impl field self::C::X% fieldOfC8;
+  late generic-covariant-impl field self::C::Y fieldOfC9;
+  field core::int fieldOfC10;
+  constructor foo(core::int fieldOfC10) → self::C<self::C::X%, self::C::Y>
+    : self::C::fieldOfC10 = fieldOfC10, super core::Object::•()
+    ;
+  constructor bar(core::int fieldOfC10) → self::C<self::C::X%, self::C::Y>
+    : self::C::fieldOfC10 = fieldOfC10, super core::Object::•()
+    ;
+}
+abstract class L<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+  static field core::int? staticFieldOfL = null;
+  static field core::int staticFieldOfLInitialized = 42;
+  generic-covariant-impl field self::L::X? fieldOfL = null;
+  field core::int? fieldOfL2 = null;
+  field dynamic fieldOfL3 = null;
+  field core::Null? fieldOfL4 = null;
+  field () →? core::int fieldOfL5 = null;
+  generic-covariant-impl field self::L::Y? fieldOfL6 = null;
+  late static field core::int lateStaticFieldOfM;
+  late field core::int fieldOfM7;
+  late generic-covariant-impl field self::L::X% fieldOfM8;
+  late generic-covariant-impl field self::L::Y fieldOfM9;
+}
+extension P on self::Foo {
+  static field staticFieldOfE = self::P|staticFieldOfE;
+}
+extension Q on self::Foo {
+  static field staticFieldOfQ = self::Q|staticFieldOfQ;
+  static field lateStaticFieldOfQ = self::Q|lateStaticFieldOfQ;
+  static field staticFieldOfQInitialized = self::Q|staticFieldOfQInitialized;
+}
+static field core::int topLevelField;
+static field core::int P|staticFieldOfE;
+static field core::int? nullableTopLevelField;
+late static field core::int lateTopLevelField;
+static field core::int topLevelFieldWithInitializer = 42;
+static field core::int? Q|staticFieldOfQ;
+late static field core::int Q|lateStaticFieldOfQ;
+static field core::int Q|staticFieldOfQInitialized = 42;
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.weak.transformed.expect
new file mode 100644
index 0000000..29e2dde
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.weak.transformed.expect
@@ -0,0 +1,128 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:7:5: Warning: Field 'topLevelField' isn't initialized and its type 'int' doesn't allow null.
+// int topLevelField; // Error.
+//     ^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:10:14: Warning: Field 'staticFieldOfA' isn't initialized and its type 'int' doesn't allow null.
+//   static int staticFieldOfA; // Error.
+//              ^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:24:14: Warning: Field 'staticFieldOfM' isn't initialized and its type 'int' doesn't allow null.
+//   static int staticFieldOfM; // Error.
+//              ^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:11:7: Warning: This constructor doesn't initialize field 'fieldOfA' and its type 'int' doesn't allow null.
+//   int fieldOfA; // Error.
+//       ^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:17:5: Warning: This constructor doesn't initialize field 'fieldOfB' and its type 'X' doesn't allow null.
+//   X fieldOfB; // Error.
+//     ^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:18:5: Warning: This constructor doesn't initialize field 'fieldOfB2' and its type 'Y' doesn't allow null.
+//   Y fieldOfB2; // Error.
+//     ^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:25:7: Warning: Field 'fieldOfM' isn't initialized and its type 'int' doesn't allow null.
+//   int fieldOfM; // Error.
+//       ^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:29:5: Warning: Field 'fieldOfN' isn't initialized and its type 'X' doesn't allow null.
+//   X fieldOfN; // Error.
+//     ^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:30:5: Warning: Field 'fieldOfN2' isn't initialized and its type 'Y' doesn't allow null.
+//   Y fieldOfN2; // Error.
+//     ^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+  synthetic constructor •() → self::Foo
+    : super core::Object::•()
+    ;
+}
+class A extends core::Object {
+  static field core::int staticFieldOfA = null;
+  field core::int fieldOfA;
+  constructor foo() → self::A
+    : self::A::fieldOfA = null, super core::Object::•()
+    ;
+  constructor bar(core::int fieldOfA) → self::A
+    : self::A::fieldOfA = fieldOfA, super core::Object::•()
+    ;
+}
+class B<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+  generic-covariant-impl field self::B::X% fieldOfB;
+  generic-covariant-impl field self::B::Y fieldOfB2;
+  constructor foo() → self::B<self::B::X%, self::B::Y>
+    : self::B::fieldOfB2 = null, self::B::fieldOfB = null, super core::Object::•()
+    ;
+  constructor bar(self::B::X% fieldOfB, self::B::Y fieldOfB2) → self::B<self::B::X%, self::B::Y>
+    : self::B::fieldOfB = fieldOfB, self::B::fieldOfB2 = fieldOfB2, super core::Object::•()
+    ;
+}
+abstract class M extends core::Object {
+  static field core::int staticFieldOfM = null;
+  field core::int fieldOfM = null;
+}
+abstract class N<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+  generic-covariant-impl field self::N::X% fieldOfN = null;
+  generic-covariant-impl field self::N::Y fieldOfN2 = null;
+}
+class C<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+  static field core::int? staticFieldOfX = null;
+  static field core::int staticFieldOfXInitialized = 42;
+  generic-covariant-impl field self::C::X? fieldOfX = null;
+  field core::int? fieldOfX2 = null;
+  field dynamic fieldOfX3 = null;
+  field core::Null? fieldOfX4 = null;
+  field () →? core::int fieldOfX5 = null;
+  generic-covariant-impl field self::C::Y? fieldOfX6 = null;
+  late static field core::int lateStaticFieldOfC;
+  late field core::int fieldOfC7;
+  late generic-covariant-impl field self::C::X% fieldOfC8;
+  late generic-covariant-impl field self::C::Y fieldOfC9;
+  field core::int fieldOfC10;
+  constructor foo(core::int fieldOfC10) → self::C<self::C::X%, self::C::Y>
+    : self::C::fieldOfC10 = fieldOfC10, super core::Object::•()
+    ;
+  constructor bar(core::int fieldOfC10) → self::C<self::C::X%, self::C::Y>
+    : self::C::fieldOfC10 = fieldOfC10, super core::Object::•()
+    ;
+}
+abstract class L<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+  static field core::int? staticFieldOfL = null;
+  static field core::int staticFieldOfLInitialized = 42;
+  generic-covariant-impl field self::L::X? fieldOfL = null;
+  field core::int? fieldOfL2 = null;
+  field dynamic fieldOfL3 = null;
+  field core::Null? fieldOfL4 = null;
+  field () →? core::int fieldOfL5 = null;
+  generic-covariant-impl field self::L::Y? fieldOfL6 = null;
+  late static field core::int lateStaticFieldOfM;
+  late field core::int fieldOfM7;
+  late generic-covariant-impl field self::L::X% fieldOfM8;
+  late generic-covariant-impl field self::L::Y fieldOfM9;
+}
+extension P on self::Foo {
+  static field staticFieldOfE = self::P|staticFieldOfE;
+}
+extension Q on self::Foo {
+  static field staticFieldOfQ = self::Q|staticFieldOfQ;
+  static field lateStaticFieldOfQ = self::Q|lateStaticFieldOfQ;
+  static field staticFieldOfQInitialized = self::Q|staticFieldOfQInitialized;
+}
+static field core::int topLevelField;
+static field core::int P|staticFieldOfE;
+static field core::int? nullableTopLevelField;
+late static field core::int lateTopLevelField;
+static field core::int topLevelFieldWithInitializer = 42;
+static field core::int? Q|staticFieldOfQ;
+late static field core::int Q|lateStaticFieldOfQ;
+static field core::int Q|staticFieldOfQInitialized = 42;
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/null_check_context.dart b/pkg/front_end/testcases/nnbd/null_check_context.dart
new file mode 100644
index 0000000..749eab7
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/null_check_context.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2020, 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.
+
+abstract class A {
+  T bar<T>();
+  String foo() => bar()!;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/null_check_context.dart.outline.expect b/pkg/front_end/testcases/nnbd/null_check_context.dart.outline.expect
new file mode 100644
index 0000000..61468b9
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/null_check_context.dart.outline.expect
@@ -0,0 +1,13 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+abstract class A extends core::Object {
+  synthetic constructor •() → self::A
+    ;
+  abstract method bar<T extends core::Object? = dynamic>() → self::A::bar::T%;
+  method foo() → core::String
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/nnbd/null_check_context.dart.strong.expect b/pkg/front_end/testcases/nnbd/null_check_context.dart.strong.expect
new file mode 100644
index 0000000..c4bea6d
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/null_check_context.dart.strong.expect
@@ -0,0 +1,13 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+abstract class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  abstract method bar<T extends core::Object? = dynamic>() → self::A::bar::T%;
+  method foo() → core::String
+    return this.{self::A::bar}<core::String?>()!;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/null_check_context.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/null_check_context.dart.strong.transformed.expect
new file mode 100644
index 0000000..c4bea6d
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/null_check_context.dart.strong.transformed.expect
@@ -0,0 +1,13 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+abstract class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  abstract method bar<T extends core::Object? = dynamic>() → self::A::bar::T%;
+  method foo() → core::String
+    return this.{self::A::bar}<core::String?>()!;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/null_check_context.dart.weak.expect b/pkg/front_end/testcases/nnbd/null_check_context.dart.weak.expect
new file mode 100644
index 0000000..c4bea6d
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/null_check_context.dart.weak.expect
@@ -0,0 +1,13 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+abstract class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  abstract method bar<T extends core::Object? = dynamic>() → self::A::bar::T%;
+  method foo() → core::String
+    return this.{self::A::bar}<core::String?>()!;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/null_check_context.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/null_check_context.dart.weak.transformed.expect
new file mode 100644
index 0000000..c4bea6d
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/null_check_context.dart.weak.transformed.expect
@@ -0,0 +1,13 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+abstract class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  abstract method bar<T extends core::Object? = dynamic>() → self::A::bar::T%;
+  method foo() → core::String
+    return this.{self::A::bar}<core::String?>()!;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/null_shorting.dart b/pkg/front_end/testcases/nnbd/null_shorting.dart
index c1f8a44..8b1c781 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting.dart
+++ b/pkg/front_end/testcases/nnbd/null_shorting.dart
@@ -179,8 +179,6 @@
   nullable2 = n2?.[nullable2] += 0;
   n2?.[nullable2] += 0;
   nullable2 = n2?.[nullable2] += 0;
-  // TODO(johnniwinther): ++ should probably not be null-shorted, awaiting spec
-  //  update.
   n2?.[nullable2]++;
   nullable2 = n2?.[nullable2]++;
   ++n2?.[nullable2];
@@ -196,8 +194,6 @@
   n1?.nonNullable2[nullable2][nullable2]?.nonNullable2Method();
   n1?.nonNullable2[nullable2][nullable2] += 0;
   nullable2 = n1?.nonNullable2[nullable2][nullable2] += 0;
-  // TODO(johnniwinther): ++ should probably not be null-shorted, awaiting spec
-  //  update.
   n1?.nonNullable2[nullable2][nullable2]++;
   nullable2 = n1?.nonNullable2[nullable2][nullable2]++;
   ++n1?.nonNullable2[nullable2][nullable2];
@@ -212,8 +208,6 @@
   nullable1 = n1?.[nullable1]?.[nullable1] ??= nullable1;
   n3?.[nullable3]?.[nullable2] += 0;
   nullable2 = n3?.[nullable3]?.[nullable2] += 0;
-  // TODO(johnniwinther): ++ should probably not be null-shorted, awaiting spec
-  //  update.
   n3?.[nullable3]?.[nullable2]++;
   nullable2 = n3?.[nullable3]?.[nullable2]++;
   ++n3?.[nullable3]?.[nullable2];
@@ -229,8 +223,6 @@
   nullable2 = n2?.nonNullable2 += 0;
   n2?.nonNullable2.nonNullable2 += 0;
   nullable2 = n2?.nonNullable2.nonNullable2 += 0;
-  // TODO(johnniwinther): ++ should probably not be null-shorted, awaiting spec
-  //  update.
   n2?.nonNullable2++;
   nullable2 = n2?.nonNullable2++;
   ++n2?.nonNullable2;
diff --git a/pkg/front_end/testcases/nnbd/null_shorting.dart.strong.expect b/pkg/front_end/testcases/nnbd/null_shorting.dart.strong.expect
index 5e1627d..7f40a02 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/null_shorting.dart.strong.expect
@@ -14,12 +14,12 @@
 //   throws(() => (n1?.nonNullable1Method()).nullable1);
 //                                           ^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/null_shorting.dart:226:33: Error: Operator '+' cannot be called on 'Class1?' because it is potentially null.
+// pkg/front_end/testcases/nnbd/null_shorting.dart:220:33: Error: Operator '+' cannot be called on 'Class1?' because it is potentially null.
 //  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting.dart'.
 //   throws(() => n1?.nonNullable1 + 0);
 //                                 ^
 //
-// pkg/front_end/testcases/nnbd/null_shorting.dart:227:16: Error: Operator 'unary-' cannot be called on 'Class1?' because it is potentially null.
+// pkg/front_end/testcases/nnbd/null_shorting.dart:221:16: Error: Operator 'unary-' cannot be called on 'Class1?' because it is potentially null.
 //  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting.dart'.
 //   throws(() => -n1?.nonNullable1);
 //                ^
@@ -232,11 +232,11 @@
 }
 static method operatorAccess(self::Class1? n1, self::Class2? n2) → void {
   self::Class2? nullable2 = n2;
-  self::throws(() → self::Class1? => let final<BottomType> #t241 = invalid-expression "pkg/front_end/testcases/nnbd/null_shorting.dart:226:33: Error: Operator '+' cannot be called on 'Class1?' because it is potentially null.
+  self::throws(() → self::Class1? => let final<BottomType> #t241 = invalid-expression "pkg/front_end/testcases/nnbd/null_shorting.dart:220:33: Error: Operator '+' cannot be called on 'Class1?' because it is potentially null.
  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting.dart'.
   throws(() => n1?.nonNullable1 + 0);
                                 ^" in (let final self::Class1? #t242 = n1 in #t242.{core::Object::==}(null) ?{self::Class1?} null : #t242{self::Class1}.{self::Class1::nonNullable1}).{self::Class1::+}(0));
-  self::throws(() → self::Class1? => let final<BottomType> #t243 = invalid-expression "pkg/front_end/testcases/nnbd/null_shorting.dart:227:16: Error: Operator 'unary-' cannot be called on 'Class1?' because it is potentially null.
+  self::throws(() → self::Class1? => let final<BottomType> #t243 = invalid-expression "pkg/front_end/testcases/nnbd/null_shorting.dart:221:16: Error: Operator 'unary-' cannot be called on 'Class1?' because it is potentially null.
  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting.dart'.
   throws(() => -n1?.nonNullable1);
                ^" in (let final self::Class1? #t244 = n1 in #t244.{core::Object::==}(null) ?{self::Class1?} null : #t244{self::Class1}.{self::Class1::nonNullable1}).{self::Class1::unary-}());
diff --git a/pkg/front_end/testcases/nnbd/null_shorting.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/null_shorting.dart.strong.transformed.expect
index 5e1627d..7f40a02 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/null_shorting.dart.strong.transformed.expect
@@ -14,12 +14,12 @@
 //   throws(() => (n1?.nonNullable1Method()).nullable1);
 //                                           ^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/null_shorting.dart:226:33: Error: Operator '+' cannot be called on 'Class1?' because it is potentially null.
+// pkg/front_end/testcases/nnbd/null_shorting.dart:220:33: Error: Operator '+' cannot be called on 'Class1?' because it is potentially null.
 //  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting.dart'.
 //   throws(() => n1?.nonNullable1 + 0);
 //                                 ^
 //
-// pkg/front_end/testcases/nnbd/null_shorting.dart:227:16: Error: Operator 'unary-' cannot be called on 'Class1?' because it is potentially null.
+// pkg/front_end/testcases/nnbd/null_shorting.dart:221:16: Error: Operator 'unary-' cannot be called on 'Class1?' because it is potentially null.
 //  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting.dart'.
 //   throws(() => -n1?.nonNullable1);
 //                ^
@@ -232,11 +232,11 @@
 }
 static method operatorAccess(self::Class1? n1, self::Class2? n2) → void {
   self::Class2? nullable2 = n2;
-  self::throws(() → self::Class1? => let final<BottomType> #t241 = invalid-expression "pkg/front_end/testcases/nnbd/null_shorting.dart:226:33: Error: Operator '+' cannot be called on 'Class1?' because it is potentially null.
+  self::throws(() → self::Class1? => let final<BottomType> #t241 = invalid-expression "pkg/front_end/testcases/nnbd/null_shorting.dart:220:33: Error: Operator '+' cannot be called on 'Class1?' because it is potentially null.
  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting.dart'.
   throws(() => n1?.nonNullable1 + 0);
                                 ^" in (let final self::Class1? #t242 = n1 in #t242.{core::Object::==}(null) ?{self::Class1?} null : #t242{self::Class1}.{self::Class1::nonNullable1}).{self::Class1::+}(0));
-  self::throws(() → self::Class1? => let final<BottomType> #t243 = invalid-expression "pkg/front_end/testcases/nnbd/null_shorting.dart:227:16: Error: Operator 'unary-' cannot be called on 'Class1?' because it is potentially null.
+  self::throws(() → self::Class1? => let final<BottomType> #t243 = invalid-expression "pkg/front_end/testcases/nnbd/null_shorting.dart:221:16: Error: Operator 'unary-' cannot be called on 'Class1?' because it is potentially null.
  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting.dart'.
   throws(() => -n1?.nonNullable1);
                ^" in (let final self::Class1? #t244 = n1 in #t244.{core::Object::==}(null) ?{self::Class1?} null : #t244{self::Class1}.{self::Class1::nonNullable1}).{self::Class1::unary-}());
diff --git a/pkg/front_end/testcases/nnbd/null_shorting.dart.weak.expect b/pkg/front_end/testcases/nnbd/null_shorting.dart.weak.expect
index b9f84d6..0a88580 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/null_shorting.dart.weak.expect
@@ -14,12 +14,12 @@
 //   throws(() => (n1?.nonNullable1Method()).nullable1);
 //                                           ^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/null_shorting.dart:226:33: Warning: Operator '+' is called on 'Class1?' which is potentially null.
+// pkg/front_end/testcases/nnbd/null_shorting.dart:220:33: Warning: Operator '+' is called on 'Class1?' which is potentially null.
 //  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting.dart'.
 //   throws(() => n1?.nonNullable1 + 0);
 //                                 ^
 //
-// pkg/front_end/testcases/nnbd/null_shorting.dart:227:16: Warning: Operator 'unary-' is called on 'Class1?' which is potentially null.
+// pkg/front_end/testcases/nnbd/null_shorting.dart:221:16: Warning: Operator 'unary-' is called on 'Class1?' which is potentially null.
 //  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting.dart'.
 //   throws(() => -n1?.nonNullable1);
 //                ^
diff --git a/pkg/front_end/testcases/nnbd/null_shorting.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/null_shorting.dart.weak.transformed.expect
index b9f84d6..0a88580 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/null_shorting.dart.weak.transformed.expect
@@ -14,12 +14,12 @@
 //   throws(() => (n1?.nonNullable1Method()).nullable1);
 //                                           ^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/null_shorting.dart:226:33: Warning: Operator '+' is called on 'Class1?' which is potentially null.
+// pkg/front_end/testcases/nnbd/null_shorting.dart:220:33: Warning: Operator '+' is called on 'Class1?' which is potentially null.
 //  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting.dart'.
 //   throws(() => n1?.nonNullable1 + 0);
 //                                 ^
 //
-// pkg/front_end/testcases/nnbd/null_shorting.dart:227:16: Warning: Operator 'unary-' is called on 'Class1?' which is potentially null.
+// pkg/front_end/testcases/nnbd/null_shorting.dart:221:16: Warning: Operator 'unary-' is called on 'Class1?' which is potentially null.
 //  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting.dart'.
 //   throws(() => -n1?.nonNullable1);
 //                ^
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart b/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart
index aba8676..64f63c5 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart
+++ b/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart
@@ -203,8 +203,6 @@
   nullable2 = Extension2(n2)?.[nullable2] += 0;
   Extension2(n2)?.[nullable2] += 0;
   nullable2 = Extension2(n2)?.[nullable2] += 0;
-  // TODO(johnniwinther): ++ should probably not be null-shorted, awaiting spec
-  //  update.
   Extension2(n2)?.[nullable2]++;
   nullable2 = Extension2(n2)?.[nullable2]++;
   ++Extension2(n2)?.[nullable2];
@@ -220,8 +218,6 @@
   Extension1(n1)?.nonNullable2[nullable2][nullable2]?.nonNullable2Method();
   Extension1(n1)?.nonNullable2[nullable2][nullable2] += 0;
   nullable2 = Extension1(n1)?.nonNullable2[nullable2][nullable2] += 0;
-  // TODO(johnniwinther): ++ should probably not be null-shorted, awaiting spec
-  //  update.
   Extension1(n1)?.nonNullable2[nullable2][nullable2]++;
   nullable2 = Extension1(n1)?.nonNullable2[nullable2][nullable2]++;
   ++Extension1(n1)?.nonNullable2[nullable2][nullable2];
@@ -236,8 +232,6 @@
   nullable1 = Extension1(n1)?.[nullable1]?.[nullable1] ??= nullable1;
   Extension3(n3)?.[nullable3]?.[nullable2] += 0;
   nullable2 = Extension3(n3)?.[nullable3]?.[nullable2] += 0;
-  // TODO(johnniwinther): ++ should probably not be null-shorted, awaiting spec
-  //  update.
   Extension3(n3)?.[nullable3]?.[nullable2]++;
   nullable2 = Extension3(n3)?.[nullable3]?.[nullable2]++;
   ++Extension3(n3)?.[nullable3]?.[nullable2];
@@ -253,8 +247,6 @@
   nullable2 = Extension2(n2)?.nonNullable2 += 0;
   Extension2(n2)?.nonNullable2.nonNullable2 += 0;
   nullable2 = Extension2(n2)?.nonNullable2.nonNullable2 += 0;
-  // TODO(johnniwinther): ++ should probably not be null-shorted, awaiting spec
-  //  update.
   Extension2(n2)?.nonNullable2++;
   nullable2 = Extension2(n2)?.nonNullable2++;
   ++Extension2(n2)?.nonNullable2;
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart.strong.expect b/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart.strong.expect
index 7bd0924..93172a1 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart.strong.expect
@@ -14,12 +14,12 @@
 //   throws(() => (Extension1(n1)?.nonNullable1Method()).nullable1);
 //                                                       ^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart:250:45: Error: Operator '+' cannot be called on 'Class1?' because it is potentially null.
+// pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart:244:45: Error: Operator '+' cannot be called on 'Class1?' because it is potentially null.
 //  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart'.
 //   throws(() => Extension1(n1)?.nonNullable1 + 0);
 //                                             ^
 //
-// pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart:251:16: Error: Operator 'unary-' cannot be called on 'Class1?' because it is potentially null.
+// pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart:245:16: Error: Operator 'unary-' cannot be called on 'Class1?' because it is potentially null.
 //  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart'.
 //   throws(() => -Extension1(n1)?.nonNullable1);
 //                ^
@@ -261,11 +261,11 @@
 }
 static method operatorAccess(self::Class1? n1, self::Class2? n2) → void {
   self::Class2? nullable2 = n2;
-  self::throws(() → self::Class1? => let final<BottomType> #t327 = invalid-expression "pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart:250:45: Error: Operator '+' cannot be called on 'Class1?' because it is potentially null.
+  self::throws(() → self::Class1? => let final<BottomType> #t327 = invalid-expression "pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart:244:45: Error: Operator '+' cannot be called on 'Class1?' because it is potentially null.
  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart'.
   throws(() => Extension1(n1)?.nonNullable1 + 0);
                                             ^" in self::Extension1|+(let final self::Class1? #t328 = n1 in #t328.{core::Object::==}(null) ?{self::Class1?} null : self::Extension1|get#nonNullable1(#t328{self::Class1}), 0));
-  self::throws(() → self::Class1? => let final<BottomType> #t329 = invalid-expression "pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart:251:16: Error: Operator 'unary-' cannot be called on 'Class1?' because it is potentially null.
+  self::throws(() → self::Class1? => let final<BottomType> #t329 = invalid-expression "pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart:245:16: Error: Operator 'unary-' cannot be called on 'Class1?' because it is potentially null.
  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart'.
   throws(() => -Extension1(n1)?.nonNullable1);
                ^" in self::Extension1|unary-(let final self::Class1? #t330 = n1 in #t330.{core::Object::==}(null) ?{self::Class1?} null : self::Extension1|get#nonNullable1(#t330{self::Class1})));
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart.strong.transformed.expect
index 7bd0924..93172a1 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart.strong.transformed.expect
@@ -14,12 +14,12 @@
 //   throws(() => (Extension1(n1)?.nonNullable1Method()).nullable1);
 //                                                       ^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart:250:45: Error: Operator '+' cannot be called on 'Class1?' because it is potentially null.
+// pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart:244:45: Error: Operator '+' cannot be called on 'Class1?' because it is potentially null.
 //  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart'.
 //   throws(() => Extension1(n1)?.nonNullable1 + 0);
 //                                             ^
 //
-// pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart:251:16: Error: Operator 'unary-' cannot be called on 'Class1?' because it is potentially null.
+// pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart:245:16: Error: Operator 'unary-' cannot be called on 'Class1?' because it is potentially null.
 //  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart'.
 //   throws(() => -Extension1(n1)?.nonNullable1);
 //                ^
@@ -261,11 +261,11 @@
 }
 static method operatorAccess(self::Class1? n1, self::Class2? n2) → void {
   self::Class2? nullable2 = n2;
-  self::throws(() → self::Class1? => let final<BottomType> #t327 = invalid-expression "pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart:250:45: Error: Operator '+' cannot be called on 'Class1?' because it is potentially null.
+  self::throws(() → self::Class1? => let final<BottomType> #t327 = invalid-expression "pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart:244:45: Error: Operator '+' cannot be called on 'Class1?' because it is potentially null.
  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart'.
   throws(() => Extension1(n1)?.nonNullable1 + 0);
                                             ^" in self::Extension1|+(let final self::Class1? #t328 = n1 in #t328.{core::Object::==}(null) ?{self::Class1?} null : self::Extension1|get#nonNullable1(#t328{self::Class1}), 0));
-  self::throws(() → self::Class1? => let final<BottomType> #t329 = invalid-expression "pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart:251:16: Error: Operator 'unary-' cannot be called on 'Class1?' because it is potentially null.
+  self::throws(() → self::Class1? => let final<BottomType> #t329 = invalid-expression "pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart:245:16: Error: Operator 'unary-' cannot be called on 'Class1?' because it is potentially null.
  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart'.
   throws(() => -Extension1(n1)?.nonNullable1);
                ^" in self::Extension1|unary-(let final self::Class1? #t330 = n1 in #t330.{core::Object::==}(null) ?{self::Class1?} null : self::Extension1|get#nonNullable1(#t330{self::Class1})));
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart.weak.expect b/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart.weak.expect
index d564c89..0f12197 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart.weak.expect
@@ -14,12 +14,12 @@
 //   throws(() => (Extension1(n1)?.nonNullable1Method()).nullable1);
 //                                                       ^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart:250:45: Warning: Operator '+' is called on 'Class1?' which is potentially null.
+// pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart:244:45: Warning: Operator '+' is called on 'Class1?' which is potentially null.
 //  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart'.
 //   throws(() => Extension1(n1)?.nonNullable1 + 0);
 //                                             ^
 //
-// pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart:251:16: Warning: Operator 'unary-' is called on 'Class1?' which is potentially null.
+// pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart:245:16: Warning: Operator 'unary-' is called on 'Class1?' which is potentially null.
 //  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart'.
 //   throws(() => -Extension1(n1)?.nonNullable1);
 //                ^
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart.weak.transformed.expect
index d564c89..0f12197 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart.weak.transformed.expect
@@ -14,12 +14,12 @@
 //   throws(() => (Extension1(n1)?.nonNullable1Method()).nullable1);
 //                                                       ^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart:250:45: Warning: Operator '+' is called on 'Class1?' which is potentially null.
+// pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart:244:45: Warning: Operator '+' is called on 'Class1?' which is potentially null.
 //  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart'.
 //   throws(() => Extension1(n1)?.nonNullable1 + 0);
 //                                             ^
 //
-// pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart:251:16: Warning: Operator 'unary-' is called on 'Class1?' which is potentially null.
+// pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart:245:16: Warning: Operator 'unary-' is called on 'Class1?' which is potentially null.
 //  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart'.
 //   throws(() => -Extension1(n1)?.nonNullable1);
 //                ^
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_extension.dart b/pkg/front_end/testcases/nnbd/null_shorting_extension.dart
index 4ec6ad4..baa5adc 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting_extension.dart
+++ b/pkg/front_end/testcases/nnbd/null_shorting_extension.dart
@@ -185,8 +185,6 @@
   nullable2 = n2?.[nullable2] += 0;
   n2?.[nullable2] += 0;
   nullable2 = n2?.[nullable2] += 0;
-  // TODO(johnniwinther): ++ should probably not be null-shorted, awaiting spec
-  //  update.
   n2?.[nullable2]++;
   nullable2 = n2?.[nullable2]++;
   ++n2?.[nullable2];
@@ -202,8 +200,6 @@
   n1?.nonNullable2[nullable2][nullable2]?.nonNullable2Method();
   n1?.nonNullable2[nullable2][nullable2] += 0;
   nullable2 = n1?.nonNullable2[nullable2][nullable2] += 0;
-  // TODO(johnniwinther): ++ should probably not be null-shorted, awaiting spec
-  //  update.
   n1?.nonNullable2[nullable2][nullable2]++;
   nullable2 = n1?.nonNullable2[nullable2][nullable2]++;
   ++n1?.nonNullable2[nullable2][nullable2];
@@ -218,8 +214,6 @@
   nullable1 = n1?.[nullable1]?.[nullable1] ??= nullable1;
   n3?.[nullable3]?.[nullable2] += 0;
   nullable2 = n3?.[nullable3]?.[nullable2] += 0;
-  // TODO(johnniwinther): ++ should probably not be null-shorted, awaiting spec
-  //  update.
   n3?.[nullable3]?.[nullable2]++;
   nullable2 = n3?.[nullable3]?.[nullable2]++;
   ++n3?.[nullable3]?.[nullable2];
@@ -235,8 +229,6 @@
   nullable2 = n2?.nonNullable2 += 0;
   n2?.nonNullable2.nonNullable2 += 0;
   nullable2 = n2?.nonNullable2.nonNullable2 += 0;
-  // TODO(johnniwinther): ++ should probably not be null-shorted, awaiting spec
-  //  update.
   n2?.nonNullable2++;
   nullable2 = n2?.nonNullable2++;
   ++n2?.nonNullable2;
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_extension.dart.strong.expect b/pkg/front_end/testcases/nnbd/null_shorting_extension.dart.strong.expect
index e4333bc..08bb2f4 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting_extension.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/null_shorting_extension.dart.strong.expect
@@ -14,12 +14,12 @@
 //   throws(() => (n1?.nonNullable1Method()).nullable1);
 //                                           ^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/null_shorting_extension.dart:232:33: Error: Operator '+' cannot be called on 'Class1?' because it is potentially null.
+// pkg/front_end/testcases/nnbd/null_shorting_extension.dart:226:33: Error: Operator '+' cannot be called on 'Class1?' because it is potentially null.
 //  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting_extension.dart'.
 //   throws(() => n1?.nonNullable1 + 0);
 //                                 ^
 //
-// pkg/front_end/testcases/nnbd/null_shorting_extension.dart:233:16: Error: Operator 'unary-' cannot be called on 'Class1?' because it is potentially null.
+// pkg/front_end/testcases/nnbd/null_shorting_extension.dart:227:16: Error: Operator 'unary-' cannot be called on 'Class1?' because it is potentially null.
 //  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting_extension.dart'.
 //   throws(() => -n1?.nonNullable1);
 //                ^
@@ -261,11 +261,11 @@
 }
 static method operatorAccess(self::Class1? n1, self::Class2? n2) → void {
   self::Class2? nullable2 = n2;
-  self::throws(() → self::Class1? => let final<BottomType> #t327 = invalid-expression "pkg/front_end/testcases/nnbd/null_shorting_extension.dart:232:33: Error: Operator '+' cannot be called on 'Class1?' because it is potentially null.
+  self::throws(() → self::Class1? => let final<BottomType> #t327 = invalid-expression "pkg/front_end/testcases/nnbd/null_shorting_extension.dart:226:33: Error: Operator '+' cannot be called on 'Class1?' because it is potentially null.
  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting_extension.dart'.
   throws(() => n1?.nonNullable1 + 0);
                                 ^" in self::Extension1|+(let final self::Class1? #t328 = n1 in #t328.{core::Object::==}(null) ?{self::Class1?} null : self::Extension1|get#nonNullable1(#t328{self::Class1}), 0));
-  self::throws(() → self::Class1? => let final<BottomType> #t329 = invalid-expression "pkg/front_end/testcases/nnbd/null_shorting_extension.dart:233:16: Error: Operator 'unary-' cannot be called on 'Class1?' because it is potentially null.
+  self::throws(() → self::Class1? => let final<BottomType> #t329 = invalid-expression "pkg/front_end/testcases/nnbd/null_shorting_extension.dart:227:16: Error: Operator 'unary-' cannot be called on 'Class1?' because it is potentially null.
  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting_extension.dart'.
   throws(() => -n1?.nonNullable1);
                ^" in self::Extension1|unary-(let final self::Class1? #t330 = n1 in #t330.{core::Object::==}(null) ?{self::Class1?} null : self::Extension1|get#nonNullable1(#t330{self::Class1})));
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_extension.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/null_shorting_extension.dart.strong.transformed.expect
index e4333bc..08bb2f4 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting_extension.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/null_shorting_extension.dart.strong.transformed.expect
@@ -14,12 +14,12 @@
 //   throws(() => (n1?.nonNullable1Method()).nullable1);
 //                                           ^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/null_shorting_extension.dart:232:33: Error: Operator '+' cannot be called on 'Class1?' because it is potentially null.
+// pkg/front_end/testcases/nnbd/null_shorting_extension.dart:226:33: Error: Operator '+' cannot be called on 'Class1?' because it is potentially null.
 //  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting_extension.dart'.
 //   throws(() => n1?.nonNullable1 + 0);
 //                                 ^
 //
-// pkg/front_end/testcases/nnbd/null_shorting_extension.dart:233:16: Error: Operator 'unary-' cannot be called on 'Class1?' because it is potentially null.
+// pkg/front_end/testcases/nnbd/null_shorting_extension.dart:227:16: Error: Operator 'unary-' cannot be called on 'Class1?' because it is potentially null.
 //  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting_extension.dart'.
 //   throws(() => -n1?.nonNullable1);
 //                ^
@@ -261,11 +261,11 @@
 }
 static method operatorAccess(self::Class1? n1, self::Class2? n2) → void {
   self::Class2? nullable2 = n2;
-  self::throws(() → self::Class1? => let final<BottomType> #t327 = invalid-expression "pkg/front_end/testcases/nnbd/null_shorting_extension.dart:232:33: Error: Operator '+' cannot be called on 'Class1?' because it is potentially null.
+  self::throws(() → self::Class1? => let final<BottomType> #t327 = invalid-expression "pkg/front_end/testcases/nnbd/null_shorting_extension.dart:226:33: Error: Operator '+' cannot be called on 'Class1?' because it is potentially null.
  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting_extension.dart'.
   throws(() => n1?.nonNullable1 + 0);
                                 ^" in self::Extension1|+(let final self::Class1? #t328 = n1 in #t328.{core::Object::==}(null) ?{self::Class1?} null : self::Extension1|get#nonNullable1(#t328{self::Class1}), 0));
-  self::throws(() → self::Class1? => let final<BottomType> #t329 = invalid-expression "pkg/front_end/testcases/nnbd/null_shorting_extension.dart:233:16: Error: Operator 'unary-' cannot be called on 'Class1?' because it is potentially null.
+  self::throws(() → self::Class1? => let final<BottomType> #t329 = invalid-expression "pkg/front_end/testcases/nnbd/null_shorting_extension.dart:227:16: Error: Operator 'unary-' cannot be called on 'Class1?' because it is potentially null.
  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting_extension.dart'.
   throws(() => -n1?.nonNullable1);
                ^" in self::Extension1|unary-(let final self::Class1? #t330 = n1 in #t330.{core::Object::==}(null) ?{self::Class1?} null : self::Extension1|get#nonNullable1(#t330{self::Class1})));
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_extension.dart.weak.expect b/pkg/front_end/testcases/nnbd/null_shorting_extension.dart.weak.expect
index 1d2e7cc..47d4d98 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting_extension.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/null_shorting_extension.dart.weak.expect
@@ -14,12 +14,12 @@
 //   throws(() => (n1?.nonNullable1Method()).nullable1);
 //                                           ^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/null_shorting_extension.dart:232:33: Warning: Operator '+' is called on 'Class1?' which is potentially null.
+// pkg/front_end/testcases/nnbd/null_shorting_extension.dart:226:33: Warning: Operator '+' is called on 'Class1?' which is potentially null.
 //  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting_extension.dart'.
 //   throws(() => n1?.nonNullable1 + 0);
 //                                 ^
 //
-// pkg/front_end/testcases/nnbd/null_shorting_extension.dart:233:16: Warning: Operator 'unary-' is called on 'Class1?' which is potentially null.
+// pkg/front_end/testcases/nnbd/null_shorting_extension.dart:227:16: Warning: Operator 'unary-' is called on 'Class1?' which is potentially null.
 //  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting_extension.dart'.
 //   throws(() => -n1?.nonNullable1);
 //                ^
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_extension.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/null_shorting_extension.dart.weak.transformed.expect
index 1d2e7cc..47d4d98 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting_extension.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/null_shorting_extension.dart.weak.transformed.expect
@@ -14,12 +14,12 @@
 //   throws(() => (n1?.nonNullable1Method()).nullable1);
 //                                           ^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/null_shorting_extension.dart:232:33: Warning: Operator '+' is called on 'Class1?' which is potentially null.
+// pkg/front_end/testcases/nnbd/null_shorting_extension.dart:226:33: Warning: Operator '+' is called on 'Class1?' which is potentially null.
 //  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting_extension.dart'.
 //   throws(() => n1?.nonNullable1 + 0);
 //                                 ^
 //
-// pkg/front_end/testcases/nnbd/null_shorting_extension.dart:233:16: Warning: Operator 'unary-' is called on 'Class1?' which is potentially null.
+// pkg/front_end/testcases/nnbd/null_shorting_extension.dart:227:16: Warning: Operator 'unary-' is called on 'Class1?' which is potentially null.
 //  - 'Class1' is from 'pkg/front_end/testcases/nnbd/null_shorting_extension.dart'.
 //   throws(() => -n1?.nonNullable1);
 //                ^
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_index.dart b/pkg/front_end/testcases/nnbd/null_shorting_index.dart
index 13812c5..79991fa 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting_index.dart
+++ b/pkg/front_end/testcases/nnbd/null_shorting_index.dart
@@ -9,7 +9,7 @@
 }
 
 class Class2 {
-  int field;
+  int field = 42;
 }
 
 extension Extension on Class2 {
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_index.dart.strong.expect b/pkg/front_end/testcases/nnbd/null_shorting_index.dart.strong.expect
index d147132..2afae89 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting_index.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/null_shorting_index.dart.strong.expect
@@ -13,7 +13,7 @@
   operator []=(core::int index, core::int value) → void {}
 }
 class Class2 extends core::Object {
-  field core::int field = null;
+  field core::int field = 42;
   synthetic constructor •() → self::Class2
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_index.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/null_shorting_index.dart.strong.transformed.expect
index d147132..2afae89 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting_index.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/null_shorting_index.dart.strong.transformed.expect
@@ -13,7 +13,7 @@
   operator []=(core::int index, core::int value) → void {}
 }
 class Class2 extends core::Object {
-  field core::int field = null;
+  field core::int field = 42;
   synthetic constructor •() → self::Class2
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_index.dart.weak.expect b/pkg/front_end/testcases/nnbd/null_shorting_index.dart.weak.expect
index d147132..2afae89 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting_index.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/null_shorting_index.dart.weak.expect
@@ -13,7 +13,7 @@
   operator []=(core::int index, core::int value) → void {}
 }
 class Class2 extends core::Object {
-  field core::int field = null;
+  field core::int field = 42;
   synthetic constructor •() → self::Class2
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_index.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/null_shorting_index.dart.weak.transformed.expect
index d147132..2afae89 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting_index.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/null_shorting_index.dart.weak.transformed.expect
@@ -13,7 +13,7 @@
   operator []=(core::int index, core::int value) → void {}
 }
 class Class2 extends core::Object {
-  field core::int field = null;
+  field core::int field = 42;
   synthetic constructor •() → self::Class2
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/nnbd/nullable_null.dart.weak.expect b/pkg/front_end/testcases/nnbd/nullable_null.dart.weak.expect
index bf6195b..d3205a9 100644
--- a/pkg/front_end/testcases/nnbd/nullable_null.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/nullable_null.dart.weak.expect
@@ -29,5 +29,5 @@
 
 constants  {
   #C1 = <core::Null?>[]
-  #C2 = <self::A<core::Null?>>[]
+  #C2 = <self::A<core::Null?>*>[]
 }
diff --git a/pkg/front_end/testcases/nnbd/nullable_null.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/nullable_null.dart.weak.transformed.expect
index bf6195b..d3205a9 100644
--- a/pkg/front_end/testcases/nnbd/nullable_null.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/nullable_null.dart.weak.transformed.expect
@@ -29,5 +29,5 @@
 
 constants  {
   #C1 = <core::Null?>[]
-  #C2 = <self::A<core::Null?>>[]
+  #C2 = <self::A<core::Null?>*>[]
 }
diff --git a/pkg/front_end/testcases/nnbd/opt_out.dart.outline.expect b/pkg/front_end/testcases/nnbd/opt_out.dart.outline.expect
index b5c1e22..b08c2be2 100644
--- a/pkg/front_end/testcases/nnbd/opt_out.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/opt_out.dart.outline.expect
@@ -29,15 +29,7 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:11:3: Error: Null safety features are disabled for this library.
-// Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
-//   late int field = 42;
-//   ^^^^
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
-// // @dart=2.5
-// ^^^^^^^^^^^^
-//
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:13:25: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:18:25: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 // class B extends A<String?> {}
 //                         ^
@@ -45,7 +37,7 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:15:28: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:20:28: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 // typedef F = void Function()?;
 //                            ^
@@ -53,7 +45,7 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:17:12: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:22:12: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 // List<String?> l = [];
 //            ^
@@ -61,7 +53,7 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:18:7: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:23:7: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 // String? s = null;
 //       ^
@@ -69,31 +61,15 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:21:1: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:28:21: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
-// late int field = 42;
-// ^^^^
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
-// // @dart=2.5
-// ^^^^^^^^^^^^
-//
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:23:21: Error: Null safety features are disabled for this library.
-// Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
-// void method(void f()?, {required int a}) {}
+// void method(void f()?, {int a}) {}
 //                     ^
 // pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:23:25: Error: Null safety features are disabled for this library.
-// Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
-// void method(void f()?, {required int a}) {}
-//                         ^^^^^^^^
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
-// // @dart=2.5
-// ^^^^^^^^^^^^
-//
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:19:10: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:24:10: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 // var t = s!;
 //          ^
@@ -106,7 +82,7 @@
 
 typedef F = () →? void;
 class A<T extends core::Object* = dynamic> extends core::Object {
-  late field core::int* field;
+  field core::int* field;
   synthetic constructor •() → self2::A<self2::A::T*>*
     ;
 }
@@ -117,8 +93,8 @@
 static field core::List<core::String?>* l;
 static field core::String? s;
 static field core::String* t;
-late static field core::int* field;
-static method method(() →? void f, {required core::int* a}) → void
+static field core::int* field;
+static method method(() →? void f, {core::int* a}) → void
   ;
 static method errors() → dynamic
   ;
diff --git a/pkg/front_end/testcases/nnbd/opt_out.dart.strong.expect b/pkg/front_end/testcases/nnbd/opt_out.dart.strong.expect
index 74171bd..02ebaa2 100644
--- a/pkg/front_end/testcases/nnbd/opt_out.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/opt_out.dart.strong.expect
@@ -34,15 +34,7 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:11:3: Error: Null safety features are disabled for this library.
-// Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
-//   late int field = 42;
-//   ^^^^
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
-// // @dart=2.5
-// ^^^^^^^^^^^^
-//
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:13:25: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:18:25: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 // class B extends A<String?> {}
 //                         ^
@@ -50,7 +42,7 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:15:28: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:20:28: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 // typedef F = void Function()?;
 //                            ^
@@ -58,7 +50,7 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:17:12: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:22:12: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 // List<String?> l = [];
 //            ^
@@ -66,7 +58,7 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:18:7: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:23:7: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 // String? s = null;
 //       ^
@@ -74,31 +66,15 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:21:1: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:28:21: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
-// late int field = 42;
-// ^^^^
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
-// // @dart=2.5
-// ^^^^^^^^^^^^
-//
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:23:21: Error: Null safety features are disabled for this library.
-// Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
-// void method(void f()?, {required int a}) {}
+// void method(void f()?, {int a}) {}
 //                     ^
 // pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:23:25: Error: Null safety features are disabled for this library.
-// Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
-// void method(void f()?, {required int a}) {}
-//                         ^^^^^^^^
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
-// // @dart=2.5
-// ^^^^^^^^^^^^
-//
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:19:10: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:24:10: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 // var t = s!;
 //          ^
@@ -106,15 +82,7 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:26:3: Error: Null safety features are disabled for this library.
-// Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
-//   late int local = 42;
-//   ^^^^
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
-// // @dart=2.5
-// ^^^^^^^^^^^^
-//
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:27:14: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:32:14: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 //   List<String?> l = null;
 //              ^
@@ -122,7 +90,7 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:28:9: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:33:9: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 //   String? s = null;
 //         ^
@@ -130,7 +98,7 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:29:12: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:34:12: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 //   var t = s!;
 //            ^
@@ -138,28 +106,24 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:31:4: Error: Null safety features are disabled for this library.
-// Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:36:6: Error: Expected an identifier, but got '.'.
 //   c?..f;
-//    ^^^
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
-// // @dart=2.5
-// ^^^^^^^^^^^^
+//      ^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:32:4: Error: Null safety features are disabled for this library.
-// Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:36:6: Error: Expected an identifier, but got ''.
+//   c?..f;
+//      ^
+//
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:37:6: Error: Expected an identifier, but got '['.
 //   c?.[0];
-//    ^^^
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
-// // @dart=2.5
-// ^^^^^^^^^^^^
+//      ^
 //
 import self as self2;
 import "dart:core" as core;
 
 typedef F = () →? void;
 class A<T extends core::Object* = dynamic> extends core::Object {
-  late field core::int* field = 42;
+  field core::int* field = 42;
   synthetic constructor •() → self2::A<self2::A::T*>*
     : super core::Object::•()
     ;
@@ -172,16 +136,20 @@
 static field core::List<core::String?>* l = <core::String?>[];
 static field core::String? s = null;
 static field core::String* t = self2::s!;
-late static field core::int* field = 42;
-static method method(() →? void f, {required core::int* a = #C1}) → void {}
+static field core::int* field = 42;
+static method method(() →? void f, {core::int* a = #C1}) → void {}
 static method errors() → dynamic {
-  late core::int* local = 42;
+  core::int* local = 42;
   core::List<core::String?>* l = null;
   core::String? s = null;
   core::String* t = s!;
   dynamic c;
-  let final dynamic #t4 = c in #t4.{core::Object::==}(null) ?{dynamic} null : let final void #t5 = #t4.f in #t4;
-  let final dynamic #t6 = c in #t6.{core::Object::==}(null) ?{dynamic} null : #t6.[](0);
+  invalid-expression "pkg/front_end/testcases/nnbd/opt_out_lib.dart:36:6: Error: Expected an identifier, but got ''.
+  c?..f;
+     ^".f;
+  invalid-expression "pkg/front_end/testcases/nnbd/opt_out_lib.dart:37:6: Error: Expected an identifier, but got '['.
+  c?.[0];
+     ^";
 }
 
 constants  {
diff --git a/pkg/front_end/testcases/nnbd/opt_out.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/opt_out.dart.strong.transformed.expect
index 74171bd..02ebaa2 100644
--- a/pkg/front_end/testcases/nnbd/opt_out.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/opt_out.dart.strong.transformed.expect
@@ -34,15 +34,7 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:11:3: Error: Null safety features are disabled for this library.
-// Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
-//   late int field = 42;
-//   ^^^^
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
-// // @dart=2.5
-// ^^^^^^^^^^^^
-//
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:13:25: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:18:25: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 // class B extends A<String?> {}
 //                         ^
@@ -50,7 +42,7 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:15:28: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:20:28: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 // typedef F = void Function()?;
 //                            ^
@@ -58,7 +50,7 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:17:12: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:22:12: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 // List<String?> l = [];
 //            ^
@@ -66,7 +58,7 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:18:7: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:23:7: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 // String? s = null;
 //       ^
@@ -74,31 +66,15 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:21:1: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:28:21: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
-// late int field = 42;
-// ^^^^
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
-// // @dart=2.5
-// ^^^^^^^^^^^^
-//
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:23:21: Error: Null safety features are disabled for this library.
-// Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
-// void method(void f()?, {required int a}) {}
+// void method(void f()?, {int a}) {}
 //                     ^
 // pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:23:25: Error: Null safety features are disabled for this library.
-// Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
-// void method(void f()?, {required int a}) {}
-//                         ^^^^^^^^
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
-// // @dart=2.5
-// ^^^^^^^^^^^^
-//
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:19:10: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:24:10: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 // var t = s!;
 //          ^
@@ -106,15 +82,7 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:26:3: Error: Null safety features are disabled for this library.
-// Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
-//   late int local = 42;
-//   ^^^^
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
-// // @dart=2.5
-// ^^^^^^^^^^^^
-//
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:27:14: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:32:14: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 //   List<String?> l = null;
 //              ^
@@ -122,7 +90,7 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:28:9: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:33:9: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 //   String? s = null;
 //         ^
@@ -130,7 +98,7 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:29:12: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:34:12: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 //   var t = s!;
 //            ^
@@ -138,28 +106,24 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:31:4: Error: Null safety features are disabled for this library.
-// Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:36:6: Error: Expected an identifier, but got '.'.
 //   c?..f;
-//    ^^^
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
-// // @dart=2.5
-// ^^^^^^^^^^^^
+//      ^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:32:4: Error: Null safety features are disabled for this library.
-// Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:36:6: Error: Expected an identifier, but got ''.
+//   c?..f;
+//      ^
+//
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:37:6: Error: Expected an identifier, but got '['.
 //   c?.[0];
-//    ^^^
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
-// // @dart=2.5
-// ^^^^^^^^^^^^
+//      ^
 //
 import self as self2;
 import "dart:core" as core;
 
 typedef F = () →? void;
 class A<T extends core::Object* = dynamic> extends core::Object {
-  late field core::int* field = 42;
+  field core::int* field = 42;
   synthetic constructor •() → self2::A<self2::A::T*>*
     : super core::Object::•()
     ;
@@ -172,16 +136,20 @@
 static field core::List<core::String?>* l = <core::String?>[];
 static field core::String? s = null;
 static field core::String* t = self2::s!;
-late static field core::int* field = 42;
-static method method(() →? void f, {required core::int* a = #C1}) → void {}
+static field core::int* field = 42;
+static method method(() →? void f, {core::int* a = #C1}) → void {}
 static method errors() → dynamic {
-  late core::int* local = 42;
+  core::int* local = 42;
   core::List<core::String?>* l = null;
   core::String? s = null;
   core::String* t = s!;
   dynamic c;
-  let final dynamic #t4 = c in #t4.{core::Object::==}(null) ?{dynamic} null : let final void #t5 = #t4.f in #t4;
-  let final dynamic #t6 = c in #t6.{core::Object::==}(null) ?{dynamic} null : #t6.[](0);
+  invalid-expression "pkg/front_end/testcases/nnbd/opt_out_lib.dart:36:6: Error: Expected an identifier, but got ''.
+  c?..f;
+     ^".f;
+  invalid-expression "pkg/front_end/testcases/nnbd/opt_out_lib.dart:37:6: Error: Expected an identifier, but got '['.
+  c?.[0];
+     ^";
 }
 
 constants  {
diff --git a/pkg/front_end/testcases/nnbd/opt_out.dart.weak.expect b/pkg/front_end/testcases/nnbd/opt_out.dart.weak.expect
index 74171bd..02ebaa2 100644
--- a/pkg/front_end/testcases/nnbd/opt_out.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/opt_out.dart.weak.expect
@@ -34,15 +34,7 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:11:3: Error: Null safety features are disabled for this library.
-// Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
-//   late int field = 42;
-//   ^^^^
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
-// // @dart=2.5
-// ^^^^^^^^^^^^
-//
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:13:25: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:18:25: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 // class B extends A<String?> {}
 //                         ^
@@ -50,7 +42,7 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:15:28: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:20:28: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 // typedef F = void Function()?;
 //                            ^
@@ -58,7 +50,7 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:17:12: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:22:12: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 // List<String?> l = [];
 //            ^
@@ -66,7 +58,7 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:18:7: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:23:7: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 // String? s = null;
 //       ^
@@ -74,31 +66,15 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:21:1: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:28:21: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
-// late int field = 42;
-// ^^^^
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
-// // @dart=2.5
-// ^^^^^^^^^^^^
-//
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:23:21: Error: Null safety features are disabled for this library.
-// Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
-// void method(void f()?, {required int a}) {}
+// void method(void f()?, {int a}) {}
 //                     ^
 // pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:23:25: Error: Null safety features are disabled for this library.
-// Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
-// void method(void f()?, {required int a}) {}
-//                         ^^^^^^^^
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
-// // @dart=2.5
-// ^^^^^^^^^^^^
-//
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:19:10: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:24:10: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 // var t = s!;
 //          ^
@@ -106,15 +82,7 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:26:3: Error: Null safety features are disabled for this library.
-// Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
-//   late int local = 42;
-//   ^^^^
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
-// // @dart=2.5
-// ^^^^^^^^^^^^
-//
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:27:14: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:32:14: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 //   List<String?> l = null;
 //              ^
@@ -122,7 +90,7 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:28:9: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:33:9: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 //   String? s = null;
 //         ^
@@ -130,7 +98,7 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:29:12: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:34:12: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 //   var t = s!;
 //            ^
@@ -138,28 +106,24 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:31:4: Error: Null safety features are disabled for this library.
-// Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:36:6: Error: Expected an identifier, but got '.'.
 //   c?..f;
-//    ^^^
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
-// // @dart=2.5
-// ^^^^^^^^^^^^
+//      ^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:32:4: Error: Null safety features are disabled for this library.
-// Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:36:6: Error: Expected an identifier, but got ''.
+//   c?..f;
+//      ^
+//
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:37:6: Error: Expected an identifier, but got '['.
 //   c?.[0];
-//    ^^^
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
-// // @dart=2.5
-// ^^^^^^^^^^^^
+//      ^
 //
 import self as self2;
 import "dart:core" as core;
 
 typedef F = () →? void;
 class A<T extends core::Object* = dynamic> extends core::Object {
-  late field core::int* field = 42;
+  field core::int* field = 42;
   synthetic constructor •() → self2::A<self2::A::T*>*
     : super core::Object::•()
     ;
@@ -172,16 +136,20 @@
 static field core::List<core::String?>* l = <core::String?>[];
 static field core::String? s = null;
 static field core::String* t = self2::s!;
-late static field core::int* field = 42;
-static method method(() →? void f, {required core::int* a = #C1}) → void {}
+static field core::int* field = 42;
+static method method(() →? void f, {core::int* a = #C1}) → void {}
 static method errors() → dynamic {
-  late core::int* local = 42;
+  core::int* local = 42;
   core::List<core::String?>* l = null;
   core::String? s = null;
   core::String* t = s!;
   dynamic c;
-  let final dynamic #t4 = c in #t4.{core::Object::==}(null) ?{dynamic} null : let final void #t5 = #t4.f in #t4;
-  let final dynamic #t6 = c in #t6.{core::Object::==}(null) ?{dynamic} null : #t6.[](0);
+  invalid-expression "pkg/front_end/testcases/nnbd/opt_out_lib.dart:36:6: Error: Expected an identifier, but got ''.
+  c?..f;
+     ^".f;
+  invalid-expression "pkg/front_end/testcases/nnbd/opt_out_lib.dart:37:6: Error: Expected an identifier, but got '['.
+  c?.[0];
+     ^";
 }
 
 constants  {
diff --git a/pkg/front_end/testcases/nnbd/opt_out.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/opt_out.dart.weak.transformed.expect
index 74171bd..02ebaa2 100644
--- a/pkg/front_end/testcases/nnbd/opt_out.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/opt_out.dart.weak.transformed.expect
@@ -34,15 +34,7 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:11:3: Error: Null safety features are disabled for this library.
-// Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
-//   late int field = 42;
-//   ^^^^
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
-// // @dart=2.5
-// ^^^^^^^^^^^^
-//
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:13:25: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:18:25: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 // class B extends A<String?> {}
 //                         ^
@@ -50,7 +42,7 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:15:28: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:20:28: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 // typedef F = void Function()?;
 //                            ^
@@ -58,7 +50,7 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:17:12: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:22:12: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 // List<String?> l = [];
 //            ^
@@ -66,7 +58,7 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:18:7: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:23:7: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 // String? s = null;
 //       ^
@@ -74,31 +66,15 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:21:1: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:28:21: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
-// late int field = 42;
-// ^^^^
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
-// // @dart=2.5
-// ^^^^^^^^^^^^
-//
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:23:21: Error: Null safety features are disabled for this library.
-// Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
-// void method(void f()?, {required int a}) {}
+// void method(void f()?, {int a}) {}
 //                     ^
 // pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:23:25: Error: Null safety features are disabled for this library.
-// Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
-// void method(void f()?, {required int a}) {}
-//                         ^^^^^^^^
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
-// // @dart=2.5
-// ^^^^^^^^^^^^
-//
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:19:10: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:24:10: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 // var t = s!;
 //          ^
@@ -106,15 +82,7 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:26:3: Error: Null safety features are disabled for this library.
-// Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
-//   late int local = 42;
-//   ^^^^
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
-// // @dart=2.5
-// ^^^^^^^^^^^^
-//
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:27:14: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:32:14: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 //   List<String?> l = null;
 //              ^
@@ -122,7 +90,7 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:28:9: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:33:9: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 //   String? s = null;
 //         ^
@@ -130,7 +98,7 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:29:12: Error: Null safety features are disabled for this library.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:34:12: Error: Null safety features are disabled for this library.
 // Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
 //   var t = s!;
 //            ^
@@ -138,28 +106,24 @@
 // // @dart=2.5
 // ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:31:4: Error: Null safety features are disabled for this library.
-// Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:36:6: Error: Expected an identifier, but got '.'.
 //   c?..f;
-//    ^^^
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
-// // @dart=2.5
-// ^^^^^^^^^^^^
+//      ^
 //
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:32:4: Error: Null safety features are disabled for this library.
-// Try removing the `@dart=` annotation or setting the language version to at least `@dart=2.7`.
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:36:6: Error: Expected an identifier, but got ''.
+//   c?..f;
+//      ^
+//
+// pkg/front_end/testcases/nnbd/opt_out_lib.dart:37:6: Error: Expected an identifier, but got '['.
 //   c?.[0];
-//    ^^^
-// pkg/front_end/testcases/nnbd/opt_out_lib.dart:5:1: Context: This is the annotation that opts out this library from null safety features.
-// // @dart=2.5
-// ^^^^^^^^^^^^
+//      ^
 //
 import self as self2;
 import "dart:core" as core;
 
 typedef F = () →? void;
 class A<T extends core::Object* = dynamic> extends core::Object {
-  late field core::int* field = 42;
+  field core::int* field = 42;
   synthetic constructor •() → self2::A<self2::A::T*>*
     : super core::Object::•()
     ;
@@ -172,16 +136,20 @@
 static field core::List<core::String?>* l = <core::String?>[];
 static field core::String? s = null;
 static field core::String* t = self2::s!;
-late static field core::int* field = 42;
-static method method(() →? void f, {required core::int* a = #C1}) → void {}
+static field core::int* field = 42;
+static method method(() →? void f, {core::int* a = #C1}) → void {}
 static method errors() → dynamic {
-  late core::int* local = 42;
+  core::int* local = 42;
   core::List<core::String?>* l = null;
   core::String? s = null;
   core::String* t = s!;
   dynamic c;
-  let final dynamic #t4 = c in #t4.{core::Object::==}(null) ?{dynamic} null : let final void #t5 = #t4.f in #t4;
-  let final dynamic #t6 = c in #t6.{core::Object::==}(null) ?{dynamic} null : #t6.[](0);
+  invalid-expression "pkg/front_end/testcases/nnbd/opt_out_lib.dart:36:6: Error: Expected an identifier, but got ''.
+  c?..f;
+     ^".f;
+  invalid-expression "pkg/front_end/testcases/nnbd/opt_out_lib.dart:37:6: Error: Expected an identifier, but got '['.
+  c?.[0];
+     ^";
 }
 
 constants  {
diff --git a/pkg/front_end/testcases/nnbd/opt_out_lib.dart b/pkg/front_end/testcases/nnbd/opt_out_lib.dart
index b2093d2..99b935f9 100644
--- a/pkg/front_end/testcases/nnbd/opt_out_lib.dart
+++ b/pkg/front_end/testcases/nnbd/opt_out_lib.dart
@@ -5,10 +5,15 @@
 // @dart=2.5
 
 // The intent of this file is to show that it's an error to use NNBD features in
-// an opt-in library.
+// an opt-out library.
+
+// TODO: Also add "late" in front of fields and variables and "required" in
+// front of the named parameter.
+// This requires a better recovery though (as it will currently destroy 'int'
+// as a type).
 
 class A<T> {
-  late int field = 42;
+  int field = 42;
 }
 class B extends A<String?> {}
 
@@ -18,12 +23,12 @@
 String? s = null;
 var t = s!;
 
-late int field = 42;
+int field = 42;
 
-void method(void f()?, {required int a}) {}
+void method(void f()?, {int a}) {}
 
 errors() {
-  late int local = 42;
+  int local = 42;
   List<String?> l = null;
   String? s = null;
   var t = s!;
diff --git a/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart b/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart
index ae83e07..acfd6cf 100644
--- a/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart
+++ b/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart
@@ -5,22 +5,22 @@
 // The test checks for compile-time errors and their absence for cases involving
 // fields of potentially non-nullable types.
 
-int x;
+int x; // Error.
 int? y; // Ok: it's nullable.
 late int z; // Ok: it's late.
 
 class A<T extends Object?> {
-  static int x;
+  static int x; // Error.
   static int? y; // Ok: it's nullable.
   static late int z; // Ok: it's late. 
 
-  int lx;
+  int lx; // Error.
   int? ly; // Ok: it's nullable.
   late int? lz; // Ok: it's late.
   int lv; // Ok: initialized in an initializing formal.
   int lu; // Ok: initialized in an initializer list entry.
 
-  T lt;
+  T lt; // Error.
   T? ls; // Ok: it's nullable.
   late T lr; // Ok: it's late.
   T lp; // Ok: initialized in an initializing formal.
diff --git a/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.outline.expect b/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.outline.expect
index 153b9bb..b56b2a7 100644
--- a/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.outline.expect
@@ -1,4 +1,15 @@
 library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart:8:5: Error: Field 'x' should be initialized because its type 'int' doesn't allow null.
+// int x; // Error.
+//     ^
+//
+// pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart:13:14: Error: Field 'x' should be initialized because its type 'int' doesn't allow null.
+//   static int x; // Error.
+//              ^
+//
 import self as self;
 import "dart:core" as core;
 
diff --git a/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.strong.expect b/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.strong.expect
index 80be9f2..0dee541 100644
--- a/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.strong.expect
@@ -1,4 +1,23 @@
 library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart:8:5: Error: Field 'x' should be initialized because its type 'int' doesn't allow null.
+// int x; // Error.
+//     ^
+//
+// pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart:13:14: Error: Field 'x' should be initialized because its type 'int' doesn't allow null.
+//   static int x; // Error.
+//              ^
+//
+// pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart:17:7: Error: Field 'lx' should be initialized because its type 'int' doesn't allow null.
+//   int lx; // Error.
+//       ^^
+//
+// pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart:23:5: Error: Field 'lt' should be initialized because its type 'T' doesn't allow null.
+//   T lt; // Error.
+//     ^^
+//
 import self as self;
 import "dart:core" as core;
 
diff --git a/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.strong.transformed.expect
index 80be9f2..0dee541 100644
--- a/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.strong.transformed.expect
@@ -1,4 +1,23 @@
 library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart:8:5: Error: Field 'x' should be initialized because its type 'int' doesn't allow null.
+// int x; // Error.
+//     ^
+//
+// pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart:13:14: Error: Field 'x' should be initialized because its type 'int' doesn't allow null.
+//   static int x; // Error.
+//              ^
+//
+// pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart:17:7: Error: Field 'lx' should be initialized because its type 'int' doesn't allow null.
+//   int lx; // Error.
+//       ^^
+//
+// pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart:23:5: Error: Field 'lt' should be initialized because its type 'T' doesn't allow null.
+//   T lt; // Error.
+//     ^^
+//
 import self as self;
 import "dart:core" as core;
 
diff --git a/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.weak.expect b/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.weak.expect
index 80be9f2..ff1e157 100644
--- a/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.weak.expect
@@ -1,4 +1,23 @@
 library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart:8:5: Warning: Field 'x' isn't initialized and its type 'int' doesn't allow null.
+// int x; // Error.
+//     ^
+//
+// pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart:13:14: Warning: Field 'x' isn't initialized and its type 'int' doesn't allow null.
+//   static int x; // Error.
+//              ^
+//
+// pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart:17:7: Warning: Field 'lx' isn't initialized and its type 'int' doesn't allow null.
+//   int lx; // Error.
+//       ^^
+//
+// pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart:23:5: Warning: Field 'lt' isn't initialized and its type 'T' doesn't allow null.
+//   T lt; // Error.
+//     ^^
+//
 import self as self;
 import "dart:core" as core;
 
diff --git a/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.weak.transformed.expect
index 80be9f2..ff1e157 100644
--- a/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.weak.transformed.expect
@@ -1,4 +1,23 @@
 library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart:8:5: Warning: Field 'x' isn't initialized and its type 'int' doesn't allow null.
+// int x; // Error.
+//     ^
+//
+// pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart:13:14: Warning: Field 'x' isn't initialized and its type 'int' doesn't allow null.
+//   static int x; // Error.
+//              ^
+//
+// pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart:17:7: Warning: Field 'lx' isn't initialized and its type 'int' doesn't allow null.
+//   int lx; // Error.
+//       ^^
+//
+// pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart:23:5: Warning: Field 'lt' isn't initialized and its type 'T' doesn't allow null.
+//   T lt; // Error.
+//     ^^
+//
 import self as self;
 import "dart:core" as core;
 
diff --git a/pkg/front_end/testcases/nnbd/required.dart b/pkg/front_end/testcases/nnbd/required.dart
index 8e57d7d..b25d1cf 100644
--- a/pkg/front_end/testcases/nnbd/required.dart
+++ b/pkg/front_end/testcases/nnbd/required.dart
@@ -17,7 +17,7 @@
 
 typedef Typedef2({int a, required int b});
 
-Function({int a, required int b}) field;
+Function({int a, required int b}) field = ({int a = 42, required int b}) {};
 
 abstract class A {
   // It's ok to omit the default values in abstract members.
@@ -38,7 +38,7 @@
   void g({int a = 42, required int b}) {}
   f = ({int a = 42, required int b}) {};
 
-  Function(int a, [int b = 42]) f2;
+  Function(int a, [int b]) f2;
   void g2(int a, [int b = 42]) {}
   f2 = (int a, [int b = 42]) {};
 }
diff --git a/pkg/front_end/testcases/nnbd/required.dart.strong.expect b/pkg/front_end/testcases/nnbd/required.dart.strong.expect
index 07ebc91..335594b 100644
--- a/pkg/front_end/testcases/nnbd/required.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/required.dart.strong.expect
@@ -6,10 +6,6 @@
 //   foo({x}) {}
 //        ^
 //
-// pkg/front_end/testcases/nnbd/required.dart:41:26: Error: Can't have a default value in a function type.
-//   Function(int a, [int b = 42]) f2;
-//                          ^
-//
 // pkg/front_end/testcases/nnbd/required.dart:51:18: Error: Non-optional parameters can't have a default value.
 // Try removing the default value or making the parameter optional.
 //   Function(int a = 42, [int b]) f2;
@@ -78,7 +74,7 @@
     ;
   method foo({core::int x = #C1}) → dynamic {}
 }
-static field ({a: core::int, required b: core::int}) → dynamic field;
+static field ({a: core::int, required b: core::int}) → dynamic field = ({core::int a = #C1, required core::int b = #C2}) → core::Null? {};
 static method method({core::int a = #C1, required core::int b = #C2, required final core::int c = #C2}) → dynamic {}
 static method ok() → dynamic {
   ({a: core::int, required b: core::int}) → dynamic f;
diff --git a/pkg/front_end/testcases/nnbd/required.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/required.dart.strong.transformed.expect
index 07ebc91..335594b 100644
--- a/pkg/front_end/testcases/nnbd/required.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/required.dart.strong.transformed.expect
@@ -6,10 +6,6 @@
 //   foo({x}) {}
 //        ^
 //
-// pkg/front_end/testcases/nnbd/required.dart:41:26: Error: Can't have a default value in a function type.
-//   Function(int a, [int b = 42]) f2;
-//                          ^
-//
 // pkg/front_end/testcases/nnbd/required.dart:51:18: Error: Non-optional parameters can't have a default value.
 // Try removing the default value or making the parameter optional.
 //   Function(int a = 42, [int b]) f2;
@@ -78,7 +74,7 @@
     ;
   method foo({core::int x = #C1}) → dynamic {}
 }
-static field ({a: core::int, required b: core::int}) → dynamic field;
+static field ({a: core::int, required b: core::int}) → dynamic field = ({core::int a = #C1, required core::int b = #C2}) → core::Null? {};
 static method method({core::int a = #C1, required core::int b = #C2, required final core::int c = #C2}) → dynamic {}
 static method ok() → dynamic {
   ({a: core::int, required b: core::int}) → dynamic f;
diff --git a/pkg/front_end/testcases/nnbd/required.dart.weak.expect b/pkg/front_end/testcases/nnbd/required.dart.weak.expect
index 4ae3e4f..35a4cfc 100644
--- a/pkg/front_end/testcases/nnbd/required.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/required.dart.weak.expect
@@ -6,10 +6,6 @@
 //   foo({x}) {}
 //        ^
 //
-// pkg/front_end/testcases/nnbd/required.dart:41:26: Error: Can't have a default value in a function type.
-//   Function(int a, [int b = 42]) f2;
-//                          ^
-//
 // pkg/front_end/testcases/nnbd/required.dart:51:18: Error: Non-optional parameters can't have a default value.
 // Try removing the default value or making the parameter optional.
 //   Function(int a = 42, [int b]) f2;
@@ -78,7 +74,7 @@
     ;
   method foo({core::int x = #C1}) → dynamic {}
 }
-static field ({a: core::int, required b: core::int}) → dynamic field;
+static field ({a: core::int, required b: core::int}) → dynamic field = ({core::int a = #C1, required core::int b = #C2}) → core::Null? {};
 static method method({core::int a = #C1, required core::int b = #C2, required final core::int c = #C2}) → dynamic {}
 static method ok() → dynamic {
   ({a: core::int, required b: core::int}) → dynamic f;
diff --git a/pkg/front_end/testcases/nnbd/required.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/required.dart.weak.transformed.expect
index 4ae3e4f..35a4cfc 100644
--- a/pkg/front_end/testcases/nnbd/required.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/required.dart.weak.transformed.expect
@@ -6,10 +6,6 @@
 //   foo({x}) {}
 //        ^
 //
-// pkg/front_end/testcases/nnbd/required.dart:41:26: Error: Can't have a default value in a function type.
-//   Function(int a, [int b = 42]) f2;
-//                          ^
-//
 // pkg/front_end/testcases/nnbd/required.dart:51:18: Error: Non-optional parameters can't have a default value.
 // Try removing the default value or making the parameter optional.
 //   Function(int a = 42, [int b]) f2;
@@ -78,7 +74,7 @@
     ;
   method foo({core::int x = #C1}) → dynamic {}
 }
-static field ({a: core::int, required b: core::int}) → dynamic field;
+static field ({a: core::int, required b: core::int}) → dynamic field = ({core::int a = #C1, required core::int b = #C2}) → core::Null? {};
 static method method({core::int a = #C1, required core::int b = #C2, required final core::int c = #C2}) → dynamic {}
 static method ok() → dynamic {
   ({a: core::int, required b: core::int}) → dynamic f;
diff --git a/pkg/front_end/testcases/nnbd/shorting_stop.dart b/pkg/front_end/testcases/nnbd/shorting_stop.dart
index c3b0a43..f51c066 100644
--- a/pkg/front_end/testcases/nnbd/shorting_stop.dart
+++ b/pkg/front_end/testcases/nnbd/shorting_stop.dart
@@ -16,17 +16,17 @@
 test(Class? c) {
   c?.next.field; // ok
   throwsInStrong(() => c?.field + 2); // error
-  // TODO(johnniwinther): Stop shorting a inc/dec.
-  ++c?.field; // error
-  c?.field++; // error
+  ++c?.field; // ok
+  c?.field++; // ok
   throwsInStrong(() => (c?.next).field); // error
+  throwsInStrong(() => -c?.field); // error
 
   c?.next[0].isEven; // ok
   throwsInStrong(() => c?.next[0] + 2); // error
-  // TODO(johnniwinther): Stop shorting a inc/dec.
-  ++c?.next[0]; // error
-  c?.next[0]++; // error
+  ++c?.next[0]; // ok
+  c?.next[0]++; // ok
   throwsInStrong(() => (c?.next[0]).isEven); // error
+  throwsInStrong(() => -c?.next[0]); // error
 }
 
 final bool inStrongMode = _inStrongMode();
diff --git a/pkg/front_end/testcases/nnbd/shorting_stop.dart.strong.expect b/pkg/front_end/testcases/nnbd/shorting_stop.dart.strong.expect
index fe0c720..69c985e 100644
--- a/pkg/front_end/testcases/nnbd/shorting_stop.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/shorting_stop.dart.strong.expect
@@ -6,21 +6,29 @@
 //   throwsInStrong(() => c?.field + 2); // error
 //                                 ^
 //
-// pkg/front_end/testcases/nnbd/shorting_stop.dart:22:34: Error: Property 'field' cannot be accessed on 'Class?' because it is potentially null.
+// pkg/front_end/testcases/nnbd/shorting_stop.dart:21:34: Error: Property 'field' cannot be accessed on 'Class?' because it is potentially null.
 //  - 'Class' is from 'pkg/front_end/testcases/nnbd/shorting_stop.dart'.
 // Try accessing using ?. instead.
 //   throwsInStrong(() => (c?.next).field); // error
 //                                  ^^^^^
 //
+// pkg/front_end/testcases/nnbd/shorting_stop.dart:22:24: Error: Operator 'unary-' cannot be called on 'int?' because it is potentially null.
+//   throwsInStrong(() => -c?.field); // error
+//                        ^
+//
 // pkg/front_end/testcases/nnbd/shorting_stop.dart:25:35: Error: Operator '+' cannot be called on 'int?' because it is potentially null.
 //   throwsInStrong(() => c?.next[0] + 2); // error
 //                                   ^
 //
-// pkg/front_end/testcases/nnbd/shorting_stop.dart:29:37: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+// pkg/front_end/testcases/nnbd/shorting_stop.dart:28:37: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
 // Try accessing using ?. instead.
 //   throwsInStrong(() => (c?.next[0]).isEven); // error
 //                                     ^^^^^^
 //
+// pkg/front_end/testcases/nnbd/shorting_stop.dart:29:24: Error: Operator 'unary-' cannot be called on 'int?' because it is potentially null.
+//   throwsInStrong(() => -c?.next[0]); // error
+//                        ^
+//
 // pkg/front_end/testcases/nnbd/shorting_stop.dart:36:7: Error: Property 'length' cannot be accessed on 'String?' because it is potentially null.
 // Try accessing using ?. instead.
 //     s.length; // This will be an invalid expression in strong mode.
@@ -51,25 +59,31 @@
                                 ^" in (let final self::Class? #t3 = c in #t3.{core::Object::==}(null) ?{core::int?} null : #t3{self::Class}.{self::Class::field}).{core::num::+}(2));
   let final self::Class? #t4 = c in #t4.{core::Object::==}(null) ?{core::int?} null : let final core::int #t5 = #t4.{self::Class::field}.{core::num::+}(1) in let final void #t6 = #t4.{self::Class::field} = #t5 in #t5;
   let final self::Class? #t7 = c in #t7.{core::Object::==}(null) ?{core::int?} null : #t7.{self::Class::field} = #t7.{self::Class::field}.{core::num::+}(1);
-  self::throwsInStrong(() → core::int => let final<BottomType> #t8 = invalid-expression "pkg/front_end/testcases/nnbd/shorting_stop.dart:22:34: Error: Property 'field' cannot be accessed on 'Class?' because it is potentially null.
+  self::throwsInStrong(() → core::int => let final<BottomType> #t8 = invalid-expression "pkg/front_end/testcases/nnbd/shorting_stop.dart:21:34: Error: Property 'field' cannot be accessed on 'Class?' because it is potentially null.
  - 'Class' is from 'pkg/front_end/testcases/nnbd/shorting_stop.dart'.
 Try accessing using ?. instead.
   throwsInStrong(() => (c?.next).field); // error
                                  ^^^^^" in (let final self::Class? #t9 = c in #t9.{core::Object::==}(null) ?{self::Class?} null : #t9{self::Class}.{self::Class::next}).{self::Class::field});
-  let final self::Class? #t10 = c in #t10.{core::Object::==}(null) ?{core::bool?} null : #t10{self::Class}.{self::Class::next}.{self::Class::[]}(0).{core::int::isEven};
-  self::throwsInStrong(() → core::int => let final<BottomType> #t11 = invalid-expression "pkg/front_end/testcases/nnbd/shorting_stop.dart:25:35: Error: Operator '+' cannot be called on 'int?' because it is potentially null.
+  self::throwsInStrong(() → core::int => let final<BottomType> #t10 = invalid-expression "pkg/front_end/testcases/nnbd/shorting_stop.dart:22:24: Error: Operator 'unary-' cannot be called on 'int?' because it is potentially null.
+  throwsInStrong(() => -c?.field); // error
+                       ^" in (let final self::Class? #t11 = c in #t11.{core::Object::==}(null) ?{core::int?} null : #t11{self::Class}.{self::Class::field}).{core::int::unary-}());
+  let final self::Class? #t12 = c in #t12.{core::Object::==}(null) ?{core::bool?} null : #t12{self::Class}.{self::Class::next}.{self::Class::[]}(0).{core::int::isEven};
+  self::throwsInStrong(() → core::int => let final<BottomType> #t13 = invalid-expression "pkg/front_end/testcases/nnbd/shorting_stop.dart:25:35: Error: Operator '+' cannot be called on 'int?' because it is potentially null.
   throwsInStrong(() => c?.next[0] + 2); // error
-                                  ^" in (let final self::Class? #t12 = c in #t12.{core::Object::==}(null) ?{core::int?} null : #t12{self::Class}.{self::Class::next}.{self::Class::[]}(0)).{core::num::+}(2));
-  let final self::Class? #t13 = c in #t13.{core::Object::==}(null) ?{core::int?} null : let final self::Class #t14 = #t13{self::Class}.{self::Class::next} in let final core::int #t15 = 0 in let final core::int #t16 = #t14.{self::Class::[]}(#t15).{core::num::+}(1) in let final void #t17 = #t14.{self::Class::[]=}(#t15, #t16) in #t16;
-  let final self::Class? #t18 = c in #t18.{core::Object::==}(null) ?{core::int?} null : let final self::Class #t19 = #t18{self::Class}.{self::Class::next} in let final core::int #t20 = 0 in #t19.{self::Class::[]=}(#t20, #t19.{self::Class::[]}(#t20).{core::num::+}(1));
-  self::throwsInStrong(() → core::bool* => let final<BottomType> #t21 = invalid-expression "pkg/front_end/testcases/nnbd/shorting_stop.dart:29:37: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+                                  ^" in (let final self::Class? #t14 = c in #t14.{core::Object::==}(null) ?{core::int?} null : #t14{self::Class}.{self::Class::next}.{self::Class::[]}(0)).{core::num::+}(2));
+  let final self::Class? #t15 = c in #t15.{core::Object::==}(null) ?{core::int?} null : let final self::Class #t16 = #t15{self::Class}.{self::Class::next} in let final core::int #t17 = 0 in let final core::int #t18 = #t16.{self::Class::[]}(#t17).{core::num::+}(1) in let final void #t19 = #t16.{self::Class::[]=}(#t17, #t18) in #t18;
+  let final self::Class? #t20 = c in #t20.{core::Object::==}(null) ?{core::int?} null : let final self::Class #t21 = #t20{self::Class}.{self::Class::next} in let final core::int #t22 = 0 in #t21.{self::Class::[]=}(#t22, #t21.{self::Class::[]}(#t22).{core::num::+}(1));
+  self::throwsInStrong(() → core::bool => let final<BottomType> #t23 = invalid-expression "pkg/front_end/testcases/nnbd/shorting_stop.dart:28:37: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
 Try accessing using ?. instead.
   throwsInStrong(() => (c?.next[0]).isEven); // error
-                                    ^^^^^^" in (let final self::Class? #t22 = c in #t22.{core::Object::==}(null) ?{core::int?} null : #t22{self::Class}.{self::Class::next}.{self::Class::[]}(0)).{core::int::isEven});
+                                    ^^^^^^" in (let final self::Class? #t24 = c in #t24.{core::Object::==}(null) ?{core::int?} null : #t24{self::Class}.{self::Class::next}.{self::Class::[]}(0)).{core::int::isEven});
+  self::throwsInStrong(() → core::int => let final<BottomType> #t25 = invalid-expression "pkg/front_end/testcases/nnbd/shorting_stop.dart:29:24: Error: Operator 'unary-' cannot be called on 'int?' because it is potentially null.
+  throwsInStrong(() => -c?.next[0]); // error
+                       ^" in (let final self::Class? #t26 = c in #t26.{core::Object::==}(null) ?{core::int?} null : #t26{self::Class}.{self::Class::next}.{self::Class::[]}(0)).{core::int::unary-}());
 }
 static method _inStrongMode() → core::bool {
   (core::String?) → core::Null? f = (core::String? s) → core::Null? {
-    let final<BottomType> #t23 = invalid-expression "pkg/front_end/testcases/nnbd/shorting_stop.dart:36:7: Error: Property 'length' cannot be accessed on 'String?' because it is potentially null.
+    let final<BottomType> #t27 = invalid-expression "pkg/front_end/testcases/nnbd/shorting_stop.dart:36:7: Error: Property 'length' cannot be accessed on 'String?' because it is potentially null.
 Try accessing using ?. instead.
     s.length; // This will be an invalid expression in strong mode.
       ^^^^^^" in s.{core::String::length};
diff --git a/pkg/front_end/testcases/nnbd/shorting_stop.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/shorting_stop.dart.strong.transformed.expect
index fe0c720..69c985e 100644
--- a/pkg/front_end/testcases/nnbd/shorting_stop.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/shorting_stop.dart.strong.transformed.expect
@@ -6,21 +6,29 @@
 //   throwsInStrong(() => c?.field + 2); // error
 //                                 ^
 //
-// pkg/front_end/testcases/nnbd/shorting_stop.dart:22:34: Error: Property 'field' cannot be accessed on 'Class?' because it is potentially null.
+// pkg/front_end/testcases/nnbd/shorting_stop.dart:21:34: Error: Property 'field' cannot be accessed on 'Class?' because it is potentially null.
 //  - 'Class' is from 'pkg/front_end/testcases/nnbd/shorting_stop.dart'.
 // Try accessing using ?. instead.
 //   throwsInStrong(() => (c?.next).field); // error
 //                                  ^^^^^
 //
+// pkg/front_end/testcases/nnbd/shorting_stop.dart:22:24: Error: Operator 'unary-' cannot be called on 'int?' because it is potentially null.
+//   throwsInStrong(() => -c?.field); // error
+//                        ^
+//
 // pkg/front_end/testcases/nnbd/shorting_stop.dart:25:35: Error: Operator '+' cannot be called on 'int?' because it is potentially null.
 //   throwsInStrong(() => c?.next[0] + 2); // error
 //                                   ^
 //
-// pkg/front_end/testcases/nnbd/shorting_stop.dart:29:37: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+// pkg/front_end/testcases/nnbd/shorting_stop.dart:28:37: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
 // Try accessing using ?. instead.
 //   throwsInStrong(() => (c?.next[0]).isEven); // error
 //                                     ^^^^^^
 //
+// pkg/front_end/testcases/nnbd/shorting_stop.dart:29:24: Error: Operator 'unary-' cannot be called on 'int?' because it is potentially null.
+//   throwsInStrong(() => -c?.next[0]); // error
+//                        ^
+//
 // pkg/front_end/testcases/nnbd/shorting_stop.dart:36:7: Error: Property 'length' cannot be accessed on 'String?' because it is potentially null.
 // Try accessing using ?. instead.
 //     s.length; // This will be an invalid expression in strong mode.
@@ -51,25 +59,31 @@
                                 ^" in (let final self::Class? #t3 = c in #t3.{core::Object::==}(null) ?{core::int?} null : #t3{self::Class}.{self::Class::field}).{core::num::+}(2));
   let final self::Class? #t4 = c in #t4.{core::Object::==}(null) ?{core::int?} null : let final core::int #t5 = #t4.{self::Class::field}.{core::num::+}(1) in let final void #t6 = #t4.{self::Class::field} = #t5 in #t5;
   let final self::Class? #t7 = c in #t7.{core::Object::==}(null) ?{core::int?} null : #t7.{self::Class::field} = #t7.{self::Class::field}.{core::num::+}(1);
-  self::throwsInStrong(() → core::int => let final<BottomType> #t8 = invalid-expression "pkg/front_end/testcases/nnbd/shorting_stop.dart:22:34: Error: Property 'field' cannot be accessed on 'Class?' because it is potentially null.
+  self::throwsInStrong(() → core::int => let final<BottomType> #t8 = invalid-expression "pkg/front_end/testcases/nnbd/shorting_stop.dart:21:34: Error: Property 'field' cannot be accessed on 'Class?' because it is potentially null.
  - 'Class' is from 'pkg/front_end/testcases/nnbd/shorting_stop.dart'.
 Try accessing using ?. instead.
   throwsInStrong(() => (c?.next).field); // error
                                  ^^^^^" in (let final self::Class? #t9 = c in #t9.{core::Object::==}(null) ?{self::Class?} null : #t9{self::Class}.{self::Class::next}).{self::Class::field});
-  let final self::Class? #t10 = c in #t10.{core::Object::==}(null) ?{core::bool?} null : #t10{self::Class}.{self::Class::next}.{self::Class::[]}(0).{core::int::isEven};
-  self::throwsInStrong(() → core::int => let final<BottomType> #t11 = invalid-expression "pkg/front_end/testcases/nnbd/shorting_stop.dart:25:35: Error: Operator '+' cannot be called on 'int?' because it is potentially null.
+  self::throwsInStrong(() → core::int => let final<BottomType> #t10 = invalid-expression "pkg/front_end/testcases/nnbd/shorting_stop.dart:22:24: Error: Operator 'unary-' cannot be called on 'int?' because it is potentially null.
+  throwsInStrong(() => -c?.field); // error
+                       ^" in (let final self::Class? #t11 = c in #t11.{core::Object::==}(null) ?{core::int?} null : #t11{self::Class}.{self::Class::field}).{core::int::unary-}());
+  let final self::Class? #t12 = c in #t12.{core::Object::==}(null) ?{core::bool?} null : #t12{self::Class}.{self::Class::next}.{self::Class::[]}(0).{core::int::isEven};
+  self::throwsInStrong(() → core::int => let final<BottomType> #t13 = invalid-expression "pkg/front_end/testcases/nnbd/shorting_stop.dart:25:35: Error: Operator '+' cannot be called on 'int?' because it is potentially null.
   throwsInStrong(() => c?.next[0] + 2); // error
-                                  ^" in (let final self::Class? #t12 = c in #t12.{core::Object::==}(null) ?{core::int?} null : #t12{self::Class}.{self::Class::next}.{self::Class::[]}(0)).{core::num::+}(2));
-  let final self::Class? #t13 = c in #t13.{core::Object::==}(null) ?{core::int?} null : let final self::Class #t14 = #t13{self::Class}.{self::Class::next} in let final core::int #t15 = 0 in let final core::int #t16 = #t14.{self::Class::[]}(#t15).{core::num::+}(1) in let final void #t17 = #t14.{self::Class::[]=}(#t15, #t16) in #t16;
-  let final self::Class? #t18 = c in #t18.{core::Object::==}(null) ?{core::int?} null : let final self::Class #t19 = #t18{self::Class}.{self::Class::next} in let final core::int #t20 = 0 in #t19.{self::Class::[]=}(#t20, #t19.{self::Class::[]}(#t20).{core::num::+}(1));
-  self::throwsInStrong(() → core::bool* => let final<BottomType> #t21 = invalid-expression "pkg/front_end/testcases/nnbd/shorting_stop.dart:29:37: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+                                  ^" in (let final self::Class? #t14 = c in #t14.{core::Object::==}(null) ?{core::int?} null : #t14{self::Class}.{self::Class::next}.{self::Class::[]}(0)).{core::num::+}(2));
+  let final self::Class? #t15 = c in #t15.{core::Object::==}(null) ?{core::int?} null : let final self::Class #t16 = #t15{self::Class}.{self::Class::next} in let final core::int #t17 = 0 in let final core::int #t18 = #t16.{self::Class::[]}(#t17).{core::num::+}(1) in let final void #t19 = #t16.{self::Class::[]=}(#t17, #t18) in #t18;
+  let final self::Class? #t20 = c in #t20.{core::Object::==}(null) ?{core::int?} null : let final self::Class #t21 = #t20{self::Class}.{self::Class::next} in let final core::int #t22 = 0 in #t21.{self::Class::[]=}(#t22, #t21.{self::Class::[]}(#t22).{core::num::+}(1));
+  self::throwsInStrong(() → core::bool => let final<BottomType> #t23 = invalid-expression "pkg/front_end/testcases/nnbd/shorting_stop.dart:28:37: Error: Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
 Try accessing using ?. instead.
   throwsInStrong(() => (c?.next[0]).isEven); // error
-                                    ^^^^^^" in (let final self::Class? #t22 = c in #t22.{core::Object::==}(null) ?{core::int?} null : #t22{self::Class}.{self::Class::next}.{self::Class::[]}(0)).{core::int::isEven});
+                                    ^^^^^^" in (let final self::Class? #t24 = c in #t24.{core::Object::==}(null) ?{core::int?} null : #t24{self::Class}.{self::Class::next}.{self::Class::[]}(0)).{core::int::isEven});
+  self::throwsInStrong(() → core::int => let final<BottomType> #t25 = invalid-expression "pkg/front_end/testcases/nnbd/shorting_stop.dart:29:24: Error: Operator 'unary-' cannot be called on 'int?' because it is potentially null.
+  throwsInStrong(() => -c?.next[0]); // error
+                       ^" in (let final self::Class? #t26 = c in #t26.{core::Object::==}(null) ?{core::int?} null : #t26{self::Class}.{self::Class::next}.{self::Class::[]}(0)).{core::int::unary-}());
 }
 static method _inStrongMode() → core::bool {
   (core::String?) → core::Null? f = (core::String? s) → core::Null? {
-    let final<BottomType> #t23 = invalid-expression "pkg/front_end/testcases/nnbd/shorting_stop.dart:36:7: Error: Property 'length' cannot be accessed on 'String?' because it is potentially null.
+    let final<BottomType> #t27 = invalid-expression "pkg/front_end/testcases/nnbd/shorting_stop.dart:36:7: Error: Property 'length' cannot be accessed on 'String?' because it is potentially null.
 Try accessing using ?. instead.
     s.length; // This will be an invalid expression in strong mode.
       ^^^^^^" in s.{core::String::length};
diff --git a/pkg/front_end/testcases/nnbd/shorting_stop.dart.weak.expect b/pkg/front_end/testcases/nnbd/shorting_stop.dart.weak.expect
index c6ea10c..0a8d639 100644
--- a/pkg/front_end/testcases/nnbd/shorting_stop.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/shorting_stop.dart.weak.expect
@@ -6,21 +6,29 @@
 //   throwsInStrong(() => c?.field + 2); // error
 //                                 ^
 //
-// pkg/front_end/testcases/nnbd/shorting_stop.dart:22:34: Warning: Property 'field' is accessed on 'Class?' which is potentially null.
+// pkg/front_end/testcases/nnbd/shorting_stop.dart:21:34: Warning: Property 'field' is accessed on 'Class?' which is potentially null.
 //  - 'Class' is from 'pkg/front_end/testcases/nnbd/shorting_stop.dart'.
 // Try accessing using ?. instead.
 //   throwsInStrong(() => (c?.next).field); // error
 //                                  ^^^^^
 //
+// pkg/front_end/testcases/nnbd/shorting_stop.dart:22:24: Warning: Operator 'unary-' is called on 'int?' which is potentially null.
+//   throwsInStrong(() => -c?.field); // error
+//                        ^
+//
 // pkg/front_end/testcases/nnbd/shorting_stop.dart:25:35: Warning: Operator '+' is called on 'int?' which is potentially null.
 //   throwsInStrong(() => c?.next[0] + 2); // error
 //                                   ^
 //
-// pkg/front_end/testcases/nnbd/shorting_stop.dart:29:37: Warning: Property 'isEven' is accessed on 'int?' which is potentially null.
+// pkg/front_end/testcases/nnbd/shorting_stop.dart:28:37: Warning: Property 'isEven' is accessed on 'int?' which is potentially null.
 // Try accessing using ?. instead.
 //   throwsInStrong(() => (c?.next[0]).isEven); // error
 //                                     ^^^^^^
 //
+// pkg/front_end/testcases/nnbd/shorting_stop.dart:29:24: Warning: Operator 'unary-' is called on 'int?' which is potentially null.
+//   throwsInStrong(() => -c?.next[0]); // error
+//                        ^
+//
 // pkg/front_end/testcases/nnbd/shorting_stop.dart:36:7: Warning: Property 'length' is accessed on 'String?' which is potentially null.
 // Try accessing using ?. instead.
 //     s.length; // This will be an invalid expression in strong mode.
@@ -50,11 +58,13 @@
   let final self::Class? #t3 = c in #t3.{core::Object::==}(null) ?{core::int?} null : let final core::int #t4 = #t3.{self::Class::field}.{core::num::+}(1) in let final void #t5 = #t3.{self::Class::field} = #t4 in #t4;
   let final self::Class? #t6 = c in #t6.{core::Object::==}(null) ?{core::int?} null : #t6.{self::Class::field} = #t6.{self::Class::field}.{core::num::+}(1);
   self::throwsInStrong(() → core::int => (let final self::Class? #t7 = c in #t7.{core::Object::==}(null) ?{self::Class?} null : #t7{self::Class}.{self::Class::next}).{self::Class::field});
-  let final self::Class? #t8 = c in #t8.{core::Object::==}(null) ?{core::bool?} null : #t8{self::Class}.{self::Class::next}.{self::Class::[]}(0).{core::int::isEven};
-  self::throwsInStrong(() → core::int => (let final self::Class? #t9 = c in #t9.{core::Object::==}(null) ?{core::int?} null : #t9{self::Class}.{self::Class::next}.{self::Class::[]}(0)).{core::num::+}(2));
-  let final self::Class? #t10 = c in #t10.{core::Object::==}(null) ?{core::int?} null : let final self::Class #t11 = #t10{self::Class}.{self::Class::next} in let final core::int #t12 = 0 in let final core::int #t13 = #t11.{self::Class::[]}(#t12).{core::num::+}(1) in let final void #t14 = #t11.{self::Class::[]=}(#t12, #t13) in #t13;
-  let final self::Class? #t15 = c in #t15.{core::Object::==}(null) ?{core::int?} null : let final self::Class #t16 = #t15{self::Class}.{self::Class::next} in let final core::int #t17 = 0 in #t16.{self::Class::[]=}(#t17, #t16.{self::Class::[]}(#t17).{core::num::+}(1));
-  self::throwsInStrong(() → core::bool* => (let final self::Class? #t18 = c in #t18.{core::Object::==}(null) ?{core::int?} null : #t18{self::Class}.{self::Class::next}.{self::Class::[]}(0)).{core::int::isEven});
+  self::throwsInStrong(() → core::int => (let final self::Class? #t8 = c in #t8.{core::Object::==}(null) ?{core::int?} null : #t8{self::Class}.{self::Class::field}).{core::int::unary-}());
+  let final self::Class? #t9 = c in #t9.{core::Object::==}(null) ?{core::bool?} null : #t9{self::Class}.{self::Class::next}.{self::Class::[]}(0).{core::int::isEven};
+  self::throwsInStrong(() → core::int => (let final self::Class? #t10 = c in #t10.{core::Object::==}(null) ?{core::int?} null : #t10{self::Class}.{self::Class::next}.{self::Class::[]}(0)).{core::num::+}(2));
+  let final self::Class? #t11 = c in #t11.{core::Object::==}(null) ?{core::int?} null : let final self::Class #t12 = #t11{self::Class}.{self::Class::next} in let final core::int #t13 = 0 in let final core::int #t14 = #t12.{self::Class::[]}(#t13).{core::num::+}(1) in let final void #t15 = #t12.{self::Class::[]=}(#t13, #t14) in #t14;
+  let final self::Class? #t16 = c in #t16.{core::Object::==}(null) ?{core::int?} null : let final self::Class #t17 = #t16{self::Class}.{self::Class::next} in let final core::int #t18 = 0 in #t17.{self::Class::[]=}(#t18, #t17.{self::Class::[]}(#t18).{core::num::+}(1));
+  self::throwsInStrong(() → core::bool => (let final self::Class? #t19 = c in #t19.{core::Object::==}(null) ?{core::int?} null : #t19{self::Class}.{self::Class::next}.{self::Class::[]}(0)).{core::int::isEven});
+  self::throwsInStrong(() → core::int => (let final self::Class? #t20 = c in #t20.{core::Object::==}(null) ?{core::int?} null : #t20{self::Class}.{self::Class::next}.{self::Class::[]}(0)).{core::int::unary-}());
 }
 static method _inStrongMode() → core::bool {
   (core::String?) → core::Null? f = (core::String? s) → core::Null? {
diff --git a/pkg/front_end/testcases/nnbd/shorting_stop.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/shorting_stop.dart.weak.transformed.expect
index c6ea10c..0a8d639 100644
--- a/pkg/front_end/testcases/nnbd/shorting_stop.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/shorting_stop.dart.weak.transformed.expect
@@ -6,21 +6,29 @@
 //   throwsInStrong(() => c?.field + 2); // error
 //                                 ^
 //
-// pkg/front_end/testcases/nnbd/shorting_stop.dart:22:34: Warning: Property 'field' is accessed on 'Class?' which is potentially null.
+// pkg/front_end/testcases/nnbd/shorting_stop.dart:21:34: Warning: Property 'field' is accessed on 'Class?' which is potentially null.
 //  - 'Class' is from 'pkg/front_end/testcases/nnbd/shorting_stop.dart'.
 // Try accessing using ?. instead.
 //   throwsInStrong(() => (c?.next).field); // error
 //                                  ^^^^^
 //
+// pkg/front_end/testcases/nnbd/shorting_stop.dart:22:24: Warning: Operator 'unary-' is called on 'int?' which is potentially null.
+//   throwsInStrong(() => -c?.field); // error
+//                        ^
+//
 // pkg/front_end/testcases/nnbd/shorting_stop.dart:25:35: Warning: Operator '+' is called on 'int?' which is potentially null.
 //   throwsInStrong(() => c?.next[0] + 2); // error
 //                                   ^
 //
-// pkg/front_end/testcases/nnbd/shorting_stop.dart:29:37: Warning: Property 'isEven' is accessed on 'int?' which is potentially null.
+// pkg/front_end/testcases/nnbd/shorting_stop.dart:28:37: Warning: Property 'isEven' is accessed on 'int?' which is potentially null.
 // Try accessing using ?. instead.
 //   throwsInStrong(() => (c?.next[0]).isEven); // error
 //                                     ^^^^^^
 //
+// pkg/front_end/testcases/nnbd/shorting_stop.dart:29:24: Warning: Operator 'unary-' is called on 'int?' which is potentially null.
+//   throwsInStrong(() => -c?.next[0]); // error
+//                        ^
+//
 // pkg/front_end/testcases/nnbd/shorting_stop.dart:36:7: Warning: Property 'length' is accessed on 'String?' which is potentially null.
 // Try accessing using ?. instead.
 //     s.length; // This will be an invalid expression in strong mode.
@@ -50,11 +58,13 @@
   let final self::Class? #t3 = c in #t3.{core::Object::==}(null) ?{core::int?} null : let final core::int #t4 = #t3.{self::Class::field}.{core::num::+}(1) in let final void #t5 = #t3.{self::Class::field} = #t4 in #t4;
   let final self::Class? #t6 = c in #t6.{core::Object::==}(null) ?{core::int?} null : #t6.{self::Class::field} = #t6.{self::Class::field}.{core::num::+}(1);
   self::throwsInStrong(() → core::int => (let final self::Class? #t7 = c in #t7.{core::Object::==}(null) ?{self::Class?} null : #t7{self::Class}.{self::Class::next}).{self::Class::field});
-  let final self::Class? #t8 = c in #t8.{core::Object::==}(null) ?{core::bool?} null : #t8{self::Class}.{self::Class::next}.{self::Class::[]}(0).{core::int::isEven};
-  self::throwsInStrong(() → core::int => (let final self::Class? #t9 = c in #t9.{core::Object::==}(null) ?{core::int?} null : #t9{self::Class}.{self::Class::next}.{self::Class::[]}(0)).{core::num::+}(2));
-  let final self::Class? #t10 = c in #t10.{core::Object::==}(null) ?{core::int?} null : let final self::Class #t11 = #t10{self::Class}.{self::Class::next} in let final core::int #t12 = 0 in let final core::int #t13 = #t11.{self::Class::[]}(#t12).{core::num::+}(1) in let final void #t14 = #t11.{self::Class::[]=}(#t12, #t13) in #t13;
-  let final self::Class? #t15 = c in #t15.{core::Object::==}(null) ?{core::int?} null : let final self::Class #t16 = #t15{self::Class}.{self::Class::next} in let final core::int #t17 = 0 in #t16.{self::Class::[]=}(#t17, #t16.{self::Class::[]}(#t17).{core::num::+}(1));
-  self::throwsInStrong(() → core::bool* => (let final self::Class? #t18 = c in #t18.{core::Object::==}(null) ?{core::int?} null : #t18{self::Class}.{self::Class::next}.{self::Class::[]}(0)).{core::int::isEven});
+  self::throwsInStrong(() → core::int => (let final self::Class? #t8 = c in #t8.{core::Object::==}(null) ?{core::int?} null : #t8{self::Class}.{self::Class::field}).{core::int::unary-}());
+  let final self::Class? #t9 = c in #t9.{core::Object::==}(null) ?{core::bool?} null : #t9{self::Class}.{self::Class::next}.{self::Class::[]}(0).{core::int::isEven};
+  self::throwsInStrong(() → core::int => (let final self::Class? #t10 = c in #t10.{core::Object::==}(null) ?{core::int?} null : #t10{self::Class}.{self::Class::next}.{self::Class::[]}(0)).{core::num::+}(2));
+  let final self::Class? #t11 = c in #t11.{core::Object::==}(null) ?{core::int?} null : let final self::Class #t12 = #t11{self::Class}.{self::Class::next} in let final core::int #t13 = 0 in let final core::int #t14 = #t12.{self::Class::[]}(#t13).{core::num::+}(1) in let final void #t15 = #t12.{self::Class::[]=}(#t13, #t14) in #t14;
+  let final self::Class? #t16 = c in #t16.{core::Object::==}(null) ?{core::int?} null : let final self::Class #t17 = #t16{self::Class}.{self::Class::next} in let final core::int #t18 = 0 in #t17.{self::Class::[]=}(#t18, #t17.{self::Class::[]}(#t18).{core::num::+}(1));
+  self::throwsInStrong(() → core::bool => (let final self::Class? #t19 = c in #t19.{core::Object::==}(null) ?{core::int?} null : #t19{self::Class}.{self::Class::next}.{self::Class::[]}(0)).{core::int::isEven});
+  self::throwsInStrong(() → core::int => (let final self::Class? #t20 = c in #t20.{core::Object::==}(null) ?{core::int?} null : #t20{self::Class}.{self::Class::next}.{self::Class::[]}(0)).{core::int::unary-}());
 }
 static method _inStrongMode() → core::bool {
   (core::String?) → core::Null? f = (core::String? s) → core::Null? {
diff --git a/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.strong.expect b/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.strong.expect
index b0ff7b9..19938b7 100644
--- a/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.strong.expect
@@ -8,10 +8,10 @@
   let final core::String #t4 = s in #t4.{core::String::==}(null) ?{core::String} "foo" : #t4;
   s.{core::String::==}(null) ?{core::String} s = "foo" : null;
   block {
-    final core::List<core::String*> #t5 = <core::String*>[];
-    final core::Iterable<core::String*>? #t6 = l;
+    final core::List<core::String> #t5 = <core::String>[];
+    final core::Iterable<core::String>? #t6 = l;
     if(!#t6.{core::Object::==}(null))
-      for (final core::String* #t7 in #t6{core::Iterable<core::String*>})
+      for (final core::String #t7 in #t6{core::Iterable<core::String>})
         #t5.{core::List::add}(#t7);
   } =>#t5;
   s!;
diff --git a/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.strong.transformed.expect
index 790e145..a35cd49 100644
--- a/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.strong.transformed.expect
@@ -9,12 +9,12 @@
   let final core::String #t4 = s in #t4.{core::String::==}(null) ?{core::String} "foo" : #t4;
   s.{core::String::==}(null) ?{core::String} s = "foo" : null;
   block {
-    final core::List<core::String*> #t5 = <core::String*>[];
-    final core::Iterable<core::String*>? #t6 = l;
+    final core::List<core::String> #t5 = <core::String>[];
+    final core::Iterable<core::String>? #t6 = l;
     if(!#t6.{core::Object::==}(null)) {
-      core::Iterator<core::String*>* :sync-for-iterator = _in::unsafeCast<core::Iterable<core::String*>*>(#t6{core::Iterable<core::String*>}).{core::Iterable::iterator};
+      core::Iterator<core::String>* :sync-for-iterator = _in::unsafeCast<core::Iterable<core::String>*>(#t6{core::Iterable<core::String>}).{core::Iterable::iterator};
       for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
-        final core::String* #t7 = :sync-for-iterator.{core::Iterator::current};
+        final core::String #t7 = :sync-for-iterator.{core::Iterator::current};
         #t5.{core::List::add}(#t7);
       }
     }
diff --git a/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.weak.expect b/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.weak.expect
index b0ff7b9..19938b7 100644
--- a/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.weak.expect
@@ -8,10 +8,10 @@
   let final core::String #t4 = s in #t4.{core::String::==}(null) ?{core::String} "foo" : #t4;
   s.{core::String::==}(null) ?{core::String} s = "foo" : null;
   block {
-    final core::List<core::String*> #t5 = <core::String*>[];
-    final core::Iterable<core::String*>? #t6 = l;
+    final core::List<core::String> #t5 = <core::String>[];
+    final core::Iterable<core::String>? #t6 = l;
     if(!#t6.{core::Object::==}(null))
-      for (final core::String* #t7 in #t6{core::Iterable<core::String*>})
+      for (final core::String #t7 in #t6{core::Iterable<core::String>})
         #t5.{core::List::add}(#t7);
   } =>#t5;
   s!;
diff --git a/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.weak.transformed.expect
index 790e145..a35cd49 100644
--- a/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.weak.transformed.expect
@@ -9,12 +9,12 @@
   let final core::String #t4 = s in #t4.{core::String::==}(null) ?{core::String} "foo" : #t4;
   s.{core::String::==}(null) ?{core::String} s = "foo" : null;
   block {
-    final core::List<core::String*> #t5 = <core::String*>[];
-    final core::Iterable<core::String*>? #t6 = l;
+    final core::List<core::String> #t5 = <core::String>[];
+    final core::Iterable<core::String>? #t6 = l;
     if(!#t6.{core::Object::==}(null)) {
-      core::Iterator<core::String*>* :sync-for-iterator = _in::unsafeCast<core::Iterable<core::String*>*>(#t6{core::Iterable<core::String*>}).{core::Iterable::iterator};
+      core::Iterator<core::String>* :sync-for-iterator = _in::unsafeCast<core::Iterable<core::String>*>(#t6{core::Iterable<core::String>}).{core::Iterable::iterator};
       for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
-        final core::String* #t7 = :sync-for-iterator.{core::Iterator::current};
+        final core::String #t7 = :sync-for-iterator.{core::Iterator::current};
         #t5.{core::List::add}(#t7);
       }
     }
diff --git a/pkg/front_end/testcases/no_such_method_forwarders/abstract_override_abstract_different_type.dart b/pkg/front_end/testcases/no_such_method_forwarders/abstract_override_abstract_different_type.dart
new file mode 100644
index 0000000..f616ccf
--- /dev/null
+++ b/pkg/front_end/testcases/no_such_method_forwarders/abstract_override_abstract_different_type.dart
@@ -0,0 +1,42 @@
+// Copyright (c) 2020, 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.
+
+// This is a regression test for http://dartbug.com/40248.
+
+class Base {
+  set push(int x);
+  set float(covariant int x);
+  noSuchMethod(i) => print("${runtimeType}: ${i.positionalArguments[0]}");
+}
+
+class Me extends Base {}
+
+class You extends Base {
+  set push(num x);
+  set float(num x);
+}
+
+main() {
+  List<Base> list = [Me(), You()];
+  for (Base baba in list) {
+    baba.push = 0;
+    baba.float = 1;
+    if (baba is You) {
+      baba.push = 2.3;
+      baba.float = 4.5;
+    }
+    try {
+      (baba as dynamic).push = 6.7;
+      baba is You || (throw "Fail!");
+    } on TypeError {
+      baba is Me || (throw "Fail!");
+    }
+    try {
+      (baba as dynamic).float = 8.9;
+      baba is You || (throw "Fail!");
+    } on TypeError {
+      baba is Me || (throw "Fail!");
+    }
+  }
+}
diff --git a/pkg/front_end/testcases/no_such_method_forwarders/abstract_override_abstract_different_type.dart.outline.expect b/pkg/front_end/testcases/no_such_method_forwarders/abstract_override_abstract_different_type.dart.outline.expect
new file mode 100644
index 0000000..bc26eb6
--- /dev/null
+++ b/pkg/front_end/testcases/no_such_method_forwarders/abstract_override_abstract_different_type.dart.outline.expect
@@ -0,0 +1,28 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Base extends core::Object {
+  synthetic constructor •() → self::Base*
+    ;
+  no-such-method-forwarder set push(core::int* x) → void
+    return this.{self::Base::noSuchMethod}(new core::_InvocationMirror::_withType(#push=, 2, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[x]), core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{})));
+  no-such-method-forwarder set float(covariant core::int* x) → void
+    return this.{self::Base::noSuchMethod}(new core::_InvocationMirror::_withType(#float=, 2, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[x]), core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{})));
+  method noSuchMethod(core::Invocation* i) → dynamic
+    ;
+}
+class Me extends self::Base {
+  synthetic constructor •() → self::Me*
+    ;
+}
+class You extends self::Base {
+  synthetic constructor •() → self::You*
+    ;
+  no-such-method-forwarder set push(core::num* x) → void
+    return this.{self::Base::noSuchMethod}(new core::_InvocationMirror::_withType(#push=, 2, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[x]), core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{})));
+  no-such-method-forwarder set float(covariant core::num* x) → void
+    return this.{self::Base::noSuchMethod}(new core::_InvocationMirror::_withType(#float=, 2, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[x]), core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{})));
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/no_such_method_forwarders/abstract_override_abstract_different_type.dart.strong.expect b/pkg/front_end/testcases/no_such_method_forwarders/abstract_override_abstract_different_type.dart.strong.expect
new file mode 100644
index 0000000..f100a39
--- /dev/null
+++ b/pkg/front_end/testcases/no_such_method_forwarders/abstract_override_abstract_different_type.dart.strong.expect
@@ -0,0 +1,62 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Base extends core::Object {
+  synthetic constructor •() → self::Base*
+    : super core::Object::•()
+    ;
+  no-such-method-forwarder set push(core::int* x) → void
+    return this.{self::Base::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[x]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
+  no-such-method-forwarder set float(covariant core::int* x) → void
+    return this.{self::Base::noSuchMethod}(new core::_InvocationMirror::_withType(#C5, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[x]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
+  method noSuchMethod(core::Invocation* i) → dynamic
+    return core::print("${this.{core::Object::runtimeType}}: ${i.{core::Invocation::positionalArguments}.{core::List::[]}(0)}");
+}
+class Me extends self::Base {
+  synthetic constructor •() → self::Me*
+    : super self::Base::•()
+    ;
+}
+class You extends self::Base {
+  synthetic constructor •() → self::You*
+    : super self::Base::•()
+    ;
+  no-such-method-forwarder set push(core::num* x) → void
+    return this.{self::Base::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[x]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
+  no-such-method-forwarder set float(covariant core::num* x) → void
+    return this.{self::Base::noSuchMethod}(new core::_InvocationMirror::_withType(#C5, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[x]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
+}
+static method main() → dynamic {
+  core::List<self::Base*>* list = <self::Base*>[new self::Me::•(), new self::You::•()];
+  for (self::Base* baba in list) {
+    baba.{self::Base::push} = 0;
+    baba.{self::Base::float} = 1;
+    if(baba is self::You*) {
+      baba{self::You*}.{self::You::push} = 2.3;
+      baba{self::You*}.{self::You::float} = 4.5;
+    }
+    try {
+      (baba as dynamic).push = 6.7;
+      baba is self::You* || (throw "Fail!");
+    }
+    on core::TypeError* catch(no-exception-var) {
+      baba is self::Me* || (throw "Fail!");
+    }
+    try {
+      (baba as dynamic).float = 8.9;
+      baba is self::You* || (throw "Fail!");
+    }
+    on core::TypeError* catch(no-exception-var) {
+      baba is self::Me* || (throw "Fail!");
+    }
+  }
+}
+
+constants  {
+  #C1 = #push=
+  #C2 = <core::Type*>[]
+  #C3 = <dynamic>[]
+  #C4 = core::_ImmutableMap<core::Symbol*, dynamic> {_kvPairs:#C3}
+  #C5 = #float=
+}
diff --git a/pkg/front_end/testcases/no_such_method_forwarders/abstract_override_abstract_different_type.dart.strong.transformed.expect b/pkg/front_end/testcases/no_such_method_forwarders/abstract_override_abstract_different_type.dart.strong.transformed.expect
new file mode 100644
index 0000000..c033f30
--- /dev/null
+++ b/pkg/front_end/testcases/no_such_method_forwarders/abstract_override_abstract_different_type.dart.strong.transformed.expect
@@ -0,0 +1,69 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+class Base extends core::Object {
+  synthetic constructor •() → self::Base*
+    : super core::Object::•()
+    ;
+  no-such-method-forwarder set push(core::int* x) → void
+    return this.{self::Base::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[x]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
+  no-such-method-forwarder set float(covariant core::int* x) → void
+    return this.{self::Base::noSuchMethod}(new core::_InvocationMirror::_withType(#C5, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[x]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
+  method noSuchMethod(core::Invocation* i) → dynamic
+    return core::print("${this.{core::Object::runtimeType}}: ${i.{core::Invocation::positionalArguments}.{core::List::[]}(0)}");
+}
+class Me extends self::Base {
+  synthetic constructor •() → self::Me*
+    : super self::Base::•()
+    ;
+}
+class You extends self::Base {
+  synthetic constructor •() → self::You*
+    : super self::Base::•()
+    ;
+  no-such-method-forwarder set push(core::num* x) → void
+    return this.{self::Base::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[x]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
+  no-such-method-forwarder set float(covariant core::num* x) → void
+    return this.{self::Base::noSuchMethod}(new core::_InvocationMirror::_withType(#C5, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[x]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
+}
+static method main() → dynamic {
+  core::List<self::Base*>* list = <self::Base*>[new self::Me::•(), new self::You::•()];
+  {
+    core::Iterator<self::Base*>* :sync-for-iterator = _in::unsafeCast<core::Iterable<self::Base*>*>(list).{core::Iterable::iterator};
+    for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+      self::Base* baba = :sync-for-iterator.{core::Iterator::current};
+      {
+        baba.{self::Base::push} = 0;
+        baba.{self::Base::float} = 1;
+        if(baba is self::You*) {
+          baba{self::You*}.{self::You::push} = 2.3;
+          baba{self::You*}.{self::You::float} = 4.5;
+        }
+        try {
+          (baba as dynamic).push = 6.7;
+          baba is self::You* || (throw "Fail!");
+        }
+        on core::TypeError* catch(no-exception-var) {
+          baba is self::Me* || (throw "Fail!");
+        }
+        try {
+          (baba as dynamic).float = 8.9;
+          baba is self::You* || (throw "Fail!");
+        }
+        on core::TypeError* catch(no-exception-var) {
+          baba is self::Me* || (throw "Fail!");
+        }
+      }
+    }
+  }
+}
+
+constants  {
+  #C1 = #push=
+  #C2 = <core::Type*>[]
+  #C3 = <dynamic>[]
+  #C4 = core::_ImmutableMap<core::Symbol*, dynamic> {_kvPairs:#C3}
+  #C5 = #float=
+}
diff --git a/pkg/front_end/testcases/no_such_method_forwarders/abstract_override_with_different_signature.dart b/pkg/front_end/testcases/no_such_method_forwarders/abstract_override_with_different_signature.dart
new file mode 100644
index 0000000..053e43c
--- /dev/null
+++ b/pkg/front_end/testcases/no_such_method_forwarders/abstract_override_with_different_signature.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2020, 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.
+
+// This is a regression test for http://dartbug.com/40248.
+
+class Cat {
+  bool eatFood(String food) => true;
+}
+
+class MockCat implements Cat {
+  dynamic noSuchMethod(Invocation invocation) {
+    var arg = invocation.positionalArguments[0];
+    return arg is String && arg.isNotEmpty;
+  }
+}
+
+class MockCat2 extends MockCat {
+  noSuchMethod(_);
+}
+
+class MockCat3 extends MockCat2 implements Cat {
+  bool eatFood(String food, {double amount});
+}
+
+class MockCat4 extends MockCat2 implements HungryCat {}
+
+abstract class HungryCat {
+  bool eatFood(String food, {double amount, double yetAnother});
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/no_such_method_forwarders/abstract_override_with_different_signature.dart.outline.expect b/pkg/front_end/testcases/no_such_method_forwarders/abstract_override_with_different_signature.dart.outline.expect
new file mode 100644
index 0000000..6db081f
--- /dev/null
+++ b/pkg/front_end/testcases/no_such_method_forwarders/abstract_override_with_different_signature.dart.outline.expect
@@ -0,0 +1,42 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Cat extends core::Object {
+  synthetic constructor •() → self::Cat*
+    ;
+  method eatFood(core::String* food) → core::bool*
+    ;
+}
+class MockCat extends core::Object implements self::Cat {
+  synthetic constructor •() → self::MockCat*
+    ;
+  method noSuchMethod(core::Invocation* invocation) → dynamic
+    ;
+  no-such-method-forwarder method eatFood(core::String* food) → core::bool*
+    return this.{self::MockCat::noSuchMethod}(new core::_InvocationMirror::_withType(#eatFood, 0, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[food]), core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{}))) as{TypeError,ForDynamic} core::bool*;
+}
+class MockCat2 extends self::MockCat {
+  synthetic constructor •() → self::MockCat2*
+    ;
+  abstract method noSuchMethod(core::Invocation* _) → dynamic;
+}
+class MockCat3 extends self::MockCat2 implements self::Cat {
+  synthetic constructor •() → self::MockCat3*
+    ;
+  no-such-method-forwarder method eatFood(core::String* food, {core::double* amount}) → core::bool*
+    return this.{self::MockCat2::noSuchMethod}(new core::_InvocationMirror::_withType(#eatFood, 0, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[food]), core::Map::unmodifiable<core::Symbol*, dynamic>(<core::Symbol*, dynamic>{#amount: amount}))) as{TypeError,ForDynamic} core::bool*;
+}
+class MockCat4 extends self::MockCat2 implements self::HungryCat {
+  synthetic constructor •() → self::MockCat4*
+    ;
+  no-such-method-forwarder method eatFood(core::String* food, {core::double* amount, core::double* yetAnother}) → core::bool*
+    return this.{self::MockCat2::noSuchMethod}(new core::_InvocationMirror::_withType(#eatFood, 0, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[food]), core::Map::unmodifiable<core::Symbol*, dynamic>(<core::Symbol*, dynamic>{#amount: amount, #yetAnother: yetAnother}))) as{TypeError,ForDynamic} core::bool*;
+}
+abstract class HungryCat extends core::Object {
+  synthetic constructor •() → self::HungryCat*
+    ;
+  abstract method eatFood(core::String* food, {core::double* amount, core::double* yetAnother}) → core::bool*;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/no_such_method_forwarders/abstract_override_with_different_signature.dart.strong.expect b/pkg/front_end/testcases/no_such_method_forwarders/abstract_override_with_different_signature.dart.strong.expect
new file mode 100644
index 0000000..680a081
--- /dev/null
+++ b/pkg/front_end/testcases/no_such_method_forwarders/abstract_override_with_different_signature.dart.strong.expect
@@ -0,0 +1,59 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Cat extends core::Object {
+  synthetic constructor •() → self::Cat*
+    : super core::Object::•()
+    ;
+  method eatFood(core::String* food) → core::bool*
+    return true;
+}
+class MockCat extends core::Object implements self::Cat {
+  synthetic constructor •() → self::MockCat*
+    : super core::Object::•()
+    ;
+  method noSuchMethod(core::Invocation* invocation) → dynamic {
+    dynamic arg = invocation.{core::Invocation::positionalArguments}.{core::List::[]}(0);
+    return arg is core::String* && arg{core::String*}.{core::String::isNotEmpty};
+  }
+  no-such-method-forwarder method eatFood(core::String* food) → core::bool*
+    return this.{self::MockCat::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 0, #C2, core::List::unmodifiable<dynamic>(<dynamic>[food]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4))) as{TypeError,ForDynamic} core::bool*;
+}
+class MockCat2 extends self::MockCat {
+  synthetic constructor •() → self::MockCat2*
+    : super self::MockCat::•()
+    ;
+  abstract method noSuchMethod(core::Invocation* _) → dynamic;
+}
+class MockCat3 extends self::MockCat2 implements self::Cat {
+  synthetic constructor •() → self::MockCat3*
+    : super self::MockCat2::•()
+    ;
+  no-such-method-forwarder method eatFood(core::String* food, {core::double* amount = #C5}) → core::bool*
+    return this.{self::MockCat2::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 0, #C2, core::List::unmodifiable<dynamic>(<dynamic>[food]), core::Map::unmodifiable<core::Symbol*, dynamic>(<core::Symbol*, dynamic>{#C6: amount}))) as{TypeError,ForDynamic} core::bool*;
+}
+class MockCat4 extends self::MockCat2 implements self::HungryCat {
+  synthetic constructor •() → self::MockCat4*
+    : super self::MockCat2::•()
+    ;
+  no-such-method-forwarder method eatFood(core::String* food, {core::double* amount = #C5, core::double* yetAnother = #C5}) → core::bool*
+    return this.{self::MockCat2::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 0, #C2, core::List::unmodifiable<dynamic>(<dynamic>[food]), core::Map::unmodifiable<core::Symbol*, dynamic>(<core::Symbol*, dynamic>{#C6: amount, #C7: yetAnother}))) as{TypeError,ForDynamic} core::bool*;
+}
+abstract class HungryCat extends core::Object {
+  synthetic constructor •() → self::HungryCat*
+    : super core::Object::•()
+    ;
+  abstract method eatFood(core::String* food, {core::double* amount = #C5, core::double* yetAnother = #C5}) → core::bool*;
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = #eatFood
+  #C2 = <core::Type*>[]
+  #C3 = <dynamic>[]
+  #C4 = core::_ImmutableMap<core::Symbol*, dynamic> {_kvPairs:#C3}
+  #C5 = null
+  #C6 = #amount
+  #C7 = #yetAnother
+}
diff --git a/pkg/front_end/testcases/no_such_method_forwarders/abstract_override_with_different_signature.dart.strong.transformed.expect b/pkg/front_end/testcases/no_such_method_forwarders/abstract_override_with_different_signature.dart.strong.transformed.expect
new file mode 100644
index 0000000..680a081
--- /dev/null
+++ b/pkg/front_end/testcases/no_such_method_forwarders/abstract_override_with_different_signature.dart.strong.transformed.expect
@@ -0,0 +1,59 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Cat extends core::Object {
+  synthetic constructor •() → self::Cat*
+    : super core::Object::•()
+    ;
+  method eatFood(core::String* food) → core::bool*
+    return true;
+}
+class MockCat extends core::Object implements self::Cat {
+  synthetic constructor •() → self::MockCat*
+    : super core::Object::•()
+    ;
+  method noSuchMethod(core::Invocation* invocation) → dynamic {
+    dynamic arg = invocation.{core::Invocation::positionalArguments}.{core::List::[]}(0);
+    return arg is core::String* && arg{core::String*}.{core::String::isNotEmpty};
+  }
+  no-such-method-forwarder method eatFood(core::String* food) → core::bool*
+    return this.{self::MockCat::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 0, #C2, core::List::unmodifiable<dynamic>(<dynamic>[food]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4))) as{TypeError,ForDynamic} core::bool*;
+}
+class MockCat2 extends self::MockCat {
+  synthetic constructor •() → self::MockCat2*
+    : super self::MockCat::•()
+    ;
+  abstract method noSuchMethod(core::Invocation* _) → dynamic;
+}
+class MockCat3 extends self::MockCat2 implements self::Cat {
+  synthetic constructor •() → self::MockCat3*
+    : super self::MockCat2::•()
+    ;
+  no-such-method-forwarder method eatFood(core::String* food, {core::double* amount = #C5}) → core::bool*
+    return this.{self::MockCat2::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 0, #C2, core::List::unmodifiable<dynamic>(<dynamic>[food]), core::Map::unmodifiable<core::Symbol*, dynamic>(<core::Symbol*, dynamic>{#C6: amount}))) as{TypeError,ForDynamic} core::bool*;
+}
+class MockCat4 extends self::MockCat2 implements self::HungryCat {
+  synthetic constructor •() → self::MockCat4*
+    : super self::MockCat2::•()
+    ;
+  no-such-method-forwarder method eatFood(core::String* food, {core::double* amount = #C5, core::double* yetAnother = #C5}) → core::bool*
+    return this.{self::MockCat2::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 0, #C2, core::List::unmodifiable<dynamic>(<dynamic>[food]), core::Map::unmodifiable<core::Symbol*, dynamic>(<core::Symbol*, dynamic>{#C6: amount, #C7: yetAnother}))) as{TypeError,ForDynamic} core::bool*;
+}
+abstract class HungryCat extends core::Object {
+  synthetic constructor •() → self::HungryCat*
+    : super core::Object::•()
+    ;
+  abstract method eatFood(core::String* food, {core::double* amount = #C5, core::double* yetAnother = #C5}) → core::bool*;
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = #eatFood
+  #C2 = <core::Type*>[]
+  #C3 = <dynamic>[]
+  #C4 = core::_ImmutableMap<core::Symbol*, dynamic> {_kvPairs:#C3}
+  #C5 = null
+  #C6 = #amount
+  #C7 = #yetAnother
+}
diff --git a/pkg/front_end/testcases/no_such_method_forwarders/forwarder_propagation.dart b/pkg/front_end/testcases/no_such_method_forwarders/forwarder_propagation.dart
new file mode 100644
index 0000000..b4af28d
--- /dev/null
+++ b/pkg/front_end/testcases/no_such_method_forwarders/forwarder_propagation.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2020, 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.
+
+// The test checks that the noSuchMethod forwarders inserted into a class aren't
+// re-inserted in its children.
+
+import './forwarder_propagation_lib.dart';
+
+abstract class A {
+  void set foo(int value);
+  int get bar;
+  void baz(int x, {String y, double z});
+}
+
+class B implements A {
+  noSuchMethod(_) {}
+}
+
+class C extends B {}
+
+class E implements D {}
+
+class F extends E {}
+
+main() {}
diff --git a/pkg/front_end/testcases/no_such_method_forwarders/forwarder_propagation.dart.outline.expect b/pkg/front_end/testcases/no_such_method_forwarders/forwarder_propagation.dart.outline.expect
new file mode 100644
index 0000000..25d1c56
--- /dev/null
+++ b/pkg/front_end/testcases/no_such_method_forwarders/forwarder_propagation.dart.outline.expect
@@ -0,0 +1,63 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "forwarder_propagation_lib.dart" as for;
+
+import "org-dartlang-testcase:///forwarder_propagation_lib.dart";
+
+abstract class A extends core::Object {
+  synthetic constructor •() → self::A*
+    ;
+  abstract set foo(core::int* value) → void;
+  abstract get bar() → core::int*;
+  abstract method baz(core::int* x, {core::String* y, core::double* z}) → void;
+}
+class B extends core::Object implements self::A {
+  synthetic constructor •() → self::B*
+    ;
+  method noSuchMethod(core::Invocation* _) → dynamic
+    ;
+  no-such-method-forwarder get bar() → core::int*
+    return this.{self::B::noSuchMethod}(new core::_InvocationMirror::_withType(#bar, 1, const <core::Type*>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{}))) as{TypeError,ForDynamic} core::int*;
+  no-such-method-forwarder method baz(core::int* x, {core::String* y, core::double* z}) → void
+    return this.{self::B::noSuchMethod}(new core::_InvocationMirror::_withType(#baz, 0, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[x]), core::Map::unmodifiable<core::Symbol*, dynamic>(<core::Symbol*, dynamic>{#y: y, #z: z})));
+  no-such-method-forwarder set foo(core::int* value) → void
+    return this.{self::B::noSuchMethod}(new core::_InvocationMirror::_withType(#foo=, 2, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{})));
+}
+class C extends self::B {
+  synthetic constructor •() → self::C*
+    ;
+}
+class E extends core::Object implements for::D {
+  synthetic constructor •() → self::E*
+    ;
+  no-such-method-forwarder get /* from org-dartlang-testcase:///forwarder_propagation_lib.dart */ _privateGetter() → core::int*
+    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#_privateGetter, 1, const <core::Type*>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{}))) as{TypeError,ForDynamic} core::int*;
+  no-such-method-forwarder get /* from org-dartlang-testcase:///forwarder_propagation_lib.dart */ _privateField() → core::int*
+    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#_privateField, 1, const <core::Type*>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{}))) as{TypeError,ForDynamic} core::int*;
+  no-such-method-forwarder method /* from org-dartlang-testcase:///forwarder_propagation_lib.dart */ _privateMethod() → void
+    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#_privateMethod, 0, const <core::Type*>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{})));
+  no-such-method-forwarder set /* from org-dartlang-testcase:///forwarder_propagation_lib.dart */ _privateSetter(core::int* value) → void
+    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#_privateSetter=, 2, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{})));
+  no-such-method-forwarder set /* from org-dartlang-testcase:///forwarder_propagation_lib.dart */ _privateField(core::int* value) → void
+    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#_privateField=, 2, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{})));
+}
+class F extends self::E {
+  synthetic constructor •() → self::F*
+    ;
+}
+static method main() → dynamic
+  ;
+
+library;
+import self as for;
+import "dart:core" as core;
+
+abstract class D extends core::Object {
+  field core::int* _privateField;
+  synthetic constructor •() → for::D*
+    ;
+  abstract get _privateGetter() → core::int*;
+  abstract set _privateSetter(core::int* value) → void;
+  abstract method _privateMethod() → void;
+}
diff --git a/pkg/front_end/testcases/no_such_method_forwarders/forwarder_propagation.dart.strong.expect b/pkg/front_end/testcases/no_such_method_forwarders/forwarder_propagation.dart.strong.expect
new file mode 100644
index 0000000..d0f1d23
--- /dev/null
+++ b/pkg/front_end/testcases/no_such_method_forwarders/forwarder_propagation.dart.strong.expect
@@ -0,0 +1,84 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "forwarder_propagation_lib.dart" as for;
+
+import "org-dartlang-testcase:///forwarder_propagation_lib.dart";
+
+abstract class A extends core::Object {
+  synthetic constructor •() → self::A*
+    : super core::Object::•()
+    ;
+  abstract set foo(core::int* value) → void;
+  abstract get bar() → core::int*;
+  abstract method baz(core::int* x, {core::String* y = #C1, core::double* z = #C1}) → void;
+}
+class B extends core::Object implements self::A {
+  synthetic constructor •() → self::B*
+    : super core::Object::•()
+    ;
+  method noSuchMethod(core::Invocation* _) → dynamic {}
+  no-such-method-forwarder get bar() → core::int*
+    return this.{self::B::noSuchMethod}(new core::_InvocationMirror::_withType(#C2, 1, #C3, #C4, core::Map::unmodifiable<core::Symbol*, dynamic>(#C5))) as{TypeError,ForDynamic} core::int*;
+  no-such-method-forwarder method baz(core::int* x, {core::String* y = #C1, core::double* z = #C1}) → void
+    return this.{self::B::noSuchMethod}(new core::_InvocationMirror::_withType(#C6, 0, #C3, core::List::unmodifiable<dynamic>(<dynamic>[x]), core::Map::unmodifiable<core::Symbol*, dynamic>(<core::Symbol*, dynamic>{#C7: y, #C8: z})));
+  no-such-method-forwarder set foo(core::int* value) → void
+    return this.{self::B::noSuchMethod}(new core::_InvocationMirror::_withType(#C9, 2, #C3, core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C5)));
+}
+class C extends self::B {
+  synthetic constructor •() → self::C*
+    : super self::B::•()
+    ;
+}
+class E extends core::Object implements for::D {
+  synthetic constructor •() → self::E*
+    : super core::Object::•()
+    ;
+  no-such-method-forwarder get /* from org-dartlang-testcase:///forwarder_propagation_lib.dart */ _privateGetter() → core::int*
+    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C10, 1, #C3, #C4, core::Map::unmodifiable<core::Symbol*, dynamic>(#C5))) as{TypeError,ForDynamic} core::int*;
+  no-such-method-forwarder get /* from org-dartlang-testcase:///forwarder_propagation_lib.dart */ _privateField() → core::int*
+    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C11, 1, #C3, #C4, core::Map::unmodifiable<core::Symbol*, dynamic>(#C5))) as{TypeError,ForDynamic} core::int*;
+  no-such-method-forwarder method /* from org-dartlang-testcase:///forwarder_propagation_lib.dart */ _privateMethod() → void
+    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C12, 0, #C3, #C4, core::Map::unmodifiable<core::Symbol*, dynamic>(#C5)));
+  no-such-method-forwarder set /* from org-dartlang-testcase:///forwarder_propagation_lib.dart */ _privateSetter(core::int* value) → void
+    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C13, 2, #C3, core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C5)));
+  no-such-method-forwarder set /* from org-dartlang-testcase:///forwarder_propagation_lib.dart */ _privateField(core::int* value) → void
+    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C14, 2, #C3, core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C5)));
+}
+class F extends self::E {
+  synthetic constructor •() → self::F*
+    : super self::E::•()
+    ;
+}
+static method main() → dynamic {}
+
+library;
+import self as for;
+import "dart:core" as core;
+
+abstract class D extends core::Object {
+  field core::int* _privateField = null;
+  synthetic constructor •() → for::D*
+    : super core::Object::•()
+    ;
+  abstract get _privateGetter() → core::int*;
+  abstract set _privateSetter(core::int* value) → void;
+  abstract method _privateMethod() → void;
+}
+
+constants  {
+  #C1 = null
+  #C2 = #bar
+  #C3 = <core::Type*>[]
+  #C4 = <dynamic>[]
+  #C5 = core::_ImmutableMap<core::Symbol*, dynamic> {_kvPairs:#C4}
+  #C6 = #baz
+  #C7 = #y
+  #C8 = #z
+  #C9 = #foo=
+  #C10 = #org-dartlang-testcase:///forwarder_propagation.dart::_privateGetter
+  #C11 = #org-dartlang-testcase:///forwarder_propagation.dart::_privateField
+  #C12 = #org-dartlang-testcase:///forwarder_propagation.dart::_privateMethod
+  #C13 = #org-dartlang-testcase:///forwarder_propagation.dart::_privateSetter=
+  #C14 = #org-dartlang-testcase:///forwarder_propagation.dart::_privateField=
+}
diff --git a/pkg/front_end/testcases/no_such_method_forwarders/forwarder_propagation.dart.strong.transformed.expect b/pkg/front_end/testcases/no_such_method_forwarders/forwarder_propagation.dart.strong.transformed.expect
new file mode 100644
index 0000000..d0f1d23
--- /dev/null
+++ b/pkg/front_end/testcases/no_such_method_forwarders/forwarder_propagation.dart.strong.transformed.expect
@@ -0,0 +1,84 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "forwarder_propagation_lib.dart" as for;
+
+import "org-dartlang-testcase:///forwarder_propagation_lib.dart";
+
+abstract class A extends core::Object {
+  synthetic constructor •() → self::A*
+    : super core::Object::•()
+    ;
+  abstract set foo(core::int* value) → void;
+  abstract get bar() → core::int*;
+  abstract method baz(core::int* x, {core::String* y = #C1, core::double* z = #C1}) → void;
+}
+class B extends core::Object implements self::A {
+  synthetic constructor •() → self::B*
+    : super core::Object::•()
+    ;
+  method noSuchMethod(core::Invocation* _) → dynamic {}
+  no-such-method-forwarder get bar() → core::int*
+    return this.{self::B::noSuchMethod}(new core::_InvocationMirror::_withType(#C2, 1, #C3, #C4, core::Map::unmodifiable<core::Symbol*, dynamic>(#C5))) as{TypeError,ForDynamic} core::int*;
+  no-such-method-forwarder method baz(core::int* x, {core::String* y = #C1, core::double* z = #C1}) → void
+    return this.{self::B::noSuchMethod}(new core::_InvocationMirror::_withType(#C6, 0, #C3, core::List::unmodifiable<dynamic>(<dynamic>[x]), core::Map::unmodifiable<core::Symbol*, dynamic>(<core::Symbol*, dynamic>{#C7: y, #C8: z})));
+  no-such-method-forwarder set foo(core::int* value) → void
+    return this.{self::B::noSuchMethod}(new core::_InvocationMirror::_withType(#C9, 2, #C3, core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C5)));
+}
+class C extends self::B {
+  synthetic constructor •() → self::C*
+    : super self::B::•()
+    ;
+}
+class E extends core::Object implements for::D {
+  synthetic constructor •() → self::E*
+    : super core::Object::•()
+    ;
+  no-such-method-forwarder get /* from org-dartlang-testcase:///forwarder_propagation_lib.dart */ _privateGetter() → core::int*
+    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C10, 1, #C3, #C4, core::Map::unmodifiable<core::Symbol*, dynamic>(#C5))) as{TypeError,ForDynamic} core::int*;
+  no-such-method-forwarder get /* from org-dartlang-testcase:///forwarder_propagation_lib.dart */ _privateField() → core::int*
+    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C11, 1, #C3, #C4, core::Map::unmodifiable<core::Symbol*, dynamic>(#C5))) as{TypeError,ForDynamic} core::int*;
+  no-such-method-forwarder method /* from org-dartlang-testcase:///forwarder_propagation_lib.dart */ _privateMethod() → void
+    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C12, 0, #C3, #C4, core::Map::unmodifiable<core::Symbol*, dynamic>(#C5)));
+  no-such-method-forwarder set /* from org-dartlang-testcase:///forwarder_propagation_lib.dart */ _privateSetter(core::int* value) → void
+    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C13, 2, #C3, core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C5)));
+  no-such-method-forwarder set /* from org-dartlang-testcase:///forwarder_propagation_lib.dart */ _privateField(core::int* value) → void
+    return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C14, 2, #C3, core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C5)));
+}
+class F extends self::E {
+  synthetic constructor •() → self::F*
+    : super self::E::•()
+    ;
+}
+static method main() → dynamic {}
+
+library;
+import self as for;
+import "dart:core" as core;
+
+abstract class D extends core::Object {
+  field core::int* _privateField = null;
+  synthetic constructor •() → for::D*
+    : super core::Object::•()
+    ;
+  abstract get _privateGetter() → core::int*;
+  abstract set _privateSetter(core::int* value) → void;
+  abstract method _privateMethod() → void;
+}
+
+constants  {
+  #C1 = null
+  #C2 = #bar
+  #C3 = <core::Type*>[]
+  #C4 = <dynamic>[]
+  #C5 = core::_ImmutableMap<core::Symbol*, dynamic> {_kvPairs:#C4}
+  #C6 = #baz
+  #C7 = #y
+  #C8 = #z
+  #C9 = #foo=
+  #C10 = #org-dartlang-testcase:///forwarder_propagation.dart::_privateGetter
+  #C11 = #org-dartlang-testcase:///forwarder_propagation.dart::_privateField
+  #C12 = #org-dartlang-testcase:///forwarder_propagation.dart::_privateMethod
+  #C13 = #org-dartlang-testcase:///forwarder_propagation.dart::_privateSetter=
+  #C14 = #org-dartlang-testcase:///forwarder_propagation.dart::_privateField=
+}
diff --git a/pkg/front_end/testcases/no_such_method_forwarders/forwarder_propagation_lib.dart b/pkg/front_end/testcases/no_such_method_forwarders/forwarder_propagation_lib.dart
new file mode 100644
index 0000000..358059d
--- /dev/null
+++ b/pkg/front_end/testcases/no_such_method_forwarders/forwarder_propagation_lib.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2020, 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.
+
+abstract class D {
+  int _privateField;
+  int get _privateGetter;
+  void set _privateSetter(int value);
+  void _privateMethod();
+}
diff --git a/pkg/front_end/testcases/no_such_method_forwarders/multiple_abstract_setters.dart b/pkg/front_end/testcases/no_such_method_forwarders/multiple_abstract_setters.dart
new file mode 100644
index 0000000..ae84f9d
--- /dev/null
+++ b/pkg/front_end/testcases/no_such_method_forwarders/multiple_abstract_setters.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2020, 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.
+
+class A {
+  void set foo(int value) {}
+  int get bar => null;
+}
+
+class B {
+  void set foo(double value) {}
+  double get bar => null;
+}
+
+class C {
+  void set foo(num value) {}
+  Null get bar => null;
+}
+
+class D implements C, A, B {
+  noSuchMethod(_) => null;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/no_such_method_forwarders/multiple_abstract_setters.dart.outline.expect b/pkg/front_end/testcases/no_such_method_forwarders/multiple_abstract_setters.dart.outline.expect
new file mode 100644
index 0000000..70f1755
--- /dev/null
+++ b/pkg/front_end/testcases/no_such_method_forwarders/multiple_abstract_setters.dart.outline.expect
@@ -0,0 +1,40 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A*
+    ;
+  set foo(core::int* value) → void
+    ;
+  get bar() → core::int*
+    ;
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B*
+    ;
+  set foo(core::double* value) → void
+    ;
+  get bar() → core::double*
+    ;
+}
+class C extends core::Object {
+  synthetic constructor •() → self::C*
+    ;
+  set foo(core::num* value) → void
+    ;
+  get bar() → core::Null?
+    ;
+}
+class D extends core::Object implements self::C, self::A, self::B {
+  synthetic constructor •() → self::D*
+    ;
+  method noSuchMethod(core::Invocation* _) → dynamic
+    ;
+  no-such-method-forwarder get bar() → core::Null?
+    return this.{self::D::noSuchMethod}(new core::_InvocationMirror::_withType(#bar, 1, const <core::Type*>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{}))) as{TypeError,ForDynamic} core::Null?;
+  no-such-method-forwarder set foo(core::num* value) → void
+    return this.{self::D::noSuchMethod}(new core::_InvocationMirror::_withType(#foo=, 2, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{})));
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/no_such_method_forwarders/multiple_abstract_setters.dart.strong.expect b/pkg/front_end/testcases/no_such_method_forwarders/multiple_abstract_setters.dart.strong.expect
new file mode 100644
index 0000000..5ae491b
--- /dev/null
+++ b/pkg/front_end/testcases/no_such_method_forwarders/multiple_abstract_setters.dart.strong.expect
@@ -0,0 +1,48 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A*
+    : super core::Object::•()
+    ;
+  set foo(core::int* value) → void {}
+  get bar() → core::int*
+    return null;
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B*
+    : super core::Object::•()
+    ;
+  set foo(core::double* value) → void {}
+  get bar() → core::double*
+    return null;
+}
+class C extends core::Object {
+  synthetic constructor •() → self::C*
+    : super core::Object::•()
+    ;
+  set foo(core::num* value) → void {}
+  get bar() → core::Null?
+    return null;
+}
+class D extends core::Object implements self::C, self::A, self::B {
+  synthetic constructor •() → self::D*
+    : super core::Object::•()
+    ;
+  method noSuchMethod(core::Invocation* _) → dynamic
+    return null;
+  no-such-method-forwarder get bar() → core::Null?
+    return this.{self::D::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 1, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4))) as{TypeError,ForDynamic} core::Null?;
+  no-such-method-forwarder set foo(core::num* value) → void
+    return this.{self::D::noSuchMethod}(new core::_InvocationMirror::_withType(#C5, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = #bar
+  #C2 = <core::Type*>[]
+  #C3 = <dynamic>[]
+  #C4 = core::_ImmutableMap<core::Symbol*, dynamic> {_kvPairs:#C3}
+  #C5 = #foo=
+}
diff --git a/pkg/front_end/testcases/no_such_method_forwarders/multiple_abstract_setters.dart.strong.transformed.expect b/pkg/front_end/testcases/no_such_method_forwarders/multiple_abstract_setters.dart.strong.transformed.expect
new file mode 100644
index 0000000..5ae491b
--- /dev/null
+++ b/pkg/front_end/testcases/no_such_method_forwarders/multiple_abstract_setters.dart.strong.transformed.expect
@@ -0,0 +1,48 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A*
+    : super core::Object::•()
+    ;
+  set foo(core::int* value) → void {}
+  get bar() → core::int*
+    return null;
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B*
+    : super core::Object::•()
+    ;
+  set foo(core::double* value) → void {}
+  get bar() → core::double*
+    return null;
+}
+class C extends core::Object {
+  synthetic constructor •() → self::C*
+    : super core::Object::•()
+    ;
+  set foo(core::num* value) → void {}
+  get bar() → core::Null?
+    return null;
+}
+class D extends core::Object implements self::C, self::A, self::B {
+  synthetic constructor •() → self::D*
+    : super core::Object::•()
+    ;
+  method noSuchMethod(core::Invocation* _) → dynamic
+    return null;
+  no-such-method-forwarder get bar() → core::Null?
+    return this.{self::D::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 1, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4))) as{TypeError,ForDynamic} core::Null?;
+  no-such-method-forwarder set foo(core::num* value) → void
+    return this.{self::D::noSuchMethod}(new core::_InvocationMirror::_withType(#C5, 2, #C2, core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C4)));
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = #bar
+  #C2 = <core::Type*>[]
+  #C3 = <dynamic>[]
+  #C4 = core::_ImmutableMap<core::Symbol*, dynamic> {_kvPairs:#C3}
+  #C5 = #foo=
+}
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index 57367c1..ef849a5 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -53,6 +53,7 @@
 extensions/issue38750: TextSerializationFailure
 extensions/issue38755: TextSerializationFailure
 extensions/issue38915: TextSerializationFailure
+extensions/issue39938/issue39938: TextSerializationFailure
 extensions/missing_toplevel: TextSerializationFailure
 extensions/nested_on_types: TextSerializationFailure
 extensions/null_aware: TextSerializationFailure
@@ -148,6 +149,7 @@
 general/default_values: TextSerializationFailure # Was: Pass
 general/deferred_lib: TextSerializationFailure # Was: Pass
 general/deferred_type_annotation: TextSerializationFailure # Was: Pass
+general/demote_closure_types: TextSerializationFailure
 general/duplicated_bad_prefix: TextSerializationFailure # Was: Pass
 general/duplicated_bad_prefix_lib1: TextSerializationFailure # Was: Pass
 general/duplicated_bad_prefix_lib2: TextSerializationFailure # Was: Pass
@@ -207,8 +209,8 @@
 general/interface_covariantInterface_from_class: TextSerializationFailure
 general/invalid_assignment: TextSerializationFailure # Was: Pass
 general/invalid_cast: TextSerializationFailure # Was: Pass
-general/invalid_operator: TypeCheckError
 general/invalid_operator2: TextSerializationFailure
+general/invalid_operator: TypeCheckError
 general/invalid_type: TypeCheckError
 general/invocations: TextSerializationFailure # Was: RuntimeError
 general/issue129167943: TextSerializationFailure
@@ -226,6 +228,7 @@
 general/issue39344: TextSerializationFailure
 general/issue39421: TextSerializationFailure
 general/issue39817: TextSerializationFailure
+general/issue40428: TextSerializationFailure
 general/literals: TextSerializationFailure # Was: Pass
 general/local_generic_function: TextSerializationFailure # Was: Pass
 general/long_chain_of_typedefs: TextSerializationFailure
@@ -288,6 +291,7 @@
 general/private_method_tearoff: TextSerializationFailure # Was: Pass
 general/private_method_tearoff_lib: TextSerializationFailure # Was: Pass
 general/promoted_access: TextSerializationFailure
+general/promoted_null_aware_access: TextSerializationFailure
 general/public_method_tearoff: TextSerializationFailure # Was: Pass
 general/public_method_tearoff_lib: TextSerializationFailure # Was: Pass
 general/qualified: TextSerializationFailure # Was: Pass
@@ -339,6 +343,7 @@
 general/var_as_type_name: TextSerializationFailure # Was: Pass
 general/void_methods: TextSerializationFailure
 general/warn_unresolved_sends: InstrumentationMismatch # Test assumes Dart 1.0 semantics
+general/well_boundness_checks_in_outline: TextSerializationFailure
 general/with_dependencies/extension_from_dill/extension_from_dill: TextSerializationFailure
 general/with_dependencies/variance_from_dill/variance_from_dill: TextSerializationFailure
 general_nnbd_opt_out/DeltaBlue: TextSerializationFailure # Was: Pass
@@ -1177,6 +1182,7 @@
 instantiate_to_bound/typedef_omitted_bound: TextSerializationFailure # Was: Pass
 instantiate_to_bound/typedef_raw_in_bound: TextSerializationFailure # Was: Pass
 instantiate_to_bound/typedef_super_bounded_type: TextSerializationFailure # Was: Pass
+late_lowering/initializer_rewrite: TextSerializationFailure
 late_lowering/instance_field_with_initializer: TextSerializationFailure
 late_lowering/instance_field_without_initializer: TextSerializationFailure
 late_lowering/instance_final_field_without_initializer: TextSerializationFailure
@@ -1200,17 +1206,22 @@
 late_lowering/late_nullable_field_without_initializer: TextSerializationFailure
 late_lowering/late_nullable_local_with_initializer: TextSerializationFailure
 late_lowering/late_nullable_local_without_initializer: TextSerializationFailure
+late_lowering/later: TextSerializationFailure
 late_lowering/override: TextSerializationFailure
 late_lowering/return_late: TextSerializationFailure
 new_const_insertion/simple: TextSerializationFailure # Was: Pass
 nnbd/assign_type_variable: TextSerializationFailure
 nnbd/assignability: TextSerializationFailure
 nnbd/call: TextSerializationFailure
+nnbd/constants: TextSerializationFailure
 nnbd/definite_assignment_and_completion: TextSerializationFailure
+nnbd/demote_closure_types: TextSerializationFailure
 nnbd/forbidden_supers: TextSerializationFailure
 nnbd/forin: TextSerializationFailure
 nnbd/function_types: TextSerializationFailure
 nnbd/generic_override: TextSerializationFailure
+nnbd/infer_from_opt_in: TextSerializationFailure
+nnbd/infer_from_opt_out: TextSerializationFailure
 nnbd/infer_if_null: TextSerializationFailure
 nnbd/inheritance_from_opt_in: TypeCheckError
 nnbd/inheritance_from_opt_out: TextSerializationFailure
@@ -1230,12 +1241,17 @@
 nnbd/messages_with_types_opt_in: TypeCheckError
 nnbd/messages_with_types_opt_out: TypeCheckError
 nnbd/missing_required_named_parameter: TextSerializationFailure
+nnbd/never_receiver: TextSerializationFailure
+nnbd/nnbd_opt_out_language_version: TextSerializationFailure
+nnbd/nnbd_opt_out_language_version_try_to_trick: TextSerializationFailure
 nnbd/no_null_shorting: TextSerializationFailure
 nnbd/no_null_shorting_explicit_extension: TextSerializationFailure
 nnbd/no_null_shorting_extension: TextSerializationFailure
+nnbd/non_nullable_field_initialization: TextSerializationFailure
 nnbd/null_access: TextSerializationFailure
 nnbd/null_aware_chain: TextSerializationFailure
 nnbd/null_check: TextSerializationFailure
+nnbd/null_check_context: TextSerializationFailure
 nnbd/null_shorting: TextSerializationFailure
 nnbd/null_shorting_cascade: TextSerializationFailure
 nnbd/null_shorting_explicit_extension: TextSerializationFailure
@@ -1264,12 +1280,16 @@
 no_such_method_forwarders/abstract_accessors_from_field_one_defined: TextSerializationFailure # Was: Pass
 no_such_method_forwarders/abstract_accessors_from_field_with_substitution: TextSerializationFailure # Was: Pass
 no_such_method_forwarders/abstract_interface_nsm_inherited: TextSerializationFailure # Was: Pass
+no_such_method_forwarders/abstract_override_abstract_different_type: TextSerializationFailure
+no_such_method_forwarders/abstract_override_with_different_signature: TextSerializationFailure
 no_such_method_forwarders/concrete_method_over_forwarder_in_mixin_application: TextSerializationFailure # Was: Pass
 no_such_method_forwarders/default_argument_values: TextSerializationFailure # Was: Pass
 no_such_method_forwarders/duplicated_abstract_method: TextSerializationFailure # Was: Pass
+no_such_method_forwarders/forwarder_propagation: TextSerializationFailure
 no_such_method_forwarders/forwarders_not_assumed_from_mixin: TextSerializationFailure # Was: Pass
 no_such_method_forwarders/interface_with_concrete: TextSerializationFailure # Was: Pass
 no_such_method_forwarders/interface_with_nsm: TextSerializationFailure # Was: Pass
+no_such_method_forwarders/multiple_abstract_setters: TextSerializationFailure
 no_such_method_forwarders/no_forwarders_for_abstract_classes: TextSerializationFailure # Was: Pass
 no_such_method_forwarders/no_forwarders_for_abstract_classes_chain: TextSerializationFailure # Was: Pass
 no_such_method_forwarders/nsm_inherited: TextSerializationFailure # Was: Pass
@@ -1522,8 +1542,8 @@
 runtime_checks_new/stub_from_interface_covariant_from_interface: TextSerializationFailure # Was: Pass
 runtime_checks_new/stub_from_interface_covariant_from_super: TextSerializationFailure # Was: Pass
 set_literals/disambiguation_rule: TextSerializationFailure # Was: RuntimeError
-triple_shift/invalid_operator: TextSerializationFailure
 top_level_variance_test: TextSerializationFailure
+triple_shift/invalid_operator: TextSerializationFailure
 unified_collections/mixed_entries: TextSerializationFailure
 unified_collections/string_concatenation: TextSerializationFailure
 variance/class_type_parameter_modifier: TextSerializationFailure
diff --git a/pkg/kernel/bin/transform.dart b/pkg/kernel/bin/transform.dart
index 6301770..c0b9d02 100755
--- a/pkg/kernel/bin/transform.dart
+++ b/pkg/kernel/bin/transform.dart
@@ -7,7 +7,7 @@
 import 'dart:io';
 
 import 'package:front_end/src/api_prototype/constant_evaluator.dart'
-    as constants show SimpleErrorReporter, transformComponent;
+    as constants show EvaluationMode, SimpleErrorReporter, transformComponent;
 
 import 'package:args/args.dart';
 import 'package:kernel/class_hierarchy.dart';
@@ -101,7 +101,11 @@
     case 'constants':
       final VmConstantsBackend backend = new VmConstantsBackend(coreTypes);
       component = constants.transformComponent(
-          component, backend, defines, const constants.SimpleErrorReporter());
+          component,
+          backend,
+          defines,
+          const constants.SimpleErrorReporter(),
+          constants.EvaluationMode.legacy);
       break;
     case 'empty':
       component = empty.transformComponent(component);
diff --git a/pkg/kernel/lib/core_types.dart b/pkg/kernel/lib/core_types.dart
index 635c160..6670ec6 100644
--- a/pkg/kernel/lib/core_types.dart
+++ b/pkg/kernel/lib/core_types.dart
@@ -59,6 +59,7 @@
   Class _invocationMirrorClass;
   Constructor _invocationMirrorWithTypeConstructor;
   Constructor _noSuchMethodErrorDefaultConstructor;
+  Procedure _listDefaultConstructor;
   Procedure _listFromConstructor;
   Procedure _listUnmodifiableConstructor;
   Procedure _identicalProcedure;
@@ -349,6 +350,10 @@
     return _listClass ??= index.getClass('dart:core', 'List');
   }
 
+  Procedure get listDefaultConstructor {
+    return _listDefaultConstructor ??= index.getMember('dart:core', 'List', '');
+  }
+
   Procedure get listFromConstructor {
     return _listFromConstructor ??=
         index.getMember('dart:core', 'List', 'from');
diff --git a/pkg/kernel/lib/naive_type_checker.dart b/pkg/kernel/lib/naive_type_checker.dart
index 726c444..b2e6f6c 100644
--- a/pkg/kernel/lib/naive_type_checker.dart
+++ b/pkg/kernel/lib/naive_type_checker.dart
@@ -249,6 +249,10 @@
     if (receiver is DynamicType) {
       return;
     }
+    if (receiver is NeverType &&
+        receiver.nullability == Nullability.nonNullable) {
+      return;
+    }
 
     // Permit any invocation on Function type.
     if (receiver == environment.coreTypes.functionLegacyRawType &&
diff --git a/pkg/kernel/lib/src/legacy_erasure.dart b/pkg/kernel/lib/src/legacy_erasure.dart
index 904f6f5..bd47475 100644
--- a/pkg/kernel/lib/src/legacy_erasure.dart
+++ b/pkg/kernel/lib/src/legacy_erasure.dart
@@ -46,6 +46,13 @@
 
   _LegacyErasure(this.coreTypes);
 
+  Nullability visitNullability(DartType node) {
+    if (node.nullability != Nullability.legacy) {
+      return Nullability.legacy;
+    }
+    return null;
+  }
+
   @override
   NamedType createNamedType(NamedType node, DartType newType) {
     if (node.isRequired || newType != null) {
@@ -55,57 +62,9 @@
   }
 
   @override
-  DartType createFunctionType(
-      FunctionType node,
-      List<TypeParameter> newTypeParameters,
-      DartType newReturnType,
-      List<DartType> newPositionalParameters,
-      List<NamedType> newNamedParameters,
-      TypedefType newTypedefType) {
-    if (node.nullability != Nullability.legacy ||
-        newTypeParameters != null ||
-        newReturnType != null ||
-        newPositionalParameters != null ||
-        newNamedParameters != null ||
-        newTypedefType != null) {
-      return new FunctionType(
-          newPositionalParameters ?? node.positionalParameters,
-          newReturnType ?? node.returnType,
-          Nullability.legacy,
-          namedParameters: newNamedParameters ?? node.namedParameters,
-          typeParameters: newTypeParameters ?? node.typeParameters,
-          requiredParameterCount: node.requiredParameterCount,
-          typedefType: newTypedefType ?? node.typedefType);
-    }
-    return null;
-  }
-
-  @override
-  DartType createInterfaceType(
-      InterfaceType node, List<DartType> newTypeArguments) {
+  DartType visitInterfaceType(InterfaceType node) {
     if (node.classNode == coreTypes.nullClass) return null;
-
-    if (node.nullability != Nullability.legacy || newTypeArguments != null) {
-      return new InterfaceType(node.classNode, Nullability.legacy,
-          newTypeArguments ?? node.typeArguments);
-    }
-    return null;
-  }
-
-  DartType createTypeParameterType(TypeParameterType node) {
-    if (node.nullability != Nullability.legacy) {
-      return new TypeParameterType(node.parameter, Nullability.legacy);
-    }
-    return null;
-  }
-
-  DartType createPromotedTypeParameterType(
-      TypeParameterType node, DartType newPromotedBound) {
-    if (node.nullability != Nullability.legacy || newPromotedBound != null) {
-      return new TypeParameterType(
-          node.parameter, Nullability.legacy, newPromotedBound);
-    }
-    return null;
+    return super.visitInterfaceType(node);
   }
 
   @override
diff --git a/pkg/kernel/lib/src/replacement_visitor.dart b/pkg/kernel/lib/src/replacement_visitor.dart
index 0b76ee8..cba47d3 100644
--- a/pkg/kernel/lib/src/replacement_visitor.dart
+++ b/pkg/kernel/lib/src/replacement_visitor.dart
@@ -12,8 +12,12 @@
 
   void changeVariance() {}
 
+  Nullability visitNullability(DartType node) => null;
+
   @override
   DartType visitFunctionType(FunctionType node) {
+    Nullability newNullability = visitNullability(node);
+
     List<TypeParameter> newTypeParameters;
     for (int i = 0; i < node.typeParameters.length; i++) {
       TypeParameter typeParameter = node.typeParameters[i];
@@ -77,8 +81,14 @@
     changeVariance();
     DartType newTypedefType = visitType(node.typedefType);
 
-    return createFunctionType(node, newTypeParameters, newReturnType,
-        newPositionalParameters, newNamedParameters, newTypedefType);
+    return createFunctionType(
+        node,
+        newNullability,
+        newTypeParameters,
+        newReturnType,
+        newPositionalParameters,
+        newNamedParameters,
+        newTypedefType);
   }
 
   NamedType createNamedType(NamedType node, DartType newType) {
@@ -91,22 +101,24 @@
 
   DartType createFunctionType(
       FunctionType node,
+      Nullability newNullability,
       List<TypeParameter> newTypeParameters,
       DartType newReturnType,
       List<DartType> newPositionalParameters,
       List<NamedType> newNamedParameters,
       TypedefType newTypedefType) {
-    if (newReturnType == null &&
+    if (newNullability == null &&
+        newReturnType == null &&
         newPositionalParameters == null &&
         newNamedParameters == null &&
         newTypedefType == null) {
-      // No types had to be substituted.
+      // No nullability or types had to be substituted.
       return null;
     } else {
       return new FunctionType(
           newPositionalParameters ?? node.positionalParameters,
           newReturnType ?? node.returnType,
-          node.nullability,
+          newNullability ?? node.nullability,
           namedParameters: newNamedParameters ?? node.namedParameters,
           typeParameters: newTypeParameters ?? node.typeParameters,
           requiredParameterCount: node.requiredParameterCount,
@@ -116,6 +128,7 @@
 
   @override
   DartType visitInterfaceType(InterfaceType node) {
+    Nullability newNullability = visitNullability(node);
     List<DartType> newTypeArguments = null;
     for (int i = 0; i < node.typeArguments.length; i++) {
       DartType substitution = node.typeArguments[i].accept(this);
@@ -124,17 +137,19 @@
         newTypeArguments[i] = substitution;
       }
     }
-    return createInterfaceType(node, newTypeArguments);
+    return createInterfaceType(node, newNullability, newTypeArguments);
   }
 
-  DartType createInterfaceType(
-      InterfaceType node, List<DartType> newTypeArguments) {
-    if (newTypeArguments == null) {
-      // No type arguments needed to be substituted.
+  DartType createInterfaceType(InterfaceType node, Nullability newNullability,
+      List<DartType> newTypeArguments) {
+    if (newNullability == null && newTypeArguments == null) {
+      // No nullability or type arguments needed to be substituted.
       return null;
     } else {
       return new InterfaceType(
-          node.classNode, node.nullability, newTypeArguments);
+          node.classNode,
+          newNullability ?? node.nullability,
+          newTypeArguments ?? node.typeArguments);
     }
   }
 
@@ -142,7 +157,19 @@
   DartType visitDynamicType(DynamicType node) => null;
 
   @override
-  DartType visitNeverType(NeverType node) => null;
+  DartType visitNeverType(NeverType node) {
+    Nullability newNullability = visitNullability(node);
+    return createNeverType(node, newNullability);
+  }
+
+  DartType createNeverType(NeverType node, Nullability newNullability) {
+    if (newNullability == null) {
+      // No nullability needed to be substituted.
+      return null;
+    } else {
+      return new NeverType(newNullability);
+    }
+  }
 
   @override
   DartType visitInvalidType(InvalidType node) => null;
@@ -155,28 +182,41 @@
 
   @override
   DartType visitTypeParameterType(TypeParameterType node) {
+    Nullability newNullability = visitNullability(node);
     if (node.promotedBound != null) {
       DartType newPromotedBound = node.promotedBound.accept(this);
-      return createPromotedTypeParameterType(node, newPromotedBound);
+      return createPromotedTypeParameterType(
+          node, newNullability, newPromotedBound);
     }
-    return createTypeParameterType(node);
+    return createTypeParameterType(node, newNullability);
   }
 
-  DartType createTypeParameterType(TypeParameterType node) {
-    return null;
+  DartType createTypeParameterType(
+      TypeParameterType node, Nullability newNullability) {
+    if (newNullability == null) {
+      // No nullability needed to be substituted.
+      return null;
+    } else {
+      return new TypeParameterType(node.parameter, newNullability);
+    }
   }
 
-  DartType createPromotedTypeParameterType(
-      TypeParameterType node, DartType newPromotedBound) {
-    if (newPromotedBound != null) {
+  DartType createPromotedTypeParameterType(TypeParameterType node,
+      Nullability newNullability, DartType newPromotedBound) {
+    if (newNullability == null && newPromotedBound == null) {
+      // No nullability or bound needed to be substituted.
+      return null;
+    } else {
       return new TypeParameterType(
-          node.parameter, node.typeParameterTypeNullability, newPromotedBound);
+          node.parameter,
+          newNullability ?? node.typeParameterTypeNullability,
+          newPromotedBound ?? node.promotedBound);
     }
-    return null;
   }
 
   @override
   DartType visitTypedefType(TypedefType node) {
+    Nullability newNullability = visitNullability(node);
     List<DartType> newTypeArguments = null;
     for (int i = 0; i < node.typeArguments.length; i++) {
       DartType substitution = node.typeArguments[i].accept(this);
@@ -185,12 +225,19 @@
         newTypeArguments[i] = substitution;
       }
     }
-    if (newTypeArguments == null) {
-      // No type arguments needed to be substituted.
+    return createTypedef(node, newNullability, newTypeArguments);
+  }
+
+  DartType createTypedef(TypedefType node, Nullability newNullability,
+      List<DartType> newTypeArguments) {
+    if (newNullability == null && newTypeArguments == null) {
+      // No nullability or type arguments needed to be substituted.
       return null;
     } else {
       return new TypedefType(
-          node.typedefNode, node.nullability, newTypeArguments);
+          node.typedefNode,
+          newNullability ?? node.nullability,
+          newTypeArguments ?? node.typeArguments);
     }
   }
 
diff --git a/pkg/nnbd_migration/lib/src/already_migrated_code_decorator.dart b/pkg/nnbd_migration/lib/src/already_migrated_code_decorator.dart
index 5885679..76ef942 100644
--- a/pkg/nnbd_migration/lib/src/already_migrated_code_decorator.dart
+++ b/pkg/nnbd_migration/lib/src/already_migrated_code_decorator.dart
@@ -40,17 +40,19 @@
           node, AlreadyMigratedTypeOrigin.forElement(element));
     }
     if (type is FunctionType) {
-      var typeFormalBounds = type.typeFormals.map((e) {
-        var bound = e.bound;
+      for (var element in type.typeFormals) {
+        var bound = element.bound;
+        DecoratedType decoratedBound;
         if (bound == null) {
-          return decorate(
+          decoratedBound = decorate(
               (_typeProvider.objectType as TypeImpl)
                   .withNullability(NullabilitySuffix.question),
               element);
         } else {
-          return decorate(bound, element);
+          decoratedBound = decorate(bound, element);
         }
-      }).toList();
+        DecoratedTypeParameterBounds.current.put(element, decoratedBound);
+      }
       var positionalParameters = <DecoratedType>[];
       var namedParameters = <String, DecoratedType>{};
       for (var parameter in type.parameters) {
@@ -61,7 +63,6 @@
         }
       }
       return DecoratedType(type, node,
-          typeFormalBounds: typeFormalBounds,
           returnType: decorate(type.returnType, element),
           namedParameters: namedParameters,
           positionalParameters: positionalParameters);
diff --git a/pkg/nnbd_migration/lib/src/decorated_type.dart b/pkg/nnbd_migration/lib/src/decorated_type.dart
index 5492a7e..23c745d 100644
--- a/pkg/nnbd_migration/lib/src/decorated_type.dart
+++ b/pkg/nnbd_migration/lib/src/decorated_type.dart
@@ -3,14 +3,11 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/dart/element/type_provider.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type_algebra.dart';
-import 'package:analyzer/src/dart/element/type_algebra.dart' as type_algebra;
-import 'package:analyzer/src/generated/utilities_dart.dart';
 import 'package:meta/meta.dart';
 import 'package:nnbd_migration/instrumentation.dart';
 import 'package:nnbd_migration/src/nullability_node.dart';
@@ -19,14 +16,6 @@
 /// tracking the (unmigrated) [DartType], we track the [ConstraintVariable]s
 /// indicating whether the type, and the types that compose it, are nullable.
 class DecoratedType implements DecoratedTypeInfo {
-  /// Mapping from type parameter elements to the decorated types of those type
-  /// parameters' bounds.
-  ///
-  /// This expando only applies to type parameters whose enclosing element is
-  /// `null`.  Type parameters whose enclosing element is not `null` should be
-  /// stored in [Variables._decoratedTypeParameterBounds].
-  static final _decoratedTypeParameterBounds = Expando<DecoratedType>();
-
   @override
   final DartType type;
 
@@ -51,16 +40,11 @@
   /// TODO(paulberry): how should we handle generic typedefs?
   final List<DecoratedType> typeArguments;
 
-  /// If `this` is a function type, the [DecoratedType] of each of the bounds of
-  /// its type parameters.
-  final List<DecoratedType> typeFormalBounds;
-
   DecoratedType(this.type, this.node,
       {this.returnType,
       this.positionalParameters = const [],
       this.namedParameters = const {},
-      this.typeArguments = const [],
-      this.typeFormalBounds = const []}) {
+      this.typeArguments = const []}) {
     assert(() {
       assert(node != null);
       var type = this.type;
@@ -68,22 +52,12 @@
         assert(returnType == null);
         assert(positionalParameters.isEmpty);
         assert(namedParameters.isEmpty);
-        assert(typeFormalBounds.isEmpty);
         assert(typeArguments.length == type.typeArguments.length);
         for (int i = 0; i < typeArguments.length; i++) {
           assert(typeArguments[i].type == type.typeArguments[i],
               '${typeArguments[i].type} != ${type.typeArguments[i]}');
         }
       } else if (type is FunctionType) {
-        assert(typeFormalBounds.length == type.typeFormals.length);
-        for (int i = 0; i < typeFormalBounds.length; i++) {
-          var declaredBound = type.typeFormals[i].bound;
-          if (declaredBound == null) {
-            assert(typeFormalBounds[i].type.toString() == 'Object');
-          } else {
-            assert(typeFormalBounds[i].type == declaredBound);
-          }
-        }
         assert(returnType.type == type.returnType);
         int positionalParameterCount = 0;
         int namedParameterCount = 0;
@@ -105,13 +79,11 @@
         assert(positionalParameters.isEmpty);
         assert(namedParameters.isEmpty);
         assert(typeArguments.isEmpty);
-        assert(typeFormalBounds.isEmpty);
       } else {
         assert(returnType == null);
         assert(positionalParameters.isEmpty);
         assert(namedParameters.isEmpty);
         assert(typeArguments.isEmpty);
-        assert(typeFormalBounds.isEmpty);
       }
       return true;
     }());
@@ -136,12 +108,16 @@
             offset: offset);
       }
     }
+    for (var element in type.typeFormals) {
+      if (DecoratedTypeParameterBounds.current.get(element) == null) {
+        DecoratedTypeParameterBounds.current.put(
+            element,
+            DecoratedType.forImplicitType(
+                typeProvider, element.bound ?? typeProvider.objectType, graph,
+                offset: offset));
+      }
+    }
     return DecoratedType(type, node,
-        typeFormalBounds: type.typeFormals
-            .map((e) => DecoratedType.forImplicitType(
-                typeProvider, e.bound ?? typeProvider.objectType, graph,
-                offset: offset))
-            .toList(),
         returnType: returnType ??
             DecoratedType.forImplicitType(typeProvider, type.returnType, graph,
                 offset: offset),
@@ -193,8 +169,7 @@
         returnType = null,
         positionalParameters = const [],
         namedParameters = const {},
-        typeArguments = const [],
-        typeFormalBounds = const [] {
+        typeArguments = const [] {
     // We'll be storing the type parameter bounds in
     // [_decoratedTypeParameterBounds] so the type parameter needs to have an
     // enclosing element of `null`.
@@ -302,104 +277,22 @@
       [DartType undecoratedResult]) {
     if (substitution.isEmpty) return this;
     if (undecoratedResult == null) {
+      var type = this.type;
       undecoratedResult = Substitution.fromPairs(
         substitution.keys.toList(),
         substitution.values.map((d) => d.type).toList(),
       ).substituteType(type);
+      if (undecoratedResult is FunctionType && type is FunctionType) {
+        for (int i = 0; i < undecoratedResult.typeFormals.length; i++) {
+          DecoratedTypeParameterBounds.current.put(
+              undecoratedResult.typeFormals[i],
+              DecoratedTypeParameterBounds.current.get(type.typeFormals[i]));
+        }
+      }
     }
     return _substitute(substitution, undecoratedResult);
   }
 
-  /// Convert this decorated type into the [DartType] that it will represent
-  /// after the code has been migrated.
-  ///
-  /// This method should be used after nullability propagation; it makes use of
-  /// the nullabilities associated with nullability nodes to determine which
-  /// types should be nullable and which types should not.
-  DartType toFinalType(TypeProvider typeProvider) {
-    var type = this.type;
-    if (type.isVoid || type.isDynamic) return type;
-    if (type.isBottom || type.isDartCoreNull) {
-      if (node.isNullable) {
-        return (typeProvider.nullType as TypeImpl)
-            .withNullability(NullabilitySuffix.none);
-      } else {
-        return NeverTypeImpl.instance;
-      }
-    }
-    var nullabilitySuffix =
-        node.isNullable ? NullabilitySuffix.question : NullabilitySuffix.none;
-    if (type is FunctionType) {
-      var newTypeFormals = <TypeParameterElementImpl>[];
-      var typeFormalSubstitution = <TypeParameterElement, DartType>{};
-      for (var typeFormal in typeFormals) {
-        var newTypeFormal = TypeParameterElementImpl.synthetic(typeFormal.name);
-        newTypeFormals.add(newTypeFormal);
-        typeFormalSubstitution[typeFormal] = TypeParameterTypeImpl(
-            newTypeFormal,
-            nullabilitySuffix: NullabilitySuffix.none);
-      }
-      for (int i = 0; i < newTypeFormals.length; i++) {
-        var bound = type_algebra.substitute(
-            typeFormalBounds[i].toFinalType(typeProvider),
-            typeFormalSubstitution);
-        if (!bound.isDynamic &&
-            !(bound.isDartCoreObject &&
-                bound.nullabilitySuffix == NullabilitySuffix.question)) {
-          newTypeFormals[i].bound = bound;
-        }
-      }
-      var parameters = <ParameterElement>[];
-      for (int i = 0; i < type.parameters.length; i++) {
-        var origParameter = type.parameters[i];
-        ParameterKind parameterKind;
-        DecoratedType parameterType;
-        var name = origParameter.name;
-        if (origParameter.isNamed) {
-          // TODO(paulberry): infer ParameterKind.NAMED_REQUIRED when
-          // appropriate. See https://github.com/dart-lang/sdk/issues/38596.
-          parameterKind = ParameterKind.NAMED;
-          parameterType = namedParameters[name];
-        } else {
-          parameterKind = origParameter.isOptional
-              ? ParameterKind.POSITIONAL
-              : ParameterKind.REQUIRED;
-          parameterType = positionalParameters[i];
-        }
-        parameters.add(ParameterElementImpl.synthetic(
-            name,
-            type_algebra.substitute(parameterType.toFinalType(typeProvider),
-                typeFormalSubstitution),
-            parameterKind));
-      }
-      return FunctionTypeImpl(
-        typeFormals: newTypeFormals,
-        parameters: parameters,
-        returnType: type_algebra.substitute(
-          returnType.toFinalType(typeProvider),
-          typeFormalSubstitution,
-        ),
-        nullabilitySuffix: nullabilitySuffix,
-      );
-    } else if (type is InterfaceType) {
-      return InterfaceTypeImpl(
-        element: type.element,
-        typeArguments: [
-          for (var arg in typeArguments) arg.toFinalType(typeProvider)
-        ],
-        nullabilitySuffix: nullabilitySuffix,
-      );
-    } else if (type is TypeParameterType) {
-      return TypeParameterTypeImpl(type.element,
-          nullabilitySuffix: nullabilitySuffix);
-    } else {
-      // The above cases should cover all possible types.  On the off chance
-      // they don't, fall back on returning DecoratedType.type.
-      assert(false, 'Unexpected type (${type.runtimeType})');
-      return type;
-    }
-  }
-
   @override
   String toString() {
     var trailing = node == null ? '' : node.debugSuffix;
@@ -456,8 +349,7 @@
       returnType: returnType,
       positionalParameters: positionalParameters,
       namedParameters: namedParameters,
-      typeArguments: typeArguments,
-      typeFormalBounds: typeFormalBounds);
+      typeArguments: typeArguments);
 
   /// Internal implementation of [_substitute], used as a recursion target.
   DecoratedType _substitute(
@@ -467,7 +359,6 @@
     if (type is FunctionType && undecoratedResult is FunctionType) {
       var typeFormals = type.typeFormals;
       assert(typeFormals.length == undecoratedResult.typeFormals.length);
-      var newTypeFormalBounds = <DecoratedType>[];
       if (typeFormals.isNotEmpty) {
         // The analyzer sometimes allocates fresh type variables when performing
         // substitutions, so we need to reflect that in our decorations by
@@ -482,13 +373,21 @@
                     undecoratedResult.typeFormals[i]);
           }
         }
-        for (int i = 0; i < typeFormalBounds.length; i++) {
-          newTypeFormalBounds.add(typeFormalBounds[i]._substitute(
-              substitution, typeFormals[i].bound ?? typeFormalBounds[i].type));
+        for (int i = 0; i < typeFormals.length; i++) {
+          var typeFormal = typeFormals[i];
+          var oldDecoratedBound =
+              DecoratedTypeParameterBounds.current.get(typeFormal);
+          var newDecoratedBound = oldDecoratedBound._substitute(
+              substitution, typeFormal.bound ?? oldDecoratedBound.type);
+          if (identical(typeFormal, undecoratedResult.typeFormals[i])) {
+            assert(oldDecoratedBound == newDecoratedBound);
+          } else {
+            DecoratedTypeParameterBounds.current
+                .put(typeFormal, newDecoratedBound);
+          }
         }
       }
-      return _substituteFunctionAfterFormals(undecoratedResult, substitution,
-          newTypeFormalBounds: newTypeFormalBounds);
+      return _substituteFunctionAfterFormals(undecoratedResult, substitution);
     } else if (type is InterfaceType && undecoratedResult is InterfaceType) {
       List<DecoratedType> newTypeArguments = [];
       for (int i = 0; i < typeArguments.length; i++) {
@@ -516,8 +415,7 @@
   /// is [undecoratedResult], and whose return type, positional parameters, and
   /// named parameters are formed by performing the given [substitution].
   DecoratedType _substituteFunctionAfterFormals(FunctionType undecoratedResult,
-      Map<TypeParameterElement, DecoratedType> substitution,
-      {List<DecoratedType> newTypeFormalBounds = const []}) {
+      Map<TypeParameterElement, DecoratedType> substitution) {
     var newPositionalParameters = <DecoratedType>[];
     var numRequiredParameters = undecoratedResult.normalParameterTypes.length;
     for (int i = 0; i < positionalParameters.length; i++) {
@@ -536,35 +434,12 @@
           (entry.value._substitute(substitution, undecoratedParameterType));
     }
     return DecoratedType(undecoratedResult, node,
-        typeFormalBounds: newTypeFormalBounds,
         returnType:
             returnType._substitute(substitution, undecoratedResult.returnType),
         positionalParameters: newPositionalParameters,
         namedParameters: newNamedParameters);
   }
 
-  /// Retrieves the decorated bound of the given [typeParameter].
-  ///
-  /// [typeParameter] must have an enclosing element of `null`.  Type parameters
-  /// whose enclosing element is not `null` are tracked by the [Variables]
-  /// class.
-  static DecoratedType decoratedTypeParameterBound(
-      TypeParameterElement typeParameter) {
-    assert(typeParameter.enclosingElement == null);
-    return _decoratedTypeParameterBounds[typeParameter];
-  }
-
-  /// Stores he decorated bound of the given [typeParameter].
-  ///
-  /// [typeParameter] must have an enclosing element of `null`.  Type parameters
-  /// whose enclosing element is not `null` are tracked by the [Variables]
-  /// class.
-  static void recordTypeParameterBound(
-      TypeParameterElement typeParameter, DecoratedType bound) {
-    assert(typeParameter.enclosingElement == null);
-    _decoratedTypeParameterBounds[typeParameter] = bound;
-  }
-
   static bool _compareLists(
       List<DecoratedType> list1, List<DecoratedType> list2) {
     if (identical(list1, list2)) return true;
@@ -586,6 +461,41 @@
   }
 }
 
+/// Data structure mapping type parameters to their decorated bounds.
+///
+/// Since we need to be able to access this mapping globally throughout the
+/// migration engine, from places where we can't easily inject it, the current
+/// mapping is stored in a static variable.
+class DecoratedTypeParameterBounds {
+  /// The [DecoratedTypeParameterBounds] currently in use, or `null` if we are
+  /// not currently in a stage of migration where we need access to the
+  /// decorated types of type parameter bounds.
+  ///
+  /// If `null`, then attempts to look up the decorated types of type parameter
+  /// bounds will fail.
+  static DecoratedTypeParameterBounds current;
+
+  final _orphanBounds = Expando<DecoratedType>();
+
+  final _parentedBounds = <TypeParameterElement, DecoratedType>{};
+
+  DecoratedType get(TypeParameterElement element) {
+    if (element.enclosingElement == null) {
+      return _orphanBounds[element];
+    } else {
+      return _parentedBounds[element];
+    }
+  }
+
+  void put(TypeParameterElement element, DecoratedType bounds) {
+    if (element.enclosingElement == null) {
+      _orphanBounds[element] = bounds;
+    } else {
+      _parentedBounds[element] = bounds;
+    }
+  }
+}
+
 /// Helper class that renames the type parameters in two decorated function
 /// types so that they match.
 class RenamedDecoratedFunctionTypes {
@@ -646,10 +556,14 @@
       substitution2[type2.typeFormals[i]] = newParameterType;
     }
     for (int i = 0; i < type1.typeFormals.length; i++) {
-      var bound1 = type1.typeFormalBounds[i].substitute(substitution1);
-      var bound2 = type2.typeFormalBounds[i].substitute(substitution2);
+      var bound1 = DecoratedTypeParameterBounds.current
+          .get((type1.type as FunctionType).typeFormals[i])
+          .substitute(substitution1);
+      var bound2 = DecoratedTypeParameterBounds.current
+          .get((type2.type as FunctionType).typeFormals[i])
+          .substitute(substitution2);
       if (!boundsMatcher(bound1, bound2)) return null;
-      DecoratedType.recordTypeParameterBound(newParameters[i], bound1);
+      DecoratedTypeParameterBounds.current.put(newParameters[i], bound1);
     }
     var returnType1 = type1.returnType.substitute(substitution1);
     var returnType2 = type2.returnType.substitute(substitution2);
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart
index 0f74586..133fa67 100644
--- a/pkg/nnbd_migration/lib/src/edge_builder.dart
+++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -1506,7 +1506,7 @@
     var typeArguments = typeName.typeArguments?.arguments;
     var element = typeName.name.staticElement;
     if (element is GenericTypeAliasElement) {
-      final typedefType = _variables.decoratedElementType(element);
+      final typedefType = _variables.decoratedElementType(element.function);
       final typeNameType = _variables.decoratedTypeAnnotation(source, typeName);
 
       Map<TypeParameterElement, DecoratedType> substitutions;
@@ -1789,7 +1789,6 @@
             isLUB, "shouldn't be possible to get a function from GLB(null, S)");
         return DecoratedType(type, node,
             returnType: right.returnType,
-            typeFormalBounds: right.typeFormalBounds,
             positionalParameters: right.positionalParameters,
             namedParameters: right.namedParameters);
       } else if (rightType.isDartCoreNull) {
@@ -1797,7 +1796,6 @@
             isLUB, "shouldn't be possible to get a function from GLB(S, null)");
         return DecoratedType(type, node,
             returnType: left.returnType,
-            typeFormalBounds: left.typeFormalBounds,
             positionalParameters: left.positionalParameters,
             namedParameters: left.namedParameters);
       }
@@ -1945,7 +1943,8 @@
           _checkAssignment(edgeOrigin,
               source: sourceType,
               destination: compoundOperatorType.positionalParameters[0],
-              hard: _postDominatedLocals.isReferenceInScope(expression));
+              hard: _postDominatedLocals.isReferenceInScope(expression),
+              sourceIsFunctionLiteral: expression is FunctionExpression);
           sourceType = _fixNumericTypes(
               compoundOperatorType.returnType, compoundOperatorInfo.staticType);
           _checkAssignment(
@@ -1961,7 +1960,8 @@
             source: sourceType,
             destination: destinationType,
             hard: questionAssignNode == null &&
-                _postDominatedLocals.isReferenceInScope(expression));
+                _postDominatedLocals.isReferenceInScope(expression),
+            sourceIsFunctionLiteral: expression is FunctionExpression);
       }
       if (destinationLocalVariable != null) {
         _flowAnalysis.write(destinationLocalVariable, sourceType);
@@ -2231,7 +2231,8 @@
     for (var i = 0; i < argumentTypes.length; ++i) {
       _checkAssignment(null,
           source: argumentTypes[i],
-          destination: type.typeFormalBounds[i],
+          destination: DecoratedTypeParameterBounds.current
+              .get((type.type as FunctionType).typeFormals[i]),
           hard: true);
     }
 
@@ -2591,11 +2592,14 @@
   /// Creates the necessary constraint(s) for an assignment from [source] to
   /// [destination].  [origin] should be used as the origin for any edges
   /// created.  [hard] indicates whether a hard edge should be created.
+  /// [sourceIsFunctionLiteral] indicates whether the source of the assignment
+  /// is a function literal expression.
   void _checkAssignment(EdgeOrigin origin,
       {@required DecoratedType source,
       @required DecoratedType destination,
       @required bool hard,
-      bool checkable = true}) {
+      bool checkable = true,
+      bool sourceIsFunctionLiteral = false}) {
     var sourceType = source.type;
     var destinationType = destination.type;
     if (!_typeSystem.isSubtypeOf(sourceType, destinationType)) {
@@ -2618,14 +2622,19 @@
     _connect(source.node, destination.node, origin,
         hard: hard, checkable: checkable);
     _checkAssignment_recursion(origin,
-        source: source, destination: destination);
+        source: source,
+        destination: destination,
+        sourceIsFunctionLiteral: sourceIsFunctionLiteral);
   }
 
   /// Does the recursive part of [_checkAssignment], visiting all of the types
   /// constituting [source] and [destination], and creating the appropriate
-  /// edges between them.
+  /// edges between them.  [sourceIsFunctionLiteral] indicates whether the
+  /// source of the assignment is a function literal expression.
   void _checkAssignment_recursion(EdgeOrigin origin,
-      {@required DecoratedType source, @required DecoratedType destination}) {
+      {@required DecoratedType source,
+      @required DecoratedType destination,
+      bool sourceIsFunctionLiteral = false}) {
     var sourceType = source.type;
     var destinationType = destination.type;
     assert(_typeSystem.isSubtypeOf(sourceType, destinationType));
@@ -2731,10 +2740,15 @@
             hard: false);
       }
     } else if (sourceType is FunctionType && destinationType is FunctionType) {
+      // If the source is a function literal, we want a hard edge, so that if a
+      // function returning non-null is required, we will insure that the
+      // function literal has a non-nullable return type (e.g. by inserting null
+      // checks into the function literal).
       _checkAssignment(origin,
           source: source.returnType,
           destination: destination.returnType,
-          hard: false);
+          hard: sourceIsFunctionLiteral,
+          checkable: false);
       if (source.typeArguments.isNotEmpty ||
           destination.typeArguments.isNotEmpty) {
         throw UnimplementedError('TODO(paulberry)');
diff --git a/pkg/nnbd_migration/lib/src/edit_plan.dart b/pkg/nnbd_migration/lib/src/edit_plan.dart
index 907e619..7fb6997 100644
--- a/pkg/nnbd_migration/lib/src/edit_plan.dart
+++ b/pkg/nnbd_migration/lib/src/edit_plan.dart
@@ -1112,11 +1112,18 @@
     separators =
         sequenceNodes == null ? null : _computeSeparators(node, sequenceNodes);
     _processPlans();
+    Precedence precedence;
+    if (node is FunctionExpression && node.body is ExpressionFunctionBody) {
+      // To avoid ambiguities when adding `as Type` after a function expression,
+      // assume assignment precedence.
+      precedence = Precedence.assignment;
+    } else if (node is Expression) {
+      precedence = node.precedence;
+    } else {
+      precedence = Precedence.primary;
+    }
     return _PassThroughEditPlan._(
-        node,
-        node is Expression ? node.precedence : Precedence.primary,
-        endsInCascade ?? node.endsInCascade,
-        changes);
+        node, precedence, endsInCascade ?? node.endsInCascade, changes);
   }
 
   /// Starting at index [planIndex] of [innerPlans] (whose value is [plan]),
diff --git a/pkg/nnbd_migration/lib/src/fantasyland/fantasy_repo.dart b/pkg/nnbd_migration/lib/src/fantasyland/fantasy_repo.dart
index 59f3d8e..0126de7 100644
--- a/pkg/nnbd_migration/lib/src/fantasyland/fantasy_repo.dart
+++ b/pkg/nnbd_migration/lib/src/fantasyland/fantasy_repo.dart
@@ -2,34 +2,31 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:io';
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:nnbd_migration/src/fantasyland/fantasy_repo_impl.dart';
 
-import 'package:nnbd_migration/src/utilities/subprocess_launcher.dart';
-import 'package:path/path.dart' as path;
-
-const _github = 'git@github.com';
-const _httpGithub = 'https://github.com';
+const githubHost = 'git@github.com';
 
 final Map<String, FantasyRepoSettings> _repoTable = {
   'archive':
-      FantasyRepoSettings('archive', '$_github:brendan-duncan/archive.git'),
+      FantasyRepoSettings('archive', '$githubHost:brendan-duncan/archive.git'),
   'build_verify': FantasyRepoSettings(
-      'build_verify', '$_github:brendan-duncan/build_verify.git'),
-  'build_version':
-      FantasyRepoSettings('build_version', '$_github:kevmoo/build_version.git'),
-  'csv': FantasyRepoSettings('csv', '$_github:close2/csv.git'),
-  'git': FantasyRepoSettings('git', '$_github:kevmoo/git.git'),
+      'build_verify', '$githubHost:brendan-duncan/build_verify.git'),
+  'build_version': FantasyRepoSettings(
+      'build_version', '$githubHost:kevmoo/build_version.git'),
+  'csv': FantasyRepoSettings('csv', '$githubHost:close2/csv.git'),
+  'git': FantasyRepoSettings('git', '$githubHost:kevmoo/git.git'),
   'node_interop': FantasyRepoSettings(
-      'node_interop', '$_github:pulyaevskiy/node-interop.git'),
+      'node_interop', '$githubHost:pulyaevskiy/node-interop.git'),
   'node_preamble': FantasyRepoSettings(
-      'package_config', '$_github:mbullington/node_preamble.dart.git'),
-  'package_config': FantasyRepoSettings(
-      'package_config', '$_github:dart-lang/package_config', 'master', '1.1.0'),
+      'package_config', '$githubHost:mbullington/node_preamble.dart.git'),
+  'package_config': FantasyRepoSettings('package_config',
+      '$githubHost:dart-lang/package_config', 'master', '1.1.0'),
   'source_gen_test': FantasyRepoSettings(
-      'source_gen_test', '$_github:kevmoo/source_gen_test.git'),
+      'source_gen_test', '$githubHost:kevmoo/source_gen_test.git'),
   'quiver-dart':
-      FantasyRepoSettings('quiver-dart', '$_github:google/quiver-dart.git'),
-  'uuid': FantasyRepoSettings('uuid', '$_github:Daegalus/dart-uuid.git'),
+      FantasyRepoSettings('quiver-dart', '$githubHost:google/quiver-dart.git'),
+  'uuid': FantasyRepoSettings('uuid', '$githubHost:Daegalus/dart-uuid.git'),
 };
 
 class FantasyRepoCloneException extends FantasyRepoException {
@@ -71,7 +68,9 @@
   final String revision;
 
   FantasyRepoSettings(this.name, this.clone,
-      [this.branch = 'master', this.revision = 'master']);
+      // TODO(jcollins-g): revision should follow master
+      [this.branch = 'master',
+      this.revision = 'master']);
 
   static RegExp _dotDart = RegExp(r'[.]dart$');
 
@@ -81,10 +80,10 @@
       return _repoTable[repoName];
     }
     if (_dotDart.hasMatch(repoName)) {
-      return FantasyRepoSettings(repoName, '$_github:google/$repoName.git');
+      return FantasyRepoSettings(repoName, '$githubHost:google/$repoName.git');
     }
     return FantasyRepoSettings(
-        repoName, '$_github:dart-lang/$repoName.git', 'master', 'master');
+        repoName, '$githubHost:dart-lang/$repoName.git', 'master', 'master');
   }
 
   @override
@@ -104,126 +103,18 @@
       'FantasyRepoSettings("$name", "$clone", "$branch", "$revision")';
 }
 
-/// Represent a single git clone that may be referred to by one or more
-/// [FantasySubPackage]s.
-class FantasyRepo {
-  final String name;
-  final FantasyRepoSettings repoSettings;
-  final Directory repoRoot;
-  final File Function(String) fileBuilder;
+/// Base class for all repository types.
+abstract class FantasyRepo {
+  String get name;
+  FantasyRepoSettings get repoSettings;
+  Folder get repoRoot;
 
-  FantasyRepo._(this.repoSettings, this.repoRoot,
-      {File Function(String) fileBuilder})
-      : name = repoSettings.name,
-        fileBuilder = fileBuilder ?? ((s) => File(s));
-
-  static Future<FantasyRepo> buildFrom(
-      FantasyRepoSettings repoSettings, Directory repoRoot,
-      {SubprocessLauncher launcher, File Function(String) fileBuilder}) async {
-    FantasyRepo newRepo =
-        FantasyRepo._(repoSettings, repoRoot, fileBuilder: fileBuilder);
-    if (launcher == null) {
-      launcher = SubprocessLauncher('FantasyRepo.buildFrom-${newRepo.name}');
-    }
-    await newRepo._init(launcher);
+  static Future<FantasyRepo> buildGitRepoFrom(
+      FantasyRepoSettings repoSettings, String repoRootPath,
+      {FantasyRepoDependencies fantasyRepoDependencies}) async {
+    FantasyRepoGitImpl newRepo = FantasyRepoGitImpl(repoSettings, repoRootPath,
+        fantasyRepoDependencies: fantasyRepoDependencies);
+    await newRepo.init();
     return newRepo;
   }
-
-  bool _isInitialized = false;
-
-  /// Call exactly once per [FantasyRepo].
-  ///
-  /// May throw [FantasyRepoException] in the event of problems and does
-  /// not clean up filesystem state.
-  Future<void> _init(SubprocessLauncher launcher) async {
-    assert(_isInitialized == false);
-    if (await repoRoot.exists()) {
-      await _update(launcher);
-      // TODO(jcollins-g): handle "update" of pinned revision edge case
-    } else {
-      await _clone(launcher);
-    }
-    _isInitialized = true;
-    return;
-  }
-
-  /// Configure a git repository locally and initialize it.
-  ///
-  /// Throws [FantasyRepoCloneException] in the event we can not finish
-  /// initializing.
-  Future<void> _clone(SubprocessLauncher launcher) async {
-    assert(_isInitialized == false);
-    if (!await repoRoot.parent.exists()) {
-      await repoRoot.parent.create(recursive: true);
-    }
-    await launcher.runStreamed('git', ['init', repoRoot.path]);
-    await launcher.runStreamed(
-        'git',
-        [
-          'remote',
-          'add',
-          'origin',
-          '-t',
-          repoSettings.branch,
-          repoSettings.clone
-        ],
-        workingDirectory: repoRoot.path);
-
-    String cloneHttp =
-        repoSettings.clone.replaceFirst('$_github:', '$_httpGithub/');
-    await launcher.runStreamed('git',
-        ['remote', 'add', 'originHTTP', '-t', repoSettings.branch, cloneHttp],
-        workingDirectory: repoRoot.path);
-
-    // Do not get the working directory wrong on this command or it could
-    // alter a user's repository config based on the CWD, which is bad.  Other
-    // commands in [FantasyRepo] will not fail silently with permanent,
-    // confusing results, but this one can.
-    await launcher.runStreamed('git', ['config', 'core.sparsecheckout', 'true'],
-        workingDirectory: repoRoot.path);
-
-    File sparseCheckout = fileBuilder(
-        path.join(repoRoot.path, '.git', 'info', 'sparse-checkout'));
-    await sparseCheckout.writeAsString([
-      '**\n',
-      '!**/.packages\n',
-      '!**/pubspec.lock\n',
-      '!**/.dart_tool/package_config.json\n'
-    ].join());
-    try {
-      await _update(launcher);
-    } catch (e) {
-      if (e is FantasyRepoUpdateException) {
-        throw FantasyRepoCloneException(
-            'Unable to initialize clone for: $repoSettings');
-      }
-      // Other kinds of exceptions are not expected, so rethrow.
-      rethrow;
-    }
-  }
-
-  Future<void> _update(SubprocessLauncher launcher) async {
-    assert(_isInitialized == false);
-    try {
-      List<String> args;
-      if (repoSettings.branch == 'master') {
-        args = [
-          'pull',
-          '--depth=1',
-          '--rebase',
-          'originHTTP',
-          repoSettings.revision
-        ];
-      } else {
-        args = ['pull', '--rebase', 'originHTTP', repoSettings.revision];
-      }
-      await launcher.runStreamed('git', args, workingDirectory: repoRoot.path);
-    } catch (e) {
-      if (e is ProcessException) {
-        throw FantasyRepoUpdateException(
-            'Unable to update clone for: $repoSettings');
-      }
-      rethrow;
-    }
-  }
 }
diff --git a/pkg/nnbd_migration/lib/src/fantasyland/fantasy_repo_impl.dart b/pkg/nnbd_migration/lib/src/fantasyland/fantasy_repo_impl.dart
new file mode 100644
index 0000000..7f3b1c2
--- /dev/null
+++ b/pkg/nnbd_migration/lib/src/fantasyland/fantasy_repo_impl.dart
@@ -0,0 +1,150 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io' show ProcessException;
+
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:nnbd_migration/src/fantasyland/fantasy_repo.dart';
+import 'package:nnbd_migration/src/fantasyland/fantasy_workspace_impl.dart';
+import 'package:nnbd_migration/src/utilities/subprocess_launcher.dart';
+
+const _httpGithub = 'https://github.com';
+
+class FantasyRepoDependencies {
+  final ResourceProvider resourceProvider;
+  final SubprocessLauncher launcher;
+
+  FantasyRepoDependencies(
+      {ResourceProvider resourceProvider,
+      String name,
+      SubprocessLauncher launcher})
+      : resourceProvider =
+            resourceProvider ?? PhysicalResourceProvider.INSTANCE,
+        launcher = launcher ??
+            SubprocessLauncher(
+                'FantasyRepo.${name == null ? "buildFrom" : "buildFrom-$name"}');
+
+  factory FantasyRepoDependencies.fromWorkspaceDependencies(
+      FantasyWorkspaceDependencies workspaceDependencies) {
+    return FantasyRepoDependencies(
+        resourceProvider: workspaceDependencies.resourceProvider,
+        launcher: workspaceDependencies.launcher);
+  }
+}
+
+/// Represent a single git clone that may be referred to by one or more
+/// [FantasySubPackage]s.
+class FantasyRepoGitImpl extends FantasyRepo {
+  final String name;
+  final FantasyRepoSettings repoSettings;
+  final String _repoRootPath;
+  Folder get repoRoot => _external.resourceProvider.getFolder(_repoRootPath);
+  final FantasyRepoDependencies _external;
+
+  FantasyRepoGitImpl(this.repoSettings, this._repoRootPath,
+      {FantasyRepoDependencies fantasyRepoDependencies})
+      : name = repoSettings.name,
+        _external = fantasyRepoDependencies ??
+            FantasyRepoDependencies(name: repoSettings.name);
+
+  bool _isInitialized = false;
+
+  /// Call exactly once per [FantasyRepoGitImpl].
+  ///
+  /// May throw [FantasyRepoException] in the event of problems and does
+  /// not clean up filesystem state.
+  Future<void> init() async {
+    assert(_isInitialized == false);
+    if (repoRoot.exists) {
+      await _update(_external.launcher);
+      // TODO(jcollins-g): handle "update" of pinned revision edge case
+    } else {
+      await _clone(_external.launcher);
+    }
+    _isInitialized = true;
+    return;
+  }
+
+  /// Configure a git repository locally and initialize it.
+  ///
+  /// Throws [FantasyRepoCloneException] in the event we can not finish
+  /// initializing.
+  Future<void> _clone(SubprocessLauncher launcher) async {
+    assert(_isInitialized == false);
+    if (!repoRoot.parent.exists) {
+      await repoRoot.parent.create();
+    }
+    await launcher.runStreamed('git', ['init', repoRoot.path]);
+    await launcher.runStreamed(
+        'git',
+        [
+          'remote',
+          'add',
+          'origin',
+          '-t',
+          repoSettings.branch,
+          repoSettings.clone
+        ],
+        workingDirectory: repoRoot.path);
+
+    String cloneHttp =
+        repoSettings.clone.replaceFirst('$githubHost:', '$_httpGithub/');
+    await launcher.runStreamed('git',
+        ['remote', 'add', 'originHTTP', '-t', repoSettings.branch, cloneHttp],
+        workingDirectory: repoRoot.path);
+
+    // Do not get the working directory wrong on this command or it could
+    // alter a user's repository config based on the CWD, which is bad.  Other
+    // commands in [FantasyRepo] will not fail silently with permanent,
+    // confusing results, but this one can.
+    await launcher.runStreamed('git', ['config', 'core.sparsecheckout', 'true'],
+        workingDirectory: repoRoot.path);
+
+    File sparseCheckout = _external.resourceProvider.getFile(_external
+        .resourceProvider.pathContext
+        .join(repoRoot.path, '.git', 'info', 'sparse-checkout'));
+    sparseCheckout.writeAsStringSync([
+      '**\n',
+      '!**/.packages\n',
+      '!**/pubspec.lock\n',
+      '!**/.dart_tool/package_config.json\n'
+    ].join());
+    try {
+      await _update(launcher);
+    } catch (e) {
+      if (e is FantasyRepoUpdateException) {
+        throw FantasyRepoCloneException(
+            'Unable to initialize clone for: $repoSettings');
+      }
+      // Other kinds of exceptions are not expected, so rethrow.
+      rethrow;
+    }
+  }
+
+  Future<void> _update(SubprocessLauncher launcher) async {
+    assert(_isInitialized == false);
+    try {
+      List<String> args;
+      if (repoSettings.branch == 'master') {
+        args = [
+          'pull',
+          '--depth=1',
+          '--rebase',
+          'originHTTP',
+          repoSettings.revision
+        ];
+      } else {
+        args = ['pull', '--rebase', 'originHTTP', repoSettings.revision];
+      }
+      await launcher.runStreamed('git', args, workingDirectory: repoRoot.path);
+    } catch (e) {
+      if (e is ProcessException) {
+        throw FantasyRepoUpdateException(
+            'Unable to update clone for: $repoSettings');
+      }
+      rethrow;
+    }
+  }
+}
diff --git a/pkg/nnbd_migration/lib/src/fantasyland/fantasy_sub_package.dart b/pkg/nnbd_migration/lib/src/fantasyland/fantasy_sub_package.dart
index dcefdc9..173d24f 100644
--- a/pkg/nnbd_migration/lib/src/fantasyland/fantasy_sub_package.dart
+++ b/pkg/nnbd_migration/lib/src/fantasyland/fantasy_sub_package.dart
@@ -2,92 +2,127 @@
 // 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/file_system/file_system.dart';
+import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/src/lint/pub.dart';
 import 'package:nnbd_migration/src/fantasyland/fantasy_repo.dart';
-import 'package:nnbd_migration/src/fantasyland/fantasy_workspace.dart';
+import 'package:nnbd_migration/src/fantasyland/fantasy_workspace_impl.dart';
+import 'package:path/path.dart' as path;
 
 final Map<String, FantasySubPackageSettings> _subPackageTable = {
-  '_fe_analyzer_shared': FantasySubPackageSettings('_fe_analyzer_shared',
-      FantasyRepoSettings.fromName('sdk'), 'pkg/_fe_analyzer_shared'),
-  'analysis_tool': FantasySubPackageSettings('analysis_tool',
-      FantasyRepoSettings.fromName('sdk'), 'pkg/analysis_tool'),
+  '_fe_analyzer_shared': FantasySubPackageSettings(
+      '_fe_analyzer_shared', FantasyRepoSettings.fromName('sdk'),
+      subDir: path.join('pkg', '_fe_analyzer_shared')),
+  'analysis_tool': FantasySubPackageSettings(
+      'analysis_tool', FantasyRepoSettings.fromName('sdk'),
+      subDir: path.join('pkg', 'analysis_tool')),
   'analyzer': FantasySubPackageSettings(
-      'analyzer', FantasyRepoSettings.fromName('sdk'), 'pkg/analyzer'),
+      'analyzer', FantasyRepoSettings.fromName('sdk'),
+      subDir: path.join('pkg', 'analyzer')),
   'build': FantasySubPackageSettings(
-      'build', FantasyRepoSettings.fromName('build'), 'build'),
+      'build', FantasyRepoSettings.fromName('build'),
+      subDir: 'build'),
   'build_config': FantasySubPackageSettings(
-      'build_config', FantasyRepoSettings.fromName('build'), 'build_config'),
+      'build_config', FantasyRepoSettings.fromName('build'),
+      subDir: 'build_config'),
   'build_daemon': FantasySubPackageSettings(
-      'build_daemon', FantasyRepoSettings.fromName('build'), 'build_daemon'),
-  'build_integration': FantasySubPackageSettings('build_integration',
-      FantasyRepoSettings.fromName('sdk'), 'pkg/build_integration'),
+      'build_daemon', FantasyRepoSettings.fromName('build'),
+      subDir: 'build_daemon'),
+  'build_integration': FantasySubPackageSettings(
+      'build_integration', FantasyRepoSettings.fromName('sdk'),
+      subDir: path.join('pkg', 'build_integration')),
   'build_modules': FantasySubPackageSettings(
-      'build_modules', FantasyRepoSettings.fromName('build'), 'build_modules'),
-  'build_node_compilers': FantasySubPackageSettings('build_node_compilers',
-      FantasyRepoSettings.fromName('node-interop'), 'build_node_compilers'),
-  'build_resolvers': FantasySubPackageSettings('build_resolvers',
-      FantasyRepoSettings.fromName('build'), 'build_resolvers'),
+      'build_modules', FantasyRepoSettings.fromName('build'),
+      subDir: 'build_modules'),
+  'build_node_compilers': FantasySubPackageSettings(
+      'build_node_compilers', FantasyRepoSettings.fromName('node-interop'),
+      subDir: 'build_node_compilers'),
+  'build_resolvers': FantasySubPackageSettings(
+      'build_resolvers', FantasyRepoSettings.fromName('build'),
+      subDir: 'build_resolvers'),
   'build_runner': FantasySubPackageSettings(
-      'build_runner', FantasyRepoSettings.fromName('build'), 'build_runner'),
-  'build_runner_core': FantasySubPackageSettings('build_runner_core',
-      FantasyRepoSettings.fromName('build'), 'build_runner_core'),
+      'build_runner', FantasyRepoSettings.fromName('build'),
+      subDir: 'build_runner'),
+  'build_runner_core': FantasySubPackageSettings(
+      'build_runner_core', FantasyRepoSettings.fromName('build'),
+      subDir: 'build_runner_core'),
   'build_test': FantasySubPackageSettings(
-      'build_test', FantasyRepoSettings.fromName('build'), 'build_test'),
-  'build_vm_compilers': FantasySubPackageSettings('build_vm_compilers',
-      FantasyRepoSettings.fromName('build'), 'build_vm_compilers'),
-  'build_web_compilers': FantasySubPackageSettings('build_web_compilers',
-      FantasyRepoSettings.fromName('build'), 'build_web_compilers'),
+      'build_test', FantasyRepoSettings.fromName('build'),
+      subDir: 'build_test'),
+  'build_vm_compilers': FantasySubPackageSettings(
+      'build_vm_compilers', FantasyRepoSettings.fromName('build'),
+      subDir: 'build_vm_compilers'),
+  'build_web_compilers': FantasySubPackageSettings(
+      'build_web_compilers', FantasyRepoSettings.fromName('build'),
+      subDir: 'build_web_compilers'),
   'built_collection': FantasySubPackageSettings('built_collection',
-      FantasyRepoSettings.fromName('built_collection.dart'), '.'),
-  'built_value': FantasySubPackageSettings('built_value',
-      FantasyRepoSettings.fromName('built_value.dart'), 'built_value'),
+      FantasyRepoSettings.fromName('built_collection.dart')),
+  'built_value': FantasySubPackageSettings(
+      'built_value', FantasyRepoSettings.fromName('built_value.dart'),
+      subDir: 'built_value'),
   'built_value_generator': FantasySubPackageSettings(
-      'built_value_generator',
-      FantasyRepoSettings.fromName('built_value.dart'),
-      'built_value_generator'),
-  'checked_yaml': FantasySubPackageSettings('checked_yaml',
-      FantasyRepoSettings.fromName('json_serializable'), 'checked_yaml'),
+      'built_value_generator', FantasyRepoSettings.fromName('built_value.dart'),
+      subDir: 'built_value_generator'),
+  'checked_yaml': FantasySubPackageSettings(
+      'checked_yaml', FantasyRepoSettings.fromName('json_serializable'),
+      subDir: 'checked_yaml'),
   'expect': FantasySubPackageSettings(
-      'expect', FantasyRepoSettings.fromName('sdk'), 'pkg/expect'),
+      'expect', FantasyRepoSettings.fromName('sdk'),
+      subDir: path.join('pkg', 'expect')),
   'front_end': FantasySubPackageSettings(
-      'front_end', FantasyRepoSettings.fromName('sdk'), 'pkg/front_end'),
+      'front_end', FantasyRepoSettings.fromName('sdk'),
+      subDir: path.join('pkg', 'front_end')),
   'grinder': FantasySubPackageSettings(
-      'grinder', FantasyRepoSettings.fromName('grinder.dart'), '.'),
+      'grinder', FantasyRepoSettings.fromName('grinder.dart')),
   'kernel': FantasySubPackageSettings(
-      'kernel', FantasyRepoSettings.fromName('sdk'), 'pkg/kernel'),
-  'meta': FantasySubPackageSettings(
-      'meta', FantasyRepoSettings.fromName('sdk'), 'pkg/meta'),
-  'node_interop': FantasySubPackageSettings('node_interop',
-      FantasyRepoSettings.fromName('node-interop'), 'node_interop'),
+      'kernel', FantasyRepoSettings.fromName('sdk'),
+      subDir: path.join('pkg', 'kernel')),
+  'meta': FantasySubPackageSettings('meta', FantasyRepoSettings.fromName('sdk'),
+      subDir: path.join('pkg', 'meta')),
+  'node_interop': FantasySubPackageSettings(
+      'node_interop', FantasyRepoSettings.fromName('node-interop'),
+      subDir: 'node_interop'),
   'node_io': FantasySubPackageSettings(
-      'node_io', FantasyRepoSettings.fromName('node-interop'), 'node_io'),
-  'js': FantasySubPackageSettings(
-      'js', FantasyRepoSettings.fromName('sdk'), 'pkg/js'),
-  'json_annotation': FantasySubPackageSettings('json_annotation',
-      FantasyRepoSettings.fromName('json_serializable'), 'json_annotation'),
-  'json_serializable': FantasySubPackageSettings('json_serializable',
-      FantasyRepoSettings.fromName('json_serializable'), 'json_serializable'),
+      'node_io', FantasyRepoSettings.fromName('node-interop'),
+      subDir: 'node_io'),
+  'js': FantasySubPackageSettings('js', FantasyRepoSettings.fromName('sdk'),
+      subDir: path.join('pkg', 'js')),
+  'json_annotation': FantasySubPackageSettings(
+      'json_annotation', FantasyRepoSettings.fromName('json_serializable'),
+      subDir: 'json_annotation'),
+  'json_serializable': FantasySubPackageSettings(
+      'json_serializable', FantasyRepoSettings.fromName('json_serializable'),
+      subDir: 'json_serializable'),
   'package_config': FantasySubPackageSettings(
-      'package_config', FantasyRepoSettings.fromName('package_config'), '.'),
+      'package_config', FantasyRepoSettings.fromName('package_config')),
   'protobuf': FantasySubPackageSettings(
-      'protobuf', FantasyRepoSettings.fromName('protobuf'), 'protobuf'),
+      'protobuf', FantasyRepoSettings.fromName('protobuf'),
+      subDir: 'protobuf'),
   'scratch_space': FantasySubPackageSettings(
-      'scratch_space', FantasyRepoSettings.fromName('build'), 'scratch_space'),
+      'scratch_space', FantasyRepoSettings.fromName('build'),
+      subDir: 'scratch_space'),
   'source_gen': FantasySubPackageSettings(
-      'source_gen', FantasyRepoSettings.fromName('source_gen'), 'source_gen'),
+      'source_gen', FantasyRepoSettings.fromName('source_gen'),
+      subDir: 'source_gen'),
   'source_gen_test': FantasySubPackageSettings(
-      'source_gen_test', FantasyRepoSettings.fromName('source_gen_test'), '.'),
+      'source_gen_test', FantasyRepoSettings.fromName('source_gen_test')),
   'test': FantasySubPackageSettings(
-      'test', FantasyRepoSettings.fromName('test'), 'pkgs/test'),
+      'test', FantasyRepoSettings.fromName('test'),
+      subDir: path.join('pkgs', 'test')),
   'test_api': FantasySubPackageSettings(
-      'test_api', FantasyRepoSettings.fromName('test'), 'pkgs/test_api'),
+      'test_api', FantasyRepoSettings.fromName('test'),
+      subDir: path.join('pkgs', 'test_api')),
   'test_core': FantasySubPackageSettings(
-      'test_core', FantasyRepoSettings.fromName('test'), 'pkgs/test_core'),
+      'test_core', FantasyRepoSettings.fromName('test'),
+      subDir: path.join('pkgs', 'test_core')),
   'testing': FantasySubPackageSettings(
-      'testing', FantasyRepoSettings.fromName('sdk'), 'pkg/testing'),
+      'testing', FantasyRepoSettings.fromName('sdk'),
+      subDir: path.join('pkg', 'testing')),
   'vm_service': FantasySubPackageSettings(
-      'vm_service', FantasyRepoSettings.fromName('sdk'), 'pkg/vm_service'),
+      'vm_service', FantasyRepoSettings.fromName('sdk'),
+      subDir: path.join('pkg', 'vm_service')),
   'quiver': FantasySubPackageSettings(
-      'quiver', FantasyRepoSettings.fromName('quiver-dart'), '.'),
+      'quiver', FantasyRepoSettings.fromName('quiver-dart')),
 };
 
 /// Data class containing settings for a package within a [FantasyWorkspaceImpl].
@@ -96,7 +131,7 @@
   final FantasyRepoSettings repoSettings;
   final String subDir;
 
-  FantasySubPackageSettings(this.name, this.repoSettings, [this.subDir = '.']);
+  FantasySubPackageSettings(this.name, this.repoSettings, {this.subDir: '.'});
 
   /// Build settings just from a name in a mostly-hardcoded table.
   factory FantasySubPackageSettings.fromName(String name) {
@@ -106,6 +141,45 @@
     return FantasySubPackageSettings(name, FantasyRepoSettings.fromName(name));
   }
 
+  /// Build [FantasySubPackageSettings] from the dependency of a given subPackage.
+  factory FantasySubPackageSettings.fromDependency(
+      FantasySubPackage subPackage, PSDependency dependency) {
+    if (dependency.host != null)
+      throw UnimplementedError(
+          'fromDependency: contains a host field:  $dependency');
+    if (dependency.git != null)
+      throw UnimplementedError(
+          'fromDependency: contains a git field:  $dependency');
+    if (dependency.path != null) {
+      return FantasySubPackageSettings.fromNested(
+          dependency.name.text, subPackage, dependency.path.value.text);
+    }
+    // Hopefully, a version is declared at least... but if not proceed onward
+    // and hope building from name works if we aren't running with asserts.
+    assert(dependency.version != null);
+    return FantasySubPackageSettings.fromName(dependency.name.text);
+  }
+
+  /// Build settings for a nested package based on the repository settings
+  /// of an existing package.
+  ///
+  /// [subDir] is resolved relative to [parent.packageRoot].
+  factory FantasySubPackageSettings.fromNested(
+      String name, FantasySubPackage parent, String subDir) {
+    var pathContext = parent.resourceProvider.pathContext;
+    String nestedSubdir;
+    if (pathContext.isRelative(subDir)) {
+      nestedSubdir = pathContext
+          .normalize(pathContext.join(parent.packageRoot.path, subDir));
+    } else {
+      nestedSubdir = pathContext.normalize(subDir);
+    }
+    assert(pathContext.isWithin(parent.packageRoot.path, nestedSubdir));
+    return FantasySubPackageSettings(name, parent.containingRepo.repoSettings,
+        subDir: pathContext.relative(nestedSubdir,
+            from: parent.containingRepo.repoRoot.path));
+  }
+
   @override
   int get hashCode => toString().hashCode;
 
@@ -122,17 +196,83 @@
       'FantasySubPackageSettings("$name", ${repoSettings.toString()}, "$subDir")';
 }
 
+class _AccumulateDependenciesVisitor<T> extends PubspecVisitor {
+  final T Function(PSDependency) transformDependency;
+  final List<T> results = [];
+
+  _AccumulateDependenciesVisitor(this.transformDependency);
+
+  void visitPackageDependency(PSDependency dependency) =>
+      results.add(transformDependency(dependency));
+}
+
+class _AccumulateAllDependenciesVisitor<T>
+    extends _AccumulateDependenciesVisitor<T> {
+  _AccumulateAllDependenciesVisitor(
+      T Function(PSDependency) transformDependency)
+      : super(transformDependency);
+
+  void visitPackageDevDependency(PSDependency dependency) =>
+      results.add(transformDependency(dependency));
+}
+
+class FantasySubPackageDependencies {
+  final ResourceProvider resourceProvider;
+  File Function(String) get fileBuilder => resourceProvider.getFile;
+
+  FantasySubPackageDependencies({ResourceProvider resourceProvider})
+      : resourceProvider =
+            resourceProvider ?? PhysicalResourceProvider.INSTANCE;
+
+  factory FantasySubPackageDependencies.fromWorkspaceDependencies(
+      FantasyWorkspaceDependencies workspaceDependencies) {
+    return FantasySubPackageDependencies(
+        resourceProvider: workspaceDependencies.resourceProvider);
+  }
+}
+
 /// Represents one package within a [FantasyWorkspaceImpl].
 ///
 /// A `FantasySubPackage` differs from a normal package in that Dart code within
 /// it depends on a global .packages file to resolve symbols.
 class FantasySubPackage {
   final FantasyRepo containingRepo;
-  final FantasyWorkspace containingWorkspace;
   final String name;
   final FantasySubPackageSettings packageSettings;
+  final ResourceProvider resourceProvider;
 
-  FantasySubPackage(
-      this.packageSettings, this.containingRepo, this.containingWorkspace)
-      : name = packageSettings.name;
+  FantasySubPackage(this.packageSettings, this.containingRepo,
+      {ResourceProvider resourceProvider})
+      : name = packageSettings.name,
+        resourceProvider =
+            resourceProvider ?? PhysicalResourceProvider.INSTANCE;
+
+  Folder _packageRoot;
+  Folder get packageRoot => _packageRoot ??= resourceProvider.getFolder(
+      resourceProvider.pathContext.normalize(resourceProvider.pathContext
+          .join(containingRepo.repoRoot.path, packageSettings.subDir)));
+
+  Future<void> _acceptPubspecVisitor<T>(
+      PubspecVisitor<T> pubspecVisitor) async {
+    File pubspecYaml = resourceProvider.getFile(
+        resourceProvider.pathContext.join(packageRoot.path, 'pubspec.yaml'));
+    if (!pubspecYaml.exists) return;
+    Pubspec pubspec = Pubspec.parse(pubspecYaml.readAsStringSync(),
+        sourceUrl: resourceProvider.pathContext.toUri(pubspecYaml.path));
+    pubspec.accept(pubspecVisitor);
+  }
+
+  Future<List<FantasySubPackageSettings>> getPackageDependencies() async {
+    var visitor = _AccumulateDependenciesVisitor(
+        (d) => FantasySubPackageSettings.fromDependency(this, d));
+    await _acceptPubspecVisitor(visitor);
+    return visitor.results;
+  }
+
+  Future<List<FantasySubPackageSettings>> getPackageAllDependencies() async {
+    var visitor = _AccumulateAllDependenciesVisitor(
+        (d) => FantasySubPackageSettings.fromDependency(this, d));
+    await _acceptPubspecVisitor(visitor);
+    return visitor.results;
+  }
 }
diff --git a/pkg/nnbd_migration/lib/src/fantasyland/fantasy_workspace.dart b/pkg/nnbd_migration/lib/src/fantasyland/fantasy_workspace.dart
index d9ec224..cda38ec 100644
--- a/pkg/nnbd_migration/lib/src/fantasyland/fantasy_workspace.dart
+++ b/pkg/nnbd_migration/lib/src/fantasyland/fantasy_workspace.dart
@@ -2,7 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:io';
+// TODO(jcollins-g): finish port away from io
+import 'dart:io' show Directory;
 
 import 'package:nnbd_migration/src/fantasyland/fantasy_sub_package.dart';
 import 'package:nnbd_migration/src/fantasyland/fantasy_workspace_impl.dart';
@@ -19,8 +20,8 @@
 
 /// Build a "fantasyland"-style repository structure suitable for applying
 /// a migration to.
-Future<FantasyWorkspace> buildFantasyLand(String topLevelPackage,
-    List<String> extraPackages, Directory fantasyLandDir) {
+Future<FantasyWorkspace> buildFantasyLand(
+    String topLevelPackage, List<String> extraPackages, String fantasyLandDir) {
   return FantasyWorkspaceTopLevelDevDepsImpl.buildFor(
       topLevelPackage, extraPackages, fantasyLandDir);
 }
diff --git a/pkg/nnbd_migration/lib/src/fantasyland/fantasy_workspace_impl.dart b/pkg/nnbd_migration/lib/src/fantasyland/fantasy_workspace_impl.dart
index 9ee506c..837eb07 100644
--- a/pkg/nnbd_migration/lib/src/fantasyland/fantasy_workspace_impl.dart
+++ b/pkg/nnbd_migration/lib/src/fantasyland/fantasy_workspace_impl.dart
@@ -2,17 +2,40 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:io';
+// TODO(jcollins-g): finish port away from io
+import 'dart:io' show Directory;
 
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/physical_file_system.dart';
 import 'package:nnbd_migration/src/fantasyland/fantasy_repo.dart';
 import 'package:nnbd_migration/src/fantasyland/fantasy_sub_package.dart';
 import 'package:nnbd_migration/src/fantasyland/fantasy_workspace.dart';
+import 'package:nnbd_migration/src/utilities/subprocess_launcher.dart';
 import 'package:path/path.dart' as path;
 
+// TODO(jcollins-g): consider refactor that makes resourceProvider required.
+class FantasyWorkspaceDependencies {
+  final Future<FantasyRepo> Function(FantasyRepoSettings, String)
+      buildGitRepoFrom;
+  final ResourceProvider resourceProvider;
+  final SubprocessLauncher launcher;
+
+  FantasyWorkspaceDependencies(
+      {ResourceProvider resourceProvider,
+      SubprocessLauncher launcher,
+      Future<FantasyRepo> Function(FantasyRepoSettings, String)
+          buildGitRepoFrom})
+      : resourceProvider =
+            resourceProvider ?? PhysicalResourceProvider.INSTANCE,
+        launcher = launcher, // Pass through to FantasyRepoDependencies.
+        buildGitRepoFrom = buildGitRepoFrom ?? FantasyRepo.buildGitRepoFrom;
+}
+
 abstract class FantasyWorkspaceImpl extends FantasyWorkspace {
   @override
   final Directory workspaceRoot;
 
+  // TODO(jcollins-g): inject FantasyWorkspaceDependencies here.
   FantasyWorkspaceImpl._(this.workspaceRoot);
 
   /// Repositories on which [addRepoToWorkspace] has been called.
@@ -63,7 +86,8 @@
     if (_repos.containsKey(repoSettings.name)) return _repos[repoSettings.name];
     Directory repoRoot = Directory(path.canonicalize(
         path.join(workspaceRoot.path, _repoSubDir, repoSettings.name)));
-    _repos[repoSettings.name] = FantasyRepo.buildFrom(repoSettings, repoRoot);
+    _repos[repoSettings.name] =
+        FantasyRepo.buildGitRepoFrom(repoSettings, repoRoot.path);
     return _repos[repoSettings.name];
   }
 }
@@ -78,12 +102,13 @@
       : super._(workspaceRoot);
 
   static Future<FantasyWorkspace> buildFor(String topLevelPackage,
-      List<String> extraPackageNames, Directory workspaceRoot) async {
-    if (!await workspaceRoot.exists())
-      await workspaceRoot.create(recursive: true);
+      List<String> extraPackageNames, String workspaceRoot) async {
+    // TODO(jcollins-g): finish port
+    Directory workspaceRootDir = Directory(workspaceRoot);
+    await workspaceRootDir.create(recursive: true);
 
-    var workspace =
-        FantasyWorkspaceTopLevelDevDepsImpl._(topLevelPackage, workspaceRoot);
+    var workspace = FantasyWorkspaceTopLevelDevDepsImpl._(
+        topLevelPackage, workspaceRootDir);
     await Future.wait([
       for (var n in [topLevelPackage, ...extraPackageNames])
         workspace.addPackageNameToWorkspace(n)
@@ -98,17 +123,9 @@
     FantasyRepo containingRepo =
         await addRepoToWorkspace(packageSettings.repoSettings);
     FantasySubPackage fantasySubPackage =
-        FantasySubPackage(packageSettings, containingRepo, this);
+        FantasySubPackage(packageSettings, containingRepo);
     subPackages[fantasySubPackage.name] = fantasySubPackage;
 
-    // Add a symlink to the top level directory.
-    Link packageSymlink =
-        Link(path.join(workspaceRoot.path, packageSettings.name));
-    if (!await packageSymlink.exists()) {
-      await packageSymlink.create(path.canonicalize(
-          path.join(containingRepo.repoRoot.path, packageSettings.subDir)));
-    }
-
     // TODO(jcollins-g): Add to .packages / package_config.json
     if (packageName == topLevelPackage) {
       throw UnimplementedError();
diff --git a/pkg/nnbd_migration/lib/src/fix_aggregator.dart b/pkg/nnbd_migration/lib/src/fix_aggregator.dart
index 6862421..857264a 100644
--- a/pkg/nnbd_migration/lib/src/fix_aggregator.dart
+++ b/pkg/nnbd_migration/lib/src/fix_aggregator.dart
@@ -6,7 +6,6 @@
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/dart/element/type.dart';
 import 'package:nnbd_migration/instrumentation.dart';
 import 'package:nnbd_migration/nnbd_migration.dart';
 import 'package:nnbd_migration/src/decorated_type.dart';
@@ -416,7 +415,7 @@
     return aggregator.planner.makeNullable(innerPlan,
         info: AtomicEditInfo(
             NullabilityFixDescription.makeTypeNullable(
-                makeNullableType.type.toString()),
+                makeNullableType.type.getDisplayString(withNullability: false)),
             [makeNullableType.node]));
   }
 }
@@ -435,8 +434,7 @@
   EditPlan _apply(VariableDeclarationList node, FixAggregator aggregator) {
     List<EditPlan> innerPlans = [];
     if (addExplicitType != null) {
-      var typeText =
-          (addExplicitType as TypeImpl).toString(withNullability: true);
+      var typeText = addExplicitType.getDisplayString(withNullability: true);
       if (node.keyword?.keyword == Keyword.VAR) {
         innerPlans.add(aggregator.planner
             .replaceToken(node, node.keyword, [AtomicEdit.insert(typeText)]));
diff --git a/pkg/nnbd_migration/lib/src/fix_builder.dart b/pkg/nnbd_migration/lib/src/fix_builder.dart
index 33e1df8..8c603ae 100644
--- a/pkg/nnbd_migration/lib/src/fix_builder.dart
+++ b/pkg/nnbd_migration/lib/src/fix_builder.dart
@@ -19,12 +19,14 @@
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/error/best_practices_verifier.dart';
+import 'package:analyzer/src/generated/element_type_provider.dart';
 import 'package:analyzer/src/generated/migration.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
 import 'package:nnbd_migration/nnbd_migration.dart';
 import 'package:nnbd_migration/src/decorated_class_hierarchy.dart';
+import 'package:nnbd_migration/src/decorated_type.dart';
 import 'package:nnbd_migration/src/edit_plan.dart';
 import 'package:nnbd_migration/src/fix_aggregator.dart';
 import 'package:nnbd_migration/src/nullability_node.dart';
@@ -88,7 +90,9 @@
   /// The compilation unit for which fixes are being built.
   final CompilationUnit unit;
 
-  FixBuilder(
+  final MigrationResolutionHooksImpl migrationResolutionHooks;
+
+  factory FixBuilder(
       Source source,
       DecoratedClassHierarchy decoratedClassHierarchy,
       TypeProvider typeProvider,
@@ -96,17 +100,21 @@
       Variables variables,
       LibraryElement definingLibrary,
       NullabilityMigrationListener listener,
-      CompilationUnit unit)
-      : this._(
-            decoratedClassHierarchy,
-            _makeNnbdTypeSystem(
-                (typeProvider as TypeProviderImpl).asNonNullableByDefault,
-                typeSystem),
-            variables,
-            source,
-            definingLibrary,
-            listener,
-            unit);
+      CompilationUnit unit) {
+    var migrationResolutionHooks = MigrationResolutionHooksImpl();
+    return FixBuilder._(
+        decoratedClassHierarchy,
+        _makeNnbdTypeSystem(
+            (typeProvider as TypeProviderImpl).asNonNullableByDefault,
+            typeSystem,
+            migrationResolutionHooks),
+        variables,
+        source,
+        definingLibrary,
+        listener,
+        unit,
+        migrationResolutionHooks);
+  }
 
   FixBuilder._(
       DecoratedClassHierarchy decoratedClassHierarchy,
@@ -115,8 +123,10 @@
       this.source,
       LibraryElement definingLibrary,
       this.listener,
-      this.unit)
+      this.unit,
+      this.migrationResolutionHooks)
       : typeProvider = _typeSystem.typeProvider {
+    migrationResolutionHooks._fixBuilder = this;
     // TODO(paulberry): make use of decoratedClassHierarchy
     assert(_typeSystem.isNonNullableByDefault);
     assert((typeProvider as TypeProviderImpl).isNonNullableByDefault);
@@ -136,13 +146,14 @@
         errorListener,
         _typeSystem,
         featureSet,
-        MigrationResolutionHooksImpl(this));
+        migrationResolutionHooks);
   }
 
   /// Visits the entire compilation [unit] using the analyzer's resolver and
   /// makes note of changes that need to be made.
   void visitAll() {
     try {
+      ElementTypeProvider.current = migrationResolutionHooks;
       unit.accept(_FixBuilderPreVisitor(this));
       unit.accept(_resolver);
       unit.accept(_FixBuilderPostVisitor(this));
@@ -152,6 +163,8 @@
       } else {
         rethrow;
       }
+    } finally {
+      ElementTypeProvider.current = const ElementTypeProvider();
     }
   }
 
@@ -174,8 +187,7 @@
         element.isSynthetic &&
         !element.variable.isSynthetic) {
       var variableType = _variables
-          .decoratedElementType(element.variable)
-          .toFinalType(typeProvider);
+          .toFinalType(_variables.decoratedElementType(element.variable));
       if (element.isSetter) {
         return FunctionTypeImpl(
             returnType: typeProvider.voidType,
@@ -193,7 +205,7 @@
             nullabilitySuffix: NullabilitySuffix.none);
       }
     } else {
-      return _variables.decoratedElementType(element).toFinalType(typeProvider);
+      return _variables.toFinalType(_variables.decoratedElementType(element));
     }
   }
 
@@ -222,7 +234,9 @@
   }
 
   static TypeSystemImpl _makeNnbdTypeSystem(
-      TypeProvider nnbdTypeProvider, Dart2TypeSystem typeSystem) {
+      TypeProvider nnbdTypeProvider,
+      Dart2TypeSystem typeSystem,
+      MigrationResolutionHooksImpl migrationResolutionHooks) {
     // TODO(paulberry): do we need to test both possible values of
     // strictInference?
     return TypeSystemImpl(
@@ -236,7 +250,7 @@
 /// Implementation of [MigrationResolutionHooks] that interfaces with
 /// [FixBuilder].
 class MigrationResolutionHooksImpl implements MigrationResolutionHooks {
-  final FixBuilder _fixBuilder;
+  FixBuilder _fixBuilder;
 
   final Expando<List<CollectionElement>> _collectionElements = Expando();
 
@@ -245,7 +259,12 @@
   FlowAnalysis<AstNode, Statement, Expression, PromotableElement, DartType>
       _flowAnalysis;
 
-  MigrationResolutionHooksImpl(this._fixBuilder);
+  @override
+  void freshTypeParameterCreated(TypeParameterElement newTypeParameter,
+      TypeParameterElement oldTypeParameter) {
+    DecoratedTypeParameterBounds.current.put(newTypeParameter,
+        DecoratedTypeParameterBounds.current.get(oldTypeParameter));
+  }
 
   @override
   bool getConditionalKnownValue(AstNode node) =>
@@ -269,15 +288,15 @@
 
   @override
   List<ParameterElement> getExecutableParameters(ExecutableElement element) =>
-      getExecutableType(element).parameters;
+      getExecutableType(element as ElementImplWithFunctionType).parameters;
 
   @override
-  DartType getExecutableReturnType(FunctionTypedElement element) =>
-      getExecutableType(element).returnType;
+  DartType getExecutableReturnType(Element element) =>
+      getExecutableType(element as ElementImplWithFunctionType).returnType;
 
   @override
-  FunctionType getExecutableType(FunctionTypedElement element) =>
-      _wrapExceptions(_fixBuilder.unit, () => element.type, () {
+  FunctionType getExecutableType(ElementImplWithFunctionType element) =>
+      _wrapExceptions(_fixBuilder.unit, () => element.typeInternal, () {
         var type = _fixBuilder._computeMigratedType(element);
         Element baseElement = element;
         if (baseElement is Member) {
@@ -287,8 +306,8 @@
       });
 
   @override
-  DartType getFieldType(FieldElement element) =>
-      _wrapExceptions(_fixBuilder.unit, () => element.type, () {
+  DartType getFieldType(PropertyInducingElementImpl element) =>
+      _wrapExceptions(_fixBuilder.unit, () => element.typeInternal, () {
         assert(!element.isSynthetic);
         return _fixBuilder._computeMigratedType(element);
       });
@@ -309,13 +328,29 @@
               _transformCollectionElements(node.elements, node.typeArguments));
 
   @override
-  DartType getVariableType(VariableElement variable) =>
-      _wrapExceptions(_fixBuilder.unit, () => variable.type, () {
+  DartType getTypeParameterBound(TypeParameterElementImpl element) {
+    var decoratedBound = _fixBuilder._variables
+        .decoratedTypeParameterBound(element, allowNullUnparentedBounds: true);
+    if (decoratedBound == null) return element.boundInternal;
+    var bound = _fixBuilder._variables.toFinalType(decoratedBound);
+    if (bound.isDynamic) {
+      return null;
+    } else if (bound.isDartCoreObject &&
+        bound.nullabilitySuffix == NullabilitySuffix.question) {
+      return null;
+    } else {
+      return bound;
+    }
+  }
+
+  @override
+  DartType getVariableType(VariableElementImpl variable) =>
+      _wrapExceptions(_fixBuilder.unit, () => variable.typeInternal, () {
         if (variable.library == null) {
           // This is a synthetic variable created during resolution (e.g. a
           // parameter of a function type), so the type it currently has is the
           // correct post-migration type.
-          return variable.type;
+          return variable.typeInternal;
         }
         return _fixBuilder._computeMigratedType(variable);
       });
@@ -378,8 +413,7 @@
             NullabilityFixDescription.checkExpression, checks.edges)
         : null;
     (_fixBuilder._getChange(node) as NodeChangeForExpression)
-      ..introduceAsType =
-          (contextType as TypeImpl).toString(withNullability: true)
+      ..introduceAsType = contextType.getDisplayString(withNullability: true)
       ..introduceAsInfo = info;
     _flowAnalysis.asExpression_end(node, contextType);
     return contextType;
@@ -603,7 +637,7 @@
         ..makeNullableType = decoratedType;
     }
     (node as GenericFunctionTypeImpl).type =
-        decoratedType.toFinalType(_fixBuilder.typeProvider);
+        _fixBuilder._variables.toFinalType(decoratedType);
     super.visitGenericFunctionType(node);
   }
 
@@ -617,7 +651,7 @@
         ..makeNullable = true
         ..makeNullableType = decoratedType;
     }
-    node.type = decoratedType.toFinalType(_fixBuilder.typeProvider);
+    node.type = _fixBuilder._variables.toFinalType(decoratedType);
     super.visitTypeName(node);
   }
 
diff --git a/pkg/nnbd_migration/lib/src/node_builder.dart b/pkg/nnbd_migration/lib/src/node_builder.dart
index 6aee695..23624f6 100644
--- a/pkg/nnbd_migration/lib/src/node_builder.dart
+++ b/pkg/nnbd_migration/lib/src/node_builder.dart
@@ -50,11 +50,6 @@
   /// seen so far.  Otherwise `null`.
   List<DecoratedType> _positionalParameters;
 
-  /// If the type parameters of a function or method are being visited, the
-  /// [DecoratedType]s of the bounds of the function's type formals that have
-  /// been seen so far.  Otherwise `null`.
-  List<DecoratedType> _typeFormalBounds;
-
   final NullabilityMigrationListener /*?*/ listener;
 
   final NullabilityMigrationInstrumentation /*?*/ instrumentation;
@@ -300,10 +295,8 @@
     }
     var previousPositionalParameters = _positionalParameters;
     var previousNamedParameters = _namedParameters;
-    var previousTypeFormalBounds = _typeFormalBounds;
     _positionalParameters = [];
     _namedParameters = {};
-    _typeFormalBounds = [];
     DecoratedType decoratedFunctionType;
     try {
       node.typeParameters?.accept(this);
@@ -312,17 +305,15 @@
       // not defining a generic function type, we're defining a generic typedef
       // of an ordinary (non-generic) function type.
       decoratedFunctionType = DecoratedType(functionType, _graph.never,
-          typeFormalBounds: const [],
           returnType: decoratedReturnType,
           positionalParameters: _positionalParameters,
           namedParameters: _namedParameters);
     } finally {
       _positionalParameters = previousPositionalParameters;
       _namedParameters = previousNamedParameters;
-      _typeFormalBounds = previousTypeFormalBounds;
     }
     _variables.recordDecoratedElementType(
-        declaredElement, decoratedFunctionType);
+        declaredElement.function, decoratedFunctionType);
     return null;
   }
 
@@ -336,17 +327,12 @@
   @override
   DecoratedType visitGenericTypeAlias(GenericTypeAlias node) {
     node.metadata.accept(this);
-    var previousTypeFormalBounds = _typeFormalBounds;
-    _typeFormalBounds = [];
     DecoratedType decoratedFunctionType;
-    try {
-      node.typeParameters?.accept(this);
-      decoratedFunctionType = node.functionType.accept(this);
-    } finally {
-      _typeFormalBounds = previousTypeFormalBounds;
-    }
+    node.typeParameters?.accept(this);
+    decoratedFunctionType = node.functionType.accept(this);
     _variables.recordDecoratedElementType(
-        node.declaredElement, decoratedFunctionType);
+        (node.declaredElement as GenericTypeAliasElement).function,
+        decoratedFunctionType);
     return null;
   }
 
@@ -396,7 +382,6 @@
     DecoratedType decoratedReturnType;
     var positionalParameters = const <DecoratedType>[];
     var namedParameters = const <String, DecoratedType>{};
-    var typeFormalBounds = const <DecoratedType>[];
     if (type is InterfaceType && type.element.typeParameters.isNotEmpty) {
       if (node is TypeName) {
         if (node.typeArguments == null) {
@@ -426,20 +411,16 @@
       }
       positionalParameters = <DecoratedType>[];
       namedParameters = <String, DecoratedType>{};
-      typeFormalBounds = <DecoratedType>[];
       var previousPositionalParameters = _positionalParameters;
       var previousNamedParameters = _namedParameters;
-      var previousTypeFormalBounds = _typeFormalBounds;
       try {
         _positionalParameters = positionalParameters;
         _namedParameters = namedParameters;
-        _typeFormalBounds = typeFormalBounds;
         node.typeParameters?.accept(this);
         node.parameters.accept(this);
       } finally {
         _positionalParameters = previousPositionalParameters;
         _namedParameters = previousNamedParameters;
-        _typeFormalBounds = previousTypeFormalBounds;
       }
     }
     NullabilityNode nullabilityNode;
@@ -467,8 +448,7 @@
           typeArguments: typeArguments,
           returnType: decoratedReturnType,
           positionalParameters: positionalParameters,
-          namedParameters: namedParameters,
-          typeFormalBounds: typeFormalBounds);
+          namedParameters: namedParameters);
     }
     _variables.recordDecoratedTypeAnnotation(
         source,
@@ -512,8 +492,7 @@
       _graph.connect(_graph.always, nullabilityNode,
           AlwaysNullableTypeOrigin.forElement(element));
     }
-    _typeFormalBounds?.add(decoratedBound);
-    _variables.recordDecoratedTypeParameterBound(element, decoratedBound);
+    DecoratedTypeParameterBounds.current.put(element, decoratedBound);
     return null;
   }
 
@@ -593,10 +572,8 @@
     }
     var previousPositionalParameters = _positionalParameters;
     var previousNamedParameters = _namedParameters;
-    var previousTypeFormalBounds = _typeFormalBounds;
     _positionalParameters = [];
     _namedParameters = {};
-    _typeFormalBounds = [];
     DecoratedType decoratedFunctionType;
     try {
       typeParameters?.accept(this);
@@ -604,7 +581,6 @@
       redirectedConstructor?.accept(this);
       initializers?.accept(this);
       decoratedFunctionType = DecoratedType(functionType, _graph.never,
-          typeFormalBounds: _typeFormalBounds,
           returnType: decoratedReturnType,
           positionalParameters: _positionalParameters,
           namedParameters: _namedParameters);
@@ -612,7 +588,6 @@
     } finally {
       _positionalParameters = previousPositionalParameters;
       _namedParameters = previousNamedParameters;
-      _typeFormalBounds = previousTypeFormalBounds;
     }
     _variables.recordDecoratedElementType(
         declaredElement, decoratedFunctionType);
@@ -750,10 +725,6 @@
   void recordDecoratedTypeAnnotation(Source source, TypeAnnotation node,
       DecoratedType type, PotentiallyAddQuestionSuffix potentialModification);
 
-  /// Stores he decorated bound of the given [typeParameter].
-  void recordDecoratedTypeParameterBound(
-      TypeParameterElement typeParameter, DecoratedType bound);
-
   /// Records that [node] is associated with the question of whether the named
   /// [parameter] should be optional (should not have a `required`
   /// annotation added to it).
diff --git a/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart b/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart
index 1cde09e..27a9453 100644
--- a/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart
+++ b/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart
@@ -9,6 +9,7 @@
 import 'package:nnbd_migration/instrumentation.dart';
 import 'package:nnbd_migration/nnbd_migration.dart';
 import 'package:nnbd_migration/src/decorated_class_hierarchy.dart';
+import 'package:nnbd_migration/src/decorated_type.dart';
 import 'package:nnbd_migration/src/edge_builder.dart';
 import 'package:nnbd_migration/src/edit_plan.dart';
 import 'package:nnbd_migration/src/fix_aggregator.dart';
@@ -38,6 +39,8 @@
   /// code that is removed.
   final bool removeViaComments;
 
+  final _decoratedTypeParameterBounds = DecoratedTypeParameterBounds();
+
   /// Prepares to perform nullability migration.
   ///
   /// If [permissive] is `true`, exception handling logic will try to proceed
@@ -60,11 +63,6 @@
   }
 
   @override
-  void update() {
-    _graph.update();
-  }
-
-  @override
   void finalizeInput(ResolvedUnitResult result) {
     if (!_propagated) {
       _propagated = true;
@@ -83,7 +81,12 @@
         library,
         listener,
         unit);
-    fixBuilder.visitAll();
+    try {
+      DecoratedTypeParameterBounds.current = _decoratedTypeParameterBounds;
+      fixBuilder.visitAll();
+    } finally {
+      DecoratedTypeParameterBounds.current = null;
+    }
     var changes = FixAggregator.run(unit, result.content, fixBuilder.changes,
         removeViaComments: removeViaComments);
     _instrumentation?.changes(source, changes);
@@ -114,22 +117,37 @@
       _decoratedClassHierarchy = DecoratedClassHierarchy(_variables, _graph);
     }
     var unit = result.unit;
-    unit.accept(NodeBuilder(_variables, unit.declaredElement.source,
-        _permissive ? listener : null, _graph, result.typeProvider,
-        instrumentation: _instrumentation));
+    try {
+      DecoratedTypeParameterBounds.current = _decoratedTypeParameterBounds;
+      unit.accept(NodeBuilder(_variables, unit.declaredElement.source,
+          _permissive ? listener : null, _graph, result.typeProvider,
+          instrumentation: _instrumentation));
+    } finally {
+      DecoratedTypeParameterBounds.current = null;
+    }
   }
 
   void processInput(ResolvedUnitResult result) {
     var unit = result.unit;
-    unit.accept(EdgeBuilder(
-        result.typeProvider,
-        result.typeSystem,
-        _variables,
-        _graph,
-        unit.declaredElement.source,
-        _permissive ? listener : null,
-        _decoratedClassHierarchy,
-        instrumentation: _instrumentation));
+    try {
+      DecoratedTypeParameterBounds.current = _decoratedTypeParameterBounds;
+      unit.accept(EdgeBuilder(
+          result.typeProvider,
+          result.typeSystem,
+          _variables,
+          _graph,
+          unit.declaredElement.source,
+          _permissive ? listener : null,
+          _decoratedClassHierarchy,
+          instrumentation: _instrumentation));
+    } finally {
+      DecoratedTypeParameterBounds.current = null;
+    }
+  }
+
+  @override
+  void update() {
+    _graph.update();
   }
 
   static Location _computeLocation(
diff --git a/pkg/nnbd_migration/lib/src/nullability_node.dart b/pkg/nnbd_migration/lib/src/nullability_node.dart
index ad77386..95f6b7c 100644
--- a/pkg/nnbd_migration/lib/src/nullability_node.dart
+++ b/pkg/nnbd_migration/lib/src/nullability_node.dart
@@ -129,12 +129,6 @@
       {bool hard: false,
       bool checkable = true,
       List<NullabilityNode> guards: const []}) {
-    // Hard nodes are always considered checkable, since the only time they
-    // arise is from an explicit use of an expression in a context that requires
-    // non-nullability (and hence, a null check could be added in that
-    // location).  Verify that the flags passed in by the caller are consistent
-    // with this.
-    assert(checkable || !hard);
     var upstreamNodes = [sourceNode]..addAll(guards);
     var kind = hard
         ? _NullabilityEdgeKind.hard
diff --git a/pkg/nnbd_migration/lib/src/potential_modification.dart b/pkg/nnbd_migration/lib/src/potential_modification.dart
index 3f429c5..1e170f9 100644
--- a/pkg/nnbd_migration/lib/src/potential_modification.dart
+++ b/pkg/nnbd_migration/lib/src/potential_modification.dart
@@ -115,7 +115,8 @@
 
   @override
   NullabilityFixDescription get description =>
-      NullabilityFixDescription.makeTypeNullable(type.toString());
+      NullabilityFixDescription.makeTypeNullable(
+          type.getDisplayString(withNullability: false));
 
   @override
   bool get isEmpty => !node.isNullable;
diff --git a/pkg/nnbd_migration/lib/src/utilities/multi_future_tracker.dart b/pkg/nnbd_migration/lib/src/utilities/multi_future_tracker.dart
index 49c4d7c..950b63b 100644
--- a/pkg/nnbd_migration/lib/src/utilities/multi_future_tracker.dart
+++ b/pkg/nnbd_migration/lib/src/utilities/multi_future_tracker.dart
@@ -2,12 +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.
 
+import 'dart:async';
+
 /// This library helps run parallel thread-like closures asynchronously.
 /// Borrowed from dartdoc:src/io_utils.dart.
 
 // TODO(jcollins-g): like SubprocessLauncher, merge with io_utils in dartdoc
 // before cut-and-paste gets out of hand.
-
 class MultiFutureTracker {
   /// Maximum number of simultaneously incomplete [Future]s.
   final int parallel;
@@ -39,6 +40,17 @@
     future.then((f) => _trackedFutures.remove(future));
   }
 
+  /// Generates a [Future] from the given closure and adds it to the queue,
+  /// once the queue is sufficiently empty.  Completes when the generated
+  /// closure completes.
+  Future<T> runFutureFromClosure<T>(FutureOr<T> Function() closure) async {
+    Completer<T> futureComplete = Completer();
+    await addFutureFromClosure(() async {
+      futureComplete.complete(await closure());
+    });
+    return futureComplete.future;
+  }
+
   /// Wait until all futures added so far have completed.
   Future<void> wait() => _waitUntil(0);
 }
diff --git a/pkg/nnbd_migration/lib/src/utilities/subprocess_launcher.dart b/pkg/nnbd_migration/lib/src/utilities/subprocess_launcher.dart
index 3ac4488..151b1d4 100644
--- a/pkg/nnbd_migration/lib/src/utilities/subprocess_launcher.dart
+++ b/pkg/nnbd_migration/lib/src/utilities/subprocess_launcher.dart
@@ -67,19 +67,13 @@
       Map<String, String> environment,
       bool includeParentEnvironment = true,
       void Function(String) perLine}) async {
-    Completer<Future<Iterable<Map>>> startedProcess = Completer();
-
-    await maxParallel.addFutureFromClosure(() async {
-      Future<Iterable<Map>> runStreamedImmediateFuture;
-      runStreamedImmediateFuture = runStreamedImmediate(executable, arguments,
+    return maxParallel.runFutureFromClosure(() async {
+      return runStreamedImmediate(executable, arguments,
           workingDirectory: workingDirectory,
           environment: environment,
           includeParentEnvironment: includeParentEnvironment,
           perLine: perLine);
-      startedProcess.complete(runStreamedImmediateFuture);
-      return runStreamedImmediateFuture;
     });
-    return await startedProcess.future;
   }
 
   /// A wrapper around start/await process.exitCode that will display the
diff --git a/pkg/nnbd_migration/lib/src/variables.dart b/pkg/nnbd_migration/lib/src/variables.dart
index e626ca4..2e48b72 100644
--- a/pkg/nnbd_migration/lib/src/variables.dart
+++ b/pkg/nnbd_migration/lib/src/variables.dart
@@ -6,12 +6,16 @@
 
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/dart/element/type_provider.dart';
+import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/generated/element_type_provider.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
 import 'package:meta/meta.dart';
 import 'package:nnbd_migration/instrumentation.dart';
 import 'package:nnbd_migration/src/already_migrated_code_decorator.dart';
@@ -35,12 +39,12 @@
 class Variables implements VariableRecorder, VariableRepository {
   final NullabilityGraph _graph;
 
+  final TypeProvider _typeProvider;
+
   final _conditionalDiscards = <Source, Map<int, ConditionalDiscard>>{};
 
   final _decoratedElementTypes = <Element, DecoratedType>{};
 
-  final _decoratedTypeParameterBounds = <Element, DecoratedType>{};
-
   final _decoratedDirectSupertypes =
       <ClassElement, Map<ClassElement, DecoratedType>>{};
 
@@ -56,9 +60,9 @@
 
   final NullabilityMigrationInstrumentation /*?*/ instrumentation;
 
-  Variables(this._graph, TypeProvider typeProvider, {this.instrumentation})
+  Variables(this._graph, this._typeProvider, {this.instrumentation})
       : _alreadyMigratedCodeDecorator =
-            AlreadyMigratedCodeDecorator(_graph, typeProvider);
+            AlreadyMigratedCodeDecorator(_graph, _typeProvider);
 
   @override
   Map<ClassElement, DecoratedType> decoratedDirectSupertypes(
@@ -93,20 +97,27 @@
     return decoratedTypeAnnotation;
   }
 
+  /// Note: the optional argument [allowNullUnparentedBounds] is intended for
+  /// the FixBuilder stage only, to allow it to cope with the situation where
+  /// a type parameter element with a null parent doesn't have a decorated type
+  /// associated with it.  This can arise because synthetic type parameter
+  /// elements get created as a result of type system operations during
+  /// resolution, and fortunately it isn't a problem during the FixBuilder stage
+  /// because at that point the types we are dealing with are all
+  /// post-migration types, so their bounds already reflect the correct
+  /// nullabilities.
   @override
-  DecoratedType decoratedTypeParameterBound(
-      TypeParameterElement typeParameter) {
-    if (typeParameter.enclosingElement == null) {
-      var decoratedType =
-          DecoratedType.decoratedTypeParameterBound(typeParameter);
-      if (decoratedType == null) {
+  DecoratedType decoratedTypeParameterBound(TypeParameterElement typeParameter,
+      {bool allowNullUnparentedBounds = false}) {
+    var enclosingElement = typeParameter.enclosingElement;
+    var decoratedType = DecoratedTypeParameterBounds.current.get(typeParameter);
+    if (enclosingElement == null) {
+      if (decoratedType == null && !allowNullUnparentedBounds) {
         throw StateError(
             'A decorated type for the bound of $typeParameter should '
             'have been stored by the NodeBuilder via recordTypeParameterBound');
       }
-      return decoratedType;
     } else {
-      var decoratedType = _decoratedTypeParameterBounds[typeParameter];
       if (decoratedType == null) {
         if (_graph.isBeingMigrated(typeParameter.library.source)) {
           throw StateError(
@@ -115,13 +126,14 @@
               'recordTypeParameterBound');
         }
         decoratedType = _alreadyMigratedCodeDecorator.decorate(
-            typeParameter.bound ?? DynamicTypeImpl.instance, typeParameter);
+            typeParameter.preMigrationBound ?? DynamicTypeImpl.instance,
+            typeParameter);
         instrumentation?.externalDecoratedTypeParameterBound(
             typeParameter, decoratedType);
-        _decoratedTypeParameterBounds[typeParameter] = decoratedType;
+        DecoratedTypeParameterBounds.current.put(typeParameter, decoratedType);
       }
-      return decoratedType;
     }
+    return decoratedType;
   }
 
   /// Retrieves the [ExpressionChecks] object corresponding to the given
@@ -179,16 +191,6 @@
   }
 
   @override
-  void recordDecoratedTypeParameterBound(
-      TypeParameterElement typeParameter, DecoratedType bound) {
-    if (typeParameter.enclosingElement == null) {
-      DecoratedType.recordTypeParameterBound(typeParameter, bound);
-    } else {
-      _decoratedTypeParameterBounds[typeParameter] = bound;
-    }
-  }
-
-  @override
   void recordExpressionChecks(
       Source source, Expression expression, ExpressionChecksOrigin origin) {
     _addPotentialModification(source, origin.checks);
@@ -211,6 +213,72 @@
     assert(newlyAdded);
   }
 
+  /// Convert this decorated type into the [DartType] that it will represent
+  /// after the code has been migrated.
+  ///
+  /// This method should be used after nullability propagation; it makes use of
+  /// the nullabilities associated with nullability nodes to determine which
+  /// types should be nullable and which types should not.
+  DartType toFinalType(DecoratedType decoratedType) {
+    var type = decoratedType.type;
+    if (type.isVoid || type.isDynamic) return type;
+    if (type.isBottom || type.isDartCoreNull) {
+      if (decoratedType.node.isNullable) {
+        return (_typeProvider.nullType as TypeImpl)
+            .withNullability(NullabilitySuffix.none);
+      } else {
+        return NeverTypeImpl.instance;
+      }
+    }
+    var nullabilitySuffix = decoratedType.node.isNullable
+        ? NullabilitySuffix.question
+        : NullabilitySuffix.none;
+    if (type is FunctionType) {
+      var parameters = <ParameterElement>[];
+      for (int i = 0; i < type.parameters.length; i++) {
+        var origParameter = type.parameters[i];
+        ParameterKind parameterKind;
+        DecoratedType parameterType;
+        var name = origParameter.name;
+        if (origParameter.isNamed) {
+          // TODO(paulberry): infer ParameterKind.NAMED_REQUIRED when
+          // appropriate. See https://github.com/dart-lang/sdk/issues/38596.
+          parameterKind = ParameterKind.NAMED;
+          parameterType = decoratedType.namedParameters[name];
+        } else {
+          parameterKind = origParameter.isOptional
+              ? ParameterKind.POSITIONAL
+              : ParameterKind.REQUIRED;
+          parameterType = decoratedType.positionalParameters[i];
+        }
+        parameters.add(ParameterElementImpl.synthetic(
+            name, toFinalType(parameterType), parameterKind));
+      }
+      return FunctionTypeImpl(
+        typeFormals: type.typeFormals,
+        parameters: parameters,
+        returnType: toFinalType(decoratedType.returnType),
+        nullabilitySuffix: nullabilitySuffix,
+      );
+    } else if (type is InterfaceType) {
+      return InterfaceTypeImpl(
+        element: type.element,
+        typeArguments: [
+          for (var arg in decoratedType.typeArguments) toFinalType(arg)
+        ],
+        nullabilitySuffix: nullabilitySuffix,
+      );
+    } else if (type is TypeParameterType) {
+      return TypeParameterTypeImpl(type.element,
+          nullabilitySuffix: nullabilitySuffix);
+    } else {
+      // The above cases should cover all possible types.  On the off chance
+      // they don't, fall back on returning DecoratedType.type.
+      assert(false, 'Unexpected type (${type.runtimeType})');
+      return type;
+    }
+  }
+
   /// Queries whether, prior to migration, an unnecessary cast existed at
   /// [node].
   bool wasUnnecessaryCast(Source source, AsExpression node) =>
@@ -245,11 +313,11 @@
     }
 
     if (element is FunctionTypedElement) {
-      decoratedType =
-          _alreadyMigratedCodeDecorator.decorate(element.type, element);
+      decoratedType = _alreadyMigratedCodeDecorator.decorate(
+          element.preMigrationType, element);
     } else if (element is VariableElement) {
-      decoratedType =
-          _alreadyMigratedCodeDecorator.decorate(element.type, element);
+      decoratedType = _alreadyMigratedCodeDecorator.decorate(
+          element.preMigrationType, element);
     } else {
       // TODO(paulberry)
       throw UnimplementedError('Decorating ${element.runtimeType}');
@@ -341,3 +409,39 @@
     return end * (end + 1) ~/ 2 + offset;
   }
 }
+
+extension on TypeParameterElement {
+  DartType get preMigrationBound {
+    var previousElementTypeProvider = ElementTypeProvider.current;
+    try {
+      ElementTypeProvider.current = const ElementTypeProvider();
+      return bound;
+    } finally {
+      ElementTypeProvider.current = previousElementTypeProvider;
+    }
+  }
+}
+
+extension on FunctionTypedElement {
+  FunctionType get preMigrationType {
+    var previousElementTypeProvider = ElementTypeProvider.current;
+    try {
+      ElementTypeProvider.current = const ElementTypeProvider();
+      return type;
+    } finally {
+      ElementTypeProvider.current = previousElementTypeProvider;
+    }
+  }
+}
+
+extension on VariableElement {
+  DartType get preMigrationType {
+    var previousElementTypeProvider = ElementTypeProvider.current;
+    try {
+      ElementTypeProvider.current = const ElementTypeProvider();
+      return type;
+    } finally {
+      ElementTypeProvider.current = previousElementTypeProvider;
+    }
+  }
+}
diff --git a/pkg/nnbd_migration/test/already_migrated_code_decorator_test.dart b/pkg/nnbd_migration/test/already_migrated_code_decorator_test.dart
index e5a9edc..1b7673d 100644
--- a/pkg/nnbd_migration/test/already_migrated_code_decorator_test.dart
+++ b/pkg/nnbd_migration/test/already_migrated_code_decorator_test.dart
@@ -38,6 +38,8 @@
 
   Element element = _MockElement();
 
+  final decoratedTypeParameterBounds = DecoratedTypeParameterBounds();
+
   _AlreadyMigratedCodeDecoratorTestBase(NullabilitySuffix nullabilitySuffix)
       : this._(
           nullabilitySuffix,
@@ -138,12 +140,23 @@
     return decoratedType;
   }
 
+  DecoratedType getDecoratedBound(TypeParameterElement element) =>
+      decoratedTypeParameterBounds.get(element);
+
+  void setUp() {
+    DecoratedTypeParameterBounds.current = decoratedTypeParameterBounds;
+  }
+
+  void tearDown() {
+    DecoratedTypeParameterBounds.current = null;
+  }
+
   void test_decorate_dynamic() {
     checkDynamic(decorate(typeProvider.dynamicType));
   }
 
   void test_decorate_functionType_generic_bounded() {
-    var typeFormal = TypeParameterElementImpl.synthetic('T')
+    var typeFormal = element = TypeParameterElementImpl.synthetic('T')
       ..bound = typeProvider.numType;
     var decoratedType = decorate(
       FunctionTypeImpl(
@@ -153,14 +166,13 @@
         nullabilitySuffix: suffix,
       ),
     );
-    expect(decoratedType.typeFormalBounds, hasLength(1));
-    checkNum(decoratedType.typeFormalBounds[0], checkExplicitlyNonNullable);
+    checkNum(getDecoratedBound(typeFormal), checkExplicitlyNonNullable);
     checkTypeParameter(
         decoratedType.returnType, checkExplicitlyNonNullable, typeFormal);
   }
 
   void test_decorate_functionType_generic_no_explicit_bound() {
-    var typeFormal = TypeParameterElementImpl.synthetic('T');
+    var typeFormal = element = TypeParameterElementImpl.synthetic('T');
     var decoratedType = decorate(
       FunctionTypeImpl(
         typeFormals: [typeFormal],
@@ -169,8 +181,7 @@
         nullabilitySuffix: suffix,
       ),
     );
-    expect(decoratedType.typeFormalBounds, hasLength(1));
-    checkObject(decoratedType.typeFormalBounds[0], checkExplicitlyNullable);
+    checkObject(getDecoratedBound(typeFormal), checkExplicitlyNullable);
     checkTypeParameter(
         decoratedType.returnType, checkExplicitlyNonNullable, typeFormal);
   }
diff --git a/pkg/nnbd_migration/test/api_test.dart b/pkg/nnbd_migration/test/api_test.dart
index e20e529..c2386bb 100644
--- a/pkg/nnbd_migration/test/api_test.dart
+++ b/pkg/nnbd_migration/test/api_test.dart
@@ -187,6 +187,30 @@
     await _checkSingleFileChanges(content, expected);
   }
 
+  Future<void> test_call_generic_function_returns_generic_class() async {
+    var content = '''
+class B<E> implements List<E/*?*/> {
+  final C c;
+  B(this.c);
+  B<T> cast<T>() => c._castFrom<E, T>(this);
+}
+abstract class C {
+  B<T> _castFrom<S, T>(B<S> source);
+}
+''';
+    var expected = '''
+class B<E> implements List<E?/*?*/> {
+  final C c;
+  B(this.c);
+  B<T> cast<T>() => c._castFrom<E, T>(this);
+}
+abstract class C {
+  B<T> _castFrom<S, T>(B<S> source);
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
   Future<void> test_catch_simple() async {
     var content = '''
 void f() {
@@ -1094,6 +1118,37 @@
     await _checkSingleFileChanges(content, expected, removeViaComments: true);
   }
 
+  Future<void> test_do_not_propagate_non_null_intent_into_callback() async {
+    var content = '''
+void f(int/*!*/ Function(int) callback) {
+  callback(null);
+}
+int g(int x) => x;
+void test() {
+  f(g);
+}
+''';
+    // Even though `g` is passed to `f`'s `callback` parameter, non-null intent
+    // is not allowed to propagate backward from the return type of `callback`
+    // to the return type of `g`, because `g` might be used elsewhere in a
+    // context where it's important for its return type to be nullable.  So no
+    // null check is added to `g`, and instead a cast (which is guaranteed to
+    // fail) is added at the site of the call to `f`.
+    //
+    // Note: https://github.com/dart-lang/sdk/issues/40471 tracks the fact that
+    // we ought to alert the user to the presence of such casts.
+    var expected = '''
+void f(int/*!*/ Function(int?) callback) {
+  callback(null);
+}
+int? g(int? x) => x;
+void test() {
+  f(g as int Function(int?));
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
   Future<void> test_downcast_dynamic_function_to_functionType() async {
     var content = '''
 void f(Function a) {
@@ -3308,6 +3363,24 @@
     await _checkSingleFileChanges(content, expected);
   }
 
+  Future<void> test_null_check_type_parameter_type_with_nullable_bound() async {
+    var content = '''
+abstract class C<E, T extends Iterable<E>/*?*/> {
+  void f(T iter) {
+    for(var i in iter) {}
+  }
+}
+''';
+    var expected = '''
+abstract class C<E, T extends Iterable<E>?/*?*/> {
+  void f(T iter) {
+    for(var i in iter!) {}
+  }
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
   Future<void> test_null_in_conditional_expression() async {
     var content = '''
 void f() {
@@ -3652,6 +3725,49 @@
     await _checkSingleFileChanges(content, expected);
   }
 
+  Future<void> test_promotion_preserves_complex_types() async {
+    var content = '''
+int/*!*/ f(List<int/*?*/>/*?*/ x) {
+  x ??= [0];
+  return x[0];
+}
+''';
+    // `x ??= [0]` promotes x from List<int?>? to List<int?>.  Since there is
+    // still a `?` on the `int`, `x[0]` must be null checked.
+    var expected = '''
+int/*!*/ f(List<int?/*?*/>?/*?*/ x) {
+  x ??= [0];
+  return x[0]!;
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  Future<void> test_propagate_non_null_intent_into_function_literal() async {
+    var content = '''
+void f(int/*!*/ Function(int) callback) {
+  callback(null);
+}
+void test() {
+  f((int x) => x);
+}
+''';
+    // Since the function literal `(int x) => x` is created right here at the
+    // point where it's passed to `f`'s `callback` parameter, non-null intent is
+    // allowed to propagate backward from the return type of `callback` to the
+    // return type of the function literal.  As a result, the reference to `x`
+    // in the function literal is null checked.
+    var expected = '''
+void f(int/*!*/ Function(int?) callback) {
+  callback(null);
+}
+void test() {
+  f((int? x) => x!);
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
   Future<void> test_redirecting_constructor_factory() async {
     var content = '''
 class C {
diff --git a/pkg/nnbd_migration/test/decorated_class_hierarchy_test.dart b/pkg/nnbd_migration/test/decorated_class_hierarchy_test.dart
index 109199f..f3fdf5e 100644
--- a/pkg/nnbd_migration/test/decorated_class_hierarchy_test.dart
+++ b/pkg/nnbd_migration/test/decorated_class_hierarchy_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/type.dart';
 import 'package:nnbd_migration/src/decorated_class_hierarchy.dart';
 import 'package:nnbd_migration/src/nullability_node.dart';
 import 'package:test/test.dart';
@@ -36,7 +37,7 @@
     var decoratedType = decoratedTypeAnnotation('Derived<int>');
     var asInstanceOfBase =
         _hierarchy.asInstanceOf(decoratedType, findElement.class_('Base'));
-    expect(asInstanceOfBase.type.toString(), 'Base<List<int>>');
+    _assertType(asInstanceOfBase.type, 'Base<List<int>>');
     expect(asInstanceOfBase.node, same(decoratedType.node));
     var listOfUType = decoratedTypeAnnotation('List<U>');
     expect(asInstanceOfBase.typeArguments[0].node, same(listOfUType.node));
@@ -59,23 +60,23 @@
     var mapRef = decoratedTypeAnnotation('Map');
     var intRef = decoratedTypeAnnotation('int');
     var vRef = decoratedTypeAnnotation('V>>');
-    expect(decoratedSupertype.type.toString(), 'Base<List<Map<int, V>>>');
+    _assertType(decoratedSupertype.type, 'Base<List<Map<int, V>>>');
     expect(decoratedSupertype.node, same(never));
     var baseArgs = decoratedSupertype.typeArguments;
     expect(baseArgs, hasLength(1));
-    expect(baseArgs[0].type.toString(), 'List<Map<int, V>>');
+    _assertType(baseArgs[0].type, 'List<Map<int, V>>');
     expect(baseArgs[0].node, same(listRef.node));
     var listArgs = baseArgs[0].typeArguments;
     expect(listArgs, hasLength(1));
-    expect(listArgs[0].type.toString(), 'Map<int, V>');
+    _assertType(listArgs[0].type, 'Map<int, V>');
     var mapNode = listArgs[0].node as NullabilityNodeForSubstitution;
     expect(mapNode.innerNode, same(mapRef.node));
     expect(mapNode.outerNode, same(uRef.node));
     var mapArgs = listArgs[0].typeArguments;
     expect(mapArgs, hasLength(2));
-    expect(mapArgs[0].type.toString(), 'int');
+    _assertType(mapArgs[0].type, 'int');
     expect(mapArgs[0].node, same(intRef.node));
-    expect(mapArgs[1].type.toString(), 'V');
+    _assertType(mapArgs[1].type, 'V');
     expect(mapArgs[1].node, same(vRef.node));
   }
 
@@ -88,12 +89,12 @@
         findElement.class_('Derived'), findElement.class_('Base'));
     var vRef = decoratedTypeAnnotation('V, W> {');
     var wRef = decoratedTypeAnnotation('W> {');
-    expect(decoratedSupertype.type.toString(), 'Base<V, W>');
+    _assertType(decoratedSupertype.type, 'Base<V, W>');
     expect(decoratedSupertype.node, same(never));
     expect(decoratedSupertype.typeArguments, hasLength(2));
-    expect(decoratedSupertype.typeArguments[0].type.toString(), 'V');
+    _assertType(decoratedSupertype.typeArguments[0].type, 'V');
     expect(decoratedSupertype.typeArguments[0].node, same(vRef.node));
-    expect(decoratedSupertype.typeArguments[1].type.toString(), 'W');
+    _assertType(decoratedSupertype.typeArguments[1].type, 'W');
     expect(decoratedSupertype.typeArguments[1].node, same(wRef.node));
   }
 
@@ -106,12 +107,12 @@
         findElement.class_('Derived'), findElement.class_('Base'));
     var vRef = decoratedTypeAnnotation('V, W> {');
     var wRef = decoratedTypeAnnotation('W> {');
-    expect(decoratedSupertype.type.toString(), 'Base<V, W>');
+    _assertType(decoratedSupertype.type, 'Base<V, W>');
     expect(decoratedSupertype.node, same(never));
     expect(decoratedSupertype.typeArguments, hasLength(2));
-    expect(decoratedSupertype.typeArguments[0].type.toString(), 'V');
+    _assertType(decoratedSupertype.typeArguments[0].type, 'V');
     expect(decoratedSupertype.typeArguments[0].node, same(vRef.node));
-    expect(decoratedSupertype.typeArguments[1].type.toString(), 'W');
+    _assertType(decoratedSupertype.typeArguments[1].type, 'W');
     expect(decoratedSupertype.typeArguments[1].node, same(wRef.node));
   }
 
@@ -122,7 +123,7 @@
 ''');
     var decoratedSupertype = _hierarchy.getDecoratedSupertype(
         findElement.class_('Derived'), findElement.class_('Base'));
-    expect(decoratedSupertype.type.toString(), 'Base');
+    _assertType(decoratedSupertype.type, 'Base');
     expect(decoratedSupertype.node, same(never));
     expect(decoratedSupertype.typeArguments, isEmpty);
   }
@@ -136,12 +137,12 @@
         findElement.mixin('Derived'), findElement.class_('Base'));
     var vRef = decoratedTypeAnnotation('V, W> {');
     var wRef = decoratedTypeAnnotation('W> {');
-    expect(decoratedSupertype.type.toString(), 'Base<V, W>');
+    _assertType(decoratedSupertype.type, 'Base<V, W>');
     expect(decoratedSupertype.node, same(never));
     expect(decoratedSupertype.typeArguments, hasLength(2));
-    expect(decoratedSupertype.typeArguments[0].type.toString(), 'V');
+    _assertType(decoratedSupertype.typeArguments[0].type, 'V');
     expect(decoratedSupertype.typeArguments[0].node, same(vRef.node));
-    expect(decoratedSupertype.typeArguments[1].type.toString(), 'W');
+    _assertType(decoratedSupertype.typeArguments[1].type, 'W');
     expect(decoratedSupertype.typeArguments[1].node, same(wRef.node));
   }
 
@@ -165,12 +166,17 @@
         findElement.class_('Derived'), findElement.class_('Base'));
     var vRef = decoratedTypeAnnotation('V, W> {');
     var wRef = decoratedTypeAnnotation('W> {');
-    expect(decoratedSupertype.type.toString(), 'Base<V, W>');
+    _assertType(decoratedSupertype.type, 'Base<V, W>');
     expect(decoratedSupertype.node, same(never));
     expect(decoratedSupertype.typeArguments, hasLength(2));
-    expect(decoratedSupertype.typeArguments[0].type.toString(), 'V');
+    _assertType(decoratedSupertype.typeArguments[0].type, 'V');
     expect(decoratedSupertype.typeArguments[0].node, same(vRef.node));
-    expect(decoratedSupertype.typeArguments[1].type.toString(), 'W');
+    _assertType(decoratedSupertype.typeArguments[1].type, 'W');
     expect(decoratedSupertype.typeArguments[1].node, same(wRef.node));
   }
+
+  void _assertType(DartType type, String expected) {
+    var typeStr = type.getDisplayString(withNullability: false);
+    expect(typeStr, expected);
+  }
 }
diff --git a/pkg/nnbd_migration/test/decorated_type_test.dart b/pkg/nnbd_migration/test/decorated_type_test.dart
index 3a6a0e8..6c4e507 100644
--- a/pkg/nnbd_migration/test/decorated_type_test.dart
+++ b/pkg/nnbd_migration/test/decorated_type_test.dart
@@ -6,9 +6,11 @@
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/dart/element/type_provider.dart';
 import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/generated/element_type_provider.dart';
 import 'package:analyzer/src/generated/testing/test_type_provider.dart';
 import 'package:nnbd_migration/src/decorated_type.dart';
 import 'package:nnbd_migration/src/nullability_node.dart';
+import 'package:nnbd_migration/src/variables.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -24,32 +26,49 @@
 class DecoratedTypeTest extends Object
     with DecoratedTypeTester
     implements DecoratedTypeTesterBase {
-  final graph = NullabilityGraph();
+  final NullabilityGraph graph;
 
   final TypeProvider typeProvider;
 
+  final Variables _variables;
+
+  final _ElementTypeProvider elementTypeProvider;
+
+  @override
+  final decoratedTypeParameterBounds = DecoratedTypeParameterBounds();
+
   factory DecoratedTypeTest() {
     var typeProvider = TestTypeProvider();
-    return DecoratedTypeTest._(typeProvider);
+    var graph = NullabilityGraph();
+    var variables = Variables(graph, typeProvider);
+    return DecoratedTypeTest._(graph, typeProvider, variables);
   }
 
-  DecoratedTypeTest._(this.typeProvider);
+  DecoratedTypeTest._(this.graph, this.typeProvider, this._variables)
+      : elementTypeProvider = _ElementTypeProvider(_variables);
 
   NullabilityNode get always => graph.always;
 
   ClassElement get listElement => typeProvider.listElement;
 
   void assertDartType(DartType type, String expected) {
-    // Note: by default DartType.toString doesn't print nullability suffixes,
-    // so we have to override that behavior in order to make sure the
+    // Note: by default DartType.getDisplayString doesn't print nullability
+    // suffixes, so we have to override that behavior in order to make sure the
     // nullability suffixes are correct.
     expect(type.getDisplayString(withNullability: true), expected);
   }
 
   void setUp() {
+    DecoratedTypeParameterBounds.current = decoratedTypeParameterBounds;
+    ElementTypeProvider.current = elementTypeProvider;
     NullabilityNode.clearDebugNames();
   }
 
+  void tearDown() {
+    DecoratedTypeParameterBounds.current = null;
+    ElementTypeProvider.current = const ElementTypeProvider();
+  }
+
   void test_equal_dynamic_and_void() {
     expect(dynamic_ == dynamic_, isTrue);
     expect(dynamic_ == void_, isFalse);
@@ -302,43 +321,48 @@
 
   void test_toFinalType_bottom_non_nullable() {
     var type =
-        DecoratedType(NeverTypeImpl.instance, never).toFinalType(typeProvider);
+        _variables.toFinalType(DecoratedType(NeverTypeImpl.instance, never));
     assertDartType(type, 'Never');
   }
 
   void test_toFinalType_bottom_nullable() {
     var type =
-        DecoratedType(NeverTypeImpl.instance, always).toFinalType(typeProvider);
+        _variables.toFinalType(DecoratedType(NeverTypeImpl.instance, always));
     assertDartType(type, 'Null');
   }
 
   void test_toFinalType_dynamic() {
-    var type = dynamic_.toFinalType(typeProvider);
+    var type = _variables.toFinalType(dynamic_);
     assertDartType(type, 'dynamic');
   }
 
   void test_toFinalType_function_generic_bound_dynamic() {
     var t = typeParameter('T', dynamic_);
-    var type = function(dynamic_, typeFormals: [t], node: never)
-        .toFinalType(typeProvider) as FunctionType;
-    assertDartType(type, 'dynamic Function<T>()');
-    expect(type.typeFormals[0].bound, isNull);
+    var type = _variables.toFinalType(
+        function(dynamic_, typeFormals: [t], node: never)) as FunctionType;
+    assertDartType(type, 'dynamic Function<T extends dynamic>()');
+    assertDartType(
+        elementTypeProvider.getTypeParameterBound(type.typeFormals[0]),
+        'dynamic');
   }
 
   void test_toFinalType_function_generic_bound_num_question() {
     var t = typeParameter('T', num_(node: always));
-    var type = function(dynamic_, typeFormals: [t], node: never)
-        .toFinalType(typeProvider) as FunctionType;
+    var type = _variables.toFinalType(
+        function(dynamic_, typeFormals: [t], node: never)) as FunctionType;
     assertDartType(type, 'dynamic Function<T extends num?>()');
-    assertDartType(type.typeFormals[0].bound, 'num?');
+    assertDartType(
+        elementTypeProvider.getTypeParameterBound(type.typeFormals[0]), 'num?');
   }
 
   void test_toFinalType_function_generic_bound_object_question() {
     var t = typeParameter('T', object(node: always));
-    var type = function(dynamic_, typeFormals: [t], node: never)
-        .toFinalType(typeProvider) as FunctionType;
-    assertDartType(type, 'dynamic Function<T>()');
-    expect(type.typeFormals[0].bound, isNull);
+    var type = _variables.toFinalType(
+        function(dynamic_, typeFormals: [t], node: never)) as FunctionType;
+    assertDartType(type, 'dynamic Function<T extends Object?>()');
+    assertDartType(
+        elementTypeProvider.getTypeParameterBound(type.typeFormals[0]),
+        'Object?');
   }
 
   void test_toFinalType_function_generic_substitute_bounds() {
@@ -347,15 +371,16 @@
         'T', list(typeParameterType(u, node: never), node: never));
     var v = typeParameter(
         'V', list(typeParameterType(u, node: never), node: never));
-    var type = function(dynamic_, typeFormals: [t, u, v], node: never)
-        .toFinalType(typeProvider) as FunctionType;
+    var type = _variables.toFinalType(
+            function(dynamic_, typeFormals: [t, u, v], node: never))
+        as FunctionType;
     assertDartType(
         type,
         'dynamic Function<T extends List<U>, U extends Object, '
         'V extends List<U>>()');
-    expect(type.typeFormals[0], isNot(same(t)));
-    expect(type.typeFormals[1], isNot(same(u)));
-    expect(type.typeFormals[2], isNot(same(v)));
+    expect(type.typeFormals[0], same(t));
+    expect(type.typeFormals[1], same(u));
+    expect(type.typeFormals[2], same(v));
     expect(
         ((type.typeFormals[0].bound as InterfaceType).typeArguments[0]
                 as TypeParameterType)
@@ -370,13 +395,12 @@
 
   void test_toFinalType_function_generic_substitute_named() {
     var t = typeParameter('T', object(node: never));
-    var type = function(dynamic_,
-            typeFormals: [t],
-            named: {'x': list(typeParameterType(t, node: never), node: never)},
-            node: never)
-        .toFinalType(typeProvider) as FunctionType;
+    var type = _variables.toFinalType(function(dynamic_,
+        typeFormals: [t],
+        named: {'x': list(typeParameterType(t, node: never), node: never)},
+        node: never)) as FunctionType;
     assertDartType(type, 'dynamic Function<T extends Object>({List<T> x})');
-    expect(type.typeFormals[0], isNot(same(t)));
+    expect(type.typeFormals[0], same(t));
     expect(
         ((type.parameters[0].type as InterfaceType).typeArguments[0]
                 as TypeParameterType)
@@ -386,13 +410,12 @@
 
   void test_toFinalType_function_generic_substitute_optional() {
     var t = typeParameter('T', object(node: never));
-    var type = function(dynamic_,
-            typeFormals: [t],
-            positional: [list(typeParameterType(t, node: never), node: never)],
-            node: never)
-        .toFinalType(typeProvider) as FunctionType;
+    var type = _variables.toFinalType(function(dynamic_,
+        typeFormals: [t],
+        positional: [list(typeParameterType(t, node: never), node: never)],
+        node: never)) as FunctionType;
     assertDartType(type, 'dynamic Function<T extends Object>([List<T>])');
-    expect(type.typeFormals[0], isNot(same(t)));
+    expect(type.typeFormals[0], same(t));
     expect(
         ((type.parameters[0].type as InterfaceType).typeArguments[0]
                 as TypeParameterType)
@@ -402,13 +425,12 @@
 
   void test_toFinalType_function_generic_substitute_required() {
     var t = typeParameter('T', object());
-    var type = function(dynamic_,
-            typeFormals: [t],
-            required: [list(typeParameterType(t, node: never), node: never)],
-            node: never)
-        .toFinalType(typeProvider) as FunctionType;
+    var type = _variables.toFinalType(function(dynamic_,
+        typeFormals: [t],
+        required: [list(typeParameterType(t, node: never), node: never)],
+        node: never)) as FunctionType;
     assertDartType(type, 'dynamic Function<T extends Object>(List<T>)');
-    expect(type.typeFormals[0], isNot(same(t)));
+    expect(type.typeFormals[0], same(t));
     expect(
         ((type.parameters[0].type as InterfaceType).typeArguments[0]
                 as TypeParameterType)
@@ -418,11 +440,12 @@
 
   void test_toFinalType_function_generic_substitute_return_type() {
     var t = typeParameter('T', object(node: never));
-    var type = function(list(typeParameterType(t, node: never), node: never),
-            typeFormals: [t], node: never)
-        .toFinalType(typeProvider) as FunctionType;
+    var type = _variables.toFinalType(function(
+        list(typeParameterType(t, node: never), node: never),
+        typeFormals: [t],
+        node: never)) as FunctionType;
     assertDartType(type, 'List<T> Function<T extends Object>()');
-    expect(type.typeFormals[0], isNot(same(t)));
+    expect(type.typeFormals[0], same(t));
     expect(
         ((type.returnType as InterfaceType).typeArguments[0]
                 as TypeParameterType)
@@ -432,116 +455,116 @@
 
   void test_toFinalType_function_named_parameter_non_nullable() {
     var xType = int_(node: never);
-    var type = function(dynamic_, named: {'x': xType}, node: never)
-        .toFinalType(typeProvider);
+    var type = _variables
+        .toFinalType(function(dynamic_, named: {'x': xType}, node: never));
     assertDartType(type, 'dynamic Function({int x})');
   }
 
   void test_toFinalType_function_named_parameter_nullable() {
     var xType = int_(node: always);
-    var type = function(dynamic_, named: {'x': xType}, node: never)
-        .toFinalType(typeProvider);
+    var type = _variables
+        .toFinalType(function(dynamic_, named: {'x': xType}, node: never));
     assertDartType(type, 'dynamic Function({int? x})');
   }
 
   void test_toFinalType_function_non_nullable() {
-    var type = function(dynamic_, node: never).toFinalType(typeProvider);
+    var type = _variables.toFinalType(function(dynamic_, node: never));
     assertDartType(type, 'dynamic Function()');
   }
 
   void test_toFinalType_function_nullable() {
-    var type = function(dynamic_, node: always).toFinalType(typeProvider);
+    var type = _variables.toFinalType(function(dynamic_, node: always));
     assertDartType(type, 'dynamic Function()?');
   }
 
   void test_toFinalType_function_optional_parameter_non_nullable() {
     var argType = int_(node: never);
-    var type = function(dynamic_, positional: [argType], node: never)
-        .toFinalType(typeProvider);
+    var type = _variables
+        .toFinalType(function(dynamic_, positional: [argType], node: never));
     assertDartType(type, 'dynamic Function([int])');
   }
 
   void test_toFinalType_function_optional_parameter_nullable() {
     var argType = int_(node: always);
-    var type = function(dynamic_, positional: [argType], node: never)
-        .toFinalType(typeProvider);
+    var type = _variables
+        .toFinalType(function(dynamic_, positional: [argType], node: never));
     assertDartType(type, 'dynamic Function([int?])');
   }
 
   void test_toFinalType_function_required_parameter_non_nullable() {
     var argType = int_(node: never);
-    var type = function(dynamic_, required: [argType], node: never)
-        .toFinalType(typeProvider);
+    var type = _variables
+        .toFinalType(function(dynamic_, required: [argType], node: never));
     assertDartType(type, 'dynamic Function(int)');
   }
 
   void test_toFinalType_function_required_parameter_nullable() {
     var argType = int_(node: always);
-    var type = function(dynamic_, required: [argType], node: never)
-        .toFinalType(typeProvider);
+    var type = _variables
+        .toFinalType(function(dynamic_, required: [argType], node: never));
     assertDartType(type, 'dynamic Function(int?)');
   }
 
   void test_toFinalType_function_return_type_non_nullable() {
     var returnType = int_(node: never);
-    var type = function(returnType, node: never).toFinalType(typeProvider);
+    var type = _variables.toFinalType(function(returnType, node: never));
     assertDartType(type, 'int Function()');
   }
 
   void test_toFinalType_function_return_type_nullable() {
     var returnType = int_(node: always);
-    var type = function(returnType, node: never).toFinalType(typeProvider);
+    var type = _variables.toFinalType(function(returnType, node: never));
     assertDartType(type, 'int? Function()');
   }
 
   void test_toFinalType_interface_non_nullable() {
-    var type = int_(node: never).toFinalType(typeProvider);
+    var type = _variables.toFinalType(int_(node: never));
     assertDartType(type, 'int');
   }
 
   void test_toFinalType_interface_nullable() {
-    var type = int_(node: always).toFinalType(typeProvider);
+    var type = _variables.toFinalType(int_(node: always));
     assertDartType(type, 'int?');
   }
 
   void test_toFinalType_interface_type_argument_non_nullable() {
     var argType = int_(node: never);
-    var type = list(argType, node: never).toFinalType(typeProvider);
+    var type = _variables.toFinalType(list(argType, node: never));
     assertDartType(type, 'List<int>');
   }
 
   void test_toFinalType_interface_type_argument_nullable() {
     var argType = int_(node: always);
-    var type = list(argType, node: never).toFinalType(typeProvider);
+    var type = _variables.toFinalType(list(argType, node: never));
     assertDartType(type, 'List<int?>');
   }
 
   void test_toFinalType_null_non_nullable() {
-    var type = DecoratedType(null_.type, never).toFinalType(typeProvider);
+    var type = _variables.toFinalType(DecoratedType(null_.type, never));
     assertDartType(type, 'Never');
   }
 
   void test_toFinalType_null_nullable() {
-    var type = DecoratedType(null_.type, always).toFinalType(typeProvider);
+    var type = _variables.toFinalType(DecoratedType(null_.type, always));
     assertDartType(type, 'Null');
   }
 
   void test_toFinalType_typeParameter_non_nullable() {
     var t = typeParameter('T', object(node: never));
-    var type = typeParameterType(t, node: never).toFinalType(typeProvider);
+    var type = _variables.toFinalType(typeParameterType(t, node: never));
     expect(type, TypeMatcher<TypeParameterType>());
     assertDartType(type, 'T');
   }
 
   void test_toFinalType_typeParameter_nullable() {
     var t = typeParameter('T', object(node: never));
-    var type = typeParameterType(t, node: always).toFinalType(typeProvider);
+    var type = _variables.toFinalType(typeParameterType(t, node: always));
     expect(type, TypeMatcher<TypeParameterType>());
     assertDartType(type, 'T?');
   }
 
   void test_toFinalType_void() {
-    var type = void_.toFinalType(typeProvider);
+    var type = _variables.toFinalType(void_);
     assertDartType(type, 'void');
   }
 
@@ -591,3 +614,22 @@
     expect(decoratedType.toString(), 'dynamic Function([$xType])?');
   }
 }
+
+class _ElementTypeProvider extends ElementTypeProvider {
+  final Variables variables;
+
+  _ElementTypeProvider(this.variables);
+
+  void freshTypeParameterCreated(TypeParameterElement newTypeParameter,
+      TypeParameterElement oldTypeParameter) {
+    DecoratedTypeParameterBounds.current.put(newTypeParameter,
+        DecoratedTypeParameterBounds.current.get(oldTypeParameter));
+  }
+
+  DartType getTypeParameterBound(TypeParameterElement element) {
+    var decoratedType = variables.decoratedTypeParameterBound(element,
+        allowNullUnparentedBounds: true);
+    if (decoratedType == null) return element.bound;
+    return variables.toFinalType(decoratedType);
+  }
+}
diff --git a/pkg/nnbd_migration/test/edge_builder_test.dart b/pkg/nnbd_migration/test/edge_builder_test.dart
index 885513f..f4c9b90 100644
--- a/pkg/nnbd_migration/test/edge_builder_test.dart
+++ b/pkg/nnbd_migration/test/edge_builder_test.dart
@@ -44,6 +44,9 @@
   @override
   final NullabilityGraphForTesting graph;
 
+  @override
+  final decoratedTypeParameterBounds = DecoratedTypeParameterBounds();
+
   final AssignmentCheckerForTesting checker;
 
   factory AssignmentCheckerTest() {
@@ -181,7 +184,8 @@
     var t1 = function(object());
     var t2 = function(object());
     assign(t1, t2, hard: true);
-    assertEdge(t1.returnType.node, t2.returnType.node, hard: false);
+    assertEdge(t1.returnType.node, t2.returnType.node,
+        hard: false, checkable: false);
   }
 
   void test_function_void_to_function_object() {
@@ -190,7 +194,8 @@
     var t1 = function(void_);
     var t2 = function(object());
     assign(t1, t2, hard: true);
-    assertEdge(t1.returnType.node, t2.returnType.node, hard: false);
+    assertEdge(t1.returnType.node, t2.returnType.node,
+        hard: false, checkable: false);
   }
 
   void test_future_int_to_future_or_int() {
@@ -2509,16 +2514,16 @@
 ''');
     var constructor = findElement.unnamedConstructor('C');
     var constructorDecoratedType = variables.decoratedElementType(constructor);
-    expect(constructorDecoratedType.type.toString(), 'C<T, U> Function()');
+    _assertType(constructorDecoratedType.type, 'C<T, U> Function()');
     expect(constructorDecoratedType.node, same(never));
     expect(constructorDecoratedType.typeFormals, isEmpty);
     expect(constructorDecoratedType.returnType.node, same(never));
-    expect(constructorDecoratedType.returnType.type.toString(), 'C<T, U>');
+    _assertType(constructorDecoratedType.returnType.type, 'C<T, U>');
     var typeArguments = constructorDecoratedType.returnType.typeArguments;
     expect(typeArguments, hasLength(2));
-    expect(typeArguments[0].type.toString(), 'T');
+    _assertType(typeArguments[0].type, 'T');
     expect(typeArguments[0].node, same(never));
-    expect(typeArguments[1].type.toString(), 'U');
+    _assertType(typeArguments[1].type, 'U');
     expect(typeArguments[1].node, same(never));
   }
 
@@ -2528,16 +2533,16 @@
 ''');
     var constructor = findElement.unnamedConstructor('C');
     var constructorDecoratedType = variables.decoratedElementType(constructor);
-    expect(constructorDecoratedType.type.toString(), 'C<T, U> Function()');
+    _assertType(constructorDecoratedType.type, 'C<T, U> Function()');
     expect(constructorDecoratedType.node, same(never));
     expect(constructorDecoratedType.typeFormals, isEmpty);
     expect(constructorDecoratedType.returnType.node, same(never));
-    expect(constructorDecoratedType.returnType.type.toString(), 'C<T, U>');
+    _assertType(constructorDecoratedType.returnType.type, 'C<T, U>');
     var typeArguments = constructorDecoratedType.returnType.typeArguments;
     expect(typeArguments, hasLength(2));
-    expect(typeArguments[0].type.toString(), 'T');
+    _assertType(typeArguments[0].type, 'T');
     expect(typeArguments[0].node, same(never));
-    expect(typeArguments[1].type.toString(), 'U');
+    _assertType(typeArguments[1].type, 'U');
     expect(typeArguments[1].node, same(never));
   }
 
@@ -2549,7 +2554,7 @@
 ''');
     var constructorDecoratedType =
         variables.decoratedElementType(findElement.unnamedConstructor('C'));
-    expect(constructorDecoratedType.type.toString(), 'C Function()');
+    _assertType(constructorDecoratedType.type, 'C Function()');
     expect(constructorDecoratedType.node, same(never));
     expect(constructorDecoratedType.typeFormals, isEmpty);
     expect(constructorDecoratedType.returnType.node, same(never));
@@ -2562,7 +2567,7 @@
 ''');
     var constructorDecoratedType =
         variables.decoratedElementType(findElement.unnamedConstructor('C'));
-    expect(constructorDecoratedType.type.toString(), 'C Function()');
+    _assertType(constructorDecoratedType.type, 'C Function()');
     expect(constructorDecoratedType.node, same(never));
     expect(constructorDecoratedType.typeFormals, isEmpty);
     expect(constructorDecoratedType.returnType.node, same(never));
@@ -2682,7 +2687,7 @@
     var fieldType = variables.decoratedElementType(findElement.field('f'));
     assertEdge(ctorParamType.node, fieldType.node, hard: true);
     assertEdge(ctorParamType.returnType.node, fieldType.returnType.node,
-        hard: false);
+        hard: false, checkable: false);
     assertEdge(fieldType.positionalParameters[0].node,
         ctorParamType.positionalParameters[0].node,
         hard: false, checkable: false);
@@ -5766,7 +5771,8 @@
     var fType = variables.decoratedElementType(findElement.method('f'));
     var gReturnType =
         variables.decoratedElementType(findElement.function('g')).returnType;
-    assertEdge(fType.returnType.node, gReturnType.returnType.node, hard: false);
+    assertEdge(fType.returnType.node, gReturnType.returnType.node,
+        hard: false, checkable: false);
     assertEdge(gReturnType.positionalParameters[0].node,
         fType.positionalParameters[0].node,
         hard: false, checkable: false);
@@ -6191,7 +6197,7 @@
 ''');
     var int1 = decoratedTypeAnnotation('int/*1*/');
     var int2 = decoratedTypeAnnotation('int/*2*/');
-    assertEdge(int2.node, int1.node, hard: false);
+    assertEdge(int2.node, int1.node, hard: false, checkable: false);
   }
 
   Future<void> test_return_implicit_null() async {
@@ -6446,7 +6452,7 @@
 
     assertEdge(decoratedTypeAnnotation('int f').node,
         decoratedTypeAnnotation('int Function').node,
-        hard: false);
+        hard: false, checkable: false);
   }
 
   Future<void> test_simpleIdentifier_local() async {
@@ -6470,7 +6476,8 @@
     var fType = variables.decoratedElementType(findElement.function('f'));
     var gReturnType =
         variables.decoratedElementType(findElement.function('g')).returnType;
-    assertEdge(fType.returnType.node, gReturnType.returnType.node, hard: false);
+    assertEdge(fType.returnType.node, gReturnType.returnType.node,
+        hard: false, checkable: false);
     assertEdge(gReturnType.positionalParameters[0].node,
         fType.positionalParameters[0].node,
         hard: false, checkable: false);
@@ -6486,7 +6493,8 @@
     var fType = variables.decoratedElementType(findElement.method('f'));
     var gReturnType =
         variables.decoratedElementType(findElement.method('g')).returnType;
-    assertEdge(fType.returnType.node, gReturnType.returnType.node, hard: false);
+    assertEdge(fType.returnType.node, gReturnType.returnType.node,
+        hard: false, checkable: false);
     assertEdge(gReturnType.positionalParameters[0].node,
         fType.positionalParameters[0].node,
         hard: false, checkable: false);
@@ -6842,7 +6850,7 @@
         findNode.typeName('Point').name.staticElement as ClassElement;
     var pointBound =
         variables.decoratedTypeParameterBound(pointClass.typeParameters[0]);
-    expect(pointBound.type.toString(), 'num');
+    _assertType(pointBound.type, 'num');
     assertEdge(decoratedTypeAnnotation('int>').node, pointBound.node,
         hard: true);
   }
@@ -6854,7 +6862,7 @@
     var listClass = typeProvider.listElement;
     var listBound =
         variables.decoratedTypeParameterBound(listClass.typeParameters[0]);
-    expect(listBound.type.toString(), 'dynamic');
+    _assertType(listBound.type, 'dynamic');
     assertEdge(decoratedTypeAnnotation('int>').node, listBound.node,
         hard: true);
   }
@@ -6953,6 +6961,11 @@
         decoratedTypeAnnotation('int j').node,
         hard: true);
   }
+
+  void _assertType(DartType type, String expected) {
+    var typeStr = type.getDisplayString(withNullability: false);
+    expect(typeStr, expected);
+  }
 }
 
 class _DecoratedClassHierarchyForTesting implements DecoratedClassHierarchy {
diff --git a/pkg/nnbd_migration/test/edit_plan_test.dart b/pkg/nnbd_migration/test/edit_plan_test.dart
index 401eb4d..d88c4f6 100644
--- a/pkg/nnbd_migration/test/edit_plan_test.dart
+++ b/pkg/nnbd_migration/test/edit_plan_test.dart
@@ -122,6 +122,16 @@
         'var x = (1 == 2) == true;');
   }
 
+  Future<void> test_addBinaryPostfix_to_expression_function() async {
+    await analyze('var x = () => null;');
+    checkPlan(
+        planner.addBinaryPostfix(
+            planner.passThrough(findNode.functionExpression('()')),
+            TokenType.AS,
+            'Object'),
+        'var x = (() => null) as Object;');
+  }
+
   Future<void> test_addBinaryPrefix_allowCascade() async {
     await analyze('f(x) => 1..isEven;');
     checkPlan(
@@ -163,6 +173,14 @@
         'var x = (1 == 2) == true;');
   }
 
+  Future<void> test_addBinaryPrefix_to_expression_function() async {
+    await analyze('f(x) => () => null;');
+    checkPlan(
+        planner.addBinaryPrefix('x', TokenType.EQ,
+            planner.passThrough(findNode.functionExpression('()'))),
+        'f(x) => x = () => null;');
+  }
+
   Future<void> test_addUnaryPostfix_inner_precedence_add_parens() async {
     await analyze('f(x) => -x;');
     checkPlan(
diff --git a/pkg/nnbd_migration/test/fantasyland/fantasy_repo_test.dart b/pkg/nnbd_migration/test/fantasyland/fantasy_repo_test.dart
index 9d64001..e1d1b67 100644
--- a/pkg/nnbd_migration/test/fantasyland/fantasy_repo_test.dart
+++ b/pkg/nnbd_migration/test/fantasyland/fantasy_repo_test.dart
@@ -2,15 +2,19 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:io';
+import 'dart:io' as io;
 
+import 'package:analyzer/file_system/file_system.dart';
 import 'package:mockito/mockito.dart';
 import 'package:nnbd_migration/src/fantasyland/fantasy_repo.dart';
+import 'package:nnbd_migration/src/fantasyland/fantasy_repo_impl.dart';
 import 'package:nnbd_migration/src/utilities/subprocess_launcher.dart';
 import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
+import 'src/filesystem_test_base.dart';
+
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(FantasyRepoSettingsTest);
@@ -64,10 +68,10 @@
 
 @reflectiveTest
 class FantasyRepoE2ETest {
-  Directory tempDir;
+  io.Directory tempDir;
 
   setUp() async {
-    tempDir = await Directory.systemTemp.createTemp('FantasyRepoE2ETest');
+    tempDir = await io.Directory.systemTemp.createTemp('FantasyRepoE2ETest');
   }
 
   test_fantasyRepoE2ETest() async {
@@ -77,17 +81,20 @@
     // TODO(jcollins-g): This test is not fully isolated from the global git
     // config.  Fix that.
     SubprocessLauncher launcher = SubprocessLauncher('FantasyRepoE2ETest');
-    Directory origRepoDir = Directory(path.join(tempDir.path, 'origRepo'));
+    FantasyRepoDependencies fantasyRepoDependencies =
+        FantasyRepoDependencies(launcher: launcher);
+    io.Directory origRepoDir =
+        io.Directory(path.join(tempDir.path, 'origRepo'));
 
     // Create and add a commit to origRepoDir that includes a file we should
     // check out, and others we shouldn't.
     await launcher.runStreamed('git', ['init', origRepoDir.path]);
-    File dotPackages = File(path.join(origRepoDir.path, '.packages'));
-    File pubspecLock = File(path.join(origRepoDir.path, 'pubspec.lock'));
-    File pubspecYaml = File(path.join(origRepoDir.path, 'pubspec.yaml'));
-    File packageConfigJson =
-        File(path.join(origRepoDir.path, '.dart_tool', 'package_config.json'));
-    List<File> allFiles = [
+    io.File dotPackages = io.File(path.join(origRepoDir.path, '.packages'));
+    io.File pubspecLock = io.File(path.join(origRepoDir.path, 'pubspec.lock'));
+    io.File pubspecYaml = io.File(path.join(origRepoDir.path, 'pubspec.yaml'));
+    io.File packageConfigJson = io.File(
+        path.join(origRepoDir.path, '.dart_tool', 'package_config.json'));
+    List<io.File> allFiles = [
       dotPackages,
       pubspecLock,
       pubspecYaml,
@@ -105,16 +112,16 @@
 
     // Use the repo builder to clone this and verify that the right files are
     // checked out.
-    Directory repoRoot = Directory(path.join(tempDir.path, 'repoRoot'));
-    await FantasyRepo.buildFrom(
-        FantasyRepoSettings('repoE2Etest', origRepoDir.path), repoRoot,
-        launcher: launcher);
+    io.Directory repoRoot = io.Directory(path.join(tempDir.path, 'repoRoot'));
+    await FantasyRepo.buildGitRepoFrom(
+        FantasyRepoSettings('repoE2Etest', origRepoDir.path), repoRoot.path,
+        fantasyRepoDependencies: fantasyRepoDependencies);
 
-    dotPackages = File(path.join(repoRoot.path, '.packages'));
-    pubspecLock = File(path.join(repoRoot.path, 'pubspec.lock'));
-    pubspecYaml = File(path.join(repoRoot.path, 'pubspec.yaml'));
+    dotPackages = io.File(path.join(repoRoot.path, '.packages'));
+    pubspecLock = io.File(path.join(repoRoot.path, 'pubspec.lock'));
+    pubspecYaml = io.File(path.join(repoRoot.path, 'pubspec.yaml'));
     packageConfigJson =
-        File(path.join(repoRoot.path, '.dart_tool', 'package_config.json'));
+        io.File(path.join(repoRoot.path, '.dart_tool', 'package_config.json'));
 
     expect(await dotPackages.exists(), isFalse);
     expect(await pubspecLock.exists(), isFalse);
@@ -122,7 +129,8 @@
     expect(await packageConfigJson.exists(), isFalse);
 
     // Update the original repository.
-    File aNewFile = File(path.join(origRepoDir.path, 'hello_new_file_here'));
+    io.File aNewFile =
+        io.File(path.join(origRepoDir.path, 'hello_new_file_here'));
     await aNewFile.create(recursive: true);
     await launcher.runStreamed(
         'git', ['add', '-f', path.canonicalize(aNewFile.path)],
@@ -132,12 +140,11 @@
 
     // Finally, use the repoBuilder to update a repository from head and verify
     // we did it right.
-    await FantasyRepo.buildFrom(
-        FantasyRepoSettings('repoE2Etest', origRepoDir.path), repoRoot,
-        launcher: launcher);
+    await FantasyRepo.buildGitRepoFrom(
+        FantasyRepoSettings('repoE2Etest', origRepoDir.path), repoRoot.path,
+        fantasyRepoDependencies: fantasyRepoDependencies);
 
-    aNewFile = File(path.join(repoRoot.path, 'hello_new_file_here'));
-
+    aNewFile = io.File(path.join(repoRoot.path, 'hello_new_file_here'));
     expect(await dotPackages.exists(), isFalse);
     expect(await pubspecLock.exists(), isFalse);
     expect(await pubspecYaml.exists(), isTrue);
@@ -146,51 +153,27 @@
   }
 }
 
-class MockDirectory extends Mock implements Directory {}
-
-class MockFile extends Mock implements File {}
-
-class MockSubprocessLauncher extends Mock implements SubprocessLauncher {}
-
 @reflectiveTest
-class FantasyRepoTest {
-  // TODO(jcollins-g): extend MemoryResourceProvider and analyzer File
-  // implementations and port over, or add mock_filesystem to third_party.
-  Map<String, MockFile> mockFiles;
-  Map<String, MockDirectory> mockDirectories;
-  MockDirectory Function(String) directoryBuilder;
-  MockFile Function(String) fileBuilder;
-  MockSubprocessLauncher mockLauncher;
+class FantasyRepoTest extends FilesystemTestBase {
   String parentPath;
   String repoPath;
+  Folder repoDir;
+  Folder parentDir;
 
   setUp() {
-    mockFiles = {};
-    mockDirectories = {};
-    fileBuilder = (String s) {
-      mockFiles[s] ??= MockFile();
-      return mockFiles[s];
-    };
-    directoryBuilder = (String s) {
-      mockDirectories[s] ??= MockDirectory();
-      return mockDirectories[s];
-    };
-    mockLauncher = MockSubprocessLauncher();
-    parentPath = 'parentdir';
-    repoPath = path.join(parentPath, 'subdir');
-    MockDirectory repoDir = directoryBuilder(repoPath);
-    MockDirectory parentDir = directoryBuilder('parentdir');
-    when(parentDir.exists()).thenAnswer((_) => Future.value(true));
-    when(repoDir.parent).thenReturn(parentDir);
-    when(repoDir.path).thenReturn(repoPath);
+    super.setUp();
+    parentPath = convertPath('/parentdir');
+    repoPath = join(parentPath, 'subdir');
+    repoDir = resourceProvider.getFolder(repoPath);
+    parentDir = resourceProvider.getFolder(parentPath);
   }
 
   _setUpNewClone(String repoName) async {
     FantasyRepoSettings settings = FantasyRepoSettings.fromName(repoName);
-    when(directoryBuilder(repoPath).exists())
-        .thenAnswer((_) => Future.value(false));
-    await FantasyRepo.buildFrom(settings, mockDirectories[repoPath],
-        launcher: mockLauncher, fileBuilder: fileBuilder);
+    FantasyRepoDependencies fantasyRepoDependencies = FantasyRepoDependencies(
+        launcher: mockLauncher, resourceProvider: resourceProvider);
+    await FantasyRepo.buildGitRepoFrom(settings, repoPath,
+        fantasyRepoDependencies: fantasyRepoDependencies);
   }
 
   test_checkHttpStringSubstitution() async {
diff --git a/pkg/nnbd_migration/test/fantasyland/fantasy_sub_package_test.dart b/pkg/nnbd_migration/test/fantasyland/fantasy_sub_package_test.dart
index 3984c66..7459c32 100644
--- a/pkg/nnbd_migration/test/fantasyland/fantasy_sub_package_test.dart
+++ b/pkg/nnbd_migration/test/fantasyland/fantasy_sub_package_test.dart
@@ -2,14 +2,20 @@
 // 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/file_system/file_system.dart';
 import 'package:nnbd_migration/src/fantasyland/fantasy_repo.dart';
 import 'package:nnbd_migration/src/fantasyland/fantasy_sub_package.dart';
+import 'package:nnbd_migration/src/fantasyland/fantasy_workspace.dart';
+import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
+import 'src/filesystem_test_base.dart';
+
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(FantasySubPackageSettingsTest);
+    defineReflectiveTests(FantasySubPackageTest);
   });
 }
 
@@ -19,7 +25,7 @@
     var subPackageSettings = FantasySubPackageSettings.fromName('vm_service');
     expect(subPackageSettings.name, equals('vm_service'));
     expect(subPackageSettings.repoSettings.name, equals('sdk'));
-    expect(subPackageSettings.subDir, equals('pkg/vm_service'));
+    expect(subPackageSettings.subDir, equals(path.join('pkg', 'vm_service')));
   }
 
   test_settingsFromTableDefault() {
@@ -34,11 +40,12 @@
   test_settingsEqual() {
     var repo1 = FantasyRepoSettings.fromName('some_repo_somewhere');
     var repo2 = FantasyRepoSettings.fromName('another_repo_somewhere_else');
-    var test1 = FantasySubPackageSettings('foo', repo1, '.');
-    var test2 = FantasySubPackageSettings('foo', repo2, '.');
-    var test3 = FantasySubPackageSettings('foo', repo1, 'pkg/something');
-    var test4 = FantasySubPackageSettings('foobie', repo1, '.');
-    var test5 = FantasySubPackageSettings('foo', repo1, '.');
+    var test1 = FantasySubPackageSettings('foo', repo1, subDir: '.');
+    var test2 = FantasySubPackageSettings('foo', repo2, subDir: '.');
+    var test3 = FantasySubPackageSettings('foo', repo1,
+        subDir: path.join('pkg', 'something'));
+    var test4 = FantasySubPackageSettings('foobie', repo1);
+    var test5 = FantasySubPackageSettings('foo', repo1);
 
     expect(test1, equals(test1));
     expect(test1, isNot(equals(test2)));
@@ -47,3 +54,99 @@
     expect(test1, equals(test5));
   }
 }
+
+class FantasyRepoFake extends FantasyRepo {
+  final String name;
+  final FantasyRepoSettings repoSettings;
+  final Folder repoRoot;
+
+  FantasyRepoFake(this.repoSettings, this.repoRoot) : name = repoSettings.name;
+}
+
+@reflectiveTest
+class FantasySubPackageTest extends FilesystemTestBase {
+  FantasyRepoFake fantasyRepo;
+  FantasySubPackage fantasySubPackage;
+  Folder repoRoot;
+  File pubspecYaml;
+
+  setUp() {
+    super.setUp();
+    String repoRootPath = convertPath('/workspace/repo_root');
+    repoRoot = resourceProvider.getFolder(repoRootPath);
+    fantasyRepo = FantasyRepoFake(
+        FantasyRepoSettings('unreal_repo', '', '', ''), repoRoot);
+    // subPackage 'unreal_package' at 'workspace_root/repo_root/unreal_package_dir'.
+    fantasySubPackage = FantasySubPackage(
+        FantasySubPackageSettings('unreal_package', fantasyRepo.repoSettings,
+            subDir: 'unreal_package_dir'),
+        fantasyRepo,
+        resourceProvider: resourceProvider);
+    // the pubspecYaml.
+    pubspecYaml = resourceProvider
+        .getFile(join(repoRootPath, 'unreal_package_dir', 'pubspec.yaml'));
+  }
+
+  test_recognizeAllDependencies() async {
+    pubspecYaml.writeAsStringSync('''
+      name: unreal_package
+      version: 1.2.3
+      dependencies:
+        package2:
+          path: correctly/enclosed
+        package3:
+          version: '0.0.0 >= 1.0.0'
+        package4:
+          version: any
+      dev_dependencies:
+        package5:
+          version: any
+    ''');
+    List<FantasySubPackageSettings> dependencies =
+        await fantasySubPackage.getPackageAllDependencies();
+    expect(dependencies.length, equals(4));
+  }
+
+  test_recognizePathSubdir() async {
+    pubspecYaml.writeAsStringSync('''
+      name: unreal_package
+      version: 1.2.3
+      dependencies:
+        package2:
+          path: correctly/enclosed
+    ''');
+    List<FantasySubPackageSettings> dependencies =
+        await fantasySubPackage.getPackageAllDependencies();
+    expect(dependencies.first.name, equals('package2'));
+    expect(dependencies.first.repoSettings.name, equals('unreal_repo'));
+    expect(dependencies.first.subDir,
+        equals(join('unreal_package_dir', 'correctly', 'enclosed')));
+  }
+
+  test_recognizeVersion() async {
+    pubspecYaml.writeAsStringSync('''
+      name: unreal_package
+      version: 1.2.3
+      dependencies:
+        package3:
+          version: '0.0.0 >= 1.0.0'
+    ''');
+    List<FantasySubPackageSettings> dependencies =
+        await fantasySubPackage.getPackageAllDependencies();
+    expect(dependencies.first.name, equals('package3'));
+    expect(dependencies.first.repoSettings.name, equals('package3'));
+    expect(dependencies.first.subDir, equals('.'));
+  }
+
+  @assertFailingTest
+  test_assertOnPathOutsidePackage() async {
+    pubspecYaml.writeAsStringSync('''
+      name: unreal_package
+      version: 1.2.3
+      dependencies:
+        package2:
+          path: ../incorrectly/enclosed
+    ''');
+    await fantasySubPackage.getPackageAllDependencies();
+  }
+}
diff --git a/pkg/nnbd_migration/test/fantasyland/fantasy_workspace_test.dart b/pkg/nnbd_migration/test/fantasyland/fantasy_workspace_test.dart
new file mode 100644
index 0000000..f0d3701
--- /dev/null
+++ b/pkg/nnbd_migration/test/fantasyland/fantasy_workspace_test.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2020, 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:test_reflective_loader/test_reflective_loader.dart';
+
+import 'src/filesystem_test_base.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(FantasyWorkspaceTest);
+  });
+}
+
+@reflectiveTest
+class FantasyWorkspaceTest extends FilesystemTestBase {}
diff --git a/pkg/nnbd_migration/test/fantasyland/src/filesystem_test_base.dart b/pkg/nnbd_migration/test/fantasyland/src/filesystem_test_base.dart
new file mode 100644
index 0000000..14878ab
--- /dev/null
+++ b/pkg/nnbd_migration/test/fantasyland/src/filesystem_test_base.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2020, 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/test_utilities/resource_provider_mixin.dart';
+import 'package:nnbd_migration/src/fantasyland/fantasy_repo_impl.dart';
+import 'package:nnbd_migration/src/fantasyland/fantasy_workspace_impl.dart';
+import 'package:nnbd_migration/src/utilities/subprocess_launcher.dart';
+import 'package:mockito/mockito.dart';
+
+class MockSubprocessLauncher extends Mock implements SubprocessLauncher {}
+
+class FilesystemTestBase with ResourceProviderMixin {
+  MockSubprocessLauncher mockLauncher;
+  FantasyRepoDependencies fantasyRepoDependencies;
+  FantasyWorkspaceDependencies workspaceDependencies;
+
+  setUp() {
+    mockLauncher = MockSubprocessLauncher();
+    workspaceDependencies = FantasyWorkspaceDependencies(
+        resourceProvider: resourceProvider, launcher: mockLauncher);
+    fantasyRepoDependencies = FantasyRepoDependencies.fromWorkspaceDependencies(
+        workspaceDependencies);
+  }
+}
diff --git a/pkg/nnbd_migration/test/fantasyland/test_all.dart b/pkg/nnbd_migration/test/fantasyland/test_all.dart
index c4601ce..fa3036a 100644
--- a/pkg/nnbd_migration/test/fantasyland/test_all.dart
+++ b/pkg/nnbd_migration/test/fantasyland/test_all.dart
@@ -6,10 +6,12 @@
 
 import 'fantasy_repo_test.dart' as fantasy_repo_test;
 import 'fantasy_sub_package_test.dart' as fantasy_sub_package_test;
+import 'fantasy_workspace_test.dart' as fantasy_workspace_test;
 
 main() {
   defineReflectiveSuite(() {
     fantasy_repo_test.main();
     fantasy_sub_package_test.main();
+    fantasy_workspace_test.main();
   });
 }
diff --git a/pkg/nnbd_migration/test/fix_aggregator_test.dart b/pkg/nnbd_migration/test/fix_aggregator_test.dart
index 504375d..19e5403 100644
--- a/pkg/nnbd_migration/test/fix_aggregator_test.dart
+++ b/pkg/nnbd_migration/test/fix_aggregator_test.dart
@@ -700,18 +700,21 @@
       this.toStringValueWithoutNullability});
 
   @override
-  noSuchMethod(Invocation invocation) {
-    return super.noSuchMethod(invocation);
-  }
-
-  @override
-  String toString({bool withNullability = false}) {
+  String getDisplayString({
+    bool skipAllDynamicArguments = false,
+    bool withNullability = false,
+  }) {
     var result = withNullability
         ? toStringValueWithNullability
         : toStringValueWithoutNullability;
     expect(result, isNotNull);
     return result;
   }
+
+  @override
+  noSuchMethod(Invocation invocation) {
+    return super.noSuchMethod(invocation);
+  }
 }
 
 class MockDecoratedType implements DecoratedType {
diff --git a/pkg/nnbd_migration/test/fix_builder_test.dart b/pkg/nnbd_migration/test/fix_builder_test.dart
index 19f863a..3fd3eb7 100644
--- a/pkg/nnbd_migration/test/fix_builder_test.dart
+++ b/pkg/nnbd_migration/test/fix_builder_test.dart
@@ -8,6 +8,7 @@
 import 'package:analyzer/dart/element/type_provider.dart';
 import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/dart/error/hint_codes.dart';
+import 'package:analyzer/src/generated/element_type_provider.dart';
 import 'package:analyzer/src/task/strong/checker.dart';
 import 'package:nnbd_migration/src/fix_aggregator.dart';
 import 'package:nnbd_migration/src/fix_builder.dart';
@@ -2261,7 +2262,6 @@
         findNode.propertyAccess('c?.toString'), 'String Function()?');
   }
 
-  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/40313')
   Future<void> test_propertyAccess_nullAware_potentiallyNullable() async {
     // In the code example below, the `?.` is not changed to `.` because `T`
     // might be instantiated to `int?`, in which case the null check is still
@@ -2725,16 +2725,19 @@
 
   AssignmentTargetInfo _computeAssignmentTargetInfo(
       Expression node, FixBuilder fixBuilder) {
-    var assignment = node.thisOrAncestorOfType<AssignmentExpression>();
-    var isReadWrite = assignment.operator.type != TokenType.EQ;
-    var readType = isReadWrite
-        ? getReadType(node,
-                elementTypeProvider:
-                    MigrationResolutionHooksImpl(fixBuilder)) ??
-            typeProvider.dynamicType
-        : null;
-    var writeType = node.staticType;
-    return AssignmentTargetInfo(readType, writeType);
+    try {
+      assert(
+          identical(ElementTypeProvider.current, const ElementTypeProvider()));
+      ElementTypeProvider.current = fixBuilder.migrationResolutionHooks;
+      var assignment = node.thisOrAncestorOfType<AssignmentExpression>();
+      var isReadWrite = assignment.operator.type != TokenType.EQ;
+      var readType =
+          isReadWrite ? getReadType(node) ?? typeProvider.dynamicType : null;
+      var writeType = node.staticType;
+      return AssignmentTargetInfo(readType, writeType);
+    } finally {
+      ElementTypeProvider.current = const ElementTypeProvider();
+    }
   }
 
   FixBuilder _createFixBuilder(AstNode scope) {
diff --git a/pkg/nnbd_migration/test/instrumentation_test.dart b/pkg/nnbd_migration/test/instrumentation_test.dart
index 82940fe..a27e8f4 100644
--- a/pkg/nnbd_migration/test/instrumentation_test.dart
+++ b/pkg/nnbd_migration/test/instrumentation_test.dart
@@ -165,7 +165,7 @@
     expect(
         externalDecoratedType[findNode.simple('print').staticElement]
             .type
-            .toString(),
+            .getDisplayString(withNullability: false),
         'void Function(Object)');
   }
 
@@ -179,7 +179,7 @@
     expect(
         externalDecoratedTypeParameterBound[pointElementTypeParameter]
             .type
-            .toString(),
+            .getDisplayString(withNullability: false),
         'num');
   }
 
diff --git a/pkg/nnbd_migration/test/migration_visitor_test_base.dart b/pkg/nnbd_migration/test/migration_visitor_test_base.dart
index 5b9f840..f4f53ac 100644
--- a/pkg/nnbd_migration/test/migration_visitor_test_base.dart
+++ b/pkg/nnbd_migration/test/migration_visitor_test_base.dart
@@ -36,9 +36,6 @@
 mixin DecoratedTypeTester implements DecoratedTypeTesterBase {
   int _offset = 0;
 
-  Map<TypeParameterElement, DecoratedType> _decoratedTypeParameterBounds =
-      Map.identity();
-
   NullabilityNode get always => graph.always;
 
   DecoratedType get bottom => DecoratedType(typeProvider.bottomType, never);
@@ -74,9 +71,6 @@
           nullabilitySuffix: NullabilitySuffix.star,
         ),
         node ?? newNode(),
-        typeFormalBounds: typeFormals
-            .map((formal) => _decoratedTypeParameterBounds[formal])
-            .toList(),
         returnType: returnType,
         positionalParameters: required.toList()..addAll(positional),
         namedParameters: named);
@@ -117,7 +111,7 @@
   TypeParameterElement typeParameter(String name, DecoratedType bound) {
     var element = TypeParameterElementImpl.synthetic(name);
     element.bound = bound.type;
-    _decoratedTypeParameterBounds[element] = bound;
+    decoratedTypeParameterBounds.put(element, bound);
     return element;
   }
 
@@ -135,6 +129,8 @@
 /// Base functionality that must be implemented by classes mixing in
 /// [DecoratedTypeTester].
 abstract class DecoratedTypeTesterBase {
+  DecoratedTypeParameterBounds get decoratedTypeParameterBounds;
+
   NullabilityGraph get graph;
 
   TypeProvider get typeProvider;
@@ -349,6 +345,8 @@
 
   final NullabilityGraphForTesting graph;
 
+  final decoratedTypeParameterBounds = DecoratedTypeParameterBounds();
+
   MigrationVisitorTestBase() : this._(NullabilityGraphForTesting());
 
   MigrationVisitorTestBase._(this.graph);
@@ -408,11 +406,21 @@
     return variables.possiblyOptionalParameter(findNode.defaultParameter(text));
   }
 
+  void setUp() {
+    DecoratedTypeParameterBounds.current = decoratedTypeParameterBounds;
+    super.setUp();
+  }
+
   /// Gets the [ConditionalDiscard] information associated with the statement
   /// whose text is [text].
   ConditionalDiscard statementDiscard(String text) {
     return variables.conditionalDiscard(findNode.statement(text));
   }
+
+  void tearDown() {
+    DecoratedTypeParameterBounds.current = null;
+    super.tearDown();
+  }
 }
 
 /// Abstract base class representing a thing that can be matched against
diff --git a/pkg/nnbd_migration/test/node_builder_test.dart b/pkg/nnbd_migration/test/node_builder_test.dart
index d993021..1972fae 100644
--- a/pkg/nnbd_migration/test/node_builder_test.dart
+++ b/pkg/nnbd_migration/test/node_builder_test.dart
@@ -101,17 +101,17 @@
     expect(constructors, hasLength(2));
     var a = findElement.constructor('a', of: 'D');
     var aType = variables.decoratedElementType(a);
-    expect(aType.type.toString(), 'D Function()');
+    _assertType(aType.type, 'D Function()');
     expect(aType.node, same(never));
     expect(aType.typeArguments, isEmpty);
-    expect(aType.returnType.type.toString(), 'D');
+    _assertType(aType.returnType.type, 'D');
     expect(aType.returnType.node, same(never));
     var b = findElement.constructor('b', of: 'D');
     var bType = variables.decoratedElementType(b);
-    expect(bType.type.toString(), 'D Function()');
+    _assertType(bType.type, 'D Function()');
     expect(bType.node, same(never));
     expect(bType.typeArguments, isEmpty);
-    expect(bType.returnType.type.toString(), 'D');
+    _assertType(bType.returnType.type, 'D');
     expect(bType.returnType.node, same(never));
   }
 
@@ -130,55 +130,54 @@
     expect(constructors, hasLength(4));
     var a = findElement.constructor('a', of: 'D');
     var aType = variables.decoratedElementType(a);
-    expect(aType.type.toString(), 'D Function(int)');
+    _assertType(aType.type, 'D Function(int)');
     expect(aType.node, same(never));
     expect(aType.typeArguments, isEmpty);
-    expect(aType.returnType.type.toString(), 'D');
+    _assertType(aType.returnType.type, 'D');
     expect(aType.returnType.node, same(never));
     expect(aType.positionalParameters, hasLength(1));
-    expect(aType.positionalParameters[0].type.toString(), 'int');
+    _assertType(aType.positionalParameters[0].type, 'int');
     expect(aType.positionalParameters[0].node,
         TypeMatcher<NullabilityNodeMutable>());
     expect(aType.namedParameters, isEmpty);
     var b = findElement.constructor('b', of: 'D');
     var bType = variables.decoratedElementType(b);
-    expect(bType.type.toString(), 'D Function([int])');
+    _assertType(bType.type, 'D Function([int])');
     expect(bType.node, same(never));
     expect(bType.typeArguments, isEmpty);
-    expect(bType.returnType.type.toString(), 'D');
+    _assertType(bType.returnType.type, 'D');
     expect(bType.returnType.node, same(never));
     expect(bType.positionalParameters, hasLength(1));
-    expect(bType.positionalParameters[0].type.toString(), 'int');
+    _assertType(bType.positionalParameters[0].type, 'int');
     expect(bType.positionalParameters[0].node,
         TypeMatcher<NullabilityNodeMutable>());
     expect(bType.namedParameters, isEmpty);
     var c = findElement.constructor('c', of: 'D');
     var cType = variables.decoratedElementType(c);
-    expect(cType.type.toString(), 'D Function({int i})');
+    _assertType(cType.type, 'D Function({int i})');
     expect(cType.node, same(never));
     expect(cType.typeArguments, isEmpty);
-    expect(cType.returnType.type.toString(), 'D');
+    _assertType(cType.returnType.type, 'D');
     expect(cType.returnType.node, same(never));
     expect(cType.positionalParameters, isEmpty);
     expect(cType.namedParameters, hasLength(1));
     expect(cType.namedParameters, contains('i'));
-    expect(cType.namedParameters['i'].type.toString(), 'int');
+    _assertType(cType.namedParameters['i'].type, 'int');
     expect(
         cType.namedParameters['i'].node, TypeMatcher<NullabilityNodeMutable>());
     var d = findElement.constructor('d', of: 'D');
     var dType = variables.decoratedElementType(d);
-    expect(dType.type.toString(), 'D Function(List<int>)');
+    _assertType(dType.type, 'D Function(List<int>)');
     expect(dType.node, same(never));
     expect(dType.typeArguments, isEmpty);
-    expect(dType.returnType.type.toString(), 'D');
+    _assertType(dType.returnType.type, 'D');
     expect(dType.returnType.node, same(never));
     expect(dType.positionalParameters, hasLength(1));
-    expect(dType.positionalParameters[0].type.toString(), 'List<int>');
+    _assertType(dType.positionalParameters[0].type, 'List<int>');
     expect(dType.positionalParameters[0].node,
         TypeMatcher<NullabilityNodeMutable>());
     expect(dType.positionalParameters[0].typeArguments, hasLength(1));
-    expect(
-        dType.positionalParameters[0].typeArguments[0].type.toString(), 'int');
+    _assertType(dType.positionalParameters[0].typeArguments[0].type, 'int');
     expect(dType.positionalParameters[0].typeArguments[0].node,
         TypeMatcher<NullabilityNodeMutable>());
     expect(dType.namedParameters, isEmpty);
@@ -195,18 +194,18 @@
 ''');
     var dConstructor = findElement.unnamedConstructor('D');
     var dConstructorType = variables.decoratedElementType(dConstructor);
-    expect(dConstructorType.type.toString(), 'D<U> Function(U)');
+    _assertType(dConstructorType.type, 'D<U> Function(U)');
     expect(dConstructorType.node, same(never));
     expect(dConstructorType.typeFormals, isEmpty);
-    expect(dConstructorType.returnType.type.toString(), 'D<U>');
+    _assertType(dConstructorType.returnType.type, 'D<U>');
     expect(dConstructorType.returnType.node, same(never));
     var typeArguments = dConstructorType.returnType.typeArguments;
     expect(typeArguments, hasLength(1));
-    expect(typeArguments[0].type.toString(), 'U');
+    _assertType(typeArguments[0].type, 'U');
     expect(typeArguments[0].node, same(never));
     var dParams = dConstructorType.positionalParameters;
     expect(dParams, hasLength(1));
-    expect(dParams[0].type.toString(), 'U');
+    _assertType(dParams[0].type, 'U');
     expect(dParams[0].node, TypeMatcher<NullabilityNodeMutable>());
   }
 
@@ -217,9 +216,9 @@
     var defaultConstructor = findElement.class_('C').constructors.single;
     var decoratedConstructorType =
         variables.decoratedElementType(defaultConstructor);
-    expect(decoratedConstructorType.type.toString(), 'C Function()');
+    _assertType(decoratedConstructorType.type, 'C Function()');
     expect(decoratedConstructorType.node, same(never));
-    expect(decoratedConstructorType.returnType.type.toString(), 'C');
+    _assertType(decoratedConstructorType.returnType.type, 'C');
     expect(decoratedConstructorType.returnType.node, same(never));
   }
 
@@ -230,16 +229,16 @@
     var defaultConstructor = findElement.class_('C').constructors.single;
     var decoratedConstructorType =
         variables.decoratedElementType(defaultConstructor);
-    expect(decoratedConstructorType.type.toString(), 'C<T, U> Function()');
+    _assertType(decoratedConstructorType.type, 'C<T, U> Function()');
     expect(decoratedConstructorType.node, same(never));
     expect(decoratedConstructorType.typeArguments, isEmpty);
     var returnType = decoratedConstructorType.returnType;
-    expect(returnType.type.toString(), 'C<T, U>');
+    _assertType(returnType.type, 'C<T, U>');
     expect(returnType.node, same(never));
     expect(returnType.typeArguments, hasLength(2));
-    expect(returnType.typeArguments[0].type.toString(), 'T');
+    _assertType(returnType.typeArguments[0].type, 'T');
     expect(returnType.typeArguments[0].node, same(never));
-    expect(returnType.typeArguments[1].type.toString(), 'U');
+    _assertType(returnType.typeArguments[1].type, 'U');
     expect(returnType.typeArguments[1].node, same(never));
   }
 
@@ -297,7 +296,7 @@
 ''');
     var types = decoratedDirectSupertypes('D');
     var decorated = types[findElement.class_('C')];
-    expect(decorated.type.toString(), 'C<int, V>');
+    _assertType(decorated.type, 'C<int, V>');
     expect(decorated.node, same(never));
     expect(decorated.typeArguments, hasLength(2));
     expect(decorated.typeArguments[0].node,
@@ -312,7 +311,7 @@
 ''');
     var types = decoratedDirectSupertypes('C');
     var decorated = types[typeProvider.objectType.element];
-    expect(decorated.type.toString(), 'Object');
+    _assertType(decorated.type, 'Object');
     assertEdge(decorated.node, never, hard: true, checkable: false);
     expect(decorated.typeArguments, isEmpty);
   }
@@ -324,7 +323,7 @@
 ''');
     var types = decoratedDirectSupertypes('D');
     var decorated = types[findElement.class_('C')];
-    expect(decorated.type.toString(), 'C<int, V>');
+    _assertType(decorated.type, 'C<int, V>');
     expect(decorated.node, same(never));
     expect(decorated.typeArguments, hasLength(2));
     expect(decorated.typeArguments[0].node,
@@ -340,7 +339,7 @@
 ''');
     var types = decoratedDirectSupertypes('D');
     var decorated = types[findElement.class_('C')];
-    expect(decorated.type.toString(), 'C<int, V>');
+    _assertType(decorated.type, 'C<int, V>');
     expect(decorated.node, same(never));
     expect(decorated.typeArguments, hasLength(2));
     expect(decorated.typeArguments[0].node,
@@ -357,7 +356,7 @@
 ''');
     var types = decoratedDirectSupertypes('D');
     var decorated = types[findElement.class_('C')];
-    expect(decorated.type.toString(), 'C<int, V>');
+    _assertType(decorated.type, 'C<int, V>');
     expect(decorated.node, same(never));
     expect(decorated.typeArguments, hasLength(2));
     expect(decorated.typeArguments[0].node,
@@ -374,7 +373,7 @@
 ''');
     var types = decoratedDirectSupertypes('D');
     var decorated = types[findElement.class_('C')];
-    expect(decorated.type.toString(), 'C<int, V>');
+    _assertType(decorated.type, 'C<int, V>');
     expect(decorated.node, same(never));
     expect(decorated.typeArguments, hasLength(2));
     expect(decorated.typeArguments[0].node,
@@ -390,7 +389,7 @@
 ''');
     var types = decoratedDirectSupertypes('D');
     var decorated = types[findElement.class_('C')];
-    expect(decorated.type.toString(), 'C<int, V>');
+    _assertType(decorated.type, 'C<int, V>');
     expect(decorated.node, same(never));
     expect(decorated.typeArguments, hasLength(2));
     expect(decorated.typeArguments[0].node,
@@ -405,7 +404,7 @@
 ''');
     var types = decoratedDirectSupertypes('D');
     var super_ = types.values.single;
-    expect(super_.type.toString(), 'Iterable<V>');
+    _assertType(super_.type, 'Iterable<V>');
     expect(super_.node, same(never));
     expect(super_.typeArguments, hasLength(1));
     expect(super_.typeArguments[0].node,
@@ -418,7 +417,7 @@
 ''');
     var types = decoratedDirectSupertypes('C');
     var decorated = types[typeProvider.objectType.element];
-    expect(decorated.type.toString(), 'Object');
+    _assertType(decorated.type, 'Object');
     assertEdge(decorated.node, never, hard: true, checkable: false);
     expect(decorated.typeArguments, isEmpty);
   }
@@ -430,7 +429,7 @@
 ''');
     var types = decoratedDirectSupertypes('D');
     var decorated = types[findElement.class_('C')];
-    expect(decorated.type.toString(), 'C<int, V>');
+    _assertType(decorated.type, 'C<int, V>');
     expect(decorated.node, same(never));
     expect(decorated.typeArguments, hasLength(2));
     expect(decorated.typeArguments[0].node,
@@ -446,7 +445,7 @@
 ''');
     var types = decoratedDirectSupertypes('D');
     var decorated = types[findElement.class_('C')];
-    expect(decorated.type.toString(), 'C<int, V>');
+    _assertType(decorated.type, 'C<int, V>');
     expect(decorated.node, same(never));
     expect(decorated.typeArguments, hasLength(2));
     expect(decorated.typeArguments[0].node,
@@ -543,7 +542,7 @@
     var ctorParamType = variables.decoratedElementType(ctorParam);
     expect(ctorType.positionalParameters[0], same(ctorParamType));
     expect(ctorParamType.node, TypeMatcher<NullabilityNodeMutable>());
-    expect(ctorParamType.namedParameters['i'].type.toString(), 'dynamic');
+    _assertType(ctorParamType.namedParameters['i'].type, 'dynamic');
     expect(ctorParamType.namedParameters['i'].node.isImmutable, false);
   }
 
@@ -579,7 +578,7 @@
     var ctorParamType = variables.decoratedElementType(ctorParam);
     expect(ctorType.positionalParameters[0], same(ctorParamType));
     expect(ctorParamType.node, TypeMatcher<NullabilityNodeMutable>());
-    expect(ctorParamType.positionalParameters[0].type.toString(), 'dynamic');
+    _assertType(ctorParamType.positionalParameters[0].type, 'dynamic');
     expect(ctorParamType.positionalParameters[0].node.isImmutable, false);
   }
 
@@ -612,7 +611,7 @@
     var ctorParamType = variables.decoratedElementType(ctorParam);
     expect(ctorType.positionalParameters[0], same(ctorParamType));
     expect(ctorParamType.node, TypeMatcher<NullabilityNodeMutable>());
-    expect(ctorParamType.returnType.type.toString(), 'dynamic');
+    _assertType(ctorParamType.returnType.type, 'dynamic');
     expect(ctorParamType.returnType.node.isImmutable, false);
   }
 
@@ -627,7 +626,7 @@
         decoratedConstructorDeclaration('named').positionalParameters[0];
     expect(decoratedTypeAnnotation('int this'),
         same(decoratedConstructorParamType));
-    expect(decoratedConstructorParamType.type.toString(), 'int');
+    _assertType(decoratedConstructorParamType.type, 'int');
     expect(decoratedConstructorParamType.node,
         TypeMatcher<NullabilityNodeMutable>());
     // Note: the edge builder will connect this node to the node for the type of
@@ -643,7 +642,7 @@
 ''');
     var decoratedConstructorParamType =
         decoratedConstructorDeclaration('named').positionalParameters[0];
-    expect(decoratedConstructorParamType.type.toString(), 'int');
+    _assertType(decoratedConstructorParamType.type, 'int');
     expect(decoratedConstructorParamType.node,
         TypeMatcher<NullabilityNodeMutable>());
     // Note: the edge builder will unify this implicit type with the type of the
@@ -654,9 +653,7 @@
     await analyze('''
 T f<T extends Object>(T t) => t;
 ''');
-    var decoratedType = decoratedFunctionType('f');
     var bound = decoratedTypeParameterBound('T extends');
-    expect(decoratedType.typeFormalBounds[0], same(bound));
     expect(decoratedTypeAnnotation('Object'), same(bound));
     expect(bound.node, isNot(always));
     expect(bound.type, typeProvider.objectType);
@@ -666,9 +663,7 @@
     await analyze('''
 T f<T>(T t) => t;
 ''');
-    var decoratedType = decoratedFunctionType('f');
     var bound = decoratedTypeParameterBound('T>');
-    expect(decoratedType.typeFormalBounds[0], same(bound));
     assertEdge(always, bound.node, hard: false);
     expect(bound.type, same(typeProvider.objectType));
   }
@@ -722,7 +717,7 @@
 typedef T F<T, U>(U u);
 ''');
     var element = findElement.functionTypeAlias('F');
-    var decoratedType = variables.decoratedElementType(element);
+    var decoratedType = variables.decoratedElementType(element.function);
     var t = element.typeParameters[0];
     var u = element.typeParameters[1];
     // typeFormals should be empty because this is not a generic function type,
@@ -746,8 +741,8 @@
     await analyze('''
 typedef F();
 ''');
-    var decoratedType =
-        variables.decoratedElementType(findElement.functionTypeAlias('F'));
+    var decoratedType = variables
+        .decoratedElementType(findElement.functionTypeAlias('F').function);
     expect(decoratedType.returnType.type.isDynamic, isTrue);
     expect(decoratedType.returnType.node.isImmutable, false);
     expect(decoratedType.typeFormals, isEmpty);
@@ -757,8 +752,8 @@
     await analyze('''
 typedef int F(String s);
 ''');
-    var decoratedType =
-        variables.decoratedElementType(findElement.functionTypeAlias('F'));
+    var decoratedType = variables
+        .decoratedElementType(findElement.functionTypeAlias('F').function);
     expect(decoratedType.returnType, same(decoratedTypeAnnotation('int')));
     expect(decoratedType.typeFormals, isEmpty);
     expect(decoratedType.positionalParameters[0],
@@ -789,7 +784,7 @@
     var gType = variables.decoratedElementType(g);
     expect(fType.positionalParameters[0], same(gType));
     expect(gType.node, TypeMatcher<NullabilityNodeMutable>());
-    expect(gType.namedParameters['i'].type.toString(), 'dynamic');
+    _assertType(gType.namedParameters['i'].type, 'dynamic');
     expect(gType.namedParameters['i'].node.isImmutable, false);
   }
 
@@ -818,7 +813,7 @@
     var gType = variables.decoratedElementType(g);
     expect(fType.positionalParameters[0], same(gType));
     expect(gType.node, TypeMatcher<NullabilityNodeMutable>());
-    expect(gType.positionalParameters[0].type.toString(), 'dynamic');
+    _assertType(gType.positionalParameters[0].type, 'dynamic');
     expect(gType.positionalParameters[0].node.isImmutable, false);
   }
 
@@ -845,7 +840,7 @@
     var gType = variables.decoratedElementType(g);
     expect(fType.positionalParameters[0], same(gType));
     expect(gType.node, TypeMatcher<NullabilityNodeMutable>());
-    expect(gType.returnType.type.toString(), 'dynamic');
+    _assertType(gType.returnType.type, 'dynamic');
     expect(gType.returnType.node.isImmutable, false);
   }
 
@@ -859,18 +854,10 @@
     var decoratedFType = decoratedMethodType('f');
     var decoratedFReturnType = decoratedFType.returnType;
     var decoratedFReturnReturnType = decoratedFReturnType.returnType;
-    expect(decoratedFReturnReturnType.type.toString(), 'dynamic');
+    _assertType(decoratedFReturnReturnType.type, 'dynamic');
     expect(decoratedFReturnReturnType.node.isImmutable, false);
   }
 
-  Future<void> test_genericFunctionType_formal_bounds() async {
-    await analyze('''
-void f(T Function<T extends num>() x) {}
-''');
-    var decoratedType = decoratedGenericFunctionTypeAnnotation('T Function');
-    expect(decoratedType.typeFormalBounds[0].type.toString(), 'num');
-  }
-
   Future<void> test_genericFunctionType_formals() async {
     await analyze('''
 void f(T Function<T, U>(U) x) {}
@@ -879,7 +866,7 @@
     expect(decoratedFunctionType('f').positionalParameters[0],
         same(decoratedType));
     expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
-    expect(decoratedType.type.toString(), 'T Function<T, U>(U)');
+    _assertType(decoratedType.type, 'T Function<T, U>(U)');
     expect(decoratedType.typeFormals, hasLength(2));
     var t = decoratedType.typeFormals[0];
     var u = decoratedType.typeFormals[1];
@@ -941,7 +928,7 @@
 typedef F = T Function<T, U>(U u);
 ''');
     var element = findElement.functionTypeAlias('F');
-    var decoratedType = variables.decoratedElementType(element);
+    var decoratedType = variables.decoratedElementType(element.function);
     expect(decoratedType,
         same(decoratedGenericFunctionTypeAnnotation('T Function')));
     expect(decoratedType.typeFormals, hasLength(2));
@@ -965,7 +952,7 @@
 typedef F<T, U> = T Function(U u);
 ''');
     var element = findElement.functionTypeAlias('F');
-    var decoratedType = variables.decoratedElementType(element);
+    var decoratedType = variables.decoratedElementType(element.function);
     expect(decoratedType,
         same(decoratedGenericFunctionTypeAnnotation('T Function')));
     var t = element.typeParameters[0];
@@ -991,8 +978,8 @@
     await analyze('''
 typedef F = Function();
 ''');
-    var decoratedType =
-        variables.decoratedElementType(findElement.functionTypeAlias('F'));
+    var decoratedType = variables
+        .decoratedElementType(findElement.functionTypeAlias('F').function);
     expect(decoratedType,
         same(decoratedGenericFunctionTypeAnnotation('Function')));
     expect(decoratedType.returnType.type.isDynamic, isTrue);
@@ -1004,8 +991,8 @@
     await analyze('''
 typedef F = int Function(String s);
 ''');
-    var decoratedType =
-        variables.decoratedElementType(findElement.functionTypeAlias('F'));
+    var decoratedType = variables
+        .decoratedElementType(findElement.functionTypeAlias('F').function);
     expect(decoratedType,
         same(decoratedGenericFunctionTypeAnnotation('int Function')));
     expect(decoratedType.returnType, same(decoratedTypeAnnotation('int')));
@@ -1198,9 +1185,7 @@
   T f<T extends Object>(T t) => t;
 }
 ''');
-    var decoratedType = decoratedMethodType('f');
     var bound = decoratedTypeParameterBound('T extends');
-    expect(decoratedType.typeFormalBounds[0], same(bound));
     expect(decoratedTypeAnnotation('Object'), same(bound));
     expect(bound.node, isNot(always));
     expect(bound.type, typeProvider.objectType);
@@ -1212,9 +1197,7 @@
   T f<T>(T t) => t;
 }
 ''');
-    var decoratedType = decoratedMethodType('f');
     var bound = decoratedTypeParameterBound('T>');
-    expect(decoratedType.typeFormalBounds[0], same(bound));
     assertEdge(always, bound.node, hard: false);
     expect(bound.type, same(typeProvider.objectType));
   }
@@ -1306,10 +1289,13 @@
     var decoratedBaseType =
         decoratedMethodType('f/*B*/').positionalParameters[0];
     var decoratedType = decoratedMethodType('f/*C*/').positionalParameters[0];
-    expect(decoratedType.typeFormalBounds, hasLength(1));
-    expect(decoratedType.typeFormalBounds[0].type.toString(), 'Object');
-    expect(decoratedType.typeFormalBounds[0].node,
-        isNot(same(decoratedBaseType.typeFormalBounds[0].node)));
+    var decoratedTypeFormalBound = decoratedTypeParameterBounds
+        .get((decoratedType.type as FunctionType).typeFormals[0]);
+    _assertType(decoratedTypeFormalBound.type, 'Object');
+    var decoratedBaseTypeFormalBound = decoratedTypeParameterBounds
+        .get((decoratedBaseType.type as FunctionType).typeFormals[0]);
+    expect(decoratedTypeFormalBound.node,
+        isNot(same(decoratedBaseTypeFormalBound.node)));
   }
 
   Future<void>
@@ -1325,10 +1311,13 @@
     var decoratedBaseType =
         decoratedMethodType('f/*B*/').positionalParameters[0];
     var decoratedType = decoratedMethodType('f/*C*/').positionalParameters[0];
-    expect(decoratedType.typeFormalBounds, hasLength(1));
-    expect(decoratedType.typeFormalBounds[0].type.toString(), 'num');
-    expect(decoratedType.typeFormalBounds[0].node,
-        isNot(same(decoratedBaseType.typeFormalBounds[0].node)));
+    var decoratedTypeFormalBound = decoratedTypeParameterBounds
+        .get((decoratedType.type as FunctionType).typeFormals[0]);
+    _assertType(decoratedTypeFormalBound.type, 'num');
+    var decoratedBaseTypeFormalBound = decoratedTypeParameterBounds
+        .get((decoratedBaseType.type as FunctionType).typeFormals[0]);
+    expect(decoratedTypeFormalBound.node,
+        isNot(same(decoratedBaseTypeFormalBound.node)));
   }
 
   Future<void> test_method_parameterType_inferred_named() async {
@@ -1555,17 +1544,16 @@
     // from the ones in the typedef (they will be unified by the edge builder).
     // This is necessary because there is no guarantee of whether the typedef or
     // its usage will be visited first.
-    var typedefDecoratedType =
-        variables.decoratedElementType(findElement.functionTypeAlias('F'));
+    var typedefDecoratedType = variables
+        .decoratedElementType(findElement.functionTypeAlias('F').function);
     var decoratedType = decoratedTypeAnnotation('F<int>');
     expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
     expect(decoratedType.node, isNot(same(typedefDecoratedType.node)));
-    expect(decoratedType.returnType.type.toString(), 'int');
+    _assertType(decoratedType.returnType.type, 'int');
     expect(
         decoratedType.returnType.node, TypeMatcher<NullabilityNodeMutable>());
     expect(decoratedType.returnType.node,
         isNot(same(typedefDecoratedType.returnType.node)));
-    expect(decoratedType.typeFormalBounds, isEmpty);
   }
 
   Future<void> test_typedef_reference_generic_uninstantiated() async {
@@ -1577,20 +1565,23 @@
     // from the ones in the typedef (they will be unified by the edge builder).
     // This is necessary because there is no guarantee of whether the typedef or
     // its usage will be visited first.
-    var typedefDecoratedType =
-        variables.decoratedElementType(findElement.functionTypeAlias('F'));
+    var typedefDecoratedType = variables
+        .decoratedElementType(findElement.functionTypeAlias('F').function);
     var decoratedType = decoratedTypeAnnotation('F f');
     expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
     expect(decoratedType.node, isNot(same(typedefDecoratedType.node)));
-    expect(decoratedType.returnType.type.toString(), 'T');
+    _assertType(decoratedType.returnType.type, 'T');
     expect(
         decoratedType.returnType.node, TypeMatcher<NullabilityNodeMutable>());
     expect(decoratedType.returnType.node,
         isNot(same(typedefDecoratedType.returnType.node)));
-    expect(decoratedType.typeFormalBounds, hasLength(1));
-    expect(decoratedType.typeFormalBounds[0].type.toString(), 'num');
-    expect(decoratedType.typeFormalBounds[0].node,
-        isNot(same(typedefDecoratedType.typeFormalBounds[0].node)));
+    var decoratedTypeFormalBound = decoratedTypeParameterBounds
+        .get((decoratedType.type as FunctionType).typeFormals[0]);
+    _assertType(decoratedTypeFormalBound.type, 'num');
+    var decoratedTypedefTypeFormalBound = decoratedTypeParameterBounds
+        .get((typedefDecoratedType.type as FunctionType).typeFormals[0]);
+    expect(decoratedTypeFormalBound.node,
+        isNot(same(decoratedTypedefTypeFormalBound.node)));
   }
 
   Future<void> test_typedef_reference_simple() async {
@@ -1602,22 +1593,21 @@
     // from the ones in the typedef (they will be unified by the edge builder).
     // This is necessary because there is no guarantee of whether the typedef or
     // its usage will be visited first.
-    var typedefDecoratedType =
-        variables.decoratedElementType(findElement.functionTypeAlias('F'));
+    var typedefDecoratedType = variables
+        .decoratedElementType(findElement.functionTypeAlias('F').function);
     var decoratedType = decoratedTypeAnnotation('F f');
     expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
     expect(decoratedType.node, isNot(same(typedefDecoratedType.node)));
-    expect(decoratedType.returnType.type.toString(), 'int');
+    _assertType(decoratedType.returnType.type, 'int');
     expect(
         decoratedType.returnType.node, TypeMatcher<NullabilityNodeMutable>());
     expect(decoratedType.returnType.node,
         isNot(same(typedefDecoratedType.returnType.node)));
-    expect(decoratedType.positionalParameters[0].type.toString(), 'String');
+    _assertType(decoratedType.positionalParameters[0].type, 'String');
     expect(decoratedType.positionalParameters[0].node,
         TypeMatcher<NullabilityNodeMutable>());
     expect(decoratedType.positionalParameters[0].node,
         isNot(same(typedefDecoratedType.positionalParameters[0].node)));
-    expect(decoratedType.typeFormalBounds, isEmpty);
   }
 
   Future<void> test_variableDeclaration_type_simple() async {
@@ -1649,4 +1639,9 @@
     expect(decoratedFunctionType('f').returnType, same(decoratedType));
     assertNoEdge(always, decoratedType.node);
   }
+
+  void _assertType(DartType type, String expected) {
+    var typeStr = type.getDisplayString(withNullability: false);
+    expect(typeStr, expected);
+  }
 }
diff --git a/pkg/nnbd_migration/test/nullability_migration_impl_test.dart b/pkg/nnbd_migration/test/nullability_migration_impl_test.dart
deleted file mode 100644
index 2dc12ff..0000000
--- a/pkg/nnbd_migration/test/nullability_migration_impl_test.dart
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (c) 2019, 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/generated/source.dart';
-import 'package:analyzer/src/generated/timestamped_data.dart';
-import 'package:mockito/mockito.dart';
-import 'package:nnbd_migration/nnbd_migration.dart';
-import 'package:nnbd_migration/src/nullability_migration_impl.dart';
-import 'package:nnbd_migration/src/variables.dart';
-import 'package:test_reflective_loader/test_reflective_loader.dart';
-
-main() {
-  defineReflectiveSuite(() {
-    defineReflectiveTests(NullabilityMigrationImplTest);
-  });
-}
-
-@reflectiveTest
-class NullabilityMigrationImplTest {
-  VariablesMock variables;
-  NullabilityMigrationImpl nullabilityMigrationImpl =
-      NullabilityMigrationImpl(null);
-
-  void setUp() {
-    variables = VariablesMock();
-  }
-}
-
-class NullabilityMigrationListenerMock extends Mock
-    implements NullabilityMigrationListener {}
-
-class SourceMock extends Mock implements Source {
-  final String _contents;
-
-  SourceMock(this._contents);
-  TimestampedData<String> get contents => TimestampedData<String>(0, _contents);
-  String get fullName => '/test.dart';
-}
-
-class VariablesMock extends Mock implements Variables {}
diff --git a/pkg/nnbd_migration/test/test_all.dart b/pkg/nnbd_migration/test/test_all.dart
index cde6e0f..76a9844 100644
--- a/pkg/nnbd_migration/test/test_all.dart
+++ b/pkg/nnbd_migration/test/test_all.dart
@@ -20,8 +20,6 @@
 import 'fix_builder_test.dart' as fix_builder_test;
 import 'instrumentation_test.dart' as instrumentation_test;
 import 'node_builder_test.dart' as node_builder_test;
-import 'nullability_migration_impl_test.dart'
-    as nullability_migration_impl_test;
 import 'nullability_node_test.dart' as nullability_node_test;
 import 'utilities/test_all.dart' as utilities;
 import 'variables_test.dart' as variables;
@@ -41,7 +39,6 @@
     fix_builder_test.main();
     instrumentation_test.main();
     node_builder_test.main();
-    nullability_migration_impl_test.main();
     nullability_node_test.main();
     utilities.main();
     variables.main();
diff --git a/pkg/nnbd_migration/test/utilities/multi_future_tracker_test.dart b/pkg/nnbd_migration/test/utilities/multi_future_tracker_test.dart
index 874c6a4..a0fb113 100644
--- a/pkg/nnbd_migration/test/utilities/multi_future_tracker_test.dart
+++ b/pkg/nnbd_migration/test/utilities/multi_future_tracker_test.dart
@@ -55,4 +55,33 @@
 
     return await testTracker.wait();
   }
+
+  Future<void> test_runsSeriallyAtLowLimit() async {
+    var completer1 = Completer();
+
+    testTracker = MultiFutureTracker(1);
+    var runFuture1 = testTracker.runFutureFromClosure(() => completer1.future);
+    var runFuture2 = testTracker.runFutureFromClosure(() => null);
+
+    // Both futures _should_ timeout.
+    await expectLater(runFuture1.timeout(Duration(milliseconds: 1)),
+        throwsA(TypeMatcher<TimeoutException>()));
+    await expectLater(runFuture2.timeout(Duration(milliseconds: 1)),
+        throwsA(TypeMatcher<TimeoutException>()));
+    expect(completer1.isCompleted, isFalse);
+
+    completer1.complete();
+
+    // Now, these should complete normally.
+    await runFuture1;
+    await runFuture2;
+  }
+
+  Future<void> test_returnsValueFromRun() async {
+    testTracker = MultiFutureTracker(1);
+    await expectLater(
+        await testTracker.runFutureFromClosure(() async => true), equals(true));
+    await expectLater(
+        await testTracker.runFutureFromClosure(() => true), equals(true));
+  }
 }
diff --git a/pkg/nnbd_migration/tool/src/package.dart b/pkg/nnbd_migration/tool/src/package.dart
index adf37f2..2dc229b 100644
--- a/pkg/nnbd_migration/tool/src/package.dart
+++ b/pkg/nnbd_migration/tool/src/package.dart
@@ -91,8 +91,8 @@
       String name, Playground playground) async {
     return FantasyLandPackage._(
         name,
-        await buildFantasyLand(name, [],
-            Directory(path.join(playground.playgroundPath, '${name}__flat'))));
+        await buildFantasyLand(
+            name, [], path.join(playground.playgroundPath, '${name}__flat')));
   }
 
   @override
@@ -156,9 +156,8 @@
             workingDirectory: packagePath);
         // TODO(jcollins-g): allow for migrating dependencies?
       }
-      await pubTracker.addFutureFromClosure(() =>
+      await pubTracker.runFutureFromClosure(() =>
           launcher.runStreamed('pub', ['get'], workingDirectory: packagePath));
-      await pubTracker.wait();
     }
   }
 
diff --git a/pkg/vm/lib/metadata/procedure_attributes.dart b/pkg/vm/lib/metadata/procedure_attributes.dart
index b5619cb..99a0023 100644
--- a/pkg/vm/lib/metadata/procedure_attributes.dart
+++ b/pkg/vm/lib/metadata/procedure_attributes.dart
@@ -8,27 +8,46 @@
 
 /// Metadata for annotating procedures with various attributes.
 class ProcedureAttributesMetadata {
-  final bool hasDynamicUses;
+  static const int kInvalidSelectorId = 0;
+
+  final bool methodOrSetterCalledDynamically;
+  final bool getterCalledDynamically;
   final bool hasThisUses;
   final bool hasNonThisUses;
   final bool hasTearOffUses;
+  final int methodOrSetterSelectorId;
+  final int getterSelectorId;
 
   const ProcedureAttributesMetadata(
-      {this.hasDynamicUses: true,
+      {this.methodOrSetterCalledDynamically: true,
+      this.getterCalledDynamically: true,
       this.hasThisUses: true,
       this.hasNonThisUses: true,
-      this.hasTearOffUses: true});
+      this.hasTearOffUses: true,
+      this.methodOrSetterSelectorId: kInvalidSelectorId,
+      this.getterSelectorId: kInvalidSelectorId});
 
   const ProcedureAttributesMetadata.noDynamicUses()
-      : this(hasDynamicUses: false);
+      : this(
+            methodOrSetterCalledDynamically: false,
+            getterCalledDynamically: false);
 
   @override
   String toString() {
     final attrs = <String>[];
-    if (!hasDynamicUses) attrs.add('hasDynamicUses:false');
+    if (!methodOrSetterCalledDynamically) {
+      attrs.add('methodOrSetterCalledDynamically:false');
+    }
+    if (!getterCalledDynamically) attrs.add('getterCalledDynamically:false');
     if (!hasThisUses) attrs.add('hasThisUses:false');
     if (!hasNonThisUses) attrs.add('hasNonThisUses:false');
     if (!hasTearOffUses) attrs.add('hasTearOffUses:false');
+    if (methodOrSetterSelectorId != kInvalidSelectorId) {
+      attrs.add('methodOrSetterSelectorId:$methodOrSetterSelectorId');
+    }
+    if (getterSelectorId != kInvalidSelectorId) {
+      attrs.add('getterSelectorId:$getterSelectorId');
+    }
     return attrs.join(',');
   }
 }
@@ -36,10 +55,11 @@
 /// Repository for [ProcedureAttributesMetadata].
 class ProcedureAttributesMetadataRepository
     extends MetadataRepository<ProcedureAttributesMetadata> {
-  static const int kDynamicUsesBit = 1 << 0;
+  static const int kMethodOrSetterCalledDynamicallyBit = 1 << 0;
   static const int kNonThisUsesBit = 1 << 1;
   static const int kTearOffUsesBit = 1 << 2;
   static const int kThisUsesBit = 1 << 3;
+  static const int kGetterCalledDynamicallyBit = 1 << 4;
 
   static const repositoryTag = 'vm.procedure-attributes.metadata';
 
@@ -52,8 +72,11 @@
 
   int _getFlags(ProcedureAttributesMetadata metadata) {
     int flags = 0;
-    if (metadata.hasDynamicUses) {
-      flags |= kDynamicUsesBit;
+    if (metadata.methodOrSetterCalledDynamically) {
+      flags |= kMethodOrSetterCalledDynamicallyBit;
+    }
+    if (metadata.getterCalledDynamically) {
+      flags |= kGetterCalledDynamicallyBit;
     }
     if (metadata.hasThisUses) {
       flags |= kThisUsesBit;
@@ -71,25 +94,41 @@
   void writeToBinary(
       ProcedureAttributesMetadata metadata, Node node, BinarySink sink) {
     sink.writeByte(_getFlags(metadata));
+    sink.writeUInt30(metadata.methodOrSetterSelectorId);
+    sink.writeUInt30(metadata.getterSelectorId);
   }
 
   @override
   ProcedureAttributesMetadata readFromBinary(Node node, BinarySource source) {
     final int flags = source.readByte();
 
-    final bool hasDynamicUses = (flags & kDynamicUsesBit) != 0;
+    final bool methodOrSetterCalledDynamically =
+        (flags & kMethodOrSetterCalledDynamicallyBit) != 0;
+    final bool getterCalledDynamically =
+        (flags & kGetterCalledDynamicallyBit) != 0;
     final bool hasThisUses = (flags & kThisUsesBit) != 0;
     final bool hasNonThisUses = (flags & kNonThisUsesBit) != 0;
     final bool hasTearOffUses = (flags & kTearOffUsesBit) != 0;
 
+    final int methodOrSetterSelectorId = source.readUInt();
+    final int getterSelectorId = source.readUInt();
+
     return new ProcedureAttributesMetadata(
-        hasDynamicUses: hasDynamicUses,
+        methodOrSetterCalledDynamically: methodOrSetterCalledDynamically,
+        getterCalledDynamically: getterCalledDynamically,
         hasThisUses: hasThisUses,
         hasNonThisUses: hasNonThisUses,
-        hasTearOffUses: hasTearOffUses);
+        hasTearOffUses: hasTearOffUses,
+        methodOrSetterSelectorId: methodOrSetterSelectorId,
+        getterSelectorId: getterSelectorId);
   }
 
   /// Converts [metadata] into a bytecode attribute.
-  Constant getBytecodeAttribute(ProcedureAttributesMetadata metadata) =>
-      IntConstant(_getFlags(metadata));
+  Constant getBytecodeAttribute(ProcedureAttributesMetadata metadata) {
+    return ListConstant(const DynamicType(), [
+      IntConstant(_getFlags(metadata)),
+      IntConstant(metadata.methodOrSetterSelectorId),
+      IntConstant(metadata.getterSelectorId),
+    ]);
+  }
 }
diff --git a/pkg/vm/lib/transformations/no_dynamic_invocations_annotator.dart b/pkg/vm/lib/transformations/no_dynamic_invocations_annotator.dart
index 9806c89..fd6484ca 100644
--- a/pkg/vm/lib/transformations/no_dynamic_invocations_annotator.dart
+++ b/pkg/vm/lib/transformations/no_dynamic_invocations_annotator.dart
@@ -93,7 +93,10 @@
     ProcedureAttributesMetadata metadata;
     if (!_selectors.nonThisSelectors.contains(selector)) {
       metadata = const ProcedureAttributesMetadata(
-          hasDynamicUses: false, hasNonThisUses: true, hasTearOffUses: false);
+          methodOrSetterCalledDynamically: false,
+          getterCalledDynamically: false,
+          hasNonThisUses: true,
+          hasTearOffUses: false);
     } else {
       metadata = const ProcedureAttributesMetadata.noDynamicUses();
     }
@@ -123,13 +126,22 @@
     ProcedureAttributesMetadata metadata;
     if (!hasNonThisUses && !hasTearOffUses) {
       metadata = const ProcedureAttributesMetadata(
-          hasDynamicUses: false, hasNonThisUses: false, hasTearOffUses: false);
+          methodOrSetterCalledDynamically: false,
+          getterCalledDynamically: false,
+          hasNonThisUses: false,
+          hasTearOffUses: false);
     } else if (!hasNonThisUses && hasTearOffUses) {
       metadata = const ProcedureAttributesMetadata(
-          hasDynamicUses: false, hasNonThisUses: false, hasTearOffUses: true);
+          methodOrSetterCalledDynamically: false,
+          getterCalledDynamically: false,
+          hasNonThisUses: false,
+          hasTearOffUses: true);
     } else if (hasNonThisUses && !hasTearOffUses) {
       metadata = const ProcedureAttributesMetadata(
-          hasDynamicUses: false, hasNonThisUses: true, hasTearOffUses: false);
+          methodOrSetterCalledDynamically: false,
+          getterCalledDynamically: false,
+          hasNonThisUses: true,
+          hasTearOffUses: false);
     } else {
       metadata = const ProcedureAttributesMetadata.noDynamicUses();
     }
diff --git a/pkg/vm/lib/transformations/type_flow/analysis.dart b/pkg/vm/lib/transformations/type_flow/analysis.dart
index f881808..b41711e 100644
--- a/pkg/vm/lib/transformations/type_flow/analysis.dart
+++ b/pkg/vm/lib/transformations/type_flow/analysis.dart
@@ -399,12 +399,16 @@
 
           if (selector.callKind != CallKind.PropertyGet) {
             if (selector is DynamicSelector) {
-              typeFlowAnalysis._calledViaDynamicSelector.add(target);
+              typeFlowAnalysis._methodsAndSettersCalledDynamically.add(target);
             } else if (selector is VirtualSelector) {
               typeFlowAnalysis._calledViaThis.add(target);
             } else {
               typeFlowAnalysis._calledViaInterfaceSelector.add(target);
             }
+          } else {
+            if (selector is DynamicSelector) {
+              typeFlowAnalysis._gettersCalledDynamically.add(target);
+            }
           }
 
           if (directInvocation.typeChecksNeeded) {
@@ -1312,7 +1316,8 @@
   final Map<Member, Summary> _summaries = <Member, Summary>{};
   final Map<Field, _FieldValue> _fieldValues = <Field, _FieldValue>{};
   final Set<Member> _tearOffTaken = new Set<Member>();
-  final Set<Member> _calledViaDynamicSelector = new Set<Member>();
+  final Set<Member> _methodsAndSettersCalledDynamically = new Set<Member>();
+  final Set<Member> _gettersCalledDynamically = new Set<Member>();
   final Set<Member> _calledViaInterfaceSelector = new Set<Member>();
   final Set<Member> _calledViaThis = new Set<Member>();
 
@@ -1396,10 +1401,15 @@
 
   bool isTearOffTaken(Member member) => _tearOffTaken.contains(member);
 
-  /// Returns true if this member is called dynamically.
-  /// Getters are not tracked. For fields, only setter is tracked.
+  /// Returns true if this member is called on a receiver with static type
+  /// dynamic. Getters are not tracked. For fields, only setter is tracked.
   bool isCalledDynamically(Member member) =>
-      _calledViaDynamicSelector.contains(member);
+      _methodsAndSettersCalledDynamically.contains(member);
+
+  /// Returns true if this getter (or implicit getter for field) is called
+  /// on a receiver with static type dynamic.
+  bool isGetterCalledDynamically(Member member) =>
+      _gettersCalledDynamically.contains(member);
 
   /// Returns true if this member is called via this call.
   /// Getters are not tracked. For fields, only setter is tracked.
@@ -1408,7 +1418,7 @@
   /// Returns true if this member is called via non-this call.
   /// Getters are not tracked. For fields, only setter is tracked.
   bool isCalledNotViaThis(Member member) =>
-      _calledViaDynamicSelector.contains(member) ||
+      _methodsAndSettersCalledDynamically.contains(member) ||
       _calledViaInterfaceSelector.contains(member);
 
   /// ---- Implementation of [CallHandler] interface. ----
diff --git a/pkg/vm/lib/transformations/type_flow/table_selector.dart b/pkg/vm/lib/transformations/type_flow/table_selector.dart
new file mode 100644
index 0000000..94fd95a
--- /dev/null
+++ b/pkg/vm/lib/transformations/type_flow/table_selector.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2020, 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:kernel/ast.dart';
+
+import '../../metadata/procedure_attributes.dart';
+
+// Assigns dispatch table selector IDs to interface targets.
+// TODO(dartbug.com/40188): Implement a more fine-grained assignment based on
+// hierarchy connectedness.
+class TableSelectorAssigner {
+  final Map<Name, int> _methodSelectorId = {};
+  final Map<Name, int> _getterSelectorId = {};
+  final Map<Name, int> _setterSelectorId = {};
+  int _nextSelectorId = ProcedureAttributesMetadata.kInvalidSelectorId + 1;
+
+  int _selectorIdForMap(Map<Name, int> map, Member member) {
+    return map.putIfAbsent(member.name, () => _nextSelectorId++);
+  }
+
+  int methodOrSetterSelectorId(Member member) {
+    if (member is Procedure) {
+      switch (member.kind) {
+        case ProcedureKind.Method:
+        case ProcedureKind.Operator:
+          return _selectorIdForMap(_methodSelectorId, member);
+        case ProcedureKind.Setter:
+          return _selectorIdForMap(_setterSelectorId, member);
+        case ProcedureKind.Getter:
+          return ProcedureAttributesMetadata.kInvalidSelectorId;
+        default:
+          throw "Unexpected procedure kind '${member.kind}'";
+      }
+    }
+    if (member is Field) {
+      return _selectorIdForMap(_setterSelectorId, member);
+    }
+    throw "Unexpected member kind '${member.runtimeType}'";
+  }
+
+  int getterSelectorId(Member member) {
+    if (member is Procedure) {
+      switch (member.kind) {
+        case ProcedureKind.Getter:
+        case ProcedureKind.Method:
+          return _selectorIdForMap(_getterSelectorId, member);
+        case ProcedureKind.Operator:
+        case ProcedureKind.Setter:
+          return ProcedureAttributesMetadata.kInvalidSelectorId;
+        default:
+          throw "Unexpected procedure kind '${member.kind}'";
+      }
+    }
+    if (member is Field) {
+      return _selectorIdForMap(_getterSelectorId, member);
+    }
+    throw "Unexpected member kind '${member.runtimeType}'";
+  }
+}
diff --git a/pkg/vm/lib/transformations/type_flow/transformer.dart b/pkg/vm/lib/transformations/type_flow/transformer.dart
index 67c2892..c29fb3c 100644
--- a/pkg/vm/lib/transformations/type_flow/transformer.dart
+++ b/pkg/vm/lib/transformations/type_flow/transformer.dart
@@ -17,6 +17,7 @@
 import 'analysis.dart';
 import 'calls.dart';
 import 'summary.dart';
+import 'table_selector.dart';
 import 'types.dart';
 import 'utils.dart';
 import '../pragma.dart';
@@ -112,6 +113,7 @@
   final InferredTypeMetadataRepository _inferredTypeMetadata;
   final UnreachableNodeMetadataRepository _unreachableNodeMetadata;
   final ProcedureAttributesMetadataRepository _procedureAttributesMetadata;
+  final TableSelectorAssigner _tableSelectorAssigner;
   final Class _intClass;
   Constant _nullConstant;
 
@@ -120,6 +122,7 @@
         _unreachableNodeMetadata = new UnreachableNodeMetadataRepository(),
         _procedureAttributesMetadata =
             new ProcedureAttributesMetadataRepository(),
+        _tableSelectorAssigner = new TableSelectorAssigner(),
         _intClass = _typeFlowAnalysis.environment.coreTypes.intClass {
     component.addMetadataRepository(_inferredTypeMetadata);
     component.addMetadataRepository(_unreachableNodeMetadata);
@@ -275,19 +278,28 @@
 
         // TODO(alexmarkov): figure out how to pass receiver type.
       }
-
-      if (member.isInstanceMember &&
-          !(member is Procedure && member.isGetter)) {
-        final attrs = new ProcedureAttributesMetadata(
-            hasDynamicUses: _typeFlowAnalysis.isCalledDynamically(member),
-            hasThisUses: _typeFlowAnalysis.isCalledViaThis(member),
-            hasNonThisUses: _typeFlowAnalysis.isCalledNotViaThis(member),
-            hasTearOffUses: _typeFlowAnalysis.isTearOffTaken(member));
-        _procedureAttributesMetadata.mapping[member] = attrs;
-      }
     } else if (!member.isAbstract) {
       _setUnreachable(member);
     }
+
+    // We need to attach ProcedureAttributesMetadata to all members, even
+    // unreachable ones, since an unreachable member could still be used as an
+    // interface target, and table dispatch calls need selector IDs for all
+    // interface targets.
+    if (member.isInstanceMember) {
+      final attrs = new ProcedureAttributesMetadata(
+          methodOrSetterCalledDynamically:
+              _typeFlowAnalysis.isCalledDynamically(member),
+          getterCalledDynamically:
+              _typeFlowAnalysis.isGetterCalledDynamically(member),
+          hasThisUses: _typeFlowAnalysis.isCalledViaThis(member),
+          hasNonThisUses: _typeFlowAnalysis.isCalledNotViaThis(member),
+          hasTearOffUses: _typeFlowAnalysis.isTearOffTaken(member),
+          methodOrSetterSelectorId:
+              _tableSelectorAssigner.methodOrSetterSelectorId(member),
+          getterSelectorId: _tableSelectorAssigner.getterSelectorId(member));
+      _procedureAttributesMetadata.mapping[member] = attrs;
+    }
   }
 
   @override
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/annotation.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/annotation.dart.expect
index 5263f59..ec084d3 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/annotation.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/annotation.dart.expect
@@ -7,15 +7,15 @@
 abstract class ClassAnnotation2 extends core::Object {
 }
 abstract class MethodAnnotation extends core::Object {
-[@vm.unreachable.metadata=]  final field core::int* x;
+[@vm.unreachable.metadata=] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  final field core::int* x;
 }
 abstract class TypedefAnnotation extends core::Object {
-[@vm.unreachable.metadata=]  final field core::List<core::int*>* list;
+[@vm.unreachable.metadata=] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4]  final field core::List<core::int*>* list;
 }
 abstract class VarAnnotation extends core::Object {
 }
 abstract class ParametrizedAnnotation<T extends core::Object* = dynamic> extends core::Object {
-[@vm.unreachable.metadata=]  final field self::ParametrizedAnnotation::T* foo;
+[@vm.unreachable.metadata=] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6]  final field self::ParametrizedAnnotation::T* foo;
 }
 abstract class A extends core::Object {
   static method staticMethod() → void {}
@@ -25,7 +25,7 @@
   synthetic constructor •() → self::B*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  @#C8
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:7,getterSelectorId:8]  @#C8
   method instanceMethod() → void {}
 }
 static method foo([@vm.inferred-type.metadata=dart.core::Null? (value: null)] (core::List<core::int*>*) →* void a) → core::int* {
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/bench_vector.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/bench_vector.dart.expect
index f7c22d7..09996bb 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/bench_vector.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/bench_vector.dart.expect
@@ -6,18 +6,18 @@
 import "dart:typed_data";
 
 class _Vector extends core::Object {
-[@vm.inferred-type.metadata=dart.core::_Smi (value: 0)] [@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false]  final field core::int* _offset;
-[@vm.inferred-type.metadata=dart.core::_Smi (value: 10)] [@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false]  final field core::int* _length;
-[@vm.inferred-type.metadata=dart.typed_data::_Float64List] [@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false]  final field core::List<core::double*>* _elements;
+[@vm.inferred-type.metadata=dart.core::_Smi (value: 0)] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:4,getterSelectorId:5]  final field core::int* _offset;
+[@vm.inferred-type.metadata=dart.core::_Smi (value: 10)] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:6,getterSelectorId:7]  final field core::int* _length;
+[@vm.inferred-type.metadata=dart.typed_data::_Float64List] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:8,getterSelectorId:9]  final field core::List<core::double*>* _elements;
   constructor •([@vm.inferred-type.metadata=dart.core::_Smi (value: 10)] core::int* size) → self::_Vector*
     : self::_Vector::_offset = 0, self::_Vector::_length = size, self::_Vector::_elements = [@vm.inferred-type.metadata=dart.typed_data::_Float64List] typ::Float64List::•(size), super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasTearOffUses:false]  operator []([@vm.inferred-type.metadata=!] core::int* i) → core::double*
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasTearOffUses:false,methodOrSetterSelectorId:1]  operator []([@vm.inferred-type.metadata=!] core::int* i) → core::double*
     return [@vm.direct-call.metadata=dart.typed_data::_Float64List::[]] [@vm.inferred-type.metadata=dart.core::_Double (skip check)] [@vm.direct-call.metadata=#lib::_Vector::_elements] [@vm.inferred-type.metadata=dart.typed_data::_Float64List] this.{self::_Vector::_elements}.{core::List::[]}([@vm.direct-call.metadata=dart.core::_IntegerImplementation::+] [@vm.inferred-type.metadata=int (skip check)] i.{core::num::+}([@vm.direct-call.metadata=#lib::_Vector::_offset] [@vm.inferred-type.metadata=dart.core::_Smi (value: 0)] this.{self::_Vector::_offset}));
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  operator []=([@vm.inferred-type.metadata=dart.core::_OneByteString] core::int* i, core::double* value) → void {
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:2]  operator []=([@vm.inferred-type.metadata=dart.core::_OneByteString] core::int* i, core::double* value) → void {
     let dynamic #t1 = [@vm.direct-call.metadata=#lib::_Vector::_elements] [@vm.inferred-type.metadata=dart.typed_data::_Float64List] this.{self::_Vector::_elements} in let dynamic #t2 = i in let dynamic #t3 = [@vm.direct-call.metadata=#lib::_Vector::_offset] [@vm.inferred-type.metadata=dart.core::_Smi (value: 0)] this.{self::_Vector::_offset} in throw "Attempt to execute code removed by Dart AOT compiler (TFA)";
   }
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  operator *([@vm.inferred-type.metadata=#lib::_Vector?] self::_Vector* a) → core::double* {
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3]  operator *([@vm.inferred-type.metadata=#lib::_Vector?] self::_Vector* a) → core::double* {
     core::double* result = 0.0;
     for (core::int* i = 0; [@vm.direct-call.metadata=dart.core::_IntegerImplementation::<] [@vm.inferred-type.metadata=dart.core::bool (skip check)] i.{core::num::<}([@vm.direct-call.metadata=#lib::_Vector::_length] [@vm.inferred-type.metadata=dart.core::_Smi (value: 10)] this.{self::_Vector::_length}); i = [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+] [@vm.inferred-type.metadata=int (skip check)] i.{core::num::+}(1))
       result = [@vm.direct-call.metadata=dart.core::_Double::+??] [@vm.inferred-type.metadata=dart.core::_Double (skip check)] result.{core::double::+}([@vm.direct-call.metadata=dart.core::_Double::*] [@vm.inferred-type.metadata=dart.core::_Double (skip check)] [@vm.direct-call.metadata=#lib::_Vector::[]] [@vm.inferred-type.metadata=dart.core::_Double (skip check)] this.{self::_Vector::[]}(i).{core::double::*}([@vm.direct-call.metadata=#lib::_Vector::[]??] [@vm.inferred-type.metadata=dart.core::_Double (skip check)] a.{self::_Vector::[]}(i)));
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/class_generics_basic.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/class_generics_basic.dart.expect
index b55b811..fd9dd20 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/class_generics_basic.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/class_generics_basic.dart.expect
@@ -6,11 +6,11 @@
   synthetic constructor •() → self::C<self::C::T*>*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasTearOffUses:false]  method foo() → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  method foo() → dynamic
     return new self::D::•<self::C::T*>();
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method id1([@vm.inferred-type.metadata=#lib::Y (skip check)] generic-covariant-impl self::C::T* x) → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4]  method id1([@vm.inferred-type.metadata=#lib::Y (skip check)] generic-covariant-impl self::C::T* x) → dynamic
     return x;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method id2([@vm.inferred-type.metadata=#lib::Z] generic-covariant-impl self::C::T* x) → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6]  method id2([@vm.inferred-type.metadata=#lib::Z] generic-covariant-impl self::C::T* x) → dynamic
     return x;
 }
 class D<T extends core::Object* = dynamic> extends core::Object {
@@ -22,11 +22,11 @@
   synthetic constructor •() → self::E<self::E::S*, self::E::T*>*
     : super self::C::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method foo() → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  method foo() → dynamic
     return [@vm.inferred-type.metadata=#lib::D<dart.core::String*>] super.{self::C::foo}();
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method bar() → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:7,getterSelectorId:8]  method bar() → dynamic
     return new self::D::•<self::E::S*>();
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method baz() → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:9,getterSelectorId:10]  method baz() → dynamic
     return new self::D::•<self::E::T*>();
 }
 abstract class X extends core::Object {
@@ -57,9 +57,9 @@
   synthetic constructor •() → self::C2<self::C2::T*>*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method id3([@vm.inferred-type.metadata=dart.core::_Double (skip check) (value: 3.0)] generic-covariant-impl core::Comparable<self::C2::T*>* x) → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:11,getterSelectorId:12]  method id3([@vm.inferred-type.metadata=dart.core::_Double (skip check) (value: 3.0)] generic-covariant-impl core::Comparable<self::C2::T*>* x) → dynamic
     return x;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method id4([@vm.inferred-type.metadata=#lib::K<#lib::J*> (skip check)] generic-covariant-impl self::K<self::I<self::C2::T*>*>* x) → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:13,getterSelectorId:14]  method id4([@vm.inferred-type.metadata=#lib::K<#lib::J*> (skip check)] generic-covariant-impl self::K<self::I<self::C2::T*>*>* x) → dynamic
     return x;
 }
 static method main() → dynamic {
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/class_generics_case1.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/class_generics_case1.dart.expect
index f850805..8c4940c 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/class_generics_case1.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/class_generics_case1.dart.expect
@@ -10,11 +10,11 @@
     ;
 }
 class InheritedElement extends self::Element {
-[@vm.inferred-type.metadata=dart.collection::_InternalLinkedHashMap<#lib::Element*, dart.core::Object*>] [@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false]  final field core::Map<self::Element*, core::Object*>* _dependents = <self::Element*, core::Object*>{};
+[@vm.inferred-type.metadata=dart.collection::_InternalLinkedHashMap<#lib::Element*, dart.core::Object*>] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4]  final field core::Map<self::Element*, core::Object*>* _dependents = <self::Element*, core::Object*>{};
   synthetic constructor •() → self::InheritedElement*
     : super self::Element::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method setDependencies([@vm.inferred-type.metadata=!] self::Element* dependent, [@vm.inferred-type.metadata=dart.core::_Smi?] core::Object* value) → void {
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  method setDependencies([@vm.inferred-type.metadata=!] self::Element* dependent, [@vm.inferred-type.metadata=dart.core::_Smi?] core::Object* value) → void {
     [@vm.call-site-attributes.metadata=receiverType:dart.core::Map<#lib::Element*, dart.core::Object*>*] [@vm.direct-call.metadata=dart.collection::__InternalLinkedHashMap&_HashVMBase&MapMixin&_LinkedHashMapMixin::[]=] [@vm.inferred-type.metadata=!? (skip check)] [@vm.direct-call.metadata=#lib::InheritedElement::_dependents] [@vm.inferred-type.metadata=dart.collection::_InternalLinkedHashMap<#lib::Element*, dart.core::Object*>] this.{self::InheritedElement::_dependents}.{core::Map::[]=}(dependent, value);
   }
 }
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/const_prop.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/const_prop.dart.expect
index fc8bc63..78eb735 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/const_prop.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/const_prop.dart.expect
@@ -6,15 +6,15 @@
   synthetic constructor •() → self::A*
     : super core::Object::•()
     ;
-  get foo() → core::String*
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:1]  get foo() → core::String*
     return "foo";
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method getBar() → core::String*
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:2,getterSelectorId:3]  method getBar() → core::String*
     return "bar";
 }
 class B extends core::Object {
-[@vm.inferred-type.metadata=dart.core::_Smi (value: 1)] [@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false]  final field core::int* index;
-[@vm.inferred-type.metadata=dart.core::_OneByteString (value: B.b2)] [@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false]  final field core::String* _name;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method toString() → core::String*
+[@vm.inferred-type.metadata=dart.core::_Smi (value: 1)] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:6,getterSelectorId:7]  final field core::int* index;
+[@vm.inferred-type.metadata=dart.core::_OneByteString (value: B.b2)] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:8,getterSelectorId:9]  final field core::String* _name;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:4,getterSelectorId:5]  method toString() → core::String*
     return [@vm.inferred-type.metadata=dart.core::_OneByteString (value: B.b2)] this.{=self::B::_name};
 }
 static method test0([@vm.inferred-type.metadata=dart.core::_Smi (value: 40)] core::int* arg) → void {
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/devirt.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/devirt.dart.expect
index 576c2b0..1469023 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/devirt.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/devirt.dart.expect
@@ -6,20 +6,20 @@
   synthetic constructor •() → self::A*
     : super core::Object::•()
     ;
-  abstract method foo() → core::int*;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  abstract method foo() → core::int*;
 }
 class B extends self::A {
   synthetic constructor •() → self::B*
     : super self::A::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method foo() → core::int*
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  method foo() → core::int*
     return 1;
 }
 class C extends core::Object implements self::A {
   synthetic constructor •() → self::C*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method foo() → core::int*
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  method foo() → core::int*
     return 2;
 }
 class D extends self::C {
@@ -31,7 +31,7 @@
   synthetic constructor •() → self::E*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method toString() → core::String*
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4]  method toString() → core::String*
     return "D";
 }
 [@vm.inferred-type.metadata=#lib::D?]static field self::A* dd;
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/future.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/future.dart.expect
index 2173803..be83db0 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/future.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/future.dart.expect
@@ -9,16 +9,16 @@
   synthetic constructor •() → self::C<self::C::T*>*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method test2c([@vm.inferred-type.metadata=dart.core::_Smi (skip check) (value: 3)] generic-covariant-impl asy::FutureOr<self::C::T*>* x) → void {}
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method test3c([@vm.inferred-type.metadata=dart.async::_Future<dart.core::int*> (skip check)] generic-covariant-impl asy::Future<self::C::T*>* x) → void {}
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method test4c([@vm.inferred-type.metadata=dart.async::_Future<dart.core::int*> (skip check)] generic-covariant-impl asy::FutureOr<self::C::T*>* x) → void {}
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method test2r([@vm.inferred-type.metadata=#lib::C<dart.core::int*> (skip check)] generic-covariant-impl self::C<asy::FutureOr<self::C::T*>*>* x) → void {}
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method test3r([@vm.inferred-type.metadata=#lib::C<dart.async::Future<dart.core::int*>*> (skip check)] generic-covariant-impl self::C<asy::Future<self::C::T*>*>* x) → void {}
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method test4r([@vm.inferred-type.metadata=#lib::C<dart.async::Future<dart.core::int*>*> (skip check)] generic-covariant-impl self::C<asy::FutureOr<self::C::T*>*>* x) → void {}
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method test5r([@vm.inferred-type.metadata=#lib::C<dart.async::FutureOr<dart.core::int*>*>] generic-covariant-impl self::C<asy::Future<self::C::T*>*>* x) → void {}
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method test6r([@vm.inferred-type.metadata=#lib::C<dart.async::FutureOr<dart.core::int*>*> (skip check)] generic-covariant-impl self::C<asy::FutureOr<self::C::T*>*>* x) → void {}
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method test7r([@vm.inferred-type.metadata=#lib::C<dart.async::FutureOr<dart.core::int*>*>] generic-covariant-impl self::C<self::C::T*>* x) → void {}
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method test8r([@vm.inferred-type.metadata=#lib::C<dart.async::Future<dart.core::int*>*>] generic-covariant-impl self::C<self::C::T*>* x) → void {}
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  method test2c([@vm.inferred-type.metadata=dart.core::_Smi (skip check) (value: 3)] generic-covariant-impl asy::FutureOr<self::C::T*>* x) → void {}
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4]  method test3c([@vm.inferred-type.metadata=dart.async::_Future<dart.core::int*> (skip check)] generic-covariant-impl asy::Future<self::C::T*>* x) → void {}
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6]  method test4c([@vm.inferred-type.metadata=dart.async::_Future<dart.core::int*> (skip check)] generic-covariant-impl asy::FutureOr<self::C::T*>* x) → void {}
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:7,getterSelectorId:8]  method test2r([@vm.inferred-type.metadata=#lib::C<dart.core::int*> (skip check)] generic-covariant-impl self::C<asy::FutureOr<self::C::T*>*>* x) → void {}
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:9,getterSelectorId:10]  method test3r([@vm.inferred-type.metadata=#lib::C<dart.async::Future<dart.core::int*>*> (skip check)] generic-covariant-impl self::C<asy::Future<self::C::T*>*>* x) → void {}
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:11,getterSelectorId:12]  method test4r([@vm.inferred-type.metadata=#lib::C<dart.async::Future<dart.core::int*>*> (skip check)] generic-covariant-impl self::C<asy::FutureOr<self::C::T*>*>* x) → void {}
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:13,getterSelectorId:14]  method test5r([@vm.inferred-type.metadata=#lib::C<dart.async::FutureOr<dart.core::int*>*>] generic-covariant-impl self::C<asy::Future<self::C::T*>*>* x) → void {}
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:15,getterSelectorId:16]  method test6r([@vm.inferred-type.metadata=#lib::C<dart.async::FutureOr<dart.core::int*>*> (skip check)] generic-covariant-impl self::C<asy::FutureOr<self::C::T*>*>* x) → void {}
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:17,getterSelectorId:18]  method test7r([@vm.inferred-type.metadata=#lib::C<dart.async::FutureOr<dart.core::int*>*>] generic-covariant-impl self::C<self::C::T*>* x) → void {}
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:19,getterSelectorId:20]  method test8r([@vm.inferred-type.metadata=#lib::C<dart.async::Future<dart.core::int*>*>] generic-covariant-impl self::C<self::C::T*>* x) → void {}
 }
 static method main() → dynamic {
   dynamic c = new self::C::•<core::int*>();
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_cycle.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_cycle.dart.expect
index 4fb48c4..5226932 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_cycle.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_cycle.dart.expect
@@ -21,16 +21,16 @@
   synthetic constructor •() → self::Stream*
     : super core::Object::•()
     ;
-  abstract method foobar((dynamic) →* void onData, {core::Function* onError = #C1}) → self::StreamSubscription*;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  abstract method foobar((dynamic) →* void onData, {core::Function* onError = #C1}) → self::StreamSubscription*;
 }
 abstract class _StreamImpl extends self::Stream {
   synthetic constructor •() → self::_StreamImpl*
     : super self::Stream::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method foobar([@vm.inferred-type.metadata=dart.core::Null? (value: null)] (dynamic) →* void onData, {[@vm.inferred-type.metadata=dart.core::Null? (value: null)] core::Function* onError = #C1}) → self::StreamSubscription* {
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  method foobar([@vm.inferred-type.metadata=dart.core::Null? (value: null)] (dynamic) →* void onData, {[@vm.inferred-type.metadata=dart.core::Null? (value: null)] core::Function* onError = #C1}) → self::StreamSubscription* {
     return [@vm.inferred-type.metadata=! (skip check)] this.{self::_StreamImpl::_createSubscription}();
   }
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasNonThisUses:false,hasTearOffUses:false]  method _createSubscription() → self::StreamSubscription* {
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4]  method _createSubscription() → self::StreamSubscription* {
     return new self::_BufferingStreamSubscription::•();
   }
 }
@@ -38,7 +38,7 @@
   synthetic constructor •() → self::_ControllerStream*
     : super self::_StreamImpl::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasNonThisUses:false,hasTearOffUses:false]  method _createSubscription() → self::StreamSubscription* {
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4]  method _createSubscription() → self::StreamSubscription* {
     return new self::_BroadcastSubscription::•();
   }
 }
@@ -48,11 +48,11 @@
     ;
 }
 abstract class StreamView extends self::Stream {
-[@vm.inferred-type.metadata=!] [@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false]  final field self::Stream* _stream;
+[@vm.inferred-type.metadata=!] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6]  final field self::Stream* _stream;
   constructor •([@vm.inferred-type.metadata=!] self::Stream* stream) → self::StreamView*
     : self::StreamView::_stream = stream, super self::Stream::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasTearOffUses:false]  method foobar([@vm.inferred-type.metadata=dart.core::Null? (value: null)] (dynamic) →* void onData, {[@vm.inferred-type.metadata=dart.core::Null? (value: null)] core::Function* onError = #C1}) → self::StreamSubscription* {
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  method foobar([@vm.inferred-type.metadata=dart.core::Null? (value: null)] (dynamic) →* void onData, {[@vm.inferred-type.metadata=dart.core::Null? (value: null)] core::Function* onError = #C1}) → self::StreamSubscription* {
     return [@vm.direct-call.metadata=#lib::StreamView::_stream] [@vm.inferred-type.metadata=!] this.{self::StreamView::_stream}.{self::Stream::foobar}(onData, onError: onError);
   }
 }
@@ -60,16 +60,16 @@
   constructor •([@vm.inferred-type.metadata=!] self::Stream* stream) → self::ByteStream*
     : super self::StreamView::•(stream)
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method super_foobar1([@vm.inferred-type.metadata=dart.core::Null? (value: null)] (dynamic) →* void onData) → dynamic {
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:7,getterSelectorId:8]  method super_foobar1([@vm.inferred-type.metadata=dart.core::Null? (value: null)] (dynamic) →* void onData) → dynamic {
     super.{self::StreamView::foobar}(onData);
   }
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method super_foobar2([@vm.inferred-type.metadata=dart.core::Null? (value: null)] (dynamic) →* void onData) → dynamic {
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:9,getterSelectorId:10]  method super_foobar2([@vm.inferred-type.metadata=dart.core::Null? (value: null)] (dynamic) →* void onData) → dynamic {
     super.{self::StreamView::foobar}(onData);
   }
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method super_foobar3({[@vm.inferred-type.metadata=dart.core::Null? (value: null)] (dynamic) →* void onData = #C1, [@vm.inferred-type.metadata=dart.core::Null? (value: null)] core::Function* onError = #C1}) → dynamic {
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:11,getterSelectorId:12]  method super_foobar3({[@vm.inferred-type.metadata=dart.core::Null? (value: null)] (dynamic) →* void onData = #C1, [@vm.inferred-type.metadata=dart.core::Null? (value: null)] core::Function* onError = #C1}) → dynamic {
     super.{self::StreamView::foobar}(onData, onError: onError);
   }
-  get super_stream() → self::Stream*
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:13]  get super_stream() → self::Stream*
     return [@vm.inferred-type.metadata=!] super.{self::StreamView::_stream};
 }
 class _HandleErrorStream extends self::Stream {
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_field_initializer.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_field_initializer.dart.expect
index 35e77bc..6d5cf67 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_field_initializer.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_field_initializer.dart.expect
@@ -13,37 +13,37 @@
     ;
 }
 abstract class A extends core::Object {
-  abstract method foo() → core::Object*;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  abstract method foo() → core::Object*;
 }
 class B extends core::Object implements self::A {
   synthetic constructor •() → self::B*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method foo() → core::Object*
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  method foo() → core::Object*
     return new self::T1::•();
 }
 class C extends core::Object implements self::A {
   synthetic constructor •() → self::C*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method foo() → core::Object*
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  method foo() → core::Object*
     return new self::T2::•();
 }
 class DeepCaller1 extends core::Object {
   synthetic constructor •() → self::DeepCaller1*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method barL1() → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4]  method barL1() → dynamic
     return [@vm.direct-call.metadata=#lib::DeepCaller1::barL2] [@vm.inferred-type.metadata=!? (skip check)] this.{self::DeepCaller1::barL2}();
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasNonThisUses:false,hasTearOffUses:false]  method barL2() → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6]  method barL2() → dynamic
     return [@vm.direct-call.metadata=#lib::DeepCaller1::barL3] [@vm.inferred-type.metadata=!? (skip check)] this.{self::DeepCaller1::barL3}();
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasNonThisUses:false,hasTearOffUses:false]  method barL3() → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:7,getterSelectorId:8]  method barL3() → dynamic
     return [@vm.direct-call.metadata=#lib::DeepCaller1::barL4] [@vm.inferred-type.metadata=!? (skip check)] this.{self::DeepCaller1::barL4}();
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasNonThisUses:false,hasTearOffUses:false]  method barL4() → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:9,getterSelectorId:10]  method barL4() → dynamic
     return self::field1;
 }
 class D extends core::Object {
-[@vm.inferred-type.metadata=!] [@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false]  field core::Object* field2 = [@vm.inferred-type.metadata=!] self::getValue();
+[@vm.inferred-type.metadata=!] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:11,getterSelectorId:12]  field core::Object* field2 = [@vm.inferred-type.metadata=!] self::getValue();
   synthetic constructor •() → self::D*
     : super core::Object::•()
     ;
@@ -52,13 +52,13 @@
   synthetic constructor •() → self::DeepCaller2*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method barL1([@vm.inferred-type.metadata=#lib::D] self::D* dd) → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4]  method barL1([@vm.inferred-type.metadata=#lib::D] self::D* dd) → dynamic
     return [@vm.direct-call.metadata=#lib::DeepCaller2::barL2] [@vm.inferred-type.metadata=! (skip check)] this.{self::DeepCaller2::barL2}(dd);
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasNonThisUses:false,hasTearOffUses:false]  method barL2([@vm.inferred-type.metadata=#lib::D] self::D* dd) → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6]  method barL2([@vm.inferred-type.metadata=#lib::D] self::D* dd) → dynamic
     return [@vm.direct-call.metadata=#lib::DeepCaller2::barL3] [@vm.inferred-type.metadata=! (skip check)] this.{self::DeepCaller2::barL3}(dd);
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasNonThisUses:false,hasTearOffUses:false]  method barL3([@vm.inferred-type.metadata=#lib::D] self::D* dd) → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:7,getterSelectorId:8]  method barL3([@vm.inferred-type.metadata=#lib::D] self::D* dd) → dynamic
     return [@vm.direct-call.metadata=#lib::DeepCaller2::barL4] [@vm.inferred-type.metadata=! (skip check)] this.{self::DeepCaller2::barL4}(dd);
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasNonThisUses:false,hasTearOffUses:false]  method barL4([@vm.inferred-type.metadata=#lib::D] self::D* dd) → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:9,getterSelectorId:10]  method barL4([@vm.inferred-type.metadata=#lib::D] self::D* dd) → dynamic
     return [@vm.direct-call.metadata=#lib::D::field2] [@vm.inferred-type.metadata=!] dd.{self::D::field2};
 }
 [@vm.inferred-type.metadata=dart.core::Null? (value: null)]static field core::Function* unknown;
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_new_class1.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_new_class1.dart.expect
index 87ebd0c..95c4d00 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_new_class1.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_new_class1.dart.expect
@@ -11,20 +11,20 @@
   synthetic constructor •() → self::A*
     : super core::Object::•()
     ;
-  abstract method foo() → dynamic;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  abstract method foo() → dynamic;
 }
 class B extends self::A {
   synthetic constructor •() → self::B*
     : super self::A::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method foo() → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  method foo() → dynamic
     return new self::T1::•();
 }
 class Intermediate extends core::Object {
   synthetic constructor •() → self::Intermediate*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method bar([@vm.inferred-type.metadata=#lib::B?] self::A* aa) → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4]  method bar([@vm.inferred-type.metadata=#lib::B?] self::A* aa) → dynamic
     return [@vm.direct-call.metadata=#lib::B::foo??] [@vm.inferred-type.metadata=#lib::T1 (skip check)] aa.{self::A::foo}();
 }
 [@vm.inferred-type.metadata=dart.core::Null? (value: null)]static field core::Function* unknown;
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_new_class2.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_new_class2.dart.expect
index caa602a..15f83fe 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_new_class2.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_new_class2.dart.expect
@@ -16,13 +16,13 @@
   synthetic constructor •() → self::A*
     : super core::Object::•()
     ;
-  abstract method foo() → dynamic;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  abstract method foo() → dynamic;
 }
 class B extends self::A {
   synthetic constructor •() → self::B*
     : super self::A::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method foo() → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  method foo() → dynamic
     return new self::T1::•();
 }
 abstract class C extends core::Object implements self::B {
@@ -41,14 +41,14 @@
   synthetic constructor •() → self::E*
     : super self::_E&D&C::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method foo() → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  method foo() → dynamic
     return new self::T2::•();
 }
 class Intermediate extends core::Object {
   synthetic constructor •() → self::Intermediate*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method bar(self::A* aa) → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4]  method bar(self::A* aa) → dynamic
     return [@vm.inferred-type.metadata=!] aa.{self::A::foo}();
 }
 [@vm.inferred-type.metadata=dart.core::Null? (value: null)]static field core::Function* unknown;
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_new_dynamic_target.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_new_dynamic_target.dart.expect
index c1b42e3..c86de6e 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_new_dynamic_target.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_new_dynamic_target.dart.expect
@@ -21,22 +21,22 @@
   synthetic constructor •() → self::A*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method foo() → dynamic
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  method foo() → dynamic
     return new self::T1::•();
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method bar() → dynamic
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4]  method bar() → dynamic
     return new self::T2::•();
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method bazz() → dynamic
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6]  method bazz() → dynamic
     return new self::T3::•();
 }
 class B extends core::Object {
   synthetic constructor •() → self::B*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method foo() → dynamic
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  method foo() → dynamic
     return new self::T1::•();
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method bar() → dynamic
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4]  method bar() → dynamic
     return new self::T2::•();
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method bazz() → dynamic
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6]  method bazz() → dynamic
     return new self::T3::•();
 }
 [@vm.inferred-type.metadata=dart.core::Null? (value: null)]static field core::Function* unknown;
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_set_field.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_set_field.dart.expect
index ccedd89..02184b8 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_set_field.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_set_field.dart.expect
@@ -13,8 +13,8 @@
     ;
 }
 class A extends core::Object {
-[@vm.inferred-type.metadata=#lib::T1] [@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false]  field dynamic field1 = new self::T1::•();
-[@vm.inferred-type.metadata=!] [@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  field dynamic field2 = new self::T1::•();
+[@vm.inferred-type.metadata=#lib::T1] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  field dynamic field1 = new self::T1::•();
+[@vm.inferred-type.metadata=!] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4]  field dynamic field2 = new self::T1::•();
   synthetic constructor •() → self::A*
     : super core::Object::•()
     ;
@@ -23,26 +23,26 @@
   synthetic constructor •() → self::DeepCaller1*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method barL1([@vm.inferred-type.metadata=#lib::A?] self::A* aa) → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6]  method barL1([@vm.inferred-type.metadata=#lib::A?] self::A* aa) → dynamic
     return [@vm.direct-call.metadata=#lib::DeepCaller1::barL2] [@vm.inferred-type.metadata=#lib::T1 (skip check)] this.{self::DeepCaller1::barL2}(aa);
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasNonThisUses:false,hasTearOffUses:false]  method barL2([@vm.inferred-type.metadata=#lib::A?] self::A* aa) → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:7,getterSelectorId:8]  method barL2([@vm.inferred-type.metadata=#lib::A?] self::A* aa) → dynamic
     return [@vm.direct-call.metadata=#lib::DeepCaller1::barL3] [@vm.inferred-type.metadata=#lib::T1 (skip check)] this.{self::DeepCaller1::barL3}(aa);
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasNonThisUses:false,hasTearOffUses:false]  method barL3([@vm.inferred-type.metadata=#lib::A?] self::A* aa) → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:9,getterSelectorId:10]  method barL3([@vm.inferred-type.metadata=#lib::A?] self::A* aa) → dynamic
     return [@vm.direct-call.metadata=#lib::DeepCaller1::barL4] [@vm.inferred-type.metadata=#lib::T1 (skip check)] this.{self::DeepCaller1::barL4}(aa);
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasNonThisUses:false,hasTearOffUses:false]  method barL4([@vm.inferred-type.metadata=#lib::A?] self::A* aa) → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:11,getterSelectorId:12]  method barL4([@vm.inferred-type.metadata=#lib::A?] self::A* aa) → dynamic
     return [@vm.direct-call.metadata=#lib::A::field1??] [@vm.inferred-type.metadata=#lib::T1] aa.{self::A::field1};
 }
 class DeepCaller2 extends core::Object {
   synthetic constructor •() → self::DeepCaller2*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method barL1([@vm.inferred-type.metadata=#lib::A?] self::A* aa) → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6]  method barL1([@vm.inferred-type.metadata=#lib::A?] self::A* aa) → dynamic
     return [@vm.direct-call.metadata=#lib::DeepCaller2::barL2] [@vm.inferred-type.metadata=! (skip check)] this.{self::DeepCaller2::barL2}(aa);
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasNonThisUses:false,hasTearOffUses:false]  method barL2([@vm.inferred-type.metadata=#lib::A?] self::A* aa) → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:7,getterSelectorId:8]  method barL2([@vm.inferred-type.metadata=#lib::A?] self::A* aa) → dynamic
     return [@vm.direct-call.metadata=#lib::DeepCaller2::barL3] [@vm.inferred-type.metadata=! (skip check)] this.{self::DeepCaller2::barL3}(aa);
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasNonThisUses:false,hasTearOffUses:false]  method barL3([@vm.inferred-type.metadata=#lib::A?] self::A* aa) → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:9,getterSelectorId:10]  method barL3([@vm.inferred-type.metadata=#lib::A?] self::A* aa) → dynamic
     return [@vm.direct-call.metadata=#lib::DeepCaller2::barL4] [@vm.inferred-type.metadata=! (skip check)] this.{self::DeepCaller2::barL4}(aa);
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasNonThisUses:false,hasTearOffUses:false]  method barL4([@vm.inferred-type.metadata=#lib::A?] self::A* aa) → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:11,getterSelectorId:12]  method barL4([@vm.inferred-type.metadata=#lib::A?] self::A* aa) → dynamic
     return [@vm.direct-call.metadata=#lib::A::field2??] [@vm.inferred-type.metadata=!] aa.{self::A::field2};
 }
 [@vm.inferred-type.metadata=dart.core::Null? (value: null)]static field core::Function* unknown;
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_set_field2.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_set_field2.dart.expect
index 8a46c82..9372e70 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_set_field2.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_set_field2.dart.expect
@@ -6,7 +6,7 @@
   synthetic constructor •() → self::T1*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method go() → self::T3*
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  method go() → self::T3*
     return new self::T3::•();
 }
 class T2 extends core::Object {
@@ -18,12 +18,12 @@
   synthetic constructor •() → self::T3*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method run() → dynamic {
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4]  method run() → dynamic {
     core::print("hi");
   }
 }
 class Q<T extends core::Object* = dynamic> extends core::Object {
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false]  final field self::Q::T* result;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6]  final field self::Q::T* result;
   constructor •(self::Q::T* result) → self::Q<self::Q::T*>*
     : self::Q::result = result, super core::Object::•()
     ;
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_while_processing.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_while_processing.dart.expect
index 8bb1b45..8da19ec 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_while_processing.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_while_processing.dart.expect
@@ -3,28 +3,28 @@
 import "dart:core" as core;
 
 abstract class I extends core::Object {
-  abstract method foo() → void;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  abstract method foo() → void;
 }
 class T1 extends core::Object implements self::I {
   synthetic constructor •() → self::T1*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method foo() → void {}
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  method foo() → void {}
 }
 class T2 extends core::Object implements self::I {
   synthetic constructor •() → self::T2*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method foo() → void {}
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  method foo() → void {}
 }
 class Point extends core::Object {
-[@vm.inferred-type.metadata=!] [@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false]  final field self::I* x;
+[@vm.inferred-type.metadata=!] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:7,getterSelectorId:8]  final field self::I* x;
   const constructor •([@vm.inferred-type.metadata=!] self::I* x) → self::Point*
     : self::Point::x = x, super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method newPoint1() → self::Point*
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4]  method newPoint1() → self::Point*
     return new self::Point::•([@vm.direct-call.metadata=#lib::Point::x] [@vm.inferred-type.metadata=!] this.{self::Point::x});
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method newPoint2() → self::Point*
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6]  method newPoint2() → self::Point*
     return new self::Point::•([@vm.direct-call.metadata=#lib::Point::x] [@vm.inferred-type.metadata=!] this.{self::Point::x});
 }
 static method getX([@vm.inferred-type.metadata=#lib::Point] dynamic point) → dynamic {
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/no_such_method.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/no_such_method.dart.expect
index 4425a1c..fa129ad 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/no_such_method.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/no_such_method.dart.expect
@@ -37,29 +37,29 @@
   synthetic constructor •() → self::A*
     : super core::Object::•()
     ;
-  abstract method foo() → dynamic;
-  abstract get bar() → dynamic;
-  abstract method bazz(dynamic a1, dynamic a2, dynamic a3, [dynamic a4 = #C1, dynamic a5 = #C1]) → dynamic;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  abstract method foo() → dynamic;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:3]  abstract get bar() → dynamic;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:4,getterSelectorId:5]  abstract method bazz(dynamic a1, dynamic a2, dynamic a3, [dynamic a4 = #C1, dynamic a5 = #C1]) → dynamic;
 }
 class B extends self::A {
   synthetic constructor •() → self::B*
     : super self::A::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasTearOffUses:false]  method noSuchMethod(core::Invocation* invocation) → dynamic {
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasTearOffUses:false,methodOrSetterSelectorId:6,getterSelectorId:7]  method noSuchMethod(core::Invocation* invocation) → dynamic {
     return new self::T1::•();
   }
-  no-such-method-forwarder get bar() → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:3]  no-such-method-forwarder get bar() → dynamic
     return _in::unsafeCast<dynamic>([@vm.direct-call.metadata=#lib::B::noSuchMethod] [@vm.inferred-type.metadata=#lib::T1 (skip check)] this.{self::B::noSuchMethod}(new core::_InvocationMirror::_withType(#C2, 1, #C3, #C4, [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView<dart.core::Symbol*, dynamic>] core::Map::unmodifiable<core::Symbol*, dynamic>(#C5))));
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  no-such-method-forwarder method foo() → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  no-such-method-forwarder method foo() → dynamic
     return _in::unsafeCast<dynamic>([@vm.direct-call.metadata=#lib::B::noSuchMethod] [@vm.inferred-type.metadata=#lib::T1 (skip check)] this.{self::B::noSuchMethod}(new core::_InvocationMirror::_withType(#C6, 0, #C3, #C4, [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView<dart.core::Symbol*, dynamic>] core::Map::unmodifiable<core::Symbol*, dynamic>(#C5))));
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  no-such-method-forwarder method bazz([@vm.inferred-type.metadata=dart.core::_Smi (value: 1)] dynamic a1, [@vm.inferred-type.metadata=dart.core::_Smi (value: 2)] dynamic a2, [@vm.inferred-type.metadata=dart.core::_Smi (value: 3)] dynamic a3, [[@vm.inferred-type.metadata=dart.core::_Smi (value: 4)] dynamic a4 = #C1, [@vm.inferred-type.metadata=dart.core::Null? (value: null)] dynamic a5 = #C1]) → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:4,getterSelectorId:5]  no-such-method-forwarder method bazz([@vm.inferred-type.metadata=dart.core::_Smi (value: 1)] dynamic a1, [@vm.inferred-type.metadata=dart.core::_Smi (value: 2)] dynamic a2, [@vm.inferred-type.metadata=dart.core::_Smi (value: 3)] dynamic a3, [[@vm.inferred-type.metadata=dart.core::_Smi (value: 4)] dynamic a4 = #C1, [@vm.inferred-type.metadata=dart.core::Null? (value: null)] dynamic a5 = #C1]) → dynamic
     return _in::unsafeCast<dynamic>([@vm.direct-call.metadata=#lib::B::noSuchMethod] [@vm.inferred-type.metadata=#lib::T1 (skip check)] this.{self::B::noSuchMethod}(new core::_InvocationMirror::_withType(#C7, 0, #C3, core::List::unmodifiable<dynamic>(<dynamic>[a1, a2, a3, a4, a5]), [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView<dart.core::Symbol*, dynamic>] core::Map::unmodifiable<core::Symbol*, dynamic>(#C5))));
 }
 abstract class C extends core::Object {
   synthetic constructor •() → self::C*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasTearOffUses:false]  method noSuchMethod(core::Invocation* invocation) → dynamic {
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasTearOffUses:false,methodOrSetterSelectorId:6,getterSelectorId:7]  method noSuchMethod(core::Invocation* invocation) → dynamic {
     return new self::T2::•();
   }
 }
@@ -67,28 +67,28 @@
   synthetic constructor •() → self::D*
     : super self::C::•()
     ;
-  no-such-method-forwarder get bar() → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:3]  no-such-method-forwarder get bar() → dynamic
     return _in::unsafeCast<dynamic>([@vm.direct-call.metadata=#lib::C::noSuchMethod] [@vm.inferred-type.metadata=#lib::T2 (skip check)] this.{self::C::noSuchMethod}(new core::_InvocationMirror::_withType(#C2, 1, #C3, #C4, [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView<dart.core::Symbol*, dynamic>] core::Map::unmodifiable<core::Symbol*, dynamic>(#C5))));
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  no-such-method-forwarder method foo() → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  no-such-method-forwarder method foo() → dynamic
     return _in::unsafeCast<dynamic>([@vm.direct-call.metadata=#lib::C::noSuchMethod] [@vm.inferred-type.metadata=#lib::T2 (skip check)] this.{self::C::noSuchMethod}(new core::_InvocationMirror::_withType(#C6, 0, #C3, #C4, [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView<dart.core::Symbol*, dynamic>] core::Map::unmodifiable<core::Symbol*, dynamic>(#C5))));
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  no-such-method-forwarder method bazz([@vm.inferred-type.metadata=dart.core::_Smi (value: 1)] dynamic a1, [@vm.inferred-type.metadata=dart.core::_Smi (value: 2)] dynamic a2, [@vm.inferred-type.metadata=dart.core::_Smi (value: 3)] dynamic a3, [[@vm.inferred-type.metadata=dart.core::_Smi (value: 4)] dynamic a4 = #C1, [@vm.inferred-type.metadata=dart.core::Null? (value: null)] dynamic a5 = #C1]) → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:4,getterSelectorId:5]  no-such-method-forwarder method bazz([@vm.inferred-type.metadata=dart.core::_Smi (value: 1)] dynamic a1, [@vm.inferred-type.metadata=dart.core::_Smi (value: 2)] dynamic a2, [@vm.inferred-type.metadata=dart.core::_Smi (value: 3)] dynamic a3, [[@vm.inferred-type.metadata=dart.core::_Smi (value: 4)] dynamic a4 = #C1, [@vm.inferred-type.metadata=dart.core::Null? (value: null)] dynamic a5 = #C1]) → dynamic
     return _in::unsafeCast<dynamic>([@vm.direct-call.metadata=#lib::C::noSuchMethod] [@vm.inferred-type.metadata=#lib::T2 (skip check)] this.{self::C::noSuchMethod}(new core::_InvocationMirror::_withType(#C7, 0, #C3, core::List::unmodifiable<dynamic>(<dynamic>[a1, a2, a3, a4, a5]), [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView<dart.core::Symbol*, dynamic>] core::Map::unmodifiable<core::Symbol*, dynamic>(#C5))));
 }
 class E extends core::Object implements self::A {
   synthetic constructor •() → self::E*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasTearOffUses:false]  method noSuchMethod(core::Invocation* invocation) → dynamic {
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasTearOffUses:false,methodOrSetterSelectorId:6,getterSelectorId:7]  method noSuchMethod(core::Invocation* invocation) → dynamic {
     return new self::T4::•();
   }
-  no-such-method-forwarder get bar() → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:3]  no-such-method-forwarder get bar() → dynamic
     return _in::unsafeCast<dynamic>([@vm.direct-call.metadata=#lib::E::noSuchMethod] [@vm.inferred-type.metadata=#lib::T4 (skip check)] this.{self::E::noSuchMethod}(new core::_InvocationMirror::_withType(#C2, 1, #C3, #C4, [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView<dart.core::Symbol*, dynamic>] core::Map::unmodifiable<core::Symbol*, dynamic>(#C5))));
 }
 class F extends core::Object {
   synthetic constructor •() → self::F*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method noSuchMethod(core::Invocation* invocation) → dynamic {
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:6,getterSelectorId:7]  method noSuchMethod(core::Invocation* invocation) → dynamic {
     return new self::T2::•();
   }
 }
@@ -96,7 +96,7 @@
   synthetic constructor •() → self::G*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method noSuchMethod(core::Invocation* invocation) → dynamic {
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:6,getterSelectorId:7]  method noSuchMethod(core::Invocation* invocation) → dynamic {
     return new self::T5::•();
   }
 }
@@ -104,9 +104,9 @@
   synthetic constructor •() → self::H*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method foo({[@vm.inferred-type.metadata=dart.core::_Smi (value: 1)] dynamic left = #C1, [@vm.inferred-type.metadata=dart.core::_Smi (value: 2)] dynamic right = #C1}) → dynamic
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  method foo({[@vm.inferred-type.metadata=dart.core::_Smi (value: 1)] dynamic left = #C1, [@vm.inferred-type.metadata=dart.core::_Smi (value: 2)] dynamic right = #C1}) → dynamic
     return new self::T6::•();
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method noSuchMethod(core::Invocation* invocation) → dynamic {
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:6,getterSelectorId:7]  method noSuchMethod(core::Invocation* invocation) → dynamic {
     return new self::T7::•();
   }
 }
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/param_types_before_strong_mode_checks.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/param_types_before_strong_mode_checks.dart.expect
index 8b68037..0378cce 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/param_types_before_strong_mode_checks.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/param_types_before_strong_mode_checks.dart.expect
@@ -6,30 +6,30 @@
   synthetic constructor •() → self::T0*
     : super core::Object::•()
     ;
-  abstract method foo() → void;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  abstract method foo() → void;
 }
 class T2 extends self::T0 {
   synthetic constructor •() → self::T2*
     : super self::T0::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method foo() → void {}
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  method foo() → void {}
 }
 class A extends core::Object {
   synthetic constructor •() → self::A*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasNonThisUses:false]  method method1(self::T0* t0) → void {
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,methodOrSetterSelectorId:3,getterSelectorId:4]  method method1(self::T0* t0) → void {
     [@vm.direct-call.metadata=#lib::T2::foo??] [@vm.inferred-type.metadata=!? (skip check)] t0.{self::T0::foo}();
   }
 }
 abstract class B extends core::Object {
-  abstract method method2(covariant dynamic arg) → void;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6]  abstract method method2(covariant dynamic arg) → void;
 }
 class C extends core::Object implements self::B {
   synthetic constructor •() → self::C*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method method2(covariant self::T0* t0) → void {
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6]  method method2(covariant self::T0* t0) → void {
     [@vm.direct-call.metadata=#lib::T2::foo??] [@vm.inferred-type.metadata=!? (skip check)] t0.{self::T0::foo}();
   }
 }
@@ -37,7 +37,7 @@
   synthetic constructor •() → self::D*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method method3(self::T0* t0) → void {
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:7,getterSelectorId:8]  method method3(self::T0* t0) → void {
     [@vm.direct-call.metadata=#lib::T2::foo??] [@vm.inferred-type.metadata=!? (skip check)] t0.{self::T0::foo}();
   }
 }
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/regress_37455.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/regress_37455.dart.expect
index 5575125..a7ca2b5 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/regress_37455.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/regress_37455.dart.expect
@@ -3,18 +3,18 @@
 import "dart:core" as core;
 
 class A extends core::Object {
-[@vm.inferred-type.metadata=dart.core::_GrowableList<dynamic>] [@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false]  final field core::List<dynamic>* afield;
+[@vm.inferred-type.metadata=dart.core::_GrowableList<dynamic>] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4]  final field core::List<dynamic>* afield;
   constructor •([@vm.inferred-type.metadata=dart.core::_GrowableList<dynamic>] core::List<dynamic>* afield) → self::A*
     : self::A::afield = afield, super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method toString() → core::String*
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  method toString() → core::String*
     return [@vm.direct-call.metadata=dart.core::_GrowableList::toString] [@vm.inferred-type.metadata=!? (skip check) (receiver not int)] [@vm.direct-call.metadata=#lib::A::afield] [@vm.inferred-type.metadata=dart.core::_GrowableList<dynamic>] this.{self::A::afield}.{core::Object::toString}();
 }
 class B extends core::Object {
   synthetic constructor •() → self::B*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasTearOffUses:false]  method _foo([@vm.inferred-type.metadata=dart._internal::ListIterator<dart.core::int*>] core::Iterator<core::int*>* iter) → core::List<dynamic>* {
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6]  method _foo([@vm.inferred-type.metadata=dart._internal::ListIterator<dart.core::int*>] core::Iterator<core::int*>* iter) → core::List<dynamic>* {
     core::List<dynamic>* result = <dynamic>[];
     while ([@vm.direct-call.metadata=dart._internal::ListIterator::moveNext] [@vm.inferred-type.metadata=dart.core::bool (skip check)] iter.{core::Iterator::moveNext}()) {
       if([@vm.direct-call.metadata=dart.core::_IntegerImplementation::<??] [@vm.inferred-type.metadata=dart.core::bool (skip check)] [@vm.direct-call.metadata=dart._internal::ListIterator::current] [@vm.inferred-type.metadata=int?] iter.{core::Iterator::current}.{core::num::<}(0)) {
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter16182.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter16182.dart.expect
index 3965b2c..4f0ebc6 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter16182.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter16182.dart.expect
@@ -10,21 +10,21 @@
   synthetic constructor •() → self::T1*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method doTest1() → void {
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  method doTest1() → void {
     self::ok = true;
   }
 }
 class A1 extends core::Object {
-[@vm.inferred-type.metadata=#lib::T1?] [@vm.procedure-attributes.metadata=hasDynamicUses:false,hasNonThisUses:false,hasTearOffUses:false]  field self::T1* foo = null;
+[@vm.inferred-type.metadata=#lib::T1?] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6]  field self::T1* foo = null;
   synthetic constructor •() → self::A1*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method call([dynamic a1 = #C1, dynamic a2 = #C1, dynamic a3 = #C1, [@vm.inferred-type.metadata=dart.core::_Smi?] dynamic a4 = #C1, [@vm.inferred-type.metadata=#lib::T1?] dynamic a5 = #C1]) → void {
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4]  method call([dynamic a1 = #C1, dynamic a2 = #C1, dynamic a3 = #C1, [@vm.inferred-type.metadata=dart.core::_Smi?] dynamic a4 = #C1, [@vm.inferred-type.metadata=#lib::T1?] dynamic a5 = #C1]) → void {
     [@vm.direct-call.metadata=#lib::A1::foo] this.{self::A1::foo} = _in::unsafeCast<self::T1*>(a5);
   }
 }
 class B1 extends core::Object {
-[@vm.inferred-type.metadata=#lib::A1] [@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false]  field self::A1* aa1 = new self::A1::•();
+[@vm.inferred-type.metadata=#lib::A1] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:7,getterSelectorId:8]  field self::A1* aa1 = new self::A1::•();
   synthetic constructor •() → self::B1*
     : super core::Object::•()
     ;
@@ -33,32 +33,32 @@
   synthetic constructor •() → self::T2*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method doTest2() → void {
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:9,getterSelectorId:10]  method doTest2() → void {
     self::ok = true;
   }
 }
 class A2 extends core::Object {
-[@vm.inferred-type.metadata=#lib::T2?] [@vm.procedure-attributes.metadata=hasDynamicUses:false,hasNonThisUses:false,hasTearOffUses:false]  field dynamic foo = null;
+[@vm.inferred-type.metadata=#lib::T2?] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6]  field dynamic foo = null;
   synthetic constructor •() → self::A2*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method call([dynamic a1 = #C1, dynamic a2 = #C1, dynamic a3 = #C1, [@vm.inferred-type.metadata=dart.core::_Smi?] dynamic a4 = #C1, [@vm.inferred-type.metadata=dart.core::_Smi?] dynamic a5 = #C1, [@vm.inferred-type.metadata=#lib::T2?] dynamic a6 = #C1]) → void {
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4]  method call([dynamic a1 = #C1, dynamic a2 = #C1, dynamic a3 = #C1, [@vm.inferred-type.metadata=dart.core::_Smi?] dynamic a4 = #C1, [@vm.inferred-type.metadata=dart.core::_Smi?] dynamic a5 = #C1, [@vm.inferred-type.metadata=#lib::T2?] dynamic a6 = #C1]) → void {
     [@vm.direct-call.metadata=#lib::A2::foo] this.{self::A2::foo} = a6;
   }
 }
 abstract class B2Base extends core::Object {
-[@vm.inferred-type.metadata=#lib::A2] [@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false]  field dynamic _aa = new self::A2::•();
+[@vm.inferred-type.metadata=#lib::A2] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:12,getterSelectorId:13]  field dynamic _aa = new self::A2::•();
   synthetic constructor •() → self::B2Base*
     : super core::Object::•()
     ;
-  get aa2() → dynamic
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:11]  get aa2() → dynamic
     return [@vm.direct-call.metadata=#lib::B2Base::_aa] [@vm.inferred-type.metadata=#lib::A2] this.{self::B2Base::_aa};
 }
 class B2 extends self::B2Base {
   synthetic constructor •() → self::B2*
     : super self::B2Base::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method doSuperCall() → void {
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:14,getterSelectorId:15]  method doSuperCall() → void {
     [@vm.call-site-attributes.metadata=receiverType:dynamic] [@vm.direct-call.metadata=#lib::A2::call] [@vm.inferred-type.metadata=!? (receiver not int)] [@vm.inferred-type.metadata=#lib::A2] super.{self::B2Base::aa2}.call(1, 2, 3, 4, 5, new self::T2::•());
   }
 }
@@ -66,21 +66,21 @@
   synthetic constructor •() → self::T3*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method doTest3() → void {
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:16,getterSelectorId:17]  method doTest3() → void {
     self::ok = true;
   }
 }
 class A3 extends core::Object {
-[@vm.inferred-type.metadata=#lib::T3?] [@vm.procedure-attributes.metadata=hasDynamicUses:false,hasNonThisUses:false,hasTearOffUses:false]  field dynamic foo = null;
+[@vm.inferred-type.metadata=#lib::T3?] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6]  field dynamic foo = null;
   synthetic constructor •() → self::A3*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method call([dynamic a1 = #C1, dynamic a2 = #C1, dynamic a3 = #C1, [@vm.inferred-type.metadata=dart.core::_Smi?] dynamic a4 = #C1, [@vm.inferred-type.metadata=dart.core::_Smi?] dynamic a5 = #C1, [@vm.inferred-type.metadata=dart.core::_Smi?] dynamic a6 = #C1, [@vm.inferred-type.metadata=#lib::T3?] dynamic a7 = #C1]) → void {
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4]  method call([dynamic a1 = #C1, dynamic a2 = #C1, dynamic a3 = #C1, [@vm.inferred-type.metadata=dart.core::_Smi?] dynamic a4 = #C1, [@vm.inferred-type.metadata=dart.core::_Smi?] dynamic a5 = #C1, [@vm.inferred-type.metadata=dart.core::_Smi?] dynamic a6 = #C1, [@vm.inferred-type.metadata=#lib::T3?] dynamic a7 = #C1]) → void {
     [@vm.direct-call.metadata=#lib::A3::foo] this.{self::A3::foo} = a7;
   }
 }
 class B3 extends core::Object {
-[@vm.inferred-type.metadata=#lib::A3] [@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  field self::A3* aa3 = new self::A3::•();
+[@vm.inferred-type.metadata=#lib::A3] [@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:18,getterSelectorId:19]  field self::A3* aa3 = new self::A3::•();
   synthetic constructor •() → self::B3*
     : super core::Object::•()
     ;
@@ -89,25 +89,25 @@
   synthetic constructor •() → self::T4*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method doTest4() → void {
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:20,getterSelectorId:21]  method doTest4() → void {
     self::ok = true;
   }
 }
 class A4 extends core::Object {
-[@vm.inferred-type.metadata=#lib::T4?] [@vm.procedure-attributes.metadata=hasDynamicUses:false,hasNonThisUses:false,hasTearOffUses:false]  field dynamic foo = null;
+[@vm.inferred-type.metadata=#lib::T4?] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6]  field dynamic foo = null;
   synthetic constructor •() → self::A4*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method call([dynamic a1 = #C1, dynamic a2 = #C1, dynamic a3 = #C1, [@vm.inferred-type.metadata=dart.core::_Smi?] dynamic a4 = #C1, [@vm.inferred-type.metadata=dart.core::_Smi?] dynamic a5 = #C1, [@vm.inferred-type.metadata=dart.core::_Smi?] dynamic a6 = #C1, [@vm.inferred-type.metadata=dart.core::_Smi?] dynamic a7 = #C1, [@vm.inferred-type.metadata=#lib::T4?] dynamic a8 = #C1]) → void {
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4]  method call([dynamic a1 = #C1, dynamic a2 = #C1, dynamic a3 = #C1, [@vm.inferred-type.metadata=dart.core::_Smi?] dynamic a4 = #C1, [@vm.inferred-type.metadata=dart.core::_Smi?] dynamic a5 = #C1, [@vm.inferred-type.metadata=dart.core::_Smi?] dynamic a6 = #C1, [@vm.inferred-type.metadata=dart.core::_Smi?] dynamic a7 = #C1, [@vm.inferred-type.metadata=#lib::T4?] dynamic a8 = #C1]) → void {
     [@vm.direct-call.metadata=#lib::A4::foo] this.{self::A4::foo} = a8;
   }
 }
 class B4 extends core::Object {
-[@vm.inferred-type.metadata=#lib::A4] [@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false]  field dynamic _aa = new self::A4::•();
+[@vm.inferred-type.metadata=#lib::A4] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:12,getterSelectorId:13]  field dynamic _aa = new self::A4::•();
   synthetic constructor •() → self::B4*
     : super core::Object::•()
     ;
-  get aa4() → dynamic
+[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false,getterSelectorId:22]  get aa4() → dynamic
     return [@vm.direct-call.metadata=#lib::B4::_aa] [@vm.inferred-type.metadata=#lib::A4] this.{self::B4::_aa};
 }
 [@vm.inferred-type.metadata=dart.core::bool?]static field core::bool* ok;
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_dynamic_method.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_dynamic_method.dart.expect
index 02808ea..616dc60 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_dynamic_method.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_dynamic_method.dart.expect
@@ -11,11 +11,11 @@
   synthetic constructor •() → self::B*
     : super self::A::•()
     ;
-[@vm.procedure-attributes.metadata=hasThisUses:false]  method foo() → core::int*
+[@vm.procedure-attributes.metadata=hasThisUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  method foo() → core::int*
     return [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+] [@vm.inferred-type.metadata=! (skip check)] 1.{core::num::+}([@vm.direct-call.metadata=#lib::B::foo] [@vm.inferred-type.metadata=!? (receiver not int)] [@vm.inferred-type.metadata=#lib::B] self::knownResult().foo() as{TypeError,ForDynamic} core::num*) as{TypeError} core::int*;
 }
 class TearOffDynamicMethod extends core::Object {
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false]  field dynamic bazz;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4]  field dynamic bazz;
   constructor •(dynamic arg) → self::TearOffDynamicMethod*
     : self::TearOffDynamicMethod::bazz = arg.foo, super core::Object::•() {
     this.{self::TearOffDynamicMethod::bazz}();
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart.expect
index e15b19c..f93e9bb 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart.expect
@@ -7,19 +7,19 @@
   synthetic constructor •() → self::A*
     : super core::Object::•()
     ;
-  abstract method foo() → core::int*;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  abstract method foo() → core::int*;
 }
 class B extends self::A {
   synthetic constructor •() → self::B*
     : super self::A::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasNonThisUses:false]  method foo() → core::int*
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  method foo() → core::int*
     return _in::unsafeCast<core::int*>([@vm.direct-call.metadata=dart.core::_IntegerImplementation::+] [@vm.inferred-type.metadata=int (skip check)] 1.{core::num::+}(_in::unsafeCast<core::num*>([@vm.direct-call.metadata=#lib::B::bar] [@vm.inferred-type.metadata=dart.core::_Smi (value: 3) (receiver not int)] [@vm.inferred-type.metadata=#lib::B] self::knownResult().bar())));
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method bar() → core::int*
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4]  method bar() → core::int*
     return 3;
 }
 class TearOffInterfaceMethod extends core::Object {
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false]  field dynamic bazz;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6]  field dynamic bazz;
   constructor •([@vm.inferred-type.metadata=#lib::B] self::A* arg) → self::TearOffInterfaceMethod*
     : self::TearOffInterfaceMethod::bazz = arg.{self::A::foo}, super core::Object::•()
     ;
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_super_method.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_super_method.dart.expect
index 73eb1d5..557d8ea 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_super_method.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_super_method.dart.expect
@@ -7,29 +7,29 @@
   synthetic constructor •() → self::A*
     : super core::Object::•()
     ;
-  abstract method foo() → core::int*;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  abstract method foo() → core::int*;
 }
 class B extends self::A {
   synthetic constructor •() → self::B*
     : super self::A::•()
     ;
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false]  method foo() → core::int*
+[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  method foo() → core::int*
     return _in::unsafeCast<core::int*>([@vm.direct-call.metadata=dart.core::_IntegerImplementation::+] [@vm.inferred-type.metadata=int (skip check)] 1.{core::num::+}(_in::unsafeCast<core::num*>([@vm.direct-call.metadata=#lib::B::foo] [@vm.inferred-type.metadata=int? (receiver not int)] [@vm.inferred-type.metadata=#lib::B] self::knownResult().foo())));
 }
 abstract class Base extends core::Object {
   synthetic constructor •() → self::Base*
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasNonThisUses:false]  method foo() → core::int*
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  method foo() → core::int*
     return _in::unsafeCast<core::int*>([@vm.direct-call.metadata=dart.core::_IntegerImplementation::+] [@vm.inferred-type.metadata=int (skip check)] 3.{core::num::+}(_in::unsafeCast<core::num*>([@vm.direct-call.metadata=#lib::B::foo] [@vm.inferred-type.metadata=int? (receiver not int)] [@vm.inferred-type.metadata=#lib::B] self::knownResult().foo())));
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasNonThisUses:false,hasTearOffUses:false]  method doCall(dynamic x) → core::int*
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4]  method doCall(dynamic x) → core::int*
     return [@vm.call-site-attributes.metadata=receiverType:dynamic] x.call() as{TypeError,ForDynamic} core::int*;
 }
 class TearOffSuperMethod extends self::Base {
   synthetic constructor •() → self::TearOffSuperMethod*
     : super self::Base::•()
     ;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  method bar() → core::int*
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6]  method bar() → core::int*
     return [@vm.direct-call.metadata=#lib::Base::doCall] [@vm.inferred-type.metadata=int? (skip check)] this.{self::Base::doCall}(super.{self::Base::foo});
 }
 [@vm.inferred-type.metadata=#lib::B?]static field self::A* aa = new self::B::•();
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/write_only_field.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/write_only_field.dart.expect
index 4cfb596..0e5a825 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/write_only_field.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/write_only_field.dart.expect
@@ -11,7 +11,7 @@
   }
 }
 class C extends core::Object {
-[@vm.inferred-type.metadata=#lib::B?] [@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false]  field self::B* instanceField = new self::B::•();
+[@vm.inferred-type.metadata=#lib::B?] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  field self::B* instanceField = new self::B::•();
   synthetic constructor •() → self::C*
     : super core::Object::•()
     ;
diff --git a/pkg/vm_service/CHANGELOG.md b/pkg/vm_service/CHANGELOG.md
index e2ee7c2..13403c7 100644
--- a/pkg/vm_service/CHANGELOG.md
+++ b/pkg/vm_service/CHANGELOG.md
@@ -1,11 +1,15 @@
 # Changelog
 
+## 2.3.2
+- Added `getClientName`, `setClientName`, and `requireResumePermission` methods.
+- Added `ClientName` class.
+
 ## 2.3.1
 - Fixed issue where `dart:io` extensions were not being exported.
 
 ## 2.3.0
 - Added `getHttpEnableTimelineLogging` and `setHttpEnableTimelineLogging` methods.
-- Added `HttpTimelineLoggingState` class.`
+- Added `HttpTimelineLoggingState` class.
 
 ## 2.2.1
 - Fixed issue where `TimelineEvent.toJson` always returned an empty map.
diff --git a/pkg/vm_service/example/vm_service_assert.dart b/pkg/vm_service/example/vm_service_assert.dart
index 65e42bc..0c3217b 100644
--- a/pkg/vm_service/example/vm_service_assert.dart
+++ b/pkg/vm_service/example/vm_service_assert.dart
@@ -365,6 +365,13 @@
   return obj;
 }
 
+vms.ClientName assertClientName(vms.ClientName obj) {
+  assertNotNull(obj);
+  assertString(obj.type);
+  assertString(obj.name);
+  return obj;
+}
+
 vms.CodeRef assertCodeRef(vms.CodeRef obj) {
   assertNotNull(obj);
   assertString(obj.type);
diff --git a/pkg/vm_service/java/.gitignore b/pkg/vm_service/java/.gitignore
index ccd4e34..6bbfbb4 100644
--- a/pkg/vm_service/java/.gitignore
+++ b/pkg/vm_service/java/.gitignore
@@ -3,6 +3,7 @@
 src/org/dartlang/vm/service/VmService.java
 src/org/dartlang/vm/service/consumer/AllocationProfileConsumer.java
 src/org/dartlang/vm/service/consumer/BreakpointConsumer.java
+src/org/dartlang/vm/service/consumer/ClientNameConsumer.java
 src/org/dartlang/vm/service/consumer/CpuSamplesConsumer.java
 src/org/dartlang/vm/service/consumer/EvaluateConsumer.java
 src/org/dartlang/vm/service/consumer/EvaluateInFrameConsumer.java
@@ -35,6 +36,7 @@
 src/org/dartlang/vm/service/element/ClassList.java
 src/org/dartlang/vm/service/element/ClassObj.java
 src/org/dartlang/vm/service/element/ClassRef.java
+src/org/dartlang/vm/service/element/ClientName.java
 src/org/dartlang/vm/service/element/Code.java
 src/org/dartlang/vm/service/element/CodeKind.java
 src/org/dartlang/vm/service/element/CodeRef.java
diff --git a/pkg/vm_service/java/version.properties b/pkg/vm_service/java/version.properties
index c025869..f56be80 100644
--- a/pkg/vm_service/java/version.properties
+++ b/pkg/vm_service/java/version.properties
@@ -1 +1 @@
-version=3.27
+version=3.29
diff --git a/pkg/vm_service/lib/src/vm_service.dart b/pkg/vm_service/lib/src/vm_service.dart
index 0f98458..1cb3174 100644
--- a/pkg/vm_service/lib/src/vm_service.dart
+++ b/pkg/vm_service/lib/src/vm_service.dart
@@ -28,7 +28,7 @@
         HeapSnapshotObjectNoData,
         HeapSnapshotObjectNullData;
 
-const String vmServiceVersion = '3.27.0';
+const String vmServiceVersion = '3.29.0';
 
 /// @optional
 const String optional = 'optional';
@@ -119,6 +119,7 @@
   'Class': Class.parse,
   'ClassHeapStats': ClassHeapStats.parse,
   'ClassList': ClassList.parse,
+  'ClientName': ClientName.parse,
   '@Code': CodeRef.parse,
   'Code': Code.parse,
   '@Context': ContextRef.parse,
@@ -195,6 +196,7 @@
   'evaluate': const ['InstanceRef', 'ErrorRef', 'Sentinel'],
   'evaluateInFrame': const ['InstanceRef', 'ErrorRef', 'Sentinel'],
   'getAllocationProfile': const ['AllocationProfile'],
+  'getClientName': const ['ClientName'],
   'getCpuSamples': const ['CpuSamples'],
   'getFlagList': const ['FlagList'],
   'getInboundReferences': const ['InboundReferences', 'Sentinel'],
@@ -219,7 +221,9 @@
   'reloadSources': const ['ReloadReport'],
   'removeBreakpoint': const ['Success'],
   'requestHeapSnapshot': const ['Success'],
+  'requirePermissionToResume': const ['Success'],
   'resume': const ['Success'],
+  'setClientName': const ['Success'],
   'setExceptionPauseMode': const ['Success'],
   'setFlag': const ['Success', 'Error'],
   'setLibraryDebuggable': const ['Success'],
@@ -447,6 +451,13 @@
   Future<AllocationProfile> getAllocationProfile(String isolateId,
       {bool reset, bool gc});
 
+  /// The `getClientName` RPC is used to retrieve the name associated with the
+  /// currently connected VM service client. If no name was previously set
+  /// through the [setClientName] RPC, a default name will be returned.
+  ///
+  /// See [ClientName].
+  Future<ClientName> getClientName();
+
   /// The `getCpuSamples` RPC is used to retrieve samples collected by the CPU
   /// profiler. Only samples collected in the time range `[timeOriginMicros,
   /// timeOriginMicros + timeExtentMicros]` will be reported.
@@ -690,8 +701,8 @@
   /// `(timeOriginMicros, timeOriginMicros + timeExtentMicros)`.
   ///
   /// If `getVMTimeline` is invoked while the current recorder is one of Fuchsia
-  /// or Macos or Systrace, the `114` error code, invalid timeline request, will be
-  /// returned as timeline events are handled by the OS in these modes.
+  /// or Macos or Systrace, the `114` error code, invalid timeline request, will
+  /// be returned as timeline events are handled by the OS in these modes.
   Future<Timeline> getVMTimeline({int timeOriginMicros, int timeExtentMicros});
 
   /// The `getVMTimelineFlags` RPC returns information about the current VM
@@ -775,6 +786,31 @@
   /// offset.
   Future<Success> requestHeapSnapshot(String isolateId);
 
+  /// The `requirePermissionToResume` RPC is used to change the pause/resume
+  /// behavior of isolates by providing a way for the VM service to wait for
+  /// approval to resume from some set of clients. This is useful for clients
+  /// which want to perform some operation on an isolate after a pause without
+  /// it being resumed by another client.
+  ///
+  /// If the `onPauseStart` parameter is `true`, isolates will not resume after
+  /// pausing on start until the client sends a `resume` request and all other
+  /// clients which need to provide resume approval for this pause type have
+  /// done so.
+  ///
+  /// If the `onPauseReload` parameter is `true`, isolates will not resume after
+  /// pausing after a reload until the client sends a `resume` request and all
+  /// other clients which need to provide resume approval for this pause type
+  /// have done so.
+  ///
+  /// If the `onPauseExit` parameter is `true`, isolates will not resume after
+  /// pausing on exit until the client sends a `resume` request and all other
+  /// clients which need to provide resume approval for this pause type have
+  /// done so.
+  ///
+  /// Important Notes:<strong>Important Notes:</strong>
+  Future<Success> requirePermissionToResume(
+      {bool onPauseStart, bool onPauseReload, bool onPauseExit});
+
   /// The `resume` RPC is used to resume execution of a paused isolate.
   ///
   /// If the `step` parameter is not provided, the program will resume regular
@@ -801,6 +837,15 @@
   Future<Success> resume(String isolateId,
       {/*StepOption*/ String step, int frameIndex});
 
+  /// The `setClientName` RPC is used to set a name to be associated with the
+  /// currently connected VM service client. If the `name` parameter is a
+  /// non-empty string, `name` will become the new name associated with the
+  /// client. If `name` is an empty string, the client's name will be reset to
+  /// its default name.
+  ///
+  /// See [Success].
+  Future<Success> setClientName(String name);
+
   /// The `setExceptionPauseMode` RPC is used to control if an isolate pauses
   /// when an exception is thrown.
   ///
@@ -1038,6 +1083,9 @@
             gc: params['gc'],
           );
           break;
+        case 'getClientName':
+          response = await _serviceImplementation.getClientName();
+          break;
         case 'getCpuSamples':
           response = await _serviceImplementation.getCpuSamples(
             params['isolateId'],
@@ -1165,6 +1213,13 @@
             params['isolateId'],
           );
           break;
+        case 'requirePermissionToResume':
+          response = await _serviceImplementation.requirePermissionToResume(
+            onPauseStart: params['onPauseStart'],
+            onPauseReload: params['onPauseReload'],
+            onPauseExit: params['onPauseExit'],
+          );
+          break;
         case 'resume':
           response = await _serviceImplementation.resume(
             params['isolateId'],
@@ -1172,6 +1227,11 @@
             frameIndex: params['frameIndex'],
           );
           break;
+        case 'setClientName':
+          response = await _serviceImplementation.setClientName(
+            params['name'],
+          );
+          break;
         case 'setExceptionPauseMode':
           response = await _serviceImplementation.setExceptionPauseMode(
             params['isolateId'],
@@ -1487,6 +1547,9 @@
   }
 
   @override
+  Future<ClientName> getClientName() => _call('getClientName');
+
+  @override
   Future<CpuSamples> getCpuSamples(
       String isolateId, int timeOriginMicros, int timeExtentMicros) {
     return _call('getCpuSamples', {
@@ -1669,6 +1732,22 @@
   }
 
   @override
+  Future<Success> requirePermissionToResume(
+      {bool onPauseStart, bool onPauseReload, bool onPauseExit}) {
+    Map m = {};
+    if (onPauseStart != null) {
+      m['onPauseStart'] = onPauseStart;
+    }
+    if (onPauseReload != null) {
+      m['onPauseReload'] = onPauseReload;
+    }
+    if (onPauseExit != null) {
+      m['onPauseExit'] = onPauseExit;
+    }
+    return _call('requirePermissionToResume', m);
+  }
+
+  @override
   Future<Success> resume(String isolateId,
       {/*StepOption*/ String step, int frameIndex}) {
     Map m = {'isolateId': isolateId};
@@ -1682,6 +1761,11 @@
   }
 
   @override
+  Future<Success> setClientName(String name) {
+    return _call('setClientName', {'name': name});
+  }
+
+  @override
   Future<Success> setExceptionPauseMode(
       String isolateId, /*ExceptionPauseMode*/ String mode) {
     return _call(
@@ -2718,6 +2802,34 @@
   String toString() => '[ClassList type: ${type}, classes: ${classes}]';
 }
 
+/// See [getClientName] and [setClientName].
+class ClientName extends Response {
+  static ClientName parse(Map<String, dynamic> json) =>
+      json == null ? null : ClientName._fromJson(json);
+
+  /// The name of the currently connected VM service client.
+  String name;
+
+  ClientName({
+    @required this.name,
+  });
+  ClientName._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
+    name = json['name'];
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    var json = <String, dynamic>{};
+    json['type'] = 'ClientName';
+    json.addAll({
+      'name': name,
+    });
+    return json;
+  }
+
+  String toString() => '[ClientName type: ${type}, name: ${name}]';
+}
+
 /// `CodeRef` is a reference to a `Code` object.
 class CodeRef extends ObjRef {
   static CodeRef parse(Map<String, dynamic> json) =>
@@ -6098,8 +6210,8 @@
       json == null ? null : TimelineFlags._fromJson(json);
 
   /// The name of the recorder currently in use. Recorder types include, but are
-  /// not limited to: Callback, Endless, Fuchsia, Macos, Ring, Startup, and Systrace.
-  /// Set to "null" if no recorder is currently set.
+  /// not limited to: Callback, Endless, Fuchsia, Macos, Ring, Startup, and
+  /// Systrace. Set to "null" if no recorder is currently set.
   String recorderName;
 
   /// The list of all available timeline streams.
diff --git a/pkg/vm_service/pubspec.yaml b/pkg/vm_service/pubspec.yaml
index fceea93..9c0912e 100644
--- a/pkg/vm_service/pubspec.yaml
+++ b/pkg/vm_service/pubspec.yaml
@@ -2,7 +2,7 @@
 description: >-
   A library to communicate with a service implementing the Dart VM
   service protocol.
-version: 2.3.1
+version: 2.3.2
 
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/vm_service
 
diff --git a/runtime/bin/builtin_impl_sources.gni b/runtime/bin/builtin_impl_sources.gni
index 97fcb96..385df57 100644
--- a/runtime/bin/builtin_impl_sources.gni
+++ b/runtime/bin/builtin_impl_sources.gni
@@ -17,6 +17,8 @@
   "crypto_win.cc",
   "dartutils.cc",
   "dartutils.h",
+  "dartdev_utils.cc",
+  "dartdev_utils.h",
   "directory.cc",
   "directory.h",
   "directory_android.cc",
@@ -24,6 +26,8 @@
   "directory_linux.cc",
   "directory_macos.cc",
   "directory_win.cc",
+  "exe_utils.h",
+  "exe_utils.cc",
   "extensions.h",
   "extensions.cc",
   "extensions_android.cc",
diff --git a/runtime/bin/dartdev_utils.cc b/runtime/bin/dartdev_utils.cc
new file mode 100644
index 0000000..b59f7a8
--- /dev/null
+++ b/runtime/bin/dartdev_utils.cc
@@ -0,0 +1,81 @@
+// Copyright (c) 2020, 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.
+
+#include "bin/dartdev_utils.h"
+
+#include <memory>
+
+#include "bin/directory.h"
+#include "bin/exe_utils.h"
+#include "bin/file.h"
+#include "platform/utils.h"
+
+namespace dart {
+namespace bin {
+
+typedef struct {
+  const char* command;
+  const char* snapshot_name;
+} DartDevCommandMapping;
+
+static const DartDevCommandMapping dart_dev_commands[] = {
+    {"format", "dartfmt.dart.snapshot"},
+    {"pub", "pub.dart.snapshot"},
+};
+
+static const DartDevCommandMapping* FindCommandMapping(const char* command) {
+  intptr_t num_commands =
+      sizeof(dart_dev_commands) / sizeof(dart_dev_commands[0]);
+  for (intptr_t i = 0; i < num_commands; i++) {
+    const DartDevCommandMapping& command_mapping = dart_dev_commands[i];
+    if (strcmp(command, command_mapping.command) == 0) {
+      return &command_mapping;
+    }
+  }
+  return nullptr;
+}
+
+bool DartDevUtils::ShouldParseCommand(const char* script_uri) {
+  return !File::ExistsUri(nullptr, script_uri);
+}
+
+bool DartDevUtils::TryParseCommandFromScriptName(char** script_name) {
+  const DartDevCommandMapping* command = FindCommandMapping(*script_name);
+
+  // Either the command doesn't exist or we've been given an HTTP resource.
+  if (command == nullptr) {
+    return true;
+  }
+
+  // |dir_prefix| includes the last path seperator.
+  auto dir_prefix = std::unique_ptr<char, void (*)(void*)>(
+      EXEUtils::GetDirectoryPrefixFromExeName(), free);
+
+  // First assume we're in dart-sdk/bin.
+  char* snapshot_path = Utils::SCreate("%s/snapshots/%s", dir_prefix.get(),
+                                       command->snapshot_name);
+  if (File::Exists(nullptr, snapshot_path)) {
+    free(*script_name);
+    *script_name = snapshot_path;
+    return true;
+  }
+  free(snapshot_path);
+
+  // If we're not in dart-sdk/bin, we might be in one of the $SDK/out/*
+  // directories. Try to use a snapshot from a previously built SDK.
+  snapshot_path = Utils::SCreate("%s/dart-sdk/bin/snapshots/%s",
+                                 dir_prefix.get(), command->snapshot_name);
+  if (File::Exists(nullptr, snapshot_path)) {
+    free(*script_name);
+    *script_name = snapshot_path;
+    return true;
+  }
+  free(snapshot_path);
+  Syslog::PrintErr("Could not find snapshot for command '%s': %s\n",
+                   *script_name, command->snapshot_name);
+  return false;
+}
+
+}  // namespace bin
+}  // namespace dart
diff --git a/runtime/bin/dartdev_utils.h b/runtime/bin/dartdev_utils.h
new file mode 100644
index 0000000..d5828cc
--- /dev/null
+++ b/runtime/bin/dartdev_utils.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2020, 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.
+
+#ifndef RUNTIME_BIN_DARTDEV_UTILS_H_
+#define RUNTIME_BIN_DARTDEV_UTILS_H_
+
+#include "platform/globals.h"
+
+namespace dart {
+namespace bin {
+
+class DartDevUtils {
+ public:
+  // Returns true if there does not exist a file at |script_uri|.
+  static bool ShouldParseCommand(const char* script_uri);
+
+  // Returns true if we were successfully able to parse a DartDev command.
+  // Returns false if we were unable to find a matching command or a matching
+  // snapshot does not exist, in which case the VM should exit.
+  static bool TryParseCommandFromScriptName(char** script_name);
+
+ private:
+  DISALLOW_ALLOCATION();
+  DISALLOW_IMPLICIT_CONSTRUCTORS(DartDevUtils);
+};
+
+}  // namespace bin
+}  // namespace dart
+
+#endif  // RUNTIME_BIN_DARTDEV_UTILS_H_
diff --git a/runtime/bin/dfe.cc b/runtime/bin/dfe.cc
index 2ea68d9..d2773211 100644
--- a/runtime/bin/dfe.cc
+++ b/runtime/bin/dfe.cc
@@ -10,6 +10,7 @@
 #include "bin/dartutils.h"
 #include "bin/directory.h"
 #include "bin/error_exit.h"
+#include "bin/exe_utils.h"
 #include "bin/file.h"
 #include "bin/main_options.h"
 #include "bin/platform.h"
@@ -41,49 +42,6 @@
 const char kKernelServiceSnapshot[] = "kernel-service.dart.snapshot";
 const char kSnapshotsDirectory[] = "snapshots";
 
-static char* GetDirectoryPrefixFromExeName() {
-  const char* name = nullptr;
-  const int kTargetSize = 4096;
-  char target[kTargetSize];
-  intptr_t target_size =
-      Platform::ResolveExecutablePathInto(target, kTargetSize);
-  if (target_size > 0 && target_size < kTargetSize - 1) {
-    target[target_size] = 0;
-    name = target;
-  }
-  if (name == nullptr) {
-    name = Platform::GetExecutableName();
-    target_size = strlen(name);
-  }
-  Namespace* namespc = Namespace::Create(Namespace::Default());
-  if (File::GetType(namespc, name, false) == File::kIsLink) {
-    // Resolve the link without creating Dart scope String.
-    name = File::LinkTarget(namespc, name, target, kTargetSize);
-    if (name == NULL) {
-      return strdup("");
-    }
-    target_size = strlen(name);
-  }
-  namespc->Release();
-  const char* sep = File::PathSeparator();
-  const intptr_t sep_length = strlen(sep);
-
-  for (intptr_t i = target_size - 1; i >= 0; --i) {
-    const char* str = name + i;
-    if (strncmp(str, sep, sep_length) == 0
-#if defined(HOST_OS_WINDOWS)
-        // TODO(aam): GetExecutableName doesn't work reliably on Windows,
-        // the code below is a workaround for that (we would be using
-        // just single Platform::Separator instead of both slashes if it did).
-        || *str == '/'
-#endif
-    ) {
-      return Utils::StrNDup(name, i + 1);
-    }
-  }
-  return strdup("");
-}
-
 DFE::DFE()
     : use_dfe_(false),
       use_incremental_compiler_(false),
@@ -156,7 +114,7 @@
 
   // |dir_prefix| includes the last path seperator.
   auto dir_prefix = std::unique_ptr<char, void (*)(void*)>(
-      GetDirectoryPrefixFromExeName(), free);
+      EXEUtils::GetDirectoryPrefixFromExeName(), free);
 
   if (target_abi_version != Options::kAbiVersionUnset) {
     kernel_service_dill_ = nullptr;
diff --git a/runtime/bin/exe_utils.cc b/runtime/bin/exe_utils.cc
new file mode 100644
index 0000000..f077ad5
--- /dev/null
+++ b/runtime/bin/exe_utils.cc
@@ -0,0 +1,59 @@
+// Copyright (c) 2020, 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.
+
+#include "bin/exe_utils.h"
+
+#include "bin/directory.h"
+#include "bin/file.h"
+#include "bin/platform.h"
+#include "platform/utils.h"
+
+namespace dart {
+namespace bin {
+
+char* EXEUtils::GetDirectoryPrefixFromExeName() {
+  const char* name = nullptr;
+  const int kTargetSize = 4096;
+  char target[kTargetSize];
+  intptr_t target_size =
+      Platform::ResolveExecutablePathInto(target, kTargetSize);
+  if (target_size > 0 && target_size < kTargetSize - 1) {
+    target[target_size] = 0;
+    name = target;
+  }
+  if (name == nullptr) {
+    name = Platform::GetExecutableName();
+    target_size = strlen(name);
+  }
+  Namespace* namespc = Namespace::Create(Namespace::Default());
+  if (File::GetType(namespc, name, false) == File::kIsLink) {
+    // Resolve the link without creating Dart scope String.
+    name = File::LinkTarget(namespc, name, target, kTargetSize);
+    if (name == NULL) {
+      return strdup("");
+    }
+    target_size = strlen(name);
+  }
+  namespc->Release();
+  const char* sep = File::PathSeparator();
+  const intptr_t sep_length = strlen(sep);
+
+  for (intptr_t i = target_size - 1; i >= 0; --i) {
+    const char* str = name + i;
+    if (strncmp(str, sep, sep_length) == 0
+#if defined(HOST_OS_WINDOWS)
+        // TODO(aam): GetExecutableName doesn't work reliably on Windows,
+        // the code below is a workaround for that (we would be using
+        // just single Platform::Separator instead of both slashes if it did).
+        || *str == '/'
+#endif
+    ) {
+      return Utils::StrNDup(name, i + 1);
+    }
+  }
+  return strdup("");
+}
+
+}  // namespace bin
+}  // namespace dart
diff --git a/runtime/bin/exe_utils.h b/runtime/bin/exe_utils.h
new file mode 100644
index 0000000..42d27fe
--- /dev/null
+++ b/runtime/bin/exe_utils.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2020, 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.
+
+#ifndef RUNTIME_BIN_EXE_UTILS_H_
+#define RUNTIME_BIN_EXE_UTILS_H_
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "include/dart_api.h"
+#include "platform/globals.h"
+
+namespace dart {
+namespace bin {
+
+class EXEUtils {
+ public:
+  // Returns the path to the directory the current executable resides in.
+  static char* GetDirectoryPrefixFromExeName();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(EXEUtils);
+};
+
+}  // namespace bin
+}  // namespace dart
+
+#endif  // RUNTIME_BIN_EXE_UTILS_H_
diff --git a/runtime/bin/file.h b/runtime/bin/file.h
index 4255ba8..2716d41 100644
--- a/runtime/bin/file.h
+++ b/runtime/bin/file.h
@@ -220,6 +220,7 @@
 #endif
 
   static bool Exists(Namespace* namespc, const char* path);
+  static bool ExistsUri(Namespace* namespc, const char* uri);
   static bool Create(Namespace* namespc, const char* path);
   static bool CreateLink(Namespace* namespc,
                          const char* path,
diff --git a/runtime/bin/file_android.cc b/runtime/bin/file_android.cc
index c79c1e0..151c969 100644
--- a/runtime/bin/file_android.cc
+++ b/runtime/bin/file_android.cc
@@ -241,15 +241,23 @@
   return new File(new FileHandle(fd));
 }
 
-File* File::OpenUri(Namespace* namespc, const char* uri, FileOpenMode mode) {
+static Utils::CStringUniquePtr DecodeUri(const char* uri) {
   const char* path = (strlen(uri) >= 8 && strncmp(uri, "file:///", 8) == 0)
       ? uri + 7 : uri;
   UriDecoder uri_decoder(path);
-  if (uri_decoder.decoded() == NULL) {
+  if (uri_decoder.decoded() == nullptr) {
     errno = EINVAL;
-    return NULL;
+    return Utils::CreateCStringUniquePtr(nullptr);
   }
-  return File::Open(namespc, uri_decoder.decoded(), mode);
+  return Utils::CreateCStringUniquePtr(strdup(uri_decoder.decoded()));
+}
+
+File* File::OpenUri(Namespace* namespc, const char* uri, FileOpenMode mode) {
+  auto path = DecodeUri(uri);
+  if (path == nullptr) {
+    return nullptr;
+  }
+  return File::Open(namespc, path.get(), mode);
 }
 
 File* File::OpenStdio(int fd) {
@@ -267,6 +275,14 @@
   }
 }
 
+bool File::ExistsUri(Namespace* namespc, const char* uri) {
+  auto path = DecodeUri(uri);
+  if (path == nullptr) {
+    return false;
+  }
+  return File::Exists(namespc, path.get());
+}
+
 bool File::Create(Namespace* namespc, const char* name) {
   NamespaceScope ns(namespc, name);
   const int fd = TEMP_FAILURE_RETRY(
diff --git a/runtime/bin/file_fuchsia.cc b/runtime/bin/file_fuchsia.cc
index 9445de6..dd618a5 100644
--- a/runtime/bin/file_fuchsia.cc
+++ b/runtime/bin/file_fuchsia.cc
@@ -243,19 +243,23 @@
   return OpenFD(fd);
 }
 
-File* File::OpenUri(Namespace* namespc, const char* uri, FileOpenMode mode) {
+static Utils::CStringUniquePtr DecodeUri(const char* uri) {
   const char* path = (strlen(uri) >= 8 && strncmp(uri, "file:///", 8) == 0)
       ? uri + 7 : uri;
   UriDecoder uri_decoder(path);
-  if (uri_decoder.decoded() == NULL) {
+  if (uri_decoder.decoded() == nullptr) {
     errno = EINVAL;
-    return NULL;
+    return Utils::CreateCStringUniquePtr(nullptr);
   }
-  return File::Open(namespc, uri_decoder.decoded(), mode);
+  return Utils::CreateCStringUniquePtr(strdup(uri_decoder.decoded()));
 }
 
-File* File::OpenStdio(int fd) {
-  return new File(new FileHandle(fd));
+File* File::OpenUri(Namespace* namespc, const char* uri, FileOpenMode mode) {
+  auto path = DecodeUri(uri);
+  if (path == nullptr) {
+    return nullptr;
+  }
+  return File::Open(namespc, path.get(), mode);
 }
 
 bool File::Exists(Namespace* namespc, const char* name) {
@@ -268,6 +272,14 @@
   return false;
 }
 
+bool File::ExistsUri(Namespace* namespc, const char* uri) {
+  auto path = DecodeUri(uri);
+  if (path == nullptr) {
+    return false;
+  }
+  return File::Exists(namespc, path.get());
+}
+
 bool File::Create(Namespace* namespc, const char* name) {
   NamespaceScope ns(namespc, name);
   const int fd = NO_RETRY_EXPECTED(
diff --git a/runtime/bin/file_linux.cc b/runtime/bin/file_linux.cc
index bd2f020..e8efaa1 100644
--- a/runtime/bin/file_linux.cc
+++ b/runtime/bin/file_linux.cc
@@ -244,15 +244,23 @@
   return OpenFD(fd);
 }
 
-File* File::OpenUri(Namespace* namespc, const char* uri, FileOpenMode mode) {
+static Utils::CStringUniquePtr DecodeUri(const char* uri) {
   const char* path = (strlen(uri) >= 8 && strncmp(uri, "file:///", 8) == 0)
       ? uri + 7 : uri;
   UriDecoder uri_decoder(path);
-  if (uri_decoder.decoded() == NULL) {
+  if (uri_decoder.decoded() == nullptr) {
     errno = EINVAL;
-    return NULL;
+    return Utils::CreateCStringUniquePtr(nullptr);
   }
-  return File::Open(namespc, uri_decoder.decoded(), mode);
+  return Utils::CreateCStringUniquePtr(strdup(uri_decoder.decoded()));
+}
+
+File* File::OpenUri(Namespace* namespc, const char* uri, FileOpenMode mode) {
+  auto path = DecodeUri(uri);
+  if (path == nullptr) {
+    return nullptr;
+  }
+  return File::Open(namespc, path.get(), mode);
 }
 
 File* File::OpenStdio(int fd) {
@@ -270,6 +278,14 @@
   }
 }
 
+bool File::ExistsUri(Namespace* namespc, const char* uri) {
+  auto path = DecodeUri(uri);
+  if (path == nullptr) {
+    return false;
+  }
+  return File::Exists(namespc, path.get());
+}
+
 bool File::Create(Namespace* namespc, const char* name) {
   NamespaceScope ns(namespc, name);
   const int fd = TEMP_FAILURE_RETRY(
diff --git a/runtime/bin/file_macos.cc b/runtime/bin/file_macos.cc
index 25af65b9..334252e 100644
--- a/runtime/bin/file_macos.cc
+++ b/runtime/bin/file_macos.cc
@@ -286,15 +286,23 @@
   return new File(new FileHandle(fd));
 }
 
-File* File::OpenUri(Namespace* namespc, const char* uri, FileOpenMode mode) {
+static Utils::CStringUniquePtr DecodeUri(const char* uri) {
   const char* path = (strlen(uri) >= 8 && strncmp(uri, "file:///", 8) == 0)
       ? uri + 7 : uri;
   UriDecoder uri_decoder(path);
-  if (uri_decoder.decoded() == NULL) {
+  if (uri_decoder.decoded() == nullptr) {
     errno = EINVAL;
-    return NULL;
+    return Utils::CreateCStringUniquePtr(nullptr);
   }
-  return File::Open(namespc, uri_decoder.decoded(), mode);
+  return Utils::CreateCStringUniquePtr(strdup(uri_decoder.decoded()));
+}
+
+File* File::OpenUri(Namespace* namespc, const char* uri, FileOpenMode mode) {
+  auto path = DecodeUri(uri);
+  if (path == nullptr) {
+    return nullptr;
+  }
+  return File::Open(namespc, path.get(), mode);
 }
 
 File* File::OpenStdio(int fd) {
@@ -311,6 +319,14 @@
   }
 }
 
+bool File::ExistsUri(Namespace* namespc, const char* uri) {
+  auto path = DecodeUri(uri);
+  if (path == nullptr) {
+    return false;
+  }
+  return File::Exists(namespc, path.get());
+}
+
 bool File::Create(Namespace* namespc, const char* name) {
   int fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CREAT, 0666));
   if (fd < 0) {
diff --git a/runtime/bin/file_win.cc b/runtime/bin/file_win.cc
index 975bd12..48c384a 100644
--- a/runtime/bin/file_win.cc
+++ b/runtime/bin/file_win.cc
@@ -353,6 +353,15 @@
   return StatHelper(system_name.wide(), &st);
 }
 
+bool File::ExistsUri(Namespace* namespc, const char* uri) {
+  UriDecoder uri_decoder(uri);
+  if (uri_decoder.decoded() == nullptr) {
+    SetLastError(ERROR_INVALID_NAME);
+    return false;
+  }
+  return File::Exists(namespc, uri_decoder.decoded());
+}
+
 bool File::Create(Namespace* namespc, const char* name) {
   Utf8ToWideScope system_name(name);
   int fd = _wopen(system_name.wide(), O_RDONLY | O_CREAT, 0666);
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index b98754b..98d5974 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -15,9 +15,9 @@
 #include "bin/builtin.h"
 #include "bin/console.h"
 #include "bin/crashpad.h"
+#include "bin/dartdev_utils.h"
 #include "bin/dartutils.h"
 #include "bin/dfe.h"
-#include "bin/directory.h"
 #include "bin/error_exit.h"
 #include "bin/eventhandler.h"
 #include "bin/extensions.h"
@@ -37,6 +37,7 @@
 #include "platform/hashmap.h"
 #include "platform/syslog.h"
 #include "platform/text_buffer.h"
+#include "platform/utils.h"
 
 extern "C" {
 extern const uint8_t kDartVmSnapshotData[];
@@ -1072,31 +1073,47 @@
 #endif
 
   // Parse command line arguments.
-  if (app_snapshot == nullptr &&
-      Options::ParseArguments(argc, argv, vm_run_app_snapshot, &vm_options,
-                              &script_name, &dart_options, &print_flags_seen,
-                              &verbose_debug_seen) < 0) {
-    if (Options::help_option()) {
-      Options::PrintUsage();
-      Platform::Exit(0);
-    } else if (Options::version_option()) {
-      Options::PrintVersion();
-      Platform::Exit(0);
-    } else if (print_flags_seen) {
-      // Will set the VM flags, print them out and then we exit as no
-      // script was specified on the command line.
-      char* error = Dart_SetVMFlags(vm_options.count(), vm_options.arguments());
-      if (error != NULL) {
-        Syslog::PrintErr("Setting VM flags failed: %s\n", error);
-        free(error);
+  if (app_snapshot == nullptr) {
+    int result = Options::ParseArguments(
+        argc, argv, vm_run_app_snapshot, &vm_options, &script_name,
+        &dart_options, &print_flags_seen, &verbose_debug_seen);
+    if (result < 0) {
+      if (Options::help_option()) {
+        Options::PrintUsage();
+        Platform::Exit(0);
+      } else if (Options::version_option()) {
+        Options::PrintVersion();
+        Platform::Exit(0);
+      } else if (print_flags_seen) {
+        // Will set the VM flags, print them out and then we exit as no
+        // script was specified on the command line.
+        char* error =
+            Dart_SetVMFlags(vm_options.count(), vm_options.arguments());
+        if (error != NULL) {
+          Syslog::PrintErr("Setting VM flags failed: %s\n", error);
+          free(error);
+          Platform::Exit(kErrorExitCode);
+        }
+        Platform::Exit(0);
+      } else {
+        Options::PrintUsage();
         Platform::Exit(kErrorExitCode);
       }
-      Platform::Exit(0);
-    } else {
-      Options::PrintUsage();
+    }
+
+    // Try to parse a DartDev command if script_name doesn't point to a valid
+    // file. If the command isn't valid we fall through to handle the
+    // possibility that the script_name points to a HTTP resource. If the
+    // relevant snapshot can't be found we abort execution.
+    if (DartDevUtils::ShouldParseCommand(script_name) &&
+        !DartDevUtils::TryParseCommandFromScriptName(&script_name)) {
       Platform::Exit(kErrorExitCode);
     }
   }
+
+  // At this point, script_name now points to either a script or a snapshot
+  // determined by DartDevUtils above.
+
   DartUtils::SetEnvironment(Options::environment());
 
   if (Options::suppress_core_dump()) {
diff --git a/runtime/bin/main_options.cc b/runtime/bin/main_options.cc
index 9eaf8c4..a07b096 100644
--- a/runtime/bin/main_options.cc
+++ b/runtime/bin/main_options.cc
@@ -440,7 +440,7 @@
 
   // Get the script name.
   if (i < argc) {
-    *script_name = argv[i];
+    *script_name = strdup(argv[i]);
     i++;
   } else {
     return -1;
diff --git a/runtime/docs/gc.md b/runtime/docs/gc.md
index 37303f1..6b8aaaa 100644
--- a/runtime/docs/gc.md
+++ b/runtime/docs/gc.md
@@ -12,20 +12,45 @@
 
 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.
 
+| Pointer    | Referent                                |
+| ---        | ---                                     |
+| 0x00000002 | Small integer 1                         |
+| 0xFFFFFFFE | Small integer -1                        |
+| 0x00A00001 | Heap object at 0x00A00000, in old-space |
+| 0x00B00005 | Heap object at 0x00B00004, in new-space |
+
 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.
 
 ## Scavenge
 
-See [Cheney's algorithm](https://dl.acm.org/citation.cfm?doid=362790.362798).
+See [Cheney's algorithm](https://en.wikipedia.org/wiki/Cheney's_algorithm).
 
 ## Mark-Sweep
 
+All objects have a bit in their header called the mark bit. At the start of a collection cycle, all objects have this bit clear.
+
+During the marking phase, the collector visits each of the root pointers. If the target object is an old-space object and its mark bit is clear, the mark bit is set and the target added to the marking stack (grey set). The collector then removes and visits objects in the marking stack, marking more old-space objects and adding them to the marking stack, until the marking stack is empty. At this point, all reachable objects have their mark bits set and all unreachable objects have their mark bits clear.
+
+During the sweeping phase, the collector visits each old-space object. If the mark bit is clear, the object's memory is added to a [free list](https://github.com/dart-lang/sdk/blob/master/runtime/vm/heap/freelist.h) to be used for future allocations. Otherwise the object's mark bit is cleared. If every object on some page is unreachable, the page is released to the OS.
+
+Note that because we do not mark new-space objects, we treat every object in new-space as a root during old-space collections. This property makes new-space and old-space collections more independent, and in particular allows a scavenge to run at the same time as concurrent marking.
+
 ## Mark-Compact
 
 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.
+
 ## 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. 
diff --git a/runtime/docs/images/aot-ic-dictionary.png b/runtime/docs/images/aot-ic-dictionary.png
new file mode 100644
index 0000000..0010089
--- /dev/null
+++ b/runtime/docs/images/aot-ic-dictionary.png
Binary files differ
diff --git a/runtime/docs/images/aot-ic-linear.png b/runtime/docs/images/aot-ic-linear.png
new file mode 100644
index 0000000..4ab8b4e
--- /dev/null
+++ b/runtime/docs/images/aot-ic-linear.png
Binary files differ
diff --git a/runtime/docs/images/aot-ic-monomorphic.png b/runtime/docs/images/aot-ic-monomorphic.png
new file mode 100644
index 0000000..a2e25da
--- /dev/null
+++ b/runtime/docs/images/aot-ic-monomorphic.png
Binary files differ
diff --git a/runtime/docs/images/aot-ic-singletarget.png b/runtime/docs/images/aot-ic-singletarget.png
new file mode 100644
index 0000000..4aed0c5
--- /dev/null
+++ b/runtime/docs/images/aot-ic-singletarget.png
Binary files differ
diff --git a/runtime/docs/images/aot-ic-unlinked.png b/runtime/docs/images/aot-ic-unlinked.png
new file mode 100644
index 0000000..bb764c6
--- /dev/null
+++ b/runtime/docs/images/aot-ic-unlinked.png
Binary files differ
diff --git a/runtime/docs/images/aot.png b/runtime/docs/images/aot.png
new file mode 100644
index 0000000..1b777fd
--- /dev/null
+++ b/runtime/docs/images/aot.png
Binary files differ
diff --git a/runtime/docs/images/dart-to-kernel.png b/runtime/docs/images/dart-to-kernel.png
new file mode 100644
index 0000000..129626c
--- /dev/null
+++ b/runtime/docs/images/dart-to-kernel.png
Binary files differ
diff --git a/runtime/docs/images/flutter-cfe.png b/runtime/docs/images/flutter-cfe.png
new file mode 100644
index 0000000..cf67b39
--- /dev/null
+++ b/runtime/docs/images/flutter-cfe.png
Binary files differ
diff --git a/runtime/docs/images/images.graffle b/runtime/docs/images/images.graffle
new file mode 100644
index 0000000..fb77688
--- /dev/null
+++ b/runtime/docs/images/images.graffle
Binary files differ
diff --git a/runtime/docs/images/inline-cache-1.png b/runtime/docs/images/inline-cache-1.png
new file mode 100644
index 0000000..0edf3b6
--- /dev/null
+++ b/runtime/docs/images/inline-cache-1.png
Binary files differ
diff --git a/runtime/docs/images/isolates.png b/runtime/docs/images/isolates.png
new file mode 100644
index 0000000..13da2c6
--- /dev/null
+++ b/runtime/docs/images/isolates.png
Binary files differ
diff --git a/runtime/docs/images/kernel-loaded-1.png b/runtime/docs/images/kernel-loaded-1.png
new file mode 100644
index 0000000..7acce6e
--- /dev/null
+++ b/runtime/docs/images/kernel-loaded-1.png
Binary files differ
diff --git a/runtime/docs/images/kernel-loaded-2.png b/runtime/docs/images/kernel-loaded-2.png
new file mode 100644
index 0000000..2580701
--- /dev/null
+++ b/runtime/docs/images/kernel-loaded-2.png
Binary files differ
diff --git a/runtime/docs/images/kernel-service.png b/runtime/docs/images/kernel-service.png
new file mode 100644
index 0000000..7e19145
--- /dev/null
+++ b/runtime/docs/images/kernel-service.png
Binary files differ
diff --git a/runtime/docs/images/optimizing-compilation.png b/runtime/docs/images/optimizing-compilation.png
new file mode 100644
index 0000000..080df28
--- /dev/null
+++ b/runtime/docs/images/optimizing-compilation.png
Binary files differ
diff --git a/runtime/docs/images/raw-function-lazy-compile.png b/runtime/docs/images/raw-function-lazy-compile.png
new file mode 100644
index 0000000..39d69ac
--- /dev/null
+++ b/runtime/docs/images/raw-function-lazy-compile.png
Binary files differ
diff --git a/runtime/docs/images/snapshot-appjit.png b/runtime/docs/images/snapshot-appjit.png
new file mode 100644
index 0000000..0afd9ba
--- /dev/null
+++ b/runtime/docs/images/snapshot-appjit.png
Binary files differ
diff --git a/runtime/docs/images/snapshot-with-code.png b/runtime/docs/images/snapshot-with-code.png
new file mode 100644
index 0000000..b6da0c5
--- /dev/null
+++ b/runtime/docs/images/snapshot-with-code.png
Binary files differ
diff --git a/runtime/docs/images/snapshot.png b/runtime/docs/images/snapshot.png
new file mode 100644
index 0000000..14d71a0
--- /dev/null
+++ b/runtime/docs/images/snapshot.png
Binary files differ
diff --git a/runtime/docs/images/unoptimized-compilation.png b/runtime/docs/images/unoptimized-compilation.png
new file mode 100644
index 0000000..aabfa0b
--- /dev/null
+++ b/runtime/docs/images/unoptimized-compilation.png
Binary files differ
diff --git a/runtime/docs/index.md b/runtime/docs/index.md
new file mode 100644
index 0000000..e446544
--- /dev/null
+++ b/runtime/docs/index.md
@@ -0,0 +1,393 @@
+# Introduction to Dart VM
+
+
+!!! WARNING
+    This document is work in progress and is currently being written. Please contact Vyacheslav Egorov ([by mail](vegorov@google.com) or [@mraleph](http://twitter.com/mraleph)) if you have any questions, suggestions, bug reports. **Last update: January 29 2020**
+
+!!! sourcecode "Purpose of this document"
+    This document is intended as a reference for new members of the Dart VM team, potential external contributors or just anybody interested in VM internals. It starts with a high-level overview of the Dart VM and then proceeds to describe various components of the VM in more details.
+
+Dart VM is a collection of components for executing Dart code natively. Notably it includes the following:
+
+* Runtime System
+    * Object Model
+    * Garbage Collection
+    * Snapshots
+* Core libraries native methods
+* Development Experience components accessible via *service protocol*
+        * Debugging
+        * Profiling
+        * Hot-reload
+* Just-in-Time (JIT) and Ahead-of-Time (AOT) compilation pipelines
+* Interpreter
+* ARM simulators
+
+The name "Dart VM" is historical. Dart VM is a virtual machine in a sense that it provides an execution environment for a high-level programming language, however it does not imply that Dart is always interpreted or JIT-compiled, when executing on Dart VM. For example, Dart code can be compiled into machine code using Dart VM AOT pipeline and then executed within a stripped version of the Dart VM, called *precompiled runtime*, which does not contain any compiler components and is incapable of loading Dart source code dynamically.
+
+## How does Dart VM run your code?
+
+Dart VM has multiple ways to execute the code, for example:
+
+* from source or Kernel binary using JIT;
+* from snapshots:
+    * from AOT snapshot;
+    * from AppJIT snapshot.
+
+However the main difference between these lies in when and how VM converts Dart source code to executable code. The runtime environment that facilitates the execution remains the same.
+
+![Isolates](images/isolates.png)
+
+Any Dart code within the VM is running within some _isolate_, which can be best described as an isolated Dart universe with its own memory (*heap*) and _usually_ with its own thread of control (*mutator thread*). There can be many isolates executing Dart code concurrently, but they cannot share any state directly and can only communicate by message passing through *ports* (not to be confused with network ports!).
+
+The relationship between OS threads and isolates is a bit blurry and highly dependent on how VM is embedded into an application. Only the following is guaranteed:
+
+* an OS thread can *enter* only one isolate at a time. It has to leave current isolate if it wants to enter another isolate;
+* there can only be a single *mutator* thread associated with an isolate at a time. Mutator thread is a thread that executes Dart code and uses VM's public C API.
+
+However the same OS thread can first enter one isolate, execute Dart code, then leave this isolate and enter another isolate. Alternatively many different OS threads can enter an isolate and execute Dart code inside it, just not simultaneously.
+
+In addition to a single *mutator* thread an isolate can also be associated with multiple helper threads, for example:
+
+* a background JIT compiler thread;
+* GC sweeper threads;
+* concurrent GC marker threads.
+
+Internally VM uses a thread pool (@{dart::ThreadPool}) to manage OS threads and the code is structured around @{dart::ThreadPool::Task} concept rather than around a concept of an OS thread. For example, instead of spawning a dedicated thread to perform background sweeping after a GC VM posts a @{dart::ConcurrentSweeperTask} to the global VM thread pool and thread pool implementation either selects an idling thread or spawns a new thread if no threads are available. Similarly the default implementation of an event loop for isolate message processing does not actually spawn a dedicated event loop thread, instead it posts a @{dart::MessageHandlerTask} to the thread pool whenever a new message arrives.
+
+!!! sourcecode "Source to read"
+    Class @{dart::Isolate} represents an isolate, class @{dart::Heap} - isolate's heap. Class @{dart::Thread} describes the state associated with a thread attached to an isolate. Note that the name `Thread` is somewhat confusing because all OS threads attached to the same isolate as a mutator would reuse the same `Thread` instance. See @{Dart_RunLoop} and @{dart::MessageHandler} for the default implementation of an isolate's message handling.
+
+### Running from source via JIT.
+
+This section tries to cover what happens when you try to execute Dart from the command line:
+
+```dart
+// hello.dart
+main() => print('Hello, World!');
+```
+
+```console
+$ dart hello.dart
+Hello, World!
+```
+
+Since Dart 2 VM no longer has the ability to directly execute Dart from raw source, instead VM expects to be given _Kernel binaries_ (also called _dill files_) which contain serialized [Kernel ASTs][what-is-kernel]. The task of translating Dart source into Kernel AST is handled by the [common front-end (CFE)][pkg-front_end] written in Dart and shared between different Dart tools (e.g. VM, dart2js, Dart Dev Compiler).
+
+![Dart to Kernel](images/dart-to-kernel.png)
+
+To preserve convenience of executing Dart directly from source standalone `dart` executable hosts a helper isolate called *kernel service*, which handles compilation of Dart source into Kernel. VM then would run resulting Kernel binary.
+
+![Running from Source in Dart 2](images/kernel-service.png)
+
+However this setup is not the only way to arrange CFE and VM to run Dart code. For example, Flutter completely separates _compilation to Kernel_ and _execution from Kernel_ by putting them onto different devices: compilation happens on the developer machine (_host_) and execution is handled on the target mobile _device_, which receives Kernel binaries send to it by `flutter` tool.
+
+![Dart to Kernel](images/flutter-cfe.png)
+
+Note that `flutter` tool does not handle parsing of Dart itself - instead it spawns another persistent process `frontend_server`, which is essentially a thin wrapper around CFE and some Flutter specific Kernel-to-Kernel transformations. `frontend_server` compiles Dart source into Kernel files, which `flutter` tool then sends to the device. Persistence of the `frontend_server` process comes into play when developer requests _hot reload_: in this case `frontend_server` can reuse CFE state from the previous compilation and recompile just libraries which actually changed.
+
+Once Kernel binary is loaded into the VM it is parsed to create objects representing various program entities. However this is done lazily: at first only basic information about libraries and classes is loaded. Each entity originating from a Kernel binary keeps a pointer back to the binary, so that later more information can be loaded as needed.
+
+<aside>We use `Raw...` prefix whenever we talk about specific objects allocated internally by the VM. This follows VM own naming convention: layout of internal VM objects is defined using C++ classes with names starting with `Raw` in the header file @{runtime/vm/raw_object.h}. For example, @{dart::RawClass} is a VM object describing Dart class, @{dart::RawField} is a VM object describing a Dart field within a Dart class and so on. We will return to this in a section covering runtime system and object model.</aside>
+
+![Kernel Loading. Stage 1](images/kernel-loaded-1.png)
+
+Information about the class is fully deserialized only when runtime later needs it (e.g. to lookup a class member, to allocate an instance, etc). At this stage class members are read from the Kernel binary. However full function bodies are not deserialized at this stage, only their signatures.
+
+![Kernel Loading. Stage 2](images/kernel-loaded-2.png)
+
+At this point enough information is loaded from Kernel binary for runtime to successfully resolve and invoke methods. For example, it could resolve and invoke `main` function from a library.
+
+!!! sourcecode "Source to read"
+    @{package:kernel/ast.dart} defines classes describing the Kernel AST. @{package:front_end} handles parsing Dart source and building Kernel AST from it. @{dart::kernel::KernelLoader::LoadEntireProgram} is an entry point for deserialization of Kernel AST into corresponding VM objects. @{pkg/vm/bin/kernel_service.dart} implements the Kernel Service isolate, @{runtime/vm/kernel_isolate.cc} glues Dart implementation to the rest of the VM. @{package:vm} hosts most of the Kernel based VM specific functionality, e.g various Kernel-to-Kernel transformations. However some VM specific transformations still live in @{package:kernel} for historical reasons. A good example of a complicated transformation is @{package:kernel/transformations/continuation.dart}, which desugars `async`,`async*` and `sync*` functions.
+
+
+!!! tryit "Trying it"
+    If you are interested in Kernel format and its VM specific usage, then you can use @{pkg/vm/bin/gen_kernel.dart} to produce a Kernel binary file from Dart source. Resulting binary can then be dumped using @{pkg/vm/bin/dump_kernel.dart}.
+
+    ```custom-shell-session
+    # Take hello.dart and compile it to hello.dill Kernel binary using CFE.
+    $ dart pkg/vm/bin/gen_kernel.dart                        \
+           --platform out/ReleaseX64/vm_platform_strong.dill \
+           -o hello.dill                                     \
+           hello.dart
+
+    # Dump textual representation of Kernel AST.
+    $ dart pkg/vm/bin/dump_kernel.dart hello.dill hello.kernel.txt
+    ```
+
+    When you try using `gen_kernel.dart` you will notice that it requires something called *platform*, a Kernel binary containing AST for all core libraries (`dart:core`, `dart:async`, etc). If you have Dart SDK build configured then you can just use platform file from the `out` directory, e.g. `out/ReleaseX64/vm_platform_strong.dill`. Alternatively you can use
+    @{pkg/front_end/tool/_fasta/compile_platform.dart} to generate the platform:
+
+    ```custom-shell-session
+    # Produce outline and platform files using the given libraries list.
+    $ dart pkg/front_end/tool/_fasta/compile_platform.dart \
+           dart:core                                       \
+           sdk/lib/libraries.json                          \
+           vm_outline.dill vm_platform.dill vm_outline.dill
+    ```
+
+Initially all functions have a placeholder instead of an actually executable code for their bodies: they point to `LazyCompileStub`, which simply asks runtime system to generate executable code for the current function and then tail-calls this newly generated code.
+
+![Lazy Compilation](images/raw-function-lazy-compile.png)
+
+When the function is compiled for the first time this is done by *unoptimizing compiler*.
+
+![Unoptimized Compilation](images/unoptimized-compilation.png)
+
+Unoptimizing compiler produces machine code in two passes:
+
+1. Serialized AST for the function's body is walked to generate a *control flow graph* (**CFG**) for the function body. CFG consists of basic blocks filled with *intermediate language* (**IL**) instructions. IL instructions used at this stage resemble instructions of a stack based virtual machine: they take operands from the stack, perform operations and then push results to the same stack.
+
+<aside>In reality not all functions have actual Dart / Kernel AST bodies, e.g. *natives* defined in C++ or artificial tear-off functions generated by Dart VM - in these cases IL is just created from the thin air, instead of being generated from Kernel AST.</aside>
+
+2. resulting CFG is directly compiled to machine code using one-to-many lowering of IL instructions: each IL instruction expands to multiple machine language instructions.
+
+There are no optimizations performed at this stage. The main goal of unoptimizing compiler is to produce executable code quickly.
+
+This also means that unoptimizing compiler does not attempt to statically resolve any calls that were not resolved in Kernel binary, so calls (`MethodInvocation` or `PropertyGet` AST nodes) are compiled as if they were completely dynamic. VM currently does not use any form of *virtual table* or *interface table* based dispatch and instead implements dynamic calls using [*inline caching*](https://en.wikipedia.org/wiki/Inline_caching).
+
+The core idea behind inline caching is to cache results of method resolution in a call site specific cache. Inline caching mechanism used by the VM consists of:
+
+<aside>Original implementations of inline caching were actually patching the native code of the function - hence the name  _**inline** caching_. The idea of inline caching dates far back to Smalltalk-80, see [Efficient implementation of the Smalltalk-80 system](https://dl.acm.org/citation.cfm?id=800542).</aside>
+
+* a call site specific cache (@{dart::RawICData} object) that maps receiver's class to a method, that should be invoked if receiver is of a matching class. The cache also stores some auxiliary information, e.g. invocation frequency counters, which track how often the given class was seen at this call site;
+* a shared lookup stub, which implements method invocation fast path. This stub searches through the given cache to see if it contains an entry that matches receiver's class. If the entry is found then stub would increment the frequency counter and tail call cached method. Otherwise stub would invoke a runtime system helper which implements method resolution logic. If method resolution succeeds then cache would be updated and subsequent invocations would not need to enter runtime system.
+
+The picture below illustrates the structure and the state of an inline cache associated with `animal.toFace()` call site, which was executed twice with an instance of `Dog` and once with an instance of a `Cat`.
+
+![Inline Caching](images/inline-cache-1.png)
+
+Unoptimizing compiler by itself is enough to execute any possible Dart code. However the code it produces is rather slow, which is why VM also implements *adaptive optimizing* compilation pipeline. The idea behind adaptive optimization is to use execution profile of a running program to drive optimization decisions.
+
+As unoptimized code is running it collects the following information:
+
+* As described above, inline caches collect information about receiver types observed at
+callsites;
+* Execution counters associated with functions and basic blocks within functions track hot regions of the code.
+
+When an execution counter associated with a function reaches certain threshold, this function is submitted to a *background optimizing compiler* for optimization.
+
+Optimizing compilations starts in the same way as unoptimizing compilation does: by walking serialized Kernel AST to build unoptimized IL for the function that is being optimized. However instead of directly lowering that IL into machine code, optimizing compiler proceeds to translate unoptimized IL into *static single assignment* (SSA) form based optimized IL. SSA based IL is then subjected to speculative specialization based on the collected type feedback and passed through a sequence of classical and Dart specific optimizations: e.g. inlining, range analysis, type propagation, representation selection, store-to-load and load-to-load forwarding, global value numbering, allocation sinking, etc. At the end optimized IL is lowered into machine code using linear scan register allocator and a simple one-to-many lowering of IL instructions.
+
+Once compilation is complete background compiler requests mutator thread to enter a *safepoint* and attaches optimized code to the function.
+
+<aside>Broadly speaking a thread in a managed environment (virtual machine) is considered to be at a *safepoint* when the state associated with it (e.g. stack frames, heap, etc) is consistent and can be accessed or modified without interruption from the thread itself. Usually this implies that the thread is either paused or is executing some code outside of the managed environment e.g. running unmanaged native code. See [GC](/gc.html) page for more information.</aside>
+
+The next time this function is called - it will use optimized code. Some functions contain very long running loops and for those it makes sense to switch execution from unoptimized to optimized code while the function is still running. This process is called *on stack replacement* (**OSR**) owing its name to the fact that a stack frame for one version of the function is transparently replaced with a stack frame for another version of the same function.
+
+![Optimizing Compilation](images/optimizing-compilation.png)
+
+!!! sourcecode "Source to read"
+    Compiler sources are in the @{runtime/vm/compiler} directory.
+    Compilation pipeline entry point is @{dart::CompileParsedFunctionHelper::Compile}. IL is defined in @{runtime/vm/compiler/backend/il.h}. Kernel-to-IL translation starts in @{dart::kernel::StreamingFlowGraphBuilder::BuildGraph}, and this function also handles construction of IL for various artificial functions. @{dart::compiler::StubCodeCompiler::GenerateNArgsCheckInlineCacheStub} generates machine code for inline-cache stub, while @{InlineCacheMissHandler} handles IC misses. @{runtime/vm/compiler/compiler_pass.cc} defines optimizing compiler passes and their order. @{dart::JitCallSpecializer} does most of the type-feedback based specializations.
+
+!!! tryit "Trying it"
+    VM also has flags which can be used to control JIT and to make it dump IL and generated machine code for the functions that are being compiled by the JIT.
+
+    | Flag | Description |
+    | ---- | ---- |
+    | `--print-flow-graph[-optimized]` | Print IL for all (or only optimized) compilations |
+    | `--disassemble[-optimized]` | Disassemble all (or only optimized) compiled functions |
+    | `--print-flow-graph-filter=xyz,abc,...` | Restrict output triggered by previous flags only to the functions which contain one of the comma separated substrings in their names |
+    | `--compiler-passes=...` | Fine control over compiler passes: force IL to be printed before/after a certain pass. Disable passes by name. Pass `help` for more information |
+    | `--no-background-compilation` | Disable background compilation, and compile all hot functions on the main thread. Useful for experimentation, otherwise short running programs might finish before background compiler compiles hot function |
+
+    For example
+
+    ```myshell
+    # Run test.dart and dump optimized IL and machine code for
+    # function(s) that contain(s) "myFunction" in its name.
+    # Disable background compilation for determinism.
+    $ dart --print-flow-graph-optimized         \
+           --disassemble-optimized              \
+           --print-flow-graph-filter=myFunction \
+           --no-background-compilation          \
+           test.dart
+    ```
+
+It is important to highlight that the code generated by optimizing compiler is specialized under speculative assumptions based on the execution profile of the application. For example, a dynamic call site that only observed instances of a single class `C` as a receiver will be converted into a direct call preceeded by a check verifying that receiver has an expected class `C`. However these assumptions might be violated later during execution of the program:
+
+```dart
+void printAnimal(obj) {
+  print('Animal {');
+  print('  ${obj.toString()}');
+  print('}');
+}
+
+// Call printAnimal(...) a lot of times with an intance of Cat.
+// As a result printAnimal(...) will be optimized under the
+// assumption that obj is always a Cat.
+for (var i = 0; i < 50000; i++)
+  printAnimal(Cat());
+
+// Now call printAnimal(...) with a Dog - optimized version
+// can not handle such an object, because it was
+// compiled under assumption that obj is always a Cat.
+// This leads to deoptimization.
+printAnimal(Dog());
+```
+
+Whenever optimized code is making some optimistic assumptions, which might be
+violated during the execution, it needs to guard against such violations and
+be able to recover if they occur.
+
+This process of recovery is known as _deoptimization_: whenever optimized version hits a case which it can't handle, it simply transfers execution into the matching point of unoptimized function and continues execution there. Unoptimized version of a function does not make any assumptions and can handle all possible inputs.
+
+<aside>Entering unoptimized function at the right spot is absolutely crucial because code has side-effects (e.g. in the function above deoptimization happens after we already executed the first `print`). Matching instructions that deoptimize to positions in the unoptimized code in VM is done using *deopt ids*</aside>
+
+VM usually discards optimized version of the function after deoptimization and
+then reoptimizes it again later - using updated type feedback.
+
+There are two ways VM guards speculative assumptions made by the compiler:
+
+* Inline checks (e.g. `CheckSmi`, `CheckClass` IL instructions) that verify if assumption holds at *use* site where compiler made this assumption. For example, when turning dynamic calls into direct calls compiler adds these checks right before a direct call. Deoptimization that happens on such checks is called *eager deoptimization*, because it occurs eagerly as the check is reached.
+* Global guards which instruct runtime to discard optimized code when it changes something that optimized code relies on. For example, optimizing compiler might observe that some class `C` is never extended and use this information during type propagation pass. However subsequent dynamic code loading or class finalization can introduce a subclass of `C` - which invalidates the assumption. At this point runtime needs to find and discard all optimized code that was compiled under the assumption that `C` has no subclasses. It is possible that runtime would find some of the now invalid optimized code on the execution stack - in which case affected frames would be marked for deoptimization and will deoptimize when execution returns to them.  This sort of deoptimization is called *lazy deoptimization*: because it is delayed until control returns back to the optimized code.
+
+!!! sourcecode "Source to read"
+    Deoptimizer machinery resides in @{runtime/vm/deopt_instructions.cc}. It is essentially a mini-interpreter for *deoptimization instructions* which describe how to reconstruct needed state of the unoptimized code from the state of optimized code. Deoptimization instructions are generated by @{dart::CompilerDeoptInfo::CreateDeoptInfo} for every potential deoptimization location in optimized code during compilation.
+
+!!! tryit "Trying it"
+    Flag `--trace-deoptimization` makes VM print information about the cause and location of every deoptimization that occurs. `--trace-deoptimization-verbose` makes VM print a line for every deoptimization instruction it executes during deoptimization.
+
+### Running from Snapshots
+
+VM has the ability to serialize isolate's heap or more precisely object graph residing in the heap into a binary *snapshot*. Snapshot then can be used to recreate the same state when starting VM isolates.
+
+![Snapshots](images/snapshot.png)
+
+Snapshot's format is low level and optimized for fast startup - it is essentially a list of objects to create and instructions on how to connect them together. That was the original idea behind snapshots: instead of parsing Dart source and gradually creating internal VM data structures, VM can just spin an isolate up with all necessary data structures quickly unpacked from the snapshot.
+
+<aside>The idea of a snapshots has roots in Smalltalk [images](https://en.wikipedia.org/wiki/Smalltalk#Image-based_persistence) which were in turn inspired by [Alan Kay's M.Sc thesis](https://www.mprove.de/visionreality/media/kay68.html). Dart VM is using clustered serialization format which is similar to techniques described in [Parcels: a Fast and Feature-Rich Binary Deployment Technology](http://scg.unibe.ch/archive/papers/Mira05aParcels.pdf) and [Clustered serialization with Fuel](https://rmod.inria.fr/archives/workshops/Dia11a-IWST11-Fuel.pdf) papers.</aside>
+
+Initially snapshots did not include machine code, however this capability was later added when AOT compiler was developed. Motivation for developing AOT compiler and snapshots-with-code was to allow VM to be used on the platforms where JITing is impossible due to platform level restrictions.
+
+Snapshots-with-code work almost in the same way as normal snapshots with a minor difference: they include a code section which unlike the rest of the snapshot does not require deserialization. This code section laid in way that allows it to directly become part of the heap after it was mapped into memory.
+
+![Snapshots](images/snapshot-with-code.png)
+
+!!! sourcecode "Source to read"
+    @{runtime/vm/clustered_snapshot.cc} handles serialization and deserialization of snapshots. A family of API functions `Dart_CreateXyzSnapshot[AsAssembly]` are responsible for writing out snapshots of the heap (e.g. @{Dart_CreateAppJITSnapshotAsBlobs} and @{Dart_CreateAppAOTSnapshotAsAssembly}). On the other hand @{Dart_CreateIsolateGroup} optionally takes snapshot data to start an isolate from.
+
+### Running from AppJIT snapshots
+
+AppJIT snapshots were introduced to reduce JIT warm up time for large Dart applications like `dartanalyzer` or `dart2js`. When these tools are used on small projects they spent as much time doing actual work as VM spends JIT compiling these apps.
+
+AppJIT snapshots allow to address this problem: an application can be run on the VM using some mock training data and then all generated code and VM internal data structures are serialized into an AppJIT snapshot. This snapshot can then be distributed instead of distributing application in the source (or Kernel binary) form. VM starting from this snapshot can still JIT - if it turns out that execution profile on the real data does not match execution profile observed during training.
+
+![Snapshots](images/snapshot-with-code.png)
+
+!!! tryit "Trying it"
+    `dart` binary will generate AppJIT snapshot after running the application if you pass `--snapshot-kind=app-jit --snapshot=path-to-snapshot` to it. Here is an example of generating and using an AppJIT snapshot for `dart2js`.
+
+    ```custom-shell-session
+    # Run from source in JIT mode.
+    $ dart pkg/compiler/lib/src/dart2js.dart -o hello.js hello.dart
+    Compiled 7,359,592 characters Dart to 10,620 characters JavaScript in 2.07 seconds
+    Dart file (hello.dart) compiled to JavaScript: hello.js
+
+    # Training run to generate app-jit snapshot
+    $ dart --snapshot-kind=app-jit --snapshot=dart2js.snapshot \
+           pkg/compiler/lib/src/dart2js.dart -o hello.js hello.dart
+    Compiled 7,359,592 characters Dart to 10,620 characters JavaScript in 2.05 seconds
+    Dart file (hello.dart) compiled to JavaScript: hello.js
+
+    # Run from app-jit snapshot.
+    $ dart dart2js.snapshot -o hello.js hello.dart
+    Compiled 7,359,592 characters Dart to 10,620 characters JavaScript in 0.73 seconds
+    Dart file (hello.dart) compiled to JavaScript: hello.js
+    ```
+
+### Running from AppAOT snapshots
+
+AOT snapshots were originally introduced for platforms which make JIT compilation impossible, but they can also be used in situations where fast startup and consistent performance is worth potential peak performance penalty.
+
+<aside>There is usually a lot of confusion around how performance characteristics of JIT and AOT compare. JIT has access to precise local type information and execution profile of the running application, however it has to pay for it with warmup. AOT can infer and prove various properties globally (for which it has to pay with compile time), but has no information of how the program will actually be executing - on the other hand AOT compiled code reaches its peak performance almost immediately with virtual no warmup. Currently Dart VM JIT has best peak performance, while Dart VM AOT has best startup time.</aside>
+
+Inability to JIT implies that:
+
+1. AOT snapshot *must* contain executable code for each and every function that could be invoked during application execution;
+2. the executable code *must not* rely on any speculative assumptions that could be violated during execution;
+
+To satisfy these requirements the process of AOT compilation does global static analysis (*type flow analysis* or *TFA*) to determine which parts of the application are reachable from known set of *entry points*, instances of which classes are allocated and how types flow through the program. All of these analyses are conservative: meaning that they err on the side of correctness - which is in stark contrast with JIT which can err on the side of performance, because it can always deoptimize into unoptimized code to implement correct behavior.
+
+All potentially reachable functions are then compiled to native code without any speculative optimizations. However type flow information is still used to specialize the code (e.g. devirtualize calls).
+
+Once all functions are compiled a snapshot of the heap can be taken.
+
+Resulting snapshot can then be run using *precompiled runtime*, a special variant of the Dart VM which excludes components like JIT and dynamic code loading facilities.
+
+![AOT pipeline](images/aot.png)
+
+!!! sourcecode "Source to read"
+    @{package:vm/transformations/type_flow/transformer.dart} is an entry point to the type flow analysis and transformation based on TFA results. @{dart::Precompiler::DoCompileAll} is an entry point to the AOT compilation loop in the VM.
+
+!!! tryit "Trying it"
+    AOT compilation pipeline is currently packaged into Dart SDK as [`dart2native` script](https://dart.dev/tools/dart2native).
+
+    ```custom-shell-session
+    $ dart2native hello.dart -o hello
+    $ ./hello
+    Hello, World!
+    ```
+
+    Note that it is impossible to pass options like `--print-flow-graph-optimized` and `--disassemble-optimized` to the `dart2native` script so if you would like to inspect generated AOT code you will need to build compiler from source.
+
+    ```custom-shell-session
+    # Need to build normal dart executable and runtime for running AOT code.
+    $ tool/build.py -m release -a x64 runtime dart_precompiled_runtime
+
+    # Now compile an application using AOT compiler
+    $ pkg/vm/tool/precompiler2 hello.dart hello.aot
+
+    # Execute AOT snapshot using runtime for AOT code
+    $ out/ReleaseX64/dart_precompiled_runtime hello.aot
+    Hello, World!
+    ```
+
+#### Switchable Calls
+
+Even with global and local analyses AOT compiled code might still contain call sites which could not be *devirtualized* (meaning they could not be statically resolved). To compensate for this AOT compiled code and runtime use an extension of inline caching technique utilized in JIT. This extended version is called *switchable calls*.
+
+JIT section already described that each inline cache associated with a call site consists of two pieces: a cache object (represented by an instance of @{dart::RawICData}) and a chunk of native code to invoke (e.g. a @{dart::compiler::StubCodeCompiler::GenerateNArgsCheckInlineCacheStub|InlineCacheStub}). In JIT mode runtime would only update the cache itself. However in AOT runtime can choose to replace both the cache and the native code to invoke depending on the state of the inline cache.
+
+![AOT IC. Unlinked](images/aot-ic-unlinked.png)
+
+Initially all dynamic calls start in the *unlinked* state. When such call-site is reached for the first time @{dart::compiler::StubCodeCompiler::GenerateUnlinkedCallStub|UnlinkedCallStub} is invoked, which simply calls into runtime helper @{DRT_UnlinkedCall} to link this call site.
+
+If possible @{DRT_UnlinkedCall} tries to transition the call site into a _monomorphic_ state. In this state call site turns into a direct call, which enters method through a special entry point which verifies that receiver has expected class.
+
+![AOT IC: Monomorphic](images/aot-ic-monomorphic.png)
+
+In the example above we assume that when `obj.method()` was executed for the first time `obj` was an instance of `C` and `obj.method` resolved to `C.method`.
+
+Next time we execute the same call-site it would invoke `C.method` directly, bypassing any sort of method lookup process. However it would enter `C.method` through a special entry point, which would verify that `obj` is still an instance of `C`. If that is not the case @{DRT_MonomorphicMiss} would be invoked and will try to select the next call site state.
+
+`C.method` might still be a valid target for an invocation, e.g `obj` is an instance of the class `D` which extends `C` but does not override `C.method`. In this case we check if call site could transition into a *single target* state, implemented by @{dart::compiler::StubCodeCompiler::GenerateSingleTargetCallStub|SingleTargetCallStub} (see also @{dart::RawSingleTargetCache}).
+
+![AOT IC: Single Target](images/aot-ic-singletarget.png)
+
+This stub is based on the fact that for AOT compilation most classes are assigned integer ids using depth-first traversal of the inheritance hierarchy. If `C` is a base class with subclasses `D0, ..., Dn` and none of those override `C.method` then `C.:cid <= classId(obj) <= max(D0.:cid, ..., Dn.:cid)` implies that `obj.method` resolves to `C.method`. In this circumstances instead of comparing to a single class (*monomorphic* state), we can use class id range check (*single target* state) which would work for all subclasses of `C`.
+
+Otherwise call site would be switched to use linear search inline cache, similar to the one used in JIT mode (see @{dart::compiler::StubCodeCompiler::GenerateICCallThroughCodeStub|ICCallThroughCodeStub}, @{dart::RawICData} and @{DRT_MegamorphicCacheMissHandler}).
+
+![AOT IC: linear IC call](images/aot-ic-linear.png)
+
+Finally if the number of checks in the linear array grows past threshold the call site is switched to use a dictionary like structure (see @{dart::compiler::StubCodeCompiler::GenerateMegamorphicCallStub|MegamorphicCallStub}, @{dart::RawMegamorphicCache} and @{DRT_MegamorphicCacheMissHandler}).
+
+![AOT IC: dictionary](images/aot-ic-dictionary.png)
+
+[what-is-kernel]: https://github.com/dart-lang/sdk/blob/master/pkg/kernel/README.md
+[pkg-front_end]: https://github.com/dart-lang/sdk/tree/master/pkg/front_end
+
+## Runtime System
+
+
+!!! WARNING
+    This section will be written next.
+
+### Object Model
+
+## TODO
+
+1. Document the difference between CoreJIT and AppJIT snapshots.
+2. Document that switchable calls are used in the unoptimized code as well.
\ No newline at end of file
diff --git a/runtime/lib/developer.cc b/runtime/lib/developer.cc
index 353f709..2b875cc 100644
--- a/runtime/lib/developer.cc
+++ b/runtime/lib/developer.cc
@@ -37,9 +37,7 @@
 DEFINE_NATIVE_ENTRY(Developer_inspect, 0, 1) {
   GET_NATIVE_ARGUMENT(Instance, inspectee, arguments->NativeArgAt(0));
 #ifndef PRODUCT
-  if (FLAG_support_service) {
-    Service::SendInspectEvent(isolate, inspectee);
-  }
+  Service::SendInspectEvent(isolate, inspectee);
 #endif  // !PRODUCT
   return inspectee.raw();
 }
@@ -48,9 +46,6 @@
 #if defined(PRODUCT)
   return Object::null();
 #else
-  if (!FLAG_support_service) {
-    return Object::null();
-  }
   GET_NON_NULL_NATIVE_ARGUMENT(String, message, arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(Integer, timestamp, arguments->NativeArgAt(1));
   GET_NON_NULL_NATIVE_ARGUMENT(Integer, sequence, arguments->NativeArgAt(2));
@@ -70,9 +65,6 @@
 #if defined(PRODUCT)
   return Object::null();
 #else
-  if (!FLAG_support_service) {
-    return Object::null();
-  }
   GET_NON_NULL_NATIVE_ARGUMENT(String, event_kind, arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(String, event_data, arguments->NativeArgAt(1));
   Service::SendExtensionEvent(isolate, event_kind, event_data);
@@ -84,9 +76,6 @@
 #if defined(PRODUCT)
   return Object::null();
 #else
-  if (!FLAG_support_service) {
-    return Object::null();
-  }
   GET_NON_NULL_NATIVE_ARGUMENT(String, name, arguments->NativeArgAt(0));
   return isolate->LookupServiceExtensionHandler(name);
 #endif  // PRODUCT
@@ -96,9 +85,6 @@
 #if defined(PRODUCT)
   return Object::null();
 #else
-  if (!FLAG_support_service) {
-    return Object::null();
-  }
   GET_NON_NULL_NATIVE_ARGUMENT(String, name, arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(Instance, handler, arguments->NativeArgAt(1));
   // We don't allow service extensions to be registered for the
diff --git a/runtime/lib/ffi.cc b/runtime/lib/ffi.cc
index df3fb7f..0a40666 100644
--- a/runtime/lib/ffi.cc
+++ b/runtime/lib/ffi.cc
@@ -10,7 +10,7 @@
 #include "vm/compiler/assembler/assembler.h"
 #include "vm/compiler/ffi/call.h"
 #include "vm/compiler/ffi/callback.h"
-#include "vm/compiler/ffi/native_representation.h"
+#include "vm/compiler/ffi/native_type.h"
 #include "vm/compiler/jit/compiler.h"
 #include "vm/exceptions.h"
 #include "vm/flags.h"
@@ -72,9 +72,10 @@
 //
 // You must check [IsConcreteNativeType] and [CheckSized] first to verify that
 // this type has a defined size.
-static size_t SizeOf(const AbstractType& type) {
+static size_t SizeOf(const AbstractType& type, Zone* zone) {
   if (RawObject::IsFfiTypeClassId(type.type_class_id())) {
-    return compiler::ffi::ElementSizeInBytes(type.type_class_id());
+    return compiler::ffi::NativeType::FromAbstractType(type, zone)
+        .SizeInBytes();
   } else {
     Class& struct_class = Class::Handle(type.type_class());
     Object& result = Object::Handle(
@@ -105,8 +106,10 @@
                                    const Integer& index) {
   // TODO(36370): Make representation consistent with kUnboxedFfiIntPtr.
   const size_t address =
-      target.NativeAddress() + static_cast<intptr_t>(index.AsInt64Value()) *
-                                   compiler::ffi::ElementSizeInBytes(type_cid);
+      target.NativeAddress() +
+      static_cast<intptr_t>(index.AsInt64Value()) *
+          compiler::ffi::NativeType::FromTypedDataClassId(type_cid, zone)
+              .SizeInBytes();
   switch (type_cid) {
     case kFfiInt8Cid:
       return Integer::New(*reinterpret_cast<int8_t*>(address));
@@ -156,8 +159,8 @@
 
   // TODO(36370): Make representation consistent with kUnboxedFfiIntPtr.
   const size_t address =
-      pointer.NativeAddress() +
-      static_cast<intptr_t>(index.AsInt64Value()) * SizeOf(pointer_type_arg);
+      pointer.NativeAddress() + static_cast<intptr_t>(index.AsInt64Value()) *
+                                    SizeOf(pointer_type_arg, zone);
 
   return Pointer::New(type_arg, *reinterpret_cast<uword*>(address));
 }
@@ -195,8 +198,8 @@
 
   // TODO(36370): Make representation consistent with kUnboxedFfiIntPtr.
   const size_t address =
-      pointer.NativeAddress() +
-      static_cast<intptr_t>(index.AsInt64Value()) * SizeOf(pointer_type_arg);
+      pointer.NativeAddress() + static_cast<intptr_t>(index.AsInt64Value()) *
+                                    SizeOf(pointer_type_arg, zone);
   const Pointer& pointer_offset =
       Pointer::Handle(zone, Pointer::New(pointer_type_arg, address));
 
@@ -210,8 +213,10 @@
                               const Instance& new_value) {
   // TODO(36370): Make representation consistent with kUnboxedFfiIntPtr.
   const size_t address =
-      pointer.NativeAddress() + static_cast<intptr_t>(index.AsInt64Value()) *
-                                    compiler::ffi::ElementSizeInBytes(type_cid);
+      pointer.NativeAddress() +
+      static_cast<intptr_t>(index.AsInt64Value()) *
+          compiler::ffi::NativeType::FromTypedDataClassId(type_cid, zone)
+              .SizeInBytes();
   switch (type_cid) {
     case kFfiInt8Cid:
       *reinterpret_cast<int8_t*>(address) = AsInteger(new_value).AsInt64Value();
@@ -291,8 +296,8 @@
   ASSERT(IsPointerType(pointer_type_arg));
   // TODO(36370): Make representation consistent with kUnboxedFfiIntPtr.
   const size_t address =
-      pointer.NativeAddress() +
-      static_cast<intptr_t>(index.AsInt64Value()) * SizeOf(pointer_type_arg);
+      pointer.NativeAddress() + static_cast<intptr_t>(index.AsInt64Value()) *
+                                    SizeOf(pointer_type_arg, zone);
   *reinterpret_cast<uword*>(address) = new_value.NativeAddress();
   return Object::null();
 }
@@ -301,7 +306,7 @@
   GET_NATIVE_TYPE_ARGUMENT(type_arg, arguments->NativeTypeArgAt(0));
   CheckSized(type_arg);
 
-  return Integer::New(SizeOf(type_arg));
+  return Integer::New(SizeOf(type_arg, zone));
 }
 
 // Static invocations to this method are translated directly in streaming FGB
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index 5fbc5e1..85e2863 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -110,7 +110,7 @@
     const AbstractType& right_type =
         AbstractType::Handle(right.GetType(Heap::kNew));
     return Bool::Get(
-               left_type.IsEquivalent(right_type, /* syntactically = */ true))
+               left_type.IsEquivalent(right_type, TypeEquality::kSyntactical))
         .raw();
   }
 
@@ -129,7 +129,7 @@
   const intptr_t num_type_params = cls.NumTypeParameters();
   return Bool::Get(left_type_arguments.IsSubvectorEquivalent(
                        right_type_arguments, num_type_args - num_type_params,
-                       num_type_params, /* syntactically = */ true))
+                       num_type_params, TypeEquality::kSyntactical))
       .raw();
 }
 
@@ -205,7 +205,7 @@
   if (type.raw() == other.raw()) {
     return Bool::True().raw();
   }
-  return Bool::Get(type.IsEquivalent(other, /* syntactically = */ true)).raw();
+  return Bool::Get(type.IsEquivalent(other, TypeEquality::kSyntactical)).raw();
 }
 
 DEFINE_NATIVE_ENTRY(Internal_inquireIs64Bit, 0, 0) {
diff --git a/runtime/lib/simd128.cc b/runtime/lib/simd128.cc
index 6066d47..e5983b3 100644
--- a/runtime/lib/simd128.cc
+++ b/runtime/lib/simd128.cc
@@ -189,14 +189,31 @@
   GET_NON_NULL_NATIVE_ARGUMENT(Float32x4, hi, arguments->NativeArgAt(2));
   // The order of the clamping must match the order of the optimized code:
   // MAX(MIN(self, hi), lo).
-  float _x = self.x() < hi.x() ? self.x() : hi.x();
-  float _y = self.y() < hi.y() ? self.y() : hi.y();
-  float _z = self.z() < hi.z() ? self.z() : hi.z();
-  float _w = self.w() < hi.w() ? self.w() : hi.w();
-  _x = _x < lo.x() ? lo.x() : _x;
-  _y = _y < lo.y() ? lo.y() : _y;
-  _z = _z < lo.z() ? lo.z() : _z;
-  _w = _w < lo.w() ? lo.w() : _w;
+  float _x;
+  float _y;
+  float _z;
+  float _w;
+  // ARM semantics are different from X86/X64 at an instruction level. Ensure
+  // that we match the semantics of the architecture in the C version.
+#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
+  _x = self.x() < hi.x() ? self.x() : hi.x();
+  _y = self.y() < hi.y() ? self.y() : hi.y();
+  _z = self.z() < hi.z() ? self.z() : hi.z();
+  _w = self.w() < hi.w() ? self.w() : hi.w();
+  _x = lo.x() < _x ? _x : lo.x();
+  _y = lo.y() < _y ? _y : lo.y();
+  _z = lo.z() < _z ? _z : lo.z();
+  _w = lo.w() < _w ? _w : lo.w();
+#else
+  _x = fminf(self.x(), hi.x());
+  _y = fminf(self.y(), hi.y());
+  _z = fminf(self.z(), hi.z());
+  _w = fminf(self.w(), hi.w());
+  _x = fmaxf(_x, lo.x());
+  _y = fmaxf(_y, lo.y());
+  _z = fmaxf(_z, lo.z());
+  _w = fmaxf(_w, lo.w());
+#endif
   return Float32x4::New(_x, _y, _z, _w);
 }
 
@@ -719,10 +736,22 @@
   GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, hi, arguments->NativeArgAt(2));
   // The order of the clamping must match the order of the optimized code:
   // MAX(MIN(self, hi), lo).
-  double _x = self.x() < hi.x() ? self.x() : hi.x();
-  double _y = self.y() < hi.y() ? self.y() : hi.y();
-  _x = _x < lo.x() ? lo.x() : _x;
-  _y = _y < lo.y() ? lo.y() : _y;
+  double _x;
+  double _y;
+
+  // ARM semantics are different from X86/X64 at an instruction level. Ensure
+  // that we match the semantics of the architecture in the C version.
+#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
+  _x = self.x() < hi.x() ? self.x() : hi.x();
+  _y = self.y() < hi.y() ? self.y() : hi.y();
+  _x = lo.x() < _x ? _x : lo.x();
+  _y = lo.y() < _y ? _y : lo.y();
+#else
+  _x = fmin(self.x(), hi.x());
+  _y = fmin(self.y(), hi.y());
+  _x = fmax(_x, lo.x());
+  _y = fmax(_y, lo.y());
+#endif
   return Float64x2::New(_x, _y);
 }
 
diff --git a/runtime/lib/vmservice.cc b/runtime/lib/vmservice.cc
index 24b65e3..1d3484d 100644
--- a/runtime/lib/vmservice.cc
+++ b/runtime/lib/vmservice.cc
@@ -80,9 +80,6 @@
 
 DEFINE_NATIVE_ENTRY(VMService_SendIsolateServiceMessage, 0, 2) {
 #ifndef PRODUCT
-  if (!FLAG_support_service) {
-    return Bool::Get(false).raw();
-  }
   GET_NON_NULL_NATIVE_ARGUMENT(SendPort, sp, arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(1));
 
@@ -104,9 +101,7 @@
 DEFINE_NATIVE_ENTRY(VMService_SendRootServiceMessage, 0, 1) {
 #ifndef PRODUCT
   GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(0));
-  if (FLAG_support_service) {
-    return Service::HandleRootMessage(message);
-  }
+  return Service::HandleRootMessage(message);
 #endif
   return Object::null();
 }
@@ -114,9 +109,7 @@
 DEFINE_NATIVE_ENTRY(VMService_SendObjectRootServiceMessage, 0, 1) {
 #ifndef PRODUCT
   GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(0));
-  if (FLAG_support_service) {
     return Service::HandleObjectRootMessage(message);
-  }
 #endif
   return Object::null();
 }
@@ -128,9 +121,6 @@
   }
   // Boot the dart:vmservice library.
   ServiceIsolate::BootVmServiceLibrary();
-  if (!FLAG_support_service) {
-    return Object::null();
-  }
   // Register running isolates with service.
   RegisterRunningIsolatesVisitor register_isolates(thread);
   if (FLAG_trace_service) {
@@ -155,9 +145,6 @@
 
 DEFINE_NATIVE_ENTRY(VMService_OnServerAddressChange, 0, 1) {
 #ifndef PRODUCT
-  if (!FLAG_support_service) {
-    return Object::null();
-  }
   GET_NATIVE_ARGUMENT(String, address, arguments->NativeArgAt(0));
   if (address.IsNull()) {
     ServiceIsolate::SetServerAddress(NULL);
@@ -171,10 +158,7 @@
 DEFINE_NATIVE_ENTRY(VMService_ListenStream, 0, 1) {
 #ifndef PRODUCT
   GET_NON_NULL_NATIVE_ARGUMENT(String, stream_id, arguments->NativeArgAt(0));
-  bool result = false;
-  if (FLAG_support_service) {
-    result = Service::ListenStream(stream_id.ToCString());
-  }
+  bool result = Service::ListenStream(stream_id.ToCString());
   return Bool::Get(result).raw();
 #else
   return Object::null();
@@ -184,18 +168,13 @@
 DEFINE_NATIVE_ENTRY(VMService_CancelStream, 0, 1) {
 #ifndef PRODUCT
   GET_NON_NULL_NATIVE_ARGUMENT(String, stream_id, arguments->NativeArgAt(0));
-  if (FLAG_support_service) {
-    Service::CancelStream(stream_id.ToCString());
-  }
+  Service::CancelStream(stream_id.ToCString());
 #endif
   return Object::null();
 }
 
 DEFINE_NATIVE_ENTRY(VMService_RequestAssets, 0, 0) {
 #ifndef PRODUCT
-  if (!FLAG_support_service) {
-    return Object::null();
-  }
   return Service::RequestAssets();
 #else
   return Object::null();
@@ -383,9 +362,6 @@
 
 DEFINE_NATIVE_ENTRY(VMService_DecodeAssets, 0, 1) {
 #ifndef PRODUCT
-  if (!FLAG_support_service) {
-    return Object::null();
-  }
   GET_NON_NULL_NATIVE_ARGUMENT(TypedData, data, arguments->NativeArgAt(0));
   Api::Scope scope(thread);
   Dart_Handle data_handle = Api::NewHandle(thread, data.raw());
@@ -441,9 +417,6 @@
 
 DEFINE_NATIVE_ENTRY(VMService_spawnUriNotify, 0, 2) {
 #ifndef PRODUCT
-  if (!FLAG_support_service) {
-    return Object::null();
-  }
   GET_NON_NULL_NATIVE_ARGUMENT(Instance, result, arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(String, token, arguments->NativeArgAt(1));
 
diff --git a/runtime/observatory/lib/src/debugger/debugger_location.dart b/runtime/observatory/lib/src/debugger/debugger_location.dart
index 1904e43..a186fd4 100644
--- a/runtime/observatory/lib/src/debugger/debugger_location.dart
+++ b/runtime/observatory/lib/src/debugger/debugger_location.dart
@@ -10,19 +10,23 @@
   DebuggerLocation.error(this.errorMessage);
 
   static RegExp sourceLocMatcher = new RegExp(r'^([^\d:][^:]+:)?(\d+)(:\d+)?');
+  static RegExp packageLocMatcher =
+      new RegExp(r'^package:([^\d:][^:]+:)?(\d+)(:\d+)?');
   static RegExp functionMatcher = new RegExp(r'^([^.]+)([.][^.]+)?');
 
   /// Parses a source location description.
   ///
   /// Formats:
-  ///   ''                -  current position
-  ///   13                -  line 13, current script
-  ///   13:20             -  line 13, col 20, current script
-  ///   script.dart:13    -  line 13, script.dart
-  ///   script.dart:13:20 -  line 13, col 20, script.dart
-  ///   main              -  function
-  ///   FormatException   -  constructor
-  ///   _SHA1._updateHash -  method
+  ///   ''                     -  current position
+  ///   13                     -  line 13, current script
+  ///   13:20                  -  line 13, col 20, current script
+  ///   script.dart:13         -  line 13, script.dart
+  ///   script.dart:13:20      -  line 13, col 20, script.dart
+  ///   package:a/b.dart:13    -  line 13, "b.dart" in package "a".
+  ///   package:a/b.dart:13:20 -  line 13, col 20, "b.dart" in package "a".
+  ///   main                   -  function
+  ///   FormatException        -  constructor
+  ///   _SHA1._updateHash      -  method
   static Future<DebuggerLocation> parse(Debugger debugger, String locDesc) {
     if (locDesc == '') {
       // Special case: '' means return current location.
@@ -34,6 +38,10 @@
     if (match != null) {
       return _parseScriptLine(debugger, match);
     }
+    match = packageLocMatcher.firstMatch(locDesc);
+    if (match != null) {
+      return _parseScriptLine(debugger, match, package: true);
+    }
     match = functionMatcher.firstMatch(locDesc);
     if (match != null) {
       return _parseFunction(debugger, match);
@@ -64,8 +72,12 @@
   }
 
   static Future<DebuggerLocation> _parseScriptLine(
-      Debugger debugger, Match match) async {
+      Debugger debugger, Match match,
+      {bool package = false}) async {
     var scriptName = match.group(1);
+    if (package) {
+      scriptName = "package:$scriptName";
+    }
     if (scriptName != null) {
       scriptName = scriptName.substring(0, scriptName.length - 1);
     }
@@ -88,11 +100,15 @@
 
     if (scriptName != null) {
       // Resolve the script.
-      var scripts = await _lookupScript(debugger.isolate, scriptName);
+      Set<Script> scripts = await _lookupScript(debugger.isolate, scriptName);
+      if (scripts.length == 0) {
+        scripts =
+            await _lookupScript(debugger.isolate, scriptName, useUri: true);
+      }
       if (scripts.length == 0) {
         return new DebuggerLocation.error("Script '${scriptName}' not found");
       } else if (scripts.length == 1) {
-        return new DebuggerLocation.file(scripts[0], line, col);
+        return new DebuggerLocation.file(scripts.single, line, col);
       } else {
         // TODO(turnidge): Allow the user to disambiguate.
         return new DebuggerLocation.error(
@@ -111,8 +127,8 @@
     }
   }
 
-  static Future<List<Script>> _lookupScript(Isolate isolate, String name,
-      {bool allowPrefix: false}) {
+  static Future<Set<Script>> _lookupScript(Isolate isolate, String name,
+      {bool allowPrefix: false, bool useUri: false}) {
     var pending = <Future>[];
     for (var lib in isolate.libraries) {
       if (!lib.loaded) {
@@ -120,15 +136,16 @@
       }
     }
     return Future.wait(pending).then((_) {
-      var matches = <Script>[];
+      var matches = <Script>{};
       for (var lib in isolate.libraries) {
         for (var script in lib.scripts) {
+          final String haystack = useUri ? script.uri : script.name;
           if (allowPrefix) {
-            if (script.name.startsWith(name)) {
+            if (haystack.startsWith(name)) {
               matches.add(script);
             }
           } else {
-            if (name == script.name) {
+            if (name == haystack) {
               matches.add(script);
             }
           }
@@ -388,7 +405,7 @@
       if (scripts.isEmpty) {
         return [];
       }
-      var script = scripts[0];
+      var script = scripts.first;
       await script.load();
       if (!lineStrComplete) {
         // Complete the line.
diff --git a/runtime/observatory/tests/service/breakpoints_with_mixin_lib1.dart b/runtime/observatory/tests/service/breakpoints_with_mixin_lib1.dart
new file mode 100644
index 0000000..3c43715
--- /dev/null
+++ b/runtime/observatory/tests/service/breakpoints_with_mixin_lib1.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2020, 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 "breakpoints_with_mixin_lib3.dart";
+
+class Test1 extends Object with Foo {}
diff --git a/runtime/observatory/tests/service/breakpoints_with_mixin_lib2.dart b/runtime/observatory/tests/service/breakpoints_with_mixin_lib2.dart
new file mode 100644
index 0000000..c054176
--- /dev/null
+++ b/runtime/observatory/tests/service/breakpoints_with_mixin_lib2.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2020, 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 "breakpoints_with_mixin_lib3.dart";
+
+class Test2 extends Object with Foo {}
diff --git a/runtime/observatory/tests/service/breakpoints_with_mixin_lib3.dart b/runtime/observatory/tests/service/breakpoints_with_mixin_lib3.dart
new file mode 100644
index 0000000..a7329de
--- /dev/null
+++ b/runtime/observatory/tests/service/breakpoints_with_mixin_lib3.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2020, 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.
+
+class Foo {
+  foo() {
+    print("I should be breakable!");
+  }
+}
+
+class Bar {
+  bar() {
+    print("I should be breakable too!");
+  }
+}
diff --git a/runtime/observatory/tests/service/breakpoints_with_mixin_test.dart b/runtime/observatory/tests/service/breakpoints_with_mixin_test.dart
new file mode 100644
index 0000000..05830b3
--- /dev/null
+++ b/runtime/observatory/tests/service/breakpoints_with_mixin_test.dart
@@ -0,0 +1,57 @@
+// Copyright (c) 2020, 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 'test_helper.dart';
+import 'service_test_common.dart';
+
+import "breakpoints_with_mixin_lib1.dart";
+import "breakpoints_with_mixin_lib2.dart";
+import "breakpoints_with_mixin_lib3.dart";
+
+const String testFilename = "breakpoints_with_mixin_test.dart";
+const int testCodeLineStart = 18;
+const String lib3Filename = "breakpoints_with_mixin_lib3.dart";
+const int lib3Bp1 = 7;
+const int lib3Bp2 = 13;
+
+void code() {
+  Test1 test1 = new Test1();
+  test1.foo();
+  Test2 test2 = new Test2();
+  test2.foo();
+  Foo foo = new Foo();
+  foo.foo();
+  Bar bar = new Bar();
+  bar.bar();
+  test1.foo();
+  test2.foo();
+  foo.foo();
+  bar.bar();
+}
+
+List<String> stops = [];
+
+List<String> expected = [
+  "$lib3Filename:$lib3Bp1:5 ($testFilename:${testCodeLineStart + 2}:9)",
+  "$lib3Filename:$lib3Bp1:5 ($testFilename:${testCodeLineStart + 4}:9)",
+  "$lib3Filename:$lib3Bp1:5 ($testFilename:${testCodeLineStart + 6}:7)",
+  "$lib3Filename:$lib3Bp2:5 ($testFilename:${testCodeLineStart + 8}:7)",
+  "$lib3Filename:$lib3Bp1:5 ($testFilename:${testCodeLineStart + 9}:9)",
+  "$lib3Filename:$lib3Bp1:5 ($testFilename:${testCodeLineStart + 10}:9)",
+  "$lib3Filename:$lib3Bp1:5 ($testFilename:${testCodeLineStart + 11}:7)",
+  "$lib3Filename:$lib3Bp2:5 ($testFilename:${testCodeLineStart + 12}:7)",
+];
+
+var tests = <IsolateTest>[
+  hasPausedAtStart,
+  setBreakpointAtUriAndLine(lib3Filename, lib3Bp1),
+  setBreakpointAtUriAndLine(lib3Filename, lib3Bp2),
+  resumeProgramRecordingStops(stops, true),
+  checkRecordedStops(stops, expected)
+];
+
+main(args) {
+  runIsolateTestsSynchronous(args, tests,
+      testeeConcurrent: code, pause_on_start: true, pause_on_exit: true);
+}
diff --git a/runtime/observatory/tests/service/client_name_rpc_test.dart b/runtime/observatory/tests/service/client_name_rpc_test.dart
new file mode 100644
index 0000000..b143bd5
--- /dev/null
+++ b/runtime/observatory/tests/service/client_name_rpc_test.dart
@@ -0,0 +1,66 @@
+// Copyright (c) 2020, 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:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+
+import 'test_helper.dart';
+
+var tests = <VMTest>[
+  (VM vm) async {
+    final defaultClientName = 'client1';
+    final clientName = 'agent-007';
+    var result = await vm.invokeRpcNoUpgrade('getClientName', {});
+    expect(result['type'], 'ClientName');
+    expect(result['name'], defaultClientName);
+
+    // Set the name for this client.
+    result = await vm.invokeRpcNoUpgrade(
+      'setClientName',
+      {
+        'name': clientName,
+      },
+    );
+    expect(result['type'], 'Success');
+
+    // Check it was set properly.
+    result = await vm.invokeRpcNoUpgrade('getClientName', {});
+    expect(result['type'], 'ClientName');
+    expect(result['name'], clientName);
+
+    // Check clearing works properly.
+    result = await vm.invokeRpcNoUpgrade(
+      'setClientName',
+      {
+        'name': '',
+      },
+    );
+    expect(result['type'], 'Success');
+
+    result = await vm.invokeRpcNoUpgrade('getClientName', {});
+    expect(result['type'], 'ClientName');
+    expect(result['name'], defaultClientName);
+  },
+  // Try to set an invalid agent name for this client.
+  (VM vm) async {
+    try {
+      await vm.invokeRpcNoUpgrade(
+        'setClientName',
+        {
+          'name': 42,
+        },
+      );
+      fail('Successfully set invalid client name');
+    } on ServerRpcException catch (e) {/* expected */}
+  },
+  // Missing parameters.
+  (VM vm) async {
+    try {
+      await vm.invokeRpcNoUpgrade('setClientName', {});
+      fail('Successfully set name with no type');
+    } on ServerRpcException catch (e) {/* expected */}
+  },
+];
+
+main(args) async => runVMTests(args, tests);
diff --git a/runtime/observatory/tests/service/client_resume_approvals_approve_then_disconnect_test.dart b/runtime/observatory/tests/service/client_resume_approvals_approve_then_disconnect_test.dart
new file mode 100644
index 0000000..3a57471
--- /dev/null
+++ b/runtime/observatory/tests/service/client_resume_approvals_approve_then_disconnect_test.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+
+import 'client_resume_approvals_common.dart';
+import 'service_test_common.dart';
+import 'test_helper.dart';
+
+void fooBar() {
+  int i = 0;
+  print(i);
+}
+
+WebSocketVM client1;
+WebSocketVM client2;
+
+final test = <IsolateTest>[
+  hasPausedAtStart,
+  (Isolate isolate) async {
+    client1 = await createClient(isolate.owner);
+    await setRequireApprovalForResume(
+      client1,
+      isolate,
+      pauseOnStart: true,
+      pauseOnExit: true,
+    );
+    client2 = await createClient(
+      isolate.owner,
+      clientName: otherClientName,
+    );
+    await setRequireApprovalForResume(
+      client2,
+      isolate,
+      pauseOnStart: true,
+      pauseOnExit: true,
+    );
+
+    // Give resume approval for client1 to ensure approval state is cleaned up
+    // properly when both client1 and client2 have disconnected.
+    await resume(client1, isolate);
+    expect(await isPausedAtStart(isolate), true);
+
+    // Once client1 is disconnected, we should still be paused.
+    client1.disconnect();
+    expect(await isPausedAtStart(isolate), true);
+
+    // Once client2 disconnects, there are no clients which require resume
+    // approval. Since there were no resume requests made by clients which are
+    // still connected, the isolate remains paused.
+    client2.disconnect();
+    expect(await isPausedAtStart(isolate), true);
+
+    await isolate.resume();
+  },
+  hasStoppedAtExit,
+];
+
+Future<void> main(args) => runIsolateTests(args, test,
+    testeeConcurrent: fooBar, pause_on_start: true, pause_on_exit: true);
diff --git a/runtime/observatory/tests/service/client_resume_approvals_common.dart b/runtime/observatory/tests/service/client_resume_approvals_common.dart
new file mode 100644
index 0000000..3323484
--- /dev/null
+++ b/runtime/observatory/tests/service/client_resume_approvals_common.dart
@@ -0,0 +1,86 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+import 'service_test_common.dart';
+
+const String clientName = 'TestClient';
+const String otherClientName = 'OtherTestClient';
+
+Future<void> setClientName(WebSocketVM client, String name) async =>
+    await client.invokeRpc('setClientName', {'name': name});
+
+Future<WebSocketVM> createClient(WebSocketVM vm,
+    {String clientName: clientName}) async {
+  final client = WebSocketVM(vm.target);
+  await client.load();
+  await setClientName(client, clientName);
+  return client;
+}
+
+Future<void> setRequireApprovalForResume(
+  WebSocketVM vm,
+  Isolate isolate, {
+  bool pauseOnStart: false,
+  bool pauseOnExit: false,
+  bool pauseOnReload: false,
+}) async {
+  int pauseTypeMask = 0;
+  if (pauseOnStart) {
+    pauseTypeMask |= 1;
+  }
+  if (pauseOnReload) {
+    pauseTypeMask |= 2;
+  }
+  if (pauseOnExit) {
+    pauseTypeMask |= 4;
+  }
+  await vm.invokeRpc('requirePermissionToResume', {
+    'isolateId': isolate.id,
+    'pauseTypeMask': pauseTypeMask,
+    'onPauseStart': pauseOnStart,
+    'onPauseReload': pauseOnReload,
+    'onPauseExit': pauseOnExit,
+  });
+}
+
+Future<void> resume(WebSocketVM vm, Isolate isolate) async =>
+    await vm.invokeRpc('resume', {
+      'isolateId': isolate.id,
+    });
+
+Future<bool> isPausedAtStart(Isolate isolate) async {
+  await isolate.reload();
+  return ((isolate.pauseEvent != null) &&
+      isEventOfKind(isolate.pauseEvent, ServiceEvent.kPauseStart));
+}
+
+Future<bool> isPausedAtExit(Isolate isolate) async {
+  await isolate.reload();
+  return ((isolate.pauseEvent != null) &&
+      isEventOfKind(isolate.pauseEvent, ServiceEvent.kPauseExit));
+}
+
+Future<bool> isPausedPostRequest(Isolate isolate) async {
+  await isolate.reload();
+  return ((isolate.pauseEvent != null) &&
+      isEventOfKind(isolate.pauseEvent, ServiceEvent.kPausePostRequest));
+}
+
+Future<void> waitForResume(Isolate isolate) async {
+  final completer = Completer<bool>();
+  isolate.vm.getEventStream(VM.kDebugStream).then((stream) {
+    var subscription;
+    subscription = stream.listen((ServiceEvent event) {
+      if (event.kind == ServiceEvent.kResume) {
+        subscription.cancel();
+        completer.complete();
+      }
+    });
+  });
+  return completer.future;
+}
diff --git a/runtime/observatory/tests/service/client_resume_approvals_disconnect_test.dart b/runtime/observatory/tests/service/client_resume_approvals_disconnect_test.dart
new file mode 100644
index 0000000..0dc0402
--- /dev/null
+++ b/runtime/observatory/tests/service/client_resume_approvals_disconnect_test.dart
@@ -0,0 +1,62 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+
+import 'client_resume_approvals_common.dart';
+import 'service_test_common.dart';
+import 'test_helper.dart';
+
+void fooBar() {
+  int i = 0;
+  print(i);
+}
+
+WebSocketVM client1;
+WebSocketVM client2;
+
+final test = <IsolateTest>[
+  // Multiple clients, disconnect client awaiting approval.
+  hasPausedAtStart,
+  (Isolate isolate) async {
+    client1 = await createClient(isolate.owner);
+    await setRequireApprovalForResume(
+      client1,
+      isolate,
+      pauseOnStart: true,
+      pauseOnExit: true,
+    );
+    client2 = await createClient(
+      isolate.owner,
+      clientName: otherClientName,
+    );
+    await setRequireApprovalForResume(
+      client2,
+      isolate,
+      pauseOnStart: true,
+      pauseOnExit: true,
+    );
+
+    // Send a resume request on the test client so we'll resume once the other
+    // clients which require approval disconnect.
+    await isolate.resume();
+    expect(await isPausedAtStart(isolate), true);
+
+    // Once client1 is disconnected, we should still be paused.
+    client1.disconnect();
+    expect(await isPausedAtStart(isolate), true);
+
+    // Once client2 disconnects, there are no clients which require resume
+    // approval. Ensure we resume immediately so we don't deadlock waiting for
+    // approvals from disconnected clients.
+    client2.disconnect();
+  },
+  hasStoppedAtExit,
+];
+
+Future<void> main(args) => runIsolateTests(args, test,
+    testeeConcurrent: fooBar, pause_on_start: true, pause_on_exit: true);
diff --git a/runtime/observatory/tests/service/client_resume_approvals_identical_names_test.dart b/runtime/observatory/tests/service/client_resume_approvals_identical_names_test.dart
new file mode 100644
index 0000000..ffbbc06
--- /dev/null
+++ b/runtime/observatory/tests/service/client_resume_approvals_identical_names_test.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+
+import 'client_resume_approvals_common.dart';
+import 'service_test_common.dart';
+import 'test_helper.dart';
+
+void fooBar() {
+  int i = 0;
+  print(i);
+}
+
+WebSocketVM client1;
+WebSocketVM client2;
+
+final sameClientNamesTest = <IsolateTest>[
+  // Multiple clients, same client names.
+  (Isolate isolate) async {
+    final resumeFuture = waitForResume(isolate);
+
+    client1 = await createClient(isolate.owner);
+    await setRequireApprovalForResume(
+      client1,
+      isolate,
+      pauseOnStart: true,
+      pauseOnExit: true,
+    );
+    client2 = await createClient(isolate.owner);
+
+    expect(await isPausedAtStart(isolate), true);
+    await resume(client2, isolate);
+    await resumeFuture;
+  },
+  hasStoppedAtExit,
+];
+
+Future<void> main(args) => runIsolateTests(args, sameClientNamesTest,
+    testeeConcurrent: fooBar, pause_on_start: true, pause_on_exit: true);
diff --git a/runtime/observatory/tests/service/client_resume_approvals_multiple_names_test.dart b/runtime/observatory/tests/service/client_resume_approvals_multiple_names_test.dart
new file mode 100644
index 0000000..65989ee
--- /dev/null
+++ b/runtime/observatory/tests/service/client_resume_approvals_multiple_names_test.dart
@@ -0,0 +1,65 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+
+import 'client_resume_approvals_common.dart';
+import 'service_test_common.dart';
+import 'test_helper.dart';
+
+void fooBar() {
+  int i = 0;
+  print(i);
+}
+
+WebSocketVM client1;
+WebSocketVM client2;
+WebSocketVM client3;
+
+final multipleClientNamesTest = <IsolateTest>[
+  // Multiple clients, different client names.
+  (Isolate isolate) async {
+    client1 = await createClient(isolate.owner);
+    await setRequireApprovalForResume(
+      client1,
+      isolate,
+      pauseOnStart: true,
+      pauseOnExit: true,
+    );
+    client2 = await createClient(
+      isolate.owner,
+      clientName: otherClientName,
+    );
+    client3 = await createClient(isolate.owner, clientName: 'DummyClient');
+
+    Future resumeFuture = waitForResume(isolate);
+    expect(await isPausedAtStart(isolate), true);
+    await resume(client2, isolate);
+    expect(await isPausedAtStart(isolate), true);
+    await resume(client1, isolate);
+    await resumeFuture;
+    expect(await isPausedAtStart(isolate), false);
+  },
+  hasStoppedAtExit,
+  (Isolate isolate) async {
+    await setRequireApprovalForResume(
+      client2,
+      isolate,
+      pauseOnExit: true,
+    );
+    final resumeFuture = waitForResume(isolate);
+    await resume(client1, isolate);
+    expect(await isPausedAtExit(isolate), true);
+    await resume(client2, isolate);
+    await resumeFuture;
+    await isolate.reload();
+    expect(await isPausedAtExit(isolate), false);
+  },
+];
+
+Future<void> main(args) => runIsolateTests(args, multipleClientNamesTest,
+    testeeConcurrent: fooBar, pause_on_start: true, pause_on_exit: true);
diff --git a/runtime/observatory/tests/service/client_resume_approvals_name_change_test.dart b/runtime/observatory/tests/service/client_resume_approvals_name_change_test.dart
new file mode 100644
index 0000000..9f0f52d
--- /dev/null
+++ b/runtime/observatory/tests/service/client_resume_approvals_name_change_test.dart
@@ -0,0 +1,55 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+
+import 'client_resume_approvals_common.dart';
+import 'service_test_common.dart';
+import 'test_helper.dart';
+
+void fooBar() {
+  int i = 0;
+  print(i);
+}
+
+WebSocketVM client1;
+WebSocketVM client2;
+WebSocketVM client3;
+
+final nameChangeTest = <IsolateTest>[
+  // Remove required approvals via name change.
+  (Isolate isolate) async {
+    final resumeFuture = waitForResume(isolate);
+
+    // Create two clients with the same name.
+    client1 = await createClient(isolate.owner);
+    client2 = await createClient(isolate.owner);
+    await setRequireApprovalForResume(
+      client1,
+      isolate,
+      pauseOnStart: true,
+      pauseOnExit: true,
+    );
+    client3 = await createClient(isolate.owner, clientName: otherClientName);
+
+    // Check that client3 can't resume the isolate on its own.
+    expect(await isPausedAtStart(isolate), true);
+    await resume(client3, isolate);
+    expect(await isPausedAtStart(isolate), true);
+
+    // Change the name of client1. Since client2 has the same name that client1
+    // originally had, the service still requires approval to resume the
+    // isolate.
+    await setClientName(client1, 'foobar');
+    expect(await isPausedAtStart(isolate), true);
+    await setClientName(client2, 'baz');
+  },
+  hasStoppedAtExit,
+];
+
+Future<void> main(args) => runIsolateTests(args, nameChangeTest,
+    testeeConcurrent: fooBar, pause_on_start: true, pause_on_exit: true);
diff --git a/runtime/observatory/tests/service/client_resume_approvals_reload_test.dart b/runtime/observatory/tests/service/client_resume_approvals_reload_test.dart
new file mode 100644
index 0000000..db0b852
--- /dev/null
+++ b/runtime/observatory/tests/service/client_resume_approvals_reload_test.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+
+import 'client_resume_approvals_common.dart';
+import 'service_test_common.dart';
+import 'test_helper.dart';
+
+void fooBar() {
+  int i = 0;
+  while (true) {
+    i++;
+  }
+  print(i);
+}
+
+WebSocketVM client1;
+WebSocketVM client2;
+
+final hotReloadTest = <IsolateTest>[
+  // Multiple clients, hot reload approval.
+  (Isolate isolate) async {
+    final resumeFuture = waitForResume(isolate);
+
+    client1 = await createClient(isolate.owner);
+    await setRequireApprovalForResume(
+      client1,
+      isolate,
+      pauseOnReload: true,
+    );
+    client2 = await createClient(
+      isolate.owner,
+      clientName: otherClientName,
+    );
+    await setRequireApprovalForResume(
+      client2,
+      isolate,
+      pauseOnReload: true,
+    );
+  },
+  // Paused on start, resume.
+  resumeIsolate,
+  // Reload and then pause.
+  reloadSources(true),
+  hasStoppedPostRequest,
+  (Isolate isolate) async {
+    // Check that client2 can't resume the isolate on its own.
+    expect(await isPausedPostRequest(isolate), true);
+    await resume(client2, isolate);
+    expect(await isPausedPostRequest(isolate), true);
+    final resumeFuture = waitForResume(isolate);
+    await resume(client1, isolate);
+    await resumeFuture;
+    expect(await isPausedPostRequest(isolate), false);
+  },
+];
+
+Future<void> main(args) => runIsolateTests(args, hotReloadTest,
+    testeeConcurrent: fooBar, pause_on_start: true);
diff --git a/runtime/observatory/tests/service/get_client_name_rpc_test.dart b/runtime/observatory/tests/service/get_client_name_rpc_test.dart
new file mode 100644
index 0000000..a3af0a6
--- /dev/null
+++ b/runtime/observatory/tests/service/get_client_name_rpc_test.dart
@@ -0,0 +1,40 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+
+import 'test_helper.dart';
+
+void fooBar() {}
+
+Future<String> getClientName(Isolate isolate) async {
+  final result = await isolate.vm.invokeRpcNoUpgrade('getClientName', {});
+  return result['name'];
+}
+
+Future<void> setClientName(Isolate isolate, String name) async =>
+    await isolate.vm.invokeRpcNoUpgrade('setClientName', {
+      'name': name,
+    });
+
+final test = <IsolateTest>[
+  (Isolate isolate) async {
+    // Each client has a default name based on the order of connection to the
+    // service.
+    expect(await getClientName(isolate), 'client1');
+
+    // Set a custom client name and check it was set properly.
+    await setClientName(isolate, 'foobar');
+    expect(await getClientName(isolate), 'foobar');
+
+    // Clear the client name and check that we're using the default again.
+    await setClientName(isolate, '');
+    expect(await getClientName(isolate), 'client1');
+  },
+];
+
+Future<void> main(args) => runIsolateTests(args, test, testeeBefore: fooBar);
diff --git a/runtime/observatory/tests/service/get_version_rpc_test.dart b/runtime/observatory/tests/service/get_version_rpc_test.dart
index a950dd0..889c1b0 100644
--- a/runtime/observatory/tests/service/get_version_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_version_rpc_test.dart
@@ -12,7 +12,7 @@
     var result = await vm.invokeRpcNoUpgrade('getVersion', {});
     expect(result['type'], equals('Version'));
     expect(result['major'], equals(3));
-    expect(result['minor'], equals(28));
+    expect(result['minor'], equals(29));
     expect(result['_privateMajor'], equals(0));
     expect(result['_privateMinor'], equals(0));
   },
diff --git a/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart b/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart
index 36638ea..a5fec01 100644
--- a/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart
@@ -1,9 +1,10 @@
 // Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
-// VMOptions=--complete_timeline
 
 import 'dart:developer';
+import 'dart:io';
+
 import 'package:observatory/service_io.dart';
 import 'package:unittest/unittest.dart';
 
@@ -165,4 +166,20 @@
   },
 ];
 
-main(args) async => runVMTests(args, tests, testeeBefore: primeTimeline);
+main(List<String> args) async {
+  // Running the subprocesses of this particular test in opt counter mode
+  // will cause it to be slow and cause many compilations.
+  //
+  // Together with "--complete-timeline" this will create a huge number of
+  // timeline events which can, on ia32, cause the process to hit OOM.
+  //
+  // So we filter out that particular argument.
+  final executableArgs = Platform.executableArguments
+      .where((String arg) => !arg.contains('optimization-counter-threshold'))
+      .toList();
+
+  await runVMTests(args, tests,
+      testeeBefore: primeTimeline,
+      extraArgs: ['--complete-timeline'],
+      executableArgs: executableArgs);
+}
diff --git a/runtime/observatory/tests/service/process_service_test.dart b/runtime/observatory/tests/service/process_service_test.dart
index df8556a..045ed2c 100644
--- a/runtime/observatory/tests/service/process_service_test.dart
+++ b/runtime/observatory/tests/service/process_service_test.dart
@@ -6,10 +6,16 @@
 import 'dart:convert';
 import 'dart:developer';
 import 'dart:io' as io;
+
 import 'package:observatory/service_io.dart';
+import 'package:path/path.dart' as path;
 import 'package:unittest/unittest.dart';
+
 import 'test_helper.dart';
 
+final dartJITBinary = path.join(path.dirname(io.Platform.executable),
+    'dart' + path.extension(io.Platform.executable));
+
 Future setupProcesses() async {
   var dir = await io.Directory.systemTemp.createTemp('file_service');
 
@@ -51,7 +57,7 @@
             await stdin.drain();
           }
           ''');
-      process3 = await io.Process.start(io.Platform.executable, [codeFilePath]);
+      process3 = await io.Process.start(dartJITBinary, [codeFilePath]);
     } catch (e) {
       closeDown();
       throw e;
@@ -106,7 +112,7 @@
 
       var third = await isolate.invokeRpcNoUpgrade(
           'ext.dart.io.getProcessById', {'id': all['data'][2]['id']});
-      expect(third['name'], io.Platform.executable);
+      expect(third['name'], dartJITBinary);
       expect(third['pid'], equals(setup['pids'][2]));
       expect(third['pid'] != first['pid'], isTrue);
       expect(third['pid'] != second['pid'], isTrue);
diff --git a/runtime/observatory/tests/service/service.status b/runtime/observatory/tests/service/service.status
index 4aa30d7..20cc72a 100644
--- a/runtime/observatory/tests/service/service.status
+++ b/runtime/observatory/tests/service/service.status
@@ -33,13 +33,13 @@
 dev_fs_http_put_weird_char_test: Skip # Windows disallows carriage returns in paths
 dev_fs_weird_char_test: Skip # Windows disallows question mark in paths
 
-[ $compiler == none && $runtime == vm && $system == fuchsia ]
-*: Skip # Not yet triaged.
-
-[ $compiler == none && ($runtime == dart_precompiled || $runtime == vm) ]
+[ $compiler == none && $runtime == vm ]
 evaluate_activation_test/instance: RuntimeError # http://dartbug.com/20047
 evaluate_activation_test/scope: RuntimeError # http://dartbug.com/20047
 
+[ $compiler == none && $runtime == vm && $system == fuchsia ]
+*: Skip # Not yet triaged.
+
 [ $mode == debug && $system == windows && $checked ]
 async_scope_test: Pass, Slow
 
diff --git a/runtime/observatory/tests/service/service_kernel.status b/runtime/observatory/tests/service/service_kernel.status
index 05b6843..2c2be97 100644
--- a/runtime/observatory/tests/service/service_kernel.status
+++ b/runtime/observatory/tests/service/service_kernel.status
@@ -59,11 +59,13 @@
 breakpoint_on_if_null_4_test: RuntimeError
 breakpoint_partfile_test: RuntimeError
 breakpoint_two_args_checked_test: Skip, Timeout
+breakpoints_with_mixin_test: RuntimeError # Debugger is disabled in AOT mode.
 capture_stdio_test: Skip, Timeout
 causal_async_stack_contents_test: Skip, Timeout
 causal_async_stack_presence_test: Skip, Timeout
 causal_async_star_stack_contents_test: Skip, Timeout
 causal_async_star_stack_presence_test: Skip, Timeout
+client_resume_approvals_reload_test: RuntimeError # Compiler is disabled in AOT mode.
 code_test: RuntimeError
 column_breakpoint_test: RuntimeError
 complex_reload_test: RuntimeError
diff --git a/runtime/observatory/tests/service/test_helper.dart b/runtime/observatory/tests/service/test_helper.dart
index 9060c00..ad76a66 100644
--- a/runtime/observatory/tests/service/test_helper.dart
+++ b/runtime/observatory/tests/service/test_helper.dart
@@ -109,15 +109,21 @@
       bool testeeControlsServer,
       Uri serviceInfoUri,
       int port,
-      List<String> extraArgs) {
+      List<String> extraArgs,
+      List<String> executableArgs) {
     assert(pause_on_start != null);
     assert(pause_on_exit != null);
     assert(pause_on_unhandled_exceptions != null);
     assert(testeeControlsServer != null);
 
     if (_shouldLaunchSkyShell()) {
-      return _spawnSkyProcess(pause_on_start, pause_on_exit,
-          pause_on_unhandled_exceptions, testeeControlsServer, extraArgs);
+      return _spawnSkyProcess(
+          pause_on_start,
+          pause_on_exit,
+          pause_on_unhandled_exceptions,
+          testeeControlsServer,
+          extraArgs,
+          executableArgs);
     } else {
       return _spawnDartProcess(
           pause_on_start,
@@ -127,7 +133,8 @@
           testeeControlsServer,
           serviceInfoUri,
           port,
-          extraArgs);
+          extraArgs,
+          executableArgs);
     }
   }
 
@@ -139,7 +146,8 @@
       bool testeeControlsServer,
       Uri serviceInfoUri,
       int port,
-      List<String> extraArgs) {
+      List<String> extraArgs,
+      List<String> executableArgs) {
     assert(!_shouldLaunchSkyShell());
 
     String dartExecutable = Platform.executable;
@@ -163,8 +171,7 @@
     if (extraArgs != null) {
       fullArgs.addAll(extraArgs);
     }
-
-    fullArgs.addAll(Platform.executableArguments);
+    fullArgs.addAll(executableArgs);
     if (!testeeControlsServer) {
       fullArgs.add('--enable-vm-service:$port');
     }
@@ -178,7 +185,8 @@
       bool pause_on_exit,
       bool pause_on_unhandled_exceptions,
       bool testeeControlsServer,
-      List<String> extraArgs) {
+      List<String> extraArgs,
+      List<String> executableArgs) {
     assert(_shouldLaunchSkyShell());
 
     String dartExecutable = _skyShellPath();
@@ -201,8 +209,7 @@
     if (extraArgs != null) {
       fullArgs.addAll(extraArgs);
     }
-
-    fullArgs.addAll(Platform.executableArguments);
+    fullArgs.addAll(executableArgs);
     if (!testeeControlsServer) {
       fullArgs.add('--observatory-port=0');
     }
@@ -233,7 +240,8 @@
       bool enable_service_port_fallback,
       bool testeeControlsServer,
       int port,
-      List<String> extraArgs) async {
+      List<String> extraArgs,
+      List<String> executableArgs) async {
     final completer = new Completer<Uri>();
     final serviceInfoDir =
         await Directory.systemTemp.createTemp('dart_service');
@@ -247,7 +255,8 @@
             testeeControlsServer,
             serviceInfoUri,
             port,
-            extraArgs)
+            extraArgs,
+            executableArgs)
         .then((p) async {
       process = p;
       Uri uri;
@@ -312,6 +321,7 @@
   void run({
     List<String> mainArgs,
     List<String> extraArgs,
+    List<String> executableArgs,
     List<VMTest> vmTests,
     List<IsolateTest> isolateTests,
     bool pause_on_start: false,
@@ -322,6 +332,10 @@
     bool testeeControlsServer: false,
     int port = 0,
   }) {
+    if (executableArgs == null) {
+      executableArgs = Platform.executableArguments;
+    }
+
     var process = new _ServiceTesteeLauncher();
     bool testsDone = false;
     runZoned(() {
@@ -333,7 +347,8 @@
               enable_service_port_fallback,
               testeeControlsServer,
               port,
-              extraArgs)
+              extraArgs,
+              executableArgs)
           .then((Uri serverAddress) async {
         if (mainArgs.contains("--gdb")) {
           var pid = process.process.pid;
@@ -515,7 +530,8 @@
     bool pause_on_unhandled_exceptions: false,
     bool enable_service_port_fallback: false,
     int port = 0,
-    List<String> extraArgs}) async {
+    List<String> extraArgs,
+    List<String> executableArgs}) async {
   if (_isTestee()) {
     new _ServiceTesteeRunner().run(
         testeeBefore: testeeBefore,
@@ -526,6 +542,7 @@
     new _ServiceTesterRunner().run(
       mainArgs: mainArgs,
       extraArgs: extraArgs,
+      executableArgs: executableArgs,
       vmTests: tests,
       pause_on_start: pause_on_start,
       pause_on_exit: pause_on_exit,
diff --git a/runtime/platform/globals.h b/runtime/platform/globals.h
index 26c981d..f3822cb 100644
--- a/runtime/platform/globals.h
+++ b/runtime/platform/globals.h
@@ -374,19 +374,6 @@
 #define TARGET_ARCH_IS_64_BIT 1
 #endif
 
-// Determine whether HOST_ARCH equals TARGET_ARCH.
-#if defined(HOST_ARCH_ARM) && defined(TARGET_ARCH_ARM)
-#define HOST_ARCH_EQUALS_TARGET_ARCH 1
-#elif defined(HOST_ARCH_ARM64) && defined(TARGET_ARCH_ARM64)
-#define HOST_ARCH_EQUALS_TARGET_ARCH 1
-#elif defined(HOST_ARCH_IA32) && defined(TARGET_ARCH_IA32)
-#define HOST_ARCH_EQUALS_TARGET_ARCH 1
-#elif defined(HOST_ARCH_X64) && defined(TARGET_ARCH_X64)
-#define HOST_ARCH_EQUALS_TARGET_ARCH 1
-#else
-// HOST_ARCH != TARGET_ARCH.
-#endif
-
 #if !defined(TARGET_OS_ANDROID) && !defined(TARGET_OS_FUCHSIA) &&              \
     !defined(TARGET_OS_MACOS_IOS) && !defined(TARGET_OS_LINUX) &&              \
     !defined(TARGET_OS_MACOS) && !defined(TARGET_OS_WINDOWS)
diff --git a/runtime/platform/growable_array.h b/runtime/platform/growable_array.h
index 615b616..83deee8 100644
--- a/runtime/platform/growable_array.h
+++ b/runtime/platform/growable_array.h
@@ -160,6 +160,16 @@
     RemoveLast();
   }
 
+  // Preserves array order.
+  void EraseAt(intptr_t idx) {
+    ASSERT(idx >= 0);
+    ASSERT(idx < length_);
+    for (intptr_t i = idx; i < length_ - 1; i++) {
+      data_[i] = data_[i + 1];
+    }
+    RemoveLast();
+  }
+
   // The content is uninitialized after calling it.
   void SetLength(intptr_t new_length);
 
diff --git a/runtime/platform/utils.cc b/runtime/platform/utils.cc
index d6a0f96..4a23476 100644
--- a/runtime/platform/utils.cc
+++ b/runtime/platform/utils.cc
@@ -295,4 +295,8 @@
   return buffer;
 }
 
+Utils::CStringUniquePtr Utils::CreateCStringUniquePtr(char* str) {
+  return std::unique_ptr<char, decltype(std::free)*>{str, std::free};
+}
+
 }  // namespace dart
diff --git a/runtime/platform/utils.h b/runtime/platform/utils.h
index 38d4d2f..ee6c0dd 100644
--- a/runtime/platform/utils.h
+++ b/runtime/platform/utils.h
@@ -6,6 +6,7 @@
 #define RUNTIME_PLATFORM_UTILS_H_
 
 #include <limits>
+#include <memory>
 #include <type_traits>
 
 #include "platform/assert.h"
@@ -416,6 +417,11 @@
   // Allocate a string and print formatted output into a malloc'd buffer.
   static char* SCreate(const char* format, ...) PRINTF_ATTRIBUTE(1, 2);
   static char* VSCreate(const char* format, va_list args);
+
+  typedef std::unique_ptr<char, decltype(std::free)*> CStringUniquePtr;
+
+  // Returns str in a unique_ptr with free used as its deleter.
+  static CStringUniquePtr CreateCStringUniquePtr(char* str);
 };
 
 }  // namespace dart
diff --git a/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart b/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart
index 965590b..9d23a87 100644
--- a/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart
+++ b/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart
@@ -203,8 +203,14 @@
     final _thisTestPath = path.join(sdkDir, 'runtime', 'tests', 'vm', 'dart',
         'v8_snapshot_profile_writer_test.dart');
     final dillPath = path.join(tempDir, 'test.dill');
-    await run(genKernel,
-        <String>['--platform', platformDill, '-o', dillPath, _thisTestPath]);
+    await run(genKernel, <String>[
+      '--aot',
+      '--platform',
+      platformDill,
+      '-o',
+      dillPath,
+      _thisTestPath
+    ]);
 
     // Test stripped ELF generation directly.
     await test(
diff --git a/runtime/tools/dartfuzz/dartfuzz_test.dart b/runtime/tools/dartfuzz/dartfuzz_test.dart
index c3124784..3edcb2f 100644
--- a/runtime/tools/dartfuzz/dartfuzz_test.dart
+++ b/runtime/tools/dartfuzz/dartfuzz_test.dart
@@ -152,7 +152,7 @@
 
 /// Concrete test runner of Dart JIT.
 class TestRunnerJIT implements TestRunner {
-  TestRunnerJIT(String prefix, String tag, String top, String tmp, this.env,
+  TestRunnerJIT(String prefix, String tag, this.top, String tmp, this.env,
       this.fileName, List<String> extraFlags) {
     description = '$prefix-$tag';
     dart = '$top/out/$tag/dart';
@@ -168,18 +168,20 @@
     return runCommand(cmd, env);
   }
 
-  void printReproductionCommand() => print(cmd.join(" "));
+  void printReproductionCommand() =>
+      print(cmd.join(" ").replaceAll('$top/', ''));
 
   String description;
   String dart;
   String fileName;
+  final String top;
   Map<String, String> env;
   List<String> cmd;
 }
 
 /// Concrete test runner of Dart AOT.
 class TestRunnerAOT implements TestRunner {
-  TestRunnerAOT(String prefix, String tag, String top, String tmp,
+  TestRunnerAOT(String prefix, String tag, this.top, this.tmp,
       Map<String, String> e, this.fileName, List<String> extraFlags) {
     description = '$prefix-$tag';
     precompiler = '$top/pkg/vm/tool/precompiler2';
@@ -205,8 +207,11 @@
       "DART_CONFIGURATION='${env['DART_CONFIGURATION']}'",
       "DART_VM_FLAGS='${env['DART_VM_FLAGS']}'",
       ...cmd
-    ].join(" "));
-    print([dart, snapshot].join(" "));
+    ].join(" ").replaceAll('$top/', '').replaceAll('$tmp/', ''));
+    print([dart, snapshot]
+        .join(" ")
+        .replaceAll('$top/', '')
+        .replaceAll('$tmp/', ''));
   }
 
   String description;
@@ -214,13 +219,15 @@
   String dart;
   String fileName;
   String snapshot;
+  final String top;
+  final String tmp;
   Map<String, String> env;
   List<String> cmd;
 }
 
 /// Concrete test runner of bytecode.
 class TestRunnerKBC implements TestRunner {
-  TestRunnerKBC(String prefix, String tag, String top, String tmp, this.env,
+  TestRunnerKBC(String prefix, String tag, this.top, this.tmp, this.env,
       this.fileName, List<String> extraFlags, bool kbcSrc) {
     description = '$prefix-$tag';
     dart = '$top/out/$tag/dart';
@@ -253,9 +260,11 @@
   void printReproductionCommand() {
     if (generate != null) {
       print([generate, '--gen-bytecode', platform, '-o', dill, fileName]
-          .join(" "));
+          .join(" ")
+          .replaceAll('$top/', '')
+          .replaceAll('$tmp/', ''));
     }
-    print(cmd.join(" "));
+    print(cmd.join(" ").replaceAll('$top/', '').replaceAll('$tmp/', ''));
   }
 
   String description;
@@ -264,14 +273,16 @@
   String dill;
   String dart;
   String fileName;
+  final String top;
+  final String tmp;
   Map<String, String> env;
   List<String> cmd;
 }
 
 /// Concrete test runner of Dart2JS.
 class TestRunnerDJS implements TestRunner {
-  TestRunnerDJS(String prefix, String tag, String top, String tmp, this.env,
-      this.fileName) {
+  TestRunnerDJS(
+      String prefix, String tag, this.top, this.tmp, this.env, this.fileName) {
     description = '$prefix-$tag';
     dart2js = '$top/sdk/bin/dart2js';
     js = '$tmp/out.js';
@@ -286,14 +297,19 @@
   }
 
   void printReproductionCommand() {
-    print([dart2js, fileName, '-o', js].join(" "));
-    print(['nodejs', js].join(" "));
+    print([dart2js, fileName, '-o', js]
+        .join(" ")
+        .replaceAll('$top/', '')
+        .replaceAll('$tmp/', ''));
+    print('nodejs out.js');
   }
 
   String description;
   String dart2js;
   String fileName;
   String js;
+  final String top;
+  final String tmp;
   Map<String, String> env;
 }
 
@@ -357,9 +373,9 @@
 
     // Testcase generation flags.
 
-    // Only use FP when modes have same precision (to avoid false
+    // Only use FP when modes have the same architecture (to avoid false
     // divergences between 32-bit and 64-bit versions).
-    fp = samePrecision(mode1, mode2);
+    fp = sameArchitecture(mode1, mode2);
     // Occasionally test FFI (if capable).
     ffi = ffiCapable(mode1, mode2) && (rand.nextInt(5) == 0);
     // Resort to flat types for the more expensive modes.
@@ -388,8 +404,11 @@
     skippedSeeds = {};
   }
 
-  bool samePrecision(String mode1, String mode2) =>
-      mode1.contains('64') == mode2.contains('64');
+  bool sameArchitecture(String mode1, String mode2) =>
+      ((mode1.contains('arm32') && mode2.contains('arm32')) ||
+          (mode1.contains('arm64') && mode2.contains('arm64')) ||
+          (mode1.contains('x64') && mode2.contains('x64')) ||
+          (mode1.contains('ia32') && mode2.contains('ia32')));
 
   bool ffiCapable(String mode1, String mode2) =>
       (mode1.startsWith('jit') || mode1.startsWith('kbc')) &&
@@ -547,9 +566,10 @@
   void showReproduce() {
     print("\n-- BEGIN REPRODUCE  --\n");
     print("DART SDK REVISION: $dartSdkRevision\n");
-    print("dartfuzz.dart --${fp ? "" : "no-"}fp --${ffi ? "" : "no-"}ffi "
+    print(
+        "dart runtime/tools/dartfuzz/dartfuzz.dart --${fp ? "" : "no-"}fp --${ffi ? "" : "no-"}ffi "
         "--${flatTp ? "" : "no-"}flat "
-        "--seed ${seed} $fileName");
+        "--seed ${seed} fuzz.dart");
     print("\n-- RUN 1 --\n");
     runner1.printReproductionCommand();
     print("\n-- RUN 2 --\n");
@@ -687,14 +707,9 @@
   }
 
   static String getDartSdkRevision(String top) {
-    top = getTop(top);
     ProcessResult res =
-        Process.runSync('git', ['--git-dir=$top/.git', 'rev-parse', 'HEAD']);
-    if (debug) {
-      print('\ngit rev-parse HEAD result:\n'
-          '${res.exitCode}\n${res.stdout}\n');
-    }
-    return res.stdout;
+        Process.runSync(Platform.resolvedExecutable, ['--version']);
+    return res.stderr;
   }
 
   // Picks a mode (command line or random).
diff --git a/runtime/tools/wiki/CustomShellSessionPygmentsLexer/custom_shell_session/__init__.py b/runtime/tools/wiki/CustomShellSessionPygmentsLexer/custom_shell_session/__init__.py
new file mode 100644
index 0000000..58baf98
--- /dev/null
+++ b/runtime/tools/wiki/CustomShellSessionPygmentsLexer/custom_shell_session/__init__.py
@@ -0,0 +1,5 @@
+#
+# Copyright (c) 2020, 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.
+#
diff --git a/runtime/tools/wiki/CustomShellSessionPygmentsLexer/custom_shell_session/lexer.py b/runtime/tools/wiki/CustomShellSessionPygmentsLexer/custom_shell_session/lexer.py
new file mode 100644
index 0000000..3e1e635
--- /dev/null
+++ b/runtime/tools/wiki/CustomShellSessionPygmentsLexer/custom_shell_session/lexer.py
@@ -0,0 +1,49 @@
+#
+# Copyright (c) 2020, 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.
+#
+"""Simple lexer for shell sessions.
+
+Highlights command lines (lines starting with $ prompt) and comments starting
+with #. For example:
+
+    # This is a comment
+    $ this-is-a-command
+    This is output of the command
+
+    $ this-is-a-multiline-command with-some-arguments \
+      and more arguments \
+      and more arguments
+    And some output.
+
+"""
+
+from pygments.lexer import RegexLexer, words
+from pygments.token import Comment, Generic, Keyword
+
+_comment_style = Comment
+# Note: there is a slight inversion of styles to make it easier to read.
+# We highlight output with Prompt style and command as a normal text.
+_output_style = Generic.Prompt
+_command_style = Generic.Text
+_prompt_style = Keyword
+
+
+class CustomShellSessionLexer(RegexLexer):
+    name = 'CustomShellSession'
+    aliases = ['custom-shell-session']
+    filenames = ['*.log']
+    tokens = {
+        'root': [
+            (r'#.*\n', _comment_style),
+            (r'^\$', _prompt_style, 'command'),
+            (r'.', _output_style),
+        ],
+        'command': [
+            (r'\\\n', _command_style),  # Continue in 'command' state.
+            (r'$', _command_style, '#pop'),  # End of line without escape.
+            (r'.',
+             _command_style),  # Anything else continue in 'command' state.
+        ]
+    }
diff --git a/runtime/tools/wiki/CustomShellSessionPygmentsLexer/setup.py b/runtime/tools/wiki/CustomShellSessionPygmentsLexer/setup.py
new file mode 100644
index 0000000..b00ade9
--- /dev/null
+++ b/runtime/tools/wiki/CustomShellSessionPygmentsLexer/setup.py
@@ -0,0 +1,15 @@
+#
+# Copyright (c) 2020, 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.
+#
+from setuptools import setup, find_packages
+
+setup(
+    name='custom-shell-session',
+    packages=find_packages(),
+    entry_points="""
+  [pygments.lexers]
+  custom-shell-session = custom_shell_session.lexer:CustomShellSessionLexer
+  """,
+)
diff --git a/runtime/tools/wiki/README.md b/runtime/tools/wiki/README.md
new file mode 100644
index 0000000..2606ac8
--- /dev/null
+++ b/runtime/tools/wiki/README.md
@@ -0,0 +1,42 @@
+This directory contains helper scripts for rendering runtime wiki pages as HTML.
+
+```shell
+# Run webserver for development.
+$ runtime/tools/wiki/build/build.py
+
+# Build wiki for deployment
+$ runtime/tools/wiki/build/build.py --deploy
+```
+
+# Markdown extensions
+
+## Asides
+
+Paragraphs wrapped into `<aside>...</aside>` will be rendered as a sidenote on
+margins of the page.
+
+## Cross-references `@{ref|text}`
+
+Cross-references are rendered as links to GitHub at the current commit.
+
+* `@{file-path}` is just rendered a link to the given file;
+* `@{package:name/path.dart}` is rendered as a link to file `path.dart` within
+package `name` - actual path is resolved via root `.packages` file in the SDK
+root;
+* `@{c++-symbol}` is rendered as a link to the line in the file which defines
+the given C++ symbol.
+
+# Prerequisites
+
+1. Install all Python dependencies.
+    ```console
+    $ pip3 install coloredlogs jinja2 markdown aiohttp watchdog pymdown-extensions pygments
+    ```
+2. Install the custom pygments lexer we use for shell session examples:
+    ```
+    $ cd runtime/tools/wiki/CustomShellSessionPygmentsLexer
+    $ python3 setup.py develop
+    ```
+3. Install SASS compiler (make sure that SASS binary is in your path).
+4. Generate `xref.json` file following instructions in
+`xref_extractor/README.md`.
\ No newline at end of file
diff --git a/runtime/tools/wiki/build/build.py b/runtime/tools/wiki/build/build.py
new file mode 100755
index 0000000..6fc31dd
--- /dev/null
+++ b/runtime/tools/wiki/build/build.py
@@ -0,0 +1,331 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2020, 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.
+#
+"""Tool used for rendering Dart Native Runtime wiki as HTML.
+
+Usage: runtime/tools/wiki/build/build.py [--deploy]
+
+If invoked without --deploy the tool would serve development version of the
+wiki which supports fast edit-(auto)refresh cycle.
+
+If invoked with --deploy it would build deployment version in the
+/tmp/dart-vm-wiki directory.
+"""
+
+from __future__ import annotations
+
+import argparse
+import asyncio
+import codecs
+import coloredlogs
+import glob
+import jinja2
+import logging
+import markdown
+import os
+import posixpath
+import re
+import shutil
+import subprocess
+import sys
+import time
+import urllib
+
+from aiohttp import web, WSCloseCode, WSMsgType
+from http.server import HTTPServer, SimpleHTTPRequestHandler
+from markdown.extensions.codehilite import CodeHiliteExtension
+from pathlib import Path
+from typing import Callable, Dict, Sequence
+from watchdog.events import FileSystemEventHandler
+from watchdog.observers import Observer
+from xrefs import XrefExtension
+
+# Configure logging to use colors.
+coloredlogs.install(
+    level='INFO', fmt='%(asctime)s - %(message)s', datefmt='%H:%M:%S')
+
+# Declare various directory paths.
+# We expected to be located in runtime/tools/wiki/build.
+TOOL_DIR = os.path.dirname(os.path.realpath(__file__))
+SDK_DIR = os.path.relpath(os.path.join(TOOL_DIR, '..', '..', '..', '..'))
+
+WIKI_SOURCE_DIR = os.path.join(SDK_DIR, 'runtime', 'docs')
+
+STYLES_DIR = os.path.relpath(os.path.join(TOOL_DIR, '..', 'styles'))
+STYLES_INCLUDES_DIR = os.path.join(STYLES_DIR, 'includes')
+
+TEMPLATES_DIR = os.path.relpath(os.path.join(TOOL_DIR, '..', 'templates'))
+TEMPLATES_INCLUDES_DIR = os.path.join(TEMPLATES_DIR, 'includes')
+
+PAGE_TEMPLATE = 'page.html'
+
+OUTPUT_DIR = '/tmp/dart-vm-wiki'
+OUTPUT_CSS_DIR = os.path.join(OUTPUT_DIR, 'css')
+
+# Clean output directory and recreate it.
+shutil.rmtree(OUTPUT_DIR, ignore_errors=True)
+os.makedirs(OUTPUT_DIR, exist_ok=True)
+os.makedirs(OUTPUT_CSS_DIR, exist_ok=True)
+
+# Parse incoming arguments.
+parser = argparse.ArgumentParser()
+parser.add_argument('--deploy', dest='deploy', action='store_true')
+parser.set_defaults(deploy=False)
+args = parser.parse_args()
+
+is_dev_mode = not args.deploy
+
+# Initialize jinja environment.
+jinja2_env = jinja2.Environment(
+    loader=jinja2.FileSystemLoader(TEMPLATES_DIR),
+    lstrip_blocks=True,
+    trim_blocks=True)
+
+
+class Artifact:
+    """Represents a build artifact with its dependencies and way of building."""
+
+    # Map of all discovered artifacts.
+    all: Dict[str, Artifact] = {}
+
+    # List of listeners which are notified whenever some artifact is rebuilt.
+    listeners = []
+
+    def __init__(self, output: str, inputs: Sequence[str]):
+        Artifact.all[output] = self
+        self.output = output
+        self.inputs = inputs
+
+    def depends_on(self, path: str) -> bool:
+        """Check if this"""
+        return path in self.inputs
+
+    def build(self):
+        pass
+
+    @staticmethod
+    def build_all():
+        """Build all artifacts."""
+        Artifact.build_matching(lambda obj: True)
+
+    @staticmethod
+    def build_matching(filter: Callable[[Artifact], bool]):
+        """Build all artifacts matching the given filter."""
+        rebuilt = False
+        for _, artifact in Artifact.all.items():
+            if filter(artifact):
+                artifact.build()
+                rebuilt = True
+
+        # If any artifacts were rebuilt notify the listeners.
+        if rebuilt:
+            for listener in Artifact.listeners:
+                listener()
+
+
+class Page(Artifact):
+    """A single wiki Page (a markdown file)."""
+
+    def __init__(self, name: str):
+        self.name = name
+        super().__init__(
+            os.path.join(OUTPUT_DIR, name + '.html'),
+            [os.path.join(WIKI_SOURCE_DIR, name + '.md')])
+
+    def __repr__(self):
+        return 'Page(%s <- %s)' % (self.output, self.inputs[0])
+
+    def depends_on(self, path: str):
+        return path.startswith(TEMPLATES_INCLUDES_DIR) or super().depends_on(
+            path)
+
+    def load_markdown(self):
+        with open(self.inputs[0], 'r') as file:
+            content = file.read()
+            content = re.sub(r'(?<=[^\n])\n+<aside>', '<span class="aside">',
+                             content)
+            content = re.sub(r'</aside>', '</span>', content)
+            return content
+
+    def build(self):
+        logging.info('Build %s from %s', self.output, self.inputs[0])
+
+        template = jinja2_env.get_template(PAGE_TEMPLATE)
+        result = template.render({
+            'dev':
+            is_dev_mode,
+            'body':
+            markdown.markdown(
+                self.load_markdown(),
+                extensions=[
+                    'admonition', 'extra',
+                    CodeHiliteExtension(), 'tables', 'pymdownx.superfences',
+                    XrefExtension()
+                ])
+        })
+
+        os.makedirs(os.path.dirname(self.output), exist_ok=True)
+        with codecs.open(self.output, "w", encoding='utf-8') as file:
+            file.write(result)
+
+        template_filename = template.filename  # pytype: disable=attribute-error
+        self.inputs = [self.inputs[0], template_filename]
+
+
+class Style(Artifact):
+    """Stylesheet written in SASS which needs to be compiled to CSS."""
+
+    def __init__(self, name: str):
+        self.name = name
+        super().__init__(
+            os.path.join(OUTPUT_CSS_DIR, name + '.css'),
+            [os.path.join(STYLES_DIR, name + '.scss')])
+
+    def __repr__(self):
+        return 'Style(%s <- %s)' % (self.output, self.inputs[0])
+
+    def depends_on(self, path: str):
+        return path.startswith(STYLES_INCLUDES_DIR) or super().depends_on(path)
+
+    def build(self):
+        logging.info('Build %s from %s', self.output, self.inputs[0])
+        subprocess.call(['sass', self.inputs[0], self.output])
+
+
+def find_images_directories():
+    """Find all subdirectories called images within wiki."""
+    return [
+        f.relative_to(Path(WIKI_SOURCE_DIR)).as_posix()
+        for f in Path(WIKI_SOURCE_DIR).rglob('images')
+    ]
+
+
+def find_artifacts():
+    """Find all wiki pages and styles and create corresponding Artifacts."""
+    Artifact.all = {}
+    for f in Path(WIKI_SOURCE_DIR).rglob('*.md'):
+        name = f.relative_to(Path(WIKI_SOURCE_DIR)).as_posix().rsplit('.', 1)[0]
+        Page(name)
+
+    for f in Path(STYLES_DIR).glob('*.scss'):
+        Style(f.stem)
+
+
+def build_for_deploy():
+    logging.info('Building wiki for deployment into %s', OUTPUT_DIR)
+    Artifact.build_all()
+    for images_dir in find_images_directories():
+        src = os.path.join(WIKI_SOURCE_DIR, images_dir)
+        dst = os.path.join(OUTPUT_DIR, images_dir)
+        logging.info('Copying %s <- %s', dst, src)
+        shutil.rmtree(dst, ignore_errors=True)
+        shutil.copytree(src, dst)
+
+    # Some images directories contain OmniGraffle source files which need
+    # to be removed before
+    logging.info('Removing image source files (*.graffle)')
+    for graffle in Path(OUTPUT_DIR).rglob('*.graffle'):
+        logging.info('... removing %s', graffle.as_posix())
+
+
+class ArtifactEventHandler(FileSystemEventHandler):
+    """File system listener rebuilding artifacts based on changed paths."""
+
+    def __init__(self):
+        super().__init__()
+
+    def on_modified(self, event):
+        Artifact.build_matching(
+            lambda artifact: artifact.depends_on(event.src_path))
+
+
+def serve_for_development():
+    logging.info('Serving wiki for development')
+    Artifact.build_all()
+
+    # Watch for file modifications and rebuild dependant artifacts when their
+    # dependencies change.
+    event_handler = ArtifactEventHandler()
+    observer = Observer()
+    observer.schedule(event_handler, TEMPLATES_DIR, recursive=False)
+    observer.schedule(event_handler, WIKI_SOURCE_DIR, recursive=True)
+    observer.schedule(event_handler, STYLES_DIR, recursive=True)
+    observer.start()
+
+    async def on_shutdown(app):
+        for ws in app['websockets']:
+            await ws.close(
+                code=WSCloseCode.GOING_AWAY, message='Server shutdown')
+        observer.stop()
+        observer.join()
+
+    async def handle_artifact(name):
+        source_path = os.path.join(OUTPUT_DIR, name)
+        logging.info('Handling source path %s for %s', source_path, name)
+        if source_path in Artifact.all:
+            return web.FileResponse(source_path)
+        else:
+            return web.HTTPNotFound()
+
+    async def handle_page(request):
+        name = request.match_info.get('name', 'index.html')
+        if name == '' or name.endswith('/'):
+            name = name + 'index.html'
+        return await handle_artifact(name)
+
+    async def handle_css(request):
+        name = request.match_info.get('name')
+        return await handle_artifact('css/' + name)
+
+    async def websocket_handler(request):
+        logging.info('websocket connection open')
+        ws = web.WebSocketResponse()
+        await ws.prepare(request)
+
+        loop = asyncio.get_event_loop()
+
+        def notify():
+            logging.info('requesting reload')
+            asyncio.run_coroutine_threadsafe(ws.send_str('reload'), loop)
+
+        Artifact.listeners.append(notify)
+        request.app['websockets'].append(ws)
+        try:
+            async for msg in ws:
+                if msg.type == WSMsgType.ERROR:
+                    logging.error(
+                        'websocket connection closed with exception %s',
+                        ws.exception())
+        finally:
+            logging.info('websocket connection closing')
+            Artifact.listeners.remove(notify)
+            request.app['websockets'].remove(ws)
+
+        logging.info('websocket connection closed')
+        return ws
+
+    app = web.Application()
+    app['websockets'] = []
+    for images_dir in find_images_directories():
+        app.router.add_static('/' + images_dir,
+                              os.path.join(WIKI_SOURCE_DIR, images_dir))
+    app.router.add_get('/ws', websocket_handler)
+    app.router.add_get('/css/{name}', handle_css)
+    app.router.add_get('/{name:[^{}]*}', handle_page)
+    app.on_shutdown.append(on_shutdown)
+    web.run_app(app, access_log_format='"%r" %s')
+
+
+def main():
+    find_artifacts()
+    if is_dev_mode:
+        serve_for_development()
+    else:
+        build_for_deploy()
+
+
+if __name__ == '__main__':
+    main()
diff --git a/runtime/tools/wiki/build/xrefs.py b/runtime/tools/wiki/build/xrefs.py
new file mode 100644
index 0000000..bb8a1b1
--- /dev/null
+++ b/runtime/tools/wiki/build/xrefs.py
@@ -0,0 +1,120 @@
+# Copyright (c) 2020, 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.
+#
+"""Support for @{ref|text} reference links in Markdown.
+
+This Markdown extension converts @{ref|text} into a link with the given
+[text] pointing to a particular source code location. [ref] can be one of
+the following:
+
+   * package:-scheme URI - it will be resolved using .packages file in the
+     root directory
+   * file path
+   * C++ symbol - will be resolved through xref.json file (see README.md)
+
+Usage: markdown.markdown(extensions=[XrefExtension()])
+"""
+
+import json
+import logging
+import os
+import subprocess
+
+from markdown.extensions import Extension
+from markdown.inlinepatterns import InlineProcessor
+from markdown.util import etree
+from typing import Optional
+from urllib.parse import urlparse
+
+_current_commit_hash = subprocess.run(['git', 'rev-parse', 'HEAD'],
+                                      capture_output=True,
+                                      encoding='utf8').stdout
+
+# Load .packages file into a dictionary.
+with open('.packages') as packages_file:
+    _packages = dict([
+        package_mapping.split(':', 1)
+        for package_mapping in packages_file
+        if not package_mapping.startswith('#')
+    ])
+
+# Load xref.json and verify that it was generated for the current commit to
+# avoid discrepancies in the generated links.
+with open('xref.json') as json_file:
+    _xrefs = json.load(json_file)
+
+if _current_commit_hash != _xrefs['commit']:
+    logging.error(
+        'xref.json is generated for commit %s while current commit is %s',
+        _xrefs['commit'], _current_commit_hash)
+
+
+def _make_github_uri(file: str, lineno: str = None) -> str:
+    """Generates source link pointing to GitHub"""
+    fragment = '#L%s' % (lineno) if lineno is not None else ''
+    return 'https://github.com/dart-lang/sdk/blob/%s/%s%s' % (
+        _current_commit_hash, file, fragment)
+
+
+def _file_ref_to_github_uri(file_ref: str) -> str:
+    """Generates source link pointing to GitHub from an xref.json reference."""
+    (file_idx, line_idx) = file_ref.split(':', 1)
+    return _make_github_uri(_xrefs['files'][int(file_idx)], line_idx)
+
+
+def _resolve_ref_via_xref(ref: str) -> Optional[str]:
+    """Resolve the target of the given reference via xref.json"""
+    if ref in _xrefs['functions']:
+        return _xrefs['functions'][ref]
+    if ref in _xrefs['classes']:
+        return _xrefs['classes'][ref][0]
+    if '::' in ref:
+        (class_name, function_name) = ref.rsplit('::', 1)
+        if class_name in _xrefs['classes'] and len(
+                _xrefs['classes'][class_name]) == 2:
+            return _xrefs['classes'][class_name][1][function_name]
+    logging.error('Failed to resolve xref %s' % ref)
+    return None
+
+
+def _resolve_ref(ref: str) -> Optional[str]:
+    if ref.startswith('package:'):
+        # Resolve as package uri via .packages.
+        uri = urlparse(ref)
+        (package_name, *path_to_file) = uri.path.split('/', 1)
+        package_path = _packages[package_name]
+        if len(path_to_file) == 0:
+            return _make_github_uri(package_path)
+        else:
+            return _make_github_uri(os.path.join(package_path, path_to_file[0]))
+    elif os.path.exists(ref):
+        # Resolve as a file link.
+        return _make_github_uri(_current_commit_hash, ref)
+    else:
+        # Resolve as a C++ symbol via xref.json
+        file_ref = _resolve_ref_via_xref(ref)
+        if file_ref is not None:
+            return _file_ref_to_github_uri(file_ref)
+
+
+class _XrefPattern(InlineProcessor):
+    """InlineProcessor responsible for handling @{ref|text} syntax."""
+
+    def handleMatch(self, m, data):
+        ref = m.group(1)
+        text = m.group(2)
+        uri = _resolve_ref(ref)
+        el = etree.Element('a')
+        el.attrib['href'] = uri
+        el.attrib['target'] = 'blank'
+        el.text = text[1:] if text is not None else ref
+        return el, m.start(0), m.end(0)
+
+
+class XrefExtension(Extension):
+    """Markdown extension responsible for expanding @{ref|text} into links."""
+
+    def extendMarkdown(self, md):
+        md.inlinePatterns.register(
+            _XrefPattern(r'@{([^}|]*)(\|[^}]+)?}'), 'xref', 175)
diff --git a/runtime/tools/wiki/styles/style.scss b/runtime/tools/wiki/styles/style.scss
new file mode 100644
index 0000000..adfc9a5
--- /dev/null
+++ b/runtime/tools/wiki/styles/style.scss
@@ -0,0 +1,379 @@
+@import url('https://fonts.googleapis.com/css?family=Source+Code+Pro|Source+Sans+Pro&display=swap');
+
+$monospace: 'Source Code Pro', Menlo, Consolas, monospace;
+$sans: 'Source Sans Pro', sans-serif;
+
+a {
+  color: #C00;
+  text-decoration: none;
+  border-bottom: dashed 1px #C00;
+}
+
+a:visited {
+  color: #a30000;
+  border-bottom: dashed 1px #a30000;
+}
+
+a:hover {
+  color: #b70000;
+  border-bottom: dashed 1px #b70000;
+}
+
+$base-font-size: 16px;
+$base-line-height: 24px;
+$pre-font-size: 16px;
+$pre-line-height: 24px;
+$code-font-size: 16px;
+$code-line-height: 24px;
+$header-font-size: 16px;
+
+div.codehilite {
+  font-size: $header-font-size;
+  margin: 0px -20px;
+  padding: 5px 20px;
+}
+
+h1 { font-size: $header-font-size * 2; }
+h2 { font-size: $header-font-size * 1.5; }
+h3 { font-size: $header-font-size * 1.17; }
+h4 { font-size: $header-font-size * 1.12; }
+h5 { font-size: $header-font-size * .83; }
+h6 { font-size: $header-font-size * .75; }
+
+p {
+  position: relative;
+}
+
+html, body {
+  margin: 0;
+  padding: 0;
+  height: 100%;
+  font: normal #{$base-font-size}/#{$base-line-height} $sans;
+  text-align: justify;
+  color: #112;
+  text-rendering: optimizeLegibility;
+  -webkit-font-smoothing: antialiased;
+  letter-spacing: 0.01em;
+}
+
+h1, h2, h3, h4, h5 {
+  font-family: $sans;
+  text-align: left;
+  position: relative;
+}
+
+.section-number {
+  position: absolute;
+  color: #C00;
+  text-align: right;
+  left: -70px;
+  width: 55px;
+  padding-right: 5px;
+}
+
+h1 .section-number {
+  color: white;
+  background: #C00;
+}
+
+h1 { color: #C00; }
+
+body.front-page {
+  background: whitesmoke;
+}
+
+p > img {
+  max-width: 90%;
+  height: auto;
+  margin-left: auto;
+  margin-right: auto;
+  display: block;
+}
+
+.content {
+  padding-top: 20px;
+  width: 800px;
+  margin-left: auto;
+  margin-right: auto;
+}
+
+.box {
+  width: 800px;
+  margin-left: auto;
+  margin-right: auto;
+  margin-top: 50px;
+  margin-bottom: 50px;
+  padding: 20px;
+}
+
+.box-centered {
+  text-align: center;
+}
+
+.box-white {
+  background: white;
+  border: 1px solid #ccc;
+  box-shadow: 2px 2px 8px #aaa;
+  border-radius: 5px;
+}
+
+.aside {
+  margin-right: -280px;
+  position: absolute;
+  right: 0;
+  top: 0;
+  width: 240px;
+  text-align: left;
+  font-size: .9em;
+}
+
+@media only screen and (max-width: 1200px) {
+  .box {
+    width: auto;
+    left: 0px;
+    right: 0px;
+    margin: 0px;
+  }
+
+  .box-white {
+    border: none;
+  }
+
+  .content {
+    width: auto;
+    left: 0px;
+    right: 0px;
+    margin: 0px;
+  }
+
+  .aside {
+    margin-right: 0px;
+    position: relative;
+    right: 0px;
+    width: auto;
+    text-align: justify;
+    font-size: .9em;
+    background: #F0F4C3;
+    display: block;
+    padding: 5px;
+  }
+
+  body {
+    font: normal 14px/18px $sans;
+    padding: 5px;
+  }
+
+  div.codehilite {
+    font: normal 10px/13px $monospace;
+    margin: 0px -5px;
+    padding: 5px 5px;
+  }
+}
+
+.book-title {
+  font: 3em $monospace;
+  text-transform: uppercase;
+  font-weight: normal;
+  /* border-width: 0px 1px 0px 1px; */
+  /* border: dashed #C00; */
+  border-width: 2px 0px 2px;
+  padding: 10px 0px 5px 0px;
+  text-align: center;
+  letter-spacing: .1em;
+  color: #C00;
+  /* background-color: white; */
+}
+
+.book-subtitle {
+  font-family: $monospace;
+  text-align: center;
+  letter-spacing: .1em;
+}
+
+code {
+  font: normal #{$code-font-size}/#{$code-line-height} $monospace;
+  white-space: pre;
+}
+
+.aside {
+  code {
+    font: normal #{$code-font-size * .9}/#{$code-line-height * .9} $monospace !important;
+  }
+}
+
+pre {
+  font: normal #{$pre-font-size}/#{$pre-line-height} $monospace;
+}
+
+.centered {
+  display: block;
+  text-align: center;
+}
+
+.start-reading span {
+  font-family: $sans;
+  color: white;
+  background-color: #C00;
+  border-radius: 10px;
+  display: inline-block;
+  padding: 10px;
+}
+
+.start-reading {
+  text-align: center;
+}
+
+// Pygments
+.codehilite {
+  background-color: #fdf6e3; color: #586e75;
+  .hll {
+    opacity: .4;
+  }
+  .c { color: #93a1a1 } /* Comment */
+  .err { color: #586e75 } /* Error */
+  .g { color: #586e75 } /* Generic */
+  .k { color: #859900 } /* Keyword */
+  .l { color: #586e75 } /* Literal */
+  .n { color: #586e75 } /* Name */
+  .o { color: #859900 } /* Operator */
+  .x { color: #cb4b16 } /* Other */
+  .p { color: #586e75 } /* Punctuation */
+  .cm { color: #93a1a1 } /* Comment.Multiline */
+  .cp { color: #859900 } /* Comment.Preproc */
+  .c1 { color: #93a1a1 } /* Comment.Single */
+  .cs { color: #859900 } /* Comment.Special */
+  .c, .cm, .cp, .c1, .cs {
+    font-style: italic;
+  }
+  .gd { color: #2aa198 } /* Generic.Deleted */
+  .ge { color: #586e75; font-style: italic } /* Generic.Emph */
+  .gr { color: #dc322f } /* Generic.Error */
+  .gh { color: #cb4b16 } /* Generic.Heading */
+  .gi { color: #859900 } /* Generic.Inserted */
+  .go { color: #586e75 } /* Generic.Output */
+  .gp { color: #586e75 } /* Generic.Prompt */
+  .gs { color: #586e75; font-weight: bold } /* Generic.Strong */
+  .gu { color: #cb4b16 } /* Generic.Subheading */
+  .gt { color: #586e75 } /* Generic.Traceback */
+  .kc { color: #cb4b16 } /* Keyword.Constant */
+  .kd { color: #268bd2 } /* Keyword.Declaration */
+  .kn { color: #859900 } /* Keyword.Namespace */
+  .kp { color: #859900 } /* Keyword.Pseudo */
+  .kr { color: #268bd2 } /* Keyword.Reserved */
+  .kt { color: #dc322f } /* Keyword.Type */
+  .ld { color: #586e75 } /* Literal.Date */
+  .m { color: #2aa198 } /* Literal.Number */
+  .s { color: #2aa198 } /* Literal.String */
+  .na { color: #586e75 } /* Name.Attribute */
+  .nb { color: #B58900 } /* Name.Builtin */
+  .nc { color: #268bd2 } /* Name.Class */
+  .no { color: #cb4b16 } /* Name.Constant */
+  .nd { color: #268bd2 } /* Name.Decorator */
+  .ni { color: #cb4b16 } /* Name.Entity */
+  .ne { color: #cb4b16 } /* Name.Exception */
+  .nf { color: #268bd2 } /* Name.Function */
+  .nl { color: #586e75 } /* Name.Label */
+  .nn { color: #586e75 } /* Name.Namespace */
+  .nx { color: #586e75 } /* Name.Other */
+  .py { color: #586e75 } /* Name.Property */
+  .nt { color: #268bd2 } /* Name.Tag */
+  .nv { color: #268bd2 } /* Name.Variable */
+  .ow { color: #859900 } /* Operator.Word */
+  .w { color: #586e75 } /* Text.Whitespace */
+  .mf { color: #2aa198 } /* Literal.Number.Float */
+  .mh { color: #2aa198 } /* Literal.Number.Hex */
+  .mi { color: #2aa198 } /* Literal.Number.Integer */
+  .mo { color: #2aa198 } /* Literal.Number.Oct */
+  .sb { color: #93a1a1 } /* Literal.String.Backtick */
+  .sc { color: #2aa198 } /* Literal.String.Char */
+  .sd { color: #586e75 } /* Literal.String.Doc */
+  .s2 { color: #2aa198 } /* Literal.String.Double */
+  .se { color: #cb4b16 } /* Literal.String.Escape */
+  .sh { color: #586e75 } /* Literal.String.Heredoc */
+  .si { color: #2aa198 } /* Literal.String.Interpol */
+  .sx { color: #2aa198 } /* Literal.String.Other */
+  .sr { color: #dc322f } /* Literal.String.Regex */
+  .s1 { color: #2aa198 } /* Literal.String.Single */
+  .ss { color: #2aa198 } /* Literal.String.Symbol */
+  .bp { color: #268bd2 } /* Name.Builtin.Pseudo */
+  .vc { color: #268bd2 } /* Name.Variable.Class */
+  .vg { color: #268bd2 } /* Name.Variable.Global */
+  .vi { color: #268bd2 } /* Name.Variable.Instance */
+  .il { color: #2aa198 } /* Literal.Number.Integer.Long */
+}
+
+div.epigraph {
+  blockquote {
+    margin-right: 0px;
+    float: right;
+    font-style: italic;
+
+    .footer {
+      font-style: normal;
+      text-align: right;
+    }
+  }
+}
+
+div.clear {
+  clear: both;
+}
+
+.sans {
+  font-family: $sans;
+}
+
+.exercise {
+  background: rgba(38, 139, 210, 0.1);
+  border-radius: 10px;
+  margin: 0px -20px;
+  padding: 5px 20px;
+}
+
+.admonition {
+  .admonition-title {
+    font-weight: bold;
+    margin-bottom: 0px;
+    margin-right: 5px;
+    float: left;
+  }
+
+  margin: 0 -20px;
+  padding: 5px 20px;
+}
+
+.admonition.warning {
+  background: #FBE9E7;
+  color: #a30000;
+  margin: 0 -20px;
+  padding: 5px 20px;
+}
+
+.admonition.sourcecode {
+  background: rgba(38, 139, 210, 0.1);
+}
+
+.admonition.tryit {
+  background: rgba(185, 246, 202, 1);
+
+  .codehilite {
+    background-color: transparent;
+    color: inherit;
+    margin: 0px 0px;
+
+    .c { color: grey; }
+  }
+}
+
+
+table {
+  thead {
+    td {
+      padding: 6px 3px;
+    }
+  }
+
+  td {
+    padding: 6px 3px;
+  }
+}
\ No newline at end of file
diff --git a/runtime/tools/wiki/templates/includes/auto-refresh.html b/runtime/tools/wiki/templates/includes/auto-refresh.html
new file mode 100644
index 0000000..29230cb
--- /dev/null
+++ b/runtime/tools/wiki/templates/includes/auto-refresh.html
@@ -0,0 +1,15 @@
+{% if dev %}
+<script>
+  (function() {
+    let ws = new WebSocket(`ws://${location.host}/ws`);
+    ws.onopen = function (event) {
+      console.log('WebSocket connected');
+    };
+    ws.onmessage = function (event) {
+      if (event.data == 'reload') {
+        location.reload(true);
+      }
+    };
+  })();
+</script>
+{% endif %}
diff --git a/runtime/tools/wiki/templates/includes/favicon.html b/runtime/tools/wiki/templates/includes/favicon.html
new file mode 100644
index 0000000..8af739c
--- /dev/null
+++ b/runtime/tools/wiki/templates/includes/favicon.html
@@ -0,0 +1,15 @@
+<link href="https://fonts.googleapis.com/css?family=Montserrat" rel="stylesheet">
+<link rel="stylesheet" href="css/style.css" type="text/css">
+<link rel="apple-touch-icon" sizes="57x57" href="images/favicon/apple-icon-57x57.png">
+<link rel="apple-touch-icon" sizes="60x60" href="images/favicon/apple-icon-60x60.png">
+<link rel="apple-touch-icon" sizes="72x72" href="images/favicon/apple-icon-72x72.png">
+<link rel="apple-touch-icon" sizes="76x76" href="images/favicon/apple-icon-76x76.png">
+<link rel="apple-touch-icon" sizes="114x114" href="images/favicon/apple-icon-114x114.png">
+<link rel="apple-touch-icon" sizes="120x120" href="images/favicon/apple-icon-120x120.png">
+<link rel="apple-touch-icon" sizes="144x144" href="images/favicon/apple-icon-144x144.png">
+<link rel="apple-touch-icon" sizes="152x152" href="images/favicon/apple-icon-152x152.png">
+<link rel="apple-touch-icon" sizes="180x180" href="images/favicon/apple-icon-180x180.png">
+<link rel="icon" type="image/png" sizes="192x192"  href="images/favicon/android-icon-192x192.png">
+<link rel="icon" type="image/png" sizes="32x32" href="images/favicon/favicon-32x32.png">
+<link rel="icon" type="image/png" sizes="96x96" href="images/favicon/favicon-96x96.png">
+<link rel="icon" type="image/png" sizes="16x16" href="images/favicon/favicon-16x16.png">
diff --git a/runtime/tools/wiki/templates/page.html b/runtime/tools/wiki/templates/page.html
new file mode 100644
index 0000000..13002c8
--- /dev/null
+++ b/runtime/tools/wiki/templates/page.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <title>Dart VM</title>
+    <link rel="stylesheet" href="/css/style.css" type="text/css">
+    {% include 'includes/favicon.html' %}
+    {% include 'includes/auto-refresh.html' %}
+  </head>
+
+  <body>
+    <div class="content">
+      {{body}}
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/runtime/tools/wiki/xref_extractor/.gitignore b/runtime/tools/wiki/xref_extractor/.gitignore
new file mode 100644
index 0000000..50602ac
--- /dev/null
+++ b/runtime/tools/wiki/xref_extractor/.gitignore
@@ -0,0 +1,11 @@
+# Files and directories created by pub
+.dart_tool/
+.packages
+# Remove the following pattern if you wish to check in your lock file
+pubspec.lock
+
+# Conventional directory for build outputs
+build/
+
+# Directory created by dartdoc
+doc/api/
diff --git a/runtime/tools/wiki/xref_extractor/README.md b/runtime/tools/wiki/xref_extractor/README.md
new file mode 100644
index 0000000..71d6af5
--- /dev/null
+++ b/runtime/tools/wiki/xref_extractor/README.md
@@ -0,0 +1,54 @@
+Tool for extracting symbolic information from C++ Dart Runtime sources using
+[cquery](https://github.com/cquery-project/cquery).
+
+It should be invoked from the root of Dart SDK checkout and will generate
+`xref.json` file containing extracted symbol information.
+
+```
+$ pushd runtime/tools/wiki/xref_extractor && pub get && popd
+$ dart runtime/tools/wiki/xref_extractor/bin/main.dart cquery/build/release/bin/cquery
+```
+
+# Prerequisites
+
+1. Build [cquery](https://github.com/cquery-project/cquery) as described [here](https://github.com/cquery-project/cquery/wiki/Building-cquery).
+2. Make sure that you have ninja files generated for ReleaseX64 configuration by
+running `tools/gn.py -a x64 -m release --no-goma` (`--no-goma` is important -
+otherwise `cquery` can't figure out which toolchain is used).
+
+# `xref.json` format
+
+```typescript
+interface Xrefs {
+    /// Commit hash for which this xref.json is generated.
+    commit: string;
+
+    /// List of files names.
+    files: string[];
+
+    /// Class information by name.
+    classes: ClassMap;
+
+    /// Global function information.
+    functions: LocationMap;
+}
+
+/// Locations are serialized as strings of form "fileIndex:lineNo", where
+/// fileIndex points into files array.
+type SymbolLocation = string;
+
+/// Information about classes is stored in an array where the first element
+/// describes location of the class itself and second optional element gives
+/// locations of class members.
+type ClassInfo = [SymbolLocation, LocationMap?];
+
+/// Map of classes by their names.
+interface ClassMap {
+    [name: string]: ClassInfo;
+}
+
+/// Map of symbols to their locations.
+interface LocationMap {
+    [symbol: string]: SymbolLocation;
+}
+```
\ No newline at end of file
diff --git a/runtime/tools/wiki/xref_extractor/analysis_options.yaml b/runtime/tools/wiki/xref_extractor/analysis_options.yaml
new file mode 100644
index 0000000..a686c1b
--- /dev/null
+++ b/runtime/tools/wiki/xref_extractor/analysis_options.yaml
@@ -0,0 +1,14 @@
+# Defines a default set of lint rules enforced for
+# projects at Google. For details and rationale,
+# see https://github.com/dart-lang/pedantic#enabled-lints.
+include: package:pedantic/analysis_options.yaml
+
+# For lint rules and documentation, see http://dart-lang.github.io/linter/lints.
+# Uncomment to specify additional rules.
+# linter:
+#   rules:
+#     - camel_case_types
+
+analyzer:
+#   exclude:
+#     - path/to/excluded/files/**
diff --git a/runtime/tools/wiki/xref_extractor/bin/main.dart b/runtime/tools/wiki/xref_extractor/bin/main.dart
new file mode 100644
index 0000000..f24a9fd
--- /dev/null
+++ b/runtime/tools/wiki/xref_extractor/bin/main.dart
@@ -0,0 +1,107 @@
+// Copyright (c) 2020, 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.
+
+// Script used to extract symbols with locations from runtime/vm files using
+// cquery. See README.md for more information.
+
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:path/path.dart' as p;
+
+import 'package:xref_extractor/cquery_driver.dart';
+import 'package:xref_extractor/xref_extractor.dart';
+
+// Note: not using Directory.createTemp to reduce indexing costs.
+const cqueryCachePath = '/tmp/cquery-cache-for-dart-sdk';
+
+void main(List<String> args) async {
+  if (args.length != 1 || !File(args[0]).existsSync()) {
+    print('''
+Usage: dart runtime/tools/wiki/xref_extractor/bin/main.dart <path-to-cquery>
+''');
+    exit(1);
+  }
+
+  final cqueryBinary = args[0];
+
+  // Sanity check that we are running from SDK checkout root.
+  final sdkCheckoutRoot = Directory.current.absolute;
+  final runtimeVmDirectory =
+      Directory(p.join(sdkCheckoutRoot.path, 'runtime/vm'));
+  final gitDirectory = Directory(p.join(sdkCheckoutRoot.path, '.git'));
+
+  if (!gitDirectory.existsSync() || !runtimeVmDirectory.existsSync()) {
+    print('This script expects to be run from SDK checkout root');
+    exit(1);
+  }
+
+  // Generate compile_commands.json from which cquery will extract compilation
+  // flags for individual C++ files.
+  await generateCompileCommands();
+
+  // Start cquery process and request indexing of runtimeVmDirectory.
+  final cquery = await CqueryDriver.start(cqueryBinary);
+
+  print('Indexing ${runtimeVmDirectory.path} with cquery');
+  cquery.progress.listen((files) =>
+      stdout.write('\rcquery is running ($files files left to index)'));
+
+  await cquery.request('initialize', params: {
+    'processId': 123,
+    'rootUri': sdkCheckoutRoot.uri.toString(),
+    'capabilities': {
+      'textDocument': {'codeLens': null}
+    },
+    'trace': 'on',
+    'initializationOptions': {
+      'cacheDirectory': cqueryCachePath,
+      'progressReportFrequencyMs': 1000,
+    },
+    'workspaceFolders': [
+      {
+        'uri': runtimeVmDirectory.uri.toString(),
+        'name': 'vm',
+      }
+    ]
+  });
+
+  // Tell cquery to wait for the indexing to complete and then exit.
+  cquery.notify(r'$cquery/wait');
+  cquery.notify(r'exit');
+
+  // Wait for cquery to exit.
+  final exitCode = await cquery.exitCode;
+  print('\r\x1b[K... completed (cquery exited with exit code ${exitCode})');
+
+  // Process cquery cache folder to extract symbolic information.
+  await generateXRef(cqueryCachePath, sdkCheckoutRoot.path,
+      (path) => path.startsWith('runtime/'));
+}
+
+/// Generate compile_commands.json for cquery so that it could index VM sources.
+///
+/// We ask ninja to produce compilation database for X64 release build and then
+/// post process it to limit it to libdart_vm_precompiler_host_targeting_host
+/// target, because otherwise we get duplicated compilation commands for the
+/// same input C++ files and this greatly confuses cquery.
+Future<void> generateCompileCommands() async {
+  print('Extracting compilation commands from build files for ReleaseX64');
+  final result = await Process.run('ninja', [
+    '-C',
+    '${Platform.isMacOS ? 'xcodebuild' : 'out'}/ReleaseX64',
+    '-t',
+    'compdb',
+    'cxx'
+  ]);
+  final List<dynamic> commands = jsonDecode(result.stdout);
+  final re = RegExp(r'/libdart(_vm)?_precompiler_host_targeting_host\.');
+  final filteredCommands = commands
+      .cast<Map<String, dynamic>>()
+      .where((item) => item['command'].contains(re))
+      .toList(growable: false);
+  File('compile_commands.json').writeAsStringSync(jsonEncode(filteredCommands));
+  print('''
+... generated compile_commands.json with ${filteredCommands.length} entries''');
+}
diff --git a/runtime/tools/wiki/xref_extractor/lib/cquery_driver.dart b/runtime/tools/wiki/xref_extractor/lib/cquery_driver.dart
new file mode 100644
index 0000000..cfc6a7b
--- /dev/null
+++ b/runtime/tools/wiki/xref_extractor/lib/cquery_driver.dart
@@ -0,0 +1,200 @@
+// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Library for spawning cquery process and communicating with it.
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+import 'dart:math' as math;
+
+/// Helper class encapsulating communication with the cquery process.
+///
+/// cquery communicates using jsonrpc via stdin/stdout streams.
+class CqueryDriver {
+  final Process _cquery;
+
+  final _pendingRequests = <int, Completer<dynamic>>{};
+  var _requestId = 1;
+
+  final _progressStreamController = StreamController<int>.broadcast();
+
+  CqueryDriver._(this._cquery) {
+    _cquery.stdout
+        .transform(utf8.decoder)
+        .transform(_JsonRpcParser.transformer)
+        .listen(_handleMessage);
+    _cquery.stderr
+        .transform(utf8.decoder)
+        .listen((data) => print('stderr: ${data}'));
+  }
+
+  static Future<CqueryDriver> start(String cqueryBinary) async {
+    final cquery = await Process.start(cqueryBinary, ['--language-server']);
+    return CqueryDriver._(cquery);
+  }
+
+  /// Stream of progress notifications from cquery. Indicate how many files
+  /// are currently pending indexing.
+  Stream<int> get progress => _progressStreamController.stream;
+
+  Future<int> get exitCode => _cquery.exitCode;
+
+  /// Send the given message to the cquery process.
+  void _sendMessage(Map<String, dynamic> data) {
+    data['jsonrpc'] = '2.0';
+
+    final rq = jsonEncode(data);
+    _cquery.stdin.write('Content-Length: ${rq.length}\r\n\r\n${rq}');
+  }
+
+  /// Send a notification message to the cquery process.
+  void notify(String method, {Map<String, dynamic> params}) {
+    final rq = <String, dynamic>{'method': method};
+    if (params != null) rq['params'] = params;
+    _sendMessage(rq);
+  }
+
+  /// Send a request message to the cquery process.
+  Future<dynamic> request(String method, {Map<String, dynamic> params}) {
+    final rq = <String, dynamic>{'method': method, 'id': _requestId++};
+    _pendingRequests[rq['id']] = Completer();
+    if (params != null) rq['params'] = params;
+    _sendMessage(rq);
+    return _pendingRequests[rq['id']].future;
+  }
+
+  /// Handle message received from cquery process.
+  void _handleMessage(Map<String, dynamic> data) {
+    final method = data['method'];
+
+    // If it is a progress notification issue progress event.
+    if (method == r'$cquery/progress') {
+      _progressStreamController.add(data['params']['indexRequestCount']);
+    }
+
+    // Otherwise check if it is a response to one of our requests and complete
+    // corresponding future if it is.
+    if (data.containsKey('id') && data.containsKey('result')) {
+      final id = data['id'];
+      final result = data['result'];
+      _pendingRequests[id].complete(result);
+      _pendingRequests[id] = null;
+      return;
+    }
+  }
+}
+
+/// Simple parser for jsonrpc protocol over arbitrary chunked stream.
+class _JsonRpcParser {
+  /// Accumulator for the message content.
+  final StringBuffer content = StringBuffer();
+
+  /// Number of bytes left to read in the current message.
+  int pendingContentLength = 0;
+
+  /// Auxiliary variable to store various state between invocations of
+  /// [state] callback.
+  int index = 0;
+
+  /// Position inside incomming chunk of data.
+  int pos = 0;
+
+  /// Current parser state.
+  Function state = _JsonRpcParser.readHeader;
+
+  /// Callback to invoke when we finish parsing complete message.
+  void Function(Map<String, dynamic>) onMessage;
+
+  _JsonRpcParser({this.onMessage});
+
+  /// StreamTransformer wrapping _JsonRpcParser.
+  static StreamTransformer<String, Map<String, dynamic>> get transformer =>
+      StreamTransformer.fromBind((Stream<String> s) {
+        final output = StreamController<Map<String, dynamic>>();
+        final p = _JsonRpcParser(onMessage: output.add);
+        s.listen(p.addChunk);
+        return output.stream;
+      });
+
+  /// Parse the chunk of data.
+  void addChunk(String data) {
+    pos = 0;
+    while (pos < data.length) {
+      state = state(this, data);
+    }
+  }
+
+  /// Parsing state: waiting for 'Content-Length' header.
+  static Function readHeader(_JsonRpcParser p, String data) {
+    final codeUnit = data.codeUnitAt(p.pos++);
+
+    if (HEADER.codeUnitAt(p.index) != codeUnit) {
+      throw 'Unexpected codeUnit: ${String.fromCharCode(codeUnit)} expected ${HEADER[p.index]}';
+    }
+
+    p.index++;
+    if (p.index == HEADER.length) {
+      p.index = 0;
+      return _JsonRpcParser.readLength;
+    }
+    return _JsonRpcParser.readHeader;
+  }
+
+  /// Parsing state: parsing content length value.
+  static Function readLength(_JsonRpcParser p, String data) {
+    final codeUnit = data.codeUnitAt(p.pos++);
+
+    if (codeUnit == CR) {
+      p.pendingContentLength = p.index;
+      p.index = 0;
+      return _JsonRpcParser.readHeaderEnd;
+    }
+    if (codeUnit < CH0 || codeUnit > CH9) {
+      throw 'Unexpected codeUnit: ${String.fromCharCode(codeUnit)} expected 0 to 9';
+    }
+    p.index = p.index * 10 + (codeUnit - CH0);
+    return _JsonRpcParser.readLength;
+  }
+
+  /// Parsing state: content length was read, skipping line breaks before
+  /// content start.
+  static Function readHeaderEnd(_JsonRpcParser p, String data) {
+    final codeUnit = data.codeUnitAt(p.pos++);
+
+    if (HEADER_END.codeUnitAt(p.index) != codeUnit) {
+      throw 'Unexpected codeUnit: ${String.fromCharCode(codeUnit)} expected ${HEADER_END[p.index]}';
+    }
+
+    p.index++;
+    if (p.index == HEADER_END.length) {
+      return _JsonRpcParser.readContent;
+    }
+    return _JsonRpcParser.readHeaderEnd;
+  }
+
+  /// Parsing state: reading message content.
+  static Function readContent(_JsonRpcParser p, String data) {
+    final availableBytes = data.length - p.pos;
+    final bytesToRead = math.min(availableBytes, p.pendingContentLength);
+    p.content.write(data.substring(p.pos, p.pos + bytesToRead));
+    p.pendingContentLength -= bytesToRead;
+    p.pos += bytesToRead;
+    if (p.pendingContentLength == 0) {
+      p.onMessage(jsonDecode(p.content.toString()));
+      p.content.clear();
+      p.index = 0;
+      return _JsonRpcParser.readHeader;
+    } else {
+      return _JsonRpcParser.readContent;
+    }
+  }
+
+  static const HEADER = 'Content-Length: ';
+  static const HEADER_END = '\n\r\n';
+  static const CH0 = 48;
+  static const CH9 = 57;
+  static const CR = 13;
+  static const LF = 10;
+}
diff --git a/runtime/tools/wiki/xref_extractor/lib/xref_extractor.dart b/runtime/tools/wiki/xref_extractor/lib/xref_extractor.dart
new file mode 100644
index 0000000..6f0b033
--- /dev/null
+++ b/runtime/tools/wiki/xref_extractor/lib/xref_extractor.dart
@@ -0,0 +1,235 @@
+// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Library for converting cquery cache into condensed symbol location
+// information expected by our xref markdown extension.
+
+import 'dart:convert';
+import 'dart:io';
+import 'dart:async';
+
+import 'package:path/path.dart' as p;
+
+typedef FileFilterCallback = bool Function(String path);
+
+/// Load cquery cache from the given directory and accumulate all symbols
+/// (global functions and class methods) for the Dart SDK related sources
+/// matching the given filter.
+Future<void> generateXRef(String cqueryCachePath, String sdkRootPath,
+    FileFilterCallback fileFilter) async {
+  final cacheRoot =
+      Directory(p.join(cqueryCachePath, sdkRootPath.replaceAll('/', '@')));
+  final files = cacheRoot
+      .listSync()
+      .whereType<File>()
+      .where((file) => file.path.endsWith('.json'))
+      .toList();
+  print('Processing ${files.length} indexes available in ${cacheRoot.path}');
+
+  final cache = CqueryCache(fileFilter: fileFilter);
+  files.forEach(cache.loadFile);
+
+  final classesByName = <String, Class>{
+    for (var entry in cache.classes.entries)
+      if (entry.value.name != null && entry.value.name != '')
+        entry.value.name: entry.value
+  };
+
+  final database = {
+    'commit': await currentCommitHash(),
+    'files': cache.filesByIndex,
+    'classes': classesByName,
+    'functions': cache.globals.uniqueMembers
+  };
+
+  File('xref.json').writeAsStringSync(jsonEncode(database));
+  print('... done (written xref.json)');
+}
+
+/// Helper class representing symbol information contained in the cquery cache.
+class CqueryCache {
+  final files = <String, int>{};
+  final filesByIndex = [];
+
+  final classes = <num, Class>{};
+  final globals = Class('\$Globals');
+
+  FileFilterCallback fileFilter;
+
+  CqueryCache({this.fileFilter});
+
+  int addFile(String name) => files.putIfAbsent(name, () {
+        filesByIndex.add(name);
+        return filesByIndex.length - 1;
+      });
+
+  Location makeLocation(String file, int lineNo) =>
+      Location(addFile(file), lineNo);
+
+  // cquery used to serialize USRs as integers but they are now serialized as
+  // doubles (with .0 at the end) for some reason. This might even lead to
+  // incorrect deserialization with a loss of a precise USR value - but
+  // should not lead to any issues as long as two different classes don't
+  // have conflicting USRs.
+  Class findClassByUsr(num usr) => classes.putIfAbsent(usr, () => Class());
+
+  void defineClass(num usr, String name, Location loc) {
+    final cls = findClassByUsr(usr);
+    if (cls.name != null && cls.name != '' && cls.name != name) {
+      throw 'Mismatched names';
+    }
+    if (name != '') cls.name = name;
+    if (cls.loc == null) {
+      cls.loc = loc;
+    } else {
+      cls.loc = Location.invalid;
+    }
+  }
+
+  void loadFile(File indexFile) {
+    final result = jsonDecode(indexFile.readAsStringSync().split('\n')[1]);
+
+    // Check if we are interested in the original source file.
+    final sourceFile =
+        p.basenameWithoutExtension(indexFile.path).replaceAll('@', '/');
+    if (!fileFilter(sourceFile)) return;
+
+    // Extract classes defined in the file.
+    for (var type in result['types']) {
+      if (type['kind'] != SymbolKind.Class) continue;
+      final extent = type['extent'];
+      if (extent == null) continue;
+
+      final detailedName = type['detailed_name'];
+      final lineStart = int.parse(extent.substring(0, extent.indexOf(':')));
+      defineClass(
+          type['usr'], detailedName, makeLocation(sourceFile, lineStart));
+    }
+
+    // Extract class methods defined in the file.
+    for (var func in result['funcs']) {
+      final kind = func['kind'];
+      if (kind != SymbolKind.Method && kind != SymbolKind.StaticMethod) {
+        continue;
+      }
+      final extent = func['extent'];
+      if (extent == null) continue;
+      final short = shortName(func);
+      final lineStart = int.parse(extent.substring(0, extent.indexOf(':')));
+      if (func['declaring_type'] == null) {
+        continue;
+      }
+      findClassByUsr(result['types'][func['declaring_type']]['usr'])
+          .defineMember(short, makeLocation(sourceFile, lineStart));
+    }
+
+    // Extract global functions defined in the file.
+    for (var func in result['funcs']) {
+      final kind = func['kind'];
+      if (kind != SymbolKind.Function) continue;
+      final extent = func['extent'];
+      if (extent == null) continue;
+      final short = shortName(func);
+      final lineStart = int.parse(extent.substring(0, extent.indexOf(':')));
+      globals.defineMember(short, makeLocation(sourceFile, lineStart));
+    }
+  }
+}
+
+class Class {
+  String name;
+  Location loc;
+
+  // Member to definition location map. If the same symbol has multiple
+  // definitions then we mark it with [Location.invalid].
+  Map<String, Location> members;
+
+  Class([this.name]);
+
+  void defineMember(String name, Location loc) {
+    members ??= <String, Location>{};
+    members[name] = members.containsKey(name) ? Location.invalid : loc;
+  }
+
+  dynamic toJson() {
+    final result = [loc?.toJson() ?? 0];
+    if (members != null) {
+      final res = uniqueMembers;
+      if (res.isNotEmpty) {
+        result.add(res);
+      }
+    }
+    return result;
+  }
+
+  Map<String, Location> get uniqueMembers => <String, Location>{
+        for (var entry in members.entries)
+          if (entry.value != Location.invalid) entry.key: entry.value
+      };
+}
+
+class Location {
+  final int file;
+  final int lineNo;
+
+  const Location(this.file, this.lineNo);
+
+  String toJson() => identical(this, invalid) ? null : '$file:$lineNo';
+
+  @override
+  String toString() => '$file:$lineNo';
+
+  static const invalid = Location(-1, -1);
+}
+
+String shortName(entity) {
+  final offset = entity['short_name_offset'];
+  final length = entity['short_name_size'] ?? 0;
+  final detailedName = entity['detailed_name'];
+  if (length == 0) return detailedName;
+  return detailedName.substring(offset, offset + length);
+}
+
+Future<String> currentCommitHash() async {
+  final results = await Process.run('git', ['rev-parse', 'HEAD']);
+  return results.stdout;
+}
+
+/// Kind of the symbol. Taken from LSP specifications and cquery source code.
+abstract class SymbolKind {
+  static const Unknown = 0;
+
+  static const File = 1;
+  static const Module = 2;
+  static const Namespace = 3;
+  static const Package = 4;
+  static const Class = 5;
+  static const Method = 6;
+  static const Property = 7;
+  static const Field = 8;
+  static const Constructor = 9;
+  static const Enum = 10;
+  static const Interface = 11;
+  static const Function = 12;
+  static const Variable = 13;
+  static const Constant = 14;
+  static const String = 15;
+  static const Number = 16;
+  static const Boolean = 17;
+  static const Array = 18;
+  static const Object = 19;
+  static const Key = 20;
+  static const Null = 21;
+  static const EnumMember = 22;
+  static const Struct = 23;
+  static const Event = 24;
+  static const Operator = 25;
+  static const TypeParameter = 26;
+
+  // cquery extensions.
+  static const TypeAlias = 252;
+  static const Parameter = 253;
+  static const StaticMethod = 254;
+  static const Macro = 255;
+}
diff --git a/runtime/tools/wiki/xref_extractor/pubspec.yaml b/runtime/tools/wiki/xref_extractor/pubspec.yaml
new file mode 100644
index 0000000..b4e9bd0
--- /dev/null
+++ b/runtime/tools/wiki/xref_extractor/pubspec.yaml
@@ -0,0 +1,13 @@
+name: xref_extractor
+description: A sample command-line application.
+# version: 1.0.0
+# homepage: https://www.example.com
+
+environment:
+  sdk: '>=2.7.0 <3.0.0'
+
+dependencies:
+  path: ^1.6.0
+
+dev_dependencies:
+  pedantic: ^1.8.0
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 5f72da1..c6a5e03 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -378,9 +378,11 @@
     if ((pending_type.raw() != type.raw()) && pending_type.IsType() &&
         (pending_type.type_class() == type_cls.raw())) {
       pending_arguments = pending_type.arguments();
+      // By using TypeEquality::kIgnoreNullability, we throw a wider net and
+      // may reject more problematic declarations.
       if (!pending_arguments.IsSubvectorEquivalent(
               arguments, first_type_param, num_type_params,
-              /* syntactically = */ true) &&
+              TypeEquality::kIgnoreNullability) &&
           !pending_arguments.IsSubvectorInstantiated(first_type_param,
                                                      num_type_params)) {
         const TypeArguments& instantiated_arguments = TypeArguments::Handle(
@@ -394,9 +396,11 @@
                           NNBDMode::kLegacyLib, Object::null_type_arguments(),
                           Object::null_type_arguments(), kNoneFree, NULL,
                           Heap::kNew));
+        // By using TypeEquality::kIgnoreNullability, we throw a wider net and
+        // may reject more problematic declarations.
         if (!instantiated_pending_arguments.IsSubvectorEquivalent(
                 instantiated_arguments, first_type_param, num_type_params,
-                /* syntactically = */ true)) {
+                TypeEquality::kIgnoreNullability)) {
           const String& type_name = String::Handle(zone, type.Name());
           ReportError(cls, type.token_pos(), "illegal recursive type '%s'",
                       type_name.ToCString());
diff --git a/runtime/vm/class_table.cc b/runtime/vm/class_table.cc
index e645df3..929a4b8 100644
--- a/runtime/vm/class_table.cc
+++ b/runtime/vm/class_table.cc
@@ -403,9 +403,6 @@
 
 #ifndef PRODUCT
 void ClassTable::PrintToJSONObject(JSONObject* object) {
-  if (!FLAG_support_service) {
-    return;
-  }
   Class& cls = Class::Handle();
   object->AddProperty("type", "ClassList");
   {
@@ -429,9 +426,6 @@
 
 
 void ClassTable::AllocationProfilePrintJSON(JSONStream* stream, bool internal) {
-  if (!FLAG_support_service) {
-    return;
-  }
   Isolate* isolate = Isolate::Current();
   ASSERT(isolate != NULL);
   Heap* heap = isolate->heap();
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index 9dddd4c..4cb654f 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -14,6 +14,7 @@
 #include "vm/compiler/backend/il_printer.h"
 #include "vm/compiler/relocation.h"
 #include "vm/dart.h"
+#include "vm/dispatch_table.h"
 #include "vm/flag_list.h"
 #include "vm/heap/heap.h"
 #include "vm/image_snapshot.h"
@@ -4437,8 +4438,11 @@
 #if !defined(DART_PRECOMPILED_RUNTIME)
 class FakeSerializationCluster : public SerializationCluster {
  public:
-  FakeSerializationCluster(const char* name, intptr_t size)
+  FakeSerializationCluster(const char* name,
+                           intptr_t num_objects,
+                           intptr_t size)
       : SerializationCluster(name) {
+    num_objects_ = num_objects;
     size_ = size;
   }
   ~FakeSerializationCluster() {}
@@ -4952,7 +4956,9 @@
 #endif
     }
   }
+}
 
+void Serializer::PrintSnapshotSizes() {
 #if !defined(DART_PRECOMPILED_RUNTIME)
   if (FLAG_print_snapshot_sizes_verbose) {
     OS::PrintErr("             Cluster   Objs     Size Fraction Cumulative\n");
@@ -4965,7 +4971,13 @@
     }
     if (GetTextSize() != 0) {
       clusters_by_size.Add(new (zone_) FakeSerializationCluster(
-          "(RO)Instructions", GetTextSize()));
+          "(RO)Instructions", 0, GetTextSize()));
+    }
+    // An null dispatch table will serialize to a single byte.
+    if (dispatch_table_size_ > 1) {
+      clusters_by_size.Add(new (zone_) FakeSerializationCluster(
+          "(RO)DispatchTable", isolate()->dispatch_table()->length(),
+          dispatch_table_size_));
     }
     clusters_by_size.Sort(CompareClusters);
     double total_size =
@@ -5084,6 +5096,8 @@
   Write<int32_t>(kSectionMarker);
 #endif
 
+  PrintSnapshotSizes();
+
   // Note we are not clearing the object id table. The full ref table
   // of the vm isolate snapshot serves as the base objects for the
   // regular isolate snapshot.
@@ -5122,10 +5136,19 @@
     WriteRootRef(*p);
   }
 
+  // Serialize dispatch table.
+  GrowableArray<RawCode*>* code_objects =
+      static_cast<CodeSerializationCluster*>(clusters_by_cid_[kCodeCid])
+          ->discovered_objects();
+  dispatch_table_size_ = DispatchTable::Serialize(
+      this, isolate()->dispatch_table(), *code_objects);
+
 #if defined(DEBUG)
   Write<int32_t>(kSectionMarker);
 #endif
 
+  PrintSnapshotSizes();
+
   heap_->ResetObjectIdTable();
 }
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
@@ -5595,6 +5618,12 @@
       *p = ReadRef();
     }
 
+    // Deserialize dispatch table
+    const Array& code_array =
+        Array::Handle(zone_, object_store->code_order_table());
+    thread()->isolate()->set_dispatch_table(
+        DispatchTable::Deserialize(this, code_array));
+
 #if defined(DEBUG)
     int32_t section_marker = Read<int32_t>();
     ASSERT(section_marker == kSectionMarker);
diff --git a/runtime/vm/clustered_snapshot.h b/runtime/vm/clustered_snapshot.h
index ed8555f..15d53f7 100644
--- a/runtime/vm/clustered_snapshot.h
+++ b/runtime/vm/clustered_snapshot.h
@@ -216,6 +216,7 @@
   void WriteVersionAndFeatures(bool is_vm_snapshot);
 
   void Serialize();
+  void PrintSnapshotSizes();
 
   FieldTable* field_table() { return field_table_; }
 
@@ -383,6 +384,8 @@
   SmiObjectIdMap smi_ids_;
   FieldTable* field_table_;
 
+  intptr_t dispatch_table_size_ = 0;
+
   // True if writing VM snapshot, false for Isolate snapshot.
   bool vm_;
 
diff --git a/runtime/vm/compiler/aot/aot_call_specializer.cc b/runtime/vm/compiler/aot/aot_call_specializer.cc
index 3e62efe..9e52a22 100644
--- a/runtime/vm/compiler/aot/aot_call_specializer.cc
+++ b/runtime/vm/compiler/aot/aot_call_specializer.cc
@@ -1261,6 +1261,67 @@
   return true;
 }
 
+void AotCallSpecializer::ReplaceInstanceCallsWithDispatchTableCalls() {
+  ASSERT(current_iterator_ == nullptr);
+  for (BlockIterator block_it = flow_graph()->reverse_postorder_iterator();
+       !block_it.Done(); block_it.Advance()) {
+    ForwardInstructionIterator it(block_it.Current());
+    current_iterator_ = &it;
+    for (; !it.Done(); it.Advance()) {
+      Instruction* instr = it.Current();
+      if (auto call = instr->AsInstanceCall()) {
+        TryReplaceWithDispatchTableCall(call);
+      } else if (auto call = instr->AsPolymorphicInstanceCall()) {
+        TryReplaceWithDispatchTableCall(call);
+      }
+    }
+    current_iterator_ = nullptr;
+  }
+}
+
+void AotCallSpecializer::TryReplaceWithDispatchTableCall(
+    InstanceCallBaseInstr* call) {
+  const Function& interface_target = call->interface_target();
+  if (interface_target.IsNull()) {
+    // Dynamic call.
+    return;
+  }
+
+  Value* receiver = call->ArgumentValueAt(call->FirstArgIndex());
+  const compiler::TableSelector* selector =
+      precompiler_->selector_map()->GetSelector(interface_target);
+
+  if (selector == nullptr) {
+    // Target functions were removed by tree shaking. This call is dead code,
+    // or the receiver is always null.
+#if defined(DEBUG)
+    AddCheckNull(receiver->CopyWithType(Z), call->function_name(),
+                 DeoptId::kNone, call->env(), call);
+    StopInstr* stop = new (Z) StopInstr("Dead instance call executed.");
+    InsertBefore(call, stop, call->env(), FlowGraph::kEffect);
+#endif
+    return;
+  }
+
+  if (!selector->on_null_interface) {
+    // Selector not implemented by Null. Add null check if receiver is nullable.
+    AddCheckNull(receiver->CopyWithType(Z), call->function_name(),
+                 DeoptId::kNone, call->env(), call);
+  }
+
+  const AbstractType& target_type =
+      AbstractType::Handle(Class::Handle(interface_target.Owner()).RareType());
+  const bool receiver_can_be_smi =
+      CompileType::Smi().IsAssignableTo(NNBDMode::kLegacyLib, target_type);
+  auto load_cid = new (Z) LoadClassIdInstr(receiver->CopyWithType(Z), kUntagged,
+                                           receiver_can_be_smi);
+  InsertBefore(call, load_cid, call->env(), FlowGraph::kValue);
+
+  auto dispatch_table_call = DispatchTableCallInstr::FromCall(
+      Z, call, new (Z) Value(load_cid), selector);
+  call->ReplaceWith(dispatch_table_call, current_iterator());
+}
+
 #endif  // DART_PRECOMPILER
 
 }  // namespace dart
diff --git a/runtime/vm/compiler/aot/aot_call_specializer.h b/runtime/vm/compiler/aot/aot_call_specializer.h
index c40aa8b..44ea0c2 100644
--- a/runtime/vm/compiler/aot/aot_call_specializer.h
+++ b/runtime/vm/compiler/aot/aot_call_specializer.h
@@ -49,6 +49,10 @@
 
   virtual bool TryOptimizeStaticCallUsingStaticTypes(StaticCallInstr* call);
 
+  // If a call can be dispatched through the global dispatch table, replace
+  // it by a dispatch table call.
+  void TryReplaceWithDispatchTableCall(InstanceCallBaseInstr* call);
+
   // Try to replace a call with a more specialized instruction working on
   // integers (e.g. BinaryInt64OpInstr, CheckedSmiComparisonInstr,
   // RelationalOpInstr)
@@ -71,6 +75,8 @@
                              Value* left_value,
                              Value* right_value);
 
+  virtual void ReplaceInstanceCallsWithDispatchTableCalls();
+
   Precompiler* precompiler_;
 
   bool has_unique_no_such_method_;
diff --git a/runtime/vm/compiler/aot/dispatch_table_generator.cc b/runtime/vm/compiler/aot/dispatch_table_generator.cc
new file mode 100644
index 0000000..5642647
--- /dev/null
+++ b/runtime/vm/compiler/aot/dispatch_table_generator.cc
@@ -0,0 +1,627 @@
+// Copyright (c) 2020, 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.
+
+#if defined(DART_PRECOMPILER) && !defined(DART_PRECOMPILED_RUNTIME)
+
+#include "vm/compiler/aot/dispatch_table_generator.h"
+
+#include <memory>
+
+#include "vm/compiler/frontend/kernel_translation_helper.h"
+#include "vm/stub_code.h"
+#include "vm/thread.h"
+
+#define Z zone_
+
+namespace dart {
+namespace compiler {
+
+class Interval {
+ public:
+  Interval() : begin_(-1), end_(-1) {}
+  Interval(int32_t begin, int32_t end) : begin_(begin), end_(end) {
+    ASSERT(end > begin);
+  }
+
+  int32_t begin() const { return begin_; }
+  void set_begin(int32_t value) { begin_ = value; }
+
+  int32_t end() const { return end_; }
+  void set_end(int32_t value) { end_ = value; }
+
+  int32_t length() const { return end_ - begin_; }
+
+  Interval WithOffset(int32_t offset) const {
+    return Interval(begin_ + offset, end_ + offset);
+  }
+
+  bool IsSame(const Interval other) const {
+    return end() == other.end() && begin() == other.begin();
+  }
+
+  bool IsBefore(const Interval other) const { return end() <= other.begin(); }
+
+  bool IsAfter(const Interval other) const { return begin() >= other.end(); }
+
+  bool Overlap(const Interval other) const {
+    return !IsBefore(other) && !IsAfter(other);
+  }
+
+  bool ContainsBeginOf(const Interval other) const {
+    return begin() <= other.begin() && other.begin() <= end();
+  }
+
+  bool ContainsEndOf(const Interval other) const {
+    return begin() <= other.end() && other.end() <= end();
+  }
+
+  bool Contains(const Interval other) const {
+    return ContainsBeginOf(other) && ContainsEndOf(other);
+  }
+
+  void ExtendToIncludeInterval(const Interval& other) {
+    if (other.begin() < begin_) begin_ = other.begin();
+    if (other.end() > end_) end_ = other.end();
+  }
+
+ private:
+  int32_t begin_;
+  int32_t end_;
+};
+
+class CidInterval {
+ public:
+  CidInterval(classid_t cid,
+              int16_t depth,
+              Interval range,
+              const Function* function)
+      : cid_(cid), depth_(depth), range_(range), function_(function) {}
+
+  classid_t cid() const { return cid_; }
+  int16_t depth() const { return depth_; }
+  const Interval& range() const { return range_; }
+  Interval& range() { return range_; }
+  const Function* function() const { return function_; }
+
+ private:
+  classid_t cid_;
+  int16_t depth_;
+  Interval range_;
+  const Function* function_;
+};
+
+class SelectorRow {
+ public:
+  SelectorRow(Zone* zone, int32_t selector_id)
+      : selector_id_(selector_id), class_ranges_(zone, 0), ranges_(zone, 0) {}
+
+  int32_t selector_id() const { return selector_id_; }
+
+  void DefineSelectorImplementationForInterval(classid_t cid,
+                                               int16_t depth,
+                                               const Interval& range,
+                                               const Function& function);
+  bool Finalize();
+
+  int32_t total_size() const { return total_size_; }
+
+  const GrowableArray<Interval>& ranges() const { return ranges_; }
+
+  const GrowableArray<CidInterval>& class_ranges() const {
+    return class_ranges_;
+  }
+
+  int32_t offset() const { return offset_; }
+  void set_offset(int32_t value) { offset_ = value; }
+
+  void FillTable(ClassTable* class_table, DispatchTable* table);
+
+ private:
+  int32_t selector_id_;
+  int32_t offset_ = SelectorMap::kInvalidSelectorOffset;
+  int32_t total_size_ = 0;
+
+  GrowableArray<CidInterval> class_ranges_;
+  GrowableArray<Interval> ranges_;
+};
+
+class RowFitter {
+ public:
+  RowFitter() { free_slots_.Add(Interval(0, INT_MAX)); }
+
+  int32_t Fit(SelectorRow* row);
+
+  int32_t TableSize() const { return free_slots_.Last().begin(); }
+
+ private:
+  int32_t FindOffset(const GrowableArray<Interval>& ranges,
+                     intptr_t* result_slot_index);
+
+  int32_t MatchRemaining(int32_t offset,
+                         const GrowableArray<Interval>& ranges,
+                         intptr_t slot_index);
+
+  intptr_t MoveForwardToCover(const Interval range, intptr_t slot_index);
+
+  void UpdateFreeSlots(int32_t offset,
+                       const GrowableArray<Interval>& ranges,
+                       intptr_t slot_index);
+
+  intptr_t FitInFreeSlot(const Interval range, intptr_t slot_index);
+
+  GrowableArray<Interval> free_slots_;
+};
+
+void SelectorRow::DefineSelectorImplementationForInterval(
+    classid_t cid,
+    int16_t depth,
+    const Interval& range,
+    const Function& function) {
+  CidInterval cid_range(cid, depth, range, &function);
+  class_ranges_.Add(cid_range);
+}
+
+bool SelectorRow::Finalize() {
+  if (class_ranges_.length() == 0) {
+    return false;
+  }
+
+  // Make a list of [begin, end) ranges which are disjunct and cover all
+  // areas that [class_ranges_] cover (i.e. there can be holes, but no overlap).
+  for (intptr_t i = 0; i < class_ranges_.length(); i++) {
+    ranges_.Add(class_ranges_[i].range());
+  }
+
+  struct IntervalSorter {
+    static int Compare(const Interval* a, const Interval* b) {
+      if (a->begin() != b->begin()) {
+        return a->begin() - b->begin();
+      }
+      return b->length() - a->length();
+    }
+  };
+
+  ranges_.Sort(IntervalSorter::Compare);
+
+  intptr_t current_index = 0;
+  intptr_t write_index = 1;
+  intptr_t read_index = 1;
+  for (; read_index < ranges_.length(); read_index++) {
+    Interval& current_range = ranges_[current_index];
+    Interval& next_range = ranges_[read_index];
+    if (current_range.Contains(next_range)) {
+      // We drop the entry.
+    } else if (current_range.end() == next_range.begin()) {
+      // We extend the current entry and drop the entry.
+      current_range.ExtendToIncludeInterval(next_range);
+    } else {
+      // We keep the entry.
+      if (read_index != write_index) {
+        ranges_[write_index] = ranges_[read_index];
+      }
+      current_index = write_index;
+      write_index++;
+    }
+  }
+  ranges_.TruncateTo(write_index);
+
+  for (intptr_t i = 0; i < ranges_.length() - 1; i++) {
+    const Interval& a = ranges_[i];
+    const Interval& b = ranges_[i + 1];
+    ASSERT(a.begin() < b.begin());
+    ASSERT(a.end() < b.begin());
+  }
+
+  for (intptr_t i = 0; i < ranges_.length(); i++) {
+    total_size_ += ranges_[i].length();
+  }
+
+  return true;
+}
+
+void SelectorRow::FillTable(ClassTable* class_table, DispatchTable* table) {
+  // Define the entries in the table by going top-down, which means more
+  // specific ones will override more general ones.
+
+  Code& code = Code::Handle();
+
+  // Sort by depth.
+  struct IntervalSorter {
+    static int Compare(const CidInterval* a, const CidInterval* b) {
+      ASSERT(a == b || a->depth() != b->depth() ||
+             !a->range().Overlap(b->range()));
+      return a->depth() - b->depth();
+    }
+  };
+  class_ranges_.Sort(IntervalSorter::Compare);
+
+  for (intptr_t i = 0; i < class_ranges_.length(); i++) {
+    const CidInterval& cid_range = class_ranges_[i];
+    const Interval& range = cid_range.range();
+    const Function* function = cid_range.function();
+    if (function->HasCode()) {
+      code = function->CurrentCode();
+      for (classid_t cid = range.begin(); cid < range.end(); cid++) {
+        table->SetCodeAt(offset_ + cid, code);
+      }
+    }
+  }
+}
+
+int32_t RowFitter::Fit(SelectorRow* row) {
+  ASSERT(row->ranges().length() > 0);
+  const GrowableArray<Interval>& ranges = row->ranges();
+
+  intptr_t slot_index;
+  const int32_t offset = FindOffset(ranges, &slot_index);
+  UpdateFreeSlots(offset, ranges, slot_index);
+
+  return offset;
+}
+
+int32_t RowFitter::FindOffset(const GrowableArray<Interval>& ranges,
+                              intptr_t* result_slot_index) {
+  const Interval first_range = ranges[0];
+
+  intptr_t index = 0;
+  int32_t min_start = 0;
+
+  while (index < free_slots_.length() - 1) {
+    const Interval slot = free_slots_[index];
+
+    int32_t start = Utils::Maximum(
+        min_start, Utils::Maximum(slot.begin(), first_range.begin()));
+    int32_t end = slot.end() - first_range.length();
+
+    while (start <= end) {
+      int32_t offset = start - first_range.begin();
+      ASSERT(offset >= 0);
+      ASSERT(slot.Contains(first_range.WithOffset(offset)));
+
+      // If the first block was the only block, we are done.
+      if (ranges.length() == 1) {
+        *result_slot_index = index;
+        return offset;
+      }
+
+      // Found an offset where the first range fits. Now match the
+      // remaining ones.
+      int32_t displacement = MatchRemaining(offset, ranges, index);
+
+      // Displacement is either 0 for a match, or a minimum distance to where
+      // a potential match can happen.
+      if (displacement == 0) {
+        *result_slot_index = index;
+        return offset;
+      }
+
+      start += displacement;
+    }
+
+    min_start = start;
+
+    index++;
+  }
+
+  ASSERT(index == (free_slots_.length() - 1));
+  const Interval slot = free_slots_[index];
+  ASSERT(slot.end() == INT_MAX);
+
+  // If we are at end, we know it fits.
+  int32_t offset = Utils::Maximum(0, slot.begin() - first_range.begin());
+
+  *result_slot_index = index;
+  return offset;
+}
+
+int32_t RowFitter::MatchRemaining(int32_t offset,
+                                  const GrowableArray<Interval>& ranges,
+                                  intptr_t slot_index) {
+  intptr_t index = 1;
+  intptr_t length = ranges.length();
+
+  for (; index < length; index++) {
+    const Interval range = ranges[index].WithOffset(offset);
+
+    slot_index = MoveForwardToCover(range, slot_index);
+    const Interval slot = free_slots_[slot_index];
+
+    if (range.begin() < slot.begin()) return slot.begin() - range.begin();
+  }
+
+  return 0;
+}
+
+intptr_t RowFitter::MoveForwardToCover(const Interval range,
+                                       intptr_t slot_index) {
+  while (free_slots_[slot_index].end() < range.end()) {
+    slot_index++;
+  }
+  return slot_index;
+}
+
+void RowFitter::UpdateFreeSlots(int32_t offset,
+                                const GrowableArray<Interval>& ranges,
+                                intptr_t slot_index) {
+  for (intptr_t i = 0; i < ranges.length(); i++) {
+    ASSERT(slot_index < free_slots_.length());
+    const Interval range = ranges[i].WithOffset(offset);
+
+    ASSERT(!free_slots_[slot_index].IsAfter(range));
+    slot_index = MoveForwardToCover(range, slot_index);
+
+    // Assert that we have a valid slot.
+    ASSERT(slot_index < free_slots_.length());
+    ASSERT(free_slots_[slot_index].begin() < range.end());
+
+    slot_index = FitInFreeSlot(range, slot_index);
+  }
+
+  for (intptr_t i = 0; i < free_slots_.length(); i++) {
+    ASSERT(free_slots_[i].begin() < free_slots_[i].end());
+  }
+}
+
+intptr_t RowFitter::FitInFreeSlot(const Interval range, intptr_t slot_index) {
+  const Interval& slot = free_slots_[slot_index];
+  ASSERT(slot.Contains(range));
+  if (slot.begin() < range.begin()) {
+    Interval free_before = Interval(slot.begin(), range.begin());
+    if (slot.end() > range.end()) {
+      Interval free_after(range.end(), slot.end());
+      free_slots_[slot_index] = free_before;
+      free_slots_.InsertAt(slot_index + 1, free_after);
+    } else {
+      free_slots_[slot_index] = free_before;
+      slot_index++;
+    }
+  } else if (slot.end() <= range.end()) {
+    ASSERT(slot.IsSame(range));
+    free_slots_.EraseAt(slot_index);
+  } else {
+    Interval free_after(range.end(), slot.end());
+    free_slots_[slot_index] = free_after;
+  }
+  return slot_index;
+}
+
+int32_t SelectorMap::SelectorId(const Function& interface_target) const {
+  kernel::ProcedureAttributesMetadata metadata;
+  metadata = kernel::ProcedureAttributesOf(interface_target, Z);
+  return interface_target.IsGetterFunction() ||
+                 interface_target.IsImplicitGetterFunction()
+             ? metadata.getter_selector_id
+             : metadata.method_or_setter_selector_id;
+}
+
+const TableSelector* SelectorMap::GetSelector(
+    const Function& interface_target) const {
+  const int32_t sid = SelectorId(interface_target);
+  if (sid == kInvalidSelectorId) return nullptr;
+  const TableSelector* selector = &selectors_[sid];
+  if (selector->offset == kInvalidSelectorOffset) return nullptr;
+  return selector;
+}
+
+void SelectorMap::SetSelectorProperties(int32_t sid,
+                                        bool on_null_interface,
+                                        bool requires_args_descriptor) {
+  while (selectors_.length() <= sid) {
+    const int32_t added_sid = selectors_.length();
+    selectors_.Add(TableSelector{added_sid, kInvalidSelectorId, false, false});
+  }
+  selectors_[sid].on_null_interface |= on_null_interface;
+  selectors_[sid].requires_args_descriptor |= requires_args_descriptor;
+}
+
+void SelectorMap::SetSelectorOffset(int32_t sid, int32_t offset) {
+  selectors_[sid].offset = offset;
+}
+
+DispatchTableGenerator::DispatchTableGenerator(Zone* zone)
+    : zone_(zone),
+      classes_(nullptr),
+      num_selectors_(-1),
+      num_classes_(-1),
+      selector_map_(zone) {}
+
+void DispatchTableGenerator::Initialize(ClassTable* table) {
+  classes_ = table;
+
+  NumberSelectors();
+  SetupSelectorRows();
+  ComputeSelectorOffsets();
+}
+
+void DispatchTableGenerator::NumberSelectors() {
+  num_classes_ = classes_->NumCids();
+
+  Object& obj = Object::Handle(Z);
+  Class& klass = Class::Handle(Z);
+  Array& functions = Array::Handle(Z);
+  Function& function = Function::Handle(Z);
+
+  for (classid_t cid = kIllegalCid + 1; cid < num_classes_; cid++) {
+    obj = classes_->At(cid);
+    if (obj.IsClass()) {
+      klass = Class::RawCast(obj.raw());
+      functions = klass.functions();
+      if (!functions.IsNull()) {
+        for (intptr_t j = 0; j < functions.Length(); j++) {
+          function ^= functions.At(j);
+          if (function.IsDynamicFunction(/*allow_abstract=*/false)) {
+            const bool on_null_interface = klass.IsObjectClass();
+            const bool requires_args_descriptor =
+                function.IsGeneric() || function.HasOptionalParameters();
+            // Get assigned selector ID for this function.
+            const int32_t sid = selector_map_.SelectorId(function);
+            if (sid == SelectorMap::kInvalidSelectorId) {
+              // Probably gen_kernel was run in non-AOT mode or without TFA.
+              FATAL("Function has no assigned selector ID.\n");
+            }
+            selector_map_.SetSelectorProperties(sid, on_null_interface,
+                                                requires_args_descriptor);
+          }
+        }
+      }
+    }
+  }
+
+  num_selectors_ = selector_map_.NumIds();
+}
+
+void DispatchTableGenerator::SetupSelectorRows() {
+  Object& obj = Object::Handle(Z);
+  Class& klass = Class::Handle(Z);
+  Array& functions = Array::Handle(Z);
+  Function& function = Function::Handle(Z);
+
+  // For each class, we first need to figure out the ranges of cids that will
+  // inherit methods from it (this is due to the fact that cids don't have the
+  // property that they are assigned preorder and don't have holes).
+
+  // Make a condensed array which stores parent cids.
+  std::unique_ptr<classid_t[]> parent_cids(new classid_t[num_classes_]);
+  std::unique_ptr<bool[]> is_concrete_class(new bool[num_classes_]);
+  for (classid_t cid = kIllegalCid + 1; cid < num_classes_; cid++) {
+    classid_t parent_cid = kIllegalCid;
+    bool concrete = false;
+    if (cid > kIllegalCid) {
+      obj = classes_->At(cid);
+      if (obj.IsClass()) {
+        klass = Class::RawCast(obj.raw());
+        concrete = !klass.is_abstract();
+        klass = klass.SuperClass();
+        if (!klass.IsNull()) {
+          parent_cid = klass.id();
+        }
+      }
+    }
+    parent_cids[cid] = parent_cid;
+    is_concrete_class[cid] = concrete;
+  }
+
+  // Precompute depth level.
+  std::unique_ptr<int16_t[]> cid_depth(new int16_t[num_classes_]);
+  for (classid_t cid = kIllegalCid + 1; cid < num_classes_; cid++) {
+    int16_t depth = 0;
+    classid_t pcid = cid;
+    while (pcid != kIllegalCid) {
+      pcid = parent_cids[pcid];
+      depth++;
+    }
+    cid_depth[cid] = depth;
+  }
+
+  // Find all regions that have [cid] as parent (which should include [cid])!
+  std::unique_ptr<GrowableArray<Interval>[]> cid_subclass_ranges(
+      new GrowableArray<Interval>[num_classes_]());
+  for (classid_t cid = kIllegalCid + 1; cid < num_classes_; cid++) {
+    classid_t start = kIllegalCid;
+    for (classid_t sub_cid = kIllegalCid + 1; sub_cid < num_classes_;
+         sub_cid++) {
+      // Is [sub_cid] a subclass of [cid]?
+      classid_t pcid = sub_cid;
+      while (pcid != kIllegalCid && pcid != cid) {
+        pcid = parent_cids[pcid];
+      }
+      const bool is_subclass = cid == pcid;
+      const bool in_range = is_subclass && is_concrete_class[sub_cid];
+
+      if (start == kIllegalCid && in_range) {
+        start = sub_cid;
+      } else if (start != kIllegalCid && !in_range) {
+        Interval range(start, sub_cid);
+        cid_subclass_ranges[cid].Add(range);
+        start = kIllegalCid;
+      }
+    }
+    if (start != kIllegalCid) {
+      Interval range(start, num_classes_);
+      cid_subclass_ranges[cid].Add(range);
+    }
+  }
+
+  // Initialize selector rows.
+  SelectorRow* selector_rows = Z->Alloc<SelectorRow>(num_selectors_);
+  for (intptr_t i = 0; i < num_selectors_; i++) {
+    new (&selector_rows[i]) SelectorRow(Z, i);
+  }
+
+  // Add implementation intervals to the selector rows for all classes that
+  // have concrete implementations of the selector.
+  for (classid_t cid = kIllegalCid + 1; cid < num_classes_; cid++) {
+    obj = classes_->At(cid);
+    if (obj.IsClass()) {
+      klass = Class::RawCast(obj.raw());
+      GrowableArray<Interval>& subclasss_cid_ranges = cid_subclass_ranges[cid];
+
+      functions = klass.functions();
+      if (!functions.IsNull()) {
+        const int16_t depth = cid_depth[cid];
+        for (intptr_t j = 0; j < functions.Length(); j++) {
+          function ^= functions.At(j);
+          if (function.IsDynamicFunction(/*allow_abstract=*/false)) {
+            const int32_t sid = selector_map_.SelectorId(function);
+
+            if (sid != SelectorMap::kInvalidSelectorId) {
+              // Make a function handle that survives until the table is built.
+              auto& function_handle = Function::ZoneHandle(Z, function.raw());
+
+              for (intptr_t i = 0; i < subclasss_cid_ranges.length(); i++) {
+                Interval& subclass_cid_range = subclasss_cid_ranges[i];
+                selector_rows[sid].DefineSelectorImplementationForInterval(
+                    cid, depth, subclass_cid_range, function_handle);
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  // Retain all selectors that contain implementation intervals.
+  for (intptr_t i = 0; i < num_selectors_; i++) {
+    if (selector_rows[i].Finalize()) {
+      table_rows_.Add(&selector_rows[i]);
+    }
+  }
+}
+
+void DispatchTableGenerator::ComputeSelectorOffsets() {
+  ASSERT(table_rows_.length() > 0);
+
+  // Sort the table rows according to size.
+  struct SelectorRowSorter {
+    static int Compare(SelectorRow* const* a, SelectorRow* const* b) {
+      return (*b)->total_size() - (*a)->total_size();
+    }
+  };
+  table_rows_.Sort(SelectorRowSorter::Compare);
+
+  RowFitter fitter;
+  for (intptr_t i = 0; i < table_rows_.length(); i++) {
+    SelectorRow* row = table_rows_[i];
+    const int32_t offset = fitter.Fit(row);
+    row->set_offset(offset);
+    selector_map_.SetSelectorOffset(row->selector_id(), offset);
+  }
+
+  table_size_ = fitter.TableSize();
+}
+
+DispatchTable* DispatchTableGenerator::BuildTable() {
+  // Allocate the dispatch table and fill it in.
+  DispatchTable* dispatch_table = new DispatchTable(table_size_);
+  for (intptr_t i = 0; i < table_rows_.length(); i++) {
+    table_rows_[i]->FillTable(classes_, dispatch_table);
+  }
+
+  return dispatch_table;
+}
+
+}  // namespace compiler
+}  // namespace dart
+
+#endif  // defined(DART_PRECOMPILER) && !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/compiler/aot/dispatch_table_generator.h b/runtime/vm/compiler/aot/dispatch_table_generator.h
new file mode 100644
index 0000000..d047853
--- /dev/null
+++ b/runtime/vm/compiler/aot/dispatch_table_generator.h
@@ -0,0 +1,89 @@
+// Copyright (c) 2020, 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.
+
+#ifndef RUNTIME_VM_COMPILER_AOT_DISPATCH_TABLE_GENERATOR_H_
+#define RUNTIME_VM_COMPILER_AOT_DISPATCH_TABLE_GENERATOR_H_
+
+#include "vm/compiler/frontend/kernel_translation_helper.h"
+#include "vm/dispatch_table.h"
+#include "vm/object.h"
+
+namespace dart {
+
+class ClassTable;
+class Precompiler;
+
+namespace compiler {
+
+class SelectorRow;
+
+struct TableSelector {
+  int32_t id;
+  int32_t offset;
+  bool on_null_interface;
+  bool requires_args_descriptor;
+};
+
+class SelectorMap {
+ public:
+  explicit SelectorMap(Zone* zone) : zone_(zone) {}
+
+  // Get the selector for this interface target, or null if the function does
+  // not have a selector assigned.
+  const TableSelector* GetSelector(const Function& interface_target) const;
+
+ private:
+  static const int32_t kInvalidSelectorId =
+      kernel::ProcedureAttributesMetadata::kInvalidSelectorId;
+  static const int32_t kInvalidSelectorOffset = -1;
+
+  int32_t SelectorId(const Function& interface_target) const;
+
+  void SetSelectorProperties(int32_t sid,
+                             bool on_null_interface,
+                             bool requires_args_descriptor);
+  void SetSelectorOffset(int32_t sid, int32_t offset);
+
+  int32_t NumIds() const { return selectors_.length(); }
+
+  friend class dart::Precompiler;
+  friend class DispatchTableGenerator;
+  friend class SelectorRow;
+
+  Zone* zone_;
+  GrowableArray<TableSelector> selectors_;
+};
+
+class DispatchTableGenerator {
+ public:
+  explicit DispatchTableGenerator(Zone* zone);
+
+  SelectorMap* selector_map() { return &selector_map_; }
+
+  // Find suitable selectors and compute offsets for them.
+  void Initialize(ClassTable* table);
+
+  // Build up the table.
+  DispatchTable* BuildTable();
+
+ private:
+  void NumberSelectors();
+  void SetupSelectorRows();
+  void ComputeSelectorOffsets();
+
+  Zone* zone_;
+  ClassTable* classes_;
+  int32_t num_selectors_;
+  int32_t num_classes_;
+  int32_t table_size_;
+
+  GrowableArray<SelectorRow*> table_rows_;
+
+  SelectorMap selector_map_;
+};
+
+}  // namespace compiler
+}  // namespace dart
+
+#endif  // RUNTIME_VM_COMPILER_AOT_DISPATCH_TABLE_GENERATOR_H_
diff --git a/runtime/vm/compiler/aot/precompiler.cc b/runtime/vm/compiler/aot/precompiler.cc
index 19ea921..a2718c2 100644
--- a/runtime/vm/compiler/aot/precompiler.cc
+++ b/runtime/vm/compiler/aot/precompiler.cc
@@ -177,6 +177,7 @@
       typeargs_to_retain_(),
       types_to_retain_(),
       consts_to_retain_(),
+      seen_table_selectors_(),
       error_(Error::Handle()),
       get_runtime_type_is_unique_(false),
       il_serialization_stream_(nullptr) {
@@ -226,6 +227,11 @@
       // as well as other type checks.
       HierarchyInfo hierarchy_info(T);
 
+      if (FLAG_use_bare_instructions && FLAG_use_table_dispatch) {
+        dispatch_table_generator_ = new compiler::DispatchTableGenerator(Z);
+        dispatch_table_generator_->Initialize(I->class_table());
+      }
+
       // Precompile constructors to compute information such as
       // optimized instruction count (used in inlining heuristics).
       ClassFinalizer::ClearAllCode(
@@ -437,6 +443,14 @@
 
     ProgramVisitor::Dedup();
 
+    if (FLAG_use_bare_instructions && FLAG_use_table_dispatch) {
+      I->set_dispatch_table(dispatch_table_generator_->BuildTable());
+      // Delete the dispatch table generator while the current zone
+      // is still alive.
+      delete dispatch_table_generator_;
+      dispatch_table_generator_ = nullptr;
+    }
+
     zone_ = NULL;
   }
 
@@ -1059,6 +1073,25 @@
   }
 }
 
+void Precompiler::AddTableSelector(const compiler::TableSelector* selector) {
+  ASSERT(FLAG_use_bare_instructions && FLAG_use_table_dispatch);
+
+  if (seen_table_selectors_.HasKey(selector->id)) return;
+
+  seen_table_selectors_.Insert(selector->id);
+  changed_ = true;
+}
+
+bool Precompiler::IsHitByTableSelector(const Function& function) {
+  if (!(FLAG_use_bare_instructions && FLAG_use_table_dispatch)) {
+    return false;
+  }
+
+  const int32_t selector_id = selector_map()->SelectorId(function);
+  if (selector_id == compiler::SelectorMap::kInvalidSelectorId) return false;
+  return seen_table_selectors_.HasKey(selector_id);
+}
+
 void Precompiler::AddInstantiatedClass(const Class& cls) {
   if (cls.is_allocated()) return;
 
@@ -1239,7 +1272,7 @@
         // if (function.HasCode()) continue;
 
         selector = function.name();
-        if (IsSent(selector)) {
+        if (IsSent(selector) || IsHitByTableSelector(function)) {
           AddFunction(function);
         }
 
@@ -1291,7 +1324,7 @@
               metadata = kernel::ProcedureAttributesOf(function, Z);
             }
 
-            if (metadata.has_dynamic_invocations) {
+            if (metadata.method_or_setter_called_dynamically) {
               function2 = function.GetDynamicInvocationForwarder(selector2);
               AddFunction(function2);
             }
@@ -2512,6 +2545,12 @@
             *graph_compiler.used_static_fields().At(i));
       }
 
+      const GrowableArray<const compiler::TableSelector*>& call_selectors =
+          graph_compiler.dispatch_table_call_targets();
+      for (intptr_t i = 0; i < call_selectors.length(); i++) {
+        precompiler_->AddTableSelector(call_selectors[i]);
+      }
+
       // In bare instructions mode try adding all entries from the object
       // pool into the global object pool. This might fail if we have
       // nested code generation (i.e. we generated some stubs) whichs means
diff --git a/runtime/vm/compiler/aot/precompiler.h b/runtime/vm/compiler/aot/precompiler.h
index 97e15a1..57041cb 100644
--- a/runtime/vm/compiler/aot/precompiler.h
+++ b/runtime/vm/compiler/aot/precompiler.h
@@ -8,6 +8,7 @@
 #ifndef DART_PRECOMPILED_RUNTIME
 
 #include "vm/allocation.h"
+#include "vm/compiler/aot/dispatch_table_generator.h"
 #include "vm/compiler/assembler/assembler.h"
 #include "vm/hash_map.h"
 #include "vm/hash_table.h"
@@ -31,6 +32,24 @@
 class FlowGraph;
 class PrecompilerEntryPointsPrinter;
 
+class TableSelectorKeyValueTrait {
+ public:
+  // Typedefs needed for the DirectChainedHashMap template.
+  typedef int32_t Key;
+  typedef int32_t Value;
+  typedef int32_t Pair;
+
+  static Key KeyOf(Pair kv) { return kv; }
+
+  static Value ValueOf(Pair kv) { return kv; }
+
+  static inline intptr_t Hashcode(Key key) { return key; }
+
+  static inline bool IsKeyEqual(Pair pair, Key key) { return pair == key; }
+};
+
+typedef DirectChainedHashMap<TableSelectorKeyValueTrait> TableSelectorSet;
+
 class SymbolKeyValueTrait {
  public:
   // Typedefs needed for the DirectChainedHashMap template.
@@ -210,11 +229,17 @@
     return &global_object_pool_builder_;
   }
 
+  compiler::SelectorMap* selector_map() {
+    ASSERT(FLAG_use_bare_instructions && FLAG_use_table_dispatch);
+    return dispatch_table_generator_->selector_map();
+  }
+
   void* il_serialization_stream() const { return il_serialization_stream_; }
 
   static Precompiler* Instance() { return singleton_; }
 
   void AddRetainedStaticField(const Field& field);
+  void AddTableSelector(const compiler::TableSelector* selector);
 
  private:
   static Precompiler* singleton_;
@@ -242,6 +267,7 @@
   void AddInstantiatedClass(const Class& cls);
   void AddSelector(const String& selector);
   bool IsSent(const String& selector);
+  bool IsHitByTableSelector(const Function& function);
 
   void ProcessFunction(const Function& function);
   void CheckForNewDynamicFunctions();
@@ -313,8 +339,11 @@
   TypeArgumentsSet typeargs_to_retain_;
   AbstractTypeSet types_to_retain_;
   InstanceSet consts_to_retain_;
+  TableSelectorSet seen_table_selectors_;
   Error& error_;
 
+  compiler::DispatchTableGenerator* dispatch_table_generator_;
+
   bool get_runtime_type_is_unique_;
   void* il_serialization_stream_;
 };
diff --git a/runtime/vm/compiler/assembler/assembler_arm.cc b/runtime/vm/compiler/assembler/assembler_arm.cc
index 595dd92..b14b8d9 100644
--- a/runtime/vm/compiler/assembler/assembler_arm.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm.cc
@@ -1591,6 +1591,10 @@
   ldr(rd, Address(THR, target::Thread::isolate_offset()));
 }
 
+void Assembler::LoadDispatchTable(Register rd) {
+  ldr(rd, Address(THR, target::Thread::dispatch_table_array_offset()));
+}
+
 bool Assembler::CanLoadFromObjectPool(const Object& object) const {
   ASSERT(IsOriginalObject(object));
   ASSERT(!target::CanLoadFromThread(object));
@@ -3156,6 +3160,13 @@
   }
 }
 
+void Assembler::SubImmediate(Register rd,
+                             Register rn,
+                             int32_t value,
+                             Condition cond) {
+  AddImmediate(rd, rn, -value, cond);
+}
+
 void Assembler::SubImmediateSetFlags(Register rd,
                                      Register rn,
                                      int32_t value,
diff --git a/runtime/vm/compiler/assembler/assembler_arm.h b/runtime/vm/compiler/assembler/assembler_arm.h
index eb973c6..98e4ce6 100644
--- a/runtime/vm/compiler/assembler/assembler_arm.h
+++ b/runtime/vm/compiler/assembler/assembler_arm.h
@@ -757,6 +757,10 @@
                             Register rn,
                             int32_t value,
                             Condition cond = AL);
+  void SubImmediate(Register rd,
+                    Register rn,
+                    int32_t value,
+                    Condition cond = AL);
   void SubImmediateSetFlags(Register rd,
                             Register rn,
                             int32_t value,
@@ -799,6 +803,7 @@
   void LoadPoolPointer(Register reg = PP);
 
   void LoadIsolate(Register rd);
+  void LoadDispatchTable(Register dst);
 
   // Load word from pool from the given offset using encoding that
   // InstructionPattern::DecodeLoadWordFromPool can decode.
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.cc b/runtime/vm/compiler/assembler/assembler_arm64.cc
index 9fcbc8a..600bf63 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm64.cc
@@ -821,6 +821,16 @@
   }
 }
 
+void Assembler::LoadSFromOffset(VRegister dest, Register base, int32_t offset) {
+  if (Address::CanHoldOffset(offset, Address::Offset, kSWord)) {
+    fldrs(dest, Address(base, offset, Address::Offset, kSWord));
+  } else {
+    ASSERT(base != TMP2);
+    AddImmediate(TMP2, base, offset);
+    fldrs(dest, Address(TMP2));
+  }
+}
+
 void Assembler::LoadDFromOffset(VRegister dest, Register base, int32_t offset) {
   if (Address::CanHoldOffset(offset, Address::Offset, kDWord)) {
     fldrd(dest, Address(base, offset, Address::Offset, kDWord));
@@ -855,6 +865,16 @@
   }
 }
 
+void Assembler::StoreSToOffset(VRegister src, Register base, int32_t offset) {
+  if (Address::CanHoldOffset(offset, Address::Offset, kSWord)) {
+    fstrs(src, Address(base, offset, Address::Offset, kSWord));
+  } else {
+    ASSERT(base != TMP2);
+    AddImmediate(TMP2, base, offset);
+    fstrs(src, Address(TMP2));
+  }
+}
+
 void Assembler::StoreDToOffset(VRegister src, Register base, int32_t offset) {
   if (Address::CanHoldOffset(offset, Address::Offset, kDWord)) {
     fstrd(src, Address(base, offset, Address::Offset, kDWord));
@@ -1162,9 +1182,17 @@
 }
 
 void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
-  LoadClassIdMayBeSmi(TMP, object);
-  // Finally, tag the result.
-  SmiTag(result, TMP);
+  if (result == object) {
+    LoadClassIdMayBeSmi(TMP, object);
+    SmiTag(result, TMP);
+  } else {
+    Label done;
+    LoadImmediate(result, target::ToRawSmi(kSmiCid));
+    BranchIfSmi(object, &done);
+    LoadClassId(result, object);
+    SmiTag(result);
+    Bind(&done);
+  }
 }
 
 // Frame entry and exit.
@@ -1207,6 +1235,16 @@
   ldr(NULL_REG, compiler::Address(THR, target::Thread::object_null_offset()));
 }
 
+void Assembler::SetupGlobalPoolAndDispatchTable() {
+  ASSERT(FLAG_precompiled_mode && FLAG_use_bare_instructions);
+  ldr(PP, Address(THR, target::Thread::global_object_pool_offset()));
+  sub(PP, PP, Operand(kHeapObjectTag));  // Pool in PP is untagged!
+  if (FLAG_use_table_dispatch) {
+    ldr(DISPATCH_TABLE_REG,
+        Address(THR, target::Thread::dispatch_table_array_offset()));
+  }
+}
+
 void Assembler::CheckCodePointer() {
 #ifdef DEBUG
   if (!FLAG_check_code_pointer) {
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.h b/runtime/vm/compiler/assembler/assembler_arm64.h
index 48d5c06..19a26c6 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.h
+++ b/runtime/vm/compiler/assembler/assembler_arm64.h
@@ -1270,6 +1270,13 @@
       orr(rd, ZR, Operand(rn));
     }
   }
+  void movw(Register rd, Register rn) {
+    if ((rd == CSP) || (rn == CSP)) {
+      addw(rd, rn, Operand(0));
+    } else {
+      orrw(rd, ZR, Operand(rn));
+    }
+  }
   void vmov(VRegister vd, VRegister vn) { vorr(vd, vn, vn); }
   void mvn(Register rd, Register rm) { orn(rd, ZR, Operand(rm)); }
   void mvnw(Register rd, Register rm) { ornw(rd, ZR, Operand(rm)); }
@@ -1406,7 +1413,7 @@
   // Macros accepting a pp Register argument may attempt to load values from
   // the object pool when possible. Unless you are sure that the untagged object
   // pool pointer is in another register, or that it is not available at all,
-  // PP should be passed for pp.
+  // PP should be passed for pp. `dest` can be TMP2, `rn` cannot.
   void AddImmediate(Register dest, Register rn, int64_t imm);
   void AddImmediateSetFlags(Register dest,
                             Register rn,
@@ -1432,6 +1439,7 @@
                            OperandSize sz = kDoubleWord) {
     LoadFromOffset(dest, base, offset - kHeapObjectTag, sz);
   }
+  void LoadSFromOffset(VRegister dest, Register base, int32_t offset);
   void LoadDFromOffset(VRegister dest, Register base, int32_t offset);
   void LoadDFieldFromOffset(VRegister dest, Register base, int32_t offset) {
     LoadDFromOffset(dest, base, offset - kHeapObjectTag);
@@ -1451,6 +1459,8 @@
                           OperandSize sz = kDoubleWord) {
     StoreToOffset(src, base, offset - kHeapObjectTag, sz);
   }
+
+  void StoreSToOffset(VRegister src, Register base, int32_t offset);
   void StoreDToOffset(VRegister src, Register base, int32_t offset);
   void StoreDFieldToOffset(VRegister src, Register base, int32_t offset) {
     StoreDToOffset(src, base, offset - kHeapObjectTag);
@@ -1555,6 +1565,7 @@
   void CompareClassId(Register object,
                       intptr_t class_id,
                       Register scratch = kNoRegister);
+  // Note: input and output registers must be different.
   void LoadClassIdMayBeSmi(Register result, Register object);
   void LoadTaggedClassIdMayBeSmi(Register result, Register object);
 
@@ -1586,6 +1597,8 @@
   // e.g. BARRIER_MASK and NULL_REG.
   void RestorePinnedRegisters();
 
+  void SetupGlobalPoolAndDispatchTable();
+
   void EnterDartFrame(intptr_t frame_size, Register new_pp = kNoRegister);
   void EnterOsrFrame(intptr_t extra_size, Register new_pp = kNoRegister);
   void LeaveDartFrame(RestorePP restore_pp = kRestoreCallerPP);
diff --git a/runtime/vm/compiler/assembler/assembler_ia32.cc b/runtime/vm/compiler/assembler/assembler_ia32.cc
index 6c44032..d9e2ae6 100644
--- a/runtime/vm/compiler/assembler/assembler_ia32.cc
+++ b/runtime/vm/compiler/assembler/assembler_ia32.cc
@@ -184,6 +184,9 @@
 }
 
 void Assembler::movb(Register dst, const Address& src) {
+  // This would leave 24 bits above the 1 byte value undefined.
+  // If we ever want to purposefully have those undefined, remove this.
+  // TODO(dartbug.com/40210): Allow this.
   FATAL("Use movzxb or movsxb instead.");
 }
 
@@ -230,6 +233,9 @@
 }
 
 void Assembler::movw(Register dst, const Address& src) {
+  // This would leave 16 bits above the 2 byte value undefined.
+  // If we ever want to purposefully have those undefined, remove this.
+  // TODO(dartbug.com/40210): Allow this.
   FATAL("Use movzxw or movsxw instead.");
 }
 
diff --git a/runtime/vm/compiler/assembler/assembler_x64.cc b/runtime/vm/compiler/assembler/assembler_x64.cc
index 19be5db..0b02b8e 100644
--- a/runtime/vm/compiler/assembler/assembler_x64.cc
+++ b/runtime/vm/compiler/assembler/assembler_x64.cc
@@ -359,6 +359,9 @@
 }
 
 void Assembler::movw(Register dst, const Address& src) {
+  // This would leave 16 bits above the 2 byte value undefined.
+  // If we ever want to purposefully have those undefined, remove this.
+  // TODO(40210): Allow this.
   FATAL("Use movzxw or movsxw instead.");
 }
 
@@ -1235,6 +1238,10 @@
   movq(dst, Address(THR, target::Thread::isolate_offset()));
 }
 
+void Assembler::LoadDispatchTable(Register dst) {
+  movq(dst, Address(THR, target::Thread::dispatch_table_array_offset()));
+}
+
 void Assembler::LoadObjectHelper(Register dst,
                                  const Object& object,
                                  bool is_unique) {
@@ -2198,12 +2205,12 @@
     Bind(&join);
   } else {
     testq(object, Immediate(kSmiTagMask));
-    movq(result, Immediate(kSmiCid));
+    movq(result, Immediate(target::ToRawSmi(kSmiCid)));
     j(EQUAL, &smi, Assembler::kNearJump);
     LoadClassId(result, object);
+    SmiTag(result);
 
     Bind(&smi);
-    SmiTag(result);
   }
 }
 
diff --git a/runtime/vm/compiler/assembler/assembler_x64.h b/runtime/vm/compiler/assembler/assembler_x64.h
index c446b81..8d94cbf 100644
--- a/runtime/vm/compiler/assembler/assembler_x64.h
+++ b/runtime/vm/compiler/assembler/assembler_x64.h
@@ -708,6 +708,7 @@
   void LoadImmediate(Register reg, const Immediate& imm);
 
   void LoadIsolate(Register dst);
+  void LoadDispatchTable(Register dst);
   void LoadObject(Register dst, const Object& obj);
   void LoadUniqueObject(Register dst, const Object& obj);
   void LoadNativeEntry(Register dst,
diff --git a/runtime/vm/compiler/backend/constant_propagator.cc b/runtime/vm/compiler/backend/constant_propagator.cc
index e6b4d57..fb02b0b 100644
--- a/runtime/vm/compiler/backend/constant_propagator.cc
+++ b/runtime/vm/compiler/backend/constant_propagator.cc
@@ -431,6 +431,10 @@
   SetValue(instr, non_constant_);
 }
 
+void ConstantPropagator::VisitDispatchTableCall(DispatchTableCallInstr* instr) {
+  SetValue(instr, non_constant_);
+}
+
 void ConstantPropagator::VisitStaticCall(StaticCallInstr* instr) {
   const auto kind = instr->function().recognized_kind();
   switch (kind) {
@@ -1315,11 +1319,6 @@
   SetValue(instr, non_constant_);
 }
 
-void ConstantPropagator::VisitUnboxedWidthExtender(
-    UnboxedWidthExtenderInstr* instr) {
-  SetValue(instr, non_constant_);
-}
-
 void ConstantPropagator::VisitBitCast(BitCastInstr* instr) {
   SetValue(instr, non_constant_);
 }
diff --git a/runtime/vm/compiler/backend/flow_graph_checker.cc b/runtime/vm/compiler/backend/flow_graph_checker.cc
index 5d7c523..7814dd1 100644
--- a/runtime/vm/compiler/backend/flow_graph_checker.cc
+++ b/runtime/vm/compiler/backend/flow_graph_checker.cc
@@ -103,7 +103,7 @@
   return instruction->IsBranch() || instruction->IsGoto() ||
          instruction->IsIndirectGoto() || instruction->IsReturn() ||
          instruction->IsThrow() || instruction->IsReThrow() ||
-         instruction->IsStop() || instruction->IsTailCall();
+         instruction->IsTailCall();
 }
 
 // Asserts that arguments appear in environment at the right place.
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index 32a947e..5f55829 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -172,10 +172,19 @@
 }
 
 bool FlowGraphCompiler::IsUnboxedField(const Field& field) {
-  bool valid_class =
-      (SupportsUnboxedDoubles() && (field.guarded_cid() == kDoubleCid)) ||
-      (SupportsUnboxedSimd128() && (field.guarded_cid() == kFloat32x4Cid)) ||
-      (SupportsUnboxedSimd128() && (field.guarded_cid() == kFloat64x2Cid));
+  bool valid_class;
+  if (FLAG_precompiled_mode) {
+    valid_class =
+        (SupportsUnboxedDoubles() && (field.guarded_cid() == kDoubleCid)) ||
+        (SupportsUnboxedSimd128() && (field.guarded_cid() == kFloat32x4Cid)) ||
+        (SupportsUnboxedSimd128() && (field.guarded_cid() == kFloat64x2Cid)) ||
+        field.is_non_nullable_integer();
+  } else {
+    valid_class =
+        (SupportsUnboxedDoubles() && (field.guarded_cid() == kDoubleCid)) ||
+        (SupportsUnboxedSimd128() && (field.guarded_cid() == kFloat32x4Cid)) ||
+        (SupportsUnboxedSimd128() && (field.guarded_cid() == kFloat64x2Cid));
+  }
   return field.is_unboxing_candidate() && !field.is_nullable() && valid_class;
 }
 
@@ -341,7 +350,7 @@
 }
 
 static CatchEntryMove CatchEntryMoveFor(compiler::Assembler* assembler,
-                                        Representation src_rep,
+                                        Representation src_type,
                                         const Location& src,
                                         intptr_t dst_index) {
   if (src.IsConstant()) {
@@ -367,7 +376,7 @@
   }
 
   CatchEntryMove::SourceKind src_kind;
-  switch (src_rep) {
+  switch (src_type) {
     case kTagged:
       src_kind = CatchEntryMove::SourceKind::kTaggedSlot;
       break;
@@ -436,11 +445,11 @@
       // Can only occur if AllocationSinking is enabled - and it is disabled
       // in functions with try.
       ASSERT(!src.IsInvalid());
-      const Representation src_rep =
+      const Representation src_type =
           env->ValueAt(i)->definition()->representation();
       intptr_t dest_index = i - num_direct_parameters;
       const auto move =
-          CatchEntryMoveFor(assembler(), src_rep, src, dest_index);
+          CatchEntryMoveFor(assembler(), src_type, src, dest_index);
       if (!move.IsRedundant()) {
         catch_entry_moves_maps_builder_->Append(move);
       }
@@ -779,6 +788,11 @@
                                      assembler()->CodeSize(), NULL, &code));
 }
 
+void FlowGraphCompiler::AddDispatchTableCallTarget(
+    const compiler::TableSelector* selector) {
+  dispatch_table_call_targets_.Add(selector);
+}
+
 CompilerDeoptInfo* FlowGraphCompiler::AddDeoptIndexAtCall(intptr_t deopt_id) {
   ASSERT(is_optimizing());
   ASSERT(!intrinsic_mode());
@@ -2470,6 +2484,232 @@
   }
 }
 
+void FlowGraphCompiler::EmitNativeMove(
+    const compiler::ffi::NativeLocation& destination,
+    const compiler::ffi::NativeLocation& source,
+    TemporaryRegisterAllocator* temp) {
+  const auto& src_payload_type = source.payload_type();
+  const auto& dst_payload_type = destination.payload_type();
+  const auto& src_container_type = source.container_type();
+  const auto& dst_container_type = destination.container_type();
+  const intptr_t src_payload_size = src_payload_type.SizeInBytes();
+  const intptr_t dst_payload_size = dst_payload_type.SizeInBytes();
+  const intptr_t src_container_size = src_container_type.SizeInBytes();
+  const intptr_t dst_container_size = dst_container_type.SizeInBytes();
+
+  // This function does not know how to do larger mem copy moves yet.
+  ASSERT(src_payload_type.IsFundamental());
+  ASSERT(dst_payload_type.IsFundamental());
+
+  // This function does not deal with sign conversions yet.
+  ASSERT(src_payload_type.IsSigned() == dst_payload_type.IsSigned());
+
+  // This function does not deal with bit casts yet.
+  ASSERT(src_container_type.IsFloat() == dst_container_type.IsFloat());
+  ASSERT(src_container_type.IsInt() == dst_container_type.IsInt());
+
+  // If the location, payload, and container are equal, we're done.
+  if (source.Equals(destination) && src_payload_type.Equals(dst_payload_type) &&
+      src_container_type.Equals(dst_container_type)) {
+    return;
+  }
+
+  // Solve descrepancies between container size and payload size.
+  if (src_payload_type.IsInt() && dst_payload_type.IsInt() &&
+      (src_payload_size != src_container_size ||
+       dst_payload_size != dst_container_size)) {
+    if (src_payload_size <= dst_payload_size &&
+        src_container_size >= dst_container_size) {
+      // The upper bits of the source are already properly sign or zero
+      // extended, so just copy the required amount of bits.
+      return EmitNativeMove(destination.WithOtherNativeType(
+                                dst_container_type, dst_container_type, zone_),
+                            source.WithOtherNativeType(
+                                dst_container_type, dst_container_type, zone_),
+                            temp);
+    }
+    if (src_payload_size >= dst_payload_size &&
+        dst_container_size > dst_payload_size) {
+      // The upper bits of the source are not properly sign or zero extended
+      // to be copied to the target, so regard the source as smaller.
+      return EmitNativeMove(
+          destination.WithOtherNativeType(dst_container_type,
+                                          dst_container_type, zone_),
+          source.WithOtherNativeType(dst_payload_type, dst_payload_type, zone_),
+          temp);
+    }
+    UNREACHABLE();
+  }
+  ASSERT(src_payload_size == src_container_size);
+  ASSERT(dst_payload_size == dst_container_size);
+
+  // Split moves that are larger than kWordSize, these require separate
+  // instructions on all architectures.
+  if (compiler::target::kWordSize == 4 && src_container_size == 8 &&
+      dst_container_size == 8 && !source.IsFpuRegisters() &&
+      !destination.IsFpuRegisters()) {
+    // TODO(40209): If this is stack to stack, we could use FpuTMP.
+    // Test the impact on code size and speed.
+    EmitNativeMove(destination.Split(0, zone_), source.Split(0, zone_), temp);
+    EmitNativeMove(destination.Split(1, zone_), source.Split(1, zone_), temp);
+    return;
+  }
+
+  // Split moves from stack to stack, none of the architectures provides
+  // memory to memory move instructions.
+  if (source.IsStack() && destination.IsStack()) {
+    Register scratch = TMP;
+    if (TMP == kNoRegister) {
+      scratch = temp->AllocateTemporary();
+    }
+    const auto& intermediate =
+        *new (zone_) compiler::ffi::NativeRegistersLocation(
+            dst_payload_type, dst_container_type, scratch);
+    EmitNativeMove(intermediate, source, temp);
+    EmitNativeMove(destination, intermediate, temp);
+    if (TMP == kNoRegister) {
+      temp->ReleaseTemporary();
+    }
+    return;
+  }
+
+  const bool sign_or_zero_extend = dst_container_size > src_container_size;
+
+  // No architecture supports sign extending with memory as destination.
+  if (sign_or_zero_extend && destination.IsStack()) {
+    ASSERT(source.IsRegisters());
+    const auto& intermediate =
+        source.WithOtherNativeType(dst_payload_type, dst_container_type, zone_);
+    EmitNativeMove(intermediate, source, temp);
+    EmitNativeMove(destination, intermediate, temp);
+    return;
+  }
+
+#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_ARM64)
+  // Arm does not support sign extending from a memory location, x86 does.
+  if (sign_or_zero_extend && source.IsStack()) {
+    ASSERT(destination.IsRegisters());
+    const auto& intermediate = destination.WithOtherNativeType(
+        src_payload_type, src_container_type, zone_);
+    EmitNativeMove(intermediate, source, temp);
+    EmitNativeMove(destination, intermediate, temp);
+    return;
+  }
+#endif
+
+  // If we're not sign extending, and we're moving 8 or 16 bits into a
+  // register, upgrade the move to take upper bits of garbage from the
+  // source location. This is the same as leaving the previous garbage in
+  // there.
+  //
+  // TODO(40210): If our assemblers would support moving 1 and 2 bytes into
+  // registers, this code can be removed.
+  if (!sign_or_zero_extend && destination.IsRegisters() &&
+      destination.container_type().SizeInBytes() <= 2) {
+    ASSERT(source.payload_type().IsInt());
+    return EmitNativeMove(destination.WidenTo4Bytes(zone_),
+                          source.WidenTo4Bytes(zone_), temp);
+  }
+
+  // Do the simple architecture specific moves.
+  EmitNativeMoveArchitecture(destination, source);
+}
+
+// TODO(dartbug.com/36730): Remove this if PairLocations can be converted
+// into NativeLocations.
+void FlowGraphCompiler::EmitMoveToNative(
+    const compiler::ffi::NativeLocation& dst,
+    Location src_loc,
+    Representation src_type,
+    TemporaryRegisterAllocator* temp) {
+  if (src_loc.IsPairLocation()) {
+    for (intptr_t i : {0, 1}) {
+      const auto& src_split = compiler::ffi::NativeLocation::FromPairLocation(
+          src_loc, src_type, i, zone_);
+      EmitNativeMove(dst.Split(i, zone_), src_split, temp);
+    }
+  } else {
+    const auto& src =
+        compiler::ffi::NativeLocation::FromLocation(src_loc, src_type, zone_);
+    EmitNativeMove(dst, src, temp);
+  }
+}
+
+// TODO(dartbug.com/36730): Remove this if PairLocations can be converted
+// into NativeLocations.
+void FlowGraphCompiler::EmitMoveFromNative(
+    Location dst_loc,
+    Representation dst_type,
+    const compiler::ffi::NativeLocation& src,
+    TemporaryRegisterAllocator* temp) {
+  if (dst_loc.IsPairLocation()) {
+    for (intptr_t i : {0, 1}) {
+      const auto& dest_split = compiler::ffi::NativeLocation::FromPairLocation(
+          dst_loc, dst_type, i, zone_);
+      EmitNativeMove(dest_split, src.Split(i, zone_), temp);
+    }
+  } else {
+    const auto& dest =
+        compiler::ffi::NativeLocation::FromLocation(dst_loc, dst_type, zone_);
+    EmitNativeMove(dest, src, temp);
+  }
+}
+
+void FlowGraphCompiler::EmitMoveConst(const compiler::ffi::NativeLocation& dst,
+                                      Location src,
+                                      Representation src_type,
+                                      TemporaryRegisterAllocator* temp) {
+  ASSERT(src.IsConstant());
+  const auto& dst_type = dst.payload_type();
+  if (dst.IsExpressibleAsLocation() &&
+      dst_type.IsExpressibleAsRepresentation() &&
+      dst_type.AsRepresentationOverApprox(zone_) == src_type) {
+    // We can directly emit the const in the right place and representation.
+    const Location dst_loc = dst.AsLocation();
+    EmitMove(dst_loc, src, temp);
+  } else {
+    // We need an intermediate location.
+    Location intermediate;
+    if (dst_type.IsInt()) {
+      if (TMP == kNoRegister) {
+        Register scratch = temp->AllocateTemporary();
+        Location::RegisterLocation(scratch);
+      } else {
+        intermediate = Location::RegisterLocation(TMP);
+      }
+    } else {
+      ASSERT(dst_type.IsFloat());
+      intermediate = Location::FpuRegisterLocation(FpuTMP);
+    }
+
+    if (src.IsPairLocation()) {
+      for (intptr_t i : {0, 1}) {
+        const Representation src_type_split =
+            compiler::ffi::NativeType::FromUnboxedRepresentation(src_type,
+                                                                 zone_)
+                .Split(i, zone_)
+                .AsRepresentation();
+        const auto& intermediate_native =
+            compiler::ffi::NativeLocation::FromLocation(intermediate,
+                                                        src_type_split, zone_);
+        EmitMove(intermediate, src.AsPairLocation()->At(i), temp);
+        EmitNativeMove(dst.Split(i, zone_), intermediate_native, temp);
+      }
+    } else {
+      const auto& intermediate_native =
+          compiler::ffi::NativeLocation::FromLocation(intermediate, src_type,
+                                                      zone_);
+      EmitMove(intermediate, src, temp);
+      EmitNativeMove(dst, intermediate_native, temp);
+    }
+
+    if (dst_type.IsInt() && TMP == kNoRegister) {
+      temp->ReleaseTemporary();
+    }
+  }
+  return;
+}
+
 #undef __
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
 
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.h b/runtime/vm/compiler/backend/flow_graph_compiler.h
index c38904d..5c94d9a 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.h
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.h
@@ -12,6 +12,7 @@
 #include "vm/compiler/assembler/assembler.h"
 #include "vm/compiler/backend/code_statistics.h"
 #include "vm/compiler/backend/il.h"
+#include "vm/compiler/backend/locations.h"
 #include "vm/runtime_entry.h"
 
 namespace dart {
@@ -28,6 +29,10 @@
 class ParsedFunction;
 class SpeculativeInliningPolicy;
 
+namespace compiler {
+struct TableSelector;
+}
+
 // Used in methods which need conditional access to a temporary register.
 // May only be used to allocate a single temporary register.
 class TemporaryRegisterAllocator : public ValueObject {
@@ -416,6 +421,10 @@
   const GrowableArray<BlockEntryInstr*>& block_order() const {
     return block_order_;
   }
+  const GrowableArray<const compiler::TableSelector*>&
+  dispatch_table_call_targets() const {
+    return dispatch_table_call_targets_;
+  }
 
   // If 'ForcedOptimization()' returns 'true', we are compiling in optimized
   // mode for a function which cannot deoptimize. Certain optimizations, e.g.
@@ -499,8 +508,46 @@
   bool TryIntrinsify();
 
   // Emits code for a generic move from a location 'src' to a location 'dst'.
+  //
+  // Note that Location does not include a size (that can only be deduced from
+  // a Representation), so these moves might overapproximate the size needed
+  // to move. The maximal overapproximation is moving 8 bytes instead of 4 on
+  // 64 bit architectures. This overapproximation is not a problem, because
+  // the Dart calling convention only uses word-sized stack slots.
+  //
+  // TODO(dartbug.com/40400): Express this in terms of EmitMove(NativeLocation
+  // NativeLocation) to remove code duplication.
   void EmitMove(Location dst, Location src, TemporaryRegisterAllocator* temp);
 
+  // Emits code for a move from a location `src` to a location `dst`.
+  //
+  // Takes into account the payload and container representations of `dst` and
+  // `src` to do the smallest move possible, and sign (or zero) extend or
+  // truncate if needed.
+  //
+  // Makes use of TMP, FpuTMP, and `temp`.
+  void EmitNativeMove(const compiler::ffi::NativeLocation& dst,
+                      const compiler::ffi::NativeLocation& src,
+                      TemporaryRegisterAllocator* temp);
+
+  // Helper method to move from a Location to a NativeLocation.
+  void EmitMoveToNative(const compiler::ffi::NativeLocation& dst,
+                        Location src_loc,
+                        Representation src_type,
+                        TemporaryRegisterAllocator* temp);
+
+  // Helper method to move from a NativeLocation to a Location.
+  void EmitMoveFromNative(Location dst_loc,
+                          Representation dst_type,
+                          const compiler::ffi::NativeLocation& src,
+                          TemporaryRegisterAllocator* temp);
+
+  // Emits a Dart const to a native location.
+  void EmitMoveConst(const compiler::ffi::NativeLocation& dst,
+                     Location src,
+                     Representation src_type,
+                     TemporaryRegisterAllocator* temp);
+
   void GenerateAssertAssignable(TokenPosition token_pos,
                                 intptr_t deopt_id,
                                 const AbstractType& dst_type,
@@ -690,6 +737,10 @@
                        intptr_t total_ic_calls,
                        Code::EntryKind entry_kind = Code::EntryKind::kNormal);
 
+  void EmitDispatchTableCall(Register cid_reg,
+                             int32_t selector_offset,
+                             const Array& arguments_descriptor);
+
   Condition EmitEqualityRegConstCompare(Register reg,
                                         const Object& obj,
                                         bool needs_number_check,
@@ -862,6 +913,7 @@
   Zone* zone() const { return zone_; }
 
   void AddStubCallTarget(const Code& code);
+  void AddDispatchTableCallTarget(const compiler::TableSelector* selector);
 
   RawArray* edge_counters_array() const { return edge_counters_array_.raw(); }
 
@@ -900,6 +952,10 @@
   friend class CheckedSmiSlowPath;          // Same.
   friend class CheckedSmiComparisonSlowPath;  // Same.
 
+  // Architecture specific implementation of simple native moves.
+  void EmitNativeMoveArchitecture(const compiler::ffi::NativeLocation& dst,
+                                  const compiler::ffi::NativeLocation& src);
+
   void EmitFrameEntry();
 
   bool TryIntrinsifyHelper();
@@ -1119,6 +1175,8 @@
   // TODO(srdjan): Evaluate if we should store allocation stub targets into a
   // separate table?
   GrowableArray<StaticCallsStruct*> static_calls_target_table_;
+  // The table selectors of all dispatch table calls in the current function.
+  GrowableArray<const compiler::TableSelector*> dispatch_table_call_targets_;
   const bool is_optimizing_;
   SpeculativeInliningPolicy* speculative_policy_;
   // Set to true if optimized code has IC calls.
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
index 0b08372..0133861 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
@@ -13,6 +13,7 @@
 #include "vm/cpu.h"
 #include "vm/dart_entry.h"
 #include "vm/deopt_instructions.h"
+#include "vm/dispatch_table.h"
 #include "vm/instructions.h"
 #include "vm/object_store.h"
 #include "vm/parser.h"
@@ -1244,6 +1245,35 @@
   __ Drop(count_with_type_args);
 }
 
+void FlowGraphCompiler::EmitDispatchTableCall(
+    Register cid_reg,
+    int32_t selector_offset,
+    const Array& arguments_descriptor) {
+  const Register table_reg = LR;
+  ASSERT(cid_reg != table_reg);
+  ASSERT(cid_reg != ARGS_DESC_REG);
+  if (!arguments_descriptor.IsNull()) {
+    __ LoadObject(ARGS_DESC_REG, arguments_descriptor);
+  }
+  intptr_t offset = (selector_offset - DispatchTable::OriginElement()) *
+                    compiler::target::kWordSize;
+  __ LoadDispatchTable(table_reg);
+  if (offset == 0) {
+    __ ldr(LR, compiler::Address(table_reg, cid_reg, LSL,
+                                 compiler::target::kWordSizeLog2));
+  } else {
+    __ add(table_reg, table_reg,
+           compiler::Operand(cid_reg, LSL, compiler::target::kWordSizeLog2));
+    if (!Utils::IsAbsoluteUint(12, offset)) {
+      const intptr_t adjust = offset & -(1 << 12);
+      __ AddImmediate(table_reg, table_reg, adjust);
+      offset -= adjust;
+    }
+    __ ldr(LR, compiler::Address(table_reg, offset));
+  }
+  __ blx(LR);
+}
+
 Condition FlowGraphCompiler::EmitEqualityRegConstCompare(
     Register reg,
     const Object& obj,
@@ -1483,6 +1513,160 @@
   }
 }
 
+static OperandSize BytesToOperandSize(intptr_t bytes) {
+  switch (bytes) {
+    case 4:
+      return OperandSize::kWord;
+    case 2:
+      return OperandSize::kHalfword;
+    case 1:
+      return OperandSize::kByte;
+    default:
+      UNIMPLEMENTED();
+  }
+}
+
+void FlowGraphCompiler::EmitNativeMoveArchitecture(
+    const compiler::ffi::NativeLocation& destination,
+    const compiler::ffi::NativeLocation& source) {
+  const auto& src_payload_type = source.payload_type();
+  const auto& dst_payload_type = destination.payload_type();
+  const auto& src_container_type = source.container_type();
+  const auto& dst_container_type = destination.container_type();
+  ASSERT(src_container_type.IsFloat() == dst_container_type.IsFloat());
+  ASSERT(src_container_type.IsInt() == dst_container_type.IsInt());
+  ASSERT(src_payload_type.IsSigned() == dst_payload_type.IsSigned());
+  ASSERT(src_payload_type.IsFundamental());
+  ASSERT(dst_payload_type.IsFundamental());
+  const intptr_t src_size = src_payload_type.SizeInBytes();
+  const intptr_t dst_size = dst_payload_type.SizeInBytes();
+  const bool sign_or_zero_extend = dst_size > src_size;
+
+  if (source.IsRegisters()) {
+    const auto& src = source.AsRegisters();
+    ASSERT(src.num_regs() == 1);
+    ASSERT(src_size <= 4);
+    const auto src_reg = src.reg_at(0);
+
+    if (destination.IsRegisters()) {
+      const auto& dst = destination.AsRegisters();
+      ASSERT(dst.num_regs() == 1);
+      const auto dst_reg = dst.reg_at(0);
+      if (!sign_or_zero_extend) {
+        ASSERT(dst_size == 4);
+        __ mov(dst_reg, compiler::Operand(src_reg));
+      } else {
+        ASSERT(sign_or_zero_extend);
+        // Arm has no sign- or zero-extension instructions, so use shifts.
+        const intptr_t shift_length =
+            (compiler::target::kWordSize - src_size) * kBitsPerByte;
+        __ Lsl(dst_reg, src_reg, compiler::Operand(shift_length));
+        if (src_payload_type.IsSigned()) {
+          __ Asr(dst_reg, dst_reg, compiler::Operand(shift_length));
+        } else {
+          __ Lsr(dst_reg, dst_reg, compiler::Operand(shift_length));
+        }
+      }
+
+    } else if (destination.IsFpuRegisters()) {
+      // Fpu Registers should only contain doubles and registers only ints.
+      // The bit casts are done with a BitCastInstr.
+      // TODO(dartbug.com/40371): Remove BitCastInstr and implement here.
+      UNIMPLEMENTED();
+
+    } else {
+      ASSERT(destination.IsStack());
+      const auto& dst = destination.AsStack();
+      ASSERT(!sign_or_zero_extend);
+      ASSERT(dst_size <= 4);
+      const OperandSize op_size = BytesToOperandSize(dst_size);
+      __ StoreToOffset(op_size, src.reg_at(0), dst.base_register(),
+                       dst.offset_in_bytes());
+    }
+
+  } else if (source.IsFpuRegisters()) {
+    const auto& src = source.AsFpuRegisters();
+    // We have not implemented conversions here, use IL convert instructions.
+    ASSERT(src_payload_type.Equals(dst_payload_type));
+
+    if (destination.IsRegisters()) {
+      // Fpu Registers should only contain doubles and registers only ints.
+      // The bit casts are done with a BitCastInstr.
+      // TODO(dartbug.com/40371): Remove BitCastInstr and implement here.
+      UNIMPLEMENTED();
+
+    } else if (destination.IsFpuRegisters()) {
+      const auto& dst = destination.AsFpuRegisters();
+      switch (dst_size) {
+        case 16:
+          __ vmovq(dst.fpu_reg(), src.fpu_reg());
+          return;
+        case 8:
+          __ vmovd(dst.fpu_as_d_reg(), src.fpu_as_d_reg());
+          return;
+        case 4:
+          __ vmovs(dst.fpu_as_s_reg(), src.fpu_as_s_reg());
+          return;
+        default:
+          UNREACHABLE();
+      }
+
+    } else {
+      ASSERT(destination.IsStack());
+      ASSERT(src_payload_type.IsFloat());
+      const auto& dst = destination.AsStack();
+      switch (dst_size) {
+        case 8:
+          __ StoreDToOffset(src.fpu_as_d_reg(), dst.base_register(),
+                            dst.offset_in_bytes());
+          return;
+        case 4:
+          __ StoreSToOffset(src.fpu_as_s_reg(), dst.base_register(),
+                            dst.offset_in_bytes());
+          return;
+        default:
+          // TODO(dartbug.com/37470): Case 16 for simd packed data.
+          UNREACHABLE();
+      }
+    }
+
+  } else {
+    ASSERT(source.IsStack());
+    const auto& src = source.AsStack();
+    if (destination.IsRegisters()) {
+      const auto& dst = destination.AsRegisters();
+      ASSERT(dst.num_regs() == 1);
+      const auto dst_reg = dst.reg_at(0);
+      ASSERT(!sign_or_zero_extend);
+      ASSERT(dst_size <= 4);
+      const OperandSize op_size = BytesToOperandSize(dst_size);
+      __ LoadFromOffset(op_size, dst_reg, src.base_register(),
+                        src.offset_in_bytes());
+
+    } else if (destination.IsFpuRegisters()) {
+      ASSERT(src_payload_type.Equals(dst_payload_type));
+      ASSERT(src_payload_type.IsFloat());
+      const auto& dst = destination.AsFpuRegisters();
+      switch (src_size) {
+        case 8:
+          __ LoadDFromOffset(dst.fpu_as_d_reg(), src.base_register(),
+                             src.offset_in_bytes());
+          return;
+        case 4:
+          __ LoadSFromOffset(dst.fpu_as_s_reg(), src.base_register(),
+                             src.offset_in_bytes());
+          return;
+        default:
+          UNIMPLEMENTED();
+      }
+
+    } else {
+      ASSERT(destination.IsStack());
+      UNREACHABLE();
+    }
+  }
+}
+
 #undef __
 #define __ compiler_->assembler()->
 
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
index 53d03d3..9278863 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
@@ -13,6 +13,7 @@
 #include "vm/cpu.h"
 #include "vm/dart_entry.h"
 #include "vm/deopt_instructions.h"
+#include "vm/dispatch_table.h"
 #include "vm/instructions.h"
 #include "vm/object_store.h"
 #include "vm/parser.h"
@@ -1214,6 +1215,21 @@
   __ Drop(count_with_type_args);
 }
 
+void FlowGraphCompiler::EmitDispatchTableCall(
+    Register cid_reg,
+    int32_t selector_offset,
+    const Array& arguments_descriptor) {
+  ASSERT(cid_reg != ARGS_DESC_REG);
+  if (!arguments_descriptor.IsNull()) {
+    __ LoadObject(ARGS_DESC_REG, arguments_descriptor);
+  }
+  const intptr_t offset = selector_offset - DispatchTable::OriginElement();
+  __ AddImmediate(cid_reg, cid_reg, offset);
+  __ ldr(LR, compiler::Address(DISPATCH_TABLE_REG, cid_reg, UXTX,
+                               compiler::Address::Scaled));
+  __ blr(LR);
+}
+
 Condition FlowGraphCompiler::EmitEqualityRegConstCompare(
     Register reg,
     const Object& obj,
@@ -1426,6 +1442,155 @@
   }
 }
 
+static OperandSize BytesToOperandSize(intptr_t bytes) {
+  switch (bytes) {
+    case 8:
+      return OperandSize::kDoubleWord;
+    case 4:
+      return OperandSize::kWord;
+    case 2:
+      return OperandSize::kHalfword;
+    case 1:
+      return OperandSize::kByte;
+    default:
+      UNIMPLEMENTED();
+  }
+}
+
+void FlowGraphCompiler::EmitNativeMoveArchitecture(
+    const compiler::ffi::NativeLocation& destination,
+    const compiler::ffi::NativeLocation& source) {
+  const auto& src_type = source.payload_type();
+  const auto& dst_type = destination.payload_type();
+  ASSERT(src_type.IsFloat() == dst_type.IsFloat());
+  ASSERT(src_type.IsInt() == dst_type.IsInt());
+  ASSERT(src_type.IsSigned() == dst_type.IsSigned());
+  ASSERT(src_type.IsFundamental());
+  ASSERT(dst_type.IsFundamental());
+  const intptr_t src_size = src_type.SizeInBytes();
+  const intptr_t dst_size = dst_type.SizeInBytes();
+  const bool sign_or_zero_extend = dst_size > src_size;
+
+  if (source.IsRegisters()) {
+    const auto& src = source.AsRegisters();
+    ASSERT(src.num_regs() == 1);
+    const auto src_reg = src.reg_at(0);
+
+    if (destination.IsRegisters()) {
+      const auto& dst = destination.AsRegisters();
+      ASSERT(dst.num_regs() == 1);
+      const auto dst_reg = dst.reg_at(0);
+      if (!sign_or_zero_extend) {
+        switch (dst_size) {
+          case 8:
+            __ mov(dst_reg, src_reg);
+            return;
+          case 4:
+            __ movw(dst_reg, src_reg);
+            return;
+          default:
+            UNIMPLEMENTED();
+        }
+      } else {
+        switch (src_type.AsFundamental().representation()) {
+          case compiler::ffi::kInt8:  // Sign extend operand.
+            __ sxtb(dst_reg, src_reg);
+            return;
+          case compiler::ffi::kInt16:
+            __ sxth(dst_reg, src_reg);
+            return;
+          case compiler::ffi::kUint8:  // Zero extend operand.
+            __ uxtb(dst_reg, src_reg);
+            return;
+          case compiler::ffi::kUint16:
+            __ uxth(dst_reg, src_reg);
+            return;
+          default:
+            // 32 to 64 bit is covered in IL by Representation conversions.
+            UNIMPLEMENTED();
+        }
+      }
+
+    } else if (destination.IsFpuRegisters()) {
+      // Fpu Registers should only contain doubles and registers only ints.
+      UNIMPLEMENTED();
+
+    } else {
+      ASSERT(destination.IsStack());
+      const auto& dst = destination.AsStack();
+      ASSERT(!sign_or_zero_extend);
+      const OperandSize op_size = BytesToOperandSize(dst_size);
+      __ StoreToOffset(src.reg_at(0), dst.base_register(),
+                       dst.offset_in_bytes(), op_size);
+    }
+
+  } else if (source.IsFpuRegisters()) {
+    const auto& src = source.AsFpuRegisters();
+    // We have not implemented conversions here, use IL convert instructions.
+    ASSERT(src_type.Equals(dst_type));
+
+    if (destination.IsRegisters()) {
+      // Fpu Registers should only contain doubles and registers only ints.
+      UNIMPLEMENTED();
+
+    } else if (destination.IsFpuRegisters()) {
+      const auto& dst = destination.AsFpuRegisters();
+      __ vmov(dst.fpu_reg(), src.fpu_reg());
+
+    } else {
+      ASSERT(destination.IsStack());
+      ASSERT(src_type.IsFloat());
+      const auto& dst = destination.AsStack();
+      switch (dst_size) {
+        case 8:
+          __ StoreDToOffset(src.fpu_reg(), dst.base_register(),
+                            dst.offset_in_bytes());
+          return;
+        case 4:
+          __ StoreSToOffset(src.fpu_reg(), dst.base_register(),
+                            dst.offset_in_bytes());
+          return;
+        default:
+          UNREACHABLE();
+      }
+    }
+
+  } else {
+    ASSERT(source.IsStack());
+    const auto& src = source.AsStack();
+    if (destination.IsRegisters()) {
+      const auto& dst = destination.AsRegisters();
+      ASSERT(dst.num_regs() == 1);
+      const auto dst_reg = dst.reg_at(0);
+      ASSERT(!sign_or_zero_extend);
+      const OperandSize op_size = BytesToOperandSize(dst_size);
+      __ LoadFromOffset(dst_reg, src.base_register(), src.offset_in_bytes(),
+                        op_size);
+
+    } else if (destination.IsFpuRegisters()) {
+      ASSERT(src_type.Equals(dst_type));
+      ASSERT(src_type.IsFloat());
+      const auto& dst = destination.AsFpuRegisters();
+      switch (src_size) {
+        case 8:
+          __ LoadDFromOffset(dst.fpu_reg(), src.base_register(),
+                             src.offset_in_bytes());
+          return;
+        case 4:
+          __ LoadSFromOffset(dst.fpu_reg(), src.base_register(),
+                             src.offset_in_bytes());
+          return;
+        default:
+          UNIMPLEMENTED();
+      }
+
+    } else {
+      ASSERT(destination.IsStack());
+      UNREACHABLE();
+    }
+  }
+}
+
 #undef __
 #define __ compiler_->assembler()->
 
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
index 14749b8..da3e9c5 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
@@ -1039,6 +1039,14 @@
   __ Drop(count_with_type_args);
 }
 
+void FlowGraphCompiler::EmitDispatchTableCall(
+    Register cid_reg,
+    int32_t selector_offset,
+    const Array& arguments_descriptor) {
+  // Only generated with precompilation.
+  UNREACHABLE();
+}
+
 Condition FlowGraphCompiler::EmitEqualityRegConstCompare(
     Register reg,
     const Object& obj,
@@ -1290,6 +1298,163 @@
   }
 }
 
+void FlowGraphCompiler::EmitNativeMoveArchitecture(
+    const compiler::ffi::NativeLocation& destination,
+    const compiler::ffi::NativeLocation& source) {
+  const auto& src_type = source.payload_type();
+  const auto& dst_type = destination.payload_type();
+  ASSERT(src_type.IsFloat() == dst_type.IsFloat());
+  ASSERT(src_type.IsInt() == dst_type.IsInt());
+  ASSERT(src_type.IsSigned() == dst_type.IsSigned());
+  ASSERT(src_type.IsFundamental());
+  ASSERT(dst_type.IsFundamental());
+  const intptr_t src_size = src_type.SizeInBytes();
+  const intptr_t dst_size = dst_type.SizeInBytes();
+  const bool sign_or_zero_extend = dst_size > src_size;
+
+  if (source.IsRegisters()) {
+    const auto& src = source.AsRegisters();
+    ASSERT(src.num_regs() == 1);
+    ASSERT(src_size <= 4);
+    const auto src_reg = src.reg_at(0);
+
+    if (destination.IsRegisters()) {
+      const auto& dst = destination.AsRegisters();
+      ASSERT(dst.num_regs() == 1);
+      const auto dst_reg = dst.reg_at(0);
+      if (!sign_or_zero_extend) {
+        ASSERT(dst_size == 4);
+        __ movl(dst_reg, src_reg);
+      } else {
+        switch (src_type.AsFundamental().representation()) {
+          case compiler::ffi::kInt8:  // Sign extend operand.
+            __ movsxb(dst_reg, ByteRegisterOf(src_reg));
+            return;
+          case compiler::ffi::kInt16:
+            __ movsxw(dst_reg, src_reg);
+            return;
+          case compiler::ffi::kUint8:  // Zero extend operand.
+            __ movzxb(dst_reg, ByteRegisterOf(src_reg));
+            return;
+          case compiler::ffi::kUint16:
+            __ movzxw(dst_reg, src_reg);
+            return;
+          default:
+            // 32 to 64 bit is covered in IL by Representation conversions.
+            UNIMPLEMENTED();
+        }
+      }
+
+    } else if (destination.IsFpuRegisters()) {
+      // Fpu Registers should only contain doubles and registers only ints.
+      UNIMPLEMENTED();
+
+    } else {
+      ASSERT(destination.IsStack());
+      ASSERT(!sign_or_zero_extend);
+      const auto& dst = destination.AsStack();
+      const auto dst_addr = NativeLocationToStackSlotAddress(dst);
+      switch (dst_size) {
+        case 4:
+          __ movl(dst_addr, src_reg);
+          return;
+        case 2:
+          __ movw(dst_addr, src_reg);
+          return;
+        case 1:
+          __ movb(dst_addr, ByteRegisterOf(src_reg));
+          return;
+        default:
+          UNREACHABLE();
+      }
+    }
+
+  } else if (source.IsFpuRegisters()) {
+    const auto& src = source.AsFpuRegisters();
+    // We have not implemented conversions here, use IL convert instructions.
+    ASSERT(src_type.Equals(dst_type));
+
+    if (destination.IsRegisters()) {
+      // Fpu Registers should only contain doubles and registers only ints.
+      UNIMPLEMENTED();
+
+    } else if (destination.IsFpuRegisters()) {
+      const auto& dst = destination.AsFpuRegisters();
+      // Optimization manual recommends using MOVAPS for register
+      // to register moves.
+      __ movaps(dst.fpu_reg(), src.fpu_reg());
+
+    } else {
+      ASSERT(destination.IsStack());
+      ASSERT(src_type.IsFloat());
+      const auto& dst = destination.AsStack();
+      const auto dst_addr = NativeLocationToStackSlotAddress(dst);
+      switch (dst_size) {
+        case 8:
+          __ movsd(dst_addr, src.fpu_reg());
+          return;
+        case 4:
+          __ movss(dst_addr, src.fpu_reg());
+          return;
+        default:
+          UNREACHABLE();
+      }
+    }
+
+  } else {
+    ASSERT(source.IsStack());
+    const auto& src = source.AsStack();
+    const auto src_addr = NativeLocationToStackSlotAddress(src);
+    if (destination.IsRegisters()) {
+      const auto& dst = destination.AsRegisters();
+      ASSERT(dst.num_regs() == 1);
+      ASSERT(dst_size <= 4);
+      const auto dst_reg = dst.reg_at(0);
+      if (!sign_or_zero_extend) {
+        ASSERT(dst_size == 4);
+        __ movl(dst_reg, src_addr);
+      } else {
+        switch (src_type.AsFundamental().representation()) {
+          case compiler::ffi::kInt8:  // Sign extend operand.
+            __ movsxb(dst_reg, src_addr);
+            return;
+          case compiler::ffi::kInt16:
+            __ movsxw(dst_reg, src_addr);
+            return;
+          case compiler::ffi::kUint8:  // Zero extend operand.
+            __ movzxb(dst_reg, src_addr);
+            return;
+          case compiler::ffi::kUint16:
+            __ movzxw(dst_reg, src_addr);
+            return;
+          default:
+            // 32 to 64 bit is covered in IL by Representation conversions.
+            UNIMPLEMENTED();
+        }
+      }
+
+    } else if (destination.IsFpuRegisters()) {
+      ASSERT(src_type.Equals(dst_type));
+      ASSERT(src_type.IsFloat());
+      const auto& dst = destination.AsFpuRegisters();
+      switch (dst_size) {
+        case 8:
+          __ movsd(dst.fpu_reg(), src_addr);
+          return;
+        case 4:
+          __ movss(dst.fpu_reg(), src_addr);
+          return;
+        default:
+          UNREACHABLE();
+      }
+
+    } else {
+      ASSERT(destination.IsStack());
+      UNREACHABLE();
+    }
+  }
+}
+
 #undef __
 #define __ compiler_->assembler()->
 
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
index e4d639e..2c26964 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
@@ -9,9 +9,11 @@
 
 #include "vm/compiler/backend/il_printer.h"
 #include "vm/compiler/backend/locations.h"
+#include "vm/compiler/ffi/native_location.h"
 #include "vm/compiler/jit/compiler.h"
 #include "vm/dart_entry.h"
 #include "vm/deopt_instructions.h"
+#include "vm/dispatch_table.h"
 #include "vm/instructions.h"
 #include "vm/object_store.h"
 #include "vm/parser.h"
@@ -1207,6 +1209,22 @@
   __ Drop(count_with_type_args, RCX);
 }
 
+void FlowGraphCompiler::EmitDispatchTableCall(
+    Register cid_reg,
+    int32_t selector_offset,
+    const Array& arguments_descriptor) {
+  const Register table_reg = RAX;
+  ASSERT(cid_reg != table_reg);
+  ASSERT(cid_reg != ARGS_DESC_REG);
+  if (!arguments_descriptor.IsNull()) {
+    __ LoadObject(ARGS_DESC_REG, arguments_descriptor);
+  }
+  const intptr_t offset = (selector_offset - DispatchTable::OriginElement()) *
+                          compiler::target::kWordSize;
+  __ LoadDispatchTable(table_reg);
+  __ call(compiler::Address(table_reg, cid_reg, TIMES_8, offset));
+}
+
 Condition FlowGraphCompiler::EmitEqualityRegConstCompare(
     Register reg,
     const Object& obj,
@@ -1416,6 +1434,180 @@
   }
 }
 
+void FlowGraphCompiler::EmitNativeMoveArchitecture(
+    const compiler::ffi::NativeLocation& destination,
+    const compiler::ffi::NativeLocation& source) {
+  const auto& src_type = source.payload_type();
+  const auto& dst_type = destination.payload_type();
+  ASSERT(src_type.IsFloat() == dst_type.IsFloat());
+  ASSERT(src_type.IsInt() == dst_type.IsInt());
+  ASSERT(src_type.IsSigned() == dst_type.IsSigned());
+  ASSERT(src_type.IsFundamental());
+  ASSERT(dst_type.IsFundamental());
+  const intptr_t src_size = src_type.SizeInBytes();
+  const intptr_t dst_size = dst_type.SizeInBytes();
+  const bool sign_or_zero_extend = dst_size > src_size;
+
+  if (source.IsRegisters()) {
+    const auto& src = source.AsRegisters();
+    ASSERT(src.num_regs() == 1);
+    const auto src_reg = src.reg_at(0);
+
+    if (destination.IsRegisters()) {
+      const auto& dst = destination.AsRegisters();
+      ASSERT(dst.num_regs() == 1);
+      const auto dst_reg = dst.reg_at(0);
+      if (!sign_or_zero_extend) {
+        switch (dst_size) {
+          case 8:
+            __ movq(dst_reg, src_reg);
+            return;
+          case 4:
+            __ movl(dst_reg, src_reg);
+            return;
+          default:
+            UNIMPLEMENTED();
+        }
+      } else {
+        switch (src_type.AsFundamental().representation()) {
+          case compiler::ffi::kInt8:  // Sign extend operand.
+            __ movsxb(dst_reg, src_reg);
+            return;
+          case compiler::ffi::kInt16:
+            __ movsxw(dst_reg, src_reg);
+            return;
+          case compiler::ffi::kUint8:  // Zero extend operand.
+            __ movzxb(dst_reg, src_reg);
+            return;
+          case compiler::ffi::kUint16:
+            __ movzxw(dst_reg, src_reg);
+            return;
+          default:
+            // 32 to 64 bit is covered in IL by Representation conversions.
+            UNIMPLEMENTED();
+        }
+      }
+
+    } else if (destination.IsFpuRegisters()) {
+      // Fpu Registers should only contain doubles and registers only ints.
+      UNIMPLEMENTED();
+
+    } else {
+      ASSERT(destination.IsStack());
+      const auto& dst = destination.AsStack();
+      const auto dst_addr = NativeLocationToStackSlotAddress(dst);
+      ASSERT(!sign_or_zero_extend);
+      switch (dst_size) {
+        case 8:
+          __ movq(dst_addr, src_reg);
+          return;
+        case 4:
+          __ movl(dst_addr, src_reg);
+          return;
+        case 2:
+          __ movw(dst_addr, src_reg);
+          return;
+        case 1:
+          __ movb(dst_addr, src_reg);
+          return;
+        default:
+          UNREACHABLE();
+      }
+    }
+
+  } else if (source.IsFpuRegisters()) {
+    const auto& src = source.AsFpuRegisters();
+    // We have not implemented conversions here, use IL convert instructions.
+    ASSERT(src_type.Equals(dst_type));
+
+    if (destination.IsRegisters()) {
+      // Fpu Registers should only contain doubles and registers only ints.
+      UNIMPLEMENTED();
+
+    } else if (destination.IsFpuRegisters()) {
+      const auto& dst = destination.AsFpuRegisters();
+      // Optimization manual recommends using MOVAPS for register
+      // to register moves.
+      __ movaps(dst.fpu_reg(), src.fpu_reg());
+
+    } else {
+      ASSERT(destination.IsStack());
+      ASSERT(src_type.IsFloat());
+      const auto& dst = destination.AsStack();
+      const auto dst_addr = NativeLocationToStackSlotAddress(dst);
+      switch (dst_size) {
+        case 8:
+          __ movsd(dst_addr, src.fpu_reg());
+          return;
+        case 4:
+          __ movss(dst_addr, src.fpu_reg());
+          return;
+        default:
+          UNREACHABLE();
+      }
+    }
+
+  } else {
+    ASSERT(source.IsStack());
+    const auto& src = source.AsStack();
+    const auto src_addr = NativeLocationToStackSlotAddress(src);
+    if (destination.IsRegisters()) {
+      const auto& dst = destination.AsRegisters();
+      ASSERT(dst.num_regs() == 1);
+      const auto dst_reg = dst.reg_at(0);
+      if (!sign_or_zero_extend) {
+        switch (dst_size) {
+          case 8:
+            __ movq(dst_reg, src_addr);
+            return;
+          case 4:
+            __ movl(dst_reg, src_addr);
+            return;
+          default:
+            UNIMPLEMENTED();
+        }
+      } else {
+        switch (src_type.AsFundamental().representation()) {
+          case compiler::ffi::kInt8:  // Sign extend operand.
+            __ movsxb(dst_reg, src_addr);
+            return;
+          case compiler::ffi::kInt16:
+            __ movsxw(dst_reg, src_addr);
+            return;
+          case compiler::ffi::kUint8:  // Zero extend operand.
+            __ movzxb(dst_reg, src_addr);
+            return;
+          case compiler::ffi::kUint16:
+            __ movzxw(dst_reg, src_addr);
+            return;
+          default:
+            // 32 to 64 bit is covered in IL by Representation conversions.
+            UNIMPLEMENTED();
+        }
+      }
+
+    } else if (destination.IsFpuRegisters()) {
+      ASSERT(src_type.Equals(dst_type));
+      ASSERT(src_type.IsFloat());
+      const auto& dst = destination.AsFpuRegisters();
+      switch (dst_size) {
+        case 8:
+          __ movsd(dst.fpu_reg(), src_addr);
+          return;
+        case 4:
+          __ movss(dst.fpu_reg(), src_addr);
+          return;
+        default:
+          UNREACHABLE();
+      }
+
+    } else {
+      ASSERT(destination.IsStack());
+      UNREACHABLE();
+    }
+  }
+}
+
 #undef __
 #define __ compiler_->assembler()->
 
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 2e3ddcf..2fcc181 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -8,6 +8,7 @@
 
 #include "vm/bit_vector.h"
 #include "vm/bootstrap.h"
+#include "vm/compiler/aot/dispatch_table_generator.h"
 #include "vm/compiler/backend/code_statistics.h"
 #include "vm/compiler/backend/constant_propagator.h"
 #include "vm/compiler/backend/evaluator.h"
@@ -19,6 +20,7 @@
 #include "vm/compiler/ffi/frame_rebase.h"
 #include "vm/compiler/ffi/native_calling_convention.h"
 #include "vm/compiler/frontend/flow_graph_builder.h"
+#include "vm/compiler/frontend/kernel_translation_helper.h"
 #include "vm/compiler/jit/compiler.h"
 #include "vm/compiler/method_recognizer.h"
 #include "vm/cpu.h"
@@ -46,7 +48,6 @@
             two_args_smi_icd,
             true,
             "Generate special IC stubs for two args Smi operations");
-DECLARE_FLAG(bool, unbox_numeric_fields);
 
 class SubclassFinder {
  public:
@@ -386,7 +387,9 @@
     // arguments are not "dynamic" but instantiated-to-bounds.
     const Type& rare_type =
         Type::Handle(zone, Type::RawCast(type_class.RareType()));
-    if (!rare_type.IsEquivalent(type, /* syntactically = */ true)) {
+    // TODO(regis): Revisit the usage of TypeEquality::kSyntactical when
+    // implementing strong mode.
+    if (!rare_type.IsEquivalent(type, TypeEquality::kSyntactical)) {
       return false;
     }
   }
@@ -875,18 +878,19 @@
 }
 
 bool LoadFieldInstr::IsUnboxedLoad() const {
-  return FLAG_unbox_numeric_fields && slot().IsDartField() &&
+  return slot().IsDartField() &&
          FlowGraphCompiler::IsUnboxedField(slot().field());
 }
 
 bool LoadFieldInstr::IsPotentialUnboxedLoad() const {
-  return FLAG_unbox_numeric_fields && slot().IsDartField() &&
+  return slot().IsDartField() &&
          FlowGraphCompiler::IsPotentialUnboxedField(slot().field());
 }
 
 Representation LoadFieldInstr::representation() const {
   if (IsUnboxedLoad()) {
-    const intptr_t cid = slot().field().UnboxedFieldCid();
+    const Field& field = slot().field();
+    const intptr_t cid = field.UnboxedFieldCid();
     switch (cid) {
       case kDoubleCid:
         return kUnboxedDouble;
@@ -895,7 +899,11 @@
       case kFloat64x2Cid:
         return kUnboxedFloat64x2;
       default:
-        UNREACHABLE();
+        if (field.is_non_nullable_integer()) {
+          return kUnboxedInt64;
+        } else {
+          UNREACHABLE();
+        }
     }
   }
   return kTagged;
@@ -912,12 +920,12 @@
 }
 
 bool StoreInstanceFieldInstr::IsUnboxedStore() const {
-  return FLAG_unbox_numeric_fields && slot().IsDartField() &&
+  return slot().IsDartField() &&
          FlowGraphCompiler::IsUnboxedField(slot().field());
 }
 
 bool StoreInstanceFieldInstr::IsPotentialUnboxedStore() const {
-  return FLAG_unbox_numeric_fields && slot().IsDartField() &&
+  return slot().IsDartField() &&
          FlowGraphCompiler::IsPotentialUnboxedField(slot().field());
 }
 
@@ -925,7 +933,8 @@
     intptr_t index) const {
   ASSERT((index == 0) || (index == 1));
   if ((index == 1) && IsUnboxedStore()) {
-    const intptr_t cid = slot().field().UnboxedFieldCid();
+    const Field& field = slot().field();
+    const intptr_t cid = field.UnboxedFieldCid();
     switch (cid) {
       case kDoubleCid:
         return kUnboxedDouble;
@@ -934,7 +943,11 @@
       case kFloat64x2Cid:
         return kUnboxedFloat64x2;
       default:
-        UNREACHABLE();
+        if (field.is_non_nullable_integer()) {
+          return kUnboxedInt64;
+        } else {
+          UNREACHABLE();
+        }
     }
   }
   return kTagged;
@@ -3435,6 +3448,10 @@
 }
 
 Definition* LoadClassIdInstr::Canonicalize(FlowGraph* flow_graph) {
+  // TODO(dartbug.com/40188): Allow this to canonicalize into an untagged
+  // constant and make a subsequent DispatchTableCallInstr canonicalize into a
+  // StaticCall.
+  if (representation() == kUntagged) return this;
   const intptr_t cid = object()->Type()->ToCid();
   if (cid != kDynamicCid) {
     const auto& smi = Smi::ZoneHandle(flow_graph->zone(), Smi::New(cid));
@@ -3921,15 +3938,7 @@
   // [Intrinsify]).
   const Function& function = compiler->parsed_function().function();
 
-  // For functions which need an args descriptor the switchable call sites will
-  // transition directly to calling via a stub (and therefore never call the
-  // monomorphic entry).
-  //
-  // See runtime_entry.cc:DEFINE_RUNTIME_ENTRY(UnlinkedCall)
-  const bool needs_args_descriptor =
-      function.HasOptionalParameters() || function.IsGeneric();
-
-  if (function.IsDynamicFunction() && !needs_args_descriptor) {
+  if (function.NeedsMonomorphicCheckedEntry(compiler->zone())) {
     compiler->SpecialStatsBegin(CombinedCodeStatistics::kTagCheckedEntry);
     if (!FLAG_precompiled_mode) {
       __ MonomorphicCheckedEntryJIT();
@@ -4091,26 +4100,30 @@
   constexpr intptr_t kEntryFramePadding = 4;
   compiler::ffi::FrameRebase rebase(
       /*old_base=*/SPREG, /*new_base=*/FPREG,
-      -kExitLinkSlotFromEntryFp + kEntryFramePadding);
-  const Location dst = locs()->out(0);
-  const Location src = rebase.Rebase(loc_);
+      (-kExitLinkSlotFromEntryFp + kEntryFramePadding) *
+          compiler::target::kWordSize,
+      compiler->zone());
+  const auto& src =
+      rebase.Rebase(marshaller_.NativeLocationOfNativeParameter(index_));
   NoTemporaryAllocator no_temp;
-  compiler->EmitMove(dst, src, &no_temp);
+  const Location out_loc = locs()->out(0);
+  const Representation out_rep = representation();
+  compiler->EmitMoveFromNative(out_loc, out_rep, src, &no_temp);
 }
 
 LocationSummary* NativeParameterInstr::MakeLocationSummary(Zone* zone,
                                                            bool opt) const {
   ASSERT(opt);
-  Location input = Location::Any();
+  Location output = Location::Any();
   if (representation() == kUnboxedInt64 && compiler::target::kWordSize < 8) {
-    input = Location::Pair(Location::RequiresRegister(),
-                           Location::RequiresFpuRegister());
+    output = Location::Pair(Location::RequiresRegister(),
+                            Location::RequiresFpuRegister());
   } else {
-    input = RegisterKindForResult() == Location::kRegister
-                ? Location::RequiresRegister()
-                : Location::RequiresFpuRegister();
+    output = RegisterKindForResult() == Location::kRegister
+                 ? Location::RequiresRegister()
+                 : Location::RequiresFpuRegister();
   }
-  return LocationSummary::Make(zone, /*num_inputs=*/0, input,
+  return LocationSummary::Make(zone, /*num_inputs=*/0, output,
                                LocationSummary::kNoCall);
 }
 
@@ -4246,6 +4259,36 @@
   SetInputAt(1, right);
 }
 
+LocationSummary* LoadClassIdInstr::MakeLocationSummary(Zone* zone,
+                                                       bool opt) const {
+  const intptr_t kNumInputs = 1;
+  return LocationSummary::Make(zone, kNumInputs, Location::RequiresRegister(),
+                               LocationSummary::kNoCall);
+}
+
+void LoadClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  const Register object = locs()->in(0).reg();
+  const Register result = locs()->out(0).reg();
+  const AbstractType& value_type = *this->object()->Type()->ToAbstractType();
+  // Using NNBDMode::kLegacyLib is safe, because it throws a wider
+  // net over the types accepting a Smi value, especially during the nnbd
+  // migration that does not guarantee soundness.
+  if (input_can_be_smi_ &&
+      (CompileType::Smi().IsAssignableTo(NNBDMode::kLegacyLib, value_type) ||
+       value_type.IsTypeParameter())) {
+    if (representation() == kTagged) {
+      __ LoadTaggedClassIdMayBeSmi(result, object);
+    } else {
+      __ LoadClassIdMayBeSmi(result, object);
+    }
+  } else {
+    __ LoadClassId(result, object);
+    if (representation() == kTagged) {
+      __ SmiTag(result);
+    }
+  }
+}
+
 LocationSummary* InstanceCallInstr::MakeLocationSummary(Zone* zone,
                                                         bool optimizing) const {
   return MakeCallSummary(zone);
@@ -4384,6 +4427,41 @@
   return *binary_;
 }
 
+DispatchTableCallInstr* DispatchTableCallInstr::FromCall(
+    Zone* zone,
+    const InstanceCallBaseInstr* call,
+    Value* cid,
+    const compiler::TableSelector* selector) {
+  InputsArray* args = new (zone) InputsArray(zone, call->ArgumentCount() + 1);
+  for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
+    args->Add(call->ArgumentValueAt(i)->CopyWithType());
+  }
+  args->Add(cid);
+  auto dispatch_table_call = new (zone) DispatchTableCallInstr(
+      call->token_pos(), call->interface_target(), selector, args,
+      call->type_args_len(), call->argument_names());
+  if (call->has_inlining_id()) {
+    dispatch_table_call->set_inlining_id(call->inlining_id());
+  }
+  return dispatch_table_call;
+}
+
+void DispatchTableCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  Array& arguments_descriptor = Array::ZoneHandle();
+  if (selector()->requires_args_descriptor) {
+    ArgumentsInfo args_info(type_args_len(), ArgumentCount(), argument_names());
+    arguments_descriptor = args_info.ToArgumentsDescriptor();
+  }
+  const Register cid_reg = locs()->in(0).reg();
+  compiler->EmitDispatchTableCall(cid_reg, selector()->offset,
+                                  arguments_descriptor);
+  compiler->EmitCallsiteMetadata(token_pos(), DeoptId::kNone,
+                                 RawPcDescriptors::kOther, locs());
+  __ Drop(ArgumentCount());
+
+  compiler->AddDispatchTableCallTarget(selector());
+}
+
 const CallTargets& StaticCallInstr::Targets() {
   if (targets_ == nullptr) {
     Zone* zone = Thread::Current()->zone();
@@ -4541,6 +4619,12 @@
   return specialized;
 }
 
+Definition* DispatchTableCallInstr::Canonicalize(FlowGraph* flow_graph) {
+  // TODO(dartbug.com/40188): Allow this to canonicalize into a StaticCall when
+  // when input class id is constant;
+  return this;
+}
+
 Definition* PolymorphicInstanceCallInstr::Canonicalize(FlowGraph* flow_graph) {
   if (!IsSureToCallSingleRecognizedTarget()) {
     return this;
@@ -5395,7 +5479,7 @@
   if (idx == TargetAddressIndex()) {
     return kUnboxedFfiIntPtr;
   } else {
-    return arg_representations_[idx];
+    return marshaller_.RepInFfiCall(idx);
   }
 }
 
@@ -5429,61 +5513,71 @@
   summary->set_temp(2, Location::RegisterLocation(
                            CallingConventions::kSecondCalleeSavedCpuReg));
 #endif
-  summary->set_out(0, compiler::ffi::ResultLocation(
-                          compiler::ffi::ResultRepresentation(signature_)));
+  summary->set_out(0, marshaller_.LocInFfiCall(compiler::ffi::kResultIndex));
 
-  for (intptr_t i = 0, n = NativeArgCount(); i < n; ++i) {
-    // Floating point values are never split: they are either in a single "FPU"
-    // register or a contiguous 64-bit slot on the stack. Unboxed 64-bit integer
-    // values, in contrast, can be split between any two registers on a 32-bit
-    // system.
-    //
-    // There is an exception for iOS and Android 32-bit ARM, where
-    // floating-point values are treated as integers as far as the calling
-    // convention is concerned. However, the representation of these arguments
-    // are set to kUnboxedInt32 or kUnboxedInt64 already, so we don't have to
-    // account for that here.
-    const bool is_atomic = arg_representations_[i] == kUnboxedFloat ||
-                           arg_representations_[i] == kUnboxedDouble;
-
-    // Since we have to move this input down to the stack, there's no point in
-    // pinning it to any specific register.
-    summary->set_in(i, UnallocateStackSlots(arg_locations_[i], is_atomic));
+  for (intptr_t i = 0, n = marshaller_.num_args(); i < n; ++i) {
+    summary->set_in(i, marshaller_.LocInFfiCall(i));
   }
 
   return summary;
 }
 
-Location FfiCallInstr::UnallocateStackSlots(Location in, bool is_atomic) {
-  if (in.IsPairLocation()) {
-    ASSERT(!is_atomic);
-    return Location::Pair(UnallocateStackSlots(in.AsPairLocation()->At(0)),
-                          UnallocateStackSlots(in.AsPairLocation()->At(1)));
-  } else if (in.IsMachineRegister()) {
-    return in;
-  } else if (in.IsDoubleStackSlot()) {
-    return is_atomic ? Location::Any()
-                     : Location::Pair(Location::Any(), Location::Any());
-  } else {
-    ASSERT(in.IsStackSlot());
-    return Location::Any();
+void FfiCallInstr::EmitParamMoves(FlowGraphCompiler* compiler) {
+  const Register saved_fp = locs()->temp(0).reg();
+  const Register temp = locs()->temp(1).reg();
+
+  compiler::ffi::FrameRebase rebase(/*old_base=*/FPREG, /*new_base=*/saved_fp,
+                                    /*stack_delta=*/0, zone_);
+  for (intptr_t i = 0, n = NativeArgCount(); i < n; ++i) {
+    const Location origin = rebase.Rebase(locs()->in(i));
+    const Representation origin_rep = RequiredInputRepresentation(i);
+    const auto& target = marshaller_.Location(i);
+    ConstantTemporaryAllocator temp_alloc(temp);
+    if (origin.IsConstant()) {
+      compiler->EmitMoveConst(target, origin, origin_rep, &temp_alloc);
+    } else {
+      compiler->EmitMoveToNative(target, origin, origin_rep, &temp_alloc);
+    }
   }
 }
 
+void FfiCallInstr::EmitReturnMoves(FlowGraphCompiler* compiler) {
+  const auto& src = marshaller_.Location(compiler::ffi::kResultIndex);
+  if (src.payload_type().IsVoid()) {
+    return;
+  }
+  const Location dst_loc = locs()->out(0);
+  const Representation dst_type = representation();
+  NoTemporaryAllocator no_temp;
+  compiler->EmitMoveFromNative(dst_loc, dst_type, src, &no_temp);
+}
+
+void NativeReturnInstr::EmitReturnMoves(FlowGraphCompiler* compiler) {
+  const auto& dst = marshaller_.Location(compiler::ffi::kResultIndex);
+  if (dst.payload_type().IsVoid()) {
+    return;
+  }
+  const Location src_loc = locs()->in(0);
+  const Representation src_type = RequiredInputRepresentation(0);
+  NoTemporaryAllocator no_temp;
+  compiler->EmitMoveToNative(dst, src_loc, src_type, &no_temp);
+}
+
 LocationSummary* NativeReturnInstr::MakeLocationSummary(Zone* zone,
                                                         bool opt) const {
   const intptr_t kNumInputs = 1;
   const intptr_t kNumTemps = 0;
   LocationSummary* locs = new (zone)
       LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
-  locs->set_in(0, result_location_);
+  locs->set_in(
+      0, marshaller_.LocationOfNativeParameter(compiler::ffi::kResultIndex));
   return locs;
 }
 
 #undef Z
 
 Representation FfiCallInstr::representation() const {
-  return compiler::ffi::ResultRepresentation(signature_);
+  return marshaller_.RepInFfiCall(compiler::ffi::kResultIndex);
 }
 
 // SIMD
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index 4c6bd4e..202a0ce 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -13,6 +13,10 @@
 #include "vm/compiler/backend/locations.h"
 #include "vm/compiler/backend/slot.h"
 #include "vm/compiler/compiler_state.h"
+#include "vm/compiler/ffi/marshaller.h"
+#include "vm/compiler/ffi/native_calling_convention.h"
+#include "vm/compiler/ffi/native_location.h"
+#include "vm/compiler/ffi/native_type.h"
 #include "vm/compiler/method_recognizer.h"
 #include "vm/flags.h"
 #include "vm/growable_array.h"
@@ -55,6 +59,7 @@
 
 namespace compiler {
 class BlockBuilder;
+struct TableSelector;
 }
 
 class Value : public ZoneAllocated {
@@ -396,6 +401,7 @@
   M(FfiCall, _)                                                                \
   M(InstanceCall, _)                                                           \
   M(PolymorphicInstanceCall, _)                                                \
+  M(DispatchTableCall, _)                                                      \
   M(StaticCall, _)                                                             \
   M(LoadLocal, kNoGC)                                                          \
   M(DropTemps, kNoGC)                                                          \
@@ -490,7 +496,6 @@
   M(UnboxInt32, kNoGC)                                                         \
   M(IntConverter, _)                                                           \
   M(BitCast, _)                                                                \
-  M(UnboxedWidthExtender, _)                                                   \
   M(Deoptimize, kNoGC)                                                         \
   M(SimdOp, kNoGC)
 
@@ -1842,7 +1847,7 @@
 // NativeParameter instead (which doesn't count as an initial definition).
 class NativeEntryInstr : public FunctionEntryInstr {
  public:
-  NativeEntryInstr(const ZoneGrowableArray<Location>* argument_locations,
+  NativeEntryInstr(const compiler::ffi::CallbackMarshaller& marshaller,
                    GraphEntryInstr* graph_entry,
                    intptr_t block_id,
                    intptr_t try_index,
@@ -1850,17 +1855,18 @@
                    intptr_t callback_id)
       : FunctionEntryInstr(graph_entry, block_id, try_index, deopt_id),
         callback_id_(callback_id),
-        argument_locations_(argument_locations) {}
+        marshaller_(marshaller) {}
 
   DECLARE_INSTRUCTION(NativeEntry)
 
   PRINT_TO_SUPPORT
 
  private:
-  void SaveArgument(FlowGraphCompiler* compiler, Location loc) const;
+  void SaveArgument(FlowGraphCompiler* compiler,
+                    const compiler::ffi::NativeLocation& loc) const;
 
   const intptr_t callback_id_;
-  const ZoneGrowableArray<Location>* const argument_locations_;
+  const compiler::ffi::CallbackMarshaller& marshaller_;
 };
 
 // Represents an OSR entrypoint to a function.
@@ -2487,21 +2493,18 @@
 // TOOD(33549): Unify with ParameterInstr.
 class NativeParameterInstr : public Definition {
  public:
-  NativeParameterInstr(Location loc, Representation representation)
-      : loc_(loc), representation_(representation) {
-    if (loc.IsPairLocation()) {
-      for (intptr_t i : {0, 1}) {
-        ASSERT(loc_.Component(i).HasStackIndex() &&
-               loc_.Component(i).base_reg() == SPREG);
-      }
-    } else {
-      ASSERT(loc_.HasStackIndex() && loc_.base_reg() == SPREG);
-    }
+  NativeParameterInstr(const compiler::ffi::CallbackMarshaller& marshaller,
+                       intptr_t index)
+      : marshaller_(marshaller), index_(index) {
+    const auto& loc = marshaller.NativeLocationOfNativeParameter(index_);
+    ASSERT(loc.IsStack() && loc.AsStack().base_register() == SPREG);
   }
 
   DECLARE_INSTRUCTION(NativeParameter)
 
-  virtual Representation representation() const { return representation_; }
+  virtual Representation representation() const {
+    return marshaller_.RepInFfiCall(index_);
+  }
 
   intptr_t InputCount() const { return 0; }
   Value* InputAt(intptr_t i) const {
@@ -2523,8 +2526,8 @@
  private:
   virtual void RawSetInputAt(intptr_t i, Value* value) { UNREACHABLE(); }
 
-  const Location loc_;
-  const Representation representation_;
+  const compiler::ffi::CallbackMarshaller& marshaller_;
+  const intptr_t index_;
 
   DISALLOW_COPY_AND_ASSIGN(NativeParameterInstr);
 };
@@ -2763,12 +2766,9 @@
  public:
   NativeReturnInstr(TokenPosition token_pos,
                     Value* value,
-                    Representation rep,
-                    Location result_location,
+                    const compiler::ffi::CallbackMarshaller& marshaller,
                     intptr_t deopt_id)
-      : ReturnInstr(token_pos, value, deopt_id),
-        result_representation_(rep),
-        result_location_(result_location) {}
+      : ReturnInstr(token_pos, value, deopt_id), marshaller_(marshaller) {}
 
   DECLARE_INSTRUCTION(NativeReturn)
 
@@ -2776,7 +2776,7 @@
 
   virtual Representation RequiredInputRepresentation(intptr_t idx) const {
     ASSERT(idx == 0);
-    return result_representation_;
+    return marshaller_.RepInFfiCall(compiler::ffi::kResultIndex);
   }
 
   virtual bool CanBecomeDeoptimizationTarget() const {
@@ -2786,8 +2786,9 @@
   }
 
  private:
-  const Representation result_representation_;
-  const Location result_location_;
+  const compiler::ffi::CallbackMarshaller& marshaller_;
+
+  void EmitReturnMoves(FlowGraphCompiler* compiler);
 
   DISALLOW_COPY_AND_ASSIGN(NativeReturnInstr);
 };
@@ -3997,6 +3998,67 @@
   DISALLOW_COPY_AND_ASSIGN(PolymorphicInstanceCallInstr);
 };
 
+// Instance call using the global dispatch table.
+//
+// Takes untagged ClassId of the receiver as extra input.
+class DispatchTableCallInstr : public TemplateDartCall<1> {
+ public:
+  DispatchTableCallInstr(TokenPosition token_pos,
+                         const Function& interface_target,
+                         const compiler::TableSelector* selector,
+                         InputsArray* arguments,
+                         intptr_t type_args_len,
+                         const Array& argument_names)
+      : TemplateDartCall(DeoptId::kNone,
+                         type_args_len,
+                         argument_names,
+                         arguments,
+                         token_pos),
+        interface_target_(interface_target),
+        selector_(selector) {
+    ASSERT(selector != nullptr);
+    ASSERT(interface_target_.IsNotTemporaryScopedHandle());
+    ASSERT(!arguments->is_empty());
+  }
+
+  static DispatchTableCallInstr* FromCall(
+      Zone* zone,
+      const InstanceCallBaseInstr* call,
+      Value* cid,
+      const compiler::TableSelector* selector);
+
+  DECLARE_INSTRUCTION(DispatchTableCall)
+
+  const Function& interface_target() const { return interface_target_; }
+  const compiler::TableSelector* selector() const { return selector_; }
+
+  Value* class_id() const { return InputAt(InputCount() - 1); }
+
+  virtual Representation RequiredInputRepresentation(intptr_t idx) const {
+    return (idx == (InputCount() - 1)) ? kUntagged : kTagged;
+  }
+
+  virtual CompileType ComputeType() const;
+
+  virtual bool ComputeCanDeoptimize() const { return false; }
+
+  virtual Definition* Canonicalize(FlowGraph* flow_graph);
+
+  virtual bool CanBecomeDeoptimizationTarget() const { return false; }
+
+  virtual intptr_t DeoptimizationTarget() const { return DeoptId::kNone; }
+
+  virtual bool HasUnknownSideEffects() const { return true; }
+
+  PRINT_OPERANDS_TO_SUPPORT
+
+ private:
+  const Function& interface_target_;
+  const compiler::TableSelector* selector_;
+
+  DISALLOW_COPY_AND_ASSIGN(DispatchTableCallInstr);
+};
+
 class StrictCompareInstr : public TemplateComparison<2, NoThrow, Pure> {
  public:
   StrictCompareInstr(TokenPosition token_pos,
@@ -4679,17 +4741,12 @@
  public:
   FfiCallInstr(Zone* zone,
                intptr_t deopt_id,
-               const Function& signature,
-               const ZoneGrowableArray<Representation>& arg_reps,
-               const ZoneGrowableArray<Location>& arg_locs)
+               const compiler::ffi::CallMarshaller& marshaller)
       : Definition(deopt_id),
         zone_(zone),
-        signature_(signature),
-        inputs_(arg_reps.length() + 1),
-        arg_representations_(arg_reps),
-        arg_locations_(arg_locs) {
-    inputs_.FillWith(nullptr, 0, arg_reps.length() + 1);
-    ASSERT(signature.IsZoneHandle());
+        marshaller_(marshaller),
+        inputs_(marshaller.num_args() + 1) {
+    inputs_.FillWith(nullptr, 0, marshaller.num_args() + 1);
   }
 
   DECLARE_INSTRUCTION(FfiCall)
@@ -4726,16 +4783,13 @@
  private:
   virtual void RawSetInputAt(intptr_t i, Value* value) { inputs_[i] = value; }
 
-  // Mark stack slots in 'loc' as unallocated. Split a double-word stack slot
-  // into a pair location if 'is_atomic' is false.
-  static Location UnallocateStackSlots(Location loc, bool is_atomic = false);
+  void EmitParamMoves(FlowGraphCompiler* compiler);
+  void EmitReturnMoves(FlowGraphCompiler* compiler);
 
   Zone* const zone_;
-  const Function& signature_;
+  const compiler::ffi::CallMarshaller& marshaller_;
 
   GrowableArray<Value*> inputs_;
-  const ZoneGrowableArray<Representation>& arg_representations_;
-  const ZoneGrowableArray<Location>& arg_locations_;
 
   DISALLOW_COPY_AND_ASSIGN(FfiCallInstr);
 };
@@ -5802,9 +5856,15 @@
 
 class LoadClassIdInstr : public TemplateDefinition<1, NoThrow, Pure> {
  public:
-  explicit LoadClassIdInstr(Value* object) { SetInputAt(0, object); }
+  explicit LoadClassIdInstr(Value* object,
+                            Representation representation = kTagged,
+                            bool input_can_be_smi = true)
+      : representation_(representation), input_can_be_smi_(input_can_be_smi) {
+    ASSERT(representation == kTagged || representation == kUntagged);
+    SetInputAt(0, object);
+  }
 
-  virtual Representation representation() const { return kTagged; }
+  virtual Representation representation() const { return representation_; }
   DECLARE_INSTRUCTION(LoadClassId)
   virtual CompileType ComputeType() const;
 
@@ -5814,9 +5874,16 @@
 
   virtual bool ComputeCanDeoptimize() const { return false; }
 
-  virtual bool AttributesEqual(Instruction* other) const { return true; }
+  virtual bool AttributesEqual(Instruction* other) const {
+    auto other_load = other->AsLoadClassId();
+    return other_load->representation_ == representation_ &&
+           other_load->input_can_be_smi_ == input_can_be_smi_;
+  }
 
  private:
+  Representation representation_;
+  bool input_can_be_smi_;
+
   DISALLOW_COPY_AND_ASSIGN(LoadClassIdInstr);
 };
 
@@ -8319,74 +8386,6 @@
   DISALLOW_COPY_AND_ASSIGN(BitCastInstr);
 };
 
-// Sign- or zero-extends an integer in unboxed 32-bit representation.
-//
-// The choice between sign- and zero- extension is made based on the whether the
-// chosen representation is signed or unsigned.
-//
-// It is only supported to extend 1- or 2-byte operands; however, since we don't
-// have a representation less than 32-bits, both the input and output
-// representations are 32-bit (and equal).
-class UnboxedWidthExtenderInstr : public TemplateDefinition<1, NoThrow, Pure> {
- public:
-  UnboxedWidthExtenderInstr(Value* value,
-                            Representation rep,
-                            SmallRepresentation from_rep)
-      : TemplateDefinition(DeoptId::kNone),
-        representation_(rep),
-        from_representation_(from_rep) {
-    ASSERT((rep == kUnboxedInt32 && (from_rep == kSmallUnboxedInt8 ||
-                                     from_rep == kSmallUnboxedInt16)) ||
-           (rep == kUnboxedUint32 && (from_rep == kSmallUnboxedUint8 ||
-                                      from_rep == kSmallUnboxedUint16)));
-    SetInputAt(0, value);
-  }
-
-  Value* value() const { return inputs_[0]; }
-
-  Representation representation() const { return representation_; }
-
-  SmallRepresentation from_representation() const {
-    return from_representation_;
-  }
-
-  bool ComputeCanDeoptimize() const { return false; }
-
-  virtual Representation RequiredInputRepresentation(intptr_t idx) const {
-    ASSERT(idx == 0);
-    return representation_;
-  }
-
-  virtual bool AttributesEqual(Instruction* other) const {
-    ASSERT(other->IsUnboxedWidthExtender());
-    const UnboxedWidthExtenderInstr* ext = other->AsUnboxedWidthExtender();
-    return ext->representation() == representation() &&
-           ext->from_representation_ == from_representation_;
-  }
-
-  virtual CompileType ComputeType() const { return CompileType::Int(); }
-
-  DECLARE_INSTRUCTION(UnboxedWidthExtender);
-
-  PRINT_OPERANDS_TO_SUPPORT
-
- private:
-  intptr_t from_width_bytes() const {
-    if (from_representation_ == kSmallUnboxedInt8 ||
-        from_representation_ == kSmallUnboxedUint8) {
-      return 1;
-    }
-    ASSERT(from_representation_ == kSmallUnboxedInt16 ||
-           from_representation_ == kSmallUnboxedUint16);
-    return 2;
-  }
-
-  const Representation representation_;
-  const SmallRepresentation from_representation_;
-
-  DISALLOW_COPY_AND_ASSIGN(UnboxedWidthExtenderInstr);
-};
-
 // SimdOpInstr
 //
 // All SIMD intrinsics and recognized methods are represented via instances
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index 235b683..8ad3543 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -13,7 +13,6 @@
 #include "vm/compiler/backend/locations_helpers.h"
 #include "vm/compiler/backend/range_analysis.h"
 #include "vm/compiler/compiler_state.h"
-#include "vm/compiler/ffi/frame_rebase.h"
 #include "vm/compiler/ffi/native_calling_convention.h"
 #include "vm/compiler/jit/compiler.h"
 #include "vm/cpu.h"
@@ -362,6 +361,17 @@
   }
 }
 
+LocationSummary* DispatchTableCallInstr::MakeLocationSummary(Zone* zone,
+                                                             bool opt) const {
+  const intptr_t kNumInputs = 1;
+  const intptr_t kNumTemps = 0;
+  LocationSummary* summary = new (zone)
+      LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall);
+  summary->set_in(0, Location::RegisterLocation(R0));  // ClassId
+  summary->set_out(0, Location::RegisterLocation(R0));
+  return summary;
+}
+
 LocationSummary* ClosureCallInstr::MakeLocationSummary(Zone* zone,
                                                        bool opt) const {
   const intptr_t kNumInputs = 1;
@@ -1122,17 +1132,9 @@
   __ EnterDartFrame(0, /*load_pool_pointer=*/false);
 
   // Reserve space for arguments and align frame before entering C++ world.
-  __ ReserveAlignedFrameSpace(compiler::ffi::NumStackSlots(arg_locations_) *
-                              compiler::target::kWordSize);
+  __ ReserveAlignedFrameSpace(marshaller_.StackTopInBytes());
 
-  compiler::ffi::FrameRebase rebase(/*old_base=*/FPREG, /*new_base=*/saved_fp,
-                                    /*stack_delta=*/0);
-  for (intptr_t i = 0, n = NativeArgCount(); i < n; ++i) {
-    const Location origin = rebase.Rebase(locs()->in(i));
-    const Location target = arg_locations_[i];
-    ConstantTemporaryAllocator temp_alloc(temp);
-    compiler->EmitMove(target, origin, &temp_alloc);
-  }
+  EmitParamMoves(compiler);
 
   // We need to copy the return address up into the dummy stack frame so the
   // stack walker will know which safepoint to use.
@@ -1177,6 +1179,8 @@
                    THR, compiler::target::Thread::global_object_pool_offset()));
   }
 
+  EmitReturnMoves(compiler);
+
   // Leave dummy exit frame.
   __ LeaveDartFrame();
   __ set_constant_pool_allowed(true);
@@ -1186,6 +1190,8 @@
 }
 
 void NativeReturnInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  EmitReturnMoves(compiler);
+
   __ LeaveDartFrame();
 
   // The dummy return address is in LR, no need to pop it as on Intel.
@@ -1229,27 +1235,30 @@
   __ set_constant_pool_allowed(true);
 }
 
-void NativeEntryInstr::SaveArgument(FlowGraphCompiler* compiler,
-                                    Location loc) const {
-  if (loc.IsPairLocation()) {
+void NativeEntryInstr::SaveArgument(
+    FlowGraphCompiler* compiler,
+    const compiler::ffi::NativeLocation& nloc) const {
+  if (nloc.IsFpuRegisters()) {
+    auto const& fpu_loc = nloc.AsFpuRegisters();
+    ASSERT(fpu_loc.fpu_reg_kind() != compiler::ffi::kQuadFpuReg);
+    const intptr_t size = fpu_loc.payload_type().SizeInBytes();
+    // TODO(dartbug.com/40469): Reduce code size.
+    __ SubImmediate(SPREG, SPREG, 8);
+    if (size == 8) {
+      __ StoreDToOffset(fpu_loc.fpu_d_reg(), SPREG, 0);
+    } else {
+      ASSERT(size == 4);
+      __ StoreSToOffset(fpu_loc.fpu_s_reg(), SPREG, 0);
+    }
+
+  } else if (nloc.IsRegisters()) {
+    const auto& reg_loc = nloc.WidenTo4Bytes(compiler->zone()).AsRegisters();
+    const intptr_t num_regs = reg_loc.num_regs();
     // Save higher-order component first, so bytes are in little-endian layout
     // overall.
-    for (intptr_t i : {1, 0}) {
-      SaveArgument(compiler, loc.Component(i));
+    for (intptr_t i = num_regs - 1; i >= 0; i--) {
+      __ Push(reg_loc.reg_at(i));
     }
-    return;
-  }
-
-  if (loc.HasStackIndex()) return;
-
-  if (loc.IsRegister()) {
-    __ Push(loc.reg());
-  } else if (loc.IsFpuRegister()) {
-    const DRegister src = EvenDRegisterOf(loc.fpu_reg());
-    __ SubImmediateSetFlags(SPREG, SPREG, 8, AL);
-    __ StoreDToOffset(src, SPREG, 0);
-  } else {
-    UNREACHABLE();
   }
 }
 
@@ -1264,8 +1273,8 @@
   __ EnterFrame((1 << FP) | (1 << LR), 0);
 
   // Save the argument registers, in reverse order.
-  for (intptr_t i = argument_locations_->length(); i-- > 0;) {
-    SaveArgument(compiler, argument_locations_->At(i));
+  for (intptr_t i = marshaller_.num_args(); i-- > 0;) {
+    SaveArgument(compiler, marshaller_.Location(i));
   }
 
   // Enter the entry frame.
@@ -1485,29 +1494,6 @@
   __ StoreToOffset(kWord, value, obj, instr->offset_from_tagged());
 }
 
-LocationSummary* LoadClassIdInstr::MakeLocationSummary(Zone* zone,
-                                                       bool opt) const {
-  const intptr_t kNumInputs = 1;
-  return LocationSummary::Make(zone, kNumInputs, Location::RequiresRegister(),
-                               LocationSummary::kNoCall);
-}
-
-void LoadClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  const Register object = locs()->in(0).reg();
-  const Register result = locs()->out(0).reg();
-  const AbstractType& value_type = *this->object()->Type()->ToAbstractType();
-  // Using NNBDMode::kLegacyLib is safe, because it throws a wider
-  // net over the types accepting a Smi value, especially during the nnbd
-  // migration that does not guarantee soundness.
-  if (CompileType::Smi().IsAssignableTo(NNBDMode::kLegacyLib, value_type) ||
-      value_type.IsTypeParameter()) {
-    __ LoadTaggedClassIdMayBeSmi(result, object);
-  } else {
-    __ LoadClassId(result, object);
-    __ SmiTag(result);
-  }
-}
-
 Representation LoadIndexedInstr::representation() const {
   switch (class_id_) {
     case kArrayCid:
@@ -1617,8 +1603,7 @@
       (representation() == kUnboxedFloat64x2)) {
     if (class_id() == kTypedDataFloat32ArrayCid) {
       // Need register < Q7 for float operations.
-      // TODO(fschneider): Add a register policy to specify a subset of
-      // registers.
+      // TODO(30953): Support register range constraints in the regalloc.
       locs->set_out(0, Location::FpuRegisterLocation(Q6));
     } else {
       locs->set_out(0, Location::RequiresFpuRegister());
@@ -2561,14 +2546,21 @@
                                  : (IsPotentialUnboxedStore() ? 3 : 0));
   LocationSummary* summary = new (zone)
       LocationSummary(zone, kNumInputs, kNumTemps,
-                      ((IsUnboxedStore() && opt && is_initialization()) ||
-                       IsPotentialUnboxedStore())
+                      (!FLAG_precompiled_mode &&
+                       ((IsUnboxedStore() && opt && is_initialization()) ||
+                        IsPotentialUnboxedStore()))
                           ? LocationSummary::kCallOnSlowPath
                           : LocationSummary::kNoCall);
 
   summary->set_in(0, Location::RequiresRegister());
   if (IsUnboxedStore() && opt) {
-    summary->set_in(1, Location::RequiresFpuRegister());
+    if (slot().field().is_non_nullable_integer()) {
+      ASSERT(FLAG_precompiled_mode);
+      summary->set_in(1, Location::Pair(Location::RequiresRegister(),
+                                        Location::RequiresRegister()));
+    } else {
+      summary->set_in(1, Location::RequiresFpuRegister());
+    }
     if (!FLAG_precompiled_mode) {
       summary->set_temp(0, Location::RequiresRegister());
       summary->set_temp(1, Location::RequiresRegister());
@@ -2618,6 +2610,19 @@
   ASSERT(offset_in_bytes > 0);  // Field is finalized and points after header.
 
   if (IsUnboxedStore() && compiler->is_optimizing()) {
+    if (slot().field().is_non_nullable_integer()) {
+      const PairLocation* value_pair = locs()->in(1).AsPairLocation();
+      const Register value_lo = value_pair->At(0).reg();
+      const Register value_hi = value_pair->At(1).reg();
+      __ Comment("UnboxedIntegerStoreInstanceFieldInstr");
+      __ StoreToOffset(kWord, value_lo, instance_reg,
+                       offset_in_bytes - kHeapObjectTag);
+      __ StoreToOffset(
+          kWord, value_hi, instance_reg,
+          offset_in_bytes - kHeapObjectTag + compiler::target::kWordSize);
+      return;
+    }
+
     const intptr_t cid = slot().field().UnboxedFieldCid();
     const DRegister value = EvenDRegisterOf(locs()->in(1).fpu_reg());
 
@@ -3004,13 +3009,22 @@
     if (!FLAG_precompiled_mode) {
       locs->set_temp(0, Location::RequiresRegister());
     }
+    if (slot().field().is_non_nullable_integer()) {
+      ASSERT(FLAG_precompiled_mode);
+      locs->set_out(0, Location::Pair(Location::RequiresRegister(),
+                                      Location::RequiresRegister()));
+    } else {
+      locs->set_out(0, Location::RequiresFpuRegister());
+    }
   } else if (IsPotentialUnboxedLoad()) {
     locs->set_temp(0, opt ? Location::RequiresFpuRegister()
                           : Location::FpuRegisterLocation(Q1));
     locs->set_temp(1, Location::RequiresRegister());
     locs->set_temp(2, Location::RequiresRegister());
+    locs->set_out(0, Location::RequiresRegister());
+  } else {
+    locs->set_out(0, Location::RequiresRegister());
   }
-  locs->set_out(0, Location::RequiresRegister());
   return locs;
 }
 
@@ -3019,6 +3033,19 @@
 
   const Register instance_reg = locs()->in(0).reg();
   if (IsUnboxedLoad() && compiler->is_optimizing()) {
+    if (slot().field().is_non_nullable_integer()) {
+      const PairLocation* out_pair = locs()->out(0).AsPairLocation();
+      const Register out_lo = out_pair->At(0).reg();
+      const Register out_hi = out_pair->At(1).reg();
+      __ Comment("UnboxedIntegerLoadFieldInstr");
+      __ LoadFromOffset(kWord, out_lo, instance_reg,
+                        OffsetInBytes() - kHeapObjectTag);
+      __ LoadFromOffset(
+          kWord, out_hi, instance_reg,
+          OffsetInBytes() - kHeapObjectTag + compiler::target::kWordSize);
+      return;
+    }
+
     const intptr_t cid = slot().field().UnboxedFieldCid();
     const DRegister result = EvenDRegisterOf(locs()->out(0).fpu_reg());
 
@@ -4618,6 +4645,10 @@
                                        Location::RequiresRegister()));
   } else if (representation() == kUnboxedInt32) {
     summary->set_out(0, Location::RequiresRegister());
+  } else if (representation() == kUnboxedFloat) {
+    // Low (< Q7) Q registers are needed for the vcvtds and vmovs instructions.
+    // TODO(30953): Support register range constraints in the regalloc.
+    summary->set_out(0, Location::FpuRegisterLocation(Q6));
   } else {
     summary->set_out(0, Location::RequiresFpuRegister());
   }
@@ -4644,6 +4675,7 @@
     }
 
     case kUnboxedFloat: {
+      // Should only be <= Q7, because >= Q8 cannot be addressed as S register.
       const DRegister result = EvenDRegisterOf(locs()->out(0).fpu_reg());
       __ LoadDFromOffset(result, box, ValueOffset() - kHeapObjectTag);
       __ vcvtsd(EvenSRegisterOf(result), result);
@@ -7208,37 +7240,6 @@
   }
 }
 
-LocationSummary* UnboxedWidthExtenderInstr::MakeLocationSummary(
-    Zone* zone,
-    bool is_optimizing) const {
-  const intptr_t kNumTemps = 0;
-  LocationSummary* summary = new (zone)
-      LocationSummary(zone, /*num_inputs=*/InputCount(),
-                      /*num_temps=*/kNumTemps, LocationSummary::kNoCall);
-  summary->set_in(0, Location::RequiresRegister());
-  summary->set_out(0, Location::SameAsFirstInput());
-  return summary;
-}
-
-void UnboxedWidthExtenderInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  Register reg = locs()->in(0).reg();
-  // There are no builtin sign- or zero-extension instructions, so we'll have to
-  // use shifts instead.
-  const intptr_t shift_length =
-      (compiler::target::kWordSize - from_width_bytes()) * kBitsPerByte;
-  __ Lsl(reg, reg, compiler::Operand(shift_length));
-  switch (representation_) {
-    case kUnboxedInt32:  // Sign extend operand.
-      __ Asr(reg, reg, compiler::Operand(shift_length));
-      break;
-    case kUnboxedUint32:  // Zero extend operand.
-      __ Lsr(reg, reg, compiler::Operand(shift_length));
-      break;
-    default:
-      UNREACHABLE();
-  }
-}
-
 LocationSummary* BitCastInstr::MakeLocationSummary(Zone* zone, bool opt) const {
   LocationSummary* summary =
       new (zone) LocationSummary(zone, /*num_inputs=*/InputCount(),
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index 9894048..4ed71aa 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -12,7 +12,6 @@
 #include "vm/compiler/backend/locations.h"
 #include "vm/compiler/backend/locations_helpers.h"
 #include "vm/compiler/backend/range_analysis.h"
-#include "vm/compiler/ffi/frame_rebase.h"
 #include "vm/compiler/ffi/native_calling_convention.h"
 #include "vm/compiler/jit/compiler.h"
 #include "vm/dart_entry.h"
@@ -300,6 +299,17 @@
   }
 }
 
+LocationSummary* DispatchTableCallInstr::MakeLocationSummary(Zone* zone,
+                                                             bool opt) const {
+  const intptr_t kNumInputs = 1;
+  const intptr_t kNumTemps = 0;
+  LocationSummary* summary = new (zone)
+      LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall);
+  summary->set_in(0, Location::RegisterLocation(R0));  // ClassId
+  summary->set_out(0, Location::RegisterLocation(R0));
+  return summary;
+}
+
 LocationSummary* ClosureCallInstr::MakeLocationSummary(Zone* zone,
                                                        bool opt) const {
   const intptr_t kNumInputs = 1;
@@ -987,17 +997,9 @@
   __ EnterDartFrame(0, PP);
 
   // Make space for arguments and align the frame.
-  __ ReserveAlignedFrameSpace(compiler::ffi::NumStackSlots(arg_locations_) *
-                              kWordSize);
+  __ ReserveAlignedFrameSpace(marshaller_.StackTopInBytes());
 
-  compiler::ffi::FrameRebase rebase(/*old_base=*/FPREG, /*new_base=*/saved_fp,
-                                    /*stack_delta=*/0);
-  for (intptr_t i = 0, n = NativeArgCount(); i < n; ++i) {
-    const Location origin = rebase.Rebase(locs()->in(i));
-    const Location target = arg_locations_[i];
-    ConstantTemporaryAllocator temp_alloc(temp);
-    compiler->EmitMove(target, origin, &temp_alloc);
-  }
+  EmitParamMoves(compiler);
 
   // We need to copy a dummy return address up into the dummy stack frame so the
   // stack walker will know which safepoint to use.
@@ -1046,21 +1048,23 @@
   // Refresh pinned registers values (inc. write barrier mask and null object).
   __ RestorePinnedRegisters();
 
+  EmitReturnMoves(compiler);
+
   // Although PP is a callee-saved register, it may have been moved by the GC.
   __ LeaveDartFrame(compiler::kRestoreCallerPP);
 
   // Restore the global object pool after returning from runtime (old space is
   // moving, so the GOP could have been relocated).
   if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
-    __ ldr(PP, compiler::Address(THR, Thread::global_object_pool_offset()));
-    __ sub(PP, PP,
-           compiler::Operand(kHeapObjectTag));  // Pool in PP is untagged!
+    __ SetupGlobalPoolAndDispatchTable();
   }
 
   __ set_constant_pool_allowed(true);
 }
 
 void NativeReturnInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  EmitReturnMoves(compiler);
+
   __ LeaveDartFrame();
 
   // The dummy return address is in LR, no need to pop it as on Intel.
@@ -1106,16 +1110,17 @@
   __ set_constant_pool_allowed(true);
 }
 
-void NativeEntryInstr::SaveArgument(FlowGraphCompiler* compiler,
-                                    Location loc) const {
-  ASSERT(!loc.IsPairLocation());
+void NativeEntryInstr::SaveArgument(
+    FlowGraphCompiler* compiler,
+    const compiler::ffi::NativeLocation& nloc) const {
+  if (nloc.IsStack()) return;
 
-  if (loc.HasStackIndex()) return;
-
-  if (loc.IsRegister()) {
-    __ Push(loc.reg());
-  } else if (loc.IsFpuRegister()) {
-    __ PushDouble(loc.fpu_reg());
+  if (nloc.IsRegisters()) {
+    const auto& regs_loc = nloc.AsRegisters();
+    ASSERT(regs_loc.num_regs() == 1);
+    __ Push(regs_loc.reg_at(0));
+  } else if (nloc.IsFpuRegisters()) {
+    __ PushDouble(nloc.AsFpuRegisters().fpu_reg());
   } else {
     UNREACHABLE();
   }
@@ -1138,8 +1143,8 @@
   __ EnterFrame(0);
 
   // Save the argument registers, in reverse order.
-  for (intptr_t i = argument_locations_->length(); i-- > 0;) {
-    SaveArgument(compiler, argument_locations_->At(i));
+  for (intptr_t i = marshaller_.num_args(); i-- > 0;) {
+    SaveArgument(compiler, marshaller_.Location(i));
   }
 
   // Enter the entry frame.
@@ -1241,10 +1246,7 @@
   __ StoreToOffset(CODE_REG, FPREG,
                    kPcMarkerSlotFromFp * compiler::target::kWordSize);
   if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
-    __ ldr(PP, compiler::Address(
-                   THR, compiler::target::Thread::global_object_pool_offset()));
-    __ sub(PP, PP,
-           compiler::Operand(kHeapObjectTag));  // Pool in PP is untagged!
+    __ SetupGlobalPoolAndDispatchTable();
   } else {
     // We now load the pool pointer (PP) with a GC safe value as we are about to
     // invoke dart code. We don't need a real object pool here.
@@ -1353,29 +1355,6 @@
   __ StoreToOffset(value, obj, instr->offset_from_tagged());
 }
 
-LocationSummary* LoadClassIdInstr::MakeLocationSummary(Zone* zone,
-                                                       bool opt) const {
-  const intptr_t kNumInputs = 1;
-  return LocationSummary::Make(zone, kNumInputs, Location::RequiresRegister(),
-                               LocationSummary::kNoCall);
-}
-
-void LoadClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  const Register object = locs()->in(0).reg();
-  const Register result = locs()->out(0).reg();
-  const AbstractType& value_type = *this->object()->Type()->ToAbstractType();
-  // Using NNBDMode::kLegacyLib is safe, because it throws a wider
-  // net over the types accepting a Smi value, especially during the nnbd
-  // migration that does not guarantee soundness.
-  if (CompileType::Smi().IsAssignableTo(NNBDMode::kLegacyLib, value_type) ||
-      value_type.IsTypeParameter()) {
-    __ LoadTaggedClassIdMayBeSmi(result, object);
-  } else {
-    __ LoadClassId(result, object);
-    __ SmiTag(result);
-  }
-}
-
 Representation LoadIndexedInstr::representation() const {
   switch (class_id_) {
     case kArrayCid:
@@ -2163,14 +2142,20 @@
                                  : (IsPotentialUnboxedStore() ? 2 : 0);
   LocationSummary* summary = new (zone)
       LocationSummary(zone, kNumInputs, kNumTemps,
-                      ((IsUnboxedStore() && opt && is_initialization()) ||
-                       IsPotentialUnboxedStore())
+                      (!FLAG_precompiled_mode &&
+                       ((IsUnboxedStore() && opt && is_initialization()) ||
+                        IsPotentialUnboxedStore()))
                           ? LocationSummary::kCallOnSlowPath
                           : LocationSummary::kNoCall);
 
   summary->set_in(0, Location::RequiresRegister());
   if (IsUnboxedStore() && opt) {
-    summary->set_in(1, Location::RequiresFpuRegister());
+    if (slot().field().is_non_nullable_integer()) {
+      ASSERT(FLAG_precompiled_mode);
+      summary->set_in(1, Location::RequiresRegister());
+    } else {
+      summary->set_in(1, Location::RequiresFpuRegister());
+    }
     if (!FLAG_precompiled_mode) {
       summary->set_temp(0, Location::RequiresRegister());
       summary->set_temp(1, Location::RequiresRegister());
@@ -2197,6 +2182,13 @@
   ASSERT(offset_in_bytes > 0);  // Field is finalized and points after header.
 
   if (IsUnboxedStore() && compiler->is_optimizing()) {
+    if (slot().field().is_non_nullable_integer()) {
+      const Register value = locs()->in(1).reg();
+      __ Comment("UnboxedIntegerStoreInstanceFieldInstr");
+      __ StoreFieldToOffset(value, instance_reg, offset_in_bytes);
+      return;
+    }
+
     const VRegister value = locs()->in(1).fpu_reg();
     const intptr_t cid = slot().field().UnboxedFieldCid();
 
@@ -2571,10 +2563,18 @@
     if (!FLAG_precompiled_mode) {
       locs->set_temp(0, Location::RequiresRegister());
     }
+    if (slot().field().is_non_nullable_integer()) {
+      ASSERT(FLAG_precompiled_mode);
+      locs->set_out(0, Location::RequiresRegister());
+    } else {
+      locs->set_out(0, Location::RequiresFpuRegister());
+    }
   } else if (IsPotentialUnboxedLoad()) {
     locs->set_temp(0, Location::RequiresRegister());
+    locs->set_out(0, Location::RequiresRegister());
+  } else {
+    locs->set_out(0, Location::RequiresRegister());
   }
-  locs->set_out(0, Location::RequiresRegister());
   return locs;
 }
 
@@ -2582,6 +2582,13 @@
   ASSERT(sizeof(classid_t) == kInt16Size);
   const Register instance_reg = locs()->in(0).reg();
   if (IsUnboxedLoad() && compiler->is_optimizing()) {
+    if (slot().field().is_non_nullable_integer()) {
+      const Register result = locs()->out(0).reg();
+      __ Comment("UnboxedIntegerLoadFieldInstr");
+      __ LoadFieldFromOffset(result, instance_reg, OffsetInBytes());
+      return;
+    }
+
     const VRegister result = locs()->out(0).fpu_reg();
     const intptr_t cid = slot().field().UnboxedFieldCid();
 
@@ -6332,38 +6339,6 @@
   }
 }
 
-LocationSummary* UnboxedWidthExtenderInstr::MakeLocationSummary(
-    Zone* zone,
-    bool is_optimizing) const {
-  const intptr_t kNumTemps = 0;
-  LocationSummary* summary = new (zone)
-      LocationSummary(zone, /*num_inputs=*/InputCount(),
-                      /*num_temps=*/kNumTemps, LocationSummary::kNoCall);
-  summary->set_in(0, Location::RequiresRegister());
-  summary->set_out(0, Location::SameAsFirstInput());
-  return summary;
-}
-
-void UnboxedWidthExtenderInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  Register reg = locs()->in(0).reg();
-  switch (from_representation()) {
-    case kSmallUnboxedInt8:  // Sign extend operand.
-      __ sxtb(reg, reg);
-      break;
-    case kSmallUnboxedInt16:
-      __ sxth(reg, reg);
-      break;
-    case kSmallUnboxedUint8:  // Zero extend operand.
-      __ uxtb(reg, reg);
-      break;
-    case kSmallUnboxedUint16:
-      __ uxth(reg, reg);
-      break;
-    default:
-      UNREACHABLE();
-  }
-}
-
 LocationSummary* ThrowInstr::MakeLocationSummary(Zone* zone, bool opt) const {
   const intptr_t kNumInputs = 1;
   const intptr_t kNumTemps = 0;
diff --git a/runtime/vm/compiler/backend/il_ia32.cc b/runtime/vm/compiler/backend/il_ia32.cc
index 28a4d59..b272d58 100644
--- a/runtime/vm/compiler/backend/il_ia32.cc
+++ b/runtime/vm/compiler/backend/il_ia32.cc
@@ -13,7 +13,6 @@
 #include "vm/compiler/backend/locations.h"
 #include "vm/compiler/backend/locations_helpers.h"
 #include "vm/compiler/backend/range_analysis.h"
-#include "vm/compiler/ffi/frame_rebase.h"
 #include "vm/compiler/ffi/native_calling_convention.h"
 #include "vm/compiler/frontend/flow_graph_builder.h"
 #include "vm/compiler/jit/compiler.h"
@@ -142,9 +141,12 @@
 }
 
 void NativeReturnInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  EmitReturnMoves(compiler);
+
   bool return_in_st0 = false;
-  if (result_representation_ == kUnboxedFloat ||
-      result_representation_ == kUnboxedDouble) {
+  if (marshaller_.Location(compiler::ffi::kResultIndex)
+          .payload_type()
+          .IsFloat()) {
     ASSERT(locs()->in(0).IsFpuRegister() && locs()->in(0).fpu_reg() == XMM0);
     return_in_st0 = true;
   }
@@ -187,7 +189,9 @@
 
   // Move XMM0 into ST0 if needed.
   if (return_in_st0) {
-    if (result_representation_ == kUnboxedDouble) {
+    if (marshaller_.Location(compiler::ffi::kResultIndex)
+            .payload_type()
+            .SizeInBytes() == 8) {
       __ movsd(compiler::Address(SPREG, -8), XMM0);
       __ fldl(compiler::Address(SPREG, -8));
     } else {
@@ -938,21 +942,14 @@
 
   // We need to create a dummy "exit frame". It will have a null code object.
   __ LoadObject(CODE_REG, Object::null_object());
-  __ EnterDartFrame(compiler::ffi::NumStackSlots(arg_locations_) * kWordSize);
+  __ EnterDartFrame(marshaller_.StackTopInBytes());
 
   // Align frame before entering C++ world.
   if (OS::ActivationFrameAlignment() > 1) {
     __ andl(SPREG, compiler::Immediate(~(OS::ActivationFrameAlignment() - 1)));
   }
 
-  compiler::ffi::FrameRebase rebase(/*old_base=*/FPREG, /*new_base=*/saved_fp,
-                                    /*stack_delta=*/0);
-  for (intptr_t i = 0, n = NativeArgCount(); i < n; ++i) {
-    const Location origin = rebase.Rebase(locs()->in(i));
-    const Location target = arg_locations_[i];
-    ConstantTemporaryAllocator temp_alloc(temp);
-    compiler->EmitMove(target, origin, &temp_alloc);
-  }
+  EmitParamMoves(compiler);
 
   // We need to copy a dummy return address up into the dummy stack frame so the
   // stack walker will know which safepoint to use. Unlike X64, there's no
@@ -997,6 +994,8 @@
     __ movss(XMM0, compiler::Address(SPREG, -kFloatSize));
   }
 
+  EmitReturnMoves(compiler);
+
   // Leave dummy exit frame.
   __ LeaveFrame();
 
@@ -1004,27 +1003,11 @@
   __ popl(temp);
 }
 
-void NativeEntryInstr::SaveArgument(FlowGraphCompiler* compiler,
-                                    Location loc) const {
-  if (loc.IsPairLocation()) {
-    // Save the components in reverse order so that they will be in
-    // little-endian order on the stack.
-    for (intptr_t i : {1, 0}) {
-      SaveArgument(compiler, loc.Component(i));
-    }
-    return;
-  }
-
-  if (loc.HasStackIndex()) return;
-
-  if (loc.IsRegister()) {
-    __ pushl(loc.reg());
-  } else if (loc.IsFpuRegister()) {
-    __ subl(SPREG, compiler::Immediate(8));
-    __ movsd(compiler::Address(SPREG, 0), loc.fpu_reg());
-  } else {
-    UNREACHABLE();
-  }
+void NativeEntryInstr::SaveArgument(
+    FlowGraphCompiler* compiler,
+    const compiler::ffi::NativeLocation& nloc) const {
+  // IA32 has no arguments passed in registers.
+  UNREACHABLE();
 }
 
 void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
@@ -1223,40 +1206,6 @@
   __ movl(compiler::Address(obj, instr->offset_from_tagged()), value);
 }
 
-LocationSummary* LoadClassIdInstr::MakeLocationSummary(Zone* zone,
-                                                       bool opt) const {
-  const intptr_t kNumInputs = 1;
-  return LocationSummary::Make(zone, kNumInputs, Location::RequiresRegister(),
-                               LocationSummary::kNoCall);
-}
-
-void LoadClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  const Register object = locs()->in(0).reg();
-  const Register result = locs()->out(0).reg();
-  const AbstractType& value_type = *this->object()->Type()->ToAbstractType();
-  // Using NNBDMode::kLegacyLib is safe, because it throws a wider
-  // net over the types accepting a Smi value, especially during the nnbd
-  // migration that does not guarantee soundness.
-  if (CompileType::Smi().IsAssignableTo(NNBDMode::kLegacyLib, value_type) ||
-      value_type.IsTypeParameter()) {
-    // We don't use Assembler::LoadTaggedClassIdMayBeSmi() here---which uses
-    // a conditional move instead, and requires an additional register---because
-    // it is slower, probably due to branch prediction usually working just fine
-    // in this case.
-    ASSERT(result != object);
-    compiler::Label done;
-    __ movl(result, compiler::Immediate(kSmiCid << 1));
-    __ testl(object, compiler::Immediate(kSmiTagMask));
-    __ j(EQUAL, &done, compiler::Assembler::kNearJump);
-    __ LoadClassId(result, object);
-    __ SmiTag(result);
-    __ Bind(&done);
-  } else {
-    __ LoadClassId(result, object);
-    __ SmiTag(result);
-  }
-}
-
 Representation LoadIndexedInstr::representation() const {
   switch (class_id_) {
     case kArrayCid:
@@ -6284,37 +6233,6 @@
   }
 }
 
-LocationSummary* UnboxedWidthExtenderInstr::MakeLocationSummary(
-    Zone* zone,
-    bool is_optimizing) const {
-  const intptr_t kNumTemps = 0;
-  LocationSummary* summary = new (zone)
-      LocationSummary(zone, /*num_inputs=*/InputCount(),
-                      /*num_temps=*/kNumTemps, LocationSummary::kNoCall);
-  summary->set_in(0, Location::RegisterLocation(EAX));
-  summary->set_out(0, Location::RegisterLocation(EAX));
-  return summary;
-}
-
-void UnboxedWidthExtenderInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  switch (from_representation()) {
-    case kSmallUnboxedInt8:  // Sign extend operand.
-      __ movsxb(EAX, AL);
-      break;
-    case kSmallUnboxedInt16:
-      __ movsxw(EAX, EAX);
-      break;
-    case kSmallUnboxedUint8:  // Zero extend operand.
-      __ movzxb(EAX, AL);
-      break;
-    case kSmallUnboxedUint16:
-      __ movzxw(EAX, EAX);
-      break;
-    default:
-      UNREACHABLE();
-  }
-}
-
 LocationSummary* ThrowInstr::MakeLocationSummary(Zone* zone, bool opt) const {
   const intptr_t kNumInputs = 1;
   const intptr_t kNumTemps = 0;
@@ -6554,6 +6472,13 @@
   }
 }
 
+LocationSummary* DispatchTableCallInstr::MakeLocationSummary(Zone* zone,
+                                                             bool opt) const {
+  // Only generated with precompilation.
+  UNREACHABLE();
+  return NULL;
+}
+
 LocationSummary* ClosureCallInstr::MakeLocationSummary(Zone* zone,
                                                        bool opt) const {
   const intptr_t kNumInputs = 1;
diff --git a/runtime/vm/compiler/backend/il_printer.cc b/runtime/vm/compiler/backend/il_printer.cc
index 78b937e..f790556 100644
--- a/runtime/vm/compiler/backend/il_printer.cc
+++ b/runtime/vm/compiler/backend/il_printer.cc
@@ -6,6 +6,7 @@
 
 #include "vm/compiler/backend/il.h"
 #include "vm/compiler/backend/range_analysis.h"
+#include "vm/compiler/ffi/native_calling_convention.h"
 #include "vm/os.h"
 #include "vm/parser.h"
 
@@ -500,16 +501,6 @@
   }
 }
 
-void FfiCallInstr::PrintOperandsTo(BufferFormatter* f) const {
-  f->Print(" pointer=");
-  InputAt(TargetAddressIndex())->PrintTo(f);
-  for (intptr_t i = 0, n = InputCount(); i < n - 1; ++i) {
-    f->Print(", ");
-    InputAt(i)->PrintTo(f);
-    f->Print(" (@%s)", arg_locations_[i].ToCString());
-  }
-}
-
 void InstanceCallInstr::PrintOperandsTo(BufferFormatter* f) const {
   f->Print(" %s<%" Pd ">", function_name().ToCString(), type_args_len());
   for (intptr_t i = 0; i < ArgumentCount(); ++i) {
@@ -546,6 +537,18 @@
   }
 }
 
+void DispatchTableCallInstr::PrintOperandsTo(BufferFormatter* f) const {
+  const String& name =
+      String::Handle(interface_target().QualifiedUserVisibleName());
+  f->Print(" cid=");
+  class_id()->PrintTo(f);
+  f->Print(" %s<%" Pd ">", name.ToCString(), type_args_len());
+  for (intptr_t i = 0; i < ArgumentCount(); ++i) {
+    f->Print(", ");
+    ArgumentValueAt(i)->PrintTo(f);
+  }
+}
+
 void StrictCompareInstr::PrintOperandsTo(BufferFormatter* f) const {
   f->Print("%s, ", Token::Str(kind()));
   left()->PrintTo(f);
@@ -995,12 +998,6 @@
   Definition::PrintOperandsTo(f);
 }
 
-void UnboxedWidthExtenderInstr::PrintOperandsTo(BufferFormatter* f) const {
-  f->Print("%" Pd " -> 4 (%s), ", from_width_bytes(),
-           RepresentationToCString(representation()));
-  Definition::PrintOperandsTo(f);
-}
-
 void BitCastInstr::PrintOperandsTo(BufferFormatter* f) const {
   Definition::PrintOperandsTo(f);
   f->Print(" (%s -> %s)", RepresentationToCString(from()),
@@ -1074,13 +1071,31 @@
   }
 }
 
+void FfiCallInstr::PrintOperandsTo(BufferFormatter* f) const {
+  f->Print(" pointer=");
+  InputAt(TargetAddressIndex())->PrintTo(f);
+  for (intptr_t i = 0, n = InputCount(); i < n - 1; ++i) {
+    f->Print(", ");
+    InputAt(i)->PrintTo(f);
+    f->Print(" (@");
+    marshaller_.Location(i).PrintTo(f);
+    f->Print(")");
+  }
+}
+
 void NativeReturnInstr::PrintOperandsTo(BufferFormatter* f) const {
   value()->PrintTo(f);
+  f->Print(" (@");
+  marshaller_.Location(compiler::ffi::kResultIndex).PrintTo(f);
+  f->Print(")");
 }
 
 void NativeParameterInstr::PrintOperandsTo(BufferFormatter* f) const {
-  f->Print("%s as %s", loc_.ToCString(),
-           RepresentationToCString(representation_));
+  // Where the calling convention puts it.
+  marshaller_.Location(index_).PrintTo(f);
+  f->Print(" at ");
+  // Where the arguments are when pushed on the stack.
+  marshaller_.NativeLocationOfNativeParameter(index_).PrintTo(f);
 }
 
 void CatchBlockEntryInstr::PrintTo(BufferFormatter* f) const {
diff --git a/runtime/vm/compiler/backend/il_test_helper.cc b/runtime/vm/compiler/backend/il_test_helper.cc
index 82094ea..9f53b4b 100644
--- a/runtime/vm/compiler/backend/il_test_helper.cc
+++ b/runtime/vm/compiler/backend/il_test_helper.cc
@@ -61,6 +61,10 @@
 
 FlowGraph* TestPipeline::RunPasses(
     std::initializer_list<CompilerPass::Id> passes) {
+  // The table dispatch transformation needs a precompiler, which is not
+  // available in the test pipeline.
+  SetFlagScope<bool> sfs(&FLAG_use_table_dispatch, false);
+
   auto thread = Thread::Current();
   auto zone = thread->zone();
   const bool optimized = true;
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index 9af1adc..2a2f7de 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -13,7 +13,6 @@
 #include "vm/compiler/backend/locations.h"
 #include "vm/compiler/backend/locations_helpers.h"
 #include "vm/compiler/backend/range_analysis.h"
-#include "vm/compiler/ffi/frame_rebase.h"
 #include "vm/compiler/ffi/native_calling_convention.h"
 #include "vm/compiler/jit/compiler.h"
 #include "vm/dart_entry.h"
@@ -146,6 +145,8 @@
 }
 
 void NativeReturnInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  EmitReturnMoves(compiler);
+
   __ LeaveDartFrame();
 
   // Pop dummy return address.
@@ -935,7 +936,6 @@
 
 void FfiCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   const Register saved_fp = locs()->temp(0).reg();
-  const Register temp = locs()->temp(1).reg();
   const Register target_address = locs()->in(TargetAddressIndex()).reg();
 
   // Save frame pointer because we're going to update it when we enter the exit
@@ -949,22 +949,14 @@
   // but have a null code object.
   __ LoadObject(CODE_REG, Object::null_object());
   __ set_constant_pool_allowed(false);
-  __ EnterDartFrame(compiler::ffi::NumStackSlots(arg_locations_) * kWordSize,
-                    PP);
+  __ EnterDartFrame(marshaller_.StackTopInBytes(), PP);
 
   // Align frame before entering C++ world.
   if (OS::ActivationFrameAlignment() > 1) {
     __ andq(SPREG, compiler::Immediate(~(OS::ActivationFrameAlignment() - 1)));
   }
 
-  compiler::ffi::FrameRebase rebase(/*old_base=*/FPREG, /*new_base=*/saved_fp,
-                                    /*stack_delta=*/0);
-  for (intptr_t i = 0, n = NativeArgCount(); i < n; ++i) {
-    const Location origin = rebase.Rebase(locs()->in(i));
-    const Location target = arg_locations_[i];
-    ConstantTemporaryAllocator temp_alloc(temp);
-    compiler->EmitMove(target, rebase.Rebase(origin), &temp_alloc);
-  }
+  EmitParamMoves(compiler);
 
   // We need to copy a dummy return address up into the dummy stack frame so the
   // stack walker will know which safepoint to use. RIP points to the *next*
@@ -1000,6 +992,8 @@
     __ call(TMP);
   }
 
+  EmitReturnMoves(compiler);
+
   // Although PP is a callee-saved register, it may have been moved by the GC.
   __ LeaveDartFrame(compiler::kRestoreCallerPP);
 
@@ -1015,16 +1009,18 @@
   __ popq(TMP);
 }
 
-void NativeEntryInstr::SaveArgument(FlowGraphCompiler* compiler,
-                                    Location loc) const {
-  ASSERT(!loc.IsPairLocation());
+void NativeEntryInstr::SaveArgument(
+    FlowGraphCompiler* compiler,
+    const compiler::ffi::NativeLocation& nloc) const {
+  if (nloc.IsStack()) return;
 
-  if (loc.HasStackIndex()) return;
-
-  if (loc.IsRegister()) {
-    __ pushq(loc.reg());
-  } else if (loc.IsFpuRegister()) {
-    __ movq(TMP, loc.fpu_reg());
+  if (nloc.IsRegisters()) {
+    const auto& regs_loc = nloc.AsRegisters();
+    ASSERT(regs_loc.num_regs() == 1);
+    __ pushq(regs_loc.reg_at(0));
+  } else if (nloc.IsFpuRegisters()) {
+    // TODO(dartbug.com/40469): Reduce code size.
+    __ movq(TMP, nloc.AsFpuRegisters().fpu_reg());
     __ pushq(TMP);
   } else {
     UNREACHABLE();
@@ -1045,8 +1041,8 @@
 #endif
 
   // Save the argument registers, in reverse order.
-  for (intptr_t i = argument_locations_->length(); i-- > 0;) {
-    SaveArgument(compiler, argument_locations_->At(i));
+  for (intptr_t i = marshaller_.num_args(); i-- > 0;) {
+    SaveArgument(compiler, marshaller_.Location(i));
   }
 
   // Enter the entry frame. Push a dummy return address for consistency with
@@ -1274,40 +1270,6 @@
   __ movq(compiler::Address(obj, instr->offset_from_tagged()), value);
 }
 
-LocationSummary* LoadClassIdInstr::MakeLocationSummary(Zone* zone,
-                                                       bool opt) const {
-  const intptr_t kNumInputs = 1;
-  return LocationSummary::Make(zone, kNumInputs, Location::RequiresRegister(),
-                               LocationSummary::kNoCall);
-}
-
-void LoadClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  const Register object = locs()->in(0).reg();
-  const Register result = locs()->out(0).reg();
-  const AbstractType& value_type = *this->object()->Type()->ToAbstractType();
-  // Using NNBDMode::kLegacyLib is safe, because it throws a wider
-  // net over the types accepting a Smi value, especially during the nnbd
-  // migration that does not guarantee soundness.
-  if (CompileType::Smi().IsAssignableTo(NNBDMode::kLegacyLib, value_type) ||
-      value_type.IsTypeParameter()) {
-    // We don't use Assembler::LoadTaggedClassIdMayBeSmi() here---which uses
-    // a conditional move instead---because it is slower, probably due to
-    // branch prediction usually working just fine in this case.
-    compiler::Label load, done;
-    __ testq(object, compiler::Immediate(kSmiTagMask));
-    __ j(NOT_ZERO, &load, compiler::Assembler::kNearJump);
-    __ LoadImmediate(result, compiler::Immediate(Smi::RawValue(kSmiCid)));
-    __ jmp(&done);
-    __ Bind(&load);
-    __ LoadClassId(result, object);
-    __ SmiTag(result);
-    __ Bind(&done);
-  } else {
-    __ LoadClassId(result, object);
-    __ SmiTag(result);
-  }
-}
-
 class BoxAllocationSlowPath : public TemplateSlowPathCode<Instruction> {
  public:
   BoxAllocationSlowPath(Instruction* instruction,
@@ -2133,14 +2095,20 @@
                                  : (IsPotentialUnboxedStore() ? 3 : 0);
   LocationSummary* summary = new (zone)
       LocationSummary(zone, kNumInputs, kNumTemps,
-                      ((IsUnboxedStore() && opt && is_initialization()) ||
-                       IsPotentialUnboxedStore())
+                      (!FLAG_precompiled_mode &&
+                       ((IsUnboxedStore() && opt && is_initialization()) ||
+                        IsPotentialUnboxedStore()))
                           ? LocationSummary::kCallOnSlowPath
                           : LocationSummary::kNoCall);
 
   summary->set_in(0, Location::RequiresRegister());
   if (IsUnboxedStore() && opt) {
-    summary->set_in(1, Location::RequiresFpuRegister());
+    if (slot().field().is_non_nullable_integer()) {
+      ASSERT(FLAG_precompiled_mode);
+      summary->set_in(1, Location::RequiresRegister());
+    } else {
+      summary->set_in(1, Location::RequiresFpuRegister());
+    }
     if (!FLAG_precompiled_mode) {
       summary->set_temp(0, Location::RequiresRegister());
       summary->set_temp(1, Location::RequiresRegister());
@@ -2188,6 +2156,13 @@
   ASSERT(offset_in_bytes > 0);  // Field is finalized and points after header.
 
   if (IsUnboxedStore() && compiler->is_optimizing()) {
+    if (slot().field().is_non_nullable_integer()) {
+      const Register value = locs()->in(1).reg();
+      __ Comment("UnboxedIntegerStoreInstanceFieldInstr");
+      __ movq(compiler::FieldAddress(instance_reg, offset_in_bytes), value);
+      return;
+    }
+
     XmmRegister value = locs()->in(1).fpu_reg();
     const intptr_t cid = slot().field().UnboxedFieldCid();
 
@@ -2574,12 +2549,20 @@
     if (!FLAG_precompiled_mode) {
       locs->set_temp(0, Location::RequiresRegister());
     }
+    if (slot().field().is_non_nullable_integer()) {
+      ASSERT(FLAG_precompiled_mode);
+      locs->set_out(0, Location::RequiresRegister());
+    } else {
+      locs->set_out(0, Location::RequiresFpuRegister());
+    }
   } else if (IsPotentialUnboxedLoad()) {
     locs->set_temp(0, opt ? Location::RequiresFpuRegister()
                           : Location::FpuRegisterLocation(XMM1));
     locs->set_temp(1, Location::RequiresRegister());
+    locs->set_out(0, Location::RequiresRegister());
+  } else {
+    locs->set_out(0, Location::RequiresRegister());
   }
-  locs->set_out(0, Location::RequiresRegister());
   return locs;
 }
 
@@ -2587,6 +2570,13 @@
   ASSERT(sizeof(classid_t) == kInt16Size);
   Register instance_reg = locs()->in(0).reg();
   if (IsUnboxedLoad() && compiler->is_optimizing()) {
+    if (slot().field().is_non_nullable_integer()) {
+      const Register result = locs()->out(0).reg();
+      __ Comment("UnboxedIntegerLoadFieldInstr");
+      __ movq(result, compiler::FieldAddress(instance_reg, OffsetInBytes()));
+      return;
+    }
+
     XmmRegister result = locs()->out(0).fpu_reg();
     const intptr_t cid = slot().field().UnboxedFieldCid();
 
@@ -6585,37 +6575,6 @@
   }
 }
 
-LocationSummary* UnboxedWidthExtenderInstr::MakeLocationSummary(
-    Zone* zone,
-    bool is_optimizing) const {
-  const intptr_t kNumTemps = 0;
-  LocationSummary* summary = new (zone)
-      LocationSummary(zone, /*num_inputs=*/InputCount(),
-                      /*num_temps=*/kNumTemps, LocationSummary::kNoCall);
-  summary->set_in(0, Location::RegisterLocation(RAX));
-  summary->set_out(0, Location::RegisterLocation(RAX));
-  return summary;
-}
-
-void UnboxedWidthExtenderInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  switch (from_representation()) {
-    case kSmallUnboxedInt8:  // Sign extend operand.
-      __ movsxb(RAX, RAX);
-      break;
-    case kSmallUnboxedInt16:
-      __ movsxw(RAX, RAX);
-      break;
-    case kSmallUnboxedUint8:  // Zero extend operand.
-      __ movzxb(RAX, RAX);
-      break;
-    case kSmallUnboxedUint16:
-      __ movzxw(RAX, RAX);
-      break;
-    default:
-      UNREACHABLE();
-  }
-}
-
 LocationSummary* ThrowInstr::MakeLocationSummary(Zone* zone, bool opt) const {
   const intptr_t kNumInputs = 1;
   const intptr_t kNumTemps = 0;
@@ -6788,6 +6747,17 @@
   return true_condition;
 }
 
+LocationSummary* DispatchTableCallInstr::MakeLocationSummary(Zone* zone,
+                                                             bool opt) const {
+  const intptr_t kNumInputs = 1;
+  const intptr_t kNumTemps = 0;
+  LocationSummary* summary = new (zone)
+      LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall);
+  summary->set_in(0, Location::RegisterLocation(RCX));  // ClassId
+  summary->set_out(0, Location::RegisterLocation(RAX));
+  return summary;
+}
+
 LocationSummary* ClosureCallInstr::MakeLocationSummary(Zone* zone,
                                                        bool opt) const {
   const intptr_t kNumInputs = 1;
diff --git a/runtime/vm/compiler/backend/locations.cc b/runtime/vm/compiler/backend/locations.cc
index 1db7fd7..6cc94cf 100644
--- a/runtime/vm/compiler/backend/locations.cc
+++ b/runtime/vm/compiler/backend/locations.cc
@@ -70,28 +70,22 @@
   return summary;
 }
 
-template <class Register, class FpuRegister>
-TemplateLocation<Register, FpuRegister>
-TemplateLocation<Register, FpuRegister>::Pair(
-    TemplateLocation<Register, FpuRegister> first,
-    TemplateLocation<Register, FpuRegister> second) {
-  TemplatePairLocation<TemplateLocation<Register, FpuRegister>>* pair_location =
-      new TemplatePairLocation<TemplateLocation<Register, FpuRegister>>();
+Location Location::Pair(Location first, Location second) {
+  PairLocation* pair_location = new PairLocation();
   ASSERT((reinterpret_cast<intptr_t>(pair_location) & kLocationTagMask) == 0);
   pair_location->SetAt(0, first);
   pair_location->SetAt(1, second);
-  TemplateLocation<Register, FpuRegister> loc(
-      reinterpret_cast<uword>(pair_location) | kPairLocationTag);
+  Location loc(reinterpret_cast<uword>(pair_location) | kPairLocationTag);
   return loc;
 }
 
-template <class Register, class FpuRegister>
-TemplatePairLocation<TemplateLocation<Register, FpuRegister>>*
-TemplateLocation<Register, FpuRegister>::AsPairLocation() const {
+PairLocation* Location::AsPairLocation() const {
   ASSERT(IsPairLocation());
-  return reinterpret_cast<
-      TemplatePairLocation<TemplateLocation<Register, FpuRegister>>*>(
-      value_ & ~kLocationTagMask);
+  return reinterpret_cast<PairLocation*>(value_ & ~kLocationTagMask);
+}
+
+Location Location::Component(intptr_t i) const {
+  return AsPairLocation()->At(i);
 }
 
 Location LocationRegisterOrConstant(Value* value) {
@@ -145,18 +139,15 @@
   return compiler::Address(loc.base_reg(), loc.ToStackSlotOffset());
 }
 
-template <class Register, class FpuRegister>
-intptr_t TemplateLocation<Register, FpuRegister>::ToStackSlotOffset() const {
+intptr_t Location::ToStackSlotOffset() const {
   return stack_index() * compiler::target::kWordSize;
 }
 
-template <class Register, class FpuRegister>
-const Object& TemplateLocation<Register, FpuRegister>::constant() const {
+const Object& Location::constant() const {
   return constant_instruction()->value();
 }
 
-template <class Register, class FpuRegister>
-const char* TemplateLocation<Register, FpuRegister>::Name() const {
+const char* Location::Name() const {
   switch (kind()) {
     case kInvalid:
       return "?";
@@ -197,9 +188,7 @@
   return "?";
 }
 
-template <class Register, class FpuRegister>
-void TemplateLocation<Register, FpuRegister>::PrintTo(
-    BufferFormatter* f) const {
+void Location::PrintTo(BufferFormatter* f) const {
   if (!FLAG_support_il_printer) {
     return;
   }
@@ -220,16 +209,14 @@
   }
 }
 
-template <class Register, class FpuRegister>
-const char* TemplateLocation<Register, FpuRegister>::ToCString() const {
+const char* Location::ToCString() const {
   char buffer[1024];
   BufferFormatter bf(buffer, 1024);
   PrintTo(&bf);
   return Thread::Current()->zone()->MakeCopyOfString(buffer);
 }
 
-template <class Register, class FpuRegister>
-void TemplateLocation<Register, FpuRegister>::Print() const {
+void Location::Print() const {
   if (kind() == kStackSlot) {
     THR_Print("S%+" Pd "", stack_index());
   } else {
@@ -237,15 +224,12 @@
   }
 }
 
-template <class Register, class FpuRegister>
-TemplateLocation<Register, FpuRegister>
-TemplateLocation<Register, FpuRegister>::Copy() const {
+Location Location::Copy() const {
   if (IsPairLocation()) {
-    TemplatePairLocation<TemplateLocation<Register, FpuRegister>>* pair =
-        AsPairLocation();
+    PairLocation* pair = AsPairLocation();
     ASSERT(!pair->At(0).IsPairLocation());
     ASSERT(!pair->At(1).IsPairLocation());
-    return TemplateLocation::Pair(pair->At(0).Copy(), pair->At(1).Copy());
+    return Location::Pair(pair->At(0).Copy(), pair->At(1).Copy());
   } else {
     // Copy by value.
     return *this;
@@ -384,14 +368,6 @@
 }
 #endif
 
-template class TemplateLocation<dart::Register, dart::FpuRegister>;
-template class TemplatePairLocation<Location>;
-
-#if !defined(HOST_ARCH_EQUALS_TARGET_ARCH)
-template class TemplateLocation<dart::host::Register, dart::host::FpuRegister>;
-template class TemplatePairLocation<HostLocation>;
-#endif  // !defined(HOST_ARCH_EQUALS_TARGET_ARCH)
-
 }  // namespace dart
 
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/compiler/backend/locations.h b/runtime/vm/compiler/backend/locations.h
index c5c7174..da9cc2b 100644
--- a/runtime/vm/compiler/backend/locations.h
+++ b/runtime/vm/compiler/backend/locations.h
@@ -17,11 +17,9 @@
 class BufferFormatter;
 class ConstantInstr;
 class Definition;
+class PairLocation;
 class Value;
 
-template <class Location>
-class TemplatePairLocation;
-
 enum Representation {
   kNoRepresentation,
   kTagged,
@@ -38,16 +36,6 @@
   kNumRepresentations
 };
 
-// The representation of 8 and 16 bit integers in 32 bit. SmallRepresentation
-// tracks the real representation of these small integers.
-enum SmallRepresentation {
-  kNoSmallRepresentation,
-  kSmallUnboxedInt8,
-  kSmallUnboxedUint8,
-  kSmallUnboxedInt16,
-  kSmallUnboxedUint16,
-};
-
 // 'UnboxedFfiIntPtr' should be able to hold a pointer of the target word-size.
 // On a 32-bit platform, it's an unsigned 32-bit int because it should be
 // zero-extended to 64-bits, not sign-extended (pointers are inherently
@@ -76,8 +64,7 @@
 // are bitwise unequal then these two locations are guaranteed to be disjoint.
 // Properties like representation belong to the value that is stored in
 // the location not to the location itself.
-template <class Register, class FpuRegister>
-class TemplateLocation : public ValueObject {
+class Location : public ValueObject {
  private:
   enum {
     // Number of bits required to encode Kind value.
@@ -129,7 +116,7 @@
     kFpuRegister = 12,
   };
 
-  TemplateLocation() : value_(kInvalidLocation) {
+  Location() : value_(kInvalidLocation) {
     // Verify that non-tagged location kinds do not interfere with location tags
     // (kConstantTag and kPairLocationTag).
     COMPILE_ASSERT((kInvalid & kLocationTagMask) != kConstantTag);
@@ -161,10 +148,9 @@
     ASSERT(IsInvalid());
   }
 
-  TemplateLocation(const TemplateLocation& other)
-      : ValueObject(), value_(other.value_) {}
+  Location(const Location& other) : ValueObject(), value_(other.value_) {}
 
-  TemplateLocation& operator=(const TemplateLocation& other) {
+  Location& operator=(const Location& other) {
     value_ = other.value_;
     return *this;
   }
@@ -176,8 +162,8 @@
     return (value_ & kLocationTagMask) == kConstantTag;
   }
 
-  static TemplateLocation Constant(const ConstantInstr* obj) {
-    TemplateLocation loc(reinterpret_cast<uword>(obj) | kConstantTag);
+  static Location Constant(const ConstantInstr* obj) {
+    Location loc(reinterpret_cast<uword>(obj) | kConstantTag);
     ASSERT(obj == loc.constant_instruction());
     return loc;
   }
@@ -193,15 +179,12 @@
     return (value_ & kLocationTagMask) == kPairLocationTag;
   }
 
-  static TemplateLocation Pair(TemplateLocation first, TemplateLocation second);
+  static Location Pair(Location first, Location second);
 
-  TemplatePairLocation<TemplateLocation<Register, FpuRegister>>*
-  AsPairLocation() const;
+  PairLocation* AsPairLocation() const;
 
   // For pair locations, returns the ith component (for i in {0, 1}).
-  TemplateLocation<Register, FpuRegister> Component(intptr_t i) const {
-    return AsPairLocation()->At(i);
-  }
+  Location Component(intptr_t i) const;
 
   // Unallocated locations.
   enum Policy {
@@ -217,37 +200,37 @@
 
   bool IsRegisterBeneficial() { return !Equals(Any()); }
 
-  static TemplateLocation UnallocatedLocation(Policy policy) {
-    return TemplateLocation(kUnallocated, PolicyField::encode(policy));
+  static Location UnallocatedLocation(Policy policy) {
+    return Location(kUnallocated, PolicyField::encode(policy));
   }
 
   // Any free register is suitable to replace this unallocated location.
-  static TemplateLocation Any() { return UnallocatedLocation(kAny); }
+  static Location Any() { return UnallocatedLocation(kAny); }
 
-  static TemplateLocation PrefersRegister() {
+  static Location PrefersRegister() {
     return UnallocatedLocation(kPrefersRegister);
   }
 
-  static TemplateLocation RequiresRegister() {
+  static Location RequiresRegister() {
     return UnallocatedLocation(kRequiresRegister);
   }
 
-  static TemplateLocation RequiresFpuRegister() {
+  static Location RequiresFpuRegister() {
     return UnallocatedLocation(kRequiresFpuRegister);
   }
 
-  static TemplateLocation WritableRegister() {
+  static Location WritableRegister() {
     return UnallocatedLocation(kWritableRegister);
   }
 
   // The location of the first input to the instruction will be
   // used to replace this unallocated location.
-  static TemplateLocation SameAsFirstInput() {
+  static Location SameAsFirstInput() {
     return UnallocatedLocation(kSameAsFirstInput);
   }
 
   // Empty location. Used if there the location should be ignored.
-  static TemplateLocation NoLocation() { return TemplateLocation(); }
+  static Location NoLocation() { return Location(); }
 
   Policy policy() const {
     ASSERT(IsUnallocated());
@@ -255,8 +238,8 @@
   }
 
   // Register locations.
-  static TemplateLocation RegisterLocation(Register reg) {
-    return TemplateLocation(kRegister, reg);
+  static Location RegisterLocation(Register reg) {
+    return Location(kRegister, reg);
   }
 
   bool IsRegister() const { return kind() == kRegister; }
@@ -267,8 +250,8 @@
   }
 
   // FpuRegister locations.
-  static TemplateLocation FpuRegisterLocation(FpuRegister reg) {
-    return TemplateLocation(kFpuRegister, reg);
+  static Location FpuRegisterLocation(FpuRegister reg) {
+    return Location(kFpuRegister, reg);
   }
 
   bool IsFpuRegister() const { return kind() == kFpuRegister; }
@@ -282,7 +265,7 @@
     return (kind == kRegister) || (kind == kFpuRegister);
   }
 
-  static TemplateLocation MachineRegisterLocation(Kind kind, intptr_t reg) {
+  static Location MachineRegisterLocation(Kind kind, intptr_t reg) {
     if (kind == kRegister) {
       return RegisterLocation(static_cast<Register>(reg));
     } else {
@@ -304,10 +287,10 @@
     return static_cast<uword>(kStackIndexBias + stack_index);
   }
 
-  static TemplateLocation StackSlot(intptr_t stack_index, Register base) {
+  static Location StackSlot(intptr_t stack_index, Register base) {
     uword payload = StackSlotBaseField::encode(base) |
                     StackIndexField::encode(EncodeStackIndex(stack_index));
-    TemplateLocation loc(kStackSlot, payload);
+    Location loc(kStackSlot, payload);
     // Ensure that sign is preserved.
     ASSERT(loc.stack_index() == stack_index);
     return loc;
@@ -315,10 +298,10 @@
 
   bool IsStackSlot() const { return kind() == kStackSlot; }
 
-  static TemplateLocation DoubleStackSlot(intptr_t stack_index, Register base) {
+  static Location DoubleStackSlot(intptr_t stack_index, Register base) {
     uword payload = StackSlotBaseField::encode(base) |
                     StackIndexField::encode(EncodeStackIndex(stack_index));
-    TemplateLocation loc(kDoubleStackSlot, payload);
+    Location loc(kDoubleStackSlot, payload);
     // Ensure that sign is preserved.
     ASSERT(loc.stack_index() == stack_index);
     return loc;
@@ -326,10 +309,10 @@
 
   bool IsDoubleStackSlot() const { return kind() == kDoubleStackSlot; }
 
-  static TemplateLocation QuadStackSlot(intptr_t stack_index, Register base) {
+  static Location QuadStackSlot(intptr_t stack_index, Register base) {
     uword payload = StackSlotBaseField::encode(base) |
                     StackIndexField::encode(EncodeStackIndex(stack_index));
-    TemplateLocation loc(kQuadStackSlot, payload);
+    Location loc(kQuadStackSlot, payload);
     // Ensure that sign is preserved.
     ASSERT(loc.stack_index() == stack_index);
     return loc;
@@ -361,19 +344,19 @@
   const char* ToCString() const;
 
   // Compare two locations.
-  bool Equals(TemplateLocation other) const { return value_ == other.value_; }
+  bool Equals(Location other) const { return value_ == other.value_; }
 
   // If current location is constant might return something that
   // is not equal to any Kind.
   Kind kind() const { return KindField::decode(value_); }
 
-  TemplateLocation Copy() const;
+  Location Copy() const;
 
-  static TemplateLocation read(uword value) { return TemplateLocation(value); }
+  static Location read(uword value) { return Location(value); }
   uword write() const { return value_; }
 
  private:
-  explicit TemplateLocation(uword value) : value_(value) {}
+  explicit Location(uword value) : value_(value) {}
 
   void set_stack_index(intptr_t index) {
     ASSERT(HasStackIndex());
@@ -387,7 +370,7 @@
                                   value_);
   }
 
-  TemplateLocation(Kind kind, uword payload)
+  Location(Kind kind, uword payload)
       : value_(KindField::encode(kind) | PayloadField::encode(payload)) {}
 
   uword payload() const { return PayloadField::decode(value_); }
@@ -421,22 +404,8 @@
   // a constant locations. Values of enumeration Kind are selected in such a
   // way that none of them can be interpreted as a kConstant tag.
   uword value_;
-
-  // The following functions are only defined for Location, not for
-  // HostLocation, but they do need access to private fields or constructors.
-  friend TemplateLocation<dart::Register, dart::FpuRegister>
-  LocationArgumentsDescriptorLocation();
-  friend TemplateLocation<dart::Register, dart::FpuRegister>
-  LocationExceptionLocation();
-  friend TemplateLocation<dart::Register, dart::FpuRegister>
-  LocationStackTraceLocation();
 };
 
-using Location = TemplateLocation<dart::Register, dart::FpuRegister>;
-using HostLocation =
-    TemplateLocation<dart::host::Register, dart::host::FpuRegister>;
-
-// The following functions are only defined for Location, not for HostLocation.
 Location LocationArgumentsDescriptorLocation();
 Location LocationExceptionLocation();
 Location LocationStackTraceLocation();
@@ -456,10 +425,9 @@
 // Return a memory operand for stack slot locations.
 compiler::Address LocationToStackSlotAddress(Location loc);
 
-template <class Location>
-class TemplatePairLocation : public ZoneAllocated {
+class PairLocation : public ZoneAllocated {
  public:
-  TemplatePairLocation() {
+  PairLocation() {
     for (intptr_t i = 0; i < kPairLength; i++) {
       ASSERT(locations_[i].IsInvalid());
     }
@@ -490,9 +458,6 @@
   Location locations_[kPairLength];
 };
 
-using PairLocation = TemplatePairLocation<Location>;
-using HostPairLocation = TemplatePairLocation<HostLocation>;
-
 template <typename T>
 class SmallSet {
  public:
diff --git a/runtime/vm/compiler/backend/slot.cc b/runtime/vm/compiler/backend/slot.cc
index 00468cc..332b864 100644
--- a/runtime/vm/compiler/backend/slot.cc
+++ b/runtime/vm/compiler/backend/slot.cc
@@ -218,6 +218,10 @@
     used_guarded_state = false;
   }
 
+  if (field.is_non_nullable_integer()) {
+    is_nullable = false;
+  }
+
   const Slot& slot = SlotCache::Instance(thread).Canonicalize(Slot(
       Kind::kDartField,
       IsImmutableBit::encode(field.is_final() || field.is_const()) |
diff --git a/runtime/vm/compiler/backend/type_propagator.cc b/runtime/vm/compiler/backend/type_propagator.cc
index 6fd0603..15664f7 100644
--- a/runtime/vm/compiler/backend/type_propagator.cc
+++ b/runtime/vm/compiler/backend/type_propagator.cc
@@ -1311,6 +1311,19 @@
   return CompileType::Dynamic();
 }
 
+CompileType DispatchTableCallInstr::ComputeType() const {
+  // TODO(dartbug.com/40188): Share implementation with InstanceCallBaseInstr.
+  const Function& target = interface_target();
+  ASSERT(!target.IsNull());
+  const auto& result_type = AbstractType::ZoneHandle(target.result_type());
+  if (result_type.IsInstantiated()) {
+    TraceStrongModeType(this, result_type);
+    return CompileType::FromAbstractType(result_type);
+  }
+
+  return CompileType::Dynamic();
+}
+
 CompileType PolymorphicInstanceCallInstr::ComputeType() const {
   bool is_nullable = CompileType::kNullable;
   if (IsSureToCallSingleRecognizedTarget()) {
diff --git a/runtime/vm/compiler/call_specializer.cc b/runtime/vm/compiler/call_specializer.cc
index ac5f06e..adbd711 100644
--- a/runtime/vm/compiler/call_specializer.cc
+++ b/runtime/vm/compiler/call_specializer.cc
@@ -738,6 +738,10 @@
   if (field.needs_load_guard()) {
     return false;
   }
+  if (field.is_late()) {
+    // TODO(http://dartbug.com/40447): Inline implicit getters for late fields.
+    return false;
+  }
   if (should_clone_fields_) {
     field = field.CloneFromOriginal();
   }
@@ -1804,5 +1808,9 @@
   flow_graph_->InsertBefore(call, store, call->env(), FlowGraph::kEffect);
 }
 
+void CallSpecializer::ReplaceInstanceCallsWithDispatchTableCalls() {
+  // Only implemented for AOT.
+}
+
 }  // namespace dart
 #endif  // DART_PRECOMPILED_RUNTIME
diff --git a/runtime/vm/compiler/call_specializer.h b/runtime/vm/compiler/call_specializer.h
index bc8544d..56db54f 100644
--- a/runtime/vm/compiler/call_specializer.h
+++ b/runtime/vm/compiler/call_specializer.h
@@ -52,6 +52,8 @@
   // Use propagated class ids to optimize, replace or eliminate instructions.
   void ApplyClassIds();
 
+  virtual void ReplaceInstanceCallsWithDispatchTableCalls();
+
   void InsertBefore(Instruction* next,
                     Instruction* instr,
                     Environment* env,
diff --git a/runtime/vm/compiler/compiler_pass.cc b/runtime/vm/compiler/compiler_pass.cc
index 1142355..b13d72a 100644
--- a/runtime/vm/compiler/compiler_pass.cc
+++ b/runtime/vm/compiler/compiler_pass.cc
@@ -345,6 +345,7 @@
   INVOKE_PASS(TypePropagation);
   INVOKE_PASS(SelectRepresentations);
   INVOKE_PASS(Canonicalize);
+  INVOKE_PASS(UseTableDispatch);
   INVOKE_PASS(EliminateStackOverflowChecks);
   INVOKE_PASS(Canonicalize);
   INVOKE_PASS(AllocationSinking_DetachMaterializations);
@@ -440,6 +441,12 @@
   flow_graph->SelectRepresentations();
 });
 
+COMPILER_PASS(UseTableDispatch, {
+  if (FLAG_use_bare_instructions && FLAG_use_table_dispatch) {
+    state->call_specializer->ReplaceInstanceCallsWithDispatchTableCalls();
+  }
+});
+
 COMPILER_PASS_REPEAT(CSE, { return DominatorBasedCSE::Optimize(flow_graph); });
 
 COMPILER_PASS(LICM, {
diff --git a/runtime/vm/compiler/compiler_pass.h b/runtime/vm/compiler/compiler_pass.h
index a9d1f87..54570dd 100644
--- a/runtime/vm/compiler/compiler_pass.h
+++ b/runtime/vm/compiler/compiler_pass.h
@@ -48,6 +48,7 @@
   V(TryCatchOptimization)                                                      \
   V(TryOptimizePatterns)                                                       \
   V(TypePropagation)                                                           \
+  V(UseTableDispatch)                                                          \
   V(WidenSmiToInt32)                                                           \
   V(WriteBarrierElimination)
 
diff --git a/runtime/vm/compiler/compiler_sources.gni b/runtime/vm/compiler/compiler_sources.gni
index 961e877..b14ca03 100644
--- a/runtime/vm/compiler/compiler_sources.gni
+++ b/runtime/vm/compiler/compiler_sources.gni
@@ -7,6 +7,8 @@
 compiler_sources = [
   "aot/aot_call_specializer.cc",
   "aot/aot_call_specializer.h",
+  "aot/dispatch_table_generator.cc",
+  "aot/dispatch_table_generator.h",
   "aot/precompiler.cc",
   "aot/precompiler.h",
   "asm_intrinsifier.cc",
@@ -107,8 +109,10 @@
   "ffi/callback.h",
   "ffi/native_calling_convention.cc",
   "ffi/native_calling_convention.h",
-  "ffi/native_representation.cc",
-  "ffi/native_representation.h",
+  "ffi/native_location.cc",
+  "ffi/native_location.h",
+  "ffi/native_type.cc",
+  "ffi/native_type.h",
   "ffi/recognized_method.cc",
   "ffi/recognized_method.h",
   "frontend/base_flow_graph_builder.cc",
diff --git a/runtime/vm/compiler/ffi/README.md b/runtime/vm/compiler/ffi/README.md
new file mode 100644
index 0000000..b46637f
--- /dev/null
+++ b/runtime/vm/compiler/ffi/README.md
@@ -0,0 +1,15 @@
+The files in this folder have the following dependencies.
+Arrow means depends on, invert arrows for includes.
+
+```
+                           Call & CallbackMarshaller
+                                       ↓
+                           NativeCallingConvention
+                             ↓         ↓                (Interop with backend)
+                             ↓    NativeLocation     →  Location
+(Interop with frontend)      ↓         ↓
+AbstractType             ←  NativeType     →  Representation
+ClassId                  ←
+```
+
+The other files stand on themselves.
diff --git a/runtime/vm/compiler/ffi/frame_rebase.cc b/runtime/vm/compiler/ffi/frame_rebase.cc
index deef5ee..cc12a56 100644
--- a/runtime/vm/compiler/ffi/frame_rebase.cc
+++ b/runtime/vm/compiler/ffi/frame_rebase.cc
@@ -12,6 +12,16 @@
 
 namespace ffi {
 
+const NativeLocation& FrameRebase::Rebase(const NativeLocation& loc) const {
+  if (!loc.IsStack() || loc.AsStack().base_register() != old_base_) {
+    return loc;
+  }
+
+  return *new (zone_) NativeStackLocation(
+      loc.payload_type(), loc.container_type(), new_base_,
+      loc.AsStack().offset_in_bytes() + stack_delta_in_bytes_);
+}
+
 Location FrameRebase::Rebase(const Location loc) const {
   if (loc.IsPairLocation()) {
     return Location::Pair(Rebase(loc.Component(0)), Rebase(loc.Component(1)));
@@ -20,7 +30,8 @@
     return loc;
   }
 
-  const intptr_t new_stack_index = loc.stack_index() + stack_delta_;
+  const intptr_t new_stack_index =
+      loc.stack_index() + stack_delta_in_bytes_ / compiler::target::kWordSize;
   if (loc.IsStackSlot()) {
     return Location::StackSlot(new_stack_index, new_base_);
   }
diff --git a/runtime/vm/compiler/ffi/frame_rebase.h b/runtime/vm/compiler/ffi/frame_rebase.h
index be10aa7..33d8683 100644
--- a/runtime/vm/compiler/ffi/frame_rebase.h
+++ b/runtime/vm/compiler/ffi/frame_rebase.h
@@ -6,6 +6,8 @@
 #define RUNTIME_VM_COMPILER_FFI_FRAME_REBASE_H_
 
 #include "vm/compiler/backend/locations.h"
+#include "vm/compiler/ffi/native_location.h"
+#include "vm/compiler/ffi/native_type.h"
 #include "vm/compiler/runtime_api.h"
 #include "vm/thread.h"
 
@@ -20,20 +22,29 @@
 // frame manipulations.
 //
 // If the stack offset register matches 'old_base', it is changed to 'new_base'
-// and 'stack_delta' (# of slots) is applied.
+// and 'stack_delta_in_bytes' (# of bytes) is applied.
+//
+// This class can be used to rebase both Locations and NativeLocations.
 class FrameRebase : public ValueObject {
  public:
   FrameRebase(const Register old_base,
               const Register new_base,
-              intptr_t stack_delta)
-      : old_base_(old_base), new_base_(new_base), stack_delta_(stack_delta) {}
+              intptr_t stack_delta_in_bytes,
+              Zone* zone)
+      : old_base_(old_base),
+        new_base_(new_base),
+        stack_delta_in_bytes_(stack_delta_in_bytes),
+        zone_(zone) {}
+
+  const NativeLocation& Rebase(const NativeLocation& loc) const;
 
   Location Rebase(const Location loc) const;
 
  private:
   const Register old_base_;
   const Register new_base_;
-  const intptr_t stack_delta_;
+  const intptr_t stack_delta_in_bytes_;
+  Zone* zone_;
 };
 
 }  // namespace ffi
diff --git a/runtime/vm/compiler/ffi/marshaller.cc b/runtime/vm/compiler/ffi/marshaller.cc
index 758d1ad..53d1e21 100644
--- a/runtime/vm/compiler/ffi/marshaller.cc
+++ b/runtime/vm/compiler/ffi/marshaller.cc
@@ -5,6 +5,8 @@
 #include "vm/compiler/ffi/marshaller.h"
 
 #include "vm/compiler/ffi/frame_rebase.h"
+#include "vm/compiler/ffi/native_location.h"
+#include "vm/compiler/ffi/native_type.h"
 #include "vm/raw_object.h"
 #include "vm/stack_frame.h"
 #include "vm/symbols.h"
@@ -17,75 +19,141 @@
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
 
-ZoneGrowableArray<Location>*
-CallbackArgumentTranslator::TranslateArgumentLocations(
-    const ZoneGrowableArray<Location>& arg_locs) {
-  auto& pushed_locs = *(new ZoneGrowableArray<Location>(arg_locs.length()));
-
-  CallbackArgumentTranslator translator;
-  for (intptr_t i = 0, n = arg_locs.length(); i < n; i++) {
-    translator.AllocateArgument(arg_locs[i]);
-  }
-  for (intptr_t i = 0, n = arg_locs.length(); i < n; ++i) {
-    pushed_locs.Add(translator.TranslateArgument(arg_locs[i]));
+Location CallMarshaller::LocInFfiCall(intptr_t arg_index) const {
+  if (arg_index == kResultIndex) {
+    return Location(arg_index).AsLocation();
   }
 
-  return &pushed_locs;
-}
+  // Floating point values are never split: they are either in a single "FPU"
+  // register or a contiguous 64-bit slot on the stack. Unboxed 64-bit integer
+  // values, in contrast, can be split between any two registers on a 32-bit
+  // system.
+  //
+  // There is an exception for iOS and Android 32-bit ARM, where
+  // floating-point values are treated as integers as far as the calling
+  // convention is concerned. However, the representation of these arguments
+  // are set to kUnboxedInt32 or kUnboxedInt64 already, so we don't have to
+  // account for that here.
+  const bool is_atomic = RepInFfiCall(arg_index) == kUnboxedDouble ||
+                         RepInFfiCall(arg_index) == kUnboxedFloat;
 
-void CallbackArgumentTranslator::AllocateArgument(Location arg) {
-  if (arg.IsPairLocation()) {
-    AllocateArgument(arg.Component(0));
-    AllocateArgument(arg.Component(1));
-    return;
-  }
-  if (arg.HasStackIndex()) return;
-  ASSERT(arg.IsRegister() || arg.IsFpuRegister());
-  if (arg.IsRegister()) {
-    argument_slots_required_++;
-  } else {
-    argument_slots_required_ += 8 / target::kWordSize;
-  }
-}
-
-Location CallbackArgumentTranslator::TranslateArgument(Location arg) {
-  if (arg.IsPairLocation()) {
-    const Location low = TranslateArgument(arg.Component(0));
-    const Location high = TranslateArgument(arg.Component(1));
-    return Location::Pair(low, high);
-  }
-
-  if (arg.HasStackIndex()) {
-    // Add extra slots after the saved arguments for the return address and
-    // frame pointer of the dummy arguments frame, which will be between the
-    // saved argument registers and stack arguments. Also add slots for the
-    // shadow space if present (factored into
-    // kCallbackSlotsBeforeSavedArguments).
-    //
-    // Finally, if we are using NativeCallbackTrampolines, factor in the extra
-    // stack space corresponding to those trampolines' frames (above the entry
-    // frame).
-    intptr_t stack_delta = kCallbackSlotsBeforeSavedArguments;
-    if (NativeCallbackTrampolines::Enabled()) {
-      stack_delta += StubCodeCompiler::kNativeCallbackTrampolineStackDelta;
+  const NativeLocation& loc = this->Location(arg_index);
+  // Don't pin stack locations, they need to be moved anyway.
+  if (loc.IsStack()) {
+    if (loc.payload_type().SizeInBytes() == 2 * compiler::target::kWordSize &&
+        !is_atomic) {
+      return Location::Pair(Location::Any(), Location::Any());
     }
-    FrameRebase rebase(
-        /*old_base=*/SPREG, /*new_base=*/SPREG,
-        /*stack_delta=*/argument_slots_required_ + stack_delta);
-    return rebase.Rebase(arg);
+    return Location::Any();
   }
 
-  if (arg.IsRegister()) {
-    return Location::StackSlot(argument_slots_used_++, SPREG);
+#if defined(TARGET_ARCH_ARM)
+  // Only pin FPU register if it is the lowest bits.
+  if (loc.IsFpuRegisters()) {
+    const auto& fpu_loc = loc.AsFpuRegisters();
+    if (fpu_loc.IsLowestBits()) {
+      return fpu_loc.WidenToQFpuRegister(zone_).AsLocation();
+    }
+    return Location::Any();
   }
+#endif  // defined(TARGET_ARCH_ARM)
 
-  ASSERT(arg.IsFpuRegister());
-  const Location result =
-      Location::DoubleStackSlot(argument_slots_used_, SPREG);
-  argument_slots_used_ += 8 / target::kWordSize;
-  return result;
+  return loc.AsLocation();
 }
 
+// This classes translates the ABI location of arguments into the locations they
+// will inhabit after entry-frame setup in the invocation of a native callback.
+//
+// Native -> Dart callbacks must push all the arguments before executing any
+// Dart code because the reading the Thread from TLS requires calling a native
+// stub, and the argument registers are volatile on all ABIs we support.
+//
+// To avoid complicating initial definitions, all callback arguments are read
+// off the stack from their pushed locations, so this class updates the argument
+// positions to account for this.
+//
+// See 'NativeEntryInstr::EmitNativeCode' for details.
+class CallbackArgumentTranslator : public ValueObject {
+ public:
+  static NativeLocations& TranslateArgumentLocations(
+      const NativeLocations& arg_locs,
+      Zone* zone) {
+    auto& pushed_locs = *(new NativeLocations(arg_locs.length()));
+
+    CallbackArgumentTranslator translator;
+    for (intptr_t i = 0, n = arg_locs.length(); i < n; i++) {
+      translator.AllocateArgument(*arg_locs[i]);
+    }
+    for (intptr_t i = 0, n = arg_locs.length(); i < n; ++i) {
+      pushed_locs.Add(&translator.TranslateArgument(*arg_locs[i], zone));
+    }
+
+    return pushed_locs;
+  }
+
+ private:
+  void AllocateArgument(const NativeLocation& arg) {
+    if (arg.IsStack()) return;
+
+    ASSERT(arg.IsRegisters() || arg.IsFpuRegisters());
+    if (arg.IsRegisters()) {
+      argument_slots_required_ += arg.AsRegisters().num_regs();
+    } else {
+      argument_slots_required_ += 8 / target::kWordSize;
+    }
+  }
+
+  const NativeLocation& TranslateArgument(const NativeLocation& arg,
+                                          Zone* zone) {
+    if (arg.IsStack()) {
+      // Add extra slots after the saved arguments for the return address and
+      // frame pointer of the dummy arguments frame, which will be between the
+      // saved argument registers and stack arguments. Also add slots for the
+      // shadow space if present (factored into
+      // kCallbackSlotsBeforeSavedArguments).
+      //
+      // Finally, if we are using NativeCallbackTrampolines, factor in the extra
+      // stack space corresponding to those trampolines' frames (above the entry
+      // frame).
+      intptr_t stack_delta = kCallbackSlotsBeforeSavedArguments;
+      if (NativeCallbackTrampolines::Enabled()) {
+        stack_delta += StubCodeCompiler::kNativeCallbackTrampolineStackDelta;
+      }
+      FrameRebase rebase(
+          /*old_base=*/SPREG, /*new_base=*/SPREG,
+          /*stack_delta=*/(argument_slots_required_ + stack_delta) *
+              compiler::target::kWordSize,
+          zone);
+      return rebase.Rebase(arg);
+    }
+
+    if (arg.IsRegisters()) {
+      const auto& result = *new (zone) NativeStackLocation(
+          arg.payload_type(), arg.container_type(), SPREG,
+          argument_slots_used_ * compiler::target::kWordSize);
+      argument_slots_used_ += arg.AsRegisters().num_regs();
+      return result;
+    }
+
+    ASSERT(arg.IsFpuRegisters());
+    const auto& result = *new (zone) NativeStackLocation(
+        arg.payload_type(), arg.container_type(), SPREG,
+        argument_slots_used_ * compiler::target::kWordSize);
+    argument_slots_used_ += 8 / target::kWordSize;
+    return result;
+  }
+
+  intptr_t argument_slots_used_ = 0;
+  intptr_t argument_slots_required_ = 0;
+};
+
+CallbackMarshaller::CallbackMarshaller(Zone* zone,
+                                       const Function& dart_signature)
+    : BaseMarshaller(zone, dart_signature),
+      callback_locs_(
+          CallbackArgumentTranslator::TranslateArgumentLocations(arg_locs_,
+                                                                 zone_)) {}
+
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
 
 }  // namespace ffi
diff --git a/runtime/vm/compiler/ffi/marshaller.h b/runtime/vm/compiler/ffi/marshaller.h
index de85c2c..19009bb 100644
--- a/runtime/vm/compiler/ffi/marshaller.h
+++ b/runtime/vm/compiler/ffi/marshaller.h
@@ -10,6 +10,8 @@
 #include "vm/compiler/backend/locations.h"
 #include "vm/compiler/ffi/callback.h"
 #include "vm/compiler/ffi/native_calling_convention.h"
+#include "vm/compiler/ffi/native_location.h"
+#include "vm/compiler/ffi/native_type.h"
 #include "vm/object.h"
 
 namespace dart {
@@ -18,29 +20,102 @@
 
 namespace ffi {
 
-// This classes translates the ABI location of arguments into the locations they
-// will inhabit after entry-frame setup in the invocation of a native callback.
+// Provides the mapping from the native calling convention to the Dart calling
+// convention.
 //
-// Native -> Dart callbacks must push all the arguments before executing any
-// Dart code because the reading the Thread from TLS requires calling a native
-// stub, and the argument registers are volatile on all ABIs we support.
+// This class is set up in a query-able way so that it's underlying logic can
+// be extended to support more native ABI features and calling conventions.
 //
-// To avoid complicating initial definitions, all callback arguments are read
-// off the stack from their pushed locations, so this class updates the argument
-// positions to account for this.
-//
-// See 'NativeEntryInstr::EmitNativeCode' for details.
-class CallbackArgumentTranslator : public ValueObject {
+// TODO(36730): Add a way to query arguments that are broken into multiple
+// parts.
+class BaseMarshaller : public NativeCallingConvention {
  public:
-  static ZoneGrowableArray<Location>* TranslateArgumentLocations(
-      const ZoneGrowableArray<Location>& arg_locs);
+  // Unboxed representation on how the value is passed or received from regular
+  // Dart code.
+  Representation RepInDart(intptr_t arg_index) const {
+    return Location(arg_index).payload_type().AsRepresentationOverApprox(zone_);
+  }
+
+  // Representation on how the value is passed to or recieved from the FfiCall
+  // instruction or StaticCall, NativeParameter, and NativeReturn instructions.
+  Representation RepInFfiCall(intptr_t arg_index) const {
+    if (Location(arg_index).container_type().IsInt() &&
+        Location(arg_index).payload_type().IsFloat()) {
+      return Location(arg_index).container_type().AsRepresentationOverApprox(
+          zone_);
+    }
+    return Location(arg_index).payload_type().AsRepresentationOverApprox(zone_);
+  }
+
+  // Bitcasting floats to ints, only required in SoftFP.
+  bool RequiresBitCast(intptr_t index) const {
+    return Location(index).payload_type().IsFloat() &&
+           Location(index).container_type().IsInt();
+  }
+
+  // 8 or 16 bit int value to sign extend from.
+  const NativeType& SignExtendFrom(intptr_t arg_index) const {
+    return Location(arg_index).payload_type();
+  }
+
+  // Requires boxing or unboxing.
+  bool IsPointer(intptr_t arg_index) const {
+    return AbstractType::Handle(zone_, CType(arg_index)).type_class_id() ==
+           kFfiPointerCid;
+  }
+
+  // Treated as a null constant in Dart.
+  bool IsVoid(intptr_t arg_index) const {
+    return AbstractType::Handle(zone_, CType(arg_index)).type_class_id() ==
+           kFfiVoidCid;
+  }
+
+  RawString* function_name() const { return dart_signature_.name(); }
+
+ protected:
+  BaseMarshaller(Zone* zone, const Function& dart_signature)
+      : NativeCallingConvention(
+            zone,
+            Function::ZoneHandle(zone, dart_signature.FfiCSignature())),
+        dart_signature_(dart_signature) {
+    ASSERT(dart_signature_.IsZoneHandle());
+  }
 
  private:
-  void AllocateArgument(Location arg);
-  Location TranslateArgument(Location arg);
+  // Contains the function pointer as argument #0.
+  // The Dart signature is used for the function and argument names.
+  const Function& dart_signature_;
+};
 
-  intptr_t argument_slots_used_ = 0;
-  intptr_t argument_slots_required_ = 0;
+class CallMarshaller : public BaseMarshaller {
+ public:
+  CallMarshaller(Zone* zone, const Function& dart_signature)
+      : BaseMarshaller(zone, dart_signature) {}
+
+  dart::Location LocInFfiCall(intptr_t arg_index) const;
+};
+
+class CallbackMarshaller : public BaseMarshaller {
+ public:
+  CallbackMarshaller(Zone* zone, const Function& dart_signature);
+
+  // All parameters are saved on stack to do safe-point transition.
+  const NativeLocation& NativeLocationOfNativeParameter(
+      intptr_t arg_index) const {
+    if (arg_index == kResultIndex) {
+      // No moving around of result.
+      return Location(arg_index);
+    }
+    return *callback_locs_.At(arg_index);
+  }
+
+  // All parameters are saved on stack to do safe-point transition.
+  dart::Location LocationOfNativeParameter(intptr_t arg_index) const {
+    return NativeLocationOfNativeParameter(arg_index).AsLocation();
+  }
+
+ protected:
+  const NativeLocations& callback_locs_;
 };
 
 }  // namespace ffi
diff --git a/runtime/vm/compiler/ffi/native_calling_convention.cc b/runtime/vm/compiler/ffi/native_calling_convention.cc
index 17aed54..9966465 100644
--- a/runtime/vm/compiler/ffi/native_calling_convention.cc
+++ b/runtime/vm/compiler/ffi/native_calling_convention.cc
@@ -4,9 +4,10 @@
 
 #include "vm/compiler/ffi/native_calling_convention.h"
 
-#include "vm/compiler/ffi/frame_rebase.h"
+#include "vm/compiler/ffi/marshaller.h"
+#include "vm/compiler/ffi/native_location.h"
+#include "vm/compiler/ffi/native_type.h"
 #include "vm/log.h"
-#include "vm/stack_frame.h"
 #include "vm/symbols.h"
 
 namespace dart {
@@ -17,270 +18,289 @@
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
 
-Representation TypeRepresentation(classid_t class_id) {
-  switch (class_id) {
-    case kFfiFloatCid:
-      return kUnboxedFloat;
-    case kFfiDoubleCid:
-      return kUnboxedDouble;
-    case kFfiInt8Cid:
-    case kFfiInt16Cid:
-    case kFfiInt32Cid:
-      return kUnboxedInt32;
-    case kFfiUint8Cid:
-    case kFfiUint16Cid:
-    case kFfiUint32Cid:
-      return kUnboxedUint32;
-    case kFfiInt64Cid:
-    case kFfiUint64Cid:
-      return kUnboxedInt64;
-    case kFfiIntPtrCid:
-      return kUnboxedIntPtr;
-    case kFfiPointerCid:
-    case kFfiVoidCid:
-      return kUnboxedFfiIntPtr;
-    default:
-      UNREACHABLE();
-  }
+// Argument #0 is the function pointer.
+const intptr_t kNativeParamsStartAt = 1;
+
+const intptr_t kNoFpuRegister = -1;
+
+// In Soft FP, floats and doubles get passed in integer registers.
+static bool SoftFpAbi() {
+#if defined(TARGET_ARCH_ARM)
+  return !TargetCPUFeatures::hardfp_supported();
+#else
+  return false;
+#endif
 }
 
-SmallRepresentation TypeSmallRepresentation(const AbstractType& ffi_type) {
-  switch (ffi_type.type_class_id()) {
-    case kFfiInt8Cid:
-      return kSmallUnboxedInt8;
-    case kFfiInt16Cid:
-      return kSmallUnboxedInt16;
-    case kFfiUint8Cid:
-      return kSmallUnboxedUint8;
-    case kFfiUint16Cid:
-      return kSmallUnboxedUint16;
-    default:
-      return kNoSmallRepresentation;
-  }
-}
-
-bool NativeTypeIsVoid(const AbstractType& result_type) {
-  return result_type.type_class_id() == kFfiVoidCid;
-}
-
-bool NativeTypeIsPointer(const AbstractType& result_type) {
-  return result_type.type_class_id() == kFfiPointerCid;
-}
-
-// Converts a Ffi [signature] to a list of Representations.
-// Note that this ignores first argument (receiver) which is dynamic.
-ZoneGrowableArray<Representation>* ArgumentRepresentations(
-    const Function& signature) {
-  intptr_t num_arguments = signature.num_fixed_parameters() - 1;
-  auto result = new ZoneGrowableArray<Representation>(num_arguments);
-  for (intptr_t i = 0; i < num_arguments; i++) {
-    AbstractType& arg_type =
-        AbstractType::Handle(signature.ParameterTypeAt(i + 1));
-    Representation rep = TypeRepresentation(arg_type.type_class_id());
-    // In non simulator mode host::CallingConventions == CallingConventions.
-    // In simulator mode convert arguments to host representation.
-    if (rep == kUnboxedFloat && CallingConventions::kAbiSoftFP) {
-      rep = kUnboxedInt32;
-    } else if (rep == kUnboxedDouble && CallingConventions::kAbiSoftFP) {
-      rep = kUnboxedInt64;
+// In Soft FP, floats are treated as 4 byte ints, and doubles as 8 byte ints.
+static const NativeType& ConvertIfSoftFp(const NativeType& rep, Zone* zone) {
+  if (SoftFpAbi() && rep.IsFloat()) {
+    ASSERT(rep.IsFloat());
+    if (rep.SizeInBytes() == 4) {
+      return *new (zone) NativeFundamentalType(kInt32);
     }
-    result->Add(rep);
-  }
-  return result;
-}
-
-Representation ResultRepresentation(const Function& signature) {
-  AbstractType& arg_type = AbstractType::Handle(signature.result_type());
-  Representation rep = TypeRepresentation(arg_type.type_class_id());
-  if (rep == kUnboxedFloat && CallingConventions::kAbiSoftFP) {
-    rep = kUnboxedInt32;
-  } else if (rep == kUnboxedDouble && CallingConventions::kAbiSoftFP) {
-    rep = kUnboxedInt64;
+    if (rep.SizeInBytes() == 8) {
+      return *new (zone) NativeFundamentalType(kInt64);
+    }
   }
   return rep;
 }
 
-// Represents the state of a stack frame going into a call, between allocations
-// of argument locations. Acts like a register allocator but for arguments in
-// the native ABI.
-class ArgumentAllocator : public ValueObject {
- public:
-  Location AllocateArgument(Representation rep) {
-    switch (rep) {
-      case kUnboxedFloat:
-      case kUnboxedDouble: {
-        Location result = AllocateFpuRegister();
-        if (!result.IsUnallocated()) return result;
-        break;
-      }
-      case kUnboxedInt64:
-      case kUnboxedUint32:
-      case kUnboxedInt32: {
-        Location result = rep == kUnboxedInt64 && target::kWordSize == 4
-                              ? AllocateAlignedRegisterPair()
-                              : AllocateCpuRegister();
-        if (!result.IsUnallocated()) return result;
-        break;
-      }
-      default:
-        UNREACHABLE();
-    }
-
-    // Argument must be spilled.
-    if (rep == kUnboxedInt64 && target::kWordSize == 4) {
-      return AllocateAlignedStackSlots(rep);
-    } else if (rep == kUnboxedDouble) {
-      // By convention, we always use DoubleStackSlot for doubles, even on
-      // 64-bit systems.
-      ASSERT(!CallingConventions::kAlignArguments);
-      return AllocateDoubleStackSlot();
-    } else {
-      return AllocateStackSlot();
-    }
-  }
-
- private:
-  Location AllocateStackSlot() {
-    return Location::StackSlot(stack_height_in_slots++,
-                               CallingConventions::kStackPointerRegister);
-  }
-
-  Location AllocateDoubleStackSlot() {
-    const Location result = Location::DoubleStackSlot(
-        stack_height_in_slots, CallingConventions::kStackPointerRegister);
-    stack_height_in_slots += 8 / target::kWordSize;
-    return result;
-  }
-
-  // Allocates a pair of stack slots where the first stack slot is aligned to an
-  // 8-byte boundary, if necessary.
-  Location AllocateAlignedStackSlots(Representation rep) {
-    if (CallingConventions::kAlignArguments && target::kWordSize == 4) {
-      stack_height_in_slots += stack_height_in_slots % 2;
-    }
-
-    Location result;
-    if (rep == kUnboxedDouble) {
-      result = Location::DoubleStackSlot(
-          stack_height_in_slots, CallingConventions::kStackPointerRegister);
-      stack_height_in_slots += 2;
-    } else {
-      const Location low = AllocateStackSlot();
-      const Location high = AllocateStackSlot();
-      result = Location::Pair(low, high);
-    }
-    return result;
-  }
-
-  Location AllocateFpuRegister() {
-    if (fpu_regs_used == CallingConventions::kNumFpuArgRegs) {
-      return Location::RequiresFpuRegister();
-    }
-
-    const Location result = Location::FpuRegisterLocation(
-        CallingConventions::FpuArgumentRegisters[fpu_regs_used]);
-    fpu_regs_used++;
-    if (CallingConventions::kArgumentIntRegXorFpuReg) {
-      cpu_regs_used++;
-    }
-    return result;
-  }
-
-  Location AllocateCpuRegister() {
-    if (cpu_regs_used == CallingConventions::kNumArgRegs) {
-      return Location::RequiresRegister();
-    }
-
-    const Location result = Location::RegisterLocation(
-        CallingConventions::ArgumentRegisters[cpu_regs_used]);
-    cpu_regs_used++;
-    if (CallingConventions::kArgumentIntRegXorFpuReg) {
-      fpu_regs_used++;
-    }
-    return result;
-  }
-
-  // Allocates a pair of registers where the first register index is even, if
-  // necessary.
-  Location AllocateAlignedRegisterPair() {
-    if (CallingConventions::kAlignArguments) {
-      cpu_regs_used += cpu_regs_used % 2;
-    }
-    if (cpu_regs_used > CallingConventions::kNumArgRegs - 2) {
-      return Location::Any();
-    }
-    return Location::Pair(AllocateCpuRegister(), AllocateCpuRegister());
-  }
-
-  intptr_t cpu_regs_used = 0;
-  intptr_t fpu_regs_used = 0;
-  intptr_t stack_height_in_slots = 0;
-};
-
-// Takes a list of argument representations, and converts it to a list of
-// argument locations based on calling convention.
-
-ZoneGrowableArray<Location>* ArgumentLocations(
-    const ZoneGrowableArray<Representation>& arg_reps) {
-  intptr_t num_arguments = arg_reps.length();
-  auto result = new ZoneGrowableArray<Location>(num_arguments);
-
-  // Loop through all arguments and assign a register or a stack location.
-  ArgumentAllocator frame_state;
+// Representations of the arguments to a C signature function.
+static ZoneGrowableArray<const NativeType*>& ArgumentRepresentations(
+    const Function& signature,
+    Zone* zone) {
+  const intptr_t num_arguments =
+      signature.num_fixed_parameters() - kNativeParamsStartAt;
+  auto& result = *new ZoneGrowableArray<const NativeType*>(zone, num_arguments);
   for (intptr_t i = 0; i < num_arguments; i++) {
-    Representation rep = arg_reps[i];
-    result->Add(frame_state.AllocateArgument(rep));
+    AbstractType& arg_type = AbstractType::Handle(
+        zone, signature.ParameterTypeAt(i + kNativeParamsStartAt));
+    const auto& rep = NativeType::FromAbstractType(arg_type, zone);
+    result.Add(&rep);
   }
   return result;
 }
 
-Location ResultLocation(Representation result_rep) {
-  switch (result_rep) {
-    case kUnboxedFloat:
-    case kUnboxedDouble:
-#if defined(TARGET_ARCH_IA32)
-      // The result is returned in ST0, but we don't allocate ST registers, so
-      // the FFI trampoline will move it to XMM0.
-      return Location::FpuRegisterLocation(XMM0);
-#else
-      return Location::FpuRegisterLocation(CallingConventions::kReturnFpuReg);
-#endif
-    case kUnboxedInt32:
-    case kUnboxedUint32:
-      return Location::RegisterLocation(CallingConventions::kReturnReg);
-    case kUnboxedInt64:
-      if (target::kWordSize == 4) {
-        return Location::Pair(
-            Location::RegisterLocation(CallingConventions::kReturnReg),
-            Location::RegisterLocation(CallingConventions::kSecondReturnReg));
-      } else {
-        return Location::RegisterLocation(CallingConventions::kReturnReg);
-      }
-    default:
-      UNREACHABLE();
-  }
+// Representation of the result of a C signature function.
+static NativeType& ResultRepresentation(const Function& signature, Zone* zone) {
+  AbstractType& result_type =
+      AbstractType::Handle(zone, signature.result_type());
+  return NativeType::FromAbstractType(result_type, zone);
 }
 
-// Accounts for alignment, where some stack slots are used as padding.
-intptr_t NumStackSlots(const ZoneGrowableArray<Location>& locations) {
-  intptr_t num_arguments = locations.length();
-  intptr_t max_height_in_slots = 0;
-  for (intptr_t i = 0; i < num_arguments; i++) {
-    intptr_t height = 0;
-    if (locations.At(i).IsStackSlot()) {
-      height = locations.At(i).stack_index() + 1;
-    } else if (locations.At(i).IsDoubleStackSlot()) {
-      height = locations.At(i).stack_index() + 8 / target::kWordSize;
-    } else if (locations.At(i).IsPairLocation()) {
-      const Location first = locations.At(i).AsPairLocation()->At(0);
-      const Location second = locations.At(i).AsPairLocation()->At(1);
-      height =
-          Utils::Maximum(first.IsStackSlot() ? first.stack_index() + 1 : 0,
-                         second.IsStackSlot() ? second.stack_index() + 1 : 0);
+// Represents the state of a stack frame going into a call, between allocations
+// of argument locations.
+class ArgumentAllocator : public ValueObject {
+ public:
+  explicit ArgumentAllocator(Zone* zone) : zone_(zone) {}
+
+  const NativeLocation& AllocateArgument(const NativeType& payload_type) {
+    const auto& payload_type_converted = ConvertIfSoftFp(payload_type, zone_);
+    if (payload_type_converted.IsFloat()) {
+      const auto kind = FpuRegKind(payload_type);
+      const intptr_t reg_index = FirstFreeFpuRegisterIndex(kind);
+      if (reg_index != kNoFpuRegister) {
+        AllocateFpuRegisterAtIndex(kind, reg_index);
+        if (CallingConventions::kArgumentIntRegXorFpuReg) {
+          cpu_regs_used++;
+        }
+        return *new (zone_) NativeFpuRegistersLocation(
+            payload_type, payload_type, kind, reg_index);
+      } else {
+        BlockAllFpuRegisters();
+        if (CallingConventions::kArgumentIntRegXorFpuReg) {
+          ASSERT(cpu_regs_used == CallingConventions::kNumArgRegs);
+        }
+      }
+    } else {
+      ASSERT(payload_type_converted.IsInt());
+      // Some calling conventions require the callee to make the lowest 32 bits
+      // in registers non-garbage.
+      const auto& container_type =
+          CallingConventions::kArgumentRegisterExtension == kExtendedTo4
+              ? payload_type_converted.WidenTo4Bytes(zone_)
+              : payload_type_converted;
+      if (target::kWordSize == 4 && payload_type.SizeInBytes() == 8) {
+        if (CallingConventions::kArgumentRegisterAlignment ==
+            kAlignedToWordSizeBut8AlignedTo8) {
+          cpu_regs_used += cpu_regs_used % 2;
+        }
+        if (cpu_regs_used + 2 <= CallingConventions::kNumArgRegs) {
+          return *new (zone_) NativeRegistersLocation(
+              payload_type, container_type, AllocateCpuRegister(),
+              AllocateCpuRegister());
+        }
+      } else {
+        ASSERT(payload_type.SizeInBytes() <= target::kWordSize);
+        if (cpu_regs_used + 1 <= CallingConventions::kNumArgRegs) {
+          return *new (zone_) NativeRegistersLocation(
+              payload_type, container_type, AllocateCpuRegister());
+        }
+      }
     }
-    max_height_in_slots = Utils::Maximum(height, max_height_in_slots);
+
+    return AllocateStack(payload_type);
   }
-  return max_height_in_slots;
+
+ private:
+  static FpuRegisterKind FpuRegKind(const NativeType& payload_type) {
+#if defined(TARGET_ARCH_ARM)
+    return FpuRegisterKindFromSize(payload_type.SizeInBytes());
+#else
+    return kQuadFpuReg;
+#endif
+  }
+
+  Register AllocateCpuRegister() {
+    ASSERT(cpu_regs_used < CallingConventions::kNumArgRegs);
+
+    const auto result = CallingConventions::ArgumentRegisters[cpu_regs_used];
+    if (CallingConventions::kArgumentIntRegXorFpuReg) {
+      AllocateFpuRegisterAtIndex(kQuadFpuReg, cpu_regs_used);
+    }
+    cpu_regs_used++;
+    return result;
+  }
+
+  const NativeLocation& AllocateStack(const NativeType& payload_type) {
+    align_stack(payload_type.AlignmentInBytesStack());
+    const intptr_t size = payload_type.SizeInBytes();
+    // If the stack arguments are not packed, the 32 lowest bits should not
+    // contain garbage.
+    const auto& container_type =
+        CallingConventions::kArgumentStackExtension == kExtendedTo4
+            ? payload_type.WidenTo4Bytes(zone_)
+            : payload_type;
+    const auto& result = *new (zone_) NativeStackLocation(
+        payload_type, container_type, CallingConventions::kStackPointerRegister,
+        stack_height_in_bytes);
+    stack_height_in_bytes += size;
+    return result;
+  }
+
+  void align_stack(intptr_t alignment) {
+    stack_height_in_bytes = Utils::RoundUp(stack_height_in_bytes, alignment);
+  }
+
+  int NumFpuRegisters(FpuRegisterKind kind) {
+#if defined(TARGET_ARCH_ARM)
+    if (SoftFpAbi()) return 0;
+    if (kind == kSingleFpuReg) return CallingConventions::kNumSFpuArgRegs;
+    if (kind == kDoubleFpuReg) return CallingConventions::kNumDFpuArgRegs;
+#endif  // defined(TARGET_ARCH_ARM)
+    if (kind == kQuadFpuReg) return CallingConventions::kNumFpuArgRegs;
+    UNREACHABLE();
+  }
+
+  // If no register is free, returns -1.
+  int FirstFreeFpuRegisterIndex(FpuRegisterKind kind) {
+    const intptr_t size = SizeFromFpuRegisterKind(kind) / 4;
+    ASSERT(size == 1 || size == 2 || size == 4);
+    if (fpu_reg_parts_used == -1) return kNoFpuRegister;
+    const intptr_t mask = (1 << size) - 1;
+    intptr_t index = 0;
+    while (index < NumFpuRegisters(kind)) {
+      const intptr_t mask_shifted = mask << (index * size);
+      if ((fpu_reg_parts_used & mask_shifted) == 0) {
+        return index;
+      }
+      index++;
+    }
+    return kNoFpuRegister;
+  }
+
+  void AllocateFpuRegisterAtIndex(FpuRegisterKind kind, int index) {
+    const intptr_t size = SizeFromFpuRegisterKind(kind) / 4;
+    ASSERT(size == 1 || size == 2 || size == 4);
+    const intptr_t mask = (1 << size) - 1;
+    const intptr_t mask_shifted = (mask << (index * size));
+    ASSERT((mask_shifted & fpu_reg_parts_used) == 0);
+    fpu_reg_parts_used |= mask_shifted;
+  }
+
+  // > The back-filling continues only so long as no VFP CPRC has been
+  // > allocated to a slot on the stack.
+  // Procedure Call Standard for the Arm Architecture, Release 2019Q1.1
+  // Chapter 7.1 page 28. https://developer.arm.com/docs/ihi0042/h
+  //
+  // Irrelevant on Android and iOS, as those are both SoftFP.
+  // > For floating-point arguments, the Base Standard variant of the
+  // > Procedure Call Standard is used. In this variant, floating-point
+  // > (and vector) arguments are passed in general purpose registers
+  // > (GPRs) instead of in VFP registers)
+  // https://developer.apple.com/library/archive/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARMv6FunctionCallingConventions.html#//apple_ref/doc/uid/TP40009021-SW1
+  // https://developer.apple.com/library/archive/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARMv7FunctionCallingConventions.html#//apple_ref/doc/uid/TP40009022-SW1
+  void BlockAllFpuRegisters() {
+    // Set all bits to 1.
+    fpu_reg_parts_used = -1;
+  }
+
+  intptr_t cpu_regs_used = 0;
+  // Every bit denotes 32 bits of FPU registers.
+  intptr_t fpu_reg_parts_used = 0;
+  intptr_t stack_height_in_bytes = 0;
+  Zone* zone_;
+};
+
+// Location for the arguments of a C signature function.
+static NativeLocations& ArgumentLocations(
+    const ZoneGrowableArray<const NativeType*>& arg_reps,
+    Zone* zone) {
+  intptr_t num_arguments = arg_reps.length();
+  auto& result = *new NativeLocations(zone, num_arguments);
+
+  // Loop through all arguments and assign a register or a stack location.
+  ArgumentAllocator frame_state(zone);
+  for (intptr_t i = 0; i < num_arguments; i++) {
+    const NativeType& rep = *arg_reps[i];
+    result.Add(&frame_state.AllocateArgument(rep));
+  }
+  return result;
+}
+
+// Location for the result of a C signature function.
+static NativeLocation& ResultLocation(const NativeType& payload_type,
+                                      Zone* zone) {
+  const auto& payload_type_converted = ConvertIfSoftFp(payload_type, zone);
+  const auto& container_type =
+      CallingConventions::kArgumentRegisterExtension == kExtendedTo4
+          ? payload_type_converted.WidenTo4Bytes(zone)
+          : payload_type_converted;
+  if (container_type.IsFloat()) {
+    return *new (zone) NativeFpuRegistersLocation(
+        payload_type, container_type, CallingConventions::kReturnFpuReg);
+  }
+
+  ASSERT(container_type.IsInt() || container_type.IsVoid());
+  if (container_type.SizeInBytes() == 8 && target::kWordSize == 4) {
+    return *new (zone) NativeRegistersLocation(
+        payload_type, container_type, CallingConventions::kReturnReg,
+        CallingConventions::kSecondReturnReg);
+  }
+
+  ASSERT(container_type.SizeInBytes() <= target::kWordSize);
+  return *new (zone) NativeRegistersLocation(payload_type, container_type,
+                                             CallingConventions::kReturnReg);
+}
+
+NativeCallingConvention::NativeCallingConvention(Zone* zone,
+                                                 const Function& c_signature)
+    : zone_(ASSERT_NOTNULL(zone)),
+      c_signature_(c_signature),
+      arg_locs_(ArgumentLocations(ArgumentRepresentations(c_signature_, zone_),
+                                  zone_)),
+      result_loc_(
+          ResultLocation(ResultRepresentation(c_signature_, zone_), zone_)) {}
+
+intptr_t NativeCallingConvention::num_args() const {
+  ASSERT(c_signature_.NumOptionalParameters() == 0);
+  ASSERT(c_signature_.NumOptionalPositionalParameters() == 0);
+
+  // Subtract the #0 argument, the function pointer.
+  return c_signature_.num_fixed_parameters() - kNativeParamsStartAt;
+}
+
+RawAbstractType* NativeCallingConvention::CType(intptr_t arg_index) const {
+  if (arg_index == kResultIndex) {
+    return c_signature_.result_type();
+  }
+
+  // Skip #0 argument, the function pointer.
+  return c_signature_.ParameterTypeAt(arg_index + kNativeParamsStartAt);
+}
+
+intptr_t NativeCallingConvention::StackTopInBytes() const {
+  const intptr_t num_arguments = arg_locs_.length();
+  intptr_t max_height_in_bytes = 0;
+  for (intptr_t i = 0; i < num_arguments; i++) {
+    if (Location(i).IsStack()) {
+      const intptr_t height = Location(i).AsStack().offset_in_bytes() +
+                              Location(i).container_type().SizeInBytes();
+      max_height_in_bytes = Utils::Maximum(height, max_height_in_bytes);
+    }
+  }
+  return Utils::RoundUp(max_height_in_bytes, compiler::target::kWordSize);
 }
 
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/compiler/ffi/native_calling_convention.h b/runtime/vm/compiler/ffi/native_calling_convention.h
index 8336f1c..459be7f 100644
--- a/runtime/vm/compiler/ffi/native_calling_convention.h
+++ b/runtime/vm/compiler/ffi/native_calling_convention.h
@@ -8,6 +8,8 @@
 #include <platform/globals.h>
 
 #include "vm/compiler/backend/locations.h"
+#include "vm/compiler/ffi/native_location.h"
+#include "vm/compiler/ffi/native_type.h"
 
 namespace dart {
 
@@ -15,42 +17,46 @@
 
 namespace ffi {
 
-// Unboxed representation of an FFI type (extends 'ffi.NativeType').
-Representation TypeRepresentation(classid_t class_id);
+using NativeLocations = ZoneGrowableArray<const NativeLocation*>;
 
-// Unboxed representation of an FFI type (extends 'ffi.NativeType') for 8 and 16
-// bit integers.
-SmallRepresentation TypeSmallRepresentation(const AbstractType& result_type);
 
-// Whether a type which extends 'ffi.NativeType' also extends 'ffi.Pointer'.
-bool NativeTypeIsPointer(const AbstractType& result_type);
+// Values below 0 index result (result might be multiple if composite).
+const intptr_t kResultIndex = -1;
 
-// Whether a type is 'ffi.Void'.
-bool NativeTypeIsVoid(const AbstractType& result_type);
+// Calculates native calling convention, is not aware of Dart calling
+// convention constraints.
+//
+// This class is meant to be extended or embedded in a class that is aware
+// of Dart calling convention constraints.
+class NativeCallingConvention : public ZoneAllocated {
+ public:
+  NativeCallingConvention(Zone* zone, const Function& c_signature);
 
-// Location for the result of a C signature function.
-Location ResultLocation(Representation result_rep);
+  // Excluding the #0 argument which is the function pointer.
+  intptr_t num_args() const;
 
-RawFunction* TrampolineFunction(const Function& dart_signature,
-                                const Function& c_signature);
+  // The C Type (expressed in a Dart Type) of the argument at `arg_index`.
+  //
+  // Excluding the #0 argument which is the function pointer.
+  RawAbstractType* CType(intptr_t arg_index) const;
 
-RawFunction* NativeCallbackFunction(const Function& c_signature,
-                                    const Function& dart_target,
-                                    const Instance& exceptional_return);
+  // The location of the argument at `arg_index`.
+  const NativeLocation& Location(intptr_t arg_index) const {
+    if (arg_index == kResultIndex) {
+      return result_loc_;
+    }
+    return *arg_locs_.At(arg_index);
+  }
 
-// Unboxed representations of the arguments to a C signature function.
-ZoneGrowableArray<Representation>* ArgumentRepresentations(
-    const Function& signature);
+  intptr_t StackTopInBytes() const;
 
-// Unboxed representation of the result of a C signature function.
-Representation ResultRepresentation(const Function& signature);
-
-// Location for the arguments of a C signature function.
-ZoneGrowableArray<Location>* ArgumentLocations(
-    const ZoneGrowableArray<Representation>& arg_reps);
-
-// Number of stack slots used in 'locations'.
-intptr_t NumStackSlots(const ZoneGrowableArray<Location>& locations);
+ protected:
+  Zone* const zone_;
+  // Contains the function pointer as argument #0.
+  const Function& c_signature_;
+  const NativeLocations& arg_locs_;
+  const NativeLocation& result_loc_;
+};
 
 }  // namespace ffi
 
diff --git a/runtime/vm/compiler/ffi/native_location.cc b/runtime/vm/compiler/ffi/native_location.cc
new file mode 100644
index 0000000..918f341
--- /dev/null
+++ b/runtime/vm/compiler/ffi/native_location.cc
@@ -0,0 +1,344 @@
+// Copyright (c) 2020, 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.
+
+#if !defined(DART_PRECOMPILED_RUNTIME)
+
+#include "vm/compiler/ffi/native_location.h"
+
+#include "vm/compiler/backend/il_printer.h"
+
+namespace dart {
+
+namespace compiler {
+
+namespace ffi {
+
+bool NativeLocation::LocationCanBeExpressed(Location loc, Representation rep) {
+  switch (loc.kind()) {
+    case Location::Kind::kRegister:
+    case Location::Kind::kFpuRegister:
+    case Location::Kind::kStackSlot:
+    case Location::Kind::kDoubleStackSlot:
+      return true;
+    default:
+      break;
+  }
+  if (loc.IsPairLocation()) {
+    // TODO(36730): We could possibly consume a pair location as struct.
+    return false;
+  }
+  return false;
+}
+
+NativeLocation& NativeLocation::FromLocation(Location loc,
+                                             Representation rep,
+                                             Zone* zone) {
+  // TODO(36730): We could possibly consume a pair location as struct.
+  ASSERT(LocationCanBeExpressed(loc, rep));
+
+  const NativeType& native_rep =
+      NativeType::FromUnboxedRepresentation(rep, zone);
+
+  switch (loc.kind()) {
+    case Location::Kind::kRegister:
+      return *new (zone)
+          NativeRegistersLocation(native_rep, native_rep, loc.reg());
+    case Location::Kind::kFpuRegister:
+      return *new (zone)
+          NativeFpuRegistersLocation(native_rep, native_rep, loc.fpu_reg());
+    case Location::Kind::kStackSlot:
+      return *new (zone)
+          NativeStackLocation(native_rep, native_rep, loc.base_reg(),
+                              loc.stack_index() * compiler::target::kWordSize);
+    case Location::Kind::kDoubleStackSlot:
+      return *new (zone)
+          NativeStackLocation(native_rep, native_rep, loc.base_reg(),
+                              loc.stack_index() * compiler::target::kWordSize);
+    default:
+      break;
+  }
+
+  UNREACHABLE();
+}
+
+// TODO(36730): Remove when being able to consume as struct.
+NativeLocation& NativeLocation::FromPairLocation(Location pair_loc,
+                                                 Representation pair_rep,
+                                                 intptr_t index,
+                                                 Zone* zone) {
+  ASSERT(pair_loc.IsPairLocation());
+  ASSERT(index == 0 || index == 1);
+  const Representation rep =
+      NativeType::FromUnboxedRepresentation(pair_rep, zone)
+          .Split(index, zone)
+          .AsRepresentation();
+  const Location loc = pair_loc.AsPairLocation()->At(index);
+  return FromLocation(loc, rep, zone);
+}
+
+const NativeRegistersLocation& NativeLocation::AsRegisters() const {
+  ASSERT(IsRegisters());
+  return static_cast<const NativeRegistersLocation&>(*this);
+}
+
+const NativeFpuRegistersLocation& NativeLocation::AsFpuRegisters() const {
+  ASSERT(IsFpuRegisters());
+  return static_cast<const NativeFpuRegistersLocation&>(*this);
+}
+
+const NativeStackLocation& NativeLocation::AsStack() const {
+  ASSERT(IsStack());
+  return static_cast<const NativeStackLocation&>(*this);
+}
+
+Location NativeRegistersLocation::AsLocation() const {
+  ASSERT(IsExpressibleAsLocation());
+  switch (num_regs()) {
+    case 1:
+      return Location::RegisterLocation(regs_->At(0));
+    case 2:
+      return Location::Pair(Location::RegisterLocation(regs_->At(0)),
+                            Location::RegisterLocation(regs_->At(1)));
+  }
+  UNREACHABLE();
+}
+
+Location NativeStackLocation::AsLocation() const {
+  ASSERT(IsExpressibleAsLocation());
+  if (payload_type().IsInt()) {
+    const intptr_t size = payload_type().SizeInBytes();
+    const intptr_t size_slots = size / compiler::target::kWordSize;
+    switch (size_slots) {
+      case 1:
+        return Location::StackSlot(offset_in_words(), base_register_);
+      case 2:
+        return Location::Pair(
+            Location::StackSlot(offset_in_words(), base_register_),
+            Location::StackSlot(offset_in_words() + 1, base_register_));
+    }
+  } else {
+    ASSERT(payload_type().IsFloat());
+    if (payload_type().AsFundamental().representation() == kFloat) {
+      return Location::StackSlot(offset_in_words(), base_register_);
+    } else {
+      ASSERT(payload_type().AsFundamental().representation() == kDouble);
+      return Location::DoubleStackSlot(offset_in_words(), base_register_);
+    }
+  }
+  UNREACHABLE();
+}
+NativeRegistersLocation& NativeRegistersLocation::Split(intptr_t index,
+                                                        Zone* zone) const {
+  ASSERT(num_regs() == 2);
+  return *new (zone) NativeRegistersLocation(
+      payload_type().Split(index, zone), container_type().Split(index, zone),
+      reg_at(index));
+}
+
+NativeStackLocation& NativeStackLocation::Split(intptr_t index,
+                                                Zone* zone) const {
+  ASSERT(index == 0 || index == 1);
+  const intptr_t size = payload_type().SizeInBytes();
+
+  return *new (zone) NativeStackLocation(
+      payload_type().Split(index, zone), container_type().Split(index, zone),
+      base_register_, offset_in_bytes_ + size / 2 * index);
+}
+
+NativeLocation& NativeLocation::WidenTo4Bytes(Zone* zone) const {
+  return WithOtherNativeType(payload_type().WidenTo4Bytes(zone),
+                             container_type().WidenTo4Bytes(zone), zone);
+}
+
+#if defined(TARGET_ARCH_ARM)
+const NativeLocation& NativeLocation::WidenToQFpuRegister(Zone* zone) const {
+  if (!IsFpuRegisters()) {
+    return *this;
+  }
+  const auto& fpu_loc = AsFpuRegisters();
+  switch (fpu_loc.fpu_reg_kind()) {
+    case kQuadFpuReg:
+      return *this;
+    case kDoubleFpuReg: {
+      return *new (zone) NativeFpuRegistersLocation(
+          payload_type_, container_type_, QRegisterOf(fpu_loc.fpu_d_reg()));
+    }
+    case kSingleFpuReg: {
+      return *new (zone) NativeFpuRegistersLocation(
+          payload_type_, container_type_, QRegisterOf(fpu_loc.fpu_s_reg()));
+    }
+  }
+  UNREACHABLE();
+}
+#endif  // defined(TARGET_ARCH_ARM)
+
+bool NativeRegistersLocation::Equals(const NativeLocation& other) const {
+  if (!other.IsRegisters()) {
+    return false;
+  }
+  const auto& other_regs = other.AsRegisters();
+  if (other_regs.num_regs() != num_regs()) {
+    return false;
+  }
+  for (intptr_t i = 0; i < num_regs(); i++) {
+    if (other_regs.reg_at(i) != reg_at(i)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool NativeFpuRegistersLocation::Equals(const NativeLocation& other) const {
+  if (!other.IsFpuRegisters()) {
+    return false;
+  }
+  return other.AsFpuRegisters().fpu_reg_ == fpu_reg_;
+}
+
+bool NativeStackLocation::Equals(const NativeLocation& other) const {
+  if (!other.IsStack()) {
+    return false;
+  }
+  const auto& other_stack = other.AsStack();
+  if (other_stack.base_register_ != base_register_) {
+    return false;
+  }
+  return other_stack.offset_in_bytes_ == offset_in_bytes_;
+}
+
+compiler::Address NativeLocationToStackSlotAddress(
+    const NativeStackLocation& loc) {
+  return compiler::Address(loc.base_register(), loc.offset_in_bytes());
+}
+
+static void PrintRepresentations(BufferFormatter* f,
+                                 const NativeLocation& loc) {
+  f->Print(" ");
+  loc.container_type().PrintTo(f);
+  if (!loc.container_type().Equals(loc.payload_type())) {
+    f->Print("[");
+    loc.payload_type().PrintTo(f);
+    f->Print("]");
+  }
+}
+
+void NativeLocation::PrintTo(BufferFormatter* f) const {
+  f->Print("I");
+  PrintRepresentations(f, *this);
+}
+
+void NativeRegistersLocation::PrintTo(BufferFormatter* f) const {
+  if (num_regs() == 1) {
+    f->Print("%s", RegisterNames::RegisterName(regs_->At(0)));
+  } else {
+    f->Print("(");
+    for (intptr_t i = 0; i < num_regs(); i++) {
+      if (i != 0) f->Print(", ");
+      f->Print("%s", RegisterNames::RegisterName(regs_->At(i)));
+    }
+    f->Print(")");
+  }
+  PrintRepresentations(f, *this);
+}
+
+void NativeFpuRegistersLocation::PrintTo(BufferFormatter* f) const {
+  switch (fpu_reg_kind()) {
+    case kQuadFpuReg:
+      f->Print("%s", RegisterNames::FpuRegisterName(fpu_reg()));
+      break;
+#if defined(TARGET_ARCH_ARM)
+    case kDoubleFpuReg:
+      f->Print("%s", RegisterNames::FpuDRegisterName(fpu_d_reg()));
+      break;
+    case kSingleFpuReg:
+      f->Print("%s", RegisterNames::FpuSRegisterName(fpu_s_reg()));
+      break;
+#endif  // defined(TARGET_ARCH_ARM)
+    default:
+      UNREACHABLE();
+  }
+
+  PrintRepresentations(f, *this);
+}
+
+void NativeStackLocation::PrintTo(BufferFormatter* f) const {
+  f->Print("S%+" Pd, offset_in_bytes_);
+  PrintRepresentations(f, *this);
+}
+
+const char* NativeLocation::ToCString() const {
+  char buffer[1024];
+  BufferFormatter bf(buffer, 1024);
+  PrintTo(&bf);
+  return Thread::Current()->zone()->MakeCopyOfString(buffer);
+}
+
+intptr_t SizeFromFpuRegisterKind(enum FpuRegisterKind kind) {
+  switch (kind) {
+    case kQuadFpuReg:
+      return 16;
+    case kDoubleFpuReg:
+      return 8;
+    case kSingleFpuReg:
+      return 4;
+  }
+  UNREACHABLE();
+}
+enum FpuRegisterKind FpuRegisterKindFromSize(intptr_t size_in_bytes) {
+  switch (size_in_bytes) {
+    case 16:
+      return kQuadFpuReg;
+    case 8:
+      return kDoubleFpuReg;
+    case 4:
+      return kSingleFpuReg;
+  }
+  UNREACHABLE();
+}
+
+#if defined(TARGET_ARCH_ARM)
+DRegister NativeFpuRegistersLocation::fpu_as_d_reg() const {
+  switch (fpu_reg_kind_) {
+    case kQuadFpuReg:
+      return EvenDRegisterOf(fpu_reg());
+    case kDoubleFpuReg:
+      return fpu_d_reg();
+    case kSingleFpuReg:
+      return DRegisterOf(fpu_s_reg());
+  }
+}
+
+SRegister NativeFpuRegistersLocation::fpu_as_s_reg() const {
+  switch (fpu_reg_kind_) {
+    case kQuadFpuReg:
+      return EvenSRegisterOf(EvenDRegisterOf(fpu_reg()));
+    case kDoubleFpuReg:
+      return EvenSRegisterOf(fpu_d_reg());
+    case kSingleFpuReg:
+      return fpu_s_reg();
+  }
+}
+
+bool NativeFpuRegistersLocation::IsLowestBits() const {
+  switch (fpu_reg_kind()) {
+    case kQuadFpuReg:
+      return true;
+    case kDoubleFpuReg: {
+      return fpu_d_reg() % 2 == 0;
+    }
+    case kSingleFpuReg: {
+      return fpu_s_reg() % 4 == 0;
+    }
+  }
+  UNREACHABLE();
+}
+#endif  // defined(TARGET_ARCH_ARM)
+
+}  // namespace ffi
+
+}  // namespace compiler
+
+}  // namespace dart
+
+#endif  // !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/compiler/ffi/native_location.h b/runtime/vm/compiler/ffi/native_location.h
new file mode 100644
index 0000000..a50872f
--- /dev/null
+++ b/runtime/vm/compiler/ffi/native_location.h
@@ -0,0 +1,331 @@
+// Copyright (c) 2020, 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.
+
+#ifndef RUNTIME_VM_COMPILER_FFI_NATIVE_LOCATION_H_
+#define RUNTIME_VM_COMPILER_FFI_NATIVE_LOCATION_H_
+
+#include "vm/compiler/backend/locations.h"
+#include "vm/compiler/ffi/native_type.h"
+#include "vm/growable_array.h"
+#include "vm/thread.h"
+
+namespace dart {
+
+class BufferFormatter;
+
+namespace compiler {
+
+namespace ffi {
+
+class NativeRegistersLocation;
+class NativeFpuRegistersLocation;
+class NativeStackLocation;
+
+// NativeLocation objects are used in the FFI to describe argument and return
+// value locations in all native ABIs that the FFI supports.
+//
+// NativeLocations contain two NativeTypes.
+// * The payload type.
+// * The container type, equal to or larger than the payload. If the
+//   container is larger than the payload, the upper bits are defined by sign
+//   or zero extension.
+//
+// NativeLocations can express things that dart::Locations cannot express:
+// * Multiple consecutive registers.
+// * Multiple sizes of FPU registers (e.g. S, D, and Q on Arm32).
+// * Arbitrary byte-size stack locations, at byte-size offsets.
+//   (The Location class uses word-size offsets.)
+// * Pointers including a backing location on the stack.
+// * No location.
+// * Split between multiple registers and stack.
+//
+// NativeLocations cannot express the following dart::Locations:
+// * No PairLocations. Instead, NativeRegistersLocations can have multiple
+//   registers, and NativeStackLocations can have arbitrary types.
+// * No ConstantLocations.
+//
+// NativeLocation does not satisfy the invariant of Location: bitwise
+// inequality cannot be used to determine disjointness.
+class NativeLocation : public ZoneAllocated {
+ public:
+  static bool LocationCanBeExpressed(Location loc, Representation rep);
+  static NativeLocation& FromLocation(Location loc,
+                                      Representation rep,
+                                      Zone* zone);
+  static NativeLocation& FromPairLocation(Location loc,
+                                          Representation rep,
+                                          intptr_t index,
+                                          Zone* zone);
+
+  // The type of the data at this location.
+  const NativeType& payload_type() const { return payload_type_; }
+
+  // The location container size, possibly larger than data.
+  //
+  // If the container is larger than the data, the remaining bits are _not_
+  // undefined. For example a uint8 inside a uint32 has the upper 24 bits set
+  // to 0. Effectively allowing the value to be read as uint8, uint16 and
+  // uint32.
+  const NativeType& container_type() const { return container_type_; }
+
+  virtual NativeLocation& WithOtherNativeType(
+      const NativeType& new_payload_type,
+      const NativeType& new_container_type,
+      Zone* zone) const = 0;
+
+#if defined(TARGET_ARCH_ARM)
+  const NativeLocation& WidenToQFpuRegister(Zone* zone) const;
+#endif  // defined(TARGET_ARCH_ARM)
+
+  NativeLocation& WidenTo4Bytes(Zone* zone) const;
+
+  virtual bool IsRegisters() const { return false; }
+  virtual bool IsFpuRegisters() const { return false; }
+  virtual bool IsStack() const { return false; }
+
+  virtual bool IsExpressibleAsLocation() const { return false; }
+  virtual Location AsLocation() const {
+    ASSERT(IsExpressibleAsLocation());
+    UNREACHABLE();
+  }
+
+  virtual void PrintTo(BufferFormatter* f) const;
+  const char* ToCString() const;
+
+  const NativeRegistersLocation& AsRegisters() const;
+  const NativeFpuRegistersLocation& AsFpuRegisters() const;
+  const NativeStackLocation& AsStack() const;
+
+  virtual NativeLocation& Split(intptr_t index, Zone* zone) const {
+    ASSERT(index == 0 || index == 1);
+    UNREACHABLE();
+  }
+
+  // Equality of location, ignores the payload and container native types.
+  virtual bool Equals(const NativeLocation& other) const { UNREACHABLE(); }
+
+  virtual ~NativeLocation() {}
+
+ protected:
+  NativeLocation(const NativeType& payload_type,
+                 const NativeType& container_type)
+      : payload_type_(payload_type), container_type_(container_type) {}
+
+ private:
+  const NativeType& payload_type_;
+  // The location container size, possibly larger than data.
+  //
+  // If the container is larger than the data, the remaining bits are _not_
+  // undefined. For example a uint8 inside a uint32 has the upper 24 bits set
+  // to 0. Effectively allowing the value to be read as uint8, uint16 and
+  // uint32.
+  const NativeType& container_type_;
+};
+
+class NativeRegistersLocation : public NativeLocation {
+ public:
+  NativeRegistersLocation(const NativeType& payload_type,
+                          const NativeType& container_type,
+                          ZoneGrowableArray<Register>* registers)
+      : NativeLocation(payload_type, container_type), regs_(registers) {}
+  NativeRegistersLocation(const NativeType& payload_type,
+                          const NativeType& container_type,
+                          Register reg)
+      : NativeLocation(payload_type, container_type) {
+    regs_ = new ZoneGrowableArray<Register>();
+    regs_->Add(reg);
+  }
+  NativeRegistersLocation(const NativeType& payload_type,
+                          const NativeType& container_type,
+                          Register register1,
+                          Register register2)
+      : NativeLocation(payload_type, container_type) {
+    regs_ = new ZoneGrowableArray<Register>();
+    regs_->Add(register1);
+    regs_->Add(register2);
+  }
+  virtual ~NativeRegistersLocation() {}
+
+  virtual NativeRegistersLocation& WithOtherNativeType(
+      const NativeType& new_payload_type,
+      const NativeType& new_container_type,
+      Zone* zone) const {
+    return *new (zone)
+        NativeRegistersLocation(new_payload_type, new_container_type, regs_);
+  }
+
+  virtual bool IsRegisters() const { return true; }
+  virtual bool IsExpressibleAsLocation() const {
+    return num_regs() == 1 || num_regs() == 2;
+  }
+  virtual Location AsLocation() const;
+  intptr_t num_regs() const { return regs_->length(); }
+  Register reg_at(intptr_t index) const { return regs_->At(index); }
+
+  virtual NativeRegistersLocation& Split(intptr_t index, Zone* zone) const;
+
+  virtual void PrintTo(BufferFormatter* f) const;
+
+  virtual bool Equals(const NativeLocation& other) const;
+
+ private:
+  ZoneGrowableArray<Register>* regs_;
+
+  DISALLOW_COPY_AND_ASSIGN(NativeRegistersLocation);
+};
+
+enum FpuRegisterKind {
+  kQuadFpuReg,    // 16 bytes
+  kDoubleFpuReg,  //  8 bytes, a double
+  kSingleFpuReg   //  4 bytes, a float
+};
+
+intptr_t SizeFromFpuRegisterKind(FpuRegisterKind kind);
+FpuRegisterKind FpuRegisterKindFromSize(intptr_t size_in_bytes);
+
+class NativeFpuRegistersLocation : public NativeLocation {
+ public:
+  NativeFpuRegistersLocation(const NativeType& payload_type,
+                             const NativeType& container_type,
+                             FpuRegisterKind fpu_reg_kind,
+                             intptr_t fpu_register)
+      : NativeLocation(payload_type, container_type),
+        fpu_reg_kind_(fpu_reg_kind),
+        fpu_reg_(fpu_register) {}
+  NativeFpuRegistersLocation(const NativeType& payload_type,
+                             const NativeType& container_type,
+                             FpuRegister fpu_register)
+      : NativeLocation(payload_type, container_type),
+        fpu_reg_kind_(kQuadFpuReg),
+        fpu_reg_(fpu_register) {}
+#if defined(TARGET_ARCH_ARM)
+  NativeFpuRegistersLocation(const NativeType& payload_type,
+                             const NativeType& container_type,
+                             DRegister fpu_register)
+      : NativeLocation(payload_type, container_type),
+        fpu_reg_kind_(kDoubleFpuReg),
+        fpu_reg_(fpu_register) {}
+  NativeFpuRegistersLocation(const NativeType& payload_type,
+                             const NativeType& container_type,
+                             SRegister fpu_register)
+      : NativeLocation(payload_type, container_type),
+        fpu_reg_kind_(kSingleFpuReg),
+        fpu_reg_(fpu_register) {}
+#endif  // defined(TARGET_ARCH_ARM)
+  virtual ~NativeFpuRegistersLocation() {}
+
+  virtual NativeFpuRegistersLocation& WithOtherNativeType(
+      const NativeType& new_payload_type,
+      const NativeType& new_container_type,
+      Zone* zone) const {
+    return *new (zone) NativeFpuRegistersLocation(
+        new_payload_type, new_container_type, fpu_reg_kind_, fpu_reg_);
+  }
+  virtual bool IsFpuRegisters() const { return true; }
+  virtual bool IsExpressibleAsLocation() const {
+    return fpu_reg_kind_ == kQuadFpuReg;
+  }
+  virtual Location AsLocation() const {
+    ASSERT(IsExpressibleAsLocation());
+    return Location::FpuRegisterLocation(fpu_reg());
+  }
+  FpuRegisterKind fpu_reg_kind() const { return fpu_reg_kind_; }
+  FpuRegister fpu_reg() const {
+    ASSERT(fpu_reg_kind_ == kQuadFpuReg);
+    return static_cast<FpuRegister>(fpu_reg_);
+  }
+#if defined(TARGET_ARCH_ARM)
+  DRegister fpu_d_reg() const {
+    ASSERT(fpu_reg_kind_ == kDoubleFpuReg);
+    return static_cast<DRegister>(fpu_reg_);
+  }
+  SRegister fpu_s_reg() const {
+    ASSERT(fpu_reg_kind_ == kSingleFpuReg);
+    return static_cast<SRegister>(fpu_reg_);
+  }
+  DRegister fpu_as_d_reg() const;
+  SRegister fpu_as_s_reg() const;
+
+  bool IsLowestBits() const;
+#endif  // defined(TARGET_ARCH_ARM)
+
+  virtual void PrintTo(BufferFormatter* f) const;
+
+  virtual bool Equals(const NativeLocation& other) const;
+
+ private:
+  FpuRegisterKind fpu_reg_kind_;
+  intptr_t fpu_reg_;
+  DISALLOW_COPY_AND_ASSIGN(NativeFpuRegistersLocation);
+};
+
+class NativeStackLocation : public NativeLocation {
+ public:
+  NativeStackLocation(const NativeType& payload_type,
+                      const NativeType& container_type,
+                      Register base_register,
+                      intptr_t offset_in_bytes)
+      : NativeLocation(payload_type, container_type),
+        base_register_(base_register),
+        offset_in_bytes_(offset_in_bytes) {}
+  virtual ~NativeStackLocation() {}
+
+  virtual NativeStackLocation& WithOtherNativeType(
+      const NativeType& new_payload_type,
+      const NativeType& new_container_type,
+      Zone* zone) const {
+    return *new (zone) NativeStackLocation(new_payload_type, new_container_type,
+                                           base_register_, offset_in_bytes_);
+  }
+
+  virtual bool IsStack() const { return true; }
+  virtual bool IsExpressibleAsLocation() const {
+    const intptr_t size = payload_type().SizeInBytes();
+    const intptr_t size_slots = size / compiler::target::kWordSize;
+    return offset_in_bytes_ % compiler::target::kWordSize == 0 &&
+           size % compiler::target::kWordSize == 0 &&
+           (size_slots == 1 || size_slots == 2);
+  }
+  virtual Location AsLocation() const;
+
+  // ConstantInstr expects DoubleStackSlot for doubles, even on 64-bit systems.
+  //
+  // So this return a wrong-sized Location on purpose.
+  Location AsDoubleStackSlotLocation() const {
+    ASSERT(compiler::target::kWordSize == 8);
+    return Location::DoubleStackSlot(offset_in_words(), base_register_);
+  }
+
+  virtual NativeStackLocation& Split(intptr_t index, Zone* zone) const;
+
+  virtual void PrintTo(BufferFormatter* f) const;
+
+  virtual bool Equals(const NativeLocation& other) const;
+
+  Register base_register() const { return base_register_; }
+  intptr_t offset_in_bytes() const { return offset_in_bytes_; }
+
+ private:
+  intptr_t offset_in_words() const {
+    ASSERT(offset_in_bytes_ % compiler::target::kWordSize == 0);
+    return offset_in_bytes_ / compiler::target::kWordSize;
+  }
+
+  Register base_register_;
+  intptr_t offset_in_bytes_;
+
+  DISALLOW_COPY_AND_ASSIGN(NativeStackLocation);
+};
+
+// Return a memory operand for stack slot locations.
+compiler::Address NativeLocationToStackSlotAddress(
+    const NativeStackLocation& loc);
+
+}  // namespace ffi
+
+}  // namespace compiler
+
+}  // namespace dart
+
+#endif  // RUNTIME_VM_COMPILER_FFI_NATIVE_LOCATION_H_
diff --git a/runtime/vm/compiler/ffi/native_representation.cc b/runtime/vm/compiler/ffi/native_representation.cc
deleted file mode 100644
index 1ccd606..0000000
--- a/runtime/vm/compiler/ffi/native_representation.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (c) 2020, 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.
-
-#include "vm/compiler/ffi/native_representation.h"
-
-#include "platform/assert.h"
-#include "platform/globals.h"
-#include "vm/compiler/backend/locations.h"
-#include "vm/compiler/runtime_api.h"
-#include "vm/object.h"
-
-namespace dart {
-
-namespace compiler {
-
-namespace ffi {
-
-static const size_t kSizeUnknown = 0;
-
-static const intptr_t kNumElementSizes = kFfiVoidCid - kFfiPointerCid + 1;
-
-static const size_t element_size_table[kNumElementSizes] = {
-    target::kWordSize,  // kFfiPointerCid
-    kSizeUnknown,       // kFfiNativeFunctionCid
-    1,                  // kFfiInt8Cid
-    2,                  // kFfiInt16Cid
-    4,                  // kFfiInt32Cid
-    8,                  // kFfiInt64Cid
-    1,                  // kFfiUint8Cid
-    2,                  // kFfiUint16Cid
-    4,                  // kFfiUint32Cid
-    8,                  // kFfiUint64Cid
-    target::kWordSize,  // kFfiIntPtrCid
-    4,                  // kFfiFloatCid
-    8,                  // kFfiDoubleCid
-    kSizeUnknown,       // kFfiVoidCid
-};
-
-size_t ElementSizeInBytes(intptr_t class_id) {
-  ASSERT(class_id != kFfiNativeFunctionCid);
-  ASSERT(class_id != kFfiVoidCid);
-  if (!RawObject::IsFfiTypeClassId(class_id)) {
-    // subtype of Pointer
-    class_id = kFfiPointerCid;
-  }
-  intptr_t index = class_id - kFfiPointerCid;
-  return element_size_table[index];
-}
-
-}  // namespace ffi
-
-}  // namespace compiler
-
-}  // namespace dart
diff --git a/runtime/vm/compiler/ffi/native_representation.h b/runtime/vm/compiler/ffi/native_representation.h
deleted file mode 100644
index 48bcd1a..0000000
--- a/runtime/vm/compiler/ffi/native_representation.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2020, 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.
-
-#ifndef RUNTIME_VM_COMPILER_FFI_NATIVE_REPRESENTATION_H_
-#define RUNTIME_VM_COMPILER_FFI_NATIVE_REPRESENTATION_H_
-
-#include <platform/globals.h>
-
-#include "platform/assert.h"
-#include "vm/allocation.h"
-#include "vm/compiler/backend/locations.h"
-#include "vm/compiler/runtime_api.h"
-
-namespace dart {
-
-namespace compiler {
-
-namespace ffi {
-
-// Storage size for an FFI type (extends 'ffi.NativeType').
-size_t ElementSizeInBytes(intptr_t class_id);
-
-}  // namespace ffi
-
-}  // namespace compiler
-
-}  // namespace dart
-
-#endif  // RUNTIME_VM_COMPILER_FFI_NATIVE_REPRESENTATION_H_
diff --git a/runtime/vm/compiler/ffi/native_type.cc b/runtime/vm/compiler/ffi/native_type.cc
new file mode 100644
index 0000000..e69380c
--- /dev/null
+++ b/runtime/vm/compiler/ffi/native_type.cc
@@ -0,0 +1,329 @@
+// Copyright (c) 2020, 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.
+
+#include "vm/compiler/ffi/native_type.h"
+
+#include "platform/assert.h"
+#include "platform/globals.h"
+#include "vm/compiler/backend/locations.h"
+#include "vm/compiler/runtime_api.h"
+#include "vm/object.h"
+
+namespace dart {
+
+namespace compiler {
+
+namespace ffi {
+
+const NativeFundamentalType& NativeType::AsFundamental() const {
+  ASSERT(IsFundamental());
+  return static_cast<const NativeFundamentalType&>(*this);
+}
+
+bool NativeFundamentalType::IsInt() const {
+  switch (representation_) {
+    case kInt8:
+    case kUint8:
+    case kInt16:
+    case kUint16:
+    case kInt32:
+    case kUint32:
+    case kInt64:
+    case kUint64:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool NativeFundamentalType::IsFloat() const {
+  return representation_ == kFloat || representation_ == kDouble ||
+         representation_ == kHalfDouble;
+}
+
+bool NativeFundamentalType::IsVoid() const {
+  return representation_ == kVoid;
+}
+
+bool NativeFundamentalType::IsSigned() const {
+  ASSERT(IsInt() || IsFloat());
+  switch (representation_) {
+    case kInt8:
+    case kInt16:
+    case kInt32:
+    case kInt64:
+    case kFloat:
+    case kDouble:
+    case kHalfDouble:
+      return true;
+    case kUint8:
+    case kUint16:
+    case kUint32:
+    case kUint64:
+    default:
+      return false;
+  }
+}
+
+static const intptr_t fundamental_size_in_bytes[kVoid + 1] = {
+    1,  // kInt8,
+    1,  // kUint8,
+    2,  // kInt16,
+    2,  // kUint16,
+    4,  // kInt32,
+    4,  // kUint32,
+    8,  // kInt64,
+    8,  // kUint64,
+    4,  // kFloat,
+    8,  // kDouble,
+    4,  // kHalfDouble
+    0,  // kVoid,
+};
+
+intptr_t NativeFundamentalType::SizeInBytes() const {
+  return fundamental_size_in_bytes[representation_];
+}
+
+intptr_t NativeFundamentalType::AlignmentInBytesStack() const {
+  switch (CallingConventions::kArgumentStackAlignment) {
+    case kAlignedToWordSize:
+      // The default is to align stack arguments to word size.
+      return compiler::target::kWordSize;
+    case kAlignedToWordSizeBut8AlignedTo8: {
+      // However, arm32 deviates slightly.
+      if (SizeInBytes() == 8) {
+        return 8;
+      }
+      return compiler::target::kWordSize;
+    }
+    case kAlignedToValueSize:
+      // iOS on arm64 only aligns to size.
+      return SizeInBytes();
+  }
+  UNREACHABLE();
+}
+
+intptr_t NativeFundamentalType::AlignmentInBytesField() const {
+  switch (CallingConventions::kFieldAlignment) {
+    case kAlignedToValueSize:
+      // The default is to align fields to their own size.
+      return SizeInBytes();
+    case kAlignedToValueSizeBut8AlignedTo4: {
+      // However, on some 32-bit architectures, 8-byte fields are only aligned
+      // to 4 bytes.
+      if (SizeInBytes() == 8) {
+        return 4;
+      }
+      return SizeInBytes();
+    }
+  }
+  UNREACHABLE();
+}
+
+bool NativeFundamentalType::IsExpressibleAsRepresentation() const {
+  switch (representation_) {
+    case kInt8:
+    case kUint8:
+    case kInt16:
+    case kUint16:
+    case kHalfDouble:
+      return false;
+    case kInt32:
+    case kUint32:
+    case kInt64:
+    case kUint64:
+    case kFloat:
+    case kDouble:
+      return true;
+    case kVoid:
+      return true;
+    default:
+      UNREACHABLE();  // Make MSVC happy.
+  }
+}
+
+Representation NativeFundamentalType::AsRepresentation() const {
+  ASSERT(IsExpressibleAsRepresentation());
+  switch (representation_) {
+    case kInt32:
+      return kUnboxedInt32;
+    case kUint32:
+      return kUnboxedUint32;
+    case kInt64:
+    case kUint64:
+      return kUnboxedInt64;
+    case kFloat:
+      return kUnboxedFloat;
+    case kDouble:
+      return kUnboxedDouble;
+    case kVoid:
+      return kUnboxedFfiIntPtr;
+    default:
+      UNREACHABLE();
+  }
+}
+
+bool NativeFundamentalType::Equals(const NativeType& other) const {
+  if (!other.IsFundamental()) {
+    return false;
+  }
+  return other.AsFundamental().representation_ == representation_;
+}
+
+static FundamentalType split_fundamental(FundamentalType in) {
+  switch (in) {
+    case kInt16:
+      return kInt8;
+    case kInt32:
+      return kInt16;
+    case kInt64:
+      return kInt32;
+    case kUint16:
+      return kUint8;
+    case kUint32:
+      return kUint16;
+    case kUint64:
+      return kUint32;
+    case kDouble:
+      return kHalfDouble;
+    default:
+      UNREACHABLE();
+  }
+}
+
+NativeFundamentalType& NativeFundamentalType::Split(intptr_t index,
+                                                    Zone* zone) const {
+  ASSERT(index == 0 || index == 1);
+  auto new_rep = split_fundamental(representation());
+  return *new (zone) NativeFundamentalType(new_rep);
+}
+
+static FundamentalType TypeRepresentation(classid_t class_id) {
+  switch (class_id) {
+    case kFfiInt8Cid:
+      return kInt8;
+    case kFfiInt16Cid:
+      return kInt16;
+    case kFfiInt32Cid:
+      return kInt32;
+    case kFfiUint8Cid:
+      return kUint8;
+    case kFfiUint16Cid:
+      return kUint16;
+    case kFfiUint32Cid:
+      return kUint32;
+    case kFfiInt64Cid:
+    case kFfiUint64Cid:
+      return kInt64;
+    case kFfiIntPtrCid:
+      return compiler::target::kWordSize == 4 ? kInt32 : kInt64;
+    case kFfiFloatCid:
+      return kFloat;
+    case kFfiDoubleCid:
+      return kDouble;
+    case kFfiPointerCid:
+      return compiler::target::kWordSize == 4 ? kUint32 : kInt64;
+    case kFfiVoidCid:
+      return kVoid;
+    default:
+      UNREACHABLE();
+  }
+}
+
+NativeType& NativeType::FromTypedDataClassId(classid_t class_id, Zone* zone) {
+  // TODO(36730): Support composites.
+  const auto fundamental_rep = TypeRepresentation(class_id);
+  return *new (zone) NativeFundamentalType(fundamental_rep);
+}
+
+NativeType& NativeType::FromAbstractType(const AbstractType& type, Zone* zone) {
+  // TODO(36730): Support composites.
+  return NativeType::FromTypedDataClassId(type.type_class_id(), zone);
+}
+
+static FundamentalType fundamental_rep(Representation rep) {
+  switch (rep) {
+    case kUnboxedDouble:
+      return kDouble;
+    case kUnboxedFloat:
+      return kFloat;
+    case kUnboxedInt32:
+      return kInt32;
+    case kUnboxedUint32:
+      return kUint32;
+    case kUnboxedInt64:
+      return kInt64;
+    default:
+      break;
+  }
+  UNREACHABLE();
+}
+
+NativeFundamentalType& NativeType::FromUnboxedRepresentation(Representation rep,
+                                                             Zone* zone) {
+  return *new (zone) NativeFundamentalType(fundamental_rep(rep));
+}
+
+const char* NativeType::ToCString() const {
+  char buffer[1024];
+  BufferFormatter bf(buffer, 1024);
+  PrintTo(&bf);
+  return Thread::Current()->zone()->MakeCopyOfString(buffer);
+}
+
+static const char* FundamentalTypeToCString(FundamentalType rep) {
+  switch (rep) {
+    case kInt8:
+      return "int8";
+    case kUint8:
+      return "uint8";
+    case kInt16:
+      return "int16";
+    case kUint16:
+      return "uint16";
+    case kInt32:
+      return "int32";
+    case kUint32:
+      return "uint32";
+    case kInt64:
+      return "int64";
+    case kUint64:
+      return "uint64";
+    case kFloat:
+      return "float";
+    case kDouble:
+      return "double";
+    case kHalfDouble:
+      return "half-double";
+    case kVoid:
+      return "void";
+    default:
+      UNREACHABLE();
+  }
+}
+
+void NativeType::PrintTo(BufferFormatter* f) const {
+  f->Print("I");
+}
+
+void NativeFundamentalType::PrintTo(BufferFormatter* f) const {
+  f->Print("%s", FundamentalTypeToCString(representation_));
+}
+
+const NativeType& NativeType::WidenTo4Bytes(Zone* zone) const {
+  if (IsInt() && SizeInBytes() <= 2) {
+    if (IsSigned()) {
+      return *new (zone) NativeFundamentalType(kInt32);
+    } else {
+      return *new (zone) NativeFundamentalType(kUint32);
+    }
+  }
+  return *this;
+}
+
+}  // namespace ffi
+
+}  // namespace compiler
+
+}  // namespace dart
diff --git a/runtime/vm/compiler/ffi/native_type.h b/runtime/vm/compiler/ffi/native_type.h
new file mode 100644
index 0000000..ddd6941
--- /dev/null
+++ b/runtime/vm/compiler/ffi/native_type.h
@@ -0,0 +1,158 @@
+// Copyright (c) 2020, 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.
+
+#ifndef RUNTIME_VM_COMPILER_FFI_NATIVE_TYPE_H_
+#define RUNTIME_VM_COMPILER_FFI_NATIVE_TYPE_H_
+
+#include <platform/globals.h>
+
+#include "platform/assert.h"
+#include "vm/allocation.h"
+#include "vm/compiler/backend/locations.h"
+#include "vm/compiler/runtime_api.h"
+
+namespace dart {
+
+namespace compiler {
+
+namespace ffi {
+
+class NativeFundamentalType;
+
+// NativeTypes are the types used in calling convention specifications:
+// integers, floats, and composites.
+//
+// NativeTypes exclude C types which are not discussed in calling conventions:
+// pointer types (they are lowered to integers).
+//
+// The NativeTypes are a partially overlapping with unboxed Representations.
+// NativeTypes do not have Dart representations such as the following:
+// * tagged
+// * untagged
+//
+// Instead, NativeTypes support representations not supprted in Dart's unboxed
+// Representations, such as:
+// * Fundamental types (https://en.cppreference.com/w/cpp/language/types):
+//   * int8_t
+//   * int16_t
+//   * uint8_t
+//   * uint16t
+//   * void
+// * Compound types (https://en.cppreference.com/w/cpp/language/type):
+//   * Struct
+//   * Union
+//
+// TODO(36730): Add composites.
+class NativeType : public ZoneAllocated {
+ public:
+  static NativeType& FromAbstractType(const AbstractType& type, Zone* zone);
+  static NativeType& FromTypedDataClassId(classid_t class_id, Zone* zone);
+  static NativeFundamentalType& FromUnboxedRepresentation(Representation rep,
+                                                          Zone* zone);
+
+  virtual bool IsFundamental() const { return false; }
+  const NativeFundamentalType& AsFundamental() const;
+
+  virtual bool IsInt() const { return false; }
+  virtual bool IsFloat() const { return false; }
+  virtual bool IsVoid() const { return false; }
+
+  virtual bool IsSigned() const = 0;
+
+  // The size in bytes of this representation.
+  //
+  // Does not take into account padding required if repeating.
+  virtual intptr_t SizeInBytes() const = 0;
+
+  // The alignment in bytes of this represntation on the stack.
+  virtual intptr_t AlignmentInBytesStack() const = 0;
+
+  // The alignment in bytes of this representation as member of a composite.
+  virtual intptr_t AlignmentInBytesField() const = 0;
+
+  // NativeTypes which are available as unboxed Representations.
+  virtual bool IsExpressibleAsRepresentation() const { return false; }
+
+  // Unboxed Representation if it exists.
+  virtual Representation AsRepresentation() const = 0;
+
+  // Unboxed Representation, over approximates if needed.
+  Representation AsRepresentationOverApprox(Zone* zone_) const {
+    const auto& widened = WidenTo4Bytes(zone_);
+    return widened.AsRepresentation();
+  }
+
+  virtual bool Equals(const NativeType& other) const { UNREACHABLE(); }
+
+  // Split representation in two.
+  virtual NativeType& Split(intptr_t index, Zone* zone) const { UNREACHABLE(); }
+
+  // If this is a 8 or 16 bit int, returns a 32 bit container.
+  // Otherwise, return original representation.
+  const NativeType& WidenTo4Bytes(Zone* zone) const;
+
+  virtual void PrintTo(BufferFormatter* f) const;
+  const char* ToCString() const;
+
+  virtual ~NativeType() {}
+
+ protected:
+  NativeType() {}
+};
+
+enum FundamentalType {
+  kInt8,
+  kUint8,
+  kInt16,
+  kUint16,
+  kInt32,
+  kUint32,
+  kInt64,
+  kUint64,
+  kFloat,
+  kDouble,
+  kHalfDouble,  // When doubles are split over two 32 bit locations.
+  kVoid,
+  // TODO(37470): Add packed data structures.
+};
+
+class NativeFundamentalType : public NativeType {
+ public:
+  explicit NativeFundamentalType(FundamentalType rep) : representation_(rep) {}
+
+  FundamentalType representation() const { return representation_; }
+
+  virtual bool IsFundamental() const { return true; }
+
+  virtual bool IsInt() const;
+  virtual bool IsFloat() const;
+  virtual bool IsVoid() const;
+
+  virtual bool IsSigned() const;
+
+  virtual intptr_t SizeInBytes() const;
+  virtual intptr_t AlignmentInBytesStack() const;
+  virtual intptr_t AlignmentInBytesField() const;
+
+  virtual bool IsExpressibleAsRepresentation() const;
+  virtual Representation AsRepresentation() const;
+
+  virtual bool Equals(const NativeType& other) const;
+  virtual NativeFundamentalType& Split(intptr_t part, Zone* zone) const;
+
+  virtual void PrintTo(BufferFormatter* f) const;
+
+  virtual ~NativeFundamentalType() {}
+
+ private:
+  const FundamentalType representation_;
+};
+
+}  // namespace ffi
+
+}  // namespace compiler
+
+}  // namespace dart
+
+#endif  // RUNTIME_VM_COMPILER_FFI_NATIVE_TYPE_H_
diff --git a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
index 58641e6..cfda6ce 100644
--- a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
+++ b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
@@ -1928,7 +1928,7 @@
       TypeArguments::Cast(B->Peek(/*depth=*/2)->AsConstant()->value());
   ASSERT(type_args.IsInstantiated() && type_args.Length() == 1);
   const Function& native_sig = Function::Handle(
-      Z, Type::Cast(AbstractType::Handle(Z, type_args.TypeAt(0))).signature());
+      Z, Type::CheckedHandle(Z, type_args.TypeAt(0)).signature());
 
   const Closure& target_closure =
       Closure::Cast(B->Peek(/*depth=*/1)->AsConstant()->value());
diff --git a/runtime/vm/compiler/frontend/bytecode_reader.cc b/runtime/vm/compiler/frontend/bytecode_reader.cc
index 616e9f3..3348981 100644
--- a/runtime/vm/compiler/frontend/bytecode_reader.cc
+++ b/runtime/vm/compiler/frontend/bytecode_reader.cc
@@ -2017,7 +2017,14 @@
     field.set_is_extension_member(is_extension_member);
     field.set_has_initializer(has_initializer);
 
-    if (!has_nontrivial_initializer) {
+    if (has_nontrivial_initializer) {
+      if (field.is_late()) {
+        // Late fields are initialized to Object::sentinel, which is a flavor of
+        // null. So we need to record that store so that the field guard doesn't
+        // prematurely optimise out the late field's sentinel checking logic.
+        field.RecordStore(Object::null_object());
+      }
+    } else {
       value ^= ReadObject();
       if (is_static) {
         if (field.is_late() && !has_initializer) {
diff --git a/runtime/vm/compiler/frontend/flow_graph_builder.cc b/runtime/vm/compiler/frontend/flow_graph_builder.cc
index c10afcd..9d8855f 100644
--- a/runtime/vm/compiler/frontend/flow_graph_builder.cc
+++ b/runtime/vm/compiler/frontend/flow_graph_builder.cc
@@ -380,7 +380,9 @@
     // type arguments, then we can still use the _simpleInstanceOf
     // implementation (see also runtime/lib/object.cc:Object_SimpleInstanceOf).
     const auto& rare_type = AbstractType::Handle(type_class.RareType());
-    return rare_type.IsEquivalent(type, /* syntactically = */ true);
+    // TODO(regis): Revisit the usage of TypeEquality::kSyntactical when
+    // implementing strong mode.
+    return rare_type.IsEquivalent(type, TypeEquality::kSyntactical);
   }
 
   // Finally a simple class for instance of checking.
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index 3db08e1..fd826d9 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -200,10 +200,6 @@
     }
     return Fragment();
   }
-  // Late fields are initialized to Object::sentinel, which is a flavor of null.
-  // So we need to record that store so that the field guard doesn't prematurely
-  // optimise out the late field's sentinel checking logic.
-  field.RecordStore(Object::null_object());
 
   Fragment instructions;
   instructions += LoadLocal(parsed_function()->receiver_var());
@@ -3572,17 +3568,21 @@
   TokenPosition position = ReadPosition();  // read position.
   if (p != NULL) *p = position;
 
+  NNBDMode nnbd_mode;
   if (translation_helper_.info().kernel_binary_version() >= 38) {
-    // TODO(alexmarkov): Handle flags.
-    ReadFlags();  // read flags.
+    const uint8_t flags = ReadFlags();  // read flags.
+    nnbd_mode = ((flags & kIsExpressionFlagForNonNullableByDefault) != 0)
+                    ? NNBDMode::kOptedInLib
+                    : NNBDMode::kLegacyLib;
+  } else {
+    nnbd_mode = parsed_function()->function().nnbd_mode();
   }
+  ASSERT(nnbd_mode == parsed_function()->function().nnbd_mode());
 
   Fragment instructions = BuildExpression();  // read operand.
 
   const AbstractType& type = T.BuildType();  // read type.
 
-  const NNBDMode nnbd_mode = parsed_function()->function().nnbd_mode();
-
   // The VM does not like an instanceOf call with a dynamic type. We need to
   // special case this situation by detecting a top type.
   if (type.IsTopType(nnbd_mode)) {
@@ -3628,14 +3628,17 @@
   TokenPosition position = ReadPosition();  // read position.
   if (p != NULL) *p = position;
 
-  // TODO(alexmarkov): Handle new flags.
   const uint8_t flags = ReadFlags();  // read flags.
-  const bool is_type_error = (flags & (1 << 0)) != 0;
+  const bool is_type_error = (flags & kAsExpressionFlagTypeError) != 0;
+  const NNBDMode nnbd_mode =
+      ((flags & kAsExpressionFlagForNonNullableByDefault) != 0)
+          ? NNBDMode::kOptedInLib
+          : NNBDMode::kLegacyLib;
+  ASSERT(nnbd_mode == parsed_function()->function().nnbd_mode());
 
   Fragment instructions = BuildExpression();  // read operand.
 
   const AbstractType& type = T.BuildType();  // read type.
-  const NNBDMode nnbd_mode = parsed_function()->function().nnbd_mode();
   if (type.IsInstantiated() && type.IsTopType(nnbd_mode)) {
     // We already evaluated the operand on the left and just leave it there as
     // the result of the `obj as dynamic` expression.
@@ -5165,8 +5168,7 @@
       T.BuildTypeArguments(list_length);  // read types.
   ASSERT(type_arguments.Length() == 1 && type_arguments.IsInstantiated());
   const Function& native_sig = Function::Handle(
-      Z, Type::Cast(AbstractType::Handle(Z, type_arguments.TypeAt(0)))
-             .signature());
+      Z, Type::CheckedHandle(Z, type_arguments.TypeAt(0)).signature());
 
   Fragment code;
   const intptr_t positional_count =
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 2a4574d..ea5bf45 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -11,7 +11,6 @@
 #include "vm/compiler/backend/locations.h"
 #include "vm/compiler/ffi/abi.h"
 #include "vm/compiler/ffi/marshaller.h"
-#include "vm/compiler/ffi/native_representation.h"
 #include "vm/compiler/ffi/recognized_method.h"
 #include "vm/compiler/frontend/kernel_binary_flowgraph.h"
 #include "vm/compiler/frontend/kernel_translation_helper.h"
@@ -372,13 +371,11 @@
 }
 
 Fragment FlowGraphBuilder::FfiCall(
-    const Function& signature,
-    const ZoneGrowableArray<Representation>& arg_reps,
-    const ZoneGrowableArray<Location>& arg_locs) {
+    const compiler::ffi::CallMarshaller& marshaller) {
   Fragment body;
 
   FfiCallInstr* const call =
-      new (Z) FfiCallInstr(Z, GetNextDeoptId(), signature, arg_reps, arg_locs);
+      new (Z) FfiCallInstr(Z, GetNextDeoptId(), marshaller);
 
   for (intptr_t i = call->InputCount() - 1; i >= 0; --i) {
     call->SetInputAt(i, Pop());
@@ -1211,8 +1208,8 @@
           compiler::ffi::RecognizedMethodTypeArgCid(kind);
       const classid_t typed_data_cid =
           compiler::ffi::ElementTypedDataCid(ffi_type_arg_cid);
-      const Representation representation =
-          compiler::ffi::TypeRepresentation(ffi_type_arg_cid);
+      const auto& native_rep = compiler::ffi::NativeType::FromTypedDataClassId(
+          ffi_type_arg_cid, zone_);
 
       // Check Dart signature type.
       const auto& receiver_type =
@@ -1233,7 +1230,7 @@
       body += CheckNullOptimized(TokenPosition::kNoSource,
                                  String::ZoneHandle(Z, function.name()));
       body += UnboxTruncate(kUnboxedFfiIntPtr);
-      body += IntConstant(compiler::ffi::ElementSizeInBytes(ffi_type_arg_cid));
+      body += IntConstant(native_rep.SizeInBytes());
       body += UnboxTruncate(kUnboxedIntPtr);
       // TODO(38831): Implement Shift for Uint32, and use that instead.
       body +=
@@ -1250,7 +1247,7 @@
         }
         body += Box(kUnboxedDouble);
       } else {
-        body += Box(representation);
+        body += Box(native_rep.AsRepresentationOverApprox(zone_));
         if (kind == MethodRecognizer::kFfiLoadPointer) {
           const auto class_table = thread_->isolate()->class_table();
           ASSERT(class_table->HasValidClassAt(kFfiPointerCid));
@@ -1301,8 +1298,8 @@
           compiler::ffi::RecognizedMethodTypeArgCid(kind);
       const classid_t typed_data_cid =
           compiler::ffi::ElementTypedDataCid(ffi_type_arg_cid);
-      const Representation representation =
-          compiler::ffi::TypeRepresentation(ffi_type_arg_cid);
+      const auto& native_rep = compiler::ffi::NativeType::FromTypedDataClassId(
+          ffi_type_arg_cid, zone_);
 
       // Check Dart signature type.
       const auto& receiver_type =
@@ -1365,7 +1362,7 @@
       body += CheckNullOptimized(TokenPosition::kNoSource,
                                  String::ZoneHandle(Z, function.name()));
       body += UnboxTruncate(kUnboxedFfiIntPtr);
-      body += IntConstant(compiler::ffi::ElementSizeInBytes(ffi_type_arg_cid));
+      body += IntConstant(native_rep.SizeInBytes());
       body += UnboxTruncate(kUnboxedFfiIntPtr);
       // TODO(38831): Implement Shift for Uint32, and use that instead.
       body +=
@@ -1386,7 +1383,7 @@
           body += DoubleToFloat();
         }
       } else {
-        body += UnboxTruncate(representation);
+        body += UnboxTruncate(native_rep.AsRepresentationOverApprox(zone_));
       }
       body += StoreIndexedTypedData(typed_data_cid);
       body += NullConstant();
@@ -2799,22 +2796,10 @@
   return Fragment(box);
 }
 
-Fragment FlowGraphBuilder::FfiUnboxedExtend(Representation representation,
-                                            const AbstractType& ffi_type) {
-  const SmallRepresentation from_representation =
-      compiler::ffi::TypeSmallRepresentation(ffi_type);
-  if (from_representation == kNoSmallRepresentation) return {};
-
-  auto* extend = new (Z)
-      UnboxedWidthExtenderInstr(Pop(), representation, from_representation);
-  Push(extend);
-  return Fragment(extend);
-}
-
-Fragment FlowGraphBuilder::NativeReturn(Representation result) {
-  auto* instr = new (Z)
-      NativeReturnInstr(TokenPosition::kNoSource, Pop(), result,
-                        compiler::ffi::ResultLocation(result), DeoptId::kNone);
+Fragment FlowGraphBuilder::NativeReturn(
+    const compiler::ffi::CallbackMarshaller& marshaller) {
+  auto* instr = new (Z) NativeReturnInstr(TokenPosition::kNoSource, Pop(),
+                                          marshaller, DeoptId::kNone);
   return Fragment(instr);
 }
 
@@ -2858,54 +2843,48 @@
 }
 
 Fragment FlowGraphBuilder::FfiConvertArgumentToDart(
-    const AbstractType& ffi_type,
-    const Representation native_representation) {
+    const compiler::ffi::BaseMarshaller& marshaller,
+    intptr_t arg_index) {
   Fragment body;
-  if (compiler::ffi::NativeTypeIsPointer(ffi_type)) {
+  if (marshaller.IsPointer(arg_index)) {
     body += Box(kUnboxedFfiIntPtr);
-    body += FfiPointerFromAddress(Type::Cast(ffi_type));
-  } else if (compiler::ffi::NativeTypeIsVoid(ffi_type)) {
+    body += FfiPointerFromAddress(
+        Type::CheckedHandle(Z, marshaller.CType(arg_index)));
+  } else if (marshaller.IsVoid(arg_index)) {
     body += Drop();
     body += NullConstant();
   } else {
-    const Representation from_rep = native_representation;
-    const Representation to_rep =
-        compiler::ffi::TypeRepresentation(ffi_type.type_class_id());
-    if (from_rep != to_rep) {
-      body += BitCast(from_rep, to_rep);
-    } else {
-      body += FfiUnboxedExtend(from_rep, ffi_type);
+    if (marshaller.RequiresBitCast(arg_index)) {
+      body += BitCast(marshaller.RepInFfiCall(arg_index),
+                      marshaller.RepInDart(arg_index));
     }
-    body += Box(to_rep);
+
+    body += Box(marshaller.RepInDart(arg_index));
   }
   return body;
 }
 
 Fragment FlowGraphBuilder::FfiConvertArgumentToNative(
-    const Function& function,
-    const AbstractType& ffi_type,
-    const Representation native_representation) {
+    const compiler::ffi::BaseMarshaller& marshaller,
+    intptr_t arg_index) {
   Fragment body;
 
   // Check for 'null'.
+  // TODO(36780): Mention the param name instead of function name and reciever.
   body += CheckNullOptimized(TokenPosition::kNoSource,
-                             String::ZoneHandle(Z, function.name()));
+                             String::ZoneHandle(Z, marshaller.function_name()));
 
-  if (compiler::ffi::NativeTypeIsPointer(ffi_type)) {
+  if (marshaller.IsPointer(arg_index)) {
     body += LoadNativeField(Slot::Pointer_c_memory_address());
-    body += UnboxTruncate(kUnboxedFfiIntPtr);
-  } else {
-    Representation from_rep =
-        compiler::ffi::TypeRepresentation(ffi_type.type_class_id());
-    body += UnboxTruncate(from_rep);
-
-    Representation to_rep = native_representation;
-    if (from_rep != to_rep) {
-      body += BitCast(from_rep, to_rep);
-    } else {
-      body += FfiUnboxedExtend(from_rep, ffi_type);
-    }
   }
+
+  body += UnboxTruncate(marshaller.RepInDart(arg_index));
+
+  if (marshaller.RequiresBitCast(arg_index)) {
+    body += BitCast(marshaller.RepInDart(arg_index),
+                    marshaller.RepInFfiCall(arg_index));
+  }
+
   return body;
 }
 
@@ -2933,19 +2912,15 @@
   Fragment body(instruction_cursor);
   body += CheckStackOverflowInPrologue(function.token_pos());
 
-  const Function& signature = Function::ZoneHandle(Z, function.FfiCSignature());
-  const auto& arg_reps = *compiler::ffi::ArgumentRepresentations(signature);
-  const auto& arg_locs = *compiler::ffi::ArgumentLocations(arg_reps);
+  const auto& marshaller = *new (Z) compiler::ffi::CallMarshaller(Z, function);
 
   BuildArgumentTypeChecks(TypeChecksToBuild::kCheckAllTypeParameterBounds,
                           &body, &body, &body);
 
   // Unbox and push the arguments.
-  AbstractType& ffi_type = AbstractType::Handle(Z);
-  for (intptr_t pos = 1; pos < function.num_fixed_parameters(); pos++) {
-    body += LoadLocal(parsed_function_->ParameterVariable(pos));
-    ffi_type = signature.ParameterTypeAt(pos);
-    body += FfiConvertArgumentToNative(function, ffi_type, arg_reps[pos - 1]);
+  for (intptr_t i = 0; i < marshaller.num_args(); i++) {
+    body += LoadLocal(parsed_function_->ParameterVariable(i + 1));
+    body += FfiConvertArgumentToNative(marshaller, i);
   }
 
   // Push the function pointer, which is stored (boxed) in the first slot of the
@@ -2957,12 +2932,10 @@
                     Z, Class::Handle(I->object_store()->ffi_pointer_class()))
                     ->context_variables()[0]));
   body += UnboxTruncate(kUnboxedFfiIntPtr);
-  body += FfiCall(signature, arg_reps, arg_locs);
+  body += FfiCall(marshaller);
 
-  ffi_type = signature.result_type();
-  const Representation from_rep =
-      compiler::ffi::ResultRepresentation(signature);
-  body += FfiConvertArgumentToDart(ffi_type, from_rep);
+  body += FfiConvertArgumentToDart(marshaller, compiler::ffi::kResultIndex);
+
   body += Return(TokenPosition::kNoSource);
 
   return new (Z) FlowGraph(*parsed_function_, graph_entry_, last_used_block_id_,
@@ -2970,18 +2943,14 @@
 }
 
 FlowGraph* FlowGraphBuilder::BuildGraphOfFfiCallback(const Function& function) {
-  const Function& signature = Function::ZoneHandle(Z, function.FfiCSignature());
-  const auto& arg_reps = *compiler::ffi::ArgumentRepresentations(signature);
-  const auto& arg_locs = *compiler::ffi::ArgumentLocations(arg_reps);
-  const auto& callback_locs =
-      *compiler::ffi::CallbackArgumentTranslator::TranslateArgumentLocations(
-          arg_locs);
+  const auto& marshaller =
+      *new (Z) compiler::ffi::CallbackMarshaller(Z, function);
 
   graph_entry_ =
       new (Z) GraphEntryInstr(*parsed_function_, Compiler::kNoOSRDeoptId);
 
   auto* const native_entry = new (Z) NativeEntryInstr(
-      &arg_locs, graph_entry_, AllocateBlockId(), CurrentTryIndex(),
+      marshaller, graph_entry_, AllocateBlockId(), CurrentTryIndex(),
       GetNextDeoptId(), function.FfiCallbackId());
 
   graph_entry_->set_normal_entry(native_entry);
@@ -2996,14 +2965,11 @@
   ++try_depth_;
 
   // Box and push the arguments.
-  AbstractType& ffi_type = AbstractType::Handle(Z);
-  for (intptr_t i = 0, n = callback_locs.length(); i < n; ++i) {
-    ffi_type = signature.ParameterTypeAt(i + 1);
-    auto* parameter =
-        new (Z) NativeParameterInstr(callback_locs[i], arg_reps[i]);
+  for (intptr_t i = 0; i < marshaller.num_args(); i++) {
+    auto* parameter = new (Z) NativeParameterInstr(marshaller, i);
     Push(parameter);
     body <<= parameter;
-    body += FfiConvertArgumentToDart(ffi_type, arg_reps[i]);
+    body += FfiConvertArgumentToDart(marshaller, i);
   }
 
   // Call the target.
@@ -3012,14 +2978,11 @@
   // rebind-rule accordingly.
   body += StaticCall(TokenPosition::kNoSource,
                      Function::ZoneHandle(Z, function.FfiCallbackTarget()),
-                     callback_locs.length(), Array::empty_array(),
+                     marshaller.num_args(), Array::empty_array(),
                      ICData::kNoRebind);
 
-  ffi_type = signature.result_type();
-  const Representation result_rep =
-      compiler::ffi::ResultRepresentation(signature);
-  body += FfiConvertArgumentToNative(function, ffi_type, result_rep);
-  body += NativeReturn(result_rep);
+  body += FfiConvertArgumentToNative(marshaller, compiler::ffi::kResultIndex);
+  body += NativeReturn(marshaller);
 
   --try_depth_;
   function_body += body;
@@ -3033,18 +2996,19 @@
   //
   // For pointer and void return types, the exceptional return is always null --
   // return 0 instead.
-  if (compiler::ffi::NativeTypeIsPointer(ffi_type) ||
-      compiler::ffi::NativeTypeIsVoid(ffi_type)) {
+  if (marshaller.IsPointer(compiler::ffi::kResultIndex) ||
+      marshaller.IsVoid(compiler::ffi::kResultIndex)) {
     ASSERT(function.FfiCallbackExceptionalReturn() == Object::null());
     catch_body += IntConstant(0);
     catch_body += UnboxTruncate(kUnboxedFfiIntPtr);
   } else {
     catch_body += Constant(
         Instance::ZoneHandle(Z, function.FfiCallbackExceptionalReturn()));
-    catch_body += FfiConvertArgumentToNative(function, ffi_type, result_rep);
+    catch_body +=
+        FfiConvertArgumentToNative(marshaller, compiler::ffi::kResultIndex);
   }
 
-  catch_body += NativeReturn(result_rep);
+  catch_body += NativeReturn(marshaller);
   --catch_depth_;
 
   PrologueInfo prologue_info(-1, -1);
@@ -3059,6 +3023,7 @@
 }
 
 }  // namespace kernel
+
 }  // namespace dart
 
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.h b/runtime/vm/compiler/frontend/kernel_to_il.h
index 595977a..564fb8f 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.h
+++ b/runtime/vm/compiler/frontend/kernel_to_il.h
@@ -12,6 +12,8 @@
 
 #include "vm/compiler/backend/flow_graph.h"
 #include "vm/compiler/backend/il.h"
+#include "vm/compiler/ffi/marshaller.h"
+#include "vm/compiler/ffi/native_type.h"
 #include "vm/compiler/frontend/base_flow_graph_builder.h"
 #include "vm/compiler/frontend/kernel_translation_helper.h"
 #include "vm/compiler/frontend/scope_builder.h"
@@ -124,9 +126,7 @@
       const CallSiteAttributesMetadata* call_site_attrs = nullptr,
       bool receiver_is_not_smi = false);
 
-  Fragment FfiCall(const Function& signature,
-                   const ZoneGrowableArray<Representation>& arg_reps,
-                   const ZoneGrowableArray<Location>& arg_locs);
+  Fragment FfiCall(const compiler::ffi::CallMarshaller& marshaller);
 
   Fragment ThrowException(TokenPosition position);
   Fragment RethrowException(TokenPosition position, int catch_try_index);
@@ -193,11 +193,6 @@
   // Sign-extends kUnboxedInt32 and zero-extends kUnboxedUint32.
   Fragment Box(Representation from);
 
-  // Sign- or zero-extends an integer parameter or return value for an FFI call
-  // as necessary.
-  Fragment FfiUnboxedExtend(Representation representation,
-                            const AbstractType& ffi_type);
-
   // Creates an ffi.Pointer holding a given address (TOS).
   Fragment FfiPointerFromAddress(const Type& result_type);
 
@@ -209,17 +204,17 @@
   // Pops a Dart object and push the unboxed native version, according to the
   // semantics of FFI argument translation.
   Fragment FfiConvertArgumentToNative(
-      const Function& function,
-      const AbstractType& ffi_type,
-      const Representation native_representation);
+      const compiler::ffi::BaseMarshaller& marshaller,
+      intptr_t arg_index);
 
   // Reverse of 'FfiConvertArgumentToNative'.
-  Fragment FfiConvertArgumentToDart(const AbstractType& ffi_type,
-                                    const Representation native_representation);
+  Fragment FfiConvertArgumentToDart(
+      const compiler::ffi::BaseMarshaller& marshaller,
+      intptr_t arg_index);
 
   // Return from a native -> Dart callback. Can only be used in conjunction with
   // NativeEntry and NativeParameter are used.
-  Fragment NativeReturn(Representation result);
+  Fragment NativeReturn(const compiler::ffi::CallbackMarshaller& marshaller);
 
   // Bit-wise cast between representations.
   // Pops the input and pushes the converted result.
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
index 9c916a1..17befed 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
@@ -1730,12 +1730,15 @@
 }
 
 void ProcedureAttributesMetadata::InitializeFromFlags(uint8_t flags) {
-  const int kDynamicUsesBit = 1 << 0;
+  const int kMethodOrSetterCalledDynamicallyBit = 1 << 0;
   const int kNonThisUsesBit = 1 << 1;
   const int kTearOffUsesBit = 1 << 2;
   const int kThisUsesBit = 1 << 3;
+  const int kGetterCalledDynamicallyBit = 1 << 4;
 
-  has_dynamic_invocations = (flags & kDynamicUsesBit) != 0;
+  method_or_setter_called_dynamically =
+      (flags & kMethodOrSetterCalledDynamicallyBit) != 0;
+  getter_called_dynamically = (flags & kGetterCalledDynamicallyBit) != 0;
   has_this_uses = (flags & kThisUsesBit) != 0;
   has_non_this_uses = (flags & kNonThisUsesBit) != 0;
   has_tearoff_uses = (flags & kTearOffUsesBit) != 0;
@@ -1758,6 +1761,8 @@
 
   const uint8_t flags = helper_->ReadByte();
   metadata->InitializeFromFlags(flags);
+  metadata->method_or_setter_selector_id = helper_->ReadUInt();
+  metadata->getter_selector_id = helper_->ReadUInt();
   return true;
 }
 
@@ -2846,8 +2851,8 @@
       helper_->ReadListLength();  // read type_arguments list length.
   const TypeArguments& type_arguments =
       BuildTypeArguments(length);  // read type arguments.
-  result_ = Type::New(klass, type_arguments, TokenPosition::kNoSource);
-  Type::Cast(result_).set_nullability(nullability);
+  result_ =
+      Type::New(klass, type_arguments, TokenPosition::kNoSource, nullability);
   if (finalize_) {
     ASSERT(active_class_->klass != NULL);
     result_ = ClassFinalizer::FinalizeType(*active_class_->klass, result_);
@@ -3173,15 +3178,19 @@
       helper_->SkipDartType();  // read ith bound.
       parameter.set_bound(Type::Handle(Z, I->object_store()->object_type()));
       if (nnbd_mode == NNBDMode::kOptedInLib) {
-        parameter.set_nullability(Nullability::kUndetermined);
+        parameter =
+            parameter.ToNullability(Nullability::kUndetermined, Heap::kOld);
+        type_parameters.SetTypeAt(i, parameter);
       }
     } else {
       AbstractType& bound = BuildTypeWithoutFinalization();  // read ith bound.
       parameter.set_bound(bound);
       if (nnbd_mode == NNBDMode::kOptedInLib) {
-        parameter.set_nullability(bound.IsNullable()
-                                      ? Nullability::kUndetermined
-                                      : Nullability::kNonNullable);
+        parameter = parameter.ToNullability(bound.IsNullable()
+                                                ? Nullability::kUndetermined
+                                                : Nullability::kNonNullable,
+                                            Heap::kOld);
+        type_parameters.SetTypeAt(i, parameter);
       }
     }
 
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.h b/runtime/vm/compiler/frontend/kernel_translation_helper.h
index 3a717c7..d5c3b6d 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.h
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.h
@@ -960,10 +960,15 @@
 };
 
 struct ProcedureAttributesMetadata {
-  bool has_dynamic_invocations = true;
+  static const int32_t kInvalidSelectorId = 0;
+
+  bool method_or_setter_called_dynamically = true;
+  bool getter_called_dynamically = true;
   bool has_this_uses = true;
   bool has_non_this_uses = true;
   bool has_tearoff_uses = true;
+  int32_t method_or_setter_selector_id = kInvalidSelectorId;
+  int32_t getter_selector_id = kInvalidSelectorId;
 
   void InitializeFromFlags(uint8_t flags);
 };
diff --git a/runtime/vm/compiler/jit/compiler.cc b/runtime/vm/compiler/jit/compiler.cc
index e6eb9c2..1a8d269 100644
--- a/runtime/vm/compiler/jit/compiler.cc
+++ b/runtime/vm/compiler/jit/compiler.cc
@@ -88,7 +88,6 @@
 DECLARE_FLAG(bool, enable_interpreter);
 DECLARE_FLAG(bool, huge_method_cutoff_in_code_size);
 DECLARE_FLAG(bool, trace_failed_optimization_attempts);
-DECLARE_FLAG(bool, unbox_numeric_fields);
 
 static void PrecompilationModeHandler(bool value) {
   if (value) {
diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h
index 4c14afd..d427bb5 100644
--- a/runtime/vm/compiler/runtime_api.h
+++ b/runtime/vm/compiler/runtime_api.h
@@ -921,6 +921,7 @@
   static word object_null_offset();
   static word bool_true_offset();
   static word bool_false_offset();
+  static word dispatch_table_array_offset();
   static word top_offset();
   static word end_offset();
   static word isolate_offset();
diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h
index 8774638..f73ebd4 100644
--- a/runtime/vm/compiler/runtime_offsets_extracted.h
+++ b/runtime/vm/compiler/runtime_offsets_extracted.h
@@ -189,152 +189,154 @@
 static constexpr dart::compiler::target::word String_length_offset = 4;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 4;
 static constexpr dart::compiler::target::word
-    Thread_AllocateArray_entry_point_offset = 328;
+    Thread_AllocateArray_entry_point_offset = 336;
 static constexpr dart::compiler::target::word Thread_active_exception_offset =
-    664;
-static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
-    668;
-static constexpr dart::compiler::target::word
-    Thread_array_write_barrier_code_offset = 120;
-static constexpr dart::compiler::target::word
-    Thread_array_write_barrier_entry_point_offset = 220;
-static constexpr dart::compiler::target::word
-    Thread_allocate_mint_with_fpu_regs_entry_point_offset = 244;
-static constexpr dart::compiler::target::word
-    Thread_allocate_mint_with_fpu_regs_stub_offset = 160;
-static constexpr dart::compiler::target::word
-    Thread_allocate_mint_without_fpu_regs_entry_point_offset = 248;
-static constexpr dart::compiler::target::word
-    Thread_allocate_mint_without_fpu_regs_stub_offset = 164;
-static constexpr dart::compiler::target::word Thread_async_stack_trace_offset =
-    92;
-static constexpr dart::compiler::target::word
-    Thread_auto_scope_native_wrapper_entry_point_offset = 288;
-static constexpr dart::compiler::target::word Thread_bool_false_offset = 112;
-static constexpr dart::compiler::target::word Thread_bool_true_offset = 108;
-static constexpr dart::compiler::target::word
-    Thread_bootstrap_native_wrapper_entry_point_offset = 280;
-static constexpr dart::compiler::target::word
-    Thread_call_to_runtime_entry_point_offset = 224;
-static constexpr dart::compiler::target::word
-    Thread_call_to_runtime_stub_offset = 140;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 700;
-static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
-    268;
-static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 180;
-static constexpr dart::compiler::target::word Thread_deoptimize_entry_offset =
-    272;
-static constexpr dart::compiler::target::word Thread_deoptimize_stub_offset =
-    184;
-static constexpr dart::compiler::target::word Thread_double_abs_address_offset =
-    308;
-static constexpr dart::compiler::target::word
-    Thread_double_negate_address_offset = 304;
-static constexpr dart::compiler::target::word Thread_end_offset = 68;
-static constexpr dart::compiler::target::word
-    Thread_enter_safepoint_stub_offset = 204;
-static constexpr dart::compiler::target::word Thread_execution_state_offset =
-    684;
-static constexpr dart::compiler::target::word
-    Thread_exit_safepoint_stub_offset = 208;
-static constexpr dart::compiler::target::word
-    Thread_call_native_through_safepoint_stub_offset = 212;
-static constexpr dart::compiler::target::word
-    Thread_call_native_through_safepoint_entry_point_offset = 276;
-static constexpr dart::compiler::target::word
-    Thread_fix_allocation_stub_code_offset = 128;
-static constexpr dart::compiler::target::word
-    Thread_fix_callers_target_code_offset = 124;
-static constexpr dart::compiler::target::word
-    Thread_float_absolute_address_offset = 320;
-static constexpr dart::compiler::target::word
-    Thread_float_negate_address_offset = 316;
-static constexpr dart::compiler::target::word Thread_float_not_address_offset =
-    312;
-static constexpr dart::compiler::target::word
-    Thread_float_zerow_address_offset = 324;
-static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
     672;
+static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
+    676;
 static constexpr dart::compiler::target::word
-    Thread_interpret_call_entry_point_offset = 292;
+    Thread_array_write_barrier_code_offset = 128;
 static constexpr dart::compiler::target::word
-    Thread_invoke_dart_code_from_bytecode_stub_offset = 136;
+    Thread_array_write_barrier_entry_point_offset = 228;
 static constexpr dart::compiler::target::word
-    Thread_invoke_dart_code_stub_offset = 132;
-static constexpr dart::compiler::target::word Thread_isolate_offset = 52;
+    Thread_allocate_mint_with_fpu_regs_entry_point_offset = 252;
+static constexpr dart::compiler::target::word
+    Thread_allocate_mint_with_fpu_regs_stub_offset = 168;
+static constexpr dart::compiler::target::word
+    Thread_allocate_mint_without_fpu_regs_entry_point_offset = 256;
+static constexpr dart::compiler::target::word
+    Thread_allocate_mint_without_fpu_regs_stub_offset = 172;
+static constexpr dart::compiler::target::word Thread_async_stack_trace_offset =
+    96;
+static constexpr dart::compiler::target::word
+    Thread_auto_scope_native_wrapper_entry_point_offset = 296;
+static constexpr dart::compiler::target::word Thread_bool_false_offset = 120;
+static constexpr dart::compiler::target::word Thread_bool_true_offset = 116;
+static constexpr dart::compiler::target::word
+    Thread_bootstrap_native_wrapper_entry_point_offset = 288;
+static constexpr dart::compiler::target::word
+    Thread_call_to_runtime_entry_point_offset = 232;
+static constexpr dart::compiler::target::word
+    Thread_call_to_runtime_stub_offset = 148;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 708;
+static constexpr dart::compiler::target::word
+    Thread_dispatch_table_array_offset = 48;
+static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
+    276;
+static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 188;
+static constexpr dart::compiler::target::word Thread_deoptimize_entry_offset =
+    280;
+static constexpr dart::compiler::target::word Thread_deoptimize_stub_offset =
+    192;
+static constexpr dart::compiler::target::word Thread_double_abs_address_offset =
+    316;
+static constexpr dart::compiler::target::word
+    Thread_double_negate_address_offset = 312;
+static constexpr dart::compiler::target::word Thread_end_offset = 56;
+static constexpr dart::compiler::target::word
+    Thread_enter_safepoint_stub_offset = 212;
+static constexpr dart::compiler::target::word Thread_execution_state_offset =
+    692;
+static constexpr dart::compiler::target::word
+    Thread_exit_safepoint_stub_offset = 216;
+static constexpr dart::compiler::target::word
+    Thread_call_native_through_safepoint_stub_offset = 220;
+static constexpr dart::compiler::target::word
+    Thread_call_native_through_safepoint_entry_point_offset = 284;
+static constexpr dart::compiler::target::word
+    Thread_fix_allocation_stub_code_offset = 136;
+static constexpr dart::compiler::target::word
+    Thread_fix_callers_target_code_offset = 132;
+static constexpr dart::compiler::target::word
+    Thread_float_absolute_address_offset = 328;
+static constexpr dart::compiler::target::word
+    Thread_float_negate_address_offset = 324;
+static constexpr dart::compiler::target::word Thread_float_not_address_offset =
+    320;
+static constexpr dart::compiler::target::word
+    Thread_float_zerow_address_offset = 332;
+static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
+    680;
+static constexpr dart::compiler::target::word
+    Thread_interpret_call_entry_point_offset = 300;
+static constexpr dart::compiler::target::word
+    Thread_invoke_dart_code_from_bytecode_stub_offset = 144;
+static constexpr dart::compiler::target::word
+    Thread_invoke_dart_code_stub_offset = 140;
+static constexpr dart::compiler::target::word Thread_isolate_offset = 44;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
-    56;
+    68;
 static constexpr dart::compiler::target::word
-    Thread_lazy_deopt_from_return_stub_offset = 188;
+    Thread_lazy_deopt_from_return_stub_offset = 196;
 static constexpr dart::compiler::target::word
-    Thread_lazy_deopt_from_throw_stub_offset = 192;
+    Thread_lazy_deopt_from_throw_stub_offset = 200;
 static constexpr dart::compiler::target::word
-    Thread_lazy_specialize_type_test_stub_offset = 200;
+    Thread_lazy_specialize_type_test_stub_offset = 208;
 static constexpr dart::compiler::target::word
-    Thread_marking_stack_block_offset = 80;
+    Thread_marking_stack_block_offset = 84;
 static constexpr dart::compiler::target::word
-    Thread_megamorphic_call_checked_entry_offset = 260;
+    Thread_megamorphic_call_checked_entry_offset = 268;
 static constexpr dart::compiler::target::word
-    Thread_monomorphic_miss_entry_offset = 264;
+    Thread_monomorphic_miss_entry_offset = 272;
 static constexpr dart::compiler::target::word
-    Thread_monomorphic_miss_stub_offset = 176;
+    Thread_monomorphic_miss_stub_offset = 184;
 static constexpr dart::compiler::target::word
-    Thread_no_scope_native_wrapper_entry_point_offset = 284;
+    Thread_no_scope_native_wrapper_entry_point_offset = 292;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_with_fpu_regs_entry_point_offset = 232;
+    Thread_null_error_shared_with_fpu_regs_entry_point_offset = 240;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_with_fpu_regs_stub_offset = 148;
+    Thread_null_error_shared_with_fpu_regs_stub_offset = 156;
 static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 240;
+    Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 248;
 static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 156;
+    Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 164;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_without_fpu_regs_entry_point_offset = 228;
+    Thread_null_error_shared_without_fpu_regs_entry_point_offset = 236;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_without_fpu_regs_stub_offset = 144;
+    Thread_null_error_shared_without_fpu_regs_stub_offset = 152;
 static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 236;
+    Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 244;
 static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 152;
-static constexpr dart::compiler::target::word Thread_object_null_offset = 104;
+    Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 160;
+static constexpr dart::compiler::target::word Thread_object_null_offset = 112;
 static constexpr dart::compiler::target::word
-    Thread_predefined_symbols_address_offset = 296;
-static constexpr dart::compiler::target::word Thread_resume_pc_offset = 676;
+    Thread_predefined_symbols_address_offset = 304;
+static constexpr dart::compiler::target::word Thread_resume_pc_offset = 684;
 static constexpr dart::compiler::target::word
-    Thread_saved_shadow_call_stack_offset = 680;
+    Thread_saved_shadow_call_stack_offset = 688;
 static constexpr dart::compiler::target::word Thread_safepoint_state_offset =
-    688;
+    696;
 static constexpr dart::compiler::target::word
-    Thread_slow_type_test_stub_offset = 196;
+    Thread_slow_type_test_stub_offset = 204;
 static constexpr dart::compiler::target::word Thread_stack_limit_offset = 36;
 static constexpr dart::compiler::target::word Thread_saved_stack_limit_offset =
-    40;
+    60;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_flags_offset = 44;
+    Thread_stack_overflow_flags_offset = 64;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 256;
+    Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 264;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 172;
+    Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 180;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 252;
+    Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 260;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 168;
+    Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 176;
 static constexpr dart::compiler::target::word Thread_store_buffer_block_offset =
-    76;
+    80;
 static constexpr dart::compiler::target::word
-    Thread_top_exit_frame_info_offset = 72;
-static constexpr dart::compiler::target::word Thread_top_offset = 64;
+    Thread_top_exit_frame_info_offset = 76;
+static constexpr dart::compiler::target::word Thread_top_offset = 52;
 static constexpr dart::compiler::target::word Thread_top_resource_offset = 24;
 static constexpr dart::compiler::target::word
-    Thread_unboxed_int64_runtime_arg_offset = 96;
-static constexpr dart::compiler::target::word Thread_vm_tag_offset = 88;
+    Thread_unboxed_int64_runtime_arg_offset = 104;
+static constexpr dart::compiler::target::word Thread_vm_tag_offset = 92;
 static constexpr dart::compiler::target::word Thread_write_barrier_code_offset =
-    116;
+    124;
 static constexpr dart::compiler::target::word
-    Thread_write_barrier_entry_point_offset = 216;
+    Thread_write_barrier_entry_point_offset = 224;
 static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset =
-    48;
-static constexpr dart::compiler::target::word Thread_callback_code_offset = 692;
+    40;
+static constexpr dart::compiler::target::word Thread_callback_code_offset = 700;
 static constexpr dart::compiler::target::word TimelineStream_enabled_offset = 8;
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 12;
 static constexpr dart::compiler::target::word Type_arguments_offset = 16;
@@ -372,8 +374,8 @@
     4, 12, 8, 16};
 static constexpr dart::compiler::target::word
     Thread_write_barrier_wrappers_thread_offset[] = {
-        628, 632, 636, 640, 644, -1, 648, 652,
-        656, 660, -1,  -1,  -1,  -1, -1,  -1};
+        636, 640, 644, 648, 652, -1, 656, 660,
+        664, 668, -1,  -1,  -1,  -1, -1,  -1};
 static constexpr dart::compiler::target::word ApiError_InstanceSize = 8;
 static constexpr dart::compiler::target::word Array_InstanceSize = 12;
 static constexpr dart::compiler::target::word Array_header_size = 12;
@@ -644,153 +646,155 @@
 static constexpr dart::compiler::target::word String_length_offset = 8;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 8;
 static constexpr dart::compiler::target::word
-    Thread_AllocateArray_entry_point_offset = 648;
+    Thread_AllocateArray_entry_point_offset = 656;
 static constexpr dart::compiler::target::word Thread_active_exception_offset =
-    1336;
-static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
     1344;
-static constexpr dart::compiler::target::word
-    Thread_array_write_barrier_code_offset = 232;
-static constexpr dart::compiler::target::word
-    Thread_array_write_barrier_entry_point_offset = 432;
-static constexpr dart::compiler::target::word
-    Thread_allocate_mint_with_fpu_regs_entry_point_offset = 480;
-static constexpr dart::compiler::target::word
-    Thread_allocate_mint_with_fpu_regs_stub_offset = 312;
-static constexpr dart::compiler::target::word
-    Thread_allocate_mint_without_fpu_regs_entry_point_offset = 488;
-static constexpr dart::compiler::target::word
-    Thread_allocate_mint_without_fpu_regs_stub_offset = 320;
-static constexpr dart::compiler::target::word Thread_async_stack_trace_offset =
-    184;
-static constexpr dart::compiler::target::word
-    Thread_auto_scope_native_wrapper_entry_point_offset = 568;
-static constexpr dart::compiler::target::word Thread_bool_false_offset = 216;
-static constexpr dart::compiler::target::word Thread_bool_true_offset = 208;
-static constexpr dart::compiler::target::word
-    Thread_bootstrap_native_wrapper_entry_point_offset = 552;
-static constexpr dart::compiler::target::word
-    Thread_call_to_runtime_entry_point_offset = 440;
-static constexpr dart::compiler::target::word
-    Thread_call_to_runtime_stub_offset = 272;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1408;
-static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
-    528;
-static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 352;
-static constexpr dart::compiler::target::word Thread_deoptimize_entry_offset =
-    536;
-static constexpr dart::compiler::target::word Thread_deoptimize_stub_offset =
-    360;
-static constexpr dart::compiler::target::word Thread_double_abs_address_offset =
-    608;
-static constexpr dart::compiler::target::word
-    Thread_double_negate_address_offset = 600;
-static constexpr dart::compiler::target::word Thread_end_offset = 136;
-static constexpr dart::compiler::target::word
-    Thread_enter_safepoint_stub_offset = 400;
-static constexpr dart::compiler::target::word Thread_execution_state_offset =
-    1376;
-static constexpr dart::compiler::target::word
-    Thread_exit_safepoint_stub_offset = 408;
-static constexpr dart::compiler::target::word
-    Thread_call_native_through_safepoint_stub_offset = 416;
-static constexpr dart::compiler::target::word
-    Thread_call_native_through_safepoint_entry_point_offset = 544;
-static constexpr dart::compiler::target::word
-    Thread_fix_allocation_stub_code_offset = 248;
-static constexpr dart::compiler::target::word
-    Thread_fix_callers_target_code_offset = 240;
-static constexpr dart::compiler::target::word
-    Thread_float_absolute_address_offset = 632;
-static constexpr dart::compiler::target::word
-    Thread_float_negate_address_offset = 624;
-static constexpr dart::compiler::target::word Thread_float_not_address_offset =
-    616;
-static constexpr dart::compiler::target::word
-    Thread_float_zerow_address_offset = 640;
-static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
+static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
     1352;
 static constexpr dart::compiler::target::word
-    Thread_interpret_call_entry_point_offset = 576;
+    Thread_array_write_barrier_code_offset = 240;
 static constexpr dart::compiler::target::word
-    Thread_invoke_dart_code_from_bytecode_stub_offset = 264;
+    Thread_array_write_barrier_entry_point_offset = 440;
 static constexpr dart::compiler::target::word
-    Thread_invoke_dart_code_stub_offset = 256;
-static constexpr dart::compiler::target::word Thread_isolate_offset = 104;
-static constexpr dart::compiler::target::word Thread_field_table_values_offset =
-    112;
+    Thread_allocate_mint_with_fpu_regs_entry_point_offset = 488;
 static constexpr dart::compiler::target::word
-    Thread_lazy_deopt_from_return_stub_offset = 368;
+    Thread_allocate_mint_with_fpu_regs_stub_offset = 320;
 static constexpr dart::compiler::target::word
-    Thread_lazy_deopt_from_throw_stub_offset = 376;
+    Thread_allocate_mint_without_fpu_regs_entry_point_offset = 496;
 static constexpr dart::compiler::target::word
-    Thread_lazy_specialize_type_test_stub_offset = 392;
+    Thread_allocate_mint_without_fpu_regs_stub_offset = 328;
+static constexpr dart::compiler::target::word Thread_async_stack_trace_offset =
+    192;
 static constexpr dart::compiler::target::word
-    Thread_marking_stack_block_offset = 160;
+    Thread_auto_scope_native_wrapper_entry_point_offset = 576;
+static constexpr dart::compiler::target::word Thread_bool_false_offset = 224;
+static constexpr dart::compiler::target::word Thread_bool_true_offset = 216;
 static constexpr dart::compiler::target::word
-    Thread_megamorphic_call_checked_entry_offset = 512;
+    Thread_bootstrap_native_wrapper_entry_point_offset = 560;
 static constexpr dart::compiler::target::word
-    Thread_monomorphic_miss_entry_offset = 520;
+    Thread_call_to_runtime_entry_point_offset = 448;
 static constexpr dart::compiler::target::word
-    Thread_monomorphic_miss_stub_offset = 344;
+    Thread_call_to_runtime_stub_offset = 280;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1416;
 static constexpr dart::compiler::target::word
-    Thread_no_scope_native_wrapper_entry_point_offset = 560;
+    Thread_dispatch_table_array_offset = 96;
+static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
+    536;
+static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 360;
+static constexpr dart::compiler::target::word Thread_deoptimize_entry_offset =
+    544;
+static constexpr dart::compiler::target::word Thread_deoptimize_stub_offset =
+    368;
+static constexpr dart::compiler::target::word Thread_double_abs_address_offset =
+    616;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_with_fpu_regs_entry_point_offset = 456;
+    Thread_double_negate_address_offset = 608;
+static constexpr dart::compiler::target::word Thread_end_offset = 112;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_with_fpu_regs_stub_offset = 288;
-static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 472;
-static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 304;
-static constexpr dart::compiler::target::word
-    Thread_null_error_shared_without_fpu_regs_entry_point_offset = 448;
-static constexpr dart::compiler::target::word
-    Thread_null_error_shared_without_fpu_regs_stub_offset = 280;
-static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 464;
-static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 296;
-static constexpr dart::compiler::target::word Thread_object_null_offset = 200;
-static constexpr dart::compiler::target::word
-    Thread_predefined_symbols_address_offset = 584;
-static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1360;
-static constexpr dart::compiler::target::word
-    Thread_saved_shadow_call_stack_offset = 1368;
-static constexpr dart::compiler::target::word Thread_safepoint_state_offset =
+    Thread_enter_safepoint_stub_offset = 408;
+static constexpr dart::compiler::target::word Thread_execution_state_offset =
     1384;
 static constexpr dart::compiler::target::word
-    Thread_slow_type_test_stub_offset = 384;
+    Thread_exit_safepoint_stub_offset = 416;
+static constexpr dart::compiler::target::word
+    Thread_call_native_through_safepoint_stub_offset = 424;
+static constexpr dart::compiler::target::word
+    Thread_call_native_through_safepoint_entry_point_offset = 552;
+static constexpr dart::compiler::target::word
+    Thread_fix_allocation_stub_code_offset = 256;
+static constexpr dart::compiler::target::word
+    Thread_fix_callers_target_code_offset = 248;
+static constexpr dart::compiler::target::word
+    Thread_float_absolute_address_offset = 640;
+static constexpr dart::compiler::target::word
+    Thread_float_negate_address_offset = 632;
+static constexpr dart::compiler::target::word Thread_float_not_address_offset =
+    624;
+static constexpr dart::compiler::target::word
+    Thread_float_zerow_address_offset = 648;
+static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
+    1360;
+static constexpr dart::compiler::target::word
+    Thread_interpret_call_entry_point_offset = 584;
+static constexpr dart::compiler::target::word
+    Thread_invoke_dart_code_from_bytecode_stub_offset = 272;
+static constexpr dart::compiler::target::word
+    Thread_invoke_dart_code_stub_offset = 264;
+static constexpr dart::compiler::target::word Thread_isolate_offset = 88;
+static constexpr dart::compiler::target::word Thread_field_table_values_offset =
+    136;
+static constexpr dart::compiler::target::word
+    Thread_lazy_deopt_from_return_stub_offset = 376;
+static constexpr dart::compiler::target::word
+    Thread_lazy_deopt_from_throw_stub_offset = 384;
+static constexpr dart::compiler::target::word
+    Thread_lazy_specialize_type_test_stub_offset = 400;
+static constexpr dart::compiler::target::word
+    Thread_marking_stack_block_offset = 168;
+static constexpr dart::compiler::target::word
+    Thread_megamorphic_call_checked_entry_offset = 520;
+static constexpr dart::compiler::target::word
+    Thread_monomorphic_miss_entry_offset = 528;
+static constexpr dart::compiler::target::word
+    Thread_monomorphic_miss_stub_offset = 352;
+static constexpr dart::compiler::target::word
+    Thread_no_scope_native_wrapper_entry_point_offset = 568;
+static constexpr dart::compiler::target::word
+    Thread_null_error_shared_with_fpu_regs_entry_point_offset = 464;
+static constexpr dart::compiler::target::word
+    Thread_null_error_shared_with_fpu_regs_stub_offset = 296;
+static constexpr dart::compiler::target::word
+    Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 480;
+static constexpr dart::compiler::target::word
+    Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 312;
+static constexpr dart::compiler::target::word
+    Thread_null_error_shared_without_fpu_regs_entry_point_offset = 456;
+static constexpr dart::compiler::target::word
+    Thread_null_error_shared_without_fpu_regs_stub_offset = 288;
+static constexpr dart::compiler::target::word
+    Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 472;
+static constexpr dart::compiler::target::word
+    Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 304;
+static constexpr dart::compiler::target::word Thread_object_null_offset = 208;
+static constexpr dart::compiler::target::word
+    Thread_predefined_symbols_address_offset = 592;
+static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1368;
+static constexpr dart::compiler::target::word
+    Thread_saved_shadow_call_stack_offset = 1376;
+static constexpr dart::compiler::target::word Thread_safepoint_state_offset =
+    1392;
+static constexpr dart::compiler::target::word
+    Thread_slow_type_test_stub_offset = 392;
 static constexpr dart::compiler::target::word Thread_stack_limit_offset = 72;
 static constexpr dart::compiler::target::word Thread_saved_stack_limit_offset =
-    80;
+    120;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_flags_offset = 88;
+    Thread_stack_overflow_flags_offset = 128;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 504;
+    Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 512;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 336;
+    Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 344;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 496;
+    Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 504;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 328;
+    Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 336;
 static constexpr dart::compiler::target::word Thread_store_buffer_block_offset =
-    152;
+    160;
 static constexpr dart::compiler::target::word
-    Thread_top_exit_frame_info_offset = 144;
-static constexpr dart::compiler::target::word Thread_top_offset = 128;
+    Thread_top_exit_frame_info_offset = 152;
+static constexpr dart::compiler::target::word Thread_top_offset = 104;
 static constexpr dart::compiler::target::word Thread_top_resource_offset = 48;
 static constexpr dart::compiler::target::word
-    Thread_unboxed_int64_runtime_arg_offset = 192;
-static constexpr dart::compiler::target::word Thread_vm_tag_offset = 176;
+    Thread_unboxed_int64_runtime_arg_offset = 200;
+static constexpr dart::compiler::target::word Thread_vm_tag_offset = 184;
 static constexpr dart::compiler::target::word Thread_write_barrier_code_offset =
-    224;
+    232;
 static constexpr dart::compiler::target::word
-    Thread_write_barrier_entry_point_offset = 424;
+    Thread_write_barrier_entry_point_offset = 432;
 static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset =
-    96;
+    80;
 static constexpr dart::compiler::target::word Thread_callback_code_offset =
-    1392;
+    1400;
 static constexpr dart::compiler::target::word TimelineStream_enabled_offset =
     16;
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 16;
@@ -829,8 +833,8 @@
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
     Thread_write_barrier_wrappers_thread_offset[] = {
-        1248, 1256, 1264, 1272, -1,   -1,   1280, 1288,
-        1296, 1304, 1312, -1,   1320, 1328, -1,   -1};
+        1256, 1264, 1272, 1280, -1,   -1,   1288, 1296,
+        1304, 1312, 1320, -1,   1328, 1336, -1,   -1};
 static constexpr dart::compiler::target::word ApiError_InstanceSize = 16;
 static constexpr dart::compiler::target::word Array_InstanceSize = 24;
 static constexpr dart::compiler::target::word Array_header_size = 24;
@@ -1100,152 +1104,154 @@
 static constexpr dart::compiler::target::word String_length_offset = 4;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 4;
 static constexpr dart::compiler::target::word
-    Thread_AllocateArray_entry_point_offset = 328;
+    Thread_AllocateArray_entry_point_offset = 336;
 static constexpr dart::compiler::target::word Thread_active_exception_offset =
-    628;
-static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
-    632;
-static constexpr dart::compiler::target::word
-    Thread_array_write_barrier_code_offset = 120;
-static constexpr dart::compiler::target::word
-    Thread_array_write_barrier_entry_point_offset = 220;
-static constexpr dart::compiler::target::word
-    Thread_allocate_mint_with_fpu_regs_entry_point_offset = 244;
-static constexpr dart::compiler::target::word
-    Thread_allocate_mint_with_fpu_regs_stub_offset = 160;
-static constexpr dart::compiler::target::word
-    Thread_allocate_mint_without_fpu_regs_entry_point_offset = 248;
-static constexpr dart::compiler::target::word
-    Thread_allocate_mint_without_fpu_regs_stub_offset = 164;
-static constexpr dart::compiler::target::word Thread_async_stack_trace_offset =
-    92;
-static constexpr dart::compiler::target::word
-    Thread_auto_scope_native_wrapper_entry_point_offset = 288;
-static constexpr dart::compiler::target::word Thread_bool_false_offset = 112;
-static constexpr dart::compiler::target::word Thread_bool_true_offset = 108;
-static constexpr dart::compiler::target::word
-    Thread_bootstrap_native_wrapper_entry_point_offset = 280;
-static constexpr dart::compiler::target::word
-    Thread_call_to_runtime_entry_point_offset = 224;
-static constexpr dart::compiler::target::word
-    Thread_call_to_runtime_stub_offset = 140;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 664;
-static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
-    268;
-static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 180;
-static constexpr dart::compiler::target::word Thread_deoptimize_entry_offset =
-    272;
-static constexpr dart::compiler::target::word Thread_deoptimize_stub_offset =
-    184;
-static constexpr dart::compiler::target::word Thread_double_abs_address_offset =
-    308;
-static constexpr dart::compiler::target::word
-    Thread_double_negate_address_offset = 304;
-static constexpr dart::compiler::target::word Thread_end_offset = 68;
-static constexpr dart::compiler::target::word
-    Thread_enter_safepoint_stub_offset = 204;
-static constexpr dart::compiler::target::word Thread_execution_state_offset =
-    648;
-static constexpr dart::compiler::target::word
-    Thread_exit_safepoint_stub_offset = 208;
-static constexpr dart::compiler::target::word
-    Thread_call_native_through_safepoint_stub_offset = 212;
-static constexpr dart::compiler::target::word
-    Thread_call_native_through_safepoint_entry_point_offset = 276;
-static constexpr dart::compiler::target::word
-    Thread_fix_allocation_stub_code_offset = 128;
-static constexpr dart::compiler::target::word
-    Thread_fix_callers_target_code_offset = 124;
-static constexpr dart::compiler::target::word
-    Thread_float_absolute_address_offset = 320;
-static constexpr dart::compiler::target::word
-    Thread_float_negate_address_offset = 316;
-static constexpr dart::compiler::target::word Thread_float_not_address_offset =
-    312;
-static constexpr dart::compiler::target::word
-    Thread_float_zerow_address_offset = 324;
-static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
     636;
+static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
+    640;
 static constexpr dart::compiler::target::word
-    Thread_interpret_call_entry_point_offset = 292;
+    Thread_array_write_barrier_code_offset = 128;
 static constexpr dart::compiler::target::word
-    Thread_invoke_dart_code_from_bytecode_stub_offset = 136;
+    Thread_array_write_barrier_entry_point_offset = 228;
 static constexpr dart::compiler::target::word
-    Thread_invoke_dart_code_stub_offset = 132;
-static constexpr dart::compiler::target::word Thread_isolate_offset = 52;
+    Thread_allocate_mint_with_fpu_regs_entry_point_offset = 252;
+static constexpr dart::compiler::target::word
+    Thread_allocate_mint_with_fpu_regs_stub_offset = 168;
+static constexpr dart::compiler::target::word
+    Thread_allocate_mint_without_fpu_regs_entry_point_offset = 256;
+static constexpr dart::compiler::target::word
+    Thread_allocate_mint_without_fpu_regs_stub_offset = 172;
+static constexpr dart::compiler::target::word Thread_async_stack_trace_offset =
+    96;
+static constexpr dart::compiler::target::word
+    Thread_auto_scope_native_wrapper_entry_point_offset = 296;
+static constexpr dart::compiler::target::word Thread_bool_false_offset = 120;
+static constexpr dart::compiler::target::word Thread_bool_true_offset = 116;
+static constexpr dart::compiler::target::word
+    Thread_bootstrap_native_wrapper_entry_point_offset = 288;
+static constexpr dart::compiler::target::word
+    Thread_call_to_runtime_entry_point_offset = 232;
+static constexpr dart::compiler::target::word
+    Thread_call_to_runtime_stub_offset = 148;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 672;
+static constexpr dart::compiler::target::word
+    Thread_dispatch_table_array_offset = 48;
+static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
+    276;
+static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 188;
+static constexpr dart::compiler::target::word Thread_deoptimize_entry_offset =
+    280;
+static constexpr dart::compiler::target::word Thread_deoptimize_stub_offset =
+    192;
+static constexpr dart::compiler::target::word Thread_double_abs_address_offset =
+    316;
+static constexpr dart::compiler::target::word
+    Thread_double_negate_address_offset = 312;
+static constexpr dart::compiler::target::word Thread_end_offset = 56;
+static constexpr dart::compiler::target::word
+    Thread_enter_safepoint_stub_offset = 212;
+static constexpr dart::compiler::target::word Thread_execution_state_offset =
+    656;
+static constexpr dart::compiler::target::word
+    Thread_exit_safepoint_stub_offset = 216;
+static constexpr dart::compiler::target::word
+    Thread_call_native_through_safepoint_stub_offset = 220;
+static constexpr dart::compiler::target::word
+    Thread_call_native_through_safepoint_entry_point_offset = 284;
+static constexpr dart::compiler::target::word
+    Thread_fix_allocation_stub_code_offset = 136;
+static constexpr dart::compiler::target::word
+    Thread_fix_callers_target_code_offset = 132;
+static constexpr dart::compiler::target::word
+    Thread_float_absolute_address_offset = 328;
+static constexpr dart::compiler::target::word
+    Thread_float_negate_address_offset = 324;
+static constexpr dart::compiler::target::word Thread_float_not_address_offset =
+    320;
+static constexpr dart::compiler::target::word
+    Thread_float_zerow_address_offset = 332;
+static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
+    644;
+static constexpr dart::compiler::target::word
+    Thread_interpret_call_entry_point_offset = 300;
+static constexpr dart::compiler::target::word
+    Thread_invoke_dart_code_from_bytecode_stub_offset = 144;
+static constexpr dart::compiler::target::word
+    Thread_invoke_dart_code_stub_offset = 140;
+static constexpr dart::compiler::target::word Thread_isolate_offset = 44;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
-    56;
+    68;
 static constexpr dart::compiler::target::word
-    Thread_lazy_deopt_from_return_stub_offset = 188;
+    Thread_lazy_deopt_from_return_stub_offset = 196;
 static constexpr dart::compiler::target::word
-    Thread_lazy_deopt_from_throw_stub_offset = 192;
+    Thread_lazy_deopt_from_throw_stub_offset = 200;
 static constexpr dart::compiler::target::word
-    Thread_lazy_specialize_type_test_stub_offset = 200;
+    Thread_lazy_specialize_type_test_stub_offset = 208;
 static constexpr dart::compiler::target::word
-    Thread_marking_stack_block_offset = 80;
+    Thread_marking_stack_block_offset = 84;
 static constexpr dart::compiler::target::word
-    Thread_megamorphic_call_checked_entry_offset = 260;
+    Thread_megamorphic_call_checked_entry_offset = 268;
 static constexpr dart::compiler::target::word
-    Thread_monomorphic_miss_entry_offset = 264;
+    Thread_monomorphic_miss_entry_offset = 272;
 static constexpr dart::compiler::target::word
-    Thread_monomorphic_miss_stub_offset = 176;
+    Thread_monomorphic_miss_stub_offset = 184;
 static constexpr dart::compiler::target::word
-    Thread_no_scope_native_wrapper_entry_point_offset = 284;
+    Thread_no_scope_native_wrapper_entry_point_offset = 292;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_with_fpu_regs_entry_point_offset = 232;
+    Thread_null_error_shared_with_fpu_regs_entry_point_offset = 240;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_with_fpu_regs_stub_offset = 148;
+    Thread_null_error_shared_with_fpu_regs_stub_offset = 156;
 static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 240;
+    Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 248;
 static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 156;
+    Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 164;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_without_fpu_regs_entry_point_offset = 228;
+    Thread_null_error_shared_without_fpu_regs_entry_point_offset = 236;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_without_fpu_regs_stub_offset = 144;
+    Thread_null_error_shared_without_fpu_regs_stub_offset = 152;
 static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 236;
+    Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 244;
 static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 152;
-static constexpr dart::compiler::target::word Thread_object_null_offset = 104;
+    Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 160;
+static constexpr dart::compiler::target::word Thread_object_null_offset = 112;
 static constexpr dart::compiler::target::word
-    Thread_predefined_symbols_address_offset = 296;
-static constexpr dart::compiler::target::word Thread_resume_pc_offset = 640;
+    Thread_predefined_symbols_address_offset = 304;
+static constexpr dart::compiler::target::word Thread_resume_pc_offset = 648;
 static constexpr dart::compiler::target::word
-    Thread_saved_shadow_call_stack_offset = 644;
+    Thread_saved_shadow_call_stack_offset = 652;
 static constexpr dart::compiler::target::word Thread_safepoint_state_offset =
-    652;
+    660;
 static constexpr dart::compiler::target::word
-    Thread_slow_type_test_stub_offset = 196;
+    Thread_slow_type_test_stub_offset = 204;
 static constexpr dart::compiler::target::word Thread_stack_limit_offset = 36;
 static constexpr dart::compiler::target::word Thread_saved_stack_limit_offset =
-    40;
+    60;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_flags_offset = 44;
+    Thread_stack_overflow_flags_offset = 64;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 256;
+    Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 264;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 172;
+    Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 180;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 252;
+    Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 260;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 168;
+    Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 176;
 static constexpr dart::compiler::target::word Thread_store_buffer_block_offset =
-    76;
+    80;
 static constexpr dart::compiler::target::word
-    Thread_top_exit_frame_info_offset = 72;
-static constexpr dart::compiler::target::word Thread_top_offset = 64;
+    Thread_top_exit_frame_info_offset = 76;
+static constexpr dart::compiler::target::word Thread_top_offset = 52;
 static constexpr dart::compiler::target::word Thread_top_resource_offset = 24;
 static constexpr dart::compiler::target::word
-    Thread_unboxed_int64_runtime_arg_offset = 96;
-static constexpr dart::compiler::target::word Thread_vm_tag_offset = 88;
+    Thread_unboxed_int64_runtime_arg_offset = 104;
+static constexpr dart::compiler::target::word Thread_vm_tag_offset = 92;
 static constexpr dart::compiler::target::word Thread_write_barrier_code_offset =
-    116;
+    124;
 static constexpr dart::compiler::target::word
-    Thread_write_barrier_entry_point_offset = 216;
+    Thread_write_barrier_entry_point_offset = 224;
 static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset =
-    48;
-static constexpr dart::compiler::target::word Thread_callback_code_offset = 656;
+    40;
+static constexpr dart::compiler::target::word Thread_callback_code_offset = 664;
 static constexpr dart::compiler::target::word TimelineStream_enabled_offset = 8;
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 12;
 static constexpr dart::compiler::target::word Type_arguments_offset = 16;
@@ -1551,151 +1557,153 @@
 static constexpr dart::compiler::target::word String_length_offset = 8;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 8;
 static constexpr dart::compiler::target::word
-    Thread_AllocateArray_entry_point_offset = 648;
+    Thread_AllocateArray_entry_point_offset = 656;
 static constexpr dart::compiler::target::word Thread_active_exception_offset =
     1416;
 static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
     1424;
 static constexpr dart::compiler::target::word
-    Thread_array_write_barrier_code_offset = 232;
+    Thread_array_write_barrier_code_offset = 240;
 static constexpr dart::compiler::target::word
-    Thread_array_write_barrier_entry_point_offset = 432;
+    Thread_array_write_barrier_entry_point_offset = 440;
 static constexpr dart::compiler::target::word
-    Thread_allocate_mint_with_fpu_regs_entry_point_offset = 480;
+    Thread_allocate_mint_with_fpu_regs_entry_point_offset = 488;
 static constexpr dart::compiler::target::word
-    Thread_allocate_mint_with_fpu_regs_stub_offset = 312;
+    Thread_allocate_mint_with_fpu_regs_stub_offset = 320;
 static constexpr dart::compiler::target::word
-    Thread_allocate_mint_without_fpu_regs_entry_point_offset = 488;
+    Thread_allocate_mint_without_fpu_regs_entry_point_offset = 496;
 static constexpr dart::compiler::target::word
-    Thread_allocate_mint_without_fpu_regs_stub_offset = 320;
+    Thread_allocate_mint_without_fpu_regs_stub_offset = 328;
 static constexpr dart::compiler::target::word Thread_async_stack_trace_offset =
-    184;
+    192;
 static constexpr dart::compiler::target::word
-    Thread_auto_scope_native_wrapper_entry_point_offset = 568;
-static constexpr dart::compiler::target::word Thread_bool_false_offset = 216;
-static constexpr dart::compiler::target::word Thread_bool_true_offset = 208;
+    Thread_auto_scope_native_wrapper_entry_point_offset = 576;
+static constexpr dart::compiler::target::word Thread_bool_false_offset = 224;
+static constexpr dart::compiler::target::word Thread_bool_true_offset = 216;
 static constexpr dart::compiler::target::word
-    Thread_bootstrap_native_wrapper_entry_point_offset = 552;
+    Thread_bootstrap_native_wrapper_entry_point_offset = 560;
 static constexpr dart::compiler::target::word
-    Thread_call_to_runtime_entry_point_offset = 440;
+    Thread_call_to_runtime_entry_point_offset = 448;
 static constexpr dart::compiler::target::word
-    Thread_call_to_runtime_stub_offset = 272;
+    Thread_call_to_runtime_stub_offset = 280;
 static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1488;
+static constexpr dart::compiler::target::word
+    Thread_dispatch_table_array_offset = 96;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
-    528;
-static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 352;
-static constexpr dart::compiler::target::word Thread_deoptimize_entry_offset =
     536;
+static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 360;
+static constexpr dart::compiler::target::word Thread_deoptimize_entry_offset =
+    544;
 static constexpr dart::compiler::target::word Thread_deoptimize_stub_offset =
-    360;
+    368;
 static constexpr dart::compiler::target::word Thread_double_abs_address_offset =
-    608;
+    616;
 static constexpr dart::compiler::target::word
-    Thread_double_negate_address_offset = 600;
-static constexpr dart::compiler::target::word Thread_end_offset = 136;
+    Thread_double_negate_address_offset = 608;
+static constexpr dart::compiler::target::word Thread_end_offset = 112;
 static constexpr dart::compiler::target::word
-    Thread_enter_safepoint_stub_offset = 400;
+    Thread_enter_safepoint_stub_offset = 408;
 static constexpr dart::compiler::target::word Thread_execution_state_offset =
     1456;
 static constexpr dart::compiler::target::word
-    Thread_exit_safepoint_stub_offset = 408;
+    Thread_exit_safepoint_stub_offset = 416;
 static constexpr dart::compiler::target::word
-    Thread_call_native_through_safepoint_stub_offset = 416;
+    Thread_call_native_through_safepoint_stub_offset = 424;
 static constexpr dart::compiler::target::word
-    Thread_call_native_through_safepoint_entry_point_offset = 544;
+    Thread_call_native_through_safepoint_entry_point_offset = 552;
 static constexpr dart::compiler::target::word
-    Thread_fix_allocation_stub_code_offset = 248;
+    Thread_fix_allocation_stub_code_offset = 256;
 static constexpr dart::compiler::target::word
-    Thread_fix_callers_target_code_offset = 240;
+    Thread_fix_callers_target_code_offset = 248;
 static constexpr dart::compiler::target::word
-    Thread_float_absolute_address_offset = 632;
+    Thread_float_absolute_address_offset = 640;
 static constexpr dart::compiler::target::word
-    Thread_float_negate_address_offset = 624;
+    Thread_float_negate_address_offset = 632;
 static constexpr dart::compiler::target::word Thread_float_not_address_offset =
-    616;
+    624;
 static constexpr dart::compiler::target::word
-    Thread_float_zerow_address_offset = 640;
+    Thread_float_zerow_address_offset = 648;
 static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
     1432;
 static constexpr dart::compiler::target::word
-    Thread_interpret_call_entry_point_offset = 576;
+    Thread_interpret_call_entry_point_offset = 584;
 static constexpr dart::compiler::target::word
-    Thread_invoke_dart_code_from_bytecode_stub_offset = 264;
+    Thread_invoke_dart_code_from_bytecode_stub_offset = 272;
 static constexpr dart::compiler::target::word
-    Thread_invoke_dart_code_stub_offset = 256;
-static constexpr dart::compiler::target::word Thread_isolate_offset = 104;
+    Thread_invoke_dart_code_stub_offset = 264;
+static constexpr dart::compiler::target::word Thread_isolate_offset = 88;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
-    112;
+    136;
 static constexpr dart::compiler::target::word
-    Thread_lazy_deopt_from_return_stub_offset = 368;
+    Thread_lazy_deopt_from_return_stub_offset = 376;
 static constexpr dart::compiler::target::word
-    Thread_lazy_deopt_from_throw_stub_offset = 376;
+    Thread_lazy_deopt_from_throw_stub_offset = 384;
 static constexpr dart::compiler::target::word
-    Thread_lazy_specialize_type_test_stub_offset = 392;
+    Thread_lazy_specialize_type_test_stub_offset = 400;
 static constexpr dart::compiler::target::word
-    Thread_marking_stack_block_offset = 160;
+    Thread_marking_stack_block_offset = 168;
 static constexpr dart::compiler::target::word
-    Thread_megamorphic_call_checked_entry_offset = 512;
+    Thread_megamorphic_call_checked_entry_offset = 520;
 static constexpr dart::compiler::target::word
-    Thread_monomorphic_miss_entry_offset = 520;
+    Thread_monomorphic_miss_entry_offset = 528;
 static constexpr dart::compiler::target::word
-    Thread_monomorphic_miss_stub_offset = 344;
+    Thread_monomorphic_miss_stub_offset = 352;
 static constexpr dart::compiler::target::word
-    Thread_no_scope_native_wrapper_entry_point_offset = 560;
+    Thread_no_scope_native_wrapper_entry_point_offset = 568;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_with_fpu_regs_entry_point_offset = 456;
+    Thread_null_error_shared_with_fpu_regs_entry_point_offset = 464;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_with_fpu_regs_stub_offset = 288;
+    Thread_null_error_shared_with_fpu_regs_stub_offset = 296;
 static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 472;
+    Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 480;
 static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 304;
+    Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 312;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_without_fpu_regs_entry_point_offset = 448;
+    Thread_null_error_shared_without_fpu_regs_entry_point_offset = 456;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_without_fpu_regs_stub_offset = 280;
+    Thread_null_error_shared_without_fpu_regs_stub_offset = 288;
 static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 464;
+    Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 472;
 static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 296;
-static constexpr dart::compiler::target::word Thread_object_null_offset = 200;
+    Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 304;
+static constexpr dart::compiler::target::word Thread_object_null_offset = 208;
 static constexpr dart::compiler::target::word
-    Thread_predefined_symbols_address_offset = 584;
+    Thread_predefined_symbols_address_offset = 592;
 static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1440;
 static constexpr dart::compiler::target::word
     Thread_saved_shadow_call_stack_offset = 1448;
 static constexpr dart::compiler::target::word Thread_safepoint_state_offset =
     1464;
 static constexpr dart::compiler::target::word
-    Thread_slow_type_test_stub_offset = 384;
+    Thread_slow_type_test_stub_offset = 392;
 static constexpr dart::compiler::target::word Thread_stack_limit_offset = 72;
 static constexpr dart::compiler::target::word Thread_saved_stack_limit_offset =
-    80;
+    120;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_flags_offset = 88;
+    Thread_stack_overflow_flags_offset = 128;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 504;
+    Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 512;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 336;
+    Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 344;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 496;
+    Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 504;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 328;
+    Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 336;
 static constexpr dart::compiler::target::word Thread_store_buffer_block_offset =
-    152;
+    160;
 static constexpr dart::compiler::target::word
-    Thread_top_exit_frame_info_offset = 144;
-static constexpr dart::compiler::target::word Thread_top_offset = 128;
+    Thread_top_exit_frame_info_offset = 152;
+static constexpr dart::compiler::target::word Thread_top_offset = 104;
 static constexpr dart::compiler::target::word Thread_top_resource_offset = 48;
 static constexpr dart::compiler::target::word
-    Thread_unboxed_int64_runtime_arg_offset = 192;
-static constexpr dart::compiler::target::word Thread_vm_tag_offset = 176;
+    Thread_unboxed_int64_runtime_arg_offset = 200;
+static constexpr dart::compiler::target::word Thread_vm_tag_offset = 184;
 static constexpr dart::compiler::target::word Thread_write_barrier_code_offset =
-    224;
+    232;
 static constexpr dart::compiler::target::word
-    Thread_write_barrier_entry_point_offset = 424;
+    Thread_write_barrier_entry_point_offset = 432;
 static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset =
-    96;
+    80;
 static constexpr dart::compiler::target::word Thread_callback_code_offset =
     1472;
 static constexpr dart::compiler::target::word TimelineStream_enabled_offset =
@@ -1736,8 +1744,8 @@
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
     Thread_write_barrier_wrappers_thread_offset[] = {
-        1248, 1256, 1264, 1272, 1280, 1288, 1296, 1304, 1312, 1320, 1328,
-        1336, 1344, 1352, 1360, -1,   -1,   -1,   -1,   1368, 1376, 1384,
+        1256, 1264, 1272, 1280, 1288, 1296, 1304, 1312, 1320, 1328, 1336,
+        1344, 1352, 1360, 1368, -1,   -1,   -1,   -1,   1376, 1384, -1,
         -1,   1392, 1400, 1408, -1,   -1,   -1,   -1,   -1,   -1};
 static constexpr dart::compiler::target::word ApiError_InstanceSize = 16;
 static constexpr dart::compiler::target::word Array_InstanceSize = 24;
@@ -2007,152 +2015,154 @@
 static constexpr dart::compiler::target::word String_length_offset = 4;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 4;
 static constexpr dart::compiler::target::word
-    Thread_AllocateArray_entry_point_offset = 328;
+    Thread_AllocateArray_entry_point_offset = 336;
 static constexpr dart::compiler::target::word Thread_active_exception_offset =
-    664;
-static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
-    668;
-static constexpr dart::compiler::target::word
-    Thread_array_write_barrier_code_offset = 120;
-static constexpr dart::compiler::target::word
-    Thread_array_write_barrier_entry_point_offset = 220;
-static constexpr dart::compiler::target::word
-    Thread_allocate_mint_with_fpu_regs_entry_point_offset = 244;
-static constexpr dart::compiler::target::word
-    Thread_allocate_mint_with_fpu_regs_stub_offset = 160;
-static constexpr dart::compiler::target::word
-    Thread_allocate_mint_without_fpu_regs_entry_point_offset = 248;
-static constexpr dart::compiler::target::word
-    Thread_allocate_mint_without_fpu_regs_stub_offset = 164;
-static constexpr dart::compiler::target::word Thread_async_stack_trace_offset =
-    92;
-static constexpr dart::compiler::target::word
-    Thread_auto_scope_native_wrapper_entry_point_offset = 288;
-static constexpr dart::compiler::target::word Thread_bool_false_offset = 112;
-static constexpr dart::compiler::target::word Thread_bool_true_offset = 108;
-static constexpr dart::compiler::target::word
-    Thread_bootstrap_native_wrapper_entry_point_offset = 280;
-static constexpr dart::compiler::target::word
-    Thread_call_to_runtime_entry_point_offset = 224;
-static constexpr dart::compiler::target::word
-    Thread_call_to_runtime_stub_offset = 140;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 700;
-static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
-    268;
-static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 180;
-static constexpr dart::compiler::target::word Thread_deoptimize_entry_offset =
-    272;
-static constexpr dart::compiler::target::word Thread_deoptimize_stub_offset =
-    184;
-static constexpr dart::compiler::target::word Thread_double_abs_address_offset =
-    308;
-static constexpr dart::compiler::target::word
-    Thread_double_negate_address_offset = 304;
-static constexpr dart::compiler::target::word Thread_end_offset = 68;
-static constexpr dart::compiler::target::word
-    Thread_enter_safepoint_stub_offset = 204;
-static constexpr dart::compiler::target::word Thread_execution_state_offset =
-    684;
-static constexpr dart::compiler::target::word
-    Thread_exit_safepoint_stub_offset = 208;
-static constexpr dart::compiler::target::word
-    Thread_call_native_through_safepoint_stub_offset = 212;
-static constexpr dart::compiler::target::word
-    Thread_call_native_through_safepoint_entry_point_offset = 276;
-static constexpr dart::compiler::target::word
-    Thread_fix_allocation_stub_code_offset = 128;
-static constexpr dart::compiler::target::word
-    Thread_fix_callers_target_code_offset = 124;
-static constexpr dart::compiler::target::word
-    Thread_float_absolute_address_offset = 320;
-static constexpr dart::compiler::target::word
-    Thread_float_negate_address_offset = 316;
-static constexpr dart::compiler::target::word Thread_float_not_address_offset =
-    312;
-static constexpr dart::compiler::target::word
-    Thread_float_zerow_address_offset = 324;
-static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
     672;
+static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
+    676;
 static constexpr dart::compiler::target::word
-    Thread_interpret_call_entry_point_offset = 292;
+    Thread_array_write_barrier_code_offset = 128;
 static constexpr dart::compiler::target::word
-    Thread_invoke_dart_code_from_bytecode_stub_offset = 136;
+    Thread_array_write_barrier_entry_point_offset = 228;
 static constexpr dart::compiler::target::word
-    Thread_invoke_dart_code_stub_offset = 132;
-static constexpr dart::compiler::target::word Thread_isolate_offset = 52;
+    Thread_allocate_mint_with_fpu_regs_entry_point_offset = 252;
+static constexpr dart::compiler::target::word
+    Thread_allocate_mint_with_fpu_regs_stub_offset = 168;
+static constexpr dart::compiler::target::word
+    Thread_allocate_mint_without_fpu_regs_entry_point_offset = 256;
+static constexpr dart::compiler::target::word
+    Thread_allocate_mint_without_fpu_regs_stub_offset = 172;
+static constexpr dart::compiler::target::word Thread_async_stack_trace_offset =
+    96;
+static constexpr dart::compiler::target::word
+    Thread_auto_scope_native_wrapper_entry_point_offset = 296;
+static constexpr dart::compiler::target::word Thread_bool_false_offset = 120;
+static constexpr dart::compiler::target::word Thread_bool_true_offset = 116;
+static constexpr dart::compiler::target::word
+    Thread_bootstrap_native_wrapper_entry_point_offset = 288;
+static constexpr dart::compiler::target::word
+    Thread_call_to_runtime_entry_point_offset = 232;
+static constexpr dart::compiler::target::word
+    Thread_call_to_runtime_stub_offset = 148;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 708;
+static constexpr dart::compiler::target::word
+    Thread_dispatch_table_array_offset = 48;
+static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
+    276;
+static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 188;
+static constexpr dart::compiler::target::word Thread_deoptimize_entry_offset =
+    280;
+static constexpr dart::compiler::target::word Thread_deoptimize_stub_offset =
+    192;
+static constexpr dart::compiler::target::word Thread_double_abs_address_offset =
+    316;
+static constexpr dart::compiler::target::word
+    Thread_double_negate_address_offset = 312;
+static constexpr dart::compiler::target::word Thread_end_offset = 56;
+static constexpr dart::compiler::target::word
+    Thread_enter_safepoint_stub_offset = 212;
+static constexpr dart::compiler::target::word Thread_execution_state_offset =
+    692;
+static constexpr dart::compiler::target::word
+    Thread_exit_safepoint_stub_offset = 216;
+static constexpr dart::compiler::target::word
+    Thread_call_native_through_safepoint_stub_offset = 220;
+static constexpr dart::compiler::target::word
+    Thread_call_native_through_safepoint_entry_point_offset = 284;
+static constexpr dart::compiler::target::word
+    Thread_fix_allocation_stub_code_offset = 136;
+static constexpr dart::compiler::target::word
+    Thread_fix_callers_target_code_offset = 132;
+static constexpr dart::compiler::target::word
+    Thread_float_absolute_address_offset = 328;
+static constexpr dart::compiler::target::word
+    Thread_float_negate_address_offset = 324;
+static constexpr dart::compiler::target::word Thread_float_not_address_offset =
+    320;
+static constexpr dart::compiler::target::word
+    Thread_float_zerow_address_offset = 332;
+static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
+    680;
+static constexpr dart::compiler::target::word
+    Thread_interpret_call_entry_point_offset = 300;
+static constexpr dart::compiler::target::word
+    Thread_invoke_dart_code_from_bytecode_stub_offset = 144;
+static constexpr dart::compiler::target::word
+    Thread_invoke_dart_code_stub_offset = 140;
+static constexpr dart::compiler::target::word Thread_isolate_offset = 44;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
-    56;
+    68;
 static constexpr dart::compiler::target::word
-    Thread_lazy_deopt_from_return_stub_offset = 188;
+    Thread_lazy_deopt_from_return_stub_offset = 196;
 static constexpr dart::compiler::target::word
-    Thread_lazy_deopt_from_throw_stub_offset = 192;
+    Thread_lazy_deopt_from_throw_stub_offset = 200;
 static constexpr dart::compiler::target::word
-    Thread_lazy_specialize_type_test_stub_offset = 200;
+    Thread_lazy_specialize_type_test_stub_offset = 208;
 static constexpr dart::compiler::target::word
-    Thread_marking_stack_block_offset = 80;
+    Thread_marking_stack_block_offset = 84;
 static constexpr dart::compiler::target::word
-    Thread_megamorphic_call_checked_entry_offset = 260;
+    Thread_megamorphic_call_checked_entry_offset = 268;
 static constexpr dart::compiler::target::word
-    Thread_monomorphic_miss_entry_offset = 264;
+    Thread_monomorphic_miss_entry_offset = 272;
 static constexpr dart::compiler::target::word
-    Thread_monomorphic_miss_stub_offset = 176;
+    Thread_monomorphic_miss_stub_offset = 184;
 static constexpr dart::compiler::target::word
-    Thread_no_scope_native_wrapper_entry_point_offset = 284;
+    Thread_no_scope_native_wrapper_entry_point_offset = 292;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_with_fpu_regs_entry_point_offset = 232;
+    Thread_null_error_shared_with_fpu_regs_entry_point_offset = 240;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_with_fpu_regs_stub_offset = 148;
+    Thread_null_error_shared_with_fpu_regs_stub_offset = 156;
 static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 240;
+    Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 248;
 static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 156;
+    Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 164;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_without_fpu_regs_entry_point_offset = 228;
+    Thread_null_error_shared_without_fpu_regs_entry_point_offset = 236;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_without_fpu_regs_stub_offset = 144;
+    Thread_null_error_shared_without_fpu_regs_stub_offset = 152;
 static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 236;
+    Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 244;
 static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 152;
-static constexpr dart::compiler::target::word Thread_object_null_offset = 104;
+    Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 160;
+static constexpr dart::compiler::target::word Thread_object_null_offset = 112;
 static constexpr dart::compiler::target::word
-    Thread_predefined_symbols_address_offset = 296;
-static constexpr dart::compiler::target::word Thread_resume_pc_offset = 676;
+    Thread_predefined_symbols_address_offset = 304;
+static constexpr dart::compiler::target::word Thread_resume_pc_offset = 684;
 static constexpr dart::compiler::target::word
-    Thread_saved_shadow_call_stack_offset = 680;
+    Thread_saved_shadow_call_stack_offset = 688;
 static constexpr dart::compiler::target::word Thread_safepoint_state_offset =
-    688;
+    696;
 static constexpr dart::compiler::target::word
-    Thread_slow_type_test_stub_offset = 196;
+    Thread_slow_type_test_stub_offset = 204;
 static constexpr dart::compiler::target::word Thread_stack_limit_offset = 36;
 static constexpr dart::compiler::target::word Thread_saved_stack_limit_offset =
-    40;
+    60;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_flags_offset = 44;
+    Thread_stack_overflow_flags_offset = 64;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 256;
+    Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 264;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 172;
+    Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 180;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 252;
+    Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 260;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 168;
+    Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 176;
 static constexpr dart::compiler::target::word Thread_store_buffer_block_offset =
-    76;
+    80;
 static constexpr dart::compiler::target::word
-    Thread_top_exit_frame_info_offset = 72;
-static constexpr dart::compiler::target::word Thread_top_offset = 64;
+    Thread_top_exit_frame_info_offset = 76;
+static constexpr dart::compiler::target::word Thread_top_offset = 52;
 static constexpr dart::compiler::target::word Thread_top_resource_offset = 24;
 static constexpr dart::compiler::target::word
-    Thread_unboxed_int64_runtime_arg_offset = 96;
-static constexpr dart::compiler::target::word Thread_vm_tag_offset = 88;
+    Thread_unboxed_int64_runtime_arg_offset = 104;
+static constexpr dart::compiler::target::word Thread_vm_tag_offset = 92;
 static constexpr dart::compiler::target::word Thread_write_barrier_code_offset =
-    116;
+    124;
 static constexpr dart::compiler::target::word
-    Thread_write_barrier_entry_point_offset = 216;
+    Thread_write_barrier_entry_point_offset = 224;
 static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset =
-    48;
-static constexpr dart::compiler::target::word Thread_callback_code_offset = 692;
+    40;
+static constexpr dart::compiler::target::word Thread_callback_code_offset = 700;
 static constexpr dart::compiler::target::word TimelineStream_enabled_offset = 8;
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 12;
 static constexpr dart::compiler::target::word Type_arguments_offset = 16;
@@ -2187,8 +2197,8 @@
     4, 12, 8, 16};
 static constexpr dart::compiler::target::word
     Thread_write_barrier_wrappers_thread_offset[] = {
-        628, 632, 636, 640, 644, -1, 648, 652,
-        656, 660, -1,  -1,  -1,  -1, -1,  -1};
+        636, 640, 644, 648, 652, -1, 656, 660,
+        664, 668, -1,  -1,  -1,  -1, -1,  -1};
 static constexpr dart::compiler::target::word ApiError_InstanceSize = 8;
 static constexpr dart::compiler::target::word Array_InstanceSize = 12;
 static constexpr dart::compiler::target::word Array_header_size = 12;
@@ -2456,153 +2466,155 @@
 static constexpr dart::compiler::target::word String_length_offset = 8;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 8;
 static constexpr dart::compiler::target::word
-    Thread_AllocateArray_entry_point_offset = 648;
+    Thread_AllocateArray_entry_point_offset = 656;
 static constexpr dart::compiler::target::word Thread_active_exception_offset =
-    1336;
-static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
     1344;
-static constexpr dart::compiler::target::word
-    Thread_array_write_barrier_code_offset = 232;
-static constexpr dart::compiler::target::word
-    Thread_array_write_barrier_entry_point_offset = 432;
-static constexpr dart::compiler::target::word
-    Thread_allocate_mint_with_fpu_regs_entry_point_offset = 480;
-static constexpr dart::compiler::target::word
-    Thread_allocate_mint_with_fpu_regs_stub_offset = 312;
-static constexpr dart::compiler::target::word
-    Thread_allocate_mint_without_fpu_regs_entry_point_offset = 488;
-static constexpr dart::compiler::target::word
-    Thread_allocate_mint_without_fpu_regs_stub_offset = 320;
-static constexpr dart::compiler::target::word Thread_async_stack_trace_offset =
-    184;
-static constexpr dart::compiler::target::word
-    Thread_auto_scope_native_wrapper_entry_point_offset = 568;
-static constexpr dart::compiler::target::word Thread_bool_false_offset = 216;
-static constexpr dart::compiler::target::word Thread_bool_true_offset = 208;
-static constexpr dart::compiler::target::word
-    Thread_bootstrap_native_wrapper_entry_point_offset = 552;
-static constexpr dart::compiler::target::word
-    Thread_call_to_runtime_entry_point_offset = 440;
-static constexpr dart::compiler::target::word
-    Thread_call_to_runtime_stub_offset = 272;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1408;
-static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
-    528;
-static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 352;
-static constexpr dart::compiler::target::word Thread_deoptimize_entry_offset =
-    536;
-static constexpr dart::compiler::target::word Thread_deoptimize_stub_offset =
-    360;
-static constexpr dart::compiler::target::word Thread_double_abs_address_offset =
-    608;
-static constexpr dart::compiler::target::word
-    Thread_double_negate_address_offset = 600;
-static constexpr dart::compiler::target::word Thread_end_offset = 136;
-static constexpr dart::compiler::target::word
-    Thread_enter_safepoint_stub_offset = 400;
-static constexpr dart::compiler::target::word Thread_execution_state_offset =
-    1376;
-static constexpr dart::compiler::target::word
-    Thread_exit_safepoint_stub_offset = 408;
-static constexpr dart::compiler::target::word
-    Thread_call_native_through_safepoint_stub_offset = 416;
-static constexpr dart::compiler::target::word
-    Thread_call_native_through_safepoint_entry_point_offset = 544;
-static constexpr dart::compiler::target::word
-    Thread_fix_allocation_stub_code_offset = 248;
-static constexpr dart::compiler::target::word
-    Thread_fix_callers_target_code_offset = 240;
-static constexpr dart::compiler::target::word
-    Thread_float_absolute_address_offset = 632;
-static constexpr dart::compiler::target::word
-    Thread_float_negate_address_offset = 624;
-static constexpr dart::compiler::target::word Thread_float_not_address_offset =
-    616;
-static constexpr dart::compiler::target::word
-    Thread_float_zerow_address_offset = 640;
-static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
+static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
     1352;
 static constexpr dart::compiler::target::word
-    Thread_interpret_call_entry_point_offset = 576;
+    Thread_array_write_barrier_code_offset = 240;
 static constexpr dart::compiler::target::word
-    Thread_invoke_dart_code_from_bytecode_stub_offset = 264;
+    Thread_array_write_barrier_entry_point_offset = 440;
 static constexpr dart::compiler::target::word
-    Thread_invoke_dart_code_stub_offset = 256;
-static constexpr dart::compiler::target::word Thread_isolate_offset = 104;
-static constexpr dart::compiler::target::word Thread_field_table_values_offset =
-    112;
+    Thread_allocate_mint_with_fpu_regs_entry_point_offset = 488;
 static constexpr dart::compiler::target::word
-    Thread_lazy_deopt_from_return_stub_offset = 368;
+    Thread_allocate_mint_with_fpu_regs_stub_offset = 320;
 static constexpr dart::compiler::target::word
-    Thread_lazy_deopt_from_throw_stub_offset = 376;
+    Thread_allocate_mint_without_fpu_regs_entry_point_offset = 496;
 static constexpr dart::compiler::target::word
-    Thread_lazy_specialize_type_test_stub_offset = 392;
+    Thread_allocate_mint_without_fpu_regs_stub_offset = 328;
+static constexpr dart::compiler::target::word Thread_async_stack_trace_offset =
+    192;
 static constexpr dart::compiler::target::word
-    Thread_marking_stack_block_offset = 160;
+    Thread_auto_scope_native_wrapper_entry_point_offset = 576;
+static constexpr dart::compiler::target::word Thread_bool_false_offset = 224;
+static constexpr dart::compiler::target::word Thread_bool_true_offset = 216;
 static constexpr dart::compiler::target::word
-    Thread_megamorphic_call_checked_entry_offset = 512;
+    Thread_bootstrap_native_wrapper_entry_point_offset = 560;
 static constexpr dart::compiler::target::word
-    Thread_monomorphic_miss_entry_offset = 520;
+    Thread_call_to_runtime_entry_point_offset = 448;
 static constexpr dart::compiler::target::word
-    Thread_monomorphic_miss_stub_offset = 344;
+    Thread_call_to_runtime_stub_offset = 280;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1416;
 static constexpr dart::compiler::target::word
-    Thread_no_scope_native_wrapper_entry_point_offset = 560;
+    Thread_dispatch_table_array_offset = 96;
+static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
+    536;
+static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 360;
+static constexpr dart::compiler::target::word Thread_deoptimize_entry_offset =
+    544;
+static constexpr dart::compiler::target::word Thread_deoptimize_stub_offset =
+    368;
+static constexpr dart::compiler::target::word Thread_double_abs_address_offset =
+    616;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_with_fpu_regs_entry_point_offset = 456;
+    Thread_double_negate_address_offset = 608;
+static constexpr dart::compiler::target::word Thread_end_offset = 112;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_with_fpu_regs_stub_offset = 288;
-static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 472;
-static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 304;
-static constexpr dart::compiler::target::word
-    Thread_null_error_shared_without_fpu_regs_entry_point_offset = 448;
-static constexpr dart::compiler::target::word
-    Thread_null_error_shared_without_fpu_regs_stub_offset = 280;
-static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 464;
-static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 296;
-static constexpr dart::compiler::target::word Thread_object_null_offset = 200;
-static constexpr dart::compiler::target::word
-    Thread_predefined_symbols_address_offset = 584;
-static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1360;
-static constexpr dart::compiler::target::word
-    Thread_saved_shadow_call_stack_offset = 1368;
-static constexpr dart::compiler::target::word Thread_safepoint_state_offset =
+    Thread_enter_safepoint_stub_offset = 408;
+static constexpr dart::compiler::target::word Thread_execution_state_offset =
     1384;
 static constexpr dart::compiler::target::word
-    Thread_slow_type_test_stub_offset = 384;
+    Thread_exit_safepoint_stub_offset = 416;
+static constexpr dart::compiler::target::word
+    Thread_call_native_through_safepoint_stub_offset = 424;
+static constexpr dart::compiler::target::word
+    Thread_call_native_through_safepoint_entry_point_offset = 552;
+static constexpr dart::compiler::target::word
+    Thread_fix_allocation_stub_code_offset = 256;
+static constexpr dart::compiler::target::word
+    Thread_fix_callers_target_code_offset = 248;
+static constexpr dart::compiler::target::word
+    Thread_float_absolute_address_offset = 640;
+static constexpr dart::compiler::target::word
+    Thread_float_negate_address_offset = 632;
+static constexpr dart::compiler::target::word Thread_float_not_address_offset =
+    624;
+static constexpr dart::compiler::target::word
+    Thread_float_zerow_address_offset = 648;
+static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
+    1360;
+static constexpr dart::compiler::target::word
+    Thread_interpret_call_entry_point_offset = 584;
+static constexpr dart::compiler::target::word
+    Thread_invoke_dart_code_from_bytecode_stub_offset = 272;
+static constexpr dart::compiler::target::word
+    Thread_invoke_dart_code_stub_offset = 264;
+static constexpr dart::compiler::target::word Thread_isolate_offset = 88;
+static constexpr dart::compiler::target::word Thread_field_table_values_offset =
+    136;
+static constexpr dart::compiler::target::word
+    Thread_lazy_deopt_from_return_stub_offset = 376;
+static constexpr dart::compiler::target::word
+    Thread_lazy_deopt_from_throw_stub_offset = 384;
+static constexpr dart::compiler::target::word
+    Thread_lazy_specialize_type_test_stub_offset = 400;
+static constexpr dart::compiler::target::word
+    Thread_marking_stack_block_offset = 168;
+static constexpr dart::compiler::target::word
+    Thread_megamorphic_call_checked_entry_offset = 520;
+static constexpr dart::compiler::target::word
+    Thread_monomorphic_miss_entry_offset = 528;
+static constexpr dart::compiler::target::word
+    Thread_monomorphic_miss_stub_offset = 352;
+static constexpr dart::compiler::target::word
+    Thread_no_scope_native_wrapper_entry_point_offset = 568;
+static constexpr dart::compiler::target::word
+    Thread_null_error_shared_with_fpu_regs_entry_point_offset = 464;
+static constexpr dart::compiler::target::word
+    Thread_null_error_shared_with_fpu_regs_stub_offset = 296;
+static constexpr dart::compiler::target::word
+    Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 480;
+static constexpr dart::compiler::target::word
+    Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 312;
+static constexpr dart::compiler::target::word
+    Thread_null_error_shared_without_fpu_regs_entry_point_offset = 456;
+static constexpr dart::compiler::target::word
+    Thread_null_error_shared_without_fpu_regs_stub_offset = 288;
+static constexpr dart::compiler::target::word
+    Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 472;
+static constexpr dart::compiler::target::word
+    Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 304;
+static constexpr dart::compiler::target::word Thread_object_null_offset = 208;
+static constexpr dart::compiler::target::word
+    Thread_predefined_symbols_address_offset = 592;
+static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1368;
+static constexpr dart::compiler::target::word
+    Thread_saved_shadow_call_stack_offset = 1376;
+static constexpr dart::compiler::target::word Thread_safepoint_state_offset =
+    1392;
+static constexpr dart::compiler::target::word
+    Thread_slow_type_test_stub_offset = 392;
 static constexpr dart::compiler::target::word Thread_stack_limit_offset = 72;
 static constexpr dart::compiler::target::word Thread_saved_stack_limit_offset =
-    80;
+    120;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_flags_offset = 88;
+    Thread_stack_overflow_flags_offset = 128;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 504;
+    Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 512;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 336;
+    Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 344;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 496;
+    Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 504;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 328;
+    Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 336;
 static constexpr dart::compiler::target::word Thread_store_buffer_block_offset =
-    152;
+    160;
 static constexpr dart::compiler::target::word
-    Thread_top_exit_frame_info_offset = 144;
-static constexpr dart::compiler::target::word Thread_top_offset = 128;
+    Thread_top_exit_frame_info_offset = 152;
+static constexpr dart::compiler::target::word Thread_top_offset = 104;
 static constexpr dart::compiler::target::word Thread_top_resource_offset = 48;
 static constexpr dart::compiler::target::word
-    Thread_unboxed_int64_runtime_arg_offset = 192;
-static constexpr dart::compiler::target::word Thread_vm_tag_offset = 176;
+    Thread_unboxed_int64_runtime_arg_offset = 200;
+static constexpr dart::compiler::target::word Thread_vm_tag_offset = 184;
 static constexpr dart::compiler::target::word Thread_write_barrier_code_offset =
-    224;
+    232;
 static constexpr dart::compiler::target::word
-    Thread_write_barrier_entry_point_offset = 424;
+    Thread_write_barrier_entry_point_offset = 432;
 static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset =
-    96;
+    80;
 static constexpr dart::compiler::target::word Thread_callback_code_offset =
-    1392;
+    1400;
 static constexpr dart::compiler::target::word TimelineStream_enabled_offset =
     16;
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 16;
@@ -2638,8 +2650,8 @@
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
     Thread_write_barrier_wrappers_thread_offset[] = {
-        1248, 1256, 1264, 1272, -1,   -1,   1280, 1288,
-        1296, 1304, 1312, -1,   1320, 1328, -1,   -1};
+        1256, 1264, 1272, 1280, -1,   -1,   1288, 1296,
+        1304, 1312, 1320, -1,   1328, 1336, -1,   -1};
 static constexpr dart::compiler::target::word ApiError_InstanceSize = 16;
 static constexpr dart::compiler::target::word Array_InstanceSize = 24;
 static constexpr dart::compiler::target::word Array_header_size = 24;
@@ -2906,152 +2918,154 @@
 static constexpr dart::compiler::target::word String_length_offset = 4;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 4;
 static constexpr dart::compiler::target::word
-    Thread_AllocateArray_entry_point_offset = 328;
+    Thread_AllocateArray_entry_point_offset = 336;
 static constexpr dart::compiler::target::word Thread_active_exception_offset =
-    628;
-static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
-    632;
-static constexpr dart::compiler::target::word
-    Thread_array_write_barrier_code_offset = 120;
-static constexpr dart::compiler::target::word
-    Thread_array_write_barrier_entry_point_offset = 220;
-static constexpr dart::compiler::target::word
-    Thread_allocate_mint_with_fpu_regs_entry_point_offset = 244;
-static constexpr dart::compiler::target::word
-    Thread_allocate_mint_with_fpu_regs_stub_offset = 160;
-static constexpr dart::compiler::target::word
-    Thread_allocate_mint_without_fpu_regs_entry_point_offset = 248;
-static constexpr dart::compiler::target::word
-    Thread_allocate_mint_without_fpu_regs_stub_offset = 164;
-static constexpr dart::compiler::target::word Thread_async_stack_trace_offset =
-    92;
-static constexpr dart::compiler::target::word
-    Thread_auto_scope_native_wrapper_entry_point_offset = 288;
-static constexpr dart::compiler::target::word Thread_bool_false_offset = 112;
-static constexpr dart::compiler::target::word Thread_bool_true_offset = 108;
-static constexpr dart::compiler::target::word
-    Thread_bootstrap_native_wrapper_entry_point_offset = 280;
-static constexpr dart::compiler::target::word
-    Thread_call_to_runtime_entry_point_offset = 224;
-static constexpr dart::compiler::target::word
-    Thread_call_to_runtime_stub_offset = 140;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 664;
-static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
-    268;
-static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 180;
-static constexpr dart::compiler::target::word Thread_deoptimize_entry_offset =
-    272;
-static constexpr dart::compiler::target::word Thread_deoptimize_stub_offset =
-    184;
-static constexpr dart::compiler::target::word Thread_double_abs_address_offset =
-    308;
-static constexpr dart::compiler::target::word
-    Thread_double_negate_address_offset = 304;
-static constexpr dart::compiler::target::word Thread_end_offset = 68;
-static constexpr dart::compiler::target::word
-    Thread_enter_safepoint_stub_offset = 204;
-static constexpr dart::compiler::target::word Thread_execution_state_offset =
-    648;
-static constexpr dart::compiler::target::word
-    Thread_exit_safepoint_stub_offset = 208;
-static constexpr dart::compiler::target::word
-    Thread_call_native_through_safepoint_stub_offset = 212;
-static constexpr dart::compiler::target::word
-    Thread_call_native_through_safepoint_entry_point_offset = 276;
-static constexpr dart::compiler::target::word
-    Thread_fix_allocation_stub_code_offset = 128;
-static constexpr dart::compiler::target::word
-    Thread_fix_callers_target_code_offset = 124;
-static constexpr dart::compiler::target::word
-    Thread_float_absolute_address_offset = 320;
-static constexpr dart::compiler::target::word
-    Thread_float_negate_address_offset = 316;
-static constexpr dart::compiler::target::word Thread_float_not_address_offset =
-    312;
-static constexpr dart::compiler::target::word
-    Thread_float_zerow_address_offset = 324;
-static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
     636;
+static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
+    640;
 static constexpr dart::compiler::target::word
-    Thread_interpret_call_entry_point_offset = 292;
+    Thread_array_write_barrier_code_offset = 128;
 static constexpr dart::compiler::target::word
-    Thread_invoke_dart_code_from_bytecode_stub_offset = 136;
+    Thread_array_write_barrier_entry_point_offset = 228;
 static constexpr dart::compiler::target::word
-    Thread_invoke_dart_code_stub_offset = 132;
-static constexpr dart::compiler::target::word Thread_isolate_offset = 52;
+    Thread_allocate_mint_with_fpu_regs_entry_point_offset = 252;
+static constexpr dart::compiler::target::word
+    Thread_allocate_mint_with_fpu_regs_stub_offset = 168;
+static constexpr dart::compiler::target::word
+    Thread_allocate_mint_without_fpu_regs_entry_point_offset = 256;
+static constexpr dart::compiler::target::word
+    Thread_allocate_mint_without_fpu_regs_stub_offset = 172;
+static constexpr dart::compiler::target::word Thread_async_stack_trace_offset =
+    96;
+static constexpr dart::compiler::target::word
+    Thread_auto_scope_native_wrapper_entry_point_offset = 296;
+static constexpr dart::compiler::target::word Thread_bool_false_offset = 120;
+static constexpr dart::compiler::target::word Thread_bool_true_offset = 116;
+static constexpr dart::compiler::target::word
+    Thread_bootstrap_native_wrapper_entry_point_offset = 288;
+static constexpr dart::compiler::target::word
+    Thread_call_to_runtime_entry_point_offset = 232;
+static constexpr dart::compiler::target::word
+    Thread_call_to_runtime_stub_offset = 148;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 672;
+static constexpr dart::compiler::target::word
+    Thread_dispatch_table_array_offset = 48;
+static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
+    276;
+static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 188;
+static constexpr dart::compiler::target::word Thread_deoptimize_entry_offset =
+    280;
+static constexpr dart::compiler::target::word Thread_deoptimize_stub_offset =
+    192;
+static constexpr dart::compiler::target::word Thread_double_abs_address_offset =
+    316;
+static constexpr dart::compiler::target::word
+    Thread_double_negate_address_offset = 312;
+static constexpr dart::compiler::target::word Thread_end_offset = 56;
+static constexpr dart::compiler::target::word
+    Thread_enter_safepoint_stub_offset = 212;
+static constexpr dart::compiler::target::word Thread_execution_state_offset =
+    656;
+static constexpr dart::compiler::target::word
+    Thread_exit_safepoint_stub_offset = 216;
+static constexpr dart::compiler::target::word
+    Thread_call_native_through_safepoint_stub_offset = 220;
+static constexpr dart::compiler::target::word
+    Thread_call_native_through_safepoint_entry_point_offset = 284;
+static constexpr dart::compiler::target::word
+    Thread_fix_allocation_stub_code_offset = 136;
+static constexpr dart::compiler::target::word
+    Thread_fix_callers_target_code_offset = 132;
+static constexpr dart::compiler::target::word
+    Thread_float_absolute_address_offset = 328;
+static constexpr dart::compiler::target::word
+    Thread_float_negate_address_offset = 324;
+static constexpr dart::compiler::target::word Thread_float_not_address_offset =
+    320;
+static constexpr dart::compiler::target::word
+    Thread_float_zerow_address_offset = 332;
+static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
+    644;
+static constexpr dart::compiler::target::word
+    Thread_interpret_call_entry_point_offset = 300;
+static constexpr dart::compiler::target::word
+    Thread_invoke_dart_code_from_bytecode_stub_offset = 144;
+static constexpr dart::compiler::target::word
+    Thread_invoke_dart_code_stub_offset = 140;
+static constexpr dart::compiler::target::word Thread_isolate_offset = 44;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
-    56;
+    68;
 static constexpr dart::compiler::target::word
-    Thread_lazy_deopt_from_return_stub_offset = 188;
+    Thread_lazy_deopt_from_return_stub_offset = 196;
 static constexpr dart::compiler::target::word
-    Thread_lazy_deopt_from_throw_stub_offset = 192;
+    Thread_lazy_deopt_from_throw_stub_offset = 200;
 static constexpr dart::compiler::target::word
-    Thread_lazy_specialize_type_test_stub_offset = 200;
+    Thread_lazy_specialize_type_test_stub_offset = 208;
 static constexpr dart::compiler::target::word
-    Thread_marking_stack_block_offset = 80;
+    Thread_marking_stack_block_offset = 84;
 static constexpr dart::compiler::target::word
-    Thread_megamorphic_call_checked_entry_offset = 260;
+    Thread_megamorphic_call_checked_entry_offset = 268;
 static constexpr dart::compiler::target::word
-    Thread_monomorphic_miss_entry_offset = 264;
+    Thread_monomorphic_miss_entry_offset = 272;
 static constexpr dart::compiler::target::word
-    Thread_monomorphic_miss_stub_offset = 176;
+    Thread_monomorphic_miss_stub_offset = 184;
 static constexpr dart::compiler::target::word
-    Thread_no_scope_native_wrapper_entry_point_offset = 284;
+    Thread_no_scope_native_wrapper_entry_point_offset = 292;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_with_fpu_regs_entry_point_offset = 232;
+    Thread_null_error_shared_with_fpu_regs_entry_point_offset = 240;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_with_fpu_regs_stub_offset = 148;
+    Thread_null_error_shared_with_fpu_regs_stub_offset = 156;
 static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 240;
+    Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 248;
 static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 156;
+    Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 164;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_without_fpu_regs_entry_point_offset = 228;
+    Thread_null_error_shared_without_fpu_regs_entry_point_offset = 236;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_without_fpu_regs_stub_offset = 144;
+    Thread_null_error_shared_without_fpu_regs_stub_offset = 152;
 static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 236;
+    Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 244;
 static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 152;
-static constexpr dart::compiler::target::word Thread_object_null_offset = 104;
+    Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 160;
+static constexpr dart::compiler::target::word Thread_object_null_offset = 112;
 static constexpr dart::compiler::target::word
-    Thread_predefined_symbols_address_offset = 296;
-static constexpr dart::compiler::target::word Thread_resume_pc_offset = 640;
+    Thread_predefined_symbols_address_offset = 304;
+static constexpr dart::compiler::target::word Thread_resume_pc_offset = 648;
 static constexpr dart::compiler::target::word
-    Thread_saved_shadow_call_stack_offset = 644;
+    Thread_saved_shadow_call_stack_offset = 652;
 static constexpr dart::compiler::target::word Thread_safepoint_state_offset =
-    652;
+    660;
 static constexpr dart::compiler::target::word
-    Thread_slow_type_test_stub_offset = 196;
+    Thread_slow_type_test_stub_offset = 204;
 static constexpr dart::compiler::target::word Thread_stack_limit_offset = 36;
 static constexpr dart::compiler::target::word Thread_saved_stack_limit_offset =
-    40;
+    60;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_flags_offset = 44;
+    Thread_stack_overflow_flags_offset = 64;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 256;
+    Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 264;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 172;
+    Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 180;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 252;
+    Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 260;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 168;
+    Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 176;
 static constexpr dart::compiler::target::word Thread_store_buffer_block_offset =
-    76;
+    80;
 static constexpr dart::compiler::target::word
-    Thread_top_exit_frame_info_offset = 72;
-static constexpr dart::compiler::target::word Thread_top_offset = 64;
+    Thread_top_exit_frame_info_offset = 76;
+static constexpr dart::compiler::target::word Thread_top_offset = 52;
 static constexpr dart::compiler::target::word Thread_top_resource_offset = 24;
 static constexpr dart::compiler::target::word
-    Thread_unboxed_int64_runtime_arg_offset = 96;
-static constexpr dart::compiler::target::word Thread_vm_tag_offset = 88;
+    Thread_unboxed_int64_runtime_arg_offset = 104;
+static constexpr dart::compiler::target::word Thread_vm_tag_offset = 92;
 static constexpr dart::compiler::target::word Thread_write_barrier_code_offset =
-    116;
+    124;
 static constexpr dart::compiler::target::word
-    Thread_write_barrier_entry_point_offset = 216;
+    Thread_write_barrier_entry_point_offset = 224;
 static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset =
-    48;
-static constexpr dart::compiler::target::word Thread_callback_code_offset = 656;
+    40;
+static constexpr dart::compiler::target::word Thread_callback_code_offset = 664;
 static constexpr dart::compiler::target::word TimelineStream_enabled_offset = 8;
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 12;
 static constexpr dart::compiler::target::word Type_arguments_offset = 16;
@@ -3351,151 +3365,153 @@
 static constexpr dart::compiler::target::word String_length_offset = 8;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 8;
 static constexpr dart::compiler::target::word
-    Thread_AllocateArray_entry_point_offset = 648;
+    Thread_AllocateArray_entry_point_offset = 656;
 static constexpr dart::compiler::target::word Thread_active_exception_offset =
     1416;
 static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
     1424;
 static constexpr dart::compiler::target::word
-    Thread_array_write_barrier_code_offset = 232;
+    Thread_array_write_barrier_code_offset = 240;
 static constexpr dart::compiler::target::word
-    Thread_array_write_barrier_entry_point_offset = 432;
+    Thread_array_write_barrier_entry_point_offset = 440;
 static constexpr dart::compiler::target::word
-    Thread_allocate_mint_with_fpu_regs_entry_point_offset = 480;
+    Thread_allocate_mint_with_fpu_regs_entry_point_offset = 488;
 static constexpr dart::compiler::target::word
-    Thread_allocate_mint_with_fpu_regs_stub_offset = 312;
+    Thread_allocate_mint_with_fpu_regs_stub_offset = 320;
 static constexpr dart::compiler::target::word
-    Thread_allocate_mint_without_fpu_regs_entry_point_offset = 488;
+    Thread_allocate_mint_without_fpu_regs_entry_point_offset = 496;
 static constexpr dart::compiler::target::word
-    Thread_allocate_mint_without_fpu_regs_stub_offset = 320;
+    Thread_allocate_mint_without_fpu_regs_stub_offset = 328;
 static constexpr dart::compiler::target::word Thread_async_stack_trace_offset =
-    184;
+    192;
 static constexpr dart::compiler::target::word
-    Thread_auto_scope_native_wrapper_entry_point_offset = 568;
-static constexpr dart::compiler::target::word Thread_bool_false_offset = 216;
-static constexpr dart::compiler::target::word Thread_bool_true_offset = 208;
+    Thread_auto_scope_native_wrapper_entry_point_offset = 576;
+static constexpr dart::compiler::target::word Thread_bool_false_offset = 224;
+static constexpr dart::compiler::target::word Thread_bool_true_offset = 216;
 static constexpr dart::compiler::target::word
-    Thread_bootstrap_native_wrapper_entry_point_offset = 552;
+    Thread_bootstrap_native_wrapper_entry_point_offset = 560;
 static constexpr dart::compiler::target::word
-    Thread_call_to_runtime_entry_point_offset = 440;
+    Thread_call_to_runtime_entry_point_offset = 448;
 static constexpr dart::compiler::target::word
-    Thread_call_to_runtime_stub_offset = 272;
+    Thread_call_to_runtime_stub_offset = 280;
 static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1488;
+static constexpr dart::compiler::target::word
+    Thread_dispatch_table_array_offset = 96;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
-    528;
-static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 352;
-static constexpr dart::compiler::target::word Thread_deoptimize_entry_offset =
     536;
+static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 360;
+static constexpr dart::compiler::target::word Thread_deoptimize_entry_offset =
+    544;
 static constexpr dart::compiler::target::word Thread_deoptimize_stub_offset =
-    360;
+    368;
 static constexpr dart::compiler::target::word Thread_double_abs_address_offset =
-    608;
+    616;
 static constexpr dart::compiler::target::word
-    Thread_double_negate_address_offset = 600;
-static constexpr dart::compiler::target::word Thread_end_offset = 136;
+    Thread_double_negate_address_offset = 608;
+static constexpr dart::compiler::target::word Thread_end_offset = 112;
 static constexpr dart::compiler::target::word
-    Thread_enter_safepoint_stub_offset = 400;
+    Thread_enter_safepoint_stub_offset = 408;
 static constexpr dart::compiler::target::word Thread_execution_state_offset =
     1456;
 static constexpr dart::compiler::target::word
-    Thread_exit_safepoint_stub_offset = 408;
+    Thread_exit_safepoint_stub_offset = 416;
 static constexpr dart::compiler::target::word
-    Thread_call_native_through_safepoint_stub_offset = 416;
+    Thread_call_native_through_safepoint_stub_offset = 424;
 static constexpr dart::compiler::target::word
-    Thread_call_native_through_safepoint_entry_point_offset = 544;
+    Thread_call_native_through_safepoint_entry_point_offset = 552;
 static constexpr dart::compiler::target::word
-    Thread_fix_allocation_stub_code_offset = 248;
+    Thread_fix_allocation_stub_code_offset = 256;
 static constexpr dart::compiler::target::word
-    Thread_fix_callers_target_code_offset = 240;
+    Thread_fix_callers_target_code_offset = 248;
 static constexpr dart::compiler::target::word
-    Thread_float_absolute_address_offset = 632;
+    Thread_float_absolute_address_offset = 640;
 static constexpr dart::compiler::target::word
-    Thread_float_negate_address_offset = 624;
+    Thread_float_negate_address_offset = 632;
 static constexpr dart::compiler::target::word Thread_float_not_address_offset =
-    616;
+    624;
 static constexpr dart::compiler::target::word
-    Thread_float_zerow_address_offset = 640;
+    Thread_float_zerow_address_offset = 648;
 static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
     1432;
 static constexpr dart::compiler::target::word
-    Thread_interpret_call_entry_point_offset = 576;
+    Thread_interpret_call_entry_point_offset = 584;
 static constexpr dart::compiler::target::word
-    Thread_invoke_dart_code_from_bytecode_stub_offset = 264;
+    Thread_invoke_dart_code_from_bytecode_stub_offset = 272;
 static constexpr dart::compiler::target::word
-    Thread_invoke_dart_code_stub_offset = 256;
-static constexpr dart::compiler::target::word Thread_isolate_offset = 104;
+    Thread_invoke_dart_code_stub_offset = 264;
+static constexpr dart::compiler::target::word Thread_isolate_offset = 88;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
-    112;
+    136;
 static constexpr dart::compiler::target::word
-    Thread_lazy_deopt_from_return_stub_offset = 368;
+    Thread_lazy_deopt_from_return_stub_offset = 376;
 static constexpr dart::compiler::target::word
-    Thread_lazy_deopt_from_throw_stub_offset = 376;
+    Thread_lazy_deopt_from_throw_stub_offset = 384;
 static constexpr dart::compiler::target::word
-    Thread_lazy_specialize_type_test_stub_offset = 392;
+    Thread_lazy_specialize_type_test_stub_offset = 400;
 static constexpr dart::compiler::target::word
-    Thread_marking_stack_block_offset = 160;
+    Thread_marking_stack_block_offset = 168;
 static constexpr dart::compiler::target::word
-    Thread_megamorphic_call_checked_entry_offset = 512;
+    Thread_megamorphic_call_checked_entry_offset = 520;
 static constexpr dart::compiler::target::word
-    Thread_monomorphic_miss_entry_offset = 520;
+    Thread_monomorphic_miss_entry_offset = 528;
 static constexpr dart::compiler::target::word
-    Thread_monomorphic_miss_stub_offset = 344;
+    Thread_monomorphic_miss_stub_offset = 352;
 static constexpr dart::compiler::target::word
-    Thread_no_scope_native_wrapper_entry_point_offset = 560;
+    Thread_no_scope_native_wrapper_entry_point_offset = 568;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_with_fpu_regs_entry_point_offset = 456;
+    Thread_null_error_shared_with_fpu_regs_entry_point_offset = 464;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_with_fpu_regs_stub_offset = 288;
+    Thread_null_error_shared_with_fpu_regs_stub_offset = 296;
 static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 472;
+    Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 480;
 static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 304;
+    Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 312;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_without_fpu_regs_entry_point_offset = 448;
+    Thread_null_error_shared_without_fpu_regs_entry_point_offset = 456;
 static constexpr dart::compiler::target::word
-    Thread_null_error_shared_without_fpu_regs_stub_offset = 280;
+    Thread_null_error_shared_without_fpu_regs_stub_offset = 288;
 static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 464;
+    Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 472;
 static constexpr dart::compiler::target::word
-    Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 296;
-static constexpr dart::compiler::target::word Thread_object_null_offset = 200;
+    Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 304;
+static constexpr dart::compiler::target::word Thread_object_null_offset = 208;
 static constexpr dart::compiler::target::word
-    Thread_predefined_symbols_address_offset = 584;
+    Thread_predefined_symbols_address_offset = 592;
 static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1440;
 static constexpr dart::compiler::target::word
     Thread_saved_shadow_call_stack_offset = 1448;
 static constexpr dart::compiler::target::word Thread_safepoint_state_offset =
     1464;
 static constexpr dart::compiler::target::word
-    Thread_slow_type_test_stub_offset = 384;
+    Thread_slow_type_test_stub_offset = 392;
 static constexpr dart::compiler::target::word Thread_stack_limit_offset = 72;
 static constexpr dart::compiler::target::word Thread_saved_stack_limit_offset =
-    80;
+    120;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_flags_offset = 88;
+    Thread_stack_overflow_flags_offset = 128;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 504;
+    Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 512;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 336;
+    Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 344;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 496;
+    Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 504;
 static constexpr dart::compiler::target::word
-    Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 328;
+    Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 336;
 static constexpr dart::compiler::target::word Thread_store_buffer_block_offset =
-    152;
+    160;
 static constexpr dart::compiler::target::word
-    Thread_top_exit_frame_info_offset = 144;
-static constexpr dart::compiler::target::word Thread_top_offset = 128;
+    Thread_top_exit_frame_info_offset = 152;
+static constexpr dart::compiler::target::word Thread_top_offset = 104;
 static constexpr dart::compiler::target::word Thread_top_resource_offset = 48;
 static constexpr dart::compiler::target::word
-    Thread_unboxed_int64_runtime_arg_offset = 192;
-static constexpr dart::compiler::target::word Thread_vm_tag_offset = 176;
+    Thread_unboxed_int64_runtime_arg_offset = 200;
+static constexpr dart::compiler::target::word Thread_vm_tag_offset = 184;
 static constexpr dart::compiler::target::word Thread_write_barrier_code_offset =
-    224;
+    232;
 static constexpr dart::compiler::target::word
-    Thread_write_barrier_entry_point_offset = 424;
+    Thread_write_barrier_entry_point_offset = 432;
 static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset =
-    96;
+    80;
 static constexpr dart::compiler::target::word Thread_callback_code_offset =
     1472;
 static constexpr dart::compiler::target::word TimelineStream_enabled_offset =
@@ -3533,8 +3549,8 @@
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
     Thread_write_barrier_wrappers_thread_offset[] = {
-        1248, 1256, 1264, 1272, 1280, 1288, 1296, 1304, 1312, 1320, 1328,
-        1336, 1344, 1352, 1360, -1,   -1,   -1,   -1,   1368, 1376, 1384,
+        1256, 1264, 1272, 1280, 1288, 1296, 1304, 1312, 1320, 1328, 1336,
+        1344, 1352, 1360, 1368, -1,   -1,   -1,   -1,   1376, 1384, -1,
         -1,   1392, 1400, 1408, -1,   -1,   -1,   -1,   -1,   -1};
 static constexpr dart::compiler::target::word ApiError_InstanceSize = 16;
 static constexpr dart::compiler::target::word Array_InstanceSize = 24;
@@ -3820,159 +3836,161 @@
 static constexpr dart::compiler::target::word
     AOT_SubtypeTestCache_cache_offset = 4;
 static constexpr dart::compiler::target::word
-    AOT_Thread_AllocateArray_entry_point_offset = 328;
+    AOT_Thread_AllocateArray_entry_point_offset = 336;
 static constexpr dart::compiler::target::word
-    AOT_Thread_active_exception_offset = 664;
+    AOT_Thread_active_exception_offset = 672;
 static constexpr dart::compiler::target::word
-    AOT_Thread_active_stacktrace_offset = 668;
+    AOT_Thread_active_stacktrace_offset = 676;
 static constexpr dart::compiler::target::word
-    AOT_Thread_array_write_barrier_code_offset = 120;
+    AOT_Thread_array_write_barrier_code_offset = 128;
 static constexpr dart::compiler::target::word
-    AOT_Thread_array_write_barrier_entry_point_offset = 220;
+    AOT_Thread_array_write_barrier_entry_point_offset = 228;
 static constexpr dart::compiler::target::word
-    AOT_Thread_allocate_mint_with_fpu_regs_entry_point_offset = 244;
+    AOT_Thread_allocate_mint_with_fpu_regs_entry_point_offset = 252;
 static constexpr dart::compiler::target::word
-    AOT_Thread_allocate_mint_with_fpu_regs_stub_offset = 160;
+    AOT_Thread_allocate_mint_with_fpu_regs_stub_offset = 168;
 static constexpr dart::compiler::target::word
-    AOT_Thread_allocate_mint_without_fpu_regs_entry_point_offset = 248;
+    AOT_Thread_allocate_mint_without_fpu_regs_entry_point_offset = 256;
 static constexpr dart::compiler::target::word
-    AOT_Thread_allocate_mint_without_fpu_regs_stub_offset = 164;
+    AOT_Thread_allocate_mint_without_fpu_regs_stub_offset = 172;
 static constexpr dart::compiler::target::word
-    AOT_Thread_async_stack_trace_offset = 92;
+    AOT_Thread_async_stack_trace_offset = 96;
 static constexpr dart::compiler::target::word
-    AOT_Thread_auto_scope_native_wrapper_entry_point_offset = 288;
+    AOT_Thread_auto_scope_native_wrapper_entry_point_offset = 296;
 static constexpr dart::compiler::target::word AOT_Thread_bool_false_offset =
-    112;
-static constexpr dart::compiler::target::word AOT_Thread_bool_true_offset = 108;
+    120;
+static constexpr dart::compiler::target::word AOT_Thread_bool_true_offset = 116;
 static constexpr dart::compiler::target::word
-    AOT_Thread_bootstrap_native_wrapper_entry_point_offset = 280;
+    AOT_Thread_bootstrap_native_wrapper_entry_point_offset = 288;
 static constexpr dart::compiler::target::word
-    AOT_Thread_call_to_runtime_entry_point_offset = 224;
+    AOT_Thread_call_to_runtime_entry_point_offset = 232;
 static constexpr dart::compiler::target::word
-    AOT_Thread_call_to_runtime_stub_offset = 140;
+    AOT_Thread_call_to_runtime_stub_offset = 148;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
-    700;
+    708;
+static constexpr dart::compiler::target::word
+    AOT_Thread_dispatch_table_array_offset = 48;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
-    268;
+    276;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
-    180;
+    188;
 static constexpr dart::compiler::target::word
-    AOT_Thread_deoptimize_entry_offset = 272;
+    AOT_Thread_deoptimize_entry_offset = 280;
 static constexpr dart::compiler::target::word
-    AOT_Thread_deoptimize_stub_offset = 184;
+    AOT_Thread_deoptimize_stub_offset = 192;
 static constexpr dart::compiler::target::word
-    AOT_Thread_double_abs_address_offset = 308;
+    AOT_Thread_double_abs_address_offset = 316;
 static constexpr dart::compiler::target::word
-    AOT_Thread_double_negate_address_offset = 304;
-static constexpr dart::compiler::target::word AOT_Thread_end_offset = 68;
+    AOT_Thread_double_negate_address_offset = 312;
+static constexpr dart::compiler::target::word AOT_Thread_end_offset = 56;
 static constexpr dart::compiler::target::word
-    AOT_Thread_enter_safepoint_stub_offset = 204;
+    AOT_Thread_enter_safepoint_stub_offset = 212;
 static constexpr dart::compiler::target::word
-    AOT_Thread_execution_state_offset = 684;
+    AOT_Thread_execution_state_offset = 692;
 static constexpr dart::compiler::target::word
-    AOT_Thread_exit_safepoint_stub_offset = 208;
+    AOT_Thread_exit_safepoint_stub_offset = 216;
 static constexpr dart::compiler::target::word
-    AOT_Thread_call_native_through_safepoint_stub_offset = 212;
+    AOT_Thread_call_native_through_safepoint_stub_offset = 220;
 static constexpr dart::compiler::target::word
-    AOT_Thread_call_native_through_safepoint_entry_point_offset = 276;
+    AOT_Thread_call_native_through_safepoint_entry_point_offset = 284;
 static constexpr dart::compiler::target::word
-    AOT_Thread_fix_allocation_stub_code_offset = 128;
+    AOT_Thread_fix_allocation_stub_code_offset = 136;
 static constexpr dart::compiler::target::word
-    AOT_Thread_fix_callers_target_code_offset = 124;
+    AOT_Thread_fix_callers_target_code_offset = 132;
 static constexpr dart::compiler::target::word
-    AOT_Thread_float_absolute_address_offset = 320;
+    AOT_Thread_float_absolute_address_offset = 328;
 static constexpr dart::compiler::target::word
-    AOT_Thread_float_negate_address_offset = 316;
+    AOT_Thread_float_negate_address_offset = 324;
 static constexpr dart::compiler::target::word
-    AOT_Thread_float_not_address_offset = 312;
+    AOT_Thread_float_not_address_offset = 320;
 static constexpr dart::compiler::target::word
-    AOT_Thread_float_zerow_address_offset = 324;
+    AOT_Thread_float_zerow_address_offset = 332;
 static constexpr dart::compiler::target::word
-    AOT_Thread_global_object_pool_offset = 672;
+    AOT_Thread_global_object_pool_offset = 680;
 static constexpr dart::compiler::target::word
-    AOT_Thread_interpret_call_entry_point_offset = 292;
+    AOT_Thread_interpret_call_entry_point_offset = 300;
 static constexpr dart::compiler::target::word
-    AOT_Thread_invoke_dart_code_from_bytecode_stub_offset = 136;
+    AOT_Thread_invoke_dart_code_from_bytecode_stub_offset = 144;
 static constexpr dart::compiler::target::word
-    AOT_Thread_invoke_dart_code_stub_offset = 132;
-static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 52;
+    AOT_Thread_invoke_dart_code_stub_offset = 140;
+static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 44;
 static constexpr dart::compiler::target::word
-    AOT_Thread_field_table_values_offset = 56;
+    AOT_Thread_field_table_values_offset = 68;
 static constexpr dart::compiler::target::word
-    AOT_Thread_lazy_deopt_from_return_stub_offset = 188;
+    AOT_Thread_lazy_deopt_from_return_stub_offset = 196;
 static constexpr dart::compiler::target::word
-    AOT_Thread_lazy_deopt_from_throw_stub_offset = 192;
+    AOT_Thread_lazy_deopt_from_throw_stub_offset = 200;
 static constexpr dart::compiler::target::word
-    AOT_Thread_lazy_specialize_type_test_stub_offset = 200;
+    AOT_Thread_lazy_specialize_type_test_stub_offset = 208;
 static constexpr dart::compiler::target::word
-    AOT_Thread_marking_stack_block_offset = 80;
+    AOT_Thread_marking_stack_block_offset = 84;
 static constexpr dart::compiler::target::word
-    AOT_Thread_megamorphic_call_checked_entry_offset = 260;
+    AOT_Thread_megamorphic_call_checked_entry_offset = 268;
 static constexpr dart::compiler::target::word
-    AOT_Thread_monomorphic_miss_entry_offset = 264;
+    AOT_Thread_monomorphic_miss_entry_offset = 272;
 static constexpr dart::compiler::target::word
-    AOT_Thread_monomorphic_miss_stub_offset = 176;
+    AOT_Thread_monomorphic_miss_stub_offset = 184;
 static constexpr dart::compiler::target::word
-    AOT_Thread_no_scope_native_wrapper_entry_point_offset = 284;
+    AOT_Thread_no_scope_native_wrapper_entry_point_offset = 292;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_error_shared_with_fpu_regs_entry_point_offset = 232;
+    AOT_Thread_null_error_shared_with_fpu_regs_entry_point_offset = 240;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_error_shared_with_fpu_regs_stub_offset = 148;
+    AOT_Thread_null_error_shared_with_fpu_regs_stub_offset = 156;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 240;
+    AOT_Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 248;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 156;
+    AOT_Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 164;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_error_shared_without_fpu_regs_entry_point_offset = 228;
+    AOT_Thread_null_error_shared_without_fpu_regs_entry_point_offset = 236;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_error_shared_without_fpu_regs_stub_offset = 144;
+    AOT_Thread_null_error_shared_without_fpu_regs_stub_offset = 152;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 236;
+    AOT_Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 244;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 152;
+    AOT_Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 160;
 static constexpr dart::compiler::target::word AOT_Thread_object_null_offset =
-    104;
+    112;
 static constexpr dart::compiler::target::word
-    AOT_Thread_predefined_symbols_address_offset = 296;
-static constexpr dart::compiler::target::word AOT_Thread_resume_pc_offset = 676;
+    AOT_Thread_predefined_symbols_address_offset = 304;
+static constexpr dart::compiler::target::word AOT_Thread_resume_pc_offset = 684;
 static constexpr dart::compiler::target::word
-    AOT_Thread_saved_shadow_call_stack_offset = 680;
+    AOT_Thread_saved_shadow_call_stack_offset = 688;
 static constexpr dart::compiler::target::word
-    AOT_Thread_safepoint_state_offset = 688;
+    AOT_Thread_safepoint_state_offset = 696;
 static constexpr dart::compiler::target::word
-    AOT_Thread_slow_type_test_stub_offset = 196;
+    AOT_Thread_slow_type_test_stub_offset = 204;
 static constexpr dart::compiler::target::word AOT_Thread_stack_limit_offset =
     36;
 static constexpr dart::compiler::target::word
-    AOT_Thread_saved_stack_limit_offset = 40;
+    AOT_Thread_saved_stack_limit_offset = 60;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_flags_offset = 44;
+    AOT_Thread_stack_overflow_flags_offset = 64;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 256;
+    AOT_Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 264;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 172;
+    AOT_Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 180;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 252;
+    AOT_Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 260;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 168;
+    AOT_Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 176;
 static constexpr dart::compiler::target::word
-    AOT_Thread_store_buffer_block_offset = 76;
+    AOT_Thread_store_buffer_block_offset = 80;
 static constexpr dart::compiler::target::word
-    AOT_Thread_top_exit_frame_info_offset = 72;
-static constexpr dart::compiler::target::word AOT_Thread_top_offset = 64;
+    AOT_Thread_top_exit_frame_info_offset = 76;
+static constexpr dart::compiler::target::word AOT_Thread_top_offset = 52;
 static constexpr dart::compiler::target::word AOT_Thread_top_resource_offset =
     24;
 static constexpr dart::compiler::target::word
-    AOT_Thread_unboxed_int64_runtime_arg_offset = 96;
-static constexpr dart::compiler::target::word AOT_Thread_vm_tag_offset = 88;
+    AOT_Thread_unboxed_int64_runtime_arg_offset = 104;
+static constexpr dart::compiler::target::word AOT_Thread_vm_tag_offset = 92;
 static constexpr dart::compiler::target::word
-    AOT_Thread_write_barrier_code_offset = 116;
+    AOT_Thread_write_barrier_code_offset = 124;
 static constexpr dart::compiler::target::word
-    AOT_Thread_write_barrier_entry_point_offset = 216;
+    AOT_Thread_write_barrier_entry_point_offset = 224;
 static constexpr dart::compiler::target::word
-    AOT_Thread_write_barrier_mask_offset = 48;
+    AOT_Thread_write_barrier_mask_offset = 40;
 static constexpr dart::compiler::target::word AOT_Thread_callback_code_offset =
-    692;
+    700;
 static constexpr dart::compiler::target::word
     AOT_TimelineStream_enabled_offset = 8;
 static constexpr dart::compiler::target::word AOT_TwoByteString_data_offset =
@@ -4017,8 +4035,8 @@
     4, 12, 8, 16};
 static constexpr dart::compiler::target::word
     AOT_Thread_write_barrier_wrappers_thread_offset[] = {
-        628, 632, 636, 640, 644, -1, 648, 652,
-        656, 660, -1,  -1,  -1,  -1, -1,  -1};
+        636, 640, 644, 648, 652, -1, 656, 660,
+        664, 668, -1,  -1,  -1,  -1, -1,  -1};
 static constexpr dart::compiler::target::word AOT_ApiError_InstanceSize = 8;
 static constexpr dart::compiler::target::word AOT_Array_InstanceSize = 12;
 static constexpr dart::compiler::target::word AOT_Array_header_size = 12;
@@ -4318,160 +4336,162 @@
 static constexpr dart::compiler::target::word
     AOT_SubtypeTestCache_cache_offset = 8;
 static constexpr dart::compiler::target::word
-    AOT_Thread_AllocateArray_entry_point_offset = 648;
+    AOT_Thread_AllocateArray_entry_point_offset = 656;
 static constexpr dart::compiler::target::word
-    AOT_Thread_active_exception_offset = 1336;
+    AOT_Thread_active_exception_offset = 1344;
 static constexpr dart::compiler::target::word
-    AOT_Thread_active_stacktrace_offset = 1344;
+    AOT_Thread_active_stacktrace_offset = 1352;
 static constexpr dart::compiler::target::word
-    AOT_Thread_array_write_barrier_code_offset = 232;
+    AOT_Thread_array_write_barrier_code_offset = 240;
 static constexpr dart::compiler::target::word
-    AOT_Thread_array_write_barrier_entry_point_offset = 432;
+    AOT_Thread_array_write_barrier_entry_point_offset = 440;
 static constexpr dart::compiler::target::word
-    AOT_Thread_allocate_mint_with_fpu_regs_entry_point_offset = 480;
+    AOT_Thread_allocate_mint_with_fpu_regs_entry_point_offset = 488;
 static constexpr dart::compiler::target::word
-    AOT_Thread_allocate_mint_with_fpu_regs_stub_offset = 312;
+    AOT_Thread_allocate_mint_with_fpu_regs_stub_offset = 320;
 static constexpr dart::compiler::target::word
-    AOT_Thread_allocate_mint_without_fpu_regs_entry_point_offset = 488;
+    AOT_Thread_allocate_mint_without_fpu_regs_entry_point_offset = 496;
 static constexpr dart::compiler::target::word
-    AOT_Thread_allocate_mint_without_fpu_regs_stub_offset = 320;
+    AOT_Thread_allocate_mint_without_fpu_regs_stub_offset = 328;
 static constexpr dart::compiler::target::word
-    AOT_Thread_async_stack_trace_offset = 184;
+    AOT_Thread_async_stack_trace_offset = 192;
 static constexpr dart::compiler::target::word
-    AOT_Thread_auto_scope_native_wrapper_entry_point_offset = 568;
+    AOT_Thread_auto_scope_native_wrapper_entry_point_offset = 576;
 static constexpr dart::compiler::target::word AOT_Thread_bool_false_offset =
-    216;
-static constexpr dart::compiler::target::word AOT_Thread_bool_true_offset = 208;
+    224;
+static constexpr dart::compiler::target::word AOT_Thread_bool_true_offset = 216;
 static constexpr dart::compiler::target::word
-    AOT_Thread_bootstrap_native_wrapper_entry_point_offset = 552;
+    AOT_Thread_bootstrap_native_wrapper_entry_point_offset = 560;
 static constexpr dart::compiler::target::word
-    AOT_Thread_call_to_runtime_entry_point_offset = 440;
+    AOT_Thread_call_to_runtime_entry_point_offset = 448;
 static constexpr dart::compiler::target::word
-    AOT_Thread_call_to_runtime_stub_offset = 272;
+    AOT_Thread_call_to_runtime_stub_offset = 280;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
-    1408;
+    1416;
+static constexpr dart::compiler::target::word
+    AOT_Thread_dispatch_table_array_offset = 96;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
-    528;
+    536;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
-    352;
+    360;
 static constexpr dart::compiler::target::word
-    AOT_Thread_deoptimize_entry_offset = 536;
+    AOT_Thread_deoptimize_entry_offset = 544;
 static constexpr dart::compiler::target::word
-    AOT_Thread_deoptimize_stub_offset = 360;
+    AOT_Thread_deoptimize_stub_offset = 368;
 static constexpr dart::compiler::target::word
-    AOT_Thread_double_abs_address_offset = 608;
+    AOT_Thread_double_abs_address_offset = 616;
 static constexpr dart::compiler::target::word
-    AOT_Thread_double_negate_address_offset = 600;
-static constexpr dart::compiler::target::word AOT_Thread_end_offset = 136;
+    AOT_Thread_double_negate_address_offset = 608;
+static constexpr dart::compiler::target::word AOT_Thread_end_offset = 112;
 static constexpr dart::compiler::target::word
-    AOT_Thread_enter_safepoint_stub_offset = 400;
+    AOT_Thread_enter_safepoint_stub_offset = 408;
 static constexpr dart::compiler::target::word
-    AOT_Thread_execution_state_offset = 1376;
+    AOT_Thread_execution_state_offset = 1384;
 static constexpr dart::compiler::target::word
-    AOT_Thread_exit_safepoint_stub_offset = 408;
+    AOT_Thread_exit_safepoint_stub_offset = 416;
 static constexpr dart::compiler::target::word
-    AOT_Thread_call_native_through_safepoint_stub_offset = 416;
+    AOT_Thread_call_native_through_safepoint_stub_offset = 424;
 static constexpr dart::compiler::target::word
-    AOT_Thread_call_native_through_safepoint_entry_point_offset = 544;
+    AOT_Thread_call_native_through_safepoint_entry_point_offset = 552;
 static constexpr dart::compiler::target::word
-    AOT_Thread_fix_allocation_stub_code_offset = 248;
+    AOT_Thread_fix_allocation_stub_code_offset = 256;
 static constexpr dart::compiler::target::word
-    AOT_Thread_fix_callers_target_code_offset = 240;
+    AOT_Thread_fix_callers_target_code_offset = 248;
 static constexpr dart::compiler::target::word
-    AOT_Thread_float_absolute_address_offset = 632;
+    AOT_Thread_float_absolute_address_offset = 640;
 static constexpr dart::compiler::target::word
-    AOT_Thread_float_negate_address_offset = 624;
+    AOT_Thread_float_negate_address_offset = 632;
 static constexpr dart::compiler::target::word
-    AOT_Thread_float_not_address_offset = 616;
+    AOT_Thread_float_not_address_offset = 624;
 static constexpr dart::compiler::target::word
-    AOT_Thread_float_zerow_address_offset = 640;
+    AOT_Thread_float_zerow_address_offset = 648;
 static constexpr dart::compiler::target::word
-    AOT_Thread_global_object_pool_offset = 1352;
+    AOT_Thread_global_object_pool_offset = 1360;
 static constexpr dart::compiler::target::word
-    AOT_Thread_interpret_call_entry_point_offset = 576;
+    AOT_Thread_interpret_call_entry_point_offset = 584;
 static constexpr dart::compiler::target::word
-    AOT_Thread_invoke_dart_code_from_bytecode_stub_offset = 264;
+    AOT_Thread_invoke_dart_code_from_bytecode_stub_offset = 272;
 static constexpr dart::compiler::target::word
-    AOT_Thread_invoke_dart_code_stub_offset = 256;
-static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 104;
+    AOT_Thread_invoke_dart_code_stub_offset = 264;
+static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 88;
 static constexpr dart::compiler::target::word
-    AOT_Thread_field_table_values_offset = 112;
+    AOT_Thread_field_table_values_offset = 136;
 static constexpr dart::compiler::target::word
-    AOT_Thread_lazy_deopt_from_return_stub_offset = 368;
+    AOT_Thread_lazy_deopt_from_return_stub_offset = 376;
 static constexpr dart::compiler::target::word
-    AOT_Thread_lazy_deopt_from_throw_stub_offset = 376;
+    AOT_Thread_lazy_deopt_from_throw_stub_offset = 384;
 static constexpr dart::compiler::target::word
-    AOT_Thread_lazy_specialize_type_test_stub_offset = 392;
+    AOT_Thread_lazy_specialize_type_test_stub_offset = 400;
 static constexpr dart::compiler::target::word
-    AOT_Thread_marking_stack_block_offset = 160;
+    AOT_Thread_marking_stack_block_offset = 168;
 static constexpr dart::compiler::target::word
-    AOT_Thread_megamorphic_call_checked_entry_offset = 512;
+    AOT_Thread_megamorphic_call_checked_entry_offset = 520;
 static constexpr dart::compiler::target::word
-    AOT_Thread_monomorphic_miss_entry_offset = 520;
+    AOT_Thread_monomorphic_miss_entry_offset = 528;
 static constexpr dart::compiler::target::word
-    AOT_Thread_monomorphic_miss_stub_offset = 344;
+    AOT_Thread_monomorphic_miss_stub_offset = 352;
 static constexpr dart::compiler::target::word
-    AOT_Thread_no_scope_native_wrapper_entry_point_offset = 560;
+    AOT_Thread_no_scope_native_wrapper_entry_point_offset = 568;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_error_shared_with_fpu_regs_entry_point_offset = 456;
+    AOT_Thread_null_error_shared_with_fpu_regs_entry_point_offset = 464;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_error_shared_with_fpu_regs_stub_offset = 288;
+    AOT_Thread_null_error_shared_with_fpu_regs_stub_offset = 296;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 472;
+    AOT_Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 480;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 304;
+    AOT_Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 312;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_error_shared_without_fpu_regs_entry_point_offset = 448;
+    AOT_Thread_null_error_shared_without_fpu_regs_entry_point_offset = 456;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_error_shared_without_fpu_regs_stub_offset = 280;
+    AOT_Thread_null_error_shared_without_fpu_regs_stub_offset = 288;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 464;
+    AOT_Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 472;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 296;
+    AOT_Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 304;
 static constexpr dart::compiler::target::word AOT_Thread_object_null_offset =
-    200;
+    208;
 static constexpr dart::compiler::target::word
-    AOT_Thread_predefined_symbols_address_offset = 584;
+    AOT_Thread_predefined_symbols_address_offset = 592;
 static constexpr dart::compiler::target::word AOT_Thread_resume_pc_offset =
-    1360;
+    1368;
 static constexpr dart::compiler::target::word
-    AOT_Thread_saved_shadow_call_stack_offset = 1368;
+    AOT_Thread_saved_shadow_call_stack_offset = 1376;
 static constexpr dart::compiler::target::word
-    AOT_Thread_safepoint_state_offset = 1384;
+    AOT_Thread_safepoint_state_offset = 1392;
 static constexpr dart::compiler::target::word
-    AOT_Thread_slow_type_test_stub_offset = 384;
+    AOT_Thread_slow_type_test_stub_offset = 392;
 static constexpr dart::compiler::target::word AOT_Thread_stack_limit_offset =
     72;
 static constexpr dart::compiler::target::word
-    AOT_Thread_saved_stack_limit_offset = 80;
+    AOT_Thread_saved_stack_limit_offset = 120;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_flags_offset = 88;
+    AOT_Thread_stack_overflow_flags_offset = 128;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 504;
+    AOT_Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 512;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 336;
+    AOT_Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 344;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 496;
+    AOT_Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 504;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 328;
+    AOT_Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 336;
 static constexpr dart::compiler::target::word
-    AOT_Thread_store_buffer_block_offset = 152;
+    AOT_Thread_store_buffer_block_offset = 160;
 static constexpr dart::compiler::target::word
-    AOT_Thread_top_exit_frame_info_offset = 144;
-static constexpr dart::compiler::target::word AOT_Thread_top_offset = 128;
+    AOT_Thread_top_exit_frame_info_offset = 152;
+static constexpr dart::compiler::target::word AOT_Thread_top_offset = 104;
 static constexpr dart::compiler::target::word AOT_Thread_top_resource_offset =
     48;
 static constexpr dart::compiler::target::word
-    AOT_Thread_unboxed_int64_runtime_arg_offset = 192;
-static constexpr dart::compiler::target::word AOT_Thread_vm_tag_offset = 176;
+    AOT_Thread_unboxed_int64_runtime_arg_offset = 200;
+static constexpr dart::compiler::target::word AOT_Thread_vm_tag_offset = 184;
 static constexpr dart::compiler::target::word
-    AOT_Thread_write_barrier_code_offset = 224;
+    AOT_Thread_write_barrier_code_offset = 232;
 static constexpr dart::compiler::target::word
-    AOT_Thread_write_barrier_entry_point_offset = 424;
+    AOT_Thread_write_barrier_entry_point_offset = 432;
 static constexpr dart::compiler::target::word
-    AOT_Thread_write_barrier_mask_offset = 96;
+    AOT_Thread_write_barrier_mask_offset = 80;
 static constexpr dart::compiler::target::word AOT_Thread_callback_code_offset =
-    1392;
+    1400;
 static constexpr dart::compiler::target::word
     AOT_TimelineStream_enabled_offset = 16;
 static constexpr dart::compiler::target::word AOT_TwoByteString_data_offset =
@@ -4516,8 +4536,8 @@
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
     AOT_Thread_write_barrier_wrappers_thread_offset[] = {
-        1248, 1256, 1264, 1272, -1,   -1,   1280, 1288,
-        1296, 1304, 1312, -1,   1320, 1328, -1,   -1};
+        1256, 1264, 1272, 1280, -1,   -1,   1288, 1296,
+        1304, 1312, 1320, -1,   1328, 1336, -1,   -1};
 static constexpr dart::compiler::target::word AOT_ApiError_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Array_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Array_header_size = 24;
@@ -4821,120 +4841,122 @@
 static constexpr dart::compiler::target::word
     AOT_SubtypeTestCache_cache_offset = 8;
 static constexpr dart::compiler::target::word
-    AOT_Thread_AllocateArray_entry_point_offset = 648;
+    AOT_Thread_AllocateArray_entry_point_offset = 656;
 static constexpr dart::compiler::target::word
     AOT_Thread_active_exception_offset = 1416;
 static constexpr dart::compiler::target::word
     AOT_Thread_active_stacktrace_offset = 1424;
 static constexpr dart::compiler::target::word
-    AOT_Thread_array_write_barrier_code_offset = 232;
+    AOT_Thread_array_write_barrier_code_offset = 240;
 static constexpr dart::compiler::target::word
-    AOT_Thread_array_write_barrier_entry_point_offset = 432;
+    AOT_Thread_array_write_barrier_entry_point_offset = 440;
 static constexpr dart::compiler::target::word
-    AOT_Thread_allocate_mint_with_fpu_regs_entry_point_offset = 480;
+    AOT_Thread_allocate_mint_with_fpu_regs_entry_point_offset = 488;
 static constexpr dart::compiler::target::word
-    AOT_Thread_allocate_mint_with_fpu_regs_stub_offset = 312;
+    AOT_Thread_allocate_mint_with_fpu_regs_stub_offset = 320;
 static constexpr dart::compiler::target::word
-    AOT_Thread_allocate_mint_without_fpu_regs_entry_point_offset = 488;
+    AOT_Thread_allocate_mint_without_fpu_regs_entry_point_offset = 496;
 static constexpr dart::compiler::target::word
-    AOT_Thread_allocate_mint_without_fpu_regs_stub_offset = 320;
+    AOT_Thread_allocate_mint_without_fpu_regs_stub_offset = 328;
 static constexpr dart::compiler::target::word
-    AOT_Thread_async_stack_trace_offset = 184;
+    AOT_Thread_async_stack_trace_offset = 192;
 static constexpr dart::compiler::target::word
-    AOT_Thread_auto_scope_native_wrapper_entry_point_offset = 568;
+    AOT_Thread_auto_scope_native_wrapper_entry_point_offset = 576;
 static constexpr dart::compiler::target::word AOT_Thread_bool_false_offset =
-    216;
-static constexpr dart::compiler::target::word AOT_Thread_bool_true_offset = 208;
+    224;
+static constexpr dart::compiler::target::word AOT_Thread_bool_true_offset = 216;
 static constexpr dart::compiler::target::word
-    AOT_Thread_bootstrap_native_wrapper_entry_point_offset = 552;
+    AOT_Thread_bootstrap_native_wrapper_entry_point_offset = 560;
 static constexpr dart::compiler::target::word
-    AOT_Thread_call_to_runtime_entry_point_offset = 440;
+    AOT_Thread_call_to_runtime_entry_point_offset = 448;
 static constexpr dart::compiler::target::word
-    AOT_Thread_call_to_runtime_stub_offset = 272;
+    AOT_Thread_call_to_runtime_stub_offset = 280;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
     1488;
+static constexpr dart::compiler::target::word
+    AOT_Thread_dispatch_table_array_offset = 96;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
-    528;
+    536;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
-    352;
+    360;
 static constexpr dart::compiler::target::word
-    AOT_Thread_deoptimize_entry_offset = 536;
+    AOT_Thread_deoptimize_entry_offset = 544;
 static constexpr dart::compiler::target::word
-    AOT_Thread_deoptimize_stub_offset = 360;
+    AOT_Thread_deoptimize_stub_offset = 368;
 static constexpr dart::compiler::target::word
-    AOT_Thread_double_abs_address_offset = 608;
+    AOT_Thread_double_abs_address_offset = 616;
 static constexpr dart::compiler::target::word
-    AOT_Thread_double_negate_address_offset = 600;
-static constexpr dart::compiler::target::word AOT_Thread_end_offset = 136;
+    AOT_Thread_double_negate_address_offset = 608;
+static constexpr dart::compiler::target::word AOT_Thread_end_offset = 112;
 static constexpr dart::compiler::target::word
-    AOT_Thread_enter_safepoint_stub_offset = 400;
+    AOT_Thread_enter_safepoint_stub_offset = 408;
 static constexpr dart::compiler::target::word
     AOT_Thread_execution_state_offset = 1456;
 static constexpr dart::compiler::target::word
-    AOT_Thread_exit_safepoint_stub_offset = 408;
+    AOT_Thread_exit_safepoint_stub_offset = 416;
 static constexpr dart::compiler::target::word
-    AOT_Thread_call_native_through_safepoint_stub_offset = 416;
+    AOT_Thread_call_native_through_safepoint_stub_offset = 424;
 static constexpr dart::compiler::target::word
-    AOT_Thread_call_native_through_safepoint_entry_point_offset = 544;
+    AOT_Thread_call_native_through_safepoint_entry_point_offset = 552;
 static constexpr dart::compiler::target::word
-    AOT_Thread_fix_allocation_stub_code_offset = 248;
+    AOT_Thread_fix_allocation_stub_code_offset = 256;
 static constexpr dart::compiler::target::word
-    AOT_Thread_fix_callers_target_code_offset = 240;
+    AOT_Thread_fix_callers_target_code_offset = 248;
 static constexpr dart::compiler::target::word
-    AOT_Thread_float_absolute_address_offset = 632;
+    AOT_Thread_float_absolute_address_offset = 640;
 static constexpr dart::compiler::target::word
-    AOT_Thread_float_negate_address_offset = 624;
+    AOT_Thread_float_negate_address_offset = 632;
 static constexpr dart::compiler::target::word
-    AOT_Thread_float_not_address_offset = 616;
+    AOT_Thread_float_not_address_offset = 624;
 static constexpr dart::compiler::target::word
-    AOT_Thread_float_zerow_address_offset = 640;
+    AOT_Thread_float_zerow_address_offset = 648;
 static constexpr dart::compiler::target::word
     AOT_Thread_global_object_pool_offset = 1432;
 static constexpr dart::compiler::target::word
-    AOT_Thread_interpret_call_entry_point_offset = 576;
+    AOT_Thread_interpret_call_entry_point_offset = 584;
 static constexpr dart::compiler::target::word
-    AOT_Thread_invoke_dart_code_from_bytecode_stub_offset = 264;
+    AOT_Thread_invoke_dart_code_from_bytecode_stub_offset = 272;
 static constexpr dart::compiler::target::word
-    AOT_Thread_invoke_dart_code_stub_offset = 256;
-static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 104;
+    AOT_Thread_invoke_dart_code_stub_offset = 264;
+static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 88;
 static constexpr dart::compiler::target::word
-    AOT_Thread_field_table_values_offset = 112;
+    AOT_Thread_field_table_values_offset = 136;
 static constexpr dart::compiler::target::word
-    AOT_Thread_lazy_deopt_from_return_stub_offset = 368;
+    AOT_Thread_lazy_deopt_from_return_stub_offset = 376;
 static constexpr dart::compiler::target::word
-    AOT_Thread_lazy_deopt_from_throw_stub_offset = 376;
+    AOT_Thread_lazy_deopt_from_throw_stub_offset = 384;
 static constexpr dart::compiler::target::word
-    AOT_Thread_lazy_specialize_type_test_stub_offset = 392;
+    AOT_Thread_lazy_specialize_type_test_stub_offset = 400;
 static constexpr dart::compiler::target::word
-    AOT_Thread_marking_stack_block_offset = 160;
+    AOT_Thread_marking_stack_block_offset = 168;
 static constexpr dart::compiler::target::word
-    AOT_Thread_megamorphic_call_checked_entry_offset = 512;
+    AOT_Thread_megamorphic_call_checked_entry_offset = 520;
 static constexpr dart::compiler::target::word
-    AOT_Thread_monomorphic_miss_entry_offset = 520;
+    AOT_Thread_monomorphic_miss_entry_offset = 528;
 static constexpr dart::compiler::target::word
-    AOT_Thread_monomorphic_miss_stub_offset = 344;
+    AOT_Thread_monomorphic_miss_stub_offset = 352;
 static constexpr dart::compiler::target::word
-    AOT_Thread_no_scope_native_wrapper_entry_point_offset = 560;
+    AOT_Thread_no_scope_native_wrapper_entry_point_offset = 568;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_error_shared_with_fpu_regs_entry_point_offset = 456;
+    AOT_Thread_null_error_shared_with_fpu_regs_entry_point_offset = 464;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_error_shared_with_fpu_regs_stub_offset = 288;
+    AOT_Thread_null_error_shared_with_fpu_regs_stub_offset = 296;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 472;
+    AOT_Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 480;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 304;
+    AOT_Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 312;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_error_shared_without_fpu_regs_entry_point_offset = 448;
+    AOT_Thread_null_error_shared_without_fpu_regs_entry_point_offset = 456;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_error_shared_without_fpu_regs_stub_offset = 280;
+    AOT_Thread_null_error_shared_without_fpu_regs_stub_offset = 288;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 464;
+    AOT_Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 472;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 296;
+    AOT_Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 304;
 static constexpr dart::compiler::target::word AOT_Thread_object_null_offset =
-    200;
+    208;
 static constexpr dart::compiler::target::word
-    AOT_Thread_predefined_symbols_address_offset = 584;
+    AOT_Thread_predefined_symbols_address_offset = 592;
 static constexpr dart::compiler::target::word AOT_Thread_resume_pc_offset =
     1440;
 static constexpr dart::compiler::target::word
@@ -4942,37 +4964,37 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_safepoint_state_offset = 1464;
 static constexpr dart::compiler::target::word
-    AOT_Thread_slow_type_test_stub_offset = 384;
+    AOT_Thread_slow_type_test_stub_offset = 392;
 static constexpr dart::compiler::target::word AOT_Thread_stack_limit_offset =
     72;
 static constexpr dart::compiler::target::word
-    AOT_Thread_saved_stack_limit_offset = 80;
+    AOT_Thread_saved_stack_limit_offset = 120;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_flags_offset = 88;
+    AOT_Thread_stack_overflow_flags_offset = 128;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 504;
+    AOT_Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 512;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 336;
+    AOT_Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 344;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 496;
+    AOT_Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 504;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 328;
+    AOT_Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 336;
 static constexpr dart::compiler::target::word
-    AOT_Thread_store_buffer_block_offset = 152;
+    AOT_Thread_store_buffer_block_offset = 160;
 static constexpr dart::compiler::target::word
-    AOT_Thread_top_exit_frame_info_offset = 144;
-static constexpr dart::compiler::target::word AOT_Thread_top_offset = 128;
+    AOT_Thread_top_exit_frame_info_offset = 152;
+static constexpr dart::compiler::target::word AOT_Thread_top_offset = 104;
 static constexpr dart::compiler::target::word AOT_Thread_top_resource_offset =
     48;
 static constexpr dart::compiler::target::word
-    AOT_Thread_unboxed_int64_runtime_arg_offset = 192;
-static constexpr dart::compiler::target::word AOT_Thread_vm_tag_offset = 176;
+    AOT_Thread_unboxed_int64_runtime_arg_offset = 200;
+static constexpr dart::compiler::target::word AOT_Thread_vm_tag_offset = 184;
 static constexpr dart::compiler::target::word
-    AOT_Thread_write_barrier_code_offset = 224;
+    AOT_Thread_write_barrier_code_offset = 232;
 static constexpr dart::compiler::target::word
-    AOT_Thread_write_barrier_entry_point_offset = 424;
+    AOT_Thread_write_barrier_entry_point_offset = 432;
 static constexpr dart::compiler::target::word
-    AOT_Thread_write_barrier_mask_offset = 96;
+    AOT_Thread_write_barrier_mask_offset = 80;
 static constexpr dart::compiler::target::word AOT_Thread_callback_code_offset =
     1472;
 static constexpr dart::compiler::target::word
@@ -5019,8 +5041,8 @@
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
     AOT_Thread_write_barrier_wrappers_thread_offset[] = {
-        1248, 1256, 1264, 1272, 1280, 1288, 1296, 1304, 1312, 1320, 1328,
-        1336, 1344, 1352, 1360, -1,   -1,   -1,   -1,   1368, 1376, 1384,
+        1256, 1264, 1272, 1280, 1288, 1296, 1304, 1312, 1320, 1328, 1336,
+        1344, 1352, 1360, 1368, -1,   -1,   -1,   -1,   1376, 1384, -1,
         -1,   1392, 1400, 1408, -1,   -1,   -1,   -1,   -1,   -1};
 static constexpr dart::compiler::target::word AOT_ApiError_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Array_InstanceSize = 24;
@@ -5320,159 +5342,161 @@
 static constexpr dart::compiler::target::word
     AOT_SubtypeTestCache_cache_offset = 4;
 static constexpr dart::compiler::target::word
-    AOT_Thread_AllocateArray_entry_point_offset = 328;
+    AOT_Thread_AllocateArray_entry_point_offset = 336;
 static constexpr dart::compiler::target::word
-    AOT_Thread_active_exception_offset = 664;
+    AOT_Thread_active_exception_offset = 672;
 static constexpr dart::compiler::target::word
-    AOT_Thread_active_stacktrace_offset = 668;
+    AOT_Thread_active_stacktrace_offset = 676;
 static constexpr dart::compiler::target::word
-    AOT_Thread_array_write_barrier_code_offset = 120;
+    AOT_Thread_array_write_barrier_code_offset = 128;
 static constexpr dart::compiler::target::word
-    AOT_Thread_array_write_barrier_entry_point_offset = 220;
+    AOT_Thread_array_write_barrier_entry_point_offset = 228;
 static constexpr dart::compiler::target::word
-    AOT_Thread_allocate_mint_with_fpu_regs_entry_point_offset = 244;
+    AOT_Thread_allocate_mint_with_fpu_regs_entry_point_offset = 252;
 static constexpr dart::compiler::target::word
-    AOT_Thread_allocate_mint_with_fpu_regs_stub_offset = 160;
+    AOT_Thread_allocate_mint_with_fpu_regs_stub_offset = 168;
 static constexpr dart::compiler::target::word
-    AOT_Thread_allocate_mint_without_fpu_regs_entry_point_offset = 248;
+    AOT_Thread_allocate_mint_without_fpu_regs_entry_point_offset = 256;
 static constexpr dart::compiler::target::word
-    AOT_Thread_allocate_mint_without_fpu_regs_stub_offset = 164;
+    AOT_Thread_allocate_mint_without_fpu_regs_stub_offset = 172;
 static constexpr dart::compiler::target::word
-    AOT_Thread_async_stack_trace_offset = 92;
+    AOT_Thread_async_stack_trace_offset = 96;
 static constexpr dart::compiler::target::word
-    AOT_Thread_auto_scope_native_wrapper_entry_point_offset = 288;
+    AOT_Thread_auto_scope_native_wrapper_entry_point_offset = 296;
 static constexpr dart::compiler::target::word AOT_Thread_bool_false_offset =
-    112;
-static constexpr dart::compiler::target::word AOT_Thread_bool_true_offset = 108;
+    120;
+static constexpr dart::compiler::target::word AOT_Thread_bool_true_offset = 116;
 static constexpr dart::compiler::target::word
-    AOT_Thread_bootstrap_native_wrapper_entry_point_offset = 280;
+    AOT_Thread_bootstrap_native_wrapper_entry_point_offset = 288;
 static constexpr dart::compiler::target::word
-    AOT_Thread_call_to_runtime_entry_point_offset = 224;
+    AOT_Thread_call_to_runtime_entry_point_offset = 232;
 static constexpr dart::compiler::target::word
-    AOT_Thread_call_to_runtime_stub_offset = 140;
+    AOT_Thread_call_to_runtime_stub_offset = 148;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
-    700;
+    708;
+static constexpr dart::compiler::target::word
+    AOT_Thread_dispatch_table_array_offset = 48;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
-    268;
+    276;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
-    180;
+    188;
 static constexpr dart::compiler::target::word
-    AOT_Thread_deoptimize_entry_offset = 272;
+    AOT_Thread_deoptimize_entry_offset = 280;
 static constexpr dart::compiler::target::word
-    AOT_Thread_deoptimize_stub_offset = 184;
+    AOT_Thread_deoptimize_stub_offset = 192;
 static constexpr dart::compiler::target::word
-    AOT_Thread_double_abs_address_offset = 308;
+    AOT_Thread_double_abs_address_offset = 316;
 static constexpr dart::compiler::target::word
-    AOT_Thread_double_negate_address_offset = 304;
-static constexpr dart::compiler::target::word AOT_Thread_end_offset = 68;
+    AOT_Thread_double_negate_address_offset = 312;
+static constexpr dart::compiler::target::word AOT_Thread_end_offset = 56;
 static constexpr dart::compiler::target::word
-    AOT_Thread_enter_safepoint_stub_offset = 204;
+    AOT_Thread_enter_safepoint_stub_offset = 212;
 static constexpr dart::compiler::target::word
-    AOT_Thread_execution_state_offset = 684;
+    AOT_Thread_execution_state_offset = 692;
 static constexpr dart::compiler::target::word
-    AOT_Thread_exit_safepoint_stub_offset = 208;
+    AOT_Thread_exit_safepoint_stub_offset = 216;
 static constexpr dart::compiler::target::word
-    AOT_Thread_call_native_through_safepoint_stub_offset = 212;
+    AOT_Thread_call_native_through_safepoint_stub_offset = 220;
 static constexpr dart::compiler::target::word
-    AOT_Thread_call_native_through_safepoint_entry_point_offset = 276;
+    AOT_Thread_call_native_through_safepoint_entry_point_offset = 284;
 static constexpr dart::compiler::target::word
-    AOT_Thread_fix_allocation_stub_code_offset = 128;
+    AOT_Thread_fix_allocation_stub_code_offset = 136;
 static constexpr dart::compiler::target::word
-    AOT_Thread_fix_callers_target_code_offset = 124;
+    AOT_Thread_fix_callers_target_code_offset = 132;
 static constexpr dart::compiler::target::word
-    AOT_Thread_float_absolute_address_offset = 320;
+    AOT_Thread_float_absolute_address_offset = 328;
 static constexpr dart::compiler::target::word
-    AOT_Thread_float_negate_address_offset = 316;
+    AOT_Thread_float_negate_address_offset = 324;
 static constexpr dart::compiler::target::word
-    AOT_Thread_float_not_address_offset = 312;
+    AOT_Thread_float_not_address_offset = 320;
 static constexpr dart::compiler::target::word
-    AOT_Thread_float_zerow_address_offset = 324;
+    AOT_Thread_float_zerow_address_offset = 332;
 static constexpr dart::compiler::target::word
-    AOT_Thread_global_object_pool_offset = 672;
+    AOT_Thread_global_object_pool_offset = 680;
 static constexpr dart::compiler::target::word
-    AOT_Thread_interpret_call_entry_point_offset = 292;
+    AOT_Thread_interpret_call_entry_point_offset = 300;
 static constexpr dart::compiler::target::word
-    AOT_Thread_invoke_dart_code_from_bytecode_stub_offset = 136;
+    AOT_Thread_invoke_dart_code_from_bytecode_stub_offset = 144;
 static constexpr dart::compiler::target::word
-    AOT_Thread_invoke_dart_code_stub_offset = 132;
-static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 52;
+    AOT_Thread_invoke_dart_code_stub_offset = 140;
+static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 44;
 static constexpr dart::compiler::target::word
-    AOT_Thread_field_table_values_offset = 56;
+    AOT_Thread_field_table_values_offset = 68;
 static constexpr dart::compiler::target::word
-    AOT_Thread_lazy_deopt_from_return_stub_offset = 188;
+    AOT_Thread_lazy_deopt_from_return_stub_offset = 196;
 static constexpr dart::compiler::target::word
-    AOT_Thread_lazy_deopt_from_throw_stub_offset = 192;
+    AOT_Thread_lazy_deopt_from_throw_stub_offset = 200;
 static constexpr dart::compiler::target::word
-    AOT_Thread_lazy_specialize_type_test_stub_offset = 200;
+    AOT_Thread_lazy_specialize_type_test_stub_offset = 208;
 static constexpr dart::compiler::target::word
-    AOT_Thread_marking_stack_block_offset = 80;
+    AOT_Thread_marking_stack_block_offset = 84;
 static constexpr dart::compiler::target::word
-    AOT_Thread_megamorphic_call_checked_entry_offset = 260;
+    AOT_Thread_megamorphic_call_checked_entry_offset = 268;
 static constexpr dart::compiler::target::word
-    AOT_Thread_monomorphic_miss_entry_offset = 264;
+    AOT_Thread_monomorphic_miss_entry_offset = 272;
 static constexpr dart::compiler::target::word
-    AOT_Thread_monomorphic_miss_stub_offset = 176;
+    AOT_Thread_monomorphic_miss_stub_offset = 184;
 static constexpr dart::compiler::target::word
-    AOT_Thread_no_scope_native_wrapper_entry_point_offset = 284;
+    AOT_Thread_no_scope_native_wrapper_entry_point_offset = 292;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_error_shared_with_fpu_regs_entry_point_offset = 232;
+    AOT_Thread_null_error_shared_with_fpu_regs_entry_point_offset = 240;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_error_shared_with_fpu_regs_stub_offset = 148;
+    AOT_Thread_null_error_shared_with_fpu_regs_stub_offset = 156;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 240;
+    AOT_Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 248;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 156;
+    AOT_Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 164;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_error_shared_without_fpu_regs_entry_point_offset = 228;
+    AOT_Thread_null_error_shared_without_fpu_regs_entry_point_offset = 236;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_error_shared_without_fpu_regs_stub_offset = 144;
+    AOT_Thread_null_error_shared_without_fpu_regs_stub_offset = 152;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 236;
+    AOT_Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 244;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 152;
+    AOT_Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 160;
 static constexpr dart::compiler::target::word AOT_Thread_object_null_offset =
-    104;
+    112;
 static constexpr dart::compiler::target::word
-    AOT_Thread_predefined_symbols_address_offset = 296;
-static constexpr dart::compiler::target::word AOT_Thread_resume_pc_offset = 676;
+    AOT_Thread_predefined_symbols_address_offset = 304;
+static constexpr dart::compiler::target::word AOT_Thread_resume_pc_offset = 684;
 static constexpr dart::compiler::target::word
-    AOT_Thread_saved_shadow_call_stack_offset = 680;
+    AOT_Thread_saved_shadow_call_stack_offset = 688;
 static constexpr dart::compiler::target::word
-    AOT_Thread_safepoint_state_offset = 688;
+    AOT_Thread_safepoint_state_offset = 696;
 static constexpr dart::compiler::target::word
-    AOT_Thread_slow_type_test_stub_offset = 196;
+    AOT_Thread_slow_type_test_stub_offset = 204;
 static constexpr dart::compiler::target::word AOT_Thread_stack_limit_offset =
     36;
 static constexpr dart::compiler::target::word
-    AOT_Thread_saved_stack_limit_offset = 40;
+    AOT_Thread_saved_stack_limit_offset = 60;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_flags_offset = 44;
+    AOT_Thread_stack_overflow_flags_offset = 64;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 256;
+    AOT_Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 264;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 172;
+    AOT_Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 180;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 252;
+    AOT_Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 260;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 168;
+    AOT_Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 176;
 static constexpr dart::compiler::target::word
-    AOT_Thread_store_buffer_block_offset = 76;
+    AOT_Thread_store_buffer_block_offset = 80;
 static constexpr dart::compiler::target::word
-    AOT_Thread_top_exit_frame_info_offset = 72;
-static constexpr dart::compiler::target::word AOT_Thread_top_offset = 64;
+    AOT_Thread_top_exit_frame_info_offset = 76;
+static constexpr dart::compiler::target::word AOT_Thread_top_offset = 52;
 static constexpr dart::compiler::target::word AOT_Thread_top_resource_offset =
     24;
 static constexpr dart::compiler::target::word
-    AOT_Thread_unboxed_int64_runtime_arg_offset = 96;
-static constexpr dart::compiler::target::word AOT_Thread_vm_tag_offset = 88;
+    AOT_Thread_unboxed_int64_runtime_arg_offset = 104;
+static constexpr dart::compiler::target::word AOT_Thread_vm_tag_offset = 92;
 static constexpr dart::compiler::target::word
-    AOT_Thread_write_barrier_code_offset = 116;
+    AOT_Thread_write_barrier_code_offset = 124;
 static constexpr dart::compiler::target::word
-    AOT_Thread_write_barrier_entry_point_offset = 216;
+    AOT_Thread_write_barrier_entry_point_offset = 224;
 static constexpr dart::compiler::target::word
-    AOT_Thread_write_barrier_mask_offset = 48;
+    AOT_Thread_write_barrier_mask_offset = 40;
 static constexpr dart::compiler::target::word AOT_Thread_callback_code_offset =
-    692;
+    700;
 static constexpr dart::compiler::target::word
     AOT_TimelineStream_enabled_offset = 8;
 static constexpr dart::compiler::target::word AOT_TwoByteString_data_offset =
@@ -5514,8 +5538,8 @@
     4, 12, 8, 16};
 static constexpr dart::compiler::target::word
     AOT_Thread_write_barrier_wrappers_thread_offset[] = {
-        628, 632, 636, 640, 644, -1, 648, 652,
-        656, 660, -1,  -1,  -1,  -1, -1,  -1};
+        636, 640, 644, 648, 652, -1, 656, 660,
+        664, 668, -1,  -1,  -1,  -1, -1,  -1};
 static constexpr dart::compiler::target::word AOT_ApiError_InstanceSize = 8;
 static constexpr dart::compiler::target::word AOT_Array_InstanceSize = 12;
 static constexpr dart::compiler::target::word AOT_Array_header_size = 12;
@@ -5811,160 +5835,162 @@
 static constexpr dart::compiler::target::word
     AOT_SubtypeTestCache_cache_offset = 8;
 static constexpr dart::compiler::target::word
-    AOT_Thread_AllocateArray_entry_point_offset = 648;
+    AOT_Thread_AllocateArray_entry_point_offset = 656;
 static constexpr dart::compiler::target::word
-    AOT_Thread_active_exception_offset = 1336;
+    AOT_Thread_active_exception_offset = 1344;
 static constexpr dart::compiler::target::word
-    AOT_Thread_active_stacktrace_offset = 1344;
+    AOT_Thread_active_stacktrace_offset = 1352;
 static constexpr dart::compiler::target::word
-    AOT_Thread_array_write_barrier_code_offset = 232;
+    AOT_Thread_array_write_barrier_code_offset = 240;
 static constexpr dart::compiler::target::word
-    AOT_Thread_array_write_barrier_entry_point_offset = 432;
+    AOT_Thread_array_write_barrier_entry_point_offset = 440;
 static constexpr dart::compiler::target::word
-    AOT_Thread_allocate_mint_with_fpu_regs_entry_point_offset = 480;
+    AOT_Thread_allocate_mint_with_fpu_regs_entry_point_offset = 488;
 static constexpr dart::compiler::target::word
-    AOT_Thread_allocate_mint_with_fpu_regs_stub_offset = 312;
+    AOT_Thread_allocate_mint_with_fpu_regs_stub_offset = 320;
 static constexpr dart::compiler::target::word
-    AOT_Thread_allocate_mint_without_fpu_regs_entry_point_offset = 488;
+    AOT_Thread_allocate_mint_without_fpu_regs_entry_point_offset = 496;
 static constexpr dart::compiler::target::word
-    AOT_Thread_allocate_mint_without_fpu_regs_stub_offset = 320;
+    AOT_Thread_allocate_mint_without_fpu_regs_stub_offset = 328;
 static constexpr dart::compiler::target::word
-    AOT_Thread_async_stack_trace_offset = 184;
+    AOT_Thread_async_stack_trace_offset = 192;
 static constexpr dart::compiler::target::word
-    AOT_Thread_auto_scope_native_wrapper_entry_point_offset = 568;
+    AOT_Thread_auto_scope_native_wrapper_entry_point_offset = 576;
 static constexpr dart::compiler::target::word AOT_Thread_bool_false_offset =
-    216;
-static constexpr dart::compiler::target::word AOT_Thread_bool_true_offset = 208;
+    224;
+static constexpr dart::compiler::target::word AOT_Thread_bool_true_offset = 216;
 static constexpr dart::compiler::target::word
-    AOT_Thread_bootstrap_native_wrapper_entry_point_offset = 552;
+    AOT_Thread_bootstrap_native_wrapper_entry_point_offset = 560;
 static constexpr dart::compiler::target::word
-    AOT_Thread_call_to_runtime_entry_point_offset = 440;
+    AOT_Thread_call_to_runtime_entry_point_offset = 448;
 static constexpr dart::compiler::target::word
-    AOT_Thread_call_to_runtime_stub_offset = 272;
+    AOT_Thread_call_to_runtime_stub_offset = 280;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
-    1408;
+    1416;
+static constexpr dart::compiler::target::word
+    AOT_Thread_dispatch_table_array_offset = 96;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
-    528;
+    536;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
-    352;
+    360;
 static constexpr dart::compiler::target::word
-    AOT_Thread_deoptimize_entry_offset = 536;
+    AOT_Thread_deoptimize_entry_offset = 544;
 static constexpr dart::compiler::target::word
-    AOT_Thread_deoptimize_stub_offset = 360;
+    AOT_Thread_deoptimize_stub_offset = 368;
 static constexpr dart::compiler::target::word
-    AOT_Thread_double_abs_address_offset = 608;
+    AOT_Thread_double_abs_address_offset = 616;
 static constexpr dart::compiler::target::word
-    AOT_Thread_double_negate_address_offset = 600;
-static constexpr dart::compiler::target::word AOT_Thread_end_offset = 136;
+    AOT_Thread_double_negate_address_offset = 608;
+static constexpr dart::compiler::target::word AOT_Thread_end_offset = 112;
 static constexpr dart::compiler::target::word
-    AOT_Thread_enter_safepoint_stub_offset = 400;
+    AOT_Thread_enter_safepoint_stub_offset = 408;
 static constexpr dart::compiler::target::word
-    AOT_Thread_execution_state_offset = 1376;
+    AOT_Thread_execution_state_offset = 1384;
 static constexpr dart::compiler::target::word
-    AOT_Thread_exit_safepoint_stub_offset = 408;
+    AOT_Thread_exit_safepoint_stub_offset = 416;
 static constexpr dart::compiler::target::word
-    AOT_Thread_call_native_through_safepoint_stub_offset = 416;
+    AOT_Thread_call_native_through_safepoint_stub_offset = 424;
 static constexpr dart::compiler::target::word
-    AOT_Thread_call_native_through_safepoint_entry_point_offset = 544;
+    AOT_Thread_call_native_through_safepoint_entry_point_offset = 552;
 static constexpr dart::compiler::target::word
-    AOT_Thread_fix_allocation_stub_code_offset = 248;
+    AOT_Thread_fix_allocation_stub_code_offset = 256;
 static constexpr dart::compiler::target::word
-    AOT_Thread_fix_callers_target_code_offset = 240;
+    AOT_Thread_fix_callers_target_code_offset = 248;
 static constexpr dart::compiler::target::word
-    AOT_Thread_float_absolute_address_offset = 632;
+    AOT_Thread_float_absolute_address_offset = 640;
 static constexpr dart::compiler::target::word
-    AOT_Thread_float_negate_address_offset = 624;
+    AOT_Thread_float_negate_address_offset = 632;
 static constexpr dart::compiler::target::word
-    AOT_Thread_float_not_address_offset = 616;
+    AOT_Thread_float_not_address_offset = 624;
 static constexpr dart::compiler::target::word
-    AOT_Thread_float_zerow_address_offset = 640;
+    AOT_Thread_float_zerow_address_offset = 648;
 static constexpr dart::compiler::target::word
-    AOT_Thread_global_object_pool_offset = 1352;
+    AOT_Thread_global_object_pool_offset = 1360;
 static constexpr dart::compiler::target::word
-    AOT_Thread_interpret_call_entry_point_offset = 576;
+    AOT_Thread_interpret_call_entry_point_offset = 584;
 static constexpr dart::compiler::target::word
-    AOT_Thread_invoke_dart_code_from_bytecode_stub_offset = 264;
+    AOT_Thread_invoke_dart_code_from_bytecode_stub_offset = 272;
 static constexpr dart::compiler::target::word
-    AOT_Thread_invoke_dart_code_stub_offset = 256;
-static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 104;
+    AOT_Thread_invoke_dart_code_stub_offset = 264;
+static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 88;
 static constexpr dart::compiler::target::word
-    AOT_Thread_field_table_values_offset = 112;
+    AOT_Thread_field_table_values_offset = 136;
 static constexpr dart::compiler::target::word
-    AOT_Thread_lazy_deopt_from_return_stub_offset = 368;
+    AOT_Thread_lazy_deopt_from_return_stub_offset = 376;
 static constexpr dart::compiler::target::word
-    AOT_Thread_lazy_deopt_from_throw_stub_offset = 376;
+    AOT_Thread_lazy_deopt_from_throw_stub_offset = 384;
 static constexpr dart::compiler::target::word
-    AOT_Thread_lazy_specialize_type_test_stub_offset = 392;
+    AOT_Thread_lazy_specialize_type_test_stub_offset = 400;
 static constexpr dart::compiler::target::word
-    AOT_Thread_marking_stack_block_offset = 160;
+    AOT_Thread_marking_stack_block_offset = 168;
 static constexpr dart::compiler::target::word
-    AOT_Thread_megamorphic_call_checked_entry_offset = 512;
+    AOT_Thread_megamorphic_call_checked_entry_offset = 520;
 static constexpr dart::compiler::target::word
-    AOT_Thread_monomorphic_miss_entry_offset = 520;
+    AOT_Thread_monomorphic_miss_entry_offset = 528;
 static constexpr dart::compiler::target::word
-    AOT_Thread_monomorphic_miss_stub_offset = 344;
+    AOT_Thread_monomorphic_miss_stub_offset = 352;
 static constexpr dart::compiler::target::word
-    AOT_Thread_no_scope_native_wrapper_entry_point_offset = 560;
+    AOT_Thread_no_scope_native_wrapper_entry_point_offset = 568;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_error_shared_with_fpu_regs_entry_point_offset = 456;
+    AOT_Thread_null_error_shared_with_fpu_regs_entry_point_offset = 464;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_error_shared_with_fpu_regs_stub_offset = 288;
+    AOT_Thread_null_error_shared_with_fpu_regs_stub_offset = 296;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 472;
+    AOT_Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 480;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 304;
+    AOT_Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 312;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_error_shared_without_fpu_regs_entry_point_offset = 448;
+    AOT_Thread_null_error_shared_without_fpu_regs_entry_point_offset = 456;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_error_shared_without_fpu_regs_stub_offset = 280;
+    AOT_Thread_null_error_shared_without_fpu_regs_stub_offset = 288;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 464;
+    AOT_Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 472;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 296;
+    AOT_Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 304;
 static constexpr dart::compiler::target::word AOT_Thread_object_null_offset =
-    200;
+    208;
 static constexpr dart::compiler::target::word
-    AOT_Thread_predefined_symbols_address_offset = 584;
+    AOT_Thread_predefined_symbols_address_offset = 592;
 static constexpr dart::compiler::target::word AOT_Thread_resume_pc_offset =
-    1360;
+    1368;
 static constexpr dart::compiler::target::word
-    AOT_Thread_saved_shadow_call_stack_offset = 1368;
+    AOT_Thread_saved_shadow_call_stack_offset = 1376;
 static constexpr dart::compiler::target::word
-    AOT_Thread_safepoint_state_offset = 1384;
+    AOT_Thread_safepoint_state_offset = 1392;
 static constexpr dart::compiler::target::word
-    AOT_Thread_slow_type_test_stub_offset = 384;
+    AOT_Thread_slow_type_test_stub_offset = 392;
 static constexpr dart::compiler::target::word AOT_Thread_stack_limit_offset =
     72;
 static constexpr dart::compiler::target::word
-    AOT_Thread_saved_stack_limit_offset = 80;
+    AOT_Thread_saved_stack_limit_offset = 120;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_flags_offset = 88;
+    AOT_Thread_stack_overflow_flags_offset = 128;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 504;
+    AOT_Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 512;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 336;
+    AOT_Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 344;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 496;
+    AOT_Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 504;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 328;
+    AOT_Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 336;
 static constexpr dart::compiler::target::word
-    AOT_Thread_store_buffer_block_offset = 152;
+    AOT_Thread_store_buffer_block_offset = 160;
 static constexpr dart::compiler::target::word
-    AOT_Thread_top_exit_frame_info_offset = 144;
-static constexpr dart::compiler::target::word AOT_Thread_top_offset = 128;
+    AOT_Thread_top_exit_frame_info_offset = 152;
+static constexpr dart::compiler::target::word AOT_Thread_top_offset = 104;
 static constexpr dart::compiler::target::word AOT_Thread_top_resource_offset =
     48;
 static constexpr dart::compiler::target::word
-    AOT_Thread_unboxed_int64_runtime_arg_offset = 192;
-static constexpr dart::compiler::target::word AOT_Thread_vm_tag_offset = 176;
+    AOT_Thread_unboxed_int64_runtime_arg_offset = 200;
+static constexpr dart::compiler::target::word AOT_Thread_vm_tag_offset = 184;
 static constexpr dart::compiler::target::word
-    AOT_Thread_write_barrier_code_offset = 224;
+    AOT_Thread_write_barrier_code_offset = 232;
 static constexpr dart::compiler::target::word
-    AOT_Thread_write_barrier_entry_point_offset = 424;
+    AOT_Thread_write_barrier_entry_point_offset = 432;
 static constexpr dart::compiler::target::word
-    AOT_Thread_write_barrier_mask_offset = 96;
+    AOT_Thread_write_barrier_mask_offset = 80;
 static constexpr dart::compiler::target::word AOT_Thread_callback_code_offset =
-    1392;
+    1400;
 static constexpr dart::compiler::target::word
     AOT_TimelineStream_enabled_offset = 16;
 static constexpr dart::compiler::target::word AOT_TwoByteString_data_offset =
@@ -6006,8 +6032,8 @@
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
     AOT_Thread_write_barrier_wrappers_thread_offset[] = {
-        1248, 1256, 1264, 1272, -1,   -1,   1280, 1288,
-        1296, 1304, 1312, -1,   1320, 1328, -1,   -1};
+        1256, 1264, 1272, 1280, -1,   -1,   1288, 1296,
+        1304, 1312, 1320, -1,   1328, 1336, -1,   -1};
 static constexpr dart::compiler::target::word AOT_ApiError_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Array_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Array_header_size = 24;
@@ -6307,120 +6333,122 @@
 static constexpr dart::compiler::target::word
     AOT_SubtypeTestCache_cache_offset = 8;
 static constexpr dart::compiler::target::word
-    AOT_Thread_AllocateArray_entry_point_offset = 648;
+    AOT_Thread_AllocateArray_entry_point_offset = 656;
 static constexpr dart::compiler::target::word
     AOT_Thread_active_exception_offset = 1416;
 static constexpr dart::compiler::target::word
     AOT_Thread_active_stacktrace_offset = 1424;
 static constexpr dart::compiler::target::word
-    AOT_Thread_array_write_barrier_code_offset = 232;
+    AOT_Thread_array_write_barrier_code_offset = 240;
 static constexpr dart::compiler::target::word
-    AOT_Thread_array_write_barrier_entry_point_offset = 432;
+    AOT_Thread_array_write_barrier_entry_point_offset = 440;
 static constexpr dart::compiler::target::word
-    AOT_Thread_allocate_mint_with_fpu_regs_entry_point_offset = 480;
+    AOT_Thread_allocate_mint_with_fpu_regs_entry_point_offset = 488;
 static constexpr dart::compiler::target::word
-    AOT_Thread_allocate_mint_with_fpu_regs_stub_offset = 312;
+    AOT_Thread_allocate_mint_with_fpu_regs_stub_offset = 320;
 static constexpr dart::compiler::target::word
-    AOT_Thread_allocate_mint_without_fpu_regs_entry_point_offset = 488;
+    AOT_Thread_allocate_mint_without_fpu_regs_entry_point_offset = 496;
 static constexpr dart::compiler::target::word
-    AOT_Thread_allocate_mint_without_fpu_regs_stub_offset = 320;
+    AOT_Thread_allocate_mint_without_fpu_regs_stub_offset = 328;
 static constexpr dart::compiler::target::word
-    AOT_Thread_async_stack_trace_offset = 184;
+    AOT_Thread_async_stack_trace_offset = 192;
 static constexpr dart::compiler::target::word
-    AOT_Thread_auto_scope_native_wrapper_entry_point_offset = 568;
+    AOT_Thread_auto_scope_native_wrapper_entry_point_offset = 576;
 static constexpr dart::compiler::target::word AOT_Thread_bool_false_offset =
-    216;
-static constexpr dart::compiler::target::word AOT_Thread_bool_true_offset = 208;
+    224;
+static constexpr dart::compiler::target::word AOT_Thread_bool_true_offset = 216;
 static constexpr dart::compiler::target::word
-    AOT_Thread_bootstrap_native_wrapper_entry_point_offset = 552;
+    AOT_Thread_bootstrap_native_wrapper_entry_point_offset = 560;
 static constexpr dart::compiler::target::word
-    AOT_Thread_call_to_runtime_entry_point_offset = 440;
+    AOT_Thread_call_to_runtime_entry_point_offset = 448;
 static constexpr dart::compiler::target::word
-    AOT_Thread_call_to_runtime_stub_offset = 272;
+    AOT_Thread_call_to_runtime_stub_offset = 280;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
     1488;
+static constexpr dart::compiler::target::word
+    AOT_Thread_dispatch_table_array_offset = 96;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
-    528;
+    536;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_stub_offset =
-    352;
+    360;
 static constexpr dart::compiler::target::word
-    AOT_Thread_deoptimize_entry_offset = 536;
+    AOT_Thread_deoptimize_entry_offset = 544;
 static constexpr dart::compiler::target::word
-    AOT_Thread_deoptimize_stub_offset = 360;
+    AOT_Thread_deoptimize_stub_offset = 368;
 static constexpr dart::compiler::target::word
-    AOT_Thread_double_abs_address_offset = 608;
+    AOT_Thread_double_abs_address_offset = 616;
 static constexpr dart::compiler::target::word
-    AOT_Thread_double_negate_address_offset = 600;
-static constexpr dart::compiler::target::word AOT_Thread_end_offset = 136;
+    AOT_Thread_double_negate_address_offset = 608;
+static constexpr dart::compiler::target::word AOT_Thread_end_offset = 112;
 static constexpr dart::compiler::target::word
-    AOT_Thread_enter_safepoint_stub_offset = 400;
+    AOT_Thread_enter_safepoint_stub_offset = 408;
 static constexpr dart::compiler::target::word
     AOT_Thread_execution_state_offset = 1456;
 static constexpr dart::compiler::target::word
-    AOT_Thread_exit_safepoint_stub_offset = 408;
+    AOT_Thread_exit_safepoint_stub_offset = 416;
 static constexpr dart::compiler::target::word
-    AOT_Thread_call_native_through_safepoint_stub_offset = 416;
+    AOT_Thread_call_native_through_safepoint_stub_offset = 424;
 static constexpr dart::compiler::target::word
-    AOT_Thread_call_native_through_safepoint_entry_point_offset = 544;
+    AOT_Thread_call_native_through_safepoint_entry_point_offset = 552;
 static constexpr dart::compiler::target::word
-    AOT_Thread_fix_allocation_stub_code_offset = 248;
+    AOT_Thread_fix_allocation_stub_code_offset = 256;
 static constexpr dart::compiler::target::word
-    AOT_Thread_fix_callers_target_code_offset = 240;
+    AOT_Thread_fix_callers_target_code_offset = 248;
 static constexpr dart::compiler::target::word
-    AOT_Thread_float_absolute_address_offset = 632;
+    AOT_Thread_float_absolute_address_offset = 640;
 static constexpr dart::compiler::target::word
-    AOT_Thread_float_negate_address_offset = 624;
+    AOT_Thread_float_negate_address_offset = 632;
 static constexpr dart::compiler::target::word
-    AOT_Thread_float_not_address_offset = 616;
+    AOT_Thread_float_not_address_offset = 624;
 static constexpr dart::compiler::target::word
-    AOT_Thread_float_zerow_address_offset = 640;
+    AOT_Thread_float_zerow_address_offset = 648;
 static constexpr dart::compiler::target::word
     AOT_Thread_global_object_pool_offset = 1432;
 static constexpr dart::compiler::target::word
-    AOT_Thread_interpret_call_entry_point_offset = 576;
+    AOT_Thread_interpret_call_entry_point_offset = 584;
 static constexpr dart::compiler::target::word
-    AOT_Thread_invoke_dart_code_from_bytecode_stub_offset = 264;
+    AOT_Thread_invoke_dart_code_from_bytecode_stub_offset = 272;
 static constexpr dart::compiler::target::word
-    AOT_Thread_invoke_dart_code_stub_offset = 256;
-static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 104;
+    AOT_Thread_invoke_dart_code_stub_offset = 264;
+static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 88;
 static constexpr dart::compiler::target::word
-    AOT_Thread_field_table_values_offset = 112;
+    AOT_Thread_field_table_values_offset = 136;
 static constexpr dart::compiler::target::word
-    AOT_Thread_lazy_deopt_from_return_stub_offset = 368;
+    AOT_Thread_lazy_deopt_from_return_stub_offset = 376;
 static constexpr dart::compiler::target::word
-    AOT_Thread_lazy_deopt_from_throw_stub_offset = 376;
+    AOT_Thread_lazy_deopt_from_throw_stub_offset = 384;
 static constexpr dart::compiler::target::word
-    AOT_Thread_lazy_specialize_type_test_stub_offset = 392;
+    AOT_Thread_lazy_specialize_type_test_stub_offset = 400;
 static constexpr dart::compiler::target::word
-    AOT_Thread_marking_stack_block_offset = 160;
+    AOT_Thread_marking_stack_block_offset = 168;
 static constexpr dart::compiler::target::word
-    AOT_Thread_megamorphic_call_checked_entry_offset = 512;
+    AOT_Thread_megamorphic_call_checked_entry_offset = 520;
 static constexpr dart::compiler::target::word
-    AOT_Thread_monomorphic_miss_entry_offset = 520;
+    AOT_Thread_monomorphic_miss_entry_offset = 528;
 static constexpr dart::compiler::target::word
-    AOT_Thread_monomorphic_miss_stub_offset = 344;
+    AOT_Thread_monomorphic_miss_stub_offset = 352;
 static constexpr dart::compiler::target::word
-    AOT_Thread_no_scope_native_wrapper_entry_point_offset = 560;
+    AOT_Thread_no_scope_native_wrapper_entry_point_offset = 568;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_error_shared_with_fpu_regs_entry_point_offset = 456;
+    AOT_Thread_null_error_shared_with_fpu_regs_entry_point_offset = 464;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_error_shared_with_fpu_regs_stub_offset = 288;
+    AOT_Thread_null_error_shared_with_fpu_regs_stub_offset = 296;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 472;
+    AOT_Thread_null_arg_error_shared_with_fpu_regs_entry_point_offset = 480;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 304;
+    AOT_Thread_null_arg_error_shared_with_fpu_regs_stub_offset = 312;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_error_shared_without_fpu_regs_entry_point_offset = 448;
+    AOT_Thread_null_error_shared_without_fpu_regs_entry_point_offset = 456;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_error_shared_without_fpu_regs_stub_offset = 280;
+    AOT_Thread_null_error_shared_without_fpu_regs_stub_offset = 288;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 464;
+    AOT_Thread_null_arg_error_shared_without_fpu_regs_entry_point_offset = 472;
 static constexpr dart::compiler::target::word
-    AOT_Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 296;
+    AOT_Thread_null_arg_error_shared_without_fpu_regs_stub_offset = 304;
 static constexpr dart::compiler::target::word AOT_Thread_object_null_offset =
-    200;
+    208;
 static constexpr dart::compiler::target::word
-    AOT_Thread_predefined_symbols_address_offset = 584;
+    AOT_Thread_predefined_symbols_address_offset = 592;
 static constexpr dart::compiler::target::word AOT_Thread_resume_pc_offset =
     1440;
 static constexpr dart::compiler::target::word
@@ -6428,37 +6456,37 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_safepoint_state_offset = 1464;
 static constexpr dart::compiler::target::word
-    AOT_Thread_slow_type_test_stub_offset = 384;
+    AOT_Thread_slow_type_test_stub_offset = 392;
 static constexpr dart::compiler::target::word AOT_Thread_stack_limit_offset =
     72;
 static constexpr dart::compiler::target::word
-    AOT_Thread_saved_stack_limit_offset = 80;
+    AOT_Thread_saved_stack_limit_offset = 120;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_flags_offset = 88;
+    AOT_Thread_stack_overflow_flags_offset = 128;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 504;
+    AOT_Thread_stack_overflow_shared_with_fpu_regs_entry_point_offset = 512;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 336;
+    AOT_Thread_stack_overflow_shared_with_fpu_regs_stub_offset = 344;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 496;
+    AOT_Thread_stack_overflow_shared_without_fpu_regs_entry_point_offset = 504;
 static constexpr dart::compiler::target::word
-    AOT_Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 328;
+    AOT_Thread_stack_overflow_shared_without_fpu_regs_stub_offset = 336;
 static constexpr dart::compiler::target::word
-    AOT_Thread_store_buffer_block_offset = 152;
+    AOT_Thread_store_buffer_block_offset = 160;
 static constexpr dart::compiler::target::word
-    AOT_Thread_top_exit_frame_info_offset = 144;
-static constexpr dart::compiler::target::word AOT_Thread_top_offset = 128;
+    AOT_Thread_top_exit_frame_info_offset = 152;
+static constexpr dart::compiler::target::word AOT_Thread_top_offset = 104;
 static constexpr dart::compiler::target::word AOT_Thread_top_resource_offset =
     48;
 static constexpr dart::compiler::target::word
-    AOT_Thread_unboxed_int64_runtime_arg_offset = 192;
-static constexpr dart::compiler::target::word AOT_Thread_vm_tag_offset = 176;
+    AOT_Thread_unboxed_int64_runtime_arg_offset = 200;
+static constexpr dart::compiler::target::word AOT_Thread_vm_tag_offset = 184;
 static constexpr dart::compiler::target::word
-    AOT_Thread_write_barrier_code_offset = 224;
+    AOT_Thread_write_barrier_code_offset = 232;
 static constexpr dart::compiler::target::word
-    AOT_Thread_write_barrier_entry_point_offset = 424;
+    AOT_Thread_write_barrier_entry_point_offset = 432;
 static constexpr dart::compiler::target::word
-    AOT_Thread_write_barrier_mask_offset = 96;
+    AOT_Thread_write_barrier_mask_offset = 80;
 static constexpr dart::compiler::target::word AOT_Thread_callback_code_offset =
     1472;
 static constexpr dart::compiler::target::word
@@ -6502,8 +6530,8 @@
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
     AOT_Thread_write_barrier_wrappers_thread_offset[] = {
-        1248, 1256, 1264, 1272, 1280, 1288, 1296, 1304, 1312, 1320, 1328,
-        1336, 1344, 1352, 1360, -1,   -1,   -1,   -1,   1368, 1376, 1384,
+        1256, 1264, 1272, 1280, 1288, 1296, 1304, 1312, 1320, 1328, 1336,
+        1344, 1352, 1360, 1368, -1,   -1,   -1,   -1,   1376, 1384, -1,
         -1,   1392, 1400, 1408, -1,   -1,   -1,   -1,   -1,   -1};
 static constexpr dart::compiler::target::word AOT_ApiError_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Array_InstanceSize = 24;
diff --git a/runtime/vm/compiler/runtime_offsets_list.h b/runtime/vm/compiler/runtime_offsets_list.h
index 296daf4..c7bd6ae 100644
--- a/runtime/vm/compiler/runtime_offsets_list.h
+++ b/runtime/vm/compiler/runtime_offsets_list.h
@@ -159,6 +159,7 @@
   FIELD(Thread, call_to_runtime_entry_point_offset)                            \
   FIELD(Thread, call_to_runtime_stub_offset)                                   \
   FIELD(Thread, dart_stream_offset)                                            \
+  FIELD(Thread, dispatch_table_array_offset)                                   \
   FIELD(Thread, optimize_entry_offset)                                         \
   FIELD(Thread, optimize_stub_offset)                                          \
   FIELD(Thread, deoptimize_entry_offset)                                       \
diff --git a/runtime/vm/compiler/stub_code_compiler_arm64.cc b/runtime/vm/compiler/stub_code_compiler_arm64.cc
index 34d927a..bf862d6 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm64.cc
@@ -161,8 +161,7 @@
   // Restore the global object pool after returning from runtime (old space is
   // moving, so the GOP could have been relocated).
   if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
-    __ ldr(PP, Address(THR, target::Thread::global_object_pool_offset()));
-    __ sub(PP, PP, Operand(kHeapObjectTag));  // Pool in PP is untagged!
+    __ SetupGlobalPoolAndDispatchTable();
   }
 
   __ LeaveStubFrame();
@@ -668,8 +667,7 @@
   // Restore the global object pool after returning from runtime (old space is
   // moving, so the GOP could have been relocated).
   if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
-    __ ldr(PP, Address(THR, target::Thread::global_object_pool_offset()));
-    __ sub(PP, PP, Operand(kHeapObjectTag));  // Pool in PP is untagged!
+    __ SetupGlobalPoolAndDispatchTable();
   }
 
   __ LeaveStubFrame();
@@ -1382,8 +1380,7 @@
   __ Bind(&done_push_arguments);
 
   if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
-    __ ldr(PP, Address(THR, target::Thread::global_object_pool_offset()));
-    __ sub(PP, PP, Operand(kHeapObjectTag));  // Pool in PP is untagged!
+    __ SetupGlobalPoolAndDispatchTable();
   } else {
     // We now load the pool pointer(PP) with a GC safe value as we are about to
     // invoke dart code. We don't need a real object pool here.
@@ -3181,8 +3178,7 @@
   // Restore the pool pointer.
   __ RestoreCodePointer();
   if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
-    __ ldr(PP, Address(THR, target::Thread::global_object_pool_offset()));
-    __ sub(PP, PP, Operand(kHeapObjectTag));  // Pool in PP is untagged!
+    __ SetupGlobalPoolAndDispatchTable();
   } else {
     __ LoadPoolPointer();
   }
diff --git a/runtime/vm/constants.h b/runtime/vm/constants.h
index f0b4045..9df918e 100644
--- a/runtime/vm/constants.h
+++ b/runtime/vm/constants.h
@@ -5,6 +5,33 @@
 #ifndef RUNTIME_VM_CONSTANTS_H_
 #define RUNTIME_VM_CONSTANTS_H_
 
+namespace dart {
+
+// Alignment strategies for how to align values.
+enum AlignmentStrategy {
+  // Align to the size of the value.
+  kAlignedToValueSize,
+  // Align to the size of the value, but align 8 byte-sized values to 4 bytes.
+  // Both double and int64.
+  kAlignedToValueSizeBut8AlignedTo4,
+  // Align to the architecture size.
+  kAlignedToWordSize,
+  // Align to the architecture size, but align 8 byte-sized values to 8 bytes.
+  // Both double and int64.
+  kAlignedToWordSizeBut8AlignedTo8,
+};
+
+// Minimum size strategies for how to store values.
+enum ExtensionStrategy {
+  // Values can have arbitrary small size with the upper bits undefined.
+  kNotExtended,
+  // Values smaller than 4 bytes are passed around zero- or signextended to
+  // 4 bytes.
+  kExtendedTo4
+};
+
+}  // namespace dart
+
 #if defined(TARGET_ARCH_IA32)
 #include "vm/constants_ia32.h"
 #elif defined(TARGET_ARCH_X64)
@@ -17,48 +44,8 @@
 #error Unknown architecture.
 #endif
 
-#if defined(HOST_ARCH_IA32)
-#include "vm/constants_ia32.h"
-#elif defined(HOST_ARCH_X64)
-#include "vm/constants_x64.h"
-#elif defined(HOST_ARCH_ARM)
-#include "vm/constants_arm.h"
-#elif defined(HOST_ARCH_ARM64)
-#include "vm/constants_arm64.h"
-#else
-#error Unknown host architecture.
-#endif
-
 namespace dart {
 
-#if defined(TARGET_ARCH_IA32)
-using namespace arch_ia32;  // NOLINT
-#elif defined(TARGET_ARCH_X64)
-using namespace arch_x64;  // NOLINT
-#elif defined(TARGET_ARCH_ARM)
-using namespace arch_arm;  // NOLINT
-#elif defined(TARGET_ARCH_ARM64)
-using namespace arch_arm64;  // NOLINT
-#else
-#error Unknown architecture.
-#endif
-
-namespace host {
-
-#if defined(HOST_ARCH_IA32)
-using namespace arch_ia32;  // NOLINT
-#elif defined(HOST_ARCH_X64)
-using namespace arch_x64;  // NOLINT
-#elif defined(HOST_ARCH_ARM)
-using namespace arch_arm;  // NOLINT
-#elif defined(HOST_ARCH_ARM64)
-using namespace arch_arm64;  // NOLINT
-#else
-#error Unknown host architecture.
-#endif
-
-}  // namespace host
-
 class RegisterNames {
  public:
   static const char* RegisterName(Register reg) {
@@ -69,16 +56,16 @@
     ASSERT((0 <= reg) && (reg < kNumberOfFpuRegisters));
     return fpu_reg_names[reg];
   }
-#if !defined(HOST_ARCH_EQUALS_TARGET_ARCH)
-  static const char* RegisterName(host::Register reg) {
-    ASSERT((0 <= reg) && (reg < host::kNumberOfCpuRegisters));
-    return host::cpu_reg_names[reg];
+#if defined(TARGET_ARCH_ARM)
+  static const char* FpuSRegisterName(SRegister reg) {
+    ASSERT((0 <= reg) && (reg < kNumberOfSRegisters));
+    return fpu_s_reg_names[reg];
   }
-  static const char* FpuRegisterName(host::FpuRegister reg) {
-    ASSERT((0 <= reg) && (reg < host::kNumberOfFpuRegisters));
-    return host::fpu_reg_names[reg];
+  static const char* FpuDRegisterName(DRegister reg) {
+    ASSERT((0 <= reg) && (reg < kNumberOfDRegisters));
+    return fpu_d_reg_names[reg];
   }
-#endif  // !defined(HOST_ARCH_EQUALS_TARGET_ARCH)
+#endif  // defined(TARGET_ARCH_ARM)
 };
 
 static constexpr bool IsArgumentRegister(Register reg) {
diff --git a/runtime/vm/constants_arm.cc b/runtime/vm/constants_arm.cc
index a4a0dd7..1f33275 100644
--- a/runtime/vm/constants_arm.cc
+++ b/runtime/vm/constants_arm.cc
@@ -2,10 +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.
 
-#define RUNTIME_VM_CONSTANTS_H_  // To work around include guard.
-#include "vm/constants_arm.h"
+#include "platform/globals.h"  // NOLINT
 
-namespace arch_arm {
+#if defined(TARGET_ARCH_ARM)
+
+#include "vm/constants.h"  // NOLINT
+
+namespace dart {
 
 using dart::bit_cast;
 
@@ -20,12 +23,27 @@
     "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15",
 #endif
 };
+const char* fpu_d_reg_names[kNumberOfDRegisters] = {
+    "d0",  "d1",  "d2",  "d3",  "d4",  "d5",  "d6",  "d7",
+    "d8",  "d9",  "d10", "d11", "d12", "d13", "d14", "d15",
+#if defined(VFPv3_D32)
+    "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
+    "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31",
+#endif
+};
+const char* fpu_s_reg_names[kNumberOfSRegisters] = {
+    "s0",  "s1",  "s2",  "s3",  "s4",  "s5",  "s6",  "s7",  "s8",  "s9",  "s10",
+    "s11", "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21",
+    "s22", "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
+};
 
 const Register CallingConventions::ArgumentRegisters[] = {R0, R1, R2, R3};
 
-// Although 'kFpuArgumentRegisters' is 0, we have to give this array at least
-// one element to appease MSVC.
-const FpuRegister CallingConventions::FpuArgumentRegisters[] = {Q0};
+const FpuRegister CallingConventions::FpuArgumentRegisters[] = {Q0, Q1, Q2, Q3};
+const DRegister CallingConventions::FpuDArgumentRegisters[] = {D0, D1, D2, D3,
+                                                               D4, D5, D6, D7};
+const SRegister CallingConventions::FpuSArgumentRegisters[] = {
+    S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15};
 
 float ReciprocalEstimate(float a) {
   // From the ARM Architecture Reference Manual A2-85.
@@ -139,4 +157,6 @@
   return (3.0f - p) / 2.0f;
 }
 
-}  // namespace arch_arm
+}  // namespace dart
+
+#endif  // defined(TARGET_ARCH_ARM)
diff --git a/runtime/vm/constants_arm.h b/runtime/vm/constants_arm.h
index 771ba41..b25b343 100644
--- a/runtime/vm/constants_arm.h
+++ b/runtime/vm/constants_arm.h
@@ -12,7 +12,7 @@
 #include "platform/assert.h"
 #include "platform/globals.h"
 
-namespace arch_arm {
+namespace dart {
 
 // We support both VFPv3-D16 and VFPv3-D32 profiles, but currently only one at
 // a time.
@@ -253,6 +253,16 @@
   return static_cast<SRegister>((d * 2) + 1);
 }
 
+static inline QRegister QRegisterOf(DRegister d) {
+  return static_cast<QRegister>(d / 2);
+}
+static inline QRegister QRegisterOf(SRegister s) {
+  return static_cast<QRegister>(s / 4);
+}
+static inline DRegister DRegisterOf(SRegister s) {
+  return static_cast<DRegister>(s / 2);
+}
+
 // Register aliases for floating point scratch registers.
 const QRegister QTMP = Q7;                     // Overlaps with DTMP, STMP.
 const DRegister DTMP = EvenDRegisterOf(QTMP);  // Overlaps with STMP.
@@ -267,6 +277,8 @@
 
 extern const char* cpu_reg_names[kNumberOfCpuRegisters];
 extern const char* fpu_reg_names[kNumberOfFpuRegisters];
+extern const char* fpu_s_reg_names[kNumberOfSRegisters];
+extern const char* fpu_d_reg_names[kNumberOfDRegisters];
 
 // Register aliases.
 const Register TMP = IP;            // Used as scratch register by assembler.
@@ -346,31 +358,43 @@
   static const Register ArgumentRegisters[];
   static const intptr_t kNumArgRegs = 4;
 
-  static const FpuRegister FpuArgumentRegisters[];
   static const intptr_t kFpuArgumentRegisters = 0;
-  static const intptr_t kNumFpuArgRegs = 0;
+
+  static const FpuRegister FpuArgumentRegisters[];
+  static const intptr_t kNumFpuArgRegs = 4;
+  static const DRegister FpuDArgumentRegisters[];
+  static const intptr_t kNumDFpuArgRegs = 8;
+  static const SRegister FpuSArgumentRegisters[];
+  static const intptr_t kNumSFpuArgRegs = 16;
 
   static constexpr bool kArgumentIntRegXorFpuReg = false;
 
   static constexpr intptr_t kCalleeSaveCpuRegisters = kAbiPreservedCpuRegs;
 
-  // Whether floating-point values should be passed as integers ("softfp" vs
-  // "hardfp"). Android and iOS always use the "softfp" calling convention, even
-  // when hardfp support is present.
-#if defined(TARGET_OS_MACOS_IOS) || defined(TARGET_OS_ANDROID)
-  static constexpr bool kAbiSoftFP = true;
+  // Whether larger than wordsize arguments are aligned to even registers.
+  static constexpr AlignmentStrategy kArgumentRegisterAlignment =
+      kAlignedToWordSizeBut8AlignedTo8;
+
+  // How stack arguments are aligned.
+  static constexpr AlignmentStrategy kArgumentStackAlignment =
+      kAlignedToWordSizeBut8AlignedTo8;
+
+  // How fields in composites are aligned.
+#if defined(TARGET_OS_MACOS_IOS)
+  static constexpr AlignmentStrategy kFieldAlignment =
+      kAlignedToValueSizeBut8AlignedTo4;
 #else
-  static constexpr bool kAbiSoftFP = false;
+  static constexpr AlignmentStrategy kFieldAlignment = kAlignedToValueSize;
 #endif
 
-  // Whether 64-bit arguments must be aligned to an even register or 8-byte
-  // stack address. True for ARM 32-bit, see "Procedure Call Standard for the
-  // ARM Architecture".
-  static constexpr bool kAlignArguments = true;
+  // Whether 1 or 2 byte-sized arguments or return values are passed extended
+  // to 4 bytes.
+  static constexpr ExtensionStrategy kArgumentRegisterExtension = kExtendedTo4;
+  static constexpr ExtensionStrategy kArgumentStackExtension = kExtendedTo4;
 
   static constexpr Register kReturnReg = R0;
   static constexpr Register kSecondReturnReg = R1;
-  static constexpr FpuRegister kReturnFpuReg = kNoFpuRegister;
+  static constexpr FpuRegister kReturnFpuReg = Q0;
 
   // We choose these to avoid overlap between themselves and reserved registers.
   static constexpr Register kFirstNonArgumentRegister = R8;
@@ -663,14 +687,14 @@
   inline float ImmFloatField() const {
     uint32_t imm32 = (Bit(19) << 31) | (((1 << 5) - Bit(18)) << 25) |
                      (Bits(16, 2) << 23) | (Bits(0, 4) << 19);
-    return ::dart::bit_cast<float, uint32_t>(imm32);
+    return bit_cast<float, uint32_t>(imm32);
   }
 
   // Field used in VFP double immediate move instruction
   inline double ImmDoubleField() const {
     uint64_t imm64 = (Bit(19) * (1LL << 63)) | (((1LL << 8) - Bit(18)) << 54) |
                      (Bits(16, 2) * (1LL << 52)) | (Bits(0, 4) * (1LL << 48));
-    return ::dart::bit_cast<double, uint64_t>(imm64);
+    return bit_cast<double, uint64_t>(imm64);
   }
 
   inline Register DivRdField() const {
@@ -818,7 +842,7 @@
   // reference to an instruction is to convert a pointer. There is no way
   // to allocate or create instances of class Instr.
   // Use the At(pc) function to create references to Instr.
-  static Instr* At(::dart::uword pc) { return reinterpret_cast<Instr*>(pc); }
+  static Instr* At(uword pc) { return reinterpret_cast<Instr*>(pc); }
 
  private:
   DISALLOW_ALLOCATION();
@@ -835,6 +859,6 @@
 float ReciprocalSqrtEstimate(float op);
 float ReciprocalSqrtStep(float op1, float op2);
 
-}  // namespace arch_arm
+}  // namespace dart
 
 #endif  // RUNTIME_VM_CONSTANTS_ARM_H_
diff --git a/runtime/vm/constants_arm64.cc b/runtime/vm/constants_arm64.cc
index 7248ef1..e0999b9 100644
--- a/runtime/vm/constants_arm64.cc
+++ b/runtime/vm/constants_arm64.cc
@@ -2,10 +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.
 
-#define RUNTIME_VM_CONSTANTS_H_  // To work around include guard.
-#include "vm/constants_arm64.h"
+#include "platform/globals.h"  // NOLINT
 
-namespace arch_arm64 {
+#if defined(TARGET_ARCH_ARM64)
+
+#include "vm/constants.h"  // NOLINT
+
+namespace dart {
 
 const char* cpu_reg_names[kNumberOfCpuRegisters] = {
     "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",  "r8",  "r9",  "r10",
@@ -27,4 +30,6 @@
     V0, V1, V2, V3, V4, V5, V6, V7,
 };
 
-}  // namespace arch_arm64
+}  // namespace dart
+
+#endif  // defined(TARGET_ARCH_ARM64)
diff --git a/runtime/vm/constants_arm64.h b/runtime/vm/constants_arm64.h
index bbda132..6b3959b 100644
--- a/runtime/vm/constants_arm64.h
+++ b/runtime/vm/constants_arm64.h
@@ -10,8 +10,9 @@
 #endif
 
 #include "platform/assert.h"
+#include "platform/globals.h"
 
-namespace arch_arm64 {
+namespace dart {
 
 enum Register {
   R0 = 0,
@@ -115,6 +116,7 @@
 const Register TMP = R16;  // Used as scratch register by assembler.
 const Register TMP2 = R17;
 const Register PP = R27;  // Caches object pool pointer in generated code.
+const Register DISPATCH_TABLE_REG = R21;  // Dispatch table register.
 const Register CODE_REG = R24;
 const Register FPREG = FP;          // Frame pointer register.
 const Register SPREG = R15;         // Stack pointer register.
@@ -178,8 +180,8 @@
     (1 << SPREG) |  // Dart SP
     (1 << FPREG) | (1 << TMP) | (1 << TMP2) | (1 << PP) | (1 << THR) |
     (1 << LR) | (1 << BARRIER_MASK) | (1 << NULL_REG) | (1 << R31) |  // C++ SP
-    (1 << R18);
-constexpr intptr_t kNumberOfReservedCpuRegisters = 11;
+    (1 << R18) | (1 << DISPATCH_TABLE_REG);
+constexpr intptr_t kNumberOfReservedCpuRegisters = 12;
 // CPU registers available to Dart allocator.
 const RegList kDartAvailableCpuRegs =
     kAllCpuRegistersList & ~kReservedCpuRegisters;
@@ -212,13 +214,30 @@
 
   static constexpr intptr_t kCalleeSaveCpuRegisters = kAbiPreservedCpuRegs;
 
-  // Whether floating-point values should be passed as integers ("softfp" vs
-  // "hardfp").
-  static constexpr bool kAbiSoftFP = false;
+  // Whether larger than wordsize arguments are aligned to even registers.
+  static constexpr AlignmentStrategy kArgumentRegisterAlignment =
+      kAlignedToWordSize;
 
-  // Whether 64-bit arguments must be aligned to an even register or 8-byte
-  // stack address. Not relevant on X64 since the word size is 64-bits already.
-  static constexpr bool kAlignArguments = false;
+  // How stack arguments are aligned.
+#if defined(TARGET_OS_MACOS_IOS)
+  static constexpr AlignmentStrategy kArgumentStackAlignment =
+      kAlignedToValueSize;
+#else
+  static constexpr AlignmentStrategy kArgumentStackAlignment =
+      kAlignedToWordSize;
+#endif
+
+  // How fields in composites are aligned.
+  static constexpr AlignmentStrategy kFieldAlignment = kAlignedToValueSize;
+
+  // Whether 1 or 2 byte-sized arguments or return values are passed extended
+  // to 4 bytes.
+#if defined(TARGET_OS_MACOS_IOS)
+  static constexpr ExtensionStrategy kArgumentRegisterExtension = kExtendedTo4;
+#else
+  static constexpr ExtensionStrategy kArgumentRegisterExtension = kNotExtended;
+#endif
+  static constexpr ExtensionStrategy kArgumentStackExtension = kNotExtended;
 
   static constexpr Register kReturnReg = R0;
   static constexpr Register kSecondReturnReg = kNoRegister;
@@ -1214,13 +1233,13 @@
   // reference to an instruction is to convert a pointer. There is no way
   // to allocate or create instances of class Instr.
   // Use the At(pc) function to create references to Instr.
-  static Instr* At(::dart::uword pc) { return reinterpret_cast<Instr*>(pc); }
+  static Instr* At(uword pc) { return reinterpret_cast<Instr*>(pc); }
 
  private:
   DISALLOW_ALLOCATION();
   DISALLOW_IMPLICIT_CONSTRUCTORS(Instr);
 };
 
-}  // namespace arch_arm64
+}  // namespace dart
 
 #endif  // RUNTIME_VM_CONSTANTS_ARM64_H_
diff --git a/runtime/vm/constants_ia32.cc b/runtime/vm/constants_ia32.cc
index 7b9124a..2d83fdd 100644
--- a/runtime/vm/constants_ia32.cc
+++ b/runtime/vm/constants_ia32.cc
@@ -2,10 +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.
 
-#define RUNTIME_VM_CONSTANTS_H_  // To work around include guard.
-#include "vm/constants_ia32.h"
+#include "platform/globals.h"  // NOLINT
 
-namespace arch_ia32 {
+#if defined(TARGET_ARCH_IA32)
+
+#include "vm/constants.h"  // NOLINT
+
+namespace dart {
 
 const char* cpu_reg_names[kNumberOfCpuRegisters] = {"eax", "ecx", "edx", "ebx",
                                                     "esp", "ebp", "esi", "edi"};
@@ -21,4 +24,6 @@
 const FpuRegister CallingConventions::FpuArgumentRegisters[] = {
     static_cast<FpuRegister>(0)};
 
-}  // namespace arch_ia32
+}  // namespace dart
+
+#endif  // defined(TARGET_ARCH_IA32)
diff --git a/runtime/vm/constants_ia32.h b/runtime/vm/constants_ia32.h
index be6e8e2..6346e75 100644
--- a/runtime/vm/constants_ia32.h
+++ b/runtime/vm/constants_ia32.h
@@ -10,8 +10,9 @@
 #endif
 
 #include "platform/assert.h"
+#include "platform/globals.h"
 
-namespace arch_ia32 {
+namespace dart {
 
 enum Register {
   EAX = 0,
@@ -38,6 +39,10 @@
   kNoByteRegister = -1  // Signals an illegal register.
 };
 
+inline ByteRegister ByteRegisterOf(Register reg) {
+  return static_cast<ByteRegister>(reg);
+}
+
 enum XmmRegister {
   XMM0 = 0,
   XMM1 = 1,
@@ -98,7 +103,7 @@
   TIMES_4 = 2,
   TIMES_8 = 3,
   TIMES_16 = 4,
-  TIMES_HALF_WORD_SIZE = ::dart::kWordSizeLog2 - 1
+  TIMES_HALF_WORD_SIZE = kWordSizeLog2 - 1
 };
 
 class Instr {
@@ -117,7 +122,7 @@
   // reference to an instruction is to convert a pointer. There is no way
   // to allocate or create instances of class Instr.
   // Use the At(pc) function to create references to Instr.
-  static Instr* At(::dart::uword pc) { return reinterpret_cast<Instr*>(pc); }
+  static Instr* At(uword pc) { return reinterpret_cast<Instr*>(pc); }
 
  private:
   DISALLOW_ALLOCATION();
@@ -145,27 +150,42 @@
 
   static const bool kArgumentIntRegXorFpuReg = false;
 
-  // Whether floating-point values should be passed as integers ("softfp" vs
-  // "hardfp").
-  static constexpr bool kAbiSoftFP = false;
-
   static constexpr Register kReturnReg = EAX;
   static constexpr Register kSecondReturnReg = EDX;
 
   // Floating point values are returned on the "FPU stack" (in "ST" registers).
-  static constexpr XmmRegister kReturnFpuReg = kNoXmmRegister;
+  // However, we use XMM0 in our compiler pipeline as the location.
+  // The move from and to ST is done in FfiCallInstr::EmitNativeCode and
+  // NativeReturnInstr::EmitNativeCode.
+  static constexpr XmmRegister kReturnFpuReg = XMM0;
 
   static constexpr Register kFirstCalleeSavedCpuReg = EBX;
   static constexpr Register kFirstNonArgumentRegister = EAX;
   static constexpr Register kSecondNonArgumentRegister = ECX;
   static constexpr Register kStackPointerRegister = SPREG;
 
-  // Whether 64-bit arguments must be aligned to an even register or 8-byte
-  // stack address. On IA32, 64-bit integers and floating-point values do *not*
-  // need to be 8-byte aligned.
-  static constexpr bool kAlignArguments = false;
+  // Whether larger than wordsize arguments are aligned to even registers.
+  static constexpr AlignmentStrategy kArgumentRegisterAlignment =
+      kAlignedToWordSize;
+
+  // How stack arguments are aligned.
+  static constexpr AlignmentStrategy kArgumentStackAlignment =
+      kAlignedToWordSize;
+
+  // How fields in composites are aligned.
+#if defined(_WIN32)
+  static constexpr AlignmentStrategy kFieldAlignment = kAlignedToValueSize;
+#else
+  static constexpr AlignmentStrategy kFieldAlignment =
+      kAlignedToValueSizeBut8AlignedTo4;
+#endif
+
+  // Whether 1 or 2 byte-sized arguments or return values are passed extended
+  // to 4 bytes.
+  static constexpr ExtensionStrategy kArgumentRegisterExtension = kNotExtended;
+  static constexpr ExtensionStrategy kArgumentStackExtension = kExtendedTo4;
 };
 
-}  // namespace arch_ia32
+}  // namespace dart
 
 #endif  // RUNTIME_VM_CONSTANTS_IA32_H_
diff --git a/runtime/vm/constants_x64.cc b/runtime/vm/constants_x64.cc
index 71b43d6..afd0a97 100644
--- a/runtime/vm/constants_x64.cc
+++ b/runtime/vm/constants_x64.cc
@@ -2,10 +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.
 
-#define RUNTIME_VM_CONSTANTS_H_  // To work around include guard.
-#include "vm/constants_x64.h"
+#include "platform/globals.h"  // NOLINT
 
-namespace arch_x64 {
+#if defined(TARGET_ARCH_X64)
+
+#include "vm/constants.h"  // NOLINT
+
+namespace dart {
 
 const char* cpu_reg_names[kNumberOfCpuRegisters] = {
     "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
@@ -33,4 +36,6 @@
     XmmRegister::XMM4, XmmRegister::XMM5, XmmRegister::XMM6, XmmRegister::XMM7};
 #endif
 
-}  // namespace arch_x64
+}  // namespace dart
+
+#endif  // defined(TARGET_ARCH_X64)
diff --git a/runtime/vm/constants_x64.h b/runtime/vm/constants_x64.h
index 47d60747..7665d65 100644
--- a/runtime/vm/constants_x64.h
+++ b/runtime/vm/constants_x64.h
@@ -12,7 +12,7 @@
 #include "platform/assert.h"
 #include "platform/globals.h"
 
-namespace arch_x64 {
+namespace dart {
 
 enum Register {
   RAX = 0,
@@ -150,7 +150,7 @@
   TIMES_4 = 2,
   TIMES_8 = 3,
   TIMES_16 = 4,
-  TIMES_HALF_WORD_SIZE = ::dart::kWordSizeLog2 - 1
+  TIMES_HALF_WORD_SIZE = kWordSizeLog2 - 1
 };
 
 #define R(reg) (1 << (reg))
@@ -176,7 +176,7 @@
   // same time? (Windows no, rest yes)
   static const bool kArgumentIntRegXorFpuReg = true;
 
-  static const intptr_t kShadowSpaceBytes = 4 * ::dart::kWordSize;
+  static const intptr_t kShadowSpaceBytes = 4 * kWordSize;
 
   static const intptr_t kVolatileCpuRegisters =
       R(RAX) | R(RCX) | R(RDX) | R(R8) | R(R9) | R(R10) | R(R11);
@@ -201,13 +201,22 @@
   static constexpr Register kSecondReturnReg = kNoRegister;
   static constexpr FpuRegister kReturnFpuReg = XMM0;
 
-  // Whether floating-point values should be passed as integers ("softfp" vs
-  // "hardfp").
-  static constexpr bool kAbiSoftFP = false;
+  // Whether larger than wordsize arguments are aligned to even registers.
+  static constexpr AlignmentStrategy kArgumentRegisterAlignment =
+      kAlignedToWordSize;
 
-  // Whether 64-bit arguments must be aligned to an even register or 8-byte
-  // stack address. Not relevant on X64 since the word size is 64-bits already.
-  static constexpr bool kAlignArguments = false;
+  // How stack arguments are aligned.
+  static constexpr AlignmentStrategy kArgumentStackAlignment =
+      kAlignedToWordSize;
+
+  // How fields in composites are aligned.
+  static constexpr AlignmentStrategy kFieldAlignment = kAlignedToValueSize;
+
+  // Whether 1 or 2 byte-sized arguments or return values are passed extended
+  // to 4 bytes.
+  static constexpr ExtensionStrategy kArgumentRegisterExtension = kNotExtended;
+  static constexpr ExtensionStrategy kArgumentStackExtension = kNotExtended;
+
 #else
   static const Register kArg1Reg = RDI;
   static const Register kArg2Reg = RSI;
@@ -253,13 +262,22 @@
   static constexpr Register kSecondReturnReg = kNoRegister;
   static constexpr FpuRegister kReturnFpuReg = XMM0;
 
-  // Whether floating-point values should be passed as integers ("softfp" vs
-  // "hardfp").
-  static constexpr bool kAbiSoftFP = false;
+  // Whether larger than wordsize arguments are aligned to even registers.
+  static constexpr AlignmentStrategy kArgumentRegisterAlignment =
+      kAlignedToWordSize;
 
-  // Whether 64-bit arguments must be aligned to an even register or 8-byte
-  // stack address. Not relevant on X64 since the word size is 64-bits already.
-  static constexpr bool kAlignArguments = false;
+  // How stack arguments are aligned.
+  static constexpr AlignmentStrategy kArgumentStackAlignment =
+      kAlignedToWordSize;
+
+  // How fields in composites are aligned.
+  static constexpr AlignmentStrategy kFieldAlignment = kAlignedToValueSize;
+
+  // Whether 1 or 2 byte-sized arguments or return values are passed extended
+  // to 4 bytes.
+  static constexpr ExtensionStrategy kArgumentRegisterExtension = kNotExtended;
+  static constexpr ExtensionStrategy kArgumentStackExtension = kExtendedTo4;
+
 #endif
 
   COMPILE_ASSERT((kArgumentRegisters & kReservedCpuRegisters) == 0);
@@ -295,7 +313,7 @@
   // reference to an instruction is to convert a pointer. There is no way
   // to allocate or create instances of class Instr.
   // Use the At(pc) function to create references to Instr.
-  static Instr* At(::dart::uword pc) { return reinterpret_cast<Instr*>(pc); }
+  static Instr* At(uword pc) { return reinterpret_cast<Instr*>(pc); }
 
  private:
   DISALLOW_ALLOCATION();
@@ -307,6 +325,6 @@
 // becomes important to us.
 const int MAX_NOP_SIZE = 8;
 
-}  // namespace arch_x64
+}  // namespace dart
 
 #endif  // RUNTIME_VM_CONSTANTS_X64_H_
diff --git a/runtime/vm/cpu_arm.cc b/runtime/vm/cpu_arm.cc
index 2ee57f4..3ae65c1 100644
--- a/runtime/vm/cpu_arm.cc
+++ b/runtime/vm/cpu_arm.cc
@@ -183,10 +183,14 @@
 #endif
   }
 
+#if defined(DART_RUN_IN_QEMU_ARMv7)
+  vfp_supported_ = true;
+#else
   // Has floating point unit.
   vfp_supported_ =
       (CpuInfo::FieldContains(kCpuInfoFeatures, "vfp") || is_arm64) &&
       FLAG_use_vfp;
+#endif
 
   // Has integer division.
   // Special cases:
@@ -224,7 +228,7 @@
 
 // Use the cross-compiler's predefined macros to determine whether we should
 // use the hard or soft float ABI.
-#if defined(__ARM_PCS_VFP)
+#if defined(__ARM_PCS_VFP) || defined(DART_RUN_IN_QEMU_ARMv7)
   hardfp_supported_ = true;
 #else
   hardfp_supported_ = false;
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index a3381d0..ce28a06 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -381,15 +381,18 @@
   Isolate::SetCleanupCallback(cleanup);
   Isolate::SetGroupCleanupCallback(cleanup_group);
 
-  if (FLAG_support_service) {
-    Service::SetGetServiceAssetsCallback(get_service_assets);
-  }
+#ifndef PRODUCT
+  const bool support_service = true;
+  Service::SetGetServiceAssetsCallback(get_service_assets);
+#else
+  const bool support_service = false;
+#endif
 
   const bool is_dart2_aot_precompiler =
       FLAG_precompiled_mode && !kDartPrecompiledRuntime;
 
   if (!is_dart2_aot_precompiler &&
-      (FLAG_support_service || !kDartPrecompiledRuntime)) {
+      (support_service || !kDartPrecompiledRuntime)) {
     ServiceIsolate::Run();
   }
 
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 6c701a1..aa6e4db 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1176,11 +1176,6 @@
       HANDLESCOPE(T);
       StackZone zone(T);
 
-      // The kernel loader is about to allocate a bunch of new libraries,
-      // classes and functions into old space. Force growth, and use of the
-      // bump allocator instead of freelists.
-      BumpAllocateScope bump_allocate_scope(T);
-
       // NOTE: We do not attach a finalizer for this object, because the
       // embedder will free it once the isolate group has shutdown.
       const auto& td = ExternalTypedData::Handle(ExternalTypedData::New(
@@ -5174,11 +5169,6 @@
   CHECK_CALLBACK_STATE(T);
   CHECK_COMPILATION_ALLOWED(I);
 
-  // The kernel loader is about to allocate a bunch of new libraries, classes,
-  // and functions into old space. Force growth, and use of the bump allocator
-  // instead of freelists.
-  BumpAllocateScope bump_allocate_scope(T);
-
   // NOTE: We do not attach a finalizer for this object, because the embedder
   // will free it once the isolate group has shutdown.
   const auto& td = ExternalTypedData::Handle(ExternalTypedData::New(
@@ -5422,11 +5412,6 @@
   CHECK_CALLBACK_STATE(T);
   CHECK_COMPILATION_ALLOWED(I);
 
-  // The kernel loader is about to allocate a bunch of new libraries, classes,
-  // and functions into old space. Force growth, and use of the bump allocator
-  // instead of freelists.
-  BumpAllocateScope bump_allocate_scope(T);
-
   // NOTE: We do not attach a finalizer for this object, because the embedder
   // will/should free it once the isolate group has shutdown.
   // See also http://dartbug.com/37030.
@@ -5491,11 +5476,6 @@
   Isolate* I = T->isolate();
   CHECK_CALLBACK_STATE(T);
 
-  // The kernel loader is about to allocate a bunch of new libraries, classes,
-  // and functions into old space. Force growth, and use of the bump allocator
-  // instead of freelists.
-  BumpAllocateScope bump_allocate_scope(T);
-
   // Finalize all classes if needed.
   Dart_Handle state = Api::CheckAndFinalizePendingClasses(T);
   if (Api::IsError(state)) {
@@ -5741,9 +5721,7 @@
     Dart_ServiceRequestCallback callback,
     void* user_data) {
 #if !defined(PRODUCT)
-  if (FLAG_support_service) {
-    Service::RegisterIsolateEmbedderCallback(name, callback, user_data);
-  }
+  Service::RegisterIsolateEmbedderCallback(name, callback, user_data);
 #endif
 }
 
@@ -5752,18 +5730,14 @@
     Dart_ServiceRequestCallback callback,
     void* user_data) {
 #if !defined(PRODUCT)
-  if (FLAG_support_service) {
-    Service::RegisterRootEmbedderCallback(name, callback, user_data);
-  }
+  Service::RegisterRootEmbedderCallback(name, callback, user_data);
 #endif
 }
 
 DART_EXPORT void Dart_SetEmbedderInformationCallback(
     Dart_EmbedderInformationCallback callback) {
 #if !defined(PRODUCT)
-  if (FLAG_support_service) {
-    Service::SetEmbedderInformationCallback(callback);
-  }
+  Service::SetEmbedderInformationCallback(callback);
 #endif
 }
 
@@ -5773,9 +5747,6 @@
 #if defined(PRODUCT)
   return NULL;
 #else
-  if (!FLAG_support_service) {
-    return NULL;
-  }
   if (listen_callback != NULL) {
     if (Service::stream_listen_callback() != NULL) {
       return strdup(
@@ -5845,9 +5816,6 @@
 DART_EXPORT char* Dart_SetFileModifiedCallback(
     Dart_FileModifiedCallback file_modified_callback) {
 #if !defined(PRODUCT)
-  if (!FLAG_support_service) {
-    return NULL;
-  }
 #if !defined(DART_PRECOMPILED_RUNTIME)
   if (file_modified_callback != NULL) {
     if (IsolateGroupReloadContext::file_modified_callback() != NULL) {
diff --git a/runtime/vm/dart_api_impl.h b/runtime/vm/dart_api_impl.h
index 982d065..47346fd 100644
--- a/runtime/vm/dart_api_impl.h
+++ b/runtime/vm/dart_api_impl.h
@@ -300,18 +300,9 @@
   static RawString* GetEnvironmentValue(Thread* thread, const String& name);
 
   static bool IsFfiEnabled() {
-    // dart:ffi is not implemented for the following configurations
-#if defined(TARGET_ARCH_ARM) &&                                                \
-    !(defined(TARGET_OS_ANDROID) || defined(TARGET_OS_MACOS_IOS))
-    // TODO(36309): Support hardfp calling convention.
-    return false;
-#elif !defined(TARGET_OS_LINUX) && !defined(TARGET_OS_MACOS) &&                \
-    !defined(TARGET_OS_ANDROID) && !defined(TARGET_OS_WINDOWS)
+#if defined(TAGET_OS_FUCHSIA)
     return false;
 #else
-    // dart:ffi is also not implemented for precompiled in which case
-    // FLAG_enable_ffi is set to false by --precompilation.
-    // Once dart:ffi is supported on all targets, only users will set this flag
     return FLAG_enable_ffi;
 #endif
   }
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 23a083a..218778c 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -2901,6 +2901,9 @@
   ApiState* state = isolate->api_state();
   EXPECT(state != NULL);
   ApiLocalScope* scope = thread->api_top_scope();
+
+  const intptr_t handle_count_start = state->CountPersistentHandles();
+
   Dart_PersistentHandle handles[2000];
   Dart_EnterScope();
   {
@@ -2952,7 +2955,7 @@
     }
   }
   EXPECT(scope == thread->api_top_scope());
-  EXPECT_EQ(2001, state->CountPersistentHandles());
+  EXPECT_EQ(handle_count_start + 2000, state->CountPersistentHandles());
   Dart_ShutdownIsolate();
 }
 
diff --git a/runtime/vm/dart_entry.cc b/runtime/vm/dart_entry.cc
index bfe8f9e..ab11b0c 100644
--- a/runtime/vm/dart_entry.cc
+++ b/runtime/vm/dart_entry.cc
@@ -9,6 +9,7 @@
 #include "vm/compiler/frontend/bytecode_reader.h"
 #include "vm/compiler/jit/compiler.h"
 #include "vm/debugger.h"
+#include "vm/dispatch_table.h"
 #include "vm/heap/safepoint.h"
 #include "vm/interpreter.h"
 #include "vm/object_store.h"
@@ -111,6 +112,10 @@
       Thread* thread = Thread::Current();
       thread->set_global_object_pool(
           thread->isolate()->object_store()->global_object_pool());
+      const DispatchTable* dispatch_table = thread->isolate()->dispatch_table();
+      if (dispatch_table != nullptr) {
+        thread->set_dispatch_table_array(dispatch_table->ArrayOrigin());
+      }
       ASSERT(thread->global_object_pool() != Object::null());
     }
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index f0b7a18..75f0f40 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -3384,106 +3384,129 @@
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
   Class& cls = Class::Handle(zone);
-  Library& lib = Library::Handle(zone, script.FindLibrary());
-  ASSERT(!lib.IsNull());
-  if (!lib.IsDebuggable()) {
-    if (FLAG_verbose_debug) {
-      OS::PrintErr("Library '%s' has been marked as non-debuggable\n",
-                   lib.ToCString());
-    }
-    return false;
-  }
-  const GrowableObjectArray& closures = GrowableObjectArray::Handle(
-      zone, isolate_->object_store()->closure_functions());
-  Array& functions = Array::Handle(zone);
-  Function& function = Function::Handle(zone);
-  Array& fields = Array::Handle(zone);
-  Field& field = Field::Handle(zone);
-  Error& error = Error::Handle(zone);
 
-  const intptr_t num_closures = closures.Length();
-  for (intptr_t i = 0; i < num_closures; i++) {
-    function ^= closures.At(i);
-    if (FunctionOverlaps(function, script, token_pos, last_token_pos)) {
-      // Select the inner most closure.
-      SelectBestFit(best_fit, &function);
-    }
-  }
-  if (!best_fit->IsNull()) {
-    // The inner most closure found will be the best fit. Going
-    // over class functions below will not help in any further
-    // narrowing.
-    return true;
-  }
-
-  const ClassTable& class_table = *isolate_->class_table();
-  const intptr_t num_classes = class_table.NumCids();
-  for (intptr_t i = 1; i < num_classes; i++) {
-    if (!class_table.HasValidClassAt(i)) {
-      continue;
-    }
-    cls = class_table.At(i);
-    // This class is relevant to us only if it belongs to the
-    // library to which |script| belongs.
-    if (cls.library() != lib.raw()) {
-      continue;
-    }
-    // Parse class definition if not done yet.
-    error = cls.EnsureIsFinalized(Thread::Current());
-    if (!error.IsNull()) {
-      // Ignore functions in this class.
-      // TODO(hausner): Should we propagate this error? How?
-      // EnsureIsFinalized only returns an error object if there
-      // is no longjump base on the stack.
-      continue;
-    }
-    functions = cls.functions();
-    if (!functions.IsNull()) {
-      const intptr_t num_functions = functions.Length();
-      for (intptr_t pos = 0; pos < num_functions; pos++) {
-        function ^= functions.At(pos);
-        ASSERT(!function.IsNull());
-        if (IsImplicitFunction(function)) {
-          // Implicit functions do not have a user specifiable source
-          // location.
-          continue;
-        }
-        if (FunctionOverlaps(function, script, token_pos, last_token_pos)) {
-          // Closures and inner functions within a class method are not
-          // present in the functions of a class. Hence, we can return
-          // right away as looking through other functions of a class
-          // will not narrow down to any inner function/closure.
-          *best_fit = function.raw();
-          return true;
-        }
+  // A single script can belong to several libraries because of mixins.
+  // Go through all libraries and for each that contains the script, try to find
+  // a fit there.
+  // Return the first fit found, but if a library doesn't contain a fit,
+  // process the next one.
+  const GrowableObjectArray& libs = GrowableObjectArray::Handle(
+      zone, thread->isolate()->object_store()->libraries());
+  Library& lib = Library::Handle(zone);
+  for (int i = 0; i < libs.Length(); i++) {
+    lib ^= libs.At(i);
+    ASSERT(!lib.IsNull());
+    const Array& scripts = Array::Handle(zone, lib.LoadedScripts());
+    bool lib_has_script = false;
+    for (intptr_t j = 0; j < scripts.Length(); j++) {
+      if (scripts.At(j) == script.raw()) {
+        lib_has_script = true;
+        break;
       }
     }
-    // If none of the functions in the class contain token_pos, then we
-    // check if it falls within a function literal initializer of a field
-    // that has not been initialized yet. If the field (and hence the
-    // function literal initializer) has already been initialized, then
-    // it would have been found above in the object store as a closure.
-    fields = cls.fields();
-    if (!fields.IsNull()) {
-      const intptr_t num_fields = fields.Length();
-      for (intptr_t pos = 0; pos < num_fields; pos++) {
-        TokenPosition start;
-        TokenPosition end;
-        field ^= fields.At(pos);
-        ASSERT(!field.IsNull());
-        if (field.Script() != script.raw()) {
-          // The field should be defined in the script we want to set
-          // the breakpoint in.
-          continue;
+    if (!lib_has_script) {
+      continue;
+    }
+
+    if (!lib.IsDebuggable()) {
+      if (FLAG_verbose_debug) {
+        OS::PrintErr("Library '%s' has been marked as non-debuggable\n",
+                     lib.ToCString());
+      }
+      continue;
+    }
+    const GrowableObjectArray& closures = GrowableObjectArray::Handle(
+        zone, isolate_->object_store()->closure_functions());
+    Array& functions = Array::Handle(zone);
+    Function& function = Function::Handle(zone);
+    Array& fields = Array::Handle(zone);
+    Field& field = Field::Handle(zone);
+    Error& error = Error::Handle(zone);
+
+    const intptr_t num_closures = closures.Length();
+    for (intptr_t i = 0; i < num_closures; i++) {
+      function ^= closures.At(i);
+      if (FunctionOverlaps(function, script, token_pos, last_token_pos)) {
+        // Select the inner most closure.
+        SelectBestFit(best_fit, &function);
+      }
+    }
+    if (!best_fit->IsNull()) {
+      // The inner most closure found will be the best fit. Going
+      // over class functions below will not help in any further
+      // narrowing.
+      return true;
+    }
+
+    const ClassTable& class_table = *isolate_->class_table();
+    const intptr_t num_classes = class_table.NumCids();
+    for (intptr_t i = 1; i < num_classes; i++) {
+      if (!class_table.HasValidClassAt(i)) {
+        continue;
+      }
+      cls = class_table.At(i);
+      // This class is relevant to us only if it belongs to the
+      // library to which |script| belongs.
+      if (cls.library() != lib.raw()) {
+        continue;
+      }
+      // Parse class definition if not done yet.
+      error = cls.EnsureIsFinalized(Thread::Current());
+      if (!error.IsNull()) {
+        // Ignore functions in this class.
+        // TODO(hausner): Should we propagate this error? How?
+        // EnsureIsFinalized only returns an error object if there
+        // is no longjump base on the stack.
+        continue;
+      }
+      functions = cls.functions();
+      if (!functions.IsNull()) {
+        const intptr_t num_functions = functions.Length();
+        for (intptr_t pos = 0; pos < num_functions; pos++) {
+          function ^= functions.At(pos);
+          ASSERT(!function.IsNull());
+          if (IsImplicitFunction(function)) {
+            // Implicit functions do not have a user specifiable source
+            // location.
+            continue;
+          }
+          if (FunctionOverlaps(function, script, token_pos, last_token_pos)) {
+            // Closures and inner functions within a class method are not
+            // present in the functions of a class. Hence, we can return
+            // right away as looking through other functions of a class
+            // will not narrow down to any inner function/closure.
+            *best_fit = function.raw();
+            return true;
+          }
         }
-        if (!field.has_nontrivial_initializer()) {
-          continue;
-        }
-        start = field.token_pos();
-        end = field.end_token_pos();
-        if ((start <= token_pos && token_pos <= end) ||
-            (token_pos <= start && start <= last_token_pos)) {
-          return true;
+      }
+      // If none of the functions in the class contain token_pos, then we
+      // check if it falls within a function literal initializer of a field
+      // that has not been initialized yet. If the field (and hence the
+      // function literal initializer) has already been initialized, then
+      // it would have been found above in the object store as a closure.
+      fields = cls.fields();
+      if (!fields.IsNull()) {
+        const intptr_t num_fields = fields.Length();
+        for (intptr_t pos = 0; pos < num_fields; pos++) {
+          TokenPosition start;
+          TokenPosition end;
+          field ^= fields.At(pos);
+          ASSERT(!field.IsNull());
+          if (field.Script() != script.raw()) {
+            // The field should be defined in the script we want to set
+            // the breakpoint in.
+            continue;
+          }
+          if (!field.has_nontrivial_initializer()) {
+            continue;
+          }
+          start = field.token_pos();
+          end = field.end_token_pos();
+          if ((start <= token_pos && token_pos <= end) ||
+              (token_pos <= start && start <= last_token_pos)) {
+            return true;
+          }
         }
       }
     }
diff --git a/runtime/vm/dispatch_table.cc b/runtime/vm/dispatch_table.cc
new file mode 100644
index 0000000..f7660245
--- /dev/null
+++ b/runtime/vm/dispatch_table.cc
@@ -0,0 +1,157 @@
+// Copyright (c) 2020, 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.
+
+#include "vm/dispatch_table.h"
+
+#include "vm/clustered_snapshot.h"
+#include "vm/hash_map.h"
+#include "vm/object.h"
+
+namespace dart {
+
+// The serialized format of the dispatch table is a sequence of variable-length
+// integers (using the built-in variable-length integer encoding/decoding of
+// the stream). Each encoded integer e is interpreted thus:
+// -kRecentCount .. -1   Pick value from the recent values buffer at index -1-e.
+// 0                     Empty (unused) entry.
+// 1 .. kMaxRepeat       Repeat previous entry e times.
+// kIndexBase or higher  Pick entry point from the code object at index
+//                       e-kIndexBase in the code array and also put it into
+//                       the recent values buffer at the next index round-robin.
+
+// Constants for serialization format. Chosen such that repeats and recent
+// values are encoded as single bytes.
+static const intptr_t kMaxRepeat = 63;
+static const intptr_t kRecentCount = 64;  // Must be a power of two.
+static const intptr_t kRecentMask = kRecentCount - 1;
+static const intptr_t kIndexBase = kMaxRepeat + 1;
+
+uword DispatchTable::EntryPointFor(const Code& code) {
+  return code.EntryPoint();
+}
+
+void DispatchTable::SetCodeAt(intptr_t index, const Code& code) {
+  ASSERT(index >= 0 && index < length());
+  // The table is built with the same representation as it has at runtime, that
+  // is, table entries are function entry points. This representation assumes
+  // that the code will not move between table building and serialization.
+  // This property is upheld by the fact that the GC does not move code around.
+  array_[index] = EntryPointFor(code);
+}
+
+intptr_t DispatchTable::Serialize(Serializer* serializer,
+                                  const DispatchTable* table,
+                                  const GrowableArray<RawCode*>& code_objects) {
+  const intptr_t bytes_before = serializer->bytes_written();
+  if (table != nullptr) {
+    table->Serialize(serializer, code_objects);
+  } else {
+    serializer->Write<uint32_t>(0);
+  }
+  return serializer->bytes_written() - bytes_before;
+}
+
+void DispatchTable::Serialize(
+    Serializer* serializer,
+    const GrowableArray<RawCode*>& code_objects) const {
+  Code& code = Code::Handle();
+  IntMap<intptr_t> entry_to_index;
+  for (intptr_t i = 0; i < code_objects.length(); i++) {
+    code = code_objects[i];
+    const uword entry = EntryPointFor(code);
+    if (!entry_to_index.HasKey(entry)) {
+      entry_to_index.Insert(entry, i + 1);
+    }
+  }
+
+  uword prev_entry = 0;
+  uword recent[kRecentCount] = {0};
+  intptr_t recent_index = 0;
+  intptr_t repeat_count = 0;
+
+  serializer->Write<uint32_t>(length());
+  for (intptr_t i = 0; i < length(); i++) {
+    const uword entry = array_[i];
+    if (entry == prev_entry) {
+      if (++repeat_count == kMaxRepeat) {
+        serializer->Write<uint32_t>(kMaxRepeat);
+        repeat_count = 0;
+      }
+    } else {
+      if (repeat_count > 0) {
+        serializer->Write<uint32_t>(repeat_count);
+        repeat_count = 0;
+      }
+      if (entry == 0) {
+        serializer->Write<uint32_t>(0);
+      } else {
+        bool found_recent = false;
+        for (intptr_t r = 0; r < kRecentCount; r++) {
+          if (recent[r] == entry) {
+            serializer->Write<uint32_t>(~r);
+            found_recent = true;
+            break;
+          }
+        }
+        if (!found_recent) {
+          intptr_t index = entry_to_index.Lookup(entry) - 1;
+          ASSERT(index != -1);
+          ASSERT(EntryPointFor(Code::Handle(code_objects[index])) == entry);
+          serializer->Write<uint32_t>(kIndexBase + index);
+          recent[recent_index] = entry;
+          recent_index = (recent_index + 1) & kRecentMask;
+        }
+      }
+    }
+    prev_entry = entry;
+  }
+  if (repeat_count > 0) {
+    serializer->Write<uint32_t>(repeat_count);
+  }
+}
+
+DispatchTable* DispatchTable::Deserialize(Deserializer* deserializer,
+                                          const Array& code_array) {
+  const intptr_t length = deserializer->Read<uint32_t>();
+  if (length == 0) {
+    return nullptr;
+  }
+
+  DispatchTable* table = new DispatchTable(length);
+
+  Code& code = Code::Handle();
+
+  uword value = 0;
+  uword recent[kRecentCount] = {0};
+  intptr_t recent_index = 0;
+  intptr_t repeat_count = 0;
+  for (intptr_t i = 0; i < length; i++) {
+    if (repeat_count > 0) {
+      repeat_count--;
+    } else {
+      int32_t encoded = deserializer->Read<uint32_t>();
+      if (encoded == 0) {
+        value = 0;
+      } else if (encoded < 0) {
+        intptr_t r = ~encoded;
+        ASSERT(r < kRecentCount);
+        value = recent[r];
+      } else if (encoded <= kMaxRepeat) {
+        repeat_count = encoded - 1;
+      } else {
+        intptr_t index = encoded - kIndexBase;
+        code ^= code_array.At(index);
+        value = EntryPointFor(code);
+        recent[recent_index] = value;
+        recent_index = (recent_index + 1) & kRecentMask;
+      }
+    }
+    table->array_[i] = value;
+  }
+  ASSERT(repeat_count == 0);
+
+  return table;
+}
+
+}  // namespace dart
diff --git a/runtime/vm/dispatch_table.h b/runtime/vm/dispatch_table.h
new file mode 100644
index 0000000..c9d3a7e
--- /dev/null
+++ b/runtime/vm/dispatch_table.h
@@ -0,0 +1,79 @@
+// Copyright (c) 2020, 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.
+
+#ifndef RUNTIME_VM_DISPATCH_TABLE_H_
+#define RUNTIME_VM_DISPATCH_TABLE_H_
+
+#include <memory>
+
+#include "vm/globals.h"
+#include "vm/growable_array.h"
+
+namespace dart {
+
+class Array;
+class Code;
+class Deserializer;
+class RawCode;
+class Serializer;
+
+namespace compiler {
+class DispatchTableGenerator;
+}
+
+class DispatchTable {
+ public:
+  explicit DispatchTable(intptr_t length)
+      : length_(length), array_(new uword[length]()) {}
+
+  intptr_t length() const { return length_; }
+  uword* array() const { return array_.get(); }
+
+  // The element of the dispatch table array to which the dispatch table
+  // register points.
+  static intptr_t OriginElement() {
+#if defined(TARGET_ARCH_X64)
+    // Max negative byte offset / 8
+    return 16;
+#elif defined(TARGET_ARCH_ARM)
+    // Max negative load offset / 4
+    return 1023;
+#elif defined(TARGET_ARCH_ARM64)
+    // Max consecutive sub immediate value
+    return 4096;
+#else
+    // No AOT on IA32
+    UNREACHABLE();
+    return 0;
+#endif
+  }
+
+  // Dispatch table array pointer to put into the dispatch table register.
+  uword* ArrayOrigin() const { return &array()[OriginElement()]; }
+
+  void SetCodeAt(intptr_t index, const Code& code);
+
+  static intptr_t Serialize(Serializer* serializer,
+                            const DispatchTable* table,
+                            const GrowableArray<RawCode*>& code_objects);
+  static DispatchTable* Deserialize(Deserializer* deserializer,
+                                    const Array& code_array);
+
+ private:
+  friend class compiler::DispatchTableGenerator;
+
+  void Serialize(Serializer* serializer,
+                 const GrowableArray<RawCode*>& code_objects) const;
+
+  static uword EntryPointFor(const Code& code);
+
+  intptr_t length_;
+  std::unique_ptr<uword[]> array_;
+
+  DISALLOW_COPY_AND_ASSIGN(DispatchTable);
+};
+
+}  // namespace dart
+
+#endif  // RUNTIME_VM_DISPATCH_TABLE_H_
diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h
index cb3cb02..20da256 100644
--- a/runtime/vm/flag_list.h
+++ b/runtime/vm/flag_list.h
@@ -178,15 +178,13 @@
   P(strong_non_nullable_type_checks, bool, false,                              \
     "Enable strong non-nullable type checking mode.")                          \
   P(use_bare_instructions, bool, true, "Enable bare instructions mode.")       \
-  P(enable_isolate_groups, bool, kDartPrecompiledRuntime,                      \
-    "Enable isolate group support.")                                           \
+  P(use_table_dispatch, bool, true, "Enable dispatch table based calls.")      \
+  P(enable_isolate_groups, bool, false, "Enable isolate group support.")       \
   P(show_invisible_frames, bool, false,                                        \
     "Show invisible frames in stack traces.")                                  \
   R(show_invisible_isolates, false, bool, false,                               \
     "Show invisible isolates in the vm-service.")                              \
   R(support_il_printer, false, bool, true, "Support the IL printer.")          \
-  C(support_reload, false, false, bool, true, "Support isolate reload.")       \
-  R(support_service, false, bool, true, "Support the service protocol.")       \
   D(trace_cha, bool, false, "Trace CHA operations")                            \
   R(trace_field_guards, false, bool, false, "Trace changes in field's cids.")  \
   D(trace_ic, bool, false, "Trace IC handling")                                \
diff --git a/runtime/vm/flags.cc b/runtime/vm/flags.cc
index 672cd68..d326235 100644
--- a/runtime/vm/flags.cc
+++ b/runtime/vm/flags.cc
@@ -487,9 +487,6 @@
 
 #ifndef PRODUCT
 void Flags::PrintFlagToJSONArray(JSONArray* jsarr, const Flag* flag) {
-  if (!FLAG_support_service) {
-    return;
-  }
   if (flag->IsUnrecognized() || flag->type_ == Flag::kFlagHandler ||
       flag->type_ == Flag::kOptionHandler) {
     return;
@@ -531,9 +528,6 @@
 }
 
 void Flags::PrintJSON(JSONStream* js) {
-  if (!FLAG_support_service) {
-    return;
-  }
   JSONObject jsobj(js);
   jsobj.AddProperty("type", "FlagList");
   JSONArray jsarr(&jsobj, "flags");
diff --git a/runtime/vm/heap/become.cc b/runtime/vm/heap/become.cc
index ef95366..936cbc5 100644
--- a/runtime/vm/heap/become.cc
+++ b/runtime/vm/heap/become.cc
@@ -294,11 +294,9 @@
   isolate->VisitObjectPointers(&pointer_visitor,
                                ValidationPolicy::kValidateFrames);
 #ifndef PRODUCT
-  if (FLAG_support_service) {
-    ObjectIdRing* ring = isolate->object_id_ring();
-    ASSERT(ring != NULL);
-    ring->VisitPointers(&pointer_visitor);
-  }
+  ObjectIdRing* ring = isolate->object_id_ring();
+  ASSERT(ring != NULL);
+  ring->VisitPointers(&pointer_visitor);
 #endif  // !PRODUCT
 
   // Weak persistent handles.
diff --git a/runtime/vm/heap/compactor.cc b/runtime/vm/heap/compactor.cc
index 743bcfd..06b9529 100644
--- a/runtime/vm/heap/compactor.cc
+++ b/runtime/vm/heap/compactor.cc
@@ -399,10 +399,8 @@
         }
 #ifndef PRODUCT
         case 5: {
-          if (FLAG_support_service) {
-            TIMELINE_FUNCTION_GC_DURATION(thread, "ForwardObjectIdRing");
-            isolate_->object_id_ring()->VisitPointers(compactor_);
-          }
+          TIMELINE_FUNCTION_GC_DURATION(thread, "ForwardObjectIdRing");
+          isolate_->object_id_ring()->VisitPointers(compactor_);
           break;
         }
 #endif  // !PRODUCT
diff --git a/runtime/vm/heap/heap.cc b/runtime/vm/heap/heap.cc
index 7f314f5..fafb257 100644
--- a/runtime/vm/heap/heap.cc
+++ b/runtime/vm/heap/heap.cc
@@ -979,7 +979,7 @@
          (type == kMarkSweep && gc_old_space_in_progress_) ||
          (type == kMarkCompact && gc_old_space_in_progress_));
 #ifndef PRODUCT
-  if (FLAG_support_service && Service::gc_stream.enabled() &&
+  if (Service::gc_stream.enabled() &&
       !Isolate::IsVMInternalIsolate(isolate())) {
     ServiceEvent event(isolate(), ServiceEvent::kGC);
     event.set_gc_stats(&stats_);
@@ -1139,22 +1139,4 @@
   isolate_->heap()->WriteProtectCode(true);
 }
 
-BumpAllocateScope::BumpAllocateScope(Thread* thread)
-    : ThreadStackResource(thread), no_reload_scope_(thread->isolate(), thread) {
-  ASSERT(!thread->bump_allocate());
-  // If the background compiler thread is not disabled, there will be a cycle
-  // between the symbol table lock and the old space data lock.
-  BackgroundCompiler::Disable(thread->isolate());
-  thread->heap()->WaitForMarkerTasks(thread);
-  thread->heap()->old_space()->AcquireDataLock();
-  thread->set_bump_allocate(true);
-}
-
-BumpAllocateScope::~BumpAllocateScope() {
-  ASSERT(thread()->bump_allocate());
-  thread()->set_bump_allocate(false);
-  thread()->heap()->old_space()->ReleaseDataLock();
-  BackgroundCompiler::Enable(thread()->isolate());
-}
-
 }  // namespace dart
diff --git a/runtime/vm/heap/heap.h b/runtime/vm/heap/heap.h
index 3f7d1b3..a9e2c05 100644
--- a/runtime/vm/heap/heap.h
+++ b/runtime/vm/heap/heap.h
@@ -275,6 +275,9 @@
   static bool IsAllocatableInNewSpace(intptr_t size) {
     return size <= kNewAllocatableSize;
   }
+  static bool IsAllocatableViaFreeLists(intptr_t size) {
+    return size < kAllocatablePageSize;
+  }
 
 #ifndef PRODUCT
   void PrintToJSONObject(Space space, JSONObject* object) const;
@@ -300,6 +303,7 @@
   }
 
   static const intptr_t kNewAllocatableSize = 256 * KB;
+  static const intptr_t kAllocatablePageSize = 64 * KB;
 
   intptr_t GetTLABSize() {
     // Inspired by V8 tlab size. More than threshold for old space allocation,
@@ -486,26 +490,6 @@
   Isolate* isolate_;
 };
 
-// This scope forces heap growth, forces use of the bump allocator, and
-// takes the page lock. It is useful e.g. at program startup when allocating
-// many objects into old gen (like libraries, classes, and functions).
-class BumpAllocateScope : ThreadStackResource {
- public:
-  explicit BumpAllocateScope(Thread* thread);
-  ~BumpAllocateScope();
-
- private:
-  // This is needed to avoid a GC while we hold the page lock, which would
-  // trigger a deadlock.
-  NoHeapGrowthControlScope no_growth_control_;
-
-  // A reload will try to allocate into new gen, which could trigger a
-  // scavenge and deadlock.
-  NoReloadScope no_reload_scope_;
-
-  DISALLOW_COPY_AND_ASSIGN(BumpAllocateScope);
-};
-
 #if defined(TESTING)
 class GCTestHelper : public AllStatic {
  public:
diff --git a/runtime/vm/heap/marker.cc b/runtime/vm/heap/marker.cc
index add8913..87d9c08 100644
--- a/runtime/vm/heap/marker.cc
+++ b/runtime/vm/heap/marker.cc
@@ -532,9 +532,6 @@
 
 void GCMarker::ProcessObjectIdTable(Thread* thread) {
 #ifndef PRODUCT
-  if (!FLAG_support_service) {
-    return;
-  }
   TIMELINE_FUNCTION_GC_DURATION(thread, "ProcessObjectIdTable");
   ObjectIdRingClearPointerVisitor visitor(isolate_);
   ObjectIdRing* ring = isolate_->object_id_ring();
diff --git a/runtime/vm/heap/pages.cc b/runtime/vm/heap/pages.cc
index 0f3be2e..a2659ad 100644
--- a/runtime/vm/heap/pages.cc
+++ b/runtime/vm/heap/pages.cc
@@ -461,7 +461,7 @@
                                         HeapPage::PageType type,
                                         GrowthPolicy growth_policy,
                                         bool is_locked) {
-  ASSERT(size < kAllocatablePageSize);
+  ASSERT(Heap::IsAllocatableViaFreeLists(size));
 
   EvaluateConcurrentMarking(growth_policy);
 
@@ -497,7 +497,7 @@
 uword PageSpace::TryAllocateInFreshLargePage(intptr_t size,
                                              HeapPage::PageType type,
                                              GrowthPolicy growth_policy) {
-  ASSERT(size >= kAllocatablePageSize);
+  ASSERT(!Heap::IsAllocatableViaFreeLists(size));
 
   EvaluateConcurrentMarking(growth_policy);
 
@@ -531,7 +531,7 @@
   ASSERT(size >= kObjectAlignment);
   ASSERT(Utils::IsAligned(size, kObjectAlignment));
   uword result = 0;
-  if (size < kAllocatablePageSize) {
+  if (Heap::IsAllocatableViaFreeLists(size)) {
     if (is_locked) {
       result = freelist_[type].TryAllocateLocked(size, is_protected);
     } else {
@@ -580,29 +580,14 @@
   usage_.external_in_words -= size_in_words;
 }
 
-// Provides exclusive access to all pages, and ensures they are walkable.
-class ExclusivePageIterator : ValueObject {
+class BasePageIterator : ValueObject {
  public:
-  explicit ExclusivePageIterator(const PageSpace* space)
-      : space_(space), ml_(&space->pages_lock_) {
-    space_->MakeIterable();
-    list_ = kRegular;
-    page_ = space_->pages_;
-    if (page_ == NULL) {
-      list_ = kExecutable;
-      page_ = space_->exec_pages_;
-      if (page_ == NULL) {
-        list_ = kLarge;
-        page_ = space_->large_pages_;
-        if (page_ == NULL) {
-          list_ = kImage;
-          page_ = space_->image_pages_;
-        }
-      }
-    }
-  }
+  explicit BasePageIterator(const PageSpace* space) : space_(space) {}
+
   HeapPage* page() const { return page_; }
+
   bool Done() const { return page_ == NULL; }
+
   void Advance() {
     ASSERT(!Done());
     page_ = page_->next();
@@ -621,14 +606,52 @@
     ASSERT((page_ != NULL) || (list_ == kImage));
   }
 
- private:
+ protected:
   enum List { kRegular, kExecutable, kLarge, kImage };
 
-  const PageSpace* space_;
+  void Initialize() {
+    list_ = kRegular;
+    page_ = space_->pages_;
+    if (page_ == NULL) {
+      list_ = kExecutable;
+      page_ = space_->exec_pages_;
+      if (page_ == NULL) {
+        list_ = kLarge;
+        page_ = space_->large_pages_;
+        if (page_ == NULL) {
+          list_ = kImage;
+          page_ = space_->image_pages_;
+        }
+      }
+    }
+  }
+
+  const PageSpace* space_ = nullptr;
+  List list_;
+  HeapPage* page_ = nullptr;
+};
+
+// Provides unsafe access to all pages. Assumes pages are walkable.
+class UnsafeExclusivePageIterator : public BasePageIterator {
+ public:
+  explicit UnsafeExclusivePageIterator(const PageSpace* space)
+      : BasePageIterator(space) {
+    Initialize();
+  }
+};
+
+// Provides exclusive access to all pages, and ensures they are walkable.
+class ExclusivePageIterator : public BasePageIterator {
+ public:
+  explicit ExclusivePageIterator(const PageSpace* space)
+      : BasePageIterator(space), ml_(&space->pages_lock_) {
+    space_->MakeIterable();
+    Initialize();
+  }
+
+ private:
   MutexLocker ml_;
   NoSafepointScope no_safepoint;
-  List list_;
-  HeapPage* page_;
 };
 
 // Provides exclusive access to code pages, and ensures they are walkable.
@@ -712,6 +735,15 @@
   return false;
 }
 
+bool PageSpace::ContainsUnsafe(uword addr) const {
+  for (UnsafeExclusivePageIterator it(this); !it.Done(); it.Advance()) {
+    if (it.page()->Contains(addr)) {
+      return true;
+    }
+  }
+  return false;
+}
+
 bool PageSpace::Contains(uword addr, HeapPage::PageType type) const {
   if (type == HeapPage::kExecutable) {
     // Fast path executable pages.
@@ -827,9 +859,6 @@
 
 #ifndef PRODUCT
 void PageSpace::PrintToJSONObject(JSONObject* object) const {
-  if (!FLAG_support_service) {
-    return;
-  }
   Isolate* isolate = Isolate::Current();
   ASSERT(isolate != NULL);
   JSONObject space(object, "old");
@@ -868,9 +897,6 @@
 
 void PageSpace::PrintHeapMapToJSONStream(Isolate* isolate,
                                          JSONStream* stream) const {
-  if (!FLAG_support_service) {
-    return;
-  }
   JSONObject heap_map(stream);
   heap_map.AddProperty("type", "HeapMap");
   heap_map.AddProperty("freeClassId", static_cast<intptr_t>(kFreeListElement));
@@ -1260,7 +1286,7 @@
   intptr_t remaining = bump_end_ - bump_top_;
   if (UNLIKELY(remaining < size)) {
     // Checking this first would be logical, but needlessly slow.
-    if (size >= kAllocatablePageSize) {
+    if (!Heap::IsAllocatableViaFreeLists(size)) {
       return TryAllocateDataLocked(size, kForceGrowth);
     }
     FreeListElement* block =
diff --git a/runtime/vm/heap/pages.h b/runtime/vm/heap/pages.h
index 836b2ed..d8ee959 100644
--- a/runtime/vm/heap/pages.h
+++ b/runtime/vm/heap/pages.h
@@ -339,6 +339,7 @@
   }
 
   bool Contains(uword addr) const;
+  bool ContainsUnsafe(uword addr) const;
   bool Contains(uword addr, HeapPage::PageType type) const;
   bool DataContains(uword addr) const;
   bool IsValidAddress(uword addr) const { return Contains(addr); }
@@ -466,8 +467,6 @@
     kAllowedGrowth = 3
   };
 
-  static const intptr_t kAllocatablePageSize = 64 * KB;
-
   uword TryAllocateInternal(intptr_t size,
                             HeapPage::PageType type,
                             GrowthPolicy growth_policy,
@@ -568,6 +567,7 @@
 
   bool enable_concurrent_mark_;
 
+  friend class BasePageIterator;
   friend class ExclusivePageIterator;
   friend class ExclusiveCodePageIterator;
   friend class ExclusiveLargePageIterator;
diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc
index 0c15bb8..1c3048b 100644
--- a/runtime/vm/heap/scavenger.cc
+++ b/runtime/vm/heap/scavenger.cc
@@ -638,9 +638,6 @@
 void Scavenger::IterateObjectIdTable(Isolate* isolate,
                                      ScavengerVisitor* visitor) {
 #ifndef PRODUCT
-  if (!FLAG_support_service) {
-    return;
-  }
   isolate->object_id_ring()->VisitPointers(visitor);
 #endif  // !PRODUCT
 }
@@ -1109,9 +1106,6 @@
 
 #ifndef PRODUCT
 void Scavenger::PrintToJSONObject(JSONObject* object) const {
-  if (!FLAG_support_service) {
-    return;
-  }
   Isolate* isolate = Isolate::Current();
   ASSERT(isolate != NULL);
   JSONObject space(object, "new");
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 0faf778..8fc58d9 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -19,6 +19,7 @@
 #include "vm/dart_entry.h"
 #include "vm/debugger.h"
 #include "vm/deopt_instructions.h"
+#include "vm/dispatch_table.h"
 #include "vm/flags.h"
 #include "vm/heap/heap.h"
 #include "vm/heap/pointer_block.h"
@@ -166,11 +167,18 @@
 }
 
 void IdleTimeHandler::NotifyIdle(int64_t deadline) {
-  MutexLocker ml(&mutex_, /*no_safepoint_scope=*/false);
+  {
+    MutexLocker ml(&mutex_);
+    disabled_counter_++;
+  }
   if (heap_ != nullptr) {
     heap_->NotifyIdle(deadline);
   }
-  idle_start_time_ = 0;
+  {
+    MutexLocker ml(&mutex_);
+    disabled_counter_--;
+    idle_start_time_ = 0;
+  }
 }
 
 void IdleTimeHandler::NotifyIdleUsingDefaultDeadline() {
@@ -381,17 +389,11 @@
 
 #ifndef PRODUCT
 void IsolateGroup::PrintJSON(JSONStream* stream, bool ref) {
-  if (!FLAG_support_service) {
-    return;
-  }
   JSONObject jsobj(stream);
   PrintToJSONObject(&jsobj, ref);
 }
 
 void IsolateGroup::PrintToJSONObject(JSONObject* jsobj, bool ref) {
-  if (!FLAG_support_service) {
-    return;
-  }
   jsobj->AddProperty("type", (ref ? "@IsolateGroup" : "IsolateGroup"));
   jsobj->AddServiceId(ISOLATE_GROUP_SERVICE_ID_FORMAT_STRING, id());
 
@@ -411,9 +413,6 @@
 }
 
 void IsolateGroup::PrintMemoryUsageJSON(JSONStream* stream) {
-  if (!FLAG_support_service) {
-    return;
-  }
   int64_t used = 0;
   int64_t capacity = 0;
   int64_t external_used = 0;
@@ -930,15 +929,15 @@
         if (oob_tag.IsSmi()) {
           switch (Smi::Cast(oob_tag).Value()) {
             case Message::kServiceOOBMsg: {
-              if (FLAG_support_service) {
-                const Error& error =
-                    Error::Handle(Service::HandleIsolateMessage(I, oob_msg));
-                if (!error.IsNull()) {
-                  status = ProcessUnhandledException(error);
-                }
-              } else {
-                UNREACHABLE();
+#ifndef PRODUCT
+              const Error& error =
+                  Error::Handle(Service::HandleIsolateMessage(I, oob_msg));
+              if (!error.IsNull()) {
+                status = ProcessUnhandledException(error);
               }
+#else
+              UNREACHABLE();
+#endif
               break;
             }
             case Message::kIsolateLibOOBMsg: {
@@ -1001,7 +1000,7 @@
 
 #ifndef PRODUCT
 void IsolateMessageHandler::NotifyPauseOnStart() {
-  if (!FLAG_support_service || Isolate::IsVMInternalIsolate(I)) {
+  if (Isolate::IsVMInternalIsolate(I)) {
     return;
   }
   if (Service::debug_stream.enabled() || FLAG_warn_on_pause_with_no_debugger) {
@@ -1017,7 +1016,7 @@
 }
 
 void IsolateMessageHandler::NotifyPauseOnExit() {
-  if (!FLAG_support_service || Isolate::IsVMInternalIsolate(I)) {
+  if (Isolate::IsVMInternalIsolate(I)) {
     return;
   }
   if (Service::debug_stream.enabled() || FLAG_warn_on_pause_with_no_debugger) {
@@ -1307,6 +1306,9 @@
   delete reverse_pc_lookup_cache_;
   reverse_pc_lookup_cache_ = nullptr;
 
+  delete dispatch_table_;
+  dispatch_table_ = nullptr;
+
   if (FLAG_enable_interpreter) {
     delete background_compiler_;
     background_compiler_ = nullptr;
@@ -1318,9 +1320,7 @@
 #if !defined(PRODUCT)
   delete debugger_;
   debugger_ = nullptr;
-  if (FLAG_support_service) {
-    delete object_id_ring_;
-  }
+  delete object_id_ring_;
   object_id_ring_ = nullptr;
   delete pause_loop_monitor_;
   pause_loop_monitor_ = nullptr;
@@ -1472,9 +1472,7 @@
   }
 
 #ifndef PRODUCT
-  if (FLAG_support_service) {
-    ObjectIdRing::Init(result);
-  }
+  ObjectIdRing::Init(result);
 #endif  // !PRODUCT
 
   // Add to isolate list. Shutdown and delete the isolate on failure.
@@ -1700,7 +1698,7 @@
   }
 #endif
 #ifndef PRODUCT
-  if (FLAG_support_service && !Isolate::IsVMInternalIsolate(this) &&
+  if (!Isolate::IsVMInternalIsolate(this) &&
       Service::isolate_stream.enabled()) {
     ServiceEvent runnableEvent(this, ServiceEvent::kIsolateRunnable);
     Service::HandleEvent(&runnableEvent);
@@ -2528,9 +2526,6 @@
 }
 
 void Isolate::PrintJSON(JSONStream* stream, bool ref) {
-  if (!FLAG_support_service) {
-    return;
-  }
   JSONObject jsobj(stream);
   jsobj.AddProperty("type", (ref ? "@Isolate" : "Isolate"));
   jsobj.AddServiceId(ISOLATE_SERVICE_ID_FORMAT_STRING,
@@ -2680,9 +2675,6 @@
 }
 
 void Isolate::PrintMemoryUsageJSON(JSONStream* stream) {
-  if (!FLAG_support_service) {
-    return;
-  }
   heap()->PrintMemoryUsageJSON(stream);
 }
 
@@ -2774,9 +2766,6 @@
 
 #ifndef PRODUCT
 RawError* Isolate::InvokePendingServiceExtensionCalls() {
-  if (!FLAG_support_service) {
-    return Error::null();
-  }
   GrowableObjectArray& calls =
       GrowableObjectArray::Handle(GetAndClearPendingServiceExtensionCalls());
   if (calls.IsNull()) {
@@ -2911,7 +2900,7 @@
 // done atomically.
 void Isolate::RegisterServiceExtensionHandler(const String& name,
                                               const Instance& closure) {
-  if (!FLAG_support_service || Isolate::IsVMInternalIsolate(this)) {
+  if (Isolate::IsVMInternalIsolate(this)) {
     return;
   }
   GrowableObjectArray& handlers =
@@ -2945,9 +2934,6 @@
 // to Dart code unless you can ensure that the operations will can be
 // done atomically.
 RawInstance* Isolate::LookupServiceExtensionHandler(const String& name) {
-  if (!FLAG_support_service) {
-    return Instance::null();
-  }
   const GrowableObjectArray& handlers =
       GrowableObjectArray::Handle(registered_service_extension_handlers());
   if (handlers.IsNull()) {
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index bab82c1..7a74bcc 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -46,6 +46,7 @@
 class CodeIndexTable;
 class Debugger;
 class DeoptContext;
+class DispatchTable;
 class ExternalTypedData;
 class HandleScope;
 class HandleVisitor;
@@ -966,6 +967,9 @@
   void set_obfuscation_map(const char** map) { obfuscation_map_ = map; }
   const char** obfuscation_map() const { return obfuscation_map_; }
 
+  const DispatchTable* dispatch_table() const { return dispatch_table_; }
+  void set_dispatch_table(DispatchTable* table) { dispatch_table_ = table; }
+
   // Returns the pc -> code lookup cache object for this isolate.
   ReversePcLookupCache* reverse_pc_lookup_cache() const {
     return reverse_pc_lookup_cache_;
@@ -1292,6 +1296,7 @@
   Dart_QualifiedFunctionName* embedder_entry_points_ = nullptr;
   const char** obfuscation_map_ = nullptr;
 
+  DispatchTable* dispatch_table_ = nullptr;
   ReversePcLookupCache* reverse_pc_lookup_cache_ = nullptr;
 
   // Used during message sending of messages between isolates.
diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc
index 4616efa..5d973a1 100644
--- a/runtime/vm/isolate_reload.cc
+++ b/runtime/vm/isolate_reload.cc
@@ -487,7 +487,7 @@
   // TODO(dartbug.com/36097): We need to change the "reloadSources" service-api
   // call to accept an isolate group instead of an isolate.
   Isolate* isolate = Isolate::Current();
-  if (!FLAG_support_service || Isolate::IsVMInternalIsolate(isolate)) {
+  if (Isolate::IsVMInternalIsolate(isolate)) {
     return;
   }
   TIR_Print("ISO-RELOAD: Error: %s\n", error.ToErrorCString());
@@ -500,7 +500,7 @@
   // TODO(dartbug.com/36097): We need to change the "reloadSources" service-api
   // call to accept an isolate group instead of an isolate.
   Isolate* isolate = Isolate::Current();
-  if (!FLAG_support_service || Isolate::IsVMInternalIsolate(isolate)) {
+  if (Isolate::IsVMInternalIsolate(isolate)) {
     return;
   }
   ServiceEvent service_event(isolate, ServiceEvent::kIsolateReload);
diff --git a/runtime/vm/isolate_reload_test.cc b/runtime/vm/isolate_reload_test.cc
index ac5ae44..fab8c65 100644
--- a/runtime/vm/isolate_reload_test.cc
+++ b/runtime/vm/isolate_reload_test.cc
@@ -2973,7 +2973,7 @@
   EXPECT_STREQ("true", SimpleInvokeStr(lib, "main"));
 }
 
-TEST_CASE(IsolateReload_ShapeChangeConstReferencedByInstructions) {
+TEST_CASE(IsolateReload_ShapeChange_Const_AddSlot) {
   // On IA32, instructions can contain direct pointers to const objects. We need
   // to be careful that if the const objects are reallocated because of a shape
   // change, they are allocated old. Because instructions normally contain
@@ -2999,30 +2999,100 @@
   EXPECT_VALID(lib);
   EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
 
-  // Flip the size back and forth a few times.
-  for (intptr_t i = 0; i < 3; i++) {
-    const char* kReloadScript = R"(
-      import 'file:///test:isolate_reload_helper';
-      class A {
-        final x, y, z;
-        const A(this.x, this.y, this.z);
-      }
-      var a;
-      main() {
-        a = const A(1, null, null);
-        collectNewSpace();
-        return 'okay';
-      }
-    )";
+  const char* kReloadScript = R"(
+    import 'file:///test:isolate_reload_helper';
+    class A {
+      final x, y, z;
+      const A(this.x, this.y, this.z);
+    }
+    var a;
+    main() {
+      a = const A(1, null, null);
+      collectNewSpace();
+      return 'okay';
+    }
+  )";
 
-    lib = TestCase::ReloadTestScript(kReloadScript);
-    EXPECT_VALID(lib);
-    EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
 
-    lib = TestCase::ReloadTestScript(kScript);
-    EXPECT_VALID(lib);
-    EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
-  }
+  const char* kReloadScript2 = R"(
+    import 'file:///test:isolate_reload_helper';
+    class A {
+      final x, y, z, w, u;
+      const A(this.x, this.y, this.z, this.w, this.u);
+    }
+    var a;
+    main() {
+      a = const A(1, null, null, null, null);
+      collectNewSpace();
+      return 'okay';
+    }
+  )";
+
+  lib = TestCase::ReloadTestScript(kReloadScript2);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
+}
+
+TEST_CASE(IsolateReload_ShapeChange_Const_RemoveSlot) {
+  const char* kScript = R"(
+    import 'file:///test:isolate_reload_helper';
+    class A {
+      final x, y, z;
+      const A(this.x, this.y, this.z);
+    }
+    var a;
+    main() {
+      a = const A(1, 2, 3);
+      collectNewSpace();
+      return 'okay';
+    }
+  )";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
+
+  const char* kReloadScript = R"(
+    import 'file:///test:isolate_reload_helper';
+    class A {
+      final x, y;
+      const A(this.x, this.y);
+    }
+    var a;
+    main() {
+      a = const A(1, null);
+      collectNewSpace();
+      return 'okay';
+    }
+  )";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_ERROR(lib,
+               "Const class cannot remove fields: "
+               "Library:'file:///test-lib' Class: A");
+
+  // Rename is seen by the VM is unrelated add and remove.
+  const char* kReloadScript2 = R"(
+    import 'file:///test:isolate_reload_helper';
+    class A {
+      final x, y, w;
+      const A(this.x, this.y, this.w);
+    }
+    var a;
+    main() {
+      a = const A(1, null, null);
+      collectNewSpace();
+      return 'okay';
+    }
+  )";
+
+  lib = TestCase::ReloadTestScript(kReloadScript2);
+  EXPECT_ERROR(lib,
+               "Const class cannot remove fields: "
+               "Library:'file:///test-lib' Class: A");
 }
 
 TEST_CASE(IsolateReload_ConstToNonConstClass) {
@@ -3059,6 +3129,39 @@
                "Library:'file:///test-lib' Class: A");
 }
 
+TEST_CASE(IsolateReload_ConstToNonConstClass_Empty) {
+  const char* kScript = R"(
+    class A {
+      const A();
+    }
+    dynamic a;
+    main() {
+      a = const A();
+      return 'okay';
+    }
+  )";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
+
+  const char* kReloadScript = R"(
+    class A {
+      dynamic x;
+      A(this.x);
+    }
+    dynamic a;
+    main() {
+      a.x = 10;
+    }
+  )";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_ERROR(lib,
+               "Const class cannot become non-const: "
+               "Library:'file:///test-lib' Class: A");
+}
+
 TEST_CASE(IsolateReload_StaticTearOffRetainsHash) {
   const char* kScript =
       "foo() {}\n"
diff --git a/runtime/vm/kernel.cc b/runtime/vm/kernel.cc
index c971495..e1cb029 100644
--- a/runtime/vm/kernel.cc
+++ b/runtime/vm/kernel.cc
@@ -798,21 +798,42 @@
   return attrs;
 }
 
+static void BytecodeProcedureAttributesError(const Object& function_or_field,
+                                             const Object& value) {
+  FATAL3("Unexpected value of %s bytecode attribute on %s: %s",
+         Symbols::vm_procedure_attributes_metadata().ToCString(),
+         function_or_field.ToCString(), value.ToCString());
+}
+
 static ProcedureAttributesMetadata ProcedureAttributesFromBytecodeAttribute(
     Zone* zone,
     const Object& function_or_field) {
   ProcedureAttributesMetadata attrs;
-  const auto& value = Object::Handle(
+  const Object& value = Object::Handle(
       zone,
       BytecodeReader::GetBytecodeAttribute(
           function_or_field, Symbols::vm_procedure_attributes_metadata()));
   if (!value.IsNull()) {
-    if (!value.IsSmi()) {
-      FATAL3("Unexpected value of %s bytecode attribute on %s: %s",
-             Symbols::vm_procedure_attributes_metadata().ToCString(),
-             function_or_field.ToCString(), value.ToCString());
+    const intptr_t kBytecodeAttributeLength = 3;
+    int32_t elements[kBytecodeAttributeLength];
+    if (!value.IsArray()) {
+      BytecodeProcedureAttributesError(function_or_field, value);
     }
-    attrs.InitializeFromFlags(Smi::Cast(value).Value());
+    const Array& array = Array::Cast(value);
+    if (array.Length() != kBytecodeAttributeLength) {
+      BytecodeProcedureAttributesError(function_or_field, value);
+    }
+    Object& element = Object::Handle(zone);
+    for (intptr_t i = 0; i < kBytecodeAttributeLength; i++) {
+      element = array.At(i);
+      if (!element.IsSmi()) {
+        BytecodeProcedureAttributesError(function_or_field, value);
+      }
+      elements[i] = Smi::Cast(element).Value();
+    }
+    attrs.InitializeFromFlags(elements[0]);
+    attrs.method_or_setter_selector_id = elements[1];
+    attrs.getter_selector_id = elements[2];
   }
   return attrs;
 }
@@ -820,6 +841,10 @@
 ProcedureAttributesMetadata ProcedureAttributesOf(const Function& function,
                                                   Zone* zone) {
   if (function.is_declared_in_bytecode()) {
+    if (function.IsImplicitGetterOrSetter()) {
+      const Field& field = Field::Handle(zone, function.accessor_field());
+      return ProcedureAttributesFromBytecodeAttribute(zone, field);
+    }
     return ProcedureAttributesFromBytecodeAttribute(zone, function);
   }
   const Script& script = Script::Handle(zone, function.script());
diff --git a/runtime/vm/kernel_binary.h b/runtime/vm/kernel_binary.h
index 2a68fe5..187d3c0 100644
--- a/runtime/vm/kernel_binary.h
+++ b/runtime/vm/kernel_binary.h
@@ -171,6 +171,19 @@
   kLegacyCovariant = 4,
 };
 
+// Keep in sync with package:kernel/lib/ast.dart
+enum AsExpressionFlags {
+  kAsExpressionFlagTypeError = 1 << 0,
+  kAsExpressionFlagCovarianceCheck = 1 << 1,
+  kAsExpressionFlagForDynamic = 1 << 2,
+  kAsExpressionFlagForNonNullableByDefault = 1 << 3,
+};
+
+// Keep in sync with package:kernel/lib/ast.dart
+enum IsExpressionFlags {
+  kIsExpressionFlagForNonNullableByDefault = 1 << 0,
+};
+
 static const int SpecializedIntLiteralBias = 3;
 static const int LibraryCountFieldCountFromEnd = 1;
 static const int SourceTableFieldCountFromFirstLibraryOffset = 6;
diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc
index bd81e37..b783ee8 100644
--- a/runtime/vm/kernel_loader.cc
+++ b/runtime/vm/kernel_loader.cc
@@ -957,8 +957,10 @@
          (field.guarded_cid() == kFloat32x4Cid &&
           FlowGraphCompiler::SupportsUnboxedSimd128()) ||
          (field.guarded_cid() == kFloat64x2Cid &&
-          FlowGraphCompiler::SupportsUnboxedSimd128())) &&
+          FlowGraphCompiler::SupportsUnboxedSimd128()) ||
+         type.IsInt()) &&
         !field.is_nullable());
+    field.set_is_non_nullable_integer(!field.is_nullable() && type.IsInt());
   }
 }
 
@@ -2119,6 +2121,13 @@
   }
   ASSERT(field.NeedsGetter());
 
+  if (field.is_late() && field.has_nontrivial_initializer()) {
+    // Late fields are initialized to Object::sentinel, which is a flavor of
+    // null. So we need to record that store so that the field guard doesn't
+    // prematurely optimise out the late field's sentinel checking logic.
+    field.RecordStore(Object::null_object());
+  }
+
   const String& getter_name = H.DartGetterName(field_helper->canonical_name_);
   const Object& script_class =
       ClassForScriptAt(klass, field_helper->source_uri_index_);
diff --git a/runtime/vm/lockers.cc b/runtime/vm/lockers.cc
index ca5c671..b5bd727 100644
--- a/runtime/vm/lockers.cc
+++ b/runtime/vm/lockers.cc
@@ -46,12 +46,8 @@
     // accordingly.
     Thread* thread = Thread::Current();
     if (thread != NULL) {
-      thread->set_execution_state(Thread::kThreadInBlockedState);
-      thread->EnterSafepoint();
+      TransitionVMToBlocked transition(thread);
       mutex->Lock();
-      // Update thread state and block if a safepoint operation is in progress.
-      thread->ExitSafepoint();
-      thread->set_execution_state(Thread::kThreadInVM);
     } else {
       mutex->Lock();
     }
@@ -66,12 +62,8 @@
     // accordingly.
     Thread* thread = Thread::Current();
     if (thread != NULL) {
-      thread->set_execution_state(Thread::kThreadInBlockedState);
-      thread->EnterSafepoint();
+      TransitionVMToBlocked transition(thread);
       monitor_->Enter();
-      // Update thread state and block if a safepoint operation is in progress.
-      thread->ExitSafepoint();
-      thread->set_execution_state(Thread::kThreadInVM);
     } else {
       monitor_->Enter();
     }
@@ -81,20 +73,11 @@
 Monitor::WaitResult SafepointMonitorLocker::Wait(int64_t millis) {
   Thread* thread = Thread::Current();
   if (thread != NULL) {
-    thread->set_execution_state(Thread::kThreadInBlockedState);
-    thread->EnterSafepoint();
-    Monitor::WaitResult result = monitor_->Wait(millis);
-    // First try a fast update of the thread state to indicate it is not at a
-    // safepoint anymore.
-    if (!thread->TryExitSafepoint()) {
-      // Fast update failed which means we could potentially be in the middle
-      // of a safepoint operation and need to block for it.
-      monitor_->Exit();
-      SafepointHandler* handler = thread->isolate()->safepoint_handler();
-      handler->ExitSafepointUsingLock(thread);
-      monitor_->Enter();
+    Monitor::WaitResult result;
+    {
+      TransitionVMToBlocked transition(thread);
+      result = monitor_->Wait(millis);
     }
-    thread->set_execution_state(Thread::kThreadInVM);
     return result;
   } else {
     return monitor_->Wait(millis);
diff --git a/runtime/vm/message.cc b/runtime/vm/message.cc
index 0bfca6d..59c1917 100644
--- a/runtime/vm/message.cc
+++ b/runtime/vm/message.cc
@@ -217,9 +217,6 @@
 
 void MessageQueue::PrintJSON(JSONStream* stream) {
 #ifndef PRODUCT
-  if (!FLAG_support_service) {
-    return;
-  }
   JSONArray messages(stream);
 
   Object& msg_handler = Object::Handle();
diff --git a/runtime/vm/metrics.cc b/runtime/vm/metrics.cc
index c20cfc7..6194760 100644
--- a/runtime/vm/metrics.cc
+++ b/runtime/vm/metrics.cc
@@ -89,9 +89,6 @@
 }
 
 void Metric::PrintJSON(JSONStream* stream) {
-  if (!FLAG_support_service) {
-    return;
-  }
   JSONObject obj(stream);
   obj.AddProperty("type", "Counter");
   obj.AddProperty("name", name_);
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index f4e7894..bb16eb8 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -93,11 +93,6 @@
 DECLARE_FLAG(bool, precompiled_mode);
 DECLARE_FLAG(int, max_polymorphic_checks);
 
-DEFINE_FLAG(bool,
-            unbox_numeric_fields,
-            true,
-            "Support unboxed double and float32x4 fields.");
-
 static const char* const kGetterPrefix = "get:";
 static const intptr_t kGetterPrefixLength = strlen(kGetterPrefix);
 static const char* const kSetterPrefix = "set:";
@@ -1046,7 +1041,13 @@
   void_type_->SetCanonical();
 
   cls = never_class_;
-  *never_type_ = Type::NewNonParameterizedType(cls);
+  *never_type_ =
+      Type::New(cls, Object::null_type_arguments(), TokenPosition::kNoSource,
+                Dart::non_nullable_flag() ? Nullability::kNonNullable
+                                          : Nullability::kLegacy);
+  never_type_->SetIsFinalized();
+  never_type_->ComputeHash();
+  never_type_->SetCanonical();
 
   // Since TypeArguments objects are passed as function arguments, make them
   // behave as Dart instances, although they are just VM objects.
@@ -2456,10 +2457,31 @@
       cur += compiler::target::kWordSize;
     }
   } else {
-    uword initial_value = reinterpret_cast<uword>(null_);
-    while (cur < end) {
-      *reinterpret_cast<uword*>(cur) = initial_value;
-      cur += kWordSize;
+    uword initial_value;
+    bool needs_init;
+    if (RawObject::IsTypedDataBaseClassId(class_id)) {
+      initial_value = 0;
+      // If the size is greater than both kNewAllocatableSize and
+      // kAllocatablePageSize, the object must have been allocated to a new
+      // large page, which must already have been zero initialized by the OS.
+      needs_init = Heap::IsAllocatableInNewSpace(size) ||
+                   Heap::IsAllocatableViaFreeLists(size);
+    } else {
+      initial_value = reinterpret_cast<uword>(null_);
+      needs_init = true;
+    }
+    if (needs_init) {
+      while (cur < end) {
+        *reinterpret_cast<uword*>(cur) = initial_value;
+        cur += kWordSize;
+      }
+    } else {
+#if defined(DEBUG)
+      while (cur < end) {
+        ASSERT(*reinterpret_cast<uword*>(cur) == initial_value);
+        cur += kWordSize;
+      }
+#endif
     }
   }
   uint32_t tags = 0;
@@ -2509,15 +2531,7 @@
   ASSERT(thread->no_callback_scope_depth() == 0);
   Heap* heap = thread->heap();
 
-  uword address;
-
-  // In a bump allocation scope, all allocations go into old space.
-  if (thread->bump_allocate() && (space != Heap::kCode)) {
-    DEBUG_ASSERT(heap->old_space()->CurrentThreadOwnsDataLock());
-    address = heap->old_space()->TryAllocateDataBumpLocked(size);
-  } else {
-    address = heap->Allocate(size, space);
-  }
+  uword address = heap->Allocate(size, space);
   if (UNLIKELY(address == 0)) {
     if (thread->top_exit_frame_info() != 0) {
       // Use the preallocated out of memory exception to avoid calling
@@ -3239,8 +3253,12 @@
             field_size = sizeof(RawFloat64x2::value_);
             break;
           default:
-            UNREACHABLE();
-            field_size = 0;
+            if (field.is_non_nullable_integer()) {
+              field_size = sizeof(RawMint::value_);
+            } else {
+              UNREACHABLE();
+              field_size = 0;
+            }
             break;
         }
 
@@ -5607,7 +5625,7 @@
 bool TypeArguments::IsSubvectorEquivalent(const TypeArguments& other,
                                           intptr_t from_index,
                                           intptr_t len,
-                                          bool syntactically,
+                                          TypeEquality kind,
                                           TrailPtr trail) const {
   if (this->raw() == other.raw()) {
     return true;
@@ -5625,7 +5643,7 @@
     type = TypeAt(i);
     other_type = other.TypeAt(i);
     // Still unfinalized vectors should not be considered equivalent.
-    if (type.IsNull() || !type.IsEquivalent(other_type, syntactically, trail)) {
+    if (type.IsNull() || !type.IsEquivalent(other_type, kind, trail)) {
       return false;
     }
   }
@@ -7703,7 +7721,8 @@
   return other_param_type.IsSubtypeOf(mode, param_type, space);
 }
 
-bool Function::HasSameTypeParametersAndBounds(const Function& other) const {
+bool Function::HasSameTypeParametersAndBounds(const Function& other,
+                                              TypeEquality kind) const {
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
 
@@ -7729,10 +7748,7 @@
       ASSERT(bound.IsFinalized());
       other_bound = other_type_param.bound();
       ASSERT(other_bound.IsFinalized());
-      // TODO(dartbug.com/40259): Treat top types as equivalent and disregard
-      // nullability in weak mode.
-      const bool syntactically = !FLAG_strong_non_nullable_type_checks;
-      if (!bound.IsEquivalent(other_bound, syntactically)) {
+      if (!bound.IsEquivalent(other_bound, kind)) {
         return false;
       }
     }
@@ -7767,7 +7783,8 @@
     return false;
   }
   // Check the type parameters and bounds of generic functions.
-  if (!HasSameTypeParametersAndBounds(other)) {
+  if (!HasSameTypeParametersAndBounds(other,
+                                      TypeEquality::kSubtypeNullability)) {
     return false;
   }
   Thread* thread = Thread::Current();
@@ -8763,6 +8780,48 @@
   return CurrentCode();
 }
 
+bool Function::NeedsMonomorphicCheckedEntry(Zone* zone) const {
+#if !defined(DART_PRECOMPILED_RUNTIME)
+  if (!IsDynamicFunction()) {
+    return false;
+  }
+
+  // For functions which need an args descriptor the switchable call sites will
+  // transition directly to calling via a stub (and therefore never call the
+  // monomorphic entry).
+  //
+  // See runtime_entry.cc:DEFINE_RUNTIME_ENTRY(UnlinkedCall)
+  if (HasOptionalParameters() || IsGeneric()) {
+    return false;
+  }
+
+  // If table dispatch is disabled, all instance calls use switchable calls.
+  if (!(FLAG_precompiled_mode && FLAG_use_bare_instructions &&
+        FLAG_use_table_dispatch)) {
+    return true;
+  }
+
+  // Method extractors are always called dynamically (for now).
+  // See dartbug.com/40188.
+  if (IsMethodExtractor()) {
+    return true;
+  }
+
+  // Use the results of TFA to determine whether this function is ever
+  // called dynamically, i.e. using switchable calls.
+  kernel::ProcedureAttributesMetadata metadata;
+  metadata = kernel::ProcedureAttributesOf(*this, zone);
+  if (IsGetterFunction() || IsImplicitGetterFunction()) {
+    return metadata.getter_called_dynamically;
+  } else {
+    return metadata.method_or_setter_called_dynamically;
+  }
+#else
+  UNREACHABLE();
+  return true;
+#endif
+}
+
 bool Function::MayHaveUncheckedEntryPoint(Isolate* I) const {
   return FLAG_enable_multiple_entrypoints &&
          (NeedsArgumentTypeChecks(I) || IsImplicitClosureFunction());
@@ -8989,7 +9048,7 @@
 }
 
 const Object* Field::CloneForUnboxed(const Object& value) const {
-  if (FLAG_unbox_numeric_fields && is_unboxing_candidate() && !is_nullable()) {
+  if (is_unboxing_candidate() && !is_nullable()) {
     switch (guarded_cid()) {
       case kDoubleCid:
       case kFloat32x4Cid:
@@ -12185,7 +12244,7 @@
   Isolate* isolate = thread->isolate();
 
 #if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
-  if (FLAG_support_reload && isolate->group()->IsReloading()) {
+  if (isolate->group()->IsReloading()) {
     // When reloading, we need to make sure we use the original private key
     // if this library previously existed.
     IsolateReloadContext* reload_context = isolate->reload_context();
@@ -17237,8 +17296,13 @@
         return Float64x2::New(
             *reinterpret_cast<simd128_value_t*>(FieldAddr(field)));
       default:
-        UNREACHABLE();
-        return nullptr;
+        if (field.is_non_nullable_integer()) {
+          return Integer::New(
+              LoadNonPointer(reinterpret_cast<int64_t*>(FieldAddr(field))));
+        } else {
+          UNREACHABLE();
+          return nullptr;
+        }
     }
   } else {
     return *FieldAddr(field);
@@ -17261,7 +17325,12 @@
                         Float64x2::Cast(value).value());
         break;
       default:
-        UNREACHABLE();
+        if (field.is_non_nullable_integer()) {
+          StoreNonPointer(reinterpret_cast<int64_t*>(FieldAddr(field)),
+                          Integer::Cast(value).AsInt64Value());
+        } else {
+          UNREACHABLE();
+        }
         break;
     }
   } else {
@@ -17912,7 +17981,7 @@
 }
 
 bool AbstractType::IsEquivalent(const Instance& other,
-                                bool syntactically,
+                                TypeEquality kind,
                                 TrailPtr trail) const {
   // AbstractType is an abstract class.
   UNREACHABLE();
@@ -18352,7 +18421,8 @@
     const TypeParameter& type_param = TypeParameter::Cast(*this);
     if (other.IsTypeParameter()) {
       const TypeParameter& other_type_param = TypeParameter::Cast(other);
-      if (type_param.Equals(other_type_param)) {
+      if (type_param.IsEquivalent(other_type_param,
+                                  TypeEquality::kSubtypeNullability)) {
         return true;
       }
       if (type_param.IsFunctionTypeParameter() &&
@@ -18371,6 +18441,10 @@
         const int other_offset = other_sig_fun.NumParentTypeParameters();
         if (type_param.index() - offset ==
             other_type_param.index() - other_offset) {
+          if (FLAG_strong_non_nullable_type_checks && type_param.IsNullable() &&
+              other_type_param.IsNonNullable()) {
+            return false;
+          }
           return true;
         }
       }
@@ -18627,6 +18701,8 @@
   type ^= Object::Clone(*this, space);
   type.set_nullability(value);
   type.SetHash(0);
+  type.SetTypeTestingStub(
+      Code::Handle(TypeTestingStubGenerator::DefaultCodeForType(type)));
   if (IsCanonical()) {
     // Object::Clone does not clone canonical bit.
     ASSERT(!type.IsCanonical());
@@ -18771,7 +18847,7 @@
 }
 
 bool Type::IsEquivalent(const Instance& other,
-                        bool syntactically,
+                        TypeEquality kind,
                         TrailPtr trail) const {
   ASSERT(!IsNull());
   if (raw() == other.raw()) {
@@ -18782,7 +18858,7 @@
     const AbstractType& other_ref_type =
         AbstractType::Handle(TypeRef::Cast(other).type());
     ASSERT(!other_ref_type.IsTypeRef());
-    return IsEquivalent(other_ref_type, syntactically, trail);
+    return IsEquivalent(other_ref_type, kind, trail);
   }
   if (!other.IsType()) {
     return false;
@@ -18794,18 +18870,30 @@
   if (type_class_id() != other_type.type_class_id()) {
     return false;
   }
-  Nullability this_type_nullability = nullability();
-  Nullability other_type_nullability = other_type.nullability();
-  if (syntactically) {
-    if (this_type_nullability == Nullability::kLegacy) {
-      this_type_nullability = Nullability::kNonNullable;
+  if (kind != TypeEquality::kIgnoreNullability) {
+    Nullability this_type_nullability = nullability();
+    Nullability other_type_nullability = other_type.nullability();
+    if (kind == TypeEquality::kSubtypeNullability) {
+      if (FLAG_strong_non_nullable_type_checks &&
+          this_type_nullability == Nullability::kNullable &&
+          other_type_nullability == Nullability::kNonNullable) {
+        return false;
+      }
+    } else {
+      if (kind == TypeEquality::kSyntactical) {
+        if (this_type_nullability == Nullability::kLegacy) {
+          this_type_nullability = Nullability::kNonNullable;
+        }
+        if (other_type_nullability == Nullability::kLegacy) {
+          other_type_nullability = Nullability::kNonNullable;
+        }
+      } else {
+        ASSERT(kind == TypeEquality::kCanonical);
+      }
+      if (this_type_nullability != other_type_nullability) {
+        return false;
+      }
     }
-    if (other_type_nullability == Nullability::kLegacy) {
-      other_type_nullability = Nullability::kNonNullable;
-    }
-  }
-  if (this_type_nullability != other_type_nullability) {
-    return false;
   }
   if (!IsFinalized() || !other_type.IsFinalized()) {
     return false;  // Too early to decide if equal.
@@ -18837,8 +18925,8 @@
           return false;
         }
       } else if (!type_args.IsSubvectorEquivalent(other_type_args, from_index,
-                                                  num_type_params,
-                                                  syntactically, trail)) {
+                                                  num_type_params, kind,
+                                                  trail)) {
         return false;
       }
 #ifdef DEBUG
@@ -18854,7 +18942,7 @@
         for (intptr_t i = 0; i < from_index; i++) {
           type_arg = type_args.TypeAt(i);
           other_type_arg = other_type_args.TypeAt(i);
-          ASSERT(type_arg.IsEquivalent(other_type_arg, syntactically, trail));
+          ASSERT(type_arg.IsEquivalent(other_type_arg, kind, trail));
         }
       }
 #endif
@@ -18875,7 +18963,7 @@
 
   // Compare function type parameters and their bounds.
   // Check the type parameters and bounds of generic functions.
-  if (!sig_fun.HasSameTypeParametersAndBounds(other_sig_fun)) {
+  if (!sig_fun.HasSameTypeParametersAndBounds(other_sig_fun, kind)) {
     return false;
   }
 
@@ -18917,7 +19005,7 @@
   for (intptr_t i = 0; i < num_params; i++) {
     param_type = sig_fun.ParameterTypeAt(i);
     other_param_type = other_sig_fun.ParameterTypeAt(i);
-    if (!param_type.IsEquivalent(other_param_type, syntactically)) {
+    if (!param_type.IsEquivalent(other_param_type, kind)) {
       return false;
     }
   }
@@ -19282,7 +19370,7 @@
 }
 
 bool TypeRef::IsEquivalent(const Instance& other,
-                           bool syntactically,
+                           TypeEquality kind,
                            TrailPtr trail) const {
   if (raw() == other.raw()) {
     return true;
@@ -19294,8 +19382,7 @@
     return true;
   }
   const AbstractType& ref_type = AbstractType::Handle(type());
-  return !ref_type.IsNull() &&
-         ref_type.IsEquivalent(other, syntactically, trail);
+  return !ref_type.IsNull() && ref_type.IsEquivalent(other, kind, trail);
 }
 
 RawTypeRef* TypeRef::InstantiateFrom(
@@ -19445,6 +19532,8 @@
   type_parameter ^= Object::Clone(*this, space);
   type_parameter.set_nullability(value);
   type_parameter.SetHash(0);
+  type_parameter.SetTypeTestingStub(Code::Handle(
+      TypeTestingStubGenerator::DefaultCodeForType(type_parameter)));
   // TODO(regis): Should we link type parameters of different nullability?
   return type_parameter.raw();
 }
@@ -19461,7 +19550,7 @@
 }
 
 bool TypeParameter::IsEquivalent(const Instance& other,
-                                 bool syntactically,
+                                 TypeEquality kind,
                                  TrailPtr trail) const {
   if (raw() == other.raw()) {
     return true;
@@ -19471,7 +19560,7 @@
     const AbstractType& other_ref_type =
         AbstractType::Handle(TypeRef::Cast(other).type());
     ASSERT(!other_ref_type.IsTypeRef());
-    return IsEquivalent(other_ref_type, syntactically, trail);
+    return IsEquivalent(other_ref_type, kind, trail);
   }
   if (!other.IsTypeParameter()) {
     return false;
@@ -19484,18 +19573,32 @@
   if (parameterized_function() != other_type_param.parameterized_function()) {
     return false;
   }
-  Nullability this_type_param_nullability = nullability();
-  Nullability other_type_param_nullability = other_type_param.nullability();
-  if (syntactically) {
-    if (this_type_param_nullability == Nullability::kLegacy) {
-      this_type_param_nullability = Nullability::kNonNullable;
+  if (kind != TypeEquality::kIgnoreNullability) {
+    Nullability this_type_param_nullability = nullability();
+    Nullability other_type_param_nullability = other_type_param.nullability();
+    if (kind == TypeEquality::kSubtypeNullability) {
+      if (FLAG_strong_non_nullable_type_checks &&
+          this_type_param_nullability == Nullability::kNullable &&
+          other_type_param_nullability == Nullability::kNonNullable) {
+        return false;
+      }
+    } else {
+      if (kind == TypeEquality::kSyntactical) {
+        if (this_type_param_nullability == Nullability::kLegacy ||
+            this_type_param_nullability == Nullability::kUndetermined) {
+          this_type_param_nullability = Nullability::kNonNullable;
+        }
+        if (other_type_param_nullability == Nullability::kLegacy ||
+            other_type_param_nullability == Nullability::kUndetermined) {
+          other_type_param_nullability = Nullability::kNonNullable;
+        }
+      } else {
+        ASSERT(kind == TypeEquality::kCanonical);
+      }
+      if (this_type_param_nullability != other_type_param_nullability) {
+        return false;
+      }
     }
-    if (other_type_param_nullability == Nullability::kLegacy) {
-      other_type_param_nullability = Nullability::kNonNullable;
-    }
-  }
-  if (this_type_param_nullability != other_type_param_nullability) {
-    return false;
   }
   if (IsFinalized() == other_type_param.IsFinalized()) {
     return (index() == other_type_param.index());
@@ -22507,9 +22610,6 @@
     result ^= raw;
     result.SetLength(len);
     result.RecomputeDataField();
-    if (len > 0) {
-      memset(result.DataAddr(0), 0, length_in_bytes);
-    }
   }
   return result.raw();
 }
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index ff4a902..6b7c8bb 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -874,6 +874,14 @@
   kLegacy = 3,
 };
 
+// Equality kind between types.
+enum class TypeEquality {
+  kCanonical = 0,
+  kSyntactical = 1,
+  kSubtypeNullability = 2,
+  kIgnoreNullability = 3,
+};
+
 // The NNBDMode is passed to routines performing type reification and/or subtype
 // tests. The mode reflects the opted-in status of the library performing type
 // reification and/or subtype tests.
@@ -2514,7 +2522,8 @@
 
   // Returns true if this function has the same number of type parameters with
   // equal bounds as the other function. Type parameter names are ignored.
-  bool HasSameTypeParametersAndBounds(const Function& other) const;
+  bool HasSameTypeParametersAndBounds(const Function& other,
+                                      TypeEquality kind) const;
 
   // Return the number of type parameters declared in parent generic functions.
   intptr_t NumParentTypeParameters() const;
@@ -2789,6 +2798,8 @@
            !(is_static() || (kind() == RawFunction::kConstructor));
   }
 
+  bool NeedsMonomorphicCheckedEntry(Zone* zone) const;
+
   bool MayHaveUncheckedEntryPoint(Isolate* I) const;
 
   TokenPosition token_pos() const {
@@ -3875,6 +3886,16 @@
     return has_initializer() && !has_nontrivial_initializer();
   }
 
+  bool is_non_nullable_integer() const {
+    return IsNonNullableIntBit::decode(raw_ptr()->kind_bits_);
+  }
+
+  void set_is_non_nullable_integer(bool is_non_nullable_integer) const {
+    ASSERT(Thread::Current()->IsMutatorThread());
+    set_kind_bits(IsNonNullableIntBit::update(is_non_nullable_integer,
+                                              raw_ptr()->kind_bits_));
+  }
+
   StaticTypeExactnessState static_type_exactness_state() const {
     return StaticTypeExactnessState::Decode(
         raw_ptr()->static_type_exactness_state_);
@@ -4103,6 +4124,7 @@
     kIsExtensionMemberBit,
     kNeedsLoadGuardBit,
     kHasInitializerBit,
+    kIsNonNullableIntBit,
   };
   class ConstBit : public BitField<uint16_t, bool, kConstBit, 1> {};
   class StaticBit : public BitField<uint16_t, bool, kStaticBit, 1> {};
@@ -4130,6 +4152,8 @@
       : public BitField<uint16_t, bool, kNeedsLoadGuardBit, 1> {};
   class HasInitializerBit
       : public BitField<uint16_t, bool, kHasInitializerBit, 1> {};
+  class IsNonNullableIntBit
+      : public BitField<uint16_t, bool, kIsNonNullableIntBit, 1> {};
 
   // Update guarded cid and guarded length for this field. Returns true, if
   // deoptimization of dependent code is required.
@@ -7016,19 +7040,19 @@
   // Check if the vectors are equal (they may be null).
   bool Equals(const TypeArguments& other) const {
     return IsSubvectorEquivalent(other, 0, IsNull() ? 0 : Length(),
-                                 /* syntactically = */ false);
+                                 TypeEquality::kCanonical);
   }
 
   bool IsEquivalent(const TypeArguments& other,
-                    bool syntactically,
+                    TypeEquality kind,
                     TrailPtr trail = NULL) const {
-    return IsSubvectorEquivalent(other, 0, IsNull() ? 0 : Length(),
-                                 syntactically, trail);
+    return IsSubvectorEquivalent(other, 0, IsNull() ? 0 : Length(), kind,
+                                 trail);
   }
   bool IsSubvectorEquivalent(const TypeArguments& other,
                              intptr_t from_index,
                              intptr_t len,
-                             bool syntactically,
+                             TypeEquality kind,
                              TrailPtr trail = NULL) const;
 
   // Check if the vector is instantiated (it must not be null).
@@ -7218,10 +7242,10 @@
   }
   virtual uint32_t CanonicalizeHash() const { return Hash(); }
   virtual bool Equals(const Instance& other) const {
-    return IsEquivalent(other, /* syntactically = */ false);
+    return IsEquivalent(other, TypeEquality::kCanonical);
   }
   virtual bool IsEquivalent(const Instance& other,
-                            bool syntactically,
+                            TypeEquality kind,
                             TrailPtr trail = NULL) const;
   virtual bool IsRecursive() const;
 
@@ -7456,11 +7480,6 @@
   virtual Nullability nullability() const {
     return static_cast<Nullability>(raw_ptr()->nullability_);
   }
-  void set_nullability(Nullability value) const {
-    ASSERT(!IsCanonical());
-    ASSERT(value != Nullability::kUndetermined);
-    StoreNonPointer(&raw_ptr()->nullability_, static_cast<int8_t>(value));
-  }
   RawType* ToNullability(Nullability value, Heap::Space space) const;
   virtual classid_t type_class_id() const;
   virtual RawClass* type_class() const;
@@ -7472,7 +7491,7 @@
                               intptr_t num_free_fun_type_params = kAllFree,
                               TrailPtr trail = NULL) const;
   virtual bool IsEquivalent(const Instance& other,
-                            bool syntactically,
+                            TypeEquality kind,
                             TrailPtr trail = NULL) const;
   virtual bool IsRecursive() const;
 
@@ -7580,6 +7599,11 @@
 
   void set_token_pos(TokenPosition token_pos) const;
   void set_type_state(int8_t state) const;
+  void set_nullability(Nullability value) const {
+    ASSERT(!IsCanonical());
+    ASSERT(value != Nullability::kUndetermined);
+    StoreNonPointer(&raw_ptr()->nullability_, static_cast<int8_t>(value));
+  }
 
   static RawType* New(Heap::Space space = Heap::kOld);
 
@@ -7632,7 +7656,7 @@
                               intptr_t num_free_fun_type_params = kAllFree,
                               TrailPtr trail = NULL) const;
   virtual bool IsEquivalent(const Instance& other,
-                            bool syntactically,
+                            TypeEquality kind,
                             TrailPtr trail = NULL) const;
   virtual bool IsRecursive() const { return true; }
   virtual bool IsFunctionType() const {
@@ -7692,7 +7716,6 @@
   virtual Nullability nullability() const {
     return static_cast<Nullability>(raw_ptr()->nullability_);
   }
-  void set_nullability(Nullability value) const;
   RawTypeParameter* ToNullability(Nullability value, Heap::Space space) const;
   virtual bool HasTypeClass() const { return false; }
   virtual classid_t type_class_id() const { return kIllegalCid; }
@@ -7717,7 +7740,7 @@
                               intptr_t num_free_fun_type_params = kAllFree,
                               TrailPtr trail = NULL) const;
   virtual bool IsEquivalent(const Instance& other,
-                            bool syntactically,
+                            TypeEquality kind,
                             TrailPtr trail = NULL) const;
   virtual bool IsRecursive() const { return false; }
   virtual RawAbstractType* InstantiateFrom(
@@ -7760,6 +7783,7 @@
   void set_name(const String& value) const;
   void set_token_pos(TokenPosition token_pos) const;
   void set_flags(uint8_t flags) const;
+  void set_nullability(Nullability value) const;
 
   static RawTypeParameter* New();
 
diff --git a/runtime/vm/object_reload.cc b/runtime/vm/object_reload.cc
index e17bd7f..70e520d 100644
--- a/runtime/vm/object_reload.cc
+++ b/runtime/vm/object_reload.cc
@@ -618,6 +618,18 @@
   }
 };
 
+class ConstClassFieldRemoved : public ClassReasonForCancelling {
+ public:
+  ConstClassFieldRemoved(Zone* zone, const Class& from, const Class& to)
+      : ClassReasonForCancelling(zone, from, to) {}
+
+ private:
+  RawString* ToString() {
+    return String::NewFormatted("Const class cannot remove fields: %s",
+                                from_.ToCString());
+  }
+};
+
 class NativeFieldsConflict : public ClassReasonForCancelling {
  public:
   NativeFieldsConflict(Zone* zone, const Class& from, const Class& to)
@@ -724,11 +736,50 @@
     TIR_Print("Finalized replacement class for %s\n", ToCString());
   }
 
-  if (is_finalized() && is_const() && !replacement.is_const()) {
-    if (constants() != Array::null() && Array::LengthOf(constants()) > 0) {
+  if (is_finalized() && is_const() && (constants() != Array::null()) &&
+      (Array::LengthOf(constants()) > 0)) {
+    // Consts can't become non-consts.
+    if (!replacement.is_const()) {
       context->group_reload_context()->AddReasonForCancelling(
           new (context->zone())
               ConstToNonConstClass(context->zone(), *this, replacement));
+      return;
+    }
+
+    // Consts can't lose fields.
+    bool field_removed = false;
+    const Array& old_fields =
+        Array::Handle(OffsetToFieldMap(true /* original classes */));
+    const Array& new_fields = Array::Handle(replacement.OffsetToFieldMap());
+    if (new_fields.Length() < old_fields.Length()) {
+      field_removed = true;
+    } else {
+      Field& old_field = Field::Handle();
+      Field& new_field = Field::Handle();
+      String& old_name = String::Handle();
+      String& new_name = String::Handle();
+      for (intptr_t i = 0, n = old_fields.Length(); i < n; i++) {
+        old_field ^= old_fields.At(i);
+        new_field ^= new_fields.At(i);
+        if (old_field.IsNull() != new_field.IsNull()) {
+          field_removed = true;
+          break;
+        }
+        if (!old_field.IsNull()) {
+          old_name = old_field.name();
+          new_name = new_field.name();
+          if (!old_name.Equals(new_name)) {
+            field_removed = true;
+            break;
+          }
+        }
+      }
+    }
+    if (field_removed) {
+      context->group_reload_context()->AddReasonForCancelling(
+          new (context->zone())
+              ConstClassFieldRemoved(context->zone(), *this, replacement));
+      return;
     }
   }
 
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index 6dcf00a..b753b96 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -42,9 +42,6 @@
 
 #ifndef PRODUCT
 void ObjectStore::PrintToJSONObject(JSONObject* jsobj) {
-  if (!FLAG_support_service) {
-    return;
-  }
   jsobj->AddProperty("type", "_ObjectStore");
 
   {
diff --git a/runtime/vm/port.cc b/runtime/vm/port.cc
index 0b580dd..9ca1d08 100644
--- a/runtime/vm/port.cc
+++ b/runtime/vm/port.cc
@@ -324,9 +324,6 @@
 void PortMap::PrintPortsForMessageHandler(MessageHandler* handler,
                                           JSONStream* stream) {
 #ifndef PRODUCT
-  if (!FLAG_support_service) {
-    return;
-  }
   JSONObject jsobj(stream);
   jsobj.AddProperty("type", "_Ports");
   Object& msg_handler = Object::Handle();
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index f858f65..8d38f6e 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -17,7 +17,13 @@
 namespace dart {
 
 bool RawObject::InVMIsolateHeap() const {
-  return Dart::vm_isolate()->heap()->Contains(ToAddr(this));
+  // All "vm-isolate" objects are pre-marked and in old space
+  // (see [Object::FinalizeVMIsolate]).
+  if (!IsOldObject() || !IsMarked()) return false;
+
+  auto heap = Dart::vm_isolate()->heap();
+  ASSERT(heap->UsedInWords(Heap::kNew) == 0);
+  return heap->old_space()->ContainsUnsafe(ToAddr(this));
 }
 
 void RawObject::Validate(Isolate* isolate) const {
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index da82750..74dc667 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -564,6 +564,7 @@
   static bool IsTwoByteStringClassId(intptr_t index);
   static bool IsExternalStringClassId(intptr_t index);
   static bool IsBuiltinListClassId(intptr_t index);
+  static bool IsTypedDataBaseClassId(intptr_t index);
   static bool IsTypedDataClassId(intptr_t index);
   static bool IsTypedDataViewClassId(intptr_t index);
   static bool IsExternalTypedDataClassId(intptr_t index);
@@ -2302,6 +2303,7 @@
   ALIGN8 int64_t value_;
 
   friend class Api;
+  friend class Class;
   friend class Integer;
   friend class SnapshotReader;
 };
@@ -2876,30 +2878,30 @@
   // Make sure this function is updated when new builtin List types are added.
   COMPILE_ASSERT(kImmutableArrayCid == kArrayCid + 1);
   return ((index >= kArrayCid && index <= kImmutableArrayCid) ||
-          (index == kGrowableObjectArrayCid) || IsTypedDataClassId(index) ||
-          IsTypedDataViewClassId(index) || IsExternalTypedDataClassId(index) ||
+          (index == kGrowableObjectArrayCid) || IsTypedDataBaseClassId(index) ||
           (index == kByteBufferCid));
 }
 
+inline bool RawObject::IsTypedDataBaseClassId(intptr_t index) {
+  // Make sure this is updated when new TypedData types are added.
+  COMPILE_ASSERT(kTypedDataInt8ArrayCid + 3 == kTypedDataUint8ArrayCid);
+  return index >= kTypedDataInt8ArrayCid && index < kByteDataViewCid;
+}
+
 inline bool RawObject::IsTypedDataClassId(intptr_t index) {
   // Make sure this is updated when new TypedData types are added.
   COMPILE_ASSERT(kTypedDataInt8ArrayCid + 3 == kTypedDataUint8ArrayCid);
-
-  const bool is_typed_data_base =
-      index >= kTypedDataInt8ArrayCid && index < kByteDataViewCid;
-  return is_typed_data_base && ((index - kTypedDataInt8ArrayCid) % 3) ==
-                                   kTypedDataCidRemainderInternal;
+  return IsTypedDataBaseClassId(index) && ((index - kTypedDataInt8ArrayCid) %
+                                           3) == kTypedDataCidRemainderInternal;
 }
 
 inline bool RawObject::IsTypedDataViewClassId(intptr_t index) {
   // Make sure this is updated when new TypedData types are added.
   COMPILE_ASSERT(kTypedDataInt8ArrayViewCid + 3 == kTypedDataUint8ArrayViewCid);
 
-  const bool is_typed_data_base =
-      index >= kTypedDataInt8ArrayCid && index < kByteDataViewCid;
   const bool is_byte_data_view = index == kByteDataViewCid;
   return is_byte_data_view ||
-         (is_typed_data_base &&
+         (IsTypedDataBaseClassId(index) &&
           ((index - kTypedDataInt8ArrayCid) % 3) == kTypedDataCidRemainderView);
 }
 
@@ -2908,10 +2910,8 @@
   COMPILE_ASSERT(kExternalTypedDataInt8ArrayCid + 3 ==
                  kExternalTypedDataUint8ArrayCid);
 
-  const bool is_typed_data_base =
-      index >= kTypedDataInt8ArrayCid && index < kByteDataViewCid;
-  return is_typed_data_base && ((index - kTypedDataInt8ArrayCid) % 3) ==
-                                   kTypedDataCidRemainderExternal;
+  return IsTypedDataBaseClassId(index) && ((index - kTypedDataInt8ArrayCid) %
+                                           3) == kTypedDataCidRemainderExternal;
 }
 
 inline bool RawObject::IsFfiNativeTypeTypeClassId(intptr_t index) {
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 31e4ed5..bcb86b6 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -103,15 +103,15 @@
       Class::RawCast(reader->ReadObjectImpl(as_reference));
   type.set_type_class(*reader->ClassHandle());
 
-  if (is_canonical) {
-    type ^= type.Canonicalize();
-  }
-
   // Fill in the type testing stub.
   Code& code = *reader->CodeHandle();
   code = TypeTestingStubGenerator::DefaultCodeForType(type);
   type.SetTypeTestingStub(code);
 
+  if (is_canonical) {
+    type ^= type.Canonicalize();
+  }
+
   return type.raw();
 }
 
diff --git a/runtime/vm/regexp.cc b/runtime/vm/regexp.cc
index 23efd9d..95567a9 100644
--- a/runtime/vm/regexp.cc
+++ b/runtime/vm/regexp.cc
@@ -3917,7 +3917,7 @@
   table_.ForEach(this);
 }
 
-void UnicodeRangeSplitter::Call(uint32_t from, DispatchTable::Entry entry) {
+void UnicodeRangeSplitter::Call(uint32_t from, ChoiceTable::Entry entry) {
   OutSet* outset = entry.out_set();
   if (!outset->Get(kBase)) return;
   ZoneGrowableArray<CharacterRange>** target = nullptr;
@@ -4965,11 +4965,11 @@
   }
 }
 
-const int32_t DispatchTable::Config::kNoKey = Utf::kInvalidChar;
+const int32_t ChoiceTable::Config::kNoKey = Utf::kInvalidChar;
 
-void DispatchTable::AddRange(CharacterRange full_range,
-                             int32_t value,
-                             Zone* zone) {
+void ChoiceTable::AddRange(CharacterRange full_range,
+                           int32_t value,
+                           Zone* zone) {
   CharacterRange current = full_range;
   if (tree()->is_empty()) {
     // If this is the first range we just insert into the table.
@@ -5057,7 +5057,7 @@
   }
 }
 
-OutSet* DispatchTable::Get(int32_t value) {
+OutSet* ChoiceTable::Get(int32_t value) {
   ZoneSplayTree<Config>::Locator loc;
   if (!tree()->FindGreatestLessThan(value, &loc)) return empty();
   Entry* entry = &loc.value();
diff --git a/runtime/vm/regexp.h b/runtime/vm/regexp.h
index febcb91..170d412 100644
--- a/runtime/vm/regexp.h
+++ b/runtime/vm/regexp.h
@@ -120,9 +120,9 @@
 
 // A mapping from integers, specified as ranges, to a set of integers.
 // Used for mapping character ranges to choices.
-class DispatchTable : public ValueObject {
+class ChoiceTable : public ValueObject {
  public:
-  explicit DispatchTable(Zone* zone) : tree_(zone) {}
+  explicit ChoiceTable(Zone* zone) : tree_(zone) {}
 
   class Entry {
    public:
@@ -183,7 +183,7 @@
 class UnicodeRangeSplitter : public ValueObject {
  public:
   UnicodeRangeSplitter(Zone* zone, ZoneGrowableArray<CharacterRange>* base);
-  void Call(uint32_t from, DispatchTable::Entry entry);
+  void Call(uint32_t from, ChoiceTable::Entry entry);
 
   ZoneGrowableArray<CharacterRange>* bmp() { return bmp_; }
   ZoneGrowableArray<CharacterRange>* lead_surrogates() {
@@ -203,7 +203,7 @@
   static const int kNonBmpCodePoints = 4;
 
   Zone* zone_;
-  DispatchTable table_;
+  ChoiceTable table_;
   ZoneGrowableArray<CharacterRange>* bmp_;
   ZoneGrowableArray<CharacterRange>* lead_surrogates_;
   ZoneGrowableArray<CharacterRange>* trail_surrogates_;
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index 6985907..134bf7b 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -2248,8 +2248,8 @@
       }
     }
   }
-  if (FLAG_deoptimize_filter != nullptr || FLAG_stacktrace_filter != nullptr ||
-      (FLAG_reload_every != 0)) {
+  if ((FLAG_deoptimize_filter != nullptr) ||
+      (FLAG_stacktrace_filter != nullptr) || (FLAG_reload_every != 0)) {
     DartFrameIterator iterator(thread,
                                StackFrameIterator::kNoCrossThreadIteration);
     StackFrame* frame = iterator.NextFrame();
@@ -2264,8 +2264,12 @@
       function = code.function();
     }
     ASSERT(!function.IsNull());
-    const char* function_name = function.ToFullyQualifiedCString();
-    ASSERT(function_name != nullptr);
+    const char* function_name = nullptr;
+    if ((FLAG_deoptimize_filter != nullptr) ||
+        (FLAG_stacktrace_filter != nullptr)) {
+      function_name = function.ToFullyQualifiedCString();
+      ASSERT(function_name != nullptr);
+    }
     if (!code.IsNull()) {
       if (!code.is_optimized() && FLAG_reload_every_optimized) {
         // Don't do the reload if we aren't inside optimized code.
diff --git a/runtime/vm/service.h b/runtime/vm/service.h
index f2ca26a..395d0fe 100644
--- a/runtime/vm/service.h
+++ b/runtime/vm/service.h
@@ -14,7 +14,7 @@
 namespace dart {
 
 #define SERVICE_PROTOCOL_MAJOR_VERSION 3
-#define SERVICE_PROTOCOL_MINOR_VERSION 28
+#define SERVICE_PROTOCOL_MINOR_VERSION 29
 
 class Array;
 class EmbedderServiceHandler;
diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md
index eeb0580..99cfa3d 100644
--- a/runtime/vm/service/service.md
+++ b/runtime/vm/service/service.md
@@ -1,8 +1,8 @@
-# Dart VM Service Protocol 3.27
+# Dart VM Service Protocol 3.29
 
 > Please post feedback to the [observatory-discuss group][discuss-list]
 
-This document describes of _version 3.27_ of the Dart VM Service Protocol. This
+This document describes of _version 3.29_ of the Dart VM Service Protocol. This
 protocol is used to communicate with a running Dart Virtual Machine.
 
 To use the Service Protocol, start the VM with the *--observe* flag.
@@ -36,6 +36,7 @@
   - [evaluate](#evaluate)
   - [evaluateInFrame](#evaluateinframe)
   - [getAllocationProfile](#getallocationprofile)
+  - [getClientName](#getclientname)
   - [getCpuSamples](#getcpusamples)
   - [getFlagList](#getflaglist)
   - [getInstances](#getinstances)
@@ -59,7 +60,9 @@
   - [registerService](#registerService)
   - [reloadSources](#reloadsources)
   - [removeBreakpoint](#removebreakpoint)
+  - [requirePermissionToResume](#requirepermissiontoresume)
   - [resume](#resume)
+  - [setClientName](#setclientname)
   - [setExceptionPauseMode](#setexceptionpausemode)
   - [setFlag](#setflag)
   - [setLibraryDebuggable](#setlibrarydebuggable)
@@ -671,6 +674,18 @@
 before collecting allocation information. There is no guarantee that a garbage
 collection will be actually be performed.
 
+### getClientName
+
+```
+ClientName getClientName()
+```
+
+The _getClientName_ RPC is used to retrieve the name associated with the currently
+connected VM service client. If no name was previously set through the
+[setClientName](#setclientname) RPC, a default name will be returned.
+
+See [ClientName](#clientname).
+
 ### getCpuSamples
 
 ```
@@ -1095,6 +1110,42 @@
 type. The splitting of the SnapshotGraph into events can happen at any byte
 offset.
 
+### requirePermissionToResume
+
+```
+Success requirePermissionToResume(bool onPauseStart [optional],
+                                  bool onPauseReload[optional],
+                                  bool onPauseExit [optional])
+```
+
+The _requirePermissionToResume_ RPC is used to change the pause/resume behavior
+of isolates by providing a way for the VM service to wait for approval to resume
+from some set of clients. This is useful for clients which want to perform some
+operation on an isolate after a pause without it being resumed by another client.
+
+If the _onPauseStart_ parameter is `true`, isolates will not resume after pausing
+on start until the client sends a `resume` request and all other clients which
+need to provide resume approval for this pause type have done so.
+
+If the _onPauseReload_ parameter is `true`, isolates will not resume after pausing
+after a reload until the client sends a `resume` request and all other clients
+which need to provide resume approval for this pause type have done so.
+
+If the _onPauseExit_ parameter is `true`, isolates will not resume after pausing
+on exit until the client sends a `resume` request and all other clients which
+need to provide resume approval for this pause type have done so.
+
+**Important Notes:**
+
+- All clients with the same client name share resume permissions. Only a
+  single client of a given name is required to provide resume approval.
+- When a client requiring approval disconnects from the service, a paused
+  isolate may resume if all other clients requiring resume approval have
+  already given approval. In the case that no other client requires resume
+  approval for the current pause event, the isolate will be resumed if at
+  least one other client has attempted to [resume](#resume) the isolate.
+
+
 ### resume
 
 ```
@@ -1126,6 +1177,19 @@
 
 See [Success](#success), [StepOption](#StepOption).
 
+### setClientName
+
+```
+Success setClientName(string name)
+```
+
+The _setClientName_ RPC is used to set a name to be associated with the currently
+connected VM service client. If the _name_ parameter is a non-empty string, _name_
+will become the new name associated with the client. If _name_ is an empty string,
+the client's name will be reset to its default name.
+
+See [Success](#success).
+
 ### setExceptionPauseMode
 
 ```
@@ -1549,6 +1613,17 @@
 }
 ```
 
+### ClientName
+
+```
+class ClientName extends Response {
+  // The name of the currently connected VM service client.
+  string name;
+}
+```
+
+See [getClientName](#getclientname) and [setClientName](#setclientname).
+
 ### Code
 
 ```
@@ -3528,33 +3603,35 @@
 ------- | --------
 1.0 | Initial revision
 2.0 | Describe protocol version 2.0.
-3.0 | Describe protocol version 3.0.  Added UnresolvedSourceLocation.  Added Sentinel return to getIsolate.  Add AddedBreakpointWithScriptUri.  Removed Isolate.entry. The type of VM.pid was changed from string to int.  Added VMUpdate events.  Add offset and count parameters to getObject() and offset and count fields to Instance. Added ServiceExtensionAdded event.
-3.1 | Add the getSourceReport RPC.  The getObject RPC now accepts offset and count for string objects.  String objects now contain length, offset, and count properties.
-3.2 | Isolate objects now include the runnable bit and many debugger related RPCs will return an error if executed on an isolate before it is runnable.
-3.3 | Pause event now indicates if the isolate is paused at an await, yield, or yield* suspension point via the 'atAsyncSuspension' field. Resume command now supports the step parameter 'OverAsyncSuspension'. A Breakpoint added synthetically by an 'OverAsyncSuspension' resume command identifies itself as such via the 'isSyntheticAsyncContinuation' field.
-3.4 | Add the superType and mixin fields to Class. Added new pause event 'None'.
-3.5 | Add the error field to SourceReportRange.  Clarify definition of token position.  Add "Isolate must be paused" error code.
-3.6 | Add 'scopeStartTokenPos', 'scopeEndTokenPos', and 'declarationTokenPos' to BoundVariable. Add 'PausePostRequest' event kind. Add 'Rewind' StepOption. Add error code 107 (isolate cannot resume). Add 'reloadSources' RPC and related error codes. Add optional parameter 'scope' to 'evaluate' and 'evaluateInFrame'.
-3.7 | Add 'setFlag'.
-3.8 | Add 'kill'.
+3.0 | Describe protocol version 3.0.  Added `UnresolvedSourceLocation`.  Added `Sentinel` return to `getIsolate`.  Add `AddedBreakpointWithScriptUri`.  Removed `Isolate.entry`. The type of `VM.pid` was changed from `string` to `int`.  Added `VMUpdate` events.  Add offset and count parameters to `getObject` and `offset` and `count` fields to `Instance`. Added `ServiceExtensionAdded` event.
+3.1 | Add the `getSourceReport` RPC.  The `getObject` RPC now accepts `offset` and `count` for string objects.  `String` objects now contain `length`, `offset`, and `count` properties.
+3.2 | `Isolate` objects now include the runnable bit and many debugger related RPCs will return an error if executed on an isolate before it is runnable.
+3.3 | Pause event now indicates if the isolate is paused at an `await`, `yield`, or `yield*` suspension point via the `atAsyncSuspension` field. Resume command now supports the step parameter `OverAsyncSuspension`. A Breakpoint added synthetically by an `OverAsyncSuspension` resume command identifies itself as such via the `isSyntheticAsyncContinuation` field.
+3.4 | Add the `superType` and `mixin` fields to `Class`. Added new pause event `None`.
+3.5 | Add the error field to `SourceReportRange.  Clarify definition of token position.  Add "Isolate must be paused" error code.
+3.6 | Add `scopeStartTokenPos`, `scopeEndTokenPos`, and `declarationTokenPos` to `BoundVariable`. Add `PausePostRequest` event kind. Add `Rewind` `StepOption`. Add error code 107 (isolate cannot resume). Add `reloadSources` RPC and related error codes. Add optional parameter `scope` to `evaluate` and `evaluateInFrame`.
+3.7 | Add `setFlag`.
+3.8 | Add `kill`.
 3.9 | Changed numbers for errors related to service extensions.
-3.10 | Add 'invoke'.
-3.11 | Rename 'invoke' parameter 'receiverId' to 'targetId.
-3.12 | Add 'getScripts' RPC and `ScriptList` object.
-3.13 | Class 'mixin' field now properly set for kernel transformed mixin applications.
-3.14 | Flag 'profile_period' can now be set at runtime, allowing for the profiler sample rate to be changed while the program is running.
+3.10 | Add `invoke`.
+3.11 | Rename `invoke` parameter `receiverId` to `targetId`.
+3.12 | Add `getScripts` RPC and `ScriptList` object.
+3.13 | Class `mixin` field now properly set for kernel transformed mixin applications.
+3.14 | Flag `profile_period` can now be set at runtime, allowing for the profiler sample rate to be changed while the program is running.
 3.15 | Added `disableBreakpoints` parameter to `invoke`, `evaluate`, and `evaluateInFrame`.
-3.16 | Add 'getMemoryUsage' RPC and 'MemoryUsage' object.
-3.17 | Add 'Logging' event kind and the LogRecord class.
-3.18 | Add 'getAllocationProfile' RPC and 'AllocationProfile' and 'ClassHeapStats' objects.
-3.19 | Add 'clearVMTimeline', 'getVMTimeline', 'getVMTimelineFlags', 'setVMTimelineFlags', 'Timeline', and 'TimelineFlags'.
-3.20 | Add 'getInstances' RPC and 'InstanceSet' object.
-3.21 | Add 'getVMTimelineMicros' RPC and 'Timestamp' object.
+3.16 | Add `getMemoryUsage` RPC and `MemoryUsage` object.
+3.17 | Add `Logging` event kind and the `LogRecord` class.
+3.18 | Add `getAllocationProfile` RPC and `AllocationProfile` and `ClassHeapStats` objects.
+3.19 | Add `clearVMTimeline`, `getVMTimeline`, `getVMTimelineFlags`, `setVMTimelineFlags`, `Timeline`, and `TimelineFlags`.
+3.20 | Add `getInstances` RPC and `InstanceSet` object.
+3.21 | Add `getVMTimelineMicros` RPC and `Timestamp` object.
 3.22 | Add `registerService` RPC, `Service` stream, and `ServiceRegistered` and `ServiceUnregistered` event kinds.
 3.23 | Add `VMFlagUpdate` event kind to the `VM` stream.
 3.24 | Add `operatingSystem` property to `VM` object.
-3.25 | Add 'getInboundReferences', 'getRetainingPath' RPCs, and 'InboundReferences', 'InboundReference', 'RetainingPath', and 'RetainingObject' objects.
-3.26 | Add 'requestHeapSnapshot'.
-3.27 | Add 'clearCpuSamples', 'getCpuSamples' RPCs and 'CpuSamples', 'CpuSample' objects.
+3.25 | Add `getInboundReferences`, `getRetainingPath` RPCs, and `InboundReferences`, `InboundReference`, `RetainingPath`, and `RetainingObject` objects.
+3.26 | Add `requestHeapSnapshot`.
+3.27 | Add `clearCpuSamples`, `getCpuSamples` RPCs and `CpuSamples`, `CpuSample` objects.
+3.28 | TODO(aam): document changes from 3.28
+3.29 | Add `getClientName`, `setClientName`, `requireResumeApproval`
 
 [discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index 1c5db00..6f1f525 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -3081,15 +3081,13 @@
                (instr->Bits(20, 2) == 2) && (instr->Bits(23, 2) == 0)) {
       // Format(instr, "vminqs 'qd, 'qn, 'qm");
       for (int i = 0; i < 4; i++) {
-        s8d.data_[i].f =
-            s8n.data_[i].f <= s8m.data_[i].f ? s8n.data_[i].f : s8m.data_[i].f;
+        s8d.data_[i].f = fminf(s8n.data_[i].f, s8m.data_[i].f);
       }
     } else if ((instr->Bits(8, 4) == 15) && (instr->Bit(4) == 0) &&
                (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 0)) {
       // Format(instr, "vmaxqs 'qd, 'qn, 'qm");
       for (int i = 0; i < 4; i++) {
-        s8d.data_[i].f =
-            s8n.data_[i].f >= s8m.data_[i].f ? s8n.data_[i].f : s8m.data_[i].f;
+        s8d.data_[i].f = fmaxf(s8n.data_[i].f, s8m.data_[i].f);
       }
     } else if ((instr->Bits(8, 4) == 7) && (instr->Bit(4) == 0) &&
                (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc
index 1618d73..629888e 100644
--- a/runtime/vm/simulator_arm64.cc
+++ b/runtime/vm/simulator_arm64.cc
@@ -2857,11 +2857,11 @@
       } else if ((U == 0) && (opcode == 0x1e)) {
         if (instr->Bit(23) == 1) {
           // Format(instr, "vmin'vsz 'vd, 'vn, 'vm");
-          const float m = (vn_flt > vm_flt) ? vm_flt : vn_flt;
+          const float m = fminf(vn_flt, vm_flt);
           res = bit_cast<int32_t, float>(m);
         } else {
           // Format(instr, "vmax'vsz 'vd, 'vn, 'vm");
-          const float m = (vn_flt < vm_flt) ? vm_flt : vn_flt;
+          const float m = fmaxf(vn_flt, vm_flt);
           res = bit_cast<int32_t, float>(m);
         }
       } else if ((U == 0) && (opcode == 0x1f)) {
@@ -2931,11 +2931,11 @@
       } else if ((U == 0) && (opcode == 0x1e)) {
         if (instr->Bit(23) == 1) {
           // Format(instr, "vmin'vsz 'vd, 'vn, 'vm");
-          const double m = (vn_dbl > vm_dbl) ? vm_dbl : vn_dbl;
+          const double m = fmin(vn_dbl, vm_dbl);
           res = bit_cast<int64_t, double>(m);
         } else {
           // Format(instr, "vmax'vsz 'vd, 'vn, 'vm");
-          const double m = (vn_dbl < vm_dbl) ? vm_dbl : vn_dbl;
+          const double m = fmax(vn_dbl, vm_dbl);
           res = bit_cast<int64_t, double>(m);
         }
       } else {
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index cc04a43..f5e3248 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -1013,6 +1013,11 @@
     WriteIndexedObject(object_id);
     return true;
   } else {
+    // We do this check down here, because it's quite expensive.
+    if (!rawobj->InVMIsolateHeap()) {
+      return false;
+    }
+
     switch (id) {
       VM_OBJECT_CLASS_LIST(VM_OBJECT_WRITE)
       case kTypedDataUint32ArrayCid: {
@@ -1073,17 +1078,17 @@
 
 void ForwardList::SetObjectId(RawObject* object, intptr_t id) {
   if (object->IsNewObject()) {
-    isolate()->forward_table_new()->SetValue(object, id);
+    isolate()->forward_table_new()->SetValueExclusive(object, id);
   } else {
-    isolate()->forward_table_old()->SetValue(object, id);
+    isolate()->forward_table_old()->SetValueExclusive(object, id);
   }
 }
 
 intptr_t ForwardList::GetObjectId(RawObject* object) {
   if (object->IsNewObject()) {
-    return isolate()->forward_table_new()->GetValue(object);
+    return isolate()->forward_table_new()->GetValueExclusive(object);
   } else {
-    return isolate()->forward_table_old()->GetValue(object);
+    return isolate()->forward_table_old()->GetValueExclusive(object);
   }
 }
 
@@ -1127,7 +1132,7 @@
 
   // Now check if it is an object from the VM isolate. These objects are shared
   // by all isolates.
-  if (rawobj->InVMIsolateHeap() && HandleVMIsolateObject(rawobj)) {
+  if (HandleVMIsolateObject(rawobj)) {
     return true;
   }
 
diff --git a/runtime/vm/stack_frame_x64.h b/runtime/vm/stack_frame_x64.h
index dd01d67..1f9435a 100644
--- a/runtime/vm/stack_frame_x64.h
+++ b/runtime/vm/stack_frame_x64.h
@@ -9,7 +9,7 @@
 #error Do not include stack_frame_x64.h directly; use stack_frame.h instead.
 #endif
 
-#include "vm/constants_x64.h"
+#include "vm/constants.h"
 
 namespace dart {
 
diff --git a/runtime/vm/tags.cc b/runtime/vm/tags.cc
index b20b42e..e756a8f 100644
--- a/runtime/vm/tags.cc
+++ b/runtime/vm/tags.cc
@@ -118,9 +118,6 @@
 
 #ifndef PRODUCT
 void VMTagCounters::PrintToJSONObject(JSONObject* obj) {
-  if (!FLAG_support_service) {
-    return;
-  }
   {
     JSONArray arr(obj, "names");
     for (intptr_t i = 1; i < VMTag::kNumVMTags; i++) {
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index 6fdf23e..43bfbfc 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -62,13 +62,14 @@
 Thread::Thread(bool is_vm_isolate)
     : ThreadState(false),
       stack_limit_(0),
-      saved_stack_limit_(0),
-      stack_overflow_flags_(0),
       write_barrier_mask_(RawObject::kGenerationalBarrierMask),
       isolate_(NULL),
-      heap_(NULL),
+      dispatch_table_array_(NULL),
       top_(0),
       end_(0),
+      saved_stack_limit_(0),
+      stack_overflow_flags_(0),
+      heap_(NULL),
       top_exit_frame_info_(0),
       store_buffer_block_(NULL),
       marking_stack_block_(NULL),
@@ -96,7 +97,6 @@
       deferred_interrupts_mask_(0),
       deferred_interrupts_(0),
       stack_overflow_count_(0),
-      bump_allocate_(false),
       hierarchy_info_(NULL),
       type_usage_info_(NULL),
       pending_functions_(GrowableObjectArray::null()),
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index a4969ee..e38386a 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -493,9 +493,6 @@
   static intptr_t top_offset() { return OFFSET_OF(Thread, top_); }
   static intptr_t end_offset() { return OFFSET_OF(Thread, end_); }
 
-  bool bump_allocate() const { return bump_allocate_; }
-  void set_bump_allocate(bool b) { bump_allocate_ = b; }
-
   int32_t no_safepoint_scope_depth() const {
 #if defined(DEBUG)
     return no_safepoint_scope_depth_;
@@ -572,6 +569,9 @@
     global_object_pool_ = raw_value;
   }
 
+  const uword* dispatch_table_array() const { return dispatch_table_array_; }
+  void set_dispatch_table_array(uword* array) { dispatch_table_array_ = array; }
+
   static bool CanLoadFromThread(const Object& object);
   static intptr_t OffsetFromThread(const Object& object);
   static bool ObjectAtOffset(intptr_t offset, Object* object);
@@ -605,6 +605,10 @@
     return OFFSET_OF(Thread, global_object_pool_);
   }
 
+  static intptr_t dispatch_table_array_offset() {
+    return OFFSET_OF(Thread, dispatch_table_array_);
+  }
+
   RawObject* active_exception() const { return active_exception_; }
   void set_active_exception(const Object& value);
   static intptr_t active_exception_offset() {
@@ -859,14 +863,18 @@
   // We use only word-sized fields to avoid differences in struct packing on the
   // different architectures. See also CheckOffsets in dart.cc.
   uword stack_limit_;
-  uword saved_stack_limit_;
-  uword stack_overflow_flags_;
   uword write_barrier_mask_;
   Isolate* isolate_;
-  RawInstance** field_table_values_;
-  Heap* heap_;
+  uword* dispatch_table_array_;
   uword top_;
   uword end_;
+  // Offsets up to this point can all fit in a byte on X64. All of the above
+  // fields are very abundantly accessed from code. Thus, keeping them first
+  // is important for code size (although code size on X64 is not a priority).
+  uword saved_stack_limit_;
+  uword stack_overflow_flags_;
+  RawInstance** field_table_values_;
+  Heap* heap_;
   uword volatile top_exit_frame_info_;
   StoreBufferBlock* store_buffer_block_;
   MarkingStackBlock* marking_stack_block_;
@@ -930,7 +938,6 @@
   uint16_t deferred_interrupts_mask_;
   uint16_t deferred_interrupts_;
   int32_t stack_overflow_count_;
-  bool bump_allocate_;
 
   // Compiler state:
   CompilerState* compiler_state_ = nullptr;
diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc
index a88d4f0..d2e88e4 100644
--- a/runtime/vm/timeline.cc
+++ b/runtime/vm/timeline.cc
@@ -596,9 +596,6 @@
 
 #ifndef PRODUCT
 void TimelineEvent::PrintJSON(JSONStream* stream) const {
-  if (!FLAG_support_service) {
-    return;
-  }
   JSONObject obj(stream);
   int64_t pid = OS::ProcessId();
   int64_t tid = OSThread::ThreadIdToIntPtr(thread_);
@@ -912,9 +909,6 @@
 
 #ifndef PRODUCT
 void TimelineEventRecorder::PrintJSONMeta(JSONArray* events) const {
-  if (!FLAG_support_service) {
-    return;
-  }
   OSThreadIterator it;
   while (it.HasNext()) {
     OSThread* thread = it.Next();
@@ -1036,9 +1030,6 @@
 
 #ifndef PRODUCT
 void TimelineEventRecorder::WriteTo(const char* directory) {
-  if (!FLAG_support_service) {
-    return;
-  }
   Dart_FileOpenCallback file_open = Dart::file_open_callback();
   Dart_FileWriteCallback file_write = Dart::file_write_callback();
   Dart_FileCloseCallback file_close = Dart::file_close_callback();
@@ -1136,9 +1127,6 @@
 void TimelineEventFixedBufferRecorder::PrintJSONEvents(
     JSONArray* events,
     TimelineEventFilter* filter) {
-  if (!FLAG_support_service) {
-    return;
-  }
   MutexLocker ml(&lock_);
   ResetTimeTracking();
   intptr_t block_offset = FindOldestBlockIndex();
@@ -1167,9 +1155,6 @@
 
 void TimelineEventFixedBufferRecorder::PrintJSON(JSONStream* js,
                                                  TimelineEventFilter* filter) {
-  if (!FLAG_support_service) {
-    return;
-  }
   JSONObject topLevel(js);
   topLevel.AddProperty("type", "Timeline");
   {
@@ -1184,9 +1169,6 @@
 void TimelineEventFixedBufferRecorder::PrintTraceEvent(
     JSONStream* js,
     TimelineEventFilter* filter) {
-  if (!FLAG_support_service) {
-    return;
-  }
   JSONArray events(js);
   PrintJSONMeta(&events);
   PrintJSONEvents(&events, filter);
@@ -1262,9 +1244,6 @@
 #ifndef PRODUCT
 void TimelineEventCallbackRecorder::PrintJSON(JSONStream* js,
                                               TimelineEventFilter* filter) {
-  if (!FLAG_support_service) {
-    return;
-  }
   JSONObject topLevel(js);
   topLevel.AddProperty("type", "Timeline");
   {
@@ -1278,9 +1257,6 @@
 void TimelineEventCallbackRecorder::PrintTraceEvent(
     JSONStream* js,
     TimelineEventFilter* filter) {
-  if (!FLAG_support_service) {
-    return;
-  }
   JSONArray events(js);
 }
 #endif
@@ -1302,9 +1278,6 @@
 #ifndef PRODUCT
 void TimelineEventPlatformRecorder::PrintJSON(JSONStream* js,
                                               TimelineEventFilter* filter) {
-  if (!FLAG_support_service) {
-    return;
-  }
   JSONObject topLevel(js);
   topLevel.AddProperty("type", "Timeline");
   {
@@ -1318,9 +1291,6 @@
 void TimelineEventPlatformRecorder::PrintTraceEvent(
     JSONStream* js,
     TimelineEventFilter* filter) {
-  if (!FLAG_support_service) {
-    return;
-  }
   JSONArray events(js);
 }
 #endif
@@ -1352,9 +1322,6 @@
 #ifndef PRODUCT
 void TimelineEventEndlessRecorder::PrintJSON(JSONStream* js,
                                              TimelineEventFilter* filter) {
-  if (!FLAG_support_service) {
-    return;
-  }
   JSONObject topLevel(js);
   topLevel.AddProperty("type", "Timeline");
   {
@@ -1369,9 +1336,6 @@
 void TimelineEventEndlessRecorder::PrintTraceEvent(
     JSONStream* js,
     TimelineEventFilter* filter) {
-  if (!FLAG_support_service) {
-    return;
-  }
   JSONArray events(js);
   PrintJSONMeta(&events);
   PrintJSONEvents(&events, filter);
@@ -1413,9 +1377,6 @@
 void TimelineEventEndlessRecorder::PrintJSONEvents(
     JSONArray* events,
     TimelineEventFilter* filter) {
-  if (!FLAG_support_service) {
-    return;
-  }
   MutexLocker ml(&lock_);
   ResetTimeTracking();
   // Collect all interesting blocks.
diff --git a/runtime/vm/type_testing_stubs.cc b/runtime/vm/type_testing_stubs.cc
index 6a69df1..492187a 100644
--- a/runtime/vm/type_testing_stubs.cc
+++ b/runtime/vm/type_testing_stubs.cc
@@ -113,7 +113,7 @@
   if (type.IsType() || type.IsTypeParameter()) {
     // TODO(dartbug.com/39755): Add support for specialized NNBD TTS.
     const bool should_specialize =
-        !FLAG_precompiled_mode && lazy_specialize && type.IsNullable();
+        !FLAG_precompiled_mode && lazy_specialize && type.IsLegacy();
     return should_specialize ? StubCode::LazySpecializeTypeTest().raw()
                              : StubCode::DefaultTypeTest().raw();
   }
diff --git a/runtime/vm/vm_sources.gni b/runtime/vm/vm_sources.gni
index b7d3f4e..fb0cc8f 100644
--- a/runtime/vm/vm_sources.gni
+++ b/runtime/vm/vm_sources.gni
@@ -89,6 +89,8 @@
   "deferred_objects.h",
   "deopt_instructions.cc",
   "deopt_instructions.h",
+  "dispatch_table.cc",
+  "dispatch_table.h",
   "double_conversion.cc",
   "double_conversion.h",
   "double_internals.h",
diff --git a/sdk/lib/_internal/js_dev_runtime/patch/cli_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/cli_patch.dart
deleted file mode 100644
index b3ba63c..0000000
--- a/sdk/lib/_internal/js_dev_runtime/patch/cli_patch.dart
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// @dart = 2.6
-
-import 'dart:_js_helper' show patch;
-
-@patch
-void _waitForEvent(int timeoutMillis) {
-  throw UnsupportedError("waitForEvent");
-}
diff --git a/sdk/lib/_internal/js_dev_runtime/patch/typed_data_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/typed_data_patch.dart
index ab74676..9cf539b 100644
--- a/sdk/lib/_internal/js_dev_runtime/patch/typed_data_patch.dart
+++ b/sdk/lib/_internal/js_dev_runtime/patch/typed_data_patch.dart
@@ -4,7 +4,6 @@
 
 // @dart = 2.6
 
-import 'dart:collection';
 import 'dart:_js_helper' show patch;
 import 'dart:_native_typed_data';
 
@@ -102,12 +101,12 @@
 class Int64List {
   @patch
   factory Int64List(int length) {
-    throw UnsupportedError("Int64List not supported by dart2js.");
+    throw UnsupportedError("Int64List not supported on the web.");
   }
 
   @patch
   factory Int64List.fromList(List<int> elements) {
-    throw UnsupportedError("Int64List not supported by dart2js.");
+    throw UnsupportedError("Int64List not supported on the web.");
   }
 }
 
@@ -115,12 +114,12 @@
 class Uint64List {
   @patch
   factory Uint64List(int length) {
-    throw UnsupportedError("Uint64List not supported by dart2js.");
+    throw UnsupportedError("Uint64List not supported on the web.");
   }
 
   @patch
   factory Uint64List.fromList(List<int> elements) {
-    throw UnsupportedError("Uint64List not supported by dart2js.");
+    throw UnsupportedError("Uint64List not supported on the web.");
   }
 }
 
diff --git a/sdk/lib/_internal/js_dev_runtime/private/native_typed_data.dart b/sdk/lib/_internal/js_dev_runtime/private/native_typed_data.dart
index a444d0c..14f173d 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/native_typed_data.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/native_typed_data.dart
@@ -4,10 +4,8 @@
 
 // @dart = 2.6
 
-/**
- * Specialized integers and floating point numbers,
- * with SIMD support and efficient lists.
- */
+/// Specialized integers and floating point numbers,
+/// with SIMD support and efficient lists.
 library dart.typed_data.implementation;
 
 import 'dart:collection';
@@ -19,7 +17,6 @@
         JavaScriptIndexingBehavior,
         JSName,
         Native,
-        Null,
         Returns,
         diagnoseIndexError,
         diagnoseRangeError;
@@ -28,7 +25,7 @@
 
 import 'dart:typed_data';
 
-@Native("ArrayBuffer")
+@Native('ArrayBuffer')
 class NativeByteBuffer implements ByteBuffer {
   @JSName('byteLength')
   external int get lengthInBytes;
@@ -102,20 +99,16 @@
   }
 }
 
-/**
- * A fixed-length list of Float32x4 numbers that is viewable as a
- * [TypedData]. For long lists, this implementation will be considerably more
- * space- and time-efficient than the default [List] implementation.
- */
+/// A fixed-length list of Float32x4 numbers that is viewable as a
+/// [TypedData]. For long lists, this implementation will be considerably more
+/// space- and time-efficient than the default [List] implementation.
 class NativeFloat32x4List extends Object
     with ListMixin<Float32x4>, FixedLengthListMixin<Float32x4>
     implements Float32x4List {
   final NativeFloat32List _storage;
 
-  /**
-   * Creates a [Float32x4List] of the specified length (in elements),
-   * all of whose elements are initially zero.
-   */
+  /// Creates a [Float32x4List] of the specified length (in elements),
+  /// all of whose elements are initially zero.
   NativeFloat32x4List(int length) : _storage = NativeFloat32List(length * 4);
 
   NativeFloat32x4List._externalStorage(this._storage);
@@ -133,10 +126,8 @@
 
   Type get runtimeType => Float32x4List;
 
-  /**
-   * Creates a [Float32x4List] with the same size as the [elements] list
-   * and copies over the elements.
-   */
+  /// Creates a [Float32x4List] with the same size as the [elements] list
+  /// and copies over the elements.
   factory NativeFloat32x4List.fromList(List<Float32x4> list) {
     if (list is NativeFloat32x4List) {
       return NativeFloat32x4List._externalStorage(
@@ -180,20 +171,16 @@
   }
 }
 
-/**
- * A fixed-length list of Int32x4 numbers that is viewable as a
- * [TypedData]. For long lists, this implementation will be considerably more
- * space- and time-efficient than the default [List] implementation.
- */
+/// A fixed-length list of Int32x4 numbers that is viewable as a
+/// [TypedData]. For long lists, this implementation will be considerably more
+/// space- and time-efficient than the default [List] implementation.
 class NativeInt32x4List extends Object
     with ListMixin<Int32x4>, FixedLengthListMixin<Int32x4>
     implements Int32x4List {
   final Int32List _storage;
 
-  /**
-   * Creates a [Int32x4List] of the specified length (in elements),
-   * all of whose elements are initially zero.
-   */
+  /// Creates a [Int32x4List] of the specified length (in elements),
+  /// all of whose elements are initially zero.
   NativeInt32x4List(int length) : _storage = NativeInt32List(length * 4);
 
   NativeInt32x4List._externalStorage(Int32List storage) : _storage = storage;
@@ -211,10 +198,8 @@
 
   Type get runtimeType => Int32x4List;
 
-  /**
-   * Creates a [Int32x4List] with the same size as the [elements] list
-   * and copies over the elements.
-   */
+  /// Creates a [Int32x4List] with the same size as the [elements] list
+  /// and copies over the elements.
   factory NativeInt32x4List.fromList(List<Int32x4> list) {
     if (list is NativeInt32x4List) {
       return NativeInt32x4List._externalStorage(
@@ -258,20 +243,16 @@
   }
 }
 
-/**
- * A fixed-length list of Float64x2 numbers that is viewable as a
- * [TypedData]. For long lists, this implementation will be considerably more
- * space- and time-efficient than the default [List] implementation.
- */
+/// A fixed-length list of Float64x2 numbers that is viewable as a
+/// [TypedData]. For long lists, this implementation will be considerably more
+/// space- and time-efficient than the default [List] implementation.
 class NativeFloat64x2List extends Object
     with ListMixin<Float64x2>, FixedLengthListMixin<Float64x2>
     implements Float64x2List {
   final NativeFloat64List _storage;
 
-  /**
-   * Creates a [Float64x2List] of the specified length (in elements),
-   * all of whose elements are initially zero.
-   */
+  /// Creates a [Float64x2List] of the specified length (in elements),
+  /// all of whose elements are initially zero.
   NativeFloat64x2List(int length) : _storage = NativeFloat64List(length * 2);
 
   NativeFloat64x2List._externalStorage(this._storage);
@@ -285,10 +266,8 @@
     }
   }
 
-  /**
-   * Creates a [Float64x2List] with the same size as the [elements] list
-   * and copies over the elements.
-   */
+  /// Creates a [Float64x2List] with the same size as the [elements] list
+  /// and copies over the elements.
   factory NativeFloat64x2List.fromList(List<Float64x2> list) {
     if (list is NativeFloat64x2List) {
       return NativeFloat64x2List._externalStorage(
@@ -330,32 +309,24 @@
   }
 }
 
-@Native("ArrayBufferView")
+@Native('ArrayBufferView')
 class NativeTypedData implements TypedData {
-  /**
-   * Returns the byte buffer associated with this object.
-   */
+  /// Returns the byte buffer associated with this object.
   @Creates('NativeByteBuffer')
   // May be Null for IE's CanvasPixelArray.
   @Returns('NativeByteBuffer|Null')
   external ByteBuffer get buffer;
 
-  /**
-   * Returns the length of this view, in bytes.
-   */
+  /// Returns the length of this view, in bytes.
   @JSName('byteLength')
   external int get lengthInBytes;
 
-  /**
-   * Returns the offset in bytes into the underlying byte buffer of this view.
-   */
+  /// Returns the offset in bytes into the underlying byte buffer of this view.
   @JSName('byteOffset')
   external int get offsetInBytes;
 
-  /**
-   * Returns the number of bytes in the representation of each element in this
-   * list.
-   */
+  /// Returns the number of bytes in the representation of each element in this
+  /// list.
   @JSName('BYTES_PER_ELEMENT')
   external int get elementSizeInBytes;
 
@@ -411,26 +382,22 @@
   return result;
 }
 
-@Native("DataView")
+@Native('DataView')
 class NativeByteData extends NativeTypedData implements ByteData {
-  /**
-   * Creates a [ByteData] of the specified length (in elements), all of
-   * whose elements are initially zero.
-   */
+  /// Creates a [ByteData] of the specified length (in elements), all of
+  /// whose elements are initially zero.
   factory NativeByteData(int length) => _create1(_checkLength(length));
 
-  /**
-   * Creates an [ByteData] _view_ of the specified region in the specified
-   * byte buffer. Changes in the [ByteData] will be visible in the byte
-   * buffer and vice versa. If the [offsetInBytes] index of the region is not
-   * specified, it defaults to zero (the first byte in the byte buffer).
-   * If the length is not specified, it defaults to null, which indicates
-   * that the view extends to the end of the byte buffer.
-   *
-   * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
-   * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
-   * the length of [buffer].
-   */
+  /// Creates an [ByteData] _view_ of the specified region in the specified
+  /// byte buffer. Changes in the [ByteData] will be visible in the byte
+  /// buffer and vice versa. If the [offsetInBytes] index of the region is not
+  /// specified, it defaults to zero (the first byte in the byte buffer).
+  /// If the length is not specified, it defaults to null, which indicates
+  /// that the view extends to the end of the byte buffer.
+  ///
+  /// Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+  /// if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+  /// the length of [buffer].
   factory NativeByteData.view(
       ByteBuffer buffer, int offsetInBytes, int length) {
     _checkViewArguments(buffer, offsetInBytes, length);
@@ -443,14 +410,12 @@
 
   int get elementSizeInBytes => 1;
 
-  /**
-   * Returns the floating point number represented by the four bytes at
-   * the specified [byteOffset] in this object, in IEEE 754
-   * single-precision binary floating-point format (binary32).
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 4` is greater than the length of this object.
-   */
+  /// Returns the floating point number represented by the four bytes at
+  /// the specified [byteOffset] in this object, in IEEE 754
+  /// single-precision binary floating-point format (binary32).
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 4` is greater than the length of this object.
   double getFloat32(int byteOffset, [Endian endian = Endian.big]) =>
       _getFloat32(byteOffset, Endian.little == endian);
 
@@ -458,14 +423,12 @@
   @Returns('double')
   double _getFloat32(int byteOffset, [bool littleEndian]) native;
 
-  /**
-   * Returns the floating point number represented by the eight bytes at
-   * the specified [byteOffset] in this object, in IEEE 754
-   * double-precision binary floating-point format (binary64).
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 8` is greater than the length of this object.
-   */
+  /// Returns the floating point number represented by the eight bytes at
+  /// the specified [byteOffset] in this object, in IEEE 754
+  /// double-precision binary floating-point format (binary64).
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 8` is greater than the length of this object.
   double getFloat64(int byteOffset, [Endian endian = Endian.big]) =>
       _getFloat64(byteOffset, Endian.little == endian);
 
@@ -473,16 +436,14 @@
   @Returns('double')
   double _getFloat64(int byteOffset, [bool littleEndian]) native;
 
-  /**
-   * Returns the (possibly negative) integer represented by the two bytes at
-   * the specified [byteOffset] in this object, in two's complement binary
-   * form.
-   * The return value will be between 2<sup>15</sup> and 2<sup>15</sup> - 1,
-   * inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 2` is greater than the length of this object.
-   */
+  /// Returns the (possibly negative) integer represented by the two bytes at
+  /// the specified [byteOffset] in this object, in two's complement binary
+  /// form.
+  /// The return value will be between 2<sup>15</sup> and 2<sup>15</sup> - 1,
+  /// inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 2` is greater than the length of this object.
   int getInt16(int byteOffset, [Endian endian = Endian.big]) =>
       _getInt16(byteOffset, Endian.little == endian);
 
@@ -490,16 +451,14 @@
   @Returns('int')
   int _getInt16(int byteOffset, [bool littleEndian]) native;
 
-  /**
-   * Returns the (possibly negative) integer represented by the four bytes at
-   * the specified [byteOffset] in this object, in two's complement binary
-   * form.
-   * The return value will be between 2<sup>31</sup> and 2<sup>31</sup> - 1,
-   * inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 4` is greater than the length of this object.
-   */
+  /// Returns the (possibly negative) integer represented by the four bytes at
+  /// the specified [byteOffset] in this object, in two's complement binary
+  /// form.
+  /// The return value will be between 2<sup>31</sup> and 2<sup>31</sup> - 1,
+  /// inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 4` is greater than the length of this object.
   int getInt32(int byteOffset, [Endian endian = Endian.big]) =>
       _getInt32(byteOffset, Endian.little == endian);
 
@@ -507,39 +466,33 @@
   @Returns('int')
   int _getInt32(int byteOffset, [bool littleEndian]) native;
 
-  /**
-   * Returns the (possibly negative) integer represented by the eight bytes at
-   * the specified [byteOffset] in this object, in two's complement binary
-   * form.
-   * The return value will be between 2<sup>63</sup> and 2<sup>63</sup> - 1,
-   * inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 8` is greater than the length of this object.
-   */
+  /// Returns the (possibly negative) integer represented by the eight bytes at
+  /// the specified [byteOffset] in this object, in two's complement binary
+  /// form.
+  /// The return value will be between 2<sup>63</sup> and 2<sup>63</sup> - 1,
+  /// inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 8` is greater than the length of this object.
   int getInt64(int byteOffset, [Endian endian = Endian.big]) {
     throw UnsupportedError('Int64 accessor not supported by dart2js.');
   }
 
-  /**
-   * Returns the (possibly negative) integer represented by the byte at the
-   * specified [byteOffset] in this object, in two's complement binary
-   * representation. The return value will be between -128 and 127, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * greater than or equal to the length of this object.
-   */
+  /// Returns the (possibly negative) integer represented by the byte at the
+  /// specified [byteOffset] in this object, in two's complement binary
+  /// representation. The return value will be between -128 and 127, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// greater than or equal to the length of this object.
   int getInt8(int byteOffset) native;
 
-  /**
-   * Returns the positive integer represented by the two bytes starting
-   * at the specified [byteOffset] in this object, in unsigned binary
-   * form.
-   * The return value will be between 0 and  2<sup>16</sup> - 1, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 2` is greater than the length of this object.
-   */
+  /// Returns the positive integer represented by the two bytes starting
+  /// at the specified [byteOffset] in this object, in unsigned binary
+  /// form.
+  /// The return value will be between 0 and  2<sup>16</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 2` is greater than the length of this object.
   int getUint16(int byteOffset, [Endian endian = Endian.big]) =>
       _getUint16(byteOffset, Endian.little == endian);
 
@@ -547,15 +500,13 @@
   @Returns('int')
   int _getUint16(int byteOffset, [bool littleEndian]) native;
 
-  /**
-   * Returns the positive integer represented by the four bytes starting
-   * at the specified [byteOffset] in this object, in unsigned binary
-   * form.
-   * The return value will be between 0 and  2<sup>32</sup> - 1, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 4` is greater than the length of this object.
-   */
+  /// Returns the positive integer represented by the four bytes starting
+  /// at the specified [byteOffset] in this object, in unsigned binary
+  /// form.
+  /// The return value will be between 0 and  2<sup>32</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 4` is greater than the length of this object.
   int getUint32(int byteOffset, [Endian endian = Endian.big]) =>
       _getUint32(byteOffset, Endian.little == endian);
 
@@ -563,172 +514,148 @@
   @Returns('int')
   int _getUint32(int byteOffset, [bool littleEndian]) native;
 
-  /**
-   * Returns the positive integer represented by the eight bytes starting
-   * at the specified [byteOffset] in this object, in unsigned binary
-   * form.
-   * The return value will be between 0 and  2<sup>64</sup> - 1, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 8` is greater than the length of this object.
-   */
+  /// Returns the positive integer represented by the eight bytes starting
+  /// at the specified [byteOffset] in this object, in unsigned binary
+  /// form.
+  /// The return value will be between 0 and  2<sup>64</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 8` is greater than the length of this object.
   int getUint64(int byteOffset, [Endian endian = Endian.big]) {
     throw UnsupportedError('Uint64 accessor not supported by dart2js.');
   }
 
-  /**
-   * Returns the positive integer represented by the byte at the specified
-   * [byteOffset] in this object, in unsigned binary form. The
-   * return value will be between 0 and 255, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * greater than or equal to the length of this object.
-   */
+  /// Returns the positive integer represented by the byte at the specified
+  /// [byteOffset] in this object, in unsigned binary form. The
+  /// return value will be between 0 and 255, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// greater than or equal to the length of this object.
   int getUint8(int byteOffset) native;
 
-  /**
-   * Sets the four bytes starting at the specified [byteOffset] in this
-   * object to the IEEE 754 single-precision binary floating-point
-   * (binary32) representation of the specified [value].
-   *
-   * **Note that this method can lose precision.** The input [value] is
-   * a 64-bit floating point value, which will be converted to 32-bit
-   * floating point value by IEEE 754 rounding rules before it is stored.
-   * If [value] cannot be represented exactly as a binary32, it will be
-   * converted to the nearest binary32 value.  If two binary32 values are
-   * equally close, the one whose least significant bit is zero will be used.
-   * Note that finite (but large) values can be converted to infinity, and
-   * small non-zero values can be converted to zero.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 4` is greater than the length of this object.
-   */
+  /// Sets the four bytes starting at the specified [byteOffset] in this
+  /// object to the IEEE 754 single-precision binary floating-point
+  /// (binary32) representation of the specified [value].
+  ///
+  /// **Note that this method can lose precision.** The input [value] is
+  /// a 64-bit floating point value, which will be converted to 32-bit
+  /// floating point value by IEEE 754 rounding rules before it is stored.
+  /// If [value] cannot be represented exactly as a binary32, it will be
+  /// converted to the nearest binary32 value.  If two binary32 values are
+  /// equally close, the one whose least significant bit is zero will be used.
+  /// Note that finite (but large) values can be converted to infinity, and
+  /// small non-zero values can be converted to zero.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 4` is greater than the length of this object.
   void setFloat32(int byteOffset, num value, [Endian endian = Endian.big]) =>
       _setFloat32(byteOffset, value, Endian.little == endian);
 
   @JSName('setFloat32')
   void _setFloat32(int byteOffset, num value, [bool littleEndian]) native;
 
-  /**
-   * Sets the eight bytes starting at the specified [byteOffset] in this
-   * object to the IEEE 754 double-precision binary floating-point
-   * (binary64) representation of the specified [value].
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 8` is greater than the length of this object.
-   */
+  /// Sets the eight bytes starting at the specified [byteOffset] in this
+  /// object to the IEEE 754 double-precision binary floating-point
+  /// (binary64) representation of the specified [value].
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 8` is greater than the length of this object.
   void setFloat64(int byteOffset, num value, [Endian endian = Endian.big]) =>
       _setFloat64(byteOffset, value, Endian.little == endian);
 
   @JSName('setFloat64')
   void _setFloat64(int byteOffset, num value, [bool littleEndian]) native;
 
-  /**
-   * Sets the two bytes starting at the specified [byteOffset] in this
-   * object to the two's complement binary representation of the specified
-   * [value], which must fit in two bytes. In other words, [value] must lie
-   * between 2<sup>15</sup> and 2<sup>15</sup> - 1, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 2` is greater than the length of this object.
-   */
+  /// Sets the two bytes starting at the specified [byteOffset] in this
+  /// object to the two's complement binary representation of the specified
+  /// [value], which must fit in two bytes. In other words, [value] must lie
+  /// between 2<sup>15</sup> and 2<sup>15</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 2` is greater than the length of this object.
   void setInt16(int byteOffset, int value, [Endian endian = Endian.big]) =>
       _setInt16(byteOffset, value, Endian.little == endian);
 
   @JSName('setInt16')
   void _setInt16(int byteOffset, int value, [bool littleEndian]) native;
 
-  /**
-   * Sets the four bytes starting at the specified [byteOffset] in this
-   * object to the two's complement binary representation of the specified
-   * [value], which must fit in four bytes. In other words, [value] must lie
-   * between 2<sup>31</sup> and 2<sup>31</sup> - 1, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 4` is greater than the length of this object.
-   */
+  /// Sets the four bytes starting at the specified [byteOffset] in this
+  /// object to the two's complement binary representation of the specified
+  /// [value], which must fit in four bytes. In other words, [value] must lie
+  /// between 2<sup>31</sup> and 2<sup>31</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 4` is greater than the length of this object.
   void setInt32(int byteOffset, int value, [Endian endian = Endian.big]) =>
       _setInt32(byteOffset, value, Endian.little == endian);
 
   @JSName('setInt32')
   void _setInt32(int byteOffset, int value, [bool littleEndian]) native;
 
-  /**
-   * Sets the eight bytes starting at the specified [byteOffset] in this
-   * object to the two's complement binary representation of the specified
-   * [value], which must fit in eight bytes. In other words, [value] must lie
-   * between 2<sup>63</sup> and 2<sup>63</sup> - 1, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 8` is greater than the length of this object.
-   */
+  /// Sets the eight bytes starting at the specified [byteOffset] in this
+  /// object to the two's complement binary representation of the specified
+  /// [value], which must fit in eight bytes. In other words, [value] must lie
+  /// between 2<sup>63</sup> and 2<sup>63</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 8` is greater than the length of this object.
   void setInt64(int byteOffset, int value, [Endian endian = Endian.big]) {
     throw UnsupportedError('Int64 accessor not supported by dart2js.');
   }
 
-  /**
-   * Sets the byte at the specified [byteOffset] in this object to the
-   * two's complement binary representation of the specified [value], which
-   * must fit in a single byte. In other words, [value] must be between
-   * -128 and 127, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * greater than or equal to the length of this object.
-   */
+  /// Sets the byte at the specified [byteOffset] in this object to the
+  /// two's complement binary representation of the specified [value], which
+  /// must fit in a single byte. In other words, [value] must be between
+  /// -128 and 127, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// greater than or equal to the length of this object.
   void setInt8(int byteOffset, int value) native;
 
-  /**
-   * Sets the two bytes starting at the specified [byteOffset] in this object
-   * to the unsigned binary representation of the specified [value],
-   * which must fit in two bytes. in other words, [value] must be between
-   * 0 and 2<sup>16</sup> - 1, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 2` is greater than the length of this object.
-   */
+  /// Sets the two bytes starting at the specified [byteOffset] in this object
+  /// to the unsigned binary representation of the specified [value],
+  /// which must fit in two bytes. in other words, [value] must be between
+  /// 0 and 2<sup>16</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 2` is greater than the length of this object.
   void setUint16(int byteOffset, int value, [Endian endian = Endian.big]) =>
       _setUint16(byteOffset, value, Endian.little == endian);
 
   @JSName('setUint16')
   void _setUint16(int byteOffset, int value, [bool littleEndian]) native;
 
-  /**
-   * Sets the four bytes starting at the specified [byteOffset] in this object
-   * to the unsigned binary representation of the specified [value],
-   * which must fit in four bytes. in other words, [value] must be between
-   * 0 and 2<sup>32</sup> - 1, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 4` is greater than the length of this object.
-   */
+  /// Sets the four bytes starting at the specified [byteOffset] in this object
+  /// to the unsigned binary representation of the specified [value],
+  /// which must fit in four bytes. in other words, [value] must be between
+  /// 0 and 2<sup>32</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 4` is greater than the length of this object.
   void setUint32(int byteOffset, int value, [Endian endian = Endian.big]) =>
       _setUint32(byteOffset, value, Endian.little == endian);
 
   @JSName('setUint32')
   void _setUint32(int byteOffset, int value, [bool littleEndian]) native;
 
-  /**
-   * Sets the eight bytes starting at the specified [byteOffset] in this object
-   * to the unsigned binary representation of the specified [value],
-   * which must fit in eight bytes. in other words, [value] must be between
-   * 0 and 2<sup>64</sup> - 1, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 8` is greater than the length of this object.
-   */
+  /// Sets the eight bytes starting at the specified [byteOffset] in this object
+  /// to the unsigned binary representation of the specified [value],
+  /// which must fit in eight bytes. in other words, [value] must be between
+  /// 0 and 2<sup>64</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 8` is greater than the length of this object.
   void setUint64(int byteOffset, int value, [Endian endian = Endian.big]) {
     throw UnsupportedError('Uint64 accessor not supported by dart2js.');
   }
 
-  /**
-   * Sets the byte at the specified [byteOffset] in this object to the
-   * unsigned binary representation of the specified [value], which must fit
-   * in a single byte. in other words, [value] must be between 0 and 255,
-   * inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative,
-   * or greater than or equal to the length of this object.
-   */
+  /// Sets the byte at the specified [byteOffset] in this object to the
+  /// unsigned binary representation of the specified [value], which must fit
+  /// in a single byte. in other words, [value] must be between 0 and 255,
+  /// inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative,
+  /// or greater than or equal to the length of this object.
   void setUint8(int byteOffset, int value) native;
 
   static NativeByteData _create1(arg) =>
@@ -815,7 +742,7 @@
   }
 }
 
-@Native("Float32Array")
+@Native('Float32Array')
 class NativeFloat32List extends NativeTypedArrayOfDouble
     implements Float32List {
   factory NativeFloat32List(int length) => _create1(_checkLength(length));
@@ -850,7 +777,7 @@
       JS<NativeFloat32List>('!', 'new Float32Array(#, #, #)', arg1, arg2, arg3);
 }
 
-@Native("Float64Array")
+@Native('Float64Array')
 class NativeFloat64List extends NativeTypedArrayOfDouble
     implements Float64List {
   factory NativeFloat64List(int length) => _create1(_checkLength(length));
@@ -884,7 +811,7 @@
       JS('NativeFloat64List', 'new Float64Array(#, #, #)', arg1, arg2, arg3);
 }
 
-@Native("Int16Array")
+@Native('Int16Array')
 class NativeInt16List extends NativeTypedArrayOfInt implements Int16List {
   factory NativeInt16List(int length) => _create1(_checkLength(length));
 
@@ -922,7 +849,7 @@
       JS('NativeInt16List', 'new Int16Array(#, #, #)', arg1, arg2, arg3);
 }
 
-@Native("Int32Array")
+@Native('Int32Array')
 class NativeInt32List extends NativeTypedArrayOfInt implements Int32List {
   factory NativeInt32List(int length) => _create1(_checkLength(length));
 
@@ -960,7 +887,7 @@
       JS<NativeInt32List>('!', 'new Int32Array(#, #, #)', arg1, arg2, arg3);
 }
 
-@Native("Int8Array")
+@Native('Int8Array')
 class NativeInt8List extends NativeTypedArrayOfInt implements Int8List {
   factory NativeInt8List(int length) => _create1(_checkLength(length));
 
@@ -998,7 +925,7 @@
       JS<NativeInt8List>('!', 'new Int8Array(#, #, #)', arg1, arg2, arg3);
 }
 
-@Native("Uint16Array")
+@Native('Uint16Array')
 class NativeUint16List extends NativeTypedArrayOfInt implements Uint16List {
   factory NativeUint16List(int length) => _create1(_checkLength(length));
 
@@ -1037,7 +964,7 @@
       JS<NativeUint16List>('!', 'new Uint16Array(#, #, #)', arg1, arg2, arg3);
 }
 
-@Native("Uint32Array")
+@Native('Uint32Array')
 class NativeUint32List extends NativeTypedArrayOfInt implements Uint32List {
   factory NativeUint32List(int length) => _create1(_checkLength(length));
 
@@ -1076,7 +1003,7 @@
       JS<NativeUint32List>('!', 'new Uint32Array(#, #, #)', arg1, arg2, arg3);
 }
 
-@Native("Uint8ClampedArray,CanvasPixelArray")
+@Native('Uint8ClampedArray,CanvasPixelArray')
 class NativeUint8ClampedList extends NativeTypedArrayOfInt
     implements Uint8ClampedList {
   factory NativeUint8ClampedList(int length) => _create1(_checkLength(length));
@@ -1127,7 +1054,7 @@
 // Uint8List as !nonleaf ensures that the native dispatch correctly handles
 // the potential for Uint8ClampedArray to 'accidentally' pick up the
 // dispatch record for Uint8List.
-@Native("Uint8Array,!nonleaf")
+@Native('Uint8Array,!nonleaf')
 class NativeUint8List extends NativeTypedArrayOfInt implements Uint8List {
   factory NativeUint8List(int length) => _create1(_checkLength(length));
 
@@ -1167,11 +1094,9 @@
       JS<NativeUint8List>('!', 'new Uint8Array(#, #, #)', arg1, arg2, arg3);
 }
 
-/**
- * Implementation of Dart Float32x4 immutable value type and operations.
- * Float32x4 stores 4 32-bit floating point values in "lanes".
- * The lanes are "x", "y", "z", and "w" respectively.
- */
+/// Implementation of Dart Float32x4 immutable value type and operations.
+/// Float32x4 stores 4 32-bit floating point values in "lanes".
+/// The lanes are "x", "y", "z", and "w" respectively.
 class NativeFloat32x4 implements Float32x4 {
   final double x;
   final double y;
@@ -1501,11 +1426,9 @@
   }
 }
 
-/**
- * Interface of Dart Int32x4 and operations.
- * Int32x4 stores 4 32-bit bit-masks in "lanes".
- * The lanes are "x", "y", "z", and "w" respectively.
- */
+/// Interface of Dart Int32x4 and operations.
+/// Int32x4 stores 4 32-bit bit-masks in "lanes".
+/// The lanes are "x", "y", "z", and "w" respectively.
 class NativeInt32x4 implements Int32x4 {
   final int x;
   final int y;
diff --git a/sdk/lib/_internal/js_runtime/lib/cli_patch.dart b/sdk/lib/_internal/js_runtime/lib/cli_patch.dart
deleted file mode 100644
index 7f02085..0000000
--- a/sdk/lib/_internal/js_runtime/lib/cli_patch.dart
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// @dart = 2.6
-
-import 'dart:_js_helper' show patch;
-
-@patch
-void _waitForEvent(int timeoutMillis) {
-  throw new UnsupportedError("waitForEvent");
-}
diff --git a/sdk/lib/_internal/js_runtime/lib/native_typed_data.dart b/sdk/lib/_internal/js_runtime/lib/native_typed_data.dart
index db57ca3..8a77b19 100644
--- a/sdk/lib/_internal/js_runtime/lib/native_typed_data.dart
+++ b/sdk/lib/_internal/js_runtime/lib/native_typed_data.dart
@@ -33,69 +33,69 @@
   Type get runtimeType => ByteBuffer;
 
   Uint8List asUint8List([int offsetInBytes = 0, int length]) {
-    return new NativeUint8List.view(this, offsetInBytes, length);
+    return NativeUint8List.view(this, offsetInBytes, length);
   }
 
   Int8List asInt8List([int offsetInBytes = 0, int length]) {
-    return new NativeInt8List.view(this, offsetInBytes, length);
+    return NativeInt8List.view(this, offsetInBytes, length);
   }
 
   Uint8ClampedList asUint8ClampedList([int offsetInBytes = 0, int length]) {
-    return new NativeUint8ClampedList.view(this, offsetInBytes, length);
+    return NativeUint8ClampedList.view(this, offsetInBytes, length);
   }
 
   Uint16List asUint16List([int offsetInBytes = 0, int length]) {
-    return new NativeUint16List.view(this, offsetInBytes, length);
+    return NativeUint16List.view(this, offsetInBytes, length);
   }
 
   Int16List asInt16List([int offsetInBytes = 0, int length]) {
-    return new NativeInt16List.view(this, offsetInBytes, length);
+    return NativeInt16List.view(this, offsetInBytes, length);
   }
 
   Uint32List asUint32List([int offsetInBytes = 0, int length]) {
-    return new NativeUint32List.view(this, offsetInBytes, length);
+    return NativeUint32List.view(this, offsetInBytes, length);
   }
 
   Int32List asInt32List([int offsetInBytes = 0, int length]) {
-    return new NativeInt32List.view(this, offsetInBytes, length);
+    return NativeInt32List.view(this, offsetInBytes, length);
   }
 
   Uint64List asUint64List([int offsetInBytes = 0, int length]) {
-    throw new UnsupportedError('Uint64List not supported by dart2js.');
+    throw UnsupportedError('Uint64List not supported by dart2js.');
   }
 
   Int64List asInt64List([int offsetInBytes = 0, int length]) {
-    throw new UnsupportedError('Int64List not supported by dart2js.');
+    throw UnsupportedError('Int64List not supported by dart2js.');
   }
 
   Int32x4List asInt32x4List([int offsetInBytes = 0, int length]) {
     NativeInt32List storage =
         this.asInt32List(offsetInBytes, length != null ? length * 4 : null);
-    return new NativeInt32x4List._externalStorage(storage);
+    return NativeInt32x4List._externalStorage(storage);
   }
 
   Float32List asFloat32List([int offsetInBytes = 0, int length]) {
-    return new NativeFloat32List.view(this, offsetInBytes, length);
+    return NativeFloat32List.view(this, offsetInBytes, length);
   }
 
   Float64List asFloat64List([int offsetInBytes = 0, int length]) {
-    return new NativeFloat64List.view(this, offsetInBytes, length);
+    return NativeFloat64List.view(this, offsetInBytes, length);
   }
 
   Float32x4List asFloat32x4List([int offsetInBytes = 0, int length]) {
     NativeFloat32List storage =
         this.asFloat32List(offsetInBytes, length != null ? length * 4 : null);
-    return new NativeFloat32x4List._externalStorage(storage);
+    return NativeFloat32x4List._externalStorage(storage);
   }
 
   Float64x2List asFloat64x2List([int offsetInBytes = 0, int length]) {
     NativeFloat64List storage =
         this.asFloat64List(offsetInBytes, length != null ? length * 2 : null);
-    return new NativeFloat64x2List._externalStorage(storage);
+    return NativeFloat64x2List._externalStorage(storage);
   }
 
   ByteData asByteData([int offsetInBytes = 0, int length]) {
-    return new NativeByteData.view(this, offsetInBytes, length);
+    return NativeByteData.view(this, offsetInBytes, length);
   }
 }
 
@@ -109,13 +109,12 @@
 
   /// Creates a [Float32x4List] of the specified length (in elements),
   /// all of whose elements are initially zero.
-  NativeFloat32x4List(int length)
-      : _storage = new NativeFloat32List(length * 4);
+  NativeFloat32x4List(int length) : _storage = NativeFloat32List(length * 4);
 
   NativeFloat32x4List._externalStorage(this._storage);
 
   NativeFloat32x4List._slowFromList(List<Float32x4> list)
-      : _storage = new NativeFloat32List(list.length * 4) {
+      : _storage = NativeFloat32List(list.length * 4) {
     for (int i = 0; i < list.length; i++) {
       var e = list[i];
       _storage[(i * 4) + 0] = e.x;
@@ -131,10 +130,10 @@
   /// and copies over the elements.
   factory NativeFloat32x4List.fromList(List<Float32x4> list) {
     if (list is NativeFloat32x4List) {
-      return new NativeFloat32x4List._externalStorage(
-          new NativeFloat32List.fromList(list._storage));
+      return NativeFloat32x4List._externalStorage(
+          NativeFloat32List.fromList(list._storage));
     } else {
-      return new NativeFloat32x4List._slowFromList(list);
+      return NativeFloat32x4List._slowFromList(list);
     }
   }
 
@@ -154,7 +153,7 @@
     double _y = _storage[(index * 4) + 1];
     double _z = _storage[(index * 4) + 2];
     double _w = _storage[(index * 4) + 3];
-    return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+    return NativeFloat32x4._truncated(_x, _y, _z, _w);
   }
 
   void operator []=(int index, Float32x4 value) {
@@ -167,7 +166,7 @@
 
   Float32x4List sublist(int start, [int end]) {
     end = _checkValidRange(start, end, this.length);
-    return new NativeFloat32x4List._externalStorage(
+    return NativeFloat32x4List._externalStorage(
         _storage.sublist(start * 4, end * 4));
   }
 }
@@ -182,12 +181,12 @@
 
   /// Creates a [Int32x4List] of the specified length (in elements),
   /// all of whose elements are initially zero.
-  NativeInt32x4List(int length) : _storage = new NativeInt32List(length * 4);
+  NativeInt32x4List(int length) : _storage = NativeInt32List(length * 4);
 
   NativeInt32x4List._externalStorage(Int32List storage) : _storage = storage;
 
   NativeInt32x4List._slowFromList(List<Int32x4> list)
-      : _storage = new NativeInt32List(list.length * 4) {
+      : _storage = NativeInt32List(list.length * 4) {
     for (int i = 0; i < list.length; i++) {
       var e = list[i];
       _storage[(i * 4) + 0] = e.x;
@@ -203,10 +202,10 @@
   /// and copies over the elements.
   factory NativeInt32x4List.fromList(List<Int32x4> list) {
     if (list is NativeInt32x4List) {
-      return new NativeInt32x4List._externalStorage(
-          new NativeInt32List.fromList(list._storage));
+      return NativeInt32x4List._externalStorage(
+          NativeInt32List.fromList(list._storage));
     } else {
-      return new NativeInt32x4List._slowFromList(list);
+      return NativeInt32x4List._slowFromList(list);
     }
   }
 
@@ -226,7 +225,7 @@
     int _y = _storage[(index * 4) + 1];
     int _z = _storage[(index * 4) + 2];
     int _w = _storage[(index * 4) + 3];
-    return new NativeInt32x4._truncated(_x, _y, _z, _w);
+    return NativeInt32x4._truncated(_x, _y, _z, _w);
   }
 
   void operator []=(int index, Int32x4 value) {
@@ -239,7 +238,7 @@
 
   Int32x4List sublist(int start, [int end]) {
     end = _checkValidRange(start, end, this.length);
-    return new NativeInt32x4List._externalStorage(
+    return NativeInt32x4List._externalStorage(
         _storage.sublist(start * 4, end * 4));
   }
 }
@@ -254,13 +253,12 @@
 
   /// Creates a [Float64x2List] of the specified length (in elements),
   /// all of whose elements are initially zero.
-  NativeFloat64x2List(int length)
-      : _storage = new NativeFloat64List(length * 2);
+  NativeFloat64x2List(int length) : _storage = NativeFloat64List(length * 2);
 
   NativeFloat64x2List._externalStorage(this._storage);
 
   NativeFloat64x2List._slowFromList(List<Float64x2> list)
-      : _storage = new NativeFloat64List(list.length * 2) {
+      : _storage = NativeFloat64List(list.length * 2) {
     for (int i = 0; i < list.length; i++) {
       var e = list[i];
       _storage[(i * 2) + 0] = e.x;
@@ -272,10 +270,10 @@
   /// and copies over the elements.
   factory NativeFloat64x2List.fromList(List<Float64x2> list) {
     if (list is NativeFloat64x2List) {
-      return new NativeFloat64x2List._externalStorage(
-          new NativeFloat64List.fromList(list._storage));
+      return NativeFloat64x2List._externalStorage(
+          NativeFloat64List.fromList(list._storage));
     } else {
-      return new NativeFloat64x2List._slowFromList(list);
+      return NativeFloat64x2List._slowFromList(list);
     }
   }
 
@@ -295,7 +293,7 @@
     _checkValidIndex(index, this, this.length);
     double _x = _storage[(index * 2) + 0];
     double _y = _storage[(index * 2) + 1];
-    return new Float64x2(_x, _y);
+    return Float64x2(_x, _y);
   }
 
   void operator []=(int index, Float64x2 value) {
@@ -306,7 +304,7 @@
 
   Float64x2List sublist(int start, [int end]) {
     end = _checkValidRange(start, end, this.length);
-    return new NativeFloat64x2List._externalStorage(
+    return NativeFloat64x2List._externalStorage(
         _storage.sublist(start * 2, end * 2));
   }
 }
@@ -334,9 +332,9 @@
 
   void _invalidPosition(int position, int length, String name) {
     if (position is! int) {
-      throw new ArgumentError.value(position, name, 'Invalid list position');
+      throw ArgumentError.value(position, name, 'Invalid list position');
     } else {
-      throw new RangeError.range(position, 0, length, name);
+      throw RangeError.range(position, 0, length, name);
     }
   }
 
@@ -353,9 +351,7 @@
 // because passing unvalidated values to the native constructors can cause
 // conversions or create views.
 int _checkLength(length) {
-  return length is int
-      ? length
-      : throw new ArgumentError('Invalid length $length');
+  return length is int ? length : throw ArgumentError('Invalid length $length');
 }
 
 // Validates `.view` constructor arguments.  Checking is necessary because
@@ -364,13 +360,13 @@
 // views of the input.
 void _checkViewArguments(buffer, offsetInBytes, length) {
   if (buffer is! NativeByteBuffer) {
-    throw new ArgumentError('Invalid view buffer');
+    throw ArgumentError('Invalid view buffer');
   }
   if (offsetInBytes is! int) {
-    throw new ArgumentError('Invalid view offsetInBytes $offsetInBytes');
+    throw ArgumentError('Invalid view offsetInBytes $offsetInBytes');
   }
   if (length != null && length is! int) {
-    throw new ArgumentError('Invalid view length $length');
+    throw ArgumentError('Invalid view length $length');
   }
 }
 
@@ -378,7 +374,7 @@
 // returns a copy of the list.
 List _ensureNativeList(List list) {
   if (list is JSIndexable) return list;
-  List result = new List(list.length);
+  List result = List(list.length);
   for (int i = 0; i < list.length; i++) {
     result[i] = list[i];
   }
@@ -478,7 +474,7 @@
   /// Throws [RangeError] if [byteOffset] is negative, or
   /// `byteOffset + 8` is greater than the length of this object.
   int getInt64(int byteOffset, [Endian endian = Endian.big]) {
-    throw new UnsupportedError('Int64 accessor not supported by dart2js.');
+    throw UnsupportedError('Int64 accessor not supported by dart2js.');
   }
 
   /// Returns the (possibly negative) integer represented by the byte at the
@@ -525,7 +521,7 @@
   /// Throws [RangeError] if [byteOffset] is negative, or
   /// `byteOffset + 8` is greater than the length of this object.
   int getUint64(int byteOffset, [Endian endian = Endian.big]) {
-    throw new UnsupportedError('Uint64 accessor not supported by dart2js.');
+    throw UnsupportedError('Uint64 accessor not supported by dart2js.');
   }
 
   /// Returns the positive integer represented by the byte at the specified
@@ -603,7 +599,7 @@
   /// Throws [RangeError] if [byteOffset] is negative, or
   /// `byteOffset + 8` is greater than the length of this object.
   void setInt64(int byteOffset, int value, [Endian endian = Endian.big]) {
-    throw new UnsupportedError('Int64 accessor not supported by dart2js.');
+    throw UnsupportedError('Int64 accessor not supported by dart2js.');
   }
 
   /// Sets the byte at the specified [byteOffset] in this object to the
@@ -649,7 +645,7 @@
   /// Throws [RangeError] if [byteOffset] is negative, or
   /// `byteOffset + 8` is greater than the length of this object.
   void setUint64(int byteOffset, int value, [Endian endian = Endian.big]) {
-    throw new UnsupportedError('Uint64 accessor not supported by dart2js.');
+    throw UnsupportedError('Uint64 accessor not supported by dart2js.');
   }
 
   /// Sets the byte at the specified [byteOffset] in this object to the
@@ -680,14 +676,14 @@
     int targetLength = this.length;
     _checkPosition(start, targetLength, 'start');
     _checkPosition(end, targetLength, 'end');
-    if (start > end) throw new RangeError.range(start, 0, end);
+    if (start > end) throw RangeError.range(start, 0, end);
     int count = end - start;
 
-    if (skipCount < 0) throw new ArgumentError(skipCount);
+    if (skipCount < 0) throw ArgumentError(skipCount);
 
     int sourceLength = source.length;
     if (sourceLength - skipCount < count) {
-      throw new StateError('Not enough elements');
+      throw StateError('Not enough elements');
     }
 
     if (skipCount != 0 || sourceLength != count) {
@@ -1098,7 +1094,7 @@
   final double z;
   final double w;
 
-  static final NativeFloat32List _list = new NativeFloat32List(4);
+  static final NativeFloat32List _list = NativeFloat32List(4);
   static final Uint32List _uint32view = _list.buffer.asUint32List();
 
   static _truncate(x) {
@@ -1113,10 +1109,10 @@
         this.w = _truncate(w) {
     // We would prefer to check for `double` but in dart2js we can't see the
     // difference anyway.
-    if (x is! num) throw new ArgumentError(x);
-    if (y is! num) throw new ArgumentError(y);
-    if (z is! num) throw new ArgumentError(z);
-    if (w is! num) throw new ArgumentError(w);
+    if (x is! num) throw ArgumentError(x);
+    if (y is! num) throw ArgumentError(y);
+    if (z is! num) throw ArgumentError(z);
+    if (w is! num) throw ArgumentError(w);
   }
 
   NativeFloat32x4.splat(double v) : this(v, v, v, v);
@@ -1128,8 +1124,7 @@
     _uint32view[1] = i.y;
     _uint32view[2] = i.z;
     _uint32view[3] = i.w;
-    return new NativeFloat32x4._truncated(
-        _list[0], _list[1], _list[2], _list[3]);
+    return NativeFloat32x4._truncated(_list[0], _list[1], _list[2], _list[3]);
   }
 
   NativeFloat32x4.fromFloat64x2(Float64x2 v)
@@ -1161,12 +1156,12 @@
     double _y = y + other.y;
     double _z = z + other.z;
     double _w = w + other.w;
-    return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+    return NativeFloat32x4._doubles(_x, _y, _z, _w);
   }
 
   /// Negate operator.
   Float32x4 operator -() {
-    return new NativeFloat32x4._truncated(-x, -y, -z, -w);
+    return NativeFloat32x4._truncated(-x, -y, -z, -w);
   }
 
   /// Subtraction operator.
@@ -1175,7 +1170,7 @@
     double _y = y - other.y;
     double _z = z - other.z;
     double _w = w - other.w;
-    return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+    return NativeFloat32x4._doubles(_x, _y, _z, _w);
   }
 
   /// Multiplication operator.
@@ -1184,7 +1179,7 @@
     double _y = y * other.y;
     double _z = z * other.z;
     double _w = w * other.w;
-    return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+    return NativeFloat32x4._doubles(_x, _y, _z, _w);
   }
 
   /// Division operator.
@@ -1193,7 +1188,7 @@
     double _y = y / other.y;
     double _z = z / other.z;
     double _w = w / other.w;
-    return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+    return NativeFloat32x4._doubles(_x, _y, _z, _w);
   }
 
   /// Relational less than.
@@ -1202,7 +1197,7 @@
     bool _cy = y < other.y;
     bool _cz = z < other.z;
     bool _cw = w < other.w;
-    return new NativeInt32x4._truncated(
+    return NativeInt32x4._truncated(
         _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
   }
 
@@ -1212,7 +1207,7 @@
     bool _cy = y <= other.y;
     bool _cz = z <= other.z;
     bool _cw = w <= other.w;
-    return new NativeInt32x4._truncated(
+    return NativeInt32x4._truncated(
         _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
   }
 
@@ -1222,7 +1217,7 @@
     bool _cy = y > other.y;
     bool _cz = z > other.z;
     bool _cw = w > other.w;
-    return new NativeInt32x4._truncated(
+    return NativeInt32x4._truncated(
         _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
   }
 
@@ -1232,7 +1227,7 @@
     bool _cy = y >= other.y;
     bool _cz = z >= other.z;
     bool _cw = w >= other.w;
-    return new NativeInt32x4._truncated(
+    return NativeInt32x4._truncated(
         _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
   }
 
@@ -1242,7 +1237,7 @@
     bool _cy = y == other.y;
     bool _cz = z == other.z;
     bool _cw = w == other.w;
-    return new NativeInt32x4._truncated(
+    return NativeInt32x4._truncated(
         _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
   }
 
@@ -1252,7 +1247,7 @@
     bool _cy = y != other.y;
     bool _cz = z != other.z;
     bool _cw = w != other.w;
-    return new NativeInt32x4._truncated(
+    return NativeInt32x4._truncated(
         _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
   }
 
@@ -1262,7 +1257,7 @@
     double _y = s * y;
     double _z = s * z;
     double _w = s * w;
-    return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+    return NativeFloat32x4._doubles(_x, _y, _z, _w);
   }
 
   /// Returns the absolute value of this [Float32x4].
@@ -1271,7 +1266,7 @@
     double _y = y.abs();
     double _z = z.abs();
     double _w = w.abs();
-    return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+    return NativeFloat32x4._truncated(_x, _y, _z, _w);
   }
 
   /// Clamps [this] to be in the range [lowerLimit]-[upperLimit].
@@ -1297,7 +1292,7 @@
     _y = _y < _ly ? _ly : _y;
     _z = _z < _lz ? _lz : _z;
     _w = _w < _lw ? _lw : _w;
-    return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+    return NativeFloat32x4._truncated(_x, _y, _z, _w);
   }
 
   /// Extract the sign bit from each lane return them in the first 4 bits.
@@ -1319,7 +1314,7 @@
   /// Shuffle the lane values. [mask] must be one of the 256 shuffle constants.
   Float32x4 shuffle(int mask) {
     if ((mask < 0) || (mask > 255)) {
-      throw new RangeError.range(mask, 0, 255, 'mask');
+      throw RangeError.range(mask, 0, 255, 'mask');
     }
     _list[0] = x;
     _list[1] = y;
@@ -1330,7 +1325,7 @@
     double _y = _list[(mask >> 2) & 0x3];
     double _z = _list[(mask >> 4) & 0x3];
     double _w = _list[(mask >> 6) & 0x3];
-    return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+    return NativeFloat32x4._truncated(_x, _y, _z, _w);
   }
 
   /// Shuffle the lane values in [this] and [other]. The returned
@@ -1338,7 +1333,7 @@
   /// Uses the same [mask] as [shuffle].
   Float32x4 shuffleMix(Float32x4 other, int mask) {
     if ((mask < 0) || (mask > 255)) {
-      throw new RangeError.range(mask, 0, 255, 'mask');
+      throw RangeError.range(mask, 0, 255, 'mask');
     }
     _list[0] = x;
     _list[1] = y;
@@ -1353,27 +1348,27 @@
     _list[3] = other.w;
     double _z = _list[(mask >> 4) & 0x3];
     double _w = _list[(mask >> 6) & 0x3];
-    return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+    return NativeFloat32x4._truncated(_x, _y, _z, _w);
   }
 
   /// Copy [this] and replace the [x] lane.
   Float32x4 withX(double newX) {
-    return new NativeFloat32x4._truncated(_truncate(newX), y, z, w);
+    return NativeFloat32x4._truncated(_truncate(newX), y, z, w);
   }
 
   /// Copy [this] and replace the [y] lane.
   Float32x4 withY(double newY) {
-    return new NativeFloat32x4._truncated(x, _truncate(newY), z, w);
+    return NativeFloat32x4._truncated(x, _truncate(newY), z, w);
   }
 
   /// Copy [this] and replace the [z] lane.
   Float32x4 withZ(double newZ) {
-    return new NativeFloat32x4._truncated(x, y, _truncate(newZ), w);
+    return NativeFloat32x4._truncated(x, y, _truncate(newZ), w);
   }
 
   /// Copy [this] and replace the [w] lane.
   Float32x4 withW(double newW) {
-    return new NativeFloat32x4._truncated(x, y, z, _truncate(newW));
+    return NativeFloat32x4._truncated(x, y, z, _truncate(newW));
   }
 
   /// Returns the lane-wise minimum value in [this] or [other].
@@ -1382,7 +1377,7 @@
     double _y = y < other.y ? y : other.y;
     double _z = z < other.z ? z : other.z;
     double _w = w < other.w ? w : other.w;
-    return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+    return NativeFloat32x4._truncated(_x, _y, _z, _w);
   }
 
   /// Returns the lane-wise maximum value in [this] or [other].
@@ -1391,7 +1386,7 @@
     double _y = y > other.y ? y : other.y;
     double _z = z > other.z ? z : other.z;
     double _w = w > other.w ? w : other.w;
-    return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+    return NativeFloat32x4._truncated(_x, _y, _z, _w);
   }
 
   /// Returns the square root of [this].
@@ -1400,7 +1395,7 @@
     double _y = Math.sqrt(y);
     double _z = Math.sqrt(z);
     double _w = Math.sqrt(w);
-    return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+    return NativeFloat32x4._doubles(_x, _y, _z, _w);
   }
 
   /// Returns the reciprocal of [this].
@@ -1409,7 +1404,7 @@
     double _y = 1.0 / y;
     double _z = 1.0 / z;
     double _w = 1.0 / w;
-    return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+    return NativeFloat32x4._doubles(_x, _y, _z, _w);
   }
 
   /// Returns the square root of the reciprocal of [this].
@@ -1418,7 +1413,7 @@
     double _y = Math.sqrt(1.0 / y);
     double _z = Math.sqrt(1.0 / z);
     double _w = Math.sqrt(1.0 / w);
-    return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+    return NativeFloat32x4._doubles(_x, _y, _z, _w);
   }
 }
 
@@ -1431,7 +1426,7 @@
   final int z;
   final int w;
 
-  static final _list = new NativeInt32List(4);
+  static final _list = NativeInt32List(4);
 
   static _truncate(x) {
     _list[0] = x;
@@ -1443,10 +1438,10 @@
         this.y = _truncate(y),
         this.z = _truncate(z),
         this.w = _truncate(w) {
-    if (x != this.x && x is! int) throw new ArgumentError(x);
-    if (y != this.y && y is! int) throw new ArgumentError(y);
-    if (z != this.z && z is! int) throw new ArgumentError(z);
-    if (w != this.w && w is! int) throw new ArgumentError(w);
+    if (x != this.x && x is! int) throw ArgumentError(x);
+    if (y != this.y && y is! int) throw ArgumentError(y);
+    if (z != this.z && z is! int) throw ArgumentError(z);
+    if (w != this.w && w is! int) throw ArgumentError(w);
   }
 
   NativeInt32x4.bool(bool x, bool y, bool z, bool w)
@@ -1463,7 +1458,7 @@
     floatList[2] = f.z;
     floatList[3] = f.w;
     NativeInt32List view = floatList.buffer.asInt32List();
-    return new NativeInt32x4._truncated(view[0], view[1], view[2], view[3]);
+    return NativeInt32x4._truncated(view[0], view[1], view[2], view[3]);
   }
 
   NativeInt32x4._truncated(this.x, this.y, this.z, this.w);
@@ -1474,7 +1469,7 @@
   Int32x4 operator |(Int32x4 other) {
     // Dart2js uses unsigned results for bit-operations.
     // We use "JS" to fall back to the signed versions.
-    return new NativeInt32x4._truncated(
+    return NativeInt32x4._truncated(
         JS('int', '# | #', x, other.x),
         JS('int', '# | #', y, other.y),
         JS('int', '# | #', z, other.z),
@@ -1485,7 +1480,7 @@
   Int32x4 operator &(Int32x4 other) {
     // Dart2js uses unsigned results for bit-operations.
     // We use "JS" to fall back to the signed versions.
-    return new NativeInt32x4._truncated(
+    return NativeInt32x4._truncated(
         JS('int', '# & #', x, other.x),
         JS('int', '# & #', y, other.y),
         JS('int', '# & #', z, other.z),
@@ -1496,7 +1491,7 @@
   Int32x4 operator ^(Int32x4 other) {
     // Dart2js uses unsigned results for bit-operations.
     // We use "JS" to fall back to the signed versions.
-    return new NativeInt32x4._truncated(
+    return NativeInt32x4._truncated(
         JS('int', '# ^ #', x, other.x),
         JS('int', '# ^ #', y, other.y),
         JS('int', '# ^ #', z, other.z),
@@ -1505,7 +1500,7 @@
 
   Int32x4 operator +(Int32x4 other) {
     // Avoid going through the typed array by "| 0" the result.
-    return new NativeInt32x4._truncated(
+    return NativeInt32x4._truncated(
         JS('int', '(# + #) | 0', x, other.x),
         JS('int', '(# + #) | 0', y, other.y),
         JS('int', '(# + #) | 0', z, other.z),
@@ -1514,7 +1509,7 @@
 
   Int32x4 operator -(Int32x4 other) {
     // Avoid going through the typed array by "| 0" the result.
-    return new NativeInt32x4._truncated(
+    return NativeInt32x4._truncated(
         JS('int', '(# - #) | 0', x, other.x),
         JS('int', '(# - #) | 0', y, other.y),
         JS('int', '(# - #) | 0', z, other.z),
@@ -1523,7 +1518,7 @@
 
   Int32x4 operator -() {
     // Avoid going through the typed array by "| 0" the result.
-    return new NativeInt32x4._truncated(
+    return NativeInt32x4._truncated(
         JS('int', '(-#) | 0', x),
         JS('int', '(-#) | 0', y),
         JS('int', '(-#) | 0', z),
@@ -1542,7 +1537,7 @@
   /// Shuffle the lane values. [mask] must be one of the 256 shuffle constants.
   Int32x4 shuffle(int mask) {
     if ((mask < 0) || (mask > 255)) {
-      throw new RangeError.range(mask, 0, 255, 'mask');
+      throw RangeError.range(mask, 0, 255, 'mask');
     }
     _list[0] = x;
     _list[1] = y;
@@ -1552,7 +1547,7 @@
     int _y = _list[(mask >> 2) & 0x3];
     int _z = _list[(mask >> 4) & 0x3];
     int _w = _list[(mask >> 6) & 0x3];
-    return new NativeInt32x4._truncated(_x, _y, _z, _w);
+    return NativeInt32x4._truncated(_x, _y, _z, _w);
   }
 
   /// Shuffle the lane values in [this] and [other]. The returned
@@ -1560,7 +1555,7 @@
   /// Uses the same [mask] as [shuffle].
   Int32x4 shuffleMix(Int32x4 other, int mask) {
     if ((mask < 0) || (mask > 255)) {
-      throw new RangeError.range(mask, 0, 255, 'mask');
+      throw RangeError.range(mask, 0, 255, 'mask');
     }
     _list[0] = x;
     _list[1] = y;
@@ -1575,31 +1570,31 @@
     _list[3] = other.w;
     int _z = _list[(mask >> 4) & 0x3];
     int _w = _list[(mask >> 6) & 0x3];
-    return new NativeInt32x4._truncated(_x, _y, _z, _w);
+    return NativeInt32x4._truncated(_x, _y, _z, _w);
   }
 
   /// Returns a new [Int32x4] copied from [this] with a new x value.
   Int32x4 withX(int x) {
     int _x = _truncate(x);
-    return new NativeInt32x4._truncated(_x, y, z, w);
+    return NativeInt32x4._truncated(_x, y, z, w);
   }
 
   /// Returns a new [Int32x4] copied from [this] with a new y value.
   Int32x4 withY(int y) {
     int _y = _truncate(y);
-    return new NativeInt32x4._truncated(x, _y, z, w);
+    return NativeInt32x4._truncated(x, _y, z, w);
   }
 
   /// Returns a new [Int32x4] copied from [this] with a new z value.
   Int32x4 withZ(int z) {
     int _z = _truncate(z);
-    return new NativeInt32x4._truncated(x, y, _z, w);
+    return NativeInt32x4._truncated(x, y, _z, w);
   }
 
   /// Returns a new [Int32x4] copied from [this] with a new w value.
   Int32x4 withW(int w) {
     int _w = _truncate(w);
-    return new NativeInt32x4._truncated(x, y, z, _w);
+    return NativeInt32x4._truncated(x, y, z, _w);
   }
 
   /// Extracted x value. Returns `false` for 0, `true` for any other value.
@@ -1617,25 +1612,25 @@
   /// Returns a new [Int32x4] copied from [this] with a new x value.
   Int32x4 withFlagX(bool flagX) {
     int _x = flagX ? -1 : 0;
-    return new NativeInt32x4._truncated(_x, y, z, w);
+    return NativeInt32x4._truncated(_x, y, z, w);
   }
 
   /// Returns a new [Int32x4] copied from [this] with a new y value.
   Int32x4 withFlagY(bool flagY) {
     int _y = flagY ? -1 : 0;
-    return new NativeInt32x4._truncated(x, _y, z, w);
+    return NativeInt32x4._truncated(x, _y, z, w);
   }
 
   /// Returns a new [Int32x4] copied from [this] with a new z value.
   Int32x4 withFlagZ(bool flagZ) {
     int _z = flagZ ? -1 : 0;
-    return new NativeInt32x4._truncated(x, y, _z, w);
+    return NativeInt32x4._truncated(x, y, _z, w);
   }
 
   /// Returns a new [Int32x4] copied from [this] with a new w value.
   Int32x4 withFlagW(bool flagW) {
     int _w = flagW ? -1 : 0;
-    return new NativeInt32x4._truncated(x, y, z, _w);
+    return NativeInt32x4._truncated(x, y, z, _w);
   }
 
   /// Merge [trueValue] and [falseValue] based on [this]' bit mask:
@@ -1670,7 +1665,7 @@
     intView[1] = _y;
     intView[2] = _z;
     intView[3] = _w;
-    return new NativeFloat32x4._truncated(
+    return NativeFloat32x4._truncated(
         floatList[0], floatList[1], floatList[2], floatList[3]);
   }
 }
@@ -1679,12 +1674,12 @@
   final double x;
   final double y;
 
-  static NativeFloat64List _list = new NativeFloat64List(2);
+  static NativeFloat64List _list = NativeFloat64List(2);
   static NativeUint32List _uint32View = _list.buffer.asUint32List();
 
   NativeFloat64x2(this.x, this.y) {
-    if (x is! num) throw new ArgumentError(x);
-    if (y is! num) throw new ArgumentError(y);
+    if (x is! num) throw ArgumentError(x);
+    if (y is! num) throw ArgumentError(y);
   }
 
   NativeFloat64x2.splat(double v) : this(v, v);
@@ -1700,37 +1695,37 @@
 
   /// Addition operator.
   Float64x2 operator +(Float64x2 other) {
-    return new NativeFloat64x2._doubles(x + other.x, y + other.y);
+    return NativeFloat64x2._doubles(x + other.x, y + other.y);
   }
 
   /// Negate operator.
   Float64x2 operator -() {
-    return new NativeFloat64x2._doubles(-x, -y);
+    return NativeFloat64x2._doubles(-x, -y);
   }
 
   /// Subtraction operator.
   Float64x2 operator -(Float64x2 other) {
-    return new NativeFloat64x2._doubles(x - other.x, y - other.y);
+    return NativeFloat64x2._doubles(x - other.x, y - other.y);
   }
 
   /// Multiplication operator.
   Float64x2 operator *(Float64x2 other) {
-    return new NativeFloat64x2._doubles(x * other.x, y * other.y);
+    return NativeFloat64x2._doubles(x * other.x, y * other.y);
   }
 
   /// Division operator.
   Float64x2 operator /(Float64x2 other) {
-    return new NativeFloat64x2._doubles(x / other.x, y / other.y);
+    return NativeFloat64x2._doubles(x / other.x, y / other.y);
   }
 
   /// Returns a copy of [this] each lane being scaled by [s].
   Float64x2 scale(double s) {
-    return new NativeFloat64x2._doubles(x * s, y * s);
+    return NativeFloat64x2._doubles(x * s, y * s);
   }
 
   /// Returns the absolute value of this [Float64x2].
   Float64x2 abs() {
-    return new NativeFloat64x2._doubles(x.abs(), y.abs());
+    return NativeFloat64x2._doubles(x.abs(), y.abs());
   }
 
   /// Clamps [this] to be in the range [lowerLimit]-[upperLimit].
@@ -1746,7 +1741,7 @@
     _y = _y > _uy ? _uy : _y;
     _x = _x < _lx ? _lx : _x;
     _y = _y < _ly ? _ly : _y;
-    return new NativeFloat64x2._doubles(_x, _y);
+    return NativeFloat64x2._doubles(_x, _y);
   }
 
   /// Extract the sign bits from each lane return them in the first 2 bits.
@@ -1761,31 +1756,31 @@
 
   /// Returns a new [Float64x2] copied from [this] with a new x value.
   Float64x2 withX(double x) {
-    if (x is! num) throw new ArgumentError(x);
-    return new NativeFloat64x2._doubles(x, y);
+    if (x is! num) throw ArgumentError(x);
+    return NativeFloat64x2._doubles(x, y);
   }
 
   /// Returns a new [Float64x2] copied from [this] with a new y value.
   Float64x2 withY(double y) {
-    if (y is! num) throw new ArgumentError(y);
-    return new NativeFloat64x2._doubles(x, y);
+    if (y is! num) throw ArgumentError(y);
+    return NativeFloat64x2._doubles(x, y);
   }
 
   /// Returns the lane-wise minimum value in [this] or [other].
   Float64x2 min(Float64x2 other) {
-    return new NativeFloat64x2._doubles(
+    return NativeFloat64x2._doubles(
         x < other.x ? x : other.x, y < other.y ? y : other.y);
   }
 
   /// Returns the lane-wise maximum value in [this] or [other].
   Float64x2 max(Float64x2 other) {
-    return new NativeFloat64x2._doubles(
+    return NativeFloat64x2._doubles(
         x > other.x ? x : other.x, y > other.y ? y : other.y);
   }
 
   /// Returns the lane-wise square root of [this].
   Float64x2 sqrt() {
-    return new NativeFloat64x2._doubles(Math.sqrt(x), Math.sqrt(y));
+    return NativeFloat64x2._doubles(Math.sqrt(x), Math.sqrt(y));
   }
 }
 
diff --git a/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart b/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart
index d49bab5..d93006b 100644
--- a/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart
+++ b/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart
@@ -281,9 +281,6 @@
   /// instances of parameterized classes.
   RTI_NAME,
 
-  /// Name used to tag typedefs.
-  TYPEDEF_TAG,
-
   /// Name used to tag a function type.
   FUNCTION_TYPE_TAG,
 
diff --git a/sdk/lib/_internal/js_runtime/lib/typed_data_patch.dart b/sdk/lib/_internal/js_runtime/lib/typed_data_patch.dart
index a4a93ab..9cf539b 100644
--- a/sdk/lib/_internal/js_runtime/lib/typed_data_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/typed_data_patch.dart
@@ -101,12 +101,12 @@
 class Int64List {
   @patch
   factory Int64List(int length) {
-    throw new UnsupportedError("Int64List not supported by dart2js.");
+    throw UnsupportedError("Int64List not supported on the web.");
   }
 
   @patch
   factory Int64List.fromList(List<int> elements) {
-    throw new UnsupportedError("Int64List not supported by dart2js.");
+    throw UnsupportedError("Int64List not supported on the web.");
   }
 }
 
@@ -114,12 +114,12 @@
 class Uint64List {
   @patch
   factory Uint64List(int length) {
-    throw new UnsupportedError("Uint64List not supported by dart2js.");
+    throw UnsupportedError("Uint64List not supported on the web.");
   }
 
   @patch
   factory Uint64List.fromList(List<int> elements) {
-    throw new UnsupportedError("Uint64List not supported by dart2js.");
+    throw UnsupportedError("Uint64List not supported on the web.");
   }
 }
 
diff --git a/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart b/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
index 2975bdc..b605648 100644
--- a/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
+++ b/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
@@ -129,8 +129,7 @@
       documented: false,
       platforms: DART2JS_PLATFORM),
   "cli": const LibraryInfo("cli/cli.dart",
-      categories: "Server",
-      dart2jsPatchPath: "_internal/js_runtime/lib/cli_patch.dart"),
+      categories: "Server", platforms: VM_PLATFORM),
   "svg": const LibraryInfo("svg/dart2js/svg_dart2js.dart",
       categories: "Client",
       maturity: Maturity.WEB_STABLE,
diff --git a/sdk/lib/_internal/vm/bin/socket_patch.dart b/sdk/lib/_internal/vm/bin/socket_patch.dart
index e8e2bd1..2e75234 100644
--- a/sdk/lib/_internal/vm/bin/socket_patch.dart
+++ b/sdk/lib/_internal/vm/bin/socket_patch.dart
@@ -1779,40 +1779,37 @@
   }
 
   bool setOption(SocketOption option, bool enabled) {
-    if (_raw == null) return false;
+    if (_raw == null) throw const SocketException.closed();
     return _raw.setOption(option, enabled);
   }
 
   Uint8List getRawOption(RawSocketOption option) {
-    if (_raw == null) return null;
+    if (_raw == null) throw const SocketException.closed();
     return _raw.getRawOption(option);
   }
 
   void setRawOption(RawSocketOption option) {
-    _raw?.setRawOption(option);
+    if (_raw == null) throw const SocketException.closed();
+    _raw.setRawOption(option);
   }
 
   int get port {
     if (_raw == null) throw const SocketException.closed();
-    ;
     return _raw.port;
   }
 
   InternetAddress get address {
     if (_raw == null) throw const SocketException.closed();
-    ;
     return _raw.address;
   }
 
   int get remotePort {
     if (_raw == null) throw const SocketException.closed();
-    ;
     return _raw.remotePort;
   }
 
   InternetAddress get remoteAddress {
     if (_raw == null) throw const SocketException.closed();
-    ;
     return _raw.remoteAddress;
   }
 
diff --git a/sdk/lib/io/socket.dart b/sdk/lib/io/socket.dart
index 7b70858..2b7edeb 100644
--- a/sdk/lib/io/socket.dart
+++ b/sdk/lib/io/socket.dart
@@ -652,21 +652,29 @@
 
   /**
    * Returns the port used by this socket.
+   *
+   * Throws a [SocketException] if the socket is closed.
    */
   int get port;
 
   /**
    * Returns the remote port connected to by this socket.
+   *
+   * Throws a [SocketException] if the socket is closed.
    */
   int get remotePort;
 
   /**
    * Returns the [InternetAddress] used to connect this socket.
+   *
+   * Throws a [SocketException] if the socket is closed.
    */
   InternetAddress get address;
 
   /**
    * Returns the remote [InternetAddress] connected to by this socket.
+   *
+   * Throws a [SocketException] if the socket is closed.
    */
   InternetAddress get remoteAddress;
 
@@ -791,6 +799,9 @@
    * available options.
    *
    * Returns [:true:] if the option was set successfully, false otherwise.
+   *
+   * Throws a [SocketException] if the socket has been destroyed or upgraded to
+   * a secure socket.
    */
   bool setOption(SocketOption option, bool enabled);
 
@@ -800,7 +811,8 @@
    *
    * Returns the [RawSocketOption.value] on success.
    *
-   * Throws an [OSError] on failure.
+   * Throws an [OSError] on failure and a [SocketException] if the socket has
+   * been destroyed or upgraded to a secure socket.
    */
   Uint8List getRawOption(RawSocketOption option);
 
@@ -808,27 +820,36 @@
    * Use [setRawOption] to customize the [RawSocket]. See [RawSocketOption] for
    * available options.
    *
-   * Throws an [OSError] on failure.
+   * Throws an [OSError] on failure and a [SocketException] if the socket has
+   * been destroyed or upgraded to a secure socket.
    */
   void setRawOption(RawSocketOption option);
 
   /**
    * Returns the port used by this socket.
+   *
+   * Throws a [SocketException] if the socket is closed.
    */
   int get port;
 
   /**
    * Returns the remote port connected to by this socket.
+   *
+   * Throws a [SocketException] if the socket is closed.
    */
   int get remotePort;
 
   /**
    * Returns the [InternetAddress] used to connect this socket.
+   *
+   * Throws a [SocketException] if the socket is closed.
    */
   InternetAddress get address;
 
   /**
    * Returns the remote [InternetAddress] connected to by this socket.
+   *
+   * Throws a [SocketException] if the socket is closed.
    */
   InternetAddress get remoteAddress;
 
diff --git a/sdk/lib/vmservice/client.dart b/sdk/lib/vmservice/client.dart
index 68cdaad..915a3d0 100644
--- a/sdk/lib/vmservice/client.dart
+++ b/sdk/lib/vmservice/client.dart
@@ -10,6 +10,15 @@
 
 // A service client.
 abstract class Client {
+  static int _idCounter = 0;
+  final int _id = ++_idCounter;
+
+  String get defaultClientName => 'client$_id';
+
+  String get name => _name;
+  set name(n) => _name = n ?? defaultClientName;
+  String _name;
+
   final VMService service;
   final bool sendEvents;
 
@@ -28,6 +37,7 @@
       new Map<String, ClientServiceHandle>();
 
   Client(this.service, {bool sendEvents: true}) : this.sendEvents = sendEvents {
+    name = defaultClientName;
     service._addClient(this);
   }
 
diff --git a/sdk/lib/vmservice/running_isolate.dart b/sdk/lib/vmservice/running_isolate.dart
index f768dec..d811463 100644
--- a/sdk/lib/vmservice/running_isolate.dart
+++ b/sdk/lib/vmservice/running_isolate.dart
@@ -10,13 +10,106 @@
   final int portId;
   final SendPort sendPort;
   final String name;
+  final Set<String> _resumeApprovalsByName = {};
 
   RunningIsolate(this.portId, this.sendPort, this.name);
 
   String get serviceId => 'isolates/$portId';
 
+  static const kInvalidPauseEvent = -1;
+  static const kPauseOnStartMask = 1 << 0;
+  static const kPauseOnReloadMask = 1 << 1;
+  static const kPauseOnExitMask = 1 << 2;
+  static const kDefaultResumePermissionMask =
+      kPauseOnStartMask | kPauseOnReloadMask | kPauseOnExitMask;
+
+  /// Resumes the isolate if all clients which need to approve a resume have
+  /// done so. Called when the last client of a given name disconnects or
+  /// changes name to ensure we don't deadlock waiting for approval to resume
+  /// from a disconnected client.
+  Future<void> maybeResumeAfterClientChange(
+      VMService service, String disconnectedClientName) async {
+    // Remove approvals from the disconnected client.
+    _resumeApprovalsByName.remove(disconnectedClientName);
+
+    // If we've received approval to resume from all clients who care, clear
+    // approval state and resume.
+    final pauseType = await _isolatePauseType(service, portId.toString());
+    if (pauseType != kInvalidPauseEvent &&
+        _shouldResume(service, null, pauseType)) {
+      _resumeApprovalsByName.clear();
+      await Message.forMethod('resume')
+        ..params.addAll({
+          'isolateId': portId,
+        })
+        ..sendToIsolate(sendPort);
+    }
+  }
+
+  bool _shouldResume(VMService service, Client client, int pauseType) {
+    if (client != null) {
+      // Mark the approval by the client.
+      _resumeApprovalsByName.add(client.name);
+    }
+    final requiredClientApprovals = <String>{};
+    final permissions = service.clientResumePermissions;
+
+    // Determine which clients require approval for this pause type.
+    permissions.forEach((name, clientNamePermissions) {
+      if (clientNamePermissions.permissionsMask & pauseType != 0) {
+        requiredClientApprovals.add(name);
+      }
+    });
+
+    // We require at least a single client to resume, even if that client
+    // doesn't require resume approval.
+    if (_resumeApprovalsByName.isEmpty) {
+      return false;
+    }
+
+    // If all the required approvals are present, we should resume.
+    return _resumeApprovalsByName.containsAll(requiredClientApprovals);
+  }
+
+  Future<int> _isolatePauseType(VMService service, String isolateId) async {
+    final getIsolateMessage = Message.forMethod('getIsolate')
+      ..params.addAll({
+        'isolateId': isolateId,
+      });
+    final result =
+        (await routeRequest(service, getIsolateMessage)).decodeJson();
+    final pauseEvent = result['result']['pauseEvent'];
+    const pauseEvents = <String, int>{
+      'PauseStart': kPauseOnStartMask,
+      'PausePostRequest': kPauseOnReloadMask,
+      'PauseExit': kPauseOnExitMask,
+    };
+    final kind = pauseEvent['kind'];
+    return pauseEvents[kind] ?? kInvalidPauseEvent;
+  }
+
+  Future<Response> _routeResumeRequest(
+      VMService service, Message message) async {
+    // If we've received approval to resume from all clients who care, clear
+    // approval state and resume.
+    final pauseType =
+        await _isolatePauseType(service, message.params['isolateId']);
+    if (pauseType == kInvalidPauseEvent ||
+        _shouldResume(service, message.client, pauseType)) {
+      _resumeApprovalsByName.clear();
+      return message.sendToIsolate(sendPort);
+    }
+
+    // We're still awaiting some approvals. Simply return success, but don't
+    // resume yet.
+    return Response(ResponsePayloadKind.String, encodeSuccess(message));
+  }
+
   @override
   Future<Response> routeRequest(VMService service, Message message) {
+    if (message.method == 'resume') {
+      return _routeResumeRequest(service, message);
+    }
     // Send message to isolate.
     return message.sendToIsolate(sendPort);
   }
diff --git a/sdk/lib/vmservice/vmservice.dart b/sdk/lib/vmservice/vmservice.dart
index 410406c..6943f13 100644
--- a/sdk/lib/vmservice/vmservice.dart
+++ b/sdk/lib/vmservice/vmservice.dart
@@ -193,6 +193,11 @@
   static WebServerControlCallback webServerControl;
 }
 
+class _ClientResumePermissions {
+  final List<Client> clients = [];
+  int permissionsMask = 0;
+}
+
 class VMService extends MessageRouter {
   static VMService _instance;
 
@@ -203,6 +208,10 @@
       new NamedLookup<Client>(prologue: serviceNamespace);
   final IdGenerator _serviceRequests = new IdGenerator(prologue: 'sr');
 
+  /// Mapping of client names to all clients of that name and their resume
+  /// permissions.
+  final Map<String, _ClientResumePermissions> clientResumePermissions = {};
+
   /// Collection of currently running isolates.
   RunningIsolates runningIsolates = new RunningIsolates();
 
@@ -214,9 +223,107 @@
 
   final devfs = new DevFS();
 
+  void _clearClientName(Client client) {
+    final name = client.name;
+    client.name = null;
+    final clientsForName = clientResumePermissions[name];
+    if (clientsForName != null) {
+      clientsForName.clients.remove(client);
+      // If this was the last client with a given name, cleanup resume
+      // permissions.
+      if (clientsForName.clients.isEmpty) {
+        clientResumePermissions.remove(name);
+
+        // Check to see if we need to resume any isolates now that the last
+        // client of a given name has disconnected or changed names.
+        //
+        // An isolate will be resumed in this situation if:
+        //
+        // 1) This client required resume approvals for the current pause event
+        // associated with the isolate and all other required resume approvals
+        // have been provided by other clients.
+        //
+        // OR
+        //
+        // 2) This client required resume approvals for the current pause event
+        // associated with the isolate, no other clients require resume approvals
+        // for the current pause event, and at least one client has issued a resume
+        // request.
+        runningIsolates.isolates.forEach((_, isolate) async =>
+            await isolate.maybeResumeAfterClientChange(this, name));
+      }
+    }
+  }
+
+  /// Sets the name associated with a [Client].
+  ///
+  /// If any resume approvals were set for this client previously they will
+  /// need to be reset after a name change.
+  String _setClientName(Message message) {
+    final client = message.client;
+    if (!message.params.containsKey('name')) {
+      return encodeRpcError(message, kInvalidParams,
+          details: "setClientName: missing required parameter 'name'");
+    }
+    final name = message.params['name'];
+    if (name is! String) {
+      return encodeRpcError(message, kInvalidParams,
+          details: "setClientName: invalid 'name' parameter: $name");
+    }
+    _setClientNameHelper(client, name);
+    return encodeSuccess(message);
+  }
+
+  void _setClientNameHelper(Client client, String name) {
+    _clearClientName(client);
+    client.name = name.isEmpty ? client.defaultClientName : name;
+    clientResumePermissions.putIfAbsent(
+        client.name, () => _ClientResumePermissions());
+    clientResumePermissions[client.name].clients.add(client);
+  }
+
+  String _getClientName(Message message) => encodeResult(message, {
+        'type': 'ClientName',
+        'name': message.client.name,
+      });
+
+  String _requirePermissionToResume(Message message) {
+    bool parsePermission(String argName) {
+      final arg = message.params[argName];
+      if (arg == null) {
+        return false;
+      }
+      if (arg is! bool) {
+        throw encodeRpcError(message, kInvalidParams,
+            details: "requirePermissionToResume: invalid '$argName': $arg");
+      }
+      return arg;
+    }
+
+    final client = message.client;
+    int pauseTypeMask = 0;
+    try {
+      if (parsePermission('onPauseStart')) {
+        pauseTypeMask |= RunningIsolate.kPauseOnStartMask;
+      }
+      if (parsePermission('onPauseReload')) {
+        pauseTypeMask |= RunningIsolate.kPauseOnReloadMask;
+      }
+      if (parsePermission('onPauseExit')) {
+        pauseTypeMask |= RunningIsolate.kPauseOnExitMask;
+      }
+    } catch (rpcError) {
+      return rpcError;
+    }
+
+    clientResumePermissions[client.name].permissionsMask = pauseTypeMask;
+    return encodeSuccess(message);
+  }
+
   void _addClient(Client client) {
     assert(client.streams.isEmpty);
     assert(client.services.isEmpty);
+    _setClientNameHelper(client, client.defaultClientName);
     clients.add(client);
   }
 
@@ -228,6 +335,10 @@
         _vmCancelStream(streamId);
       }
     }
+
+    // Clean up client approvals state.
+    _clearClientName(client);
+
     for (var service in client.services.keys) {
       _eventMessageHandler(
           'Service',
@@ -625,6 +736,15 @@
       if (message.method == '_spawnUri') {
         return await _spawnUri(message);
       }
+      if (message.method == 'setClientName') {
+        return _setClientName(message);
+      }
+      if (message.method == 'getClientName') {
+        return _getClientName(message);
+      }
+      if (message.method == 'requirePermissionToResume') {
+        return _requirePermissionToResume(message);
+      }
       if (devfs.shouldHandleMessage(message)) {
         return await devfs.handleMessage(message);
       }
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/cli_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/cli_patch.dart
deleted file mode 100644
index 266941b..0000000
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/cli_patch.dart
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// @dart = 2.5
-
-import 'dart:_js_helper' show patch;
-
-@patch
-void _waitForEvent(int timeoutMillis) {
-  throw UnsupportedError("waitForEvent");
-}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/typed_data_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/typed_data_patch.dart
index f1e2dc1..d1c6a1a 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/typed_data_patch.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/typed_data_patch.dart
@@ -2,7 +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 'dart:_js_helper' show patch;
 import 'dart:_native_typed_data';
 
@@ -100,12 +99,12 @@
 class Int64List {
   @patch
   factory Int64List(int length) {
-    throw UnsupportedError("Int64List not supported by dart2js.");
+    throw UnsupportedError("Int64List not supported on the web.");
   }
 
   @patch
   factory Int64List.fromList(List<int> elements) {
-    throw UnsupportedError("Int64List not supported by dart2js.");
+    throw UnsupportedError("Int64List not supported on the web.");
   }
 }
 
@@ -113,12 +112,12 @@
 class Uint64List {
   @patch
   factory Uint64List(int length) {
-    throw UnsupportedError("Uint64List not supported by dart2js.");
+    throw UnsupportedError("Uint64List not supported on the web.");
   }
 
   @patch
   factory Uint64List.fromList(List<int> elements) {
-    throw UnsupportedError("Uint64List not supported by dart2js.");
+    throw UnsupportedError("Uint64List not supported on the web.");
   }
 }
 
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/interceptors.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/interceptors.dart
index 77451b4..04d492f 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/private/interceptors.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/interceptors.dart
@@ -227,7 +227,7 @@
 // Warning: calls to these methods need to be removed before custom elements
 // and cross-frame dom objects behave correctly in ddc.
 // See https://github.com/dart-lang/sdk/issues/28326
-findInterceptorConstructorForType(Type type) {}
-findConstructorForNativeSubclassType(Type type, String name) {}
+findInterceptorConstructorForType(Type? type) {}
+findConstructorForNativeSubclassType(Type? type, String name) {}
 getNativeInterceptor(object) {}
 setDispatchProperty(object, value) {}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_array.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_array.dart
index 97a6b6b..466cace 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_array.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_array.dart
@@ -452,7 +452,8 @@
   void sort([int Function(E, E)? compare]) {
     checkMutable('sort');
     if (compare == null) {
-      Sort.sort(this, (a, b) => Comparable.compare(a, b));
+      Sort.sort(
+          this, (a, b) => Comparable.compare(a as Comparable, b as Comparable));
     } else {
       Sort.sort(this, compare);
     }
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/native_typed_data.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/native_typed_data.dart
index 4ef894a..3e28657 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/private/native_typed_data.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/native_typed_data.dart
@@ -2,10 +2,8 @@
 // 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.
 
-/**
- * Specialized integers and floating point numbers,
- * with SIMD support and efficient lists.
- */
+/// Specialized integers and floating point numbers,
+/// with SIMD support and efficient lists.
 library dart.typed_data.implementation;
 
 import 'dart:collection';
@@ -17,7 +15,6 @@
         JavaScriptIndexingBehavior,
         JSName,
         Native,
-        Null,
         Returns,
         diagnoseIndexError,
         diagnoseRangeError;
@@ -26,7 +23,7 @@
 
 import 'dart:typed_data';
 
-@Native("ArrayBuffer")
+@Native('ArrayBuffer')
 class NativeByteBuffer implements ByteBuffer {
   @JSName('byteLength')
   external int get lengthInBytes;
@@ -100,20 +97,16 @@
   }
 }
 
-/**
- * A fixed-length list of Float32x4 numbers that is viewable as a
- * [TypedData]. For long lists, this implementation will be considerably more
- * space- and time-efficient than the default [List] implementation.
- */
+/// A fixed-length list of Float32x4 numbers that is viewable as a
+/// [TypedData]. For long lists, this implementation will be considerably more
+/// space- and time-efficient than the default [List] implementation.
 class NativeFloat32x4List extends Object
     with ListMixin<Float32x4>, FixedLengthListMixin<Float32x4>
     implements Float32x4List {
   final Float32List _storage;
 
-  /**
-   * Creates a [Float32x4List] of the specified length (in elements),
-   * all of whose elements are initially zero.
-   */
+  /// Creates a [Float32x4List] of the specified length (in elements),
+  /// all of whose elements are initially zero.
   NativeFloat32x4List(int length) : _storage = NativeFloat32List(length * 4);
 
   NativeFloat32x4List._externalStorage(this._storage);
@@ -131,10 +124,8 @@
 
   Type get runtimeType => Float32x4List;
 
-  /**
-   * Creates a [Float32x4List] with the same size as the [elements] list
-   * and copies over the elements.
-   */
+  /// Creates a [Float32x4List] with the same size as the [elements] list
+  /// and copies over the elements.
   factory NativeFloat32x4List.fromList(List<Float32x4> list) {
     if (list is NativeFloat32x4List) {
       return NativeFloat32x4List._externalStorage(
@@ -178,20 +169,16 @@
   }
 }
 
-/**
- * A fixed-length list of Int32x4 numbers that is viewable as a
- * [TypedData]. For long lists, this implementation will be considerably more
- * space- and time-efficient than the default [List] implementation.
- */
+/// A fixed-length list of Int32x4 numbers that is viewable as a
+/// [TypedData]. For long lists, this implementation will be considerably more
+/// space- and time-efficient than the default [List] implementation.
 class NativeInt32x4List extends Object
     with ListMixin<Int32x4>, FixedLengthListMixin<Int32x4>
     implements Int32x4List {
   final Int32List _storage;
 
-  /**
-   * Creates a [Int32x4List] of the specified length (in elements),
-   * all of whose elements are initially zero.
-   */
+  /// Creates a [Int32x4List] of the specified length (in elements),
+  /// all of whose elements are initially zero.
   NativeInt32x4List(int length) : _storage = NativeInt32List(length * 4);
 
   NativeInt32x4List._externalStorage(Int32List storage) : _storage = storage;
@@ -209,10 +196,8 @@
 
   Type get runtimeType => Int32x4List;
 
-  /**
-   * Creates a [Int32x4List] with the same size as the [elements] list
-   * and copies over the elements.
-   */
+  /// Creates a [Int32x4List] with the same size as the [elements] list
+  /// and copies over the elements.
   factory NativeInt32x4List.fromList(List<Int32x4> list) {
     if (list is NativeInt32x4List) {
       return NativeInt32x4List._externalStorage(
@@ -256,20 +241,16 @@
   }
 }
 
-/**
- * A fixed-length list of Float64x2 numbers that is viewable as a
- * [TypedData]. For long lists, this implementation will be considerably more
- * space- and time-efficient than the default [List] implementation.
- */
+/// A fixed-length list of Float64x2 numbers that is viewable as a
+/// [TypedData]. For long lists, this implementation will be considerably more
+/// space- and time-efficient than the default [List] implementation.
 class NativeFloat64x2List extends Object
     with ListMixin<Float64x2>, FixedLengthListMixin<Float64x2>
     implements Float64x2List {
   final Float64List _storage;
 
-  /**
-   * Creates a [Float64x2List] of the specified length (in elements),
-   * all of whose elements are initially zero.
-   */
+  /// Creates a [Float64x2List] of the specified length (in elements),
+  /// all of whose elements are initially zero.
   NativeFloat64x2List(int length) : _storage = NativeFloat64List(length * 2);
 
   NativeFloat64x2List._externalStorage(this._storage);
@@ -283,10 +264,8 @@
     }
   }
 
-  /**
-   * Creates a [Float64x2List] with the same size as the [elements] list
-   * and copies over the elements.
-   */
+  /// Creates a [Float64x2List] with the same size as the [elements] list
+  /// and copies over the elements.
   factory NativeFloat64x2List.fromList(List<Float64x2> list) {
     if (list is NativeFloat64x2List) {
       return NativeFloat64x2List._externalStorage(
@@ -328,32 +307,24 @@
   }
 }
 
-@Native("ArrayBufferView")
+@Native('ArrayBufferView')
 class NativeTypedData implements TypedData {
-  /**
-   * Returns the byte buffer associated with this object.
-   */
+  /// Returns the byte buffer associated with this object.
   @Creates('NativeByteBuffer')
   // May be Null for IE's CanvasPixelArray.
   @Returns('NativeByteBuffer|Null')
   external ByteBuffer get buffer;
 
-  /**
-   * Returns the length of this view, in bytes.
-   */
+  /// Returns the length of this view, in bytes.
   @JSName('byteLength')
   external int get lengthInBytes;
 
-  /**
-   * Returns the offset in bytes into the underlying byte buffer of this view.
-   */
+  /// Returns the offset in bytes into the underlying byte buffer of this view.
   @JSName('byteOffset')
   external int get offsetInBytes;
 
-  /**
-   * Returns the number of bytes in the representation of each element in this
-   * list.
-   */
+  /// Returns the number of bytes in the representation of each element in this
+  /// list.
   @JSName('BYTES_PER_ELEMENT')
   external int get elementSizeInBytes;
 
@@ -409,26 +380,22 @@
   return result;
 }
 
-@Native("DataView")
+@Native('DataView')
 class NativeByteData extends NativeTypedData implements ByteData {
-  /**
-   * Creates a [ByteData] of the specified length (in elements), all of
-   * whose elements are initially zero.
-   */
+  /// Creates a [ByteData] of the specified length (in elements), all of
+  /// whose elements are initially zero.
   factory NativeByteData(int length) => _create1(_checkLength(length));
 
-  /**
-   * Creates an [ByteData] _view_ of the specified region in the specified
-   * byte buffer. Changes in the [ByteData] will be visible in the byte
-   * buffer and vice versa. If the [offsetInBytes] index of the region is not
-   * specified, it defaults to zero (the first byte in the byte buffer).
-   * If the length is not specified, it defaults to null, which indicates
-   * that the view extends to the end of the byte buffer.
-   *
-   * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
-   * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
-   * the length of [buffer].
-   */
+  /// Creates an [ByteData] _view_ of the specified region in the specified
+  /// byte buffer. Changes in the [ByteData] will be visible in the byte
+  /// buffer and vice versa. If the [offsetInBytes] index of the region is not
+  /// specified, it defaults to zero (the first byte in the byte buffer).
+  /// If the length is not specified, it defaults to null, which indicates
+  /// that the view extends to the end of the byte buffer.
+  ///
+  /// Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+  /// if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+  /// the length of [buffer].
   factory NativeByteData.view(
       ByteBuffer buffer, int offsetInBytes, int? length) {
     _checkViewArguments(buffer, offsetInBytes, length);
@@ -441,14 +408,12 @@
 
   int get elementSizeInBytes => 1;
 
-  /**
-   * Returns the floating point number represented by the four bytes at
-   * the specified [byteOffset] in this object, in IEEE 754
-   * single-precision binary floating-point format (binary32).
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 4` is greater than the length of this object.
-   */
+  /// Returns the floating point number represented by the four bytes at
+  /// the specified [byteOffset] in this object, in IEEE 754
+  /// single-precision binary floating-point format (binary32).
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 4` is greater than the length of this object.
   double getFloat32(int byteOffset, [Endian endian = Endian.big]) =>
       _getFloat32(byteOffset, Endian.little == endian);
 
@@ -456,14 +421,12 @@
   @Returns('double')
   double _getFloat32(int byteOffset, [bool? littleEndian]) native;
 
-  /**
-   * Returns the floating point number represented by the eight bytes at
-   * the specified [byteOffset] in this object, in IEEE 754
-   * double-precision binary floating-point format (binary64).
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 8` is greater than the length of this object.
-   */
+  /// Returns the floating point number represented by the eight bytes at
+  /// the specified [byteOffset] in this object, in IEEE 754
+  /// double-precision binary floating-point format (binary64).
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 8` is greater than the length of this object.
   double getFloat64(int byteOffset, [Endian endian = Endian.big]) =>
       _getFloat64(byteOffset, Endian.little == endian);
 
@@ -471,16 +434,14 @@
   @Returns('double')
   double _getFloat64(int byteOffset, [bool? littleEndian]) native;
 
-  /**
-   * Returns the (possibly negative) integer represented by the two bytes at
-   * the specified [byteOffset] in this object, in two's complement binary
-   * form.
-   * The return value will be between 2<sup>15</sup> and 2<sup>15</sup> - 1,
-   * inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 2` is greater than the length of this object.
-   */
+  /// Returns the (possibly negative) integer represented by the two bytes at
+  /// the specified [byteOffset] in this object, in two's complement binary
+  /// form.
+  /// The return value will be between 2<sup>15</sup> and 2<sup>15</sup> - 1,
+  /// inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 2` is greater than the length of this object.
   int getInt16(int byteOffset, [Endian endian = Endian.big]) =>
       _getInt16(byteOffset, Endian.little == endian);
 
@@ -488,16 +449,14 @@
   @Returns('int')
   int _getInt16(int byteOffset, [bool? littleEndian]) native;
 
-  /**
-   * Returns the (possibly negative) integer represented by the four bytes at
-   * the specified [byteOffset] in this object, in two's complement binary
-   * form.
-   * The return value will be between 2<sup>31</sup> and 2<sup>31</sup> - 1,
-   * inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 4` is greater than the length of this object.
-   */
+  /// Returns the (possibly negative) integer represented by the four bytes at
+  /// the specified [byteOffset] in this object, in two's complement binary
+  /// form.
+  /// The return value will be between 2<sup>31</sup> and 2<sup>31</sup> - 1,
+  /// inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 4` is greater than the length of this object.
   int getInt32(int byteOffset, [Endian endian = Endian.big]) =>
       _getInt32(byteOffset, Endian.little == endian);
 
@@ -505,39 +464,33 @@
   @Returns('int')
   int _getInt32(int byteOffset, [bool? littleEndian]) native;
 
-  /**
-   * Returns the (possibly negative) integer represented by the eight bytes at
-   * the specified [byteOffset] in this object, in two's complement binary
-   * form.
-   * The return value will be between 2<sup>63</sup> and 2<sup>63</sup> - 1,
-   * inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 8` is greater than the length of this object.
-   */
+  /// Returns the (possibly negative) integer represented by the eight bytes at
+  /// the specified [byteOffset] in this object, in two's complement binary
+  /// form.
+  /// The return value will be between 2<sup>63</sup> and 2<sup>63</sup> - 1,
+  /// inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 8` is greater than the length of this object.
   int getInt64(int byteOffset, [Endian endian = Endian.big]) {
     throw UnsupportedError('Int64 accessor not supported by dart2js.');
   }
 
-  /**
-   * Returns the (possibly negative) integer represented by the byte at the
-   * specified [byteOffset] in this object, in two's complement binary
-   * representation. The return value will be between -128 and 127, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * greater than or equal to the length of this object.
-   */
+  /// Returns the (possibly negative) integer represented by the byte at the
+  /// specified [byteOffset] in this object, in two's complement binary
+  /// representation. The return value will be between -128 and 127, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// greater than or equal to the length of this object.
   int getInt8(int byteOffset) native;
 
-  /**
-   * Returns the positive integer represented by the two bytes starting
-   * at the specified [byteOffset] in this object, in unsigned binary
-   * form.
-   * The return value will be between 0 and  2<sup>16</sup> - 1, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 2` is greater than the length of this object.
-   */
+  /// Returns the positive integer represented by the two bytes starting
+  /// at the specified [byteOffset] in this object, in unsigned binary
+  /// form.
+  /// The return value will be between 0 and  2<sup>16</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 2` is greater than the length of this object.
   int getUint16(int byteOffset, [Endian endian = Endian.big]) =>
       _getUint16(byteOffset, Endian.little == endian);
 
@@ -545,15 +498,13 @@
   @Returns('int')
   int _getUint16(int byteOffset, [bool? littleEndian]) native;
 
-  /**
-   * Returns the positive integer represented by the four bytes starting
-   * at the specified [byteOffset] in this object, in unsigned binary
-   * form.
-   * The return value will be between 0 and  2<sup>32</sup> - 1, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 4` is greater than the length of this object.
-   */
+  /// Returns the positive integer represented by the four bytes starting
+  /// at the specified [byteOffset] in this object, in unsigned binary
+  /// form.
+  /// The return value will be between 0 and  2<sup>32</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 4` is greater than the length of this object.
   int getUint32(int byteOffset, [Endian endian = Endian.big]) =>
       _getUint32(byteOffset, Endian.little == endian);
 
@@ -561,172 +512,148 @@
   @Returns('int')
   int _getUint32(int byteOffset, [bool? littleEndian]) native;
 
-  /**
-   * Returns the positive integer represented by the eight bytes starting
-   * at the specified [byteOffset] in this object, in unsigned binary
-   * form.
-   * The return value will be between 0 and  2<sup>64</sup> - 1, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 8` is greater than the length of this object.
-   */
+  /// Returns the positive integer represented by the eight bytes starting
+  /// at the specified [byteOffset] in this object, in unsigned binary
+  /// form.
+  /// The return value will be between 0 and  2<sup>64</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 8` is greater than the length of this object.
   int getUint64(int byteOffset, [Endian endian = Endian.big]) {
     throw UnsupportedError('Uint64 accessor not supported by dart2js.');
   }
 
-  /**
-   * Returns the positive integer represented by the byte at the specified
-   * [byteOffset] in this object, in unsigned binary form. The
-   * return value will be between 0 and 255, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * greater than or equal to the length of this object.
-   */
+  /// Returns the positive integer represented by the byte at the specified
+  /// [byteOffset] in this object, in unsigned binary form. The
+  /// return value will be between 0 and 255, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// greater than or equal to the length of this object.
   int getUint8(int byteOffset) native;
 
-  /**
-   * Sets the four bytes starting at the specified [byteOffset] in this
-   * object to the IEEE 754 single-precision binary floating-point
-   * (binary32) representation of the specified [value].
-   *
-   * **Note that this method can lose precision.** The input [value] is
-   * a 64-bit floating point value, which will be converted to 32-bit
-   * floating point value by IEEE 754 rounding rules before it is stored.
-   * If [value] cannot be represented exactly as a binary32, it will be
-   * converted to the nearest binary32 value.  If two binary32 values are
-   * equally close, the one whose least significant bit is zero will be used.
-   * Note that finite (but large) values can be converted to infinity, and
-   * small non-zero values can be converted to zero.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 4` is greater than the length of this object.
-   */
+  /// Sets the four bytes starting at the specified [byteOffset] in this
+  /// object to the IEEE 754 single-precision binary floating-point
+  /// (binary32) representation of the specified [value].
+  ///
+  /// **Note that this method can lose precision.** The input [value] is
+  /// a 64-bit floating point value, which will be converted to 32-bit
+  /// floating point value by IEEE 754 rounding rules before it is stored.
+  /// If [value] cannot be represented exactly as a binary32, it will be
+  /// converted to the nearest binary32 value.  If two binary32 values are
+  /// equally close, the one whose least significant bit is zero will be used.
+  /// Note that finite (but large) values can be converted to infinity, and
+  /// small non-zero values can be converted to zero.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 4` is greater than the length of this object.
   void setFloat32(int byteOffset, num value, [Endian endian = Endian.big]) =>
       _setFloat32(byteOffset, value, Endian.little == endian);
 
   @JSName('setFloat32')
   void _setFloat32(int byteOffset, num value, [bool? littleEndian]) native;
 
-  /**
-   * Sets the eight bytes starting at the specified [byteOffset] in this
-   * object to the IEEE 754 double-precision binary floating-point
-   * (binary64) representation of the specified [value].
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 8` is greater than the length of this object.
-   */
+  /// Sets the eight bytes starting at the specified [byteOffset] in this
+  /// object to the IEEE 754 double-precision binary floating-point
+  /// (binary64) representation of the specified [value].
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 8` is greater than the length of this object.
   void setFloat64(int byteOffset, num value, [Endian endian = Endian.big]) =>
       _setFloat64(byteOffset, value, Endian.little == endian);
 
   @JSName('setFloat64')
   void _setFloat64(int byteOffset, num value, [bool? littleEndian]) native;
 
-  /**
-   * Sets the two bytes starting at the specified [byteOffset] in this
-   * object to the two's complement binary representation of the specified
-   * [value], which must fit in two bytes. In other words, [value] must lie
-   * between 2<sup>15</sup> and 2<sup>15</sup> - 1, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 2` is greater than the length of this object.
-   */
+  /// Sets the two bytes starting at the specified [byteOffset] in this
+  /// object to the two's complement binary representation of the specified
+  /// [value], which must fit in two bytes. In other words, [value] must lie
+  /// between 2<sup>15</sup> and 2<sup>15</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 2` is greater than the length of this object.
   void setInt16(int byteOffset, int value, [Endian endian = Endian.big]) =>
       _setInt16(byteOffset, value, Endian.little == endian);
 
   @JSName('setInt16')
   void _setInt16(int byteOffset, int value, [bool? littleEndian]) native;
 
-  /**
-   * Sets the four bytes starting at the specified [byteOffset] in this
-   * object to the two's complement binary representation of the specified
-   * [value], which must fit in four bytes. In other words, [value] must lie
-   * between 2<sup>31</sup> and 2<sup>31</sup> - 1, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 4` is greater than the length of this object.
-   */
+  /// Sets the four bytes starting at the specified [byteOffset] in this
+  /// object to the two's complement binary representation of the specified
+  /// [value], which must fit in four bytes. In other words, [value] must lie
+  /// between 2<sup>31</sup> and 2<sup>31</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 4` is greater than the length of this object.
   void setInt32(int byteOffset, int value, [Endian endian = Endian.big]) =>
       _setInt32(byteOffset, value, Endian.little == endian);
 
   @JSName('setInt32')
   void _setInt32(int byteOffset, int value, [bool? littleEndian]) native;
 
-  /**
-   * Sets the eight bytes starting at the specified [byteOffset] in this
-   * object to the two's complement binary representation of the specified
-   * [value], which must fit in eight bytes. In other words, [value] must lie
-   * between 2<sup>63</sup> and 2<sup>63</sup> - 1, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 8` is greater than the length of this object.
-   */
+  /// Sets the eight bytes starting at the specified [byteOffset] in this
+  /// object to the two's complement binary representation of the specified
+  /// [value], which must fit in eight bytes. In other words, [value] must lie
+  /// between 2<sup>63</sup> and 2<sup>63</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 8` is greater than the length of this object.
   void setInt64(int byteOffset, int value, [Endian endian = Endian.big]) {
     throw UnsupportedError('Int64 accessor not supported by dart2js.');
   }
 
-  /**
-   * Sets the byte at the specified [byteOffset] in this object to the
-   * two's complement binary representation of the specified [value], which
-   * must fit in a single byte. In other words, [value] must be between
-   * -128 and 127, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * greater than or equal to the length of this object.
-   */
+  /// Sets the byte at the specified [byteOffset] in this object to the
+  /// two's complement binary representation of the specified [value], which
+  /// must fit in a single byte. In other words, [value] must be between
+  /// -128 and 127, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// greater than or equal to the length of this object.
   void setInt8(int byteOffset, int value) native;
 
-  /**
-   * Sets the two bytes starting at the specified [byteOffset] in this object
-   * to the unsigned binary representation of the specified [value],
-   * which must fit in two bytes. in other words, [value] must be between
-   * 0 and 2<sup>16</sup> - 1, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 2` is greater than the length of this object.
-   */
+  /// Sets the two bytes starting at the specified [byteOffset] in this object
+  /// to the unsigned binary representation of the specified [value],
+  /// which must fit in two bytes. in other words, [value] must be between
+  /// 0 and 2<sup>16</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 2` is greater than the length of this object.
   void setUint16(int byteOffset, int value, [Endian endian = Endian.big]) =>
       _setUint16(byteOffset, value, Endian.little == endian);
 
   @JSName('setUint16')
   void _setUint16(int byteOffset, int value, [bool? littleEndian]) native;
 
-  /**
-   * Sets the four bytes starting at the specified [byteOffset] in this object
-   * to the unsigned binary representation of the specified [value],
-   * which must fit in four bytes. in other words, [value] must be between
-   * 0 and 2<sup>32</sup> - 1, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 4` is greater than the length of this object.
-   */
+  /// Sets the four bytes starting at the specified [byteOffset] in this object
+  /// to the unsigned binary representation of the specified [value],
+  /// which must fit in four bytes. in other words, [value] must be between
+  /// 0 and 2<sup>32</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 4` is greater than the length of this object.
   void setUint32(int byteOffset, int value, [Endian endian = Endian.big]) =>
       _setUint32(byteOffset, value, Endian.little == endian);
 
   @JSName('setUint32')
   void _setUint32(int byteOffset, int value, [bool? littleEndian]) native;
 
-  /**
-   * Sets the eight bytes starting at the specified [byteOffset] in this object
-   * to the unsigned binary representation of the specified [value],
-   * which must fit in eight bytes. in other words, [value] must be between
-   * 0 and 2<sup>64</sup> - 1, inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative, or
-   * `byteOffset + 8` is greater than the length of this object.
-   */
+  /// Sets the eight bytes starting at the specified [byteOffset] in this object
+  /// to the unsigned binary representation of the specified [value],
+  /// which must fit in eight bytes. in other words, [value] must be between
+  /// 0 and 2<sup>64</sup> - 1, inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative, or
+  /// `byteOffset + 8` is greater than the length of this object.
   void setUint64(int byteOffset, int value, [Endian endian = Endian.big]) {
     throw UnsupportedError('Uint64 accessor not supported by dart2js.');
   }
 
-  /**
-   * Sets the byte at the specified [byteOffset] in this object to the
-   * unsigned binary representation of the specified [value], which must fit
-   * in a single byte. in other words, [value] must be between 0 and 255,
-   * inclusive.
-   *
-   * Throws [RangeError] if [byteOffset] is negative,
-   * or greater than or equal to the length of this object.
-   */
+  /// Sets the byte at the specified [byteOffset] in this object to the
+  /// unsigned binary representation of the specified [value], which must fit
+  /// in a single byte. in other words, [value] must be between 0 and 255,
+  /// inclusive.
+  ///
+  /// Throws [RangeError] if [byteOffset] is negative,
+  /// or greater than or equal to the length of this object.
   void setUint8(int byteOffset, int value) native;
 
   static NativeByteData _create1(arg) =>
@@ -813,7 +740,7 @@
   }
 }
 
-@Native("Float32Array")
+@Native('Float32Array')
 class NativeFloat32List extends NativeTypedArrayOfDouble
     implements Float32List {
   factory NativeFloat32List(int length) => _create1(_checkLength(length));
@@ -848,7 +775,7 @@
       JS<NativeFloat32List>('!', 'new Float32Array(#, #, #)', arg1, arg2, arg3);
 }
 
-@Native("Float64Array")
+@Native('Float64Array')
 class NativeFloat64List extends NativeTypedArrayOfDouble
     implements Float64List {
   factory NativeFloat64List(int length) => _create1(_checkLength(length));
@@ -882,7 +809,7 @@
       JS('NativeFloat64List', 'new Float64Array(#, #, #)', arg1, arg2, arg3);
 }
 
-@Native("Int16Array")
+@Native('Int16Array')
 class NativeInt16List extends NativeTypedArrayOfInt implements Int16List {
   factory NativeInt16List(int length) => _create1(_checkLength(length));
 
@@ -920,7 +847,7 @@
       JS('NativeInt16List', 'new Int16Array(#, #, #)', arg1, arg2, arg3);
 }
 
-@Native("Int32Array")
+@Native('Int32Array')
 class NativeInt32List extends NativeTypedArrayOfInt implements Int32List {
   factory NativeInt32List(int length) => _create1(_checkLength(length));
 
@@ -959,7 +886,7 @@
       JS<NativeInt32List>('!', 'new Int32Array(#, #, #)', arg1, arg2, arg3);
 }
 
-@Native("Int8Array")
+@Native('Int8Array')
 class NativeInt8List extends NativeTypedArrayOfInt implements Int8List {
   factory NativeInt8List(int length) => _create1(_checkLength(length));
 
@@ -997,7 +924,7 @@
       JS<NativeInt8List>('!', 'new Int8Array(#, #, #)', arg1, arg2, arg3);
 }
 
-@Native("Uint16Array")
+@Native('Uint16Array')
 class NativeUint16List extends NativeTypedArrayOfInt implements Uint16List {
   factory NativeUint16List(int length) => _create1(_checkLength(length));
 
@@ -1036,7 +963,7 @@
       JS<NativeUint16List>('!', 'new Uint16Array(#, #, #)', arg1, arg2, arg3);
 }
 
-@Native("Uint32Array")
+@Native('Uint32Array')
 class NativeUint32List extends NativeTypedArrayOfInt implements Uint32List {
   factory NativeUint32List(int length) => _create1(_checkLength(length));
 
@@ -1075,7 +1002,7 @@
       JS<NativeUint32List>('!', 'new Uint32Array(#, #, #)', arg1, arg2, arg3);
 }
 
-@Native("Uint8ClampedArray,CanvasPixelArray")
+@Native('Uint8ClampedArray,CanvasPixelArray')
 class NativeUint8ClampedList extends NativeTypedArrayOfInt
     implements Uint8ClampedList {
   factory NativeUint8ClampedList(int length) => _create1(_checkLength(length));
@@ -1126,7 +1053,7 @@
 // Uint8List as !nonleaf ensures that the native dispatch correctly handles
 // the potential for Uint8ClampedArray to 'accidentally' pick up the
 // dispatch record for Uint8List.
-@Native("Uint8Array,!nonleaf")
+@Native('Uint8Array,!nonleaf')
 class NativeUint8List extends NativeTypedArrayOfInt implements Uint8List {
   factory NativeUint8List(int length) => _create1(_checkLength(length));
 
@@ -1167,11 +1094,9 @@
       JS<NativeUint8List>('!', 'new Uint8Array(#, #, #)', arg1, arg2, arg3);
 }
 
-/**
- * Implementation of Dart Float32x4 immutable value type and operations.
- * Float32x4 stores 4 32-bit floating point values in "lanes".
- * The lanes are "x", "y", "z", and "w" respectively.
- */
+/// Implementation of Dart Float32x4 immutable value type and operations.
+/// Float32x4 stores 4 32-bit floating point values in "lanes".
+/// The lanes are "x", "y", "z", and "w" respectively.
 class NativeFloat32x4 implements Float32x4 {
   final double x;
   final double y;
@@ -1501,11 +1426,9 @@
   }
 }
 
-/**
- * Interface of Dart Int32x4 and operations.
- * Int32x4 stores 4 32-bit bit-masks in "lanes".
- * The lanes are "x", "y", "z", and "w" respectively.
- */
+/// Interface of Dart Int32x4 and operations.
+/// Int32x4 stores 4 32-bit bit-masks in "lanes".
+/// The lanes are "x", "y", "z", and "w" respectively.
 class NativeInt32x4 implements Int32x4 {
   final int x;
   final int y;
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/cli_patch.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/cli_patch.dart
deleted file mode 100644
index e66d4e6..0000000
--- a/sdk_nnbd/lib/_internal/js_runtime/lib/cli_patch.dart
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// @dart = 2.5
-
-import 'dart:_js_helper' show patch;
-
-@patch
-void _waitForEvent(int timeoutMillis) {
-  throw new UnsupportedError("waitForEvent");
-}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/native_typed_data.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/native_typed_data.dart
index 47aa6a0..5197c91 100644
--- a/sdk_nnbd/lib/_internal/js_runtime/lib/native_typed_data.dart
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/native_typed_data.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.
 
-// @dart = 2.5
-
 /// Specialized integers and floating point numbers,
 /// with SIMD support and efficient lists.
 library dart.typed_data.implementation;
@@ -28,74 +26,74 @@
 @Native('ArrayBuffer')
 class NativeByteBuffer implements ByteBuffer {
   @JSName('byteLength')
-  final int lengthInBytes;
+  int get lengthInBytes native;
 
   Type get runtimeType => ByteBuffer;
 
-  Uint8List asUint8List([int offsetInBytes = 0, int length]) {
-    return new NativeUint8List.view(this, offsetInBytes, length);
+  Uint8List asUint8List([int offsetInBytes = 0, int? length]) {
+    return NativeUint8List.view(this, offsetInBytes, length);
   }
 
-  Int8List asInt8List([int offsetInBytes = 0, int length]) {
-    return new NativeInt8List.view(this, offsetInBytes, length);
+  Int8List asInt8List([int offsetInBytes = 0, int? length]) {
+    return NativeInt8List.view(this, offsetInBytes, length);
   }
 
-  Uint8ClampedList asUint8ClampedList([int offsetInBytes = 0, int length]) {
-    return new NativeUint8ClampedList.view(this, offsetInBytes, length);
+  Uint8ClampedList asUint8ClampedList([int offsetInBytes = 0, int? length]) {
+    return NativeUint8ClampedList.view(this, offsetInBytes, length);
   }
 
-  Uint16List asUint16List([int offsetInBytes = 0, int length]) {
-    return new NativeUint16List.view(this, offsetInBytes, length);
+  Uint16List asUint16List([int offsetInBytes = 0, int? length]) {
+    return NativeUint16List.view(this, offsetInBytes, length);
   }
 
-  Int16List asInt16List([int offsetInBytes = 0, int length]) {
-    return new NativeInt16List.view(this, offsetInBytes, length);
+  Int16List asInt16List([int offsetInBytes = 0, int? length]) {
+    return NativeInt16List.view(this, offsetInBytes, length);
   }
 
-  Uint32List asUint32List([int offsetInBytes = 0, int length]) {
-    return new NativeUint32List.view(this, offsetInBytes, length);
+  Uint32List asUint32List([int offsetInBytes = 0, int? length]) {
+    return NativeUint32List.view(this, offsetInBytes, length);
   }
 
-  Int32List asInt32List([int offsetInBytes = 0, int length]) {
-    return new NativeInt32List.view(this, offsetInBytes, length);
+  Int32List asInt32List([int offsetInBytes = 0, int? length]) {
+    return NativeInt32List.view(this, offsetInBytes, length);
   }
 
-  Uint64List asUint64List([int offsetInBytes = 0, int length]) {
-    throw new UnsupportedError('Uint64List not supported by dart2js.');
+  Uint64List asUint64List([int offsetInBytes = 0, int? length]) {
+    throw UnsupportedError('Uint64List not supported by dart2js.');
   }
 
-  Int64List asInt64List([int offsetInBytes = 0, int length]) {
-    throw new UnsupportedError('Int64List not supported by dart2js.');
+  Int64List asInt64List([int offsetInBytes = 0, int? length]) {
+    throw UnsupportedError('Int64List not supported by dart2js.');
   }
 
-  Int32x4List asInt32x4List([int offsetInBytes = 0, int length]) {
-    NativeInt32List storage =
+  Int32x4List asInt32x4List([int offsetInBytes = 0, int? length]) {
+    var storage =
         this.asInt32List(offsetInBytes, length != null ? length * 4 : null);
-    return new NativeInt32x4List._externalStorage(storage);
+    return NativeInt32x4List._externalStorage(storage);
   }
 
-  Float32List asFloat32List([int offsetInBytes = 0, int length]) {
-    return new NativeFloat32List.view(this, offsetInBytes, length);
+  Float32List asFloat32List([int offsetInBytes = 0, int? length]) {
+    return NativeFloat32List.view(this, offsetInBytes, length);
   }
 
-  Float64List asFloat64List([int offsetInBytes = 0, int length]) {
-    return new NativeFloat64List.view(this, offsetInBytes, length);
+  Float64List asFloat64List([int offsetInBytes = 0, int? length]) {
+    return NativeFloat64List.view(this, offsetInBytes, length);
   }
 
-  Float32x4List asFloat32x4List([int offsetInBytes = 0, int length]) {
-    NativeFloat32List storage =
+  Float32x4List asFloat32x4List([int offsetInBytes = 0, int? length]) {
+    var storage =
         this.asFloat32List(offsetInBytes, length != null ? length * 4 : null);
-    return new NativeFloat32x4List._externalStorage(storage);
+    return NativeFloat32x4List._externalStorage(storage);
   }
 
-  Float64x2List asFloat64x2List([int offsetInBytes = 0, int length]) {
-    NativeFloat64List storage =
+  Float64x2List asFloat64x2List([int offsetInBytes = 0, int? length]) {
+    var storage =
         this.asFloat64List(offsetInBytes, length != null ? length * 2 : null);
-    return new NativeFloat64x2List._externalStorage(storage);
+    return NativeFloat64x2List._externalStorage(storage);
   }
 
-  ByteData asByteData([int offsetInBytes = 0, int length]) {
-    return new NativeByteData.view(this, offsetInBytes, length);
+  ByteData asByteData([int offsetInBytes = 0, int? length]) {
+    return NativeByteData.view(this, offsetInBytes, length);
   }
 }
 
@@ -105,17 +103,16 @@
 class NativeFloat32x4List extends Object
     with ListMixin<Float32x4>, FixedLengthListMixin<Float32x4>
     implements Float32x4List {
-  final NativeFloat32List _storage;
+  final Float32List _storage;
 
   /// Creates a [Float32x4List] of the specified length (in elements),
   /// all of whose elements are initially zero.
-  NativeFloat32x4List(int length)
-      : _storage = new NativeFloat32List(length * 4);
+  NativeFloat32x4List(int length) : _storage = NativeFloat32List(length * 4);
 
   NativeFloat32x4List._externalStorage(this._storage);
 
   NativeFloat32x4List._slowFromList(List<Float32x4> list)
-      : _storage = new NativeFloat32List(list.length * 4) {
+      : _storage = NativeFloat32List(list.length * 4) {
     for (int i = 0; i < list.length; i++) {
       var e = list[i];
       _storage[(i * 4) + 0] = e.x;
@@ -131,10 +128,10 @@
   /// and copies over the elements.
   factory NativeFloat32x4List.fromList(List<Float32x4> list) {
     if (list is NativeFloat32x4List) {
-      return new NativeFloat32x4List._externalStorage(
-          new NativeFloat32List.fromList(list._storage));
+      return NativeFloat32x4List._externalStorage(
+          NativeFloat32List.fromList(list._storage));
     } else {
-      return new NativeFloat32x4List._slowFromList(list);
+      return NativeFloat32x4List._slowFromList(list);
     }
   }
 
@@ -154,7 +151,7 @@
     double _y = _storage[(index * 4) + 1];
     double _z = _storage[(index * 4) + 2];
     double _w = _storage[(index * 4) + 3];
-    return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+    return NativeFloat32x4._truncated(_x, _y, _z, _w);
   }
 
   void operator []=(int index, Float32x4 value) {
@@ -165,10 +162,10 @@
     _storage[(index * 4) + 3] = value.w;
   }
 
-  Float32x4List sublist(int start, [int end]) {
-    end = _checkValidRange(start, end, this.length);
-    return new NativeFloat32x4List._externalStorage(
-        _storage.sublist(start * 4, end * 4));
+  Float32x4List sublist(int start, [int? end]) {
+    var stop = _checkValidRange(start, end, this.length);
+    return NativeFloat32x4List._externalStorage(
+        _storage.sublist(start * 4, stop * 4));
   }
 }
 
@@ -182,12 +179,12 @@
 
   /// Creates a [Int32x4List] of the specified length (in elements),
   /// all of whose elements are initially zero.
-  NativeInt32x4List(int length) : _storage = new NativeInt32List(length * 4);
+  NativeInt32x4List(int length) : _storage = NativeInt32List(length * 4);
 
   NativeInt32x4List._externalStorage(Int32List storage) : _storage = storage;
 
   NativeInt32x4List._slowFromList(List<Int32x4> list)
-      : _storage = new NativeInt32List(list.length * 4) {
+      : _storage = NativeInt32List(list.length * 4) {
     for (int i = 0; i < list.length; i++) {
       var e = list[i];
       _storage[(i * 4) + 0] = e.x;
@@ -203,10 +200,10 @@
   /// and copies over the elements.
   factory NativeInt32x4List.fromList(List<Int32x4> list) {
     if (list is NativeInt32x4List) {
-      return new NativeInt32x4List._externalStorage(
-          new NativeInt32List.fromList(list._storage));
+      return NativeInt32x4List._externalStorage(
+          NativeInt32List.fromList(list._storage));
     } else {
-      return new NativeInt32x4List._slowFromList(list);
+      return NativeInt32x4List._slowFromList(list);
     }
   }
 
@@ -226,7 +223,7 @@
     int _y = _storage[(index * 4) + 1];
     int _z = _storage[(index * 4) + 2];
     int _w = _storage[(index * 4) + 3];
-    return new NativeInt32x4._truncated(_x, _y, _z, _w);
+    return NativeInt32x4._truncated(_x, _y, _z, _w);
   }
 
   void operator []=(int index, Int32x4 value) {
@@ -237,10 +234,10 @@
     _storage[(index * 4) + 3] = value.w;
   }
 
-  Int32x4List sublist(int start, [int end]) {
-    end = _checkValidRange(start, end, this.length);
-    return new NativeInt32x4List._externalStorage(
-        _storage.sublist(start * 4, end * 4));
+  Int32x4List sublist(int start, [int? end]) {
+    var stop = _checkValidRange(start, end, this.length);
+    return NativeInt32x4List._externalStorage(
+        _storage.sublist(start * 4, stop * 4));
   }
 }
 
@@ -250,17 +247,16 @@
 class NativeFloat64x2List extends Object
     with ListMixin<Float64x2>, FixedLengthListMixin<Float64x2>
     implements Float64x2List {
-  final NativeFloat64List _storage;
+  final Float64List _storage;
 
   /// Creates a [Float64x2List] of the specified length (in elements),
   /// all of whose elements are initially zero.
-  NativeFloat64x2List(int length)
-      : _storage = new NativeFloat64List(length * 2);
+  NativeFloat64x2List(int length) : _storage = NativeFloat64List(length * 2);
 
   NativeFloat64x2List._externalStorage(this._storage);
 
   NativeFloat64x2List._slowFromList(List<Float64x2> list)
-      : _storage = new NativeFloat64List(list.length * 2) {
+      : _storage = NativeFloat64List(list.length * 2) {
     for (int i = 0; i < list.length; i++) {
       var e = list[i];
       _storage[(i * 2) + 0] = e.x;
@@ -272,10 +268,10 @@
   /// and copies over the elements.
   factory NativeFloat64x2List.fromList(List<Float64x2> list) {
     if (list is NativeFloat64x2List) {
-      return new NativeFloat64x2List._externalStorage(
-          new NativeFloat64List.fromList(list._storage));
+      return NativeFloat64x2List._externalStorage(
+          NativeFloat64List.fromList(list._storage));
     } else {
-      return new NativeFloat64x2List._slowFromList(list);
+      return NativeFloat64x2List._slowFromList(list);
     }
   }
 
@@ -295,7 +291,7 @@
     _checkValidIndex(index, this, this.length);
     double _x = _storage[(index * 2) + 0];
     double _y = _storage[(index * 2) + 1];
-    return new Float64x2(_x, _y);
+    return Float64x2(_x, _y);
   }
 
   void operator []=(int index, Float64x2 value) {
@@ -304,10 +300,10 @@
     _storage[(index * 2) + 1] = value.y;
   }
 
-  Float64x2List sublist(int start, [int end]) {
-    end = _checkValidRange(start, end, this.length);
-    return new NativeFloat64x2List._externalStorage(
-        _storage.sublist(start * 2, end * 2));
+  Float64x2List sublist(int start, [int? end]) {
+    var stop = _checkValidRange(start, end, this.length);
+    return NativeFloat64x2List._externalStorage(
+        _storage.sublist(start * 2, stop * 2));
   }
 }
 
@@ -317,26 +313,26 @@
   @Creates('NativeByteBuffer')
   // May be Null for IE's CanvasPixelArray.
   @Returns('NativeByteBuffer|Null')
-  final ByteBuffer buffer;
+  ByteBuffer get buffer native;
 
   /// Returns the length of this view, in bytes.
   @JSName('byteLength')
-  final int lengthInBytes;
+  int get lengthInBytes native;
 
   /// Returns the offset in bytes into the underlying byte buffer of this view.
   @JSName('byteOffset')
-  final int offsetInBytes;
+  int get offsetInBytes native;
 
   /// Returns the number of bytes in the representation of each element in this
   /// list.
   @JSName('BYTES_PER_ELEMENT')
-  final int elementSizeInBytes;
+  int get elementSizeInBytes native;
 
   void _invalidPosition(int position, int length, String name) {
     if (position is! int) {
-      throw new ArgumentError.value(position, name, 'Invalid list position');
+      throw ArgumentError.value(position, name, 'Invalid list position');
     } else {
-      throw new RangeError.range(position, 0, length, name);
+      throw RangeError.range(position, 0, length, name);
     }
   }
 
@@ -353,9 +349,8 @@
 // because passing unvalidated values to the native constructors can cause
 // conversions or create views.
 int _checkLength(length) {
-  return length is int
-      ? length
-      : throw new ArgumentError('Invalid length $length');
+  if (length is! int) throw ArgumentError('Invalid length $length');
+  return length;
 }
 
 // Validates `.view` constructor arguments.  Checking is necessary because
@@ -364,13 +359,13 @@
 // views of the input.
 void _checkViewArguments(buffer, offsetInBytes, length) {
   if (buffer is! NativeByteBuffer) {
-    throw new ArgumentError('Invalid view buffer');
+    throw ArgumentError('Invalid view buffer');
   }
   if (offsetInBytes is! int) {
-    throw new ArgumentError('Invalid view offsetInBytes $offsetInBytes');
+    throw ArgumentError('Invalid view offsetInBytes $offsetInBytes');
   }
-  if (length != null && length is! int) {
-    throw new ArgumentError('Invalid view length $length');
+  if (length is! int?) {
+    throw ArgumentError('Invalid view length $length');
   }
 }
 
@@ -402,7 +397,7 @@
   /// if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
   /// the length of [buffer].
   factory NativeByteData.view(
-      ByteBuffer buffer, int offsetInBytes, int length) {
+      ByteBuffer buffer, int offsetInBytes, int? length) {
     _checkViewArguments(buffer, offsetInBytes, length);
     return length == null
         ? _create2(buffer, offsetInBytes)
@@ -423,8 +418,8 @@
       _getFloat32(byteOffset, Endian.little == endian);
 
   @JSName('getFloat32')
-  @Returns('num')
-  num _getFloat32(int byteOffset, [bool littleEndian]) native;
+  @Returns('double')
+  double _getFloat32(int byteOffset, [bool? littleEndian]) native;
 
   /// Returns the floating point number represented by the eight bytes at
   /// the specified [byteOffset] in this object, in IEEE 754
@@ -436,8 +431,8 @@
       _getFloat64(byteOffset, Endian.little == endian);
 
   @JSName('getFloat64')
-  @Returns('num')
-  num _getFloat64(int byteOffset, [bool littleEndian]) native;
+  @Returns('double')
+  double _getFloat64(int byteOffset, [bool? littleEndian]) native;
 
   /// Returns the (possibly negative) integer represented by the two bytes at
   /// the specified [byteOffset] in this object, in two's complement binary
@@ -452,7 +447,7 @@
 
   @JSName('getInt16')
   @Returns('int')
-  int _getInt16(int byteOffset, [bool littleEndian]) native;
+  int _getInt16(int byteOffset, [bool? littleEndian]) native;
 
   /// Returns the (possibly negative) integer represented by the four bytes at
   /// the specified [byteOffset] in this object, in two's complement binary
@@ -467,7 +462,7 @@
 
   @JSName('getInt32')
   @Returns('int')
-  int _getInt32(int byteOffset, [bool littleEndian]) native;
+  int _getInt32(int byteOffset, [bool? littleEndian]) native;
 
   /// Returns the (possibly negative) integer represented by the eight bytes at
   /// the specified [byteOffset] in this object, in two's complement binary
@@ -478,7 +473,7 @@
   /// Throws [RangeError] if [byteOffset] is negative, or
   /// `byteOffset + 8` is greater than the length of this object.
   int getInt64(int byteOffset, [Endian endian = Endian.big]) {
-    throw new UnsupportedError('Int64 accessor not supported by dart2js.');
+    throw UnsupportedError('Int64 accessor not supported by dart2js.');
   }
 
   /// Returns the (possibly negative) integer represented by the byte at the
@@ -501,7 +496,7 @@
 
   @JSName('getUint16')
   @Returns('JSUInt31')
-  int _getUint16(int byteOffset, [bool littleEndian]) native;
+  int _getUint16(int byteOffset, [bool? littleEndian]) native;
 
   /// Returns the positive integer represented by the four bytes starting
   /// at the specified [byteOffset] in this object, in unsigned binary
@@ -515,7 +510,7 @@
 
   @JSName('getUint32')
   @Returns('JSUInt32')
-  int _getUint32(int byteOffset, [bool littleEndian]) native;
+  int _getUint32(int byteOffset, [bool? littleEndian]) native;
 
   /// Returns the positive integer represented by the eight bytes starting
   /// at the specified [byteOffset] in this object, in unsigned binary
@@ -525,7 +520,7 @@
   /// Throws [RangeError] if [byteOffset] is negative, or
   /// `byteOffset + 8` is greater than the length of this object.
   int getUint64(int byteOffset, [Endian endian = Endian.big]) {
-    throw new UnsupportedError('Uint64 accessor not supported by dart2js.');
+    throw UnsupportedError('Uint64 accessor not supported by dart2js.');
   }
 
   /// Returns the positive integer represented by the byte at the specified
@@ -555,7 +550,7 @@
       _setFloat32(byteOffset, value, Endian.little == endian);
 
   @JSName('setFloat32')
-  void _setFloat32(int byteOffset, num value, [bool littleEndian]) native;
+  void _setFloat32(int byteOffset, num value, [bool? littleEndian]) native;
 
   /// Sets the eight bytes starting at the specified [byteOffset] in this
   /// object to the IEEE 754 double-precision binary floating-point
@@ -567,7 +562,7 @@
       _setFloat64(byteOffset, value, Endian.little == endian);
 
   @JSName('setFloat64')
-  void _setFloat64(int byteOffset, num value, [bool littleEndian]) native;
+  void _setFloat64(int byteOffset, num value, [bool? littleEndian]) native;
 
   /// Sets the two bytes starting at the specified [byteOffset] in this
   /// object to the two's complement binary representation of the specified
@@ -580,7 +575,7 @@
       _setInt16(byteOffset, value, Endian.little == endian);
 
   @JSName('setInt16')
-  void _setInt16(int byteOffset, int value, [bool littleEndian]) native;
+  void _setInt16(int byteOffset, int value, [bool? littleEndian]) native;
 
   /// Sets the four bytes starting at the specified [byteOffset] in this
   /// object to the two's complement binary representation of the specified
@@ -593,7 +588,7 @@
       _setInt32(byteOffset, value, Endian.little == endian);
 
   @JSName('setInt32')
-  void _setInt32(int byteOffset, int value, [bool littleEndian]) native;
+  void _setInt32(int byteOffset, int value, [bool? littleEndian]) native;
 
   /// Sets the eight bytes starting at the specified [byteOffset] in this
   /// object to the two's complement binary representation of the specified
@@ -603,7 +598,7 @@
   /// Throws [RangeError] if [byteOffset] is negative, or
   /// `byteOffset + 8` is greater than the length of this object.
   void setInt64(int byteOffset, int value, [Endian endian = Endian.big]) {
-    throw new UnsupportedError('Int64 accessor not supported by dart2js.');
+    throw UnsupportedError('Int64 accessor not supported by dart2js.');
   }
 
   /// Sets the byte at the specified [byteOffset] in this object to the
@@ -626,7 +621,7 @@
       _setUint16(byteOffset, value, Endian.little == endian);
 
   @JSName('setUint16')
-  void _setUint16(int byteOffset, int value, [bool littleEndian]) native;
+  void _setUint16(int byteOffset, int value, [bool? littleEndian]) native;
 
   /// Sets the four bytes starting at the specified [byteOffset] in this object
   /// to the unsigned binary representation of the specified [value],
@@ -639,7 +634,7 @@
       _setUint32(byteOffset, value, Endian.little == endian);
 
   @JSName('setUint32')
-  void _setUint32(int byteOffset, int value, [bool littleEndian]) native;
+  void _setUint32(int byteOffset, int value, [bool? littleEndian]) native;
 
   /// Sets the eight bytes starting at the specified [byteOffset] in this object
   /// to the unsigned binary representation of the specified [value],
@@ -649,7 +644,7 @@
   /// Throws [RangeError] if [byteOffset] is negative, or
   /// `byteOffset + 8` is greater than the length of this object.
   void setUint64(int byteOffset, int value, [Endian endian = Endian.big]) {
-    throw new UnsupportedError('Uint64 accessor not supported by dart2js.');
+    throw UnsupportedError('Uint64 accessor not supported by dart2js.');
   }
 
   /// Sets the byte at the specified [byteOffset] in this object to the
@@ -680,14 +675,14 @@
     int targetLength = this.length;
     _checkPosition(start, targetLength, 'start');
     _checkPosition(end, targetLength, 'end');
-    if (start > end) throw new RangeError.range(start, 0, end);
+    if (start > end) throw RangeError.range(start, 0, end);
     int count = end - start;
 
-    if (skipCount < 0) throw new ArgumentError(skipCount);
+    if (skipCount < 0) throw ArgumentError(skipCount);
 
     int sourceLength = source.length;
     if (sourceLength - skipCount < count) {
-      throw new StateError('Not enough elements');
+      throw StateError('Not enough elements');
     }
 
     if (skipCount != 0 || sourceLength != count) {
@@ -750,7 +745,7 @@
       _create1(_ensureNativeList(elements));
 
   factory NativeFloat32List.view(
-      ByteBuffer buffer, int offsetInBytes, int length) {
+      ByteBuffer buffer, int offsetInBytes, int? length) {
     _checkViewArguments(buffer, offsetInBytes, length);
     return length == null
         ? _create2(buffer, offsetInBytes)
@@ -759,9 +754,9 @@
 
   Type get runtimeType => Float32List;
 
-  Float32List sublist(int start, [int end]) {
-    end = _checkValidRange(start, end, this.length);
-    var source = JS('NativeFloat32List', '#.subarray(#, #)', this, start, end);
+  Float32List sublist(int start, [int? end]) {
+    var stop = _checkValidRange(start, end, this.length);
+    var source = JS('NativeFloat32List', '#.subarray(#, #)', this, start, stop);
     return _create1(source);
   }
 
@@ -784,7 +779,7 @@
       _create1(_ensureNativeList(elements));
 
   factory NativeFloat64List.view(
-      ByteBuffer buffer, int offsetInBytes, int length) {
+      ByteBuffer buffer, int offsetInBytes, int? length) {
     _checkViewArguments(buffer, offsetInBytes, length);
     return length == null
         ? _create2(buffer, offsetInBytes)
@@ -793,9 +788,9 @@
 
   Type get runtimeType => Float64List;
 
-  Float64List sublist(int start, [int end]) {
-    end = _checkValidRange(start, end, this.length);
-    var source = JS('NativeFloat64List', '#.subarray(#, #)', this, start, end);
+  Float64List sublist(int start, [int? end]) {
+    var stop = _checkValidRange(start, end, this.length);
+    var source = JS('NativeFloat64List', '#.subarray(#, #)', this, start, stop);
     return _create1(source);
   }
 
@@ -817,7 +812,7 @@
       _create1(_ensureNativeList(elements));
 
   factory NativeInt16List.view(
-      NativeByteBuffer buffer, int offsetInBytes, int length) {
+      NativeByteBuffer buffer, int offsetInBytes, int? length) {
     _checkViewArguments(buffer, offsetInBytes, length);
     return length == null
         ? _create2(buffer, offsetInBytes)
@@ -831,9 +826,9 @@
     return JS('int', '#[#]', this, index);
   }
 
-  Int16List sublist(int start, [int end]) {
-    end = _checkValidRange(start, end, this.length);
-    var source = JS('NativeInt16List', '#.subarray(#, #)', this, start, end);
+  Int16List sublist(int start, [int? end]) {
+    var stop = _checkValidRange(start, end, this.length);
+    var source = JS('NativeInt16List', '#.subarray(#, #)', this, start, stop);
     return _create1(source);
   }
 
@@ -855,7 +850,7 @@
       _create1(_ensureNativeList(elements));
 
   factory NativeInt32List.view(
-      ByteBuffer buffer, int offsetInBytes, int length) {
+      ByteBuffer buffer, int offsetInBytes, int? length) {
     _checkViewArguments(buffer, offsetInBytes, length);
     return length == null
         ? _create2(buffer, offsetInBytes)
@@ -869,9 +864,9 @@
     return JS('int', '#[#]', this, index);
   }
 
-  Int32List sublist(int start, [int end]) {
-    end = _checkValidRange(start, end, this.length);
-    var source = JS('NativeInt32List', '#.subarray(#, #)', this, start, end);
+  Int32List sublist(int start, [int? end]) {
+    var stop = _checkValidRange(start, end, this.length);
+    var source = JS('NativeInt32List', '#.subarray(#, #)', this, start, stop);
     return _create1(source);
   }
 
@@ -893,7 +888,7 @@
       _create1(_ensureNativeList(elements));
 
   factory NativeInt8List.view(
-      ByteBuffer buffer, int offsetInBytes, int length) {
+      ByteBuffer buffer, int offsetInBytes, int? length) {
     _checkViewArguments(buffer, offsetInBytes, length);
     return length == null
         ? _create2(buffer, offsetInBytes)
@@ -907,9 +902,9 @@
     return JS('int', '#[#]', this, index);
   }
 
-  Int8List sublist(int start, [int end]) {
-    end = _checkValidRange(start, end, this.length);
-    var source = JS('NativeInt8List', '#.subarray(#, #)', this, start, end);
+  Int8List sublist(int start, [int? end]) {
+    var stop = _checkValidRange(start, end, this.length);
+    var source = JS('NativeInt8List', '#.subarray(#, #)', this, start, stop);
     return _create1(source);
   }
 
@@ -919,7 +914,7 @@
   static NativeInt8List _create2(arg1, arg2) =>
       JS('NativeInt8List', 'new Int8Array(#, #)', arg1, arg2);
 
-  static Int8List _create3(arg1, arg2, arg3) =>
+  static NativeInt8List _create3(arg1, arg2, arg3) =>
       JS('NativeInt8List', 'new Int8Array(#, #, #)', arg1, arg2, arg3);
 }
 
@@ -931,7 +926,7 @@
       _create1(_ensureNativeList(list));
 
   factory NativeUint16List.view(
-      ByteBuffer buffer, int offsetInBytes, int length) {
+      ByteBuffer buffer, int offsetInBytes, int? length) {
     _checkViewArguments(buffer, offsetInBytes, length);
     return length == null
         ? _create2(buffer, offsetInBytes)
@@ -945,9 +940,9 @@
     return JS('JSUInt31', '#[#]', this, index);
   }
 
-  Uint16List sublist(int start, [int end]) {
-    end = _checkValidRange(start, end, this.length);
-    var source = JS('NativeUint16List', '#.subarray(#, #)', this, start, end);
+  Uint16List sublist(int start, [int? end]) {
+    var stop = _checkValidRange(start, end, this.length);
+    var source = JS('NativeUint16List', '#.subarray(#, #)', this, start, stop);
     return _create1(source);
   }
 
@@ -969,7 +964,7 @@
       _create1(_ensureNativeList(elements));
 
   factory NativeUint32List.view(
-      ByteBuffer buffer, int offsetInBytes, int length) {
+      ByteBuffer buffer, int offsetInBytes, int? length) {
     _checkViewArguments(buffer, offsetInBytes, length);
     return length == null
         ? _create2(buffer, offsetInBytes)
@@ -983,9 +978,9 @@
     return JS('JSUInt32', '#[#]', this, index);
   }
 
-  Uint32List sublist(int start, [int end]) {
-    end = _checkValidRange(start, end, this.length);
-    var source = JS('NativeUint32List', '#.subarray(#, #)', this, start, end);
+  Uint32List sublist(int start, [int? end]) {
+    var stop = _checkValidRange(start, end, this.length);
+    var source = JS('NativeUint32List', '#.subarray(#, #)', this, start, stop);
     return _create1(source);
   }
 
@@ -1008,7 +1003,7 @@
       _create1(_ensureNativeList(elements));
 
   factory NativeUint8ClampedList.view(
-      ByteBuffer buffer, int offsetInBytes, int length) {
+      ByteBuffer buffer, int offsetInBytes, int? length) {
     _checkViewArguments(buffer, offsetInBytes, length);
     return length == null
         ? _create2(buffer, offsetInBytes)
@@ -1024,10 +1019,10 @@
     return JS('JSUInt31', '#[#]', this, index);
   }
 
-  Uint8ClampedList sublist(int start, [int end]) {
-    end = _checkValidRange(start, end, this.length);
+  Uint8ClampedList sublist(int start, [int? end]) {
+    var stop = _checkValidRange(start, end, this.length);
     var source =
-        JS('NativeUint8ClampedList', '#.subarray(#, #)', this, start, end);
+        JS('NativeUint8ClampedList', '#.subarray(#, #)', this, start, stop);
     return _create1(source);
   }
 
@@ -1057,7 +1052,7 @@
       _create1(_ensureNativeList(elements));
 
   factory NativeUint8List.view(
-      ByteBuffer buffer, int offsetInBytes, int length) {
+      ByteBuffer buffer, int offsetInBytes, int? length) {
     _checkViewArguments(buffer, offsetInBytes, length);
     return length == null
         ? _create2(buffer, offsetInBytes)
@@ -1073,9 +1068,9 @@
     return JS('JSUInt31', '#[#]', this, index);
   }
 
-  Uint8List sublist(int start, [int end]) {
-    end = _checkValidRange(start, end, this.length);
-    var source = JS('NativeUint8List', '#.subarray(#, #)', this, start, end);
+  Uint8List sublist(int start, [int? end]) {
+    var stop = _checkValidRange(start, end, this.length);
+    var source = JS('NativeUint8List', '#.subarray(#, #)', this, start, stop);
     return _create1(source);
   }
 
@@ -1098,7 +1093,7 @@
   final double z;
   final double w;
 
-  static final NativeFloat32List _list = new NativeFloat32List(4);
+  static final NativeFloat32List _list = NativeFloat32List(4);
   static final Uint32List _uint32view = _list.buffer.asUint32List();
 
   static _truncate(x) {
@@ -1113,10 +1108,10 @@
         this.w = _truncate(w) {
     // We would prefer to check for `double` but in dart2js we can't see the
     // difference anyway.
-    if (x is! num) throw new ArgumentError(x);
-    if (y is! num) throw new ArgumentError(y);
-    if (z is! num) throw new ArgumentError(z);
-    if (w is! num) throw new ArgumentError(w);
+    if (x is! num) throw ArgumentError(x);
+    if (y is! num) throw ArgumentError(y);
+    if (z is! num) throw ArgumentError(z);
+    if (w is! num) throw ArgumentError(w);
   }
 
   NativeFloat32x4.splat(double v) : this(v, v, v, v);
@@ -1128,8 +1123,7 @@
     _uint32view[1] = i.y;
     _uint32view[2] = i.z;
     _uint32view[3] = i.w;
-    return new NativeFloat32x4._truncated(
-        _list[0], _list[1], _list[2], _list[3]);
+    return NativeFloat32x4._truncated(_list[0], _list[1], _list[2], _list[3]);
   }
 
   NativeFloat32x4.fromFloat64x2(Float64x2 v)
@@ -1161,12 +1155,12 @@
     double _y = y + other.y;
     double _z = z + other.z;
     double _w = w + other.w;
-    return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+    return NativeFloat32x4._doubles(_x, _y, _z, _w);
   }
 
   /// Negate operator.
   Float32x4 operator -() {
-    return new NativeFloat32x4._truncated(-x, -y, -z, -w);
+    return NativeFloat32x4._truncated(-x, -y, -z, -w);
   }
 
   /// Subtraction operator.
@@ -1175,7 +1169,7 @@
     double _y = y - other.y;
     double _z = z - other.z;
     double _w = w - other.w;
-    return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+    return NativeFloat32x4._doubles(_x, _y, _z, _w);
   }
 
   /// Multiplication operator.
@@ -1184,7 +1178,7 @@
     double _y = y * other.y;
     double _z = z * other.z;
     double _w = w * other.w;
-    return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+    return NativeFloat32x4._doubles(_x, _y, _z, _w);
   }
 
   /// Division operator.
@@ -1193,7 +1187,7 @@
     double _y = y / other.y;
     double _z = z / other.z;
     double _w = w / other.w;
-    return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+    return NativeFloat32x4._doubles(_x, _y, _z, _w);
   }
 
   /// Relational less than.
@@ -1202,7 +1196,7 @@
     bool _cy = y < other.y;
     bool _cz = z < other.z;
     bool _cw = w < other.w;
-    return new NativeInt32x4._truncated(
+    return NativeInt32x4._truncated(
         _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
   }
 
@@ -1212,7 +1206,7 @@
     bool _cy = y <= other.y;
     bool _cz = z <= other.z;
     bool _cw = w <= other.w;
-    return new NativeInt32x4._truncated(
+    return NativeInt32x4._truncated(
         _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
   }
 
@@ -1222,7 +1216,7 @@
     bool _cy = y > other.y;
     bool _cz = z > other.z;
     bool _cw = w > other.w;
-    return new NativeInt32x4._truncated(
+    return NativeInt32x4._truncated(
         _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
   }
 
@@ -1232,7 +1226,7 @@
     bool _cy = y >= other.y;
     bool _cz = z >= other.z;
     bool _cw = w >= other.w;
-    return new NativeInt32x4._truncated(
+    return NativeInt32x4._truncated(
         _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
   }
 
@@ -1242,7 +1236,7 @@
     bool _cy = y == other.y;
     bool _cz = z == other.z;
     bool _cw = w == other.w;
-    return new NativeInt32x4._truncated(
+    return NativeInt32x4._truncated(
         _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
   }
 
@@ -1252,7 +1246,7 @@
     bool _cy = y != other.y;
     bool _cz = z != other.z;
     bool _cw = w != other.w;
-    return new NativeInt32x4._truncated(
+    return NativeInt32x4._truncated(
         _cx ? -1 : 0, _cy ? -1 : 0, _cz ? -1 : 0, _cw ? -1 : 0);
   }
 
@@ -1262,7 +1256,7 @@
     double _y = s * y;
     double _z = s * z;
     double _w = s * w;
-    return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+    return NativeFloat32x4._doubles(_x, _y, _z, _w);
   }
 
   /// Returns the absolute value of this [Float32x4].
@@ -1271,7 +1265,7 @@
     double _y = y.abs();
     double _z = z.abs();
     double _w = w.abs();
-    return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+    return NativeFloat32x4._truncated(_x, _y, _z, _w);
   }
 
   /// Clamps [this] to be in the range [lowerLimit]-[upperLimit].
@@ -1297,7 +1291,7 @@
     _y = _y < _ly ? _ly : _y;
     _z = _z < _lz ? _lz : _z;
     _w = _w < _lw ? _lw : _w;
-    return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+    return NativeFloat32x4._truncated(_x, _y, _z, _w);
   }
 
   /// Extract the sign bit from each lane return them in the first 4 bits.
@@ -1319,7 +1313,7 @@
   /// Shuffle the lane values. [mask] must be one of the 256 shuffle constants.
   Float32x4 shuffle(int mask) {
     if ((mask < 0) || (mask > 255)) {
-      throw new RangeError.range(mask, 0, 255, 'mask');
+      throw RangeError.range(mask, 0, 255, 'mask');
     }
     _list[0] = x;
     _list[1] = y;
@@ -1330,7 +1324,7 @@
     double _y = _list[(mask >> 2) & 0x3];
     double _z = _list[(mask >> 4) & 0x3];
     double _w = _list[(mask >> 6) & 0x3];
-    return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+    return NativeFloat32x4._truncated(_x, _y, _z, _w);
   }
 
   /// Shuffle the lane values in [this] and [other]. The returned
@@ -1338,7 +1332,7 @@
   /// Uses the same [mask] as [shuffle].
   Float32x4 shuffleMix(Float32x4 other, int mask) {
     if ((mask < 0) || (mask > 255)) {
-      throw new RangeError.range(mask, 0, 255, 'mask');
+      throw RangeError.range(mask, 0, 255, 'mask');
     }
     _list[0] = x;
     _list[1] = y;
@@ -1353,27 +1347,27 @@
     _list[3] = other.w;
     double _z = _list[(mask >> 4) & 0x3];
     double _w = _list[(mask >> 6) & 0x3];
-    return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+    return NativeFloat32x4._truncated(_x, _y, _z, _w);
   }
 
   /// Copy [this] and replace the [x] lane.
   Float32x4 withX(double newX) {
-    return new NativeFloat32x4._truncated(_truncate(newX), y, z, w);
+    return NativeFloat32x4._truncated(_truncate(newX), y, z, w);
   }
 
   /// Copy [this] and replace the [y] lane.
   Float32x4 withY(double newY) {
-    return new NativeFloat32x4._truncated(x, _truncate(newY), z, w);
+    return NativeFloat32x4._truncated(x, _truncate(newY), z, w);
   }
 
   /// Copy [this] and replace the [z] lane.
   Float32x4 withZ(double newZ) {
-    return new NativeFloat32x4._truncated(x, y, _truncate(newZ), w);
+    return NativeFloat32x4._truncated(x, y, _truncate(newZ), w);
   }
 
   /// Copy [this] and replace the [w] lane.
   Float32x4 withW(double newW) {
-    return new NativeFloat32x4._truncated(x, y, z, _truncate(newW));
+    return NativeFloat32x4._truncated(x, y, z, _truncate(newW));
   }
 
   /// Returns the lane-wise minimum value in [this] or [other].
@@ -1382,7 +1376,7 @@
     double _y = y < other.y ? y : other.y;
     double _z = z < other.z ? z : other.z;
     double _w = w < other.w ? w : other.w;
-    return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+    return NativeFloat32x4._truncated(_x, _y, _z, _w);
   }
 
   /// Returns the lane-wise maximum value in [this] or [other].
@@ -1391,7 +1385,7 @@
     double _y = y > other.y ? y : other.y;
     double _z = z > other.z ? z : other.z;
     double _w = w > other.w ? w : other.w;
-    return new NativeFloat32x4._truncated(_x, _y, _z, _w);
+    return NativeFloat32x4._truncated(_x, _y, _z, _w);
   }
 
   /// Returns the square root of [this].
@@ -1400,7 +1394,7 @@
     double _y = Math.sqrt(y);
     double _z = Math.sqrt(z);
     double _w = Math.sqrt(w);
-    return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+    return NativeFloat32x4._doubles(_x, _y, _z, _w);
   }
 
   /// Returns the reciprocal of [this].
@@ -1409,7 +1403,7 @@
     double _y = 1.0 / y;
     double _z = 1.0 / z;
     double _w = 1.0 / w;
-    return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+    return NativeFloat32x4._doubles(_x, _y, _z, _w);
   }
 
   /// Returns the square root of the reciprocal of [this].
@@ -1418,7 +1412,7 @@
     double _y = Math.sqrt(1.0 / y);
     double _z = Math.sqrt(1.0 / z);
     double _w = Math.sqrt(1.0 / w);
-    return new NativeFloat32x4._doubles(_x, _y, _z, _w);
+    return NativeFloat32x4._doubles(_x, _y, _z, _w);
   }
 }
 
@@ -1431,7 +1425,7 @@
   final int z;
   final int w;
 
-  static final _list = new NativeInt32List(4);
+  static final _list = NativeInt32List(4);
 
   static _truncate(x) {
     _list[0] = x;
@@ -1443,10 +1437,10 @@
         this.y = _truncate(y),
         this.z = _truncate(z),
         this.w = _truncate(w) {
-    if (x != this.x && x is! int) throw new ArgumentError(x);
-    if (y != this.y && y is! int) throw new ArgumentError(y);
-    if (z != this.z && z is! int) throw new ArgumentError(z);
-    if (w != this.w && w is! int) throw new ArgumentError(w);
+    if (x != this.x && x is! int) throw ArgumentError(x);
+    if (y != this.y && y is! int) throw ArgumentError(y);
+    if (z != this.z && z is! int) throw ArgumentError(z);
+    if (w != this.w && w is! int) throw ArgumentError(w);
   }
 
   NativeInt32x4.bool(bool x, bool y, bool z, bool w)
@@ -1462,8 +1456,8 @@
     floatList[1] = f.y;
     floatList[2] = f.z;
     floatList[3] = f.w;
-    NativeInt32List view = floatList.buffer.asInt32List();
-    return new NativeInt32x4._truncated(view[0], view[1], view[2], view[3]);
+    var view = floatList.buffer.asInt32List();
+    return NativeInt32x4._truncated(view[0], view[1], view[2], view[3]);
   }
 
   NativeInt32x4._truncated(this.x, this.y, this.z, this.w);
@@ -1474,7 +1468,7 @@
   Int32x4 operator |(Int32x4 other) {
     // Dart2js uses unsigned results for bit-operations.
     // We use "JS" to fall back to the signed versions.
-    return new NativeInt32x4._truncated(
+    return NativeInt32x4._truncated(
         JS('int', '# | #', x, other.x),
         JS('int', '# | #', y, other.y),
         JS('int', '# | #', z, other.z),
@@ -1485,7 +1479,7 @@
   Int32x4 operator &(Int32x4 other) {
     // Dart2js uses unsigned results for bit-operations.
     // We use "JS" to fall back to the signed versions.
-    return new NativeInt32x4._truncated(
+    return NativeInt32x4._truncated(
         JS('int', '# & #', x, other.x),
         JS('int', '# & #', y, other.y),
         JS('int', '# & #', z, other.z),
@@ -1496,7 +1490,7 @@
   Int32x4 operator ^(Int32x4 other) {
     // Dart2js uses unsigned results for bit-operations.
     // We use "JS" to fall back to the signed versions.
-    return new NativeInt32x4._truncated(
+    return NativeInt32x4._truncated(
         JS('int', '# ^ #', x, other.x),
         JS('int', '# ^ #', y, other.y),
         JS('int', '# ^ #', z, other.z),
@@ -1505,7 +1499,7 @@
 
   Int32x4 operator +(Int32x4 other) {
     // Avoid going through the typed array by "| 0" the result.
-    return new NativeInt32x4._truncated(
+    return NativeInt32x4._truncated(
         JS('int', '(# + #) | 0', x, other.x),
         JS('int', '(# + #) | 0', y, other.y),
         JS('int', '(# + #) | 0', z, other.z),
@@ -1514,7 +1508,7 @@
 
   Int32x4 operator -(Int32x4 other) {
     // Avoid going through the typed array by "| 0" the result.
-    return new NativeInt32x4._truncated(
+    return NativeInt32x4._truncated(
         JS('int', '(# - #) | 0', x, other.x),
         JS('int', '(# - #) | 0', y, other.y),
         JS('int', '(# - #) | 0', z, other.z),
@@ -1523,7 +1517,7 @@
 
   Int32x4 operator -() {
     // Avoid going through the typed array by "| 0" the result.
-    return new NativeInt32x4._truncated(
+    return NativeInt32x4._truncated(
         JS('int', '(-#) | 0', x),
         JS('int', '(-#) | 0', y),
         JS('int', '(-#) | 0', z),
@@ -1542,7 +1536,7 @@
   /// Shuffle the lane values. [mask] must be one of the 256 shuffle constants.
   Int32x4 shuffle(int mask) {
     if ((mask < 0) || (mask > 255)) {
-      throw new RangeError.range(mask, 0, 255, 'mask');
+      throw RangeError.range(mask, 0, 255, 'mask');
     }
     _list[0] = x;
     _list[1] = y;
@@ -1552,7 +1546,7 @@
     int _y = _list[(mask >> 2) & 0x3];
     int _z = _list[(mask >> 4) & 0x3];
     int _w = _list[(mask >> 6) & 0x3];
-    return new NativeInt32x4._truncated(_x, _y, _z, _w);
+    return NativeInt32x4._truncated(_x, _y, _z, _w);
   }
 
   /// Shuffle the lane values in [this] and [other]. The returned
@@ -1560,7 +1554,7 @@
   /// Uses the same [mask] as [shuffle].
   Int32x4 shuffleMix(Int32x4 other, int mask) {
     if ((mask < 0) || (mask > 255)) {
-      throw new RangeError.range(mask, 0, 255, 'mask');
+      throw RangeError.range(mask, 0, 255, 'mask');
     }
     _list[0] = x;
     _list[1] = y;
@@ -1575,31 +1569,31 @@
     _list[3] = other.w;
     int _z = _list[(mask >> 4) & 0x3];
     int _w = _list[(mask >> 6) & 0x3];
-    return new NativeInt32x4._truncated(_x, _y, _z, _w);
+    return NativeInt32x4._truncated(_x, _y, _z, _w);
   }
 
   /// Returns a new [Int32x4] copied from [this] with a new x value.
   Int32x4 withX(int x) {
     int _x = _truncate(x);
-    return new NativeInt32x4._truncated(_x, y, z, w);
+    return NativeInt32x4._truncated(_x, y, z, w);
   }
 
   /// Returns a new [Int32x4] copied from [this] with a new y value.
   Int32x4 withY(int y) {
     int _y = _truncate(y);
-    return new NativeInt32x4._truncated(x, _y, z, w);
+    return NativeInt32x4._truncated(x, _y, z, w);
   }
 
   /// Returns a new [Int32x4] copied from [this] with a new z value.
   Int32x4 withZ(int z) {
     int _z = _truncate(z);
-    return new NativeInt32x4._truncated(x, y, _z, w);
+    return NativeInt32x4._truncated(x, y, _z, w);
   }
 
   /// Returns a new [Int32x4] copied from [this] with a new w value.
   Int32x4 withW(int w) {
     int _w = _truncate(w);
-    return new NativeInt32x4._truncated(x, y, z, _w);
+    return NativeInt32x4._truncated(x, y, z, _w);
   }
 
   /// Extracted x value. Returns `false` for 0, `true` for any other value.
@@ -1617,25 +1611,25 @@
   /// Returns a new [Int32x4] copied from [this] with a new x value.
   Int32x4 withFlagX(bool flagX) {
     int _x = flagX ? -1 : 0;
-    return new NativeInt32x4._truncated(_x, y, z, w);
+    return NativeInt32x4._truncated(_x, y, z, w);
   }
 
   /// Returns a new [Int32x4] copied from [this] with a new y value.
   Int32x4 withFlagY(bool flagY) {
     int _y = flagY ? -1 : 0;
-    return new NativeInt32x4._truncated(x, _y, z, w);
+    return NativeInt32x4._truncated(x, _y, z, w);
   }
 
   /// Returns a new [Int32x4] copied from [this] with a new z value.
   Int32x4 withFlagZ(bool flagZ) {
     int _z = flagZ ? -1 : 0;
-    return new NativeInt32x4._truncated(x, y, _z, w);
+    return NativeInt32x4._truncated(x, y, _z, w);
   }
 
   /// Returns a new [Int32x4] copied from [this] with a new w value.
   Int32x4 withFlagW(bool flagW) {
     int _w = flagW ? -1 : 0;
-    return new NativeInt32x4._truncated(x, y, z, _w);
+    return NativeInt32x4._truncated(x, y, z, _w);
   }
 
   /// Merge [trueValue] and [falseValue] based on [this]' bit mask:
@@ -1670,7 +1664,7 @@
     intView[1] = _y;
     intView[2] = _z;
     intView[3] = _w;
-    return new NativeFloat32x4._truncated(
+    return NativeFloat32x4._truncated(
         floatList[0], floatList[1], floatList[2], floatList[3]);
   }
 }
@@ -1679,12 +1673,12 @@
   final double x;
   final double y;
 
-  static NativeFloat64List _list = new NativeFloat64List(2);
-  static NativeUint32List _uint32View = _list.buffer.asUint32List();
+  static NativeFloat64List _list = NativeFloat64List(2);
+  static Uint32List _uint32View = _list.buffer.asUint32List();
 
   NativeFloat64x2(this.x, this.y) {
-    if (x is! num) throw new ArgumentError(x);
-    if (y is! num) throw new ArgumentError(y);
+    if (x is! num) throw ArgumentError(x);
+    if (y is! num) throw ArgumentError(y);
   }
 
   NativeFloat64x2.splat(double v) : this(v, v);
@@ -1700,37 +1694,37 @@
 
   /// Addition operator.
   Float64x2 operator +(Float64x2 other) {
-    return new NativeFloat64x2._doubles(x + other.x, y + other.y);
+    return NativeFloat64x2._doubles(x + other.x, y + other.y);
   }
 
   /// Negate operator.
   Float64x2 operator -() {
-    return new NativeFloat64x2._doubles(-x, -y);
+    return NativeFloat64x2._doubles(-x, -y);
   }
 
   /// Subtraction operator.
   Float64x2 operator -(Float64x2 other) {
-    return new NativeFloat64x2._doubles(x - other.x, y - other.y);
+    return NativeFloat64x2._doubles(x - other.x, y - other.y);
   }
 
   /// Multiplication operator.
   Float64x2 operator *(Float64x2 other) {
-    return new NativeFloat64x2._doubles(x * other.x, y * other.y);
+    return NativeFloat64x2._doubles(x * other.x, y * other.y);
   }
 
   /// Division operator.
   Float64x2 operator /(Float64x2 other) {
-    return new NativeFloat64x2._doubles(x / other.x, y / other.y);
+    return NativeFloat64x2._doubles(x / other.x, y / other.y);
   }
 
   /// Returns a copy of [this] each lane being scaled by [s].
   Float64x2 scale(double s) {
-    return new NativeFloat64x2._doubles(x * s, y * s);
+    return NativeFloat64x2._doubles(x * s, y * s);
   }
 
   /// Returns the absolute value of this [Float64x2].
   Float64x2 abs() {
-    return new NativeFloat64x2._doubles(x.abs(), y.abs());
+    return NativeFloat64x2._doubles(x.abs(), y.abs());
   }
 
   /// Clamps [this] to be in the range [lowerLimit]-[upperLimit].
@@ -1746,7 +1740,7 @@
     _y = _y > _uy ? _uy : _y;
     _x = _x < _lx ? _lx : _x;
     _y = _y < _ly ? _ly : _y;
-    return new NativeFloat64x2._doubles(_x, _y);
+    return NativeFloat64x2._doubles(_x, _y);
   }
 
   /// Extract the sign bits from each lane return them in the first 2 bits.
@@ -1761,31 +1755,31 @@
 
   /// Returns a new [Float64x2] copied from [this] with a new x value.
   Float64x2 withX(double x) {
-    if (x is! num) throw new ArgumentError(x);
-    return new NativeFloat64x2._doubles(x, y);
+    if (x is! num) throw ArgumentError(x);
+    return NativeFloat64x2._doubles(x, y);
   }
 
   /// Returns a new [Float64x2] copied from [this] with a new y value.
   Float64x2 withY(double y) {
-    if (y is! num) throw new ArgumentError(y);
-    return new NativeFloat64x2._doubles(x, y);
+    if (y is! num) throw ArgumentError(y);
+    return NativeFloat64x2._doubles(x, y);
   }
 
   /// Returns the lane-wise minimum value in [this] or [other].
   Float64x2 min(Float64x2 other) {
-    return new NativeFloat64x2._doubles(
+    return NativeFloat64x2._doubles(
         x < other.x ? x : other.x, y < other.y ? y : other.y);
   }
 
   /// Returns the lane-wise maximum value in [this] or [other].
   Float64x2 max(Float64x2 other) {
-    return new NativeFloat64x2._doubles(
+    return NativeFloat64x2._doubles(
         x > other.x ? x : other.x, y > other.y ? y : other.y);
   }
 
   /// Returns the lane-wise square root of [this].
   Float64x2 sqrt() {
-    return new NativeFloat64x2._doubles(Math.sqrt(x), Math.sqrt(y));
+    return NativeFloat64x2._doubles(Math.sqrt(x), Math.sqrt(y));
   }
 }
 
@@ -1811,7 +1805,7 @@
 ///
 /// Returns the actual value of `end`, which is `length` if `end` is `null`, and
 /// the original value of `end` otherwise.
-int _checkValidRange(int start, int end, int length) {
+int _checkValidRange(int start, int? end, int length) {
   if (_isInvalidArrayIndex(start) || // Ensures start is non-negative int.
       ((end == null)
           ? start > length
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/shared/embedded_names.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/shared/embedded_names.dart
index fd2477a..1a581dc 100644
--- a/sdk_nnbd/lib/_internal/js_runtime/lib/shared/embedded_names.dart
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/shared/embedded_names.dart
@@ -281,9 +281,6 @@
   /// instances of parameterized classes.
   RTI_NAME,
 
-  /// Name used to tag typedefs.
-  TYPEDEF_TAG,
-
   /// Name used to tag a function type.
   FUNCTION_TYPE_TAG,
 
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/typed_data_patch.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/typed_data_patch.dart
index 20fe6f6..d1c6a1a 100644
--- a/sdk_nnbd/lib/_internal/js_runtime/lib/typed_data_patch.dart
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/typed_data_patch.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.
 
-// @dart = 2.5
-
 import 'dart:_js_helper' show patch;
 import 'dart:_native_typed_data';
 
@@ -101,12 +99,12 @@
 class Int64List {
   @patch
   factory Int64List(int length) {
-    throw new UnsupportedError("Int64List not supported by dart2js.");
+    throw UnsupportedError("Int64List not supported on the web.");
   }
 
   @patch
   factory Int64List.fromList(List<int> elements) {
-    throw new UnsupportedError("Int64List not supported by dart2js.");
+    throw UnsupportedError("Int64List not supported on the web.");
   }
 }
 
@@ -114,12 +112,12 @@
 class Uint64List {
   @patch
   factory Uint64List(int length) {
-    throw new UnsupportedError("Uint64List not supported by dart2js.");
+    throw UnsupportedError("Uint64List not supported on the web.");
   }
 
   @patch
   factory Uint64List.fromList(List<int> elements) {
-    throw new UnsupportedError("Uint64List not supported by dart2js.");
+    throw UnsupportedError("Uint64List not supported on the web.");
   }
 }
 
diff --git a/sdk_nnbd/lib/_internal/sdk_library_metadata/lib/libraries.dart b/sdk_nnbd/lib/_internal/sdk_library_metadata/lib/libraries.dart
index 2b3e33c..9927bd4 100644
--- a/sdk_nnbd/lib/_internal/sdk_library_metadata/lib/libraries.dart
+++ b/sdk_nnbd/lib/_internal/sdk_library_metadata/lib/libraries.dart
@@ -129,8 +129,7 @@
       documented: false,
       platforms: DART2JS_PLATFORM),
   "cli": const LibraryInfo("cli/cli.dart",
-      categories: "Server",
-      dart2jsPatchPath: "_internal/js_runtime/lib/cli_patch.dart"),
+      categories: "Server", platforms: VM_PLATFORM),
   "svg": const LibraryInfo("svg/dart2js/svg_dart2js.dart",
       categories: "Client",
       maturity: Maturity.WEB_STABLE,
diff --git a/sdk_nnbd/lib/_internal/vm/lib/bigint_patch.dart b/sdk_nnbd/lib/_internal/vm/lib/bigint_patch.dart
index 6c20b56..25f9dbc 100644
--- a/sdk_nnbd/lib/_internal/vm/lib/bigint_patch.dart
+++ b/sdk_nnbd/lib/_internal/vm/lib/bigint_patch.dart
@@ -107,10 +107,10 @@
       new bool.fromEnvironment('dart.vm.not.a.compile.time.constant');
 
   // Result cache for last _divRem call.
-  static late Uint32List _lastDividendDigits;
-  static late int _lastDividendUsed;
-  static late Uint32List _lastDivisorDigits;
-  static late int _lastDivisorUsed;
+  static Uint32List? _lastDividendDigits;
+  static int? _lastDividendUsed;
+  static Uint32List? _lastDivisorDigits;
+  static int? _lastDivisorUsed;
   static late Uint32List _lastQuoRemDigits;
   static late int _lastQuoRemUsed;
   static late int _lastRemUsed;
diff --git a/sdk_nnbd/lib/_internal/vm/lib/convert_patch.dart b/sdk_nnbd/lib/_internal/vm/lib/convert_patch.dart
index 4b0bcf8..d4c2a46 100644
--- a/sdk_nnbd/lib/_internal/vm/lib/convert_patch.dart
+++ b/sdk_nnbd/lib/_internal/vm/lib/convert_patch.dart
@@ -115,7 +115,7 @@
    * started. If the container is a [Map], there is also a current [key]
    * which is also stored on the stack.
    */
-  final List<String> stack = <String>[];
+  final List<Object?> stack = [];
   /** The current [Map] or [List] being built. */
   var currentContainer;
   /** The most recently read property key. */
@@ -133,7 +133,7 @@
   void popContainer() {
     value = currentContainer;
     currentContainer = stack.removeLast();
-    if (currentContainer is Map) key = stack.removeLast();
+    if (currentContainer is Map) key = stack.removeLast() as String;
   }
 
   void handleString(String value) {
diff --git a/sdk_nnbd/lib/cli/wait_for.dart b/sdk_nnbd/lib/cli/wait_for.dart
index 3c9525b..b24fd4d 100644
--- a/sdk_nnbd/lib/cli/wait_for.dart
+++ b/sdk_nnbd/lib/cli/wait_for.dart
@@ -116,7 +116,7 @@
   bool futureCompleted = false;
   Object? error;
   StackTrace? stacktrace;
-  future.then((r) {
+  future.then((T r) {
     futureCompleted = true;
     result = r;
   }, onError: (e, st) {
diff --git a/sdk_nnbd/lib/html/dart2js/html_dart2js.dart b/sdk_nnbd/lib/html/dart2js/html_dart2js.dart
index fb306dc..2bc2ee8 100644
--- a/sdk_nnbd/lib/html/dart2js/html_dart2js.dart
+++ b/sdk_nnbd/lib/html/dart2js/html_dart2js.dart
@@ -36304,7 +36304,7 @@
     if (!containsKey(key)) {
       this[key] = ifAbsent();
     }
-    return this[key];
+    return this[key] as String;
   }
 
   void clear() {
@@ -36316,7 +36316,7 @@
   void forEach(void f(String key, String value)) {
     for (var key in keys) {
       var value = this[key];
-      f(key, value);
+      f(key, value as String);
     }
   }
 
@@ -36325,7 +36325,7 @@
     var attributes = _element._attributes;
     var keys = <String>[];
     for (int i = 0, len = attributes.length; i < len; i++) {
-      _Attr attr = attributes[i];
+      _Attr attr = attributes[i] as _Attr;
       if (_matches(attr)) {
         keys.add(attr.name);
       }
@@ -36338,7 +36338,7 @@
     var attributes = _element._attributes;
     var values = <String>[];
     for (int i = 0, len = attributes.length; i < len; i++) {
-      _Attr attr = attributes[i];
+      _Attr attr = attributes[i] as _Attr;
       if (_matches(attr)) {
         values.add(attr.value);
       }
@@ -36371,11 +36371,11 @@
   _ElementAttributeMap(Element element) : super(element);
 
   bool containsKey(Object? key) {
-    return _element._hasAttribute(key);
+    return _element._hasAttribute(key as String);
   }
 
   String? operator [](Object? key) {
-    return _element.getAttribute(key);
+    return _element.getAttribute(key as String?);
   }
 
   void operator []=(String key, String value) {
@@ -36419,11 +36419,11 @@
   _NamespacedAttributeMap(Element element, this._namespace) : super(element);
 
   bool containsKey(Object? key) {
-    return _element._hasAttributeNS(_namespace, key);
+    return _element._hasAttributeNS(_namespace, key as String);
   }
 
   String? operator [](Object? key) {
-    return _element.getAttributeNS(_namespace, key);
+    return _element.getAttributeNS(_namespace, key as String?);
   }
 
   void operator []=(String key, String value) {
@@ -36482,9 +36482,10 @@
   // TODO: Use lazy iterator when it is available on Map.
   bool containsValue(Object? value) => values.any((v) => v == value);
 
-  bool containsKey(Object? key) => _attributes.containsKey(_attr(key));
+  bool containsKey(Object? key) =>
+      _attributes.containsKey(_attr(key as String));
 
-  String? operator [](Object? key) => _attributes[_attr(key)];
+  String? operator [](Object? key) => _attributes[_attr(key as String)];
 
   void operator []=(String key, String value) {
     _attributes[_attr(key)] = value;
@@ -36493,7 +36494,7 @@
   String putIfAbsent(String key, String ifAbsent()) =>
       _attributes.putIfAbsent(_attr(key), ifAbsent);
 
-  String? remove(Object? key) => _attributes.remove(_attr(key));
+  String? remove(Object? key) => _attributes.remove(_attr(key as String));
 
   void clear() {
     // Needs to operate on a snapshot since we are mutating the collection.
@@ -36672,7 +36673,7 @@
    *     WindowBase otherWindow = thisWindow.open('http://www.example.com/', 'foo');
    *     print(otherWindow.opener == thisWindow); // 'true'
    */
-  WindowBase get opener;
+  WindowBase? get opener;
 
   /**
    * A reference to the parent of this window.
@@ -36686,7 +36687,7 @@
    *
    *     print(window.parent == window) // 'true'
    */
-  WindowBase get parent;
+  WindowBase? get parent;
 
   /**
    * A reference to the topmost window in the window hierarchy.
@@ -36707,7 +36708,7 @@
    *
    *     print(window.top == window) // 'true'
    */
-  WindowBase get top;
+  WindowBase? get top;
 
   // Methods.
   /**
@@ -36753,7 +36754,7 @@
    *   from WHATWG.
    */
   void postMessage(var message, String targetOrigin,
-      [List<MessagePort> messagePorts]);
+      [List<MessagePort>? messagePorts]);
 }
 
 abstract class LocationBase {
@@ -36788,7 +36789,7 @@
    * non-empty string containing no whitespace.  To toggle multiple classes, use
    * [toggleAll].
    */
-  bool toggle(String value, [bool shouldAdd]);
+  bool toggle(String value, [bool? shouldAdd]);
 
   /**
    * Returns [:true:] if classes cannot be added or removed from this
@@ -36872,7 +36873,7 @@
    * Each element of [iterable] must be a valid 'token' representing a single
    * class, i.e. a non-empty string containing no whitespace.
    */
-  void toggleAll(Iterable<String> iterable, [bool shouldAdd]);
+  void toggleAll(Iterable<String> iterable, [bool? shouldAdd]);
 }
 // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
@@ -36949,9 +36950,9 @@
 class _ContentCssListRect extends _ContentCssRect {
   List<Element> _elementList;
 
-  _ContentCssListRect(List<Element> elementList) : super(elementList.first) {
-    _elementList = elementList;
-  }
+  _ContentCssListRect(List<Element> elementList)
+      : _elementList = elementList,
+        super(elementList.first);
 
   /**
    * Set the height to `newHeight`.
@@ -37173,7 +37174,7 @@
    * Returns the intersection of this and `other`, or `null` if they don't
    * intersect.
    */
-  Rectangle<num> intersection(Rectangle<num> other) {
+  Rectangle<num>? intersection(Rectangle<num> other) {
     var x0 = max(left, other.left);
     var x1 = min(left + width, other.left + other.width);
 
@@ -37380,7 +37381,7 @@
     _removeWhere(_element, test, false);
   }
 
-  static bool _contains(Element _element, Object value) {
+  static bool _contains(Element _element, Object? value) {
     return value is String && _classListContains(_classListOf(_element), value);
   }
 
@@ -37437,10 +37438,10 @@
     }
   }
 
-  static void _removeAll(Element _element, Iterable<Object> iterable) {
+  static void _removeAll(Element _element, Iterable<Object?> iterable) {
     DomTokenList list = _classListOf(_element);
-    for (String value in iterable) {
-      _classListRemove(list, value);
+    for (Object? value in iterable) {
+      _classListRemove(list, value as String);
     }
   }
 
@@ -37449,7 +37450,7 @@
     DomTokenList list = _classListOf(_element);
     int i = 0;
     while (i < _classListLength(list)) {
-      String item = list.item(i);
+      String item = list.item(i)!;
       if (doRemove == test(item)) {
         _classListRemove(list, item);
       } else {
@@ -37560,7 +37561,9 @@
    * `inherit` or invalid CSS will cause this constructor to throw a
    * FormatError.
    */
-  Dimension.css(String cssValue) {
+  Dimension.css(String cssValue)
+      : _unit = '',
+        _value = 0 {
     if (cssValue == '') cssValue = '0px';
     if (cssValue.endsWith('%')) {
       _unit = '%';
@@ -37622,7 +37625,7 @@
    * * [EventTarget.addEventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)
    *   from MDN.
    */
-  Stream<T> forTarget(EventTarget e, {bool useCapture: false}) =>
+  Stream<T> forTarget(EventTarget? e, {bool useCapture: false}) =>
       new _EventStream<T>(e, _eventType, useCapture);
 
   /**
@@ -37714,7 +37717,7 @@
  * Adapter for exposing DOM events as Dart streams.
  */
 class _EventStream<T extends Event> extends Stream<T> {
-  final EventTarget _target;
+  final EventTarget? _target;
   final String _eventType;
   final bool _useCapture;
 
@@ -37813,9 +37816,9 @@
 
 class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> {
   int _pauseCount = 0;
-  EventTarget _target;
+  EventTarget? _target;
   final String _eventType;
-  EventListener _onData;
+  EventListener? _onData;
   final bool _useCapture;
 
   // TODO(leafp): It would be better to write this as
@@ -37828,7 +37831,7 @@
   // which are typed correctly.  But this currently runs afoul of restrictions
   // on is checks for compatibility with the VM.
   _EventStreamSubscription(
-      this._target, this._eventType, void onData(T event), this._useCapture)
+      this._target, this._eventType, void onData(T event)?, this._useCapture)
       : _onData = onData == null
             ? null
             : _wrapZone<Event>((e) => (onData as dynamic)(e)) {
@@ -37836,13 +37839,16 @@
   }
 
   Future cancel() {
-    if (_canceled) return null;
+    // Return type cannot be null due to override, so return empty Future
+    // instead.
+    var emptyFuture = new Future<void>.value();
+    if (_canceled) return emptyFuture;
 
     _unlisten();
     // Clear out the target to indicate this is complete.
     _target = null;
     _onData = null;
-    return null;
+    return emptyFuture;
   }
 
   bool get _canceled => _target == null;
@@ -37885,13 +37891,13 @@
 
   void _tryResume() {
     if (_onData != null && !isPaused) {
-      _target.addEventListener(_eventType, _onData, _useCapture);
+      _target!.addEventListener(_eventType, _onData, _useCapture);
     }
   }
 
   void _unlisten() {
     if (_onData != null) {
-      _target.removeEventListener(_eventType, _onData, _useCapture);
+      _target!.removeEventListener(_eventType, _onData, _useCapture);
     }
   }
 
@@ -37920,10 +37926,9 @@
   /** The type of event this stream is providing (e.g. "keydown"). */
   String _type;
 
-  _CustomEventStreamImpl(String type) {
-    _type = type;
-    _streamController = new StreamController.broadcast(sync: true);
-  }
+  _CustomEventStreamImpl(String type)
+      : _type = type,
+        _streamController = new StreamController.broadcast(sync: true);
 
   // Delegate all regular Stream behavior to our wrapped Stream.
   StreamSubscription<T> listen(void onData(T event)?,
@@ -37950,7 +37955,7 @@
 
   void add(KeyEvent event) {
     if (event.type == _type) {
-      event.currentTarget.dispatchEvent(event._parent);
+      event.currentTarget!.dispatchEvent(event._parent);
       _streamController.add(event);
     }
   }
@@ -37962,7 +37967,7 @@
  */
 // TODO (efortuna): Remove this when Issue 12218 is addressed.
 class _StreamPool<T> {
-  StreamController<T> _controller;
+  StreamController<T>? _controller;
 
   /// Subscriptions to the streams that make up the pool.
   var _subscriptions = new Map<Stream<T>, StreamSubscription<T>>();
@@ -37982,7 +37987,7 @@
   /**
    * The stream through which all events from streams in the pool are emitted.
    */
-  Stream<T> get stream => _controller.stream;
+  Stream<T> get stream => _controller!.stream;
 
   /**
    * Adds [stream] as a member of this pool.
@@ -37993,8 +37998,8 @@
    */
   void add(Stream<T> stream) {
     if (_subscriptions.containsKey(stream)) return;
-    _subscriptions[stream] = stream.listen(_controller.add,
-        onError: _controller.addError, onDone: () => remove(stream));
+    _subscriptions[stream] = stream.listen(_controller!.add,
+        onError: _controller!.addError, onDone: () => remove(stream));
   }
 
   /** Removes [stream] as a member of this pool. */
@@ -38009,7 +38014,7 @@
       subscription.cancel();
     }
     _subscriptions.clear();
-    _controller.close();
+    _controller!.close();
   }
 }
 
@@ -38022,7 +38027,7 @@
   final _eventTypeGetter;
   const _CustomEventStreamProvider(this._eventTypeGetter);
 
-  Stream<T> forTarget(EventTarget e, {bool useCapture: false}) {
+  Stream<T> forTarget(EventTarget? e, {bool useCapture: false}) {
     return new _EventStream<T>(e, _eventTypeGetter(e), useCapture);
   }
 
@@ -39455,7 +39460,7 @@
   final String _type;
 
   /** The element we are watching for events to happen on. */
-  final EventTarget _target;
+  final EventTarget? _target;
 
   // The distance to shift from upper case alphabet Roman letters to lower case.
   static final int _ROMAN_ALPHABET_OFFSET = "a".codeUnits[0] - "A".codeUnits[0];
@@ -39498,7 +39503,7 @@
 
   /** Return a stream for KeyEvents for the specified target. */
   // Note: this actually functions like a factory constructor.
-  CustomStream<KeyEvent> forTarget(EventTarget e, {bool useCapture: false}) {
+  CustomStream<KeyEvent> forTarget(EventTarget? e, {bool useCapture: false}) {
     var handler =
         new _KeyboardEventHandler.initializeAllEventListeners(_type, e);
     return handler._stream;
@@ -39518,7 +39523,8 @@
    * and charcodes when they are not provided.
    */
   _KeyboardEventHandler.initializeAllEventListeners(this._type, this._target)
-      : super(_EVENT_TYPE) {
+      : _stream = new _CustomKeyEventStreamImpl(_type),
+        super(_EVENT_TYPE) {
     Element.keyDownEvent
         .forTarget(_target, useCapture: true)
         .listen(processKeyDown);
@@ -39528,7 +39534,6 @@
     Element.keyUpEvent
         .forTarget(_target, useCapture: true)
         .listen(processKeyUp);
-    _stream = new _CustomKeyEventStreamImpl(_type);
   }
 
   /** Determine if caps lock is one of the currently depressed keys. */
@@ -39770,7 +39775,7 @@
         _keyIdentifier.containsKey(e._shadowKeyIdentifier)) {
       // This is needed for Safari Windows because it currently doesn't give a
       // keyCode/which for non printable keys.
-      e._shadowKeyCode = _keyIdentifier[e._shadowKeyIdentifier];
+      e._shadowKeyCode = _keyIdentifier[e._shadowKeyIdentifier]!;
     }
     e._shadowAltKey = _keyDownList.any((var element) => element.altKey);
     _stream.add(e);
@@ -39779,7 +39784,7 @@
   /** Handle keyup events. */
   void processKeyUp(KeyboardEvent event) {
     var e = new KeyEvent.wrap(event);
-    KeyboardEvent toRemove = null;
+    KeyboardEvent? toRemove = null;
     for (var key in _keyDownList) {
       if (key.keyCode == e.keyCode) {
         toRemove = key;
@@ -39883,7 +39888,7 @@
    * The UriPolicy can be used to restrict the locations the navigation elements
    * are allowed to direct to. By default this will use the default [UriPolicy].
    */
-  void allowNavigation([UriPolicy uriPolicy]) {
+  void allowNavigation([UriPolicy? uriPolicy]) {
     if (uriPolicy == null) {
       uriPolicy = new UriPolicy();
     }
@@ -39896,7 +39901,7 @@
    * The UriPolicy can be used to restrict the locations the images may be
    * loaded from. By default this will use the default [UriPolicy].
    */
-  void allowImages([UriPolicy uriPolicy]) {
+  void allowImages([UriPolicy? uriPolicy]) {
     if (uriPolicy == null) {
       uriPolicy = new UriPolicy();
     }
@@ -39937,7 +39942,7 @@
    * If [tagName] is not specified then this allows inline styles on all
    * elements. Otherwise tagName limits the styles to the specified elements.
    */
-  void allowInlineStyles({String tagName}) {
+  void allowInlineStyles({String? tagName}) {
     if (tagName == null) {
       tagName = '*';
     } else {
@@ -39955,7 +39960,7 @@
    * Common things which are not allowed are script elements, style attributes
    * and any script handlers.
    */
-  void allowHtml5({UriPolicy uriPolicy}) {
+  void allowHtml5({UriPolicy? uriPolicy}) {
     add(new _Html5NodeValidator(uriPolicy: uriPolicy));
   }
 
@@ -39974,9 +39979,9 @@
    * tag extensions.
    */
   void allowCustomElement(String tagName,
-      {UriPolicy uriPolicy,
+      {UriPolicy? uriPolicy,
       Iterable<String>? attributes,
-      Iterable<String> uriAttributes}) {
+      Iterable<String>? uriAttributes}) {
     var tagNameUpper = tagName.toUpperCase();
     var attrs = attributes
         ?.map<String>((name) => '$tagNameUpper::${name.toLowerCase()}');
@@ -39999,9 +40004,9 @@
    * custom tags.
    */
   void allowTagExtension(String tagName, String baseName,
-      {UriPolicy uriPolicy,
-      Iterable<String> attributes,
-      Iterable<String> uriAttributes}) {
+      {UriPolicy? uriPolicy,
+      Iterable<String>? attributes,
+      Iterable<String>? uriAttributes}) {
     var baseNameUpper = baseName.toUpperCase();
     var tagNameUpper = tagName.toUpperCase();
     var attrs = attributes
@@ -40017,9 +40022,9 @@
   }
 
   void allowElement(String tagName,
-      {UriPolicy uriPolicy,
-      Iterable<String> attributes,
-      Iterable<String> uriAttributes}) {
+      {UriPolicy? uriPolicy,
+      Iterable<String>? attributes,
+      Iterable<String>? uriAttributes}) {
     allowCustomElement(tagName,
         uriPolicy: uriPolicy,
         attributes: attributes,
@@ -40061,7 +40066,7 @@
   final Set<String> allowedElements = new Set<String>();
   final Set<String> allowedAttributes = new Set<String>();
   final Set<String> allowedUriAttributes = new Set<String>();
-  final UriPolicy uriPolicy;
+  final UriPolicy? uriPolicy;
 
   factory _SimpleNodeValidator.allowNavigation(UriPolicy uriPolicy) {
     return new _SimpleNodeValidator(uriPolicy, allowedElements: const [
@@ -40136,9 +40141,9 @@
    * lowercase attribute name. For example `'IMG:src'`.
    */
   _SimpleNodeValidator(this.uriPolicy,
-      {Iterable<String> allowedElements,
-      Iterable<String> allowedAttributes,
-      Iterable<String> allowedUriAttributes}) {
+      {Iterable<String>? allowedElements,
+      Iterable<String>? allowedAttributes,
+      Iterable<String>? allowedUriAttributes}) {
     this.allowedElements.addAll(allowedElements ?? const []);
     allowedAttributes = allowedAttributes ?? const [];
     allowedUriAttributes = allowedUriAttributes ?? const [];
@@ -40158,9 +40163,9 @@
   bool allowsAttribute(Element element, String attributeName, String value) {
     var tagName = Element._safeTagName(element);
     if (allowedUriAttributes.contains('$tagName::$attributeName')) {
-      return uriPolicy.allowsUri(value);
+      return uriPolicy!.allowsUri(value);
     } else if (allowedUriAttributes.contains('*::$attributeName')) {
-      return uriPolicy.allowsUri(value);
+      return uriPolicy!.allowsUri(value);
     } else if (allowedAttributes.contains('$tagName::$attributeName')) {
       return true;
     } else if (allowedAttributes.contains('*::$attributeName')) {
@@ -40181,8 +40186,8 @@
   _CustomElementNodeValidator(
       UriPolicy uriPolicy,
       Iterable<String> allowedElements,
-      Iterable<String> allowedAttributes,
-      Iterable<String> allowedUriAttributes,
+      Iterable<String>? allowedAttributes,
+      Iterable<String>? allowedUriAttributes,
       bool allowTypeExtension,
       bool allowCustomTag)
       : this.allowTypeExtension = allowTypeExtension == true,
@@ -40335,7 +40340,7 @@
 
   // List APIs
 
-  E operator [](int index) => _list[index];
+  E operator [](int index) => _list[index] as E;
 
   void operator []=(int index, E value) {
     _list[index] = value;
@@ -40346,18 +40351,22 @@
   }
 
   void sort([int compare(E a, E b)?]) {
-    // Implicit downcast on argument from Node to E-extends-Node.
-    _list.sort((Node a, Node b) => compare(a, b));
+    if (compare == null) {
+      _list.sort();
+    } else {
+      _list.sort((Node a, Node b) => compare(a as E, b as E));
+    }
   }
 
-  int indexOf(Object element, [int start = 0]) => _list.indexOf(element, start);
+  int indexOf(Object element, [int start = 0]) =>
+      _list.indexOf(element as Node, start);
 
   int lastIndexOf(Object element, [int? start]) =>
-      _list.lastIndexOf(element, start);
+      _list.lastIndexOf(element as Node, start);
 
   void insert(int index, E element) => _list.insert(index, element);
 
-  E removeAt(int index) => _list.removeAt(index);
+  E removeAt(int index) => _list.removeAt(index) as E;
 
   void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
     _list.setRange(start, end, iterable, skipCount);
@@ -40425,7 +40434,7 @@
   final List<T> _array;
   final int _length; // Cache array length for faster access.
   int _position;
-  T _current;
+  T? _current;
 
   FixedSizeListIterator(List<T> array)
       : _array = array,
@@ -40444,14 +40453,14 @@
     return false;
   }
 
-  T get current => _current;
+  T get current => _current as T;
 }
 
 // Iterator for arrays with variable size.
 class _VariableSizeListIterator<T> implements Iterator<T> {
   final List<T> _array;
   int _position;
-  T _current;
+  T? _current;
 
   _VariableSizeListIterator(List<T> array)
       : _array = array,
@@ -40469,7 +40478,7 @@
     return false;
   }
 
-  T get current => _current;
+  T get current => _current as T;
 }
 // Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
@@ -40481,7 +40490,7 @@
 
   bool get _isConsoleDefined => JS('bool', 'typeof console != "undefined"');
 
-  MemoryInfo get memory =>
+  MemoryInfo? get memory =>
       _isConsoleDefined ? JS('MemoryInfo', 'window.console.memory') : null;
 
   void assertCondition(bool condition, Object arg) => _isConsoleDefined
@@ -40561,12 +40570,12 @@
 // We omit an unwrapper for Window as no methods take a non-local
 // window as a parameter.
 
-WindowBase _convertNativeToDart_Window(win) {
+WindowBase? _convertNativeToDart_Window(win) {
   if (win == null) return null;
   return _DOMWindowCrossFrame._createSafe(win);
 }
 
-EventTarget _convertNativeToDart_EventTarget(e) {
+EventTarget? _convertNativeToDart_EventTarget(e) {
   if (e == null) {
     return null;
   }
@@ -40664,7 +40673,7 @@
   }
 }
 
-Function _registerCustomElement(context, document, String tag, [Map options]) {
+Function _registerCustomElement(context, document, String tag, [Map? options]) {
   // Function follows the same pattern as the following JavaScript code for
   // registering a custom element.
   //
@@ -40680,7 +40689,7 @@
   //    var e = document.createElement('x-foo');
 
   var extendsTagName = '';
-  Type type;
+  Type? type;
   if (options != null) {
     extendsTagName = options['extends'];
     type = options['prototype'];
@@ -40760,7 +40769,7 @@
   var _constructor;
   var _nativeType;
 
-  _JSElementUpgrader(Document document, Type type, String extendsTag) {
+  _JSElementUpgrader(Document document, Type type, String? extendsTag) {
     var interceptorClass = findInterceptorConstructorForType(type);
     if (interceptorClass == null) {
       throw new ArgumentError(type);
@@ -40840,8 +40849,7 @@
   // Methods.
   void close() => JS('void', '#.close()', _window);
 
-  void postMessage(var message, String targetOrigin,
-      [List messagePorts = null]) {
+  void postMessage(var message, String targetOrigin, [List? messagePorts]) {
     if (messagePorts == null) {
       JS('void', '#.postMessage(#,#)', _window,
           convertDartToNative_SerializedScriptValue(message), targetOrigin);
@@ -40878,8 +40886,8 @@
       throw new UnsupportedError(
           'You can only attach EventListeners to your own window.');
   // TODO(efortuna): Remove this method. dartbug.com/16814
-  void addEventListener(String type, EventListener listener,
-          [bool useCapture]) =>
+  void addEventListener(String type, EventListener? listener,
+          [bool? useCapture]) =>
       throw new UnsupportedError(
           'You can only attach EventListeners to your own window.');
   // TODO(efortuna): Remove this method. dartbug.com/16814
@@ -40891,8 +40899,8 @@
       throw new UnsupportedError(
           'You can only attach EventListeners to your own window.');
   // TODO(efortuna): Remove this method. dartbug.com/16814
-  void removeEventListener(String type, EventListener listener,
-          [bool useCapture]) =>
+  void removeEventListener(String type, EventListener? listener,
+          [bool? useCapture]) =>
       throw new UnsupportedError(
           'You can only attach EventListeners to your own window.');
 }
@@ -41008,9 +41016,10 @@
   bool get _realAltKey => JS('bool', '#.altKey', _parent);
 
   /** Shadows on top of the parent's currentTarget. */
-  EventTarget _currentTarget;
+  EventTarget? _currentTarget;
 
-  final InputDeviceCapabilities sourceCapabilities;
+  InputDeviceCapabilities? get sourceCapabilities =>
+      JS('InputDeviceCapabilities', '#.sourceCapabilities', this);
 
   /**
    * The value we want to use for this object's dispatch. Created here so it is
@@ -41025,7 +41034,12 @@
   }
 
   /** Construct a KeyEvent with [parent] as the event we're emulating. */
-  KeyEvent.wrap(KeyboardEvent parent) : super(parent) {
+  KeyEvent.wrap(KeyboardEvent parent)
+      : _parent = parent,
+        _shadowAltKey = false,
+        _shadowCharCode = 0,
+        _shadowKeyCode = 0,
+        super(parent) {
     _parent = parent;
     _shadowAltKey = _realAltKey;
     _shadowCharCode = _realCharCode;
@@ -41035,7 +41049,7 @@
 
   /** Programmatically create a new KeyEvent (and KeyboardEvent). */
   factory KeyEvent(String type,
-      {Window view,
+      {Window? view,
       bool canBubble: true,
       bool cancelable: true,
       int keyCode: 0,
@@ -41045,7 +41059,7 @@
       bool altKey: false,
       bool shiftKey: false,
       bool metaKey: false,
-      EventTarget currentTarget}) {
+      EventTarget? currentTarget}) {
     if (view == null) {
       view = window;
     }
@@ -41103,7 +41117,7 @@
           '&& document.body.dispatchEvent.length > 0');
 
   /** The currently registered target for this event. */
-  EventTarget get currentTarget => _currentTarget;
+  EventTarget? get currentTarget => _currentTarget;
 
   // This is an experimental method to be sure.
   static String _convertToHexString(int charCode, int keyCode) {
@@ -41146,7 +41160,7 @@
   bool get metaKey => _parent.metaKey;
   /** True if the shift key was pressed during this event. */
   bool get shiftKey => _parent.shiftKey;
-  Window get view => _parent.view;
+  WindowBase? get view => _parent.view;
   void _initUIEvent(
       String type, bool canBubble, bool cancelable, Window? view, int detail) {
     throw new UnsupportedError("Cannot initialize a UI Event from a KeyEvent.");
@@ -41166,9 +41180,9 @@
       String type,
       bool canBubble,
       bool cancelable,
-      Window view,
+      Window? view,
       String keyIdentifier,
-      int location,
+      int? location,
       bool ctrlKey,
       bool altKey,
       bool shiftKey,
@@ -41213,7 +41227,7 @@
   final Event wrapped;
 
   /** The CSS selector involved with event delegation. */
-  String _selector;
+  String? _selector;
 
   _WrappedEvent(this.wrapped);
 
@@ -41223,7 +41237,7 @@
 
   bool get composed => wrapped.composed;
 
-  EventTarget get currentTarget => wrapped.currentTarget;
+  EventTarget? get currentTarget => wrapped.currentTarget;
 
   bool get defaultPrevented => wrapped.defaultPrevented;
 
@@ -41231,9 +41245,9 @@
 
   bool get isTrusted => wrapped.isTrusted;
 
-  EventTarget get target => wrapped.target;
+  EventTarget? get target => wrapped.target;
 
-  double get timeStamp => wrapped.timeStamp;
+  double get timeStamp => wrapped.timeStamp as double;
 
   String get type => wrapped.type;
 
@@ -41265,13 +41279,12 @@
       throw new UnsupportedError('Cannot call matchingTarget if this Event did'
           ' not arise as a result of event delegation.');
     }
-    Element currentTarget = this.currentTarget;
-    Element target = this.target;
-    var matchedTarget;
+    Element? currentTarget = this.currentTarget as Element?;
+    Element? target = this.target as Element?;
     do {
-      if (target.matches(_selector)) return target;
+      if (target!.matches(_selector!)) return target;
       target = target.parent;
-    } while (target != null && target != currentTarget.parent);
+    } while (target != null && target != currentTarget!.parent);
     throw new StateError('No selector matched for populating matchedTarget.');
   }
 
@@ -41285,7 +41298,7 @@
    *   from W3C.
    */
   // https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#extensions-to-event
-  List<Node> get path => wrapped.path;
+  List<Node> get path => wrapped.path as List<Node>;
 
   dynamic get _get_currentTarget => wrapped._get_currentTarget;
 
@@ -41298,14 +41311,12 @@
 void Function(T) _wrapZone<T>(void Function(T) callback) {
   // For performance reasons avoid wrapping if we are in the root zone.
   if (Zone.current == Zone.root) return callback;
-  if (callback == null) return null;
   return Zone.current.bindUnaryCallbackGuarded(callback);
 }
 
 void Function(T1, T2) _wrapBinaryZone<T1, T2>(void Function(T1, T2) callback) {
   // For performance reasons avoid wrapping if we are in the root zone.
   if (Zone.current == Zone.root) return callback;
-  if (callback == null) return null;
   return Zone.current.bindBinaryCallbackGuarded(callback);
 }
 
@@ -41326,7 +41337,7 @@
  * For details about CSS selector syntax, see the
  * [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
  */
-Element querySelector(String selectors) => document.querySelector(selectors);
+Element? querySelector(String selectors) => document.querySelector(selectors);
 
 /**
  * Finds all descendant elements of this document that match the specified
@@ -41374,7 +41385,7 @@
    *
    * If a uriPolicy is not specified then the default uriPolicy will be used.
    */
-  factory NodeValidator({UriPolicy uriPolicy}) =>
+  factory NodeValidator({UriPolicy? uriPolicy}) =>
       new _Html5NodeValidator(uriPolicy: uriPolicy);
 
   factory NodeValidator.throws(NodeValidator base) =>
@@ -41514,7 +41525,7 @@
   _ValidatingTreeSanitizer(this.validator) {}
 
   void sanitizeTree(Node node) {
-    void walk(Node node, Node parent) {
+    void walk(Node node, Node? parent) {
       sanitizeNode(node, parent);
 
       var child = node.lastChild;
@@ -41541,7 +41552,7 @@
   }
 
   /// Aggressively try to remove node.
-  void _removeNode(Node node, Node parent) {
+  void _removeNode(Node node, Node? parent) {
     // If we have the parent, it's presumably already passed more sanitization
     // or is the fragment, so ask it to remove the child. And if that fails
     // try to set the outer html.
@@ -41553,7 +41564,7 @@
   }
 
   /// Sanitize the element, assuming we can't trust anything about it.
-  void _sanitizeUntrustedElement(/* Element */ element, Node parent) {
+  void _sanitizeUntrustedElement(/* Element */ element, Node? parent) {
     // If the _hasCorruptedAttributes does not successfully return false,
     // then we consider it corrupted and remove.
     // TODO(alanknight): This is a workaround because on Firefox
@@ -41602,7 +41613,7 @@
   /// Having done basic sanity checking on the element, and computed the
   /// important attributes we want to check, remove it if it's not valid
   /// or not allowed, either as a whole or particular attributes.
-  void _sanitizeElement(Element element, Node parent, bool corrupted,
+  void _sanitizeElement(Element element, Node? parent, bool corrupted,
       String text, String tag, Map attrs, String isAttr) {
     if (false != corrupted) {
       _removeNode(element, parent);
@@ -41645,7 +41656,7 @@
   }
 
   /// Sanitize the node and its children recursively.
-  void sanitizeNode(Node node, Node parent) {
+  void sanitizeNode(Node node, Node? parent) {
     switch (node.nodeType) {
       case Node.ELEMENT_NODE:
         _sanitizeUntrustedElement(node, parent);
diff --git a/sdk_nnbd/lib/libraries.json b/sdk_nnbd/lib/libraries.json
index 72a984b..d98f2aa 100644
--- a/sdk_nnbd/lib/libraries.json
+++ b/sdk_nnbd/lib/libraries.json
@@ -223,11 +223,11 @@
         "supported": false
       },
       "typed_data": {
-        "uri": "../../sdk/lib/typed_data/typed_data.dart",
-        "patches": "../../sdk/lib/_internal/js_runtime/lib/typed_data_patch.dart"
+        "uri": "typed_data/typed_data.dart",
+        "patches": "_internal/js_runtime/lib/typed_data_patch.dart"
       },
       "_native_typed_data": {
-        "uri": "../../sdk/lib/_internal/js_runtime/lib/native_typed_data.dart"
+        "uri": "_internal/js_runtime/lib/native_typed_data.dart"
       },
       "svg": {
         "uri": "../../sdk/lib/svg/dart2js/svg_dart2js.dart"
@@ -333,11 +333,11 @@
         "supported": false
       },
       "typed_data": {
-        "uri": "../../sdk/lib/typed_data/typed_data.dart",
-        "patches": "../../sdk/lib/_internal/js_runtime/lib/typed_data_patch.dart"
+        "uri": "typed_data/typed_data.dart",
+        "patches": "_internal/js_runtime/lib/typed_data_patch.dart"
       },
       "_native_typed_data": {
-        "uri": "../../sdk/lib/_internal/js_runtime/lib/native_typed_data.dart"
+        "uri": "_internal/js_runtime/lib/native_typed_data.dart"
       },
       "_internal": {
         "uri": "../../sdk/lib/internal/internal.dart",
diff --git a/sdk_nnbd/lib/libraries.yaml b/sdk_nnbd/lib/libraries.yaml
index 1feb5cc..8d4d307 100644
--- a/sdk_nnbd/lib/libraries.yaml
+++ b/sdk_nnbd/lib/libraries.yaml
@@ -220,11 +220,11 @@
       supported: false
 
     typed_data:
-      uri: "../../sdk/lib/typed_data/typed_data.dart"
-      patches: "../../sdk/lib/_internal/js_runtime/lib/typed_data_patch.dart"
+      uri: "typed_data/typed_data.dart"
+      patches: "_internal/js_runtime/lib/typed_data_patch.dart"
 
     _native_typed_data:
-      uri: "../../sdk/lib/_internal/js_runtime/lib/native_typed_data.dart"
+      uri: "_internal/js_runtime/lib/native_typed_data.dart"
 
     svg:
       uri: "../../sdk/lib/svg/dart2js/svg_dart2js.dart"
@@ -328,11 +328,11 @@
       supported: false
 
     typed_data:
-      uri: "../../sdk/lib/typed_data/typed_data.dart"
-      patches: "../../sdk/lib/_internal/js_runtime/lib/typed_data_patch.dart"
+      uri: "typed_data/typed_data.dart"
+      patches: "_internal/js_runtime/lib/typed_data_patch.dart"
 
     _native_typed_data:
-      uri: "../../sdk/lib/_internal/js_runtime/lib/native_typed_data.dart"
+      uri: "_internal/js_runtime/lib/native_typed_data.dart"
 
     _internal:
       uri: "../../sdk/lib/internal/internal.dart"
diff --git a/sdk_nnbd/lib/svg/dart2js/svg_dart2js.dart b/sdk_nnbd/lib/svg/dart2js/svg_dart2js.dart
index 4393f4b..792a63a 100644
--- a/sdk_nnbd/lib/svg/dart2js/svg_dart2js.dart
+++ b/sdk_nnbd/lib/svg/dart2js/svg_dart2js.dart
@@ -30,7 +30,7 @@
   static SvgElement createSvgElement_tag(String tag) {
     final Element temp =
         document.createElementNS("http://www.w3.org/2000/svg", tag);
-    return temp;
+    return temp as SvgElement;
   }
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
diff --git a/sdk_nnbd/lib/vmservice/client.dart b/sdk_nnbd/lib/vmservice/client.dart
index 69bb112..65a72ba 100644
--- a/sdk_nnbd/lib/vmservice/client.dart
+++ b/sdk_nnbd/lib/vmservice/client.dart
@@ -11,6 +11,15 @@
   final VMService service;
   final bool sendEvents;
 
+  static int _idCounter = 0;
+  final int _id = ++_idCounter;
+
+  String get defaultClientName => 'client$_id';
+
+  String get name => _name;
+  set name(String? n) => _name = (n ?? defaultClientName);
+  late String _name;
+
   /// A set streamIds which describes the streams the client is connected to
   final streams = <String>{};
 
@@ -25,6 +34,7 @@
   final serviceHandles = <String, ClientServiceHandle>{};
 
   Client(this.service, {this.sendEvents = true}) {
+    _name = defaultClientName;
     service._addClient(this);
   }
 
diff --git a/sdk_nnbd/lib/vmservice/message.dart b/sdk_nnbd/lib/vmservice/message.dart
index 2c0a48c..31275b4 100644
--- a/sdk_nnbd/lib/vmservice/message.dart
+++ b/sdk_nnbd/lib/vmservice/message.dart
@@ -159,7 +159,7 @@
     };
     final keys = _makeAllString(params.keys.toList(growable: false));
     final values = _makeAllString(params.values.toList(growable: false));
-    final request = List.filled(6, null)
+    final request = List<dynamic>.filled(6, null)
       ..[0] = 0 // Make room for OOB message type.
       ..[1] = receivePort.sendPort
       ..[2] = serial
@@ -207,7 +207,7 @@
       keys = _makeAllString(keys);
       values = _makeAllString(values);
     }
-    final request = List.filled(6, null)
+    final request = List<dynamic>.filled(6, null)
       ..[0] = 0 // Make room for OOB message type.
       ..[1] = receivePort.sendPort
       ..[2] = serial
diff --git a/sdk_nnbd/lib/vmservice/running_isolate.dart b/sdk_nnbd/lib/vmservice/running_isolate.dart
index 9e88b6d..38af814 100644
--- a/sdk_nnbd/lib/vmservice/running_isolate.dart
+++ b/sdk_nnbd/lib/vmservice/running_isolate.dart
@@ -8,15 +8,109 @@
   final int portId;
   final SendPort sendPort;
   final String name;
+  final Set<String> _resumeApprovalsByName = {};
 
   RunningIsolate(this.portId, this.sendPort, this.name);
 
   String get serviceId => 'isolates/$portId';
 
+  static const kInvalidPauseEvent = -1;
+  static const kPauseOnStartMask = 1 << 0;
+  static const kPauseOnReloadMask = 1 << 1;
+  static const kPauseOnExitMask = 1 << 2;
+  static const kDefaultResumePermissionMask =
+      kPauseOnStartMask | kPauseOnReloadMask | kPauseOnExitMask;
+
+  /// Resumes the isolate if all clients which need to approve a resume have
+  /// done so. Called when the last client of a given name disconnects or
+  /// changes name to ensure we don't deadlock waiting for approval to resume
+  /// from a disconnected client.
+  Future<void> maybeResumeAfterClientChange(
+      VMService service, String disconnectedClientName) async {
+    // Remove approvals from the disconnected client.
+    _resumeApprovalsByName.remove(disconnectedClientName);
+
+    // If we've received approval to resume from all clients who care, clear
+    // approval state and resume.
+    final pauseType = await _isolatePauseType(service, portId.toString());
+    if (pauseType != kInvalidPauseEvent &&
+        _shouldResume(service, null, pauseType)) {
+      _resumeApprovalsByName.clear();
+      await Message.forMethod('resume')
+        ..params.addAll({
+          'isolateId': portId,
+        })
+        ..sendToIsolate(sendPort);
+    }
+  }
+
+  bool _shouldResume(VMService service, Client? client, int pauseType) {
+    if (client != null) {
+      // Mark the approval by the client.
+      _resumeApprovalsByName.add(client.name);
+    }
+    final requiredClientApprovals = <String>{};
+    final permissions = service.clientResumePermissions;
+
+    // Determine which clients require approval for this pause type.
+    permissions.forEach((name, clientNamePermissions) {
+      if (clientNamePermissions.permissionsMask & pauseType != 0) {
+        requiredClientApprovals.add(name);
+      }
+    });
+
+    // We require at least a single client to resume, even if that client
+    // doesn't require resume approval.
+    if (_resumeApprovalsByName.isEmpty) {
+      return false;
+    }
+
+    // If all the required approvals are present, we should resume.
+    return _resumeApprovalsByName.containsAll(requiredClientApprovals);
+  }
+
+  Future<int> _isolatePauseType(VMService service, String isolateId) async {
+    final getIsolateMessage = Message.forMethod('getIsolate')
+      ..params.addAll({
+        'isolateId': isolateId,
+      });
+    final result =
+        (await routeRequest(service, getIsolateMessage)).decodeJson();
+    final pauseEvent = result['result']['pauseEvent'];
+    const pauseEvents = <String, int>{
+      'PauseStart': kPauseOnStartMask,
+      'PausePostRequest': kPauseOnReloadMask,
+      'PauseExit': kPauseOnExitMask,
+    };
+    final kind = pauseEvent['kind'];
+    return pauseEvents[kind] ?? kInvalidPauseEvent;
+  }
+
+  Future<Response> _routeResumeRequest(
+      VMService service, Message message) async {
+    // If we've received approval to resume from all clients who care, clear
+    // approval state and resume.
+    final pauseType =
+        await _isolatePauseType(service, message.params['isolateId']);
+    if (pauseType == kInvalidPauseEvent ||
+        _shouldResume(service, message.client, pauseType)) {
+      _resumeApprovalsByName.clear();
+      return message.sendToIsolate(sendPort);
+    }
+
+    // We're still awaiting some approvals. Simply return success, but don't
+    // resume yet.
+    return Response(ResponsePayloadKind.String, encodeSuccess(message));
+  }
+
   @override
-  Future<Response> routeRequest(VMService service, Message message) =>
-      // Send message to isolate.
-      message.sendToIsolate(sendPort);
+  Future<Response> routeRequest(VMService service, Message message) {
+    if (message.method == 'resume') {
+      return _routeResumeRequest(service, message);
+    }
+    // Send message to isolate.
+    return message.sendToIsolate(sendPort);
+  }
 
   @override
   void routeResponse(Message message) {}
diff --git a/sdk_nnbd/lib/vmservice/vmservice.dart b/sdk_nnbd/lib/vmservice/vmservice.dart
index 272ba1a..41833ba 100644
--- a/sdk_nnbd/lib/vmservice/vmservice.dart
+++ b/sdk_nnbd/lib/vmservice/vmservice.dart
@@ -183,6 +183,11 @@
   static WebServerControlCallback? webServerControl;
 }
 
+class _ClientResumePermissions {
+  final List<Client> clients = [];
+  int permissionsMask = 0;
+}
+
 class VMService extends MessageRouter {
   static VMService? _instance;
 
@@ -192,6 +197,10 @@
   final clients = NamedLookup<Client>(prologue: serviceNamespace);
   final _serviceRequests = IdGenerator(prologue: 'sr');
 
+  /// Mapping of client names to all clients of that name and their resume
+  /// permissions.
+  final Map<String, _ClientResumePermissions> clientResumePermissions = {};
+
   /// Collection of currently running isolates.
   final runningIsolates = RunningIsolates();
 
@@ -203,6 +212,104 @@
 
   final devfs = DevFS();
 
+  void _clearClientName(Client client) {
+    final name = client.name;
+    client.name = null;
+    final clientsForName = clientResumePermissions[name];
+    if (clientsForName != null) {
+      clientsForName.clients.remove(client);
+      // If this was the last client with a given name, cleanup resume
+      // permissions.
+      if (clientsForName.clients.isEmpty) {
+        clientResumePermissions.remove(name);
+
+        // Check to see if we need to resume any isolates now that the last
+        // client of a given name has disconnected or changed names.
+        //
+        // An isolate will be resumed in this situation if:
+        //
+        // 1) This client required resume approvals for the current pause event
+        // associated with the isolate and all other required resume approvals
+        // have been provided by other clients.
+        //
+        // OR
+        //
+        // 2) This client required resume approvals for the current pause event
+        // associated with the isolate, no other clients require resume approvals
+        // for the current pause event, and at least one client has issued a resume
+        // request.
+        runningIsolates.isolates.forEach((_, isolate) async =>
+            await isolate.maybeResumeAfterClientChange(this, name));
+      }
+    }
+  }
+
+  /// Sets the name associated with a [Client].
+  ///
+  /// If any resume approvals were set for this client previously they will
+  /// need to be reset after a name change.
+  String _setClientName(Message message) {
+    final client = message.client!;
+    if (!message.params.containsKey('name')) {
+      return encodeRpcError(message, kInvalidParams,
+          details: "setClientName: missing required parameter 'name'");
+    }
+    final name = message.params['name'];
+    if (name is! String) {
+      return encodeRpcError(message, kInvalidParams,
+          details: "setClientName: invalid 'name' parameter: $name");
+    }
+    _setClientNameHelper(client, name);
+    return encodeSuccess(message);
+  }
+
+  void _setClientNameHelper(Client client, String name) {
+    _clearClientName(client);
+    name = name.isEmpty ? client.defaultClientName : name;
+    client.name = name;
+    clientResumePermissions.putIfAbsent(
+        client.name, () => _ClientResumePermissions());
+    clientResumePermissions[name]!.clients.add(client);
+  }
+
+  String _getClientName(Message message) => encodeResult(message, {
+        'type': 'ClientName',
+        'name': message.client!.name,
+      });
+
+  String _requirePermissionToResume(Message message) {
+    bool parsePermission(String argName) {
+      final arg = message.params[argName];
+      if (arg == null) {
+        return false;
+      }
+      if (arg is! bool) {
+        throw encodeRpcError(message, kInvalidParams,
+            details: "requirePermissionToResume: invalid '$argName': $arg");
+      }
+      return arg;
+    }
+
+    final client = message.client!;
+    int pauseTypeMask = 0;
+    try {
+      if (parsePermission('onPauseStart')) {
+        pauseTypeMask |= RunningIsolate.kPauseOnStartMask;
+      }
+      if (parsePermission('onPauseReload')) {
+        pauseTypeMask |= RunningIsolate.kPauseOnReloadMask;
+      }
+      if (parsePermission('onPauseExit')) {
+        pauseTypeMask |= RunningIsolate.kPauseOnExitMask;
+      }
+    } catch (rpcError) {
+      return rpcError;
+    }
+
+    clientResumePermissions[client.name]!.permissionsMask = pauseTypeMask;
+    return encodeSuccess(message);
+  }
+
   void _addClient(Client client) {
     assert(client.streams.isEmpty);
     assert(client.services.isEmpty);
@@ -217,6 +324,10 @@
         _vmCancelStream(streamId);
       }
     }
+
+    // Clean up client approvals state.
+    _clearClientName(client);
+
     for (final service in client.services.keys) {
       _eventMessageHandler(
           'Service',
@@ -617,6 +728,15 @@
       if (message.method == '_spawnUri') {
         return await _spawnUri(message);
       }
+      if (message.method == 'setClientName') {
+        return _setClientName(message);
+      }
+      if (message.method == 'getClientName') {
+        return _getClientName(message);
+      }
+      if (message.method == 'requirePermissionToResume') {
+        return _requirePermissionToResume(message);
+      }
       if (devfs.shouldHandleMessage(message)) {
         return await devfs.handleMessage(message);
       }
diff --git a/tests/compiler/dart2js/deferred_loading/data/deferred_typedef/main.dart b/tests/compiler/dart2js/deferred_loading/data/deferred_typedef/main.dart
index 229b18d..b6bd66b 100644
--- a/tests/compiler/dart2js/deferred_loading/data/deferred_typedef/main.dart
+++ b/tests/compiler/dart2js/deferred_loading/data/deferred_typedef/main.dart
@@ -4,12 +4,7 @@
 
 import 'lib1.dart' deferred as lib1;
 
-/*member: main:
- OutputUnit(main, {}),
- constants=[
-  ConstructedConstant(C(a=TypeConstant(MyF1),b=FunctionConstant(topLevelMethod)))=OutputUnit(1, {lib1}),
-  TypeConstant(MyF1)=OutputUnit(1, {lib1})]
-*/
+/*member: main:OutputUnit(main, {}),constants=[ConstructedConstant(C(a=TypeConstant(void Function()),b=FunctionConstant(topLevelMethod)))=OutputUnit(1, {lib1}),TypeConstant(void Function())=OutputUnit(1, {lib1})]*/
 main() async {
   await lib1.loadLibrary();
   print(lib1.cA);
diff --git a/tests/compiler/dart2js/deferred_loading/deferred_loading_test.dart b/tests/compiler/dart2js/deferred_loading/deferred_loading_test.dart
index fc041f3..4f3e3d1 100644
--- a/tests/compiler/dart2js/deferred_loading/deferred_loading_test.dart
+++ b/tests/compiler/dart2js/deferred_loading/deferred_loading_test.dart
@@ -32,7 +32,9 @@
   asyncTest(() async {
     Directory dataDir = new Directory.fromUri(Platform.script.resolve('data'));
     await checkTests(dataDir, const OutputUnitDataComputer(),
-        options: compilerOptions, args: args, setUpFunction: () {
+        options: compilerOptions,
+        args: args,
+        supportedMarkers: [strongMarker], setUpFunction: () {
       importPrefixes.clear();
     }, testedConfigs: allStrongConfigs);
   });
diff --git a/tests/compiler/dart2js/equivalence/check_helpers.dart b/tests/compiler/dart2js/equivalence/check_helpers.dart
index 1b7ae3a..37bd658 100644
--- a/tests/compiler/dart2js/equivalence/check_helpers.dart
+++ b/tests/compiler/dart2js/equivalence/check_helpers.dart
@@ -473,16 +473,6 @@
   }
 
   @override
-  visitTypedefType(TypedefType type, _) {
-    sb.write(type.element.name);
-    if (type.typeArguments.any((type) => type is! DynamicType)) {
-      sb.write('<');
-      visitTypes(type.typeArguments);
-      sb.write('>');
-    }
-  }
-
-  @override
   visitInterfaceType(InterfaceType type, _) {
     sb.write(type.element.name);
     if (type.typeArguments.any((type) => type is! DynamicType)) {
diff --git a/tests/compiler/dart2js/helpers/shared_helper.dart b/tests/compiler/dart2js/helpers/shared_helper.dart
index 34b897b..0a19323 100644
--- a/tests/compiler/dart2js/helpers/shared_helper.dart
+++ b/tests/compiler/dart2js/helpers/shared_helper.dart
@@ -94,16 +94,6 @@
   }
 
   @override
-  void visitTypedefType(TypedefType type, StringBuffer sb) {
-    sb.write(type.element.name);
-    if (type.typeArguments.isNotEmpty) {
-      sb.write('<');
-      visitList(type.typeArguments, sb);
-      sb.write('>');
-    }
-  }
-
-  @override
   void visitDynamicType(DynamicType type, StringBuffer sb) {
     sb.write('dynamic');
   }
diff --git a/tests/compiler/dart2js/rti/type_representation_test.dart b/tests/compiler/dart2js/rti/type_representation_test.dart
index 7cae429..f6d7afc 100644
--- a/tests/compiler/dart2js/rti/type_representation_test.dart
+++ b/tests/compiler/dart2js/rti/type_representation_test.dart
@@ -70,9 +70,7 @@
   RuntimeTypeTags rtiTags = const RuntimeTypeTags();
   TypeRepresentationGenerator typeRepresentation =
       new TypeRepresentationGenerator(
-          compiler.frontendStrategy.commonElements.dartTypes,
-          rtiTags,
-          compiler.backendClosedWorldForTesting.nativeData);
+          rtiTags, compiler.backendClosedWorldForTesting.nativeData);
 
   Expression onVariable(TypeVariableType _variable) {
     TypeVariableType variable = _variable;
@@ -86,20 +84,12 @@
 
   void expect(DartType type, String expectedRepresentation,
       [String expectedTypedefRepresentation]) {
-    bool encodeTypedefName = false;
     Expression expression = typeRepresentation.getTypeRepresentation(
-        backendStrategy.emitterTask.emitter,
-        type,
-        onVariable,
-        (x) => encodeTypedefName);
+        backendStrategy.emitterTask.emitter, type, onVariable);
     Expect.stringEquals(expectedRepresentation, stringify(expression));
 
-    encodeTypedefName = true;
     expression = typeRepresentation.getTypeRepresentation(
-        backendStrategy.emitterTask.emitter,
-        type,
-        onVariable,
-        (x) => encodeTypedefName);
+        backendStrategy.emitterTask.emitter, type, onVariable);
     if (expectedTypedefRepresentation == null) {
       expectedTypedefRepresentation = expectedRepresentation;
     }
diff --git a/tests/corelib/iterable_skip_test.dart b/tests/corelib/iterable_skip_test.dart
index 06fb801..609ffe9 100644
--- a/tests/corelib/iterable_skip_test.dart
+++ b/tests/corelib/iterable_skip_test.dart
@@ -15,7 +15,6 @@
   Iterable<int> skip0 = list1.skip(0);
   Expect.isTrue(skip0 is! List);
   Iterator<int> it = skip0.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(1, it.current);
   Expect.isTrue(it.moveNext());
@@ -23,45 +22,36 @@
   Expect.isTrue(it.moveNext());
   Expect.equals(3, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   Iterable<int> skip1 = list1.skip(1);
   Expect.isTrue(skip1 is! List);
   Expect.isTrue(skip1.skip(2).skip(1) is! List);
   it = skip1.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(2, it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(3, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   Iterable<int> skip2 = list1.skip(2);
   Expect.isTrue(skip2 is! List);
   Expect.isTrue(skip2.skip(2).skip(1) is! List);
   it = skip2.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(3, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   Iterable<int> skip3 = list1.skip(3);
   Expect.isTrue(skip3 is! List);
   Expect.isTrue(skip3.skip(2).skip(1) is! List);
   it = skip3.iterator;
-  Expect.isNull(it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   Iterable<int> skip4 = list1.skip(4);
   Expect.isTrue(skip4 is! List);
   Expect.isTrue(skip4.skip(2).skip(1) is! List);
   it = skip4.iterator;
-  Expect.isNull(it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   skip0 = list1.skip(0);
   skip1 = skip0.skip(1);
@@ -69,7 +59,6 @@
   skip3 = skip2.skip(1);
   skip4 = skip3.skip(1);
   it = skip0.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(1, it.current);
   Expect.isTrue(it.moveNext());
@@ -77,83 +66,62 @@
   Expect.isTrue(it.moveNext());
   Expect.equals(3, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
   it = skip1.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(2, it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(3, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
   it = skip2.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(3, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
   it = skip3.iterator;
-  Expect.isNull(it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
   it = skip4.iterator;
-  Expect.isNull(it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   skip0 = list2.skip(0);
   Expect.isTrue(skip0 is! List);
   Expect.isTrue(skip0.skip(2).skip(1) is! List);
   it = skip0.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(4, it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(5, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   skip1 = list2.skip(1);
   Expect.isTrue(skip1 is! List);
   Expect.isTrue(skip1.skip(2).skip(1) is! List);
   it = skip1.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(5, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   skip2 = list2.skip(2);
   Expect.isTrue(skip2 is! List);
   Expect.isTrue(skip2.skip(2).skip(1) is! List);
   it = skip2.iterator;
-  Expect.isNull(it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   skip3 = list2.skip(3);
   Expect.isTrue(skip3 is! List);
   Expect.isTrue(skip3.skip(2).skip(1) is! List);
   it = skip3.iterator;
-  Expect.isNull(it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   Iterable<String> skip02 = list3.skip(0);
   Expect.isTrue(skip02 is! List);
   Expect.isTrue(skip02.skip(2).skip(1) is! List);
   Iterator<String> it2 = skip02.iterator;
-  Expect.isNull(it2.current);
   Expect.isFalse(it2.moveNext());
-  Expect.isNull(it2.current);
 
   Iterable<String> skip12 = list3.skip(1);
   Expect.isTrue(skip12 is! List);
   Expect.isTrue(skip12.skip(2).skip(1) is! List);
   it2 = skip12.iterator;
-  Expect.isNull(it2.current);
   Expect.isFalse(it2.moveNext());
-  Expect.isNull(it2.current);
 
   skip0 = set1.skip(0);
   List<int> copied = skip0.toList();
@@ -165,7 +133,6 @@
   Expect.isTrue(copied[0] != copied[2]);
   Expect.isTrue(copied[1] != copied[2]);
   it = skip0.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.isNotNull(it.current);
   Expect.isTrue(it.moveNext());
@@ -173,7 +140,6 @@
   Expect.isTrue(it.moveNext());
   Expect.isNotNull(it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   skip1 = set1.skip(1);
   copied = skip1.toList();
@@ -182,48 +148,36 @@
   Expect.isTrue(set1.contains(copied[1]));
   Expect.isTrue(copied[0] != copied[1]);
   it = skip1.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.isNotNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.isNotNull(it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   skip2 = set1.skip(2);
   copied = skip2.toList();
   Expect.equals(1, copied.length);
   Expect.isTrue(set1.contains(copied[0]));
   it = skip2.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.isNotNull(it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   skip3 = set1.skip(3);
   it = skip3.iterator;
-  Expect.isNull(it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   skip4 = set1.skip(4);
   it = skip4.iterator;
-  Expect.isNull(it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   var dynamicSkip0 = set2.skip(0);
   var dynamicIt = dynamicSkip0.iterator;
-  Expect.isNull(dynamicIt.current);
   Expect.isFalse(dynamicIt.moveNext());
-  Expect.isNull(dynamicIt.current);
 
   var dynamicSkip1 = set2.skip(1);
   dynamicIt = dynamicSkip1.iterator;
-  Expect.isNull(dynamicIt.current);
   Expect.isFalse(dynamicIt.moveNext());
-  Expect.isNull(dynamicIt.current);
 
   testSkipTake(Iterable input, int skip, int take) {
     List expected = [];
diff --git a/tests/corelib/iterable_skip_while_test.dart b/tests/corelib/iterable_skip_while_test.dart
index d372122..2f9d7f6 100644
--- a/tests/corelib/iterable_skip_while_test.dart
+++ b/tests/corelib/iterable_skip_while_test.dart
@@ -14,31 +14,24 @@
 
   Iterable<int> skipWhileTrue = list1.skipWhile((x) => true);
   Iterator<int> it = skipWhileTrue.iterator;
-  Expect.isNull(it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   Iterable<int> skipWhileOdd = list1.skipWhile((x) => x.isOdd);
   it = skipWhileOdd.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(2, it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(3, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   Iterable<int> skipWhileLessThan3 = list1.skipWhile((x) => x < 3);
   it = skipWhileLessThan3.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(3, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   Iterable<int> skipWhileFalse = list1.skipWhile((x) => false);
   it = skipWhileFalse.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(1, it.current);
   Expect.isTrue(it.moveNext());
@@ -46,11 +39,9 @@
   Expect.isTrue(it.moveNext());
   Expect.equals(3, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   Iterable<int> skipWhileEven = list1.skipWhile((x) => x.isEven);
   it = skipWhileEven.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(1, it.current);
   Expect.isTrue(it.moveNext());
@@ -58,59 +49,44 @@
   Expect.isTrue(it.moveNext());
   Expect.equals(3, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   skipWhileTrue = list2.skipWhile((x) => true);
   it = skipWhileTrue.iterator;
-  Expect.isNull(it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   skipWhileEven = list2.skipWhile((x) => x.isEven);
   it = skipWhileEven.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(5, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   skipWhileOdd = list2.skipWhile((x) => x.isOdd);
   it = skipWhileOdd.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(4, it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(5, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   skipWhileFalse = list2.skipWhile((x) => false);
   it = skipWhileFalse.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(4, it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(5, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   Iterable<String> skipWhileFalse2 = list3.skipWhile((x) => false);
   Iterator<String> it2 = skipWhileFalse2.iterator;
-  Expect.isNull(it2.current);
   Expect.isFalse(it2.moveNext());
-  Expect.isNull(it2.current);
 
   Iterable<String> skipWhileTrue2 = list3.skipWhile((x) => true);
   it2 = skipWhileTrue2.iterator;
-  Expect.isNull(it2.current);
   Expect.isFalse(it2.moveNext());
-  Expect.isNull(it2.current);
 
   skipWhileTrue = set1.skipWhile((x) => true);
   it = skipWhileTrue.iterator;
-  Expect.isNull(it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   skipWhileFalse = set1.skipWhile((x) => false);
   List<int> copied = skipWhileFalse.toList();
@@ -122,25 +98,16 @@
   Expect.isTrue(copied[0] != copied[2]);
   Expect.isTrue(copied[1] != copied[2]);
   it = skipWhileFalse.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
-  Expect.isTrue(it.current != null);
   Expect.isTrue(it.moveNext());
-  Expect.isTrue(it.current != null);
   Expect.isTrue(it.moveNext());
-  Expect.isTrue(it.current != null);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   var dynamicSkipWhileTrue = set2.skipWhile((x) => true);
   var dynamicIt = dynamicSkipWhileTrue.iterator;
-  Expect.isNull(dynamicIt.current);
   Expect.isFalse(dynamicIt.moveNext());
-  Expect.isNull(dynamicIt.current);
 
   var dynamicSkipWhileFalse = set2.skipWhile((x) => false);
   dynamicIt = dynamicSkipWhileFalse.iterator;
-  Expect.isNull(dynamicIt.current);
   Expect.isFalse(dynamicIt.moveNext());
-  Expect.isNull(dynamicIt.current);
 }
diff --git a/tests/corelib/iterable_take_test.dart b/tests/corelib/iterable_take_test.dart
index fccb5a2..59cd518 100644
--- a/tests/corelib/iterable_take_test.dart
+++ b/tests/corelib/iterable_take_test.dart
@@ -14,31 +14,24 @@
 
   Iterable<int> take0 = list1.take(0);
   Iterator<int> it = take0.iterator;
-  Expect.isNull(it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   Iterable<int> take1 = list1.take(1);
   it = take1.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(1, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   Iterable<int> take2 = list1.take(2);
   it = take2.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(1, it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(2, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   Iterable<int> take3 = list1.take(3);
   it = take3.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(1, it.current);
   Expect.isTrue(it.moveNext());
@@ -46,11 +39,9 @@
   Expect.isTrue(it.moveNext());
   Expect.equals(3, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   Iterable<int> take4 = list1.take(4);
   it = take4.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(1, it.current);
   Expect.isTrue(it.moveNext());
@@ -58,7 +49,6 @@
   Expect.isTrue(it.moveNext());
   Expect.equals(3, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   take4 = list1.take(4);
   take3 = take4.take(3);
@@ -66,25 +56,18 @@
   take1 = take2.take(1);
   take0 = take1.take(0);
   it = take0.iterator;
-  Expect.isNull(it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
   it = take1.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(1, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
   it = take2.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(1, it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(2, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
   it = take3.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(1, it.current);
   Expect.isTrue(it.moveNext());
@@ -92,9 +75,7 @@
   Expect.isTrue(it.moveNext());
   Expect.equals(3, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
   it = take4.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(1, it.current);
   Expect.isTrue(it.moveNext());
@@ -102,70 +83,53 @@
   Expect.isTrue(it.moveNext());
   Expect.equals(3, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   take0 = list2.take(0);
   it = take0.iterator;
-  Expect.isNull(it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   take1 = list2.take(1);
   it = take1.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(4, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   take2 = list2.take(2);
   it = take2.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(4, it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(5, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   take3 = list2.take(3);
   it = take3.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(4, it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(5, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   Iterable<String> take02 = list3.take(0);
   Iterator<String> it2 = take02.iterator;
-  Expect.isNull(it2.current);
   Expect.isFalse(it2.moveNext());
-  Expect.isNull(it2.current);
 
   Iterable<String> take12 = list3.take(1);
   it2 = take12.iterator;
-  Expect.isNull(it2.current);
   Expect.isFalse(it2.moveNext());
-  Expect.isNull(it2.current);
 
   take0 = set1.take(0);
   it = take0.iterator;
-  Expect.isNull(it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   take1 = set1.take(1);
   List<int> copied = take1.toList();
   Expect.equals(1, copied.length);
   Expect.isTrue(set1.contains(copied[0]));
   it = take1.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.isNotNull(it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   take2 = set1.take(2);
   copied = take2.toList();
@@ -174,13 +138,11 @@
   Expect.isTrue(set1.contains(copied[1]));
   Expect.isTrue(copied[0] != copied[1]);
   it = take2.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.isNotNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.isNotNull(it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   take3 = set1.take(3);
   copied = take3.toList();
@@ -192,7 +154,6 @@
   Expect.isTrue(copied[0] != copied[2]);
   Expect.isTrue(copied[1] != copied[2]);
   it = take3.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.isNotNull(it.current);
   Expect.isTrue(it.moveNext());
@@ -200,19 +161,14 @@
   Expect.isTrue(it.moveNext());
   Expect.isNotNull(it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   var dynamicTake0 = set2.take(0);
   var dynamicIt = dynamicTake0.iterator;
-  Expect.isNull(dynamicIt.current);
   Expect.isFalse(dynamicIt.moveNext());
-  Expect.isNull(dynamicIt.current);
 
   var dynamicTake1 = set2.take(1);
   dynamicIt = dynamicTake1.iterator;
-  Expect.isNull(dynamicIt.current);
   Expect.isFalse(dynamicIt.moveNext());
-  Expect.isNull(dynamicIt.current);
 
   Expect.throwsRangeError(() => list1.skip(-1));
   Expect.throwsRangeError(() => list2.skip(-1));
diff --git a/tests/corelib/iterable_take_while_test.dart b/tests/corelib/iterable_take_while_test.dart
index 1e9b5f9..86eedab 100644
--- a/tests/corelib/iterable_take_while_test.dart
+++ b/tests/corelib/iterable_take_while_test.dart
@@ -14,31 +14,24 @@
 
   Iterable<int> takeWhileFalse = list1.takeWhile((x) => false);
   Iterator<int> it = takeWhileFalse.iterator;
-  Expect.isNull(it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   Iterable<int> takeWhileOdd = list1.takeWhile((x) => x.isOdd);
   it = takeWhileOdd.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(1, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   Iterable<int> takeWhileLessThan3 = list1.takeWhile((x) => x < 3);
   it = takeWhileLessThan3.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(1, it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(2, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   Iterable<int> takeEverything = list1.takeWhile((x) => true);
   it = takeEverything.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(1, it.current);
   Expect.isTrue(it.moveNext());
@@ -46,55 +39,40 @@
   Expect.isTrue(it.moveNext());
   Expect.equals(3, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   Iterable<int> takeWhileEven = list1.takeWhile((x) => x.isEven);
   it = takeWhileFalse.iterator;
-  Expect.isNull(it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   takeWhileFalse = list2.takeWhile((x) => false);
   it = takeWhileFalse.iterator;
-  Expect.isNull(it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   takeWhileEven = list2.takeWhile((x) => x.isEven);
   it = takeWhileEven.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(4, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   takeEverything = list2.takeWhile((x) => true);
   it = takeEverything.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(4, it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(5, it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   Iterable<String> takeWhileFalse2 = list3.takeWhile((x) => false);
   Iterator<String> it2 = takeWhileFalse2.iterator;
-  Expect.isNull(it2.current);
   Expect.isFalse(it2.moveNext());
-  Expect.isNull(it2.current);
 
   Iterable<String> takeEverything2 = list3.takeWhile((x) => true);
   it2 = takeEverything2.iterator;
-  Expect.isNull(it2.current);
   Expect.isFalse(it2.moveNext());
-  Expect.isNull(it2.current);
 
   takeWhileFalse = set1.takeWhile((x) => false);
   it = takeWhileFalse.iterator;
-  Expect.isNull(it.current);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   takeEverything = set1.takeWhile((x) => true);
   List<int> copied = takeEverything.toList();
@@ -106,7 +84,6 @@
   Expect.isTrue(copied[0] != copied[2]);
   Expect.isTrue(copied[1] != copied[2]);
   it = takeEverything.iterator;
-  Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.isTrue(it.current != null);
   Expect.isTrue(it.moveNext());
@@ -114,17 +91,12 @@
   Expect.isTrue(it.moveNext());
   Expect.isTrue(it.current != null);
   Expect.isFalse(it.moveNext());
-  Expect.isNull(it.current);
 
   var dynamicTakeWhileFalse = set2.takeWhile((x) => false);
   var dynamicIt = dynamicTakeWhileFalse.iterator;
-  Expect.isNull(dynamicIt.current);
   Expect.isFalse(dynamicIt.moveNext());
-  Expect.isNull(dynamicIt.current);
 
   var dynamicTakeEverything = set2.takeWhile((x) => true);
   dynamicIt = dynamicTakeEverything.iterator;
-  Expect.isNull(dynamicIt.current);
   Expect.isFalse(dynamicIt.moveNext());
-  Expect.isNull(dynamicIt.current);
 }
diff --git a/tests/corelib/list_iterators_test.dart b/tests/corelib/list_iterators_test.dart
index 092082e..edc6282 100644
--- a/tests/corelib/list_iterators_test.dart
+++ b/tests/corelib/list_iterators_test.dart
@@ -7,14 +7,12 @@
 class ListIteratorsTest {
   static void checkListIterator(List a) {
     Iterator it = a.iterator;
-    Expect.isNull(it.current);
     for (int i = 0; i < a.length; i++) {
       Expect.isTrue(it.moveNext());
       var elem = it.current;
       Expect.equals(a[i], elem);
     }
     Expect.isFalse(it.moveNext());
-    Expect.isNull(it.current);
   }
 
   static testMain() {
diff --git a/tests/corelib/queue_iterator_test.dart b/tests/corelib/queue_iterator_test.dart
index af0458b..c42e7b7 100644
--- a/tests/corelib/queue_iterator_test.dart
+++ b/tests/corelib/queue_iterator_test.dart
@@ -31,7 +31,6 @@
     Iterator<int> it = queue.iterator;
     sum(6, it);
     Expect.isFalse(it.moveNext());
-    Expect.isNull(it.current);
   }
 
   static void testLargeQueue() {
@@ -44,7 +43,6 @@
     Iterator<int> it = queue.iterator;
     sum(count, it);
     Expect.isFalse(it.moveNext());
-    Expect.isNull(it.current);
   }
 
   static void testEmptyQueue() {
@@ -52,7 +50,6 @@
     Iterator<int> it = queue.iterator;
     sum(0, it);
     Expect.isFalse(it.moveNext());
-    Expect.isNull(it.current);
   }
 }
 
diff --git a/tests/corelib/regexp/v8_regexp_utils.dart b/tests/corelib/regexp/v8_regexp_utils.dart
index 111ab90..c9959e2 100644
--- a/tests/corelib/regexp/v8_regexp_utils.dart
+++ b/tests/corelib/regexp/v8_regexp_utils.dart
@@ -6,23 +6,23 @@
 
 import "package:expect/expect.dart";
 
-void assertEquals(actual, expected, [String message = null]) {
+void assertEquals(actual, expected, [String? message = null]) {
   Expect.equals(actual, expected, message);
 }
 
-void assertTrue(actual, [String message = null]) {
+void assertTrue(actual, [String? message = null]) {
   Expect.isTrue(actual, message);
 }
 
-void assertFalse(actual, [String message = null]) {
+void assertFalse(actual, [String? message = null]) {
   Expect.isFalse(actual, message);
 }
 
-void assertThrows(fn, [num testid = null]) {
+void assertThrows(fn, [num? testid = null]) {
   Expect.throws(fn, null, "Test $testid");
 }
 
-void assertDoesNotThrow(fn, [num testid = null]) {
+void assertDoesNotThrow(fn, [num? testid = null]) {
   fn();
 }
 
@@ -30,7 +30,7 @@
   Expect.isNull(actual, "Test $testid");
 }
 
-void assertToStringEquals(str, match, num testid) {
+void assertToStringEquals(str, match, num? testid) {
   var actual = [];
   for (int i = 0; i <= match.groupCount; i++) {
     var g = match.group(i);
@@ -51,7 +51,7 @@
   Expect.isNull(actual);
 }
 
-void shouldBe(actual, expected, [String message = null]) {
+void shouldBe(actual, expected, [String? message = null]) {
   if (expected == null) {
     Expect.isNull(actual, message);
   } else {
diff --git a/tests/corelib/set_iterator_test.dart b/tests/corelib/set_iterator_test.dart
index 26d0dee..4b36545 100644
--- a/tests/corelib/set_iterator_test.dart
+++ b/tests/corelib/set_iterator_test.dart
@@ -40,7 +40,6 @@
     Iterator<int> it = set.iterator;
     sum(6, it);
     Expect.isFalse(it.moveNext());
-    Expect.isNull(it.current);
   }
 
   static void testLargeSet() {
@@ -53,7 +52,6 @@
     Iterator<int> it = set.iterator;
     sum(count, it);
     Expect.isFalse(it.moveNext());
-    Expect.isNull(it.current);
   }
 
   static void testEmptySet() {
@@ -61,7 +59,6 @@
     Iterator<int> it = set.iterator;
     sum(0, it);
     Expect.isFalse(it.moveNext());
-    Expect.isNull(it.current);
   }
 
   static void testSetWithDeletedEntries() {
@@ -77,7 +74,6 @@
     it = set.iterator;
     sum(0, it);
     Expect.isFalse(it.moveNext());
-    Expect.isNull(it.current);
 
     int count = 0;
     for (int i = 0; i < 100; i++) {
@@ -90,7 +86,6 @@
     it = set.iterator;
     sum(count, it);
     Expect.isFalse(it.moveNext());
-    Expect.isNull(it.current);
   }
 
   static void testBug5116829() {
diff --git a/tests/ffi/ffi.status b/tests/ffi/ffi.status
index 6400609..8db64fb 100644
--- a/tests/ffi/ffi.status
+++ b/tests/ffi/ffi.status
@@ -8,9 +8,6 @@
 [ $system == android ]
 *: Pass, Slow # https://github.com/dart-lang/sdk/issues/38489
 
-[ $arch == arm && $system != android ]
-*: Skip # "hardfp" calling convention is not yet supported (iOS is also supported but not tested): dartbug.com/36309
-
 [ $compiler != dart2analyzer && $compiler != fasta && $runtime != dart_precompiled && $runtime != vm ]
 *: SkipByDesign # FFI is a VM-only feature. (This test suite is part of the default set.)
 
diff --git a/tests/ffi_2/ffi_2.status b/tests/ffi_2/ffi_2.status
index 6400609..8db64fb 100644
--- a/tests/ffi_2/ffi_2.status
+++ b/tests/ffi_2/ffi_2.status
@@ -8,9 +8,6 @@
 [ $system == android ]
 *: Pass, Slow # https://github.com/dart-lang/sdk/issues/38489
 
-[ $arch == arm && $system != android ]
-*: Skip # "hardfp" calling convention is not yet supported (iOS is also supported but not tested): dartbug.com/36309
-
 [ $compiler != dart2analyzer && $compiler != fasta && $runtime != dart_precompiled && $runtime != vm ]
 *: SkipByDesign # FFI is a VM-only feature. (This test suite is part of the default set.)
 
diff --git a/tests/language/abstract/exact_selector_runtime_test.dart b/tests/language/abstract/exact_selector_runtime_test.dart
new file mode 100644
index 0000000..e8fc4ec
--- /dev/null
+++ b/tests/language/abstract/exact_selector_runtime_test.dart
@@ -0,0 +1,40 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for dart2js that used to duplicate some `Object`
+// methods to handle `noSuchMethod`.
+
+import "package:expect/expect.dart";
+import "../compiler_annotations.dart";
+
+class Foo {
+  noSuchMethod(im) => 42;
+}
+
+@DontInline()
+returnFoo() {
+  (() => 42)();
+  return new Foo();
+}
+
+class Bar {
+  operator ==(other) => false;
+}
+
+var a = [false, true, new Object(), new Bar()];
+
+main() {
+  if (a[0] as bool) {
+    // This `==` call will make the compiler create a selector with an
+    // exact `TypeMask` of `Foo`. Since `Foo` is abstract, such a call
+    // cannot happen, but we still used to generate a `==` method on
+    // the `Object` class to handle `noSuchMethod`.
+    print(returnFoo() == 42);
+  } else {
+    Expect.isFalse(a[2] == 42);
+  }
+}
diff --git a/tests/language/abstract/factory_constructor_runtime_test.dart b/tests/language/abstract/factory_constructor_runtime_test.dart
new file mode 100644
index 0000000..8743c6d
--- /dev/null
+++ b/tests/language/abstract/factory_constructor_runtime_test.dart
@@ -0,0 +1,34 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Dart test program for constructors and initializers.
+
+// Exercises issue 2282, factory constructors in abstract classes should
+// not emit a static type warning
+
+class B extends A1 {
+  B() {}
+  method() {}
+}
+
+abstract class A1 {
+  A1() {}
+  method(); // Abstract.
+  factory A1.make() {
+    return new B();
+  }
+}
+
+class A2 {
+  // Intentionally abstract method.
+
+  A2.make() {}
+}
+
+main() {
+  new A1.make();
+
+}
diff --git a/tests/language/abstract/syntax_runtime_test.dart b/tests/language/abstract/syntax_runtime_test.dart
new file mode 100644
index 0000000..8646921
--- /dev/null
+++ b/tests/language/abstract/syntax_runtime_test.dart
@@ -0,0 +1,23 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+main() {
+  var b = new B();
+  Expect.equals(42, b.foo());
+}
+
+class A {
+
+
+}
+
+class B extends A {
+  foo() => 42;
+  bar() => 87;
+}
diff --git a/tests/language/accessor_conflict/export2_helper.dart b/tests/language/accessor_conflict/export2_helper.dart
new file mode 100644
index 0000000..7827821
--- /dev/null
+++ b/tests/language/accessor_conflict/export2_helper.dart
@@ -0,0 +1,6 @@
+// Copyright (c) 2016, 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.
+
+export "setter.dart";
+export "getter.dart";
diff --git a/tests/language/accessor_conflict/export2_test.dart b/tests/language/accessor_conflict/export2_test.dart
new file mode 100644
index 0000000..58a1a77
--- /dev/null
+++ b/tests/language/accessor_conflict/export2_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2016, 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.
+
+// Verify that a getter and its corresponding setter can be imported from two
+// different files via a common export.  In this test the setter is imported
+// first.
+
+import "package:expect/expect.dart";
+
+import "export2_helper.dart";
+
+main() {
+  getValue = 123;
+  Expect.equals(x, 123);
+  x = 456;
+  Expect.equals(setValue, 456);
+}
diff --git a/tests/language/accessor_conflict/export_helper.dart b/tests/language/accessor_conflict/export_helper.dart
new file mode 100644
index 0000000..ef02437
--- /dev/null
+++ b/tests/language/accessor_conflict/export_helper.dart
@@ -0,0 +1,6 @@
+// Copyright (c) 2016, 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.
+
+export "getter.dart";
+export "setter.dart";
diff --git a/tests/language/accessor_conflict/export_test.dart b/tests/language/accessor_conflict/export_test.dart
new file mode 100644
index 0000000..babde00
--- /dev/null
+++ b/tests/language/accessor_conflict/export_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2016, 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.
+
+// Verify that a getter and its corresponding setter can be imported from two
+// different files via a common export.  In this test the getter is imported
+// first.
+
+import "package:expect/expect.dart";
+
+import "export_helper.dart";
+
+main() {
+  getValue = 123;
+  Expect.equals(x, 123);
+  x = 456;
+  Expect.equals(setValue, 456);
+}
diff --git a/tests/language/accessor_conflict/getter.dart b/tests/language/accessor_conflict/getter.dart
new file mode 100644
index 0000000..5b8d72f
--- /dev/null
+++ b/tests/language/accessor_conflict/getter.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2016, 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.
+
+var getValue;
+
+get x => getValue;
diff --git a/tests/language/accessor_conflict/import2_test.dart b/tests/language/accessor_conflict/import2_test.dart
new file mode 100644
index 0000000..874b321
--- /dev/null
+++ b/tests/language/accessor_conflict/import2_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2016, 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.
+
+// Verify that a getter and its corresponding setter can be imported from two
+// different files.  In this test the setter is imported first.
+
+import "package:expect/expect.dart";
+
+import "setter.dart";
+import "getter.dart";
+
+main() {
+  getValue = 123;
+  Expect.equals(x, 123);
+  x = 456;
+  Expect.equals(setValue, 456);
+}
diff --git a/tests/language/accessor_conflict/import_prefixed2_test.dart b/tests/language/accessor_conflict/import_prefixed2_test.dart
new file mode 100644
index 0000000..283decf
--- /dev/null
+++ b/tests/language/accessor_conflict/import_prefixed2_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2016, 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.
+
+// Verify that a getter and its corresponding setter can be imported from two
+// different files.  In this test the setter is imported first.
+
+import "package:expect/expect.dart";
+
+import "setter.dart" as p;
+import "getter.dart" as p;
+
+main() {
+  p.getValue = 123;
+  Expect.equals(p.x, 123);
+  p.x = 456;
+  Expect.equals(p.setValue, 456);
+}
diff --git a/tests/language/accessor_conflict/import_prefixed_test.dart b/tests/language/accessor_conflict/import_prefixed_test.dart
new file mode 100644
index 0000000..fdb3ca8
--- /dev/null
+++ b/tests/language/accessor_conflict/import_prefixed_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2016, 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.
+
+// Verify that a getter and its corresponding setter can be imported from two
+// different files.  In this test the getter is imported first.
+
+import "package:expect/expect.dart";
+
+import "getter.dart" as p;
+import "setter.dart" as p;
+
+main() {
+  p.getValue = 123;
+  Expect.equals(p.x, 123);
+  p.x = 456;
+  Expect.equals(p.setValue, 456);
+}
diff --git a/tests/language/accessor_conflict/import_test.dart b/tests/language/accessor_conflict/import_test.dart
new file mode 100644
index 0000000..49be4e5
--- /dev/null
+++ b/tests/language/accessor_conflict/import_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2016, 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.
+
+// Verify that a getter and its corresponding setter can be imported from two
+// different files.  In this test the getter is imported first.
+
+import "package:expect/expect.dart";
+
+import "getter.dart";
+import "setter.dart";
+
+main() {
+  getValue = 123;
+  Expect.equals(x, 123);
+  x = 456;
+  Expect.equals(setValue, 456);
+}
diff --git a/tests/language/accessor_conflict/setter.dart b/tests/language/accessor_conflict/setter.dart
new file mode 100644
index 0000000..c3d383b
--- /dev/null
+++ b/tests/language/accessor_conflict/setter.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2016, 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.
+
+var setValue;
+
+set x(value) {
+  setValue = value;
+}
diff --git a/tests/language/argument/assignability_function_typed_runtime_4_test.dart b/tests/language/argument/assignability_function_typed_runtime_4_test.dart
new file mode 100644
index 0000000..d350955
--- /dev/null
+++ b/tests/language/argument/assignability_function_typed_runtime_4_test.dart
@@ -0,0 +1,40 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2017, 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:expect/expect.dart";
+
+void f(num callback(num x)) {}
+
+Object intToObject(int x) => 0;
+Object numToObject(num x) => 0;
+Object objectToObject(Object x) => 0;
+int intToInt(int x) => 0;
+int numToInt(num x) => 0;
+int objectToInt(Object x) => 0;
+num intToNum(int x) => 0;
+num numToNum(num x) => 0;
+num objectToNum(Object x) => 0;
+
+main() {
+  // Unrelated types (not assignable)
+
+
+
+  // Assignable but fails at runtime.
+  var intToObject2 = intToObject;
+
+  var intToNum2 = intToNum;
+
+  var numToObject2 = numToObject;
+
+
+  // Ok
+  f(numToNum);
+
+
+
+}
diff --git a/tests/language/argument/assignability_function_typed_runtime_5_test.dart b/tests/language/argument/assignability_function_typed_runtime_5_test.dart
new file mode 100644
index 0000000..e23f244
--- /dev/null
+++ b/tests/language/argument/assignability_function_typed_runtime_5_test.dart
@@ -0,0 +1,40 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2017, 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:expect/expect.dart";
+
+void f(num callback(num x)) {}
+
+Object intToObject(int x) => 0;
+Object numToObject(num x) => 0;
+Object objectToObject(Object x) => 0;
+int intToInt(int x) => 0;
+int numToInt(num x) => 0;
+int objectToInt(Object x) => 0;
+num intToNum(int x) => 0;
+num numToNum(num x) => 0;
+num objectToNum(Object x) => 0;
+
+main() {
+  // Unrelated types (not assignable)
+
+
+
+  // Assignable but fails at runtime.
+  var intToObject2 = intToObject;
+
+  var intToNum2 = intToNum;
+
+  var numToObject2 = numToObject;
+
+
+  // Ok
+
+  f(numToInt);
+
+
+}
diff --git a/tests/language/argument/assignability_function_typed_runtime_6_test.dart b/tests/language/argument/assignability_function_typed_runtime_6_test.dart
new file mode 100644
index 0000000..4c857cb
--- /dev/null
+++ b/tests/language/argument/assignability_function_typed_runtime_6_test.dart
@@ -0,0 +1,40 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2017, 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:expect/expect.dart";
+
+void f(num callback(num x)) {}
+
+Object intToObject(int x) => 0;
+Object numToObject(num x) => 0;
+Object objectToObject(Object x) => 0;
+int intToInt(int x) => 0;
+int numToInt(num x) => 0;
+int objectToInt(Object x) => 0;
+num intToNum(int x) => 0;
+num numToNum(num x) => 0;
+num objectToNum(Object x) => 0;
+
+main() {
+  // Unrelated types (not assignable)
+
+
+
+  // Assignable but fails at runtime.
+  var intToObject2 = intToObject;
+
+  var intToNum2 = intToNum;
+
+  var numToObject2 = numToObject;
+
+
+  // Ok
+
+
+  f(objectToNum);
+
+}
diff --git a/tests/language/argument/assignability_function_typed_runtime_7_test.dart b/tests/language/argument/assignability_function_typed_runtime_7_test.dart
new file mode 100644
index 0000000..f1c3a76
--- /dev/null
+++ b/tests/language/argument/assignability_function_typed_runtime_7_test.dart
@@ -0,0 +1,40 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2017, 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:expect/expect.dart";
+
+void f(num callback(num x)) {}
+
+Object intToObject(int x) => 0;
+Object numToObject(num x) => 0;
+Object objectToObject(Object x) => 0;
+int intToInt(int x) => 0;
+int numToInt(num x) => 0;
+int objectToInt(Object x) => 0;
+num intToNum(int x) => 0;
+num numToNum(num x) => 0;
+num objectToNum(Object x) => 0;
+
+main() {
+  // Unrelated types (not assignable)
+
+
+
+  // Assignable but fails at runtime.
+  var intToObject2 = intToObject;
+
+  var intToNum2 = intToNum;
+
+  var numToObject2 = numToObject;
+
+
+  // Ok
+
+
+
+  f(objectToInt);
+}
diff --git a/tests/language/argument/assignability_function_typed_runtime_test.dart b/tests/language/argument/assignability_function_typed_runtime_test.dart
new file mode 100644
index 0000000..22802bb
--- /dev/null
+++ b/tests/language/argument/assignability_function_typed_runtime_test.dart
@@ -0,0 +1,40 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2017, 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:expect/expect.dart";
+
+void f(num callback(num x)) {}
+
+Object intToObject(int x) => 0;
+Object numToObject(num x) => 0;
+Object objectToObject(Object x) => 0;
+int intToInt(int x) => 0;
+int numToInt(num x) => 0;
+int objectToInt(Object x) => 0;
+num intToNum(int x) => 0;
+num numToNum(num x) => 0;
+num objectToNum(Object x) => 0;
+
+main() {
+  // Unrelated types (not assignable)
+
+
+
+  // Assignable but fails at runtime.
+  var intToObject2 = intToObject;
+
+  var intToNum2 = intToNum;
+
+  var numToObject2 = numToObject;
+
+
+  // Ok
+
+
+
+
+}
diff --git a/tests/language/argument/assignability_function_typed_test.dart b/tests/language/argument/assignability_function_typed_test.dart
new file mode 100644
index 0000000..d6751f9
--- /dev/null
+++ b/tests/language/argument/assignability_function_typed_test.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2017, 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:expect/expect.dart";
+
+void f(num callback(num x)) {}
+
+Object intToObject(int x) => 0;
+Object numToObject(num x) => 0;
+Object objectToObject(Object x) => 0;
+int intToInt(int x) => 0;
+int numToInt(num x) => 0;
+int objectToInt(Object x) => 0;
+num intToNum(int x) => 0;
+num numToNum(num x) => 0;
+num objectToNum(Object x) => 0;
+
+main() {
+  // Unrelated types (not assignable).
+  f(intToInt);
+  //^^^^^^^^
+  // [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE
+  // [cfe] The argument type 'int Function(int)' can't be assigned to the parameter type 'num Function(num)'.
+  f(objectToObject);
+  //^^^^^^^^^^^^^^
+  // [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE
+  // [cfe] The argument type 'Object Function(Object)' can't be assigned to the parameter type 'num Function(num)'.
+
+  // Downcasts.
+  f(intToObject);
+  //^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.INVALID_CAST_FUNCTION
+  // [cfe] The top level function has type 'Object Function(int)' that isn't of expected type 'num Function(num)'.
+  f(intToNum);
+  //^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.INVALID_CAST_FUNCTION
+  // [cfe] The top level function has type 'num Function(int)' that isn't of expected type 'num Function(num)'.
+  f(numToObject);
+  //^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.INVALID_CAST_FUNCTION
+  // [cfe] The top level function has type 'Object Function(num)' that isn't of expected type 'num Function(num)'.
+
+  // Ok.
+  f(numToNum);
+  f(numToInt);
+  f(objectToNum);
+  f(objectToInt);
+}
diff --git a/tests/language/argument/named_argument_test.dart b/tests/language/argument/named_argument_test.dart
new file mode 100644
index 0000000..d0f0d0e
--- /dev/null
+++ b/tests/language/argument/named_argument_test.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+main() {
+  var c1 = ({b, a}) => 'a: $a b: $b';
+  var c2 = ({a, b}) => 'a: $a b: $b';
+
+  Expect.equals('a: 2 b: 1', c1(b: 1, a: 2));
+  Expect.equals('a: 1 b: 2', c1(a: 1, b: 2));
+
+  Expect.equals('a: 2 b: 1', c2(b: 1, a: 2));
+  Expect.equals('a: 1 b: 2', c2(a: 1, b: 2));
+}
diff --git a/tests/language/argument/named_in_const_creation_test.dart b/tests/language/argument/named_in_const_creation_test.dart
new file mode 100644
index 0000000..93fe6e5
--- /dev/null
+++ b/tests/language/argument/named_in_const_creation_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+class A {
+  final x;
+  final y;
+  const A(a, {b})
+      : x = a,
+        y = b;
+  static const test = const A(1, b: 2);
+}
+
+main() {
+  A a = A.test;
+  Expect.equals(1, a.x);
+  Expect.equals(2, a.y);
+}
diff --git a/tests/language/argument/not_enough_positional_arguments_test.dart b/tests/language/argument/not_enough_positional_arguments_test.dart
new file mode 100644
index 0000000..9ebd09f
--- /dev/null
+++ b/tests/language/argument/not_enough_positional_arguments_test.dart
@@ -0,0 +1,72 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+foo(a, [b]) {}
+
+bar(a, {b}) {}
+
+class A {
+  A();
+  A.test(a, [b]);
+}
+
+class B {
+  B()
+    : super.test(b: 1)
+    //^^^^^^^^^^^^^^^^
+    // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER
+    // [cfe] Superclass has no constructor named 'Object.test'.
+  ;
+}
+
+class C extends A {
+  C()
+    : super.test(b: 1)
+    //          ^^^^^^
+    // [analyzer] COMPILE_TIME_ERROR.NOT_ENOUGH_POSITIONAL_ARGUMENTS
+    // [cfe] Too few positional arguments: 1 required, 0 given.
+    //           ^
+    // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_NAMED_PARAMETER
+  ;
+}
+
+class D {
+  D();
+  D.test(a, {b});
+}
+
+class E extends D {
+  E()
+    : super.test(b: 1)
+    //          ^^^^^^
+    // [analyzer] COMPILE_TIME_ERROR.NOT_ENOUGH_POSITIONAL_ARGUMENTS
+    // [cfe] Too few positional arguments: 1 required, 0 given.
+  ;
+}
+
+main() {
+  new A.test(b: 1);
+  //        ^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.NOT_ENOUGH_POSITIONAL_ARGUMENTS
+  // [cfe] Too few positional arguments: 1 required, 0 given.
+  //         ^
+  // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_NAMED_PARAMETER
+  new B();
+  new C();
+  new D.test(b: 1);
+  //        ^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.NOT_ENOUGH_POSITIONAL_ARGUMENTS
+  // [cfe] Too few positional arguments: 1 required, 0 given.
+  new E();
+  foo(b: 1);
+  // ^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.NOT_ENOUGH_POSITIONAL_ARGUMENTS
+  // [cfe] Too few positional arguments: 1 required, 0 given.
+  //  ^
+  // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_NAMED_PARAMETER
+  bar(b: 1);
+  // ^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.NOT_ENOUGH_POSITIONAL_ARGUMENTS
+  // [cfe] Too few positional arguments: 1 required, 0 given.
+}
diff --git a/tests/language/argument/not_enough_positional_runtime_test.dart b/tests/language/argument/not_enough_positional_runtime_test.dart
new file mode 100644
index 0000000..4ad8424
--- /dev/null
+++ b/tests/language/argument/not_enough_positional_runtime_test.dart
@@ -0,0 +1,48 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+foo(a, [b]) {}
+
+bar(a, {b}) {}
+
+class A {
+  A();
+  A.test(a, [b]);
+}
+
+class B {
+  B()
+
+  ;
+}
+
+class C extends A {
+  C()
+
+  ;
+}
+
+class D {
+  D();
+  D.test(a, {b});
+}
+
+class E extends D {
+  E()
+
+  ;
+}
+
+main() {
+
+  new B();
+  new C();
+
+  new E();
+
+
+}
diff --git a/tests/language/assign/instance_method_test.dart b/tests/language/assign/instance_method_test.dart
new file mode 100644
index 0000000..0b4fa35
--- /dev/null
+++ b/tests/language/assign/instance_method_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2011, 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:expect/expect.dart';
+
+class A {
+  A() {}
+  imethod() {
+    return 0;
+  }
+}
+
+main() {
+  dynamic a = new A();
+
+  // Illegal, can't change a member method.
+  Expect.throws(() {
+    a.imethod = () {
+      return 1;
+    };
+  });
+}
diff --git a/tests/language/assign/op_test.dart b/tests/language/assign/op_test.dart
new file mode 100644
index 0000000..9ee3eae
--- /dev/null
+++ b/tests/language/assign/op_test.dart
@@ -0,0 +1,96 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Dart test program for testing assign operators.
+// VMOptions=--optimization-counter-threshold=10 --no-background-compilation
+
+import "package:expect/expect.dart";
+
+class AssignOpTest {
+  AssignOpTest() {}
+
+  static testMain() {
+    var b = 0;
+    b += 1;
+    Expect.equals(1, b);
+    b *= 5;
+    Expect.equals(5, b);
+    b -= 1;
+    Expect.equals(4, b);
+    b ~/= 2;
+    Expect.equals(2, b);
+
+    f = 0;
+    f += 1;
+    Expect.equals(1, f);
+    f *= 5;
+    Expect.equals(5, f);
+    f -= 1;
+    Expect.equals(4, f);
+    f ~/= 2;
+    Expect.equals(2, f);
+    f /= 4;
+    Expect.equals(.5, f);
+
+    AssignOpTest.f = 0;
+    AssignOpTest.f += 1;
+    Expect.equals(1, AssignOpTest.f);
+    AssignOpTest.f *= 5;
+    Expect.equals(5, AssignOpTest.f);
+    AssignOpTest.f -= 1;
+    Expect.equals(4, AssignOpTest.f);
+    AssignOpTest.f ~/= 2;
+    Expect.equals(2, AssignOpTest.f);
+    AssignOpTest.f /= 4;
+    Expect.equals(.5, f);
+
+    var o = new AssignOpTest();
+    o.instf = 0;
+    o.instf += 1;
+    Expect.equals(1, o.instf);
+    o.instf *= 5;
+    Expect.equals(5, o.instf);
+    o.instf -= 1;
+    Expect.equals(4, o.instf);
+    o.instf ~/= 2;
+    Expect.equals(2, o.instf);
+    o.instf /= 4;
+    Expect.equals(.5, o.instf);
+
+    var x = 0xFF;
+    x >>= 3;
+    Expect.equals(0x1F, x);
+    x <<= 3;
+    Expect.equals(0xF8, x);
+    x |= 0xF00;
+    Expect.equals(0xFF8, x);
+    x &= 0xF0;
+    Expect.equals(0xF0, x);
+    x ^= 0x11;
+    Expect.equals(0xE1, x);
+
+    var y = 100;
+    y += 1 << 3;
+    Expect.equals(108, y);
+    y *= 2 + 1;
+    Expect.equals(324, y);
+    y -= 3 - 2;
+    Expect.equals(323, y);
+    y += 3 * 4;
+    Expect.equals(335, y);
+
+    var a = [1, 2, 3];
+    var ix = 0;
+    a[ix] |= 12;
+    Expect.equals(13, a[ix]);
+  }
+
+  static var f;
+  var instf;
+}
+
+main() {
+  for (int i = 0; i < 20; i++) {
+    AssignOpTest.testMain();
+  }
+}
diff --git a/tests/language/assign/static_type_runtime_test.dart b/tests/language/assign/static_type_runtime_test.dart
new file mode 100644
index 0000000..2b0c4a4
--- /dev/null
+++ b/tests/language/assign/static_type_runtime_test.dart
@@ -0,0 +1,28 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This test insures that statically initialized variables, fields, and
+// parameters report compile-time errors.
+
+
+
+class A {
+
+
+
+  A() {
+
+  }
+  method(
+      [
+
+      g = "String"]) {
+    return g;
+  }
+}
+
+main() {}
diff --git a/tests/language/assign/static_type_test.dart b/tests/language/assign/static_type_test.dart
new file mode 100644
index 0000000..d184bf4
--- /dev/null
+++ b/tests/language/assign/static_type_test.dart
@@ -0,0 +1,45 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This test insures that statically initialized variables, fields, and
+// parameters report compile-time errors.
+
+int a = "String";
+//      ^^^^^^^^
+// [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT
+// [cfe] A value of type 'String' can't be assigned to a variable of type 'int'.
+
+class A {
+  static const int c = "String";
+  //                   ^^^^^^^^
+  // [analyzer] CHECKED_MODE_COMPILE_TIME_ERROR.VARIABLE_TYPE_MISMATCH
+  // [cfe] A value of type 'String' can't be assigned to a variable of type 'int'.
+  //                   ^^^^^^^^
+  // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT
+  final int d = "String";
+  //            ^^^^^^^^
+  // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT
+  // [cfe] A value of type 'String' can't be assigned to a variable of type 'int'.
+  int e = "String";
+  //      ^^^^^^^^
+  // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT
+  // [cfe] A value of type 'String' can't be assigned to a variable of type 'int'.
+  A() {
+     int f = "String";
+     //      ^^^^^^^^
+     // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT
+     // [cfe] A value of type 'String' can't be assigned to a variable of type 'int'.
+  }
+  method(
+      [
+     int
+      g = "String"]) {
+      //  ^^^^^^^^
+      // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT
+      // [cfe] A value of type 'String' can't be assigned to a variable of type 'int'.
+    return g;
+  }
+}
+
+main() {}
diff --git a/tests/language/assign/to_type_runtime_test.dart b/tests/language/assign/to_type_runtime_test.dart
new file mode 100644
index 0000000..ecb363e
--- /dev/null
+++ b/tests/language/assign/to_type_runtime_test.dart
@@ -0,0 +1,28 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Verify that an attempt to assign to a class, enum, typedef, or type
+// parameter produces a compile error.
+
+class C<T> {
+  f() {
+
+  }
+}
+
+class D {}
+
+enum E { e0 }
+
+typedef void F();
+
+main() {
+  new C<D>().f();
+
+
+
+}
diff --git a/tests/language/assign/to_type_test.dart b/tests/language/assign/to_type_test.dart
new file mode 100644
index 0000000..b8e4480
--- /dev/null
+++ b/tests/language/assign/to_type_test.dart
@@ -0,0 +1,37 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Verify that an attempt to assign to a class, enum, typedef, or type
+// parameter produces a compile error.
+
+class C<T> {
+  f() {
+    T = Null;
+//  ^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_TYPE
+// [cfe] Setter not found: 'T'.
+  }
+}
+
+class D {}
+
+enum E { e0 }
+
+typedef void F();
+
+main() {
+  new C<D>().f();
+  D = Null;
+//^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_TYPE
+// [cfe] Setter not found: 'D'.
+  E = Null;
+//^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_TYPE
+// [cfe] Setter not found: 'E'.
+  F = Null;
+//^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_TYPE
+// [cfe] Setter not found: 'F'.
+}
diff --git a/tests/language/assign/top_method_test.dart b/tests/language/assign/top_method_test.dart
new file mode 100644
index 0000000..1b889b9
--- /dev/null
+++ b/tests/language/assign/top_method_test.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+method() {
+  return 0;
+}
+
+main() {
+  // Illegal, can't change a top level method
+  /*@compile-error=unspecified*/ method = () { return 1; };
+}
diff --git a/tests/language/nnbd/is_type_test/legacy_library.dart b/tests/language/nnbd/is_type_test/legacy_library.dart
new file mode 100644
index 0000000..f457d73
--- /dev/null
+++ b/tests/language/nnbd/is_type_test/legacy_library.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2020, 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.
+
+// Opt out of Null Safety:
+// @dart = 2.6
+
+import 'null_safe_library.dart';
+
+/// Performs the type test [value] is [T] in a legacy library.
+///
+/// NOTE: The [T] here is in a legacy library and will become `T*` which might
+/// be normalized away depending on the value of `T`.
+bool legacyIs<T>(Object value) => value is T;
+
+/// Performs the type test [value] is [T] in a null safe library.
+///
+/// NOTE: The [T] here is in a legacy library and will become `T*` which might
+/// be normalized away depending on the value of `T`.
+bool nullSafeIsLegacy<T>(Object value) => nullSafeIs<T>(value);
diff --git a/tests/language/nnbd/is_type_test/null_is_type_in_legacy_lib_test.dart b/tests/language/nnbd/is_type_test/null_is_type_in_legacy_lib_test.dart
new file mode 100644
index 0000000..00c2449
--- /dev/null
+++ b/tests/language/nnbd/is_type_test/null_is_type_in_legacy_lib_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2020, 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.
+
+// Opt out of Null Safety:
+// @dart = 2.6
+
+import 'package:expect/expect.dart';
+import 'null_safe_library.dart';
+
+// Type tests (is checks) located in a legacy library.
+main() {
+  // `null is Never*`
+  Expect.isTrue(null is Never);
+  // `null is Never?`
+  Expect.isTrue(legacyIsNullable<Never>(null));
+  Expect.isTrue(null is Null);
+  // `null is int*`
+  Expect.isFalse(null is int);
+  // `null is int?`
+  Expect.isTrue(legacyIsNullable<int>(null));
+  // `null is Object*`
+  Expect.isTrue(null is Object);
+  // `null is Object?`
+  Expect.isTrue(legacyIsNullable<Object>(null));
+  Expect.isTrue(null is dynamic);
+}
diff --git a/tests/language/nnbd/is_type_test/null_is_type_in_null_safe_lib_test.dart b/tests/language/nnbd/is_type_test/null_is_type_in_null_safe_lib_test.dart
new file mode 100644
index 0000000..6a2acd5
--- /dev/null
+++ b/tests/language/nnbd/is_type_test/null_is_type_in_null_safe_lib_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2020, 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:expect/expect.dart';
+import 'legacy_library.dart';
+
+// Type tests (is checks) located in a null safe library.
+main() {
+  Expect.isFalse(null is Never);
+  // `null is Never*`
+  Expect.isTrue(nullSafeIsLegacy<Never>(null));
+  Expect.isTrue(null is Never?);
+  Expect.isTrue(null is Null);
+  Expect.isFalse(null is int);
+  // `null is int*`
+  Expect.isFalse(nullSafeIsLegacy<int>(null));
+  Expect.isTrue(null is int?);
+  Expect.isFalse(null is Object);
+  // `null is Object*`
+  Expect.isTrue(nullSafeIsLegacy<Object>(null));
+  Expect.isTrue(null is Object?);
+  Expect.isTrue(null is dynamic);
+}
diff --git a/tests/language/nnbd/is_type_test/null_safe_library.dart b/tests/language/nnbd/is_type_test/null_safe_library.dart
new file mode 100644
index 0000000..3e801cd
--- /dev/null
+++ b/tests/language/nnbd/is_type_test/null_safe_library.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2020, 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 'legacy_library.dart';
+
+/// Performs the type test [value] is [T] in a null safe library.
+bool nullSafeIs<T>(Object? value) => value is T;
+
+/// Performs the type test [value] is `T?` in a legacy library.
+bool legacyIsNullable<T>(Object? value) => legacyIs<T?>(value);
diff --git a/tests/language/nnbd/operator_type_test.dart b/tests/language/nnbd/operator_type_test.dart
new file mode 100644
index 0000000..9a17555
--- /dev/null
+++ b/tests/language/nnbd/operator_type_test.dart
@@ -0,0 +1,327 @@
+// Copyright (c) 2020, 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.
+
+// SharedOptions=--enable-experiment=non-nullable
+
+// Tests that language operators and constructrs requiring non-nullable values
+// will not accept an operand with a nullable static type.
+// See: https://github.com/dart-lang/language/issues/298
+
+main() {
+  nonNullable();
+  potentiallyNonNullable<bool>();
+  nullable();
+  potentiallyNullable();
+}
+
+dynamic nonNullable() {
+  // Check that a nullable expression is not allowed where a non-nullable
+  // value is required.
+
+  bool? bq = maybeNullable(true); // Prevent promotion.
+  bool b = true;
+
+  dynamic _;
+
+  _ = bq && b;
+  //  ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  _ = b && bq;
+  //       ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  _ = bq || b;
+  //  ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  _ = b || bq;
+  //       ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  _ = !bq;
+  //   ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  _ = bq ? "a" : "b";
+  //  ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  if (bq) {}
+  //  ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  while (bq) {}
+  //     ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  do {} while (bq);
+  //           ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  for (; bq;) {}
+  //     ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  try {
+    throw bq;
+    //    ^^
+    // [analyzer] unspecified
+    // [cfe] unspecified
+  } catch (e) {}
+
+  assert(bq);
+  //     ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  _ = [if (bq) 1];
+  //       ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  _ = [for (; bq;) 1];
+  //         ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  Iterable<int>? iq = maybeNullable([1]);
+  for (var v in iq) {}
+  //            ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  _ = [...iq];
+  //       ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  Stream<Object?> foo() async* {
+    Stream<int>? sq = maybeNullable(Stream<int>.fromIterable([1]));
+    await for (var v in sq) {}
+    //                  ^^
+    // [analyzer] unspecified
+    // [cfe] unspecified
+
+    yield* sq;
+    //     ^^
+    // [analyzer] unspecified
+    // [cfe] unspecified
+  }
+
+  foo().toList();
+  C.factory();
+
+  return _;
+}
+
+dynamic potentiallyNonNullable<BQ extends bool?>() {
+  // Check that a potentially nullable expression is not allowed where
+  // a non-null value is required.
+
+  BQ bq = maybeNotNullable<BQ>(true);
+  bool b = true;
+
+  dynamic _;
+
+  _ = bq && b;
+  //  ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  _ = b && bq;
+  //       ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  _ = bq || b;
+  //  ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  _ = b || bq;
+  //       ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  _ = !bq;
+  //   ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  _ = bq ? "a" : "b";
+  //  ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  if (bq) {}
+  //  ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  while (bq) {}
+  //     ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  do {} while (bq);
+  //           ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  for (; bq;) {}
+  //     ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  try {
+    throw bq;
+    //    ^^
+    // [analyzer] unspecified
+    // [cfe] unspecified
+  } catch (e) {}
+
+  assert(bq);
+  //     ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  _ = [if (bq) 1];
+  //       ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  _ = [for (; bq;) 1];
+  //         ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  Iterable<int>? iq = maybeNullable([1]);
+  for (var v in iq) {}
+  //            ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  _ = [...iq];
+  //      ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  Stream<Object?> foo<SQ extends Stream<Object?>?>() async* {
+    SQ sq = maybeNotNullable<SQ>(Stream<int>.fromIterable([1]));
+    await for (var v in sq) {}
+    //                  ^^
+    // [analyzer] unspecified
+    // [cfe] unspecified
+
+    yield* sq;
+    //     ^^
+    // [analyzer] unspecified
+    // [cfe] unspecified
+  }
+
+  foo<Stream<Object?>>().toList();
+
+  C.factory();
+
+  return _;
+}
+
+T? maybeNullable<T>(Object value) =>
+    identical(value, Object()) ? null : value as T;
+T maybeNotNullable<T>(Object value) => value as T;
+
+class C {
+  C();
+  factory C.factory() {
+    C? cq = maybeNullable(C());
+    // A factory constructor must not return `null`.
+    return cq;
+    //     ^^
+    // [analyzer] unspecified
+    // [cfe] unspecified
+  }
+}
+
+dynamic nullable() {
+  // Check places where the operand type must be *nullable*.
+  // This should only generate *warnings*, not errors.
+  // This is generally null-aware operations.
+  int nn = 0;
+
+  dynamic _;
+
+  _ = nn ?? 1;
+  //  ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  _ = nn ??= 1;
+  //  ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  _ = nn?.toRadixString(16);
+  //  ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  _ = nn?..toRadixString(16);
+  //  ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  _ = nn!;
+  //  ^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  List<int> nni = [1];
+  _ = [...?nni];
+  //       ^^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  _ = nni?[0];
+  //  ^^^
+  // [analyzer] unspecified
+  // [cfe] unspecified
+
+  return _;
+}
+
+void potentiallyNullable<NN extends int?, NNI extends List<int>?>() {
+  // Check places where the operand type must not be *non-nullable*.
+  // See that it does allow *potentially* nullable expression.
+  // This allows a potentially nullable value to be implicitly used as
+  // nullable (which is a safe approximation, since it might be one,
+  // and if not, it's just not null).
+  NN nn = maybeNotNullable<NN>(0);
+
+  nn ?? 1;
+
+  nn ??= 1;
+
+  nn?.toRadixString(16);
+
+  nn?..toRadixString(16);
+
+  nn!;
+
+  NNI nni = maybeNotNullable<NNI>(<int>[1]);
+
+  [...?nni];
+
+  nni?[0];
+}
diff --git a/tests/language/nnbd/syntax/late_modifier_final_field_test.dart b/tests/language/nnbd/syntax/late_modifier_final_field_test.dart
index e7d8acb..a22c6ec 100644
--- a/tests/language/nnbd/syntax/late_modifier_final_field_test.dart
+++ b/tests/language/nnbd/syntax/late_modifier_final_field_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 // SharedOptions=--enable-experiment=non-nullable
+// VMOptions=--optimization_counter_threshold=10
 import 'package:expect/expect.dart';
 
 int initCalls = 0;
@@ -25,45 +26,48 @@
 }
 
 main() {
-  Base a = A();
-  Expect.equals(0, initCalls);
-  Expect.equals(123, a.fieldWithInit);
-  Expect.equals(1, initCalls);
-  Expect.equals(123, a.fieldWithInit);
-  Expect.equals(1, initCalls);
-  // Setting Base.fieldWithInit once is ok but causes no calls to init().
-  a.fieldWithInit = 456;
-  Expect.equals(456, (a as A).superFieldWithInit);
-  Expect.equals(123, a.fieldWithInit);
-  Expect.equals(1, initCalls);
-  // Setting Base.fieldWithInit twice throws an error.
-  Expect.throws(() => {a.fieldWithInit = 789},
-      (error) => error is LateInitializationError);
-  Expect.equals(1, initCalls);
-  Expect.equals(123, a.fieldWithInit);
-  Expect.equals(1, initCalls);
-  initCalls = 0;
+  for (int i = 0; i < 20; ++i) {
+    Base a = A();
+    Expect.equals(0, initCalls);
+    Expect.equals(123, a.fieldWithInit);
+    Expect.equals(1, initCalls);
+    Expect.equals(123, a.fieldWithInit);
+    Expect.equals(1, initCalls);
+    // Setting Base.fieldWithInit once is ok but causes no calls to init().
+    a.fieldWithInit = 456;
+    Expect.equals(456, (a as A).superFieldWithInit);
+    Expect.equals(123, a.fieldWithInit);
+    Expect.equals(1, initCalls);
+    // Setting Base.fieldWithInit twice throws an error.
+    Expect.throws(() => {a.fieldWithInit = 789},
+        (error) => error is LateInitializationError);
+    Expect.equals(1, initCalls);
+    Expect.equals(123, a.fieldWithInit);
+    Expect.equals(1, initCalls);
+    initCalls = 0;
 
-  Base a2 = A();
-  Expect.equals(0, initCalls);
-  // Setting Base.fieldWithInit once is ok but causes no calls to init().
-  a2.fieldWithInit = 456;
-  Expect.equals(456, (a as A).superFieldWithInit);
-  Expect.equals(0, initCalls);
-  // Setting Base.fieldWithInit twice throws an error.
-  Expect.throws(() => {a2.fieldWithInit = 789},
-      (error) => error is LateInitializationError);
-  Expect.equals(0, initCalls);
-  Expect.equals(123, a2.fieldWithInit);
-  Expect.equals(456, (a as A).superFieldWithInit);
-  Expect.equals(1, initCalls);
+    Base a2 = A();
+    Expect.equals(0, initCalls);
+    // Setting Base.fieldWithInit once is ok but causes no calls to init().
+    a2.fieldWithInit = 456;
+    Expect.equals(456, (a as A).superFieldWithInit);
+    Expect.equals(0, initCalls);
+    // Setting Base.fieldWithInit twice throws an error.
+    Expect.throws(() => {a2.fieldWithInit = 789},
+        (error) => error is LateInitializationError);
+    Expect.equals(0, initCalls);
+    Expect.equals(123, a2.fieldWithInit);
+    Expect.equals(456, (a as A).superFieldWithInit);
+    Expect.equals(1, initCalls);
 
-  B b = B();
-  Expect.throws(
-      () => b.fieldWithNoInit, (error) => error is LateInitializationError);
-  b.fieldWithNoInit = 123;
-  Expect.equals(123, b.fieldWithNoInit);
-  Expect.throws(() => {b.fieldWithNoInit = 456},
-      (error) => error is LateInitializationError);
-  Expect.equals(123, b.fieldWithNoInit);
+    B b = B();
+    Expect.throws(
+        () => b.fieldWithNoInit, (error) => error is LateInitializationError);
+    b.fieldWithNoInit = 123;
+    Expect.equals(123, b.fieldWithNoInit);
+    Expect.throws(() => {b.fieldWithNoInit = 456},
+        (error) => error is LateInitializationError);
+    Expect.equals(123, b.fieldWithNoInit);
+    initCalls = 0;
+  }
 }
diff --git a/tests/language/nnbd/syntax/late_modifier_final_local_var_test.dart b/tests/language/nnbd/syntax/late_modifier_final_local_var_test.dart
index 011cfe5..97d790d 100644
--- a/tests/language/nnbd/syntax/late_modifier_final_local_var_test.dart
+++ b/tests/language/nnbd/syntax/late_modifier_final_local_var_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 // SharedOptions=--enable-experiment=non-nullable
+// VMOptions=--optimization_counter_threshold=10
 import 'package:expect/expect.dart';
 
 int initCalls = 0;
@@ -12,28 +13,31 @@
 }
 
 main() {
-  late final int fieldWithInit = init();
-  Expect.equals(0, initCalls);
-  Expect.equals(123, fieldWithInit);
-  Expect.equals(1, initCalls);
-  Expect.equals(123, fieldWithInit);
-  Expect.equals(1, initCalls);
+  for (int i = 0; i < 20; ++i) {
+    late final int fieldWithInit = init();
+    Expect.equals(0, initCalls);
+    Expect.equals(123, fieldWithInit);
+    Expect.equals(1, initCalls);
+    Expect.equals(123, fieldWithInit);
+    Expect.equals(1, initCalls);
 
-  late final int fieldWithNoInit;
-  Expect.throws(
-    () => fieldWithNoInit,
-    (error) => error is LateInitializationError,
-  );
-  // Confuse the definite assignment analysis.
-  if (1 > 0) {
-    fieldWithNoInit = 123;
+    late final int fieldWithNoInit;
+    Expect.throws(
+      () => fieldWithNoInit,
+      (error) => error is LateInitializationError,
+    );
+    // Confuse the definite assignment analysis.
+    if (1 > 0) {
+      fieldWithNoInit = 123;
+    }
+    Expect.equals(123, fieldWithNoInit);
+    Expect.throws(
+      () {
+        fieldWithNoInit = 456;
+      },
+      (error) => error is LateInitializationError,
+    );
+    Expect.equals(123, fieldWithNoInit);
+    initCalls = 0;
   }
-  Expect.equals(123, fieldWithNoInit);
-  Expect.throws(
-    () {
-      fieldWithNoInit = 456;
-    },
-    (error) => error is LateInitializationError,
-  );
-  Expect.equals(123, fieldWithNoInit);
 }
diff --git a/tests/language/nnbd/syntax/late_modifier_local_var_test.dart b/tests/language/nnbd/syntax/late_modifier_local_var_test.dart
index d52ff6f..4164b8b 100644
--- a/tests/language/nnbd/syntax/late_modifier_local_var_test.dart
+++ b/tests/language/nnbd/syntax/late_modifier_local_var_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 // SharedOptions=--enable-experiment=non-nullable
+// VMOptions=--optimization_counter_threshold=10
 import 'package:expect/expect.dart';
 
 int initCalls = 0;
@@ -12,59 +13,62 @@
 }
 
 main() {
-  late int varWithInit = init();
-  late int varWithTrivialInit = 123;
-  late int? varWithNullInit = null;
-  late int varWithNoInit;
-  Expect.equals(0, initCalls);
-  Expect.equals(123, varWithInit);
-  Expect.equals(123, varWithTrivialInit);
-  Expect.equals(null, varWithNullInit);
-  Expect.throws(
-      () => varWithNoInit, (error) => error is LateInitializationError);
-  Expect.equals(1, initCalls);
-  Expect.equals(123, varWithInit);
-  Expect.equals(123, varWithTrivialInit);
-  Expect.equals(null, varWithNullInit);
-  Expect.throws(
-      () => varWithNoInit, (error) => error is LateInitializationError);
-  Expect.equals(1, initCalls);
-  varWithInit = 456;
-  varWithTrivialInit = 456;
-  varWithNullInit = 456;
-  varWithNoInit = 456;
-  Expect.equals(1, initCalls);
-  Expect.equals(456, varWithInit);
-  Expect.equals(456, varWithTrivialInit);
-  Expect.equals(456, varWithNullInit);
-  Expect.equals(456, varWithNoInit);
-  Expect.equals(1, initCalls);
-  initCalls = 0;
-
-  late int varWithInit2 = init();
-  Expect.equals(0, initCalls);
-  varWithInit2 = 456;
-  Expect.equals(0, initCalls);
-  Expect.equals(456, varWithInit2);
-  Expect.equals(0, initCalls);
-
-  late int? varWithInit3 = init();
-  Expect.equals(0, initCalls);
-  varWithInit3 = null;
-  Expect.equals(0, initCalls);
-  Expect.equals(null, varWithInit3);
-  Expect.equals(0, initCalls);
-
-  late int varWithCondInit = null ?? init();
-  var lambda = () {
-    Expect.equals(123, varWithCondInit);
+  for (int i = 0; i < 20; ++i) {
+    late int varWithInit = init();
+    late int varWithTrivialInit = 123;
+    late int? varWithNullInit = null;
+    late int varWithNoInit;
+    Expect.equals(0, initCalls);
+    Expect.equals(123, varWithInit);
+    Expect.equals(123, varWithTrivialInit);
+    Expect.equals(null, varWithNullInit);
+    Expect.throws(
+        () => varWithNoInit, (error) => error is LateInitializationError);
     Expect.equals(1, initCalls);
-  };
-  lambda();
-  lambda();
-  lambda();
-  initCalls = 0;
+    Expect.equals(123, varWithInit);
+    Expect.equals(123, varWithTrivialInit);
+    Expect.equals(null, varWithNullInit);
+    Expect.throws(
+        () => varWithNoInit, (error) => error is LateInitializationError);
+    Expect.equals(1, initCalls);
+    varWithInit = 456;
+    varWithTrivialInit = 456;
+    varWithNullInit = 456;
+    varWithNoInit = 456;
+    Expect.equals(1, initCalls);
+    Expect.equals(456, varWithInit);
+    Expect.equals(456, varWithTrivialInit);
+    Expect.equals(456, varWithNullInit);
+    Expect.equals(456, varWithNoInit);
+    Expect.equals(1, initCalls);
+    initCalls = 0;
 
-  if (true) late int varNotInBlock = init();
-  Expect.equals(0, initCalls);
+    late int varWithInit2 = init();
+    Expect.equals(0, initCalls);
+    varWithInit2 = 456;
+    Expect.equals(0, initCalls);
+    Expect.equals(456, varWithInit2);
+    Expect.equals(0, initCalls);
+
+    late int? varWithInit3 = init();
+    Expect.equals(0, initCalls);
+    varWithInit3 = null;
+    Expect.equals(0, initCalls);
+    Expect.equals(null, varWithInit3);
+    Expect.equals(0, initCalls);
+
+    late int varWithCondInit = null ?? init();
+    var lambda = () {
+      Expect.equals(123, varWithCondInit);
+      Expect.equals(1, initCalls);
+    };
+    lambda();
+    lambda();
+    lambda();
+    initCalls = 0;
+
+    if (true) late int varNotInBlock = init();
+    Expect.equals(0, initCalls);
+    initCalls = 0;
+  }
 }
diff --git a/tests/language/nnbd/syntax/late_modifier_non_final_field_test.dart b/tests/language/nnbd/syntax/late_modifier_non_final_field_test.dart
index 804e519..0447025 100644
--- a/tests/language/nnbd/syntax/late_modifier_non_final_field_test.dart
+++ b/tests/language/nnbd/syntax/late_modifier_non_final_field_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 // SharedOptions=--enable-experiment=non-nullable
+// VMOptions=--optimization_counter_threshold=10
 import 'package:expect/expect.dart';
 
 int initCalls = 0;
@@ -19,46 +20,49 @@
 }
 
 main() {
-  // Late, non-final, with init.
-  var a = A();
-  Expect.equals(0, initCalls);
-  Expect.equals(123, a.fieldWithInit);
-  Expect.equals(123, a.fieldWithTrivialInit);
-  Expect.equals(null, a.fieldWithNullInit);
-  Expect.throws(
-      () => a.fieldWithNoInit, (error) => error is LateInitializationError);
-  Expect.equals(1, initCalls);
-  Expect.equals(123, a.fieldWithInit);
-  Expect.equals(123, a.fieldWithTrivialInit);
-  Expect.equals(null, a.fieldWithNullInit);
-  Expect.throws(
-      () => a.fieldWithNoInit, (error) => error is LateInitializationError);
-  Expect.equals(1, initCalls);
-  a.fieldWithInit = 456;
-  a.fieldWithTrivialInit = 456;
-  a.fieldWithNullInit = 456;
-  a.fieldWithNoInit = 456;
-  Expect.equals(1, initCalls);
-  Expect.equals(456, a.fieldWithInit);
-  Expect.equals(456, a.fieldWithTrivialInit);
-  Expect.equals(456, a.fieldWithNullInit);
-  Expect.equals(456, a.fieldWithNoInit);
-  Expect.equals(1, initCalls);
-  initCalls = 0;
+  for (int i = 0; i < 20; ++i) {
+    // Late, non-final, with init.
+    var a = A();
+    Expect.equals(0, initCalls);
+    Expect.equals(123, a.fieldWithInit);
+    Expect.equals(123, a.fieldWithTrivialInit);
+    Expect.equals(null, a.fieldWithNullInit);
+    Expect.throws(
+        () => a.fieldWithNoInit, (error) => error is LateInitializationError);
+    Expect.equals(1, initCalls);
+    Expect.equals(123, a.fieldWithInit);
+    Expect.equals(123, a.fieldWithTrivialInit);
+    Expect.equals(null, a.fieldWithNullInit);
+    Expect.throws(
+        () => a.fieldWithNoInit, (error) => error is LateInitializationError);
+    Expect.equals(1, initCalls);
+    a.fieldWithInit = 456;
+    a.fieldWithTrivialInit = 456;
+    a.fieldWithNullInit = 456;
+    a.fieldWithNoInit = 456;
+    Expect.equals(1, initCalls);
+    Expect.equals(456, a.fieldWithInit);
+    Expect.equals(456, a.fieldWithTrivialInit);
+    Expect.equals(456, a.fieldWithNullInit);
+    Expect.equals(456, a.fieldWithNoInit);
+    Expect.equals(1, initCalls);
+    initCalls = 0;
 
-  // Late, non-final, with init that's pre-empted by setter.
-  var b = A();
-  Expect.equals(0, initCalls);
-  b.fieldWithInit = 456;
-  Expect.equals(0, initCalls);
-  Expect.equals(456, b.fieldWithInit);
-  Expect.equals(0, initCalls);
+    // Late, non-final, with init that's pre-empted by setter.
+    var b = A();
+    Expect.equals(0, initCalls);
+    b.fieldWithInit = 456;
+    Expect.equals(0, initCalls);
+    Expect.equals(456, b.fieldWithInit);
+    Expect.equals(0, initCalls);
 
-  // Late, non-final, with init that's pre-empted by null setter.
-  var c = A();
-  Expect.equals(0, initCalls);
-  c.fieldWithInit = null;
-  Expect.equals(0, initCalls);
-  Expect.equals(null, c.fieldWithInit);
-  Expect.equals(0, initCalls);
+    // Late, non-final, with init that's pre-empted by null setter.
+    var c = A();
+    Expect.equals(0, initCalls);
+    c.fieldWithInit = null;
+    Expect.equals(0, initCalls);
+    Expect.equals(null, c.fieldWithInit);
+    Expect.equals(0, initCalls);
+    initCalls = 0;
+  }
 }
diff --git a/tests/language/operator/invalid_operators_test.dart b/tests/language/operator/invalid_operators_test.dart
index d0ec7e4..5faf742 100644
--- a/tests/language/operator/invalid_operators_test.dart
+++ b/tests/language/operator/invalid_operators_test.dart
@@ -161,9 +161,10 @@
 }
 
 class Operators3 {
-  operator ==([a]) => true;
+  operator ==([dynamic a]) => true;
   //           ^
   // [analyzer] COMPILE_TIME_ERROR.OPTIONAL_PARAMETER_IN_OPERATOR
+  //                   ^
   // [cfe] An operator can't have optional parameters.
   operator <([a]) => true;
   //          ^
diff --git a/tests/language_2/argument/assignability_function_typed_runtime_1_test.dart b/tests/language_2/argument/assignability_function_typed_runtime_1_test.dart
index 4b6ea49..506b358 100644
--- a/tests/language_2/argument/assignability_function_typed_runtime_1_test.dart
+++ b/tests/language_2/argument/assignability_function_typed_runtime_1_test.dart
@@ -5,6 +5,9 @@
 // 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.
 
+// [NNBD non-migrated] Note: This test is specific to legacy mode and
+// deliberately does not have a counter-part in language/.
+
 import "package:expect/expect.dart";
 
 void f(num callback(num x)) {}
diff --git a/tests/language_2/argument/assignability_function_typed_runtime_2_test.dart b/tests/language_2/argument/assignability_function_typed_runtime_2_test.dart
index 420f70a..4a355f2 100644
--- a/tests/language_2/argument/assignability_function_typed_runtime_2_test.dart
+++ b/tests/language_2/argument/assignability_function_typed_runtime_2_test.dart
@@ -5,6 +5,9 @@
 // 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.
 
+// [NNBD non-migrated] Note: This test is specific to legacy mode and
+// deliberately does not have a counter-part in language/.
+
 import "package:expect/expect.dart";
 
 void f(num callback(num x)) {}
diff --git a/tests/language_2/argument/assignability_function_typed_runtime_3_test.dart b/tests/language_2/argument/assignability_function_typed_runtime_3_test.dart
index 0afae71..a99329a 100644
--- a/tests/language_2/argument/assignability_function_typed_runtime_3_test.dart
+++ b/tests/language_2/argument/assignability_function_typed_runtime_3_test.dart
@@ -5,6 +5,9 @@
 // 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.
 
+// [NNBD non-migrated] Note: This test is specific to legacy mode and
+// deliberately does not have a counter-part in language/.
+
 import "package:expect/expect.dart";
 
 void f(num callback(num x)) {}
diff --git a/tests/language_2/generic/function_dcall_test.dart b/tests/language_2/generic/function_dcall_test.dart
index 6de579f..28fa0dc 100644
--- a/tests/language_2/generic/function_dcall_test.dart
+++ b/tests/language_2/generic/function_dcall_test.dart
@@ -46,7 +46,8 @@
 
 void testGenericFnTypeToString() {
   T f<T>(T a) => a;
-  Expect.equals(f.runtimeType.toString(), "<T>(T) => T");
+  Expect.isTrue(
+      f.runtimeType.toString().contains(RegExp(r'<(\w+)>\(\1\) => \1')));
 }
 
 main() {
diff --git a/tests/language_2/nosuchmethod_forwarding/abstract_override_with_different_type.dart b/tests/language_2/nosuchmethod_forwarding/abstract_override_with_different_type.dart
new file mode 100644
index 0000000..9a1aa2d
--- /dev/null
+++ b/tests/language_2/nosuchmethod_forwarding/abstract_override_with_different_type.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2018, 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.
+
+// This is a regression test for http://dartbug.com/40248.
+
+import "package:expect/expect.dart";
+
+class Base {
+  set push(int x);
+  set float(covariant int x);
+  noSuchMethod(i) => print("${runtimeType}: ${i.positionalArguments[0]}");
+}
+
+class Me extends Base {}
+
+class You extends Base {
+  set push(num x);
+  set float(num x);
+}
+
+main() {
+  List<Base> list = [Me(), You()];
+  for (Base baba in list) {
+    baba.push = 0;
+    baba.float = 1;
+    if (baba is You) {
+      baba.push = 2.3;
+      baba.float = 4.5;
+    }
+    try {
+      (baba as dynamic).push = 6.7;
+      Expect.isTrue(baba is You);
+    } on TypeError {
+      Expect.isTrue(baba is Me);
+    }
+    try {
+      (baba as dynamic).float = 8.9;
+      Expect.isTrue(baba is You);
+    } on TypeError {
+      Expect.isTrue(baba is Me);
+    }
+  }
+}
diff --git a/tests/language_2/type_object/literal_type_literal_test.dart b/tests/language_2/type_object/literal_type_literal_test.dart
index 78c0541..92da452 100644
--- a/tests/language_2/type_object/literal_type_literal_test.dart
+++ b/tests/language_2/type_object/literal_type_literal_test.dart
@@ -69,12 +69,11 @@
       ["GenericTypedef2", "GenericTypedef2<dynamic>", "(dynamic) => int"]);
   testType(new Box<GenericTypedef<int>>().typeArg,
       ["GenericTypedef<int>", "(int) => int"]);
-  testType(GenericFunc, ["GenericFunc", "<T>(T) => int", "<T1>(T1) => int"]);
+  testType(GenericFunc, ["GenericFunc", RegExp(r'<(\w+)>\((\1)\) => int')]);
   testType(GenericTypedefAndFunc, [
     "GenericTypedefAndFunc",
     "GenericTypedefAndFunc<dynamic>",
-    "<T>(T) => dynamic",
-    "<T1>(T1) => dynamic",
+    RegExp(r'<(\w+)>\((\1)\) => dynamic')
   ]);
 
   // Literals are canonicalized.
@@ -103,7 +102,15 @@
   if (text.contains('minified:')) return;
 
   if (expectedToStringValues is List) {
-    Expect.isTrue(expectedToStringValues.contains(text),
+    var matched = false;
+    for (var value in expectedToStringValues) {
+      if (value is String) {
+        matched = matched || value == text;
+      } else if (value is RegExp) {
+        matched = matched || value.hasMatch(text);
+      }
+    }
+    Expect.isTrue(matched,
         'type `$type`.toString() should be one of: $expectedToStringValues.');
   } else {
     var string = expectedToStringValues as String;
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 4dd40c9..432516a 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -123,3 +123,4 @@
 mirrors/library_imports_deferred_test: Crash # Deferred loading
 mirrors/load_library_test: Crash # Deferred loading
 mirrors/typedef_deferred_library_test: Crash # Deferred loading
+typed_data/zeroed_allocation_test: SkipSlow
diff --git a/tests/lib/typed_data/float32x4_clamp_test.dart b/tests/lib/typed_data/float32x4_clamp_test.dart
index 0109478..2a9fb32 100644
--- a/tests/lib/typed_data/float32x4_clamp_test.dart
+++ b/tests/lib/typed_data/float32x4_clamp_test.dart
@@ -31,9 +31,41 @@
   Expect.equals(a.w, 0.0);
 }
 
+Float32x4 negativeZeroClamp() {
+  final negZero = -Float32x4.zero();
+  return negZero.clamp(negZero, Float32x4.zero());
+}
+
+Float32x4 zeroClamp() {
+  final negOne = -Float32x4(1.0, 1.0, 1.0, 1.0);
+  return Float32x4.zero().clamp(negOne, -Float32x4.zero());
+}
+
+// Regression test for https://github.com/dart-lang/sdk/issues/40426.
+void testNegativeZeroClamp(Float32x4 unopt) {
+  final res = negativeZeroClamp();
+  Expect.equals(res.x.compareTo(unopt.x), 0);
+  Expect.equals(res.y.compareTo(unopt.y), 0);
+  Expect.equals(res.z.compareTo(unopt.z), 0);
+  Expect.equals(res.w.compareTo(unopt.w), 0);
+}
+
+// Regression test for https://github.com/dart-lang/sdk/issues/40426.
+void testZeroClamp(Float32x4 unopt) {
+  final res = zeroClamp();
+  Expect.equals(res.x.compareTo(unopt.x), 0);
+  Expect.equals(res.y.compareTo(unopt.y), 0);
+  Expect.equals(res.z.compareTo(unopt.z), 0);
+  Expect.equals(res.w.compareTo(unopt.w), 0);
+}
+
 main() {
+  final unoptNegZeroClamp = negativeZeroClamp();
+  final unoptZeroClamp = zeroClamp();
   for (int i = 0; i < 2000; i++) {
     testClampLowerGreaterThanUpper();
     testClamp();
+    testNegativeZeroClamp(unoptNegZeroClamp);
+    testZeroClamp(unoptZeroClamp);
   }
 }
diff --git a/tests/lib/typed_data/zeroed_allocation_test.dart b/tests/lib/typed_data/zeroed_allocation_test.dart
new file mode 100644
index 0000000..ee5c229
--- /dev/null
+++ b/tests/lib/typed_data/zeroed_allocation_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:typed_data';
+import 'package:expect/expect.dart';
+
+final KB = 1024;
+
+final interestingSizes = <int>[
+  4 * KB, // VirtualMemory::PageSize()
+  64 * KB, // Heap::kAllocatablePageSize
+  256 * KB, // Heap::kNewAllocatableSize
+  512 * KB, // PageSpace::kPageSize
+];
+
+main() {
+  for (var base in interestingSizes) {
+    for (var delta = -32; delta <= 32; delta++) {
+      final size = base + delta;
+      final array = new Uint8List(size);
+      for (var i = 0; i < size; i++) {
+        Expect.equals(0, array[i]);
+      }
+    }
+  }
+}
diff --git a/tests/lib_2/lib_2.status b/tests/lib_2/lib_2.status
index 4dd40c9..432516a 100644
--- a/tests/lib_2/lib_2.status
+++ b/tests/lib_2/lib_2.status
@@ -123,3 +123,4 @@
 mirrors/library_imports_deferred_test: Crash # Deferred loading
 mirrors/load_library_test: Crash # Deferred loading
 mirrors/typedef_deferred_library_test: Crash # Deferred loading
+typed_data/zeroed_allocation_test: SkipSlow
diff --git a/tests/lib_2/typed_data/float32x4_clamp_test.dart b/tests/lib_2/typed_data/float32x4_clamp_test.dart
index 0109478..2a9fb32 100644
--- a/tests/lib_2/typed_data/float32x4_clamp_test.dart
+++ b/tests/lib_2/typed_data/float32x4_clamp_test.dart
@@ -31,9 +31,41 @@
   Expect.equals(a.w, 0.0);
 }
 
+Float32x4 negativeZeroClamp() {
+  final negZero = -Float32x4.zero();
+  return negZero.clamp(negZero, Float32x4.zero());
+}
+
+Float32x4 zeroClamp() {
+  final negOne = -Float32x4(1.0, 1.0, 1.0, 1.0);
+  return Float32x4.zero().clamp(negOne, -Float32x4.zero());
+}
+
+// Regression test for https://github.com/dart-lang/sdk/issues/40426.
+void testNegativeZeroClamp(Float32x4 unopt) {
+  final res = negativeZeroClamp();
+  Expect.equals(res.x.compareTo(unopt.x), 0);
+  Expect.equals(res.y.compareTo(unopt.y), 0);
+  Expect.equals(res.z.compareTo(unopt.z), 0);
+  Expect.equals(res.w.compareTo(unopt.w), 0);
+}
+
+// Regression test for https://github.com/dart-lang/sdk/issues/40426.
+void testZeroClamp(Float32x4 unopt) {
+  final res = zeroClamp();
+  Expect.equals(res.x.compareTo(unopt.x), 0);
+  Expect.equals(res.y.compareTo(unopt.y), 0);
+  Expect.equals(res.z.compareTo(unopt.z), 0);
+  Expect.equals(res.w.compareTo(unopt.w), 0);
+}
+
 main() {
+  final unoptNegZeroClamp = negativeZeroClamp();
+  final unoptZeroClamp = zeroClamp();
   for (int i = 0; i < 2000; i++) {
     testClampLowerGreaterThanUpper();
     testClamp();
+    testNegativeZeroClamp(unoptNegZeroClamp);
+    testZeroClamp(unoptZeroClamp);
   }
 }
diff --git a/tests/lib_2/typed_data/zeroed_allocation_test.dart b/tests/lib_2/typed_data/zeroed_allocation_test.dart
new file mode 100644
index 0000000..ee5c229
--- /dev/null
+++ b/tests/lib_2/typed_data/zeroed_allocation_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:typed_data';
+import 'package:expect/expect.dart';
+
+final KB = 1024;
+
+final interestingSizes = <int>[
+  4 * KB, // VirtualMemory::PageSize()
+  64 * KB, // Heap::kAllocatablePageSize
+  256 * KB, // Heap::kNewAllocatableSize
+  512 * KB, // PageSpace::kPageSize
+];
+
+main() {
+  for (var base in interestingSizes) {
+    for (var delta = -32; delta <= 32; delta++) {
+      final size = base + delta;
+      final array = new Uint8List(size);
+      for (var i = 0; i < size; i++) {
+        Expect.equals(0, array[i]);
+      }
+    }
+  }
+}
diff --git a/tools/VERSION b/tools/VERSION
index fe48ed7..d082e04 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -33,7 +33,7 @@
 MAJOR 2
 MINOR 8
 PATCH 0
-PRERELEASE 7
+PRERELEASE 8
 PRERELEASE_PATCH 0
 ABI_VERSION 28
 OLDEST_SUPPORTED_ABI_VERSION 28
diff --git a/tools/bots/post_results_to_pubsub.dart b/tools/bots/post_results_to_pubsub.dart
index 92e91d1..d864765 100644
--- a/tools/bots/post_results_to_pubsub.dart
+++ b/tools/bots/post_results_to_pubsub.dart
@@ -32,7 +32,7 @@
   exit(1);
 }
 
-const resultsPerMessage = 50;
+const resultsPerMessage = 100;
 const postUrl =
     'https://pubsub.googleapis.com/v1/projects/dart-ci/topics/results:publish';
 
diff --git a/tools/build.py b/tools/build.py
index 6b99e44..274374c 100755
--- a/tools/build.py
+++ b/tools/build.py
@@ -214,13 +214,15 @@
     return True
 
 
-def RunGNIfNeeded(out_dir, target_os, mode, arch, use_nnbd):
+def RunGNIfNeeded(out_dir, target_os, mode, arch, use_nnbd, sanitizer):
     if os.path.isfile(os.path.join(out_dir, 'args.gn')):
         return
     gn_os = 'host' if target_os == HOST_OS else target_os
     gn_command = [
         'python',
         os.path.join(DART_ROOT, 'tools', 'gn.py'),
+        '--sanitizer',
+        sanitizer,
         '-m',
         mode,
         '-a',
@@ -291,7 +293,7 @@
     using_goma = False
     # TODO(zra): Remove auto-run of gn, replace with prompt for user to run
     # gn.py manually.
-    RunGNIfNeeded(out_dir, target_os, mode, arch, options.nnbd)
+    RunGNIfNeeded(out_dir, target_os, mode, arch, options.nnbd, sanitizer)
     command = ['ninja', '-C', out_dir]
     if options.verbose:
         command += ['-v']
diff --git a/tools/dom/nnbd_src/AttributeMap.dart b/tools/dom/nnbd_src/AttributeMap.dart
index e8c79aa..7c57d7d 100644
--- a/tools/dom/nnbd_src/AttributeMap.dart
+++ b/tools/dom/nnbd_src/AttributeMap.dart
@@ -29,7 +29,7 @@
     if (!containsKey(key)) {
       this[key] = ifAbsent();
     }
-    return this[key];
+    return this[key] as String;
   }
 
   void clear() {
@@ -41,7 +41,7 @@
   void forEach(void f(String key, String value)) {
     for (var key in keys) {
       var value = this[key];
-      f(key, value);
+      f(key, value as String);
     }
   }
 
@@ -50,7 +50,7 @@
     var attributes = _element._attributes;
     var keys = <String>[];
     for (int i = 0, len = attributes.length; i < len; i++) {
-      _Attr attr = attributes[i];
+      _Attr attr = attributes[i] as _Attr;
       if (_matches(attr)) {
         keys.add(attr.name);
       }
@@ -63,7 +63,7 @@
     var attributes = _element._attributes;
     var values = <String>[];
     for (int i = 0, len = attributes.length; i < len; i++) {
-      _Attr attr = attributes[i];
+      _Attr attr = attributes[i] as _Attr;
       if (_matches(attr)) {
         values.add(attr.value);
       }
@@ -96,11 +96,11 @@
   _ElementAttributeMap(Element element) : super(element);
 
   bool containsKey(Object? key) {
-    return _element._hasAttribute(key);
+    return _element._hasAttribute(key as String);
   }
 
   String? operator [](Object? key) {
-    return _element.getAttribute(key);
+    return _element.getAttribute(key as String?);
   }
 
   void operator []=(String key, String value) {
@@ -144,11 +144,11 @@
   _NamespacedAttributeMap(Element element, this._namespace) : super(element);
 
   bool containsKey(Object? key) {
-    return _element._hasAttributeNS(_namespace, key);
+    return _element._hasAttributeNS(_namespace, key as String);
   }
 
   String? operator [](Object? key) {
-    return _element.getAttributeNS(_namespace, key);
+    return _element.getAttributeNS(_namespace, key as String?);
   }
 
   void operator []=(String key, String value) {
@@ -207,9 +207,10 @@
   // TODO: Use lazy iterator when it is available on Map.
   bool containsValue(Object? value) => values.any((v) => v == value);
 
-  bool containsKey(Object? key) => _attributes.containsKey(_attr(key));
+  bool containsKey(Object? key) =>
+      _attributes.containsKey(_attr(key as String));
 
-  String? operator [](Object? key) => _attributes[_attr(key)];
+  String? operator [](Object? key) => _attributes[_attr(key as String)];
 
   void operator []=(String key, String value) {
     _attributes[_attr(key)] = value;
@@ -218,7 +219,7 @@
   String putIfAbsent(String key, String ifAbsent()) =>
       _attributes.putIfAbsent(_attr(key), ifAbsent);
 
-  String? remove(Object? key) => _attributes.remove(_attr(key));
+  String? remove(Object? key) => _attributes.remove(_attr(key as String));
 
   void clear() {
     // Needs to operate on a snapshot since we are mutating the collection.
diff --git a/tools/dom/nnbd_src/CrossFrameTypes.dart b/tools/dom/nnbd_src/CrossFrameTypes.dart
index a2aa545..7d210a3 100644
--- a/tools/dom/nnbd_src/CrossFrameTypes.dart
+++ b/tools/dom/nnbd_src/CrossFrameTypes.dart
@@ -61,7 +61,7 @@
    *     WindowBase otherWindow = thisWindow.open('http://www.example.com/', 'foo');
    *     print(otherWindow.opener == thisWindow); // 'true'
    */
-  WindowBase get opener;
+  WindowBase? get opener;
 
   /**
    * A reference to the parent of this window.
@@ -75,7 +75,7 @@
    *
    *     print(window.parent == window) // 'true'
    */
-  WindowBase get parent;
+  WindowBase? get parent;
 
   /**
    * A reference to the topmost window in the window hierarchy.
@@ -96,7 +96,7 @@
    *
    *     print(window.top == window) // 'true'
    */
-  WindowBase get top;
+  WindowBase? get top;
 
   // Methods.
   /**
@@ -142,7 +142,7 @@
    *   from WHATWG.
    */
   void postMessage(var message, String targetOrigin,
-      [List<MessagePort> messagePorts]);
+      [List<MessagePort>? messagePorts]);
 }
 
 abstract class LocationBase {
diff --git a/tools/dom/nnbd_src/CssClassSet.dart b/tools/dom/nnbd_src/CssClassSet.dart
index d2a28e1..9b38b8d 100644
--- a/tools/dom/nnbd_src/CssClassSet.dart
+++ b/tools/dom/nnbd_src/CssClassSet.dart
@@ -23,7 +23,7 @@
    * non-empty string containing no whitespace.  To toggle multiple classes, use
    * [toggleAll].
    */
-  bool toggle(String value, [bool shouldAdd]);
+  bool toggle(String value, [bool? shouldAdd]);
 
   /**
    * Returns [:true:] if classes cannot be added or removed from this
@@ -107,5 +107,5 @@
    * Each element of [iterable] must be a valid 'token' representing a single
    * class, i.e. a non-empty string containing no whitespace.
    */
-  void toggleAll(Iterable<String> iterable, [bool shouldAdd]);
+  void toggleAll(Iterable<String> iterable, [bool? shouldAdd]);
 }
diff --git a/tools/dom/nnbd_src/CssRectangle.dart b/tools/dom/nnbd_src/CssRectangle.dart
index 9cdef06..d26aac7 100644
--- a/tools/dom/nnbd_src/CssRectangle.dart
+++ b/tools/dom/nnbd_src/CssRectangle.dart
@@ -75,9 +75,9 @@
 class _ContentCssListRect extends _ContentCssRect {
   List<Element> _elementList;
 
-  _ContentCssListRect(List<Element> elementList) : super(elementList.first) {
-    _elementList = elementList;
-  }
+  _ContentCssListRect(List<Element> elementList)
+      : _elementList = elementList,
+        super(elementList.first);
 
   /**
    * Set the height to `newHeight`.
@@ -299,7 +299,7 @@
    * Returns the intersection of this and `other`, or `null` if they don't
    * intersect.
    */
-  Rectangle<num> intersection(Rectangle<num> other) {
+  Rectangle<num>? intersection(Rectangle<num> other) {
     var x0 = max(left, other.left);
     var x1 = min(left + width, other.left + other.width);
 
diff --git a/tools/dom/nnbd_src/Dimension.dart b/tools/dom/nnbd_src/Dimension.dart
index 502b68d..7ed02192 100644
--- a/tools/dom/nnbd_src/Dimension.dart
+++ b/tools/dom/nnbd_src/Dimension.dart
@@ -57,7 +57,9 @@
    * `inherit` or invalid CSS will cause this constructor to throw a
    * FormatError.
    */
-  Dimension.css(String cssValue) {
+  Dimension.css(String cssValue)
+      : _unit = '',
+        _value = 0 {
     if (cssValue == '') cssValue = '0px';
     if (cssValue.endsWith('%')) {
       _unit = '%';
diff --git a/tools/dom/nnbd_src/EventStreamProvider.dart b/tools/dom/nnbd_src/EventStreamProvider.dart
index cb7e69b..ec89e89 100644
--- a/tools/dom/nnbd_src/EventStreamProvider.dart
+++ b/tools/dom/nnbd_src/EventStreamProvider.dart
@@ -34,7 +34,7 @@
    * * [EventTarget.addEventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)
    *   from MDN.
    */
-  Stream<T> forTarget(EventTarget e, {bool useCapture: false}) =>
+  Stream<T> forTarget(EventTarget? e, {bool useCapture: false}) =>
       new _EventStream<T>(e, _eventType, useCapture);
 
   /**
@@ -126,7 +126,7 @@
  * Adapter for exposing DOM events as Dart streams.
  */
 class _EventStream<T extends Event> extends Stream<T> {
-  final EventTarget _target;
+  final EventTarget? _target;
   final String _eventType;
   final bool _useCapture;
 
@@ -225,9 +225,9 @@
 
 class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> {
   int _pauseCount = 0;
-  EventTarget _target;
+  EventTarget? _target;
   final String _eventType;
-  EventListener _onData;
+  EventListener? _onData;
   final bool _useCapture;
 
   // TODO(leafp): It would be better to write this as
@@ -240,7 +240,7 @@
   // which are typed correctly.  But this currently runs afoul of restrictions
   // on is checks for compatibility with the VM.
   _EventStreamSubscription(
-      this._target, this._eventType, void onData(T event), this._useCapture)
+      this._target, this._eventType, void onData(T event)?, this._useCapture)
       : _onData = onData == null
             ? null
             : _wrapZone<Event>((e) => (onData as dynamic)(e)) {
@@ -248,13 +248,16 @@
   }
 
   Future cancel() {
-    if (_canceled) return null;
+    // Return type cannot be null due to override, so return empty Future
+    // instead.
+    var emptyFuture = new Future<void>.value();
+    if (_canceled) return emptyFuture;
 
     _unlisten();
     // Clear out the target to indicate this is complete.
     _target = null;
     _onData = null;
-    return null;
+    return emptyFuture;
   }
 
   bool get _canceled => _target == null;
@@ -297,13 +300,13 @@
 
   void _tryResume() {
     if (_onData != null && !isPaused) {
-      _target.addEventListener(_eventType, _onData, _useCapture);
+      _target!.addEventListener(_eventType, _onData, _useCapture);
     }
   }
 
   void _unlisten() {
     if (_onData != null) {
-      _target.removeEventListener(_eventType, _onData, _useCapture);
+      _target!.removeEventListener(_eventType, _onData, _useCapture);
     }
   }
 
@@ -332,10 +335,9 @@
   /** The type of event this stream is providing (e.g. "keydown"). */
   String _type;
 
-  _CustomEventStreamImpl(String type) {
-    _type = type;
-    _streamController = new StreamController.broadcast(sync: true);
-  }
+  _CustomEventStreamImpl(String type)
+      : _type = type,
+        _streamController = new StreamController.broadcast(sync: true);
 
   // Delegate all regular Stream behavior to our wrapped Stream.
   StreamSubscription<T> listen(void onData(T event)?,
@@ -362,7 +364,7 @@
 
   void add(KeyEvent event) {
     if (event.type == _type) {
-      event.currentTarget.dispatchEvent(event._parent);
+      event.currentTarget!.dispatchEvent(event._parent);
       _streamController.add(event);
     }
   }
@@ -374,7 +376,7 @@
  */
 // TODO (efortuna): Remove this when Issue 12218 is addressed.
 class _StreamPool<T> {
-  StreamController<T> _controller;
+  StreamController<T>? _controller;
 
   /// Subscriptions to the streams that make up the pool.
   var _subscriptions = new Map<Stream<T>, StreamSubscription<T>>();
@@ -394,7 +396,7 @@
   /**
    * The stream through which all events from streams in the pool are emitted.
    */
-  Stream<T> get stream => _controller.stream;
+  Stream<T> get stream => _controller!.stream;
 
   /**
    * Adds [stream] as a member of this pool.
@@ -405,8 +407,8 @@
    */
   void add(Stream<T> stream) {
     if (_subscriptions.containsKey(stream)) return;
-    _subscriptions[stream] = stream.listen(_controller.add,
-        onError: _controller.addError, onDone: () => remove(stream));
+    _subscriptions[stream] = stream.listen(_controller!.add,
+        onError: _controller!.addError, onDone: () => remove(stream));
   }
 
   /** Removes [stream] as a member of this pool. */
@@ -421,7 +423,7 @@
       subscription.cancel();
     }
     _subscriptions.clear();
-    _controller.close();
+    _controller!.close();
   }
 }
 
@@ -434,7 +436,7 @@
   final _eventTypeGetter;
   const _CustomEventStreamProvider(this._eventTypeGetter);
 
-  Stream<T> forTarget(EventTarget e, {bool useCapture: false}) {
+  Stream<T> forTarget(EventTarget? e, {bool useCapture: false}) {
     return new _EventStream<T>(e, _eventTypeGetter(e), useCapture);
   }
 
diff --git a/tools/dom/nnbd_src/KeyboardEventStream.dart b/tools/dom/nnbd_src/KeyboardEventStream.dart
index 48f7a68..399c037 100644
--- a/tools/dom/nnbd_src/KeyboardEventStream.dart
+++ b/tools/dom/nnbd_src/KeyboardEventStream.dart
@@ -22,7 +22,7 @@
   final String _type;
 
   /** The element we are watching for events to happen on. */
-  final EventTarget _target;
+  final EventTarget? _target;
 
   // The distance to shift from upper case alphabet Roman letters to lower case.
   static final int _ROMAN_ALPHABET_OFFSET = "a".codeUnits[0] - "A".codeUnits[0];
@@ -65,7 +65,7 @@
 
   /** Return a stream for KeyEvents for the specified target. */
   // Note: this actually functions like a factory constructor.
-  CustomStream<KeyEvent> forTarget(EventTarget e, {bool useCapture: false}) {
+  CustomStream<KeyEvent> forTarget(EventTarget? e, {bool useCapture: false}) {
     var handler =
         new _KeyboardEventHandler.initializeAllEventListeners(_type, e);
     return handler._stream;
@@ -85,7 +85,8 @@
    * and charcodes when they are not provided.
    */
   _KeyboardEventHandler.initializeAllEventListeners(this._type, this._target)
-      : super(_EVENT_TYPE) {
+      : _stream = new _CustomKeyEventStreamImpl(_type),
+        super(_EVENT_TYPE) {
     Element.keyDownEvent
         .forTarget(_target, useCapture: true)
         .listen(processKeyDown);
@@ -95,7 +96,6 @@
     Element.keyUpEvent
         .forTarget(_target, useCapture: true)
         .listen(processKeyUp);
-    _stream = new _CustomKeyEventStreamImpl(_type);
   }
 
   /** Determine if caps lock is one of the currently depressed keys. */
@@ -337,7 +337,7 @@
         _keyIdentifier.containsKey(e._shadowKeyIdentifier)) {
       // This is needed for Safari Windows because it currently doesn't give a
       // keyCode/which for non printable keys.
-      e._shadowKeyCode = _keyIdentifier[e._shadowKeyIdentifier];
+      e._shadowKeyCode = _keyIdentifier[e._shadowKeyIdentifier]!;
     }
     e._shadowAltKey = _keyDownList.any((var element) => element.altKey);
     _stream.add(e);
@@ -346,7 +346,7 @@
   /** Handle keyup events. */
   void processKeyUp(KeyboardEvent event) {
     var e = new KeyEvent.wrap(event);
-    KeyboardEvent toRemove = null;
+    KeyboardEvent? toRemove = null;
     for (var key in _keyDownList) {
       if (key.keyCode == e.keyCode) {
         toRemove = key;
diff --git a/tools/dom/nnbd_src/NodeValidatorBuilder.dart b/tools/dom/nnbd_src/NodeValidatorBuilder.dart
index 0c8216f..59f2b27 100644
--- a/tools/dom/nnbd_src/NodeValidatorBuilder.dart
+++ b/tools/dom/nnbd_src/NodeValidatorBuilder.dart
@@ -58,7 +58,7 @@
    * The UriPolicy can be used to restrict the locations the navigation elements
    * are allowed to direct to. By default this will use the default [UriPolicy].
    */
-  void allowNavigation([UriPolicy uriPolicy]) {
+  void allowNavigation([UriPolicy? uriPolicy]) {
     if (uriPolicy == null) {
       uriPolicy = new UriPolicy();
     }
@@ -71,7 +71,7 @@
    * The UriPolicy can be used to restrict the locations the images may be
    * loaded from. By default this will use the default [UriPolicy].
    */
-  void allowImages([UriPolicy uriPolicy]) {
+  void allowImages([UriPolicy? uriPolicy]) {
     if (uriPolicy == null) {
       uriPolicy = new UriPolicy();
     }
@@ -112,7 +112,7 @@
    * If [tagName] is not specified then this allows inline styles on all
    * elements. Otherwise tagName limits the styles to the specified elements.
    */
-  void allowInlineStyles({String tagName}) {
+  void allowInlineStyles({String? tagName}) {
     if (tagName == null) {
       tagName = '*';
     } else {
@@ -130,7 +130,7 @@
    * Common things which are not allowed are script elements, style attributes
    * and any script handlers.
    */
-  void allowHtml5({UriPolicy uriPolicy}) {
+  void allowHtml5({UriPolicy? uriPolicy}) {
     add(new _Html5NodeValidator(uriPolicy: uriPolicy));
   }
 
@@ -149,9 +149,9 @@
    * tag extensions.
    */
   void allowCustomElement(String tagName,
-      {UriPolicy uriPolicy,
+      {UriPolicy? uriPolicy,
       Iterable<String>? attributes,
-      Iterable<String> uriAttributes}) {
+      Iterable<String>? uriAttributes}) {
     var tagNameUpper = tagName.toUpperCase();
     var attrs = attributes
         ?.map<String>((name) => '$tagNameUpper::${name.toLowerCase()}');
@@ -174,9 +174,9 @@
    * custom tags.
    */
   void allowTagExtension(String tagName, String baseName,
-      {UriPolicy uriPolicy,
-      Iterable<String> attributes,
-      Iterable<String> uriAttributes}) {
+      {UriPolicy? uriPolicy,
+      Iterable<String>? attributes,
+      Iterable<String>? uriAttributes}) {
     var baseNameUpper = baseName.toUpperCase();
     var tagNameUpper = tagName.toUpperCase();
     var attrs = attributes
@@ -192,9 +192,9 @@
   }
 
   void allowElement(String tagName,
-      {UriPolicy uriPolicy,
-      Iterable<String> attributes,
-      Iterable<String> uriAttributes}) {
+      {UriPolicy? uriPolicy,
+      Iterable<String>? attributes,
+      Iterable<String>? uriAttributes}) {
     allowCustomElement(tagName,
         uriPolicy: uriPolicy,
         attributes: attributes,
@@ -236,7 +236,7 @@
   final Set<String> allowedElements = new Set<String>();
   final Set<String> allowedAttributes = new Set<String>();
   final Set<String> allowedUriAttributes = new Set<String>();
-  final UriPolicy uriPolicy;
+  final UriPolicy? uriPolicy;
 
   factory _SimpleNodeValidator.allowNavigation(UriPolicy uriPolicy) {
     return new _SimpleNodeValidator(uriPolicy, allowedElements: const [
@@ -311,9 +311,9 @@
    * lowercase attribute name. For example `'IMG:src'`.
    */
   _SimpleNodeValidator(this.uriPolicy,
-      {Iterable<String> allowedElements,
-      Iterable<String> allowedAttributes,
-      Iterable<String> allowedUriAttributes}) {
+      {Iterable<String>? allowedElements,
+      Iterable<String>? allowedAttributes,
+      Iterable<String>? allowedUriAttributes}) {
     this.allowedElements.addAll(allowedElements ?? const []);
     allowedAttributes = allowedAttributes ?? const [];
     allowedUriAttributes = allowedUriAttributes ?? const [];
@@ -333,9 +333,9 @@
   bool allowsAttribute(Element element, String attributeName, String value) {
     var tagName = Element._safeTagName(element);
     if (allowedUriAttributes.contains('$tagName::$attributeName')) {
-      return uriPolicy.allowsUri(value);
+      return uriPolicy!.allowsUri(value);
     } else if (allowedUriAttributes.contains('*::$attributeName')) {
-      return uriPolicy.allowsUri(value);
+      return uriPolicy!.allowsUri(value);
     } else if (allowedAttributes.contains('$tagName::$attributeName')) {
       return true;
     } else if (allowedAttributes.contains('*::$attributeName')) {
@@ -356,8 +356,8 @@
   _CustomElementNodeValidator(
       UriPolicy uriPolicy,
       Iterable<String> allowedElements,
-      Iterable<String> allowedAttributes,
-      Iterable<String> allowedUriAttributes,
+      Iterable<String>? allowedAttributes,
+      Iterable<String>? allowedUriAttributes,
       bool allowTypeExtension,
       bool allowCustomTag)
       : this.allowTypeExtension = allowTypeExtension == true,
diff --git a/tools/dom/nnbd_src/Validators.dart b/tools/dom/nnbd_src/Validators.dart
index ac0663d..01569af 100644
--- a/tools/dom/nnbd_src/Validators.dart
+++ b/tools/dom/nnbd_src/Validators.dart
@@ -19,7 +19,7 @@
    *
    * If a uriPolicy is not specified then the default uriPolicy will be used.
    */
-  factory NodeValidator({UriPolicy uriPolicy}) =>
+  factory NodeValidator({UriPolicy? uriPolicy}) =>
       new _Html5NodeValidator(uriPolicy: uriPolicy);
 
   factory NodeValidator.throws(NodeValidator base) =>
@@ -159,7 +159,7 @@
   _ValidatingTreeSanitizer(this.validator) {}
 
   void sanitizeTree(Node node) {
-    void walk(Node node, Node parent) {
+    void walk(Node node, Node? parent) {
       sanitizeNode(node, parent);
 
       var child = node.lastChild;
@@ -186,7 +186,7 @@
   }
 
   /// Aggressively try to remove node.
-  void _removeNode(Node node, Node parent) {
+  void _removeNode(Node node, Node? parent) {
     // If we have the parent, it's presumably already passed more sanitization
     // or is the fragment, so ask it to remove the child. And if that fails
     // try to set the outer html.
@@ -198,7 +198,7 @@
   }
 
   /// Sanitize the element, assuming we can't trust anything about it.
-  void _sanitizeUntrustedElement(/* Element */ element, Node parent) {
+  void _sanitizeUntrustedElement(/* Element */ element, Node? parent) {
     // If the _hasCorruptedAttributes does not successfully return false,
     // then we consider it corrupted and remove.
     // TODO(alanknight): This is a workaround because on Firefox
@@ -247,7 +247,7 @@
   /// Having done basic sanity checking on the element, and computed the
   /// important attributes we want to check, remove it if it's not valid
   /// or not allowed, either as a whole or particular attributes.
-  void _sanitizeElement(Element element, Node parent, bool corrupted,
+  void _sanitizeElement(Element element, Node? parent, bool corrupted,
       String text, String tag, Map attrs, String isAttr) {
     if (false != corrupted) {
       _removeNode(element, parent);
@@ -290,7 +290,7 @@
   }
 
   /// Sanitize the node and its children recursively.
-  void sanitizeNode(Node node, Node parent) {
+  void sanitizeNode(Node node, Node? parent) {
     switch (node.nodeType) {
       case Node.ELEMENT_NODE:
         _sanitizeUntrustedElement(node, parent);
diff --git a/tools/dom/nnbd_src/WrappedList.dart b/tools/dom/nnbd_src/WrappedList.dart
index 6a8d43c..733e784 100644
--- a/tools/dom/nnbd_src/WrappedList.dart
+++ b/tools/dom/nnbd_src/WrappedList.dart
@@ -34,7 +34,7 @@
 
   // List APIs
 
-  E operator [](int index) => _list[index];
+  E operator [](int index) => _list[index] as E;
 
   void operator []=(int index, E value) {
     _list[index] = value;
@@ -45,18 +45,22 @@
   }
 
   void sort([int compare(E a, E b)?]) {
-    // Implicit downcast on argument from Node to E-extends-Node.
-    _list.sort((Node a, Node b) => compare(a, b));
+    if (compare == null) {
+      _list.sort();
+    } else {
+      _list.sort((Node a, Node b) => compare(a as E, b as E));
+    }
   }
 
-  int indexOf(Object element, [int start = 0]) => _list.indexOf(element, start);
+  int indexOf(Object element, [int start = 0]) =>
+      _list.indexOf(element as Node, start);
 
   int lastIndexOf(Object element, [int? start]) =>
-      _list.lastIndexOf(element, start);
+      _list.lastIndexOf(element as Node, start);
 
   void insert(int index, E element) => _list.insert(index, element);
 
-  E removeAt(int index) => _list.removeAt(index);
+  E removeAt(int index) => _list.removeAt(index) as E;
 
   void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
     _list.setRange(start, end, iterable, skipCount);
diff --git a/tools/dom/nnbd_src/_ListIterators.dart b/tools/dom/nnbd_src/_ListIterators.dart
index 0a9080e..74aaddc 100644
--- a/tools/dom/nnbd_src/_ListIterators.dart
+++ b/tools/dom/nnbd_src/_ListIterators.dart
@@ -9,7 +9,7 @@
   final List<T> _array;
   final int _length; // Cache array length for faster access.
   int _position;
-  T _current;
+  T? _current;
 
   FixedSizeListIterator(List<T> array)
       : _array = array,
@@ -28,14 +28,14 @@
     return false;
   }
 
-  T get current => _current;
+  T get current => _current as T;
 }
 
 // Iterator for arrays with variable size.
 class _VariableSizeListIterator<T> implements Iterator<T> {
   final List<T> _array;
   int _position;
-  T _current;
+  T? _current;
 
   _VariableSizeListIterator(List<T> array)
       : _array = array,
@@ -53,5 +53,5 @@
     return false;
   }
 
-  T get current => _current;
+  T get current => _current as T;
 }
diff --git a/tools/dom/nnbd_src/dart2js_Console.dart b/tools/dom/nnbd_src/dart2js_Console.dart
index 5ed9206..b3297d2 100644
--- a/tools/dom/nnbd_src/dart2js_Console.dart
+++ b/tools/dom/nnbd_src/dart2js_Console.dart
@@ -10,7 +10,7 @@
 
   bool get _isConsoleDefined => JS('bool', 'typeof console != "undefined"');
 
-  MemoryInfo get memory =>
+  MemoryInfo? get memory =>
       _isConsoleDefined ? JS('MemoryInfo', 'window.console.memory') : null;
 
   void assertCondition(bool condition, Object arg) => _isConsoleDefined
diff --git a/tools/dom/nnbd_src/dart2js_Conversions.dart b/tools/dom/nnbd_src/dart2js_Conversions.dart
index aa78ec1..75e944f 100644
--- a/tools/dom/nnbd_src/dart2js_Conversions.dart
+++ b/tools/dom/nnbd_src/dart2js_Conversions.dart
@@ -10,12 +10,12 @@
 
 part of html;
 
-WindowBase _convertNativeToDart_Window(win) {
+WindowBase? _convertNativeToDart_Window(win) {
   if (win == null) return null;
   return _DOMWindowCrossFrame._createSafe(win);
 }
 
-EventTarget _convertNativeToDart_EventTarget(e) {
+EventTarget? _convertNativeToDart_EventTarget(e) {
   if (e == null) {
     return null;
   }
diff --git a/tools/dom/nnbd_src/dart2js_CssClassSet.dart b/tools/dom/nnbd_src/dart2js_CssClassSet.dart
index 0afe6fcf..00d80bc 100644
--- a/tools/dom/nnbd_src/dart2js_CssClassSet.dart
+++ b/tools/dom/nnbd_src/dart2js_CssClassSet.dart
@@ -136,7 +136,7 @@
     _removeWhere(_element, test, false);
   }
 
-  static bool _contains(Element _element, Object value) {
+  static bool _contains(Element _element, Object? value) {
     return value is String && _classListContains(_classListOf(_element), value);
   }
 
@@ -193,10 +193,10 @@
     }
   }
 
-  static void _removeAll(Element _element, Iterable<Object> iterable) {
+  static void _removeAll(Element _element, Iterable<Object?> iterable) {
     DomTokenList list = _classListOf(_element);
-    for (String value in iterable) {
-      _classListRemove(list, value);
+    for (Object? value in iterable) {
+      _classListRemove(list, value as String);
     }
   }
 
@@ -205,7 +205,7 @@
     DomTokenList list = _classListOf(_element);
     int i = 0;
     while (i < _classListLength(list)) {
-      String item = list.item(i);
+      String item = list.item(i)!;
       if (doRemove == test(item)) {
         _classListRemove(list, item);
       } else {
diff --git a/tools/dom/nnbd_src/dart2js_CustomElementSupport.dart b/tools/dom/nnbd_src/dart2js_CustomElementSupport.dart
index 98c3c24..bbe6a37 100644
--- a/tools/dom/nnbd_src/dart2js_CustomElementSupport.dart
+++ b/tools/dom/nnbd_src/dart2js_CustomElementSupport.dart
@@ -66,7 +66,7 @@
   }
 }
 
-Function _registerCustomElement(context, document, String tag, [Map options]) {
+Function _registerCustomElement(context, document, String tag, [Map? options]) {
   // Function follows the same pattern as the following JavaScript code for
   // registering a custom element.
   //
@@ -82,7 +82,7 @@
   //    var e = document.createElement('x-foo');
 
   var extendsTagName = '';
-  Type type;
+  Type? type;
   if (options != null) {
     extendsTagName = options['extends'];
     type = options['prototype'];
@@ -162,7 +162,7 @@
   var _constructor;
   var _nativeType;
 
-  _JSElementUpgrader(Document document, Type type, String extendsTag) {
+  _JSElementUpgrader(Document document, Type type, String? extendsTag) {
     var interceptorClass = findInterceptorConstructorForType(type);
     if (interceptorClass == null) {
       throw new ArgumentError(type);
diff --git a/tools/dom/nnbd_src/dart2js_DOMImplementation.dart b/tools/dom/nnbd_src/dart2js_DOMImplementation.dart
index e45e37c..8016f6e 100644
--- a/tools/dom/nnbd_src/dart2js_DOMImplementation.dart
+++ b/tools/dom/nnbd_src/dart2js_DOMImplementation.dart
@@ -30,8 +30,7 @@
   // Methods.
   void close() => JS('void', '#.close()', _window);
 
-  void postMessage(var message, String targetOrigin,
-      [List messagePorts = null]) {
+  void postMessage(var message, String targetOrigin, [List? messagePorts]) {
     if (messagePorts == null) {
       JS('void', '#.postMessage(#,#)', _window,
           convertDartToNative_SerializedScriptValue(message), targetOrigin);
@@ -68,8 +67,8 @@
       throw new UnsupportedError(
           'You can only attach EventListeners to your own window.');
   // TODO(efortuna): Remove this method. dartbug.com/16814
-  void addEventListener(String type, EventListener listener,
-          [bool useCapture]) =>
+  void addEventListener(String type, EventListener? listener,
+          [bool? useCapture]) =>
       throw new UnsupportedError(
           'You can only attach EventListeners to your own window.');
   // TODO(efortuna): Remove this method. dartbug.com/16814
@@ -81,8 +80,8 @@
       throw new UnsupportedError(
           'You can only attach EventListeners to your own window.');
   // TODO(efortuna): Remove this method. dartbug.com/16814
-  void removeEventListener(String type, EventListener listener,
-          [bool useCapture]) =>
+  void removeEventListener(String type, EventListener? listener,
+          [bool? useCapture]) =>
       throw new UnsupportedError(
           'You can only attach EventListeners to your own window.');
 }
diff --git a/tools/dom/nnbd_src/dart2js_KeyEvent.dart b/tools/dom/nnbd_src/dart2js_KeyEvent.dart
index aca9fd2..2b2caf8 100644
--- a/tools/dom/nnbd_src/dart2js_KeyEvent.dart
+++ b/tools/dom/nnbd_src/dart2js_KeyEvent.dart
@@ -60,9 +60,10 @@
   bool get _realAltKey => JS('bool', '#.altKey', _parent);
 
   /** Shadows on top of the parent's currentTarget. */
-  EventTarget _currentTarget;
+  EventTarget? _currentTarget;
 
-  final InputDeviceCapabilities sourceCapabilities;
+  InputDeviceCapabilities? get sourceCapabilities =>
+      JS('InputDeviceCapabilities', '#.sourceCapabilities', this);
 
   /**
    * The value we want to use for this object's dispatch. Created here so it is
@@ -77,7 +78,12 @@
   }
 
   /** Construct a KeyEvent with [parent] as the event we're emulating. */
-  KeyEvent.wrap(KeyboardEvent parent) : super(parent) {
+  KeyEvent.wrap(KeyboardEvent parent)
+      : _parent = parent,
+        _shadowAltKey = false,
+        _shadowCharCode = 0,
+        _shadowKeyCode = 0,
+        super(parent) {
     _parent = parent;
     _shadowAltKey = _realAltKey;
     _shadowCharCode = _realCharCode;
@@ -87,7 +93,7 @@
 
   /** Programmatically create a new KeyEvent (and KeyboardEvent). */
   factory KeyEvent(String type,
-      {Window view,
+      {Window? view,
       bool canBubble: true,
       bool cancelable: true,
       int keyCode: 0,
@@ -97,7 +103,7 @@
       bool altKey: false,
       bool shiftKey: false,
       bool metaKey: false,
-      EventTarget currentTarget}) {
+      EventTarget? currentTarget}) {
     if (view == null) {
       view = window;
     }
@@ -155,7 +161,7 @@
           '&& document.body.dispatchEvent.length > 0');
 
   /** The currently registered target for this event. */
-  EventTarget get currentTarget => _currentTarget;
+  EventTarget? get currentTarget => _currentTarget;
 
   // This is an experimental method to be sure.
   static String _convertToHexString(int charCode, int keyCode) {
@@ -198,7 +204,7 @@
   bool get metaKey => _parent.metaKey;
   /** True if the shift key was pressed during this event. */
   bool get shiftKey => _parent.shiftKey;
-  Window get view => _parent.view;
+  WindowBase? get view => _parent.view;
   void _initUIEvent(
       String type, bool canBubble, bool cancelable, Window? view, int detail) {
     throw new UnsupportedError("Cannot initialize a UI Event from a KeyEvent.");
@@ -218,9 +224,9 @@
       String type,
       bool canBubble,
       bool cancelable,
-      Window view,
+      Window? view,
       String keyIdentifier,
-      int location,
+      int? location,
       bool ctrlKey,
       bool altKey,
       bool shiftKey,
diff --git a/tools/dom/nnbd_src/dart2js_WrappedEvent.dart b/tools/dom/nnbd_src/dart2js_WrappedEvent.dart
index 089b223..dff9e38 100644
--- a/tools/dom/nnbd_src/dart2js_WrappedEvent.dart
+++ b/tools/dom/nnbd_src/dart2js_WrappedEvent.dart
@@ -11,7 +11,7 @@
   final Event wrapped;
 
   /** The CSS selector involved with event delegation. */
-  String _selector;
+  String? _selector;
 
   _WrappedEvent(this.wrapped);
 
@@ -21,7 +21,7 @@
 
   bool get composed => wrapped.composed;
 
-  EventTarget get currentTarget => wrapped.currentTarget;
+  EventTarget? get currentTarget => wrapped.currentTarget;
 
   bool get defaultPrevented => wrapped.defaultPrevented;
 
@@ -29,9 +29,9 @@
 
   bool get isTrusted => wrapped.isTrusted;
 
-  EventTarget get target => wrapped.target;
+  EventTarget? get target => wrapped.target;
 
-  double get timeStamp => wrapped.timeStamp;
+  double get timeStamp => wrapped.timeStamp as double;
 
   String get type => wrapped.type;
 
@@ -63,13 +63,12 @@
       throw new UnsupportedError('Cannot call matchingTarget if this Event did'
           ' not arise as a result of event delegation.');
     }
-    Element currentTarget = this.currentTarget;
-    Element target = this.target;
-    var matchedTarget;
+    Element? currentTarget = this.currentTarget as Element?;
+    Element? target = this.target as Element?;
     do {
-      if (target.matches(_selector)) return target;
+      if (target!.matches(_selector!)) return target;
       target = target.parent;
-    } while (target != null && target != currentTarget.parent);
+    } while (target != null && target != currentTarget!.parent);
     throw new StateError('No selector matched for populating matchedTarget.');
   }
 
@@ -83,7 +82,7 @@
    *   from W3C.
    */
   // https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#extensions-to-event
-  List<Node> get path => wrapped.path;
+  List<Node> get path => wrapped.path as List<Node>;
 
   dynamic get _get_currentTarget => wrapped._get_currentTarget;
 
diff --git a/tools/dom/nnbd_src/native_DOMImplementation.dart b/tools/dom/nnbd_src/native_DOMImplementation.dart
index 6f197d0..79f5d04 100644
--- a/tools/dom/nnbd_src/native_DOMImplementation.dart
+++ b/tools/dom/nnbd_src/native_DOMImplementation.dart
@@ -137,7 +137,7 @@
     return matches.toList();
   }
 
-  static setLibrary([String name]) {
+  static setLibrary([String? name]) {
     // Bust cache in case library list has changed. Ideally we would listen for
     // when libraries are loaded and invalidate based on that.
     _validCache = false;
@@ -1107,7 +1107,7 @@
   // Methods.
   void close() => _blink.BlinkWindow.instance.close_Callback_0_(this);
   void postMessage(Object message, String targetOrigin,
-          [List<MessagePort> transfer]) =>
+          [List<MessagePort>? transfer]) =>
       _blink.BlinkWindow.instance.postMessage_Callback_3_(
           this,
           convertDartToNative_SerializedScriptValue(message),
@@ -1122,12 +1122,12 @@
       'You can only attach EventListeners to your own window.');
   // TODO(efortuna): Remove this method. dartbug.com/16814
   void _addEventListener(
-          [String type, EventListener listener, bool useCapture]) =>
+          [String? type, EventListener? listener, bool? useCapture]) =>
       throw new UnsupportedError(
           'You can only attach EventListeners to your own window.');
   // TODO(efortuna): Remove this method. dartbug.com/16814
-  void addEventListener(String type, EventListener listener,
-          [bool useCapture]) =>
+  void addEventListener(String type, EventListener? listener,
+          [bool? useCapture]) =>
       throw new UnsupportedError(
           'You can only attach EventListeners to your own window.');
   // TODO(efortuna): Remove this method. dartbug.com/16814
@@ -1135,12 +1135,12 @@
       'You can only attach EventListeners to your own window.');
   // TODO(efortuna): Remove this method. dartbug.com/16814
   void _removeEventListener(
-          [String type, EventListener listener, bool useCapture]) =>
+          [String? type, EventListener? listener, bool? useCapture]) =>
       throw new UnsupportedError(
           'You can only attach EventListeners to your own window.');
   // TODO(efortuna): Remove this method. dartbug.com/16814
-  void removeEventListener(String type, EventListener listener,
-          [bool useCapture]) =>
+  void removeEventListener(String type, EventListener? listener,
+          [bool? useCapture]) =>
       throw new UnsupportedError(
           'You can only attach EventListeners to your own window.');
 }
@@ -1151,7 +1151,7 @@
   // Methods.
   void back() => _blink.BlinkHistory.instance.back_Callback_0_(this);
   void forward() => _blink.BlinkHistory.instance.forward_Callback_0_(this);
-  void go([int delta]) {
+  void go([int? delta]) {
     if (delta != null) {
       _blink.BlinkHistory.instance.go_Callback_1_(this, delta);
       return;
diff --git a/tools/dom/nnbd_src/shared_SVGFactoryProviders.dart b/tools/dom/nnbd_src/shared_SVGFactoryProviders.dart
index a4aab93..2c729f7 100644
--- a/tools/dom/nnbd_src/shared_SVGFactoryProviders.dart
+++ b/tools/dom/nnbd_src/shared_SVGFactoryProviders.dart
@@ -8,6 +8,6 @@
   static SvgElement createSvgElement_tag(String tag) {
     final Element temp =
         document.createElementNS("http://www.w3.org/2000/svg", tag);
-    return temp;
+    return temp as SvgElement;
   }
 }
diff --git a/tools/dom/nnbd_src/shared_html.dart b/tools/dom/nnbd_src/shared_html.dart
index f2aa8a9..b9a8d7f 100644
--- a/tools/dom/nnbd_src/shared_html.dart
+++ b/tools/dom/nnbd_src/shared_html.dart
@@ -7,14 +7,12 @@
 void Function(T) _wrapZone<T>(void Function(T) callback) {
   // For performance reasons avoid wrapping if we are in the root zone.
   if (Zone.current == Zone.root) return callback;
-  if (callback == null) return null;
   return Zone.current.bindUnaryCallbackGuarded(callback);
 }
 
 void Function(T1, T2) _wrapBinaryZone<T1, T2>(void Function(T1, T2) callback) {
   // For performance reasons avoid wrapping if we are in the root zone.
   if (Zone.current == Zone.root) return callback;
-  if (callback == null) return null;
   return Zone.current.bindBinaryCallbackGuarded(callback);
 }
 
@@ -35,7 +33,7 @@
  * For details about CSS selector syntax, see the
  * [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
  */
-Element querySelector(String selectors) => document.querySelector(selectors);
+Element? querySelector(String selectors) => document.querySelector(selectors);
 
 /**
  * Finds all descendant elements of this document that match the specified