mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
[dart2js] separate main and deferred units in programInfo tree structures
Change-Id: Ia1a6ba772fa6384ef23ab5d814a0228c7d5613bc Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/252870 Commit-Queue: Islina Shan <islinashan@google.com> Reviewed-by: Mark Zhou <markzipan@google.com>
This commit is contained in:
parent
7ed2d68b59
commit
abd6e8eba7
|
@ -1,13 +1,13 @@
|
||||||
|
library dart2js_info.bin.to_devtools_format;
|
||||||
|
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
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/info.dart';
|
||||||
import 'package:dart2js_info/src/io.dart';
|
import 'package:dart2js_info/src/io.dart';
|
||||||
import 'package:dart2js_info/src/util.dart';
|
import 'package:dart2js_info/src/util.dart' show longName, libraryGroupName;
|
||||||
import 'package:vm_snapshot_analysis/program_info.dart' as vm;
|
import 'package:vm_snapshot_analysis/program_info.dart' as vm;
|
||||||
import 'package:vm_snapshot_analysis/treemap.dart';
|
|
||||||
|
|
||||||
import 'usage_exception.dart';
|
import 'usage_exception.dart';
|
||||||
|
|
||||||
/// Command that converts a `--dump-info` JSON output into a format ingested by Devtools.
|
/// Command that converts a `--dump-info` JSON output into a format ingested by Devtools.
|
||||||
|
@ -39,12 +39,12 @@ class DevtoolsFormatCommand extends Command<void> with PrintUsageException {
|
||||||
final AllInfo allInfo = await infoFromFile(args.rest.first);
|
final AllInfo allInfo = await infoFromFile(args.rest.first);
|
||||||
final builder = ProgramInfoBuilder(allInfo);
|
final builder = ProgramInfoBuilder(allInfo);
|
||||||
vm.ProgramInfo programInfo = builder.build(allInfo);
|
vm.ProgramInfo programInfo = builder.build(allInfo);
|
||||||
Map<String, dynamic> treeMap = treemapFromInfo(programInfo);
|
Map<String, dynamic> programInfoTree = programInfo.toJson();
|
||||||
var treeMapJson = jsonEncode(treeMap);
|
// TODO: convert the programInfo tree to a treemap
|
||||||
if (outputPath == null) {
|
if (outputPath == null) {
|
||||||
print(treeMapJson);
|
print(jsonEncode(programInfoTree));
|
||||||
} else {
|
} else {
|
||||||
await File(outputPath).writeAsString(treeMapJson);
|
await File(outputPath).writeAsString(jsonEncode(programInfoTree));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,17 +61,34 @@ class ProgramInfoBuilder extends VMProgramInfoVisitor<vm.ProgramInfoNode> {
|
||||||
|
|
||||||
final List<vm.ProgramInfoNode> outputInfo = [];
|
final List<vm.ProgramInfoNode> outputInfo = [];
|
||||||
|
|
||||||
|
/// Mapping between the filename of the outputUnit and the [vm.ProgramInfo]
|
||||||
|
/// subtree representing a program unit (main or deferred).
|
||||||
|
final Map<String, vm.ProgramInfo> outputUnits = {};
|
||||||
|
|
||||||
|
/// Mapping between the name of the library [vm.ProgramInfoNode]
|
||||||
|
/// object and its corresponding outputUnit [vm.ProgramInfo] tree.
|
||||||
|
final Map<String, vm.ProgramInfo> libraryUnits = {};
|
||||||
|
|
||||||
|
/// Mapping between the name of an [Info] object and the corresponding
|
||||||
|
/// [vm.ProgramInfoNode] object.
|
||||||
|
///
|
||||||
|
/// For packages and libraries, since their children can be split among
|
||||||
|
/// different outputUnits, a composite name is used instead to differentiate
|
||||||
|
/// between [vm.ProgramInfoNode] in different outputUnits.
|
||||||
|
final Map<String, vm.ProgramInfoNode> infoNodesByName = {};
|
||||||
|
|
||||||
|
/// A unique key composed of the name of an [Info] object and the
|
||||||
|
/// filename of the outputUnit.
|
||||||
|
String compositeName(String name, String outputUnitName) =>
|
||||||
|
"$name/$outputUnitName";
|
||||||
|
|
||||||
/// Mapping between the name of a [Info] object and the corresponding
|
/// Mapping between the name of a [Info] object and the corresponding
|
||||||
/// [vm.ProgramInfoNode] object.
|
/// [vm.ProgramInfoNode] object.
|
||||||
Map<String, vm.ProgramInfoNode> infoNodesByName = {};
|
|
||||||
|
|
||||||
/// Mapping between the id (aka coverageId) of an [AllInfo] node and the
|
|
||||||
/// corresponding [vm.ProgramInfoNode] object.
|
|
||||||
final Map<String, vm.ProgramInfoNode> infoNodesById = {};
|
final Map<String, vm.ProgramInfoNode> infoNodesById = {};
|
||||||
|
|
||||||
/// Mapping between package names and the corresponding [vm.ProgramInfoNode]
|
/// Mapping between the composite name of a package and the corresponding
|
||||||
/// objects of [vm.NodeType.packageNode].
|
/// [vm.ProgramInfoNode] objects of [vm.NodeType.packageNode].
|
||||||
final Map<String, vm.ProgramInfoNode> packageInfoNodes = {};
|
final Map<String, dynamic> packageInfoNodes = {};
|
||||||
|
|
||||||
/// Mapping between an <unnamed> [LibraryInfo] object and the name of the
|
/// Mapping between an <unnamed> [LibraryInfo] object and the name of the
|
||||||
/// corresponding [vm.ProgramInfoNode] object.
|
/// corresponding [vm.ProgramInfoNode] object.
|
||||||
|
@ -79,33 +96,289 @@ class ProgramInfoBuilder extends VMProgramInfoVisitor<vm.ProgramInfoNode> {
|
||||||
|
|
||||||
ProgramInfoBuilder(this.info);
|
ProgramInfoBuilder(this.info);
|
||||||
|
|
||||||
|
/// Collect libraries into packages and aggregate their sizes.
|
||||||
|
void makePackage(LibraryInfo libraryInfo, String outputUnitName) {
|
||||||
|
vm.ProgramInfo outputUnit = outputUnits[outputUnitName]!;
|
||||||
|
String libraryName = libraryInfo.name;
|
||||||
|
if (libraryInfo.name == '<unnamed>') {
|
||||||
|
libraryName = longName(libraryInfo, useLibraryUri: true, forId: true);
|
||||||
|
}
|
||||||
|
String packageName = libraryGroupName(libraryInfo) ?? libraryName;
|
||||||
|
vm.ProgramInfoNode? packageInfoNode = packageInfoNodes[packageName];
|
||||||
|
if (packageInfoNode == null) {
|
||||||
|
String compositePackageName = compositeName(packageName, outputUnitName);
|
||||||
|
vm.ProgramInfoNode newPackage = outputUnit.makeNode(
|
||||||
|
name: compositePackageName,
|
||||||
|
parent: outputUnit.root,
|
||||||
|
type: vm.NodeType.packageNode);
|
||||||
|
newPackage.size = libraryInfo.size;
|
||||||
|
packageInfoNodes[compositePackageName] = newPackage;
|
||||||
|
outputUnit.root.children[compositePackageName] = newPackage;
|
||||||
|
outputInfo.add(newPackage);
|
||||||
|
var packageNode = infoNodesByName[compositePackageName];
|
||||||
|
assert(packageNode == null,
|
||||||
|
"encountered package with duplicated name: $compositePackageName");
|
||||||
|
infoNodesByName[compositePackageName] = newPackage;
|
||||||
|
} else {
|
||||||
|
packageInfoNode.size = (packageInfoNode.size ?? 0) + libraryInfo.size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void makeLibrary(LibraryInfo libraryInfo, String outputUnitName) {
|
||||||
|
vm.ProgramInfo outputUnit = outputUnits[outputUnitName]!;
|
||||||
|
String libraryName = libraryInfo.name;
|
||||||
|
if (libraryName == '<unnamed>') {
|
||||||
|
libraryName = longName(libraryInfo, useLibraryUri: true, forId: true);
|
||||||
|
unnamedLibraries[libraryInfo] = libraryName;
|
||||||
|
}
|
||||||
|
String packageName = libraryGroupName(libraryInfo) ?? libraryName;
|
||||||
|
String compositePackageName = compositeName(packageName, outputUnitName);
|
||||||
|
vm.ProgramInfoNode parentNode = infoNodesByName[compositePackageName]!;
|
||||||
|
String compositeLibraryName = compositeName(libraryName, outputUnitName);
|
||||||
|
vm.ProgramInfoNode newLibrary = outputUnit.makeNode(
|
||||||
|
name: compositeLibraryName,
|
||||||
|
parent: parentNode,
|
||||||
|
type: vm.NodeType.libraryNode);
|
||||||
|
newLibrary.size = libraryInfo.size;
|
||||||
|
parentNode.children[newLibrary.name] = newLibrary;
|
||||||
|
vm.ProgramInfoNode? libraryNode = infoNodesByName[compositeLibraryName];
|
||||||
|
assert(libraryNode == null,
|
||||||
|
"encountered library with duplicated name: $compositeLibraryName");
|
||||||
|
infoNodesByName[compositeLibraryName] = newLibrary;
|
||||||
|
outputInfo.add(newLibrary);
|
||||||
|
}
|
||||||
|
|
||||||
|
void makeFunction(FunctionInfo functionInfo) {
|
||||||
|
Info? parent = functionInfo.parent;
|
||||||
|
String outputUnitName = functionInfo.outputUnit!.filename;
|
||||||
|
vm.ProgramInfo? outputUnit = outputUnits[outputUnitName];
|
||||||
|
if (parent != null && outputUnit != null) {
|
||||||
|
assert(parent.kind == kindFromString('library'));
|
||||||
|
vm.ProgramInfoNode parentNode;
|
||||||
|
if (parent.kind == kindFromString('library')) {
|
||||||
|
if (parent.name == "<unnamed>") {
|
||||||
|
var tempName =
|
||||||
|
compositeName(unnamedLibraries[parent]!, outputUnitName);
|
||||||
|
parentNode = infoNodesByName[tempName]!;
|
||||||
|
} else {
|
||||||
|
parentNode =
|
||||||
|
infoNodesByName[compositeName(parent.name, outputUnitName)]!;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
parentNode = infoNodesByName[parent.name]!;
|
||||||
|
}
|
||||||
|
vm.ProgramInfoNode newFunction = outputUnit.makeNode(
|
||||||
|
name: functionInfo.name,
|
||||||
|
parent: parentNode,
|
||||||
|
type: vm.NodeType.functionNode);
|
||||||
|
newFunction.size = functionInfo.size;
|
||||||
|
parentNode.children[newFunction.name] = newFunction;
|
||||||
|
vm.ProgramInfoNode? functionNode = infoNodesByName[newFunction.name];
|
||||||
|
assert(functionNode == null,
|
||||||
|
"encountered function with duplicated name: $newFunction.name");
|
||||||
|
infoNodesByName[newFunction.name] = newFunction;
|
||||||
|
outputInfo.add(newFunction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void makeClass(ClassInfo classInfo) {
|
||||||
|
Info? parent = classInfo.parent;
|
||||||
|
String outputUnitName = classInfo.outputUnit!.filename;
|
||||||
|
vm.ProgramInfo? outputUnit = outputUnits[outputUnitName];
|
||||||
|
if (parent != null && outputUnit != null) {
|
||||||
|
vm.ProgramInfoNode parentNode;
|
||||||
|
if (parent.kind == kindFromString('library')) {
|
||||||
|
if (parent.name == "<unnamed>") {
|
||||||
|
var tempName =
|
||||||
|
compositeName(unnamedLibraries[parent]!, outputUnitName);
|
||||||
|
parentNode = infoNodesByName[tempName]!;
|
||||||
|
} else {
|
||||||
|
parentNode =
|
||||||
|
infoNodesByName[compositeName(parent.name, outputUnitName)]!;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
parentNode = infoNodesByName[parent.name]!;
|
||||||
|
}
|
||||||
|
vm.ProgramInfoNode newClass = outputUnit.makeNode(
|
||||||
|
name: classInfo.name,
|
||||||
|
parent: parentNode,
|
||||||
|
type: vm.NodeType.classNode);
|
||||||
|
newClass.size = classInfo.size;
|
||||||
|
parentNode.children[newClass.name] = newClass;
|
||||||
|
vm.ProgramInfoNode? classNode = infoNodesByName[newClass.name];
|
||||||
|
assert(classNode == null,
|
||||||
|
"encountered class with duplicated name: $newClass.name");
|
||||||
|
infoNodesByName[newClass.name] = newClass;
|
||||||
|
outputInfo.add(newClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fields are currently assigned [vm.NodeType.other].
|
||||||
|
///
|
||||||
|
/// Note: we might want to create a separate [vm.NodeType.fieldNode] to
|
||||||
|
/// differentiate fields from other miscellaneous nodes for constructing
|
||||||
|
/// the call graph.
|
||||||
|
void makeField(FieldInfo fieldInfo) {
|
||||||
|
Info? parent = fieldInfo.parent;
|
||||||
|
String outputUnitName = fieldInfo.outputUnit!.filename;
|
||||||
|
vm.ProgramInfo? outputUnit = outputUnits[outputUnitName];
|
||||||
|
if (parent != null && outputUnit != null) {
|
||||||
|
vm.ProgramInfoNode parentNode;
|
||||||
|
if (parent.kind == kindFromString('library')) {
|
||||||
|
if (parent.name == "<unnamed>") {
|
||||||
|
var tempName =
|
||||||
|
compositeName(unnamedLibraries[parent]!, outputUnitName);
|
||||||
|
parentNode = infoNodesByName[tempName]!;
|
||||||
|
} else {
|
||||||
|
parentNode =
|
||||||
|
infoNodesByName[compositeName(parent.name, outputUnitName)]!;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
parentNode = infoNodesByName[parent.name]!;
|
||||||
|
}
|
||||||
|
vm.ProgramInfoNode newField = outputUnit.makeNode(
|
||||||
|
name: fieldInfo.name, parent: parentNode, type: vm.NodeType.other);
|
||||||
|
newField.size = fieldInfo.size;
|
||||||
|
parentNode.children[newField.name] = newField;
|
||||||
|
vm.ProgramInfoNode? fieldNode = infoNodesByName[newField.name];
|
||||||
|
assert(fieldNode == null,
|
||||||
|
"encountered field with duplicated name: $newField.name");
|
||||||
|
infoNodesByName[newField.name] = newField;
|
||||||
|
outputInfo.add(newField);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void makeConstant(ConstantInfo constantInfo) {
|
||||||
|
String? constantName = constantInfo.code.first.text ??
|
||||||
|
"${constantInfo.code.first.start}/${constantInfo.code.first.end}";
|
||||||
|
String outputUnitName = constantInfo.outputUnit!.filename;
|
||||||
|
vm.ProgramInfo? outputUnit = outputUnits[outputUnitName];
|
||||||
|
vm.ProgramInfoNode newConstant = outputUnit!.makeNode(
|
||||||
|
name: constantName, parent: outputUnit.root, type: vm.NodeType.other);
|
||||||
|
newConstant.size = constantInfo.size;
|
||||||
|
outputUnit.root.children[newConstant.name] = newConstant;
|
||||||
|
vm.ProgramInfoNode? constantNode = infoNodesByName[newConstant.name];
|
||||||
|
assert(constantNode == null,
|
||||||
|
"encountered constant with duplicated name: $newConstant.name");
|
||||||
|
infoNodesByName[newConstant.name] = newConstant;
|
||||||
|
outputInfo.add(newConstant);
|
||||||
|
}
|
||||||
|
|
||||||
|
void makeTypedef(TypedefInfo typedefInfo) {
|
||||||
|
String outputUnitName = typedefInfo.outputUnit!.filename;
|
||||||
|
vm.ProgramInfo? outputUnit = outputUnits[outputUnitName];
|
||||||
|
vm.ProgramInfoNode newTypedef = outputUnit!.makeNode(
|
||||||
|
name: typedefInfo.name,
|
||||||
|
parent: outputUnit.root,
|
||||||
|
type: vm.NodeType.other);
|
||||||
|
newTypedef.size = typedefInfo.size;
|
||||||
|
vm.ProgramInfoNode? typedefNode = infoNodesByName[newTypedef.name];
|
||||||
|
assert(typedefNode == null,
|
||||||
|
"encountered constant with duplicated name: $newTypedef.name");
|
||||||
|
outputInfo.add(newTypedef);
|
||||||
|
}
|
||||||
|
|
||||||
|
void makeClassType(ClassTypeInfo classTypeInfo) {
|
||||||
|
Info? parent = classTypeInfo.parent;
|
||||||
|
String outputUnitName = classTypeInfo.outputUnit!.filename;
|
||||||
|
vm.ProgramInfo? outputUnit = outputUnits[outputUnitName];
|
||||||
|
if (parent != null && outputUnit != null) {
|
||||||
|
assert(parent.kind == kindFromString('library'));
|
||||||
|
vm.ProgramInfoNode parentNode;
|
||||||
|
if (parent.name == "<unnamed>") {
|
||||||
|
var tempName = compositeName(unnamedLibraries[parent]!, outputUnitName);
|
||||||
|
parentNode = infoNodesByName[tempName]!;
|
||||||
|
} else {
|
||||||
|
parentNode =
|
||||||
|
infoNodesByName[compositeName(parent.name, outputUnitName)]!;
|
||||||
|
}
|
||||||
|
vm.ProgramInfoNode newClassType = outputUnit.makeNode(
|
||||||
|
name: classTypeInfo.name,
|
||||||
|
parent: parentNode,
|
||||||
|
type: vm.NodeType.other);
|
||||||
|
newClassType.size = classTypeInfo.size;
|
||||||
|
vm.ProgramInfoNode? classTypeNode = infoNodesByName[newClassType.name];
|
||||||
|
assert(classTypeNode == null,
|
||||||
|
"encountered classType with duplicated name: $newClassType.name");
|
||||||
|
infoNodesByName[newClassType.name] = newClassType;
|
||||||
|
outputInfo.add(newClassType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void makeClosure(ClosureInfo closureInfo) {
|
||||||
|
Info? parent = closureInfo.parent;
|
||||||
|
String outputUnitName = closureInfo.outputUnit!.filename;
|
||||||
|
vm.ProgramInfo? outputUnit = outputUnits[outputUnitName];
|
||||||
|
if (parent != null && outputUnit != null) {
|
||||||
|
vm.ProgramInfoNode parentNode;
|
||||||
|
if (parent.kind == kindFromString('library')) {
|
||||||
|
if (parent.name == "<unnamed>") {
|
||||||
|
var tempName =
|
||||||
|
compositeName(unnamedLibraries[parent]!, outputUnitName);
|
||||||
|
parentNode = infoNodesByName[tempName]!;
|
||||||
|
} else {
|
||||||
|
parentNode =
|
||||||
|
infoNodesByName[compositeName(parent.name, outputUnitName)]!;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
parentNode = infoNodesByName[parent.name]!;
|
||||||
|
}
|
||||||
|
vm.ProgramInfoNode newClosure = outputUnit.makeNode(
|
||||||
|
name: closureInfo.name,
|
||||||
|
parent: parentNode,
|
||||||
|
// ProgramInfo trees consider closures and functions to both be of the functionNode type.
|
||||||
|
type: vm.NodeType.functionNode);
|
||||||
|
newClosure.size = closureInfo.size;
|
||||||
|
parentNode.children[newClosure.name] = newClosure;
|
||||||
|
vm.ProgramInfoNode? closureNode = infoNodesByName[newClosure.name];
|
||||||
|
assert(closureNode == null,
|
||||||
|
"encountered closure with duplicated name: $newClosure.name");
|
||||||
|
infoNodesByName[newClosure.name] = newClosure;
|
||||||
|
outputInfo.add(newClosure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
vm.ProgramInfoNode visitAll(AllInfo info) {
|
vm.ProgramInfoNode visitAll(AllInfo info, String outputUnitName) {
|
||||||
outputInfo.add(program.root);
|
outputInfo.add(outputUnits[outputUnitName]!.root);
|
||||||
info.libraries.forEach(makePackage);
|
visitProgram(info.program!);
|
||||||
info.packages.forEach(visitPackage);
|
for (var package in info.packages) {
|
||||||
info.libraries.forEach(makeLibrary);
|
visitPackage(package, outputUnitName);
|
||||||
info.libraries.forEach(visitLibrary);
|
}
|
||||||
|
for (var library in info.libraries) {
|
||||||
|
visitLibrary(library, outputUnitName);
|
||||||
|
}
|
||||||
info.constants.forEach(makeConstant);
|
info.constants.forEach(makeConstant);
|
||||||
info.constants.forEach(visitConstant);
|
info.constants.forEach(visitConstant);
|
||||||
return program.root;
|
return outputUnits[outputUnitName]!.root;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
vm.ProgramInfoNode visitOutput(OutputUnitInfo info) {
|
||||||
|
vm.ProgramInfo? outputUnit = outputUnits[info.filename];
|
||||||
|
assert(outputUnit == null, "encountered outputUnit with duplicated name");
|
||||||
|
var newUnit = vm.ProgramInfo();
|
||||||
|
outputUnits[info.filename] = newUnit;
|
||||||
|
outputUnits[info.filename]!.root.size = info.size;
|
||||||
|
return outputUnits[info.filename]!.root;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
vm.ProgramInfoNode visitProgram(ProgramInfo info) {
|
vm.ProgramInfoNode visitProgram(ProgramInfo info) {
|
||||||
throw Exception('Not supported for devtools format.');
|
program.root.size = info.size;
|
||||||
|
return program.root;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
vm.ProgramInfoNode visitPackage(PackageInfo info) {
|
vm.ProgramInfoNode visitPackage(PackageInfo info, String outputUnitName) {
|
||||||
info.libraries.forEach(makePackage);
|
for (var library in info.libraries) {
|
||||||
info.libraries.forEach(makeLibrary);
|
visitLibrary(library, outputUnitName);
|
||||||
info.libraries.forEach(visitLibrary);
|
}
|
||||||
return infoNodesByName[info.name]!;
|
return infoNodesByName[compositeName(info.name, outputUnitName)]!;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
vm.ProgramInfoNode visitLibrary(LibraryInfo info) {
|
vm.ProgramInfoNode visitLibrary(LibraryInfo info, String outputUnitName) {
|
||||||
info.topLevelFunctions.forEach(makeFunction);
|
info.topLevelFunctions.forEach(makeFunction);
|
||||||
info.topLevelFunctions.forEach(visitFunction);
|
info.topLevelFunctions.forEach(visitFunction);
|
||||||
info.topLevelVariables.forEach(makeField);
|
info.topLevelVariables.forEach(makeField);
|
||||||
|
@ -116,8 +389,9 @@ class ProgramInfoBuilder extends VMProgramInfoVisitor<vm.ProgramInfoNode> {
|
||||||
info.classTypes.forEach(visitClassType);
|
info.classTypes.forEach(visitClassType);
|
||||||
info.typedefs.forEach(makeTypedef);
|
info.typedefs.forEach(makeTypedef);
|
||||||
info.typedefs.forEach(visitTypedef);
|
info.typedefs.forEach(visitTypedef);
|
||||||
return infoNodesByName[info.name] ??
|
return infoNodesByName[compositeName(info.name, outputUnitName)] ??
|
||||||
infoNodesByName[unnamedLibraries[info]]!;
|
infoNodesByName[
|
||||||
|
compositeName(unnamedLibraries[info]!, outputUnitName)]!;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -157,7 +431,8 @@ class ProgramInfoBuilder extends VMProgramInfoVisitor<vm.ProgramInfoNode> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
vm.ProgramInfoNode visitConstant(ConstantInfo info) {
|
vm.ProgramInfoNode visitConstant(ConstantInfo info) {
|
||||||
return infoNodesByName[info.code.first.text!]!;
|
return infoNodesByName[info.code.first.text] ??
|
||||||
|
infoNodesByName["${info.code.first.start}/${info.code.first.end}"]!;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -165,191 +440,18 @@ class ProgramInfoBuilder extends VMProgramInfoVisitor<vm.ProgramInfoNode> {
|
||||||
return infoNodesByName[info.name]!;
|
return infoNodesByName[info.name]!;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
vm.ProgramInfoNode visitOutput(OutputUnitInfo info) {
|
|
||||||
throw Exception("For deferred loading.");
|
|
||||||
}
|
|
||||||
|
|
||||||
vm.ProgramInfo build(AllInfo info) {
|
vm.ProgramInfo build(AllInfo info) {
|
||||||
visitAll(info);
|
info.outputUnits.forEach(visitOutput);
|
||||||
|
for (var outputUnitName in outputUnits.keys) {
|
||||||
|
for (var library in info.libraries) {
|
||||||
|
makePackage(library, outputUnitName);
|
||||||
|
makeLibrary(library, outputUnitName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var outputUnitName in outputUnits.keys) {
|
||||||
|
visitAll(info, outputUnitName);
|
||||||
|
program.root.children[outputUnitName] = outputUnits[outputUnitName]!.root;
|
||||||
|
}
|
||||||
return program;
|
return program;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Collect libraries into packages and aggregate their sizes.
|
|
||||||
void makePackage(LibraryInfo libraryInfo) {
|
|
||||||
String packageName = libraryGroupName(libraryInfo) ?? libraryInfo.name;
|
|
||||||
vm.ProgramInfoNode? packageInfoNode = packageInfoNodes[packageName];
|
|
||||||
if (packageInfoNode == null) {
|
|
||||||
vm.ProgramInfoNode newPackage = program.makeNode(
|
|
||||||
name: packageName,
|
|
||||||
parent: program.root,
|
|
||||||
type: vm.NodeType.packageNode);
|
|
||||||
newPackage.size = libraryInfo.size;
|
|
||||||
packageInfoNodes[packageName] = newPackage;
|
|
||||||
program.root.children[packageName] = newPackage;
|
|
||||||
outputInfo.add(newPackage);
|
|
||||||
var packageNode = infoNodesByName[newPackage.name];
|
|
||||||
assert(packageNode == null, "encountered package with duplicated name");
|
|
||||||
infoNodesByName[newPackage.name] = newPackage;
|
|
||||||
} else {
|
|
||||||
packageInfoNode.size = (packageInfoNode.size ?? 0) + libraryInfo.size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void makeLibrary(LibraryInfo libraryInfo) {
|
|
||||||
String packageName = libraryGroupName(libraryInfo) ?? libraryInfo.name;
|
|
||||||
vm.ProgramInfoNode parentNode = infoNodesByName[packageName]!;
|
|
||||||
String libraryName = libraryInfo.name;
|
|
||||||
if (libraryName == '<unnamed>') {
|
|
||||||
libraryName = longName(libraryInfo, useLibraryUri: true, forId: true);
|
|
||||||
unnamedLibraries[libraryInfo] = libraryName;
|
|
||||||
}
|
|
||||||
vm.ProgramInfoNode newLibrary = program.makeNode(
|
|
||||||
name: libraryName, parent: parentNode, type: vm.NodeType.libraryNode);
|
|
||||||
newLibrary.size = libraryInfo.size;
|
|
||||||
parentNode.children[newLibrary.name] = newLibrary;
|
|
||||||
vm.ProgramInfoNode? libraryNode = infoNodesByName[newLibrary.name];
|
|
||||||
assert(libraryNode == null, "encountered library with duplicated name");
|
|
||||||
infoNodesByName[newLibrary.name] = newLibrary;
|
|
||||||
outputInfo.add(newLibrary);
|
|
||||||
}
|
|
||||||
|
|
||||||
void makeFunction(FunctionInfo functionInfo) {
|
|
||||||
Info? parent = functionInfo.parent;
|
|
||||||
if (parent != null) {
|
|
||||||
vm.ProgramInfoNode parentNode;
|
|
||||||
if (parent.name == "<unnamed>" &&
|
|
||||||
parent.kind == kindFromString('library')) {
|
|
||||||
parentNode = infoNodesByName[unnamedLibraries[parent]]!;
|
|
||||||
} else {
|
|
||||||
parentNode = infoNodesByName[parent.name]!;
|
|
||||||
}
|
|
||||||
vm.ProgramInfoNode newFunction = program.makeNode(
|
|
||||||
name: functionInfo.name,
|
|
||||||
parent: parentNode,
|
|
||||||
type: vm.NodeType.functionNode);
|
|
||||||
newFunction.size = functionInfo.size;
|
|
||||||
parentNode.children[newFunction.name] = newFunction;
|
|
||||||
vm.ProgramInfoNode? functionNode = infoNodesByName[newFunction.name];
|
|
||||||
assert(functionNode == null, "encountered function with duplicated name");
|
|
||||||
infoNodesByName[newFunction.name] = newFunction;
|
|
||||||
outputInfo.add(newFunction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void makeClass(ClassInfo classInfo) {
|
|
||||||
Info? parent = classInfo.parent;
|
|
||||||
if (parent != null) {
|
|
||||||
vm.ProgramInfoNode parentNode;
|
|
||||||
if (parent.name == "<unnamed>" &&
|
|
||||||
parent.kind == kindFromString('library')) {
|
|
||||||
parentNode = infoNodesByName[unnamedLibraries[parent]]!;
|
|
||||||
} else {
|
|
||||||
parentNode = infoNodesByName[parent.name]!;
|
|
||||||
}
|
|
||||||
vm.ProgramInfoNode newClass = program.makeNode(
|
|
||||||
name: classInfo.name,
|
|
||||||
parent: parentNode,
|
|
||||||
type: vm.NodeType.classNode);
|
|
||||||
newClass.size = classInfo.size;
|
|
||||||
parentNode.children[newClass.name] = newClass;
|
|
||||||
vm.ProgramInfoNode? classNode = infoNodesByName[newClass.name];
|
|
||||||
assert(classNode == null, "encountered class with duplicated name");
|
|
||||||
infoNodesByName[newClass.name] = newClass;
|
|
||||||
outputInfo.add(newClass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Fields are currently assigned [vm.NodeType.other].
|
|
||||||
///
|
|
||||||
/// Note: we might want to create a separate [vm.NodeType.fieldNode] to
|
|
||||||
/// differentiate fields from other miscellaneous nodes for constructing
|
|
||||||
/// the call graph.
|
|
||||||
void makeField(FieldInfo fieldInfo) {
|
|
||||||
Info? parent = fieldInfo.parent;
|
|
||||||
if (parent != null) {
|
|
||||||
vm.ProgramInfoNode parentNode;
|
|
||||||
if (parent.name == "<unnamed>" &&
|
|
||||||
parent.kind == kindFromString('library')) {
|
|
||||||
parentNode = infoNodesByName[unnamedLibraries[parent]]!;
|
|
||||||
} else {
|
|
||||||
parentNode = infoNodesByName[parent.name]!;
|
|
||||||
}
|
|
||||||
vm.ProgramInfoNode newField = program.makeNode(
|
|
||||||
name: fieldInfo.name, parent: parentNode, type: vm.NodeType.other);
|
|
||||||
newField.size = fieldInfo.size;
|
|
||||||
parentNode.children[newField.name] = newField;
|
|
||||||
vm.ProgramInfoNode? fieldNode = infoNodesByName[newField.name];
|
|
||||||
assert(fieldNode == null, "encountered field with duplicated name");
|
|
||||||
infoNodesByName[newField.name] = newField;
|
|
||||||
outputInfo.add(newField);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void makeConstant(ConstantInfo constantInfo) {
|
|
||||||
String constantName = constantInfo.code.first.text!;
|
|
||||||
vm.ProgramInfoNode newConstant = program.makeNode(
|
|
||||||
name: constantName, parent: program.root, type: vm.NodeType.other);
|
|
||||||
newConstant.size = constantInfo.size;
|
|
||||||
program.root.children[newConstant.name] = newConstant;
|
|
||||||
vm.ProgramInfoNode? constantNode = infoNodesByName[newConstant.name];
|
|
||||||
assert(constantNode == null, "encountered constant with duplicated name");
|
|
||||||
infoNodesByName[newConstant.name] = newConstant;
|
|
||||||
outputInfo.add(newConstant);
|
|
||||||
}
|
|
||||||
|
|
||||||
void makeTypedef(TypedefInfo typedefInfo) {
|
|
||||||
vm.ProgramInfoNode newTypedef = program.makeNode(
|
|
||||||
name: typedefInfo.name, parent: program.root, type: vm.NodeType.other);
|
|
||||||
newTypedef.size = typedefInfo.size;
|
|
||||||
infoNodesByName[newTypedef.name] = newTypedef;
|
|
||||||
outputInfo.add(newTypedef);
|
|
||||||
}
|
|
||||||
|
|
||||||
void makeClassType(ClassTypeInfo classTypeInfo) {
|
|
||||||
Info? parent = classTypeInfo.parent;
|
|
||||||
if (parent != null) {
|
|
||||||
vm.ProgramInfoNode parentNode;
|
|
||||||
if (parent.name == "<unnamed>" &&
|
|
||||||
parent.kind == kindFromString('library')) {
|
|
||||||
parentNode = infoNodesByName[unnamedLibraries[parent]]!;
|
|
||||||
} else {
|
|
||||||
parentNode = infoNodesByName[parent.name]!;
|
|
||||||
}
|
|
||||||
vm.ProgramInfoNode newClassType = program.makeNode(
|
|
||||||
name: classTypeInfo.name,
|
|
||||||
parent: parentNode,
|
|
||||||
type: vm.NodeType.other);
|
|
||||||
newClassType.size = classTypeInfo.size;
|
|
||||||
vm.ProgramInfoNode? classTypeNode = infoNodesByName[newClassType.name];
|
|
||||||
assert(
|
|
||||||
classTypeNode == null, "encountered classType with duplicated name");
|
|
||||||
infoNodesByName[newClassType.name] = newClassType;
|
|
||||||
outputInfo.add(newClassType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void makeClosure(ClosureInfo closureInfo) {
|
|
||||||
Info? parent = closureInfo.parent;
|
|
||||||
if (parent != null) {
|
|
||||||
vm.ProgramInfoNode parentNode;
|
|
||||||
if (parent.name == "<unnamed>" &&
|
|
||||||
parent.kind == kindFromString('library')) {
|
|
||||||
parentNode = infoNodesByName[unnamedLibraries[parent]]!;
|
|
||||||
} else {
|
|
||||||
parentNode = infoNodesByName[parent.name]!;
|
|
||||||
}
|
|
||||||
vm.ProgramInfoNode newClosure = program.makeNode(
|
|
||||||
name: closureInfo.name,
|
|
||||||
parent: parentNode,
|
|
||||||
// ProgramInfo trees consider closures and functions to both be of the functionNode type.
|
|
||||||
type: vm.NodeType.functionNode);
|
|
||||||
newClosure.size = closureInfo.size;
|
|
||||||
parentNode.children[newClosure.name] = newClosure;
|
|
||||||
vm.ProgramInfoNode? closureNode = infoNodesByName[newClosure.name];
|
|
||||||
assert(closureNode == null, "encountered closure with duplicated name");
|
|
||||||
infoNodesByName[newClosure.name] = newClosure;
|
|
||||||
outputInfo.add(newClosure);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -203,14 +203,8 @@ class PackageInfo extends BasicInfo {
|
||||||
: super(InfoKind.package, name, outputUnit, size, null);
|
: super(InfoKind.package, name, outputUnit, size, null);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
T accept<T>(InfoVisitor<T> visitor) {
|
T accept<T>(InfoVisitor<T> visitor) =>
|
||||||
if (visitor is VMProgramInfoVisitor<T>) {
|
throw Exception("PackageInfo is not supported by InfoVisitor.");
|
||||||
return visitor.visitPackage(this);
|
|
||||||
} else {
|
|
||||||
throw ArgumentError(
|
|
||||||
"PackageInfo can only be visited by a VMProgramInfoVisitor");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Info associated with a library element.
|
/// Info associated with a library element.
|
||||||
|
@ -620,8 +614,19 @@ abstract class InfoVisitor<T> {
|
||||||
|
|
||||||
/// A visitor that adds implementation for PackageInfo specifically for building
|
/// A visitor that adds implementation for PackageInfo specifically for building
|
||||||
/// the VM ProgramInfo Tree from a Dart2js info tree.
|
/// the VM ProgramInfo Tree from a Dart2js info tree.
|
||||||
abstract class VMProgramInfoVisitor<T> extends InfoVisitor<T> {
|
abstract class VMProgramInfoVisitor<T> {
|
||||||
T visitPackage(PackageInfo info);
|
T visitAll(AllInfo info, String outputUnit);
|
||||||
|
T visitProgram(ProgramInfo info);
|
||||||
|
T visitPackage(PackageInfo info, String outputUnit);
|
||||||
|
T visitLibrary(LibraryInfo info, String outputUnit);
|
||||||
|
T visitClass(ClassInfo info);
|
||||||
|
T visitClassType(ClassTypeInfo info);
|
||||||
|
T visitField(FieldInfo info);
|
||||||
|
T visitConstant(ConstantInfo info);
|
||||||
|
T visitFunction(FunctionInfo info);
|
||||||
|
T visitTypedef(TypedefInfo info);
|
||||||
|
T visitClosure(ClosureInfo info);
|
||||||
|
T visitOutput(OutputUnitInfo info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A visitor that recursively walks each portion of the program. Because the
|
/// A visitor that recursively walks each portion of the program. Because the
|
||||||
|
@ -642,6 +647,11 @@ class RecursiveInfoVisitor extends InfoVisitor<void> {
|
||||||
@override
|
@override
|
||||||
void visitProgram(ProgramInfo info) {}
|
void visitProgram(ProgramInfo info) {}
|
||||||
|
|
||||||
|
void visitPackage(PackageInfo info) {
|
||||||
|
throw Exception(
|
||||||
|
"PackageInfo objects are only defined for the VM Devtools format.");
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void visitLibrary(LibraryInfo info) {
|
void visitLibrary(LibraryInfo info) {
|
||||||
info.topLevelFunctions.forEach(visitFunction);
|
info.topLevelFunctions.forEach(visitFunction);
|
||||||
|
|
Loading…
Reference in a new issue