Skip to content
This repository has been archived by the owner on Aug 11, 2021. It is now read-only.

Commit

Permalink
Add ClosureInfo for closures.
Browse files Browse the repository at this point in the history
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 .
  • Loading branch information
harryterkelsen committed Oct 6, 2016
1 parent 8c4b4f6 commit 205f3ed
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 27 deletions.
2 changes: 1 addition & 1 deletion bin/debug_info.dart
Expand Up @@ -67,7 +67,7 @@ validateSize(AllInfo info, String debugLibName) {
_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)');
Expand Down
40 changes: 34 additions & 6 deletions lib/info.dart
Expand Up @@ -104,6 +104,9 @@ class AllInfo {
// 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>[];
Expand All @@ -123,7 +126,7 @@ class AllInfo {
/// 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
Expand Down Expand Up @@ -263,7 +266,7 @@ class FieldInfo extends BasicInfo with CodeInfo {
String inferredType;

/// Nested closures seen in the field initializer.
List<FunctionInfo> closures;
List<ClosureInfo> closures;

/// The actual generated code for the field.
String code;
Expand Down Expand Up @@ -321,7 +324,7 @@ class FunctionInfo extends BasicInfo with CodeInfo {
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;
Expand Down Expand Up @@ -371,6 +374,22 @@ class FunctionInfo extends BasicInfo with CodeInfo {
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.
Expand Down Expand Up @@ -407,7 +426,7 @@ class FunctionModifiers {
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,
Expand All @@ -416,6 +435,7 @@ enum InfoKind {
constant,
outputUnit,
typedef,
closure,
}

String kindToString(InfoKind kind) {
Expand All @@ -434,6 +454,8 @@ String kindToString(InfoKind kind) {
return 'outputUnit';
case InfoKind.typedef:
return 'typedef';
case InfoKind.closure:
return 'closure';
default:
return null;
}
Expand Down Expand Up @@ -461,6 +483,8 @@ InfoKind kindFromString(String kind) {
return InfoKind.outputUnit;
case 'typedef':
return InfoKind.typedef;
case 'closure':
return InfoKind.closure;
default:
return null;
}
Expand All @@ -476,6 +500,7 @@ abstract class InfoVisitor<T> {
T visitConstant(ConstantInfo info);
T visitFunction(FunctionInfo info);
T visitTypedef(TypedefInfo info);
T visitClosure(ClosureInfo info);
T visitOutput(OutputUnitInfo info);
}

Expand Down Expand Up @@ -508,15 +533,18 @@ class RecursiveInfoVisitor extends InfoVisitor<Null> {
}

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);
}
}
35 changes: 26 additions & 9 deletions lib/json_info_codec.dart
Expand Up @@ -7,10 +7,10 @@ part of dart2js_info.info;

// 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'];
Expand All @@ -19,15 +19,13 @@ class JsonToAllInfoConverter extends Converter<Map<String, dynamic>, AllInfo> {
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) {
Expand Down Expand Up @@ -208,11 +206,23 @@ class JsonToAllInfoConverter extends Converter<Map<String, dynamic>, AllInfo> {
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/')) {
Expand Down Expand Up @@ -249,13 +259,15 @@ class AllInfoToJsonConverter extends Converter<AllInfo, Map>
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,
};
}

Expand Down Expand Up @@ -433,6 +445,11 @@ class AllInfoToJsonConverter extends Converter<AllInfo, Map>
});
}

Map visitClosure(ClosureInfo info) {
return _visitBasicInfo(info)
..addAll({'function': info.function.serializedId});
}

visitTypedef(TypedefInfo info) => _visitBasicInfo(info)..['type'] = info.type;

visitOutput(OutputUnitInfo info) =>
Expand Down
2 changes: 1 addition & 1 deletion 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.
Expand Down
15 changes: 8 additions & 7 deletions test/hello_world/hello_world.js.info.json
Expand Up @@ -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]",
Expand Down Expand Up @@ -1802,7 +1802,8 @@
"type": "E"
}
},
"constant": {}
"constant": {},
"closure": {}
},
"holding": {
"function/0": [
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 3 additions & 3 deletions test/parse_test.dart
Expand Up @@ -19,10 +19,10 @@ main() {
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);
Expand Down

0 comments on commit 205f3ed

Please sign in to comment.