Chromium Code Reviews| 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 |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..addaff824fb5c2ba13d7f909f404c4ccff8135b9 |
| --- /dev/null |
| +++ b/pkg/compiler/lib/src/info/info.dart |
| @@ -0,0 +1,399 @@ |
| +// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| +// for details. All rights reserved. Use of this source code is governed by a |
| +// BSD-style license that can be found in the LICENSE file. |
| + |
| +/// Data collected by the dump-info task. |
| +library compiler.src.lib.info; |
| + |
| +// Note: this file intentionally doesn't import anything from the compiler. That |
| +// should make it easier for tools to depend on this library. The idea is that |
| +// by using this library, tools can consume the information in the same way it |
| +// is produced by the compiler. |
| +// TODO(sigmund): make this a proper public API (export this explicitly at the |
| +// lib folder level.) |
| + |
| +/// Common interface to many pieces of information generated by the compiler. |
| +abstract class Info { |
| + /// An identifier for the kind of information. |
| + String get kind; |
| + |
| + /// An unique id used to create references to this info. |
| + int get id; |
| + |
| + /// Serializes the information into a JSON format. |
| + Map toJson(); |
| +} |
| + |
| +/// Common information used for most kind of elements. |
| +// TODO(sigmund): add more: |
| +// - inputSize: bytes used in the Dart source program |
| +// - transitiveSize: bytes including the size of dependencies that are only |
| +// retained because of this element. |
| +class BasicInfo implements Info { |
| + final String kind; |
| + final int id; |
| + |
| + /// Bytes used in the generated code for the corresponding element. |
| + int size; |
| + |
| + String get serializedId => '$kind/$id'; |
| + |
| + // TODO(sigmund): make final (currently not final because we amend the name in |
|
Johnni Winther
2015/07/27 10:14:42
'name in of' -> 'name of'
Siggi Cherem (dart-lang)
2015/07/27 20:10:59
Done.
|
| + // of nested closures to record their enclosing element). |
| + String name; |
| + |
| + /// If using deferred libraries, where the element associated with this info |
| + /// is generated. |
| + final OutputUnitInfo outputUnit; |
| + |
| + BasicInfo(this.kind, this.id, this.name, this.outputUnit, [this.size = 0]); |
| + |
| + Map toJson() { |
| + var res = {'id': serializedId, 'kind': 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; |
| + return res; |
| + } |
| +} |
| + |
| +/// The entire information produced while compiling a program. |
| +class AllInfo { |
| + /// Summary information about the program. |
| + ProgramInfo program; |
| + |
| + /// Information about each library processed by the compiler. |
| + List<LibraryInfo> libraries = []; |
| + |
| + /// Information about each function (includes methods and getters in any |
| + /// library) |
| + List<FunctionInfo> functions = []; |
| + |
| + /// Information about type defs in the program. |
| + List<TypedefInfo> typedefs = []; |
| + |
| + /// Information about each class (in any library). |
| + List<ClassInfo> classes = []; |
| + |
| + /// Information about fields (in any class). |
| + List<FieldInfo> fields = []; |
| + |
| + /// Information about output units (should be just one entry if not using |
| + /// deferred loading). |
| + List<OutputUnitInfo> outputUnits = []; |
| + |
| + /// Details about all deferred imports and what files would be loaded when the |
| + /// import is resolved. |
| + // TODO(sigmund): use a different format for dump-info. This currently emits |
| + // the same map that is created for the `--deferred-map` flag. |
| + Map<String, Map<String, dynamic>> deferredFiles; |
| + |
| + /// Major version indicating breaking changes in the format. A new version |
| + /// means that an old deserialization algorithm will not work with the new |
| + /// format. |
| + final int version = 3; |
| + |
| + /// Minor version indicating non-breaking changes in the format. A change in |
| + /// this version number means that the json parsing in this library from a |
| + /// previous will continue to work after the change. This is typically |
| + /// increased when adding new entries to the file format. |
| + // Note: the dump-info.viewer app was written using a json parser version 3.2. |
| + final int minorVersion = 3; |
| + |
| + AllInfo(); |
| + |
| + factory AllInfo.fromJson(Map map) { |
| + // TODO(sigmund): implement |
| + throw UnimplementedError('deserialization of dump-info not implemented'); |
| + } |
| + |
| + Map _listAsJsonMap(List<Info> list) { |
| + var map = <String, Map>{}; |
| + for (var info in list) { |
| + map['${info.id}'] = info.toJson(); |
| + } |
| + return map; |
| + } |
| + |
| + Map _extractHoldingInfo() { |
| + var map = <String, List>{}; |
| + for (var f in functions) { |
| + if (f.uses.isEmpty) continue; |
| + map[f.serializedId] = f.uses.map((u) => u.toJson()).toList(); |
| + } |
| + return map; |
| + } |
| + |
| + Map toJson() => { |
| + 'elements': { |
|
Siggi Cherem (dart-lang)
2015/07/24 01:07:58
seems wasteful that this is indented so much by th
|
| + 'library': _listAsJsonMap(libraries), |
| + 'class': _listAsJsonMap(classes), |
| + 'function': _listAsJsonMap(functions), |
| + 'typedef': _listAsJsonMap(typedefs), |
| + 'field': _listAsJsonMap(fields), |
| + }, |
| + 'holding': _extractHoldingInfo(), |
| + 'outputUnits': outputUnits.map((u) => u.toJson()).toList(), |
| + 'dump_version': version, |
| + 'deferredFiles': deferredFiles, |
| + 'dump_minor_version': '$minorVersion', |
| + // TODO(sigmund): change viewer to accept an int? |
| + 'program': program.toJson(), |
| + }; |
| +} |
| + |
| +class ProgramInfo { |
| + int size; |
| + String dart2jsVersion; |
| + DateTime compilationMoment; |
| + Duration compilationDuration; |
| + // TODO(sigmund): use Duration. |
| + int toJsonDuration; |
| + int dumpInfoDuration; |
| + bool noSuchMethodEnabled; |
| + bool minified; |
| + |
| + ProgramInfo( |
| + {this.size, |
| + this.dart2jsVersion, |
| + this.compilationMoment, |
| + this.compilationDuration, |
| + this.toJsonDuration, |
| + this.dumpInfoDuration, |
| + this.noSuchMethodEnabled, |
| + this.minified}); |
| + |
| + Map toJson() => { |
| + 'size': size, |
| + 'dart2jsVersion': dart2jsVersion, |
| + 'compilationMoment': '$compilationMoment', |
| + 'compilationDuration': '${compilationDuration}', |
| + 'toJsonDuration': toJsonDuration, |
| + 'dumpInfoDuration': '$dumpInfoDuration', |
| + 'noSuchMethodEnabled': noSuchMethodEnabled, |
| + 'minified': minified, |
| + }; |
| +} |
| + |
| +class LibraryInfo extends BasicInfo { |
| + final Uri uri; |
| + final List<FunctionInfo> topLevelFunctions = []; |
| + final List<FieldInfo> topLevelVariables = []; |
| + final List<ClassInfo> classes = []; |
| + |
| + static int _id = 0; |
| + |
| + bool get isEmpty => |
| + topLevelFunctions.isEmpty && topLevelVariables.isEmpty && classes.isEmpty; |
| + |
| + LibraryInfo(String name, this.uri, OutputUnitInfo outputUnit, int size) |
| + : super('library', _id++, name, outputUnit, size); |
| + |
| + Map toJson() => super.toJson() |
| + ..addAll({ |
| + 'children': [] |
| + ..addAll(topLevelFunctions.map((f) => f.serializedId)) |
| + ..addAll(topLevelVariables.map((v) => v.serializedId)) |
| + ..addAll(classes.map((c) => c.serializedId)), |
| + 'canonicalUri': '$uri', |
| + }); |
| +} |
| + |
| +class OutputUnitInfo extends BasicInfo { |
| + static int _ids = 0; |
| + OutputUnitInfo(String name, int size) |
| + : super('outputUnit', _ids++, name, null, size); |
| +} |
| + |
| +class ClassInfo extends BasicInfo { |
| + final bool isAbstract; |
| + |
| + // TODO(sigmund): split static vs instance vs closures |
| + final List<FunctionInfo> functions = []; |
| + final List<FieldInfo> fields = []; |
| + static int _ids = 0; |
| + |
| + ClassInfo( |
| + {String name, this.isAbstract, OutputUnitInfo outputUnit, int size: 0}) |
| + : super('class', _ids++, name, outputUnit, size); |
| + |
| + Map toJson() => super.toJson() |
| + ..addAll({ |
| + // TODO(sigmund): change format, include only when abstract is true. |
| + 'modifiers': {'abstract': isAbstract}, |
| + 'children': [] |
| + ..addAll(fields.map((f) => f.serializedId)) |
| + ..addAll(functions.map((m) => m.serializedId)) |
| + }); |
| +} |
| + |
| +class FieldInfo extends BasicInfo { |
| + String type; |
| + String inferredType; |
| + List<FunctionInfo> closures; |
| + String code; |
| + |
| + static int _ids = 0; |
| + FieldInfo( |
| + {String name, |
| + int size, |
| + this.type, |
| + this.inferredType, |
| + this.closures, |
| + this.code, |
| + OutputUnitInfo outputUnit}) |
| + : super('field', _ids++, name, outputUnit, size); |
| + |
| + Map toJson() => super.toJson() |
| + ..addAll({ |
| + 'children': closures.map((i) => i.serializedId).toList(), |
| + 'inferredType': inferredType, |
| + 'code': code, |
| + 'type': type, |
| + }); |
| +} |
| + |
| +class TypedefInfo extends BasicInfo { |
| + String type; |
| + |
| + static int _ids = 0; |
| + TypedefInfo(String name, this.type, OutputUnitInfo outputUnit) |
| + : super('typedef', _ids++, name, outputUnit); |
| + |
| + Map toJson() => super.toJson()..['type'] = '$type'; |
| +} |
| + |
| +class FunctionInfo extends BasicInfo { |
| + static const int TOP_LEVEL_FUNCTION_KIND = 0; |
| + static const int CLOSURE_FUNCTION_KIND = 1; |
| + static const int METHOD_FUNCTION_KIND = 2; |
| + static const int CONSTRUCTOR_FUNCTION_KIND = 3; |
| + static int _ids = 0; |
| + |
| + /// Kind of function (top-level function, closure, method, or constructor). |
| + final int functionKind; |
| + |
| + /// Modifiers applied to this function. |
| + final FunctionModifiers modifiers; |
| + |
| + /// Nested closures that appear within the body of this function. |
| + List<FunctionInfo> closures; |
| + |
| + /// The type of this function. |
| + String type; |
| + |
| + /// The declared return type. |
| + String returnType; |
| + |
| + /// The inferred return type. |
| + String inferredReturnType; |
| + |
| + /// Name and type information for each parameter. |
| + List<ParameterInfo> parameters; |
| + |
| + /// Side-effects. |
| + // TODO(sigmund): serialize more precisely, not just a string representation. |
| + String sideEffects; |
| + |
| + /// How many function calls were inlined into this function. |
| + int inlinedCount; |
| + |
| + /// The actual generated code. |
| + String code; |
| + |
| + /// How does this function depend on other functions or fields. |
| + List<DependencyInfo> uses = []; |
|
karlklose
2015/07/24 07:08:22
Please add type arguments to literals (several pla
Siggi Cherem (dart-lang)
2015/07/27 20:10:59
Done. We should chat more about this long term - i
|
| + |
| + FunctionInfo( |
| + {String name, |
| + OutputUnitInfo outputUnit, |
| + int size, |
| + this.functionKind, |
| + this.modifiers, |
| + this.closures, |
| + this.type, |
| + this.returnType, |
| + this.inferredReturnType, |
| + this.parameters, |
| + this.sideEffects, |
| + this.inlinedCount, |
| + this.code}) |
| + : super('function', _ids++, name, outputUnit, size); |
| + |
| + Map toJson() => super.toJson() |
| + ..addAll({ |
| + 'children': closures.map((i) => i.serializedId).toList(), |
| + 'modifiers': modifiers.toJson(), |
| + 'returnType': returnType, |
| + 'inferredReturnType': inferredReturnType, |
| + 'parameters': parameters.map((p) => p.toJson()).toList(), |
| + 'sideEffects': sideEffects, |
| + 'inlinedCount': inlinedCount, |
| + 'code': code, |
| + 'type': type, |
| + // Note: version 3.2 of dump-info serializes `uses` in a section called |
| + // `holding` at the top-level. |
| + }); |
| +} |
| + |
| +/// Information about how a dependency is used. |
| +class DependencyInfo { |
| + /// The dependency, either a FunctionInfo or FieldInfo. |
| + final Info target; |
| + |
| + /// Either a selector mask indicating how this is used, or 'inlined'. |
| + final String mask; |
|
karlklose
2015/07/24 07:08:22
Preferably we would have an enum that describes ex
Siggi Cherem (dart-lang)
2015/07/27 20:10:58
good point. I added a TODO for now. I'm thinking t
|
| + |
| + DependencyInfo(this.target, this.mask); |
| + |
| + Map toJson() => {'id': target.serializedId, 'mask': mask}; |
| +} |
| + |
| +/// Name and type information about a function parameter. |
| +class ParameterInfo { |
| + final String name; |
| + final String type; |
| + final String declaredType; |
| + |
| + ParameterInfo(this.name, this.type, this.declaredType); |
| + |
| + Map toJson() => {'name': name, 'type': type, 'declaredType': declaredType}; |
| +} |
| + |
| +/// Modifiers that may apply to methods. |
| +class FunctionModifiers { |
| + final bool isStatic; |
| + final bool isConst; |
| + final bool isFactory; |
| + final bool isExternal; |
| + |
| + FunctionModifiers( |
| + {this.isStatic: false, |
| + this.isConst: false, |
| + this.isFactory: false, |
| + this.isExternal: false}); |
| + |
| + factory FunctionModifiers.fromJson(Map<String, bool> json) { |
| + return new FunctionModifiers( |
| + isStatic: json['static'] == true, |
| + isConst: json['const'] == true, |
| + isFactory: json['factory'] == true, |
| + isExternal: json['external'] == true); |
| + } |
| + |
| + // TODO(sigmund): exclude false values (requires bumping the format version): |
| + // Map toJson() { |
| + // var res = <String, bool>{}; |
| + // if (isStatic) res['static'] = true; |
| + // if (isConst) res['const'] = true; |
| + // if (isFactory) res['factory'] = true; |
| + // if (isExternal) res['external'] = true; |
| + // return res; |
| + // } |
| + Map toJson() => { |
| + 'static': isStatic, |
| + 'const': isConst, |
| + 'factory': isFactory, |
| + 'external': isExternal, |
| + }; |
| +} |