| Index: pkg/compiler/lib/src/info/info.dart
|
| diff --git a/pkg/compiler/lib/src/info/info.dart b/pkg/compiler/lib/src/info/info.dart
|
| index 5aa06f2665d707202012ab70c0b58a060ec51e0e..941a9454e262240969d5daf941cd1d2c7384524a 100644
|
| --- a/pkg/compiler/lib/src/info/info.dart
|
| +++ b/pkg/compiler/lib/src/info/info.dart
|
| @@ -15,7 +15,7 @@ library compiler.src.lib.info;
|
| /// Common interface to many pieces of information generated by the compiler.
|
| abstract class Info {
|
| /// An identifier for the kind of information.
|
| - String get kind;
|
| + InfoKind get kind;
|
|
|
| /// Name of the element associated with this info.
|
| String name;
|
| @@ -33,17 +33,19 @@ abstract class Info {
|
| // TODO(sigmund): refactor and put toJson outside the class, so we can have 2
|
| // different serializer/deserializers at once.
|
| Map toJson();
|
| +
|
| + void accept(InfoVisitor visitor);
|
| }
|
|
|
| /// Common information used for most kind of elements.
|
| // TODO(sigmund): add more:
|
| // - inputSize: bytes used in the Dart source program
|
| abstract class BasicInfo implements Info {
|
| - final String kind;
|
| + final InfoKind kind;
|
| final int id;
|
| int size;
|
|
|
| - String get serializedId => '$kind/$id';
|
| + String get serializedId => '${_kindToString(kind)}/$id';
|
|
|
| String name;
|
|
|
| @@ -53,8 +55,17 @@ abstract class BasicInfo implements Info {
|
|
|
| BasicInfo(this.kind, this.id, this.name, this.outputUnit, this.size);
|
|
|
| + BasicInfo._fromId(String serializedId)
|
| + : kind = _kindFromSerializedId(serializedId),
|
| + id = _idFromSerializedId(serializedId);
|
| +
|
| Map toJson() {
|
| - var res = {'id': serializedId, 'kind': kind, 'name': name, 'size': size};
|
| + var res = {
|
| + 'id': serializedId,
|
| + 'kind': _kindToString(kind),
|
| + 'name': name,
|
| + 'size': size,
|
| + };
|
| // TODO(sigmund): omit this also when outputUnit.id == 0
|
| // (most code is by default in the main output unit)
|
| if (outputUnit != null) res['outputUnit'] = outputUnit.serializedId;
|
| @@ -117,6 +128,8 @@ class AllInfo {
|
|
|
| AllInfo();
|
|
|
| + static AllInfo parseFromJson(Map map) => new _ParseHelper().parseAll(map);
|
| +
|
| Map _listAsJsonMap(List<Info> list) {
|
| var map = <String, Map>{};
|
| for (var info in list) {
|
| @@ -136,7 +149,6 @@ class AllInfo {
|
| return map;
|
| }
|
|
|
| - // TODO(sigmund): implement fromJson
|
| Map toJson() => {
|
| 'elements': {
|
| 'library': _listAsJsonMap(libraries),
|
| @@ -153,6 +165,8 @@ class AllInfo {
|
| // TODO(sigmund): change viewer to accept an int?
|
| 'program': program.toJson(),
|
| };
|
| +
|
| + void accept(InfoVisitor visitor) => visitor.visitAll(this);
|
| }
|
|
|
| class ProgramInfo {
|
| @@ -186,22 +200,178 @@ class ProgramInfo {
|
| 'noSuchMethodEnabled': noSuchMethodEnabled,
|
| 'minified': minified,
|
| };
|
| +
|
| + void accept(InfoVisitor visitor) => visitor.visitProgram(this);
|
| }
|
|
|
| +// TODO(sigmund): add unit tests.
|
| +class _ParseHelper {
|
| + Map<String, Info> registry = {};
|
| +
|
| + AllInfo parseAll(Map json) {
|
| + var result = new AllInfo();
|
| + var elements = json['elements'];
|
| + result.libraries.addAll(elements['library'].values.map(parseLibrary));
|
| + result.classes.addAll(elements['class'].values.map(parseClass));
|
| + result.functions.addAll(elements['function'].values.map(parseFunction));
|
| + result.fields.addAll(elements['field'].values.map(parseField));
|
| + result.typedefs.addAll(elements['typedef'].values.map(parseTypedef));
|
| +
|
| + var idMap = {};
|
| + for (var f in result.functions) {
|
| + idMap[f.serializedId] = f;
|
| + }
|
| + for (var f in result.fields) {
|
| + idMap[f.serializedId] = f;
|
| + }
|
| +
|
| + json['holding'].forEach((k, deps) {
|
| + var src = idMap[k];
|
| + assert (src != null);
|
| + for (var dep in deps) {
|
| + var target = idMap[dep['id']];
|
| + assert (target != null);
|
| + src.uses.add(new DependencyInfo(target, dep['mask']));
|
| + }
|
| + });
|
| +
|
| + result.program = parseProgram(json['program']);
|
| + // todo: version, etc
|
| + return result;
|
| + }
|
| +
|
| + LibraryInfo parseLibrary(Map json) {
|
| + var result = parseId(json['id'])
|
| + ..name = json['name']
|
| + ..uri = Uri.parse(json['canonicalUri'])
|
| + ..outputUnit = parseId(json['outputUnit'])
|
| + ..size = json['size'];
|
| + assert(result is LibraryInfo);
|
| + for (var child in json['children'].map(parseId)) {
|
| + if (child is FunctionInfo) {
|
| + result.topLevelFunctions.add(child);
|
| + } else if (child is FieldInfo) {
|
| + result.topLevelVariables.add(child);
|
| + } else if (child is ClassInfo) {
|
| + result.classes.add(child);
|
| + } else {
|
| + assert(child is TypedefInfo);
|
| + result.typedefs.add(child);
|
| + }
|
| + }
|
| + return result;
|
| + }
|
| +
|
| + ClassInfo parseClass(Map json) {
|
| + var result = parseId(json['id'])
|
| + ..name = json['name']
|
| + ..outputUnit = parseId(json['outputUnit'])
|
| + ..size = json['size']
|
| + ..isAbstract = json['modifiers']['abstract'] == true;
|
| + assert(result is ClassInfo);
|
| + for (var child in json['children'].map(parseId)) {
|
| + if (child is FunctionInfo) {
|
| + result.functions.add(child);
|
| + } else {
|
| + assert(child is FieldInfo);
|
| + result.fields.add(child);
|
| + }
|
| + }
|
| + return result;
|
| + }
|
| +
|
| + FieldInfo parseField(Map json) {
|
| + return parseId(json['id'])
|
| + ..name = json['name']
|
| + ..outputUnit = parseId(json['outputUnit'])
|
| + ..size = json['size']
|
| + ..type = json['type']
|
| + ..inferredType = json['inferredType']
|
| + ..code = json['code']
|
| + ..closures = json['children'].map(parseId).toList();
|
| + }
|
| +
|
| + TypedefInfo parseTypedef(Map json) => parseId(json['id'])
|
| + ..name = json['name']
|
| + ..type = json['type']
|
| + ..size = 0;
|
| +
|
| + ProgramInfo parseProgram(Map json) =>
|
| + new ProgramInfo()..size = json['size'];
|
| +
|
| + FunctionInfo parseFunction(Map json) {
|
| + return parseId(json['id'])
|
| + ..name = json['name']
|
| + ..outputUnit = parseId(json['outputUnit'])
|
| + ..size = json['size']
|
| + ..type = json['type']
|
| + ..returnType = json['returnType']
|
| + ..inferredReturnType = json['inferredReturnType']
|
| + ..parameters = json['parameters'].map(parseParameter).toList()
|
| + ..code = json['code']
|
| + ..sideEffects = json['sideEffects']
|
| + ..modifiers = parseModifiers(json['modifiers'])
|
| + ..closures = json['children'].map(parseId).toList();
|
| + }
|
| +
|
| + ParameterInfo parseParameter(Map json) =>
|
| + new ParameterInfo(json['name'], json['type'], json['declaredType']);
|
| +
|
| + FunctionModifiers parseModifiers(Map<String, bool> json) {
|
| + return new FunctionModifiers(
|
| + isStatic: json['static'] == true,
|
| + isConst: json['const'] == true,
|
| + isFactory: json['factory'] == true,
|
| + isExternal: json['external'] == true);
|
| + }
|
| +
|
| + Info parseId(String serializedId) => registry.putIfAbsent(serializedId, () {
|
| + if (serializedId == null) {
|
| + return null;
|
| + } else if (serializedId.startsWith('function/')) {
|
| + return new FunctionInfo._(serializedId);
|
| + } else if (serializedId.startsWith('library/')) {
|
| + return new LibraryInfo._(serializedId);
|
| + } else if (serializedId.startsWith('class/')) {
|
| + return new ClassInfo._(serializedId);
|
| + } else if (serializedId.startsWith('field/')) {
|
| + return new FieldInfo._(serializedId);
|
| + } else if (serializedId.startsWith('typedef/')) {
|
| + return new TypedefInfo._(serializedId);
|
| + } else if (serializedId.startsWith('outputUnit/')) {
|
| + return new OutputUnitInfo._(serializedId);
|
| + }
|
| + assert(false);
|
| + });
|
| +}
|
| +
|
| +/// Info associated with a library element.
|
| class LibraryInfo extends BasicInfo {
|
| + /// Canonical uri that identifies the library.
|
| Uri uri;
|
| +
|
| + /// Top level functions defined within the library.
|
| final List<FunctionInfo> topLevelFunctions = <FunctionInfo>[];
|
| +
|
| + /// Top level fields defined within the library.
|
| final List<FieldInfo> topLevelVariables = <FieldInfo>[];
|
| +
|
| + /// Classes defined within the library.
|
| final List<ClassInfo> classes = <ClassInfo>[];
|
| +
|
| + /// Typedefs defined within the library.
|
| final List<TypedefInfo> typedefs = <TypedefInfo>[];
|
|
|
| static int _id = 0;
|
|
|
| + /// Whether there is any information recorded for this library.
|
| bool get isEmpty =>
|
| topLevelFunctions.isEmpty && topLevelVariables.isEmpty && classes.isEmpty;
|
|
|
| LibraryInfo(String name, this.uri, OutputUnitInfo outputUnit, int size)
|
| - : super('library', _id++, name, outputUnit, size);
|
| + : super(InfoKind.library, _id++, name, outputUnit, size);
|
| +
|
| + LibraryInfo._(String serializedId) : super._fromId(serializedId);
|
|
|
| Map toJson() => super.toJson()
|
| ..addAll({
|
| @@ -212,25 +382,43 @@ class LibraryInfo extends BasicInfo {
|
| ..addAll(typedefs.map((t) => t.serializedId)),
|
| 'canonicalUri': '$uri',
|
| });
|
| +
|
| + void accept(InfoVisitor visitor) => visitor.visitLibrary(this);
|
| }
|
|
|
| +/// Information about an output unit. Normally there is just one for the entire
|
| +/// program unless the application uses deferred imports, in which case there
|
| +/// would be an additional output unit per deferred chunk.
|
| class OutputUnitInfo extends BasicInfo {
|
| static int _ids = 0;
|
| OutputUnitInfo(String name, int size)
|
| - : super('outputUnit', _ids++, name, null, size);
|
| + : super(InfoKind.outputUnit, _ids++, name, null, size);
|
| +
|
| + OutputUnitInfo._(String serializedId) : super._fromId(serializedId);
|
| +
|
| + void accept(InfoVisitor visitor) => visitor.visitOutput(this);
|
| }
|
|
|
| +/// Information about a class element.
|
| class ClassInfo extends BasicInfo {
|
| + /// Whether the class is abstract.
|
| bool isAbstract;
|
|
|
| // TODO(sigmund): split static vs instance vs closures
|
| + /// Functions (static or instance) defined in the class.
|
| final List<FunctionInfo> functions = <FunctionInfo>[];
|
| +
|
| + /// Fields defined in the class.
|
| + // TODO(sigmund): currently appears to only be populated with instance fields,
|
| + // but this should be fixed.
|
| final List<FieldInfo> fields = <FieldInfo>[];
|
| static int _ids = 0;
|
|
|
| ClassInfo(
|
| {String name, this.isAbstract, OutputUnitInfo outputUnit, int size: 0})
|
| - : super('class', _ids++, name, outputUnit, size);
|
| + : super(InfoKind.clazz, _ids++, name, outputUnit, size);
|
| +
|
| + ClassInfo._(String serializedId) : super._fromId(serializedId);
|
|
|
| Map toJson() => super.toJson()
|
| ..addAll({
|
| @@ -240,12 +428,22 @@ class ClassInfo extends BasicInfo {
|
| ..addAll(fields.map((f) => f.serializedId))
|
| ..addAll(functions.map((m) => m.serializedId))
|
| });
|
| +
|
| + void accept(InfoVisitor visitor) => visitor.visitClass(this);
|
| }
|
|
|
| +/// Information about a field element.
|
| class FieldInfo extends BasicInfo with CodeInfo {
|
| + /// The type of the field.
|
| String type;
|
| +
|
| + /// The type inferred by dart2js's whole program analysis
|
| String inferredType;
|
| +
|
| + /// Nested closures seen in the field initializer.
|
| List<FunctionInfo> closures;
|
| +
|
| + /// The actual generated code for the field.
|
| String code;
|
|
|
| static int _ids = 0;
|
| @@ -257,7 +455,9 @@ class FieldInfo extends BasicInfo with CodeInfo {
|
| this.closures,
|
| this.code,
|
| OutputUnitInfo outputUnit})
|
| - : super('field', _ids++, name, outputUnit, size);
|
| + : super(InfoKind.field, _ids++, name, outputUnit, size);
|
| +
|
| + FieldInfo._(String serializedId) : super._fromId(serializedId);
|
|
|
| Map toJson() => super.toJson()
|
| ..addAll({
|
| @@ -266,18 +466,27 @@ class FieldInfo extends BasicInfo with CodeInfo {
|
| 'code': code,
|
| 'type': type,
|
| });
|
| +
|
| + void accept(InfoVisitor visitor) => visitor.visitField(this);
|
| }
|
|
|
| +/// Information about a typedef declaration.
|
| class TypedefInfo extends BasicInfo {
|
| + /// The declared type.
|
| String type;
|
|
|
| static int _ids = 0;
|
| TypedefInfo(String name, this.type, OutputUnitInfo outputUnit)
|
| - : super('typedef', _ids++, name, outputUnit, 0);
|
| + : super(InfoKind.typedef, _ids++, name, outputUnit, 0);
|
| +
|
| + TypedefInfo._(String serializedId) : super._fromId(serializedId);
|
|
|
| Map toJson() => super.toJson()..['type'] = '$type';
|
| +
|
| + void accept(InfoVisitor visitor) => visitor.visitTypedef(this);
|
| }
|
|
|
| +/// Information about a function or method.
|
| class FunctionInfo extends BasicInfo with CodeInfo {
|
| static const int TOP_LEVEL_FUNCTION_KIND = 0;
|
| static const int CLOSURE_FUNCTION_KIND = 1;
|
| @@ -286,10 +495,10 @@ class FunctionInfo extends BasicInfo with CodeInfo {
|
| static int _ids = 0;
|
|
|
| /// Kind of function (top-level function, closure, method, or constructor).
|
| - final int functionKind;
|
| + int functionKind;
|
|
|
| /// Modifiers applied to this function.
|
| - final FunctionModifiers modifiers;
|
| + FunctionModifiers modifiers;
|
|
|
| /// Nested closures that appear within the body of this function.
|
| List<FunctionInfo> closures;
|
| @@ -330,7 +539,9 @@ class FunctionInfo extends BasicInfo with CodeInfo {
|
| this.sideEffects,
|
| this.inlinedCount,
|
| this.code})
|
| - : super('function', _ids++, name, outputUnit, size);
|
| + : super(InfoKind.function, _ids++, name, outputUnit, size);
|
| +
|
| + FunctionInfo._(String serializedId) : super._fromId(serializedId);
|
|
|
| Map toJson() => super.toJson()
|
| ..addAll({
|
| @@ -346,6 +557,8 @@ class FunctionInfo extends BasicInfo with CodeInfo {
|
| // Note: version 3.2 of dump-info serializes `uses` in a section called
|
| // `holding` at the top-level.
|
| });
|
| +
|
| + void accept(InfoVisitor visitor) => visitor.visitFunction(this);
|
| }
|
|
|
| /// Information about how a dependency is used.
|
| @@ -403,3 +616,89 @@ class FunctionModifiers {
|
| 'external': isExternal,
|
| };
|
| }
|
| +
|
| +/// Possible values of the `kind` field in the serialied infos.
|
| +enum InfoKind {
|
| + library,
|
| + clazz,
|
| + function,
|
| + field,
|
| + outputUnit,
|
| + typedef,
|
| +}
|
| +
|
| +String _kindToString(InfoKind kind) {
|
| + switch(kind) {
|
| + case InfoKind.library: return 'library';
|
| + case InfoKind.clazz: return 'class';
|
| + case InfoKind.function: return 'function';
|
| + case InfoKind.field: return 'field';
|
| + case InfoKind.outputUnit: return 'outputUnit';
|
| + case InfoKind.typedef: return 'typedef';
|
| + default: return null;
|
| + }
|
| +}
|
| +
|
| +int _idFromSerializedId(String serialiedId) =>
|
| + int.parse(serializedId.substring(serializedId.indexOf('/') + 1));
|
| +
|
| +String _kindFromSerializedId(String serializedId) =>
|
| + _kindFromString(serializedId.substring(0, serializedId.indexOf('/')));
|
| +
|
| +InfoKind _kindFromString(String kind) {
|
| + switch(kind) {
|
| + case 'library': return InfoKind.library;
|
| + case 'class': return InfoKind.clazz;
|
| + case 'function': return InfoKind.function;
|
| + case 'field': return InfoKind.field;
|
| + case 'outputUnit': return InfoKind.outputUnit;
|
| + case 'typedef': return InfoKind.typedef;
|
| + default: return null;
|
| + }
|
| +}
|
| +
|
| +/// A simple visitor for information produced by the dart2js compiler.
|
| +class InfoVisitor {
|
| + visitAll(AllInfo info) {}
|
| + visitProgram(ProgramInfo info) {}
|
| + visitLibrary(LibraryInfo info) {}
|
| + visitClass(ClassInfo info) {}
|
| + visitField(FieldInfo info) {}
|
| + visitFunction(FunctionInfo info) {}
|
| + visitTypedef(TypedefInfo info) {}
|
| + visitOutput(OutputUnitInfo info) {}
|
| +}
|
| +
|
| +/// A visitor that recursively walks each portion of the program. Because the
|
| +/// info representation is redundant, this visitor only walks the structure of
|
| +/// the program and skips some redundant links. For example, even though
|
| +/// 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 {
|
| + visitAll(AllInfo info) {
|
| + // Note: we don't visit functions, fields, classes, and typedefs because
|
| + // they are reachable from the library info.
|
| + info.libraries.forEach(visitLibrary);
|
| + }
|
| +
|
| + visitLibrary(LibraryInfo info) {
|
| + info.topLevelFunctions.forEach(visitFunction);
|
| + info.topLevelVariables.forEach(visitField);
|
| + info.classes.forEach(visitClass);
|
| + info.typedefs.forEach(visitTypedef);
|
| + }
|
| +
|
| + visitClass(ClassInfo info) {
|
| + info.functions.forEach(visitFunction);
|
| + info.fields.forEach(visitField);
|
| + }
|
| +
|
| + visitField(FieldInfo info) {
|
| + info.closures.forEach(visitFunction);
|
| + }
|
| +
|
| + visitFunction(FunctionInfo info) {
|
| + info.closures.forEach(visitFunction);
|
| + }
|
| +}
|
|
|