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

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
« no previous file with comments | « no previous file | tests/compiler/dart2js/analyze_unused_dart2js_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..4100a4baa81db960ae306e6b945a3ff946709be3 100644
--- a/pkg/compiler/lib/src/info/info.dart
+++ b/pkg/compiler/lib/src/info/info.dart
@@ -33,6 +33,8 @@ 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.
@@ -41,6 +43,8 @@ abstract class Info {
abstract class BasicInfo implements Info {
final String kind;
Harry Terkelsen 2015/08/11 01:15:18 consider making kind an enum?
Siggi Cherem (dart-lang) 2015/08/11 16:09:27 It's interesting because I only had in mind to use
Harry Terkelsen 2015/08/11 20:11:55 I've run into the same problem when trying to enum
final int id;
+
+ /// Bytes used in the generated code for the corresponding element.
int size;
String get serializedId => '$kind/$id';
@@ -53,6 +57,10 @@ abstract class BasicInfo implements Info {
BasicInfo(this.kind, this.id, this.name, this.outputUnit, this.size);
+ BasicInfo._fromId(String serializedId)
+ : kind = serializedId.substring(0, serializedId.indexOf('/')),
+ id = int.parse(serializedId.substring(serializedId.indexOf('/') + 1));
+
Map toJson() {
var res = {'id': serializedId, 'kind': kind, 'name': name, 'size': size};
// TODO(sigmund): omit this also when outputUnit.id == 0
@@ -117,6 +125,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 +146,6 @@ class AllInfo {
return map;
}
- // TODO(sigmund): implement fromJson
Map toJson() => {
'elements': {
'library': _listAsJsonMap(libraries),
@@ -153,6 +162,8 @@ class AllInfo {
// TODO(sigmund): change viewer to accept an int?
'program': program.toJson(),
};
+
+ void accept(InfoVisitor visitor) => visitor.visitAll(this);
}
class ProgramInfo {
@@ -186,6 +197,148 @@ class ProgramInfo {
'noSuchMethodEnabled': noSuchMethodEnabled,
'minified': minified,
};
+
+ void accept(InfoVisitor visitor) => visitor.visitProgram(this);
+}
+
+class _ParseHelper {
Johnni Winther 2015/08/11 08:45:37 Do we have a test of the serialization/deserializa
Siggi Cherem (dart-lang) 2015/08/11 16:09:27 Not yet, but we will. Added a TODO
+ 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.kind == 'library');
+ 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.kind == 'class');
+ 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);
+ });
}
class LibraryInfo extends BasicInfo {
@@ -203,6 +356,8 @@ class LibraryInfo extends BasicInfo {
LibraryInfo(String name, this.uri, OutputUnitInfo outputUnit, int size)
: super('library', _id++, name, outputUnit, size);
+ LibraryInfo._(String serializedId) : super._fromId(serializedId);
+
Map toJson() => super.toJson()
..addAll({
'children': []
@@ -212,12 +367,18 @@ class LibraryInfo extends BasicInfo {
..addAll(typedefs.map((t) => t.serializedId)),
'canonicalUri': '$uri',
});
+
+ void accept(InfoVisitor visitor) => visitor.visitLibrary(this);
}
class OutputUnitInfo extends BasicInfo {
static int _ids = 0;
OutputUnitInfo(String name, int size)
: super('outputUnit', _ids++, name, null, size);
+
+ OutputUnitInfo._(String serializedId) : super._fromId(serializedId);
+
+ void accept(InfoVisitor visitor) => visitor.visitOutput(this);
}
class ClassInfo extends BasicInfo {
@@ -232,6 +393,8 @@ class ClassInfo extends BasicInfo {
{String name, this.isAbstract, OutputUnitInfo outputUnit, int size: 0})
: super('class', _ids++, name, outputUnit, size);
+ ClassInfo._(String serializedId) : super._fromId(serializedId);
+
Map toJson() => super.toJson()
..addAll({
// TODO(sigmund): change format, include only when abstract is true.
@@ -240,6 +403,8 @@ class ClassInfo extends BasicInfo {
..addAll(fields.map((f) => f.serializedId))
..addAll(functions.map((m) => m.serializedId))
});
+
+ void accept(InfoVisitor visitor) => visitor.visitClass(this);
}
class FieldInfo extends BasicInfo with CodeInfo {
@@ -259,6 +424,8 @@ class FieldInfo extends BasicInfo with CodeInfo {
OutputUnitInfo outputUnit})
: super('field', _ids++, name, outputUnit, size);
+ FieldInfo._(String serializedId) : super._fromId(serializedId);
+
Map toJson() => super.toJson()
..addAll({
'children': closures.map((i) => i.serializedId).toList(),
@@ -266,6 +433,8 @@ class FieldInfo extends BasicInfo with CodeInfo {
'code': code,
'type': type,
});
+
+ void accept(InfoVisitor visitor) => visitor.visitField(this);
}
class TypedefInfo extends BasicInfo {
@@ -275,7 +444,11 @@ class TypedefInfo extends BasicInfo {
TypedefInfo(String name, this.type, OutputUnitInfo outputUnit)
: super('typedef', _ids++, name, outputUnit, 0);
+ TypedefInfo._(String serializedId) : super._fromId(serializedId);
+
Map toJson() => super.toJson()..['type'] = '$type';
+
+ void accept(InfoVisitor visitor) => visitor.visitTypedef(this);
}
class FunctionInfo extends BasicInfo with CodeInfo {
@@ -286,10 +459,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;
@@ -332,6 +505,8 @@ class FunctionInfo extends BasicInfo with CodeInfo {
this.code})
: super('function', _ids++, name, outputUnit, size);
+ FunctionInfo._(String serializedId) : super._fromId(serializedId);
+
Map toJson() => super.toJson()
..addAll({
'children': closures.map((i) => i.serializedId).toList(),
@@ -346,6 +521,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 +580,52 @@ class FunctionModifiers {
'external': isExternal,
};
}
+
+/// 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);
+ }
+
+ visitTypedef(TypedefInfo info) {}
Harry Terkelsen 2015/08/11 01:15:18 remove or make InfoVisitor abstract
Siggi Cherem (dart-lang) 2015/08/11 16:09:27 Done.
+ visitOutput(OutputUnitInfo info) {}
Harry Terkelsen 2015/08/11 01:15:18 ditto
Siggi Cherem (dart-lang) 2015/08/11 16:09:27 Done.
+}
« no previous file with comments | « no previous file | tests/compiler/dart2js/analyze_unused_dart2js_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698