Add ClosureInfo for closures.
This allows us to track closure size, including captured variables,
in addition to the function size.
R=sigmund@google.com
Review URL: https://codereview.chromium.org//2402473002 .
diff --git a/bin/debug_info.dart b/bin/debug_info.dart
index 3c09114..ec39001 100644
--- a/bin/debug_info.dart
+++ b/bin/debug_info.dart
@@ -67,7 +67,7 @@
_fail('$percent% size missing: $accounted (all libs + consts) '
'< $realTotal (total)');
}
- var missingTotal = tracker.missing.values.fold(0, (a, b) => a + b);
+ int missingTotal = tracker.missing.values.fold(0, (a, b) => a + b);
if (missingTotal > 0) {
var percent = (missingTotal * 100 / realTotal).toStringAsFixed(2);
_fail('$percent% size missing in libraries (sum of elements > lib.size)');
diff --git a/lib/info.dart b/lib/info.dart
index 9661dcc..e25eb43 100644
--- a/lib/info.dart
+++ b/lib/info.dart
@@ -104,6 +104,9 @@
// and we'll include it only once in the output.
List<ConstantInfo> constants = <ConstantInfo>[];
+ /// Information about closures anywhere in the program.
+ List<ClosureInfo> closures = <ClosureInfo>[];
+
/// Information about output units (should be just one entry if not using
/// deferred loading).
List<OutputUnitInfo> outputUnits = <OutputUnitInfo>[];
@@ -123,7 +126,7 @@
/// 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 = 4;
+ final int version = 5;
/// 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
@@ -263,7 +266,7 @@
String inferredType;
/// Nested closures seen in the field initializer.
- List<FunctionInfo> closures;
+ List<ClosureInfo> closures;
/// The actual generated code for the field.
String code;
@@ -321,7 +324,7 @@
FunctionModifiers modifiers;
/// Nested closures that appear within the body of this function.
- List<FunctionInfo> closures;
+ List<ClosureInfo> closures;
/// The type of this function.
String type;
@@ -371,6 +374,22 @@
dynamic accept(InfoVisitor visitor) => visitor.visitFunction(this);
}
+/// Information about a closure, also known as a local function.
+class ClosureInfo extends BasicInfo {
+ static int _ids = 0;
+
+ /// The function that is wrapped by this closure.
+ FunctionInfo function;
+
+ ClosureInfo(
+ {String name, OutputUnitInfo outputUnit, int size: 0, this.function})
+ : super(InfoKind.closure, _ids++, name, outputUnit, size, null);
+
+ ClosureInfo._(String serializedId) : super._fromId(serializedId);
+
+ dynamic accept(InfoVisitor visitor) => visitor.visitClosure(this);
+}
+
/// Information about how a dependency is used.
class DependencyInfo {
/// The dependency, either a FunctionInfo or FieldInfo.
@@ -407,7 +426,7 @@
this.isExternal: false});
}
-/// Possible values of the `kind` field in the serialied infos.
+/// Possible values of the `kind` field in the serialized infos.
enum InfoKind {
library,
clazz,
@@ -416,6 +435,7 @@
constant,
outputUnit,
typedef,
+ closure,
}
String kindToString(InfoKind kind) {
@@ -434,6 +454,8 @@
return 'outputUnit';
case InfoKind.typedef:
return 'typedef';
+ case InfoKind.closure:
+ return 'closure';
default:
return null;
}
@@ -461,6 +483,8 @@
return InfoKind.outputUnit;
case 'typedef':
return InfoKind.typedef;
+ case 'closure':
+ return InfoKind.closure;
default:
return null;
}
@@ -476,6 +500,7 @@
T visitConstant(ConstantInfo info);
T visitFunction(FunctionInfo info);
T visitTypedef(TypedefInfo info);
+ T visitClosure(ClosureInfo info);
T visitOutput(OutputUnitInfo info);
}
@@ -508,15 +533,18 @@
}
visitField(FieldInfo info) {
- info.closures.forEach(visitFunction);
+ info.closures.forEach(visitClosure);
}
visitConstant(ConstantInfo info) {}
visitFunction(FunctionInfo info) {
- info.closures.forEach(visitFunction);
+ info.closures.forEach(visitClosure);
}
visitTypedef(TypedefInfo info) {}
visitOutput(OutputUnitInfo info) {}
+ visitClosure(ClosureInfo info) {
+ visitFunction(info.function);
+ }
}
diff --git a/lib/json_info_codec.dart b/lib/json_info_codec.dart
index 5176ce3..8382bb0 100644
--- a/lib/json_info_codec.dart
+++ b/lib/json_info_codec.dart
@@ -7,10 +7,10 @@
// TODO(sigmund): add unit tests.
class JsonToAllInfoConverter extends Converter<Map<String, dynamic>, AllInfo> {
- Map<String, Info> registry;
+ Map<String, Info> registry = <String, Info>{};
AllInfo convert(Map<String, dynamic> json) {
- registry = <String, Info>{};
+ registry.clear();
var result = new AllInfo();
var elements = json['elements'];
@@ -19,15 +19,13 @@
result.classes.addAll((elements['class'] as Map).values.map(parseClass));
result.functions
.addAll((elements['function'] as Map).values.map(parseFunction));
+ result.closures
+ .addAll((elements['closure'] as Map).values.map(parseClosure));
result.fields.addAll((elements['field'] as Map).values.map(parseField));
result.typedefs
.addAll((elements['typedef'] as Map).values.map(parseTypedef));
-
- // TODO(sigmund): remove null check on next breaking version
- var constants = elements['constant'];
- if (constants != null) {
- result.constants.addAll((constants as Map).values.map(parseConstant));
- }
+ result.constants
+ .addAll((elements['constant'] as Map).values.map(parseConstant));
var idMap = <String, Info>{};
for (var f in result.functions) {
@@ -208,11 +206,23 @@
isExternal: json['external'] == true);
}
+ ClosureInfo parseClosure(Map json) {
+ ClosureInfo result = parseId(json['id']);
+ return result
+ ..name = json['name']
+ ..parent = parseId(json['parent'])
+ ..outputUnit = parseId(json['outputUnit'])
+ ..size = json['size']
+ ..function = parseId(json['function']);
+ }
+
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('closure/')) {
+ return new ClosureInfo._(serializedId);
} else if (serializedId.startsWith('library/')) {
return new LibraryInfo._(serializedId);
} else if (serializedId.startsWith('class/')) {
@@ -249,13 +259,15 @@
var jsonTypedefs = _visitList(info.typedefs);
var jsonFields = _visitList(info.fields);
var jsonConstants = _visitList(info.constants);
+ var jsonClosures = _visitList(info.closures);
return {
'library': jsonLibraries,
'class': jsonClasses,
'function': jsonFunctions,
'typedef': jsonTypedefs,
'field': jsonFields,
- 'constant': jsonConstants
+ 'constant': jsonConstants,
+ 'closure': jsonClosures,
};
}
@@ -433,6 +445,11 @@
});
}
+ Map visitClosure(ClosureInfo info) {
+ return _visitBasicInfo(info)
+ ..addAll({'function': info.function.serializedId});
+ }
+
visitTypedef(TypedefInfo info) => _visitBasicInfo(info)..['type'] = info.type;
visitOutput(OutputUnitInfo info) =>
diff --git a/pubspec.yaml b/pubspec.yaml
index a5f9d21..2c7d6e9 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
name: dart2js_info
-version: 0.3.0
+version: 0.5.0
description: >
Libraries and tools to process data produced when running dart2js with
--dump-info.
diff --git a/test/hello_world/hello_world.js.info.json b/test/hello_world/hello_world.js.info.json
index 33eacf6..2bd859d 100644
--- a/test/hello_world/hello_world.js.info.json
+++ b/test/hello_world/hello_world.js.info.json
@@ -1452,7 +1452,7 @@
"name": "message",
"size": 0,
"outputUnit": "outputUnit/0",
- "coverageId": "4090",
+ "coverageId": "4087",
"parent": "class/143",
"children": [],
"inferredType": "Value mask: [\"Intercepted function with no arguments.\"] type: [exact=JSString]",
@@ -1802,7 +1802,8 @@
"type": "E"
}
},
- "constant": {}
+ "constant": {},
+ "closure": {}
},
"holding": {
"function/0": [
@@ -1846,21 +1847,21 @@
"id": "outputUnit/0",
"kind": "outputUnit",
"name": null,
- "size": 10124,
+ "size": 10116,
"imports": [
null
]
}
],
- "dump_version": 4,
+ "dump_version": 5,
"deferredFiles": {},
"dump_minor_version": "0",
"program": {
"entrypoint": "function/0",
- "size": 10124,
+ "size": 10116,
"dart2jsVersion": null,
- "compilationMoment": "2016-09-30 16:14:58.038530",
- "compilationDuration": 2726976,
+ "compilationMoment": "2016-10-06 10:14:59.145665",
+ "compilationDuration": 2729236,
"toJsonDuration": 4000,
"dumpInfoDuration": 0,
"noSuchMethodEnabled": false,
diff --git a/test/parse_test.dart b/test/parse_test.dart
index ead1701..8b891dc 100644
--- a/test/parse_test.dart
+++ b/test/parse_test.dart
@@ -19,10 +19,10 @@
expect(program, isNotNull);
expect(program.entrypoint, isNotNull);
- expect(program.size, 10124);
+ expect(program.size, 10116);
expect(program.compilationMoment,
- DateTime.parse("2016-09-30 16:14:58.038530"));
- expect(program.compilationDuration, new Duration(microseconds: 2726976));
+ DateTime.parse("2016-10-06 10:14:59.145665"));
+ expect(program.compilationDuration, new Duration(microseconds: 2729236));
expect(program.toJsonDuration, new Duration(milliseconds: 4));
expect(program.dumpInfoDuration, new Duration(seconds: 0));
expect(program.noSuchMethodEnabled, false);