Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2312)

Unified Diff: pkg/compiler/lib/src/info/info.dart

Issue 1285743002: dart2js: add visitors and parsing support to infos (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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);
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698