Version 2.17.0-85.0.dev

Merge commit '2e731c540a4921ae08a98fe0d5847d80b3e3c0e8' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index db965d7..95cb252 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -61,7 +61,8 @@
 
 #### `dart:io`
 
-- **Breaking Change** [#45410](https://github.com/dart-lang/sdk/issues/45410):
+- **Breaking Change** [#45410](https://github.com/dart-lang/sdk/issues/45410),
+  **security advisory** [CVE-2022-0451](https://github.com/dart-lang/sdk/security/advisories/GHSA-c8mh-jj22-xg5h):
   `HttpClient` no longer transmits some headers (i.e. `authorization`,
   `www-authenticate`, `cookie`, `cookie2`) when processing redirects to a
   different domain.
diff --git a/benchmarks/Iterators/dart/Iterators.dart b/benchmarks/Iterators/dart/Iterators.dart
new file mode 100644
index 0000000..b58e880
--- /dev/null
+++ b/benchmarks/Iterators/dart/Iterators.dart
@@ -0,0 +1,595 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// # Benchmark for iterators of common collections.
+///
+/// The purpose of this benchmark is to detect performance changes in the
+/// iterators for common collections (system Lists, Maps, etc).
+///
+/// ## Polymorphic benchmarks
+///
+/// Benchmark names beginning with `Iterators.poly.`.
+///
+/// These benchmark use the iterators from a common polymorphic for-in loop, so
+/// none of the methods involved in iterating are inlined. This gives an
+/// indication of worst-case performance.
+///
+/// Iterables of different sizes (small (N=1) and large (N=100)) are used to
+/// give insight into the fixed vs per-element costs.
+///
+/// Results are normalized by iterating 1000 elements and reporting the time per
+/// element. There is an outer loop that calls the iterator loop in `sinkAll`.
+///
+/// The dispatched (polymorphic) calls are to `get:iterator`, `moveNext` and
+/// `get:current`.
+///
+///  |    N | outer | `get:iterator` | `moveNext` | `get:current` |
+///  | ---: | ----: | -------------: | ---------: | ------------: |
+///  |   0* |  1000 |           1000 |       1000 |             0 |
+///  |   1  |  1000 |           1000 |       2000 |          1000 |
+///  |   2* |   500 |            500 |       1500 |          1000 |
+///  | 100  |    10 |             10 |       1010 |          1000 |
+///
+/// * By default only the N=1 and N=100 benchmarks arer run. The N=0 and N=2
+/// series are available running manually with `--0` and `--2` command-line
+/// arguments.
+///
+/// Generic Iterables have benchmarks for different element types. There are
+/// benchmarks for `int` type arguments, which have a fast type test, and for
+/// `Thing<Iterable<Comparable>>`, which is harder to test quickly. These tests
+/// are distingished by `int` and `Hard` in the name.
+///
+/// ## Monomorphic benchmarks
+///
+/// Benchmark names beginning with `Iterators.mono.`.
+///
+/// A subset of the polymorphic benchmarks are also implemented with a
+/// per-benchmark for-in loop directly iterating a collection of known
+/// representation. This gives the compiler the opportunity to inline the
+/// methods into the loop and represents the best-case performance.
+///
+/// ## Example benchmarks
+///
+/// The name has 4-7 words separated by periods. The first word is always
+/// 'Iterators', and the second is either 'mono' for monomorphic loops, or
+/// 'poly' for benchmarks using a shared polymorphic loop. The last word is a
+/// number which is the size (length) of the Iterable.
+///
+/// ### Iterators.mono.const.Map.int.values.100
+///
+/// A for-in loop over the values iterable of a known constant Map with value
+/// type `int` and 100 entries.
+///
+/// ### Iterators.poly.Runes.1
+///
+/// An interation over the String.runes iterable of a single character String
+/// using the shared polymorphic loop.
+///
+/// ### Iterators.poly.HashMap.Hard.keys.100
+///
+/// An iteration of over the keys iterable of a HashMap with key type
+/// `Thing<Iterable<Comparable>>` and 100 entries.
+///
+/// ### Iterators.*.UpTo.*
+///
+/// The UpTo iterable is a minimal iterable that provides successive
+/// numbers. The `moveNext` and `get:current` methods are small. Comparing
+/// Iterators.poly.UpTo.*.100 to Iterators.poly.*.100 gives an indication of how
+/// much work is done by `moveNext` (and sometimes `get:current`).
+///
+/// ### Iterators.mono.Nothing.*
+///
+/// The Nothing benchmark has no iteration over an iterable and is used to get a
+/// baseline time for running the benchmark loop for monomorphic
+/// benchmarks. This can be a substantial fraction of
+///
+/// Consider the times
+///
+///     Iterators.mono.CodeUnits.1   = 7.0ns
+///     Iterators.mono.Nothing.1     = 3.1ns
+///
+/// Because the trip count (i.e. 1) of the for-in loop is so small, there is a
+/// lot of overhead attributable to the outer loop in `MonoBenchmark.run`. The
+/// 1000/1 = 1000 trips of outer loops takes 3.1us (3.1ns * 1000 trips), so
+/// CodeUnits is spending only 7.0-3.1 = 3.9ns per character in the for-in
+/// loop over the `.codeUnits` of the single-character String.
+///
+///     Iterators.mono.CodeUnits.100 = 1.83ns
+///     Iterators.mono.Nothing.100   = 0.05ns
+///
+/// Now the outer loop runs only 1000/100 = 10 times, for 0.05us. If we subtract
+/// this from 1.83, we get 1.78ns per character for long strings.
+///
+library iterators_benchmark;
+
+// TODO(48277): Update when fixed:
+// ignore_for_file: unnecessary_lambdas
+
+import 'dart:collection';
+
+import 'package:benchmark_harness/benchmark_harness.dart';
+
+import 'data.dart';
+
+const targetSize = 1000;
+
+class Emitter implements ScoreEmitter {
+  @override
+  void emit(String testName, double value) {
+    // [value] is microseconds per ten calls to `run()`.
+    final nanoSeconds = value * 1000;
+    final singleElementTimeNs = nanoSeconds / 10 / targetSize;
+    print('$testName(RunTimeRaw): $singleElementTimeNs ns.');
+  }
+}
+
+abstract class Benchmark extends BenchmarkBase {
+  final int size;
+  bool selected = false;
+  Benchmark._(String name, this.size)
+      : super('Iterators.$name.$size', emitter: Emitter());
+
+  factory Benchmark(String name, int size, Iterable Function(int) generate) =
+      PolyBenchmark;
+}
+
+abstract class MonoBenchmark extends Benchmark {
+  final int _repeats;
+  MonoBenchmark(String name, int size)
+      : _repeats = size == 0 ? targetSize : targetSize ~/ size,
+        super._('mono.$name', size);
+
+  @override
+  void run() {
+    for (int i = 0; i < _repeats; i++) {
+      sinkMono();
+    }
+  }
+
+  void sinkMono();
+}
+
+class PolyBenchmark extends Benchmark {
+  final Iterable Function(int) generate;
+  final List<Iterable> inputs = [];
+
+  PolyBenchmark(String name, int size, this.generate)
+      : super._('poly.$name', size);
+
+  @override
+  void setup() {
+    if (inputs.isNotEmpty) return; // Ensure setup() is idempotent.
+
+    int totalSize = 0;
+    while (totalSize < targetSize) {
+      final sample = generate(size);
+      inputs.add(sample);
+      totalSize += size == 0 ? 1 : size;
+    }
+  }
+
+  @override
+  void run() {
+    for (int i = 0; i < inputs.length; i++) {
+      sinkAll(inputs[i]);
+    }
+  }
+}
+
+/// This function is the inner loop of the benchmark.
+@pragma('dart2js:noInline')
+@pragma('vm:never-inline')
+void sinkAll(Iterable iterable) {
+  for (final value in iterable) {
+    sink = value;
+  }
+}
+
+Object? sink;
+
+class BenchmarkConstMapIntKeys1 extends MonoBenchmark {
+  BenchmarkConstMapIntKeys1() : super('const.Map.int.keys', 1);
+
+  static const _map = constMapIntInt1;
+
+  @override
+  void sinkMono() {
+    for (final value in _map.keys) {
+      sink = value;
+    }
+  }
+}
+
+class BenchmarkConstMapIntKeys2 extends MonoBenchmark {
+  BenchmarkConstMapIntKeys2() : super('const.Map.int.keys', 2);
+
+  static const _map = constMapIntInt2;
+
+  @override
+  void sinkMono() {
+    for (final value in _map.keys) {
+      sink = value;
+    }
+  }
+}
+
+class BenchmarkConstMapIntKeys100 extends MonoBenchmark {
+  BenchmarkConstMapIntKeys100() : super('const.Map.int.keys', 100);
+
+  static const _map = constMapIntInt100;
+
+  @override
+  void sinkMono() {
+    for (final value in _map.keys) {
+      sink = value;
+    }
+  }
+}
+
+class BenchmarkConstMapIntValues1 extends MonoBenchmark {
+  BenchmarkConstMapIntValues1() : super('const.Map.int.values', 1);
+
+  static const _map = constMapIntInt1;
+
+  @override
+  void sinkMono() {
+    for (final value in _map.values) {
+      sink = value;
+    }
+  }
+}
+
+class BenchmarkConstMapIntValues2 extends MonoBenchmark {
+  BenchmarkConstMapIntValues2() : super('const.Map.int.values', 2);
+
+  static const _map = constMapIntInt2;
+
+  @override
+  void sinkMono() {
+    for (final value in _map.values) {
+      sink = value;
+    }
+  }
+}
+
+class BenchmarkConstMapIntValues100 extends MonoBenchmark {
+  BenchmarkConstMapIntValues100() : super('const.Map.int.values', 100);
+
+  static const _map = constMapIntInt100;
+
+  @override
+  void sinkMono() {
+    for (final value in _map.values) {
+      sink = value;
+    }
+  }
+}
+
+class BenchmarkMapIntKeys extends MonoBenchmark {
+  BenchmarkMapIntKeys(int size) : super('Map.int.keys', size) {
+    _map.addAll(generateMapIntInt(size));
+  }
+
+  final Map<int, int> _map = {};
+
+  @override
+  void sinkMono() {
+    for (final value in _map.keys) {
+      sink = value;
+    }
+  }
+}
+
+class BenchmarkUpTo extends MonoBenchmark {
+  BenchmarkUpTo(int size) : super('UpTo', size);
+
+  @override
+  void sinkMono() {
+    for (final value in UpTo(size)) {
+      sink = value;
+    }
+  }
+}
+
+class BenchmarkNothing extends MonoBenchmark {
+  BenchmarkNothing(int size) : super('Nothing', size);
+
+  @override
+  void sinkMono() {
+    sink = size;
+  }
+}
+
+class BenchmarkCodeUnits extends MonoBenchmark {
+  BenchmarkCodeUnits(int size)
+      : string = generateString(size),
+        super('CodeUnits', size);
+
+  final String string;
+
+  @override
+  void sinkMono() {
+    for (final value in string.codeUnits) {
+      sink = value;
+    }
+  }
+}
+
+class BenchmarkListIntGrowable extends MonoBenchmark {
+  BenchmarkListIntGrowable(int size)
+      : _list = List.generate(size, (i) => i),
+        super('List.int.growable', size);
+
+  final List<int> _list;
+
+  @override
+  void sinkMono() {
+    for (final value in _list) {
+      sink = value;
+    }
+  }
+}
+
+/// A simple Iterable that yields the integers 0 through `length`.
+///
+/// This Iterable serves as the minimal interesting example to serve as a
+/// baseline, and is useful in constructing other benchmark inputs.
+class UpTo extends IterableBase<int> {
+  final int _length;
+  UpTo(this._length);
+
+  @override
+  Iterator<int> get iterator => UpToIterator(_length);
+}
+
+class UpToIterator implements Iterator<int> {
+  final int _length;
+  int _position = 0;
+  int? _current;
+
+  UpToIterator(this._length);
+
+  @override
+  int get current => _current!;
+
+  @override
+  bool moveNext() {
+    if (_position < _length) {
+      _current = _position++;
+      return true;
+    }
+    _current = null;
+    return false;
+  }
+}
+
+/// A `Thing` has a type parameter which makes type tests in the Iterators
+/// potentially harder, and equality uses the type parameter, making Iterables
+/// that do lookups slower.
+class Thing<T> {
+  static int _nextIndex = 0;
+  final int _index;
+  Thing() : _index = _nextIndex++;
+
+  @override
+  int get hashCode => _index;
+
+  @override
+  bool operator ==(Object other) => other is Thing<T> && other._index == _index;
+}
+
+final thingGenerators = [
+  // TODO(48277): Use instantiated constructor tear-offs when fixed:
+  () => Thing<Set<String>>(),
+  () => Thing<Set<Duration>>(),
+  () => Thing<Set<BigInt>>(),
+  () => Thing<Queue<String>>(),
+  () => Thing<Queue<Duration>>(),
+  () => Thing<Queue<BigInt>>(),
+  () => Thing<List<String>>(),
+  () => Thing<List<Duration>>(),
+  () => Thing<List<BigInt>>(),
+];
+
+int _generateThingListState = 0;
+List<Thing<Iterable<Comparable>>> generateThingList(int n) {
+  Thing nextThing(_) {
+    final next = (_generateThingListState++).remainder(thingGenerators.length);
+    return thingGenerators[next]();
+  }
+
+  return List.from(UpTo(n).map(nextThing));
+}
+
+Map<Thing<Iterable<Comparable>>, Thing<Iterable<Comparable>>> generateThingMap(
+    int n) {
+  return Map.fromIterables(generateThingList(n), generateThingList(n));
+}
+
+Map<Thing<Iterable<Comparable>>, Thing<Iterable<Comparable>>>
+    generateThingHashMap(int n) {
+  return HashMap.fromIterables(generateThingList(n), generateThingList(n));
+}
+
+int _generateStringState = 0;
+String generateString(int n) {
+  return ((_generateStringState++).isEven ? 'x' : '\u2192') * n;
+}
+
+Map<int, int> generateMapIntInt(int n) =>
+    Map<int, int>.fromIterables(UpTo(n), UpTo(n));
+
+Map<int, int> generateIdentityMapIntInt(int n) {
+  return Map<int, int>.identity()..addAll(generateMapIntInt(n));
+}
+
+/// Run the benchmark loop on various inputs to pollute type inference and JIT
+/// caches.
+void pollute() {
+  // This iterable reads `sink` mid-loop, making it infeasible for the compiler
+  // to move the write to `sink` out of the loop.
+  sinkAll(UpTo(100).map((i) {
+    if (i > 0 && sink != i - 1) throw StateError('sink');
+    return i;
+  }));
+
+  // TODO(sra): Do we need to add anything here? There are a lot of benchmarks,
+  // so that is probably sufficient to make the necessary places polymorphic.
+}
+
+/// Command-line arguments:
+///
+/// `--0`: Run benchmarks for empty iterables.
+/// `--1`: Run benchmarks for singleton iterables.
+/// `--2`: Run benchmarks for two-element iterables.
+/// `--100`: Run benchmarks for 100-element iterables.
+///
+///    Default sizes are 1 and 100.
+///
+/// `--all`: Run all benchmark variants and sizes.
+///
+/// `foo`, `foo.bar`: a Selector.
+///
+///    Run benchmarks with name containing all the dot-separated words in the
+///    selector, so `--Set.const` will run benchmark
+///    'Iterators.const.Set.int.N`, and `--2.UpTo` will select
+///    `Iterators.UpTo.2`.  Each selector is matched independently, and if
+///    selectors are used, only benchmarks matching some selector are run.
+///
+void main(List<String> commandLineArguments) {
+  final arguments = [...commandLineArguments];
+
+  const allSizes = {0, 1, 2, 100};
+  const defaultSizes = {1, 100};
+  final allSizeWords = Set.unmodifiable(allSizes.map((size) => '$size'));
+
+  final Set<int> sizes = {};
+  final Set<String> selectors = {};
+
+  if (arguments.remove('--0')) sizes.add(0);
+  if (arguments.remove('--1')) sizes.add(1);
+  if (arguments.remove('--2')) sizes.add(2);
+  if (arguments.remove('--100')) sizes.add(100);
+
+  if (arguments.remove('--all')) {
+    sizes.addAll(allSizes);
+  }
+
+  selectors.addAll(arguments);
+
+  if (sizes.isEmpty) sizes.addAll(defaultSizes);
+  if (selectors.isEmpty) selectors.add('Iterators');
+
+  List<Benchmark> makeBenchmarksForSize(int size) {
+    return [
+      // Simple
+      BenchmarkNothing(size),
+      BenchmarkUpTo(size),
+      BenchmarkCodeUnits(size),
+      Benchmark('UpTo', size, (n) => UpTo(n)),
+      Benchmark('CodeUnits', size, (n) => generateString(n).codeUnits),
+      Benchmark('Runes', size, (n) => generateString(n).runes),
+      // ---
+      BenchmarkListIntGrowable(size),
+      Benchmark('List.int.growable', size,
+          (n) => List<int>.of(UpTo(n), growable: true)),
+      Benchmark('List.int.fixed', size,
+          (n) => List<int>.of(UpTo(n), growable: false)),
+      Benchmark('List.int.unmodifiable', size,
+          (n) => List<int>.unmodifiable(UpTo(n))),
+      // ---
+      Benchmark('List.Hard.growable', size, generateThingList),
+      // ---
+      Benchmark('Set.int', size, (n) => Set<int>.of(UpTo(n))),
+      Benchmark('const.Set.int', size, generateConstSetOfInt),
+      // ---
+      BenchmarkMapIntKeys(size),
+      Benchmark('Map.int.keys', size, (n) => generateMapIntInt(n).keys),
+      Benchmark('Map.int.values', size, (n) => generateMapIntInt(n).values),
+      Benchmark('Map.int.entries', size, (n) => generateMapIntInt(n).entries),
+      // ---
+      Benchmark('Map.identity.int.keys', size,
+          (n) => generateIdentityMapIntInt(n).keys),
+      Benchmark('Map.identity.int.values', size,
+          (n) => generateIdentityMapIntInt(n).values),
+      Benchmark('Map.identity.int.entries', size,
+          (n) => generateIdentityMapIntInt(n).entries),
+      // ---
+      Benchmark(
+          'const.Map.int.keys', size, (n) => generateConstMapIntInt(n).keys),
+      Benchmark('const.Map.int.values', size,
+          (n) => generateConstMapIntInt(n).values),
+      Benchmark('const.Map.int.entries', size,
+          (n) => generateConstMapIntInt(n).entries),
+      // ---
+      Benchmark('Map.Hard.keys', size, (n) => generateThingMap(n).keys),
+      Benchmark('Map.Hard.values', size, (n) => generateThingMap(n).values),
+      // ---
+      Benchmark('HashMap.int.keys', size,
+          (n) => HashMap<int, int>.fromIterables(UpTo(n), UpTo(n)).keys),
+      Benchmark('HashMap.int.values', size,
+          (n) => HashMap<int, int>.fromIterables(UpTo(n), UpTo(n)).values),
+      Benchmark('HashMap.int.entries', size,
+          (n) => HashMap<int, int>.fromIterables(UpTo(n), UpTo(n)).entries),
+      // ---
+      Benchmark('HashMap.Hard.keys', size, (n) => generateThingHashMap(n).keys),
+      Benchmark(
+          'HashMap.Hard.values', size, (n) => generateThingHashMap(n).values),
+    ];
+  }
+
+  final benchmarks = [
+    BenchmarkConstMapIntKeys1(),
+    BenchmarkConstMapIntKeys2(),
+    BenchmarkConstMapIntKeys100(),
+    BenchmarkConstMapIntValues1(),
+    BenchmarkConstMapIntValues2(),
+    BenchmarkConstMapIntValues100(),
+    for (final size in allSizes) ...makeBenchmarksForSize(size),
+  ];
+
+  // Select benchmarks
+  final unusedSelectors = {...selectors};
+  for (final benchmark in benchmarks) {
+    final nameWords = benchmark.name.split('.').toSet();
+    for (final selector in selectors) {
+      final selectorWords = selector.split('.').toSet();
+      if (nameWords.containsAll(selectorWords)) {
+        unusedSelectors.remove(selector);
+        if (selectorWords.any(allSizeWords.contains) ||
+            sizes.contains(benchmark.size)) {
+          benchmark.selected = true;
+        }
+        // continue matching to remove other matching selectors.
+      }
+    }
+  }
+  if (unusedSelectors.isNotEmpty) {
+    throw ArgumentError(unusedSelectors, 'selectors match no benchmark');
+  }
+
+  // Warmup all benchmarks to ensure JIT compilers see full polymorphism.
+  for (var benchmark in benchmarks) {
+    pollute();
+    benchmark.setup();
+  }
+
+  // Warm up all the benchmarks, including the non-selected ones.
+  for (int i = 0; i < 10; i++) {
+    for (var benchmark in benchmarks) {
+      pollute();
+      final marker = Object();
+      sink = marker;
+      benchmark.warmup();
+      if (benchmark.size > 0 && identical(sink, marker)) throw 'unexpected';
+    }
+  }
+
+  for (var benchmark in benchmarks) {
+    // `report` calls `setup`, but `setup` is idempotent.
+    if (benchmark.selected) {
+      benchmark.report();
+    }
+  }
+}
diff --git a/benchmarks/Iterators/dart/data.dart b/benchmarks/Iterators/dart/data.dart
new file mode 100644
index 0000000..eabe7f4
--- /dev/null
+++ b/benchmarks/Iterators/dart/data.dart
@@ -0,0 +1,239 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+Map<int, int> generateConstMapIntInt(int n) {
+  return constMapIntIntTable[n] ??
+      (throw ArgumentError.value(n, 'n', 'size not supported'));
+}
+
+Set<int> generateConstSetOfInt(int n) {
+  return constSetOfIntTable[n] ??
+      (throw ArgumentError.value(n, 'n', 'size not supported'));
+}
+
+const Map<int, Map<int, int>> constMapIntIntTable = {
+  0: constMapIntInt0,
+  1: constMapIntInt1,
+  2: constMapIntInt2,
+  100: constMapIntInt100
+};
+
+const Map<int, int> constMapIntInt0 = {};
+const Map<int, int> constMapIntInt1 = {0: 0};
+const Map<int, int> constMapIntInt2 = {0: 0, 1: 1};
+const Map<int, int> constMapIntInt100 = {
+  0: 0,
+  1: 1,
+  2: 2,
+  3: 3,
+  4: 4,
+  5: 5,
+  6: 6,
+  7: 7,
+  8: 8,
+  9: 9,
+  10: 10,
+  11: 11,
+  12: 12,
+  13: 13,
+  14: 14,
+  15: 15,
+  16: 16,
+  17: 17,
+  18: 18,
+  19: 19,
+  20: 20,
+  21: 21,
+  22: 22,
+  23: 23,
+  24: 24,
+  25: 25,
+  26: 26,
+  27: 27,
+  28: 28,
+  29: 29,
+  30: 30,
+  31: 31,
+  32: 32,
+  33: 33,
+  34: 34,
+  35: 35,
+  36: 36,
+  37: 37,
+  38: 38,
+  39: 39,
+  40: 40,
+  41: 41,
+  42: 42,
+  43: 43,
+  44: 44,
+  45: 45,
+  46: 46,
+  47: 47,
+  48: 48,
+  49: 49,
+  50: 50,
+  51: 51,
+  52: 52,
+  53: 53,
+  54: 54,
+  55: 55,
+  56: 56,
+  57: 57,
+  58: 58,
+  59: 59,
+  60: 60,
+  61: 61,
+  62: 62,
+  63: 63,
+  64: 64,
+  65: 65,
+  66: 66,
+  67: 67,
+  68: 68,
+  69: 69,
+  70: 70,
+  71: 71,
+  72: 72,
+  73: 73,
+  74: 74,
+  75: 75,
+  76: 76,
+  77: 77,
+  78: 78,
+  79: 79,
+  80: 80,
+  81: 81,
+  82: 82,
+  83: 83,
+  84: 84,
+  85: 85,
+  86: 86,
+  87: 87,
+  88: 88,
+  89: 89,
+  90: 90,
+  91: 91,
+  92: 92,
+  93: 93,
+  94: 94,
+  95: 95,
+  96: 96,
+  97: 97,
+  98: 98,
+  99: 99
+};
+
+const Map<int, Set<int>> constSetOfIntTable = {
+  0: constSetOfInt0,
+  1: constSetOfInt1,
+  2: constSetOfInt2,
+  100: constSetOfInt100
+};
+
+const Set<int> constSetOfInt0 = {};
+const Set<int> constSetOfInt1 = {0};
+const Set<int> constSetOfInt2 = {0, 1};
+const Set<int> constSetOfInt100 = {
+  0,
+  1,
+  2,
+  3,
+  4,
+  5,
+  6,
+  7,
+  8,
+  9,
+  10,
+  11,
+  12,
+  13,
+  14,
+  15,
+  16,
+  17,
+  18,
+  19,
+  20,
+  21,
+  22,
+  23,
+  24,
+  25,
+  26,
+  27,
+  28,
+  29,
+  30,
+  31,
+  32,
+  33,
+  34,
+  35,
+  36,
+  37,
+  38,
+  39,
+  40,
+  41,
+  42,
+  43,
+  44,
+  45,
+  46,
+  47,
+  48,
+  49,
+  50,
+  51,
+  52,
+  53,
+  54,
+  55,
+  56,
+  57,
+  58,
+  59,
+  60,
+  61,
+  62,
+  63,
+  64,
+  65,
+  66,
+  67,
+  68,
+  69,
+  70,
+  71,
+  72,
+  73,
+  74,
+  75,
+  76,
+  77,
+  78,
+  79,
+  80,
+  81,
+  82,
+  83,
+  84,
+  85,
+  86,
+  87,
+  88,
+  89,
+  90,
+  91,
+  92,
+  93,
+  94,
+  95,
+  96,
+  97,
+  98,
+  99
+};
diff --git a/benchmarks/Iterators/dart2/Iterators.dart b/benchmarks/Iterators/dart2/Iterators.dart
new file mode 100644
index 0000000..cc03515
--- /dev/null
+++ b/benchmarks/Iterators/dart2/Iterators.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// @dart=2.9
+
+import '../dart/Iterators.dart' as benchmark;
+
+void main(List<String> arguments) {
+  benchmark.main(arguments);
+}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
index 8cdcb87..3922723 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:_fe_analyzer_shared/src/scanner/token.dart';
 import 'package:analysis_server/src/provisional/completion/completion_core.dart';
 import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
 import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
@@ -42,7 +43,7 @@
 
   void _addDefaultParamSuggestions(Iterable<ParameterElement> parameters,
       {bool appendComma = false, int? replacementLength}) {
-    var appendColon = !_isInNamedExpression();
+    var appendColon = !_isEditingNamedArgLabel();
     var namedArgs = _namedArgs();
     for (var parameter in parameters) {
       if (parameter.isNamed) {
@@ -197,6 +198,11 @@
   bool _isEditingNamedArgLabel() {
     if (argumentList != null) {
       var entity = request.target.entity;
+      if (entity is SimpleIdentifier &&
+          entity.isSynthetic &&
+          entity.token.next?.type == TokenType.COLON) {
+        return true;
+      }
       if (entity is NamedExpression) {
         var offset = request.offset;
         if (entity.offset < offset && offset < entity.end) {
@@ -215,16 +221,6 @@
     return newExpr != null && flutter.isWidgetCreation(newExpr);
   }
 
-  /// Return `true` if the [request] is inside of a [NamedExpression] name.
-  bool _isInNamedExpression() {
-    var entity = request.target.entity;
-    if (entity is NamedExpression) {
-      var name = entity.name;
-      return name.offset < request.offset && request.offset < name.end;
-    }
-    return false;
-  }
-
   /// Return `true` if the completion target is in the middle or beginning of
   /// the list of named arguments and is not preceded by a comma. This method
   /// assumes that [_isAppendingToArgList] has been called and returned `false`.
diff --git a/pkg/analysis_server/lib/src/services/correction/assist.dart b/pkg/analysis_server/lib/src/services/correction/assist.dart
index c7233ba..3f8be5c 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist.dart
@@ -196,6 +196,11 @@
     30,
     'Convert to a spread',
   );
+  static const CONVERT_TO_SUPER_INITIALIZING_PARAMETER = AssistKind(
+    'dart.assist.convert.toSuperInitializingParameter',
+    30,
+    'Convert to a super initializing parameter',
+  );
   static const ENCAPSULATE_FIELD = AssistKind(
     'dart.assist.encapsulateField',
     30,
diff --git a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
index 2e8d400..3cbb3f8 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -38,6 +38,7 @@
 import 'package:analysis_server/src/services/correction/dart/convert_to_package_import.dart';
 import 'package:analysis_server/src/services/correction/dart/convert_to_relative_import.dart';
 import 'package:analysis_server/src/services/correction/dart/convert_to_set_literal.dart';
+import 'package:analysis_server/src/services/correction/dart/convert_to_super_initializing_parameter.dart';
 import 'package:analysis_server/src/services/correction/dart/encapsulate_field.dart';
 import 'package:analysis_server/src/services/correction/dart/exchange_operands.dart';
 import 'package:analysis_server/src/services/correction/dart/flutter_convert_to_children.dart';
@@ -104,19 +105,20 @@
     ConvertMapFromIterableToForLiteral.newInstance,
     ConvertPartOfToUri.newInstance,
     ConvertToDoubleQuotes.newInstance,
-    ConvertToFieldParameter.newInstance,
-    ConvertToMultilineString.newInstance,
-    ConvertToNormalParameter.newInstance,
-    ConvertToSingleQuotes.newInstance,
     ConvertToExpressionFunctionBody.newInstance,
+    ConvertToFieldParameter.newInstance,
     ConvertToGenericFunctionSyntax.newInstance,
     ConvertToIntLiteral.newInstance,
     ConvertToListLiteral.newInstance,
     ConvertToMapLiteral.newInstance,
+    ConvertToMultilineString.newInstance,
+    ConvertToNormalParameter.newInstance,
     ConvertToNullAware.newInstance,
     ConvertToPackageImport.newInstance,
     ConvertToRelativeImport.newInstance,
     ConvertToSetLiteral.newInstance,
+    ConvertToSingleQuotes.newInstance,
+    ConvertToSuperInitializingParameter.newInstance,
     EncapsulateField.newInstance,
     ExchangeOperands.newInstance,
     FlutterConvertToChildren.newInstance,
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_super_initializing_parameter.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_super_initializing_parameter.dart
new file mode 100644
index 0000000..b26d127
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_super_initializing_parameter.dart
@@ -0,0 +1,360 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
+import 'package:analyzer/dart/analysis/features.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/source/source_range.dart';
+import 'package:analyzer_plugin/utilities/assist/assist.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
+import 'package:analyzer_plugin/utilities/range_factory.dart';
+
+class ConvertToSuperInitializingParameter extends CorrectionProducer {
+  @override
+  AssistKind get assistKind =>
+      DartAssistKind.CONVERT_TO_SUPER_INITIALIZING_PARAMETER;
+
+  /// If the selected node is the name of either a simple formal parameter or a
+  /// function-typed formal parameter, either with or without a default value,
+  /// then return the formal parameter. Otherwise return `null`.
+  FormalParameter? get _formalParameter {
+    final node = this.node;
+    if (node is SimpleIdentifier) {
+      var parent = node.parent;
+      if (parent is NormalFormalParameter &&
+          (parent is SimpleFormalParameter ||
+              parent is FunctionTypedFormalParameter) &&
+          parent.identifier == node) {
+        var grandparent = parent.parent;
+        if (grandparent is DefaultFormalParameter) {
+          return grandparent;
+        }
+        return parent;
+      }
+    }
+    return null;
+  }
+
+  @override
+  Future<void> compute(ChangeBuilder builder) async {
+    if (!libraryElement.featureSet.isEnabled(Feature.super_parameters)) {
+      // If the library doesn't support super_parameters then the change isn't
+      // appropriate.
+      return;
+    }
+    var parameter = _formalParameter;
+    if (parameter == null) {
+      // If the user hasn't selected a formal parameter to convert then there
+      // is nothing to change.
+      return;
+    }
+    var parameterList = parameter.parent;
+    if (parameterList is! FormalParameterList) {
+      // This is here to safely cast the parent. This branch should never be
+      // reached.
+      return;
+    }
+    var constructor = parameterList.parent;
+    if (constructor is! ConstructorDeclaration) {
+      // If this isn't a parameter in a constructor declaration then the change
+      // isn't appropriate.
+      return;
+    }
+    var superInvocation = _superInvocation(constructor);
+    if (superInvocation == null) {
+      // If there isn't an explicit invocation of the super constructor then the
+      // change isn't appropriate.
+      return;
+    }
+    var superConstructor = superInvocation.staticElement;
+    if (superConstructor == null) {
+      // If the super constructor wasn't resolved then we can't apply the
+      // change.
+      return;
+    }
+    var thisParameter = parameter.declaredElement;
+    if (thisParameter == null) {
+      return;
+    }
+
+    _ParameterData? data;
+    if (parameter.isPositional) {
+      data = _dataForPositionalParameter(
+          parameter, thisParameter, superConstructor, superInvocation);
+    } else if (parameter.isNamed) {
+      data = _dataForNamedParameter(
+          parameter, thisParameter, superConstructor, superInvocation);
+    }
+    if (data == null) {
+      return;
+    }
+
+    final parameterData = data;
+    await builder.addDartFileEdit(file, (builder) {
+      var typeToDelete = parameterData.typeToDelete;
+      if (typeToDelete == null) {
+        builder.addSimpleInsertion(parameter.identifier!.offset, 'super.');
+      } else {
+        var primaryRange = typeToDelete.primaryRange;
+        if (primaryRange == null) {
+          builder.addSimpleInsertion(parameter.identifier!.offset, 'super.');
+        } else {
+          builder.addSimpleReplacement(primaryRange, 'super.');
+        }
+        var parameterRange = typeToDelete.parameterRange;
+        if (parameterRange != null) {
+          builder.addDeletion(parameterRange);
+        }
+      }
+      parameterData.argumentUpdate.addDeletion(builder);
+      var defaultValueRange = parameterData.defaultValueRange;
+      if (defaultValueRange != null) {
+        builder.addDeletion(defaultValueRange);
+      }
+    });
+  }
+
+  ParameterElement? _correspondingNamedParameter(
+      ConstructorElement superConstructor, ParameterElement thisParameter) {
+    for (var superParameter in superConstructor.parameters) {
+      if (superParameter.isNamed && superParameter.name == thisParameter.name) {
+        return superParameter;
+      }
+    }
+    return null;
+  }
+
+  /// Return `true` if the named [parameter] can be converted into a super
+  /// initializing formal parameter.
+  _ParameterData? _dataForNamedParameter(
+      FormalParameter parameter,
+      ParameterElement thisParameter,
+      ConstructorElement superConstructor,
+      SuperConstructorInvocation superInvocation) {
+    var superParameter =
+        _correspondingNamedParameter(superConstructor, thisParameter);
+    if (superParameter == null) {
+      return null;
+    }
+    // Validate that the parameter is used in the super constructor invocation.
+    _ArgumentUpdate? argumentUpdate;
+    var arguments = superInvocation.argumentList.arguments;
+    for (var argument in arguments) {
+      if (argument is NamedExpression &&
+          argument.name.label.name == thisParameter.name) {
+        var expression = argument.expression;
+        if (expression is SimpleIdentifier &&
+            expression.staticElement == thisParameter) {
+          argumentUpdate = _RemoveArgument(argument);
+          break;
+        }
+      }
+    }
+    if (argumentUpdate == null) {
+      // If the selected parameter isn't being passed to the super constructor,
+      // then the change isn't appropriate.
+      return null;
+    } else if (arguments.length == 1) {
+      // If the selected parameter is the only parameter being passed to the
+      // super constructor then we no longer need to invoke the super
+      // constructor.
+      argumentUpdate = _RemoveInvocation(superInvocation);
+    }
+    // Compare the types.
+    var superType = superParameter.type;
+    var thisType = thisParameter.type;
+    if (!typeSystem.isAssignableTo(superType, thisType)) {
+      // If the type of the selected parameter can't be assigned to the super
+      // parameter, the the change isn't appropriate.
+      return null;
+    }
+    // Return the data.
+    return _ParameterData(
+      argumentUpdate: argumentUpdate,
+      defaultValueRange:
+          _defaultValueRange(parameter, superParameter, thisParameter),
+      typeToDelete: superType == thisType ? _type(parameter) : null,
+    );
+  }
+
+  /// Return `true` if the positional [parameter] can be converted into a super
+  /// initializing formal parameter.
+  _ParameterData? _dataForPositionalParameter(
+      FormalParameter parameter,
+      ParameterElement thisParameter,
+      ConstructorElement superConstructor,
+      SuperConstructorInvocation superInvocation) {
+    var positionalArguments = _positionalArguments(superInvocation);
+    if (positionalArguments.length != 1) {
+      // If there's more than one positional parameter then they would all need
+      // to be converted at the same time. If there's less than one, the the
+      // selected parameter isn't being passed to the super constructor.
+      return null;
+    }
+    var argument = positionalArguments[0];
+    if (argument is! SimpleIdentifier ||
+        argument.staticElement != parameter.declaredElement) {
+      // If the selected parameter isn't the one being passed to the super
+      // constructor then the change isn't appropriate.
+      return null;
+    }
+    var positionalParameters = superConstructor.parameters
+        .where((param) => param.isPositional)
+        .toList();
+    if (positionalParameters.isEmpty) {
+      return null;
+    }
+    var superParameter = positionalParameters[0];
+    _ArgumentUpdate? argumentUpdate;
+    if (superInvocation.argumentList.arguments.length == 1) {
+      argumentUpdate = _RemoveInvocation(superInvocation);
+    } else {
+      argumentUpdate = _RemoveArgument(argument);
+    }
+    // Compare the types.
+    var superType = superParameter.type;
+    var thisType = thisParameter.type;
+    if (!typeSystem.isSubtypeOf(thisType, superType)) {
+      // If the type of the selected parameter can't be assigned to the super
+      // parameter, the the change isn't appropriate.
+      return null;
+    }
+    // Return the data.
+    return _ParameterData(
+      argumentUpdate: argumentUpdate,
+      defaultValueRange:
+          _defaultValueRange(parameter, superParameter, thisParameter),
+      typeToDelete: superType == thisType ? _type(parameter) : null,
+    );
+  }
+
+  /// Return the range of the default value associated with the [parameter], or
+  /// `null` if the parameter doesn't have a default value or if the default
+  /// value is not the same as the default value in the super constructor.
+  SourceRange? _defaultValueRange(FormalParameter parameter,
+      ParameterElement superParameter, ParameterElement thisParameter) {
+    if (parameter is DefaultFormalParameter) {
+      var defaultValue = parameter.defaultValue;
+      if (defaultValue != null) {
+        var superDefault = superParameter.computeConstantValue();
+        var thisDefault = thisParameter.computeConstantValue();
+        if (superDefault != null && superDefault == thisDefault) {
+          return range.endEnd(parameter.identifier!, defaultValue);
+        }
+      }
+    }
+    return null;
+  }
+
+  List<Expression> _positionalArguments(SuperConstructorInvocation invocation) {
+    return invocation.argumentList.arguments
+        .where((argument) => argument is! NamedExpression)
+        .toList();
+  }
+
+  SuperConstructorInvocation? _superInvocation(
+      ConstructorDeclaration constructor) {
+    var initializers = constructor.initializers;
+    // Search all of the initializers in case the code is invalid, but start
+    // from the end because the code will usually be correct.
+    for (var i = initializers.length - 1; i >= 0; i--) {
+      var initializer = initializers[i];
+      if (initializer is SuperConstructorInvocation) {
+        return initializer;
+      }
+    }
+    return null;
+  }
+
+  _TypeData? _type(FormalParameter parameter) {
+    if (parameter is DefaultFormalParameter) {
+      return _type(parameter.parameter);
+    } else if (parameter is SimpleFormalParameter) {
+      var typeAnnotation = parameter.type;
+      if (typeAnnotation != null) {
+        return _TypeData(
+            primaryRange:
+                range.startStart(typeAnnotation, parameter.identifier!));
+      }
+    } else if (parameter is FunctionTypedFormalParameter) {
+      var returnType = parameter.returnType;
+      return _TypeData(
+          primaryRange: returnType != null
+              ? range.startStart(returnType, parameter.identifier)
+              : null,
+          parameterRange: range.node(parameter.parameters));
+    }
+    return null;
+  }
+
+  /// Return an instance of this class. Used as a tear-off in `AssistProcessor`.
+  static ConvertToSuperInitializingParameter newInstance() =>
+      ConvertToSuperInitializingParameter();
+}
+
+abstract class _ArgumentUpdate {
+  void addDeletion(DartFileEditBuilder builder);
+}
+
+class _ParameterData {
+  /// Information used to remove the argument from the super constructor
+  /// invocation.
+  final _ArgumentUpdate argumentUpdate;
+
+  /// Information about the type annotation that should be deleted, or `null` if
+  /// there is no type annotation to delete or if the type should not be
+  /// deleted.
+  final _TypeData? typeToDelete;
+
+  /// The range of the default value that is to be deleted, or `null` if there
+  /// is no default value, the default value isn't to be deleted.
+  final SourceRange? defaultValueRange;
+
+  /// Initialize a newly create data object.
+  _ParameterData(
+      {required this.argumentUpdate,
+      required this.typeToDelete,
+      required this.defaultValueRange});
+}
+
+class _RemoveArgument extends _ArgumentUpdate {
+  final Expression argument;
+
+  _RemoveArgument(this.argument);
+
+  @override
+  void addDeletion(DartFileEditBuilder builder) {
+    var argumentList = argument.parent as ArgumentList;
+    var index = argumentList.arguments.indexOf(argument);
+    builder.addDeletion(range.argumentRange(argumentList, index, index, true));
+  }
+}
+
+class _RemoveInvocation extends _ArgumentUpdate {
+  final SuperConstructorInvocation invocation;
+
+  _RemoveInvocation(this.invocation);
+
+  @override
+  void addDeletion(DartFileEditBuilder builder) {
+    var declaration = invocation.parent as ConstructorDeclaration;
+    var initializerList = declaration.initializers;
+    if (initializerList.length == 1) {
+      builder.addDeletion(range.endEnd(declaration.parameters, invocation));
+    } else {
+      builder.addDeletion(range.nodeInList(initializerList, invocation));
+    }
+  }
+}
+
+class _TypeData {
+  SourceRange? primaryRange;
+
+  SourceRange? parameterRange;
+
+  _TypeData({required this.primaryRange, this.parameterRange});
+}
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index 608f706..6f03e81 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -2058,8 +2058,8 @@
   Future<void> test_ArgumentList_imported_function_named_param_label3() async {
     addTestFile('void f() { int.parse("16", ^: 16);}');
     await getSuggestions();
-    assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'radix: ');
-    assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'onError: ');
+    assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'radix');
+    assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'onError');
     expect(suggestions, hasLength(2));
   }
 
diff --git a/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
index 7bf72fe..ac6847a 100644
--- a/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
@@ -660,17 +660,15 @@
       check: (response) {
         _checkNamedArguments(response).matchesInAnyOrder([
           (suggestion) => suggestion
-            // TODO(scheglov) This does not seem right.
-            ..completion.isEqualTo('two: ')
+            ..completion.isEqualTo('two')
             ..parameterType.isEqualTo('int')
             ..hasEmptyReplacement()
-            ..hasSelection(offset: 5),
+            ..hasSelection(offset: 3),
           (suggestion) => suggestion
-            // TODO(scheglov) This does not seem right.
-            ..completion.isEqualTo('three: ')
+            ..completion.isEqualTo('three')
             ..parameterType.isEqualTo('double')
             ..hasEmptyReplacement()
-            ..hasSelection(offset: 7),
+            ..hasSelection(offset: 5),
         ]);
       },
     );
diff --git a/pkg/analysis_server/test/services/completion/dart/completion_check.dart b/pkg/analysis_server/test/services/completion/dart/completion_check.dart
index de00669..222d9dd 100644
--- a/pkg/analysis_server/test/services/completion/dart/completion_check.dart
+++ b/pkg/analysis_server/test/services/completion/dart/completion_check.dart
@@ -214,6 +214,11 @@
     element.isNotNull.kind.isMethod;
   }
 
+  void get isNamedArgument {
+    kind.isNamedArgument;
+    element.isNull;
+  }
+
   @useResult
   CheckTarget<bool?> get isNotImported {
     return nest(
@@ -333,6 +338,10 @@
   void get isInvocation {
     isEqualTo(CompletionSuggestionKind.INVOCATION);
   }
+
+  void get isNamedArgument {
+    isEqualTo(CompletionSuggestionKind.NAMED_ARGUMENT);
+  }
 }
 
 extension CompletionSuggestionsExtension
diff --git a/pkg/analysis_server/test/services/completion/dart/location/named_expression_test.dart b/pkg/analysis_server/test/services/completion/dart/location/named_expression_test.dart
new file mode 100644
index 0000000..e3fd183
--- /dev/null
+++ b/pkg/analysis_server/test/services/completion/dart/location/named_expression_test.dart
@@ -0,0 +1,89 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer_utilities/check/check.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../../../../client/completion_driver_test.dart';
+import '../completion_check.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(NamedExpressionExpressionTest1);
+    defineReflectiveTests(NamedExpressionExpressionTest2);
+  });
+}
+
+@reflectiveTest
+class NamedExpressionExpressionTest1 extends AbstractCompletionDriverTest
+    with NamedExpressionExpressionTestCases {
+  @override
+  TestingCompletionProtocol get protocol => TestingCompletionProtocol.version1;
+}
+
+@reflectiveTest
+class NamedExpressionExpressionTest2 extends AbstractCompletionDriverTest
+    with NamedExpressionExpressionTestCases {
+  @override
+  TestingCompletionProtocol get protocol => TestingCompletionProtocol.version2;
+}
+
+mixin NamedExpressionExpressionTestCases on AbstractCompletionDriverTest {
+  @override
+  bool get supportsAvailableSuggestions => true;
+
+  Future<void> test_beforePositional() async {
+    var response = await getTestCodeSuggestions('''
+void f(int x) {
+  g(b: ^, 0);
+}
+
+void g(int a, {required int b}) {}
+''');
+
+    check(response)
+      ..hasEmptyReplacement()
+      ..suggestions.includesAll([
+        (suggestion) => suggestion
+          ..completion.isEqualTo('x')
+          ..isParameter,
+      ]);
+  }
+
+  Future<void> test_lastArgument() async {
+    var response = await getTestCodeSuggestions('''
+void f(int x) {
+  g(0, b: ^);
+}
+
+void g(int a, {required int b}) {}
+''');
+
+    check(response)
+      ..hasEmptyReplacement()
+      ..suggestions.includesAll([
+        (suggestion) => suggestion
+          ..completion.isEqualTo('x')
+          ..isParameter,
+      ]);
+  }
+
+  Future<void> test_onlyArgument() async {
+    var response = await getTestCodeSuggestions('''
+void f(int x) {
+  g(a: ^);
+}
+
+void g({required int a}) {}
+''');
+
+    check(response)
+      ..hasEmptyReplacement()
+      ..suggestions.includesAll([
+        (suggestion) => suggestion
+          ..completion.isEqualTo('x')
+          ..isParameter,
+      ]);
+  }
+}
diff --git a/pkg/analysis_server/test/services/completion/dart/location/test_all.dart b/pkg/analysis_server/test/services/completion/dart/location/test_all.dart
index 66dc07d..3e30b45 100644
--- a/pkg/analysis_server/test/services/completion/dart/location/test_all.dart
+++ b/pkg/analysis_server/test/services/completion/dart/location/test_all.dart
@@ -5,12 +5,14 @@
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import 'field_formal_parameter_test.dart' as field_formal_parameter;
+import 'named_expression_test.dart' as named_expression;
 import 'super_formal_parameter_test.dart' as super_formal_parameter;
 
 /// Tests suggestions produced at specific locations.
 void main() {
   defineReflectiveSuite(() {
     field_formal_parameter.main();
+    named_expression.main();
     super_formal_parameter.main();
   });
 }
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_to_super_initializing_parameter_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_to_super_initializing_parameter_test.dart
new file mode 100644
index 0000000..df4f094
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_to_super_initializing_parameter_test.dart
@@ -0,0 +1,484 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analyzer_plugin/utilities/assist/assist.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'assist_processor.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ConvertToSuperInitializingParameterTest);
+  });
+}
+
+@reflectiveTest
+class ConvertToSuperInitializingParameterTest extends AssistProcessorTest {
+  @override
+  AssistKind get kind => DartAssistKind.CONVERT_TO_SUPER_INITIALIZING_PARAMETER;
+
+  Future<void> test_named_first() async {
+    await resolveTestCode('''
+class A {
+  A({int? x, int? y});
+}
+class B extends A {
+  B({int? x, int? y}) : super(x: x, y: y);
+}
+''');
+    await assertHasAssistAt('x, int? y}) :', '''
+class A {
+  A({int? x, int? y});
+}
+class B extends A {
+  B({super.x, int? y}) : super(y: y);
+}
+''');
+  }
+
+  Future<void> test_named_last() async {
+    await resolveTestCode('''
+class A {
+  A({int? x, int? y});
+}
+class B extends A {
+  B({int? x, int? y}) : super(x: x, y: y);
+}
+''');
+    await assertHasAssistAt('y}) :', '''
+class A {
+  A({int? x, int? y});
+}
+class B extends A {
+  B({int? x, super.y}) : super(x: x);
+}
+''');
+  }
+
+  Future<void> test_named_middle() async {
+    await resolveTestCode('''
+class A {
+  A({int? x, int? y, int? z});
+}
+class B extends A {
+  B({int? x, int? y, int? z}) : super(x: x, y: y, z: z);
+}
+''');
+    await assertHasAssistAt('y, int? z}) :', '''
+class A {
+  A({int? x, int? y, int? z});
+}
+class B extends A {
+  B({int? x, super.y, int? z}) : super(x: x, z: z);
+}
+''');
+  }
+
+  Future<void> test_named_noSuperInvocation() async {
+    await resolveTestCode('''
+class A {
+  A({int x = 0});
+}
+class B extends A {
+  B({int x = 1});
+}
+''');
+    await assertNoAssistAt('x = 1');
+  }
+
+  Future<void> test_named_notGenerative() async {
+    await resolveTestCode('''
+class A {
+  A({required int x});
+}
+class B extends A {
+  static List<B> instances = [];
+  factory B({required int x}) => instances[x];
+}
+''');
+    await assertNoAssistAt('x}) =>');
+  }
+
+  Future<void> test_named_notInConstructor() async {
+    await resolveTestCode('''
+class A {
+  void m({required int x}) {}
+}
+''');
+    await assertNoAssistAt('x})');
+  }
+
+  Future<void> test_named_notPassed_unreferenced() async {
+    await resolveTestCode('''
+class A {
+  A({int x = 0});
+}
+class B extends A {
+  B({int x = 0}) : super(x: 0);
+}
+''');
+    await assertNoAssistAt('x = 0}) :');
+  }
+
+  Future<void> test_named_notPassed_usedInExpression() async {
+    await resolveTestCode('''
+class A {
+  A({String x = ''});
+}
+class B extends A {
+  B({required Object x}) : super(x: x.toString());
+}
+''');
+    await assertNoAssistAt('x}) :');
+  }
+
+  Future<void> test_named_notSupported() async {
+    await resolveTestCode('''
+// @dart=2.16
+class A {
+  A({int? x});
+}
+class B extends A {
+  B({int? x}) : super(x: x);
+}
+''');
+    await assertNoAssistAt('x}) :');
+  }
+
+  Future<void> test_named_only() async {
+    await resolveTestCode('''
+class A {
+  A({int? x});
+}
+class B extends A {
+  B({int? x}) : super(x: x);
+}
+''');
+    await assertHasAssistAt('x}) :', '''
+class A {
+  A({int? x});
+}
+class B extends A {
+  B({super.x});
+}
+''');
+  }
+
+  Future<void> test_named_withDifferentDefaultValue() async {
+    await resolveTestCode('''
+class A {
+  A({int x = 0});
+}
+class B extends A {
+  B({int x = 2}) : super(x: x);
+}
+''');
+    await assertHasAssistAt('x = 2}) :', '''
+class A {
+  A({int x = 0});
+}
+class B extends A {
+  B({super.x = 2});
+}
+''');
+  }
+
+  Future<void> test_named_withEqualDefaultValue() async {
+    await resolveTestCode('''
+class A {
+  A({int x = 0});
+}
+class B extends A {
+  B({int x = 0}) : super(x: x);
+}
+''');
+    await assertHasAssistAt('x = 0}) :', '''
+class A {
+  A({int x = 0});
+}
+class B extends A {
+  B({super.x});
+}
+''');
+  }
+
+  Future<void> test_optionalPositional_singleSuperParameter_only() async {
+    await resolveTestCode('''
+class A {
+  A(int x);
+}
+class B extends A {
+  B([int x = 0]) : super(x);
+}
+''');
+    await assertHasAssistAt('x = 0]', '''
+class A {
+  A(int x);
+}
+class B extends A {
+  B([super.x = 0]);
+}
+''');
+  }
+
+  Future<void> test_requiredPositional_mixedSuperParameters_first() async {
+    await resolveTestCode('''
+class A {
+  A(int x, {int? y});
+}
+class B extends A {
+  B(int x, int y) : super(x, y: y);
+}
+''');
+    await assertHasAssistAt('x, int y)', '''
+class A {
+  A(int x, {int? y});
+}
+class B extends A {
+  B(super.x, int y) : super(y: y);
+}
+''');
+  }
+
+  Future<void> test_requiredPositional_mixedSuperParameters_last() async {
+    await resolveTestCode('''
+class A {
+  A(int x, {int? y});
+}
+class B extends A {
+  B(int y, int x) : super(x, y: y);
+}
+''');
+    await assertHasAssistAt('x) :', '''
+class A {
+  A(int x, {int? y});
+}
+class B extends A {
+  B(int y, super.x) : super(y: y);
+}
+''');
+  }
+
+  Future<void> test_requiredPositional_mixedSuperParameters_middle() async {
+    await resolveTestCode('''
+class A {
+  A(int y, {int? z});
+}
+class B extends A {
+  B(int x, int y, int z) : super(y, z: z);
+}
+''');
+    await assertHasAssistAt('y, int z) :', '''
+class A {
+  A(int y, {int? z});
+}
+class B extends A {
+  B(int x, super.y, int z) : super(z: z);
+}
+''');
+  }
+
+  Future<void> test_requiredPositional_multipleSuperParameters_first() async {
+    await resolveTestCode('''
+class A {
+  A(int x, int y);
+}
+class B extends A {
+  B(int x, int y) : super(x, y);
+}
+''');
+    await assertNoAssistAt('x, int y) :');
+  }
+
+  Future<void> test_requiredPositional_multipleSuperParameters_last() async {
+    await resolveTestCode('''
+class A {
+  A(int x, int y);
+}
+class B extends A {
+  B(int x, int y) : super(x, y);
+}
+''');
+    await assertNoAssistAt('y) :');
+  }
+
+  Future<void> test_requiredPositional_multipleSuperParameters_middle() async {
+    await resolveTestCode('''
+class A {
+  A(int x, int y, int z);
+}
+class B extends A {
+  B(int x, int y, int z) : super(x, y, z);
+}
+''');
+    await assertNoAssistAt('y, int z) :');
+  }
+
+  Future<void> test_requiredPositional_noSuperInvocation() async {
+    await resolveTestCode('''
+class A {
+  A();
+}
+class B extends A {
+  B(int x);
+}
+''');
+    await assertNoAssistAt('x);');
+  }
+
+  Future<void> test_requiredPositional_notGenerative() async {
+    await resolveTestCode('''
+class A {
+  A(int x);
+}
+class B extends A {
+  static List<B> instances = [];
+  factory B(int x) => instances[x];
+}
+''');
+    await assertNoAssistAt('x) =>');
+  }
+
+  Future<void> test_requiredPositional_notInConstructor() async {
+    await resolveTestCode('''
+class A {
+  void m(int x) {}
+}
+''');
+    await assertNoAssistAt('x)');
+  }
+
+  Future<void> test_requiredPositional_notPassed_unreferenced() async {
+    await resolveTestCode('''
+class A {
+  A(int x);
+}
+class B extends A {
+  B(int x) : super(0);
+}
+''');
+    await assertNoAssistAt('x) :');
+  }
+
+  Future<void> test_requiredPositional_notPassed_usedInExpression() async {
+    await resolveTestCode('''
+class A {
+  A(String x);
+}
+class B extends A {
+  B(Object x) : super(x.toString());
+}
+''');
+    await assertNoAssistAt('x) :');
+  }
+
+  Future<void> test_requiredPositional_notSupported() async {
+    await resolveTestCode('''
+// @dart=2.16
+class A {
+  A(int x);
+}
+class B extends A {
+  B(int x) : super(x);
+}
+''');
+    await assertNoAssistAt('x) :');
+  }
+
+  Future<void> test_requiredPositional_singleSuperParameter_first() async {
+    await resolveTestCode('''
+class A {
+  A(int x);
+}
+class B extends A {
+  B(int x, int y) : super(x);
+}
+''');
+    await assertHasAssistAt('x, int y)', '''
+class A {
+  A(int x);
+}
+class B extends A {
+  B(super.x, int y);
+}
+''');
+  }
+
+  Future<void> test_requiredPositional_singleSuperParameter_last() async {
+    await resolveTestCode('''
+class A {
+  A(int x);
+}
+class B extends A {
+  B(int x, int y) : super(y);
+}
+''');
+    await assertHasAssistAt('y) :', '''
+class A {
+  A(int x);
+}
+class B extends A {
+  B(int x, super.y);
+}
+''');
+  }
+
+  Future<void> test_requiredPositional_singleSuperParameter_middle() async {
+    await resolveTestCode('''
+class A {
+  A(int x);
+}
+class B extends A {
+  B(int x, int y, int z) : super(y);
+}
+''');
+    await assertHasAssistAt('y, int z) :', '''
+class A {
+  A(int x);
+}
+class B extends A {
+  B(int x, super.y, int z);
+}
+''');
+  }
+
+  Future<void> test_requiredPositional_singleSuperParameter_only() async {
+    await resolveTestCode('''
+class A {
+  A(int x);
+}
+class B extends A {
+  B(int x) : super(x);
+}
+''');
+    await assertHasAssistAt('x) :', '''
+class A {
+  A(int x);
+}
+class B extends A {
+  B(super.x);
+}
+''');
+  }
+
+  Future<void> test_requiredPositional_unpassedOptionalPositional() async {
+    await resolveTestCode('''
+class A {
+  A(int x, [int y = 0]);
+}
+class B extends A {
+  B(int x) : super(x);
+}
+''');
+    await assertHasAssistAt('x) :', '''
+class A {
+  A(int x, [int y = 0]);
+}
+class B extends A {
+  B(super.x);
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/assist/test_all.dart b/pkg/analysis_server/test/src/services/correction/assist/test_all.dart
index 1773afd..e61b6f7 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/test_all.dart
@@ -41,6 +41,8 @@
 import 'convert_to_single_quoted_string_test.dart'
     as convert_to_single_quoted_string;
 import 'convert_to_spread_test.dart' as convert_to_spread;
+import 'convert_to_super_initializing_parameter_test.dart'
+    as convert_to_super_initializing_parameter;
 import 'encapsulate_field_test.dart' as encapsulate_field;
 import 'exchange_operands_test.dart' as exchange_operands;
 import 'flutter_convert_to_children_test.dart' as flutter_convert_to_children;
@@ -122,6 +124,7 @@
     convert_to_set_literal.main();
     convert_to_single_quoted_string.main();
     convert_to_spread.main();
+    convert_to_super_initializing_parameter.main();
     encapsulate_field.main();
     exchange_operands.main();
     flutter_convert_to_children.main();
diff --git a/pkg/analyzer/lib/src/error/codes.g.dart b/pkg/analyzer/lib/src/error/codes.g.dart
index 88d2afe..6cccc05 100644
--- a/pkg/analyzer/lib/src/error/codes.g.dart
+++ b/pkg/analyzer/lib/src/error/codes.g.dart
@@ -9417,7 +9417,6 @@
     "Non-abstract classes can't have 'Enum' as a superinterface.",
     correctionMessage:
         "Try specifying a different interface, or remove it from the list.",
-    uniqueName: 'NON_ABSTRACT_CLASS_HAS_ENUM_SUPERINTERFACE',
   );
 
   /**
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index b46f83c..233fb5f 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -563,6 +563,26 @@
     try {
       _enclosingClass = node.declaredElement;
       _duplicateDefinitionVerifier.checkEnum(node);
+
+      // TODO(scheglov) implement
+      // List<ClassMember> members = node.members;
+      _checkForBuiltInIdentifierAsName(
+          node.name, CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE_NAME);
+      // _checkForConflictingClassTypeVariableErrorCodes();
+      var implementsClause = node.implementsClause;
+      var withClause = node.withClause;
+
+      if (implementsClause != null || withClause != null) {
+        _checkClassInheritance(node, null, withClause, implementsClause);
+      }
+
+      // TODO(scheglov) implement
+      // _checkForConflictingClassMembers();
+      // _constructorFieldsVerifier.enterClass(node);
+      // _checkForFinalNotInitializedInClass(members);
+      _checkForWrongTypeParameterVarianceInSuperinterfaces();
+      _checkForMainFunction(node.name);
+
       super.visitEnumDeclaration(node);
     } finally {
       _enclosingClass = outerClass;
diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml
index 41e3bc3..58539a7 100644
--- a/pkg/analyzer/messages.yaml
+++ b/pkg/analyzer/messages.yaml
@@ -8043,7 +8043,6 @@
       A f() => A();
       ```
   NON_ABSTRACT_CLASS_HAS_ENUM_SUPERINTERFACE:
-    sharedName: NON_ABSTRACT_CLASS_HAS_ENUM_SUPERINTERFACE
     problemMessage: "Non-abstract classes can't have 'Enum' as a superinterface."
     correctionMessage: Try specifying a different interface, or remove it from the list.
   NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FIVE_PLUS:
diff --git a/pkg/analyzer/test/generated/constant_test.dart b/pkg/analyzer/test/generated/constant_test.dart
index e52a181..2387698b 100644
--- a/pkg/analyzer/test/generated/constant_test.dart
+++ b/pkg/analyzer/test/generated/constant_test.dart
@@ -392,6 +392,71 @@
 ''');
   }
 
+  test_object_enum_enhanced_named() async {
+    await resolveTestCode('''
+enum E<T> {
+  v1<double>.named(10),
+  v2.named(20);
+  final T f;
+  const E.named(this.f);
+}
+
+const x1 = E.v1;
+const x2 = E.v2;
+''');
+
+    _assertTopVarConstValue('x1', r'''
+E<double>
+  _name: String v1
+  f: double 10.0
+  index: int 0
+''');
+
+    _assertTopVarConstValue('x2', r'''
+E<int>
+  _name: String v2
+  f: int 20
+  index: int 1
+''');
+  }
+
+  test_object_enum_enhanced_unnamed() async {
+    await resolveTestCode('''
+enum E<T> {
+  v1<int>(10),
+  v2(20),
+  v3('abc');
+  final T f;
+  const E(this.f);
+}
+
+const x1 = E.v1;
+const x2 = E.v2;
+const x3 = E.v3;
+''');
+
+    _assertTopVarConstValue('x1', r'''
+E<int>
+  _name: String v1
+  f: int 10
+  index: int 0
+''');
+
+    _assertTopVarConstValue('x2', r'''
+E<int>
+  _name: String v2
+  f: int 20
+  index: int 1
+''');
+
+    _assertTopVarConstValue('x3', r'''
+E<String>
+  _name: String v3
+  f: String abc
+  index: int 2
+''');
+  }
+
   test_parenthesizedExpression() async {
     await _assertValueString("a", "('a')");
   }
diff --git a/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart b/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
index c564c0c..eb3fbbc 100644
--- a/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
@@ -2606,6 +2606,51 @@
     );
   }
 
+  test_hasReceiver_interfaceType_enum() async {
+    await assertNoErrorsInCode(r'''
+enum E {
+  v;
+  void foo() {}
+}
+
+void f(E e) {
+  e.foo();
+}
+''');
+
+    assertMethodInvocation2(
+      findNode.methodInvocation('e.foo()'),
+      element: findElement.method('foo', of: 'E'),
+      typeArgumentTypes: [],
+      invokeType: 'void Function()',
+      type: 'void',
+    );
+  }
+
+  test_hasReceiver_interfaceType_enum_fromMixin() async {
+    await assertNoErrorsInCode(r'''
+mixin M on Enum {
+  void foo() {}
+}
+
+enum E with M {
+  v;
+}
+
+void f(E e) {
+  e.foo();
+}
+''');
+
+    assertMethodInvocation2(
+      findNode.methodInvocation('e.foo()'),
+      element: findElement.method('foo', of: 'M'),
+      typeArgumentTypes: [],
+      invokeType: 'void Function()',
+      type: 'void',
+    );
+  }
+
   test_hasReceiver_interfaceTypeQ_defined() async {
     await assertErrorsInCode(r'''
 class A {
diff --git a/pkg/analyzer/test/src/dart/resolution/prefixed_identifier_test.dart b/pkg/analyzer/test/src/dart/resolution/prefixed_identifier_test.dart
index f0523f1..b9df396 100644
--- a/pkg/analyzer/test/src/dart/resolution/prefixed_identifier_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/prefixed_identifier_test.dart
@@ -46,6 +46,81 @@
     );
   }
 
+  test_enum_read() async {
+    await assertNoErrorsInCode('''
+enum E {
+  v;
+  int get foo => 0;
+}
+
+void f(E e) {
+  e.foo;
+}
+''');
+
+    var prefixed = findNode.prefixed('e.foo');
+    assertPrefixedIdentifier(
+      prefixed,
+      element: findElement.getter('foo'),
+      type: 'int',
+    );
+
+    assertSimpleIdentifier(
+      prefixed.prefix,
+      element: findElement.parameter('e'),
+      type: 'E',
+    );
+
+    assertSimpleIdentifier(
+      prefixed.identifier,
+      element: findElement.getter('foo'),
+      type: 'int',
+    );
+  }
+
+  test_enum_write() async {
+    await assertNoErrorsInCode('''
+enum E {
+  v;
+  set foo(int _) {}
+}
+
+void f(E e) {
+  e.foo = 1;
+}
+''');
+
+    var assignment = findNode.assignment('foo = 1');
+    assertAssignment(
+      assignment,
+      readElement: null,
+      readType: null,
+      writeElement: findElement.setter('foo'),
+      writeType: 'int',
+      operatorElement: null,
+      type: 'int',
+    );
+
+    var prefixed = assignment.leftHandSide as PrefixedIdentifier;
+    if (hasAssignmentLeftResolution) {
+      assertPrefixedIdentifier(
+        prefixed,
+        element: findElement.setter('foo'),
+        type: 'int',
+      );
+    }
+
+    assertSimpleIdentifier(
+      prefixed.prefix,
+      element: findElement.parameter('e'),
+      type: 'E',
+    );
+
+    assertSimpleIdentifierAssignmentTarget(
+      prefixed.identifier,
+    );
+  }
+
   test_hasReceiver_typeAlias_staticGetter() async {
     await assertNoErrorsInCode(r'''
 class A {
@@ -137,6 +212,218 @@
 }
 
 mixin PrefixedIdentifierResolutionTestCases on PubPackageResolutionTest {
+  test_class_read() async {
+    await assertNoErrorsInCode('''
+class A {
+  int foo = 0;
+}
+
+void f(A a) {
+  a.foo;
+}
+''');
+
+    var prefixed = findNode.prefixed('a.foo');
+    assertPrefixedIdentifier(
+      prefixed,
+      element: findElement.getter('foo'),
+      type: 'int',
+    );
+
+    assertSimpleIdentifier(
+      prefixed.prefix,
+      element: findElement.parameter('a'),
+      type: 'A',
+    );
+
+    assertSimpleIdentifier(
+      prefixed.identifier,
+      element: findElement.getter('foo'),
+      type: 'int',
+    );
+  }
+
+  test_class_read_staticMethod_generic() async {
+    await assertNoErrorsInCode('''
+class A<T> {
+  static void foo<U>(int a, U u) {}
+}
+
+void f() {
+  A.foo;
+}
+''');
+
+    var prefixed = findNode.prefixed('A.foo');
+    assertPrefixedIdentifier(
+      prefixed,
+      element: findElement.method('foo'),
+      type: 'void Function<U>(int, U)',
+    );
+
+    assertSimpleIdentifier(
+      prefixed.prefix,
+      element: findElement.class_('A'),
+      type: null,
+    );
+
+    assertSimpleIdentifier(
+      prefixed.identifier,
+      element: findElement.method('foo'),
+      type: 'void Function<U>(int, U)',
+    );
+  }
+
+  test_class_read_staticMethod_ofGenericClass() async {
+    await assertNoErrorsInCode('''
+class A<T> {
+  static void foo(int a) {}
+}
+
+void f() {
+  A.foo;
+}
+''');
+
+    var prefixed = findNode.prefixed('A.foo');
+    assertPrefixedIdentifier(
+      prefixed,
+      element: findElement.method('foo'),
+      type: 'void Function(int)',
+    );
+
+    assertSimpleIdentifier(
+      prefixed.prefix,
+      element: findElement.class_('A'),
+      type: null,
+    );
+
+    assertSimpleIdentifier(
+      prefixed.identifier,
+      element: findElement.method('foo'),
+      type: 'void Function(int)',
+    );
+  }
+
+  test_class_read_typedef_functionType() async {
+    newFile('$testPackageLibPath/a.dart', content: r'''
+typedef A = void Function();
+''');
+
+    await assertNoErrorsInCode('''
+import 'a.dart' as p;
+
+void f() {
+  p.A;
+}
+''');
+
+    var importFind = findElement.importFind('package:test/a.dart');
+    var A = importFind.typeAlias('A');
+
+    var prefixed = findNode.prefixed('p.A');
+    assertPrefixedIdentifier(
+      prefixed,
+      element: A,
+      type: 'Type',
+    );
+
+    assertImportPrefix(prefixed.prefix, importFind.prefix);
+
+    assertSimpleIdentifier(
+      prefixed.identifier,
+      element: A,
+      type: 'Type',
+    );
+  }
+
+  test_class_readWrite_assignment() async {
+    await assertNoErrorsInCode('''
+class A {
+  int foo = 0;
+}
+
+void f(A a) {
+  a.foo += 1;
+}
+''');
+
+    var assignment = findNode.assignment('foo += 1');
+    assertAssignment(
+      assignment,
+      readElement: findElement.getter('foo'),
+      readType: 'int',
+      writeElement: findElement.setter('foo'),
+      writeType: 'int',
+      operatorElement: elementMatcher(
+        numElement.getMethod('+'),
+        isLegacy: isLegacyLibrary,
+      ),
+      type: 'int',
+    );
+
+    var prefixed = assignment.leftHandSide as PrefixedIdentifier;
+    if (hasAssignmentLeftResolution) {
+      assertPrefixedIdentifier(
+        prefixed,
+        element: findElement.setter('foo'),
+        type: 'int',
+      );
+    }
+
+    assertSimpleIdentifier(
+      prefixed.prefix,
+      element: findElement.parameter('a'),
+      type: 'A',
+    );
+
+    assertSimpleIdentifierAssignmentTarget(
+      prefixed.identifier,
+    );
+  }
+
+  test_class_write() async {
+    await assertNoErrorsInCode('''
+class A {
+  int foo = 0;
+}
+
+void f(A a) {
+  a.foo = 1;
+}
+''');
+
+    var assignment = findNode.assignment('foo = 1');
+    assertAssignment(
+      assignment,
+      readElement: null,
+      readType: null,
+      writeElement: findElement.setter('foo'),
+      writeType: 'int',
+      operatorElement: null,
+      type: 'int',
+    );
+
+    var prefixed = assignment.leftHandSide as PrefixedIdentifier;
+    if (hasAssignmentLeftResolution) {
+      assertPrefixedIdentifier(
+        prefixed,
+        element: findElement.setter('foo'),
+        type: 'int',
+      );
+    }
+
+    assertSimpleIdentifier(
+      prefixed.prefix,
+      element: findElement.parameter('a'),
+      type: 'A',
+    );
+
+    assertSimpleIdentifierAssignmentTarget(
+      prefixed.identifier,
+    );
+  }
+
   test_dynamic_explicitCore_withPrefix() async {
     await assertNoErrorsInCode(r'''
 import 'dart:core' as mycore;
@@ -190,218 +477,6 @@
     );
     assertType(identifier, 'A');
   }
-
-  test_read() async {
-    await assertNoErrorsInCode('''
-class A {
-  int foo = 0;
-}
-
-void f(A a) {
-  a.foo;
-}
-''');
-
-    var prefixed = findNode.prefixed('a.foo');
-    assertPrefixedIdentifier(
-      prefixed,
-      element: findElement.getter('foo'),
-      type: 'int',
-    );
-
-    assertSimpleIdentifier(
-      prefixed.prefix,
-      element: findElement.parameter('a'),
-      type: 'A',
-    );
-
-    assertSimpleIdentifier(
-      prefixed.identifier,
-      element: findElement.getter('foo'),
-      type: 'int',
-    );
-  }
-
-  test_read_staticMethod_generic() async {
-    await assertNoErrorsInCode('''
-class A<T> {
-  static void foo<U>(int a, U u) {}
-}
-
-void f() {
-  A.foo;
-}
-''');
-
-    var prefixed = findNode.prefixed('A.foo');
-    assertPrefixedIdentifier(
-      prefixed,
-      element: findElement.method('foo'),
-      type: 'void Function<U>(int, U)',
-    );
-
-    assertSimpleIdentifier(
-      prefixed.prefix,
-      element: findElement.class_('A'),
-      type: null,
-    );
-
-    assertSimpleIdentifier(
-      prefixed.identifier,
-      element: findElement.method('foo'),
-      type: 'void Function<U>(int, U)',
-    );
-  }
-
-  test_read_staticMethod_ofGenericClass() async {
-    await assertNoErrorsInCode('''
-class A<T> {
-  static void foo(int a) {}
-}
-
-void f() {
-  A.foo;
-}
-''');
-
-    var prefixed = findNode.prefixed('A.foo');
-    assertPrefixedIdentifier(
-      prefixed,
-      element: findElement.method('foo'),
-      type: 'void Function(int)',
-    );
-
-    assertSimpleIdentifier(
-      prefixed.prefix,
-      element: findElement.class_('A'),
-      type: null,
-    );
-
-    assertSimpleIdentifier(
-      prefixed.identifier,
-      element: findElement.method('foo'),
-      type: 'void Function(int)',
-    );
-  }
-
-  test_read_typedef_functionType() async {
-    newFile('$testPackageLibPath/a.dart', content: r'''
-typedef A = void Function();
-''');
-
-    await assertNoErrorsInCode('''
-import 'a.dart' as p;
-
-void f() {
-  p.A;
-}
-''');
-
-    var importFind = findElement.importFind('package:test/a.dart');
-    var A = importFind.typeAlias('A');
-
-    var prefixed = findNode.prefixed('p.A');
-    assertPrefixedIdentifier(
-      prefixed,
-      element: A,
-      type: 'Type',
-    );
-
-    assertImportPrefix(prefixed.prefix, importFind.prefix);
-
-    assertSimpleIdentifier(
-      prefixed.identifier,
-      element: A,
-      type: 'Type',
-    );
-  }
-
-  test_readWrite_assignment() async {
-    await assertNoErrorsInCode('''
-class A {
-  int foo = 0;
-}
-
-void f(A a) {
-  a.foo += 1;
-}
-''');
-
-    var assignment = findNode.assignment('foo += 1');
-    assertAssignment(
-      assignment,
-      readElement: findElement.getter('foo'),
-      readType: 'int',
-      writeElement: findElement.setter('foo'),
-      writeType: 'int',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int',
-    );
-
-    var prefixed = assignment.leftHandSide as PrefixedIdentifier;
-    if (hasAssignmentLeftResolution) {
-      assertPrefixedIdentifier(
-        prefixed,
-        element: findElement.setter('foo'),
-        type: 'int',
-      );
-    }
-
-    assertSimpleIdentifier(
-      prefixed.prefix,
-      element: findElement.parameter('a'),
-      type: 'A',
-    );
-
-    assertSimpleIdentifierAssignmentTarget(
-      prefixed.identifier,
-    );
-  }
-
-  test_write() async {
-    await assertNoErrorsInCode('''
-class A {
-  int foo = 0;
-}
-
-void f(A a) {
-  a.foo = 1;
-}
-''');
-
-    var assignment = findNode.assignment('foo = 1');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('foo'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
-
-    var prefixed = assignment.leftHandSide as PrefixedIdentifier;
-    if (hasAssignmentLeftResolution) {
-      assertPrefixedIdentifier(
-        prefixed,
-        element: findElement.setter('foo'),
-        type: 'int',
-      );
-    }
-
-    assertSimpleIdentifier(
-      prefixed.prefix,
-      element: findElement.parameter('a'),
-      type: 'A',
-    );
-
-    assertSimpleIdentifierAssignmentTarget(
-      prefixed.identifier,
-    );
-  }
 }
 
 @reflectiveTest
diff --git a/pkg/analyzer/test/src/dart/resolution/property_access_test.dart b/pkg/analyzer/test/src/dart/resolution/property_access_test.dart
index d2faf92..5c75760 100644
--- a/pkg/analyzer/test/src/dart/resolution/property_access_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/property_access_test.dart
@@ -170,6 +170,90 @@
 
     assertType(findNode.cascade('foo?'), 'A?');
   }
+
+  test_ofEnum_read() async {
+    await assertNoErrorsInCode('''
+enum E {
+  v;
+  int get foo => 0;
+}
+
+void f(E e) {
+  (e).foo;
+}
+''');
+
+    var propertyAccess = findNode.propertyAccess('foo;');
+    assertPropertyAccess2(
+      propertyAccess,
+      element: findElement.getter('foo'),
+      type: 'int',
+    );
+
+    assertSimpleIdentifier(
+      propertyAccess.propertyName,
+      element: findElement.getter('foo'),
+      type: 'int',
+    );
+  }
+
+  test_ofEnum_read_fromMixin() async {
+    await assertNoErrorsInCode('''
+mixin M on Enum {
+  int get foo => 0;
+}
+
+enum E with M {
+  v;
+}
+
+void f(E e) {
+  (e).foo;
+}
+''');
+
+    var propertyAccess = findNode.propertyAccess('foo;');
+    assertPropertyAccess2(
+      propertyAccess,
+      element: findElement.getter('foo'),
+      type: 'int',
+    );
+
+    assertSimpleIdentifier(
+      propertyAccess.propertyName,
+      element: findElement.getter('foo'),
+      type: 'int',
+    );
+  }
+
+  test_ofEnum_write() async {
+    await assertNoErrorsInCode('''
+enum E {
+  v;
+  set foo(int _) {}
+}
+
+void f(E e) {
+  (e).foo = 1;
+}
+''');
+
+    var assignment = findNode.assignment('foo = 1');
+    assertAssignment(
+      assignment,
+      readElement: null,
+      readType: null,
+      writeElement: findElement.setter('foo'),
+      writeType: 'int',
+      operatorElement: null,
+      type: 'int',
+    );
+
+    var propertyAccess = assignment.leftHandSide as PropertyAccess;
+    assertSimpleIdentifierAssignmentTarget(
+      propertyAccess.propertyName,
+    );
+  }
 }
 
 mixin PropertyAccessResolutionTestCases on PubPackageResolutionTest {
diff --git a/pkg/analyzer/test/src/diagnostics/built_in_identifier_as_type_name_test.dart b/pkg/analyzer/test/src/diagnostics/built_in_identifier_as_type_name_test.dart
index 2a7e27d..71eb8e1 100644
--- a/pkg/analyzer/test/src/diagnostics/built_in_identifier_as_type_name_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/built_in_identifier_as_type_name_test.dart
@@ -23,6 +23,16 @@
     ]);
   }
 
+  test_enum() async {
+    await assertErrorsInCode('''
+enum as {
+  v
+}
+''', [
+      error(CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE_NAME, 5, 2),
+    ]);
+  }
+
   test_mixin() async {
     await assertErrorsInCode('''
 mixin as {}
diff --git a/pkg/analyzer/test/src/diagnostics/conflicting_generic_interfaces_test.dart b/pkg/analyzer/test/src/diagnostics/conflicting_generic_interfaces_test.dart
index 2754202..cfa5128 100644
--- a/pkg/analyzer/test/src/diagnostics/conflicting_generic_interfaces_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/conflicting_generic_interfaces_test.dart
@@ -176,6 +176,32 @@
     ]);
   }
 
+  test_enum_implements() async {
+    await assertErrorsInCode('''
+class I<T> {}
+class A implements I<int> {}
+class B implements I<String> {}
+enum E implements A, B {
+  v
+}
+''', [
+      error(CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES, 80, 1),
+    ]);
+  }
+
+  test_enum_with() async {
+    await assertErrorsInCode('''
+class I<T> {}
+mixin M1 implements I<int> {}
+mixin M2 implements I<String> {}
+enum E with M1, M2 {
+  v
+}
+''', [
+      error(CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES, 82, 1),
+    ]);
+  }
+
   test_mixin_on_implements() async {
     await assertErrorsInCode('''
 class I<T> {}
diff --git a/pkg/analyzer/test/src/diagnostics/implements_repeated_test.dart b/pkg/analyzer/test/src/diagnostics/implements_repeated_test.dart
index 1cf6c42..d9cdfa7 100644
--- a/pkg/analyzer/test/src/diagnostics/implements_repeated_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/implements_repeated_test.dart
@@ -61,6 +61,58 @@
     ]);
   }
 
+  test_enum_implements_2times() async {
+    await assertErrorsInCode(r'''
+class A {}
+enum E implements A, A { // ref
+  v
+}
+''', [
+      error(CompileTimeErrorCode.IMPLEMENTS_REPEATED, 32, 1),
+    ]);
+
+    var A = findElement.class_('A');
+    assertNamedType(findNode.namedType('A, A { // ref'), A, 'A');
+    assertNamedType(findNode.namedType('A { // ref'), A, 'A');
+  }
+
+  test_enum_implements_2times_viaTypeAlias() async {
+    await assertErrorsInCode(r'''
+class A {}
+typedef B = A;
+enum E implements A, B {
+  v
+}
+''', [
+      error(CompileTimeErrorCode.IMPLEMENTS_REPEATED, 47, 1),
+    ]);
+
+    assertNamedType(
+      findNode.namedType('A, B {'),
+      findElement.class_('A'),
+      'A',
+    );
+
+    assertNamedType(
+      findNode.namedType('B {'),
+      findElement.typeAlias('B'),
+      'A',
+    );
+  }
+
+  test_enum_implements_4times() async {
+    await assertErrorsInCode(r'''
+class A {} class C{}
+enum E implements A, A, A, A {
+  v
+}
+''', [
+      error(CompileTimeErrorCode.IMPLEMENTS_REPEATED, 42, 1),
+      error(CompileTimeErrorCode.IMPLEMENTS_REPEATED, 45, 1),
+      error(CompileTimeErrorCode.IMPLEMENTS_REPEATED, 48, 1),
+    ]);
+  }
+
   test_mixin_implements_2times() async {
     await assertErrorsInCode(r'''
 class A {}
diff --git a/pkg/analyzer/test/src/diagnostics/main_is_not_function_test.dart b/pkg/analyzer/test/src/diagnostics/main_is_not_function_test.dart
index 2060e25..93d3d37 100644
--- a/pkg/analyzer/test/src/diagnostics/main_is_not_function_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/main_is_not_function_test.dart
@@ -39,6 +39,17 @@
     ], legacy: []));
   }
 
+  test_enum() async {
+    await resolveTestCode('''
+enum main {
+  v
+}
+''');
+    assertErrorsInResult(expectedErrorsByNullability(nullable: [
+      error(CompileTimeErrorCode.MAIN_IS_NOT_FUNCTION, 5, 4),
+    ], legacy: []));
+  }
+
   test_function() async {
     await assertNoErrorsInCode('''
 void main() {}
diff --git a/pkg/analyzer/test/src/diagnostics/mixin_application_concrete_super_invoked_member_type_test.dart b/pkg/analyzer/test/src/diagnostics/mixin_application_concrete_super_invoked_member_type_test.dart
index 37dd4c5..4b37af3 100644
--- a/pkg/analyzer/test/src/diagnostics/mixin_application_concrete_super_invoked_member_type_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/mixin_application_concrete_super_invoked_member_type_test.dart
@@ -16,7 +16,7 @@
 @reflectiveTest
 class MixinApplicationConcreteSuperInvokedMemberTypeTest
     extends PubPackageResolutionTest {
-  test_method() async {
+  test_class_method() async {
     await assertErrorsInCode(r'''
 class I {
   void foo([int? p]) {}
@@ -46,7 +46,7 @@
     ]);
   }
 
-  test_method_OK_overriddenInMixin() async {
+  test_class_method_OK_overriddenInMixin() async {
     await assertNoErrorsInCode(r'''
 class A<T> {
   void remove(T x) {}
@@ -61,4 +61,35 @@
 class X<T> = A<T> with M<T>;
 ''');
   }
+
+  test_enum_method() async {
+    await assertErrorsInCode(r'''
+abstract class I {
+  void foo([int? p]);
+}
+
+mixin M1 {
+  void foo(int? p) {}
+}
+
+mixin M2 implements I {}
+
+mixin M3 on I {
+  void bar() {
+    super.foo(42);
+  }
+}
+
+enum E with M1, M2, M3 {
+  v;
+  void foo([int? p]) {}
+}
+''', [
+      error(
+          CompileTimeErrorCode
+              .MIXIN_APPLICATION_CONCRETE_SUPER_INVOKED_MEMBER_TYPE,
+          183,
+          2),
+    ]);
+  }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/mixin_application_no_concrete_super_invoked_member_test.dart b/pkg/analyzer/test/src/diagnostics/mixin_application_no_concrete_super_invoked_member_test.dart
index 71d5ed5..115f527 100644
--- a/pkg/analyzer/test/src/diagnostics/mixin_application_no_concrete_super_invoked_member_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/mixin_application_no_concrete_super_invoked_member_test.dart
@@ -16,7 +16,7 @@
 @reflectiveTest
 class MixinApplicationNoConcreteSuperInvokedMemberTest
     extends PubPackageResolutionTest {
-  test_getter() async {
+  test_class_getter() async {
     await assertErrorsInCode(r'''
 abstract class A {
   int get foo;
@@ -38,7 +38,7 @@
     ]);
   }
 
-  test_inNextMixin() async {
+  test_class_inNextMixin() async {
     await assertErrorsInCode('''
 abstract class A {
   void foo();
@@ -64,7 +64,7 @@
     ]);
   }
 
-  test_inSameMixin() async {
+  test_class_inSameMixin() async {
     await assertErrorsInCode('''
 abstract class A {
   void foo();
@@ -86,7 +86,7 @@
     ]);
   }
 
-  test_method() async {
+  test_class_method() async {
     await assertErrorsInCode(r'''
 abstract class A {
   void foo();
@@ -108,7 +108,7 @@
     ]);
   }
 
-  test_OK_hasNSM() async {
+  test_class_OK_hasNSM() async {
     await assertNoErrorsInCode(r'''
 abstract class A {
   void foo();
@@ -128,7 +128,7 @@
 ''');
   }
 
-  test_OK_hasNSM2() async {
+  test_class_OK_hasNSM2() async {
     await assertNoErrorsInCode(r'''
 abstract class A {
   void foo();
@@ -152,7 +152,7 @@
 ''');
   }
 
-  test_OK_inPreviousMixin() async {
+  test_class_OK_inPreviousMixin() async {
     await assertNoErrorsInCode(r'''
 abstract class A {
   void foo();
@@ -172,7 +172,7 @@
 ''');
   }
 
-  test_OK_inSuper_fromMixin() async {
+  test_class_OK_inSuper_fromMixin() async {
     await assertNoErrorsInCode(r'''
 abstract class A {
   void foo();
@@ -194,7 +194,7 @@
 ''');
   }
 
-  test_OK_notInvoked() async {
+  test_class_OK_notInvoked() async {
     await assertNoErrorsInCode(r'''
 abstract class A {
   void foo();
@@ -206,7 +206,7 @@
 ''');
   }
 
-  test_OK_super_covariant() async {
+  test_class_OK_super_covariant() async {
     await assertNoErrorsInCode(r'''
 class A {
   bar(num n) {}
@@ -226,7 +226,7 @@
 ''');
   }
 
-  test_setter() async {
+  test_class_setter() async {
     await assertErrorsInCode(r'''
 abstract class A {
   void set foo(_);
@@ -247,4 +247,97 @@
           1),
     ]);
   }
+
+  test_enum_getter() async {
+    await assertErrorsInCode(r'''
+mixin M1 {
+  int get foo;
+}
+
+mixin M2 on M1 {
+  void bar() {
+    super.foo;
+  }
+}
+
+enum E with M1, M2 {
+  v;
+  int get foo => 0;
+}
+''', [
+      error(
+          CompileTimeErrorCode
+              .MIXIN_APPLICATION_NO_CONCRETE_SUPER_INVOKED_MEMBER,
+          99,
+          2),
+    ]);
+  }
+
+  test_enum_method() async {
+    await assertErrorsInCode(r'''
+mixin M1 {
+  void foo();
+}
+
+mixin M2 on M1 {
+  void bar() {
+    super.foo();
+  }
+}
+
+enum E with M1, M2 {
+  v;
+  void foo() {}
+}
+''', [
+      error(
+          CompileTimeErrorCode
+              .MIXIN_APPLICATION_NO_CONCRETE_SUPER_INVOKED_MEMBER,
+          100,
+          2),
+    ]);
+  }
+
+  test_enum_OK_getter_inPreviousMixin() async {
+    await assertNoErrorsInCode(r'''
+mixin M1 {
+  int get foo => 0;
+}
+
+mixin M2 on M1 {
+  void bar() {
+    super.foo;
+  }
+}
+
+enum E with M1, M2 {
+  v;
+}
+''');
+  }
+
+  test_enum_setter() async {
+    await assertErrorsInCode(r'''
+mixin M1 {
+  set foo(int _);
+}
+
+mixin M2 on M1 {
+  void bar() {
+    super.foo = 0;
+  }
+}
+
+enum E with M1, M2 {
+  v;
+  set foo(int _) {}
+}
+''', [
+      error(
+          CompileTimeErrorCode
+              .MIXIN_APPLICATION_NO_CONCRETE_SUPER_INVOKED_MEMBER,
+          106,
+          2),
+    ]);
+  }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/mixin_application_not_implemented_interface_test.dart b/pkg/analyzer/test/src/diagnostics/mixin_application_not_implemented_interface_test.dart
index 9354651a..8fb3ea2 100644
--- a/pkg/analyzer/test/src/diagnostics/mixin_application_not_implemented_interface_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/mixin_application_not_implemented_interface_test.dart
@@ -16,20 +16,16 @@
 @reflectiveTest
 class MixinApplicationNotImplementedInterfaceTest
     extends PubPackageResolutionTest {
-  test_generic() async {
-    await assertErrorsInCode(r'''
-class A<T> {}
-
-mixin M on A<int> {}
-
-class X = A<double> with M;
-''', [
-      error(CompileTimeErrorCode.MIXIN_APPLICATION_NOT_IMPLEMENTED_INTERFACE,
-          62, 1),
-    ]);
+  test_class_matchingInterface() async {
+    await assertNoErrorsInCode('''
+abstract class A<T> {}
+class B {}
+mixin M<T> on A<T> {}
+class C extends A<int> with M {}
+''');
   }
 
-  test_matchingClass_inPreviousMixin_new_syntax() async {
+  test_class_matchingInterface_inPreviousMixin() async {
     await assertNoErrorsInCode('''
 abstract class A<T> {}
 class B {}
@@ -39,28 +35,7 @@
 ''');
   }
 
-  test_matchingClass_new_syntax() async {
-    await assertNoErrorsInCode('''
-abstract class A<T> {}
-class B {}
-mixin M<T> on A<T> {}
-class C extends A<int> with M {}
-''');
-  }
-
-  test_noMatchingClass_namedMixinApplication_new_syntax() async {
-    await assertErrorsInCode('''
-abstract class A<T> {}
-class B {}
-mixin M<T> on A<T> {}
-class C = Object with M;
-''', [
-      error(CompileTimeErrorCode.MIXIN_APPLICATION_NOT_IMPLEMENTED_INTERFACE,
-          78, 1),
-    ]);
-  }
-
-  test_noMatchingClass_new_syntax() async {
+  test_class_noMatchingInterface() async {
     await assertErrorsInCode('''
 abstract class A<T> {}
 class B {}
@@ -72,16 +47,7 @@
     ]);
   }
 
-  test_noMatchingClass_noSuperclassConstraint_new_syntax() async {
-    await assertNoErrorsInCode('''
-abstract class A<T> {}
-class B {}
-mixin M<T> {}
-class C extends Object with M {}
-''');
-  }
-
-  test_noMatchingClass_typeParametersSupplied_new_syntax() async {
+  test_class_noMatchingInterface_withTypeArguments() async {
     await assertErrorsInCode('''
 abstract class A<T> {}
 class B {}
@@ -93,7 +59,7 @@
     ]);
   }
 
-  test_noMemberErrors() async {
+  test_class_noMemberErrors() async {
     await assertErrorsInCode(r'''
 class A {
   void foo() {}
@@ -116,77 +82,16 @@
     ]);
   }
 
-  test_notGeneric() async {
-    await assertErrorsInCode(r'''
-class A {}
-
-mixin M on A {}
-
-class X = Object with M;
-''', [
-      error(CompileTimeErrorCode.MIXIN_APPLICATION_NOT_IMPLEMENTED_INTERFACE,
-          51, 1),
-    ]);
-  }
-
-  test_OK_0() async {
-    await assertNoErrorsInCode(r'''
-mixin M {}
-
-class X = Object with M;
-''');
-  }
-
-  test_OK_1() async {
-    await assertNoErrorsInCode(r'''
-class A {}
-
-mixin M on A {}
-
-class X = A with M;
-''');
-  }
-
-  test_OK_generic() async {
-    await assertNoErrorsInCode(r'''
-class A<T> {}
-
-mixin M<T> on A<T> {}
-
-class B<T> implements A<T> {}
-
-class C<T> = B<T> with M<T>;
-''');
-  }
-
-  test_OK_previousMixin() async {
-    await assertNoErrorsInCode(r'''
-class A {}
-
-mixin M1 implements A {}
-
-mixin M2 on A {}
-
-class X = Object with M1, M2;
-''');
-  }
-
-  test_oneOfTwo() async {
-    await assertErrorsInCode(r'''
-class A {}
+  test_class_noSuperclassConstraint() async {
+    await assertNoErrorsInCode('''
+abstract class A<T> {}
 class B {}
-class C {}
-
-mixin M on A, B {}
-
-class X = C with M;
-''', [
-      error(CompileTimeErrorCode.MIXIN_APPLICATION_NOT_IMPLEMENTED_INTERFACE,
-          71, 1),
-    ]);
+mixin M<T> {}
+class C extends Object with M {}
+''');
   }
 
-  test_recursiveSubtypeCheck_new_syntax() async {
+  test_class_recursiveSubtypeCheck() async {
     // See dartbug.com/32353 for a detailed explanation.
     await assertErrorsInCode('''
 class ioDirectory implements ioFileSystemEntity {}
@@ -220,4 +125,138 @@
         result.unit.declaredElement!.getType('_LocalDirectory')!.mixins;
     assertType(mixins[0], 'ForwardingDirectory<_LocalDirectory>');
   }
+
+  test_classTypeAlias_generic() async {
+    await assertErrorsInCode(r'''
+class A<T> {}
+
+mixin M on A<int> {}
+
+class X = A<double> with M;
+''', [
+      error(CompileTimeErrorCode.MIXIN_APPLICATION_NOT_IMPLEMENTED_INTERFACE,
+          62, 1),
+    ]);
+  }
+
+  test_classTypeAlias_noMatchingInterface() async {
+    await assertErrorsInCode('''
+abstract class A<T> {}
+class B {}
+mixin M<T> on A<T> {}
+class C = Object with M;
+''', [
+      error(CompileTimeErrorCode.MIXIN_APPLICATION_NOT_IMPLEMENTED_INTERFACE,
+          78, 1),
+    ]);
+  }
+
+  test_classTypeAlias_notGeneric() async {
+    await assertErrorsInCode(r'''
+class A {}
+
+mixin M on A {}
+
+class X = Object with M;
+''', [
+      error(CompileTimeErrorCode.MIXIN_APPLICATION_NOT_IMPLEMENTED_INTERFACE,
+          51, 1),
+    ]);
+  }
+
+  test_classTypeAlias_OK_0() async {
+    await assertNoErrorsInCode(r'''
+mixin M {}
+
+class X = Object with M;
+''');
+  }
+
+  test_classTypeAlias_OK_1() async {
+    await assertNoErrorsInCode(r'''
+class A {}
+
+mixin M on A {}
+
+class X = A with M;
+''');
+  }
+
+  test_classTypeAlias_OK_generic() async {
+    await assertNoErrorsInCode(r'''
+class A<T> {}
+
+mixin M<T> on A<T> {}
+
+class B<T> implements A<T> {}
+
+class C<T> = B<T> with M<T>;
+''');
+  }
+
+  test_classTypeAlias_OK_previousMixin() async {
+    await assertNoErrorsInCode(r'''
+class A {}
+
+mixin M1 implements A {}
+
+mixin M2 on A {}
+
+class X = Object with M1, M2;
+''');
+  }
+
+  test_classTypeAlias_oneOfTwo() async {
+    await assertErrorsInCode(r'''
+class A {}
+class B {}
+class C {}
+
+mixin M on A, B {}
+
+class X = C with M;
+''', [
+      error(CompileTimeErrorCode.MIXIN_APPLICATION_NOT_IMPLEMENTED_INTERFACE,
+          71, 1),
+    ]);
+  }
+
+  test_enum_matchingInterface_inPreviousMixin() async {
+    await assertNoErrorsInCode('''
+abstract class A {}
+
+mixin M1 implements A {}
+
+mixin M2 on A {}
+
+enum E with M1, M2 {
+  v
+}
+''');
+  }
+
+  test_enum_noMatchingInterface() async {
+    await assertErrorsInCode('''
+abstract class A {}
+
+mixin M on A {}
+
+enum E with M {
+  v
+}
+''', [
+      error(CompileTimeErrorCode.MIXIN_APPLICATION_NOT_IMPLEMENTED_INTERFACE,
+          50, 1),
+    ]);
+  }
+
+  test_enum_noSuperclassConstraint() async {
+    await assertNoErrorsInCode('''
+mixin M {}
+
+enum E with M {
+  v;
+}
+''');
+  }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/mixin_class_declares_constructor_test.dart b/pkg/analyzer/test/src/diagnostics/mixin_class_declares_constructor_test.dart
index baece03..c826797 100644
--- a/pkg/analyzer/test/src/diagnostics/mixin_class_declares_constructor_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/mixin_class_declares_constructor_test.dart
@@ -15,7 +15,7 @@
 
 @reflectiveTest
 class MixinClassDeclaresConstructorTest extends PubPackageResolutionTest {
-  test_classDeclaration() async {
+  test_class() async {
     await assertErrorsInCode(
       r'''
 class A {
@@ -29,7 +29,7 @@
     );
   }
 
-  test_typeAlias() async {
+  test_classTypeAlias() async {
     await assertErrorsInCode(
       r'''
 class A {
@@ -42,4 +42,21 @@
       ],
     );
   }
+
+  test_enum() async {
+    await assertErrorsInCode(
+      r'''
+class A {
+  A() {}
+}
+
+enum E with A {
+  v
+}
+''',
+      [
+        error(CompileTimeErrorCode.MIXIN_CLASS_DECLARES_CONSTRUCTOR, 34, 1),
+      ],
+    );
+  }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/mixin_deferred_class_test.dart b/pkg/analyzer/test/src/diagnostics/mixin_deferred_class_test.dart
index a9bccb9..b8a8c67 100644
--- a/pkg/analyzer/test/src/diagnostics/mixin_deferred_class_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/mixin_deferred_class_test.dart
@@ -30,6 +30,20 @@
     ]);
   }
 
+  test_enum() async {
+    newFile('$testPackageLibPath/a.dart', content: '''
+class A {}
+''');
+    await assertErrorsInCode('''
+import 'a.dart' deferred as a;
+enum E with a.A {
+  v;
+}
+''', [
+      error(CompileTimeErrorCode.MIXIN_DEFERRED_CLASS, 43, 3),
+    ]);
+  }
+
   test_mixin_deferred_class() async {
     newFile('$testPackageLibPath/lib1.dart', content: '''
 library lib1;
diff --git a/pkg/analyzer/test/src/diagnostics/mixin_inherits_from_not_object_test.dart b/pkg/analyzer/test/src/diagnostics/mixin_inherits_from_not_object_test.dart
index 5af77a8..7fff8ae 100644
--- a/pkg/analyzer/test/src/diagnostics/mixin_inherits_from_not_object_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/mixin_inherits_from_not_object_test.dart
@@ -15,54 +15,7 @@
 
 @reflectiveTest
 class MixinInheritsFromNotObjectTest extends PubPackageResolutionTest {
-  test_classAlias_class_extends() async {
-    await assertErrorsInCode(r'''
-class A {}
-class B extends A {}
-class C = Object with B;
-''', [
-      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 54, 1),
-    ]);
-  }
-
-  test_classAlias_class_with() async {
-    await assertErrorsInCode(r'''
-class A {}
-class B extends Object with A {}
-class C = Object with B;
-''', [
-      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 66, 1),
-    ]);
-  }
-
-  test_classAlias_classAlias_with() async {
-    await assertNoErrorsInCode(r'''
-class A {}
-class B = Object with A;
-class C = Object with B;
-''');
-  }
-
-  test_classAlias_classAlias_with2() async {
-    await assertErrorsInCode(r'''
-class A {}
-class B {}
-class C = Object with A, B;
-class D = Object with C;
-''', [
-      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 72, 1),
-    ]);
-  }
-
-  test_classAlias_mixin() async {
-    await assertNoErrorsInCode(r'''
-class A {}
-mixin B on A {}
-class C = A with B;
-''');
-  }
-
-  test_classDeclaration_class_extends() async {
+  test_class_class_extends() async {
     await assertErrorsInCode(r'''
 class A {}
 class B extends A {}
@@ -72,7 +25,7 @@
     ]);
   }
 
-  test_classDeclaration_class_extends_Object() async {
+  test_class_class_extends_Object() async {
     await assertNoErrorsInCode(r'''
 class A {}
 class B extends Object {}
@@ -80,7 +33,7 @@
 ''');
   }
 
-  test_classDeclaration_class_with() async {
+  test_class_class_with() async {
     await assertErrorsInCode(r'''
 class A {}
 class B extends Object with A {}
@@ -90,7 +43,7 @@
     ]);
   }
 
-  test_classDeclaration_classAlias_with() async {
+  test_class_classTypeAlias_with() async {
     await assertNoErrorsInCode(r'''
 class A {}
 class B = Object with A;
@@ -98,7 +51,7 @@
 ''');
   }
 
-  test_classDeclaration_classAlias_with2() async {
+  test_class_classTypeAlias_with2() async {
     await assertErrorsInCode(r'''
 class A {}
 class B {}
@@ -109,11 +62,115 @@
     ]);
   }
 
-  test_classDeclaration_mixin() async {
+  test_class_mixin() async {
     await assertNoErrorsInCode(r'''
 class A {}
 mixin B on A {}
 class C extends A with B {}
 ''');
   }
+
+  test_classTypeAlias_class_extends() async {
+    await assertErrorsInCode(r'''
+class A {}
+class B extends A {}
+class C = Object with B;
+''', [
+      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 54, 1),
+    ]);
+  }
+
+  test_classTypeAlias_class_with() async {
+    await assertErrorsInCode(r'''
+class A {}
+class B extends Object with A {}
+class C = Object with B;
+''', [
+      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 66, 1),
+    ]);
+  }
+
+  test_classTypeAlias_classAlias_with() async {
+    await assertNoErrorsInCode(r'''
+class A {}
+class B = Object with A;
+class C = Object with B;
+''');
+  }
+
+  test_classTypeAlias_classAlias_with2() async {
+    await assertErrorsInCode(r'''
+class A {}
+class B {}
+class C = Object with A, B;
+class D = Object with C;
+''', [
+      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 72, 1),
+    ]);
+  }
+
+  test_classTypeAlias_mixin() async {
+    await assertNoErrorsInCode(r'''
+class A {}
+mixin B on A {}
+class C = A with B;
+''');
+  }
+
+  test_enum_class_extends() async {
+    await assertErrorsInCode(r'''
+class A {}
+class B extends A {}
+enum E with B {
+  v
+}
+''', [
+      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 44, 1),
+    ]);
+  }
+
+  test_enum_class_extends_Object() async {
+    await assertNoErrorsInCode(r'''
+class A {}
+class B extends Object {}
+enum E with B {
+  v
+}
+''');
+  }
+
+  test_enum_class_with() async {
+    await assertErrorsInCode(r'''
+class A {}
+class B extends Object with A {}
+enum E with B {
+  v
+}
+''', [
+      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 56, 1),
+    ]);
+  }
+
+  test_enum_classTypeAlias_with() async {
+    await assertNoErrorsInCode(r'''
+class A {}
+class B = Object with A;
+enum E with B {
+  v
+}
+''');
+  }
+
+  test_enum_classTypeAlias_with2() async {
+    await assertErrorsInCode(r'''
+class A {}
+class B {}
+class C = Object with A, B;
+enum E with C {
+  v
+}
+''', [
+      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 62, 1),
+    ]);
+  }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/private_collision_in_mixin_application_test.dart b/pkg/analyzer/test/src/diagnostics/private_collision_in_mixin_application_test.dart
index 4ded8b3..60dea5a 100644
--- a/pkg/analyzer/test/src/diagnostics/private_collision_in_mixin_application_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/private_collision_in_mixin_application_test.dart
@@ -264,4 +264,107 @@
       error(CompileTimeErrorCode.PRIVATE_COLLISION_IN_MIXIN_APPLICATION, 35, 1),
     ]);
   }
+
+  test_enum_getter_mixinAndMixin() async {
+    newFile('$testPackageLibPath/a.dart', content: r'''
+mixin A {
+  int get _foo => 0;
+}
+
+mixin B {
+  int get _foo => 0;
+}
+''');
+
+    await assertErrorsInCode('''
+import 'a.dart';
+
+enum E with A, B {
+  v
+}
+''', [
+      error(CompileTimeErrorCode.PRIVATE_COLLISION_IN_MIXIN_APPLICATION, 33, 1),
+    ]);
+  }
+
+  test_enum_method_interfaceAndMixin_same() async {
+    newFile('$testPackageLibPath/a.dart', content: r'''
+mixin A {
+  void _foo() {}
+}
+''');
+
+    await assertNoErrorsInCode('''
+import 'a.dart';
+
+mixin B implements A {}
+enum E with B, A {
+  v
+}
+''');
+  }
+
+  test_enum_method_mixinAndMixin() async {
+    newFile('$testPackageLibPath/a.dart', content: r'''
+mixin A {
+  void _foo() {}
+}
+
+mixin B {
+  void _foo() {}
+}
+''');
+
+    await assertErrorsInCode('''
+import 'a.dart';
+
+enum E with A, B {
+  v
+}
+''', [
+      error(CompileTimeErrorCode.PRIVATE_COLLISION_IN_MIXIN_APPLICATION, 33, 1),
+    ]);
+  }
+
+  test_enum_method_staticAndInstanceElement() async {
+    newFile('$testPackageLibPath/a.dart', content: r'''
+mixin A {
+  static void _foo() {}
+}
+
+mixin B {
+  void _foo() {}
+}
+''');
+
+    await assertNoErrorsInCode('''
+import 'a.dart';
+
+enum E with A, B {
+  v
+}
+''');
+  }
+
+  test_enum_setter_mixinAndMixin() async {
+    newFile('$testPackageLibPath/a.dart', content: r'''
+mixin A {
+  set _foo(int _) {}
+}
+
+mixin B {
+  set _foo(int _) {}
+}
+''');
+
+    await assertErrorsInCode('''
+import 'a.dart';
+
+enum E with A, B {
+  v
+}
+''', [
+      error(CompileTimeErrorCode.PRIVATE_COLLISION_IN_MIXIN_APPLICATION, 33, 1),
+    ]);
+  }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/wrong_type_parameter_variance_in_superinterface_test.dart b/pkg/analyzer/test/src/diagnostics/wrong_type_parameter_variance_in_superinterface_test.dart
index 52b3fab..60db55e 100644
--- a/pkg/analyzer/test/src/diagnostics/wrong_type_parameter_variance_in_superinterface_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/wrong_type_parameter_variance_in_superinterface_test.dart
@@ -250,6 +250,76 @@
 ''');
   }
 
+  test_enum_implements_function_parameterType() async {
+    await assertErrorsInCode(r'''
+typedef F<X> = void Function(X);
+class A<X> {}
+enum E<X> implements A<F<X>> {
+  v
+}
+''', [
+      error(
+        CompileTimeErrorCode.WRONG_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE,
+        54,
+        1,
+      ),
+    ]);
+  }
+
+  test_enum_implements_function_returnType() async {
+    await assertNoErrorsInCode(r'''
+typedef F<X> = X Function();
+class A<X> {}
+enum E<X> implements A<F<X>> {
+  v
+}
+''');
+  }
+
+  test_enum_implements_withoutFunction() async {
+    await assertNoErrorsInCode(r'''
+class A<X> {}
+enum E<X> implements A<X> {
+  v
+}
+''');
+  }
+
+  test_enum_with_function_parameterType() async {
+    await assertErrorsInCode(r'''
+typedef F<X> = void Function(X);
+class A<X> {}
+enum E<X> with A<F<X>> {
+  v
+}
+''', [
+      error(
+        CompileTimeErrorCode.WRONG_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE,
+        54,
+        1,
+      ),
+    ]);
+  }
+
+  test_enum_with_function_returnType() async {
+    await assertNoErrorsInCode(r'''
+typedef F<X> = X Function();
+class A<X> {}
+enum E<X> with A<F<X>> {
+  v
+}
+''');
+  }
+
+  test_enum_with_withoutFunction() async {
+    await assertNoErrorsInCode(r'''
+class A<X> {}
+enum E<X> with A<X> {
+  v
+}
+''');
+  }
+
   test_mixin_implements_function_parameterType() async {
     await assertErrorsInCode(r'''
 typedef F<X> = void Function(X);
diff --git a/pkg/compiler/README.md b/pkg/compiler/README.md
index d7e7a1a..deb6c60 100644
--- a/pkg/compiler/README.md
+++ b/pkg/compiler/README.md
@@ -340,7 +340,7 @@
   compilation either because they are first-class in the language or because
   they are implicitly used to implement some features. These include:
 
-  * `lib/src/common_elements.dart`: provides an interface to lookup basic
+  * `lib/src/common/elements.dart`: provides an interface to lookup basic
     elements like the class of `Object`, `int`, `List`, and their corresponding
     interface types, constructors for symbols, annotations such as
     `@MirrorsUsed`, the `identical` function, etc. These are normally restricted
diff --git a/pkg/compiler/lib/src/common/codegen.dart b/pkg/compiler/lib/src/common/codegen.dart
index 3f766ba..16d9ed1 100644
--- a/pkg/compiler/lib/src/common/codegen.dart
+++ b/pkg/compiler/lib/src/common/codegen.dart
@@ -7,7 +7,7 @@
 import 'package:js_ast/src/precedence.dart' as js show PRIMARY;
 
 import '../common.dart';
-import '../common_elements.dart';
+import '../common/elements.dart';
 import '../constants/values.dart';
 import '../deferred_load/output_unit.dart';
 import '../elements/entities.dart';
diff --git a/pkg/compiler/lib/src/common_elements.dart b/pkg/compiler/lib/src/common/elements.dart
similarity index 98%
rename from pkg/compiler/lib/src/common_elements.dart
rename to pkg/compiler/lib/src/common/elements.dart
index cead301..734b23c 100644
--- a/pkg/compiler/lib/src/common_elements.dart
+++ b/pkg/compiler/lib/src/common/elements.dart
@@ -1,20 +1,18 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// TODO(sigmund): rename and move to common/elements.dart
-library dart2js.type_system;
+import '../common.dart';
+import '../constants/constant_system.dart' as constant_system;
+import '../constants/values.dart';
+import '../elements/entities.dart';
+import '../elements/types.dart';
+import '../inferrer/abstract_value_domain.dart';
+import '../js_backend/native_data.dart' show NativeBasicData;
+import '../js_model/locals.dart';
+import '../universe/selector.dart' show Selector;
 
-import 'common.dart';
-import 'common/names.dart' show Identifiers, Uris;
-import 'constants/constant_system.dart' as constant_system;
-import 'constants/values.dart';
-import 'elements/entities.dart';
-import 'elements/types.dart';
-import 'inferrer/abstract_value_domain.dart';
-import 'js_backend/native_data.dart' show NativeBasicData;
-import 'js_model/locals.dart';
-import 'universe/selector.dart' show Selector;
+import 'names.dart' show Identifiers, Uris;
 
 /// The common elements and types in Dart.
 abstract class CommonElements {
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 35d9f52..9bbada1 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -13,12 +13,12 @@
 
 import '../compiler_new.dart' as api;
 import 'backend_strategy.dart';
+import 'common.dart';
 import 'common/codegen.dart';
+import 'common/elements.dart' show ElementEnvironment;
 import 'common/names.dart' show Selectors;
 import 'common/tasks.dart' show CompilerTask, GenericTask, Measurer;
 import 'common/work.dart' show WorkItem;
-import 'common.dart';
-import 'common_elements.dart' show ElementEnvironment;
 import 'deferred_load/deferred_load.dart' show DeferredLoadTask;
 import 'deferred_load/output_unit.dart' show OutputUnitData;
 import 'deferred_load/program_split_constraints/nodes.dart' as psc
diff --git a/pkg/compiler/lib/src/constants/constant_system.dart b/pkg/compiler/lib/src/constants/constant_system.dart
index 4c3a3e7..2795e48 100644
--- a/pkg/compiler/lib/src/constants/constant_system.dart
+++ b/pkg/compiler/lib/src/constants/constant_system.dart
@@ -6,7 +6,7 @@
 /// compiled to JavaScript.
 library dart2js.constant_system;
 
-import '../common_elements.dart' show CommonElements;
+import '../common/elements.dart' show CommonElements;
 import '../elements/entities.dart';
 import '../elements/operators.dart';
 import '../elements/types.dart';
diff --git a/pkg/compiler/lib/src/constants/values.dart b/pkg/compiler/lib/src/constants/values.dart
index 86abfd0..885a8bc 100644
--- a/pkg/compiler/lib/src/constants/values.dart
+++ b/pkg/compiler/lib/src/constants/values.dart
@@ -5,7 +5,7 @@
 library dart2js.constants.values;
 
 import '../common.dart';
-import '../common_elements.dart';
+import '../common/elements.dart';
 import '../elements/entities.dart';
 import '../elements/types.dart';
 import '../deferred_load/output_unit.dart' show OutputUnit;
diff --git a/pkg/compiler/lib/src/deferred_load/deferred_load.dart b/pkg/compiler/lib/src/deferred_load/deferred_load.dart
index a48f290..503c1bb 100644
--- a/pkg/compiler/lib/src/deferred_load/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load/deferred_load.dart
@@ -276,11 +276,11 @@
 import 'output_unit.dart';
 
 import '../../compiler_new.dart' show OutputType;
+import '../common.dart';
+import '../common/elements.dart' show KElementEnvironment;
 import '../common/metrics.dart'
     show Metric, Metrics, CountMetric, DurationMetric;
 import '../common/tasks.dart' show CompilerTask;
-import '../common.dart';
-import '../common_elements.dart' show KElementEnvironment;
 import '../compiler.dart' show Compiler;
 import '../constants/values.dart' show ConstantValue;
 import '../elements/types.dart';
diff --git a/pkg/compiler/lib/src/deferred_load/entity_data_info.dart b/pkg/compiler/lib/src/deferred_load/entity_data_info.dart
index f3d9ecc..d61c350 100644
--- a/pkg/compiler/lib/src/deferred_load/entity_data_info.dart
+++ b/pkg/compiler/lib/src/deferred_load/entity_data_info.dart
@@ -9,7 +9,7 @@
 import 'entity_data.dart';
 
 import '../common.dart';
-import '../common_elements.dart' show CommonElements, KElementEnvironment;
+import '../common/elements.dart' show CommonElements, KElementEnvironment;
 import '../compiler.dart' show Compiler;
 import '../constants/values.dart'
     show ConstantValue, ConstructedConstantValue, InstantiationConstantValue;
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index ccbcbe5..f7c4faf 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -13,10 +13,10 @@
 
 import '../compiler_new.dart';
 import 'backend_strategy.dart';
+import 'common.dart';
+import 'common/elements.dart' show JElementEnvironment;
 import 'common/names.dart';
 import 'common/tasks.dart' show CompilerTask;
-import 'common.dart';
-import 'common_elements.dart' show JElementEnvironment;
 import 'compiler.dart' show Compiler;
 import 'constants/values.dart' show ConstantValue, InterceptorConstantValue;
 import 'deferred_load/output_unit.dart' show OutputUnit, deferredPartFileName;
diff --git a/pkg/compiler/lib/src/elements/types.dart b/pkg/compiler/lib/src/elements/types.dart
index 357a571..c93c535 100644
--- a/pkg/compiler/lib/src/elements/types.dart
+++ b/pkg/compiler/lib/src/elements/types.dart
@@ -2,8 +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 '../common/elements.dart';
 import '../common/names.dart';
-import '../common_elements.dart';
 import '../options.dart';
 import '../serialization/serialization.dart';
 import '../util/util.dart' show equalElements, equalSets, identicalElements;
diff --git a/pkg/compiler/lib/src/enqueue.dart b/pkg/compiler/lib/src/enqueue.dart
index ccea928..6c53667 100644
--- a/pkg/compiler/lib/src/enqueue.dart
+++ b/pkg/compiler/lib/src/enqueue.dart
@@ -6,11 +6,11 @@
 
 import 'dart:collection' show Queue;
 
+import 'common.dart';
 import 'common/codegen.dart';
+import 'common/elements.dart' show ElementEnvironment;
 import 'common/tasks.dart' show CompilerTask;
 import 'common/work.dart' show WorkItem;
-import 'common.dart';
-import 'common_elements.dart' show ElementEnvironment;
 import 'constants/values.dart';
 import 'compiler.dart' show Compiler;
 import 'elements/entities.dart';
diff --git a/pkg/compiler/lib/src/frontend_strategy.dart b/pkg/compiler/lib/src/frontend_strategy.dart
index 423a69b..1edd506 100644
--- a/pkg/compiler/lib/src/frontend_strategy.dart
+++ b/pkg/compiler/lib/src/frontend_strategy.dart
@@ -5,8 +5,8 @@
 library dart2js.frontend_strategy;
 
 import 'common.dart';
+import 'common/elements.dart';
 import 'common/tasks.dart';
-import 'common_elements.dart';
 import 'compiler.dart' show Compiler;
 import 'deferred_load/deferred_load.dart' show DeferredLoadTask;
 import 'elements/entities.dart';
diff --git a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
index aff7306..89caef1 100644
--- a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
+++ b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
@@ -7,10 +7,10 @@
 import '../../compiler_new.dart';
 import '../closure.dart';
 import '../common.dart';
+import '../common/elements.dart';
 import '../common/metrics.dart';
 import '../common/names.dart';
 import '../compiler.dart';
-import '../common_elements.dart';
 import '../constants/values.dart';
 import '../elements/entities.dart';
 import '../elements/names.dart';
diff --git a/pkg/compiler/lib/src/inferrer/powersets/powerset_bits.dart b/pkg/compiler/lib/src/inferrer/powersets/powerset_bits.dart
index 9557395..fd657bd 100644
--- a/pkg/compiler/lib/src/inferrer/powersets/powerset_bits.dart
+++ b/pkg/compiler/lib/src/inferrer/powersets/powerset_bits.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.
 
-import '../../common_elements.dart' show CommonElements;
+import '../../common/elements.dart' show CommonElements;
 import '../../constants/values.dart';
 import '../../elements/entities.dart';
 import '../../elements/names.dart';
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/masks.dart b/pkg/compiler/lib/src/inferrer/typemasks/masks.dart
index 999d317..c6e534b 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/masks.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/masks.dart
@@ -7,7 +7,7 @@
 import 'package:kernel/ast.dart' as ir;
 
 import '../../common.dart';
-import '../../common_elements.dart' show CommonElements;
+import '../../common/elements.dart' show CommonElements;
 import '../../constants/values.dart';
 import '../../elements/entities.dart';
 import '../../elements/names.dart';
diff --git a/pkg/compiler/lib/src/ir/element_map.dart b/pkg/compiler/lib/src/ir/element_map.dart
index f2b9a66..8e73cf4 100644
--- a/pkg/compiler/lib/src/ir/element_map.dart
+++ b/pkg/compiler/lib/src/ir/element_map.dart
@@ -6,7 +6,7 @@
 import 'package:kernel/core_types.dart' as ir;
 
 import '../common.dart';
-import '../common_elements.dart';
+import '../common/elements.dart';
 import '../elements/entities.dart';
 import '../elements/indexed.dart';
 import '../elements/types.dart';
diff --git a/pkg/compiler/lib/src/ir/types.dart b/pkg/compiler/lib/src/ir/types.dart
index f725d34..114b68c 100644
--- a/pkg/compiler/lib/src/ir/types.dart
+++ b/pkg/compiler/lib/src/ir/types.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.
 
-import '../common_elements.dart';
+import '../common/elements.dart';
 import '../elements/entities.dart';
 import '../elements/types.dart';
 import '../options.dart';
diff --git a/pkg/compiler/lib/src/js_backend/backend_impact.dart b/pkg/compiler/lib/src/js_backend/backend_impact.dart
index 170924c..977d2da 100644
--- a/pkg/compiler/lib/src/js_backend/backend_impact.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_impact.dart
@@ -4,8 +4,8 @@
 
 library dart2js.js_helpers.impact;
 
+import '../common/elements.dart' show CommonElements, ElementEnvironment;
 import '../common/names.dart';
-import '../common_elements.dart' show CommonElements, ElementEnvironment;
 import '../elements/types.dart' show InterfaceType;
 import '../elements/entities.dart';
 import '../universe/selector.dart';
diff --git a/pkg/compiler/lib/src/js_backend/backend_usage.dart b/pkg/compiler/lib/src/js_backend/backend_usage.dart
index ef67a46..23f8c73 100644
--- a/pkg/compiler/lib/src/js_backend/backend_usage.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_usage.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import '../common.dart';
-import '../common_elements.dart';
+import '../common/elements.dart';
 import '../elements/entities.dart';
 import '../elements/types.dart';
 import '../frontend_strategy.dart';
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 85d2323..15f9436 100644
--- a/pkg/compiler/lib/src/js_backend/checked_mode_helpers.dart
+++ b/pkg/compiler/lib/src/js_backend/checked_mode_helpers.dart
@@ -5,7 +5,7 @@
 // TODO(39733): This file exists now just to register the use of
 // 'boolConversionCheck'. Fix the registration and remove this file.
 
-import '../common_elements.dart';
+import '../common/elements.dart';
 import '../universe/call_structure.dart' show CallStructure;
 import '../universe/use.dart' show StaticUse;
 
diff --git a/pkg/compiler/lib/src/js_backend/codegen_listener.dart b/pkg/compiler/lib/src/js_backend/codegen_listener.dart
index 4a93bce..93c1745 100644
--- a/pkg/compiler/lib/src/js_backend/codegen_listener.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen_listener.dart
@@ -6,8 +6,8 @@
 
 import 'dart:collection';
 
+import '../common/elements.dart' show CommonElements, ElementEnvironment;
 import '../common/names.dart' show Identifiers;
-import '../common_elements.dart' show CommonElements, ElementEnvironment;
 import '../constants/values.dart';
 import '../elements/entities.dart';
 import '../elements/types.dart';
diff --git a/pkg/compiler/lib/src/js_backend/constant_emitter.dart b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
index d08b4a8..304694a 100644
--- a/pkg/compiler/lib/src/js_backend/constant_emitter.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import '../common.dart';
-import '../common_elements.dart';
+import '../common/elements.dart';
 import '../constants/constant_system.dart' as constant_system;
 import '../constants/values.dart';
 import '../elements/entities.dart';
diff --git a/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart b/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart
index efbc78d..fd88ef8 100644
--- a/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/custom_elements_analysis.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.
 
-import '../common_elements.dart';
+import '../common/elements.dart';
 import '../constants/constant_system.dart' as constant_system;
 import '../constants/values.dart';
 import '../elements/entities.dart';
diff --git a/pkg/compiler/lib/src/js_backend/deferred_holder_expression.dart b/pkg/compiler/lib/src/js_backend/deferred_holder_expression.dart
index a9aa753..30bf295 100644
--- a/pkg/compiler/lib/src/js_backend/deferred_holder_expression.dart
+++ b/pkg/compiler/lib/src/js_backend/deferred_holder_expression.dart
@@ -5,7 +5,7 @@
 import 'package:js_ast/src/precedence.dart' as js show PRIMARY;
 import 'package:front_end/src/api_unstable/dart2js.dart' show $A;
 
-import '../common_elements.dart' show JCommonElements;
+import '../common/elements.dart' show JCommonElements;
 import '../elements/entities.dart';
 import '../js/js.dart' as js;
 import '../serialization/serialization.dart';
diff --git a/pkg/compiler/lib/src/js_backend/enqueuer.dart b/pkg/compiler/lib/src/js_backend/enqueuer.dart
index 73ba934..768a940 100644
--- a/pkg/compiler/lib/src/js_backend/enqueuer.dart
+++ b/pkg/compiler/lib/src/js_backend/enqueuer.dart
@@ -6,10 +6,10 @@
 
 import 'dart:collection' show Queue;
 
+import '../common.dart';
+import '../common/elements.dart' show ElementEnvironment;
 import '../common/tasks.dart' show CompilerTask;
 import '../common/work.dart' show WorkItem;
-import '../common.dart';
-import '../common_elements.dart' show ElementEnvironment;
 import '../elements/entities.dart';
 import '../elements/types.dart';
 import '../enqueue.dart';
diff --git a/pkg/compiler/lib/src/js_backend/impact_transformer.dart b/pkg/compiler/lib/src/js_backend/impact_transformer.dart
index 6427bee..3a92051 100644
--- a/pkg/compiler/lib/src/js_backend/impact_transformer.dart
+++ b/pkg/compiler/lib/src/js_backend/impact_transformer.dart
@@ -7,7 +7,7 @@
 import '../universe/class_hierarchy.dart' show ClassHierarchyBuilder;
 
 import '../common.dart';
-import '../common_elements.dart';
+import '../common/elements.dart';
 import '../common/backend_api.dart' show ImpactTransformer;
 import '../common/codegen.dart' show CodegenImpact;
 import '../common/resolution.dart' show ResolutionImpact;
diff --git a/pkg/compiler/lib/src/js_backend/interceptor_data.dart b/pkg/compiler/lib/src/js_backend/interceptor_data.dart
index 956a0f3..0300e2d 100644
--- a/pkg/compiler/lib/src/js_backend/interceptor_data.dart
+++ b/pkg/compiler/lib/src/js_backend/interceptor_data.dart
@@ -4,9 +4,9 @@
 
 library js_backend.interceptor_data;
 
-import '../common/names.dart' show Identifiers;
-import '../common_elements.dart'
+import '../common/elements.dart'
     show CommonElements, KCommonElements, KElementEnvironment;
+import '../common/names.dart' show Identifiers;
 import '../elements/entities.dart';
 import '../elements/types.dart';
 import '../inferrer/abstract_value_domain.dart';
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index 83c7797..b8e9f66 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -12,11 +12,11 @@
 import '../closure.dart';
 import '../common.dart';
 import '../common/codegen.dart';
+import '../common/elements.dart' show JElementEnvironment;
 import '../common/names.dart' show Identifiers, Names, Selectors;
-import '../common_elements.dart' show JElementEnvironment;
 import '../constants/constant_system.dart' as constant_system;
 import '../constants/values.dart';
-import '../common_elements.dart' show CommonElements, ElementEnvironment;
+import '../common/elements.dart' show CommonElements, ElementEnvironment;
 import '../diagnostics/invariant.dart' show DEBUG_MODE;
 import '../elements/entities.dart';
 import '../elements/entity_utils.dart' as utils;
diff --git a/pkg/compiler/lib/src/js_backend/native_data.dart b/pkg/compiler/lib/src/js_backend/native_data.dart
index 1ef691d..2f77a5a 100644
--- a/pkg/compiler/lib/src/js_backend/native_data.dart
+++ b/pkg/compiler/lib/src/js_backend/native_data.dart
@@ -7,7 +7,7 @@
 import 'package:kernel/ast.dart' as ir;
 
 import '../common.dart';
-import '../common_elements.dart' show ElementEnvironment;
+import '../common/elements.dart' show ElementEnvironment;
 import '../elements/entities.dart';
 import '../ir/annotations.dart';
 import '../kernel/element_map.dart';
diff --git a/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart b/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
index 1ef96e6..915c542 100644
--- a/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
+++ b/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import '../common.dart';
-import '../common_elements.dart' show CommonElements;
+import '../common/elements.dart' show CommonElements;
 import '../common/names.dart' show Identifiers, Selectors;
 import '../elements/entities.dart';
 import '../inferrer/types.dart';
diff --git a/pkg/compiler/lib/src/js_backend/resolution_listener.dart b/pkg/compiler/lib/src/js_backend/resolution_listener.dart
index 0b220af..5e63dbe 100644
--- a/pkg/compiler/lib/src/js_backend/resolution_listener.dart
+++ b/pkg/compiler/lib/src/js_backend/resolution_listener.dart
@@ -4,8 +4,8 @@
 
 library js_backend.backend.resolution_listener;
 
+import '../common/elements.dart' show KCommonElements, KElementEnvironment;
 import '../common/names.dart' show Identifiers;
-import '../common_elements.dart' show KCommonElements, KElementEnvironment;
 import '../constants/values.dart';
 import '../deferred_load/deferred_load.dart';
 import '../elements/entities.dart';
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart
index ffbad60..f27a4c4 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart
@@ -5,9 +5,9 @@
 library js_backend.runtime_types;
 
 import '../common.dart';
-import '../common/names.dart' show Identifiers;
-import '../common_elements.dart'
+import '../common/elements.dart'
     show ElementEnvironment, JCommonElements, JElementEnvironment;
+import '../common/names.dart' show Identifiers;
 import '../elements/entities.dart';
 import '../elements/types.dart';
 import '../js/js.dart' as jsAst;
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 c2fea1a..75fa30e 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types_new.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types_new.dart
@@ -6,7 +6,7 @@
 
 import 'package:js_runtime/shared/recipe_syntax.dart';
 
-import '../common_elements.dart' show CommonElements, JCommonElements;
+import '../common/elements.dart' show CommonElements, JCommonElements;
 import '../elements/entities.dart';
 import '../elements/types.dart';
 import '../js/js.dart' as jsAst;
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 5f3b75b..253d438 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types_resolution.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types_resolution.dart
@@ -5,8 +5,8 @@
 library js_backend.runtime_types_resolution;
 
 import '../common.dart';
+import '../common/elements.dart' show CommonElements, ElementEnvironment;
 import '../common/names.dart' show Identifiers;
-import '../common_elements.dart' show CommonElements, ElementEnvironment;
 import '../elements/entities.dart';
 import '../elements/names.dart';
 import '../elements/types.dart';
diff --git a/pkg/compiler/lib/src/js_backend/specialized_checks.dart b/pkg/compiler/lib/src/js_backend/specialized_checks.dart
index 9a887aa..b81a547 100644
--- a/pkg/compiler/lib/src/js_backend/specialized_checks.dart
+++ b/pkg/compiler/lib/src/js_backend/specialized_checks.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.
 
-import '../common_elements.dart' show ElementEnvironment, JCommonElements;
+import '../common/elements.dart' show ElementEnvironment, JCommonElements;
 import '../deferred_load/output_unit.dart';
 import '../elements/entities.dart';
 import '../elements/types.dart';
diff --git a/pkg/compiler/lib/src/js_backend/type_reference.dart b/pkg/compiler/lib/src/js_backend/type_reference.dart
index e135ab8..d796de1 100644
--- a/pkg/compiler/lib/src/js_backend/type_reference.dart
+++ b/pkg/compiler/lib/src/js_backend/type_reference.dart
@@ -64,7 +64,7 @@
 import 'package:front_end/src/api_unstable/dart2js.dart'
     show $0, $9, $A, $Z, $_, $a, $z;
 
-import '../common_elements.dart' show CommonElements;
+import '../common/elements.dart' show CommonElements;
 import '../elements/types.dart';
 import '../js/js.dart' as js;
 import '../js_emitter/code_emitter_task.dart' show Emitter;
diff --git a/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
index 638d53d..31cb0a5 100644
--- a/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
@@ -7,8 +7,8 @@
 import 'package:js_runtime/shared/embedded_names.dart'
     show TearOffParametersPropertyNames;
 
+import '../common/elements.dart' show CommonElements;
 import '../common/names.dart' show Identifiers, Selectors;
-import '../common_elements.dart' show CommonElements;
 import '../constants/values.dart';
 import '../elements/entities.dart';
 import '../js/js.dart' as jsAst;
diff --git a/pkg/compiler/lib/src/js_emitter/instantiation_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/instantiation_stub_generator.dart
index 627dbe5..3ab380f 100644
--- a/pkg/compiler/lib/src/js_emitter/instantiation_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/instantiation_stub_generator.dart
@@ -4,7 +4,7 @@
 
 library dart2js.js_emitter.instantiation_stub_generator;
 
-import '../common_elements.dart' show JCommonElements, JElementEnvironment;
+import '../common/elements.dart' show JCommonElements, JElementEnvironment;
 import '../elements/entities.dart';
 import '../io/source_information.dart';
 import '../js/js.dart' as jsAst;
diff --git a/pkg/compiler/lib/src/js_emitter/interceptor_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/interceptor_stub_generator.dart
index b96d0e8..1324ece 100644
--- a/pkg/compiler/lib/src/js_emitter/interceptor_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/interceptor_stub_generator.dart
@@ -6,7 +6,7 @@
 
 import 'package:js_runtime/shared/embedded_names.dart' as embeddedNames;
 
-import '../common_elements.dart';
+import '../common/elements.dart';
 import '../constants/values.dart';
 import '../elements/entities.dart';
 import '../elements/types.dart' show InterfaceType;
diff --git a/pkg/compiler/lib/src/js_emitter/main_call_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/main_call_stub_generator.dart
index 2913bbe..724da21 100644
--- a/pkg/compiler/lib/src/js_emitter/main_call_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/main_call_stub_generator.dart
@@ -6,10 +6,10 @@
 
 import 'package:js_runtime/shared/embedded_names.dart' as embeddedNames;
 
+import '../common/elements.dart';
 import '../elements/entities.dart';
 import '../js/js.dart' as jsAst;
 import '../js/js.dart' show js;
-import '../common_elements.dart';
 
 import 'code_emitter_task.dart' show Emitter;
 
diff --git a/pkg/compiler/lib/src/js_emitter/model.dart b/pkg/compiler/lib/src/js_emitter/model.dart
index 706385f..39fa4eb 100644
--- a/pkg/compiler/lib/src/js_emitter/model.dart
+++ b/pkg/compiler/lib/src/js_emitter/model.dart
@@ -4,7 +4,7 @@
 
 library dart2js.new_js_emitter.model;
 
-import '../common_elements.dart';
+import '../common/elements.dart';
 import '../constants/values.dart' show ConstantValue;
 import '../deferred_load/output_unit.dart' show OutputUnit;
 import '../elements/entities.dart';
diff --git a/pkg/compiler/lib/src/js_emitter/native_emitter.dart b/pkg/compiler/lib/src/js_emitter/native_emitter.dart
index 857b67b..a288989 100644
--- a/pkg/compiler/lib/src/js_emitter/native_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/native_emitter.dart
@@ -5,7 +5,7 @@
 library dart2js.js_emitter.native_emitter;
 
 import '../common.dart';
-import '../common_elements.dart' show JCommonElements, JElementEnvironment;
+import '../common/elements.dart' show JCommonElements, JElementEnvironment;
 import '../elements/types.dart' show DartType, FunctionType;
 import '../elements/entities.dart';
 import '../js/js.dart' as jsAst;
diff --git a/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
index 022cd5a..fea65fb 100644
--- a/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
@@ -4,7 +4,7 @@
 
 library dart2js.js_emitter.parameter_stub_generator;
 
-import '../common_elements.dart' show JElementEnvironment;
+import '../common/elements.dart' show JElementEnvironment;
 import '../constants/values.dart';
 import '../elements/entities.dart';
 import '../elements/types.dart';
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
index 69dc9f4..d04ed4a 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
@@ -5,10 +5,10 @@
 library dart2js.js_emitter.program_builder;
 
 import '../../common.dart';
+import '../../common/elements.dart' show JCommonElements, JElementEnvironment;
 import '../../common/names.dart' show Names, Selectors;
 import '../../constants/values.dart'
     show ConstantValue, InterceptorConstantValue;
-import '../../common_elements.dart' show JCommonElements, JElementEnvironment;
 import '../../deferred_load/output_unit.dart'
     show deferredPartFileName, OutputUnit, OutputUnitData;
 import '../../elements/entities.dart';
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 ca7d511..011f679 100644
--- a/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
@@ -4,7 +4,7 @@
 
 library dart2js.js_emitter.runtime_type_generator;
 
-import '../common_elements.dart' show CommonElements;
+import '../common/elements.dart' show CommonElements;
 import '../deferred_load/output_unit.dart' show OutputUnit, OutputUnitData;
 import '../elements/entities.dart';
 import '../elements/types.dart';
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_merger.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_merger.dart
index faac415..6a92212 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_merger.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_merger.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:collection';
-import '../../common_elements.dart' show ElementEnvironment;
+import '../../common/elements.dart' show ElementEnvironment;
 import '../../deferred_load/output_unit.dart'
     show ImportDescription, OutputUnit, OutputUnitData, deferredPartFileName;
 import '../../elements/entities.dart';
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
index 16c003c..88049eb 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
@@ -34,10 +34,10 @@
 
 import '../../../compiler_new.dart';
 import '../../common.dart';
+import '../../common/elements.dart' show CommonElements, JElementEnvironment;
 import '../../common/tasks.dart';
 import '../../constants/values.dart'
     show ConstantValue, FunctionConstantValue, LateSentinelConstantValue;
-import '../../common_elements.dart' show CommonElements, JElementEnvironment;
 import '../../deferred_load/output_unit.dart' show OutputUnit;
 import '../../dump_info.dart';
 import '../../elements/entities.dart';
diff --git a/pkg/compiler/lib/src/js_model/element_map.dart b/pkg/compiler/lib/src/js_model/element_map.dart
index a7526f4..e87d834 100644
--- a/pkg/compiler/lib/src/js_model/element_map.dart
+++ b/pkg/compiler/lib/src/js_model/element_map.dart
@@ -5,8 +5,8 @@
 import 'package:kernel/ast.dart' as ir;
 
 import '../common.dart';
+import '../common/elements.dart' show JCommonElements, JElementEnvironment;
 import '../constants/values.dart';
-import '../common_elements.dart' show JCommonElements, JElementEnvironment;
 import '../elements/entities.dart';
 import '../elements/jumps.dart';
 import '../elements/names.dart';
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 ae9a0a0..8e1bf87 100644
--- a/pkg/compiler/lib/src/js_model/element_map_impl.dart
+++ b/pkg/compiler/lib/src/js_model/element_map_impl.dart
@@ -14,8 +14,8 @@
 
 import '../closure.dart' show BoxLocal, ThisLocal;
 import '../common.dart';
+import '../common/elements.dart';
 import '../common/names.dart';
-import '../common_elements.dart';
 import '../constants/values.dart';
 import '../deferred_load/output_unit.dart';
 import '../elements/entities.dart';
diff --git a/pkg/compiler/lib/src/js_model/js_strategy.dart b/pkg/compiler/lib/src/js_model/js_strategy.dart
index bfd0363..fa22c30 100644
--- a/pkg/compiler/lib/src/js_model/js_strategy.dart
+++ b/pkg/compiler/lib/src/js_model/js_strategy.dart
@@ -9,9 +9,9 @@
 import '../backend_strategy.dart';
 import '../common.dart';
 import '../common/codegen.dart';
+import '../common/elements.dart' show CommonElements, ElementEnvironment;
 import '../common/tasks.dart';
 import '../common/work.dart';
-import '../common_elements.dart' show CommonElements, ElementEnvironment;
 import '../compiler.dart';
 import '../deferred_load/output_unit.dart';
 import '../dump_info.dart';
diff --git a/pkg/compiler/lib/src/js_model/js_world.dart b/pkg/compiler/lib/src/js_model/js_world.dart
index 17fd5d2..1c45fd2 100644
--- a/pkg/compiler/lib/src/js_model/js_world.dart
+++ b/pkg/compiler/lib/src/js_model/js_world.dart
@@ -7,8 +7,8 @@
 
 import '../closure.dart';
 import '../common.dart';
+import '../common/elements.dart' show JCommonElements, JElementEnvironment;
 import '../common/names.dart';
-import '../common_elements.dart' show JCommonElements, JElementEnvironment;
 import '../deferred_load/output_unit.dart';
 import '../elements/entities.dart';
 import '../elements/entity_utils.dart' as utils;
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 1292491..a6f2b04 100644
--- a/pkg/compiler/lib/src/js_model/js_world_builder.dart
+++ b/pkg/compiler/lib/src/js_model/js_world_builder.dart
@@ -6,7 +6,7 @@
 
 import '../closure.dart';
 import '../common.dart';
-import '../common_elements.dart';
+import '../common/elements.dart';
 import '../constants/constant_system.dart' as constant_system;
 import '../constants/values.dart';
 import '../deferred_load/output_unit.dart';
diff --git a/pkg/compiler/lib/src/kernel/element_map.dart b/pkg/compiler/lib/src/kernel/element_map.dart
index e92452a..ac578ee 100644
--- a/pkg/compiler/lib/src/kernel/element_map.dart
+++ b/pkg/compiler/lib/src/kernel/element_map.dart
@@ -7,8 +7,8 @@
 import 'package:kernel/class_hierarchy.dart' as ir;
 import 'package:kernel/type_environment.dart' as ir;
 
+import '../common/elements.dart' show KCommonElements, KElementEnvironment;
 import '../constants/values.dart';
-import '../common_elements.dart' show KCommonElements, KElementEnvironment;
 import '../elements/entities.dart';
 import '../elements/names.dart';
 import '../elements/types.dart';
diff --git a/pkg/compiler/lib/src/kernel/element_map_impl.dart b/pkg/compiler/lib/src/kernel/element_map_impl.dart
index 7e4b112..2d8e7b6 100644
--- a/pkg/compiler/lib/src/kernel/element_map_impl.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart
@@ -15,9 +15,9 @@
 import 'package:kernel/type_environment.dart' as ir;
 
 import '../common.dart';
+import '../common/elements.dart';
 import '../common/names.dart';
 import '../common/resolution.dart';
-import '../common_elements.dart';
 import '../constants/values.dart';
 import '../elements/entities.dart';
 import '../elements/indexed.dart';
diff --git a/pkg/compiler/lib/src/kernel/kernel_impact.dart b/pkg/compiler/lib/src/kernel/kernel_impact.dart
index f45ec96..9df3e23 100644
--- a/pkg/compiler/lib/src/kernel/kernel_impact.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_impact.dart
@@ -8,7 +8,7 @@
 import '../common.dart';
 import '../common/names.dart';
 import '../common/resolution.dart';
-import '../common_elements.dart';
+import '../common/elements.dart';
 import '../constants/values.dart';
 import '../elements/entities.dart';
 import '../elements/types.dart';
diff --git a/pkg/compiler/lib/src/kernel/kernel_strategy.dart b/pkg/compiler/lib/src/kernel/kernel_strategy.dart
index 86fd3c3..bf63a26 100644
--- a/pkg/compiler/lib/src/kernel/kernel_strategy.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_strategy.dart
@@ -8,11 +8,11 @@
 
 import '../common.dart';
 import '../common/backend_api.dart';
+import '../common/elements.dart';
 import '../common/names.dart' show Uris;
 import '../common/resolution.dart';
 import '../common/tasks.dart';
 import '../common/work.dart';
-import '../common_elements.dart';
 import '../compiler.dart';
 import '../deferred_load/deferred_load.dart' show DeferredLoadTask;
 import '../elements/entities.dart';
diff --git a/pkg/compiler/lib/src/kernel/kernel_world.dart b/pkg/compiler/lib/src/kernel/kernel_world.dart
index 3c7d99a..14bbbff 100644
--- a/pkg/compiler/lib/src/kernel/kernel_world.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_world.dart
@@ -3,8 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import '../common.dart';
+import '../common/elements.dart';
 import '../common/names.dart';
-import '../common_elements.dart';
 import '../elements/entities.dart';
 import '../elements/types.dart';
 import '../js_backend/annotations.dart';
diff --git a/pkg/compiler/lib/src/kernel/native_basic_data.dart b/pkg/compiler/lib/src/kernel/native_basic_data.dart
index 014ceff..d058403 100644
--- a/pkg/compiler/lib/src/kernel/native_basic_data.dart
+++ b/pkg/compiler/lib/src/kernel/native_basic_data.dart
@@ -5,7 +5,7 @@
 import 'package:kernel/ast.dart' as ir;
 
 import '../common.dart';
-import '../common_elements.dart';
+import '../common/elements.dart';
 import '../constants/values.dart';
 import '../elements/entities.dart';
 import '../frontend_strategy.dart';
diff --git a/pkg/compiler/lib/src/kernel/no_such_method_resolver.dart b/pkg/compiler/lib/src/kernel/no_such_method_resolver.dart
index 2e347e0..606ea21 100644
--- a/pkg/compiler/lib/src/kernel/no_such_method_resolver.dart
+++ b/pkg/compiler/lib/src/kernel/no_such_method_resolver.dart
@@ -4,6 +4,7 @@
 
 part of dart2js.kernel.element_map;
 
+/// Interface for determining the form of a `noSuchMethod` implementation.
 class KernelNoSuchMethodResolver implements NoSuchMethodResolver {
   final KernelToElementMapImpl elementMap;
 
diff --git a/pkg/compiler/lib/src/native/behavior.dart b/pkg/compiler/lib/src/native/behavior.dart
index f59b9fd..eabde14 100644
--- a/pkg/compiler/lib/src/native/behavior.dart
+++ b/pkg/compiler/lib/src/native/behavior.dart
@@ -3,8 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import '../common.dart';
+import '../common/elements.dart' show CommonElements, ElementEnvironment;
 import '../constants/values.dart';
-import '../common_elements.dart' show CommonElements, ElementEnvironment;
 import '../elements/entities.dart';
 import '../elements/types.dart';
 import '../js/js.dart' as js;
diff --git a/pkg/compiler/lib/src/native/enqueue.dart b/pkg/compiler/lib/src/native/enqueue.dart
index 26ff0d0..1876079 100644
--- a/pkg/compiler/lib/src/native/enqueue.dart
+++ b/pkg/compiler/lib/src/native/enqueue.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.
 
-import '../common_elements.dart' show CommonElements, ElementEnvironment;
+import '../common/elements.dart' show CommonElements, ElementEnvironment;
 import '../elements/entities.dart';
 import '../elements/types.dart';
 import '../js_backend/native_data.dart' show NativeData;
diff --git a/pkg/compiler/lib/src/native/resolver.dart b/pkg/compiler/lib/src/native/resolver.dart
index a1a0d84..99f0ab8 100644
--- a/pkg/compiler/lib/src/native/resolver.dart
+++ b/pkg/compiler/lib/src/native/resolver.dart
@@ -5,7 +5,7 @@
 import 'package:kernel/ast.dart' as ir;
 
 import '../common.dart';
-import '../common_elements.dart' show KElementEnvironment;
+import '../common/elements.dart' show KElementEnvironment;
 import '../constants/values.dart';
 import '../elements/entities.dart';
 import '../elements/types.dart';
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 56dc39ec..37d2d3e 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -8,8 +8,8 @@
 import '../closure.dart';
 import '../common.dart';
 import '../common/codegen.dart' show CodegenRegistry;
+import '../common/elements.dart';
 import '../common/names.dart';
-import '../common_elements.dart';
 import '../constants/constant_system.dart' as constant_system;
 import '../constants/values.dart';
 import '../deferred_load/output_unit.dart';
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 5e44fa5..d54ffe8 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -8,13 +8,13 @@
 import 'package:front_end/src/api_unstable/dart2js.dart' show Link;
 
 import '../common.dart';
+import '../common/elements.dart' show JCommonElements;
 import '../common/metrics.dart';
 import '../common/names.dart';
 import '../common/codegen.dart' show CodegenRegistry;
 import '../common/tasks.dart' show Measurer, CompilerTask;
 import '../constants/constant_system.dart' as constant_system;
 import '../constants/values.dart';
-import '../common_elements.dart' show JCommonElements;
 import '../elements/entities.dart';
 import '../elements/jumps.dart';
 import '../elements/types.dart';
diff --git a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart b/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
index 4def583..b52be9d 100644
--- a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
+++ b/pkg/compiler/lib/src/ssa/interceptor_simplifier.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.
 
-import '../common_elements.dart' show CommonElements;
+import '../common/elements.dart' show CommonElements;
 import '../constants/values.dart';
 import '../elements/entities.dart';
 import '../inferrer/abstract_value_domain.dart';
diff --git a/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart b/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart
index ab0b1a6..ab80914 100644
--- a/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart
+++ b/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.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.
 
-import '../common_elements.dart' show JCommonElements;
+import '../common/elements.dart' show JCommonElements;
 import '../constants/constant_system.dart' as constant_system;
 import '../constants/values.dart';
 import '../elements/entities.dart';
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index 8c57682..fa96a89 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -6,7 +6,7 @@
 
 import '../closure.dart';
 import '../common.dart';
-import '../common_elements.dart';
+import '../common/elements.dart';
 import '../constants/constant_system.dart' as constant_system;
 import '../constants/values.dart';
 import '../elements/entities.dart';
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index 3b1f064..5ef83e7 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -4,11 +4,11 @@
 
 import '../common.dart';
 import '../common/codegen.dart' show CodegenRegistry;
+import '../common/elements.dart' show JCommonElements;
 import '../common/names.dart' show Selectors;
 import '../common/tasks.dart' show Measurer, CompilerTask;
 import '../constants/constant_system.dart' as constant_system;
 import '../constants/values.dart';
-import '../common_elements.dart' show JCommonElements;
 import '../elements/entities.dart';
 import '../elements/types.dart';
 import '../inferrer/abstract_value_domain.dart';
diff --git a/pkg/compiler/lib/src/ssa/ssa.dart b/pkg/compiler/lib/src/ssa/ssa.dart
index 39c3355..77182b9 100644
--- a/pkg/compiler/lib/src/ssa/ssa.dart
+++ b/pkg/compiler/lib/src/ssa/ssa.dart
@@ -6,8 +6,8 @@
 
 import '../backend_strategy.dart';
 import '../common.dart';
-import '../common_elements.dart' show CommonElements, JElementEnvironment;
 import '../common/codegen.dart' show CodegenResult, CodegenRegistry;
+import '../common/elements.dart' show CommonElements, JElementEnvironment;
 import '../common/tasks.dart' show CompilerTask, Measurer;
 import '../elements/entities.dart';
 import '../elements/types.dart';
diff --git a/pkg/compiler/lib/src/ssa/types.dart b/pkg/compiler/lib/src/ssa/types.dart
index 0d1a3b8..f72163a 100644
--- a/pkg/compiler/lib/src/ssa/types.dart
+++ b/pkg/compiler/lib/src/ssa/types.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.
 
-import '../common_elements.dart' show CommonElements;
+import '../common/elements.dart' show CommonElements;
 import '../elements/entities.dart';
 import '../elements/types.dart';
 import '../inferrer/abstract_value_domain.dart';
diff --git a/pkg/compiler/lib/src/ssa/types_propagation.dart b/pkg/compiler/lib/src/ssa/types_propagation.dart
index bd8c259..a8ff036 100644
--- a/pkg/compiler/lib/src/ssa/types_propagation.dart
+++ b/pkg/compiler/lib/src/ssa/types_propagation.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.
 
-import '../common_elements.dart' show CommonElements;
+import '../common/elements.dart' show CommonElements;
 import '../elements/entities.dart';
 import '../elements/types.dart';
 import '../inferrer/abstract_value_domain.dart';
diff --git a/pkg/compiler/lib/src/universe/class_hierarchy.dart b/pkg/compiler/lib/src/universe/class_hierarchy.dart
index df7ee72..295204e 100644
--- a/pkg/compiler/lib/src/universe/class_hierarchy.dart
+++ b/pkg/compiler/lib/src/universe/class_hierarchy.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import '../common.dart';
-import '../common_elements.dart';
+import '../common/elements.dart';
 import '../elements/entities.dart';
 import '../elements/types.dart' show InterfaceType;
 import '../serialization/serialization.dart';
diff --git a/pkg/compiler/lib/src/universe/codegen_world_builder.dart b/pkg/compiler/lib/src/universe/codegen_world_builder.dart
index 7299ebe..c41f8e3 100644
--- a/pkg/compiler/lib/src/universe/codegen_world_builder.dart
+++ b/pkg/compiler/lib/src/universe/codegen_world_builder.dart
@@ -5,8 +5,8 @@
 import 'dart:collection';
 
 import '../common.dart';
+import '../common/elements.dart';
 import '../common/names.dart' show Identifiers;
-import '../common_elements.dart';
 import '../constants/values.dart';
 import '../elements/entities.dart';
 import '../elements/types.dart';
diff --git a/pkg/compiler/lib/src/universe/resolution_world_builder.dart b/pkg/compiler/lib/src/universe/resolution_world_builder.dart
index ca69de6..3b3d0d37 100644
--- a/pkg/compiler/lib/src/universe/resolution_world_builder.dart
+++ b/pkg/compiler/lib/src/universe/resolution_world_builder.dart
@@ -3,8 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import '../common.dart';
+import '../common/elements.dart';
 import '../common/names.dart' show Identifiers, Names;
-import '../common_elements.dart';
 import '../constants/values.dart';
 import '../elements/entities.dart';
 import '../elements/types.dart';
diff --git a/pkg/compiler/lib/src/universe/world_builder.dart b/pkg/compiler/lib/src/universe/world_builder.dart
index 9352fa8..9470571 100644
--- a/pkg/compiler/lib/src/universe/world_builder.dart
+++ b/pkg/compiler/lib/src/universe/world_builder.dart
@@ -4,7 +4,7 @@
 
 library world_builder;
 
-import '../common_elements.dart';
+import '../common/elements.dart';
 import '../elements/entities.dart';
 import '../elements/names.dart';
 import '../elements/types.dart';
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index f3d9ab1..b5c4d4f 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -6,7 +6,7 @@
 
 import 'closure.dart';
 import 'common.dart';
-import 'common_elements.dart'
+import 'common/elements.dart'
     show
         JCommonElements,
         JElementEnvironment,
diff --git a/pkg/compiler/test/codegen/type_inference8_test.dart b/pkg/compiler/test/codegen/type_inference8_test.dart
index 252f2e4..7188c69 100644
--- a/pkg/compiler/test/codegen/type_inference8_test.dart
+++ b/pkg/compiler/test/codegen/type_inference8_test.dart
@@ -8,7 +8,7 @@
 
 import "package:async_helper/async_helper.dart";
 import "package:compiler/src/commandline_options.dart";
-import "package:compiler/src/common_elements.dart";
+import "package:compiler/src/common/elements.dart";
 import "package:compiler/src/compiler.dart";
 import "package:compiler/src/constants/values.dart";
 import "package:compiler/src/elements/entities.dart";
diff --git a/pkg/compiler/test/end_to_end/dill_loader_test.dart b/pkg/compiler/test/end_to_end/dill_loader_test.dart
index 46626f4..6cf4fb9 100644
--- a/pkg/compiler/test/end_to_end/dill_loader_test.dart
+++ b/pkg/compiler/test/end_to_end/dill_loader_test.dart
@@ -7,7 +7,7 @@
 import '../helpers/memory_compiler.dart';
 import 'package:async_helper/async_helper.dart';
 import 'package:compiler/src/apiimpl.dart' show CompilerImpl;
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/elements/entities.dart'
     show LibraryEntity, ClassEntity;
 import 'package:compiler/src/kernel/dart2js_target.dart';
diff --git a/pkg/compiler/test/end_to_end/modular_loader_test.dart b/pkg/compiler/test/end_to_end/modular_loader_test.dart
index b5819f0..6b5c882 100644
--- a/pkg/compiler/test/end_to_end/modular_loader_test.dart
+++ b/pkg/compiler/test/end_to_end/modular_loader_test.dart
@@ -7,7 +7,7 @@
 import '../helpers/memory_compiler.dart';
 import 'package:async_helper/async_helper.dart';
 import 'package:compiler/src/apiimpl.dart' show CompilerImpl;
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/elements/entities.dart'
     show LibraryEntity, ClassEntity;
 import 'package:compiler/src/kernel/dart2js_target.dart';
diff --git a/pkg/compiler/test/equivalence/id_equivalence_helper.dart b/pkg/compiler/test/equivalence/id_equivalence_helper.dart
index d0288ee..8a34cb9 100644
--- a/pkg/compiler/test/equivalence/id_equivalence_helper.dart
+++ b/pkg/compiler/test/equivalence/id_equivalence_helper.dart
@@ -10,7 +10,7 @@
 import 'package:_fe_analyzer_shared/src/testing/id_testing.dart';
 import 'package:compiler/src/common.dart';
 import 'package:compiler/compiler_new.dart';
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/elements/entities.dart';
diff --git a/pkg/compiler/test/generic_methods/generic_method_test.dart b/pkg/compiler/test/generic_methods/generic_method_test.dart
index 14a4038..119d58c 100644
--- a/pkg/compiler/test/generic_methods/generic_method_test.dart
+++ b/pkg/compiler/test/generic_methods/generic_method_test.dart
@@ -6,7 +6,7 @@
 
 import 'package:async_helper/async_helper.dart';
 import 'package:compiler/src/commandline_options.dart';
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/js/js.dart' as js;
diff --git a/pkg/compiler/test/helpers/compiler_helper.dart b/pkg/compiler/test/helpers/compiler_helper.dart
index 463d171..648db35 100644
--- a/pkg/compiler/test/helpers/compiler_helper.dart
+++ b/pkg/compiler/test/helpers/compiler_helper.dart
@@ -9,7 +9,7 @@
 import 'dart:async';
 import 'package:compiler/compiler_new.dart';
 import 'package:compiler/src/commandline_options.dart';
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/compiler.dart' show Compiler;
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/js_model/js_strategy.dart';
diff --git a/pkg/compiler/test/helpers/element_lookup.dart b/pkg/compiler/test/helpers/element_lookup.dart
index e72f0f6..0ff12c2 100644
--- a/pkg/compiler/test/helpers/element_lookup.dart
+++ b/pkg/compiler/test/helpers/element_lookup.dart
@@ -4,7 +4,7 @@
 
 // @dart = 2.7
 
-import 'package:compiler/src/common_elements.dart' show JElementEnvironment;
+import 'package:compiler/src/common/elements.dart' show JElementEnvironment;
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/elements/types.dart';
 import 'package:compiler/src/world.dart' show JClosedWorld;
diff --git a/pkg/compiler/test/helpers/program_lookup.dart b/pkg/compiler/test/helpers/program_lookup.dart
index 9e985f5..b575f55 100644
--- a/pkg/compiler/test/helpers/program_lookup.dart
+++ b/pkg/compiler/test/helpers/program_lookup.dart
@@ -4,7 +4,7 @@
 
 // @dart = 2.7
 
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/deferred_load/output_unit.dart';
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/js/js.dart' as js;
diff --git a/pkg/compiler/test/helpers/type_test_helper.dart b/pkg/compiler/test/helpers/type_test_helper.dart
index 90b3202..5fdd343 100644
--- a/pkg/compiler/test/helpers/type_test_helper.dart
+++ b/pkg/compiler/test/helpers/type_test_helper.dart
@@ -8,7 +8,7 @@
 
 import 'dart:async';
 import 'package:expect/expect.dart';
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/compiler.dart' show Compiler;
 import 'package:compiler/src/elements/types.dart';
diff --git a/pkg/compiler/test/inference/load_deferred_library_test.dart b/pkg/compiler/test/inference/load_deferred_library_test.dart
index 8c6e15e..8596c41 100644
--- a/pkg/compiler/test/inference/load_deferred_library_test.dart
+++ b/pkg/compiler/test/inference/load_deferred_library_test.dart
@@ -6,7 +6,7 @@
 
 import 'package:async_helper/async_helper.dart';
 import 'package:compiler/src/commandline_options.dart';
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/common/names.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/elements/entities.dart';
diff --git a/pkg/compiler/test/inference/powerset_bits2_test.dart b/pkg/compiler/test/inference/powerset_bits2_test.dart
index db5fe3d..de617b5 100644
--- a/pkg/compiler/test/inference/powerset_bits2_test.dart
+++ b/pkg/compiler/test/inference/powerset_bits2_test.dart
@@ -6,7 +6,7 @@
 
 import 'package:async_helper/async_helper.dart';
 import 'package:compiler/src/common.dart';
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/inferrer/powersets/powersets.dart';
 import 'package:compiler/src/inferrer/powersets/powerset_bits.dart';
diff --git a/pkg/compiler/test/inference/type_combination_test.dart b/pkg/compiler/test/inference/type_combination_test.dart
index 0588216..0d371ed 100644
--- a/pkg/compiler/test/inference/type_combination_test.dart
+++ b/pkg/compiler/test/inference/type_combination_test.dart
@@ -6,7 +6,7 @@
 
 import 'package:async_helper/async_helper.dart';
 import 'package:expect/expect.dart';
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/inferrer/abstract_value_domain.dart';
diff --git a/pkg/compiler/test/inference/type_mask_disjoint_test.dart b/pkg/compiler/test/inference/type_mask_disjoint_test.dart
index 519770c..bff1090 100644
--- a/pkg/compiler/test/inference/type_mask_disjoint_test.dart
+++ b/pkg/compiler/test/inference/type_mask_disjoint_test.dart
@@ -6,7 +6,7 @@
 
 import 'package:async_helper/async_helper.dart';
 import 'package:expect/expect.dart';
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/inferrer/abstract_value_domain.dart';
diff --git a/pkg/compiler/test/inference/type_mask_test.dart b/pkg/compiler/test/inference/type_mask_test.dart
index ea40214..2f5938d 100644
--- a/pkg/compiler/test/inference/type_mask_test.dart
+++ b/pkg/compiler/test/inference/type_mask_test.dart
@@ -6,7 +6,7 @@
 
 import 'package:async_helper/async_helper.dart';
 import 'package:compiler/src/common.dart';
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/inferrer/abstract_value_domain.dart';
 import 'package:compiler/src/inferrer/typemasks/masks.dart';
diff --git a/pkg/compiler/test/inlining/meta_annotations_test.dart b/pkg/compiler/test/inlining/meta_annotations_test.dart
index 4d59a1d..0551ccb 100644
--- a/pkg/compiler/test/inlining/meta_annotations_test.dart
+++ b/pkg/compiler/test/inlining/meta_annotations_test.dart
@@ -6,7 +6,7 @@
 
 import 'package:expect/expect.dart';
 import 'package:async_helper/async_helper.dart';
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/world.dart' show KClosedWorld;
diff --git a/pkg/compiler/test/jsinterop/internal_annotations_test.dart b/pkg/compiler/test/jsinterop/internal_annotations_test.dart
index 62deced..861aaf1 100644
--- a/pkg/compiler/test/jsinterop/internal_annotations_test.dart
+++ b/pkg/compiler/test/jsinterop/internal_annotations_test.dart
@@ -8,7 +8,7 @@
 
 import 'package:expect/expect.dart';
 import 'package:async_helper/async_helper.dart';
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/elements/entities.dart' show ClassEntity;
 import 'package:compiler/src/elements/names.dart';
diff --git a/pkg/compiler/test/jsinterop/world_test.dart b/pkg/compiler/test/jsinterop/world_test.dart
index 230873f..e1294d9 100644
--- a/pkg/compiler/test/jsinterop/world_test.dart
+++ b/pkg/compiler/test/jsinterop/world_test.dart
@@ -8,7 +8,7 @@
 
 import 'package:expect/expect.dart';
 import 'package:async_helper/async_helper.dart';
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/elements/entities.dart' show ClassEntity;
 import 'package:compiler/src/elements/names.dart';
diff --git a/pkg/compiler/test/model/cfe_constant_evaluation_test.dart b/pkg/compiler/test/model/cfe_constant_evaluation_test.dart
index 24c4a58..693dccb 100644
--- a/pkg/compiler/test/model/cfe_constant_evaluation_test.dart
+++ b/pkg/compiler/test/model/cfe_constant_evaluation_test.dart
@@ -10,7 +10,7 @@
 import 'package:async_helper/async_helper.dart';
 import 'package:expect/expect.dart';
 import 'package:compiler/src/commandline_options.dart';
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/constants/values.dart';
 import 'package:compiler/src/elements/entities.dart';
diff --git a/pkg/compiler/test/model/enqueuer_test.dart b/pkg/compiler/test/model/enqueuer_test.dart
index 9102ac5..87dcf5f 100644
--- a/pkg/compiler/test/model/enqueuer_test.dart
+++ b/pkg/compiler/test/model/enqueuer_test.dart
@@ -10,7 +10,7 @@
 import 'package:async_helper/async_helper.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/commandline_options.dart';
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/elements/names.dart';
 import 'package:compiler/src/elements/types.dart';
diff --git a/pkg/compiler/test/model/forwarding_stub_test.dart b/pkg/compiler/test/model/forwarding_stub_test.dart
index 0035c58..921e3ca 100644
--- a/pkg/compiler/test/model/forwarding_stub_test.dart
+++ b/pkg/compiler/test/model/forwarding_stub_test.dart
@@ -5,7 +5,7 @@
 // @dart = 2.7
 
 import 'package:async_helper/async_helper.dart';
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/world.dart';
diff --git a/pkg/compiler/test/model/native_test.dart b/pkg/compiler/test/model/native_test.dart
index ed2e47f..4ce0a28 100644
--- a/pkg/compiler/test/model/native_test.dart
+++ b/pkg/compiler/test/model/native_test.dart
@@ -6,7 +6,7 @@
 
 import 'dart:io';
 import 'package:async_helper/async_helper.dart';
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/world.dart';
 import 'package:expect/expect.dart';
diff --git a/pkg/compiler/test/model/no_such_method_enabled_test.dart b/pkg/compiler/test/model/no_such_method_enabled_test.dart
index df08980..ce01c8c 100644
--- a/pkg/compiler/test/model/no_such_method_enabled_test.dart
+++ b/pkg/compiler/test/model/no_such_method_enabled_test.dart
@@ -5,7 +5,7 @@
 // @dart = 2.7
 
 import 'package:async_helper/async_helper.dart';
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/js_backend/no_such_method_registry.dart';
diff --git a/pkg/compiler/test/model/open_world_test.dart b/pkg/compiler/test/model/open_world_test.dart
index 49c37fb..e694730 100644
--- a/pkg/compiler/test/model/open_world_test.dart
+++ b/pkg/compiler/test/model/open_world_test.dart
@@ -7,7 +7,7 @@
 import 'package:expect/expect.dart';
 import 'package:async_helper/async_helper.dart';
 import 'package:compiler/src/compiler.dart';
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/ir/static_type.dart';
 import 'package:compiler/src/js_backend/native_data.dart';
diff --git a/pkg/compiler/test/model/strong_mode_closed_world_test.dart b/pkg/compiler/test/model/strong_mode_closed_world_test.dart
index ba41687..76d847e 100644
--- a/pkg/compiler/test/model/strong_mode_closed_world_test.dart
+++ b/pkg/compiler/test/model/strong_mode_closed_world_test.dart
@@ -7,7 +7,7 @@
 import 'package:expect/expect.dart';
 import 'package:async_helper/async_helper.dart';
 import 'package:compiler/src/compiler.dart';
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/world.dart';
 import '../helpers/memory_compiler.dart';
diff --git a/pkg/compiler/test/model/strong_mode_impact_test.dart b/pkg/compiler/test/model/strong_mode_impact_test.dart
index 6daea56..fc045cc 100644
--- a/pkg/compiler/test/model/strong_mode_impact_test.dart
+++ b/pkg/compiler/test/model/strong_mode_impact_test.dart
@@ -9,7 +9,7 @@
 import 'package:compiler/src/common.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/commandline_options.dart';
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/elements/types.dart';
 import 'package:compiler/src/world.dart';
diff --git a/pkg/compiler/test/model/supermixin_test.dart b/pkg/compiler/test/model/supermixin_test.dart
index e347d70..b7b0ada 100644
--- a/pkg/compiler/test/model/supermixin_test.dart
+++ b/pkg/compiler/test/model/supermixin_test.dart
@@ -6,7 +6,7 @@
 
 import 'package:async_helper/async_helper.dart';
 import 'package:compiler/src/commandline_options.dart';
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/elements/entities.dart';
 import 'package:expect/expect.dart';
 import '../helpers/program_lookup.dart';
diff --git a/pkg/compiler/test/model/type_substitution_test.dart b/pkg/compiler/test/model/type_substitution_test.dart
index ff3aae1..d648263 100644
--- a/pkg/compiler/test/model/type_substitution_test.dart
+++ b/pkg/compiler/test/model/type_substitution_test.dart
@@ -9,7 +9,7 @@
 import 'package:expect/expect.dart';
 import 'package:async_helper/async_helper.dart';
 import 'package:compiler/src/commandline_options.dart';
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/elements/types.dart';
 import '../helpers/type_test_helper.dart';
diff --git a/pkg/compiler/test/model/world_test.dart b/pkg/compiler/test/model/world_test.dart
index bf49a4f..ce5f4cc 100644
--- a/pkg/compiler/test/model/world_test.dart
+++ b/pkg/compiler/test/model/world_test.dart
@@ -8,8 +8,8 @@
 
 import 'package:expect/expect.dart';
 import 'package:async_helper/async_helper.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/common/names.dart';
-import 'package:compiler/src/common_elements.dart';
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/universe/class_hierarchy.dart';
 import 'package:compiler/src/universe/class_set.dart';
diff --git a/pkg/compiler/test/rti/disable_rti_test.dart b/pkg/compiler/test/rti/disable_rti_test.dart
index e993dc6..01248a6 100644
--- a/pkg/compiler/test/rti/disable_rti_test.dart
+++ b/pkg/compiler/test/rti/disable_rti_test.dart
@@ -6,7 +6,7 @@
 
 import 'package:async_helper/async_helper.dart';
 import 'package:compiler/src/commandline_options.dart';
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/js_backend/runtime_types_resolution.dart';
diff --git a/pkg/compiler/test/rti/factory_call_test.dart b/pkg/compiler/test/rti/factory_call_test.dart
index e77adc2..714c425 100644
--- a/pkg/compiler/test/rti/factory_call_test.dart
+++ b/pkg/compiler/test/rti/factory_call_test.dart
@@ -5,7 +5,7 @@
 // @dart = 2.7
 
 import 'package:async_helper/async_helper.dart';
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/js_backend/runtime_types_resolution.dart';
diff --git a/pkg/compiler/test/rti/instance_call_test.dart b/pkg/compiler/test/rti/instance_call_test.dart
index 6b123c3..d7eacdc 100644
--- a/pkg/compiler/test/rti/instance_call_test.dart
+++ b/pkg/compiler/test/rti/instance_call_test.dart
@@ -6,7 +6,7 @@
 
 import 'package:async_helper/async_helper.dart';
 import 'package:compiler/src/commandline_options.dart';
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/elements/names.dart';
diff --git a/pkg/compiler/test/rti/rti_need_test_helper.dart b/pkg/compiler/test/rti/rti_need_test_helper.dart
index 50cb925..8973cd7 100644
--- a/pkg/compiler/test/rti/rti_need_test_helper.dart
+++ b/pkg/compiler/test/rti/rti_need_test_helper.dart
@@ -9,7 +9,7 @@
 import 'package:async_helper/async_helper.dart';
 import 'package:compiler/src/closure.dart';
 import 'package:compiler/src/common.dart';
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/elements/types.dart';
diff --git a/pkg/compiler/test/sourcemaps/name_test.dart b/pkg/compiler/test/sourcemaps/name_test.dart
index 5f2e197..fee442f 100644
--- a/pkg/compiler/test/sourcemaps/name_test.dart
+++ b/pkg/compiler/test/sourcemaps/name_test.dart
@@ -9,7 +9,7 @@
 import 'package:async_helper/async_helper.dart';
 import 'package:expect/expect.dart';
 import 'package:compiler/src/commandline_options.dart';
-import 'package:compiler/src/common_elements.dart' show JElementEnvironment;
+import 'package:compiler/src/common/elements.dart' show JElementEnvironment;
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/io/kernel_source_information.dart';
diff --git a/pkg/compiler/test/sourcemaps/tools/diff_view.dart b/pkg/compiler/test/sourcemaps/tools/diff_view.dart
index 9d245c3..ba9d49a 100644
--- a/pkg/compiler/test/sourcemaps/tools/diff_view.dart
+++ b/pkg/compiler/test/sourcemaps/tools/diff_view.dart
@@ -11,7 +11,7 @@
 import 'dart:io';
 
 import 'package:_fe_analyzer_shared/src/util/filenames.dart';
-import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/common/elements.dart';
 import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/diagnostics/invariant.dart';
 import 'package:compiler/src/elements/entities.dart';
diff --git a/pkg/dds/lib/src/devtools/memory_profile.dart b/pkg/dds/lib/src/devtools/memory_profile.dart
index da6fa61..03fe5c1 100644
--- a/pkg/dds/lib/src/devtools/memory_profile.dart
+++ b/pkg/dds/lib/src/devtools/memory_profile.dart
@@ -8,6 +8,7 @@
 import 'dart:async';
 import 'dart:io' as io;
 
+import 'package:collection/collection.dart';
 import 'package:devtools_shared/devtools_shared.dart';
 import 'package:vm_service/vm_service.dart';
 
@@ -227,9 +228,8 @@
         flutterViewListResponse.json!['views'].cast<Map<String, dynamic>>();
 
     // Each isolate should only have one FlutterView.
-    final flutterView = views.firstWhere(
+    final flutterView = views.firstWhereOrNull(
       (view) => view['type'] == 'FlutterView',
-      orElse: () => null,
     );
 
     if (flutterView == null) {
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 1e9bf59..2aef55f 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -234,7 +234,7 @@
 
 # Timeout. These tests do not run efficiently on our simulator or low-end
 # devices.
-[ $runtime == vm && ($arch == simarm || $arch == simarm64 || $arch == simarm64c) ]
+[ $runtime == vm && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ]
 *: Skip
 
 [ $mode == debug || $runtime != vm || $system == android ]
diff --git a/pkg/status_file/test/data/vm.status b/pkg/status_file/test/data/vm.status
index d04bfc5..1cd16ea 100644
--- a/pkg/status_file/test/data/vm.status
+++ b/pkg/status_file/test/data/vm.status
@@ -50,7 +50,7 @@
 # On the simluator stack traces produced by the Profiler do not match
 # up with the real Dart stack trace and hence we don't get correct
 # symbol names.
-[ $arch == simarm || $arch == simarm64 || $arch == simarm64c]
+[ $arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64]
 cc/Service_Profile: Skip
 cc/Profiler_AllocationSampleTest: Skip
 cc/Profiler_ArrayAllocation: Skip
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/enum_from_lib_used_as_type.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/enum_from_lib_used_as_type.dart.expect
index 7a6dc01..9c9d0a4 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/enum_from_lib_used_as_type.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/enum_from_lib_used_as_type.dart.expect
@@ -22,6 +22,6 @@
   synthetic constructor •() → self::Class
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3396,getterSelectorId:3397]  method method([@vm.inferred-type.metadata=dart.core::Null? (value: null)] self::Enum e) → core::int
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3395,getterSelectorId:3396]  method method([@vm.inferred-type.metadata=dart.core::Null? (value: null)] self::Enum e) → core::int
     return [@vm.inferred-type.metadata=!] e.{core::_Enum::index}{core::int};
 }
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/tree_shake_enum_from_lib.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/tree_shake_enum_from_lib.dart.expect
index 5bebd25..c4d4faf 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/tree_shake_enum_from_lib.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/tree_shake_enum_from_lib.dart.expect
@@ -51,6 +51,6 @@
   synthetic constructor •() → self::ConstClass
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3400,getterSelectorId:3401]  method method([@vm.inferred-type.metadata=dart.core::Null? (value: null)] self::ConstEnum e) → core::int
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3399,getterSelectorId:3400]  method method([@vm.inferred-type.metadata=dart.core::Null? (value: null)] self::ConstEnum e) → core::int
     return [@vm.inferred-type.metadata=!] e.{core::_Enum::index}{core::int};
 }
diff --git a/runtime/lib/math.cc b/runtime/lib/math.cc
index 59e2305..d13b2ef 100644
--- a/runtime/lib/math.cc
+++ b/runtime/lib/math.cc
@@ -22,91 +22,11 @@
   return Double::New(pow(operand, exponent));
 }
 
-// Returns the typed-data array store in '_Random._state' field.
-static TypedDataPtr GetRandomStateArray(const Instance& receiver) {
-  const Class& random_class = Class::Handle(receiver.clazz());
-  const Field& state_field =
-      Field::Handle(random_class.LookupFieldAllowPrivate(Symbols::_state()));
-  ASSERT(!state_field.IsNull());
-  const Instance& state_field_value =
-      Instance::Cast(Object::Handle(receiver.GetField(state_field)));
-  ASSERT(!state_field_value.IsNull());
-  ASSERT(state_field_value.IsTypedData());
-  const TypedData& array = TypedData::Cast(state_field_value);
-  ASSERT(array.Length() == 2);
-  ASSERT(array.ElementType() == kUint32ArrayElement);
-  return array.ptr();
-}
-
-// Implements:
-//   var state =
-//       ((_A * (_state[_kSTATE_LO])) + _state[_kSTATE_HI]) & (1 << 64) - 1);
-//   _state[_kSTATE_LO] = state & (1 << 32) - 1);
-//   _state[_kSTATE_HI] = state >> 32;
-DEFINE_NATIVE_ENTRY(Random_nextState, 0, 1) {
-  GET_NON_NULL_NATIVE_ARGUMENT(Instance, receiver, arguments->NativeArgAt(0));
-  const TypedData& array = TypedData::Handle(GetRandomStateArray(receiver));
-  const uint64_t state_lo = array.GetUint32(0);
-  const uint64_t state_hi = array.GetUint32(array.ElementSizeInBytes());
-  const uint64_t A = 0xffffda61;
-  uint64_t state = (A * state_lo) + state_hi;
-  array.SetUint32(0, static_cast<uint32_t>(state));
-  array.SetUint32(array.ElementSizeInBytes(),
-                  static_cast<uint32_t>(state >> 32));
-  return Object::null();
-}
-
-TypedDataPtr CreateRandomState(Zone* zone, uint64_t seed) {
-  const TypedData& result =
-      TypedData::Handle(zone, TypedData::New(kTypedDataUint32ArrayCid, 2));
-  result.SetUint32(0, static_cast<uint32_t>(seed));
-  result.SetUint32(result.ElementSizeInBytes(),
-                   static_cast<uint32_t>(seed >> 32));
-  return result.ptr();
-}
-
-uint64_t mix64(uint64_t n) {
-  // Thomas Wang 64-bit mix.
-  // http://www.concentric.net/~Ttwang/tech/inthash.htm
-  // via. http://web.archive.org/web/20071223173210/http://www.concentric.net/~Ttwang/tech/inthash.htm
-  n = (~n) + (n << 21);  // n = (n << 21) - n - 1;
-  n = n ^ (n >> 24);
-  n = n * 265;  // n = (n + (n << 3)) + (n << 8);
-  n = n ^ (n >> 14);
-  n = n * 21;  // n = (n + (n << 2)) + (n << 4);
-  n = n ^ (n >> 28);
-  n = n + (n << 31);
-  return n;
-}
-
-// Implements:
-//   uint64_t hash = 0;
-//   do {
-//      hash = hash * 1037 ^ mix64((uint64_t)seed);
-//      seed >>= 64;
-//   } while (seed != 0 && seed != -1);  // Limits if seed positive or negative.
-//   if (hash == 0) {
-//     hash = 0x5A17;
-//   }
-//   var result = new Uint32List(2);
-//   result[_kSTATE_LO] = seed & ((1 << 32) - 1);
-//   result[_kSTATE_HI] = seed >> 32;
-//   return result;
-DEFINE_NATIVE_ENTRY(Random_setupSeed, 0, 1) {
-  GET_NON_NULL_NATIVE_ARGUMENT(Integer, seed_int, arguments->NativeArgAt(0));
-  uint64_t seed = mix64(static_cast<uint64_t>(seed_int.AsInt64Value()));
-
-  if (seed == 0) {
-    seed = 0x5a17;
-  }
-  return CreateRandomState(zone, seed);
-}
-
 DEFINE_NATIVE_ENTRY(Random_initialSeed, 0, 0) {
   Random* rnd = isolate->random();
   uint64_t seed = rnd->NextUInt32();
   seed |= (static_cast<uint64_t>(rnd->NextUInt32()) << 32);
-  return CreateRandomState(zone, seed);
+  return Integer::New(seed);
 }
 
 DEFINE_NATIVE_ENTRY(SecureRandom_getBytes, 0, 1) {
diff --git a/runtime/observatory/tests/service/service.status b/runtime/observatory/tests/service/service.status
index ee2c8dc..0b85116 100644
--- a/runtime/observatory/tests/service/service.status
+++ b/runtime/observatory/tests/service/service.status
@@ -51,11 +51,11 @@
 [ $mode == debug && $system == windows && $checked ]
 async_scope_test: Pass, Slow
 
-[ $mode == debug && ($arch == simarm || $arch == simarm64 || $arch == simarm64c) ]
+[ $mode == debug && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ]
 *: SkipSlow
 
 # These tests are slow on simulators.
-[ $arch == simarm || $arch == simarm64 || $arch == simarm64c ]
+[ $arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64 ]
 *: Pass, Slow
 
 # All tests use dart:io
diff --git a/runtime/observatory/tests/service/service_kernel.status b/runtime/observatory/tests/service/service_kernel.status
index 95723e9..b358a82 100644
--- a/runtime/observatory/tests/service/service_kernel.status
+++ b/runtime/observatory/tests/service/service_kernel.status
@@ -277,7 +277,7 @@
 step_through_switch_test: Skip # Times out. Issue 32137.
 step_through_switch_with_continue_test: Skip # Times out. Issue 32137.
 
-[ $compiler == dartk && ($arch == simarm || $arch == simarm64 || $arch == simarm64c) ]
+[ $compiler == dartk && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ]
 add_breakpoint_rpc_kernel_test: RuntimeError # Issue #34736
 async_generator_breakpoint_test: SkipByDesign # No incremental compiler available.
 bad_reload_test: Skip # Times out on sim architectures, also RuntimeError.
diff --git a/runtime/observatory_2/tests/service_2/service_2.status b/runtime/observatory_2/tests/service_2/service_2.status
index c5a50bb..54c0328 100644
--- a/runtime/observatory_2/tests/service_2/service_2.status
+++ b/runtime/observatory_2/tests/service_2/service_2.status
@@ -54,11 +54,11 @@
 [ $mode == debug && $system == windows && $checked ]
 async_scope_test: Pass, Slow
 
-[ $mode == debug && ($arch == simarm || $arch == simarm64 || $arch == simarm64c) ]
+[ $mode == debug && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ]
 *: SkipSlow
 
 # These tests are slow on simulators.
-[ $arch == simarm || $arch == simarm64 || $arch == simarm64c ]
+[ $arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64 ]
 *: Pass, Slow
 
 # All tests use dart:io
diff --git a/runtime/observatory_2/tests/service_2/service_2_kernel.status b/runtime/observatory_2/tests/service_2/service_2_kernel.status
index b27568f..c64d881 100644
--- a/runtime/observatory_2/tests/service_2/service_2_kernel.status
+++ b/runtime/observatory_2/tests/service_2/service_2_kernel.status
@@ -277,7 +277,7 @@
 step_through_switch_test: Skip # Times out. Issue 32137.
 step_through_switch_with_continue_test: Skip # Times out. Issue 32137.
 
-[ $compiler == dartk && ($arch == simarm || $arch == simarm64 || $arch == simarm64c) ]
+[ $compiler == dartk && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ]
 add_breakpoint_rpc_kernel_test: RuntimeError # Issue #34736
 async_generator_breakpoint_test: SkipByDesign # No incremental compiler available.
 bad_reload_test: Skip # Times out on sim architectures, also RuntimeError.
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index fdb96d1..c850c6c 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -180,7 +180,7 @@
 dart/transferable_test: Skip # This is performance test and somehow debug win ia32 bot's performance is unpredictable
 dart_2/transferable_test: Skip # This is performance test and somehow debug win ia32 bot's performance is unpredictable
 
-[ $arch != simarm && $arch != simarm64 && $arch != simarm64c && $compiler == dartk && $hot_reload ]
+[ $arch != simarm && $arch != simarm64 && $arch != simarm64c && $arch != simriscv32 && $arch != simriscv64 && $compiler == dartk && $hot_reload ]
 dart/data_uri_import_test/base64: Crash
 dart/data_uri_import_test/nocharset: Crash
 dart/data_uri_import_test/nomime: Crash
@@ -211,7 +211,7 @@
 # Enabling of dartk for sim{arm,arm64} revelaed these test failures, which
 # are to be triaged.  Isolate tests are skipped on purpose due to the usage of
 # batch mode.
-[ $compiler == dartk && $mode == debug && ($arch == simarm || $arch == simarm64 || $arch == simarm64c) ]
+[ $compiler == dartk && $mode == debug && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ]
 cc/StackTraceMallocHookLengthTest: Fail # Please triage.
 
 [ $compiler == dartk && $mode == product && $runtime == vm ]
@@ -245,7 +245,7 @@
 [ $compiler == dartk && $system == windows ]
 cc/IsolateReload_LibraryLookup: Fail, Crash
 
-[ $compiler == dartk && ($arch == simarm || $arch == simarm64 || $arch == simarm64c) ]
+[ $compiler == dartk && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ]
 dart/appjit*: SkipSlow # DFE too slow
 dart/b162922506_test: SkipSlow # Generates large input file
 dart/data_uri_spawn_test: Skip # Please triage.
@@ -284,11 +284,11 @@
 dart/isolates/dart_api_create_lightweight_isolate_test: SkipByDesign # https://dartbug.com/40579 Dart C API symbols not available.
 dart_2/isolates/dart_api_create_lightweight_isolate_test: SkipByDesign # https://dartbug.com/40579 Dart C API symbols not available.
 
-[ $compiler == dartkp && ($arch == simarm || $arch == simarm64 || $arch == simarm64c) ]
+[ $compiler == dartkp && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ]
 dart/causal_stacks/async_throws_stack_lazy_non_symbolic_test: Pass, Slow
 dart_2/causal_stacks/async_throws_stack_lazy_non_symbolic_test: Pass, Slow
 
-[ $compiler == dartkp && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $builder_tag == tsan) ]
+[ $compiler == dartkp && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64 || $builder_tag == tsan) ]
 dart/regress_45898_test: Pass, Slow
 dart_2/regress_45898_test: Pass, Slow
 
@@ -318,14 +318,14 @@
 [ $system != fuchsia && ($arch != x64 || $system != linux) ]
 cc/CodeExecutability: SkipByDesign # --dual-map-code not supported on non-Linux/Fuchsia
 
-[ $arch == arm || $arch == arm64 || $builder_tag == crossword || $builder_tag == crossword_ast || $compiler != dartkp || $system == linux && ($arch == simarm || $arch == simarm64 || $arch == simarm64c) ]
+[ $arch == arm || $arch == arm64 || $builder_tag == crossword || $builder_tag == crossword_ast || $compiler != dartkp || $system == linux && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ]
 dart/v8_snapshot_profile_writer_test: SkipByDesign # Only relevant for AOT. Doesn't work in cross-compilation (has to run on the host). On Linux/simarm64 and Linux/simarm this test requires buildtools/clang which is not always available on testing shards.
 dart_2/v8_snapshot_profile_writer_test: SkipByDesign # Only relevant for AOT. Doesn't work in cross-compilation (has to run on the host). On Linux/simarm64 and Linux/simarm this test requires buildtools/clang which is not always available on testing shards.
 
 # On the simluator stack traces produced by the Profiler do not match
 # up with the real Dart stack trace and hence we don't get correct
 # symbol names.
-[ $arch == simarm || $arch == simarm64 || $arch == simarm64c ]
+[ $arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64 ]
 cc/DartAPI_NativeFieldAccess: SkipByDesign # https://dartbug.com/37299 Test uses dart:ffi which is not supported on simulators.
 cc/DartAPI_NativeFieldAccess_Throws: SkipByDesign # https://dartbug.com/37299 Test uses dart:ffi which is not supported on simulators.
 cc/Dart_SetFfiNativeResolver: SkipByDesign # https://dartbug.com/37299 Test uses dart:ffi which is not supported on simulators.
@@ -373,15 +373,15 @@
 dart_2/unboxed_param_tear_off_test: SkipByDesign # https://dartbug.com/37299 FFI helper not supported on simulator
 dart_2/unboxed_param_test: SkipByDesign # https://dartbug.com/37299 FFI helper not supported on simulator
 
-[ $arch == simarm || $arch == simarm64 || $arch == simarm64c || $system != macos ]
+[ $arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64 || $system != macos ]
 dart/thread_priority_macos_test: SkipByDesign
 dart_2/thread_priority_macos_test: SkipByDesign
 
-[ $arch == simarm || $arch == simarm64 || $arch == simarm64c || $system != windows ]
+[ $arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64 || $system != windows ]
 dart/thread_priority_windows_test: SkipByDesign
 dart_2/thread_priority_windows_test: SkipByDesign
 
-[ $arch == simarm || $arch == simarm64 || $arch == simarm64c || $system != android && $system != linux ]
+[ $arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64 || $system != android && $system != linux ]
 dart/thread_priority_linux_test: SkipByDesign
 dart_2/thread_priority_linux_test: SkipByDesign
 
@@ -427,7 +427,7 @@
 # as that would involve running CFE (the front end) in simulator mode
 # to compile the URI file specified in spawnURI code.
 # These Isolate tests that use spawnURI are hence skipped on purpose.
-[ $runtime == dart_precompiled || $runtime == vm && ($arch == simarm || $arch == simarm64 || $arch == simarm64c) ]
+[ $runtime == dart_precompiled || $runtime == vm && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ]
 dart/data_uri_spawn_test: SkipByDesign # Isolate.spawnUri
 dart/isolates/send_object_to_spawn_uri_isolate_test: SkipByDesign # uses spawnUri
 dart/issue32950_test: SkipByDesign # uses spawnUri.
diff --git a/runtime/third_party/binary_size/README.dart b/runtime/third_party/binary_size/README.dart
new file mode 100644
index 0000000..0f2124e
--- /dev/null
+++ b/runtime/third_party/binary_size/README.dart
@@ -0,0 +1 @@
+A local copy of tools/binary_size from Chromium project.
\ No newline at end of file
diff --git a/runtime/third_party/binary_size/src/binary_size_utils.py b/runtime/third_party/binary_size/src/binary_size_utils.py
new file mode 100644
index 0000000..8ef283e
--- /dev/null
+++ b/runtime/third_party/binary_size/src/binary_size_utils.py
@@ -0,0 +1,69 @@
+# Copyright 2014 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.
+"""Common utilities for tools that deal with binary size information.
+"""
+
+import logging
+import re
+
+
+def ParseNm(nm_lines):
+    """Parse nm output, returning data for all relevant (to binary size)
+  symbols and ignoring the rest.
+
+  Args:
+      nm_lines: an iterable over lines of nm output.
+
+  Yields:
+      (symbol name, symbol type, symbol size, source file path).
+
+      Path may be None if nm couldn't figure out the source file.
+  """
+
+    # Match lines with size, symbol, optional location, optional discriminator
+    sym_re = re.compile(r'^([0-9a-f]{8,}) '  # address (8+ hex digits)
+                        '([0-9a-f]{8,}) '  # size (8+ hex digits)
+                        '(.) '  # symbol type, one character
+                        '([^\t]+)'  # symbol name, separated from next by tab
+                        '(?:\t(.*):[\d\?]+)?.*$')  # location
+    # Match lines with addr but no size.
+    addr_re = re.compile(r'^[0-9a-f]{8,} (.) ([^\t]+)(?:\t.*)?$')
+    # Match lines that don't have an address at all -- typically external symbols.
+    noaddr_re = re.compile(r'^ {8,} (.) (.*)$')
+    # Match lines with no symbol name, only addr and type
+    addr_only_re = re.compile(r'^[0-9a-f]{8,} (.)$')
+
+    seen_lines = set()
+    for line in nm_lines:
+        line = line.rstrip()
+        if line in seen_lines:
+            # nm outputs identical lines at times. We don't want to treat
+            # those as distinct symbols because that would make no sense.
+            continue
+        seen_lines.add(line)
+        match = sym_re.match(line)
+        if match:
+            address, size, sym_type, sym = match.groups()[0:4]
+            size = int(size, 16)
+            if sym_type in ('B', 'b'):
+                continue  # skip all BSS for now.
+            path = match.group(5)
+            yield sym, sym_type, size, path, address
+            continue
+        match = addr_re.match(line)
+        if match:
+            # sym_type, sym = match.groups()[0:2]
+            continue  # No size == we don't care.
+        match = noaddr_re.match(line)
+        if match:
+            sym_type, sym = match.groups()
+            if sym_type in ('U', 'w'):
+                continue  # external or weak symbol
+        match = addr_only_re.match(line)
+        if match:
+            continue  # Nothing to do.
+
+        # If we reach this part of the loop, there was something in the
+        # line that we didn't expect or recognize.
+        logging.warning('nm output parser failed to parse: %s', repr(line))
diff --git a/runtime/third_party/binary_size/src/elf_symbolizer.py b/runtime/third_party/binary_size/src/elf_symbolizer.py
new file mode 100644
index 0000000..5154a9b
--- /dev/null
+++ b/runtime/third_party/binary_size/src/elf_symbolizer.py
@@ -0,0 +1,490 @@
+# Copyright 2014 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.
+
+import collections
+import datetime
+import logging
+import multiprocessing
+import os
+import posixpath
+import queue
+import re
+import subprocess
+import sys
+import threading
+import time
+
+# addr2line builds a possibly infinite memory cache that can exhaust
+# the computer's memory if allowed to grow for too long. This constant
+# controls how many lookups we do before restarting the process. 4000
+# gives near peak performance without extreme memory usage.
+ADDR2LINE_RECYCLE_LIMIT = 4000
+
+
+class ELFSymbolizer(object):
+    """An uber-fast (multiprocessing, pipelined and asynchronous) ELF symbolizer.
+
+  This class is a frontend for addr2line (part of GNU binutils), designed to
+  symbolize batches of large numbers of symbols for a given ELF file. It
+  supports sharding symbolization against many addr2line instances and
+  pipelining of multiple requests per each instance (in order to hide addr2line
+  internals and OS pipe latencies).
+
+  The interface exhibited by this class is a very simple asynchronous interface,
+  which is based on the following three methods:
+  - SymbolizeAsync(): used to request (enqueue) resolution of a given address.
+  - The |callback| method: used to communicated back the symbol information.
+  - Join(): called to conclude the batch to gather the last outstanding results.
+  In essence, before the Join method returns, this class will have issued as
+  many callbacks as the number of SymbolizeAsync() calls. In this regard, note
+  that due to multiprocess sharding, callbacks can be delivered out of order.
+
+  Some background about addr2line:
+  - it is invoked passing the elf path in the cmdline, piping the addresses in
+    its stdin and getting results on its stdout.
+  - it has pretty large response times for the first requests, but it
+    works very well in streaming mode once it has been warmed up.
+  - it doesn't scale by itself (on more cores). However, spawning multiple
+    instances at the same time on the same file is pretty efficient as they
+    keep hitting the pagecache and become mostly CPU bound.
+  - it might hang or crash, mostly for OOM. This class deals with both of these
+    problems.
+
+  Despite the "scary" imports and the multi* words above, (almost) no multi-
+  threading/processing is involved from the python viewpoint. Concurrency
+  here is achieved by spawning several addr2line subprocesses and handling their
+  output pipes asynchronously. Therefore, all the code here (with the exception
+  of the Queue instance in Addr2Line) should be free from mind-blowing
+  thread-safety concerns.
+
+  The multiprocess sharding works as follows:
+  The symbolizer tries to use the lowest number of addr2line instances as
+  possible (with respect of |max_concurrent_jobs|) and enqueue all the requests
+  in a single addr2line instance. For few symbols (i.e. dozens) sharding isn't
+  worth the startup cost.
+  The multiprocess logic kicks in as soon as the queues for the existing
+  instances grow. Specifically, once all the existing instances reach the
+  |max_queue_size| bound, a new addr2line instance is kicked in.
+  In the case of a very eager producer (i.e. all |max_concurrent_jobs| instances
+  have a backlog of |max_queue_size|), back-pressure is applied on the caller by
+  blocking the SymbolizeAsync method.
+
+  This module has been deliberately designed to be dependency free (w.r.t. of
+  other modules in this project), to allow easy reuse in external projects.
+  """
+
+    def __init__(self,
+                 elf_file_path,
+                 addr2line_path,
+                 callback,
+                 inlines=False,
+                 max_concurrent_jobs=None,
+                 addr2line_timeout=30,
+                 max_queue_size=50,
+                 source_root_path=None,
+                 strip_base_path=None):
+        """Args:
+      elf_file_path: path of the elf file to be symbolized.
+      addr2line_path: path of the toolchain's addr2line binary.
+      callback: a callback which will be invoked for each resolved symbol with
+          the two args (sym_info, callback_arg). The former is an instance of
+          |ELFSymbolInfo| and contains the symbol information. The latter is an
+          embedder-provided argument which is passed to SymbolizeAsync().
+      inlines: when True, the ELFSymbolInfo will contain also the details about
+          the outer inlining functions. When False, only the innermost function
+          will be provided.
+      max_concurrent_jobs: Max number of addr2line instances spawned.
+          Parallelize responsibly, addr2line is a memory and I/O monster.
+      max_queue_size: Max number of outstanding requests per addr2line instance.
+      addr2line_timeout: Max time (in seconds) to wait for a addr2line response.
+          After the timeout, the instance will be considered hung and respawned.
+      source_root_path: In some toolchains only the name of the source file is
+          is output, without any path information; disambiguation searches
+          through the source directory specified by |source_root_path| argument
+          for files whose name matches, adding the full path information to the
+          output. For example, if the toolchain outputs "unicode.cc" and there
+          is a file called "unicode.cc" located under |source_root_path|/foo,
+          the tool will replace "unicode.cc" with
+          "|source_root_path|/foo/unicode.cc". If there are multiple files with
+          the same name, disambiguation will fail because the tool cannot
+          determine which of the files was the source of the symbol.
+      strip_base_path: Rebases the symbols source paths onto |source_root_path|
+          (i.e replace |strip_base_path| with |source_root_path).
+    """
+        assert (os.path.isfile(addr2line_path)), 'Cannot find ' + addr2line_path
+        self.elf_file_path = elf_file_path
+        self.addr2line_path = addr2line_path
+        self.callback = callback
+        self.inlines = inlines
+        self.max_concurrent_jobs = (max_concurrent_jobs or
+                                    min(multiprocessing.cpu_count(), 4))
+        self.max_queue_size = max_queue_size
+        self.addr2line_timeout = addr2line_timeout
+        self.requests_counter = 0  # For generating monotonic request IDs.
+        self._a2l_instances = []  # Up to |max_concurrent_jobs| _Addr2Line inst.
+
+        # If necessary, create disambiguation lookup table
+        self.disambiguate = source_root_path is not None
+        self.disambiguation_table = {}
+        self.strip_base_path = strip_base_path
+        if (self.disambiguate):
+            self.source_root_path = os.path.abspath(source_root_path)
+            self._CreateDisambiguationTable()
+
+        # Create one addr2line instance. More instances will be created on demand
+        # (up to |max_concurrent_jobs|) depending on the rate of the requests.
+        self._CreateNewA2LInstance()
+
+    def SymbolizeAsync(self, addr, callback_arg=None):
+        """Requests symbolization of a given address.
+
+    This method is not guaranteed to return immediately. It generally does, but
+    in some scenarios (e.g. all addr2line instances have full queues) it can
+    block to create back-pressure.
+
+    Args:
+      addr: address to symbolize.
+      callback_arg: optional argument which will be passed to the |callback|."""
+        assert (isinstance(addr, int))
+
+        # Process all the symbols that have been resolved in the meanwhile.
+        # Essentially, this drains all the addr2line(s) out queues.
+        for a2l_to_purge in self._a2l_instances:
+            a2l_to_purge.ProcessAllResolvedSymbolsInQueue()
+            a2l_to_purge.RecycleIfNecessary()
+
+        # Find the best instance according to this logic:
+        # 1. Find an existing instance with the shortest queue.
+        # 2. If all of instances' queues are full, but there is room in the pool,
+        #    (i.e. < |max_concurrent_jobs|) create a new instance.
+        # 3. If there were already |max_concurrent_jobs| instances and all of them
+        #    had full queues, make back-pressure.
+
+        # 1.
+        def _SortByQueueSizeAndReqID(a2l):
+            return (a2l.queue_size, a2l.first_request_id)
+
+        a2l = min(self._a2l_instances, key=_SortByQueueSizeAndReqID)
+
+        # 2.
+        if (a2l.queue_size >= self.max_queue_size and
+                len(self._a2l_instances) < self.max_concurrent_jobs):
+            a2l = self._CreateNewA2LInstance()
+
+        # 3.
+        if a2l.queue_size >= self.max_queue_size:
+            a2l.WaitForNextSymbolInQueue()
+
+        a2l.EnqueueRequest(addr, callback_arg)
+
+    def Join(self):
+        """Waits for all the outstanding requests to complete and terminates."""
+        for a2l in self._a2l_instances:
+            a2l.WaitForIdle()
+            a2l.Terminate()
+
+    def _CreateNewA2LInstance(self):
+        assert (len(self._a2l_instances) < self.max_concurrent_jobs)
+        a2l = ELFSymbolizer.Addr2Line(self)
+        self._a2l_instances.append(a2l)
+        return a2l
+
+    def _CreateDisambiguationTable(self):
+        """ Non-unique file names will result in None entries"""
+        start_time = time.time()
+        logging.info('Collecting information about available source files...')
+        self.disambiguation_table = {}
+
+        for root, _, filenames in os.walk(self.source_root_path):
+            for f in filenames:
+                self.disambiguation_table[f] = os.path.join(
+                    root, f) if (f not in self.disambiguation_table) else None
+        logging.info(
+            'Finished collecting information about '
+            'possible files (took %.1f s).', (time.time() - start_time))
+
+    class Addr2Line(object):
+        """A python wrapper around an addr2line instance.
+
+    The communication with the addr2line process looks as follows:
+      [STDIN]         [STDOUT]  (from addr2line's viewpoint)
+    > f001111
+    > f002222
+                    < Symbol::Name(foo, bar) for f001111
+                    < /path/to/source/file.c:line_number
+    > f003333
+                    < Symbol::Name2() for f002222
+                    < /path/to/source/file.c:line_number
+                    < Symbol::Name3() for f003333
+                    < /path/to/source/file.c:line_number
+    """
+
+        SYM_ADDR_RE = re.compile(r'([^:]+):(\?|\d+).*')
+
+        def __init__(self, symbolizer):
+            self._symbolizer = symbolizer
+            self._lib_file_name = posixpath.basename(symbolizer.elf_file_path)
+
+            # The request queue (i.e. addresses pushed to addr2line's stdin and not
+            # yet retrieved on stdout)
+            self._request_queue = collections.deque()
+
+            # This is essentially len(self._request_queue). It has been optimized to a
+            # separate field because turned out to be a perf hot-spot.
+            self.queue_size = 0
+
+            # Keep track of the number of symbols a process has processed to
+            # avoid a single process growing too big and using all the memory.
+            self._processed_symbols_count = 0
+
+            # Objects required to handle the addr2line subprocess.
+            self._proc = None  # Subprocess.Popen(...) instance.
+            self._thread = None  # Threading.thread instance.
+            self._out_queue = None  # queue.Queue instance (for buffering a2l stdout).
+            self._RestartAddr2LineProcess()
+
+        def EnqueueRequest(self, addr, callback_arg):
+            """Pushes an address to addr2line's stdin (and keeps track of it)."""
+            self._symbolizer.requests_counter += 1  # For global "age" of requests.
+            req_idx = self._symbolizer.requests_counter
+            self._request_queue.append((addr, callback_arg, req_idx))
+            self.queue_size += 1
+            self._WriteToA2lStdin(addr)
+
+        def WaitForIdle(self):
+            """Waits until all the pending requests have been symbolized."""
+            while self.queue_size > 0:
+                self.WaitForNextSymbolInQueue()
+
+        def WaitForNextSymbolInQueue(self):
+            """Waits for the next pending request to be symbolized."""
+            if not self.queue_size:
+                return
+
+            # This outer loop guards against a2l hanging (detecting stdout timeout).
+            while True:
+                start_time = datetime.datetime.now()
+                timeout = datetime.timedelta(
+                    seconds=self._symbolizer.addr2line_timeout)
+
+                # The inner loop guards against a2l crashing (checking if it exited).
+                while (datetime.datetime.now() - start_time < timeout):
+                    # poll() returns !None if the process exited. a2l should never exit.
+                    if self._proc.poll():
+                        logging.warning(
+                            'addr2line crashed, respawning (lib: %s).' %
+                            self._lib_file_name)
+                        self._RestartAddr2LineProcess()
+                        # TODO(primiano): the best thing to do in this case would be
+                        # shrinking the pool size as, very likely, addr2line is crashed
+                        # due to low memory (and the respawned one will die again soon).
+
+                    try:
+                        lines = self._out_queue.get(block=True, timeout=0.25)
+                    except queue.Empty:
+                        # On timeout (1/4 s.) repeat the inner loop and check if either the
+                        # addr2line process did crash or we waited its output for too long.
+                        continue
+
+                    # In nominal conditions, we get straight to this point.
+                    self._ProcessSymbolOutput(lines)
+                    return
+
+                # If this point is reached, we waited more than |addr2line_timeout|.
+                logging.warning('Hung addr2line process, respawning (lib: %s).'
+                                % self._lib_file_name)
+                self._RestartAddr2LineProcess()
+
+        def ProcessAllResolvedSymbolsInQueue(self):
+            """Consumes all the addr2line output lines produced (without blocking)."""
+            if not self.queue_size:
+                return
+            while True:
+                try:
+                    lines = self._out_queue.get_nowait()
+                except queue.Empty:
+                    break
+                self._ProcessSymbolOutput(lines)
+
+        def RecycleIfNecessary(self):
+            """Restarts the process if it has been used for too long.
+
+      A long running addr2line process will consume excessive amounts
+      of memory without any gain in performance."""
+            if self._processed_symbols_count >= ADDR2LINE_RECYCLE_LIMIT:
+                self._RestartAddr2LineProcess()
+
+        def Terminate(self):
+            """Kills the underlying addr2line process.
+
+      The poller |_thread| will terminate as well due to the broken pipe."""
+            try:
+                self._proc.kill()
+                self._proc.communicate(
+                )  # Essentially wait() without risking deadlock.
+            except Exception:  # An exception while terminating? How interesting.
+                pass
+            self._proc = None
+
+        def _WriteToA2lStdin(self, addr):
+            self._proc.stdin.write(('%s\n' % hex(addr)).encode())
+            if self._symbolizer.inlines:
+                # In the case of inlines we output an extra blank line, which causes
+                # addr2line to emit a (??,??:0) tuple that we use as a boundary marker.
+                self._proc.stdin.write('\n')
+            self._proc.stdin.flush()
+
+        def _ProcessSymbolOutput(self, lines):
+            """Parses an addr2line symbol output and triggers the client callback."""
+            (_, callback_arg, _) = self._request_queue.popleft()
+            self.queue_size -= 1
+
+            innermost_sym_info = None
+            sym_info = None
+            for (line1, line2) in lines:
+                prev_sym_info = sym_info
+                name = line1 if not line1.startswith('?') else None
+                source_path = None
+                source_line = None
+                m = ELFSymbolizer.Addr2Line.SYM_ADDR_RE.match(line2)
+                if m:
+                    if not m.group(1).startswith('?'):
+                        source_path = m.group(1)
+                        if not m.group(2).startswith('?'):
+                            source_line = int(m.group(2))
+                else:
+                    logging.warning(
+                        'Got invalid symbol path from addr2line: %s' % line2)
+
+                # In case disambiguation is on, and needed
+                was_ambiguous = False
+                disambiguated = False
+                if self._symbolizer.disambiguate:
+                    if source_path and not posixpath.isabs(source_path):
+                        path = self._symbolizer.disambiguation_table.get(
+                            source_path)
+                        was_ambiguous = True
+                        disambiguated = path is not None
+                        source_path = path if disambiguated else source_path
+
+                    # Use absolute paths (so that paths are consistent, as disambiguation
+                    # uses absolute paths)
+                    if source_path and not was_ambiguous:
+                        source_path = os.path.abspath(source_path)
+
+                if source_path and self._symbolizer.strip_base_path:
+                    # Strip the base path
+                    source_path = re.sub(
+                        '^' + self._symbolizer.strip_base_path,
+                        self._symbolizer.source_root_path or '', source_path)
+
+                sym_info = ELFSymbolInfo(name, source_path, source_line,
+                                         was_ambiguous, disambiguated)
+                if prev_sym_info:
+                    prev_sym_info.inlined_by = sym_info
+                if not innermost_sym_info:
+                    innermost_sym_info = sym_info
+
+            self._processed_symbols_count += 1
+            self._symbolizer.callback(innermost_sym_info, callback_arg)
+
+        def _RestartAddr2LineProcess(self):
+            if self._proc:
+                self.Terminate()
+
+            # The only reason of existence of this Queue (and the corresponding
+            # Thread below) is the lack of a subprocess.stdout.poll_avail_lines().
+            # Essentially this is a pipe able to extract a couple of lines atomically.
+            self._out_queue = queue.Queue()
+
+            # Start the underlying addr2line process in line buffered mode.
+
+            cmd = [
+                self._symbolizer.addr2line_path, '--functions', '--demangle',
+                '--exe=' + self._symbolizer.elf_file_path
+            ]
+            if self._symbolizer.inlines:
+                cmd += ['--inlines']
+            self._proc = subprocess.Popen(
+                cmd,
+                stdout=subprocess.PIPE,
+                stdin=subprocess.PIPE,
+                stderr=sys.stderr,
+                close_fds=True)
+
+            # Start the poller thread, which simply moves atomically the lines read
+            # from the addr2line's stdout to the |_out_queue|.
+            self._thread = threading.Thread(
+                target=ELFSymbolizer.Addr2Line.StdoutReaderThread,
+                args=(self._proc.stdout, self._out_queue,
+                      self._symbolizer.inlines))
+            self._thread.daemon = True  # Don't prevent early process exit.
+            self._thread.start()
+
+            self._processed_symbols_count = 0
+
+            # Replay the pending requests on the new process (only for the case
+            # of a hung addr2line timing out during the game).
+            for (addr, _, _) in self._request_queue:
+                self._WriteToA2lStdin(addr)
+
+        @staticmethod
+        def StdoutReaderThread(process_pipe, queue, inlines):
+            """The poller thread fn, which moves the addr2line stdout to the |queue|.
+
+      This is the only piece of code not running on the main thread. It merely
+      writes to a Queue, which is thread-safe. In the case of inlines, it
+      detects the ??,??:0 marker and sends the lines atomically, such that the
+      main thread always receives all the lines corresponding to one symbol in
+      one shot."""
+            try:
+                lines_for_one_symbol = []
+                while True:
+                    line1 = process_pipe.readline().decode().rstrip('\r\n')
+                    line2 = process_pipe.readline().decode().rstrip('\r\n')
+                    if not line1 or not line2:
+                        break
+                    inline_has_more_lines = inlines and (
+                        len(lines_for_one_symbol) == 0 or
+                        (line1 != '??' and line2 != '??:0'))
+                    if not inlines or inline_has_more_lines:
+                        lines_for_one_symbol += [(line1, line2)]
+                    if inline_has_more_lines:
+                        continue
+                    queue.put(lines_for_one_symbol)
+                    lines_for_one_symbol = []
+                process_pipe.close()
+
+            # Every addr2line processes will die at some point, please die silently.
+            except (IOError, OSError):
+                pass
+
+        @property
+        def first_request_id(self):
+            """Returns the request_id of the oldest pending request in the queue."""
+            return self._request_queue[0][2] if self._request_queue else 0
+
+
+class ELFSymbolInfo(object):
+    """The result of the symbolization passed as first arg. of each callback."""
+
+    def __init__(self,
+                 name,
+                 source_path,
+                 source_line,
+                 was_ambiguous=False,
+                 disambiguated=False):
+        """All the fields here can be None (if addr2line replies with '??')."""
+        self.name = name
+        self.source_path = source_path
+        self.source_line = source_line
+        # In the case of |inlines|=True, the |inlined_by| points to the outer
+        # function inlining the current one (and so on, to form a chain).
+        self.inlined_by = None
+        self.disambiguated = disambiguated
+        self.was_ambiguous = was_ambiguous
+
+    def __str__(self):
+        return '%s [%s:%d]' % (self.name or '??', self.source_path or '??',
+                               self.source_line or 0)
diff --git a/runtime/third_party/binary_size/src/explain_binary_size_delta.py b/runtime/third_party/binary_size/src/explain_binary_size_delta.py
new file mode 100755
index 0000000..13f7c12
--- /dev/null
+++ b/runtime/third_party/binary_size/src/explain_binary_size_delta.py
@@ -0,0 +1,519 @@
+#!/usr/bin/env python3
+# Copyright 2014 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.
+"""Describe the size difference of two binaries.
+
+Generates a description of the size difference of two binaries based
+on the difference of the size of various symbols.
+
+This tool needs "nm" dumps of each binary with full symbol
+information. You can obtain the necessary dumps by running the
+run_binary_size_analysis.py script upon each binary, with the
+"--nm-out" parameter set to the location in which you want to save the
+dumps. Example:
+
+  # obtain symbol data from first binary in /tmp/nm1.dump
+  cd $CHECKOUT1_SRC
+  ninja -C out/Release binary_size_tool
+  tools/binary_size/run_binary_size_analysis \
+      --library <path_to_library>
+      --destdir /tmp/throwaway
+      --nm-out /tmp/nm1.dump
+
+  # obtain symbol data from second binary in /tmp/nm2.dump
+  cd $CHECKOUT2_SRC
+  ninja -C out/Release binary_size_tool
+  tools/binary_size/run_binary_size_analysis \
+      --library <path_to_library>
+      --destdir /tmp/throwaway
+      --nm-out /tmp/nm2.dump
+
+  # cleanup useless files
+  rm -r /tmp/throwaway
+
+  # run this tool
+  explain_binary_size_delta.py --nm1 /tmp/nm1.dump --nm2 /tmp/nm2.dump
+"""
+
+import collections
+from collections import Counter
+from math import ceil
+import operator
+import optparse
+import os
+import sys
+
+import binary_size_utils
+
+
+def CalculateSharedAddresses(symbols):
+    """Checks how many symbols share the same memory space. This returns a
+Counter result where result[address] will tell you how many times address was
+used by symbols."""
+    count = Counter()
+    for _, _, _, _, address in symbols:
+        count[address] += 1
+
+    return count
+
+
+def CalculateEffectiveSize(share_count, address, symbol_size):
+    """Given a raw symbol_size and an address, this method returns the
+  size we should blame on this symbol considering it might share the
+  machine code/data with other symbols. Using the raw symbol_size for
+  each symbol would in those cases over estimate the true cost of that
+  block.
+
+  """
+    shared_count = share_count[address]
+    if shared_count == 1:
+        return symbol_size
+
+    assert shared_count > 1
+    return int(ceil(symbol_size / float(shared_count)))
+
+
+class SymbolDelta(object):
+    """Stores old size, new size and some metadata."""
+
+    def __init__(self, shared):
+        self.old_size = None
+        self.new_size = None
+        self.shares_space_with_other_symbols = shared
+
+    def __eq__(self, other):
+        return (self.old_size == other.old_size and
+                self.new_size == other.new_size and
+                self.shares_space_with_other_symbols == other.
+                shares_space_with_other_symbols)
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+    def copy_symbol_delta(self):
+        symbol_delta = SymbolDelta(self.shares_space_with_other_symbols)
+        symbol_delta.old_size = self.old_size
+        symbol_delta.new_size = self.new_size
+        return symbol_delta
+
+
+class DeltaInfo(SymbolDelta):
+    """Summary of a the change for one symbol between two instances."""
+
+    def __init__(self, file_path, symbol_type, symbol_name, shared):
+        SymbolDelta.__init__(self, shared)
+        self.file_path = file_path
+        self.symbol_type = symbol_type
+        self.symbol_name = symbol_name
+
+    def __eq__(self, other):
+        return (self.file_path == other.file_path and
+                self.symbol_type == other.symbol_type and
+                self.symbol_name == other.symbol_name and
+                SymbolDelta.__eq__(self, other))
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+    def ExtractSymbolDelta(self):
+        """Returns a copy of the SymbolDelta for this DeltaInfo."""
+        return SymbolDelta.copy_symbol_delta(self)
+
+
+def Compare(symbols1, symbols2):
+    """Executes a comparison of the symbols in symbols1 and symbols2.
+
+  Returns:
+      tuple of lists: (added_symbols, removed_symbols, changed_symbols, others)
+      where each list contains DeltaInfo objects.
+  """
+    added = []  # tuples
+    removed = []  # tuples
+    changed = []  # tuples
+    unchanged = []  # tuples
+
+    cache1 = {}
+    cache2 = {}
+    # Make a map of (file, symbol_type) : (symbol_name, effective_symbol_size)
+    share_count1 = CalculateSharedAddresses(symbols1)
+    share_count2 = CalculateSharedAddresses(symbols2)
+    for cache, symbols, share_count in ((cache1, symbols1, share_count1),
+                                        (cache2, symbols2, share_count2)):
+        for symbol_name, symbol_type, symbol_size, file_path, address in symbols:
+            if 'vtable for ' in symbol_name:
+                symbol_type = '@'  # hack to categorize these separately
+            if file_path:
+                file_path = os.path.normpath(file_path)
+                if sys.platform.startswith('win'):
+                    file_path = file_path.replace('\\', '/')
+            else:
+                file_path = '(No Path)'
+            # Take into consideration that multiple symbols might share the same
+            # block of code.
+            effective_symbol_size = CalculateEffectiveSize(
+                share_count, address, symbol_size)
+            key = (file_path, symbol_type)
+            bucket = cache.setdefault(key, {})
+            size_list = bucket.setdefault(symbol_name, [])
+            size_list.append((effective_symbol_size,
+                              effective_symbol_size != symbol_size))
+
+    # Now diff them. We iterate over the elements in cache1. For each symbol
+    # that we find in cache2, we record whether it was deleted, changed, or
+    # unchanged. We then remove it from cache2; all the symbols that remain
+    # in cache2 at the end of the iteration over cache1 are the 'new' symbols.
+    for key, bucket1 in cache1.items():
+        bucket2 = cache2.get(key)
+        file_path, symbol_type = key
+        if not bucket2:
+            # A file was removed. Everything in bucket1 is dead.
+            for symbol_name, symbol_size_list in bucket1.items():
+                for (symbol_size, shared) in symbol_size_list:
+                    delta_info = DeltaInfo(file_path, symbol_type, symbol_name,
+                                           shared)
+                    delta_info.old_size = symbol_size
+                    removed.append(delta_info)
+        else:
+            # File still exists, look for changes within.
+            for symbol_name, symbol_size_list in bucket1.items():
+                size_list2 = bucket2.get(symbol_name)
+                if size_list2 is None:
+                    # Symbol no longer exists in bucket2.
+                    for (symbol_size, shared) in symbol_size_list:
+                        delta_info = DeltaInfo(file_path, symbol_type,
+                                               symbol_name, shared)
+                        delta_info.old_size = symbol_size
+                        removed.append(delta_info)
+                else:
+                    del bucket2[
+                        symbol_name]  # Symbol is not new, delete from cache2.
+                    if len(symbol_size_list) == 1 and len(size_list2) == 1:
+                        symbol_size, shared1 = symbol_size_list[0]
+                        size2, shared2 = size_list2[0]
+                        delta_info = DeltaInfo(file_path, symbol_type,
+                                               symbol_name, shared1 or shared2)
+                        delta_info.old_size = symbol_size
+                        delta_info.new_size = size2
+                        if symbol_size != size2:
+                            # Symbol has change size in bucket.
+                            changed.append(delta_info)
+                        else:
+                            # Symbol is unchanged.
+                            unchanged.append(delta_info)
+                    else:
+                        # Complex comparison for when a symbol exists multiple times
+                        # in the same file (where file can be "unknown file").
+                        symbol_size_counter = collections.Counter(
+                            symbol_size_list)
+                        delta_counter = collections.Counter(symbol_size_list)
+                        delta_counter.subtract(size_list2)
+                        for delta_counter_key in sorted(delta_counter.keys()):
+                            delta = delta_counter[delta_counter_key]
+                            unchanged_count = symbol_size_counter[
+                                delta_counter_key]
+                            (symbol_size, shared) = delta_counter_key
+                            if delta > 0:
+                                unchanged_count -= delta
+                            for _ in range(unchanged_count):
+                                delta_info = DeltaInfo(file_path, symbol_type,
+                                                       symbol_name, shared)
+                                delta_info.old_size = symbol_size
+                                delta_info.new_size = symbol_size
+                                unchanged.append(delta_info)
+                            if delta > 0:  # Used to be more of these than there is now.
+                                for _ in range(delta):
+                                    delta_info = DeltaInfo(
+                                        file_path, symbol_type, symbol_name,
+                                        shared)
+                                    delta_info.old_size = symbol_size
+                                    removed.append(delta_info)
+                            elif delta < 0:  # More of this (symbol,size) now.
+                                for _ in range(-delta):
+                                    delta_info = DeltaInfo(
+                                        file_path, symbol_type, symbol_name,
+                                        shared)
+                                    delta_info.new_size = symbol_size
+                                    added.append(delta_info)
+
+                    if len(bucket2) == 0:
+                        del cache1[
+                            key]  # Entire bucket is empty, delete from cache2
+
+    # We have now analyzed all symbols that are in cache1 and removed all of
+    # the encountered symbols from cache2. What's left in cache2 is the new
+    # symbols.
+    for key, bucket2 in cache2.items():
+        file_path, symbol_type = key
+        for symbol_name, symbol_size_list in bucket2.items():
+            for (symbol_size, shared) in symbol_size_list:
+                delta_info = DeltaInfo(file_path, symbol_type, symbol_name,
+                                       shared)
+                delta_info.new_size = symbol_size
+                added.append(delta_info)
+    return (added, removed, changed, unchanged)
+
+
+def DeltaStr(number):
+    """Returns the number as a string with a '+' prefix if it's > 0 and
+  a '-' prefix if it's < 0."""
+    result = str(number)
+    if number > 0:
+        result = '+' + result
+    return result
+
+
+def SharedInfoStr(symbol_info):
+    """Returns a string (prefixed by space) explaining that numbers are
+  adjusted because of shared space between symbols, or an empty string
+  if space had not been shared."""
+
+    if symbol_info.shares_space_with_other_symbols:
+        return " (adjusted sizes because of memory sharing)"
+
+    return ""
+
+
+class CrunchStatsData(object):
+    """Stores a summary of data of a certain kind."""
+
+    def __init__(self, symbols):
+        self.symbols = symbols
+        self.sources = set()
+        self.before_size = 0
+        self.after_size = 0
+        self.symbols_by_path = {}
+
+
+def CrunchStats(added, removed, changed, unchanged, showsources, showsymbols):
+    """Outputs to stdout a summary of changes based on the symbol lists."""
+    # Split changed into grown and shrunk because that is easier to
+    # discuss.
+    grown = []
+    shrunk = []
+    for item in changed:
+        if item.old_size < item.new_size:
+            grown.append(item)
+        else:
+            shrunk.append(item)
+
+    new_symbols = CrunchStatsData(added)
+    removed_symbols = CrunchStatsData(removed)
+    grown_symbols = CrunchStatsData(grown)
+    shrunk_symbols = CrunchStatsData(shrunk)
+    sections = [new_symbols, removed_symbols, grown_symbols, shrunk_symbols]
+    for section in sections:
+        for item in section.symbols:
+            section.sources.add(item.file_path)
+            if item.old_size is not None:
+                section.before_size += item.old_size
+            if item.new_size is not None:
+                section.after_size += item.new_size
+            bucket = section.symbols_by_path.setdefault(item.file_path, [])
+            bucket.append((item.symbol_name, item.symbol_type,
+                           item.ExtractSymbolDelta()))
+
+    total_change = sum(s.after_size - s.before_size for s in sections)
+    summary = 'Total change: %s bytes' % DeltaStr(total_change)
+    print(summary)
+    print('=' * len(summary))
+    for section in sections:
+        if not section.symbols:
+            continue
+        if section.before_size == 0:
+            description = (
+                'added, totalling %s bytes' % DeltaStr(section.after_size))
+        elif section.after_size == 0:
+            description = (
+                'removed, totalling %s bytes' % DeltaStr(-section.before_size))
+        else:
+            if section.after_size > section.before_size:
+                type_str = 'grown'
+            else:
+                type_str = 'shrunk'
+            description = (
+                '%s, for a net change of %s bytes '
+                '(%d bytes before, %d bytes after)' %
+                (type_str, DeltaStr(section.after_size - section.before_size),
+                 section.before_size, section.after_size))
+        print('  %d %s across %d sources' % (len(section.symbols), description,
+                                             len(section.sources)))
+
+    maybe_unchanged_sources = set()
+    unchanged_symbols_size = 0
+    for item in unchanged:
+        maybe_unchanged_sources.add(item.file_path)
+        unchanged_symbols_size += item.old_size  # == item.new_size
+    print('  %d unchanged, totalling %d bytes' % (len(unchanged),
+                                                  unchanged_symbols_size))
+
+    # High level analysis, always output.
+    unchanged_sources = maybe_unchanged_sources
+    for section in sections:
+        unchanged_sources = unchanged_sources - section.sources
+    new_sources = (
+        new_symbols.sources - maybe_unchanged_sources - removed_symbols.sources)
+    removed_sources = (
+        removed_symbols.sources - maybe_unchanged_sources - new_symbols.sources)
+    partially_changed_sources = (
+        grown_symbols.sources | shrunk_symbols.sources | new_symbols.sources |
+        removed_symbols.sources) - removed_sources - new_sources
+    allFiles = set()
+    for section in sections:
+        allFiles = allFiles | section.sources
+    allFiles = allFiles | maybe_unchanged_sources
+    print('Source stats:')
+    print('  %d sources encountered.' % len(allFiles))
+    print('  %d completely new.' % len(new_sources))
+    print('  %d removed completely.' % len(removed_sources))
+    print('  %d partially changed.' % len(partially_changed_sources))
+    print('  %d completely unchanged.' % len(unchanged_sources))
+    remainder = (allFiles - new_sources - removed_sources -
+                 partially_changed_sources - unchanged_sources)
+    assert len(remainder) == 0
+
+    if not showsources:
+        return  # Per-source analysis, only if requested
+    print('Per-source Analysis:')
+    delta_by_path = {}
+    for section in sections:
+        for path in section.symbols_by_path:
+            entry = delta_by_path.get(path)
+            if not entry:
+                entry = {'plus': 0, 'minus': 0}
+                delta_by_path[path] = entry
+            for symbol_name, symbol_type, symbol_delta in \
+                  section.symbols_by_path[path]:
+                if symbol_delta.old_size is None:
+                    delta = symbol_delta.new_size
+                elif symbol_delta.new_size is None:
+                    delta = -symbol_delta.old_size
+                else:
+                    delta = symbol_delta.new_size - symbol_delta.old_size
+
+                if delta > 0:
+                    entry['plus'] += delta
+                else:
+                    entry['minus'] += (-1 * delta)
+
+    def delta_sort_key(item):
+        _path, size_data = item
+        growth = size_data['plus'] - size_data['minus']
+        return growth
+
+    for path, size_data in sorted(delta_by_path.items(),
+                                  key=delta_sort_key,
+                                  reverse=True):
+        gain = size_data['plus']
+        loss = size_data['minus']
+        delta = size_data['plus'] - size_data['minus']
+        header = ' %s - Source: %s - (gained %d, lost %d)' % (DeltaStr(delta),
+                                                              path, gain, loss)
+        divider = '-' * len(header)
+        print('')
+        print(divider)
+        print(header)
+        print(divider)
+        if showsymbols:
+
+            def ExtractNewSize(tup):
+                symbol_delta = tup[2]
+                return symbol_delta.new_size
+
+            def ExtractOldSize(tup):
+                symbol_delta = tup[2]
+                return symbol_delta.old_size
+
+            if path in new_symbols.symbols_by_path:
+                print('  New symbols:')
+                for symbol_name, symbol_type, symbol_delta in \
+                    sorted(new_symbols.symbols_by_path[path],
+                           key=ExtractNewSize,
+                           reverse=True):
+                    print('   %8s: %s type=%s, size=%d bytes%s' %
+                          (DeltaStr(symbol_delta.new_size), symbol_name,
+                           symbol_type, symbol_delta.new_size,
+                           SharedInfoStr(symbol_delta)))
+            if path in removed_symbols.symbols_by_path:
+                print('  Removed symbols:')
+                for symbol_name, symbol_type, symbol_delta in \
+                    sorted(removed_symbols.symbols_by_path[path],
+                           key=ExtractOldSize):
+                    print('   %8s: %s type=%s, size=%d bytes%s' %
+                          (DeltaStr(-symbol_delta.old_size), symbol_name,
+                           symbol_type, symbol_delta.old_size,
+                           SharedInfoStr(symbol_delta)))
+            for (changed_symbols_by_path,
+                 type_str) in [(grown_symbols.symbols_by_path, "Grown"),
+                               (shrunk_symbols.symbols_by_path, "Shrunk")]:
+                if path in changed_symbols_by_path:
+                    print('  %s symbols:' % type_str)
+
+                    def changed_symbol_sortkey(item):
+                        symbol_name, _symbol_type, symbol_delta = item
+                        return (symbol_delta.old_size - symbol_delta.new_size,
+                                symbol_name)
+
+                    for symbol_name, symbol_type, symbol_delta in \
+                        sorted(changed_symbols_by_path[path], key=changed_symbol_sortkey):
+                        print(
+                            '   %8s: %s type=%s, (was %d bytes, now %d bytes)%s'
+                            % (DeltaStr(symbol_delta.new_size -
+                                        symbol_delta.old_size), symbol_name,
+                               symbol_type,
+                               symbol_delta.old_size, symbol_delta.new_size,
+                               SharedInfoStr(symbol_delta)))
+
+
+def main():
+    usage = """%prog [options]
+
+  Analyzes the symbolic differences between two binary files
+  (typically, not necessarily, two different builds of the same
+  library) and produces a detailed description of symbols that have
+  been added, removed, or whose size has changed.
+
+  Example:
+       explain_binary_size_delta.py --nm1 /tmp/nm1.dump --nm2 /tmp/nm2.dump
+
+  Options are available via '--help'.
+  """
+    parser = optparse.OptionParser(usage=usage)
+    parser.add_option(
+        '--nm1', metavar='PATH', help='the nm dump of the first library')
+    parser.add_option(
+        '--nm2', metavar='PATH', help='the nm dump of the second library')
+    parser.add_option(
+        '--showsources',
+        action='store_true',
+        default=False,
+        help='show per-source statistics')
+    parser.add_option(
+        '--showsymbols',
+        action='store_true',
+        default=False,
+        help='show all symbol information; implies --showsources')
+    parser.add_option(
+        '--verbose',
+        action='store_true',
+        default=False,
+        help='output internal debugging stuff')
+    opts, _args = parser.parse_args()
+
+    if not opts.nm1:
+        parser.error('--nm1 is required')
+    if not opts.nm2:
+        parser.error('--nm2 is required')
+    symbols = []
+    for path in [opts.nm1, opts.nm2]:
+        with open(path, 'r') as nm_input:
+            if opts.verbose:
+                print('parsing ' + path + '...')
+            symbols.append(list(binary_size_utils.ParseNm(nm_input)))
+    (added, removed, changed, unchanged) = Compare(symbols[0], symbols[1])
+    CrunchStats(added, removed, changed, unchanged,
+                opts.showsources | opts.showsymbols, opts.showsymbols)
+
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git a/runtime/third_party/binary_size/src/run_binary_size_analysis.py b/runtime/third_party/binary_size/src/run_binary_size_analysis.py
new file mode 100755
index 0000000..dfd5b97
--- /dev/null
+++ b/runtime/third_party/binary_size/src/run_binary_size_analysis.py
@@ -0,0 +1,710 @@
+#!/usr/bin/env python3
+# Copyright 2014 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.
+"""Generate a spatial analysis against an arbitrary library.
+
+To use, build the 'binary_size_tool' target. Then run this tool, passing
+in the location of the library to be analyzed along with any other options
+you desire.
+"""
+
+import json
+import logging
+import multiprocessing
+import optparse
+import os
+import re
+import shutil
+import struct
+import subprocess
+import sys
+import tempfile
+import time
+
+import binary_size_utils
+import elf_symbolizer
+
+# Node dictionary keys. These are output in json read by the webapp so
+# keep them short to save file size.
+# Note: If these change, the webapp must also change.
+NODE_TYPE_KEY = 'k'
+NODE_NAME_KEY = 'n'
+NODE_CHILDREN_KEY = 'children'
+NODE_SYMBOL_TYPE_KEY = 't'
+NODE_SYMBOL_SIZE_KEY = 'value'
+NODE_MAX_DEPTH_KEY = 'maxDepth'
+NODE_LAST_PATH_ELEMENT_KEY = 'lastPathElement'
+
+# The display name of the bucket where we put symbols without path.
+NAME_NO_PATH_BUCKET = '(No Path)'
+
+# Try to keep data buckets smaller than this to avoid killing the
+# graphing lib.
+BIG_BUCKET_LIMIT = 3000
+
+
+def _MkChild(node, name):
+    child = node[NODE_CHILDREN_KEY].get(name)
+    if child is None:
+        child = {NODE_NAME_KEY: name, NODE_CHILDREN_KEY: {}}
+        node[NODE_CHILDREN_KEY][name] = child
+    return child
+
+
+def SplitNoPathBucket(node):
+    """NAME_NO_PATH_BUCKET can be too large for the graphing lib to
+  handle. Split it into sub-buckets in that case."""
+    root_children = node[NODE_CHILDREN_KEY]
+    if NAME_NO_PATH_BUCKET in root_children:
+        no_path_bucket = root_children[NAME_NO_PATH_BUCKET]
+        old_children = no_path_bucket[NODE_CHILDREN_KEY]
+        count = 0
+        for symbol_type, symbol_bucket in old_children.items():
+            count += len(symbol_bucket[NODE_CHILDREN_KEY])
+        if count > BIG_BUCKET_LIMIT:
+            new_children = {}
+            no_path_bucket[NODE_CHILDREN_KEY] = new_children
+            current_bucket = None
+            index = 0
+            for symbol_type, symbol_bucket in old_children.items():
+                for symbol_name, value in symbol_bucket[
+                        NODE_CHILDREN_KEY].items():
+                    if index % BIG_BUCKET_LIMIT == 0:
+                        group_no = (index / BIG_BUCKET_LIMIT) + 1
+                        current_bucket = _MkChild(
+                            no_path_bucket,
+                            '%s subgroup %d' % (NAME_NO_PATH_BUCKET, group_no))
+                        assert not NODE_TYPE_KEY in node or node[
+                            NODE_TYPE_KEY] == 'p'
+                        node[NODE_TYPE_KEY] = 'p'  # p for path
+                    index += 1
+                    symbol_size = value[NODE_SYMBOL_SIZE_KEY]
+                    AddSymbolIntoFileNode(current_bucket, symbol_type,
+                                          symbol_name, symbol_size)
+
+
+def MakeChildrenDictsIntoLists(node):
+    largest_list_len = 0
+    if NODE_CHILDREN_KEY in node:
+        largest_list_len = len(node[NODE_CHILDREN_KEY])
+        child_list = []
+        for child in node[NODE_CHILDREN_KEY].values():
+            child_largest_list_len = MakeChildrenDictsIntoLists(child)
+            if child_largest_list_len > largest_list_len:
+                largest_list_len = child_largest_list_len
+            child_list.append(child)
+        node[NODE_CHILDREN_KEY] = child_list
+
+    return largest_list_len
+
+
+def AddSymbolIntoFileNode(node, symbol_type, symbol_name, symbol_size):
+    """Puts symbol into the file path node |node|.
+  Returns the number of added levels in tree. I.e. returns 2."""
+
+    # 'node' is the file node and first step is to find its symbol-type bucket.
+    node[NODE_LAST_PATH_ELEMENT_KEY] = True
+    node = _MkChild(node, symbol_type)
+    assert not NODE_TYPE_KEY in node or node[NODE_TYPE_KEY] == 'b'
+    node[NODE_SYMBOL_TYPE_KEY] = symbol_type
+    node[NODE_TYPE_KEY] = 'b'  # b for bucket
+
+    # 'node' is now the symbol-type bucket. Make the child entry.
+    node = _MkChild(node, symbol_name)
+    if NODE_CHILDREN_KEY in node:
+        if node[NODE_CHILDREN_KEY]:
+            logging.warning(
+                'A container node used as symbol for %s.' % symbol_name)
+        # This is going to be used as a leaf so no use for child list.
+        del node[NODE_CHILDREN_KEY]
+    node[NODE_SYMBOL_SIZE_KEY] = symbol_size
+    node[NODE_SYMBOL_TYPE_KEY] = symbol_type
+    node[NODE_TYPE_KEY] = 's'  # s for symbol
+
+    return 2  # Depth of the added subtree.
+
+
+def MakeCompactTree(symbols, symbol_path_origin_dir):
+    result = {
+        NODE_NAME_KEY: '/',
+        NODE_CHILDREN_KEY: {},
+        NODE_TYPE_KEY: 'p',
+        NODE_MAX_DEPTH_KEY: 0
+    }
+    seen_symbol_with_path = False
+    cwd = os.path.abspath(os.getcwd())
+    for symbol_name, symbol_type, symbol_size, file_path, _address in symbols:
+
+        if 'vtable for ' in symbol_name:
+            symbol_type = '@'  # hack to categorize these separately
+        # Take path like '/foo/bar/baz', convert to ['foo', 'bar', 'baz']
+        if file_path and file_path != "??":
+            file_path = os.path.abspath(
+                os.path.join(symbol_path_origin_dir, file_path))
+            # Let the output structure be relative to $CWD if inside $CWD,
+            # otherwise relative to the disk root. This is to avoid
+            # unnecessary click-through levels in the output.
+            if file_path.startswith(cwd + os.sep):
+                file_path = file_path[len(cwd):]
+            if file_path.startswith('/'):
+                file_path = file_path[1:]
+            seen_symbol_with_path = True
+        else:
+            file_path = NAME_NO_PATH_BUCKET
+
+        path_parts = file_path.split('/')
+
+        # Find pre-existing node in tree, or update if it already exists
+        node = result
+        depth = 0
+        while len(path_parts) > 0:
+            path_part = path_parts.pop(0)
+            if len(path_part) == 0:
+                continue
+            depth += 1
+            node = _MkChild(node, path_part)
+            assert not NODE_TYPE_KEY in node or node[NODE_TYPE_KEY] == 'p'
+            node[NODE_TYPE_KEY] = 'p'  # p for path
+
+        depth += AddSymbolIntoFileNode(node, symbol_type, symbol_name,
+                                       symbol_size)
+        result[NODE_MAX_DEPTH_KEY] = max(result[NODE_MAX_DEPTH_KEY], depth)
+
+    if not seen_symbol_with_path:
+        logging.warning('Symbols lack paths. Data will not be structured.')
+
+    # The (no path) bucket can be extremely large if we failed to get
+    # path information. Split it into subgroups if needed.
+    SplitNoPathBucket(result)
+
+    largest_list_len = MakeChildrenDictsIntoLists(result)
+
+    if largest_list_len > BIG_BUCKET_LIMIT:
+        logging.warning('There are sections with %d nodes. '
+                        'Results might be unusable.' % largest_list_len)
+    return result
+
+
+def DumpCompactTree(symbols, symbol_path_origin_dir, outfile):
+    tree_root = MakeCompactTree(symbols, symbol_path_origin_dir)
+    with open(outfile, 'w') as out:
+        out.write('var tree_data=')
+        # Use separators without whitespace to get a smaller file.
+        json.dump(tree_root, out, separators=(',', ':'))
+    print('Writing %d bytes json' % os.path.getsize(outfile))
+
+
+def MakeSourceMap(symbols):
+    sources = {}
+    for _sym, _symbol_type, size, path, _address in symbols:
+        key = None
+        if path:
+            key = os.path.normpath(path)
+        else:
+            key = '[no path]'
+        if key not in sources:
+            sources[key] = {'path': path, 'symbol_count': 0, 'size': 0}
+        record = sources[key]
+        record['size'] += size
+        record['symbol_count'] += 1
+    return sources
+
+
+# Regex for parsing "nm" output. A sample line looks like this:
+# 0167b39c 00000018 t ACCESS_DESCRIPTION_free /path/file.c:95
+#
+# The fields are: address, size, type, name, source location
+# Regular expression explained ( see also: https://xkcd.com/208 ):
+# ([0-9a-f]{8,}+)   The address
+# [\s]+             Whitespace separator
+# ([0-9a-f]{8,}+)   The size. From here on out it's all optional.
+# [\s]+             Whitespace separator
+# (\S?)             The symbol type, which is any non-whitespace char
+# [\s*]             Whitespace separator
+# ([^\t]*)          Symbol name, any non-tab character (spaces ok!)
+# [\t]?             Tab separator
+# (.*)              The location (filename[:linennum|?][ (discriminator n)]
+sNmPattern = re.compile(
+    r'([0-9a-f]{8,})[\s]+([0-9a-f]{8,})[\s]*(\S?)[\s*]([^\t]*)[\t]?(.*)')
+
+
+class Progress():
+
+    def __init__(self):
+        self.count = 0
+        self.skip_count = 0
+        self.collisions = 0
+        self.time_last_output = time.time()
+        self.count_last_output = 0
+        self.disambiguations = 0
+        self.was_ambiguous = 0
+
+
+def RunElfSymbolizer(outfile, library, addr2line_binary, nm_binary, jobs,
+                     disambiguate, src_path):
+    nm_output = RunNm(library, nm_binary)
+    nm_output_lines = nm_output.splitlines()
+    nm_output_lines_len = len(nm_output_lines)
+    address_symbol = {}
+    progress = Progress()
+
+    def map_address_symbol(symbol, addr):
+        progress.count += 1
+        if addr in address_symbol:
+            # 'Collision between %s and %s.' % (str(symbol.name),
+            #                                   str(address_symbol[addr].name))
+            progress.collisions += 1
+        else:
+            if symbol.disambiguated:
+                progress.disambiguations += 1
+            if symbol.was_ambiguous:
+                progress.was_ambiguous += 1
+
+            address_symbol[addr] = symbol
+
+        progress_output()
+
+    def progress_output():
+        progress_chunk = 100
+        if progress.count % progress_chunk == 0:
+            time_now = time.time()
+            time_spent = time_now - progress.time_last_output
+            if time_spent > 1.0:
+                # Only output at most once per second.
+                progress.time_last_output = time_now
+                chunk_size = progress.count - progress.count_last_output
+                progress.count_last_output = progress.count
+                if time_spent > 0:
+                    speed = chunk_size / time_spent
+                else:
+                    speed = 0
+                progress_percent = (100.0 * (
+                    progress.count + progress.skip_count) / nm_output_lines_len)
+                disambiguation_percent = 0
+                if progress.disambiguations != 0:
+                    disambiguation_percent = (100.0 * progress.disambiguations /
+                                              progress.was_ambiguous)
+
+                sys.stdout.write(
+                    '\r%.1f%%: Looked up %d symbols (%d collisions, '
+                    '%d disambiguations where %.1f%% succeeded)'
+                    ' - %.1f lookups/s.' %
+                    (progress_percent, progress.count, progress.collisions,
+                     progress.disambiguations, disambiguation_percent, speed))
+
+    # In case disambiguation was disabled, we remove the source path (which upon
+    # being set signals the symbolizer to enable disambiguation)
+    if not disambiguate:
+        src_path = None
+    symbolizer = elf_symbolizer.ELFSymbolizer(
+        library,
+        addr2line_binary,
+        map_address_symbol,
+        max_concurrent_jobs=jobs,
+        source_root_path=src_path)
+    user_interrupted = False
+    try:
+        for binary_line in nm_output_lines:
+            line = binary_line.decode()
+            match = sNmPattern.match(line)
+            if match:
+                location = match.group(5)
+                if not location:
+                    addr = int(match.group(1), 16)
+                    size = int(match.group(2), 16)
+                    if addr in address_symbol:  # Already looked up, shortcut
+                        # ELFSymbolizer.
+                        map_address_symbol(address_symbol[addr], addr)
+                        continue
+                    elif size == 0:
+                        # Save time by not looking up empty symbols (do they even exist?)
+                        print('Empty symbol: ' + line)
+                    else:
+                        symbolizer.SymbolizeAsync(addr, addr)
+                        continue
+
+            progress.skip_count += 1
+    except KeyboardInterrupt:
+        user_interrupted = True
+        print('Interrupting - killing subprocesses. Please wait.')
+
+    try:
+        symbolizer.Join()
+    except KeyboardInterrupt:
+        # Don't want to abort here since we will be finished in a few seconds.
+        user_interrupted = True
+        print('Patience you must have my young padawan.')
+
+    print('')
+
+    if user_interrupted:
+        print('Skipping the rest of the file mapping. '
+              'Output will not be fully classified.')
+
+    symbol_path_origin_dir = os.path.dirname(os.path.abspath(library))
+
+    with open(outfile, 'w') as out:
+        for binary_line in nm_output_lines:
+            line = binary_line.decode()
+            match = sNmPattern.match(line)
+            if match:
+                location = match.group(5)
+                if not location:
+                    addr = int(match.group(1), 16)
+                    symbol = address_symbol.get(addr)
+                    if symbol is not None:
+                        path = '??'
+                        if symbol.source_path is not None:
+                            path = os.path.abspath(
+                                os.path.join(symbol_path_origin_dir,
+                                             symbol.source_path))
+                        line_number = 0
+                        if symbol.source_line is not None:
+                            line_number = symbol.source_line
+                        out.write('%s\t%s:%d\n' % (line, path, line_number))
+                        continue
+
+            out.write('%s\n' % line)
+
+    print('%d symbols in the results.' % len(address_symbol))
+
+
+def RunNm(binary, nm_binary):
+    cmd = [
+        nm_binary, '-C', '--print-size', '--size-sort', '--reverse-sort', binary
+    ]
+    nm_process = subprocess.Popen(
+        cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    (process_output, err_output) = nm_process.communicate()
+
+    if nm_process.returncode != 0:
+        if err_output:
+            raise Exception(err_output)
+        else:
+            raise Exception(process_output)
+
+    return process_output
+
+
+def GetNmSymbols(nm_infile, outfile, library, jobs, verbose, addr2line_binary,
+                 nm_binary, disambiguate, src_path):
+    if nm_infile is None:
+        if outfile is None:
+            outfile = tempfile.NamedTemporaryFile(delete=False).name
+
+        if verbose:
+            print('Running parallel addr2line, dumping symbols to ' + outfile)
+        RunElfSymbolizer(outfile, library, addr2line_binary, nm_binary, jobs,
+                         disambiguate, src_path)
+
+        nm_infile = outfile
+
+    elif verbose:
+        print('Using nm input from ' + nm_infile)
+    with open(nm_infile, 'r') as infile:
+        return list(binary_size_utils.ParseNm(infile))
+
+
+PAK_RESOURCE_ID_TO_STRING = {"inited": False}
+
+
+def LoadPakIdsFromResourceFile(filename):
+    """Given a file name, it loads everything that looks like a resource id
+  into PAK_RESOURCE_ID_TO_STRING."""
+    with open(filename) as resource_header:
+        for line in resource_header:
+            if line.startswith("#define "):
+                line_data = line.split()
+                if len(line_data) == 3:
+                    try:
+                        resource_number = int(line_data[2])
+                        resource_name = line_data[1]
+                        PAK_RESOURCE_ID_TO_STRING[
+                            resource_number] = resource_name
+                    except ValueError:
+                        pass
+
+
+def GetReadablePakResourceName(pak_file, resource_id):
+    """Pak resources have a numeric identifier. It is not helpful when
+  trying to locate where footprint is generated. This does its best to
+  map the number to a usable string."""
+    if not PAK_RESOURCE_ID_TO_STRING['inited']:
+        # Try to find resource header files generated by grit when
+        # building the pak file. We'll look for files named *resources.h"
+        # and lines of the type:
+        #    #define MY_RESOURCE_JS 1234
+        PAK_RESOURCE_ID_TO_STRING['inited'] = True
+        gen_dir = os.path.join(os.path.dirname(pak_file), 'gen')
+        if os.path.isdir(gen_dir):
+            for dirname, _dirs, files in os.walk(gen_dir):
+                for filename in files:
+                    if filename.endswith('resources.h'):
+                        LoadPakIdsFromResourceFile(
+                            os.path.join(dirname, filename))
+    return PAK_RESOURCE_ID_TO_STRING.get(resource_id,
+                                         'Pak Resource %d' % resource_id)
+
+
+def AddPakData(symbols, pak_file):
+    """Adds pseudo-symbols from a pak file."""
+    pak_file = os.path.abspath(pak_file)
+    with open(pak_file, 'rb') as pak:
+        data = pak.read()
+
+    PAK_FILE_VERSION = 4
+    HEADER_LENGTH = 2 * 4 + 1  # Two uint32s. (file version, number of entries)
+    # and one uint8 (encoding of text resources)
+    INDEX_ENTRY_SIZE = 2 + 4  # Each entry is a uint16 and a uint32.
+    version, num_entries, _encoding = struct.unpack('<IIB',
+                                                    data[:HEADER_LENGTH])
+    assert version == PAK_FILE_VERSION, (
+        'Unsupported pak file '
+        'version (%d) in %s. Only '
+        'support version %d' % (version, pak_file, PAK_FILE_VERSION))
+    if num_entries > 0:
+        # Read the index and data.
+        data = data[HEADER_LENGTH:]
+        for _ in range(num_entries):
+            resource_id, offset = struct.unpack('<HI', data[:INDEX_ENTRY_SIZE])
+            data = data[INDEX_ENTRY_SIZE:]
+            _next_id, next_offset = struct.unpack('<HI',
+                                                  data[:INDEX_ENTRY_SIZE])
+            resource_size = next_offset - offset
+
+            symbol_name = GetReadablePakResourceName(pak_file, resource_id)
+            symbol_path = pak_file
+            symbol_type = 'd'  # Data. Approximation.
+            symbol_size = resource_size
+            symbols.append((symbol_name, symbol_type, symbol_size, symbol_path))
+
+
+def _find_in_system_path(binary):
+    """Locate the full path to binary in the system path or return None
+  if not found."""
+    system_path = os.environ["PATH"].split(os.pathsep)
+    for path in system_path:
+        binary_path = os.path.join(path, binary)
+        if os.path.isfile(binary_path):
+            return binary_path
+    return None
+
+
+def CheckDebugFormatSupport(library, addr2line_binary):
+    """Kills the program if debug data is in an unsupported format.
+
+  There are two common versions of the DWARF debug formats and
+  since we are right now transitioning from DWARF2 to newer formats,
+  it's possible to have a mix of tools that are not compatible. Detect
+  that and abort rather than produce meaningless output."""
+    tool_output = subprocess.check_output([addr2line_binary,
+                                           '--version']).decode()
+    version_re = re.compile(r'^GNU [^ ]+ .* (\d+).(\d+).*?$', re.M)
+    parsed_output = version_re.match(tool_output)
+    major = int(parsed_output.group(1))
+    minor = int(parsed_output.group(2))
+    supports_dwarf4 = major > 2 or major == 2 and minor > 22
+
+    if supports_dwarf4:
+        return
+
+    print('Checking version of debug information in %s.' % library)
+    debug_info = subprocess.check_output(
+        ['readelf', '--debug-dump=info', '--dwarf-depth=1', library])
+    dwarf_version_re = re.compile(r'^\s+Version:\s+(\d+)$', re.M)
+    parsed_dwarf_format_output = dwarf_version_re.search(debug_info)
+    version = int(parsed_dwarf_format_output.group(1))
+    if version > 2:
+        print(
+            'The supplied tools only support DWARF2 debug data but the binary\n'
+            + 'uses DWARF%d. Update the tools or compile the binary\n' % version
+            + 'with -gdwarf-2.')
+        sys.exit(1)
+
+
+def main():
+    usage = """%prog [options]
+
+  Runs a spatial analysis on a given library, looking up the source locations
+  of its symbols and calculating how much space each directory, source file,
+  and so on is taking. The result is a report that can be used to pinpoint
+  sources of large portions of the binary, etceteras.
+
+  Under normal circumstances, you only need to pass two arguments, thusly:
+
+      %prog --library /path/to/library --destdir /path/to/output
+
+  In this mode, the program will dump the symbols from the specified library
+  and map those symbols back to source locations, producing a web-based
+  report in the specified output directory.
+
+  Other options are available via '--help'.
+  """
+    parser = optparse.OptionParser(usage=usage)
+    parser.add_option(
+        '--nm-in',
+        metavar='PATH',
+        help='if specified, use nm input from <path> instead of '
+        'generating it. Note that source locations should be '
+        'present in the file; i.e., no addr2line symbol lookups '
+        'will be performed when this option is specified. '
+        'Mutually exclusive with --library.')
+    parser.add_option(
+        '--destdir',
+        metavar='PATH',
+        help='write output to the specified directory. An HTML '
+        'report is generated here along with supporting files; '
+        'any existing report will be overwritten.')
+    parser.add_option(
+        '--library',
+        metavar='PATH',
+        help='if specified, process symbols in the library at '
+        'the specified path. Mutually exclusive with --nm-in.')
+    parser.add_option(
+        '--pak',
+        metavar='PATH',
+        help='if specified, includes the contents of the '
+        'specified *.pak file in the output.')
+    parser.add_option(
+        '--nm-binary',
+        help='use the specified nm binary to analyze library. '
+        'This is to be used when the nm in the path is not for '
+        'the right architecture or of the right version.')
+    parser.add_option(
+        '--addr2line-binary',
+        help='use the specified addr2line binary to analyze '
+        'library. This is to be used when the addr2line in '
+        'the path is not for the right architecture or '
+        'of the right version.')
+    parser.add_option(
+        '--jobs',
+        type='int',
+        help='number of jobs to use for the parallel '
+        'addr2line processing pool; defaults to 1. More '
+        'jobs greatly improve throughput but eat RAM like '
+        'popcorn, and take several gigabytes each. Start low '
+        'and ramp this number up until your machine begins to '
+        'struggle with RAM. '
+        'This argument is only valid when using --library.')
+    parser.add_option(
+        '-v',
+        '--verbose',
+        dest='verbose',
+        action='store_true',
+        help='be verbose, printing lots of status information.')
+    parser.add_option(
+        '--nm-out',
+        metavar='PATH',
+        help='(deprecated) No-op. nm.out is stored in --destdir.')
+    parser.add_option(
+        '--no-nm-out',
+        action='store_true',
+        help='do not keep the nm output file. This file is useful '
+        'if you want to see the fully processed nm output after '
+        'the symbols have been mapped to source locations, or if '
+        'you plan to run explain_binary_size_delta.py. By default '
+        'the file \'nm.out\' is placed alongside the generated '
+        'report. The nm.out file is only created when using '
+        '--library.')
+    parser.add_option(
+        '--disable-disambiguation',
+        action='store_true',
+        help='disables the disambiguation process altogether,'
+        ' NOTE: this may, depending on your toolchain, produce'
+        ' output with some symbols at the top layer if addr2line'
+        ' could not get the entire source path.')
+    parser.add_option(
+        '--source-path',
+        default='./',
+        help='the path to the source code of the output binary, '
+        'default set to current directory. Used in the'
+        ' disambiguation process.')
+    opts, _args = parser.parse_args()
+
+    if ((not opts.library) and
+        (not opts.nm_in)) or (opts.library and opts.nm_in):
+        parser.error('exactly one of --library or --nm-in is required')
+    if opts.nm_out:
+        print('WARNING: --nm-out is deprecated and has no effect.',
+              file=sys.stderr)
+    if (opts.nm_in):
+        if opts.jobs:
+            print('WARNING: --jobs has no effect when used with --nm-in',
+                  file=sys.stderr)
+    if not opts.destdir:
+        parser.error('--destdir is a required argument')
+    if not opts.jobs:
+        # Use the number of processors but cap between 2 and 4 since raw
+        # CPU power isn't the limiting factor. It's I/O limited, memory
+        # bus limited and available-memory-limited. Too many processes and
+        # the computer will run out of memory and it will be slow.
+        opts.jobs = max(2, min(4, multiprocessing.cpu_count()))
+
+    if opts.addr2line_binary:
+        assert os.path.isfile(opts.addr2line_binary)
+        addr2line_binary = opts.addr2line_binary
+    else:
+        addr2line_binary = _find_in_system_path('addr2line')
+        assert addr2line_binary, 'Unable to find addr2line in the path. '\
+            'Use --addr2line-binary to specify location.'
+
+    if opts.nm_binary:
+        assert os.path.isfile(opts.nm_binary)
+        nm_binary = opts.nm_binary
+    else:
+        nm_binary = _find_in_system_path('nm')
+        assert nm_binary, 'Unable to find nm in the path. Use --nm-binary '\
+            'to specify location.'
+
+    if opts.pak:
+        assert os.path.isfile(opts.pak), 'Could not find ' % opts.pak
+
+    print('addr2line: %s' % addr2line_binary)
+    print('nm: %s' % nm_binary)
+
+    if opts.library:
+        CheckDebugFormatSupport(opts.library, addr2line_binary)
+
+    # Prepare output directory and report guts
+    if not os.path.exists(opts.destdir):
+        os.makedirs(opts.destdir, 0o755)
+    nm_out = os.path.join(opts.destdir, 'nm.out')
+    if opts.no_nm_out:
+        nm_out = None
+
+    # Copy report boilerplate into output directory. This also proves that the
+    # output directory is safe for writing, so there should be no problems writing
+    # the nm.out file later.
+    data_js_file_name = os.path.join(opts.destdir, 'data.js')
+    d3_out = os.path.join(opts.destdir, 'd3')
+    if not os.path.exists(d3_out):
+        os.makedirs(d3_out, 0o755)
+    d3_src = os.path.join(os.path.dirname(__file__), '..', '..', 'd3', 'src')
+    template_src = os.path.join(os.path.dirname(__file__), 'template')
+    shutil.copy(os.path.join(d3_src, 'LICENSE'), d3_out)
+    shutil.copy(os.path.join(d3_src, 'd3.js'), d3_out)
+    shutil.copy(os.path.join(template_src, 'index.html'), opts.destdir)
+    shutil.copy(os.path.join(template_src, 'D3SymbolTreeMap.js'), opts.destdir)
+
+    # Run nm and/or addr2line to gather the data
+    symbols = GetNmSymbols(opts.nm_in, nm_out, opts.library, opts.jobs,
+                           opts.verbose is True, addr2line_binary, nm_binary,
+                           opts.disable_disambiguation is None,
+                           opts.source_path)
+
+    # Post-processing
+    if opts.pak:
+        AddPakData(symbols, opts.pak)
+    if opts.library:
+        symbol_path_origin_dir = os.path.dirname(os.path.abspath(opts.library))
+    else:
+        # Just a guess. Hopefully all paths in the input file are absolute.
+        symbol_path_origin_dir = os.path.abspath(os.getcwd())
+    # Dump JSON for the HTML report.
+    DumpCompactTree(symbols, symbol_path_origin_dir, data_js_file_name)
+    print('Report saved to ' + opts.destdir + '/index.html')
+
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git a/runtime/third_party/binary_size/src/template/D3SymbolTreeMap.js b/runtime/third_party/binary_size/src/template/D3SymbolTreeMap.js
new file mode 100644
index 0000000..88dd692
--- /dev/null
+++ b/runtime/third_party/binary_size/src/template/D3SymbolTreeMap.js
@@ -0,0 +1,938 @@
+// Copyright 2014 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.
+
+// TODO:
+// 1. Visibility functions: base on boxPadding.t, not 15
+// 2. Track a maxDisplayDepth that is user-settable:
+//    maxDepth == currentRoot.depth + maxDisplayDepth
+function D3SymbolTreeMap(mapWidth, mapHeight, levelsToShow) {
+  this._mapContainer = undefined;
+  this._mapWidth = mapWidth;
+  this._mapHeight = mapHeight;
+  this.boxPadding = {'l': 5, 'r': 5, 't': 20, 'b': 5};
+  this.infobox = undefined;
+  this._maskContainer = undefined;
+  this._highlightContainer = undefined;
+  // Transition in this order:
+  // 1. Exiting items go away.
+  // 2. Updated items move.
+  // 3. New items enter.
+  this._exitDuration=500;
+  this._updateDuration=500;
+  this._enterDuration=500;
+  this._firstTransition=true;
+  this._layout = undefined;
+  this._currentRoot = undefined;
+  this._currentNodes = undefined;
+  this._treeData = undefined;
+  this._maxLevelsToShow = levelsToShow;
+  this._currentMaxDepth = this._maxLevelsToShow;
+}
+
+/**
+ * Make a number pretty, with comma separators.
+ */
+D3SymbolTreeMap._pretty = function(num) {
+  var asString = String(num);
+  var result = '';
+  var counter = 0;
+  for (var x = asString.length - 1; x >= 0; x--) {
+    counter++;
+    if (counter === 4) {
+      result = ',' + result;
+      counter = 1;
+    }
+    result = asString.charAt(x) + result;
+  }
+  return result;
+}
+
+/**
+ * Express a number in terms of KiB, MiB, GiB, etc.
+ * Note that these are powers of 2, not of 10.
+ */
+D3SymbolTreeMap._byteify = function(num) {
+  var suffix;
+  if (num >= 1024) {
+    if (num >= 1024 * 1024 * 1024) {
+      suffix = 'GiB';
+      num = num / (1024 * 1024 * 1024);
+    } else if (num >= 1024 * 1024) {
+      suffix = 'MiB';
+      num = num / (1024 * 1024);
+    } else if (num >= 1024) {
+      suffix = 'KiB'
+      num = num / 1024;
+    }
+    return num.toFixed(2) + ' ' + suffix;
+  }
+  return num + ' B';
+}
+
+D3SymbolTreeMap._NM_SYMBOL_TYPE_DESCRIPTIONS = {
+  // Definitions concisely derived from the nm 'man' page
+  'A': 'Global absolute (A)',
+  'B': 'Global uninitialized data (B)',
+  'b': 'Local uninitialized data (b)',
+  'C': 'Global uninitialized common (C)',
+  'D': 'Global initialized data (D)',
+  'd': 'Local initialized data (d)',
+  'G': 'Global small initialized data (G)',
+  'g': 'Local small initialized data (g)',
+  'i': 'Indirect function (i)',
+  'N': 'Debugging (N)',
+  'p': 'Stack unwind (p)',
+  'R': 'Global read-only data (R)',
+  'r': 'Local read-only data (r)',
+  'S': 'Global small uninitialized data (S)',
+  's': 'Local small uninitialized data (s)',
+  'T': 'Global code (T)',
+  't': 'Local code (t)',
+  'U': 'Undefined (U)',
+  'u': 'Unique (u)',
+  'V': 'Global weak object (V)',
+  'v': 'Local weak object (v)',
+  'W': 'Global weak symbol (W)',
+  'w': 'Local weak symbol (w)',
+  '@': 'Vtable entry (@)', // non-standard, hack.
+  '-': 'STABS debugging (-)',
+  '?': 'Unrecognized (?)',
+};
+D3SymbolTreeMap._NM_SYMBOL_TYPES = '';
+for (var symbol_type in D3SymbolTreeMap._NM_SYMBOL_TYPE_DESCRIPTIONS) {
+  D3SymbolTreeMap._NM_SYMBOL_TYPES += symbol_type;
+}
+
+/**
+ * Given a symbol type code, look up and return a human-readable description
+ * of that symbol type. If the symbol type does not match one of the known
+ * types, the unrecognized description (corresponding to symbol type '?') is
+ * returned instead of null or undefined.
+ */
+D3SymbolTreeMap._getSymbolDescription = function(type) {
+  var result = D3SymbolTreeMap._NM_SYMBOL_TYPE_DESCRIPTIONS[type];
+  if (result === undefined) {
+    result = D3SymbolTreeMap._NM_SYMBOL_TYPE_DESCRIPTIONS['?'];
+  }
+  return result;
+}
+
+// Qualitative 12-value pastel Brewer palette.
+D3SymbolTreeMap._colorArray = [
+  'rgb(141,211,199)',
+  'rgb(255,255,179)',
+  'rgb(190,186,218)',
+  'rgb(251,128,114)',
+  'rgb(128,177,211)',
+  'rgb(253,180,98)',
+  'rgb(179,222,105)',
+  'rgb(252,205,229)',
+  'rgb(217,217,217)',
+  'rgb(188,128,189)',
+  'rgb(204,235,197)',
+  'rgb(255,237,111)'];
+
+D3SymbolTreeMap._initColorMap = function() {
+  var map = {};
+  var numColors = D3SymbolTreeMap._colorArray.length;
+  var count = 0;
+  for (var key in D3SymbolTreeMap._NM_SYMBOL_TYPE_DESCRIPTIONS) {
+    var index = count++ % numColors;
+    map[key] = d3.rgb(D3SymbolTreeMap._colorArray[index]);
+  }
+  D3SymbolTreeMap._colorMap = map;
+}
+D3SymbolTreeMap._initColorMap();
+
+D3SymbolTreeMap.getColorForType = function(type) {
+  var result = D3SymbolTreeMap._colorMap[type];
+  if (result === undefined) return d3.rgb('rgb(255,255,255)');
+  return result;
+}
+
+D3SymbolTreeMap.prototype.init = function() {
+  this.infobox = this._createInfoBox();
+  this._mapContainer = d3.select('body').append('div')
+      .style('position', 'relative')
+      .style('width', this._mapWidth)
+      .style('height', this._mapHeight)
+      .style('padding', 0)
+      .style('margin', 0)
+      .style('box-shadow', '5px 5px 5px #888');
+  this._layout = this._createTreeMapLayout();
+  this._setData(tree_data); // TODO: Don't use global 'tree_data'
+}
+
+/**
+ * Sets the data displayed by the treemap and layint out the map.
+ */
+D3SymbolTreeMap.prototype._setData = function(data) {
+  this._treeData = data;
+  console.time('_crunchStats');
+  this._crunchStats(data);
+  console.timeEnd('_crunchStats');
+  this._currentRoot = this._treeData;
+  this._currentNodes = this._layout.nodes(this._currentRoot);
+  this._currentMaxDepth = this._maxLevelsToShow;
+  this._doLayout();
+}
+
+/**
+ * Recursively traverses the entire tree starting from the specified node,
+ * computing statistics and recording metadata as it goes. Call this method
+ * only once per imported tree.
+ */
+D3SymbolTreeMap.prototype._crunchStats = function(node) {
+  var stack = [];
+  stack.idCounter = 0;
+  this._crunchStatsHelper(stack, node);
+}
+
+/**
+ * Invoke the specified visitor function on all data elements currently shown
+ * in the treemap including any and all of their children, starting at the
+ * currently-displayed root and descending recursively. The function will be
+ * passed the datum element representing each node. No traversal guarantees
+ * are made.
+ */
+D3SymbolTreeMap.prototype.visitFromDisplayedRoot = function(visitor) {
+  this._visit(this._currentRoot, visitor);
+}
+
+/**
+ * Helper function for visit functions.
+ */
+D3SymbolTreeMap.prototype._visit = function(datum, visitor) {
+  visitor.call(this, datum);
+  if (datum.children) for (var i = 0; i < datum.children.length; i++) {
+    this._visit(datum.children[i], visitor);
+  }
+}
+
+D3SymbolTreeMap.prototype._crunchStatsHelper = function(stack, node) {
+  // Only overwrite the node ID if it isn't already set.
+  // This allows stats to be crunched multiple times on subsets of data
+  // without breaking the data-to-ID bindings. New nodes get new IDs.
+  if (node.id === undefined) node.id = stack.idCounter++;
+  if (node.children === undefined) {
+    // Leaf node (symbol); accumulate stats.
+    for (var i = 0; i < stack.length; i++) {
+      var ancestor = stack[i];
+      if (!ancestor.symbol_stats) ancestor.symbol_stats = {};
+      if (ancestor.symbol_stats[node.t] === undefined) {
+        // New symbol type we haven't seen before, just record.
+        ancestor.symbol_stats[node.t] = {'count': 1,
+                                         'size': node.value};
+      } else {
+        // Existing symbol type, increment.
+        ancestor.symbol_stats[node.t].count++;
+        ancestor.symbol_stats[node.t].size += node.value;
+      }
+    }
+  } else for (var i = 0; i < node.children.length; i++) {
+    stack.push(node);
+    this._crunchStatsHelper(stack, node.children[i]);
+    stack.pop();
+  }
+}
+
+D3SymbolTreeMap.prototype._createTreeMapLayout = function() {
+  var result = d3.layout.treemap()
+      .padding([this.boxPadding.t, this.boxPadding.r,
+                this.boxPadding.b, this.boxPadding.l])
+      .size([this._mapWidth, this._mapHeight]);
+  return result;
+}
+
+D3SymbolTreeMap.prototype.resize = function(width, height) {
+  this._mapWidth = width;
+  this._mapHeight = height;
+  this._mapContainer.style('width', width).style('height', height);
+  this._layout.size([this._mapWidth, this._mapHeight]);
+  this._currentNodes = this._layout.nodes(this._currentRoot);
+  this._doLayout();
+}
+
+D3SymbolTreeMap.prototype._zoomDatum = function(datum) {
+  if (this._currentRoot === datum) return; // already here
+  this._hideHighlight(datum);
+  this._hideInfoBox(datum);
+  this._currentRoot = datum;
+  this._currentNodes = this._layout.nodes(this._currentRoot);
+  this._currentMaxDepth = this._currentRoot.depth + this._maxLevelsToShow;
+  console.log('zooming into datum ' + this._currentRoot.n);
+  this._doLayout();
+}
+
+D3SymbolTreeMap.prototype.setMaxLevels = function(levelsToShow) {
+  this._maxLevelsToShow = levelsToShow;
+  this._currentNodes = this._layout.nodes(this._currentRoot);
+  this._currentMaxDepth = this._currentRoot.depth + this._maxLevelsToShow;
+  console.log('setting max levels to show: ' + this._maxLevelsToShow);
+  this._doLayout();
+}
+
+/**
+ * Clone the specified tree, returning an independent copy of the data.
+ * Only the original attributes expected to exist prior to invoking
+ * _crunchStatsHelper are retained, with the exception of the 'id' attribute
+ * (which must be retained for proper transitions).
+ * If the optional filter parameter is provided, it will be called with 'this'
+ * set to this treemap instance and passed the 'datum' object as an argument.
+ * When specified, the copy will retain only the data for which the filter
+ * function returns true.
+ */
+D3SymbolTreeMap.prototype._clone = function(datum, filter) {
+  var trackingStats = false;
+  if (this.__cloneState === undefined) {
+    console.time('_clone');
+    trackingStats = true;
+    this.__cloneState = {'accepted': 0, 'rejected': 0,
+                         'forced': 0, 'pruned': 0};
+  }
+
+  // Must go depth-first. All parents of children that are accepted by the
+  // filter must be preserved!
+  var copy = {'n': datum.n, 'k': datum.k};
+  var childAccepted = false;
+  if (datum.children !== undefined) {
+    for (var i = 0; i < datum.children.length; i++) {
+      var copiedChild = this._clone(datum.children[i], filter);
+      if (copiedChild !== undefined) {
+        childAccepted = true; // parent must also be accepted.
+        if (copy.children === undefined) copy.children = [];
+        copy.children.push(copiedChild);
+      }
+    }
+  }
+
+  // Ignore nodes that don't match the filter, when present.
+  var accept = false;
+  if (childAccepted) {
+    // Parent of an accepted child must also be accepted.
+    this.__cloneState.forced++;
+    accept = true;
+  } else if (filter !== undefined && filter.call(this, datum) !== true) {
+    this.__cloneState.rejected++;
+  } else if (datum.children === undefined) {
+    // Accept leaf nodes that passed the filter
+    this.__cloneState.accepted++;
+    accept = true;
+  } else {
+    // Non-leaf node. If no children are accepted, prune it.
+    this.__cloneState.pruned++;
+  }
+
+  if (accept) {
+    if (datum.id !== undefined) copy.id = datum.id;
+    if (datum.lastPathElement !== undefined) {
+      copy.lastPathElement = datum.lastPathElement;
+    }
+    if (datum.t !== undefined) copy.t = datum.t;
+    if (datum.value !== undefined && datum.children === undefined) {
+      copy.value = datum.value;
+    }
+  } else {
+    // Discard the copy we were going to return
+    copy = undefined;
+  }
+
+  if (trackingStats === true) {
+    // We are the fist call in the recursive chain.
+    console.timeEnd('_clone');
+    var totalAccepted = this.__cloneState.accepted +
+                        this.__cloneState.forced;
+    console.log(
+        totalAccepted + ' nodes retained (' +
+        this.__cloneState.forced + ' forced by accepted children, ' +
+        this.__cloneState.accepted + ' accepted on their own merits), ' +
+        this.__cloneState.rejected + ' nodes (and their children) ' +
+                                     'filtered out,' +
+        this.__cloneState.pruned + ' nodes pruned because because no ' +
+                                   'children remained.');
+    delete this.__cloneState;
+  }
+  return copy;
+}
+
+D3SymbolTreeMap.prototype.filter = function(filter) {
+  // Ensure we have a copy of the original root.
+  if (this._backupTree === undefined) this._backupTree = this._treeData;
+  this._mapContainer.selectAll('div').remove();
+  this._setData(this._clone(this._backupTree, filter));
+}
+
+D3SymbolTreeMap.prototype._doLayout = function() {
+  console.time('_doLayout');
+  this._handleInodes();
+  this._handleLeaves();
+  this._firstTransition = false;
+  console.timeEnd('_doLayout');
+}
+
+D3SymbolTreeMap.prototype._highlightElement = function(datum, selection) {
+  this._showHighlight(datum, selection);
+}
+
+D3SymbolTreeMap.prototype._unhighlightElement = function(datum, selection) {
+  this._hideHighlight(datum, selection);
+}
+
+D3SymbolTreeMap.prototype._handleInodes = function() {
+  console.time('_handleInodes');
+  var thisTreeMap = this;
+  var inodes = this._currentNodes.filter(function(datum){
+    return (datum.depth <= thisTreeMap._currentMaxDepth) &&
+            datum.children !== undefined;
+  });
+  var cellsEnter = this._mapContainer.selectAll('div.inode')
+      .data(inodes, function(datum) { return datum.id; })
+      .enter()
+      .append('div').attr('class', 'inode').attr('id', function(datum){
+          return 'node-' + datum.id;});
+
+
+  // Define enter/update/exit for inodes
+  cellsEnter
+      .append('div')
+      .attr('class', 'rect inode_rect_entering')
+      .style('z-index', function(datum) { return datum.id * 2; })
+      .style('position', 'absolute')
+      .style('left', function(datum) { return datum.x; })
+      .style('top', function(datum){ return datum.y; })
+      .style('width', function(datum){ return datum.dx; })
+      .style('height', function(datum){ return datum.dy; })
+      .style('opacity', '0')
+      .style('border', '1px solid black')
+      .style('background-image', function(datum) {
+        return thisTreeMap._makeSymbolBucketBackgroundImage.call(
+               thisTreeMap, datum);
+      })
+      .style('background-color', function(datum) {
+        if (datum.t === undefined) return 'rgb(220,220,220)';
+        return D3SymbolTreeMap.getColorForType(datum.t).toString();
+      })
+      .on('mouseover', function(datum){
+        thisTreeMap._highlightElement.call(
+            thisTreeMap, datum, d3.select(this));
+        thisTreeMap._showInfoBox.call(thisTreeMap, datum);
+      })
+      .on('mouseout', function(datum){
+        thisTreeMap._unhighlightElement.call(
+            thisTreeMap, datum, d3.select(this));
+        thisTreeMap._hideInfoBox.call(thisTreeMap, datum);
+      })
+      .on('mousemove', function(){
+          thisTreeMap._moveInfoBox.call(thisTreeMap, event);
+      })
+      .on('dblclick', function(datum){
+        if (datum !== thisTreeMap._currentRoot) {
+          // Zoom into the selection
+          thisTreeMap._zoomDatum(datum);
+        } else if (datum.parent) {
+          console.log('event.shiftKey=' + event.shiftKey);
+          if (event.shiftKey === true) {
+            // Back to root
+            thisTreeMap._zoomDatum(thisTreeMap._treeData);
+          } else {
+            // Zoom out of the selection
+            thisTreeMap._zoomDatum(datum.parent);
+          }
+        }
+      });
+  cellsEnter
+      .append('div')
+      .attr('class', 'label inode_label_entering')
+      .style('z-index', function(datum) { return (datum.id * 2) + 1; })
+      .style('position', 'absolute')
+      .style('left', function(datum){ return datum.x; })
+      .style('top', function(datum){ return datum.y; })
+      .style('width', function(datum) { return datum.dx; })
+      .style('height', function(datum) { return thisTreeMap.boxPadding.t; })
+      .style('opacity', '0')
+      .style('pointer-events', 'none')
+      .style('-webkit-user-select', 'none')
+      .style('overflow', 'hidden') // required for ellipsis
+      .style('white-space', 'nowrap') // required for ellipsis
+      .style('text-overflow', 'ellipsis')
+      .style('text-align', 'center')
+      .style('vertical-align', 'top')
+      .style('visibility', function(datum) {
+        return (datum.dx < 15 || datum.dy < 15) ? 'hidden' : 'visible';
+      })
+      .text(function(datum) {
+        var sizeish = ' [' + D3SymbolTreeMap._byteify(datum.value) + ']'
+        var text;
+        if (datum.k === 'b') { // bucket
+          if (datum === thisTreeMap._currentRoot) {
+            text = thisTreeMap.pathFor(datum) + ': '
+                + D3SymbolTreeMap._getSymbolDescription(datum.t)
+          } else {
+            text = D3SymbolTreeMap._getSymbolDescription(datum.t);
+          }
+        } else if (datum === thisTreeMap._currentRoot) {
+          // The top-most level should always show the complete path
+          text = thisTreeMap.pathFor(datum);
+        } else {
+          // Anything that isn't a bucket or a leaf (symbol) or the
+          // current root should just show its name.
+          text = datum.n;
+        }
+        return text + sizeish;
+      }
+  );
+
+  // Complicated transition logic:
+  // For nodes that are entering, we want to fade them in in-place AFTER
+  // any adjusting nodes have resized and moved around. That way, new nodes
+  // seamlessly appear in the right spot after their containers have resized
+  // and moved around.
+  // To do this we do some trickery:
+  // 1. Define a '_entering' class on the entering elements
+  // 2. Use this to select only the entering elements and apply the opacity
+  //    transition.
+  // 3. Use the same transition to drop the '_entering' suffix, so that they
+  //    will correctly update in later zoom/resize/whatever operations.
+  // 4. The update transition is achieved by selecting the elements without
+  //    the '_entering_' suffix and applying movement and resizing transition
+  //    effects.
+  this._mapContainer.selectAll('div.inode_rect_entering').transition()
+      .duration(thisTreeMap._enterDuration).delay(
+          this._firstTransition ? 0 : thisTreeMap._exitDuration +
+              thisTreeMap._updateDuration)
+      .attr('class', 'rect inode_rect')
+      .style('opacity', '1')
+  this._mapContainer.selectAll('div.inode_label_entering').transition()
+      .duration(thisTreeMap._enterDuration).delay(
+          this._firstTransition ? 0 : thisTreeMap._exitDuration +
+              thisTreeMap._updateDuration)
+      .attr('class', 'label inode_label')
+      .style('opacity', '1')
+  this._mapContainer.selectAll('div.inode_rect').transition()
+      .duration(thisTreeMap._updateDuration).delay(thisTreeMap._exitDuration)
+      .style('opacity', '1')
+      .style('background-image', function(datum) {
+        return thisTreeMap._makeSymbolBucketBackgroundImage.call(
+            thisTreeMap, datum);
+      })
+      .style('left', function(datum) { return datum.x; })
+      .style('top', function(datum){ return datum.y; })
+      .style('width', function(datum){ return datum.dx; })
+      .style('height', function(datum){ return datum.dy; });
+  this._mapContainer.selectAll('div.inode_label').transition()
+      .duration(thisTreeMap._updateDuration).delay(thisTreeMap._exitDuration)
+      .style('opacity', '1')
+      .style('visibility', function(datum) {
+        return (datum.dx < 15 || datum.dy < 15) ? 'hidden' : 'visible';
+      })
+      .style('left', function(datum){ return datum.x; })
+      .style('top', function(datum){ return datum.y; })
+      .style('width', function(datum) { return datum.dx; })
+      .style('height', function(datum) { return thisTreeMap.boxPadding.t; })
+      .text(function(datum) {
+        var sizeish = ' [' + D3SymbolTreeMap._byteify(datum.value) + ']'
+        var text;
+        if (datum.k === 'b') {
+          if (datum === thisTreeMap._currentRoot) {
+            text = thisTreeMap.pathFor(datum) + ': ' +
+                D3SymbolTreeMap._getSymbolDescription(datum.t)
+          } else {
+            text = D3SymbolTreeMap._getSymbolDescription(datum.t);
+          }
+        } else if (datum === thisTreeMap._currentRoot) {
+          // The top-most level should always show the complete path
+          text = thisTreeMap.pathFor(datum);
+        } else {
+          // Anything that isn't a bucket or a leaf (symbol) or the
+          // current root should just show its name.
+          text = datum.n;
+        }
+        return text + sizeish;
+      });
+  var exit = this._mapContainer.selectAll('div.inode')
+      .data(inodes, function(datum) { return 'inode-' + datum.id; })
+      .exit();
+  exit.selectAll('div.inode_rect').transition().duration(
+      thisTreeMap._exitDuration).style('opacity', 0);
+  exit.selectAll('div.inode_label').transition().duration(
+      thisTreeMap._exitDuration).style('opacity', 0);
+  exit.transition().delay(thisTreeMap._exitDuration + 1).remove();
+
+  console.log(inodes.length + ' inodes layed out.');
+  console.timeEnd('_handleInodes');
+}
+
+D3SymbolTreeMap.prototype._handleLeaves = function() {
+  console.time('_handleLeaves');
+  var color_fn = d3.scale.category10();
+  var thisTreeMap = this;
+  var leaves = this._currentNodes.filter(function(datum){
+    return (datum.depth <= thisTreeMap._currentMaxDepth) &&
+        datum.children === undefined; });
+  var cellsEnter = this._mapContainer.selectAll('div.leaf')
+      .data(leaves, function(datum) { return datum.id; })
+      .enter()
+      .append('div').attr('class', 'leaf').attr('id', function(datum){
+        return 'node-' + datum.id;
+      });
+
+  // Define enter/update/exit for leaves
+  cellsEnter
+      .append('div')
+      .attr('class', 'rect leaf_rect_entering')
+      .style('z-index', function(datum) { return datum.id * 2; })
+      .style('position', 'absolute')
+      .style('left', function(datum){ return datum.x; })
+      .style('top', function(datum){ return datum.y; })
+      .style('width', function(datum){ return datum.dx; })
+      .style('height', function(datum){ return datum.dy; })
+      .style('opacity', '0')
+      .style('background-color', function(datum) {
+        if (datum.t === undefined) return 'rgb(220,220,220)';
+        return D3SymbolTreeMap.getColorForType(datum.t)
+            .darker(0.3).toString();
+      })
+      .style('border', '1px solid black')
+      .on('mouseover', function(datum){
+        thisTreeMap._highlightElement.call(
+            thisTreeMap, datum, d3.select(this));
+        thisTreeMap._showInfoBox.call(thisTreeMap, datum);
+      })
+      .on('mouseout', function(datum){
+        thisTreeMap._unhighlightElement.call(
+            thisTreeMap, datum, d3.select(this));
+        thisTreeMap._hideInfoBox.call(thisTreeMap, datum);
+      })
+      .on('mousemove', function(){ thisTreeMap._moveInfoBox.call(
+        thisTreeMap, event);
+      });
+  cellsEnter
+      .append('div')
+      .attr('class', 'label leaf_label_entering')
+      .style('z-index', function(datum) { return (datum.id * 2) + 1; })
+      .style('position', 'absolute')
+      .style('left', function(datum){ return datum.x; })
+      .style('top', function(datum){ return datum.y; })
+      .style('width', function(datum) { return datum.dx; })
+      .style('height', function(datum) { return datum.dy; })
+      .style('opacity', '0')
+      .style('pointer-events', 'none')
+      .style('-webkit-user-select', 'none')
+      .style('overflow', 'hidden') // required for ellipsis
+      .style('white-space', 'nowrap') // required for ellipsis
+      .style('text-overflow', 'ellipsis')
+      .style('text-align', 'center')
+      .style('vertical-align', 'middle')
+      .style('visibility', function(datum) {
+        return (datum.dx < 15 || datum.dy < 15) ? 'hidden' : 'visible';
+      })
+      .text(function(datum) { return datum.n; });
+
+  // Complicated transition logic: See note in _handleInodes()
+  this._mapContainer.selectAll('div.leaf_rect_entering').transition()
+      .duration(thisTreeMap._enterDuration).delay(
+          this._firstTransition ? 0 : thisTreeMap._exitDuration +
+              thisTreeMap._updateDuration)
+      .attr('class', 'rect leaf_rect')
+      .style('opacity', '1')
+  this._mapContainer.selectAll('div.leaf_label_entering').transition()
+      .duration(thisTreeMap._enterDuration).delay(
+          this._firstTransition ? 0 : thisTreeMap._exitDuration +
+              thisTreeMap._updateDuration)
+      .attr('class', 'label leaf_label')
+      .style('opacity', '1')
+  this._mapContainer.selectAll('div.leaf_rect').transition()
+      .duration(thisTreeMap._updateDuration).delay(thisTreeMap._exitDuration)
+      .style('opacity', '1')
+      .style('left', function(datum){ return datum.x; })
+      .style('top', function(datum){ return datum.y; })
+      .style('width', function(datum){ return datum.dx; })
+      .style('height', function(datum){ return datum.dy; });
+  this._mapContainer.selectAll('div.leaf_label').transition()
+      .duration(thisTreeMap._updateDuration).delay(thisTreeMap._exitDuration)
+      .style('opacity', '1')
+      .style('visibility', function(datum) {
+          return (datum.dx < 15 || datum.dy < 15) ? 'hidden' : 'visible';
+      })
+      .style('left', function(datum){ return datum.x; })
+      .style('top', function(datum){ return datum.y; })
+      .style('width', function(datum) { return datum.dx; })
+      .style('height', function(datum) { return datum.dy; });
+  var exit = this._mapContainer.selectAll('div.leaf')
+      .data(leaves, function(datum) { return 'leaf-' + datum.id; })
+      .exit();
+  exit.selectAll('div.leaf_rect').transition()
+      .duration(thisTreeMap._exitDuration)
+      .style('opacity', 0);
+  exit.selectAll('div.leaf_label').transition()
+      .duration(thisTreeMap._exitDuration)
+      .style('opacity', 0);
+  exit.transition().delay(thisTreeMap._exitDuration + 1).remove();
+
+  console.log(leaves.length + ' leaves layed out.');
+  console.timeEnd('_handleLeaves');
+}
+
+D3SymbolTreeMap.prototype._makeSymbolBucketBackgroundImage = function(datum) {
+  if (!(datum.t === undefined && datum.depth == this._currentMaxDepth)) {
+    return 'none';
+  }
+  var text = '';
+  var lastStop = 0;
+  for (var x = 0; x < D3SymbolTreeMap._NM_SYMBOL_TYPES.length; x++) {
+    symbol_type = D3SymbolTreeMap._NM_SYMBOL_TYPES.charAt(x);
+    var stats = datum.symbol_stats[symbol_type];
+    if (stats !== undefined) {
+      if (text.length !== 0) {
+        text += ', ';
+      }
+      var percent = 100 * (stats.size / datum.value);
+      var nowStop = lastStop + percent;
+      var tempcolor = D3SymbolTreeMap.getColorForType(symbol_type);
+      var color = d3.rgb(tempcolor).toString();
+      text += color + ' ' + lastStop + '%, ' + color + ' ' +
+          nowStop + '%';
+      lastStop = nowStop;
+    }
+  }
+  return 'linear-gradient(' + (datum.dx > datum.dy ? 'to right' :
+                               'to bottom') + ', ' + text + ')';
+}
+
+D3SymbolTreeMap.prototype.pathFor = function(datum) {
+  if (datum.__path) return datum.__path;
+  parts=[];
+  node = datum;
+  while (node) {
+    if (node.k === 'p') { // path node
+      if(node.n !== '/') parts.unshift(node.n);
+    }
+    node = node.parent;
+  }
+  datum.__path = '/' + parts.join('/');
+  return datum.__path;
+}
+
+D3SymbolTreeMap.prototype._createHighlight = function(datum, selection) {
+  var x = parseInt(selection.style('left'));
+  var y = parseInt(selection.style('top'));
+  var w = parseInt(selection.style('width'));
+  var h = parseInt(selection.style('height'));
+  datum.highlight = this._mapContainer.append('div')
+      .attr('id', 'h-' + datum.id)
+      .attr('class', 'highlight')
+      .style('pointer-events', 'none')
+      .style('-webkit-user-select', 'none')
+      .style('z-index', '999999')
+      .style('position', 'absolute')
+      .style('top', y-2)
+      .style('left', x-2)
+      .style('width', w+4)
+      .style('height', h+4)
+      .style('margin', 0)
+      .style('padding', 0)
+      .style('border', '4px outset rgba(250,40,200,0.9)')
+      .style('box-sizing', 'border-box')
+      .style('opacity', 0.0);
+}
+
+D3SymbolTreeMap.prototype._showHighlight = function(datum, selection) {
+  if (datum === this._currentRoot) return;
+  if (datum.highlight === undefined) {
+    this._createHighlight(datum, selection);
+  }
+  datum.highlight.transition().duration(200).style('opacity', 1.0);
+}
+
+D3SymbolTreeMap.prototype._hideHighlight = function(datum, selection) {
+  if (datum.highlight === undefined) return;
+  datum.highlight.transition().duration(750)
+      .style('opacity', 0)
+      .each('end', function(){
+        if (datum.highlight) datum.highlight.remove();
+        delete datum.highlight;
+      });
+}
+
+D3SymbolTreeMap.prototype._createInfoBox = function() {
+  return d3.select('body')
+      .append('div')
+      .attr('id', 'infobox')
+      .style('z-index', '2147483647') // (2^31) - 1: Hopefully safe :)
+      .style('position', 'absolute')
+      .style('visibility', 'hidden')
+      .style('background-color', 'rgba(255,255,255, 0.9)')
+      .style('border', '1px solid black')
+      .style('padding', '10px')
+      .style('-webkit-user-select', 'none')
+      .style('box-shadow', '3px 3px rgba(70,70,70,0.5)')
+      .style('border-radius', '10px')
+      .style('white-space', 'nowrap');
+}
+
+D3SymbolTreeMap.prototype._showInfoBox = function(datum) {
+  this.infobox.text('');
+  var numSymbols = 0;
+  var sizeish = D3SymbolTreeMap._pretty(datum.value) + ' bytes (' +
+      D3SymbolTreeMap._byteify(datum.value) + ')';
+  if (datum.k === 'p' || datum.k === 'b') { // path or bucket
+    if (datum.symbol_stats) { // can be empty if filters are applied
+      for (var x = 0; x < D3SymbolTreeMap._NM_SYMBOL_TYPES.length; x++) {
+        symbol_type = D3SymbolTreeMap._NM_SYMBOL_TYPES.charAt(x);
+        var stats = datum.symbol_stats[symbol_type];
+        if (stats !== undefined) numSymbols += stats.count;
+      }
+    }
+  } else if (datum.k === 's') { // symbol
+    numSymbols = 1;
+  }
+
+  if (datum.k === 'p' && !datum.lastPathElement) {
+    this.infobox.append('div').text('Directory: ' + this.pathFor(datum))
+    this.infobox.append('div').text('Size: ' + sizeish);
+  } else {
+    if (datum.k === 'p') { // path
+      this.infobox.append('div').text('File: ' + this.pathFor(datum))
+      this.infobox.append('div').text('Size: ' + sizeish);
+    } else if (datum.k === 'b') { // bucket
+      this.infobox.append('div').text('Symbol Bucket: ' +
+          D3SymbolTreeMap._getSymbolDescription(datum.t));
+      this.infobox.append('div').text('Count: ' + numSymbols);
+      this.infobox.append('div').text('Size: ' + sizeish);
+      this.infobox.append('div').text('Location: ' + this.pathFor(datum))
+    } else if (datum.k === 's') { // symbol
+      this.infobox.append('div').text('Symbol: ' + datum.n);
+      this.infobox.append('div').text('Type: ' +
+          D3SymbolTreeMap._getSymbolDescription(datum.t));
+      this.infobox.append('div').text('Size: ' + sizeish);
+      this.infobox.append('div').text('Location: ' + this.pathFor(datum))
+    }
+  }
+  if (datum.k === 'p') {
+    this.infobox.append('div')
+        .text('Number of symbols: ' + D3SymbolTreeMap._pretty(numSymbols));
+    if (datum.symbol_stats) { // can be empty if filters are applied
+      var table = this.infobox.append('table')
+          .attr('border', 1).append('tbody');
+      var header = table.append('tr');
+      header.append('th').text('Type');
+      header.append('th').text('Count');
+      header.append('th')
+          .style('white-space', 'nowrap')
+          .text('Total Size (Bytes)');
+      for (var x = 0; x < D3SymbolTreeMap._NM_SYMBOL_TYPES.length; x++) {
+        symbol_type = D3SymbolTreeMap._NM_SYMBOL_TYPES.charAt(x);
+        var stats = datum.symbol_stats[symbol_type];
+        if (stats !== undefined) {
+          var tr = table.append('tr');
+          tr.append('td')
+              .style('white-space', 'nowrap')
+              .text(D3SymbolTreeMap._getSymbolDescription(
+                  symbol_type));
+          tr.append('td').text(D3SymbolTreeMap._pretty(stats.count));
+          tr.append('td').text(D3SymbolTreeMap._pretty(stats.size));
+        }
+      }
+    }
+  }
+  this.infobox.style('visibility', 'visible');
+}
+
+D3SymbolTreeMap.prototype._hideInfoBox = function(datum) {
+  this.infobox.style('visibility', 'hidden');
+}
+
+D3SymbolTreeMap.prototype._moveInfoBox = function(event) {
+  var element = document.getElementById('infobox');
+  var w = element.offsetWidth;
+  var h = element.offsetHeight;
+  var offsetLeft = 10;
+  var offsetTop = 10;
+
+  var rightLimit = window.innerWidth;
+  var rightEdge = event.pageX + offsetLeft + w;
+  if (rightEdge > rightLimit) {
+    // Too close to screen edge, reflect around the cursor
+    offsetLeft = -1 * (w + offsetLeft);
+  }
+
+  var bottomLimit = window.innerHeight;
+  var bottomEdge = event.pageY + offsetTop + h;
+  if (bottomEdge > bottomLimit) {
+    // Too close ot screen edge, reflect around the cursor
+    offsetTop = -1 * (h + offsetTop);
+  }
+
+  this.infobox.style('top', (event.pageY + offsetTop) + 'px')
+      .style('left', (event.pageX + offsetLeft) + 'px');
+}
+
+D3SymbolTreeMap.prototype.biggestSymbols = function(maxRecords) {
+  var result = undefined;
+  var smallest = undefined;
+  var sortFunction = function(a,b) {
+    var result = b.value - a.value;
+    if (result !== 0) return result; // sort by size
+    var pathA = treemap.pathFor(a); // sort by path
+    var pathB = treemap.pathFor(b);
+    if (pathA > pathB) return 1;
+    if (pathB > pathA) return -1;
+    return a.n - b.n; // sort by symbol name
+  };
+  this.visitFromDisplayedRoot(function(datum) {
+    if (datum.children) return; // ignore non-leaves
+    if (!result) { // first element
+      result = [datum];
+      smallest = datum.value;
+      return;
+    }
+    if (result.length < maxRecords) { // filling the array
+      result.push(datum);
+      return;
+    }
+    if (datum.value > smallest) { // array is already full
+      result.push(datum);
+      result.sort(sortFunction);
+      result.pop(); // get rid of smallest element
+      smallest = result[maxRecords - 1].value; // new threshold for entry
+    }
+  });
+  result.sort(sortFunction);
+  return result;
+}
+
+D3SymbolTreeMap.prototype.biggestPaths = function(maxRecords) {
+  var result = undefined;
+  var smallest = undefined;
+  var sortFunction = function(a,b) {
+    var result = b.value - a.value;
+    if (result !== 0) return result; // sort by size
+    var pathA = treemap.pathFor(a); // sort by path
+    var pathB = treemap.pathFor(b);
+    if (pathA > pathB) return 1;
+    if (pathB > pathA) return -1;
+    console.log('warning, multiple entries for the same path: ' + pathA);
+    return 0; // should be impossible
+  };
+  this.visitFromDisplayedRoot(function(datum) {
+    if (!datum.lastPathElement) return; // ignore non-files
+    if (!result) { // first element
+      result = [datum];
+      smallest = datum.value;
+      return;
+    }
+    if (result.length < maxRecords) { // filling the array
+      result.push(datum);
+      return;
+    }
+    if (datum.value > smallest) { // array is already full
+      result.push(datum);
+      result.sort(sortFunction);
+      result.pop(); // get rid of smallest element
+      smallest = result[maxRecords - 1].value; // new threshold for entry
+    }
+  });
+  result.sort(sortFunction);
+  return result;
+}
diff --git a/runtime/third_party/binary_size/src/template/index.html b/runtime/third_party/binary_size/src/template/index.html
new file mode 100644
index 0000000..7e1a1fc
--- /dev/null
+++ b/runtime/third_party/binary_size/src/template/index.html
@@ -0,0 +1,525 @@
+<!--
+  Copyright 2014 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.
+-->
+<html>
+<head>
+<title>Binary Size Analysis</title>
+<script src="d3/d3.js" charset="utf-8"></script>
+<script src="D3SymbolTreeMap.js" charset="utf-8"></script>
+<script src="data.js" charset="utf-8"></script>
+<style>
+body {
+    margin: 0px;
+    padding: 5px;
+}
+.swatch {
+    border: 1px solid rgb(100,100,100);
+    -webkit-user-select: none;
+    cursor: default;
+}
+</style>
+<script>
+var treemap;
+var filterChanging = false;
+var savedSettings = {};
+
+function init() {
+    if (window.metadata !== undefined && window.metadata.subtitle) {
+        document.getElementById('subtitle').innerHTML = ': ' + escape(metadata.subtitle);
+    }
+    initFilterOptions();
+    treemap = new D3SymbolTreeMap(
+        savedSettings.width,
+        savedSettings.height,
+        savedSettings.maxLevels);
+    treemap.init();
+}
+
+function getIdealSizes() {
+    var width = window.innerWidth - 20;
+    var height = window.innerHeight - 70;
+    return {'width': width, 'height': height};
+}
+
+function showReport(title, data, headers, dataFunction, styleFunction) {
+    var div =  d3.select('body').append('div')
+        .style('margin', '0')
+        .style('padding', '5px')
+        .style('position', 'absolute')
+        .style('top', '10%')
+        .style('left', '10%')
+        .style('background-color', 'rgba(255,255,255,0.9)')
+        .style('width', '80%')
+        .style('height', '80%')
+        .style('z-index', '2147483647')
+        .style('border', '3px ridge grey')
+        .style('box-shadow', '10px 10px 5px rgba(80,80,80,0.7)')
+        .style('text-align', 'center')
+        .style('border-radius', '10px');
+    var titlebar = div.append('div')
+        .style('margin', '0')
+        .style('padding', '5px')
+        .style('position', 'absolute')
+        .style('top', '0%')
+        .style('left', '0%')
+        .style('width', '100%')
+        .style('height', '10%')
+        .style('font-size', 'x-large');
+    titlebar.text(title);
+    var controls = div.append('div')
+        .style('margin', '0')
+        .style('padding', '5px')
+        .style('position', 'absolute')
+        .style('top', '90%')
+        .style('left', '0%')
+        .style('width', '100%')
+        .style('height', '10%');
+    controls.append('input').attr('type', 'button')
+        .attr('value', 'Dismiss')
+        .on('click', function(){div.remove();});
+
+    var tableDiv = div.append('div')
+        .style('overflow', 'auto')
+        .style('position', 'absolute')
+        .style('top', '10%')
+        .style('left', '0%')
+        .style('width', '100%')
+        .style('height', '80%')
+        .style('border-top', '1px solid rgb(230,230,230)')
+        .style('border-bottom', '1px solid rgb(230,230,230)');
+    var table = tableDiv.append('table')
+        .attr('border', '1')
+        .attr('cellspacing', '0')
+        .attr('cellpadding', '2')
+        .style('margin-left', 'auto')
+        .style('margin-right', 'auto');
+    var header = table.append('tr');
+    for (var i = 0; i < headers.length; i++) {
+        header.append('th').text(headers[i]);
+    }
+
+    for (var i = 0; i < data.length; i++) {
+        var row = table.append('tr');
+        for (j = 0; j < headers.length; j++) {
+            var td = row.append('td');
+            if (styleFunction) {
+                styleFunction.call(this, td, j);
+            }
+            dataFunction.call(this, data[i], j, td);
+        }
+    }
+}
+
+function bigSymbolsReport() {
+    var list = treemap.biggestSymbols(100);
+    var headers = ['Rank', 'Size (Bytes)', 'Type', 'Location'];
+    var styleFunction = function(selection, index) {
+        if (index === 3) {
+            selection.style('font-family', 'monospace');
+        }
+    };
+    var recordIndex = 1;
+    var dataFunction = function(record, index, cell) {
+        if (index === 0) {
+            cell.text(recordIndex++);
+        } else if (index === 1) {
+            cell.text(D3SymbolTreeMap._pretty(record.value));
+        } else if (index === 2) {
+            cell.text(record.t);
+        } else {
+            if (treemap.pathFor(record).indexOf('/out') == 0) {
+                cell.append('span').text(treemap.pathFor(record));
+                cell.append('br');
+                cell.append('span').text('Symbol: ');
+                cell.append('span').text(record.n);
+            } else {
+                var href = 'https://code.google.com/p/chromium/codesearch#chromium/src'
+                    + treemap.pathFor(record)
+                    + '&q='
+                    + record.n;
+                cell.append('a')
+                    .attr('href', href)
+                    .attr('target', '_blank')
+                    .text(treemap.pathFor(record));
+                cell.append('br');
+                cell.append('span').text('Symbol: ');
+                cell.append('span').text(record.n);
+            }
+        }
+    };
+    showReport('100 Largest Symbols', list, headers, dataFunction, styleFunction);
+}
+
+function bigPathsReport() {
+    var list = treemap.biggestPaths(100);
+    var headers = ['Rank', 'Size (Bytes)', 'Location'];
+    var styleFunction = function(selection, index) {
+        if (index === 2) {
+            selection.style('font-family', 'monospace');
+        }
+    };
+    var recordIndex = 1;
+    var dataFunction = function(record, index, cell) {
+        if (index === 0) {
+            cell.text(recordIndex++);
+        } else if (index === 1) {
+            cell.text(D3SymbolTreeMap._pretty(record.value));
+        } else if (index === 2) {
+            if (treemap.pathFor(record).indexOf('/out') == 0) {
+                cell.text(treemap.pathFor(record));
+            } else {
+                var href = 'https://code.google.com/p/chromium/codesearch#chromium/src' + treemap.pathFor(record);
+                cell.append('a')
+                    .attr('href', href)
+                    .attr('target', '_blank')
+                    .text(treemap.pathFor(record));
+            }
+
+        }
+    };
+    showReport('100 Largest Paths', list, headers, dataFunction, styleFunction);
+}
+
+function symbolFilterTextChanged() {
+    if (filterChanging) return true;
+    filterChanging = true;
+    var enabled = document.getElementById('symbol_types_filter').value;
+    for (var x=0; x<=25; x++) {
+        var checkBox = document.getElementById('check_' + x);
+        checkBox.checked = (enabled.indexOf(checkBox.value) != -1);
+    }
+    filterChanging = false;
+}
+
+function updateFilterText() {
+    if (filterChanging) return true;
+    filterChanging = true;
+    var text = '';
+    for (var x=0; x<=25; x++) {
+        var checkBox = document.getElementById('check_' + x);
+        if (checkBox.checked) {
+            text += checkBox.value;
+        }
+    }
+    document.getElementById('symbol_types_filter').value=text;
+    filterChanging = false;
+}
+
+function initFilterOptions() {
+    updateFilterText();
+    for (var x=0; x<=25; x++) {
+        var checkBox = document.getElementById('check_' + x);
+        checkBox.onchange=updateFilterText;
+        var swatch = document.getElementById('swatch_' + x);
+        swatch.style.backgroundColor = D3SymbolTreeMap.getColorForType(checkBox.value).toString();
+    }
+    var gteCheckbox = document.getElementById('check_gte');
+    gteCheckbox.onchange = function() {
+        document.getElementById('symbol_filter_gte').disabled = !gteCheckbox.checked;
+    }
+    var regexCheckbox = document.getElementById('check_regex');
+    regexCheckbox.onchange = function() {
+        document.getElementById('symbol_filter_regex').disabled = !regexCheckbox.checked;
+    }
+    var excludeRegexCheckbox = document.getElementById('check_exclude_regex');
+    excludeRegexCheckbox.onchange = function() {
+        document.getElementById('symbol_filter_exclude_regex').disabled = !excludeRegexCheckbox.checked;
+    }
+    var idealSizes = getIdealSizes();
+    document.getElementById('width').value = idealSizes.width;
+    document.getElementById('height').value = idealSizes.height;
+    saveFilterSettings();
+}
+
+function filterSetAll(enabled) {
+    for (var x=0; x<=25; x++) {
+        var checkBox = document.getElementById('check_' + x);
+        checkBox.checked = enabled;
+    }
+    updateFilterText();
+}
+
+function showOptions() {
+    loadFilterSettings();
+    var container = document.getElementById('options_container');
+    var w = container.offsetWidth;
+    var h = container.offsetHeight;
+    container.style.margin = '-' + (h/2) + 'px 0 0 -' + (w/2) + 'px';
+    container.style.visibility = 'visible';
+}
+
+function hideOptions() {
+    var container = document.getElementById('options_container');
+    container.style.visibility = 'hidden';
+}
+
+function applySettings() {
+    hideOptions();
+    var oldWidth = savedSettings.width;
+    var oldHeight = savedSettings.height;
+    var oldSymbols = savedSettings.symbolTypes;
+    var oldRegex = savedSettings.regex;
+    var oldExcludeRegex = savedSettings.excludeRegex;
+    var oldGte = savedSettings.gte;
+    var oldMaxLevels = savedSettings.maxLevels;
+    saveFilterSettings();
+    var resizeNeeded = oldWidth !== savedSettings.width || oldHeight !== savedSettings.height;
+    var regexChanged = oldRegex !== savedSettings.regex;
+    var excludeRegexChanged = oldExcludeRegex !== savedSettings.excludeRegex;
+    var symbolsChanged = oldSymbols !== savedSettings.symbolTypes;
+    var gteChanged = oldGte !== savedSettings.gte;
+    var filterChanged = regexChanged || excludeRegexChanged || symbolsChanged || gteChanged;
+    var maxLevelsChanged = oldMaxLevels !== savedSettings.maxLevels;
+
+    if (filterChanged) {
+        // Type filters
+        typeFilter = function(datum) {
+            if (datum.depth === 0) return true; // root node
+            if (datum.t === undefined) return true;
+            return savedSettings.symbolTypes !== undefined &&
+                savedSettings.symbolTypes.indexOf(datum.t) !== -1;
+        }
+
+        // Regex filter
+        var regexFilter = undefined;
+        if (savedSettings.regex !== undefined && savedSettings.regex.length > 0) {
+            console.log('filter: regex is "' + savedSettings.regex + '"');
+            var regex = new RegExp(savedSettings.regex);
+            regexFilter = function(datum) {
+                if (datum.depth === 0) return true; // root node
+                var fullName = this.pathFor(datum);
+                if (datum.children === undefined) { // it is a leaf node (symbol)
+                    fullName += ':' + datum.n;
+                }
+                return regex.test(fullName);
+            }
+        }
+
+        // Exclude regex filter
+        var excludeRegexFilter = undefined;
+        if (savedSettings.excludeRegex !== undefined && savedSettings.excludeRegex.length > 0) {
+            console.log('filter: exclude-regex is "' + savedSettings.excludeRegex + '"');
+            var excludeRegex = new RegExp(savedSettings.excludeRegex);
+            excludeRegexFilter = function(datum) {
+                if (datum.depth === 0) return true; // root node
+                var fullName = this.pathFor(datum);
+                if (datum.children === undefined) { // it is a leaf node (symbol)
+                    fullName += ':' + datum.n;
+                }
+                return !excludeRegex.test(fullName);
+            }
+        }
+
+        // Size filter
+        var sizeFilter = undefined;
+        if (savedSettings.gte !== undefined) {
+            console.log('filter: minimum size is ' + savedSettings.gte + ' bytes');
+            sizeFilter = function(datum) {
+                if (datum.children !== undefined) return true; // non-leaf
+                if (datum.value === undefined) console.log('whoops');
+                return datum.value >= savedSettings.gte;
+            }
+        }
+
+        // Make a filter to apply to the tree
+        var filter = function(datum) {
+            if (typeFilter && !typeFilter.call(this, datum)) return false;
+            if (regexFilter && !regexFilter.call(this, datum)) return false;
+            if (excludeRegexFilter && !excludeRegexFilter.call(this, datum)) return false;
+            if (sizeFilter && !sizeFilter.call(this, datum)) return false;
+            return true;
+        };
+        treemap.filter(filter);
+    }
+
+    // Adjust levels if needed.
+    if (maxLevelsChanged) {
+        treemap.setMaxLevels(savedSettings.maxLevels);
+    }
+
+    // Resize map if necessary.
+    if (resizeNeeded) {
+        console.log('desired treemap dimensions have changed, requesting resize');
+        treemap.resize(savedSettings.width, savedSettings.height);
+    }
+}
+
+function cancelSettings() {
+    hideOptions();
+    loadFilterSettings();
+}
+
+function saveFilterSettings() {
+    savedSettings.symbolTypes = document.getElementById('symbol_types_filter').value;
+    if (document.getElementById('check_regex').checked) {
+        savedSettings.regex = document.getElementById('symbol_filter_regex').value;
+    } else {
+        savedSettings.regex = undefined;
+    }
+    if (document.getElementById('check_exclude_regex').checked) {
+        savedSettings.excludeRegex = document.getElementById('symbol_filter_exclude_regex').value;
+    } else {
+        savedSettings.excludeRegex = undefined;
+    }
+    if (document.getElementById('check_gte').checked) {
+        savedSettings.gte = parseInt(document.getElementById('symbol_filter_gte').value);
+    } else {
+        savedSettings.gte = undefined;
+    }
+    savedSettings.width = parseInt(document.getElementById('width').value);
+    savedSettings.height = parseInt(document.getElementById('height').value);
+    savedSettings.maxLevels = parseInt(document.getElementById('max_levels').value);
+}
+
+function loadFilterSettings() {
+    document.getElementById('symbol_types_filter').value = savedSettings.symbolTypes;
+    symbolFilterTextChanged();
+    if (savedSettings.regex !== undefined) {
+        document.getElementById('check_regex').checked = true;
+        document.getElementById('symbol_filter_regex').value = savedSettings.regex;
+    } else {
+        document.getElementById('check_regex').checked = false;
+    }
+    if (savedSettings.excludeRegex !== undefined) {
+        document.getElementById('check_exclude_regex').checked = true;
+        document.getElementById('symbol_filter_exclude_regex').value = savedSettings.excludeRegex;
+    } else {
+        document.getElementById('check_exclude_regex').checked = false;
+    }
+    if (savedSettings.gte !== undefined) {
+        document.getElementById('check_gte').checked = true;
+        document.getElementById('symbol_filter_gte').value = savedSettings.gte;
+    } else {
+        document.getElementById('check_gte').checked = false;
+    }
+    document.getElementById('width').value = savedSettings.width;
+    document.getElementById('height').value = savedSettings.height;
+    document.getElementById('max_levels').value = savedSettings.maxLevels;
+}
+
+function escape(str) {
+    return str.replace(/&/g, '&amp;')
+              .replace(/"/g, '&quot;')
+              .replace(/</g, '&lt;')
+              .replace(/>/g, '&gt;');
+}
+</script>
+</head>
+<body onload='init()'>
+<div style='position: absolute; top: 5px; left: 5px;'>
+  <input type='button' onclick='showOptions()' value='Options &amp; Legend...'>
+  <span style='-webkit-user-select: none; cursor: help;' title='Click to view the symbol legend or to configure filters and options for the treemap'>[?]</span>
+</div>
+<div style='position: absolute; right: 5px; top: 5px; white-space: nowrap;'>
+    Reports:
+    <input type='button' onclick='bigSymbolsReport()' value='Large Symbols' title='Click to view a report of the largest 100 symbols that are with the bounds of the treemap that is currently displayed.'>
+    <input type='button' onclick='bigPathsReport()' value='Large Files' title='Click to view a report of the largest 100 source files that are with the bounds of the treemap that is currently displayed.'>
+</div>
+<div style='text-align: center; margin-bottom: 5px;'>
+    <span style='font-size: x-large; font-weight: bold; font-variant: small-caps'>Binary Size Analysis<span id='subtitle'></span></span>
+    <br><span style='font-size: small; font-style: italic;'>Double-click a box to zoom in, double-click outermost title to zoom out.</span>
+</div>
+<table id='options_container' style='visibility: hidden; border: 3px ridge grey; padding: 0px; top: 50%; left: 50%; position: fixed; z-index: 2147483646; overflow: auto; background-color: rgba(255,255,255,0.9); border-radius: 10px; box-shadow: 10px 10px 5px rgba(80,80,80,0.7);'><tr><td style='vertical-align: top'>
+    <table cellspacing=0 cellborder=0 style='width:100%'>
+        <tr><th colspan=3 style='padding-bottom: .25em; text-decoration: underline;'>Symbol Types To Show</th></tr>
+        <tr>
+            <td style='width: 33%; white-space: nowrap; vertical-align: top;'>
+                    <span class='swatch' id='swatch_0'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_0' value='A'>Global absolute (A)
+                <br><span class='swatch' id='swatch_1'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_1' value='B'>Global uninitialized data (B)
+                <br><span class='swatch' id='swatch_2'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_2' value='b'>Local uninitialized data (b)
+                <br><span class='swatch' id='swatch_3'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_3' value='C'>Global uninitialized common (C)
+                <br><span class='swatch' id='swatch_4'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_4' value='D'>Global initialized data (D)
+                <br><span class='swatch' id='swatch_5'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_5' value='d'>Local initialized data (d)
+                <br><span class='swatch' id='swatch_6'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_6' value='G'>Global small initialized data (G)
+                <br><span class='swatch' id='swatch_7'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_7' value='g'>Local small initialized data (g)
+                <br><span class='swatch' id='swatch_8'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_8' value='i'>Indirect function (i)
+            </td>
+            <td style='width: 33%; white-space: nowrap; vertical-align: top;'>
+                    <span class='swatch' id='swatch_9'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_9' value='N'>Debugging (N)
+                <br><span class='swatch' id='swatch_10'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_10' value='p'>Stack unwind (p)
+                <br><span class='swatch' id='swatch_11'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_11' value='R'>Global read-only data (R)
+                <br><span class='swatch' id='swatch_12'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_12' value='r'>Local read-only data (r)
+                <br><span class='swatch' id='swatch_13'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_13' value='S'>Global small uninitialized data (S)
+                <br><span class='swatch' id='swatch_14'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_14' value='s'>Local small uninitialized data (s)
+                <br><span class='swatch' id='swatch_15'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_15' value='T'>Global code (T)
+                <br><span class='swatch' id='swatch_16'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_16' value='t'>Local code (t)
+                <br><span class='swatch' id='swatch_17'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_17' value='U'>Undefined (U)
+            </td>
+            <td style='width: 33%; white-space: nowrap; vertical-align: top;'>
+                    <span class='swatch' id='swatch_18'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_18' value='u'>Unique (u)
+                <br><span class='swatch' id='swatch_19'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_19' value='V'>Global weak object (V)
+                <br><span class='swatch' id='swatch_20'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_20' value='v'>Local weak object (v)
+                <br><span class='swatch' id='swatch_21'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_21' value='W'>Global weak symbol (W)
+                <br><span class='swatch' id='swatch_22'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_22' value='w'>Local weak symbol (w)
+                <br><span class='swatch' id='swatch_23'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_23' value='@'>Vtable entry (@)
+                <br><span class='swatch' id='swatch_24'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_24' value='-'>STABS debugging (-)
+                <br><span class='swatch' id='swatch_25'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_25' value='?'>Unrecognized (?)
+            </td>
+        </tr>
+        <tr><td colspan=3 style='text-align: center; white-space: nowrap; padding-top: 1em;'>
+            Select <input type='button' onclick='filterSetAll(true)' value='All'>,
+            <input type='button' onclick='filterSetAll(false)' value='None'>,
+            or type a string: <input id='symbol_types_filter' size=30 value='' onkeyup='symbolFilterTextChanged()' onblur='updateFilterText()'>
+            <span style='-webkit-user-select: none; cursor: help;' title='Enter codes from the list above for the symbols you want to see. The checkboxes will update automatically to match the string that you enter.'>[?]</span>
+        </td></tr>
+   </table>
+</td></tr><tr><td style='vertical-align: top; padding-top: 10px; border-top: 1px solid grey;'>
+    <table cellspacing=0 cellborder=0 style='width: 100%'>
+        <tr><th colspan=2 style='padding-bottom: .25em; text-decoration: underline;'>Advanced Options</th></tr>
+        <tr>
+            <td style='white-space: nowrap; vertical-align: top;'>
+                <input type='checkbox' id='check_regex'>
+                Only include symbols matching this regex:
+            </td>
+            <td style='text-align: right; vertical-align: top;'>
+                <input disabled id='symbol_filter_regex' size=30 value='' style='text-align: right;'>
+                <span style='-webkit-user-select: none; cursor: help;' title='Enter a javascript regex. Only symbols that match this regex will be shown. This filter applies before any exclusion regex specified below. The format of each symbol is [path]:[symbol_name]'>[?]</span>
+            </td>
+        </tr>
+        <tr>
+            <td style='white-space: nowrap; vertical-align: top;'>
+                <input type='checkbox' id='check_exclude_regex'>
+                Exclude all symbols matching this regex:
+            </td>
+            <td style='text-align: right; vertical-align: top;'>
+                <input disabled id='symbol_filter_exclude_regex' size=30 value='' style='text-align: right;'>
+                <span style='-webkit-user-select: none; cursor: help;' title='Enter a javascript regex. Symbols that match this tegex will not be shown. This filter applies after any inclusion filter specified above. The format of each symbol is [path]:[symbol_name]'>[?]</span>
+            </td>
+        </tr>
+        <tr>
+            <td style='white-space: nowrap; vertical-align: top;'>
+                <input type='checkbox' id='check_gte'>
+                Only include symbols that are at least <span style='font-style: italic;'>n</span> bytes:
+            </td>
+            <td style='text-align: right; vertical-align: top;'>
+                <input disabled id='symbol_filter_gte' size=8 value='' style='text-align: right;'>
+                <span style='-webkit-user-select: none; cursor: help;' title='Symbols whose size is less than this value will be hidden.'>[?]</span>
+            </td>
+        </tr>
+        <tr>
+            <td style='white-space: nowrap vertical-align: top;;'>
+                Show at most <span style='font-style: italic;'>n</span> levels of detail at a time:
+            </td>
+            <td style='text-align: right; vertical-align: top;'>
+                <input id='max_levels' size=4 value='2' style='text-align: right;'><span style='-webkit-user-select: none; cursor: help;' title='Increasing this value shows more detail without the need to zoom, but uses more computing power.'>[?]</span>
+            </td>
+        </tr>
+        <tr>
+            <td style='white-space: nowrap vertical-align: top;;'>
+                Set the size of the treemap to <span style='font-style: italic;'>W x H</span> pixels:
+            </td>
+            <td style='text-align: right; vertical-align: top;'>
+                <input id='width' size=4 value='' style='text-align: right;'>
+                &nbsp;x&nbsp;<input id='height' size=4 value='' style='text-align: right;'>
+            </td>
+        </tr>
+    </table>
+</td></tr>
+<tr><td style='padding-top: 10px; text-align: right; border-top: 1px solid grey'>
+    <input type='button' value='Apply' onclick='applySettings()'>
+    <input type='button' value='Cancel' onclick='cancelSettings()'>
+</td></tr></table>
+</body>
+</html>
diff --git a/runtime/third_party/binary_size/src/template/test-data-generator.html b/runtime/third_party/binary_size/src/template/test-data-generator.html
new file mode 100644
index 0000000..9c6790a
--- /dev/null
+++ b/runtime/third_party/binary_size/src/template/test-data-generator.html
@@ -0,0 +1,157 @@
+<!DOCTYPE html>
+<!--
+  Copyright 2014 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.
+-->
+<html>
+<head>
+<script>
+function rnd(max) {
+    return Math.round(Math.random()*max);
+}
+
+function gen() {
+  var dirs1=['usr1', 'etc1', 'var1'];
+  var dirs2=['aaa2', 'bbb2', 'ccc2', 'ddd2', 'eee2', 'fff2', 'ggg2', 'hhh2',
+             'frobozz2', 'kazaam2', 'shazam2'];
+  var dirs3=['iii3', 'jjj3', 'kkk3', 'lll3', 'mmm3', 'nnn3', 'ooo3', 'ppp3',
+             'wonderllama3', 'excelsior3', 'src3'];
+  var filenames=['awesome.cc', 'rad.h', 'tubular.cxx', 'cool.cc', 'groovy.h',
+                 'excellent.c', 'gnarly.h', 'green.C', 'articulate.cc'];
+  //All possible types (we only see a subset in practice): 'ABbCDdGgiNpRrSsTtUuVvWw-?';
+  var nm_symbol_types = 'trd';
+  var minSize = 4;
+  var maxSize = 10000;
+  var numGen = 300000;
+  var text = 'var nm_data=[\n';
+  var vtablePercent = 5;
+  for (var x=0; x<numGen; x++) {
+    var path = '/' +
+        dirs1[rnd(dirs1.length - 1)] + '/' +
+        dirs2[rnd(dirs2.length - 1)] + '/' +
+        dirs3[rnd(dirs3.length - 1)] + '/' +
+        filenames[rnd(filenames.length - 1)];
+    var isVtable = Math.floor((Math.random()*100)+1) <= vtablePercent;
+    var size = rnd(maxSize);
+    var symbol_name;
+    var type;
+    if (!isVtable) {
+      symbol_name = 'sym' + x.toString(16);
+      type = nm_symbol_types.charAt(rnd(nm_symbol_types.length - 1));
+    } else {
+      symbol_name = 'vtable for ' + x.toString(16);
+      type = '@'
+    }
+    text = text + "{'n': '" + symbol_name +
+        "', 't': '" + type +
+        "', 's': " + size +
+        ", 'p': '" + path + "'},\n";
+  }
+  text += '];';
+
+  eval(text);
+  var treeified = to_d3_tree(nm_data);
+  generateDownloadLink('tree_data=' + JSON.stringify(treeified));
+}
+
+function generateDownloadLink(content) {
+  var blob = new Blob([content], {type: 'text/plain'});
+  var link = document.createElement('a');
+  link.download = 'generated-content.txt';
+  link.href = window.URL.createObjectURL(blob);
+  link.textContent = 'Download ready, click here.';
+  link.dataset.downloadurl = ['text/plain', link.download, link.href].join(':');
+  link.onclick = function(e) {
+    if ('disabled' in this.dataset) { return false; }
+    link.dataset.disabled = true;
+    setTimeout(function() { window.URL.revokeObjectURL(link.href); }, 1500);
+  };
+  document.getElementById('linkcontainer').innerHTML = '';
+  document.getElementById('linkcontainer').appendChild(link);
+}
+
+/**
+ * This function takes in an array of nm records and converts them into a
+ * hierarchical data structure suitable for use in a d3-base treemap layout.
+ * Leaves are individual symbols. The parents of the leaves are logical
+ * groupings by common symbol-type (for BSS, read-only data, code, etc).
+ * Above this, each node represents part of a filesystem path relative
+ * to the parent node. The root node has the name '/', and represents
+ * a root (though not necessarily THE root) of a file system traversal.
+ * The root node also has a special property, 'maxDepth', to which is bound
+ * the deepest level of nesting that was found during conversion: for the
+ * record at path /a/b/c/d.foo, the maxDepth will be 6; the file 'd.foo'
+ * is at depth 4, the type-bucket is depth 5 and the symbols are depth 6.
+ */
+function to_d3_tree(records) {
+  var result = {'n': '/', 'children': [], 'k': 'p'};
+  var maxDepth = 0;
+  //{'n': 'symbol1', 't': 'b', 's': 1000, 'p': '/usr/local/foo/foo.cc'},
+  for (index in records) {
+    var record = records[index];
+    var parts = record.p.split("/");
+    var node = result;
+    var depth = 0;
+    // Walk the tree and find the file that is named by the "location"
+    // field of the record. We create any intermediate nodes required.
+    // This is directly analogous to "mkdir -p".
+    while(parts.length > 0) {
+      var part = parts.shift();
+      if (part.length == 0) continue;
+      depth++;
+      node = _mk_child(node, part, record.s);
+      node.k = 'p'; // p for path
+    }
+    node.lastPathElement = true;
+
+    // 'node' is now the file node. Find the symbol-type bucket.
+    node = _mk_child(node, record.t, record.s);
+    node.t = record.t;
+    node.k = 'b'; // b for bucket
+    depth++;
+    // 'node' is now the symbol-type bucket. Make the child entry.
+    node = _mk_child(node, record.n, record.s);
+    delete node.children;
+    node.value = record.s;
+    node.t = record.t;
+    node.k = 's'; // s for symbol
+    depth++;
+
+    maxDepth = Math.max(maxDepth, depth);
+  }
+  result.maxDepth = maxDepth;
+  return result;
+}
+
+/**
+ * Given a node and a name, return the child within node.children whose
+ * name matches the specified name. If necessary, a new child node is
+ * created and appended to node.children.
+ * If this method creates a new node, the 'name' attribute is set to the
+ * specified name and the 'children' attribute is an empty array, and
+ * total_size is the specified size. Otherwise, the existing node is
+ * returned and its total_size value is incremented by the specified size.
+ */
+function _mk_child(node, name, size) {
+  var child = undefined;
+  for (child_index in node.children) {
+    if (node.children[child_index].n == name) {
+      child = node.children[child_index];
+    }
+  }
+  if (child === undefined) {
+    child = {'n': name, 'children': []};
+    node.children.push(child);
+  }
+  return child;
+}
+</script>
+</head>
+<body style='white-space: pre; font-family: monospace;'>
+This script generates sample data for use in D3SymbolTreeMap, and can be used
+for testing.
+<input type=button onclick='gen();' value='Generate data'></input>
+<div id='linkcontainer'></div>
+</body>
+</html>
diff --git a/runtime/tools/binary_size b/runtime/tools/binary_size
deleted file mode 100755
index 5621bf5..0000000
--- a/runtime/tools/binary_size
+++ /dev/null
@@ -1,402 +0,0 @@
-#!/usr/bin/env dart
-// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "dart:io";
-
-class Symbol {
-  String? name;
-  String? type;
-  int? shallowSize;
-  int? retainedSize;
-  List<Symbol> children = <Symbol>[];
-
-  Symbol compressTrivialPaths() {
-    for (var i = 0; i < children.length; i++) {
-      children[i] = children[i].compressTrivialPaths();
-    }
-    if ((type == "path") && (children.length == 1)) {
-      return children[0];
-    }
-    return this;
-  }
-
-  int computeRetainedSize() {
-    var s = shallowSize!;
-    for (var child in children) {
-      s += child.computeRetainedSize();
-    }
-    retainedSize = s;
-    return s;
-  }
-
-  writeJson(StringBuffer out) {
-    out.write("{");
-    out.write('"name": "$name",');
-    out.write('"shallowSize": $shallowSize,');
-    out.write('"retainedSize": $retainedSize,');
-    out.write('"type": "$type",');
-    out.write('"children": [');
-    bool first = true;
-    for (var child in children) {
-      if (first) {
-        first = false;
-      } else {
-        out.write(",");
-      }
-      child.writeJson(out);
-    }
-    out.write("]}");
-  }
-}
-
-const filteredPathComponents = <String>[
-  "",
-  ".",
-  "..",
-  "out",
-  "src",
-  "source",
-  "third_party",
-  "DebugX64",
-  "ReleaseX64",
-  "ProductX64",
-];
-
-String prettyPath(String path) {
-  return path
-      .split("/")
-      .where((component) => !filteredPathComponents.contains(component))
-      .join("/");
-}
-
-main(List<String> args) {
-  if (args.isEmpty) {
-    print("Usage: binary_size <binaries>");
-    exit(1);
-  }
-
-  for (var arg in args) {
-    analyze(arg);
-  }
-}
-
-analyze(String binaryPath) {
-  var nmExec = "nm";
-  var nmArgs = ["--demangle", "--line-numbers", "--print-size", binaryPath];
-  var nmResult = Process.runSync(nmExec, nmArgs);
-  if (nmResult.exitCode != 0) {
-    print("+ ${nmExec} ${nmArgs.join(' ')}");
-    print(nmResult.exitCode);
-    print(nmResult.stdout);
-    print(nmResult.stderr);
-    exit(1);
-  }
-
-  var root = new Symbol();
-  root.name = binaryPath;
-  root.type = "path";
-  root.shallowSize = 0;
-  var paths = new Map<String, Symbol>();
-  paths[""] = root;
-  addToPath(Symbol s, String path) {
-    Symbol? p = paths[path];
-    if (p == null) {
-      p = new Symbol();
-      p.name = path;
-      p.type = "path";
-      p.shallowSize = 0;
-      paths[path] = p;
-
-      var i = path.lastIndexOf("/");
-      if (i != -1) {
-        p.name = path.substring(i + 1);
-        addToPath(p, path.substring(0, i));
-      } else {
-        root.children.add(p);
-      }
-    }
-    p.children.add(s);
-  }
-
-  var lines = nmResult.stdout.split("\n");
-  var regex = new RegExp("([0-9a-f]+) ([0-9a-f]+) ([a-zA-z]) (.*)");
-  for (var line in lines) {
-    var match = regex.firstMatch(line);
-    if (match == null) {
-      continue;
-    }
-
-    var address = int.parse(match[1]!, radix: 16);
-    var size = int.parse(match[2]!, radix: 16);
-    var type = match[3];
-    if (type == "b" || type == "B") {
-      // Uninitialized data does not contribute to file size.
-      continue;
-    }
-
-    var nameAndPath = match[4]!.split("\t");
-    var name = nameAndPath[0].trim();
-    var path = nameAndPath.length == 1
-        ? ""
-        : prettyPath(nameAndPath[1].trim().split(":")[0]);
-
-    var s = new Symbol();
-    s.name = name;
-    s.type = type;
-    s.shallowSize = size;
-    addToPath(s, path);
-  }
-
-  root.compressTrivialPaths();
-  root.computeRetainedSize();
-
-  var json = new StringBuffer();
-  root.writeJson(json);
-
-  var html = viewer.replaceAll("__DATA__", json.toString());
-  new File("${binaryPath}.html").writeAsStringSync(html);
-
-  // This written as a URL instead of path because some terminals will
-  // automatically recognize it and make it a link.
-  var url = Directory.current.uri.resolve("${binaryPath}.html");
-  print("Wrote $url");
-}
-
-var viewer = """
-<html>
-<head>
-<style>
-.treemapTile {
-    position: absolute;
-    box-sizing: border-box;
-    border: solid 1px;
-    font-size: 10;
-    text-align: center;
-    overflow: hidden;
-    white-space: nowrap;
-    cursor: default;
-}
-</style>
-</head>
-<body>
-<script>
-var root = __DATA__;
-
-function hash(string) {
-  // Jenkin's one_at_a_time.
-  let h = string.length;
-  for (let i = 0; i < string.length; i++) {
-    h += string.charCodeAt(i);
-    h += h << 10;
-    h ^= h >> 6;
-  }
-  h += h << 3;
-  h ^= h >> 11;
-  h += h << 15;
-  return h;
-}
-
-function color(string) {
-  let hue = hash(string) % 360;
-  return "hsl(" + hue + ",60%,60%)";
-}
-
-function prettySize(size) {
-  if (size < 1024) return size + "B";
-  size /= 1024;
-  if (size < 1024) return size.toFixed(1) + "KiB";
-  size /= 1024;
-  if (size < 1024) return size.toFixed(1) + "MiB";
-  size /= 1024;
-  return size.toFixed(1) + "GiB";
-}
-
-function createTreemapTile(v, width, height, depth) {
-  let div = document.createElement("div");
-  div.className = "treemapTile";
-  div.style["background-color"] = color(v.type);
-  div.ondblclick = function(event) {
-    event.stopPropagation();
-    if (depth == 0) {
-      let parent = v.parent;
-      if (parent === undefined) {
-        // Already at root.
-      } else {
-        showDominatorTree(parent);  // Zoom out.
-      }
-    } else {
-      showDominatorTree(v);  // Zoom in.
-    }
-  };
-
-  let left = 0;
-  let top = 0;
-
-  const kPadding = 5;
-  const kBorder = 1;
-  left += kPadding - kBorder;
-  top += kPadding - kBorder;
-  width -= 2 * kPadding;
-  height -= 2 * kPadding;
-
-  div.title =
-    v.name +
-    " \\ntype: " + v.type +
-    " \\nretained: " + v.retainedSize +
-    " \\nshallow: " + v.shallowSize;
-
-  if (width < 10 || height < 10) {
-    // Too small: don't render label or children.
-    return div;
-  }
-
-  let label = v.name + " [" + prettySize(v.retainedSize) + "]";
-  div.appendChild(document.createTextNode(label));
-  const kLabelHeight = 9;
-  top += kLabelHeight;
-  height -= kLabelHeight;
-
-  if (depth > 2) {
-    // Too deep: don't render children.
-    return div;
-  }
-  if (width < 4 || height < 4) {
-    // Too small: don't render children.
-    return div;
-  }
-
-  let children = new Array();
-  v.children.forEach(function(c) {
-    // Size 0 children seem to confuse the layout algorithm (accumulating
-    // rounding errors?).
-    if (c.retainedSize > 0) {
-      children.push(c);
-    }
-  });
-  children.sort(function (a, b) {
-    return b.retainedSize - a.retainedSize;
-  });
-
-  const scale = width * height / v.retainedSize;
-
-  // Bruls M., Huizing K., van Wijk J.J. (2000) Squarified Treemaps. In: de
-  // Leeuw W.C., van Liere R. (eds) Data Visualization 2000. Eurographics.
-  // Springer, Vienna.
-  for (let rowStart = 0;  // Index of first child in the next row.
-       rowStart < children.length;) {
-    // Prefer wider rectangles, the better to fit text labels.
-    const GOLDEN_RATIO = 1.61803398875;
-    let verticalSplit = (width / height) > GOLDEN_RATIO;
-
-    let space;
-    if (verticalSplit) {
-      space = height;
-    } else {
-      space = width;
-    }
-
-    let rowMin = children[rowStart].retainedSize * scale;
-    let rowMax = rowMin;
-    let rowSum = 0;
-    let lastRatio = 0;
-
-    let rowEnd;  // One after index of last child in the next row.
-    for (rowEnd = rowStart; rowEnd < children.length; rowEnd++) {
-      let size = children[rowEnd].retainedSize * scale;
-      if (size < rowMin) rowMin = size;
-      if (size > rowMax) rowMax = size;
-      rowSum += size;
-
-      let ratio = Math.max((space * space * rowMax) / (rowSum * rowSum),
-                           (rowSum * rowSum) / (space * space * rowMin));
-      if ((lastRatio != 0) && (ratio > lastRatio)) {
-        // Adding the next child makes the aspect ratios worse: remove it and
-        // add the row.
-        rowSum -= size;
-        break;
-      }
-      lastRatio = ratio;
-    }
-
-    let rowLeft = left;
-    let rowTop = top;
-    let rowSpace = rowSum / space;
-
-    for (let i = rowStart; i < rowEnd; i++) {
-      let child = children[i];
-      let size = child.retainedSize * scale;
-
-      let childWidth;
-      let childHeight;
-      if (verticalSplit) {
-        childWidth = rowSpace;
-        childHeight = size / childWidth;
-      } else {
-        childHeight = rowSpace;
-        childWidth = size / childHeight;
-      }
-
-      let childDiv = createTreemapTile(child, childWidth, childHeight, depth + 1);
-      childDiv.style.left = rowLeft + "px";
-      childDiv.style.top = rowTop + "px";
-      // Oversize the final div by kBorder to make the borders overlap.
-      childDiv.style.width = (childWidth + kBorder) + "px";
-      childDiv.style.height = (childHeight + kBorder) + "px";
-      div.appendChild(childDiv);
-
-      if (verticalSplit)
-        rowTop += childHeight;
-      else
-        rowLeft += childWidth;
-    }
-
-    if (verticalSplit) {
-      left += rowSpace;
-      width -= rowSpace;
-    } else {
-      top += rowSpace;
-      height -= rowSpace;
-    }
-
-    rowStart = rowEnd;
-  }
-
-  return div;
-}
-
-function showDominatorTree(v) {
-  // Add the content div to the document first so the browser will calculate
-  // the available width and height.
-  let w = document.body.offsetWidth;
-  let h = document.body.offsetHeight;
-
-  let topTile = createTreemapTile(v, w, h, 0);
-  topTile.style.width = w;
-  topTile.style.height = h;
-  setBody(topTile);
-}
-
-function setBody(div) {
-  let body = document.body;
-  while (body.firstChild) {
-    body.removeChild(body.firstChild);
-  }
-  body.appendChild(div);
-}
-
-function setParents(v) {
-  v.children.forEach(function (child) {
-    child.parent = v;
-    setParents(child);
-  });
-}
-
-setParents(root);
-showDominatorTree(root);
-
-</script>
-</body>
-</html>
-""";
diff --git a/runtime/vm/app_snapshot.cc b/runtime/vm/app_snapshot.cc
index fd5ab028..1a5a835 100644
--- a/runtime/vm/app_snapshot.cc
+++ b/runtime/vm/app_snapshot.cc
@@ -4567,10 +4567,11 @@
 };
 #endif  // !DART_PRECOMPILED_RUNTIME
 
-class MintDeserializationCluster : public DeserializationCluster {
+class MintDeserializationCluster
+    : public AbstractInstanceDeserializationCluster {
  public:
   explicit MintDeserializationCluster(bool is_canonical)
-      : DeserializationCluster("int", is_canonical) {}
+      : AbstractInstanceDeserializationCluster("int", is_canonical) {}
   ~MintDeserializationCluster() {}
 
   void ReadAlloc(Deserializer* d) {
@@ -4595,31 +4596,6 @@
   }
 
   void ReadFill(Deserializer* d, bool primary) {}
-
-#if defined(DART_PRECOMPILED_RUNTIME)
-  void PostLoad(Deserializer* d, const Array& refs, bool primary) {
-    if (!primary && is_canonical()) {
-      const Class& mint_cls = Class::Handle(
-          d->zone(), d->isolate_group()->object_store()->mint_class());
-      Object& number = Object::Handle(d->zone());
-      Mint& number2 = Mint::Handle(d->zone());
-      SafepointMutexLocker ml(
-          d->isolate_group()->constant_canonicalization_mutex());
-      for (intptr_t i = start_index_; i < stop_index_; i++) {
-        number = refs.At(i);
-        if (!number.IsMint()) continue;
-        number2 =
-            mint_cls.LookupCanonicalMint(d->zone(), Mint::Cast(number).value());
-        if (number2.IsNull()) {
-          number.SetCanonical();
-          mint_cls.InsertCanonicalMint(d->zone(), Mint::Cast(number));
-        } else {
-          refs.SetAt(i, number2);
-        }
-      }
-    }
-  }
-#endif
 };
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
@@ -4660,10 +4636,11 @@
 };
 #endif  // !DART_PRECOMPILED_RUNTIME
 
-class DoubleDeserializationCluster : public DeserializationCluster {
+class DoubleDeserializationCluster
+    : public AbstractInstanceDeserializationCluster {
  public:
   explicit DoubleDeserializationCluster(bool is_canonical)
-      : DeserializationCluster("double", is_canonical) {}
+      : AbstractInstanceDeserializationCluster("double", is_canonical) {}
   ~DoubleDeserializationCluster() {}
 
   void ReadAlloc(Deserializer* d) {
@@ -4678,30 +4655,6 @@
       dbl->untag()->value_ = d->Read<double>();
     }
   }
-
-#if defined(DART_PRECOMPILED_RUNTIME)
-  void PostLoad(Deserializer* d, const Array& refs, bool primary) {
-    if (!primary && is_canonical()) {
-      auto Z = d->zone();
-      auto isolate_group = d->isolate_group();
-      const Class& cls =
-          Class::Handle(Z, isolate_group->object_store()->double_class());
-      SafepointMutexLocker ml(isolate_group->constant_canonicalization_mutex());
-      Double& dbl = Double::Handle(Z);
-      Double& dbl2 = Double::Handle(Z);
-      for (intptr_t i = start_index_; i < stop_index_; i++) {
-        dbl ^= refs.At(i);
-        dbl2 = cls.LookupCanonicalDouble(Z, dbl.value());
-        if (dbl2.IsNull()) {
-          dbl.SetCanonical();
-          cls.InsertCanonicalDouble(Z, dbl);
-        } else {
-          refs.SetAt(i, dbl2);
-        }
-      }
-    }
-  }
-#endif
 };
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 271ff4c..0c7b4b7 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -139,8 +139,6 @@
   V(String_toUpperCase, 1)                                                     \
   V(String_concatRange, 3)                                                     \
   V(Math_doublePow, 2)                                                         \
-  V(Random_nextState, 1)                                                       \
-  V(Random_setupSeed, 1)                                                       \
   V(Random_initialSeed, 0)                                                     \
   V(SecureRandom_getBytes, 1)                                                  \
   V(DateTime_currentTimeMicros, 0)                                             \
diff --git a/runtime/vm/compiler/aot/precompiler.cc b/runtime/vm/compiler/aot/precompiler.cc
index 756c8b1..57239ec 100644
--- a/runtime/vm/compiler/aot/precompiler.cc
+++ b/runtime/vm/compiler/aot/precompiler.cc
@@ -2482,28 +2482,11 @@
           }
         }
       }
-      intptr_t cid = cls.id();
-      if (cid == kDoubleCid) {
-        // Rehash.
-        cls.set_constants(Object::null_array());
-        for (intptr_t j = 0; j < retained_constants.Length(); j++) {
-          constant ^= retained_constants.At(j);
-          cls.InsertCanonicalDouble(Z, Double::Cast(constant));
-        }
-      } else if (cid == kMintCid) {
-        // Rehash.
-        cls.set_constants(Object::null_array());
-        for (intptr_t j = 0; j < retained_constants.Length(); j++) {
-          constant ^= retained_constants.At(j);
-          cls.InsertCanonicalMint(Z, Mint::Cast(constant));
-        }
-      } else {
-        // Rehash.
-        cls.set_constants(Object::null_array());
-        for (intptr_t j = 0; j < retained_constants.Length(); j++) {
-          constant ^= retained_constants.At(j);
-          cls.InsertCanonicalConstant(Z, constant);
-        }
+      // Rehash.
+      cls.set_constants(Object::null_array());
+      for (intptr_t j = 0; j < retained_constants.Length(); j++) {
+        constant ^= retained_constants.At(j);
+        cls.InsertCanonicalConstant(Z, constant);
       }
 
       if (retained_constants.Length() > 0) {
diff --git a/runtime/vm/compiler/asm_intrinsifier.h b/runtime/vm/compiler/asm_intrinsifier.h
index d4e45e7..6696b4a 100644
--- a/runtime/vm/compiler/asm_intrinsifier.h
+++ b/runtime/vm/compiler/asm_intrinsifier.h
@@ -31,10 +31,6 @@
  private:
   friend class Intrinsifier;
 
-  // The "_A" value used in the intrinsification of
-  // `runtime/lib/math_patch.dart:_Random._nextState()`
-  static const int64_t kRandomAValue = 0xffffda61;
-
 #define DECLARE_FUNCTION(class_name, function_name, enum_name, fp)             \
   static void enum_name(Assembler* assembler, Label* normal_ir_body);
   ALL_INTRINSICS_LIST(DECLARE_FUNCTION)
diff --git a/runtime/vm/compiler/asm_intrinsifier_arm.cc b/runtime/vm/compiler/asm_intrinsifier_arm.cc
index 822cb23..7702c24 100644
--- a/runtime/vm/compiler/asm_intrinsifier_arm.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_arm.cc
@@ -1024,42 +1024,6 @@
   __ Bind(normal_ir_body);
 }
 
-//    var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64;
-//    _state[kSTATE_LO] = state & _MASK_32;
-//    _state[kSTATE_HI] = state >> 32;
-void AsmIntrinsifier::Random_nextState(Assembler* assembler,
-                                       Label* normal_ir_body) {
-  const Field& state_field = LookupMathRandomStateFieldOffset();
-  const int64_t a_int_value = AsmIntrinsifier::kRandomAValue;
-
-  // 'a_int_value' is a mask.
-  ASSERT(Utils::IsUint(32, a_int_value));
-  int32_t a_int32_value = static_cast<int32_t>(a_int_value);
-
-  // Receiver.
-  __ ldr(R0, Address(SP, 0 * target::kWordSize));
-  // Field '_state'.
-  __ ldr(R1, FieldAddress(R0, target::Field::OffsetOf(state_field)));
-  // Addresses of _state[0] and _state[1].
-
-  const int64_t disp_0 =
-      target::Instance::DataOffsetFor(kTypedDataUint32ArrayCid);
-  const int64_t disp_1 =
-      disp_0 + target::Instance::ElementSizeFor(kTypedDataUint32ArrayCid);
-
-  __ LoadImmediate(R0, a_int32_value);
-  __ LoadFieldFromOffset(R2, R1, disp_0);
-  __ LoadFieldFromOffset(R3, R1, disp_1);
-  __ mov(R8, Operand(0));  // Zero extend unsigned _state[kSTATE_HI].
-  // Unsigned 32-bit multiply and 64-bit accumulate into R8:R3.
-  __ umlal(R3, R8, R0, R2);  // R8:R3 <- R8:R3 + R0 * R2.
-  __ StoreFieldToOffset(R3, R1, disp_0);
-  __ StoreFieldToOffset(R8, R1, disp_1);
-  ASSERT(target::ToRawSmi(0) == 0);
-  __ eor(R0, R0, Operand(R0));
-  __ Ret();
-}
-
 void AsmIntrinsifier::ObjectEquals(Assembler* assembler,
                                    Label* normal_ir_body) {
   __ ldr(R0, Address(SP, 0 * target::kWordSize));
diff --git a/runtime/vm/compiler/asm_intrinsifier_arm64.cc b/runtime/vm/compiler/asm_intrinsifier_arm64.cc
index fac75ab..429099c 100644
--- a/runtime/vm/compiler/asm_intrinsifier_arm64.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_arm64.cc
@@ -1184,37 +1184,6 @@
   __ Bind(normal_ir_body);
 }
 
-//    var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64;
-//    _state[kSTATE_LO] = state & _MASK_32;
-//    _state[kSTATE_HI] = state >> 32;
-void AsmIntrinsifier::Random_nextState(Assembler* assembler,
-                                       Label* normal_ir_body) {
-  const Field& state_field = LookupMathRandomStateFieldOffset();
-  const int64_t a_int_value = AsmIntrinsifier::kRandomAValue;
-
-  // Receiver.
-  __ ldr(R0, Address(SP, 0 * target::kWordSize));
-  // Field '_state'.
-  __ LoadCompressed(R1,
-                    FieldAddress(R0, LookupFieldOffsetInBytes(state_field)));
-
-  // Addresses of _state[0].
-  const int64_t disp =
-      target::Instance::DataOffsetFor(kTypedDataUint32ArrayCid) -
-      kHeapObjectTag;
-
-  __ LoadImmediate(R0, a_int_value);
-  __ LoadFromOffset(R2, R1, disp);
-  __ LsrImmediate(R3, R2, 32);
-  __ andi(R2, R2, Immediate(0xffffffff));
-  __ mul(R2, R0, R2);
-  __ add(R2, R2, Operand(R3));
-  __ StoreToOffset(R2, R1, disp);
-  ASSERT(target::ToRawSmi(0) == 0);
-  __ eor(R0, R0, Operand(R0));
-  __ ret();
-}
-
 void AsmIntrinsifier::ObjectEquals(Assembler* assembler,
                                    Label* normal_ir_body) {
   __ ldr(R0, Address(SP, 0 * target::kWordSize));
diff --git a/runtime/vm/compiler/asm_intrinsifier_ia32.cc b/runtime/vm/compiler/asm_intrinsifier_ia32.cc
index b744428..7d264aa7 100644
--- a/runtime/vm/compiler/asm_intrinsifier_ia32.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_ia32.cc
@@ -1147,41 +1147,6 @@
   __ Bind(normal_ir_body);
 }
 
-//    var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64;
-//    _state[kSTATE_LO] = state & _MASK_32;
-//    _state[kSTATE_HI] = state >> 32;
-void AsmIntrinsifier::Random_nextState(Assembler* assembler,
-                                       Label* normal_ir_body) {
-  const Field& state_field = LookupMathRandomStateFieldOffset();
-  const int64_t a_int_value = AsmIntrinsifier::kRandomAValue;
-
-  // 'a_int_value' is a mask.
-  ASSERT(Utils::IsUint(32, a_int_value));
-  int32_t a_int32_value = static_cast<int32_t>(a_int_value);
-
-  // Receiver.
-  __ movl(EAX, Address(ESP, +1 * target::kWordSize));
-  // Field '_state'.
-  __ movl(EBX, FieldAddress(EAX, LookupFieldOffsetInBytes(state_field)));
-  // Addresses of _state[0] and _state[1].
-  const intptr_t scale =
-      target::Instance::ElementSizeFor(kTypedDataUint32ArrayCid);
-  const intptr_t offset =
-      target::Instance::DataOffsetFor(kTypedDataUint32ArrayCid);
-  Address addr_0 = FieldAddress(EBX, 0 * scale + offset);
-  Address addr_1 = FieldAddress(EBX, 1 * scale + offset);
-  __ movl(EAX, Immediate(a_int32_value));
-  // 64-bit multiply EAX * value -> EDX:EAX.
-  __ mull(addr_0);
-  __ addl(EAX, addr_1);
-  __ adcl(EDX, Immediate(0));
-  __ movl(addr_1, EDX);
-  __ movl(addr_0, EAX);
-  ASSERT(target::ToRawSmi(0) == 0);
-  __ xorl(EAX, EAX);
-  __ ret();
-}
-
 // Identity comparison.
 void AsmIntrinsifier::ObjectEquals(Assembler* assembler,
                                    Label* normal_ir_body) {
diff --git a/runtime/vm/compiler/asm_intrinsifier_riscv.cc b/runtime/vm/compiler/asm_intrinsifier_riscv.cc
index bd85776..a800323 100644
--- a/runtime/vm/compiler/asm_intrinsifier_riscv.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_riscv.cc
@@ -440,15 +440,6 @@
   __ Bind(normal_ir_body);
 }
 
-//    var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64;
-//    _state[kSTATE_LO] = state & _MASK_32;
-//    _state[kSTATE_HI] = state >> 32;
-void AsmIntrinsifier::Random_nextState(Assembler* assembler,
-                                       Label* normal_ir_body) {
-  // TODO(riscv)
-  __ Bind(normal_ir_body);
-}
-
 void AsmIntrinsifier::ObjectEquals(Assembler* assembler,
                                    Label* normal_ir_body) {
   Label true_label;
diff --git a/runtime/vm/compiler/asm_intrinsifier_x64.cc b/runtime/vm/compiler/asm_intrinsifier_x64.cc
index 2720da8..48bfe54 100644
--- a/runtime/vm/compiler/asm_intrinsifier_x64.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_x64.cc
@@ -1047,39 +1047,6 @@
   __ Bind(normal_ir_body);
 }
 
-//    var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64;
-//    _state[kSTATE_LO] = state & _MASK_32;
-//    _state[kSTATE_HI] = state >> 32;
-void AsmIntrinsifier::Random_nextState(Assembler* assembler,
-                                       Label* normal_ir_body) {
-  const Field& state_field = LookupMathRandomStateFieldOffset();
-  const int64_t a_int_value = AsmIntrinsifier::kRandomAValue;
-
-  // Receiver.
-  __ movq(RAX, Address(RSP, +1 * target::kWordSize));
-  // Field '_state'.
-  __ LoadCompressed(RBX,
-                    FieldAddress(RAX, LookupFieldOffsetInBytes(state_field)));
-  // Addresses of _state[0] and _state[1].
-  const intptr_t scale =
-      target::Instance::ElementSizeFor(kTypedDataUint32ArrayCid);
-  const intptr_t offset =
-      target::Instance::DataOffsetFor(kTypedDataUint32ArrayCid);
-  Address addr_0 = FieldAddress(RBX, 0 * scale + offset);
-  Address addr_1 = FieldAddress(RBX, 1 * scale + offset);
-  __ movq(RAX, Immediate(a_int_value));
-  __ movl(RCX, addr_0);
-  __ imulq(RCX, RAX);
-  __ movl(RDX, addr_1);
-  __ addq(RDX, RCX);
-  __ movl(addr_0, RDX);
-  __ shrq(RDX, Immediate(32));
-  __ movl(addr_1, RDX);
-  ASSERT(target::ToRawSmi(0) == 0);
-  __ xorq(RAX, RAX);
-  __ ret();
-}
-
 // Identity comparison.
 void AsmIntrinsifier::ObjectEquals(Assembler* assembler,
                                    Label* normal_ir_body) {
diff --git a/runtime/vm/compiler/assembler/assembler_riscv_test.cc b/runtime/vm/compiler/assembler/assembler_riscv_test.cc
index b596017..9f25743 100644
--- a/runtime/vm/compiler/assembler/assembler_riscv_test.cc
+++ b/runtime/vm/compiler/assembler/assembler_riscv_test.cc
@@ -1102,6 +1102,8 @@
 
 #if XLEN >= 64
 ASSEMBLER_TEST_GENERATE(LoadWordUnsigned_0, assembler) {
+  FLAG_use_compressed_instructions = false;
+  __ SetExtensions(RV_G);
   __ lwu(A0, Address(A0, 0));
   __ ret();
 }
diff --git a/runtime/vm/compiler/intrinsifier.cc b/runtime/vm/compiler/intrinsifier.cc
index 072e8ca..ba448a7 100644
--- a/runtime/vm/compiler/intrinsifier.cc
+++ b/runtime/vm/compiler/intrinsifier.cc
@@ -179,11 +179,6 @@
   {nullptr, nullptr},
 };
 
-static const IntrinsicDesc math_intrinsics[] = {
-  MATH_LIB_INTRINSIC_LIST(DEFINE_INTRINSIC)
-  {nullptr, nullptr},
-};
-
 static const IntrinsicDesc typed_data_intrinsics[] = {
   GRAPH_TYPED_DATA_INTRINSICS_LIST(DEFINE_INTRINSIC)
   {nullptr, nullptr},
@@ -210,10 +205,9 @@
   String& str2 = String::Handle(zone);
   Error& error = Error::Handle(zone);
 
-  static const intptr_t kNumLibs = 5;
+  static const intptr_t kNumLibs = 4;
   const LibraryInstrinsicsDesc intrinsics[kNumLibs] = {
       {Library::Handle(zone, Library::CoreLibrary()), core_intrinsics},
-      {Library::Handle(zone, Library::MathLibrary()), math_intrinsics},
       {Library::Handle(zone, Library::TypedDataLibrary()),
        typed_data_intrinsics},
       {Library::Handle(zone, Library::DeveloperLibrary()),
diff --git a/runtime/vm/compiler/recognized_methods_list.h b/runtime/vm/compiler/recognized_methods_list.h
index 9dc2df9..341e699 100644
--- a/runtime/vm/compiler/recognized_methods_list.h
+++ b/runtime/vm/compiler/recognized_methods_list.h
@@ -303,9 +303,6 @@
   V(_IntegerImplementation, >=, Integer_greaterEqualThan, 0xfecba6b3)          \
   V(_IntegerImplementation, <<, Integer_shl, 0x2d855b02)                       \
 
-#define MATH_LIB_INTRINSIC_LIST(V)                                             \
-  V(_Random, _nextState, Random_nextState, 0x7207677d)                         \
-
 #define GRAPH_TYPED_DATA_INTRINSICS_LIST(V)                                    \
   V(_Int8List, [], Int8ArrayGetIndexed, 0x35f3fab6)                            \
   V(_Int8List, []=, Int8ArraySetIndexed, 0x6e4fdaa7)                           \
@@ -408,7 +405,6 @@
   CORE_LIB_INTRINSIC_LIST(V)                                                   \
   DEVELOPER_LIB_INTRINSIC_LIST(V)                                              \
   INTERNAL_LIB_INTRINSIC_LIST(V)                                               \
-  MATH_LIB_INTRINSIC_LIST(V)                                                   \
 
 #define ALL_INTRINSICS_LIST(V)                                                 \
   ALL_INTRINSICS_NO_INTEGER_LIB_LIST(V)                                        \
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 0a98a83..ba3ba97 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -5843,108 +5843,13 @@
   return static_cast<uint32_t>(v);
 }
 
-class CanonicalDoubleKey {
- public:
-  explicit CanonicalDoubleKey(const Double& key)
-      : key_(&key), value_(key.value()) {}
-  explicit CanonicalDoubleKey(const double value) : key_(NULL), value_(value) {}
-  bool Matches(const Double& obj) const {
-    return obj.BitwiseEqualsToDouble(value_);
-  }
-  uword Hash() const { return Hash(value_); }
-  static uword Hash(double value) {
-    return Hash64To32(bit_cast<uint64_t>(value));
-  }
-
-  const Double* key_;
-  const double value_;
-
- private:
-  DISALLOW_ALLOCATION();
-};
-
-class CanonicalMintKey {
- public:
-  explicit CanonicalMintKey(const Mint& key)
-      : key_(&key), value_(key.value()) {}
-  explicit CanonicalMintKey(const int64_t value) : key_(NULL), value_(value) {}
-  bool Matches(const Mint& obj) const { return obj.value() == value_; }
-  uword Hash() const { return Hash(value_); }
-  static uword Hash(int64_t value) {
-    return Hash64To32(bit_cast<uint64_t>(value));
-  }
-
-  const Mint* key_;
-  const int64_t value_;
-
- private:
-  DISALLOW_ALLOCATION();
-};
-
-// Traits for looking up Canonical numbers based on a hash of the value.
-template <typename ObjectType, typename KeyType>
-class CanonicalNumberTraits {
- public:
-  static const char* Name() { return "CanonicalNumberTraits"; }
-  static bool ReportStats() { return false; }
-
-  // Called when growing the table.
-  static bool IsMatch(const Object& a, const Object& b) {
-    return a.ptr() == b.ptr();
-  }
-  static bool IsMatch(const KeyType& a, const Object& b) {
-    return a.Matches(ObjectType::Cast(b));
-  }
-  static uword Hash(const Object& key) {
-    return KeyType::Hash(ObjectType::Cast(key).value());
-  }
-  static uword Hash(const KeyType& key) { return key.Hash(); }
-  static ObjectPtr NewKey(const KeyType& obj) {
-    if (obj.key_ != NULL) {
-      return obj.key_->ptr();
-    } else {
-      UNIMPLEMENTED();
-      return NULL;
-    }
-  }
-};
-typedef UnorderedHashSet<CanonicalNumberTraits<Double, CanonicalDoubleKey> >
-    CanonicalDoubleSet;
-typedef UnorderedHashSet<CanonicalNumberTraits<Mint, CanonicalMintKey> >
-    CanonicalMintSet;
-
-// Returns an instance of Double or Double::null().
-DoublePtr Class::LookupCanonicalDouble(Zone* zone, double value) const {
-  ASSERT(this->ptr() ==
-         IsolateGroup::Current()->object_store()->double_class());
-  if (this->constants() == Array::null()) return Double::null();
-
-  Double& canonical_value = Double::Handle(zone);
-  CanonicalDoubleSet constants(zone, this->constants());
-  canonical_value ^= constants.GetOrNull(CanonicalDoubleKey(value));
-  this->set_constants(constants.Release());
-  return canonical_value.ptr();
-}
-
-// Returns an instance of Mint or Mint::null().
-MintPtr Class::LookupCanonicalMint(Zone* zone, int64_t value) const {
-  ASSERT(this->ptr() == IsolateGroup::Current()->object_store()->mint_class());
-  if (this->constants() == Array::null()) return Mint::null();
-
-  Mint& canonical_value = Mint::Handle(zone);
-  CanonicalMintSet constants(zone, this->constants());
-  canonical_value ^= constants.GetOrNull(CanonicalMintKey(value));
-  this->set_constants(constants.Release());
-  return canonical_value.ptr();
-}
-
 class CanonicalInstanceKey {
  public:
   explicit CanonicalInstanceKey(const Instance& key) : key_(key) {
-    ASSERT(!(key.IsString() || key.IsInteger() || key.IsAbstractType()));
+    ASSERT(!(key.IsString() || key.IsAbstractType()));
   }
   bool Matches(const Instance& obj) const {
-    ASSERT(!(obj.IsString() || obj.IsInteger() || obj.IsAbstractType()));
+    ASSERT(!(obj.IsString() || obj.IsAbstractType()));
     if (key_.CanonicalizeEquals(obj)) {
       ASSERT(obj.IsCanonical());
       return true;
@@ -5966,15 +5871,15 @@
 
   // Called when growing the table.
   static bool IsMatch(const Object& a, const Object& b) {
-    ASSERT(!(a.IsString() || a.IsInteger() || a.IsAbstractType()));
-    ASSERT(!(b.IsString() || b.IsInteger() || b.IsAbstractType()));
+    ASSERT(!(a.IsString() || a.IsAbstractType()));
+    ASSERT(!(b.IsString() || b.IsAbstractType()));
     return a.ptr() == b.ptr();
   }
   static bool IsMatch(const CanonicalInstanceKey& a, const Object& b) {
     return a.Matches(Instance::Cast(b));
   }
   static uword Hash(const Object& key) {
-    ASSERT(!(key.IsString() || key.IsNumber() || key.IsAbstractType()));
+    ASSERT(!(key.IsString() || key.IsAbstractType()));
     ASSERT(key.IsInstance());
     return Instance::Cast(key).CanonicalizeHash();
   }
@@ -6017,26 +5922,6 @@
   return canonical_value.ptr();
 }
 
-void Class::InsertCanonicalDouble(Zone* zone, const Double& constant) const {
-  if (this->constants() == Array::null()) {
-    this->set_constants(Array::Handle(
-        zone, HashTables::New<CanonicalDoubleSet>(128, Heap::kOld)));
-  }
-  CanonicalDoubleSet constants(zone, this->constants());
-  constants.InsertNewOrGet(CanonicalDoubleKey(constant));
-  this->set_constants(constants.Release());
-}
-
-void Class::InsertCanonicalMint(Zone* zone, const Mint& constant) const {
-  if (this->constants() == Array::null()) {
-    this->set_constants(Array::Handle(
-        zone, HashTables::New<CanonicalMintSet>(128, Heap::kOld)));
-  }
-  CanonicalMintSet constants(zone, this->constants());
-  constants.InsertNewOrGet(CanonicalMintKey(constant));
-  this->set_constants(constants.Release());
-}
-
 void Class::RehashConstants(Zone* zone) const {
   intptr_t cid = id();
   if ((cid == kMintCid) || (cid == kDoubleCid)) {
@@ -14469,10 +14354,6 @@
   all_libs.Add(&Library::ZoneHandle(Library::DeveloperLibrary()));
   DEVELOPER_LIB_INTRINSIC_LIST(CHECK_FINGERPRINTS_ASM_INTRINSIC);
 
-  all_libs.Clear();
-  all_libs.Add(&Library::ZoneHandle(Library::MathLibrary()));
-  MATH_LIB_INTRINSIC_LIST(CHECK_FINGERPRINTS_ASM_INTRINSIC);
-
 #undef CHECK_FINGERPRINTS_INNER
 #undef CHECK_FINGERPRINTS
 #undef CHECK_FINGERPRINTS_ASM_INTRINSIC
@@ -19138,7 +19019,7 @@
 }
 
 InstancePtr Instance::CanonicalizeLocked(Thread* thread) const {
-  if (this->IsCanonical()) {
+  if (!this->ptr()->IsHeapObject() || this->IsCanonical()) {
     return this->ptr();
   }
   ASSERT(!IsNull());
@@ -22155,46 +22036,6 @@
   return printer.buffer();
 }
 
-InstancePtr Number::CanonicalizeLocked(Thread* thread) const {
-  intptr_t cid = GetClassId();
-  switch (cid) {
-    case kSmiCid:
-      return static_cast<SmiPtr>(raw_value());
-    case kMintCid:
-      return Mint::NewCanonicalLocked(thread, Mint::Cast(*this).value());
-    case kDoubleCid:
-      return Double::NewCanonicalLocked(thread, Double::Cast(*this).value());
-    default:
-      UNREACHABLE();
-  }
-  return Instance::null();
-}
-
-#if defined(DEBUG)
-bool Number::CheckIsCanonical(Thread* thread) const {
-  intptr_t cid = GetClassId();
-  Zone* zone = thread->zone();
-  const Class& cls = Class::Handle(zone, this->clazz());
-  switch (cid) {
-    case kSmiCid:
-      return true;
-    case kMintCid: {
-      Mint& result = Mint::Handle(zone);
-      result ^= cls.LookupCanonicalMint(zone, Mint::Cast(*this).value());
-      return (result.ptr() == this->ptr());
-    }
-    case kDoubleCid: {
-      Double& dbl = Double::Handle(zone);
-      dbl ^= cls.LookupCanonicalDouble(zone, Double::Cast(*this).value());
-      return (dbl.ptr() == this->ptr());
-    }
-    default:
-      UNREACHABLE();
-  }
-  return false;
-}
-#endif  // DEBUG
-
 const char* Number::ToCString() const {
   // Number is an interface. No instances of Number should exist.
   UNREACHABLE();
@@ -22541,29 +22382,9 @@
 
 MintPtr Mint::NewCanonical(int64_t value) {
   Thread* thread = Thread::Current();
-  SafepointMutexLocker ml(
-      thread->isolate_group()->constant_canonicalization_mutex());
-  return NewCanonicalLocked(thread, value);
-}
-
-MintPtr Mint::NewCanonicalLocked(Thread* thread, int64_t value) {
-  // Do not allocate a Mint if Smi would do.
-  ASSERT(!Smi::IsValid(value));
-  Zone* zone = thread->zone();
-  auto isolate_group = thread->isolate_group();
-  const Class& cls =
-      Class::Handle(zone, isolate_group->object_store()->mint_class());
-  Mint& canonical_value =
-      Mint::Handle(zone, cls.LookupCanonicalMint(zone, value));
-  if (!canonical_value.IsNull()) {
-    return canonical_value.ptr();
-  }
-  canonical_value = Mint::New(value, Heap::kOld);
-  canonical_value.SetCanonical();
-  // The value needs to be added to the constants list. Grow the list if
-  // it is full.
-  cls.InsertCanonicalMint(zone, canonical_value);
-  return canonical_value.ptr();
+  Mint& mint = Mint::Handle(thread->zone(), Mint::New(value, Heap::kOld));
+  mint ^= mint.Canonicalize(thread);
+  return mint.ptr();
 }
 
 bool Mint::Equals(const Instance& other) const {
@@ -22672,28 +22493,9 @@
 
 DoublePtr Double::NewCanonical(double value) {
   Thread* thread = Thread::Current();
-  SafepointMutexLocker ml(
-      thread->isolate_group()->constant_canonicalization_mutex());
-  return NewCanonicalLocked(thread, value);
-}
-
-DoublePtr Double::NewCanonicalLocked(Thread* thread, double value) {
-  Zone* zone = thread->zone();
-  auto isolate_group = thread->isolate_group();
-  const Class& cls =
-      Class::Handle(zone, isolate_group->object_store()->double_class());
-  // Linear search to see whether this value is already present in the
-  // list of canonicalized constants.
-  Double& canonical_value =
-      Double::Handle(zone, cls.LookupCanonicalDouble(zone, value));
-  if (!canonical_value.IsNull()) {
-    return canonical_value.ptr();
-  }
-  canonical_value = Double::New(value, Heap::kOld);
-  canonical_value.SetCanonical();
-  // The value needs to be added to the constants list.
-  cls.InsertCanonicalDouble(zone, canonical_value);
-  return canonical_value.ptr();
+  Double& dbl = Double::Handle(thread->zone(), Double::New(value, Heap::kOld));
+  dbl ^= dbl.Canonicalize(thread);
+  return dbl.ptr();
 }
 
 DoublePtr Double::NewCanonical(const String& str) {
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 6b5cb1b..b8d8a8a 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1497,16 +1497,11 @@
   FieldPtr LookupInstanceFieldAllowPrivate(const String& name) const;
   FieldPtr LookupStaticFieldAllowPrivate(const String& name) const;
 
-  DoublePtr LookupCanonicalDouble(Zone* zone, double value) const;
-  MintPtr LookupCanonicalMint(Zone* zone, int64_t value) const;
-
   // The methods above are more efficient than this generic one.
   InstancePtr LookupCanonicalInstance(Zone* zone, const Instance& value) const;
 
   InstancePtr InsertCanonicalConstant(Zone* zone,
                                       const Instance& constant) const;
-  void InsertCanonicalDouble(Zone* zone, const Double& constant) const;
-  void InsertCanonicalMint(Zone* zone, const Mint& constant) const;
 
   void RehashConstants(Zone* zone) const;
 
@@ -9117,15 +9112,6 @@
   // TODO(iposva): Add more useful Number methods.
   StringPtr ToString(Heap::Space space) const;
 
-  // Numbers are canonicalized differently from other instances/strings.
-  // Caller must hold IsolateGroup::constant_canonicalization_mutex_.
-  virtual InstancePtr CanonicalizeLocked(Thread* thread) const;
-
-#if defined(DEBUG)
-  // Check if number is canonical.
-  virtual bool CheckIsCanonical(Thread* thread) const;
-#endif  // DEBUG
-
  private:
   OBJECT_IMPLEMENTATION(Number, Instance);
 
@@ -9329,7 +9315,6 @@
   static MintPtr New(int64_t value, Heap::Space space = Heap::kNew);
 
   static MintPtr NewCanonical(int64_t value);
-  static MintPtr NewCanonicalLocked(Thread* thread, int64_t value);
 
  private:
   void set_value(int64_t value) const;
@@ -9356,7 +9341,6 @@
 
   // Returns a canonical double object allocated in the old gen space.
   static DoublePtr NewCanonical(double d);
-  static DoublePtr NewCanonicalLocked(Thread* thread, double d);
 
   // Returns a canonical double object (allocated in the old gen space) or
   // Double::null() if str points to a string that does not convert to a
diff --git a/samples/samples.status b/samples/samples.status
index 6f471b2..f119b0e 100644
--- a/samples/samples.status
+++ b/samples/samples.status
@@ -20,7 +20,7 @@
 [ $compiler == none && $runtime == vm && $system == fuchsia ]
 *: Skip # Not yet triaged.
 
-[ $arch == simarm || $arch == simarm64 || $arch == simarm64c ]
+[ $arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64 ]
 ffi/*: SkipByDesign # FFI skips, see ffi.status
 
 [ $arch != x64 || $compiler != dartk || $system != linux || $hot_reload || $hot_reload_rollback ]
diff --git a/samples_2/samples_2.status b/samples_2/samples_2.status
index 6f471b2..f119b0e 100644
--- a/samples_2/samples_2.status
+++ b/samples_2/samples_2.status
@@ -20,7 +20,7 @@
 [ $compiler == none && $runtime == vm && $system == fuchsia ]
 *: Skip # Not yet triaged.
 
-[ $arch == simarm || $arch == simarm64 || $arch == simarm64c ]
+[ $arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64 ]
 ffi/*: SkipByDesign # FFI skips, see ffi.status
 
 [ $arch != x64 || $compiler != dartk || $system != linux || $hot_reload || $hot_reload_rollback ]
diff --git a/sdk/lib/_internal/vm/lib/math_patch.dart b/sdk/lib/_internal/vm/lib/math_patch.dart
index ae7872c..05b498b 100644
--- a/sdk/lib/_internal/vm/lib/math_patch.dart
+++ b/sdk/lib/_internal/vm/lib/math_patch.dart
@@ -214,30 +214,19 @@
 }
 
 class _Random implements Random {
-  // Internal state of the random number generator.
-  @pragma("vm:entry-point")
-  final Uint32List _state;
-  static const _kSTATE_LO = 0;
-  static const _kSTATE_HI = 1; // Unused in Dart code.
+  int _state;
 
   _Random._withState(this._state);
 
   // The algorithm used here is Multiply with Carry (MWC) with a Base b = 2^32.
   // http://en.wikipedia.org/wiki/Multiply-with-carry
   // The constant A is selected from "Numerical Recipes 3rd Edition" p.348 B1.
-
-  // Implements:
-  //   const _A = 0xffffda61;
-  //   var state =
-  //       ((_A * (_state[_kSTATE_LO])) + _state[_kSTATE_HI]) & ((1 << 64) - 1);
-  //   _state[_kSTATE_LO] = state & ((1 << 32) - 1);
-  //   _state[_kSTATE_HI] = state >> 32;
-  // This is a native to prevent 64-bit operations in Dart, which
-  // fail with --throw_on_javascript_int_overflow.
-  // TODO(regis): Implement in Dart and remove Random_nextState in math.cc.
-  @pragma("vm:recognized", "asm-intrinsic")
-  @pragma("vm:external-name", "Random_nextState")
-  external void _nextState();
+  void _nextState() {
+    const A = 0xffffda61;
+    final state_lo = _state & 0xFFFFFFFF;
+    final state_hi = _state >>> 32;
+    _state = (A * state_lo) + state_hi;
+  }
 
   int nextInt(int max) {
     const limit = 0x3FFFFFFF;
@@ -248,14 +237,14 @@
     if ((max & -max) == max) {
       // Fast case for powers of two.
       _nextState();
-      return _state[_kSTATE_LO] & (max - 1);
+      return _state & 0xFFFFFFFF & (max - 1);
     }
 
     var rnd32;
     var result;
     do {
       _nextState();
-      rnd32 = _state[_kSTATE_LO];
+      rnd32 = _state & 0xFFFFFFFF;
       result = rnd32 % max;
     } while ((rnd32 - result + max) > _POW2_32);
     return result;
@@ -277,19 +266,31 @@
   // Use a singleton Random object to get a new seed if no seed was passed.
   static final _prng = new _Random._withState(_initialSeed());
 
-  // This is a native to prevent 64-bit operations in Dart, which
-  // fail with --throw_on_javascript_int_overflow.
-  // TODO(regis): Implement here in Dart and remove native in math.cc.
-  @pragma("vm:external-name", "Random_setupSeed")
-  external static Uint32List _setupSeed(int seed);
+  // Thomas Wang 64-bit mix.
+  // http://www.concentric.net/~Ttwang/tech/inthash.htm
+  // via. http://web.archive.org/web/20071223173210/http://www.concentric.net/~Ttwang/tech/inthash.htm
+  static int _setupSeed(int n) {
+    n = (~n) + (n << 21); // n = (n << 21) - n - 1;
+    n = n ^ (n >>> 24);
+    n = n * 265; // n = (n + (n << 3)) + (n << 8);
+    n = n ^ (n >>> 14);
+    n = n * 21; // n = (n + (n << 2)) + (n << 4);
+    n = n ^ (n >>> 28);
+    n = n + (n << 31);
+    if (n == 0) {
+      n = 0x5a17;
+    }
+    return n;
+  }
+
   // Get a seed from the VM's random number provider.
   @pragma("vm:external-name", "Random_initialSeed")
-  external static Uint32List _initialSeed();
+  external static int _initialSeed();
 
   static int _nextSeed() {
     // Trigger the PRNG once to change the internal state.
     _prng._nextState();
-    return _prng._state[_kSTATE_LO];
+    return _prng._state & 0xFFFFFFFF;
   }
 }
 
diff --git a/tests/co19/co19-kernel.status b/tests/co19/co19-kernel.status
index 09b27c9..4e3c7d4 100644
--- a/tests/co19/co19-kernel.status
+++ b/tests/co19/co19-kernel.status
@@ -27,7 +27,7 @@
 LibTest/core/List/List_class_A01_t02: Slow, Pass
 LibTest/core/List/List_class_A01_t03: Slow, Pass
 
-[ $runtime == dart_precompiled && ($arch == simarm64 || $arch == simarm64c) ]
+[ $runtime == dart_precompiled && ($arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ]
 LibTest/collection/ListBase/ListBase_class_A01_t01: SkipSlow # Issue 43036
 LibTest/collection/ListMixin/ListMixin_class_A01_t01: SkipSlow # Issue 43036
 
@@ -35,5 +35,5 @@
 # as that would involve running CFE (the front end) in simulator mode
 # to compile the URI file specified in spawnURI code.
 # These Isolate tests that use spawnURI are hence skipped on purpose.
-[ $runtime == dart_precompiled || $runtime == vm && ($arch == simarm || $arch == simarm64 || $arch == simarm64c) ]
+[ $runtime == dart_precompiled || $runtime == vm && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ]
 LibTest/isolate/Isolate/spawnUri*: Skip
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index d3b0fe3..fb4d981 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -20,10 +20,10 @@
 LibTest/core/List/List_all_t05: SkipSlow # Very slow compilation in debug mode.
 LibTest/core/List/List_all_t06: SkipSlow # Very slow compilation in debug mode.
 
-[ $runtime == dart_precompiled && ($arch == simarm64 || $arch == simarm64c) ]
+[ $runtime == dart_precompiled && ($arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ]
 LibTest/async/Stream/Stream.periodic_all_t02: Skip # Issue 42898
 
-[ $arch == simarm || $arch == simarm64 || $arch == simarm64c ]
+[ $arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64 ]
 Language/Libraries_and_Scripts/Scripts/top_level_main_t01: SkipSlow # Very slow on sim* architectures.
 Language/Libraries_and_Scripts/Scripts/top_level_main_t06: SkipSlow # Very slow on sim* architectures.
 LibTest/collection/ListBase/ListBase_class_A01_t01: SkipSlow # Very slow on sim* architectures.
diff --git a/tests/co19_2/co19_2-kernel.status b/tests/co19_2/co19_2-kernel.status
index 0ea8baf..4953365 100644
--- a/tests/co19_2/co19_2-kernel.status
+++ b/tests/co19_2/co19_2-kernel.status
@@ -30,7 +30,7 @@
 LibTest/core/List/List_class_A01_t02: Slow, Pass
 LibTest/core/List/List_class_A01_t03: Slow, Pass
 
-[ $runtime == dart_precompiled && ($arch == simarm64 || $arch == simarm64c) ]
+[ $runtime == dart_precompiled && ($arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ]
 LibTest/collection/ListBase/ListBase_class_A01_t01: SkipSlow # Issue 43036
 LibTest/collection/ListMixin/ListMixin_class_A01_t01: SkipSlow # Issue 43036
 
@@ -38,5 +38,5 @@
 # as that would involve running CFE (the front end) in simulator mode
 # to compile the URI file specified in spawnURI code.
 # These Isolate tests that use spawnURI are hence skipped on purpose.
-[ $runtime == dart_precompiled || $runtime == vm && ($arch == simarm || $arch == simarm64 || $arch == simarm64c) ]
+[ $runtime == dart_precompiled || $runtime == vm && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ]
 LibTest/isolate/Isolate/spawnUri*: Skip
diff --git a/tests/co19_2/co19_2-runtime.status b/tests/co19_2/co19_2-runtime.status
index 2871e90..9236eaf 100644
--- a/tests/co19_2/co19_2-runtime.status
+++ b/tests/co19_2/co19_2-runtime.status
@@ -15,10 +15,10 @@
 LibTest/collection/ListMixin/ListMixin_class_A01_t05: SkipSlow # Very slow compilation in debug mode.
 LibTest/collection/ListMixin/ListMixin_class_A01_t06: SkipSlow # Very slow compilation in debug mode.
 
-[ $runtime == dart_precompiled && ($arch == simarm64 || $arch == simarm64c) ]
+[ $runtime == dart_precompiled && ($arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ]
 LibTest/async/Stream/Stream.periodic_all_t02: Skip # Issue 42898
 
-[ $arch == simarm || $arch == simarm64 || $arch == simarm64c ]
+[ $arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64 ]
 LibTest/collection/ListBase/ListBase_class_A01_t01: SkipSlow # Very slow on sim* architectures.
 LibTest/collection/ListBase/ListBase_class_A01_t04: SkipSlow # Very slow on sim* architectures.
 LibTest/collection/ListBase/ListBase_class_A01_t05: SkipSlow # Very slow on sim* architectures.
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index ecde5a5..413ef72 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -49,7 +49,7 @@
 iterable_return_type_int64_test: SkipByDesign # Requires int64 support.
 typed_data_with_limited_ints_test: SkipByDesign # Requires fixed-size int64 support.
 
-[ $arch == simarm || $arch == simarm64 || $arch == simarm64c ]
+[ $arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64 ]
 bigint_parse_radix_test: Skip # Issue 31659
 bigint_test: Skip # Issue 31659
 
diff --git a/tests/corelib_2/corelib_2.status b/tests/corelib_2/corelib_2.status
index 3ee1d12..87e8d4a 100644
--- a/tests/corelib_2/corelib_2.status
+++ b/tests/corelib_2/corelib_2.status
@@ -52,7 +52,7 @@
 iterable_return_type_int64_test: SkipByDesign # Requires int64 support.
 typed_data_with_limited_ints_test: SkipByDesign # Requires fixed-size int64 support.
 
-[ $arch == simarm || $arch == simarm64 || $arch == simarm64c ]
+[ $arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64 ]
 bigint_parse_radix_test: Skip # Issue 31659
 bigint_test: Skip # Issue 31659
 
diff --git a/tests/ffi/ffi.status b/tests/ffi/ffi.status
index b119eb8..e22df5b 100644
--- a/tests/ffi/ffi.status
+++ b/tests/ffi/ffi.status
@@ -33,7 +33,7 @@
 [ $system != android && $system != linux && $system != macos && $system != windows ]
 *: Skip # FFI not yet supported on other OSes.
 
-[ $arch == simarm || $arch == simarm64 || $arch == simarm64c ]
+[ $arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64 ]
 *: Skip # FFI not yet supported on the arm simulator.
 
 [ $builder_tag == asan || $builder_tag == msan || $builder_tag == tsan ]
diff --git a/tests/ffi_2/ffi_2.status b/tests/ffi_2/ffi_2.status
index b119eb8..e22df5b 100644
--- a/tests/ffi_2/ffi_2.status
+++ b/tests/ffi_2/ffi_2.status
@@ -33,7 +33,7 @@
 [ $system != android && $system != linux && $system != macos && $system != windows ]
 *: Skip # FFI not yet supported on other OSes.
 
-[ $arch == simarm || $arch == simarm64 || $arch == simarm64c ]
+[ $arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64 ]
 *: Skip # FFI not yet supported on the arm simulator.
 
 [ $builder_tag == asan || $builder_tag == msan || $builder_tag == tsan ]
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index ae16628..0b262df 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -71,7 +71,7 @@
 [ $runtime != dart_precompiled && ($runtime != vm || $compiler != dartk && $compiler != none) ]
 isolate/vm_rehash_test: SkipByDesign
 
-[ $arch == simarm64 || $arch == simarm64c ]
+[ $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64 ]
 convert/utf85_test: Skip # Pass, Slow Issue 20111.
 
 [ $arch != x64 || $runtime != vm ]
@@ -85,7 +85,7 @@
 # as that would involve running CFE (the front end) in simulator mode
 # to compile the URI file specified in spawnURI code.
 # These Isolate tests that use spawnURI are hence skipped on purpose.
-[ $runtime == dart_precompiled || $runtime == vm && ($arch == simarm || $arch == simarm64 || $arch == simarm64c) ]
+[ $runtime == dart_precompiled || $runtime == vm && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ]
 isolate/count_test: Skip # Isolate.spawnUri
 isolate/cross_isolate_message_test: Skip # Isolate.spawnUri
 isolate/deferred_in_isolate2_test: Skip # Isolate.spawnUri
diff --git a/tests/lib/lib_vm.status b/tests/lib/lib_vm.status
index 07ece5a..2a3deea 100644
--- a/tests/lib/lib_vm.status
+++ b/tests/lib/lib_vm.status
@@ -76,10 +76,10 @@
 mirrors/library_uri_io_test: RuntimeError
 mirrors/library_uri_package_test: RuntimeError
 
-[ $runtime == vm && ($arch == simarm64 || $arch == simarm64c) ]
+[ $runtime == vm && ($arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ]
 convert/utf85_test: Skip # Pass, Slow Issue 20111.
 
-[ $arch == simarm || $arch == simarm64 || $arch == simarm64c || $hot_reload || $hot_reload_rollback ]
+[ $arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64 || $hot_reload || $hot_reload_rollback ]
 convert/chunked_conversion_utf88_test: SkipSlow
 convert/streamed_conversion_json_utf8_decode_test: SkipSlow
 convert/utf85_test: SkipSlow
diff --git a/tests/lib_2/lib_2.status b/tests/lib_2/lib_2.status
index fbaf7af..cb20d17 100644
--- a/tests/lib_2/lib_2.status
+++ b/tests/lib_2/lib_2.status
@@ -71,7 +71,7 @@
 [ $runtime != dart_precompiled && ($runtime != vm || $compiler != dartk && $compiler != none) ]
 isolate/vm_rehash_test: SkipByDesign
 
-[ $arch == simarm64 || $arch == simarm64c ]
+[ $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64 ]
 convert/utf85_test: Skip # Pass, Slow Issue 20111.
 
 [ $arch != x64 || $runtime != vm ]
@@ -85,7 +85,7 @@
 # as that would involve running CFE (the front end) in simulator mode
 # to compile the URI file specified in spawnURI code.
 # These Isolate tests that use spawnURI are hence skipped on purpose.
-[ $runtime == dart_precompiled || $runtime == vm && ($arch == simarm || $arch == simarm64 || $arch == simarm64c) ]
+[ $runtime == dart_precompiled || $runtime == vm && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ]
 isolate/count_test: Skip # Isolate.spawnUri
 isolate/cross_isolate_message_test: Skip # Isolate.spawnUri
 isolate/deferred_in_isolate2_test: Skip # Isolate.spawnUri
diff --git a/tests/lib_2/lib_2_vm.status b/tests/lib_2/lib_2_vm.status
index c2e26f4..2409de0 100644
--- a/tests/lib_2/lib_2_vm.status
+++ b/tests/lib_2/lib_2_vm.status
@@ -66,7 +66,7 @@
 mirrors/library_uri_io_test: RuntimeError
 mirrors/library_uri_package_test: RuntimeError
 
-[ $arch == simarm || $arch == simarm64 || $arch == simarm64c || $hot_reload || $hot_reload_rollback ]
+[ $arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64 || $hot_reload || $hot_reload_rollback ]
 convert/chunked_conversion_utf88_test: SkipSlow
 convert/streamed_conversion_json_utf8_decode_test: SkipSlow
 convert/utf85_test: SkipSlow
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index 1c9d7d1..905ce63 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -101,7 +101,7 @@
 fragmentation_test: SkipSlow
 fragmentation_typed_data_test: SkipSlow
 
-[ $arch == simarm || $arch == simarm64 || $arch == simarm64c ]
+[ $arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64 ]
 io/socket_sigpipe_test: SkipByDesign # Test uses ffi
 
 [ $compiler == dart2js || $compiler == dartdevc || $compiler == dartdevk ]
diff --git a/tests/standalone/standalone_kernel.status b/tests/standalone/standalone_kernel.status
index a958509..609c61b 100644
--- a/tests/standalone/standalone_kernel.status
+++ b/tests/standalone/standalone_kernel.status
@@ -52,12 +52,12 @@
 # Enabling of dartk for sim{arm,arm64} revealed these test failures, which
 # are to be triaged.  Isolate tests are skipped on purpose due to the usage of
 # batch mode.
-[ $compiler == dartk && ($arch == simarm || $arch == simarm64 || $arch == simarm64c) ]
+[ $compiler == dartk && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ]
 io/file_blocking_lock_test: Crash # Please triage.
 io/file_lock_test: Slow, Pass
 map_insert_remove_oom_test: Skip # Heap limit too low.
 
-[ $compiler == dartk && ($arch == simarm64 || $arch == simarm64c) ]
+[ $compiler == dartk && ($arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ]
 io/http_bind_test: Slow, Pass
 
 [ $compiler == dartk && ($hot_reload || $hot_reload_rollback) ]
diff --git a/tests/standalone/standalone_vm.status b/tests/standalone/standalone_vm.status
index 86c5c3c..067e3e05 100644
--- a/tests/standalone/standalone_vm.status
+++ b/tests/standalone/standalone_vm.status
@@ -61,7 +61,7 @@
 [ $mode == release && $runtime == vm && $system == windows ]
 io/http_server_close_response_after_error_test: Pass, Timeout # Issue 28370: timeout.
 
-[ $runtime == dart_precompiled && $system == linux && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == x64) ]
+[ $runtime == dart_precompiled && $system == linux && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64 || $arch == x64) ]
 io/stdout_stderr_non_blocking_test: Pass, Timeout # Issue 35192
 
 [ $runtime == vm && ($arch == arm || $arch == arm64) ]
@@ -71,7 +71,7 @@
 io/file_typed_data_test: Skip # Issue 26109
 io/process_sync_test: Timeout, Pass
 
-[ $runtime == vm && ($arch == simarm || $arch == simarm64 || $arch == simarm64c) ]
+[ $runtime == vm && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ]
 io/dart_std_io_pipe_test: Timeout, Pass
 io/http_client_stays_alive_test: Skip # Spawns process in Dart2 mode.
 io/process_sync_test: Timeout, Pass
diff --git a/tests/standalone_2/standalone_2.status b/tests/standalone_2/standalone_2.status
index 6b785dd..5e3852e 100644
--- a/tests/standalone_2/standalone_2.status
+++ b/tests/standalone_2/standalone_2.status
@@ -108,7 +108,7 @@
 fragmentation_test: SkipSlow
 fragmentation_typed_data_test: SkipSlow
 
-[ $arch == simarm || $arch == simarm64 || $arch == simarm64c ]
+[ $arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64 ]
 io/socket_sigpipe_test: SkipByDesign # Test uses ffi
 
 [ $compiler == dart2js || $compiler == dartdevc || $compiler == dartdevk ]
diff --git a/tests/standalone_2/standalone_2_kernel.status b/tests/standalone_2/standalone_2_kernel.status
index 77236ea..afb2751 100644
--- a/tests/standalone_2/standalone_2_kernel.status
+++ b/tests/standalone_2/standalone_2_kernel.status
@@ -54,12 +54,12 @@
 # Enabling of dartk for sim{arm,arm64} revealed these test failures, which
 # are to be triaged.  Isolate tests are skipped on purpose due to the usage of
 # batch mode.
-[ $compiler == dartk && ($arch == simarm || $arch == simarm64 || $arch == simarm64c) ]
+[ $compiler == dartk && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ]
 io/file_blocking_lock_test: Crash # Please triage.
 io/file_lock_test: Slow, Pass
 map_insert_remove_oom_test: Skip # Heap limit too low.
 
-[ $compiler == dartk && ($arch == simarm64 || $arch == simarm64c) ]
+[ $compiler == dartk && ($arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ]
 io/http_bind_test: Slow, Pass
 
 [ $compiler == dartk && ($hot_reload || $hot_reload_rollback) ]
diff --git a/tests/standalone_2/standalone_2_vm.status b/tests/standalone_2/standalone_2_vm.status
index 86c5c3c..067e3e05 100644
--- a/tests/standalone_2/standalone_2_vm.status
+++ b/tests/standalone_2/standalone_2_vm.status
@@ -61,7 +61,7 @@
 [ $mode == release && $runtime == vm && $system == windows ]
 io/http_server_close_response_after_error_test: Pass, Timeout # Issue 28370: timeout.
 
-[ $runtime == dart_precompiled && $system == linux && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == x64) ]
+[ $runtime == dart_precompiled && $system == linux && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64 || $arch == x64) ]
 io/stdout_stderr_non_blocking_test: Pass, Timeout # Issue 35192
 
 [ $runtime == vm && ($arch == arm || $arch == arm64) ]
@@ -71,7 +71,7 @@
 io/file_typed_data_test: Skip # Issue 26109
 io/process_sync_test: Timeout, Pass
 
-[ $runtime == vm && ($arch == simarm || $arch == simarm64 || $arch == simarm64c) ]
+[ $runtime == vm && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ]
 io/dart_std_io_pipe_test: Timeout, Pass
 io/http_client_stays_alive_test: Skip # Spawns process in Dart2 mode.
 io/process_sync_test: Timeout, Pass
diff --git a/third_party/pkg_tested/pkg_tested.status b/third_party/pkg_tested/pkg_tested.status
index b80af3e..5fb6028 100644
--- a/third_party/pkg_tested/pkg_tested.status
+++ b/third_party/pkg_tested/pkg_tested.status
@@ -24,7 +24,7 @@
 pub/test/run/app_can_read_from_stdin_test: Fail # Issue 19448
 pub/test/run/forwards_signal_posix_test: SkipByDesign
 
-[ $runtime == vm && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $builder_tag == asan || $mode == debug) ]
+[ $runtime == vm && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64 || $builder_tag == asan || $mode == debug) ]
 dart_style/test/command_line_test: Skip # The test controller does not take into account that tests take much longer in debug mode or on simulators.
 dart_style/test/formatter_test: Skip # The test controller does not take into account that tests take much longer in debug mode or on simulators.
 
diff --git a/tools/VERSION b/tools/VERSION
index e692984..8a18778 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 17
 PATCH 0
-PRERELEASE 84
+PRERELEASE 85
 PRERELEASE_PATCH 0
\ No newline at end of file