dart2js_info: enable and fix lints, validate analysis on CI
Also updated dependencies and dropped publish information Change-Id: Ie5d8ca907599c5e504c747d97413d32ef9e329e3 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/217061 Auto-Submit: Kevin Moore <kevmoo@google.com> Reviewed-by: Sigmund Cherem <sigmund@google.com> Commit-Queue: Kevin Moore <kevmoo@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
189aeead47
commit
cc40080d96
@@ -11,7 +11,7 @@
|
||||
"constraint, update this by running tools/generate_package_config.dart."
|
||||
],
|
||||
"configVersion": 2,
|
||||
"generated": "2021-10-13T14:43:47.733371",
|
||||
"generated": "2021-10-15T13:46:59.969883",
|
||||
"generator": "tools/generate_package_config.dart",
|
||||
"packages": [
|
||||
{
|
||||
@@ -208,7 +208,7 @@
|
||||
"name": "dart2js_info",
|
||||
"rootUri": "../pkg/dart2js_info",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "2.3"
|
||||
"languageVersion": "2.11"
|
||||
},
|
||||
{
|
||||
"name": "dart2js_runtime_metrics",
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
include: package:lints/recommended.yaml
|
||||
|
||||
analyzer:
|
||||
errors:
|
||||
# Until the protobuf package generates the right code - or the right ignores
|
||||
constant_identifier_names: ignore
|
||||
@@ -37,16 +37,20 @@ import 'package:dart2js_info/src/util.dart';
|
||||
import 'usage_exception.dart';
|
||||
|
||||
class CodeDepsCommand extends Command<void> with PrintUsageException {
|
||||
@override
|
||||
final String name = "code_deps";
|
||||
@override
|
||||
final String description = "";
|
||||
|
||||
CodeDepsCommand() {
|
||||
addSubcommand(new _SomePathQuery());
|
||||
addSubcommand(_SomePathQuery());
|
||||
}
|
||||
}
|
||||
|
||||
class _SomePathQuery extends Command<void> with PrintUsageException {
|
||||
@override
|
||||
final String name = "some_path";
|
||||
@override
|
||||
final String description = "find a call-graph path between two elements.";
|
||||
|
||||
@override
|
||||
@@ -62,9 +66,9 @@ class _SomePathQuery extends Command<void> with PrintUsageException {
|
||||
var graph = graphFromInfo(info);
|
||||
|
||||
var source = info.functions
|
||||
.firstWhere(_longNameMatcher(new RegExp(args[1])), orElse: () => null);
|
||||
.firstWhere(_longNameMatcher(RegExp(args[1])), orElse: () => null);
|
||||
var target = info.functions
|
||||
.firstWhere(_longNameMatcher(new RegExp(args[2])), orElse: () => null);
|
||||
.firstWhere(_longNameMatcher(RegExp(args[2])), orElse: () => null);
|
||||
print('query: some_path');
|
||||
if (source == null) {
|
||||
usageException("source '${args[1]}' not found in '${args[0]}'");
|
||||
@@ -74,7 +78,7 @@ class _SomePathQuery extends Command<void> with PrintUsageException {
|
||||
usageException("target '${args[2]}' not found in '${args[0]}'");
|
||||
}
|
||||
print('target: ${longName(target)}');
|
||||
var path = new SomePathQuery(source, target).run(graph);
|
||||
var path = SomePathQuery(source, target).run(graph);
|
||||
if (path.isEmpty) {
|
||||
print('result: no path found');
|
||||
} else {
|
||||
@@ -103,12 +107,12 @@ class SomePathQuery {
|
||||
|
||||
List<Info> run(Graph<Info> graph) {
|
||||
var seen = <Info, Info>{source: null};
|
||||
var queue = new Queue<Info>();
|
||||
var queue = Queue<Info>();
|
||||
queue.addLast(source);
|
||||
while (queue.isNotEmpty) {
|
||||
var node = queue.removeFirst();
|
||||
if (identical(node, target)) {
|
||||
var result = new Queue<Info>();
|
||||
var result = Queue<Info>();
|
||||
while (node != null) {
|
||||
result.addFirst(node);
|
||||
node = seen[node];
|
||||
@@ -125,7 +129,7 @@ class SomePathQuery {
|
||||
}
|
||||
}
|
||||
|
||||
typedef bool LongNameMatcher(FunctionInfo info);
|
||||
typedef LongNameMatcher = bool Function(FunctionInfo info);
|
||||
|
||||
LongNameMatcher _longNameMatcher(RegExp regexp) =>
|
||||
(e) => regexp.hasMatch(longName(e));
|
||||
|
||||
@@ -11,13 +11,15 @@ import 'usage_exception.dart';
|
||||
|
||||
/// This tool reports how code is divided among deferred chunks.
|
||||
class ConvertCommand extends Command<void> with PrintUsageException {
|
||||
@override
|
||||
final String name = "convert";
|
||||
@override
|
||||
final String description = "Convert between info formats.";
|
||||
|
||||
ConvertCommand() {
|
||||
_addSubcommand(new ToJsonCommand());
|
||||
_addSubcommand(new ToBinaryCommand());
|
||||
_addSubcommand(new ToProtoCommand());
|
||||
_addSubcommand(ToJsonCommand());
|
||||
_addSubcommand(ToBinaryCommand());
|
||||
_addSubcommand(ToProtoCommand());
|
||||
}
|
||||
|
||||
_addSubcommand(Command<void> command) {
|
||||
|
||||
@@ -31,7 +31,9 @@ import 'package:shelf/shelf_io.dart' as shelf;
|
||||
import 'usage_exception.dart';
|
||||
|
||||
class CoverageLogServerCommand extends Command<void> with PrintUsageException {
|
||||
@override
|
||||
final String name = 'coverage_server';
|
||||
@override
|
||||
final String description = 'Server to gather code coverage data';
|
||||
|
||||
CoverageLogServerCommand() {
|
||||
@@ -46,30 +48,29 @@ class CoverageLogServerCommand extends Command<void> with PrintUsageException {
|
||||
' into the .js file',
|
||||
defaultsTo: '')
|
||||
..addOption('out',
|
||||
abbr: 'o',
|
||||
help: 'output log file',
|
||||
defaultsTo: _DEFAULT_OUT_TEMPLATE);
|
||||
abbr: 'o', help: 'output log file', defaultsTo: _defaultOutTemplate);
|
||||
}
|
||||
|
||||
@override
|
||||
void run() async {
|
||||
if (argResults.rest.isEmpty) {
|
||||
usageException('Missing arguments: <dart2js-out-file> [<html-file>]');
|
||||
}
|
||||
|
||||
var jsPath = argResults.rest[0];
|
||||
var htmlPath = null;
|
||||
String htmlPath;
|
||||
if (argResults.rest.length > 1) {
|
||||
htmlPath = argResults.rest[1];
|
||||
}
|
||||
var outPath = argResults['out'];
|
||||
if (outPath == _DEFAULT_OUT_TEMPLATE) outPath = '$jsPath.coverage.json';
|
||||
var server = new _Server(argResults['host'], int.parse(argResults['port']),
|
||||
if (outPath == _defaultOutTemplate) outPath = '$jsPath.coverage.json';
|
||||
var server = _Server(argResults['host'], int.parse(argResults['port']),
|
||||
jsPath, htmlPath, outPath, argResults['uri-prefix']);
|
||||
await server.run();
|
||||
}
|
||||
}
|
||||
|
||||
const _DEFAULT_OUT_TEMPLATE = '<dart2js-out-file>.coverage.json';
|
||||
const _defaultOutTemplate = '<dart2js-out-file>.coverage.json';
|
||||
|
||||
class _Server {
|
||||
/// Server hostname, typically `localhost`, but can be `0.0.0.0`.
|
||||
@@ -102,12 +103,11 @@ class _Server {
|
||||
/// against dump-info data.
|
||||
Map data = {};
|
||||
|
||||
String get _serializedData => new JsonEncoder.withIndent(' ').convert(data);
|
||||
String get _serializedData => JsonEncoder.withIndent(' ').convert(data);
|
||||
|
||||
_Server(this.hostname, this.port, String jsPath, this.htmlPath, this.outPath,
|
||||
_Server(this.hostname, this.port, this.jsPath, this.htmlPath, this.outPath,
|
||||
String prefix)
|
||||
: jsPath = jsPath,
|
||||
jsCode = _adjustRequestUrl(new File(jsPath).readAsStringSync(), prefix),
|
||||
: jsCode = _adjustRequestUrl(File(jsPath).readAsStringSync(), prefix),
|
||||
prefix = _normalize(prefix);
|
||||
|
||||
run() async {
|
||||
@@ -135,29 +135,29 @@ class _Server {
|
||||
urlPath == _expectedPath(baseHtmlName)) {
|
||||
var contents = htmlPath == null
|
||||
? '<html><script src="$baseJsName"></script>'
|
||||
: await new File(htmlPath).readAsString();
|
||||
return new shelf.Response.ok(contents, headers: HTML_HEADERS);
|
||||
: await File(htmlPath).readAsString();
|
||||
return shelf.Response.ok(contents, headers: _htmlHeaders);
|
||||
}
|
||||
|
||||
if (urlPath == _expectedPath(baseJsName)) {
|
||||
return new shelf.Response.ok(jsCode, headers: JS_HEADERS);
|
||||
return shelf.Response.ok(jsCode, headers: _jsHeaders);
|
||||
}
|
||||
|
||||
// Handle POST requests to record coverage data, and GET requests to display
|
||||
// the currently coverage results.
|
||||
if (urlPath == _expectedPath('coverage')) {
|
||||
if (request.method == 'GET') {
|
||||
return new shelf.Response.ok(_serializedData, headers: TEXT_HEADERS);
|
||||
return shelf.Response.ok(_serializedData, headers: _textHeaders);
|
||||
}
|
||||
|
||||
if (request.method == 'POST') {
|
||||
_record(jsonDecode(await request.readAsString()));
|
||||
return new shelf.Response.ok("Thanks!");
|
||||
return shelf.Response.ok("Thanks!");
|
||||
}
|
||||
}
|
||||
|
||||
// Any other request is not supported.
|
||||
return new shelf.Response.notFound('Not found: "$urlPath"');
|
||||
return shelf.Response.notFound('Not found: "$urlPath"');
|
||||
}
|
||||
|
||||
_record(List entries) {
|
||||
@@ -174,8 +174,8 @@ class _Server {
|
||||
_enqueueSave() async {
|
||||
if (!_savePending) {
|
||||
_savePending = true;
|
||||
await new Future.delayed(new Duration(seconds: 3));
|
||||
await new File(outPath).writeAsString(_serializedData);
|
||||
await Future.delayed(Duration(seconds: 3));
|
||||
await File(outPath).writeAsString(_serializedData);
|
||||
var diff = data.length - _total;
|
||||
print(diff == 0
|
||||
? ' - no new element covered'
|
||||
@@ -215,6 +215,6 @@ _adjustRequestUrl(String code, String prefix) {
|
||||
return '$hook$code';
|
||||
}
|
||||
|
||||
const HTML_HEADERS = const {'content-type': 'text/html'};
|
||||
const JS_HEADERS = const {'content-type': 'text/javascript'};
|
||||
const TEXT_HEADERS = const {'content-type': 'text/plain'};
|
||||
const _htmlHeaders = {'content-type': 'text/html'};
|
||||
const _jsHeaders = {'content-type': 'text/javascript'};
|
||||
const _textHeaders = {'content-type': 'text/plain'};
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
library dart2js_info.bin.debug_info;
|
||||
|
||||
import 'package:args/command_runner.dart';
|
||||
|
||||
import 'package:dart2js_info/info.dart';
|
||||
import 'package:dart2js_info/src/graph.dart';
|
||||
import 'package:dart2js_info/src/io.dart';
|
||||
@@ -16,7 +15,9 @@ import 'package:dart2js_info/src/util.dart';
|
||||
import 'usage_exception.dart';
|
||||
|
||||
class DebugCommand extends Command<void> with PrintUsageException {
|
||||
@override
|
||||
final String name = "debug";
|
||||
@override
|
||||
final String description = "Dart2js-team diagnostics on a dump-info file.";
|
||||
|
||||
DebugCommand() {
|
||||
@@ -24,9 +25,10 @@ class DebugCommand extends Command<void> with PrintUsageException {
|
||||
help: "Show detailed data for a library with the given name");
|
||||
}
|
||||
|
||||
@override
|
||||
void run() async {
|
||||
var args = argResults.rest;
|
||||
if (args.length < 1) {
|
||||
if (args.isEmpty) {
|
||||
usageException('Missing argument: info.data');
|
||||
}
|
||||
|
||||
@@ -43,24 +45,22 @@ class DebugCommand extends Command<void> with PrintUsageException {
|
||||
/// Validates that codesize of elements adds up to total codesize.
|
||||
validateSize(AllInfo info, String debugLibName) {
|
||||
// Gather data from visiting all info elements.
|
||||
var tracker = new _SizeTracker(debugLibName);
|
||||
var tracker = _SizeTracker(debugLibName);
|
||||
info.accept(tracker);
|
||||
|
||||
// Validate that listed elements include elements of each library.
|
||||
Set<Info> listed = new Set()
|
||||
..addAll(info.functions)
|
||||
..addAll(info.fields);
|
||||
final listed = {...info.functions, ...info.fields};
|
||||
// For our sanity we do some validation of dump-info invariants
|
||||
var diff1 = listed.difference(tracker.discovered);
|
||||
var diff2 = tracker.discovered.difference(listed);
|
||||
if (diff1.length == 0 || diff2.length == 0) {
|
||||
if (diff1.isEmpty || diff2.isEmpty) {
|
||||
_pass('all fields and functions are covered');
|
||||
} else {
|
||||
if (diff1.length > 0) {
|
||||
if (diff1.isNotEmpty) {
|
||||
_fail("some elements where listed globally that weren't part of any "
|
||||
"library (non-zero ${diff1.where((f) => f.size > 0).length})");
|
||||
}
|
||||
if (diff2.length > 0) {
|
||||
if (diff2.isNotEmpty) {
|
||||
_fail("some elements found in libraries weren't part of the global list"
|
||||
" (non-zero ${diff2.where((f) => f.size > 0).length})");
|
||||
}
|
||||
@@ -87,7 +87,7 @@ validateSize(AllInfo info, String debugLibName) {
|
||||
|
||||
/// Validates that every element in the model has a parent (except libraries).
|
||||
validateParents(AllInfo info) {
|
||||
final parentlessInfos = new Set<Info>();
|
||||
final parentlessInfos = <Info>{};
|
||||
|
||||
failIfNoParents(List<Info> infos) {
|
||||
for (var info in infos) {
|
||||
@@ -118,7 +118,7 @@ class _SizeTracker extends RecursiveInfoVisitor {
|
||||
|
||||
/// [FunctionInfo]s and [FieldInfo]s transitively reachable from [LibraryInfo]
|
||||
/// elements.
|
||||
final Set<Info> discovered = new Set<Info>();
|
||||
final Set<Info> discovered = <Info>{};
|
||||
|
||||
/// Total number of bytes missing if you look at the reported size compared
|
||||
/// to the sum of the nested infos (e.g. if a class size is smaller than the
|
||||
@@ -131,13 +131,13 @@ class _SizeTracker extends RecursiveInfoVisitor {
|
||||
final List unused = [];
|
||||
|
||||
/// Tracks the current state of this visitor.
|
||||
List<_State> stack = [new _State()];
|
||||
List<_State> stack = [_State()];
|
||||
|
||||
/// Code discovered for a [LibraryInfo], only used for debugging.
|
||||
final StringBuffer _debugCode = new StringBuffer();
|
||||
final StringBuffer _debugCode = StringBuffer();
|
||||
int _indent = 2;
|
||||
|
||||
void _push() => stack.add(new _State());
|
||||
void _push() => stack.add(_State());
|
||||
|
||||
void _pop(info) {
|
||||
var last = stack.removeLast();
|
||||
@@ -158,6 +158,7 @@ class _SizeTracker extends RecursiveInfoVisitor {
|
||||
}
|
||||
|
||||
bool _debug = false;
|
||||
@override
|
||||
visitLibrary(LibraryInfo info) {
|
||||
if (_debugLibName != null) _debug = info.name.contains(_debugLibName);
|
||||
_push();
|
||||
@@ -189,7 +190,7 @@ class _SizeTracker extends RecursiveInfoVisitor {
|
||||
_debugCode.write('...\n');
|
||||
}
|
||||
|
||||
print('$info ${isClosureClass} \n${info.code}');
|
||||
print('$info $isClosureClass \n${info.code}');
|
||||
_debugCode.write(' ' * _indent);
|
||||
var endsInNewLine = code.endsWith('\n');
|
||||
if (endsInNewLine) code = code.substring(0, code.length - 1);
|
||||
@@ -206,22 +207,26 @@ class _SizeTracker extends RecursiveInfoVisitor {
|
||||
stack.last._count++;
|
||||
}
|
||||
|
||||
@override
|
||||
visitField(FieldInfo info) {
|
||||
_handleCodeInfo(info);
|
||||
super.visitField(info);
|
||||
}
|
||||
|
||||
@override
|
||||
visitFunction(FunctionInfo info) {
|
||||
_handleCodeInfo(info);
|
||||
super.visitFunction(info);
|
||||
}
|
||||
|
||||
@override
|
||||
visitTypedef(TypedefInfo info) {
|
||||
if (_debug) print('$info');
|
||||
stack.last._totalSize += info.size;
|
||||
super.visitTypedef(info);
|
||||
}
|
||||
|
||||
@override
|
||||
visitClass(ClassInfo info) {
|
||||
if (_debug) {
|
||||
print('$info');
|
||||
@@ -239,6 +244,7 @@ class _SizeTracker extends RecursiveInfoVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
visitClassType(ClassTypeInfo info) {
|
||||
if (_debug) {
|
||||
print('$info');
|
||||
@@ -265,8 +271,8 @@ class _State {
|
||||
|
||||
/// Validates that both forms of dependency information match.
|
||||
void compareGraphs(AllInfo info) {
|
||||
var g1 = new EdgeListGraph<Info>();
|
||||
var g2 = new EdgeListGraph<Info>();
|
||||
var g1 = EdgeListGraph<Info>();
|
||||
var g2 = EdgeListGraph<Info>();
|
||||
for (var f in info.functions) {
|
||||
g1.addNode(f);
|
||||
for (var g in f.uses) {
|
||||
@@ -320,11 +326,9 @@ void compareGraphs(AllInfo info) {
|
||||
verifyDeps(AllInfo info) {
|
||||
var graph = graphFromInfo(info);
|
||||
var entrypoint = info.program.entrypoint;
|
||||
var reachables = new Set.from(graph.preOrder(entrypoint));
|
||||
var reachables = Set.from(graph.preOrder(entrypoint));
|
||||
|
||||
var functionsAndFields = []
|
||||
..addAll(info.functions)
|
||||
..addAll(info.fields);
|
||||
var functionsAndFields = <BasicInfo>[...info.functions, ...info.fields];
|
||||
var unreachables =
|
||||
functionsAndFields.where((func) => !reachables.contains(func));
|
||||
if (unreachables.isNotEmpty) {
|
||||
|
||||
@@ -47,10 +47,13 @@ import 'usage_exception.dart';
|
||||
|
||||
/// A command that computes the diff between two info files.
|
||||
class DeferredLibraryCheck extends Command<void> with PrintUsageException {
|
||||
@override
|
||||
final String name = "deferred_check";
|
||||
@override
|
||||
final String description =
|
||||
"Verify that deferred libraries are split as expected";
|
||||
|
||||
@override
|
||||
void run() async {
|
||||
var args = argResults.rest;
|
||||
if (args.length < 2) {
|
||||
@@ -66,6 +69,6 @@ class DeferredLibraryCheck extends Command<void> with PrintUsageException {
|
||||
}
|
||||
|
||||
Future manifestFromFile(String fileName) async {
|
||||
var file = await new File(fileName).readAsString();
|
||||
var file = await File(fileName).readAsString();
|
||||
return loadYaml(file);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ library dart2js_info.bin.deferred_library_layout;
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:args/command_runner.dart';
|
||||
|
||||
import 'package:dart2js_info/info.dart';
|
||||
import 'package:dart2js_info/src/io.dart';
|
||||
|
||||
@@ -16,12 +15,15 @@ import 'usage_exception.dart';
|
||||
|
||||
/// This tool reports how code is divided among deferred chunks.
|
||||
class DeferredLibraryLayout extends Command<void> with PrintUsageException {
|
||||
@override
|
||||
final String name = "deferred_layout";
|
||||
@override
|
||||
final String description = "Show how code is divided among deferred parts.";
|
||||
|
||||
@override
|
||||
void run() async {
|
||||
var args = argResults.rest;
|
||||
if (args.length < 1) {
|
||||
if (args.isEmpty) {
|
||||
usageException('Missing argument: info.data');
|
||||
}
|
||||
await _showLayout(args.first);
|
||||
@@ -37,7 +39,7 @@ _showLayout(String file) async {
|
||||
var unit = info.outputUnit;
|
||||
var lib = _libOf(info);
|
||||
if (lib == null) return;
|
||||
libToHunks.putIfAbsent(lib, () => new Set()).add(unit);
|
||||
libToHunks.putIfAbsent(lib, () => <OutputUnitInfo>{}).add(unit);
|
||||
hunkMembers
|
||||
.putIfAbsent(unit, () => {})
|
||||
.putIfAbsent(lib, () => [])
|
||||
|
||||
@@ -16,12 +16,15 @@ import 'usage_exception.dart';
|
||||
|
||||
/// This tool gives a breakdown of code size by deferred part in the program.
|
||||
class DeferredLibrarySize extends Command<void> with PrintUsageException {
|
||||
@override
|
||||
final String name = "deferred_size";
|
||||
@override
|
||||
final String description = "Show breakdown of codesize by deferred part.";
|
||||
|
||||
@override
|
||||
void run() async {
|
||||
var args = argResults.rest;
|
||||
if (args.length < 1) {
|
||||
if (args.isEmpty) {
|
||||
usageException('Missing argument: info.data');
|
||||
}
|
||||
// TODO(het): Would be faster to only parse the 'outputUnits' part
|
||||
@@ -37,6 +40,7 @@ class ImportSize {
|
||||
|
||||
const ImportSize(this.import, this.size);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '$import: $size';
|
||||
}
|
||||
@@ -45,14 +49,14 @@ class ImportSize {
|
||||
void printSizes(Map<String, int> sizeByImport, int programSize) {
|
||||
var importSizes = <ImportSize>[];
|
||||
sizeByImport.forEach((import, size) {
|
||||
importSizes.add(new ImportSize(import, size));
|
||||
importSizes.add(ImportSize(import, size));
|
||||
});
|
||||
// Sort by size, largest first.
|
||||
importSizes.sort((a, b) => b.size - a.size);
|
||||
int longest = importSizes.fold('Percent of code deferred'.length,
|
||||
(longest, importSize) => max(longest, importSize.import.length));
|
||||
|
||||
_printRow(label, data, {int width: 15}) {
|
||||
_printRow(label, data, {int width = 15}) {
|
||||
print('${label.toString().padRight(longest + 1)}'
|
||||
'${data.toString().padLeft(width)}');
|
||||
}
|
||||
|
||||
@@ -13,7 +13,9 @@ import 'usage_exception.dart';
|
||||
|
||||
/// A command that computes the diff between two info files.
|
||||
class DiffCommand extends Command<void> with PrintUsageException {
|
||||
@override
|
||||
final String name = "diff";
|
||||
@override
|
||||
final String description =
|
||||
"See code size differences between two dump-info files.";
|
||||
|
||||
@@ -23,6 +25,7 @@ class DiffCommand extends Command<void> with PrintUsageException {
|
||||
help: "Show only a summary and hide details of each library");
|
||||
}
|
||||
|
||||
@override
|
||||
void run() async {
|
||||
var args = argResults.rest;
|
||||
if (args.length < 2) {
|
||||
|
||||
@@ -8,7 +8,6 @@ library compiler.tool.function_size_analysis;
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:args/command_runner.dart';
|
||||
|
||||
import 'package:dart2js_info/info.dart';
|
||||
import 'package:dart2js_info/src/graph.dart';
|
||||
import 'package:dart2js_info/src/io.dart';
|
||||
@@ -18,12 +17,15 @@ import 'usage_exception.dart';
|
||||
|
||||
/// Command presenting how much each function contributes to the total code.
|
||||
class FunctionSizeCommand extends Command<void> with PrintUsageException {
|
||||
@override
|
||||
final String name = "function_size";
|
||||
@override
|
||||
final String description = "See breakdown of code size by function.";
|
||||
|
||||
@override
|
||||
void run() async {
|
||||
var args = argResults.rest;
|
||||
if (args.length < 1) {
|
||||
if (args.isEmpty) {
|
||||
usageException('Missing argument: info.data');
|
||||
}
|
||||
var info = await infoFromFile(args.first);
|
||||
@@ -32,12 +34,13 @@ class FunctionSizeCommand extends Command<void> with PrintUsageException {
|
||||
}
|
||||
|
||||
showCodeDistribution(AllInfo info,
|
||||
{bool filter(Info info), bool showLibrarySizes: false}) {
|
||||
{bool Function(Info info) filter, bool showLibrarySizes = false}) {
|
||||
var realTotal = info.program.size;
|
||||
if (filter == null) filter = (i) => true;
|
||||
var reported = <BasicInfo>[]
|
||||
..addAll(info.functions.where(filter))
|
||||
..addAll(info.fields.where(filter));
|
||||
filter ??= (i) => true;
|
||||
var reported = <BasicInfo>[
|
||||
...info.functions.where(filter),
|
||||
...info.fields.where(filter)
|
||||
];
|
||||
|
||||
// Compute a graph from the dependencies in [info].
|
||||
Graph<Info> graph = graphFromInfo(info);
|
||||
@@ -51,7 +54,7 @@ showCodeDistribution(AllInfo info,
|
||||
var minS = totalCount;
|
||||
var nodeData = {};
|
||||
for (var scc in components) {
|
||||
var sccData = new _SccData();
|
||||
var sccData = _SccData();
|
||||
maxS = math.max(maxS, scc.length);
|
||||
minS = math.min(minS, scc.length);
|
||||
for (var f in scc) {
|
||||
@@ -85,7 +88,9 @@ showCodeDistribution(AllInfo info,
|
||||
}
|
||||
|
||||
helper(mainMethod);
|
||||
reported.forEach((n) => dominatedSize.putIfAbsent(n, () => n.size));
|
||||
for (var n in reported) {
|
||||
dominatedSize.putIfAbsent(n, () => n.size);
|
||||
}
|
||||
reported.sort((a, b) =>
|
||||
(dominatedSize[b] + nodeData[b].maxSize) -
|
||||
(dominatedSize[a] + nodeData[a].maxSize));
|
||||
@@ -94,7 +99,7 @@ showCodeDistribution(AllInfo info,
|
||||
print(' --- Results per library ---');
|
||||
var totals = <LibraryInfo, int>{};
|
||||
var longest = 0;
|
||||
reported.forEach((info) {
|
||||
for (var info in reported) {
|
||||
var size = info.size;
|
||||
while (info != null && info is! LibraryInfo) {
|
||||
info = info.parent;
|
||||
@@ -104,31 +109,31 @@ showCodeDistribution(AllInfo info,
|
||||
totals.putIfAbsent(lib, () => 0);
|
||||
totals[lib] += size;
|
||||
longest = math.max(longest, '${lib.uri}'.length);
|
||||
});
|
||||
}
|
||||
|
||||
_showLibHeader(longest + 1);
|
||||
var reportedByLibrary = totals.keys.toList();
|
||||
reportedByLibrary.sort((a, b) => totals[b] - totals[a]);
|
||||
reportedByLibrary.forEach((info) {
|
||||
for (var info in reportedByLibrary) {
|
||||
_showLib('${info.uri}', totals[info], realTotal, longest + 1);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
print('\n --- Results per element (field or function) ---');
|
||||
_showElementHeader();
|
||||
reported.forEach((info) {
|
||||
for (var info in reported) {
|
||||
var size = info.size;
|
||||
var min = dominatedSize[info];
|
||||
var max = nodeData[info].maxSize;
|
||||
_showElement(
|
||||
longName(info, useLibraryUri: true), size, min, max, realTotal);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Data associated with an SCC. Used to compute the reachable code size.
|
||||
class _SccData {
|
||||
int size = 0;
|
||||
Set deps = new Set();
|
||||
Set deps = {};
|
||||
_SccData();
|
||||
|
||||
int _maxSize;
|
||||
@@ -140,7 +145,7 @@ class _SccData {
|
||||
void compute() {
|
||||
if (_maxSize != null) return;
|
||||
var max = 0;
|
||||
var seen = new Set();
|
||||
var seen = <dynamic>{};
|
||||
helper(n) {
|
||||
if (!seen.add(n)) return;
|
||||
max += n.size;
|
||||
|
||||
@@ -14,22 +14,28 @@ import 'package:dart2js_info/info.dart';
|
||||
void injectText(AllInfo info) {
|
||||
// Fill the text of each code span. The binary form produced by dart2js
|
||||
// produces code spans, but excludes the orignal text
|
||||
info.functions.forEach((f) {
|
||||
f.code.forEach((span) => _fillSpan(span, f.outputUnit));
|
||||
});
|
||||
info.fields.forEach((f) {
|
||||
f.code.forEach((span) => _fillSpan(span, f.outputUnit));
|
||||
});
|
||||
info.constants.forEach((c) {
|
||||
c.code.forEach((span) => _fillSpan(span, c.outputUnit));
|
||||
});
|
||||
for (var f in info.functions) {
|
||||
for (var span in f.code) {
|
||||
_fillSpan(span, f.outputUnit);
|
||||
}
|
||||
}
|
||||
for (var f in info.fields) {
|
||||
for (var span in f.code) {
|
||||
_fillSpan(span, f.outputUnit);
|
||||
}
|
||||
}
|
||||
for (var c in info.constants) {
|
||||
for (var span in c.code) {
|
||||
_fillSpan(span, c.outputUnit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, String> _cache = {};
|
||||
|
||||
_getContents(OutputUnitInfo unit) => _cache.putIfAbsent(unit.filename, () {
|
||||
var uri = Uri.base.resolve(unit.filename);
|
||||
return new File.fromUri(uri).readAsStringSync();
|
||||
return File.fromUri(uri).readAsStringSync();
|
||||
});
|
||||
|
||||
_fillSpan(CodeSpan span, OutputUnitInfo unit) {
|
||||
|
||||
@@ -72,7 +72,9 @@ import 'usage_exception.dart';
|
||||
|
||||
/// Command presenting how much each library contributes to the total code.
|
||||
class LibrarySizeCommand extends Command<void> with PrintUsageException {
|
||||
@override
|
||||
final String name = "library_size";
|
||||
@override
|
||||
final String description = "See breakdown of code size by library.";
|
||||
|
||||
LibrarySizeCommand() {
|
||||
@@ -80,9 +82,10 @@ class LibrarySizeCommand extends Command<void> with PrintUsageException {
|
||||
help: 'YAML file specifying how libraries should be grouped.');
|
||||
}
|
||||
|
||||
@override
|
||||
void run() async {
|
||||
var args = argResults.rest;
|
||||
if (args.length < 1) {
|
||||
if (args.isEmpty) {
|
||||
usageException('Missing argument: info.data');
|
||||
print('usage: dart tool/library_size_split.dart '
|
||||
'path-to-info.json [grouping.yaml]');
|
||||
@@ -93,29 +96,29 @@ class LibrarySizeCommand extends Command<void> with PrintUsageException {
|
||||
|
||||
var groupingFile = argResults['grouping'];
|
||||
var groupingText = groupingFile != null
|
||||
? new File(groupingFile).readAsStringSync()
|
||||
? File(groupingFile).readAsStringSync()
|
||||
: defaultGrouping;
|
||||
var groupingYaml = loadYaml(groupingText);
|
||||
var groups = [];
|
||||
for (var group in groupingYaml['groups']) {
|
||||
groups.add(new _Group(
|
||||
group['name'], new RegExp(group['regexp']), group['cluster'] ?? 0));
|
||||
groups.add(_Group(
|
||||
group['name'], RegExp(group['regexp']), group['cluster'] ?? 0));
|
||||
}
|
||||
|
||||
var sizes = {};
|
||||
var allLibs = 0;
|
||||
for (LibraryInfo lib in info.libraries) {
|
||||
allLibs += lib.size;
|
||||
groups.forEach((group) {
|
||||
for (var group in groups) {
|
||||
var match = group.matcher.firstMatch('${lib.uri}');
|
||||
if (match != null) {
|
||||
var name = group.name;
|
||||
if (name == null && match.groupCount > 0) name = match.group(1);
|
||||
if (name == null) name = match.group(0);
|
||||
sizes.putIfAbsent(name, () => new _SizeEntry(name, group.cluster));
|
||||
name ??= match.group(0);
|
||||
sizes.putIfAbsent(name, () => _SizeEntry(name, group.cluster));
|
||||
sizes[name].size += lib.size;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var allConstants = 0;
|
||||
@@ -129,7 +132,7 @@ class LibrarySizeCommand extends Command<void> with PrintUsageException {
|
||||
var longest = 0;
|
||||
var rows = <_Row>[];
|
||||
_addRow(String label, int value) {
|
||||
rows.add(new _Row(label, value));
|
||||
rows.add(_Row(label, value));
|
||||
longest = max(longest, label.length);
|
||||
}
|
||||
|
||||
@@ -204,7 +207,7 @@ class _Divider extends _Row {
|
||||
const _Divider() : super('', 0);
|
||||
}
|
||||
|
||||
_pad(value, n, {bool right: false}) {
|
||||
_pad(value, n, {bool right = false}) {
|
||||
var s = '$value';
|
||||
if (s.length >= n) return s;
|
||||
var pad = ' ' * (n - s.length);
|
||||
|
||||
@@ -47,7 +47,9 @@ import 'function_size_analysis.dart';
|
||||
import 'usage_exception.dart';
|
||||
|
||||
class LiveCodeAnalysisCommand extends Command<void> with PrintUsageException {
|
||||
@override
|
||||
final String name = "coverage_analysis";
|
||||
@override
|
||||
final String description = "Analyze coverage data collected via the"
|
||||
" 'coverage_server' command";
|
||||
|
||||
@@ -56,6 +58,7 @@ class LiveCodeAnalysisCommand extends Command<void> with PrintUsageException {
|
||||
abbr: 'v', negatable: false, help: 'Show verbose details.');
|
||||
}
|
||||
|
||||
@override
|
||||
void run() async {
|
||||
var args = argResults.rest;
|
||||
if (args.length < 2) {
|
||||
@@ -67,7 +70,7 @@ class LiveCodeAnalysisCommand extends Command<void> with PrintUsageException {
|
||||
|
||||
_liveCodeAnalysis(infoFile, coverageFile, bool verbose) async {
|
||||
var info = await infoFromFile(infoFile);
|
||||
var coverage = jsonDecode(new File(coverageFile).readAsStringSync());
|
||||
var coverage = jsonDecode(File(coverageFile).readAsStringSync());
|
||||
|
||||
int realTotal = info.program.size;
|
||||
int totalLib = info.libraries.fold(0, (n, lib) => n + lib.size);
|
||||
|
||||
@@ -15,7 +15,9 @@ import 'package:dart2js_info/src/io.dart';
|
||||
import 'usage_exception.dart';
|
||||
|
||||
class ShowInferredTypesCommand extends Command<void> with PrintUsageException {
|
||||
@override
|
||||
final String name = "show_inferred";
|
||||
@override
|
||||
final String description = "Show data inferred by dart2js global inference";
|
||||
|
||||
ShowInferredTypesCommand() {
|
||||
@@ -23,6 +25,7 @@ class ShowInferredTypesCommand extends Command<void> with PrintUsageException {
|
||||
abbr: 'l', negatable: false, help: 'Show long qualified names.');
|
||||
}
|
||||
|
||||
@override
|
||||
void run() async {
|
||||
var args = argResults.rest;
|
||||
if (args.length < 2) {
|
||||
@@ -35,7 +38,7 @@ class ShowInferredTypesCommand extends Command<void> with PrintUsageException {
|
||||
|
||||
_showInferredTypes(String infoFile, String pattern, bool showLongName) async {
|
||||
var info = await infoFromFile(infoFile);
|
||||
var nameRegExp = new RegExp(pattern);
|
||||
var nameRegExp = RegExp(pattern);
|
||||
matches(e) => nameRegExp.hasMatch(longName(e));
|
||||
|
||||
bool noResults = true;
|
||||
|
||||
@@ -3,18 +3,20 @@
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'dart:io';
|
||||
import 'package:args/command_runner.dart';
|
||||
|
||||
import 'package:args/command_runner.dart';
|
||||
import 'package:dart2js_info/info.dart';
|
||||
import 'package:dart2js_info/src/util.dart';
|
||||
import 'package:dart2js_info/src/io.dart';
|
||||
import 'package:dart2js_info/src/util.dart';
|
||||
|
||||
import 'inject_text.dart';
|
||||
import 'usage_exception.dart';
|
||||
|
||||
/// Shows the contents of an info file as text.
|
||||
class ShowCommand extends Command<void> with PrintUsageException {
|
||||
@override
|
||||
final String name = "show";
|
||||
@override
|
||||
final String description = "Show a text representation of the info file.";
|
||||
|
||||
ShowCommand() {
|
||||
@@ -28,8 +30,9 @@ class ShowCommand extends Command<void> with PrintUsageException {
|
||||
'option can be used to embed the text directly in the output.');
|
||||
}
|
||||
|
||||
@override
|
||||
void run() async {
|
||||
if (argResults.rest.length < 1) {
|
||||
if (argResults.rest.isEmpty) {
|
||||
usageException('Missing argument: <input-info>');
|
||||
}
|
||||
|
||||
@@ -37,13 +40,13 @@ class ShowCommand extends Command<void> with PrintUsageException {
|
||||
AllInfo info = await infoFromFile(filename);
|
||||
if (argResults['inject-text']) injectText(info);
|
||||
|
||||
var buffer = new StringBuffer();
|
||||
info.accept(new TextPrinter(buffer, argResults['inject-text']));
|
||||
var buffer = StringBuffer();
|
||||
info.accept(TextPrinter(buffer, argResults['inject-text']));
|
||||
var outputPath = argResults['out'];
|
||||
if (outputPath == null) {
|
||||
print(buffer);
|
||||
} else {
|
||||
new File(outputPath).writeAsStringSync('$buffer');
|
||||
File(outputPath).writeAsStringSync('$buffer');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,13 +68,14 @@ class TextPrinter implements InfoVisitor<void> {
|
||||
buffer.writeln(s.replaceAll('\n', '\n$_textIndent'));
|
||||
}
|
||||
|
||||
void _writeBlock(String s, void f()) {
|
||||
_writeIndented("$s");
|
||||
void _writeBlock(String s, void Function() f) {
|
||||
_writeIndented(s);
|
||||
_indent++;
|
||||
f();
|
||||
_indent--;
|
||||
}
|
||||
|
||||
@override
|
||||
void visitAll(AllInfo info) {
|
||||
_writeBlock("Summary data", () => visitProgram(info.program));
|
||||
buffer.writeln();
|
||||
@@ -87,6 +91,7 @@ class TextPrinter implements InfoVisitor<void> {
|
||||
_writeBlock("Output units", () => info.outputUnits.forEach(visitOutput));
|
||||
}
|
||||
|
||||
@override
|
||||
void visitProgram(ProgramInfo info) {
|
||||
_writeIndented('main: ${longName(info.entrypoint, useLibraryUri: true)}');
|
||||
_writeIndented('size: ${info.size}');
|
||||
@@ -109,6 +114,7 @@ class TextPrinter implements InfoVisitor<void> {
|
||||
return "${(size / (1024 * 1024)).toStringAsFixed(2)} Mb ($size b)";
|
||||
}
|
||||
|
||||
@override
|
||||
void visitLibrary(LibraryInfo info) {
|
||||
_writeBlock('${info.uri}: ${_size(info.size)}', () {
|
||||
if (info.topLevelFunctions.isNotEmpty) {
|
||||
@@ -135,6 +141,7 @@ class TextPrinter implements InfoVisitor<void> {
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void visitClass(ClassInfo info) {
|
||||
_writeBlock(
|
||||
'${info.name}: ${_size(info.size)} [${info.outputUnit.filename}]', () {
|
||||
@@ -148,12 +155,14 @@ class TextPrinter implements InfoVisitor<void> {
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void visitClassType(ClassTypeInfo info) {
|
||||
_writeBlock(
|
||||
'${info.name}: ${_size(info.size)} [${info.outputUnit.filename}]',
|
||||
() {});
|
||||
}
|
||||
|
||||
@override
|
||||
void visitField(FieldInfo info) {
|
||||
_writeBlock('${info.type} ${info.name}: ${_size(info.size)}', () {
|
||||
_writeIndented('inferred type: ${info.inferredType}');
|
||||
@@ -167,6 +176,7 @@ class TextPrinter implements InfoVisitor<void> {
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void visitFunction(FunctionInfo info) {
|
||||
var outputUnitFile = '';
|
||||
if (info.functionKind == FunctionInfo.TOP_LEVEL_FUNCTION_KIND) {
|
||||
@@ -177,7 +187,7 @@ class TextPrinter implements InfoVisitor<void> {
|
||||
_writeBlock(
|
||||
'${info.returnType} ${info.name}($params): ${_size(info.size)}$outputUnitFile',
|
||||
() {
|
||||
String params = info.parameters.map((p) => "${p.type}").join(', ');
|
||||
String params = info.parameters.map((p) => p.type).join(', ');
|
||||
_writeIndented('declared type: ${info.type}');
|
||||
_writeIndented(
|
||||
'inferred type: ${info.inferredReturnType} Function($params)');
|
||||
@@ -197,14 +207,17 @@ class TextPrinter implements InfoVisitor<void> {
|
||||
_writeIndented('- ${longName(info.target, useLibraryUri: true)} $mask');
|
||||
}
|
||||
|
||||
@override
|
||||
void visitTypedef(TypedefInfo info) {
|
||||
_writeIndented('${info.name}: ${info.type}');
|
||||
}
|
||||
|
||||
@override
|
||||
void visitClosure(ClosureInfo info) {
|
||||
_writeBlock('${info.name}', () => visitFunction(info.function));
|
||||
_writeBlock(info.name, () => visitFunction(info.function));
|
||||
}
|
||||
|
||||
@override
|
||||
void visitConstant(ConstantInfo info) {
|
||||
_writeBlock('${_size(info.size)}:', () => _writeCode(info.code));
|
||||
}
|
||||
@@ -213,6 +226,7 @@ class TextPrinter implements InfoVisitor<void> {
|
||||
_writeIndented(code.map((c) => c.text).join('\n'));
|
||||
}
|
||||
|
||||
@override
|
||||
void visitOutput(OutputUnitInfo info) {
|
||||
_writeIndented('${info.filename}: ${_size(info.size)}');
|
||||
}
|
||||
|
||||
@@ -15,11 +15,14 @@ import 'usage_exception.dart';
|
||||
|
||||
/// Converts a dump-info file emitted by dart2js in JSON to binary format.
|
||||
class ToBinaryCommand extends Command<void> with PrintUsageException {
|
||||
@override
|
||||
final String name = "to_binary";
|
||||
@override
|
||||
final String description = "Convert any info file to binary format.";
|
||||
|
||||
@override
|
||||
void run() async {
|
||||
if (argResults.rest.length < 1) {
|
||||
if (argResults.rest.isEmpty) {
|
||||
usageException('Missing argument: <input-info>');
|
||||
exit(1);
|
||||
}
|
||||
@@ -28,7 +31,7 @@ class ToBinaryCommand extends Command<void> with PrintUsageException {
|
||||
AllInfo info = await infoFromFile(filename);
|
||||
if (argResults['inject-text']) injectText(info);
|
||||
String outputFilename = argResults['out'] ?? '$filename.data';
|
||||
var outstream = new File(outputFilename).openWrite();
|
||||
var outstream = File(outputFilename).openWrite();
|
||||
binary.encode(info, outstream);
|
||||
await outstream.done;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,9 @@ import 'usage_exception.dart';
|
||||
|
||||
/// Converts a dump-info file emitted by dart2js in binary format to JSON.
|
||||
class ToJsonCommand extends Command<void> with PrintUsageException {
|
||||
@override
|
||||
final String name = "to_json";
|
||||
@override
|
||||
final String description = "Convert any info file to JSON format.";
|
||||
|
||||
ToJsonCommand() {
|
||||
@@ -32,8 +34,9 @@ class ToJsonCommand extends Command<void> with PrintUsageException {
|
||||
'available in the input file.');
|
||||
}
|
||||
|
||||
@override
|
||||
void run() async {
|
||||
if (argResults.rest.length < 1) {
|
||||
if (argResults.rest.isEmpty) {
|
||||
usageException('Missing argument: <input-info>');
|
||||
}
|
||||
|
||||
@@ -45,10 +48,10 @@ class ToJsonCommand extends Command<void> with PrintUsageException {
|
||||
injectText(info);
|
||||
}
|
||||
|
||||
var json = new AllInfoJsonCodec(isBackwardCompatible: isBackwardCompatible)
|
||||
var json = AllInfoJsonCodec(isBackwardCompatible: isBackwardCompatible)
|
||||
.encode(info);
|
||||
String outputFilename = argResults['out'] ?? '$filename.json';
|
||||
new File(outputFilename)
|
||||
File(outputFilename)
|
||||
.writeAsStringSync(const JsonEncoder.withIndent(" ").convert(json));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,11 +17,14 @@ import 'usage_exception.dart';
|
||||
|
||||
/// Converts a dump-info file emitted by dart2js to the proto format
|
||||
class ToProtoCommand extends Command<void> with PrintUsageException {
|
||||
@override
|
||||
final String name = "to_proto";
|
||||
@override
|
||||
final String description = "Convert any info file to proto format.";
|
||||
|
||||
@override
|
||||
void run() async {
|
||||
if (argResults.rest.length < 1) {
|
||||
if (argResults.rest.isEmpty) {
|
||||
usageException('Missing argument: <input-info>');
|
||||
exit(1);
|
||||
}
|
||||
@@ -29,9 +32,9 @@ class ToProtoCommand extends Command<void> with PrintUsageException {
|
||||
String filename = argResults.rest[0];
|
||||
final info = await infoFromFile(filename);
|
||||
if (argResults['inject-text']) injectText(info);
|
||||
final proto = new AllInfoProtoCodec().encode(info);
|
||||
final proto = AllInfoProtoCodec().encode(info);
|
||||
String outputFilename = argResults['out'] ?? '$filename.pb';
|
||||
final outputFile = new File(outputFilename);
|
||||
final outputFile = File(outputFilename);
|
||||
await outputFile.writeAsBytes(proto.writeToBuffer(), mode: FileMode.write);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import 'package:args/command_runner.dart';
|
||||
abstract class PrintUsageException implements Command<void> {
|
||||
// TODO(rnystrom): Use "Never" for the return type when this package is
|
||||
// migrated to null safety.
|
||||
@override
|
||||
usageException(String message) {
|
||||
print(message);
|
||||
printUsage();
|
||||
|
||||
@@ -20,20 +20,20 @@ import 'src/text_print.dart';
|
||||
|
||||
/// Entrypoint to run all dart2js_info tools.
|
||||
void main(args) {
|
||||
var commandRunner = new CommandRunner("dart2js_info",
|
||||
var commandRunner = CommandRunner("dart2js_info",
|
||||
"collection of tools to digest the output of dart2js's --dump-info")
|
||||
..addCommand(new CodeDepsCommand())
|
||||
..addCommand(new CoverageLogServerCommand())
|
||||
..addCommand(new DebugCommand())
|
||||
..addCommand(new DiffCommand())
|
||||
..addCommand(new DeferredLibraryCheck())
|
||||
..addCommand(new DeferredLibrarySize())
|
||||
..addCommand(new DeferredLibraryLayout())
|
||||
..addCommand(new ConvertCommand())
|
||||
..addCommand(new FunctionSizeCommand())
|
||||
..addCommand(new LibrarySizeCommand())
|
||||
..addCommand(new LiveCodeAnalysisCommand())
|
||||
..addCommand(new ShowInferredTypesCommand())
|
||||
..addCommand(new ShowCommand());
|
||||
..addCommand(CodeDepsCommand())
|
||||
..addCommand(CoverageLogServerCommand())
|
||||
..addCommand(DebugCommand())
|
||||
..addCommand(DiffCommand())
|
||||
..addCommand(DeferredLibraryCheck())
|
||||
..addCommand(DeferredLibrarySize())
|
||||
..addCommand(DeferredLibraryLayout())
|
||||
..addCommand(ConvertCommand())
|
||||
..addCommand(FunctionSizeCommand())
|
||||
..addCommand(LibrarySizeCommand())
|
||||
..addCommand(LiveCodeAnalysisCommand())
|
||||
..addCommand(ShowInferredTypesCommand())
|
||||
..addCommand(ShowCommand());
|
||||
commandRunner.run(args);
|
||||
}
|
||||
|
||||
@@ -13,11 +13,11 @@ import 'src/binary/source.dart';
|
||||
import 'info.dart';
|
||||
|
||||
void encode(AllInfo info, Sink<List<int>> sink) {
|
||||
new BinaryPrinter(new BinarySink(sink)).visitAll(info);
|
||||
BinaryPrinter(BinarySink(sink)).visitAll(info);
|
||||
}
|
||||
|
||||
AllInfo decode(List<int> data) {
|
||||
return new BinaryReader(new BinarySource(data)).readAll();
|
||||
return BinaryReader(BinarySource(data)).readAll();
|
||||
}
|
||||
|
||||
class BinaryPrinter implements InfoVisitor<void> {
|
||||
@@ -38,6 +38,7 @@ class BinaryPrinter implements InfoVisitor<void> {
|
||||
info.accept(this);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitAll(AllInfo info) {
|
||||
sink.writeInt(info.version);
|
||||
sink.writeInt(info.minorVersion);
|
||||
@@ -70,6 +71,7 @@ class BinaryPrinter implements InfoVisitor<void> {
|
||||
sink.close();
|
||||
}
|
||||
|
||||
@override
|
||||
void visitProgram(ProgramInfo info) {
|
||||
visitFunction(info.entrypoint);
|
||||
sink.writeInt(info.size);
|
||||
@@ -94,6 +96,7 @@ class BinaryPrinter implements InfoVisitor<void> {
|
||||
// Note: parent-pointers are not serialized, they get deduced during deserialization.
|
||||
}
|
||||
|
||||
@override
|
||||
void visitLibrary(LibraryInfo library) {
|
||||
sink.writeCached(library, (LibraryInfo info) {
|
||||
sink.writeUri(info.uri);
|
||||
@@ -106,6 +109,7 @@ class BinaryPrinter implements InfoVisitor<void> {
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void visitClass(ClassInfo cls) {
|
||||
sink.writeCached(cls, (ClassInfo info) {
|
||||
_visitBasicInfo(info);
|
||||
@@ -115,12 +119,14 @@ class BinaryPrinter implements InfoVisitor<void> {
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void visitClassType(ClassTypeInfo cls) {
|
||||
sink.writeCached(cls, (ClassTypeInfo info) {
|
||||
_visitBasicInfo(info);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void visitField(FieldInfo field) {
|
||||
sink.writeCached(field, (FieldInfo info) {
|
||||
_visitBasicInfo(info);
|
||||
@@ -148,6 +154,7 @@ class BinaryPrinter implements InfoVisitor<void> {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void visitConstant(ConstantInfo constant) {
|
||||
sink.writeCached(constant, (ConstantInfo info) {
|
||||
_visitBasicInfo(info);
|
||||
@@ -170,6 +177,7 @@ class BinaryPrinter implements InfoVisitor<void> {
|
||||
sink.writeString(info.declaredType);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitFunction(FunctionInfo function) {
|
||||
sink.writeCached(function, (FunctionInfo info) {
|
||||
_visitBasicInfo(info);
|
||||
@@ -190,6 +198,7 @@ class BinaryPrinter implements InfoVisitor<void> {
|
||||
sink.writeStringOrNull(info.mask);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitClosure(ClosureInfo closure) {
|
||||
sink.writeCached(closure, (ClosureInfo info) {
|
||||
_visitBasicInfo(info);
|
||||
@@ -197,6 +206,7 @@ class BinaryPrinter implements InfoVisitor<void> {
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void visitTypedef(TypedefInfo typedef) {
|
||||
sink.writeCached(typedef, (TypedefInfo info) {
|
||||
_visitBasicInfo(info);
|
||||
@@ -211,6 +221,7 @@ class BinaryPrinter implements InfoVisitor<void> {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void visitOutput(OutputUnitInfo output) {
|
||||
sink.writeCached(output, (OutputUnitInfo info) {
|
||||
_visitBasicInfo(info);
|
||||
@@ -229,7 +240,7 @@ class BinaryReader {
|
||||
}
|
||||
|
||||
Duration readDuration() {
|
||||
return new Duration(microseconds: source.readInt());
|
||||
return Duration(microseconds: source.readInt());
|
||||
}
|
||||
|
||||
Info readInfoWithKind() {
|
||||
@@ -258,7 +269,7 @@ class BinaryReader {
|
||||
}
|
||||
|
||||
AllInfo readAll() {
|
||||
var info = new AllInfo();
|
||||
var info = AllInfo();
|
||||
int version = source.readInt();
|
||||
int minorVersion = source.readInt();
|
||||
if (info.version != version || info.minorVersion != minorVersion) {
|
||||
@@ -311,13 +322,13 @@ class BinaryReader {
|
||||
}
|
||||
|
||||
ProgramInfo readProgram() {
|
||||
var info = new ProgramInfo();
|
||||
var info = ProgramInfo();
|
||||
info.entrypoint = readFunction();
|
||||
info.size = source.readInt();
|
||||
info.dart2jsVersion = source.readStringOrNull();
|
||||
info.compilationMoment = readDate();
|
||||
info.compilationDuration = readDuration();
|
||||
info.toJsonDuration = new Duration(microseconds: 0);
|
||||
info.toJsonDuration = Duration(microseconds: 0);
|
||||
info.dumpInfoDuration = readDuration();
|
||||
info.noSuchMethodEnabled = source.readBool();
|
||||
info.isRuntimeTypeUsed = source.readBool();
|
||||
@@ -337,7 +348,7 @@ class BinaryReader {
|
||||
}
|
||||
|
||||
LibraryInfo readLibrary() => source.readCached<LibraryInfo>(() {
|
||||
LibraryInfo info = new LibraryInfo.internal();
|
||||
LibraryInfo info = LibraryInfo.internal();
|
||||
info.uri = source.readUri();
|
||||
_readBasicInfo(info);
|
||||
info.topLevelFunctions = source.readList(readFunction);
|
||||
@@ -356,7 +367,7 @@ class BinaryReader {
|
||||
});
|
||||
|
||||
ClassInfo readClass() => source.readCached<ClassInfo>(() {
|
||||
ClassInfo info = new ClassInfo.internal();
|
||||
ClassInfo info = ClassInfo.internal();
|
||||
_readBasicInfo(info);
|
||||
info.isAbstract = source.readBool();
|
||||
info.fields = source.readList(readField);
|
||||
@@ -375,7 +386,7 @@ class BinaryReader {
|
||||
});
|
||||
|
||||
FieldInfo readField() => source.readCached<FieldInfo>(() {
|
||||
FieldInfo info = new FieldInfo.internal();
|
||||
FieldInfo info = FieldInfo.internal();
|
||||
_readBasicInfo(info);
|
||||
info.closures = source.readList(readClosure);
|
||||
info.inferredType = source.readString();
|
||||
@@ -385,12 +396,14 @@ class BinaryReader {
|
||||
if (info.isConst) {
|
||||
info.initializer = _readConstantOrNull();
|
||||
}
|
||||
info.closures.forEach((c) => c.parent = info);
|
||||
for (var c in info.closures) {
|
||||
c.parent = info;
|
||||
}
|
||||
return info;
|
||||
});
|
||||
|
||||
CodeSpan _readCodeSpan() {
|
||||
return new CodeSpan()
|
||||
return CodeSpan()
|
||||
..start = source.readIntOrNull()
|
||||
..end = source.readIntOrNull()
|
||||
..text = source.readStringOrNull();
|
||||
@@ -403,7 +416,7 @@ class BinaryReader {
|
||||
}
|
||||
|
||||
ConstantInfo readConstant() => source.readCached<ConstantInfo>(() {
|
||||
ConstantInfo info = new ConstantInfo.internal();
|
||||
ConstantInfo info = ConstantInfo.internal();
|
||||
_readBasicInfo(info);
|
||||
info.code = source.readList(_readCodeSpan);
|
||||
return info;
|
||||
@@ -411,7 +424,7 @@ class BinaryReader {
|
||||
|
||||
FunctionModifiers _readFunctionModifiers() {
|
||||
int value = source.readInt();
|
||||
return new FunctionModifiers(
|
||||
return FunctionModifiers(
|
||||
isStatic: value & _staticMask != 0,
|
||||
isConst: value & _constMask != 0,
|
||||
isFactory: value & _factoryMask != 0,
|
||||
@@ -419,12 +432,12 @@ class BinaryReader {
|
||||
}
|
||||
|
||||
ParameterInfo _readParameterInfo() {
|
||||
return new ParameterInfo(
|
||||
return ParameterInfo(
|
||||
source.readString(), source.readString(), source.readString());
|
||||
}
|
||||
|
||||
FunctionInfo readFunction() => source.readCached<FunctionInfo>(() {
|
||||
FunctionInfo info = new FunctionInfo.internal();
|
||||
FunctionInfo info = FunctionInfo.internal();
|
||||
_readBasicInfo(info);
|
||||
info.closures = source.readList(readClosure);
|
||||
info.modifiers = _readFunctionModifiers();
|
||||
@@ -435,15 +448,17 @@ class BinaryReader {
|
||||
info.inlinedCount = source.readIntOrNull();
|
||||
info.code = source.readList(_readCodeSpan);
|
||||
info.type = source.readString();
|
||||
info.closures.forEach((c) => c.parent = info);
|
||||
for (var c in info.closures) {
|
||||
c.parent = info;
|
||||
}
|
||||
return info;
|
||||
});
|
||||
|
||||
DependencyInfo _readDependencyInfo() =>
|
||||
new DependencyInfo(readInfoWithKind(), source.readStringOrNull());
|
||||
DependencyInfo(readInfoWithKind(), source.readStringOrNull());
|
||||
|
||||
ClosureInfo readClosure() => source.readCached<ClosureInfo>(() {
|
||||
ClosureInfo info = new ClosureInfo.internal();
|
||||
ClosureInfo info = ClosureInfo.internal();
|
||||
_readBasicInfo(info);
|
||||
info.function = readFunction();
|
||||
info.function.parent = info;
|
||||
@@ -451,7 +466,7 @@ class BinaryReader {
|
||||
});
|
||||
|
||||
TypedefInfo readTypedef() => source.readCached<TypedefInfo>(() {
|
||||
TypedefInfo info = new TypedefInfo.internal();
|
||||
TypedefInfo info = TypedefInfo.internal();
|
||||
_readBasicInfo(info);
|
||||
info.type = source.readString();
|
||||
return info;
|
||||
@@ -464,7 +479,7 @@ class BinaryReader {
|
||||
}
|
||||
|
||||
OutputUnitInfo readOutput() => source.readCached<OutputUnitInfo>(() {
|
||||
OutputUnitInfo info = new OutputUnitInfo.internal();
|
||||
OutputUnitInfo info = OutputUnitInfo.internal();
|
||||
_readBasicInfo(info);
|
||||
info.filename = source.readStringOrNull();
|
||||
info.imports = source.readList(source.readString);
|
||||
|
||||
@@ -42,8 +42,8 @@ import 'info.dart';
|
||||
|
||||
List<ManifestComplianceFailure> checkDeferredLibraryManifest(
|
||||
AllInfo info, Map manifest) {
|
||||
var includedPackages = new Map<String, Set<String>>();
|
||||
var excludedPackages = new Map<String, Set<String>>();
|
||||
var includedPackages = <String, Set<String>>{};
|
||||
var excludedPackages = <String, Set<String>>{};
|
||||
for (var part in manifest.keys) {
|
||||
for (var package in manifest[part]['include'] ?? []) {
|
||||
(includedPackages[part] ??= {}).add(package);
|
||||
@@ -59,16 +59,20 @@ List<ManifestComplianceFailure> checkDeferredLibraryManifest(
|
||||
// the outputUnits whose list of 'imports' contains a single import. If the
|
||||
// part is shared, it will have more than one import since it will include the
|
||||
// imports of all the top-level deferred parts that will load the shared part.
|
||||
List<String> validParts = ['main']..addAll(info.outputUnits
|
||||
.where((unit) => unit.imports.length == 1)
|
||||
.map((unit) => unit.imports.single));
|
||||
List<String> mentionedParts = []
|
||||
..addAll(includedPackages.keys)
|
||||
..addAll(excludedPackages.keys);
|
||||
List<String> validParts = [
|
||||
'main',
|
||||
...info.outputUnits
|
||||
.where((unit) => unit.imports.length == 1)
|
||||
.map((unit) => unit.imports.single)
|
||||
];
|
||||
List<String> mentionedParts = [
|
||||
...includedPackages.keys,
|
||||
...excludedPackages.keys
|
||||
];
|
||||
var partNameFailures = <_InvalidPartName>[];
|
||||
for (var part in mentionedParts) {
|
||||
if (!validParts.contains(part)) {
|
||||
partNameFailures.add(new _InvalidPartName(part, validParts));
|
||||
partNameFailures.add(_InvalidPartName(part, validParts));
|
||||
}
|
||||
}
|
||||
if (partNameFailures.isNotEmpty) {
|
||||
@@ -79,7 +83,7 @@ List<ManifestComplianceFailure> checkDeferredLibraryManifest(
|
||||
for (var values in includedPackages.values) ...values,
|
||||
for (var values in excludedPackages.values) ...values
|
||||
};
|
||||
var actualIncludedPackages = new Map<String, Set<String>>();
|
||||
var actualIncludedPackages = <String, Set<String>>{};
|
||||
|
||||
var failures = <ManifestComplianceFailure>[];
|
||||
|
||||
@@ -98,8 +102,7 @@ List<ManifestComplianceFailure> checkDeferredLibraryManifest(
|
||||
for (var part in containingParts) {
|
||||
(actualIncludedPackages[part] ??= {}).add(packageName);
|
||||
if (excludedPackages[part].contains(packageName)) {
|
||||
failures
|
||||
.add(new _PartContainedExcludedPackage(part, packageName, info));
|
||||
failures.add(_PartContainedExcludedPackage(part, packageName, info));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,7 +115,7 @@ List<ManifestComplianceFailure> checkDeferredLibraryManifest(
|
||||
for (var package in packages) {
|
||||
if (!actualIncludedPackages.containsKey(part) ||
|
||||
!actualIncludedPackages[part].contains(package)) {
|
||||
failures.add(new _PartDidNotContainPackage(part, package));
|
||||
failures.add(_PartDidNotContainPackage(part, package));
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -146,6 +149,7 @@ class _InvalidPartName extends ManifestComplianceFailure {
|
||||
final List<String> validPartNames;
|
||||
const _InvalidPartName(this.part, this.validPartNames);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Manifest file declares invalid part "$part". '
|
||||
'Valid part names are: $validPartNames';
|
||||
@@ -158,6 +162,7 @@ class _PartContainedExcludedPackage extends ManifestComplianceFailure {
|
||||
final BasicInfo info;
|
||||
const _PartContainedExcludedPackage(this.part, this.package, this.info);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Part "$part" was specified to exclude package "$package" but it '
|
||||
'actually contains ${kindToString(info.kind)} "${info.name}" which '
|
||||
@@ -170,6 +175,7 @@ class _PartDidNotContainPackage extends ManifestComplianceFailure {
|
||||
final String package;
|
||||
const _PartDidNotContainPackage(this.part, this.package);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Part "$part" was specified to include package "$package" but it '
|
||||
'does not contain any elements from that package.';
|
||||
|
||||
@@ -33,12 +33,17 @@ abstract class Info {
|
||||
// TODO(sigmund): add more:
|
||||
// - inputSize: bytes used in the Dart source program
|
||||
abstract class BasicInfo implements Info {
|
||||
@override
|
||||
final InfoKind kind;
|
||||
|
||||
@override
|
||||
String coverageId;
|
||||
@override
|
||||
int size;
|
||||
@override
|
||||
Info parent;
|
||||
|
||||
@override
|
||||
String name;
|
||||
|
||||
/// If using deferred libraries, where the element associated with this info
|
||||
@@ -49,6 +54,7 @@ abstract class BasicInfo implements Info {
|
||||
|
||||
BasicInfo.internal(this.kind);
|
||||
|
||||
@override
|
||||
String toString() => '$kind $name [$size]';
|
||||
}
|
||||
|
||||
@@ -205,6 +211,7 @@ class LibraryInfo extends BasicInfo {
|
||||
|
||||
LibraryInfo.internal() : super.internal(InfoKind.library);
|
||||
|
||||
@override
|
||||
T accept<T>(InfoVisitor<T> visitor) => visitor.visitLibrary(this);
|
||||
}
|
||||
|
||||
@@ -222,6 +229,7 @@ class OutputUnitInfo extends BasicInfo {
|
||||
|
||||
OutputUnitInfo.internal() : super.internal(InfoKind.outputUnit);
|
||||
|
||||
@override
|
||||
T accept<T>(InfoVisitor<T> visitor) => visitor.visitOutput(this);
|
||||
}
|
||||
|
||||
@@ -240,11 +248,12 @@ class ClassInfo extends BasicInfo {
|
||||
List<FieldInfo> fields = <FieldInfo>[];
|
||||
|
||||
ClassInfo(
|
||||
{String name, this.isAbstract, OutputUnitInfo outputUnit, int size: 0})
|
||||
{String name, this.isAbstract, OutputUnitInfo outputUnit, int size = 0})
|
||||
: super(InfoKind.clazz, name, outputUnit, size, null);
|
||||
|
||||
ClassInfo.internal() : super.internal(InfoKind.clazz);
|
||||
|
||||
@override
|
||||
T accept<T>(InfoVisitor<T> visitor) => visitor.visitClass(this);
|
||||
}
|
||||
|
||||
@@ -252,11 +261,12 @@ class ClassInfo extends BasicInfo {
|
||||
/// [ClassInfo] because a class and its type may end up in different output
|
||||
/// units.
|
||||
class ClassTypeInfo extends BasicInfo {
|
||||
ClassTypeInfo({String name, OutputUnitInfo outputUnit, int size: 0})
|
||||
ClassTypeInfo({String name, OutputUnitInfo outputUnit, int size = 0})
|
||||
: super(InfoKind.classType, name, outputUnit, size, null);
|
||||
|
||||
ClassTypeInfo.internal() : super.internal(InfoKind.classType);
|
||||
|
||||
@override
|
||||
T accept<T>(InfoVisitor<T> visitor) => visitor.visitClassType(this);
|
||||
}
|
||||
|
||||
@@ -284,11 +294,12 @@ class ConstantInfo extends BasicInfo {
|
||||
List<CodeSpan> code;
|
||||
|
||||
// TODO(sigmund): Add coverage support to constants?
|
||||
ConstantInfo({int size: 0, this.code, OutputUnitInfo outputUnit})
|
||||
ConstantInfo({int size = 0, this.code, OutputUnitInfo outputUnit})
|
||||
: super(InfoKind.constant, null, outputUnit, size, null);
|
||||
|
||||
ConstantInfo.internal() : super.internal(InfoKind.constant);
|
||||
|
||||
@override
|
||||
T accept<T>(InfoVisitor<T> visitor) => visitor.visitConstant(this);
|
||||
}
|
||||
|
||||
@@ -315,7 +326,7 @@ class FieldInfo extends BasicInfo with CodeInfo {
|
||||
FieldInfo(
|
||||
{String name,
|
||||
String coverageId,
|
||||
int size: 0,
|
||||
int size = 0,
|
||||
this.type,
|
||||
this.inferredType,
|
||||
this.closures,
|
||||
@@ -326,6 +337,7 @@ class FieldInfo extends BasicInfo with CodeInfo {
|
||||
|
||||
FieldInfo.internal() : super.internal(InfoKind.field);
|
||||
|
||||
@override
|
||||
T accept<T>(InfoVisitor<T> visitor) => visitor.visitField(this);
|
||||
}
|
||||
|
||||
@@ -339,6 +351,7 @@ class TypedefInfo extends BasicInfo {
|
||||
|
||||
TypedefInfo.internal() : super.internal(InfoKind.typedef);
|
||||
|
||||
@override
|
||||
T accept<T>(InfoVisitor<T> visitor) => visitor.visitTypedef(this);
|
||||
}
|
||||
|
||||
@@ -384,7 +397,7 @@ class FunctionInfo extends BasicInfo with CodeInfo {
|
||||
{String name,
|
||||
String coverageId,
|
||||
OutputUnitInfo outputUnit,
|
||||
int size: 0,
|
||||
int size = 0,
|
||||
this.functionKind,
|
||||
this.modifiers,
|
||||
this.closures,
|
||||
@@ -399,6 +412,7 @@ class FunctionInfo extends BasicInfo with CodeInfo {
|
||||
|
||||
FunctionInfo.internal() : super.internal(InfoKind.function);
|
||||
|
||||
@override
|
||||
T accept<T>(InfoVisitor<T> visitor) => visitor.visitFunction(this);
|
||||
}
|
||||
|
||||
@@ -408,11 +422,12 @@ class ClosureInfo extends BasicInfo {
|
||||
FunctionInfo function;
|
||||
|
||||
ClosureInfo(
|
||||
{String name, OutputUnitInfo outputUnit, int size: 0, this.function})
|
||||
{String name, OutputUnitInfo outputUnit, int size = 0, this.function})
|
||||
: super(InfoKind.closure, name, outputUnit, size, null);
|
||||
|
||||
ClosureInfo.internal() : super.internal(InfoKind.closure);
|
||||
|
||||
@override
|
||||
T accept<T>(InfoVisitor<T> visitor) => visitor.visitClosure(this);
|
||||
}
|
||||
|
||||
@@ -446,10 +461,10 @@ class FunctionModifiers {
|
||||
final bool isExternal;
|
||||
|
||||
FunctionModifiers(
|
||||
{this.isStatic: false,
|
||||
this.isConst: false,
|
||||
this.isFactory: false,
|
||||
this.isExternal: false});
|
||||
{this.isStatic = false,
|
||||
this.isConst = false,
|
||||
this.isFactory = false,
|
||||
this.isExternal = false});
|
||||
}
|
||||
|
||||
/// Possible values of the `kind` field in the serialized infos.
|
||||
@@ -536,7 +551,8 @@ abstract class InfoVisitor<T> {
|
||||
/// visitAll contains references to functions, this visitor only recurses to
|
||||
/// visit libraries, then from each library we visit functions and classes, and
|
||||
/// so on.
|
||||
class RecursiveInfoVisitor extends InfoVisitor<Null> {
|
||||
class RecursiveInfoVisitor extends InfoVisitor<void> {
|
||||
@override
|
||||
visitAll(AllInfo info) {
|
||||
// Note: we don't visit functions, fields, classes, and typedefs because
|
||||
// they are reachable from the library info.
|
||||
@@ -544,8 +560,10 @@ class RecursiveInfoVisitor extends InfoVisitor<Null> {
|
||||
info.constants.forEach(visitConstant);
|
||||
}
|
||||
|
||||
@override
|
||||
visitProgram(ProgramInfo info) {}
|
||||
|
||||
@override
|
||||
visitLibrary(LibraryInfo info) {
|
||||
info.topLevelFunctions.forEach(visitFunction);
|
||||
info.topLevelVariables.forEach(visitField);
|
||||
@@ -554,25 +572,33 @@ class RecursiveInfoVisitor extends InfoVisitor<Null> {
|
||||
info.typedefs.forEach(visitTypedef);
|
||||
}
|
||||
|
||||
@override
|
||||
visitClass(ClassInfo info) {
|
||||
info.functions.forEach(visitFunction);
|
||||
info.fields.forEach(visitField);
|
||||
}
|
||||
|
||||
@override
|
||||
visitClassType(ClassTypeInfo info) {}
|
||||
|
||||
@override
|
||||
visitField(FieldInfo info) {
|
||||
info.closures.forEach(visitClosure);
|
||||
}
|
||||
|
||||
@override
|
||||
visitConstant(ConstantInfo info) {}
|
||||
|
||||
@override
|
||||
visitFunction(FunctionInfo info) {
|
||||
info.closures.forEach(visitClosure);
|
||||
}
|
||||
|
||||
@override
|
||||
visitTypedef(TypedefInfo info) {}
|
||||
@override
|
||||
visitOutput(OutputUnitInfo info) {}
|
||||
@override
|
||||
visitClosure(ClosureInfo info) {
|
||||
visitFunction(info.function);
|
||||
}
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
/// Converters and codecs for converting between JSON and [Info] classes.
|
||||
|
||||
import 'dart:collection';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'src/util.dart';
|
||||
|
||||
import 'info.dart';
|
||||
import 'src/util.dart';
|
||||
|
||||
List<String> _toSortedSerializedIds(
|
||||
Iterable<Info> infos, Id Function(Info) getId) =>
|
||||
@@ -18,13 +18,14 @@ List<String> _toSortedSerializedIds(
|
||||
// TODO(sigmund): add unit tests.
|
||||
class JsonToAllInfoConverter extends Converter<Map<String, dynamic>, AllInfo> {
|
||||
// Using `MashMap` here because it's faster than the default `LinkedHashMap`.
|
||||
final Map<String, Info> registry = new HashMap<String, Info>();
|
||||
final Map<String, Info> registry = HashMap<String, Info>();
|
||||
|
||||
AllInfo convert(Map<String, dynamic> json) {
|
||||
@override
|
||||
AllInfo convert(Map<String, dynamic> input) {
|
||||
registry.clear();
|
||||
|
||||
var result = new AllInfo();
|
||||
var elements = json['elements'];
|
||||
var result = AllInfo();
|
||||
var elements = input['elements'];
|
||||
// TODO(srawlins): Since only the Map values are being extracted below,
|
||||
// replace `as` with `cast` when `cast` becomes available in Dart 2.0:
|
||||
//
|
||||
@@ -50,29 +51,29 @@ class JsonToAllInfoConverter extends Converter<Map<String, dynamic>, AllInfo> {
|
||||
result.constants.addAll(
|
||||
(elements['constant'] as Map).values.map((c) => parseConstant(c)));
|
||||
|
||||
json['holding'].forEach((k, deps) {
|
||||
input['holding'].forEach((k, deps) {
|
||||
CodeInfo src = registry[k];
|
||||
assert(src != null);
|
||||
for (var dep in deps) {
|
||||
var target = registry[dep['id']];
|
||||
assert(target != null);
|
||||
src.uses.add(new DependencyInfo(target, dep['mask']));
|
||||
src.uses.add(DependencyInfo(target, dep['mask']));
|
||||
}
|
||||
});
|
||||
|
||||
json['dependencies']?.forEach((String k, dependencies) {
|
||||
input['dependencies']?.forEach((String k, dependencies) {
|
||||
List<String> deps = dependencies;
|
||||
result.dependencies[registry[k]] = deps.map((d) => registry[d]).toList();
|
||||
});
|
||||
|
||||
result.outputUnits
|
||||
.addAll((json['outputUnits'] as List).map((o) => parseOutputUnit(o)));
|
||||
.addAll((input['outputUnits'] as List).map((o) => parseOutputUnit(o)));
|
||||
|
||||
result.program = parseProgram(json['program']);
|
||||
result.program = parseProgram(input['program']);
|
||||
|
||||
if (json['deferredFiles'] != null) {
|
||||
if (input['deferredFiles'] != null) {
|
||||
final deferredFilesMap =
|
||||
(json['deferredFiles'] as Map).cast<String, Map<String, dynamic>>();
|
||||
(input['deferredFiles'] as Map).cast<String, Map<String, dynamic>>();
|
||||
for (final library in deferredFilesMap.values) {
|
||||
if (library['imports'] != null) {
|
||||
// The importMap needs to be typed as <String, List<String>>, but the
|
||||
@@ -192,7 +193,7 @@ class JsonToAllInfoConverter extends Converter<Map<String, dynamic>, AllInfo> {
|
||||
}
|
||||
|
||||
ProgramInfo parseProgram(Map json) {
|
||||
var programInfo = new ProgramInfo()
|
||||
var programInfo = ProgramInfo()
|
||||
..entrypoint = parseId(json['entrypoint'])
|
||||
..size = json['size']
|
||||
..compilationMoment = DateTime.parse(json['compilationMoment'])
|
||||
@@ -211,7 +212,7 @@ class JsonToAllInfoConverter extends Converter<Map<String, dynamic>, AllInfo> {
|
||||
} else {
|
||||
assert(compilationDuration is int);
|
||||
programInfo.compilationDuration =
|
||||
new Duration(microseconds: compilationDuration);
|
||||
Duration(microseconds: compilationDuration);
|
||||
}
|
||||
|
||||
var toJsonDuration = json['toJsonDuration'];
|
||||
@@ -219,7 +220,7 @@ class JsonToAllInfoConverter extends Converter<Map<String, dynamic>, AllInfo> {
|
||||
programInfo.toJsonDuration = _parseDuration(toJsonDuration);
|
||||
} else {
|
||||
assert(toJsonDuration is int);
|
||||
programInfo.toJsonDuration = new Duration(microseconds: toJsonDuration);
|
||||
programInfo.toJsonDuration = Duration(microseconds: toJsonDuration);
|
||||
}
|
||||
|
||||
var dumpInfoDuration = json['dumpInfoDuration'];
|
||||
@@ -227,8 +228,7 @@ class JsonToAllInfoConverter extends Converter<Map<String, dynamic>, AllInfo> {
|
||||
programInfo.dumpInfoDuration = _parseDuration(dumpInfoDuration);
|
||||
} else {
|
||||
assert(dumpInfoDuration is int);
|
||||
programInfo.dumpInfoDuration =
|
||||
new Duration(microseconds: dumpInfoDuration);
|
||||
programInfo.dumpInfoDuration = Duration(microseconds: dumpInfoDuration);
|
||||
}
|
||||
|
||||
return programInfo;
|
||||
@@ -237,7 +237,7 @@ class JsonToAllInfoConverter extends Converter<Map<String, dynamic>, AllInfo> {
|
||||
/// Parse a string formatted as "XX:YY:ZZ.ZZZZZ" into a [Duration].
|
||||
Duration _parseDuration(String duration) {
|
||||
if (!duration.contains(':')) {
|
||||
return new Duration(milliseconds: int.parse(duration));
|
||||
return Duration(milliseconds: int.parse(duration));
|
||||
}
|
||||
var parts = duration.split(':');
|
||||
var hours = double.parse(parts[0]);
|
||||
@@ -249,7 +249,7 @@ class JsonToAllInfoConverter extends Converter<Map<String, dynamic>, AllInfo> {
|
||||
var totalMillis = secondsInMillis * seconds +
|
||||
minutesInMillis * minutes +
|
||||
hoursInMillis * hours;
|
||||
return new Duration(milliseconds: totalMillis.round());
|
||||
return Duration(milliseconds: totalMillis.round());
|
||||
}
|
||||
|
||||
FunctionInfo parseFunction(Map json) {
|
||||
@@ -268,18 +268,17 @@ class JsonToAllInfoConverter extends Converter<Map<String, dynamic>, AllInfo> {
|
||||
..code = parseCode(json['code'])
|
||||
..sideEffects = json['sideEffects']
|
||||
..inlinedCount = json['inlinedCount']
|
||||
..modifiers =
|
||||
parseModifiers(new Map<String, bool>.from(json['modifiers']))
|
||||
..modifiers = parseModifiers(Map<String, bool>.from(json['modifiers']))
|
||||
..closures = (json['children'] as List)
|
||||
.map<ClosureInfo>((c) => parseId(c))
|
||||
.toList();
|
||||
}
|
||||
|
||||
ParameterInfo parseParameter(Map json) =>
|
||||
new ParameterInfo(json['name'], json['type'], json['declaredType']);
|
||||
ParameterInfo(json['name'], json['type'], json['declaredType']);
|
||||
|
||||
FunctionModifiers parseModifiers(Map<String, bool> json) {
|
||||
return new FunctionModifiers(
|
||||
return FunctionModifiers(
|
||||
isStatic: json['static'] == true,
|
||||
isConst: json['const'] == true,
|
||||
isFactory: json['factory'] == true,
|
||||
@@ -303,23 +302,23 @@ class JsonToAllInfoConverter extends Converter<Map<String, dynamic>, AllInfo> {
|
||||
}
|
||||
return registry.putIfAbsent(serializedId, () {
|
||||
if (serializedId.startsWith('function/')) {
|
||||
return new FunctionInfo.internal();
|
||||
return FunctionInfo.internal();
|
||||
} else if (serializedId.startsWith('closure/')) {
|
||||
return new ClosureInfo.internal();
|
||||
return ClosureInfo.internal();
|
||||
} else if (serializedId.startsWith('library/')) {
|
||||
return new LibraryInfo.internal();
|
||||
return LibraryInfo.internal();
|
||||
} else if (serializedId.startsWith('class/')) {
|
||||
return new ClassInfo.internal();
|
||||
return ClassInfo.internal();
|
||||
} else if (serializedId.startsWith('classType/')) {
|
||||
return new ClassTypeInfo.internal();
|
||||
return ClassTypeInfo.internal();
|
||||
} else if (serializedId.startsWith('field/')) {
|
||||
return new FieldInfo.internal();
|
||||
return FieldInfo.internal();
|
||||
} else if (serializedId.startsWith('constant/')) {
|
||||
return new ConstantInfo.internal();
|
||||
return ConstantInfo.internal();
|
||||
} else if (serializedId.startsWith('typedef/')) {
|
||||
return new TypedefInfo.internal();
|
||||
return TypedefInfo.internal();
|
||||
} else if (serializedId.startsWith('outputUnit/')) {
|
||||
return new OutputUnitInfo.internal();
|
||||
return OutputUnitInfo.internal();
|
||||
}
|
||||
assert(false);
|
||||
return null;
|
||||
@@ -329,13 +328,13 @@ class JsonToAllInfoConverter extends Converter<Map<String, dynamic>, AllInfo> {
|
||||
List<CodeSpan> parseCode(dynamic json) {
|
||||
// backwards compatibility with format 5.1:
|
||||
if (json is String) {
|
||||
return [new CodeSpan(start: null, end: null, text: json)];
|
||||
return [CodeSpan(start: null, end: null, text: json)];
|
||||
}
|
||||
|
||||
if (json is List) {
|
||||
return json.map((dynamic value) {
|
||||
Map<String, dynamic> jsonCode = value;
|
||||
return new CodeSpan(
|
||||
return CodeSpan(
|
||||
start: jsonCode['start'],
|
||||
end: jsonCode['end'],
|
||||
text: jsonCode['text']);
|
||||
@@ -350,10 +349,10 @@ class AllInfoToJsonConverter extends Converter<AllInfo, Map>
|
||||
implements InfoVisitor<Map> {
|
||||
/// Whether to generate json compatible with format 5.1
|
||||
final bool isBackwardCompatible;
|
||||
final Map<Info, Id> ids = new HashMap<Info, Id>();
|
||||
final Set<int> usedIds = new Set<int>();
|
||||
final Map<Info, Id> ids = HashMap<Info, Id>();
|
||||
final Set<int> usedIds = <int>{};
|
||||
|
||||
AllInfoToJsonConverter({this.isBackwardCompatible: false});
|
||||
AllInfoToJsonConverter({this.isBackwardCompatible = false});
|
||||
|
||||
Id idFor(Info info) {
|
||||
var serializedId = ids[info];
|
||||
@@ -381,17 +380,18 @@ class AllInfoToJsonConverter extends Converter<AllInfo, Map>
|
||||
while (!usedIds.add(id)) {
|
||||
id++;
|
||||
}
|
||||
serializedId = new Id(info.kind, '$id');
|
||||
serializedId = Id(info.kind, '$id');
|
||||
return ids[info] = serializedId;
|
||||
}
|
||||
|
||||
Map convert(AllInfo info) => info.accept(this);
|
||||
@override
|
||||
Map convert(AllInfo input) => input.accept(this);
|
||||
|
||||
Map _visitList(List<Info> infos) {
|
||||
// Using SplayTree to maintain a consistent order of keys
|
||||
var map = new SplayTreeMap<String, Map>(compareNatural);
|
||||
var map = SplayTreeMap<String, Map>(compareNatural);
|
||||
for (var info in infos) {
|
||||
map['${idFor(info).id}'] = info.accept(this);
|
||||
map[idFor(info).id] = info.accept(this);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
@@ -421,7 +421,7 @@ class AllInfoToJsonConverter extends Converter<AllInfo, Map>
|
||||
{'id': idFor(info.target).serializedId, 'mask': info.mask};
|
||||
|
||||
Map _visitAllInfoHolding(AllInfo allInfo) {
|
||||
var map = new SplayTreeMap<String, List>(compareNatural);
|
||||
var map = SplayTreeMap<String, List>(compareNatural);
|
||||
void helper(CodeInfo info) {
|
||||
if (info.uses.isEmpty) return;
|
||||
map[idFor(info).serializedId] = info.uses
|
||||
@@ -436,13 +436,14 @@ class AllInfoToJsonConverter extends Converter<AllInfo, Map>
|
||||
}
|
||||
|
||||
Map _visitAllInfoDependencies(AllInfo allInfo) {
|
||||
var map = new SplayTreeMap<String, List>(compareNatural);
|
||||
var map = SplayTreeMap<String, List>(compareNatural);
|
||||
allInfo.dependencies.forEach((k, v) {
|
||||
map[idFor(k).serializedId] = _toSortedSerializedIds(v, idFor);
|
||||
});
|
||||
return map;
|
||||
}
|
||||
|
||||
@override
|
||||
Map visitAll(AllInfo info) {
|
||||
var elements = _visitAllInfoElements(info);
|
||||
var jsonHolding = _visitAllInfoHolding(info);
|
||||
@@ -459,6 +460,7 @@ class AllInfoToJsonConverter extends Converter<AllInfo, Map>
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
Map visitProgram(ProgramInfo info) {
|
||||
return {
|
||||
'entrypoint': idFor(info.entrypoint).serializedId,
|
||||
@@ -494,6 +496,7 @@ class AllInfoToJsonConverter extends Converter<AllInfo, Map>
|
||||
return res;
|
||||
}
|
||||
|
||||
@override
|
||||
Map visitLibrary(LibraryInfo info) {
|
||||
return _visitBasicInfo(info)
|
||||
..addAll(<String, Object>{
|
||||
@@ -510,6 +513,7 @@ class AllInfoToJsonConverter extends Converter<AllInfo, Map>
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Map visitClass(ClassInfo info) {
|
||||
return _visitBasicInfo(info)
|
||||
..addAll(<String, Object>{
|
||||
@@ -520,10 +524,12 @@ class AllInfoToJsonConverter extends Converter<AllInfo, Map>
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Map visitClassType(ClassTypeInfo info) {
|
||||
return _visitBasicInfo(info);
|
||||
}
|
||||
|
||||
@override
|
||||
Map visitField(FieldInfo info) {
|
||||
var result = _visitBasicInfo(info)
|
||||
..addAll(<String, Object>{
|
||||
@@ -541,6 +547,7 @@ class AllInfoToJsonConverter extends Converter<AllInfo, Map>
|
||||
return result;
|
||||
}
|
||||
|
||||
@override
|
||||
Map visitConstant(ConstantInfo info) => _visitBasicInfo(info)
|
||||
..addAll(<String, Object>{'code': _serializeCode(info.code)});
|
||||
|
||||
@@ -561,6 +568,7 @@ class AllInfoToJsonConverter extends Converter<AllInfo, Map>
|
||||
Map _visitParameterInfo(ParameterInfo info) =>
|
||||
{'name': info.name, 'type': info.type, 'declaredType': info.declaredType};
|
||||
|
||||
@override
|
||||
Map visitFunction(FunctionInfo info) {
|
||||
return _visitBasicInfo(info)
|
||||
..addAll(<String, Object>{
|
||||
@@ -579,13 +587,16 @@ class AllInfoToJsonConverter extends Converter<AllInfo, Map>
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Map visitClosure(ClosureInfo info) {
|
||||
return _visitBasicInfo(info)
|
||||
..addAll(<String, Object>{'function': idFor(info.function).serializedId});
|
||||
}
|
||||
|
||||
@override
|
||||
visitTypedef(TypedefInfo info) => _visitBasicInfo(info)..['type'] = info.type;
|
||||
|
||||
@override
|
||||
visitOutput(OutputUnitInfo info) => _visitBasicInfo(info)
|
||||
..['filename'] = info.filename
|
||||
..['imports'] = info.imports;
|
||||
@@ -605,12 +616,14 @@ class AllInfoToJsonConverter extends Converter<AllInfo, Map>
|
||||
}
|
||||
|
||||
class AllInfoJsonCodec extends Codec<AllInfo, Map> {
|
||||
@override
|
||||
final Converter<AllInfo, Map> encoder;
|
||||
final Converter<Map, AllInfo> decoder = new JsonToAllInfoConverter();
|
||||
@override
|
||||
final Converter<Map, AllInfo> decoder = JsonToAllInfoConverter();
|
||||
|
||||
AllInfoJsonCodec({bool isBackwardCompatible: false})
|
||||
: encoder = new AllInfoToJsonConverter(
|
||||
isBackwardCompatible: isBackwardCompatible);
|
||||
AllInfoJsonCodec({bool isBackwardCompatible = false})
|
||||
: encoder =
|
||||
AllInfoToJsonConverter(isBackwardCompatible: isBackwardCompatible);
|
||||
}
|
||||
|
||||
class Id {
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
/// Converters and codecs for converting between Protobuf and [Info] classes.
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:fixnum/fixnum.dart';
|
||||
|
||||
import 'info.dart';
|
||||
@@ -14,18 +14,19 @@ import 'src/util.dart';
|
||||
export 'src/proto/info.pb.dart';
|
||||
|
||||
class ProtoToAllInfoConverter extends Converter<AllInfoPB, AllInfo> {
|
||||
AllInfo convert(AllInfoPB info) {
|
||||
@override
|
||||
AllInfo convert(AllInfoPB input) {
|
||||
// TODO(lorenvs): Implement this conversion. It is unlikely to to be used
|
||||
// by production code since the goal of the proto codec is to consume this
|
||||
// information from other languages. However, it is useful for roundtrip
|
||||
// testing, so we should support it.
|
||||
throw new UnimplementedError('ProtoToAllInfoConverter is not implemented');
|
||||
throw UnimplementedError('ProtoToAllInfoConverter is not implemented');
|
||||
}
|
||||
}
|
||||
|
||||
class AllInfoToProtoConverter extends Converter<AllInfo, AllInfoPB> {
|
||||
final Map<Info, Id> ids = {};
|
||||
final Set<int> usedIds = new Set<int>();
|
||||
final Set<int> usedIds = <int>{};
|
||||
|
||||
Id idFor(Info info) {
|
||||
if (info == null) return null;
|
||||
@@ -51,14 +52,15 @@ class AllInfoToProtoConverter extends Converter<AllInfo, AllInfoPB> {
|
||||
while (!usedIds.add(id)) {
|
||||
id++;
|
||||
}
|
||||
serializedId = new Id(info.kind, id);
|
||||
serializedId = Id(info.kind, id);
|
||||
return ids[info] = serializedId;
|
||||
}
|
||||
|
||||
AllInfoPB convert(AllInfo info) => _convertToAllInfoPB(info);
|
||||
@override
|
||||
AllInfoPB convert(AllInfo input) => _convertToAllInfoPB(input);
|
||||
|
||||
DependencyInfoPB _convertToDependencyInfoPB(DependencyInfo info) {
|
||||
var result = new DependencyInfoPB()
|
||||
var result = DependencyInfoPB()
|
||||
..targetId = idFor(info.target)?.serializedId;
|
||||
if (info.mask != null) {
|
||||
result.mask = info.mask;
|
||||
@@ -67,14 +69,14 @@ class AllInfoToProtoConverter extends Converter<AllInfo, AllInfoPB> {
|
||||
}
|
||||
|
||||
static ParameterInfoPB _convertToParameterInfoPB(ParameterInfo info) {
|
||||
return new ParameterInfoPB()
|
||||
return ParameterInfoPB()
|
||||
..name = info.name
|
||||
..type = info.type
|
||||
..declaredType = info.declaredType;
|
||||
}
|
||||
|
||||
LibraryInfoPB _convertToLibraryInfoPB(LibraryInfo info) {
|
||||
final proto = new LibraryInfoPB()..uri = info.uri.toString();
|
||||
final proto = LibraryInfoPB()..uri = info.uri.toString();
|
||||
|
||||
proto.childrenIds
|
||||
.addAll(info.topLevelFunctions.map((func) => idFor(func).serializedId));
|
||||
@@ -91,7 +93,7 @@ class AllInfoToProtoConverter extends Converter<AllInfo, AllInfoPB> {
|
||||
}
|
||||
|
||||
ClassInfoPB _convertToClassInfoPB(ClassInfo info) {
|
||||
final proto = new ClassInfoPB()..isAbstract = info.isAbstract;
|
||||
final proto = ClassInfoPB()..isAbstract = info.isAbstract;
|
||||
|
||||
proto.childrenIds
|
||||
.addAll(info.functions.map((func) => idFor(func).serializedId));
|
||||
@@ -107,7 +109,7 @@ class AllInfoToProtoConverter extends Converter<AllInfo, AllInfoPB> {
|
||||
|
||||
static FunctionModifiersPB _convertToFunctionModifiers(
|
||||
FunctionModifiers modifiers) {
|
||||
return new FunctionModifiersPB()
|
||||
return FunctionModifiersPB()
|
||||
..isStatic = modifiers.isStatic
|
||||
..isConst = modifiers.isConst
|
||||
..isFactory = modifiers.isFactory
|
||||
@@ -115,7 +117,7 @@ class AllInfoToProtoConverter extends Converter<AllInfo, AllInfoPB> {
|
||||
}
|
||||
|
||||
FunctionInfoPB _convertToFunctionInfoPB(FunctionInfo info) {
|
||||
final proto = new FunctionInfoPB()
|
||||
final proto = FunctionInfoPB()
|
||||
..functionModifiers = _convertToFunctionModifiers(info.modifiers)
|
||||
..inlinedCount = info.inlinedCount ?? 0;
|
||||
|
||||
@@ -143,7 +145,7 @@ class AllInfoToProtoConverter extends Converter<AllInfo, AllInfoPB> {
|
||||
}
|
||||
|
||||
FieldInfoPB _convertToFieldInfoPB(FieldInfo info) {
|
||||
final proto = new FieldInfoPB()
|
||||
final proto = FieldInfoPB()
|
||||
..type = info.type
|
||||
..inferredType = info.inferredType
|
||||
..isConst = info.isConst;
|
||||
@@ -163,25 +165,25 @@ class AllInfoToProtoConverter extends Converter<AllInfo, AllInfoPB> {
|
||||
}
|
||||
|
||||
static ConstantInfoPB _convertToConstantInfoPB(ConstantInfo info) {
|
||||
return new ConstantInfoPB()..code = info.code.map((c) => c.text).join('\n');
|
||||
return ConstantInfoPB()..code = info.code.map((c) => c.text).join('\n');
|
||||
}
|
||||
|
||||
static OutputUnitInfoPB _convertToOutputUnitInfoPB(OutputUnitInfo info) {
|
||||
final proto = new OutputUnitInfoPB();
|
||||
final proto = OutputUnitInfoPB();
|
||||
proto.imports.addAll(info.imports.where((import) => import != null));
|
||||
return proto;
|
||||
}
|
||||
|
||||
static TypedefInfoPB _convertToTypedefInfoPB(TypedefInfo info) {
|
||||
return new TypedefInfoPB()..type = info.type;
|
||||
return TypedefInfoPB()..type = info.type;
|
||||
}
|
||||
|
||||
ClosureInfoPB _convertToClosureInfoPB(ClosureInfo info) {
|
||||
return new ClosureInfoPB()..functionId = idFor(info.function).serializedId;
|
||||
return ClosureInfoPB()..functionId = idFor(info.function).serializedId;
|
||||
}
|
||||
|
||||
InfoPB _convertToInfoPB(Info info) {
|
||||
final proto = new InfoPB()
|
||||
final proto = InfoPB()
|
||||
..id = idFor(info).id
|
||||
..serializedId = idFor(info).serializedId
|
||||
..size = info.size;
|
||||
@@ -233,14 +235,13 @@ class AllInfoToProtoConverter extends Converter<AllInfo, AllInfoPB> {
|
||||
}
|
||||
|
||||
ProgramInfoPB _convertToProgramInfoPB(ProgramInfo info) {
|
||||
var result = new ProgramInfoPB()
|
||||
var result = ProgramInfoPB()
|
||||
..entrypointId = idFor(info.entrypoint).serializedId
|
||||
..size = info.size
|
||||
..compilationMoment =
|
||||
new Int64(info.compilationMoment.microsecondsSinceEpoch)
|
||||
..compilationDuration = new Int64(info.compilationDuration.inMicroseconds)
|
||||
..toProtoDuration = new Int64(info.toJsonDuration.inMicroseconds)
|
||||
..dumpInfoDuration = new Int64(info.dumpInfoDuration.inMicroseconds)
|
||||
..compilationMoment = Int64(info.compilationMoment.microsecondsSinceEpoch)
|
||||
..compilationDuration = Int64(info.compilationDuration.inMicroseconds)
|
||||
..toProtoDuration = Int64(info.toJsonDuration.inMicroseconds)
|
||||
..dumpInfoDuration = Int64(info.dumpInfoDuration.inMicroseconds)
|
||||
..noSuchMethodEnabled = info.noSuchMethodEnabled ?? false
|
||||
..isRuntimeTypeUsed = info.isRuntimeTypeUsed ?? false
|
||||
..isIsolateUsed = info.isIsolateInUse ?? false
|
||||
@@ -265,13 +266,13 @@ class AllInfoToProtoConverter extends Converter<AllInfo, AllInfoPB> {
|
||||
|
||||
static LibraryDeferredImportsPB _convertToLibraryDeferredImportsPB(
|
||||
String libraryUri, Map<String, dynamic> fields) {
|
||||
final proto = new LibraryDeferredImportsPB()
|
||||
final proto = LibraryDeferredImportsPB()
|
||||
..libraryUri = libraryUri
|
||||
..libraryName = fields['name'] ?? '<unnamed>';
|
||||
|
||||
Map<String, List<String>> imports = fields['imports'];
|
||||
imports.forEach((prefix, files) {
|
||||
final import = new DeferredImportPB()..prefix = prefix;
|
||||
final import = DeferredImportPB()..prefix = prefix;
|
||||
import.files.addAll(files);
|
||||
proto.imports.add(import);
|
||||
});
|
||||
@@ -280,8 +281,7 @@ class AllInfoToProtoConverter extends Converter<AllInfo, AllInfoPB> {
|
||||
}
|
||||
|
||||
AllInfoPB _convertToAllInfoPB(AllInfo info) {
|
||||
final proto = new AllInfoPB()
|
||||
..program = _convertToProgramInfoPB(info.program);
|
||||
final proto = AllInfoPB()..program = _convertToProgramInfoPB(info.program);
|
||||
|
||||
proto.allInfos.addEntries(_convertToAllInfosEntries(info.libraries));
|
||||
proto.allInfos.addEntries(_convertToAllInfosEntries(info.classes));
|
||||
@@ -307,8 +307,10 @@ class AllInfoToProtoConverter extends Converter<AllInfo, AllInfoPB> {
|
||||
/// This codec is still experimental, and will likely crash on certain output
|
||||
/// from dart2js.
|
||||
class AllInfoProtoCodec extends Codec<AllInfo, AllInfoPB> {
|
||||
final Converter<AllInfo, AllInfoPB> encoder = new AllInfoToProtoConverter();
|
||||
final Converter<AllInfoPB, AllInfo> decoder = new ProtoToAllInfoConverter();
|
||||
@override
|
||||
final Converter<AllInfo, AllInfoPB> encoder = AllInfoToProtoConverter();
|
||||
@override
|
||||
final Converter<AllInfoPB, AllInfo> decoder = ProtoToAllInfoConverter();
|
||||
}
|
||||
|
||||
class Id {
|
||||
|
||||
@@ -20,22 +20,22 @@ abstract class DataSink {
|
||||
|
||||
/// Writes a reference to [value] to this data sink. If [value] has not yet
|
||||
/// been serialized, [f] is called to serialize the value itself.
|
||||
void writeCached<E>(E value, void f(E value));
|
||||
void writeCached<E>(E value, void Function(E value) f);
|
||||
|
||||
/// Writes the potentially `null` [value] to this data sink. If [value] is
|
||||
/// non-null [f] is called to write the non-null value to the data sink.
|
||||
///
|
||||
/// This is a convenience method to be used together with
|
||||
/// [DataSource.readValueOrNull].
|
||||
void writeValueOrNull<E>(E value, void f(E value));
|
||||
void writeValueOrNull<E>(E value, void Function(E value) f);
|
||||
|
||||
/// Writes the [values] to this data sink calling [f] to write each value to
|
||||
/// the data sink. If [allowNull] is `true`, [values] is allowed to be `null`.
|
||||
///
|
||||
/// This is a convenience method to be used together with
|
||||
/// [DataSource.readList].
|
||||
void writeList<E>(Iterable<E> values, void f(E value),
|
||||
{bool allowNull: false});
|
||||
void writeList<E>(Iterable<E> values, void Function(E value) f,
|
||||
{bool allowNull = false});
|
||||
|
||||
/// Writes the boolean [value] to this data sink.
|
||||
void writeBool(bool value);
|
||||
@@ -63,7 +63,7 @@ abstract class DataSink {
|
||||
///
|
||||
/// This is a convenience method to be used together with
|
||||
/// [DataSource.readStrings].
|
||||
void writeStrings(Iterable<String> values, {bool allowNull: false});
|
||||
void writeStrings(Iterable<String> values, {bool allowNull = false});
|
||||
|
||||
/// Writes the [map] from string to [V] values to this data sink, calling [f]
|
||||
/// to write each value to the data sink. If [allowNull] is `true`, [map] is
|
||||
@@ -71,8 +71,8 @@ abstract class DataSink {
|
||||
///
|
||||
/// This is a convenience method to be used together with
|
||||
/// [DataSource.readStringMap].
|
||||
void writeStringMap<V>(Map<String, V> map, void f(V value),
|
||||
{bool allowNull: false});
|
||||
void writeStringMap<V>(Map<String, V> map, void Function(V value) f,
|
||||
{bool allowNull = false});
|
||||
|
||||
/// Writes the enum value [value] to this data sink.
|
||||
// TODO(johnniwinther): Change the signature to
|
||||
@@ -103,7 +103,7 @@ abstract class DataSinkMixin implements DataSink {
|
||||
}
|
||||
|
||||
@override
|
||||
void writeStrings(Iterable<String> values, {bool allowNull: false}) {
|
||||
void writeStrings(Iterable<String> values, {bool allowNull = false}) {
|
||||
if (values == null) {
|
||||
assert(allowNull);
|
||||
writeInt(0);
|
||||
@@ -116,8 +116,8 @@ abstract class DataSinkMixin implements DataSink {
|
||||
}
|
||||
|
||||
@override
|
||||
void writeStringMap<V>(Map<String, V> map, void f(V value),
|
||||
{bool allowNull: false}) {
|
||||
void writeStringMap<V>(Map<String, V> map, void Function(V value) f,
|
||||
{bool allowNull = false}) {
|
||||
if (map == null) {
|
||||
assert(allowNull);
|
||||
writeInt(0);
|
||||
@@ -131,8 +131,8 @@ abstract class DataSinkMixin implements DataSink {
|
||||
}
|
||||
|
||||
@override
|
||||
void writeList<E>(Iterable<E> values, void f(E value),
|
||||
{bool allowNull: false}) {
|
||||
void writeList<E>(Iterable<E> values, void Function(E value) f,
|
||||
{bool allowNull = false}) {
|
||||
if (values == null) {
|
||||
assert(allowNull);
|
||||
writeInt(0);
|
||||
@@ -143,7 +143,7 @@ abstract class DataSinkMixin implements DataSink {
|
||||
}
|
||||
|
||||
@override
|
||||
void writeValueOrNull<E>(E value, void f(E value)) {
|
||||
void writeValueOrNull<E>(E value, void Function(E value) f) {
|
||||
writeBool(value != null);
|
||||
if (value != null) {
|
||||
f(value);
|
||||
@@ -162,7 +162,7 @@ class IndexedSink<E> {
|
||||
///
|
||||
/// If [value] has not been canonicalized yet, [writeValue] is called to
|
||||
/// serialize the [value] itself.
|
||||
void write(E value, void writeValue(E value)) {
|
||||
void write(E value, void Function(E value) writeValue) {
|
||||
int index = _cache[value];
|
||||
if (index == null) {
|
||||
index = _cache.length;
|
||||
@@ -180,17 +180,16 @@ class IndexedSink<E> {
|
||||
abstract class AbstractDataSink extends DataSinkMixin implements DataSink {
|
||||
IndexedSink<String> _stringIndex;
|
||||
IndexedSink<Uri> _uriIndex;
|
||||
Map<Type, IndexedSink> _generalCaches = {};
|
||||
final Map<Type, IndexedSink> _generalCaches = {};
|
||||
|
||||
AbstractDataSink() {
|
||||
_stringIndex = new IndexedSink<String>(_writeIntInternal);
|
||||
_uriIndex = new IndexedSink<Uri>(_writeIntInternal);
|
||||
_stringIndex = IndexedSink<String>(_writeIntInternal);
|
||||
_uriIndex = IndexedSink<Uri>(_writeIntInternal);
|
||||
}
|
||||
|
||||
@override
|
||||
void writeCached<E>(E value, void f(E value)) {
|
||||
IndexedSink sink =
|
||||
_generalCaches[E] ??= new IndexedSink<E>(_writeIntInternal);
|
||||
void writeCached<E>(E value, void Function(E value) f) {
|
||||
IndexedSink sink = _generalCaches[E] ??= IndexedSink<E>(_writeIntInternal);
|
||||
sink.write(value, (v) => f(v));
|
||||
}
|
||||
|
||||
@@ -254,7 +253,7 @@ class BinarySink extends AbstractDataSink {
|
||||
BufferedSink _bufferedSink;
|
||||
int _length = 0;
|
||||
|
||||
BinarySink(this.sink) : _bufferedSink = new BufferedSink(sink);
|
||||
BinarySink(this.sink) : _bufferedSink = BufferedSink(sink);
|
||||
|
||||
@override
|
||||
void _writeUriInternal(Uri value) {
|
||||
@@ -290,6 +289,7 @@ class BinarySink extends AbstractDataSink {
|
||||
_writeIntInternal(value.index);
|
||||
}
|
||||
|
||||
@override
|
||||
void close() {
|
||||
_bufferedSink.flushAndDestroy();
|
||||
_bufferedSink = null;
|
||||
@@ -297,6 +297,7 @@ class BinarySink extends AbstractDataSink {
|
||||
}
|
||||
|
||||
/// Returns the number of bytes written to this data sink.
|
||||
@override
|
||||
int get length => _length;
|
||||
}
|
||||
|
||||
@@ -304,15 +305,15 @@ class BinarySink extends AbstractDataSink {
|
||||
// TODO(sigmund): share with the implementation in
|
||||
// package:kernel/binary/ast_to_binary.dart
|
||||
class BufferedSink {
|
||||
static const int SIZE = 100000;
|
||||
static const int SAFE_SIZE = SIZE - 5;
|
||||
static const int SMALL = 10000;
|
||||
static const int _size = 100000;
|
||||
static const int _safeSize = _size - 5;
|
||||
static const int _small = 10000;
|
||||
final Sink<List<int>> _sink;
|
||||
Uint8List _buffer = new Uint8List(SIZE);
|
||||
Uint8List _buffer = Uint8List(_size);
|
||||
int length = 0;
|
||||
int flushedLength = 0;
|
||||
|
||||
Float64List _doubleBuffer = new Float64List(1);
|
||||
final Float64List _doubleBuffer = Float64List(1);
|
||||
Uint8List _doubleBufferUint8;
|
||||
|
||||
int get offset => length + flushedLength;
|
||||
@@ -330,16 +331,16 @@ class BufferedSink {
|
||||
|
||||
void addByte(int byte) {
|
||||
_buffer[length++] = byte;
|
||||
if (length == SIZE) {
|
||||
if (length == _size) {
|
||||
_sink.add(_buffer);
|
||||
_buffer = new Uint8List(SIZE);
|
||||
_buffer = Uint8List(_size);
|
||||
length = 0;
|
||||
flushedLength += SIZE;
|
||||
flushedLength += _size;
|
||||
}
|
||||
}
|
||||
|
||||
void addByte2(int byte1, int byte2) {
|
||||
if (length < SAFE_SIZE) {
|
||||
if (length < _safeSize) {
|
||||
_buffer[length++] = byte1;
|
||||
_buffer[length++] = byte2;
|
||||
} else {
|
||||
@@ -349,7 +350,7 @@ class BufferedSink {
|
||||
}
|
||||
|
||||
void addByte4(int byte1, int byte2, int byte3, int byte4) {
|
||||
if (length < SAFE_SIZE) {
|
||||
if (length < _safeSize) {
|
||||
_buffer[length++] = byte1;
|
||||
_buffer[length++] = byte2;
|
||||
_buffer[length++] = byte3;
|
||||
@@ -365,22 +366,22 @@ class BufferedSink {
|
||||
void addBytes(List<int> bytes) {
|
||||
// Avoid copying a large buffer into the another large buffer. Also, if
|
||||
// the bytes buffer is too large to fit in our own buffer, just emit both.
|
||||
if (length + bytes.length < SIZE &&
|
||||
(bytes.length < SMALL || length < SMALL)) {
|
||||
if (length + bytes.length < _size &&
|
||||
(bytes.length < _small || length < _small)) {
|
||||
_buffer.setRange(length, length + bytes.length, bytes);
|
||||
length += bytes.length;
|
||||
} else if (bytes.length < SMALL) {
|
||||
} else if (bytes.length < _small) {
|
||||
// Flush as much as we can in the current buffer.
|
||||
_buffer.setRange(length, SIZE, bytes);
|
||||
_buffer.setRange(length, _size, bytes);
|
||||
_sink.add(_buffer);
|
||||
// Copy over the remainder into a new buffer. It is guaranteed to fit
|
||||
// because the input byte array is small.
|
||||
int alreadyEmitted = SIZE - length;
|
||||
int alreadyEmitted = _size - length;
|
||||
int remainder = bytes.length - alreadyEmitted;
|
||||
_buffer = new Uint8List(SIZE);
|
||||
_buffer = Uint8List(_size);
|
||||
_buffer.setRange(0, remainder, bytes, alreadyEmitted);
|
||||
length = remainder;
|
||||
flushedLength += SIZE;
|
||||
flushedLength += _size;
|
||||
} else {
|
||||
flush();
|
||||
_sink.add(bytes);
|
||||
@@ -390,7 +391,7 @@ class BufferedSink {
|
||||
|
||||
void flush() {
|
||||
_sink.add(_buffer.sublist(0, length));
|
||||
_buffer = new Uint8List(SIZE);
|
||||
_buffer = Uint8List(_size);
|
||||
flushedLength += length;
|
||||
length = 0;
|
||||
}
|
||||
|
||||
@@ -2,29 +2,29 @@
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'dart:typed_data';
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
/// Interface for deserialization.
|
||||
// TODO(sigmund): share this with pkg:compiler/src/serialization/*
|
||||
abstract class DataSource {
|
||||
/// Reads a reference to an [E] value from this data source. If the value has
|
||||
/// not yet been deserialized, [f] is called to deserialize the value itself.
|
||||
E readCached<E>(E f());
|
||||
E readCached<E>(E Function() f);
|
||||
|
||||
/// Reads a potentially `null` [E] value from this data source, calling [f] to
|
||||
/// read the non-null value from the data source.
|
||||
///
|
||||
/// This is a convenience method to be used together with
|
||||
/// [DataSink.writeValueOrNull].
|
||||
E readValueOrNull<E>(E f());
|
||||
E readValueOrNull<E>(E Function() f);
|
||||
|
||||
/// Reads a list of [E] values from this data source. If [emptyAsNull] is
|
||||
/// `true`, `null` is returned instead of an empty list.
|
||||
///
|
||||
/// This is a convenience method to be used together with
|
||||
/// [DataSink.writeList].
|
||||
List<E> readList<E>(E f(), {bool emptyAsNull: false});
|
||||
List<E> readList<E>(E Function() f, {bool emptyAsNull = false});
|
||||
|
||||
/// Reads a boolean value from this data source.
|
||||
bool readBool();
|
||||
@@ -53,7 +53,7 @@ abstract class DataSource {
|
||||
///
|
||||
/// This is a convenience method to be used together with
|
||||
/// [DataSink.writeStrings].
|
||||
List<String> readStrings({bool emptyAsNull: false});
|
||||
List<String> readStrings({bool emptyAsNull = false});
|
||||
|
||||
/// Reads a map from string values to [V] values from this data source,
|
||||
/// calling [f] to read each value from the data source. If [emptyAsNull] is
|
||||
@@ -61,7 +61,7 @@ abstract class DataSource {
|
||||
///
|
||||
/// This is a convenience method to be used together with
|
||||
/// [DataSink.writeStringMap].
|
||||
Map<String, V> readStringMap<V>(V f(), {bool emptyAsNull: false});
|
||||
Map<String, V> readStringMap<V>(V Function() f, {bool emptyAsNull = false});
|
||||
|
||||
/// Reads an enum value from the list of enum [values] from this data source.
|
||||
///
|
||||
@@ -81,7 +81,7 @@ abstract class DataSource {
|
||||
/// Mixin that implements all convenience methods of [DataSource].
|
||||
abstract class DataSourceMixin implements DataSource {
|
||||
@override
|
||||
E readValueOrNull<E>(E f()) {
|
||||
E readValueOrNull<E>(E Function() f) {
|
||||
bool hasValue = readBool();
|
||||
if (hasValue) {
|
||||
return f();
|
||||
@@ -90,14 +90,10 @@ abstract class DataSourceMixin implements DataSource {
|
||||
}
|
||||
|
||||
@override
|
||||
List<E> readList<E>(E f(), {bool emptyAsNull: false}) {
|
||||
List<E> readList<E>(E Function() f, {bool emptyAsNull = false}) {
|
||||
int count = readInt();
|
||||
if (count == 0 && emptyAsNull) return null;
|
||||
List<E> list = new List<E>(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
list[i] = f();
|
||||
}
|
||||
return list;
|
||||
return List.generate(count, (i) => f());
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -119,18 +115,14 @@ abstract class DataSourceMixin implements DataSource {
|
||||
}
|
||||
|
||||
@override
|
||||
List<String> readStrings({bool emptyAsNull: false}) {
|
||||
List<String> readStrings({bool emptyAsNull = false}) {
|
||||
int count = readInt();
|
||||
if (count == 0 && emptyAsNull) return null;
|
||||
List<String> list = new List<String>(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
list[i] = readString();
|
||||
}
|
||||
return list;
|
||||
return List.generate(count, (index) => readString());
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, V> readStringMap<V>(V f(), {bool emptyAsNull: false}) {
|
||||
Map<String, V> readStringMap<V>(V Function() f, {bool emptyAsNull = false}) {
|
||||
int count = readInt();
|
||||
if (count == 0 && emptyAsNull) return null;
|
||||
Map<String, V> map = {};
|
||||
@@ -147,7 +139,7 @@ abstract class DataSourceMixin implements DataSource {
|
||||
class IndexedSource<E> {
|
||||
final int Function() _readInt;
|
||||
final List<E> _cache = [];
|
||||
final Set<int> _pending = new Set();
|
||||
final Set<int> _pending = {};
|
||||
|
||||
IndexedSource(this._readInt);
|
||||
|
||||
@@ -155,7 +147,7 @@ class IndexedSource<E> {
|
||||
///
|
||||
/// If the value hasn't yet been read, [readValue] is called to deserialize
|
||||
/// the value itself.
|
||||
E read(E readValue()) {
|
||||
E read(E Function() readValue) {
|
||||
int index = _readInt();
|
||||
if (_pending.contains(index)) throw "serialization cycles not supported";
|
||||
if (index >= _cache.length) {
|
||||
@@ -177,17 +169,17 @@ abstract class AbstractDataSource extends DataSourceMixin
|
||||
implements DataSource {
|
||||
IndexedSource<String> _stringIndex;
|
||||
IndexedSource<Uri> _uriIndex;
|
||||
Map<Type, IndexedSource> _generalCaches = {};
|
||||
final Map<Type, IndexedSource> _generalCaches = {};
|
||||
|
||||
AbstractDataSource() {
|
||||
_stringIndex = new IndexedSource<String>(_readIntInternal);
|
||||
_uriIndex = new IndexedSource<Uri>(_readIntInternal);
|
||||
_stringIndex = IndexedSource<String>(_readIntInternal);
|
||||
_uriIndex = IndexedSource<Uri>(_readIntInternal);
|
||||
}
|
||||
|
||||
@override
|
||||
E readCached<E>(E f()) {
|
||||
E readCached<E>(E Function() f) {
|
||||
IndexedSource source =
|
||||
_generalCaches[E] ??= new IndexedSource<E>(_readIntInternal);
|
||||
_generalCaches[E] ??= IndexedSource<E>(_readIntInternal);
|
||||
return source.read(f);
|
||||
}
|
||||
|
||||
@@ -254,7 +246,7 @@ class BinarySource extends AbstractDataSource {
|
||||
@override
|
||||
String _readStringInternal() {
|
||||
int length = _readIntInternal();
|
||||
List<int> bytes = new Uint8List(length);
|
||||
List<int> bytes = Uint8List(length);
|
||||
bytes.setRange(0, bytes.length, _bytes, _byteOffset);
|
||||
_byteOffset += bytes.length;
|
||||
return utf8.decode(bytes);
|
||||
|
||||
@@ -29,12 +29,12 @@ class DeferredStatusDiff extends Diff {
|
||||
}
|
||||
|
||||
List<Diff> diff(AllInfo oldInfo, AllInfo newInfo) {
|
||||
var differ = new _InfoDiffer(oldInfo, newInfo);
|
||||
var differ = _InfoDiffer(oldInfo, newInfo);
|
||||
differ.diff();
|
||||
return differ.diffs;
|
||||
}
|
||||
|
||||
class _InfoDiffer extends InfoVisitor<Null> {
|
||||
class _InfoDiffer extends InfoVisitor<void> {
|
||||
final AllInfo _old;
|
||||
final AllInfo _new;
|
||||
|
||||
@@ -50,23 +50,23 @@ class _InfoDiffer extends InfoVisitor<Null> {
|
||||
|
||||
@override
|
||||
visitAll(AllInfo info) {
|
||||
throw new StateError('should not diff AllInfo');
|
||||
throw StateError('should not diff AllInfo');
|
||||
}
|
||||
|
||||
@override
|
||||
visitProgram(ProgramInfo info) {
|
||||
throw new StateError('should not diff ProgramInfo');
|
||||
throw StateError('should not diff ProgramInfo');
|
||||
}
|
||||
|
||||
@override
|
||||
visitOutput(OutputUnitInfo info) {
|
||||
throw new StateError('should not diff OutputUnitInfo');
|
||||
throw StateError('should not diff OutputUnitInfo');
|
||||
}
|
||||
|
||||
// TODO(het): diff constants
|
||||
@override
|
||||
visitConstant(ConstantInfo info) {
|
||||
throw new StateError('should not diff ConstantInfo');
|
||||
throw StateError('should not diff ConstantInfo');
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -127,7 +127,7 @@ class _InfoDiffer extends InfoVisitor<Null> {
|
||||
|
||||
void _checkSize(BasicInfo info, BasicInfo other) {
|
||||
if (info.size != other.size) {
|
||||
diffs.add(new SizeDiff(info, other.size - info.size));
|
||||
diffs.add(SizeDiff(info, other.size - info.size));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ class _InfoDiffer extends InfoVisitor<Null> {
|
||||
var oldIsDeferred = _isDeferred(oldInfo);
|
||||
var newIsDeferred = _isDeferred(newInfo);
|
||||
if (oldIsDeferred != newIsDeferred) {
|
||||
diffs.add(new DeferredStatusDiff(oldInfo, oldIsDeferred));
|
||||
diffs.add(DeferredStatusDiff(oldInfo, oldIsDeferred));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ class _InfoDiffer extends InfoVisitor<Null> {
|
||||
}
|
||||
for (var oldName in oldNames.keys) {
|
||||
if (newNames[oldName] == null) {
|
||||
diffs.add(new RemoveDiff(oldNames[oldName]));
|
||||
diffs.add(RemoveDiff(oldNames[oldName]));
|
||||
} else {
|
||||
_other = newNames[oldName];
|
||||
oldNames[oldName].accept(this);
|
||||
@@ -165,7 +165,7 @@ class _InfoDiffer extends InfoVisitor<Null> {
|
||||
}
|
||||
for (var newName in newNames.keys) {
|
||||
if (oldNames[newName] == null) {
|
||||
diffs.add(new AddDiff(newNames[newName]));
|
||||
diffs.add(AddDiff(newNames[newName]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,13 +25,13 @@ abstract class Graph<N> {
|
||||
/// of nodes. The nodes in each strongly connected components only have edges
|
||||
/// that point to nodes in the same component or earlier components.
|
||||
List<List<N>> computeTopologicalSort() {
|
||||
_SccFinder<N> finder = new _SccFinder<N>(this);
|
||||
_SccFinder<N> finder = _SccFinder<N>(this);
|
||||
return finder.computeTopologicalSort();
|
||||
}
|
||||
|
||||
/// Whether [source] can transitively reach [target].
|
||||
bool containsPath(N source, N target) {
|
||||
Set<N> seen = new Set<N>();
|
||||
Set<N> seen = <N>{};
|
||||
bool helper(N node) {
|
||||
if (identical(node, target)) return true;
|
||||
if (!seen.add(node)) return false;
|
||||
@@ -43,7 +43,7 @@ abstract class Graph<N> {
|
||||
|
||||
/// Returns all nodes reachable from [root] in post order.
|
||||
Iterable<N> postOrder(N root) sync* {
|
||||
var seen = new Set<N>();
|
||||
var seen = <N>{};
|
||||
Iterable<N> helper(N n) sync* {
|
||||
if (!seen.add(n)) return;
|
||||
for (var x in targetsOf(n)) {
|
||||
@@ -57,7 +57,7 @@ abstract class Graph<N> {
|
||||
|
||||
/// Returns an iterable of all nodes reachable from [root] in preorder.
|
||||
Iterable<N> preOrder(N root) sync* {
|
||||
var seen = new Set<N>();
|
||||
var seen = <N>{};
|
||||
var stack = <N>[root];
|
||||
while (stack.isNotEmpty) {
|
||||
var next = stack.removeLast();
|
||||
@@ -74,7 +74,7 @@ abstract class Graph<N> {
|
||||
/// the node itself will be returned.
|
||||
List<N> findCycleContaining(N node) {
|
||||
assert(node != null);
|
||||
_SccFinder<N> finder = new _SccFinder<N>(this);
|
||||
_SccFinder<N> finder = _SccFinder<N>(this);
|
||||
return finder._componentContaining(node);
|
||||
}
|
||||
|
||||
@@ -103,8 +103,8 @@ abstract class Graph<N> {
|
||||
/// Internally we compute dominators using (Cooper, Harvey, and Kennedy's
|
||||
/// algorithm)[http://www.cs.rice.edu/~keith/EMBED/dom.pdf].
|
||||
Graph<N> dominatorTree(N root) {
|
||||
var iDom = (new _DominatorFinder(this)..run(root)).immediateDominators;
|
||||
var graph = new EdgeListGraph<N>();
|
||||
var iDom = (_DominatorFinder(this)..run(root)).immediateDominators;
|
||||
var graph = EdgeListGraph<N>();
|
||||
for (N node in iDom.keys) {
|
||||
if (node != root) graph.addEdge(iDom[node], node);
|
||||
}
|
||||
@@ -114,18 +114,23 @@ abstract class Graph<N> {
|
||||
|
||||
class EdgeListGraph<N> extends Graph<N> {
|
||||
/// Edges in the graph.
|
||||
Map<N, Set<N>> _edges = new Map<N, Set<N>>();
|
||||
final Map<N, Set<N>> _edges = <N, Set<N>>{};
|
||||
|
||||
/// The reverse of _edges.
|
||||
Map<N, Set<N>> _revEdges = new Map<N, Set<N>>();
|
||||
final Map<N, Set<N>> _revEdges = <N, Set<N>>{};
|
||||
|
||||
@override
|
||||
Iterable<N> get nodes => _edges.keys;
|
||||
@override
|
||||
bool get isEmpty => _edges.isEmpty;
|
||||
@override
|
||||
int get nodeCount => _edges.length;
|
||||
|
||||
final _empty = new Set<N>();
|
||||
final _empty = <N>{};
|
||||
|
||||
@override
|
||||
Iterable<N> targetsOf(N source) => _edges[source] ?? _empty;
|
||||
@override
|
||||
Iterable<N> sourcesOf(N source) => _revEdges[source] ?? _empty;
|
||||
|
||||
void addEdge(N source, N target) {
|
||||
@@ -139,8 +144,8 @@ class EdgeListGraph<N> extends Graph<N> {
|
||||
|
||||
void addNode(N node) {
|
||||
assert(node != null);
|
||||
_edges.putIfAbsent(node, () => new Set<N>());
|
||||
_revEdges.putIfAbsent(node, () => new Set<N>());
|
||||
_edges.putIfAbsent(node, () => <N>{});
|
||||
_revEdges.putIfAbsent(node, () => <N>{});
|
||||
}
|
||||
|
||||
/// Remove the edge from the given [source] node to the given [target] node.
|
||||
@@ -200,15 +205,15 @@ class _SccFinder<N> {
|
||||
int _index = 0;
|
||||
|
||||
/// Nodes that are being visited in order to identify components.
|
||||
List<N> _stack = new List<N>();
|
||||
final List<N> _stack = <N>[];
|
||||
|
||||
/// Information associated with each node.
|
||||
Map<N, _NodeInfo<N>> _info = <N, _NodeInfo<N>>{};
|
||||
final Map<N, _NodeInfo<N>> _info = <N, _NodeInfo<N>>{};
|
||||
|
||||
/// All strongly connected components found, in topological sort order (each
|
||||
/// node in a strongly connected component only has edges that point to nodes
|
||||
/// in the same component or earlier components).
|
||||
List<List<N>> _allComponents = new List<List<N>>();
|
||||
final List<List<N>> _allComponents = <List<N>>[];
|
||||
|
||||
_SccFinder(this._graph);
|
||||
|
||||
@@ -246,7 +251,7 @@ class _SccFinder<N> {
|
||||
/// component.
|
||||
_NodeInfo<N> _strongConnect(N v) {
|
||||
// Set the depth index for v to the smallest unused index
|
||||
var vInfo = new _NodeInfo<N>(_index++);
|
||||
var vInfo = _NodeInfo<N>(_index++);
|
||||
_info[v] = vInfo;
|
||||
_push(v);
|
||||
|
||||
@@ -264,7 +269,7 @@ class _SccFinder<N> {
|
||||
|
||||
// If v is a root node, pop the stack and generate an SCC
|
||||
if (vInfo.lowlink == vInfo.index) {
|
||||
var component = new List<N>();
|
||||
var component = <N>[];
|
||||
N w;
|
||||
do {
|
||||
w = _pop();
|
||||
|
||||
@@ -6,9 +6,9 @@ import 'package:dart2js_info/json_info_codec.dart';
|
||||
import 'package:dart2js_info/binary_serialization.dart' as binary;
|
||||
|
||||
Future<AllInfo> infoFromFile(String fileName) async {
|
||||
var file = new File(fileName);
|
||||
var file = File(fileName);
|
||||
if (fileName.endsWith('.json')) {
|
||||
return new AllInfoJsonCodec().decode(jsonDecode(await file.readAsString()));
|
||||
return AllInfoJsonCodec().decode(jsonDecode(await file.readAsString()));
|
||||
} else {
|
||||
return binary.decode(file.readAsBytesSync());
|
||||
}
|
||||
|
||||
@@ -18,12 +18,12 @@ class StringEditBuffer {
|
||||
|
||||
StringEditBuffer(this.original);
|
||||
|
||||
bool get hasEdits => _edits.length > 0;
|
||||
bool get hasEdits => _edits.isNotEmpty;
|
||||
|
||||
/// Edit the original text, replacing text on the range [begin] and
|
||||
/// exclusive [end] with the [replacement] string.
|
||||
void replace(int begin, int end, String replacement, [int sortId]) {
|
||||
_edits.add(new _StringEdit(begin, end, replacement, sortId));
|
||||
_edits.add(_StringEdit(begin, end, replacement, sortId));
|
||||
}
|
||||
|
||||
/// Insert [string] at [offset].
|
||||
@@ -43,9 +43,10 @@ class StringEditBuffer {
|
||||
///
|
||||
/// Throws [UnsupportedError] if the edits were overlapping. If no edits were
|
||||
/// made, the original string will be returned.
|
||||
@override
|
||||
String toString() {
|
||||
var sb = new StringBuffer();
|
||||
if (_edits.length == 0) return original;
|
||||
var sb = StringBuffer();
|
||||
if (_edits.isEmpty) return original;
|
||||
|
||||
// Sort edits by start location.
|
||||
_edits.sort();
|
||||
@@ -53,7 +54,7 @@ class StringEditBuffer {
|
||||
int consumed = 0;
|
||||
for (var edit in _edits) {
|
||||
if (consumed > edit.begin) {
|
||||
sb = new StringBuffer();
|
||||
sb = StringBuffer();
|
||||
sb.write('overlapping edits. Insert at offset ');
|
||||
sb.write(edit.begin);
|
||||
sb.write(' but have consumed ');
|
||||
@@ -63,7 +64,7 @@ class StringEditBuffer {
|
||||
sb.write('\n ');
|
||||
sb.write(e);
|
||||
}
|
||||
throw new UnsupportedError(sb.toString());
|
||||
throw UnsupportedError(sb.toString());
|
||||
}
|
||||
|
||||
// Add characters from the original string between this edit and the last
|
||||
@@ -94,14 +95,15 @@ class _StringEdit implements Comparable<_StringEdit> {
|
||||
// String to insert
|
||||
final String string;
|
||||
|
||||
_StringEdit(int begin, this.end, this.string, [int sortId])
|
||||
: begin = begin,
|
||||
sortId = sortId == null ? begin : sortId;
|
||||
_StringEdit(this.begin, this.end, this.string, [int sortId])
|
||||
: sortId = sortId ?? begin;
|
||||
|
||||
int get length => end - begin;
|
||||
|
||||
@override
|
||||
String toString() => '(Edit @ $begin,$end: "$string")';
|
||||
|
||||
@override
|
||||
int compareTo(_StringEdit other) {
|
||||
int diff = begin - other.begin;
|
||||
if (diff != 0) return diff;
|
||||
|
||||
@@ -28,7 +28,7 @@ class Table {
|
||||
List<List> rows = [];
|
||||
|
||||
/// Columns to skip, for example, if they are all zero entries.
|
||||
List<bool> _skipped = <bool>[];
|
||||
final List<bool> _skipped = <bool>[];
|
||||
|
||||
/// Whether we started adding entries. Indicates that no more columns can be
|
||||
/// added.
|
||||
@@ -39,14 +39,16 @@ class Table {
|
||||
|
||||
/// Add a column with the given [name].
|
||||
void declareColumn(String name,
|
||||
{bool abbreviate: false, String color: _NO_COLOR}) {
|
||||
{bool abbreviate = false, String color = _noColor}) {
|
||||
assert(!_sealed);
|
||||
var headerName = name;
|
||||
if (abbreviate) {
|
||||
// abbreviate the header by using only the initials of each word
|
||||
headerName =
|
||||
name.split(' ').map((s) => s.substring(0, 1).toUpperCase()).join('');
|
||||
while (abbreviations[headerName] != null) headerName = "$headerName'";
|
||||
while (abbreviations[headerName] != null) {
|
||||
headerName = "$headerName'";
|
||||
}
|
||||
abbreviations[headerName] = name;
|
||||
}
|
||||
widths.add(max(5, headerName.length + 1));
|
||||
@@ -94,11 +96,12 @@ class Table {
|
||||
|
||||
/// Generates a string representation of the table to print on a terminal.
|
||||
// TODO(sigmund): add also a .csv format
|
||||
@override
|
||||
String toString() {
|
||||
var sb = new StringBuffer();
|
||||
var sb = StringBuffer();
|
||||
sb.write('\n');
|
||||
for (var row in rows) {
|
||||
var lastColor = _NO_COLOR;
|
||||
var lastColor = _noColor;
|
||||
for (int i = 0; i < _totalColumns; i++) {
|
||||
if (_skipped[i]) continue;
|
||||
var entry = row[i];
|
||||
@@ -111,7 +114,7 @@ class Table {
|
||||
sb.write(
|
||||
i == 0 ? entry.padRight(widths[i]) : entry.padLeft(widths[i] + 1));
|
||||
}
|
||||
if (lastColor != _NO_COLOR) sb.write(_NO_COLOR);
|
||||
if (lastColor != _noColor) sb.write(_noColor);
|
||||
sb.write('\n');
|
||||
}
|
||||
sb.write('\nWhere:\n');
|
||||
@@ -123,4 +126,4 @@ class Table {
|
||||
}
|
||||
}
|
||||
|
||||
const _NO_COLOR = "\x1b[0m";
|
||||
const _noColor = "\x1b[0m";
|
||||
|
||||
@@ -18,7 +18,7 @@ Graph<Info> graphFromInfo(AllInfo info) {
|
||||
// of them.
|
||||
// TODO(sigmund): create a concrete implementation of InfoGraph, instead of
|
||||
// using the EdgeListGraph.
|
||||
var graph = new EdgeListGraph<Info>();
|
||||
var graph = EdgeListGraph<Info>();
|
||||
for (var f in info.functions) {
|
||||
graph.addNode(f);
|
||||
for (var g in f.uses) {
|
||||
@@ -48,13 +48,13 @@ Graph<Info> graphFromInfo(AllInfo info) {
|
||||
|
||||
/// Provide a unique long name associated with [info].
|
||||
// TODO(sigmund): guarantee that the name is actually unique.
|
||||
String longName(Info info, {bool useLibraryUri: false, bool forId: false}) {
|
||||
String longName(Info info, {bool useLibraryUri = false, bool forId = false}) {
|
||||
var infoPath = [];
|
||||
while (info != null) {
|
||||
infoPath.add(info);
|
||||
info = info.parent;
|
||||
}
|
||||
var sb = new StringBuffer();
|
||||
var sb = StringBuffer();
|
||||
var first = true;
|
||||
for (var segment in infoPath.reversed) {
|
||||
if (!first) sb.write('.');
|
||||
@@ -91,7 +91,7 @@ String longName(Info info, {bool useLibraryUri: false, bool forId: false}) {
|
||||
}
|
||||
|
||||
/// Produce a string containing [value] padded with white space up to [n] chars.
|
||||
pad(value, n, {bool right: false}) {
|
||||
pad(value, n, {bool right = false}) {
|
||||
var s = '$value';
|
||||
if (s.length >= n) return s;
|
||||
var pad = ' ' * (n - s.length);
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
name: dart2js_info
|
||||
version: 0.6.5
|
||||
publish_to: none
|
||||
|
||||
description: >-
|
||||
Libraries and tools to process data produced when running dart2js with
|
||||
--dump-info.
|
||||
homepage: https://github.com/dart-lang/dart2js_info/
|
||||
|
||||
environment:
|
||||
sdk: '>=2.3.0 <3.0.0'
|
||||
sdk: '>=2.11.99 <3.0.0'
|
||||
|
||||
dependencies:
|
||||
args: ^1.4.3
|
||||
args: ^2.3.0
|
||||
collection: ^1.10.1
|
||||
fixnum: '>=0.10.5 <2.0.0'
|
||||
path: ^1.3.6
|
||||
protobuf: '>=1.0.1 <3.0.0'
|
||||
shelf: ^0.7.3
|
||||
yaml: ^2.1.0
|
||||
shelf: ^1.2.0
|
||||
yaml: ^3.1.0
|
||||
|
||||
dev_dependencies:
|
||||
lints: ^1.0.0
|
||||
test: ^1.2.0
|
||||
|
||||
executables:
|
||||
|
||||
@@ -12,15 +12,17 @@ import 'package:test/test.dart';
|
||||
class ByteSink implements Sink<List<int>> {
|
||||
BytesBuilder builder = BytesBuilder();
|
||||
|
||||
@override
|
||||
add(List<int> data) => builder.add(data);
|
||||
@override
|
||||
close() {}
|
||||
}
|
||||
|
||||
main() {
|
||||
group('json to proto conversion with deferred files', () {
|
||||
test('hello_world_deferred', () {
|
||||
var uri = Platform.script.resolve(
|
||||
'hello_world_deferred/hello_world_deferred.js.info.json');
|
||||
var uri = Platform.script
|
||||
.resolve('hello_world_deferred/hello_world_deferred.js.info.json');
|
||||
var helloWorld = File.fromUri(uri);
|
||||
var contents = helloWorld.readAsStringSync();
|
||||
var json = jsonDecode(contents);
|
||||
|
||||
@@ -60,7 +60,7 @@ main() {
|
||||
/// C
|
||||
/// ```
|
||||
Graph<String> makeTestGraph() {
|
||||
var graph = new EdgeListGraph<String>();
|
||||
var graph = EdgeListGraph<String>();
|
||||
graph.addEdge('A', 'B');
|
||||
graph.addEdge('A', 'D');
|
||||
graph.addEdge('A', 'E');
|
||||
|
||||
@@ -12,8 +12,8 @@ import 'package:test/test.dart';
|
||||
main() {
|
||||
group('json to proto conversion with deferred files', () {
|
||||
test('hello_world_deferred', () {
|
||||
var uri = Platform.script.resolve(
|
||||
'hello_world_deferred/hello_world_deferred.js.info.json');
|
||||
var uri = Platform.script
|
||||
.resolve('hello_world_deferred/hello_world_deferred.js.info.json');
|
||||
final helloWorld = File.fromUri(uri);
|
||||
final json = jsonDecode(helloWorld.readAsStringSync());
|
||||
final decoded = AllInfoJsonCodec().decode(json);
|
||||
|
||||
@@ -13,8 +13,7 @@ import 'package:test/test.dart';
|
||||
main() {
|
||||
group('json to proto conversion', () {
|
||||
test('hello_world', () {
|
||||
var uri = Platform.script.resolve(
|
||||
'hello_world/hello_world.js.info.json');
|
||||
var uri = Platform.script.resolve('hello_world/hello_world.js.info.json');
|
||||
final helloWorld = File.fromUri(uri);
|
||||
final json = jsonDecode(helloWorld.readAsStringSync());
|
||||
final decoded = AllInfoJsonCodec().decode(json);
|
||||
@@ -33,8 +32,7 @@ main() {
|
||||
});
|
||||
|
||||
test('has proper id format', () {
|
||||
var uri = Platform.script.resolve(
|
||||
'hello_world/hello_world.js.info.json');
|
||||
var uri = Platform.script.resolve('hello_world/hello_world.js.info.json');
|
||||
final helloWorld = File.fromUri(uri);
|
||||
final json = jsonDecode(helloWorld.readAsStringSync());
|
||||
final decoded = AllInfoJsonCodec().decode(json);
|
||||
@@ -54,8 +52,8 @@ main() {
|
||||
expect(
|
||||
value.serializedId, startsWith(expectedPrefixes[InfoKind.clazz]));
|
||||
} else if (value.hasClassTypeInfo()) {
|
||||
expect(
|
||||
value.serializedId, startsWith(expectedPrefixes[InfoKind.classType]));
|
||||
expect(value.serializedId,
|
||||
startsWith(expectedPrefixes[InfoKind.classType]));
|
||||
} else if (value.hasFunctionInfo()) {
|
||||
expect(value.serializedId,
|
||||
startsWith(expectedPrefixes[InfoKind.function]));
|
||||
|
||||
@@ -11,8 +11,7 @@ import 'package:test/test.dart';
|
||||
main() {
|
||||
group('parse', () {
|
||||
test('hello_world', () {
|
||||
var uri =
|
||||
Platform.script.resolve('hello_world/hello_world.js.info.json');
|
||||
var uri = Platform.script.resolve('hello_world/hello_world.js.info.json');
|
||||
var helloWorld = File.fromUri(uri);
|
||||
var json = jsonDecode(helloWorld.readAsStringSync());
|
||||
var decoded = AllInfoJsonCodec().decode(json);
|
||||
@@ -24,9 +23,9 @@ main() {
|
||||
expect(program.size, 94182);
|
||||
expect(program.compilationMoment,
|
||||
DateTime.parse("2021-09-27 15:32:00.380236"));
|
||||
expect(program.compilationDuration, new Duration(microseconds: 2848001));
|
||||
expect(program.toJsonDuration, new Duration(milliseconds: 3));
|
||||
expect(program.dumpInfoDuration, new Duration(seconds: 0));
|
||||
expect(program.compilationDuration, Duration(microseconds: 2848001));
|
||||
expect(program.toJsonDuration, Duration(milliseconds: 3));
|
||||
expect(program.dumpInfoDuration, Duration(seconds: 0));
|
||||
expect(program.noSuchMethodEnabled, false);
|
||||
expect(program.minified, false);
|
||||
});
|
||||
|
||||
@@ -3247,6 +3247,15 @@
|
||||
"pkg/dartdev"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "analyze pkg/dart2js_info",
|
||||
"script": "out/ReleaseX64/dart-sdk/bin/dart",
|
||||
"arguments": [
|
||||
"analyze",
|
||||
"--fatal-infos",
|
||||
"pkg/dart2js_info"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "analyze pkg/dart2js_tools",
|
||||
"script": "out/ReleaseX64/dart-sdk/bin/dart",
|
||||
|
||||
Reference in New Issue
Block a user