| 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..5aa06f2665d707202012ab70c0b58a060ec51e0e
|
| --- /dev/null
|
| +++ b/pkg/compiler/lib/src/info/info.dart
|
| @@ -0,0 +1,405 @@
|
| +// 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;
|
| +
|
| + /// Name of the element associated with this info.
|
| + String name;
|
| +
|
| + /// An id to uniquely identify this info among infos of the same [kind].
|
| + int get id;
|
| +
|
| + /// A globally unique id combining [kind] and [id] together.
|
| + String get serializedId;
|
| +
|
| + /// Bytes used in the generated code for the corresponding element.
|
| + int size;
|
| +
|
| + /// Serializes the information into a JSON format.
|
| + // TODO(sigmund): refactor and put toJson outside the class, so we can have 2
|
| + // different serializer/deserializers at once.
|
| + Map toJson();
|
| +}
|
| +
|
| +/// 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 int id;
|
| + int size;
|
| +
|
| + String get serializedId => '$kind/$id';
|
| +
|
| + String name;
|
| +
|
| + /// If using deferred libraries, where the element associated with this info
|
| + /// is generated.
|
| + OutputUnitInfo outputUnit;
|
| +
|
| + BasicInfo(this.kind, this.id, this.name, this.outputUnit, this.size);
|
| +
|
| + 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;
|
| + }
|
| +
|
| + String toString() => '$serializedId $name [$size]';
|
| +}
|
| +
|
| +/// Info associated with elements containing executable code (like fields and
|
| +/// methods)
|
| +abstract class CodeInfo implements Info {
|
| + /// How does this function or field depend on others.
|
| + final List<DependencyInfo> uses = <DependencyInfo>[];
|
| +}
|
| +
|
| +
|
| +/// 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 = <LibraryInfo>[];
|
| +
|
| + /// Information about each function (includes methods and getters in any
|
| + /// library)
|
| + List<FunctionInfo> functions = <FunctionInfo>[];
|
| +
|
| + /// Information about type defs in the program.
|
| + List<TypedefInfo> typedefs = <TypedefInfo>[];
|
| +
|
| + /// Information about each class (in any library).
|
| + List<ClassInfo> classes = <ClassInfo>[];
|
| +
|
| + /// Information about fields (in any class).
|
| + List<FieldInfo> fields = <FieldInfo>[];
|
| +
|
| + /// Information about output units (should be just one entry if not using
|
| + /// deferred loading).
|
| + List<OutputUnitInfo> outputUnits = <OutputUnitInfo>[];
|
| +
|
| + /// 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();
|
| +
|
| + 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>{};
|
| + void helper(CodeInfo info) {
|
| + if (info.uses.isEmpty) return;
|
| + map[info.serializedId] = info.uses.map((u) => u.toJson()).toList();
|
| + }
|
| + functions.forEach(helper);
|
| + fields.forEach(helper);
|
| + return map;
|
| + }
|
| +
|
| + // TODO(sigmund): implement fromJson
|
| + Map toJson() => {
|
| + 'elements': {
|
| + '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 {
|
| + Uri uri;
|
| + final List<FunctionInfo> topLevelFunctions = <FunctionInfo>[];
|
| + final List<FieldInfo> topLevelVariables = <FieldInfo>[];
|
| + final List<ClassInfo> classes = <ClassInfo>[];
|
| + final List<TypedefInfo> typedefs = <TypedefInfo>[];
|
| +
|
| + 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))
|
| + ..addAll(typedefs.map((t) => t.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 {
|
| + bool isAbstract;
|
| +
|
| + // TODO(sigmund): split static vs instance vs closures
|
| + final List<FunctionInfo> functions = <FunctionInfo>[];
|
| + 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);
|
| +
|
| + 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 with CodeInfo {
|
| + String type;
|
| + String inferredType;
|
| + List<FunctionInfo> closures;
|
| + String code;
|
| +
|
| + static int _ids = 0;
|
| + FieldInfo(
|
| + {String name,
|
| + int size: 0,
|
| + 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, 0);
|
| +
|
| + Map toJson() => super.toJson()..['type'] = '$type';
|
| +}
|
| +
|
| +class FunctionInfo extends BasicInfo with CodeInfo {
|
| + 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;
|
| +
|
| + FunctionInfo(
|
| + {String name,
|
| + OutputUnitInfo outputUnit,
|
| + int size: 0,
|
| + 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'.
|
| + // TODO(sigmund): split mask into an enum or something more precise to really
|
| + // describe the dependencies in detail.
|
| + final String mask;
|
| +
|
| + 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});
|
| +
|
| + // 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,
|
| + };
|
| +}
|
|
|