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, '&')
+ .replace(/"/g, '"')
+ .replace(/</g, '<')
+ .replace(/>/g, '>');
+}
+</script>
+</head>
+<body onload='init()'>
+<div style='position: absolute; top: 5px; left: 5px;'>
+ <input type='button' onclick='showOptions()' value='Options & 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'> </span><input checked type='checkbox' id='check_0' value='A'>Global absolute (A)
+ <br><span class='swatch' id='swatch_1'> </span><input checked type='checkbox' id='check_1' value='B'>Global uninitialized data (B)
+ <br><span class='swatch' id='swatch_2'> </span><input checked type='checkbox' id='check_2' value='b'>Local uninitialized data (b)
+ <br><span class='swatch' id='swatch_3'> </span><input checked type='checkbox' id='check_3' value='C'>Global uninitialized common (C)
+ <br><span class='swatch' id='swatch_4'> </span><input checked type='checkbox' id='check_4' value='D'>Global initialized data (D)
+ <br><span class='swatch' id='swatch_5'> </span><input checked type='checkbox' id='check_5' value='d'>Local initialized data (d)
+ <br><span class='swatch' id='swatch_6'> </span><input checked type='checkbox' id='check_6' value='G'>Global small initialized data (G)
+ <br><span class='swatch' id='swatch_7'> </span><input checked type='checkbox' id='check_7' value='g'>Local small initialized data (g)
+ <br><span class='swatch' id='swatch_8'> </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'> </span><input checked type='checkbox' id='check_9' value='N'>Debugging (N)
+ <br><span class='swatch' id='swatch_10'> </span><input checked type='checkbox' id='check_10' value='p'>Stack unwind (p)
+ <br><span class='swatch' id='swatch_11'> </span><input checked type='checkbox' id='check_11' value='R'>Global read-only data (R)
+ <br><span class='swatch' id='swatch_12'> </span><input checked type='checkbox' id='check_12' value='r'>Local read-only data (r)
+ <br><span class='swatch' id='swatch_13'> </span><input checked type='checkbox' id='check_13' value='S'>Global small uninitialized data (S)
+ <br><span class='swatch' id='swatch_14'> </span><input checked type='checkbox' id='check_14' value='s'>Local small uninitialized data (s)
+ <br><span class='swatch' id='swatch_15'> </span><input checked type='checkbox' id='check_15' value='T'>Global code (T)
+ <br><span class='swatch' id='swatch_16'> </span><input checked type='checkbox' id='check_16' value='t'>Local code (t)
+ <br><span class='swatch' id='swatch_17'> </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'> </span><input checked type='checkbox' id='check_18' value='u'>Unique (u)
+ <br><span class='swatch' id='swatch_19'> </span><input checked type='checkbox' id='check_19' value='V'>Global weak object (V)
+ <br><span class='swatch' id='swatch_20'> </span><input checked type='checkbox' id='check_20' value='v'>Local weak object (v)
+ <br><span class='swatch' id='swatch_21'> </span><input checked type='checkbox' id='check_21' value='W'>Global weak symbol (W)
+ <br><span class='swatch' id='swatch_22'> </span><input checked type='checkbox' id='check_22' value='w'>Local weak symbol (w)
+ <br><span class='swatch' id='swatch_23'> </span><input checked type='checkbox' id='check_23' value='@'>Vtable entry (@)
+ <br><span class='swatch' id='swatch_24'> </span><input checked type='checkbox' id='check_24' value='-'>STABS debugging (-)
+ <br><span class='swatch' id='swatch_25'> </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;'>
+ x <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