OLD | NEW |
---|---|
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /// Data produced by dart2js when run with the `--dump-info` flag. | 5 /// Data produced by dart2js when run with the `--dump-info` flag. |
6 library dart2js_info.info; | 6 library dart2js_info.info; |
7 | 7 |
8 import 'dart:convert'; | |
9 | |
8 import 'src/measurements.dart'; | 10 import 'src/measurements.dart'; |
9 export 'src/measurements.dart'; | 11 export 'src/measurements.dart'; |
10 | 12 |
13 part 'json_info_codec.dart'; | |
14 | |
11 /// Common interface to many pieces of information generated by the dart2js | 15 /// Common interface to many pieces of information generated by the dart2js |
12 /// compiler that are directly associated with an element (compilation unit, | 16 /// compiler that are directly associated with an element (compilation unit, |
13 /// library, class, function, or field). | 17 /// library, class, function, or field). |
14 abstract class Info { | 18 abstract class Info { |
15 /// An identifier for the kind of information. | 19 /// An identifier for the kind of information. |
16 InfoKind get kind; | 20 InfoKind get kind; |
17 | 21 |
18 /// Name of the element associated with this info. | 22 /// Name of the element associated with this info. |
19 String name; | 23 String name; |
20 | 24 |
21 /// An id to uniquely identify this info among infos of the same [kind]. | 25 /// An id to uniquely identify this info among infos of the same [kind]. |
22 int get id; | 26 int get id; |
23 | 27 |
24 /// A globally unique id combining [kind] and [id] together. | 28 /// A globally unique id combining [kind] and [id] together. |
25 String get serializedId; | 29 String get serializedId; |
26 | 30 |
27 /// Id used by the compiler when instrumenting code for code coverage. | 31 /// Id used by the compiler when instrumenting code for code coverage. |
28 // TODO(sigmund): It would be nice if we could use the same id for | 32 // TODO(sigmund): It would be nice if we could use the same id for |
29 // serialization and for coverage. Could we unify them? | 33 // serialization and for coverage. Could we unify them? |
30 String coverageId; | 34 String coverageId; |
31 | 35 |
32 /// Bytes used in the generated code for the corresponding element. | 36 /// Bytes used in the generated code for the corresponding element. |
33 int size; | 37 int size; |
34 | 38 |
35 /// Info of the enclosing element. | 39 /// Info of the enclosing element. |
36 Info parent; | 40 Info parent; |
37 | 41 |
38 /// Serializes the information into a JSON format. | 42 dynamic accept(InfoVisitor visitor); |
39 // TODO(sigmund): refactor and put toJson outside the class, so we can have 2 | |
40 // different serializer/deserializers at once. | |
41 Map toJson(); | |
42 | |
43 void accept(InfoVisitor visitor); | |
44 } | 43 } |
45 | 44 |
46 /// Common information used for most kind of elements. | 45 /// Common information used for most kind of elements. |
47 // TODO(sigmund): add more: | 46 // TODO(sigmund): add more: |
48 // - inputSize: bytes used in the Dart source program | 47 // - inputSize: bytes used in the Dart source program |
49 abstract class BasicInfo implements Info { | 48 abstract class BasicInfo implements Info { |
50 final InfoKind kind; | 49 final InfoKind kind; |
51 final int id; | 50 final int id; |
52 String coverageId; | 51 String coverageId; |
53 int size; | 52 int size; |
54 Info parent; | 53 Info parent; |
55 | 54 |
56 String get serializedId => '${_kindToString(kind)}/$id'; | 55 String get serializedId => '${_kindToString(kind)}/$id'; |
57 | 56 |
58 String name; | 57 String name; |
59 | 58 |
60 /// If using deferred libraries, where the element associated with this info | 59 /// If using deferred libraries, where the element associated with this info |
61 /// is generated. | 60 /// is generated. |
62 OutputUnitInfo outputUnit; | 61 OutputUnitInfo outputUnit; |
63 | 62 |
64 BasicInfo(this.kind, this.id, this.name, this.outputUnit, this.size, | 63 BasicInfo(this.kind, this.id, this.name, this.outputUnit, this.size, |
65 this.coverageId); | 64 this.coverageId); |
66 | 65 |
67 BasicInfo._fromId(String serializedId) | 66 BasicInfo._fromId(String serializedId) |
68 : kind = _kindFromSerializedId(serializedId), | 67 : kind = _kindFromSerializedId(serializedId), |
69 id = _idFromSerializedId(serializedId); | 68 id = _idFromSerializedId(serializedId); |
70 | 69 |
71 Map toJson() { | |
72 var res = { | |
73 'id': serializedId, | |
74 'kind': _kindToString(kind), | |
75 'name': name, | |
76 'size': size, | |
77 }; | |
78 // TODO(sigmund): Omit this also when outputUnit.id == 0 (most code is in | |
79 // the main output unit by default). | |
80 if (outputUnit != null) res['outputUnit'] = outputUnit.serializedId; | |
81 if (coverageId != null) res['coverageId'] = coverageId; | |
82 if (parent != null) res['parent'] = parent.serializedId; | |
83 return res; | |
84 } | |
85 | |
86 String toString() => '$serializedId $name [$size]'; | 70 String toString() => '$serializedId $name [$size]'; |
87 } | 71 } |
88 | 72 |
89 /// Info associated with elements containing executable code (like fields and | 73 /// Info associated with elements containing executable code (like fields and |
90 /// methods) | 74 /// methods) |
91 abstract class CodeInfo implements Info { | 75 abstract class CodeInfo implements Info { |
92 /// How does this function or field depend on others. | 76 /// How does this function or field depend on others. |
93 final List<DependencyInfo> uses = <DependencyInfo>[]; | 77 final List<DependencyInfo> uses = <DependencyInfo>[]; |
94 } | 78 } |
95 | 79 |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
143 | 127 |
144 /// Minor version indicating non-breaking changes in the format. A change in | 128 /// Minor version indicating non-breaking changes in the format. A change in |
145 /// this version number means that the json parsing in this library from a | 129 /// this version number means that the json parsing in this library from a |
146 /// previous will continue to work after the change. This is typically | 130 /// previous will continue to work after the change. This is typically |
147 /// increased when adding new entries to the file format. | 131 /// increased when adding new entries to the file format. |
148 // Note: the dump-info.viewer app was written using a json parser version 3.2. | 132 // Note: the dump-info.viewer app was written using a json parser version 3.2. |
149 final int minorVersion = 6; | 133 final int minorVersion = 6; |
150 | 134 |
151 AllInfo(); | 135 AllInfo(); |
152 | 136 |
153 // TODO(het): Remove this when we have an external InfoCodec, see | 137 dynamic accept(InfoVisitor visitor) => visitor.visitAll(this); |
154 // https://github.com/dart-lang/dart2js_info/issues/4 | |
155 factory AllInfo.fromJson(Map json) => new _ParseHelper().parseAll(json); | |
156 | |
157 Map _listAsJsonMap(List<Info> list) { | |
158 var map = <String, Map>{}; | |
159 for (var info in list) { | |
160 map['${info.id}'] = info.toJson(); | |
161 } | |
162 return map; | |
163 } | |
164 | |
165 Map _extractHoldingInfo() { | |
166 var map = <String, List>{}; | |
167 void helper(CodeInfo info) { | |
168 if (info.uses.isEmpty) return; | |
169 map[info.serializedId] = info.uses.map((u) => u.toJson()).toList(); | |
170 } | |
171 functions.forEach(helper); | |
172 fields.forEach(helper); | |
173 return map; | |
174 } | |
175 | |
176 Map _extractDependencies() { | |
177 var map = <String, List>{}; | |
178 dependencies.forEach((k, v) { | |
179 map[k.serializedId] = v.map((i) => i.serializedId).toList(); | |
180 }); | |
181 return map; | |
182 } | |
183 | |
184 Map toJson() => { | |
185 'elements': { | |
186 'library': _listAsJsonMap(libraries), | |
187 'class': _listAsJsonMap(classes), | |
188 'function': _listAsJsonMap(functions), | |
189 'typedef': _listAsJsonMap(typedefs), | |
190 'field': _listAsJsonMap(fields), | |
191 'constant': _listAsJsonMap(constants), | |
192 }, | |
193 'holding': _extractHoldingInfo(), | |
194 'dependencies': _extractDependencies(), | |
195 'outputUnits': outputUnits.map((u) => u.toJson()).toList(), | |
196 'dump_version': version, | |
197 'deferredFiles': deferredFiles, | |
198 'dump_minor_version': '$minorVersion', | |
199 // TODO(sigmund): change viewer to accept an int? | |
200 'program': program.toJson(), | |
201 }; | |
202 | |
203 void accept(InfoVisitor visitor) => visitor.visitAll(this); | |
204 } | 138 } |
205 | 139 |
206 class ProgramInfo { | 140 class ProgramInfo { |
207 FunctionInfo entrypoint; | 141 FunctionInfo entrypoint; |
208 int size; | 142 int size; |
209 String dart2jsVersion; | 143 String dart2jsVersion; |
210 DateTime compilationMoment; | 144 DateTime compilationMoment; |
211 Duration compilationDuration; | 145 Duration compilationDuration; |
212 // TODO(sigmund): use Duration. | 146 // TODO(sigmund): use Duration. |
213 int toJsonDuration; | 147 int toJsonDuration; |
214 int dumpInfoDuration; | 148 int dumpInfoDuration; |
215 bool noSuchMethodEnabled; | 149 bool noSuchMethodEnabled; |
216 bool minified; | 150 bool minified; |
217 | 151 |
218 ProgramInfo( | 152 ProgramInfo( |
219 {this.entrypoint, | 153 {this.entrypoint, |
220 this.size, | 154 this.size, |
221 this.dart2jsVersion, | 155 this.dart2jsVersion, |
222 this.compilationMoment, | 156 this.compilationMoment, |
223 this.compilationDuration, | 157 this.compilationDuration, |
224 this.toJsonDuration, | 158 this.toJsonDuration, |
225 this.dumpInfoDuration, | 159 this.dumpInfoDuration, |
226 this.noSuchMethodEnabled, | 160 this.noSuchMethodEnabled, |
227 this.minified}); | 161 this.minified}); |
228 | 162 |
229 Map toJson() => { | 163 dynamic accept(InfoVisitor visitor) => visitor.visitProgram(this); |
230 'entrypoint': entrypoint.serializedId, | |
231 'size': size, | |
232 'dart2jsVersion': dart2jsVersion, | |
233 'compilationMoment': '$compilationMoment', | |
234 'compilationDuration': '${compilationDuration}', | |
235 'toJsonDuration': toJsonDuration, | |
236 'dumpInfoDuration': '$dumpInfoDuration', | |
237 'noSuchMethodEnabled': noSuchMethodEnabled, | |
238 'minified': minified, | |
239 }; | |
240 | |
241 void accept(InfoVisitor visitor) => visitor.visitProgram(this); | |
242 } | |
243 | |
244 // TODO(sigmund): add unit tests. | |
245 class _ParseHelper { | |
246 Map<String, Info> registry = {}; | |
247 | |
248 AllInfo parseAll(Map json) { | |
249 var result = new AllInfo(); | |
250 var elements = json['elements']; | |
251 result.libraries.addAll(elements['library'].values.map(parseLibrary)); | |
252 result.classes.addAll(elements['class'].values.map(parseClass)); | |
253 result.functions.addAll(elements['function'].values.map(parseFunction)); | |
254 result.fields.addAll(elements['field'].values.map(parseField)); | |
255 result.typedefs.addAll(elements['typedef'].values.map(parseTypedef)); | |
256 | |
257 // TODO(sigmund): remove null check on next breaking version | |
258 var constants = elements['constant']; | |
259 if (constants != null) { | |
260 result.constants.addAll(constants.values.map(parseConstant)); | |
261 } | |
262 | |
263 var idMap = {}; | |
264 for (var f in result.functions) { | |
265 idMap[f.serializedId] = f; | |
266 } | |
267 for (var f in result.fields) { | |
268 idMap[f.serializedId] = f; | |
269 } | |
270 | |
271 json['holding'].forEach((k, deps) { | |
272 var src = idMap[k]; | |
273 assert(src != null); | |
274 for (var dep in deps) { | |
275 var target = idMap[dep['id']]; | |
276 assert(target != null); | |
277 src.uses.add(new DependencyInfo(target, dep['mask'])); | |
278 } | |
279 }); | |
280 | |
281 json['dependencies']?.forEach((k, deps) { | |
282 result.dependencies[idMap[k]] = deps.map((d) => idMap[d]).toList(); | |
283 }); | |
284 | |
285 result.program = parseProgram(json['program']); | |
286 // todo: version, etc | |
287 return result; | |
288 } | |
289 | |
290 LibraryInfo parseLibrary(Map json) { | |
291 LibraryInfo result = parseId(json['id']); | |
292 result | |
293 ..name = json['name'] | |
294 ..uri = Uri.parse(json['canonicalUri']) | |
295 ..outputUnit = parseId(json['outputUnit']) | |
296 ..size = json['size']; | |
297 for (var child in json['children'].map(parseId)) { | |
298 if (child is FunctionInfo) { | |
299 result.topLevelFunctions.add(child); | |
300 } else if (child is FieldInfo) { | |
301 result.topLevelVariables.add(child); | |
302 } else if (child is ClassInfo) { | |
303 result.classes.add(child); | |
304 } else { | |
305 assert(child is TypedefInfo); | |
306 result.typedefs.add(child); | |
307 } | |
308 } | |
309 return result; | |
310 } | |
311 | |
312 ClassInfo parseClass(Map json) { | |
313 ClassInfo result = parseId(json['id']); | |
314 result | |
315 ..name = json['name'] | |
316 ..parent = parseId(json['parent']) | |
317 ..outputUnit = parseId(json['outputUnit']) | |
318 ..size = json['size'] | |
319 ..isAbstract = json['modifiers']['abstract'] == true; | |
320 assert(result is ClassInfo); | |
321 for (var child in json['children'].map(parseId)) { | |
322 if (child is FunctionInfo) { | |
323 result.functions.add(child); | |
324 } else { | |
325 assert(child is FieldInfo); | |
326 result.fields.add(child); | |
327 } | |
328 } | |
329 return result; | |
330 } | |
331 | |
332 FieldInfo parseField(Map json) { | |
333 FieldInfo result = parseId(json['id']); | |
334 return result | |
335 ..name = json['name'] | |
336 ..parent = parseId(json['parent']) | |
337 ..coverageId = json['coverageId'] | |
338 ..outputUnit = parseId(json['outputUnit']) | |
339 ..size = json['size'] | |
340 ..type = json['type'] | |
341 ..inferredType = json['inferredType'] | |
342 ..code = json['code'] | |
343 ..isConst = json['const'] ?? false | |
344 ..initializer = parseId(json['initializer']) | |
345 ..closures = json['children'].map(parseId).toList(); | |
346 } | |
347 | |
348 ConstantInfo parseConstant(Map json) { | |
349 ConstantInfo result = parseId(json['id']); | |
350 return result | |
351 ..code = json['code'] | |
352 ..size = json['size']; | |
353 } | |
354 | |
355 TypedefInfo parseTypedef(Map json) { | |
356 TypedefInfo result = parseId(json['id']); | |
357 return result | |
358 ..name = json['name'] | |
359 ..parent = parseId(json['parent']) | |
360 ..type = json['type'] | |
361 ..size = 0; | |
362 } | |
363 | |
364 ProgramInfo parseProgram(Map json) => new ProgramInfo() | |
365 ..size = json['size'] | |
366 ..entrypoint = parseId(json['entrypoint']); | |
367 | |
368 FunctionInfo parseFunction(Map json) { | |
369 FunctionInfo result = parseId(json['id']); | |
370 return result | |
371 ..name = json['name'] | |
372 ..parent = parseId(json['parent']) | |
373 ..coverageId = json['coverageId'] | |
374 ..outputUnit = parseId(json['outputUnit']) | |
375 ..size = json['size'] | |
376 ..type = json['type'] | |
377 ..returnType = json['returnType'] | |
378 ..inferredReturnType = json['inferredReturnType'] | |
379 ..parameters = json['parameters'].map(parseParameter).toList() | |
380 ..code = json['code'] | |
381 ..sideEffects = json['sideEffects'] | |
382 ..modifiers = parseModifiers(json['modifiers']) | |
383 ..closures = json['children'].map(parseId).toList() | |
384 ..measurements = parseMeasurements(json['measurements']); | |
385 } | |
386 | |
387 ParameterInfo parseParameter(Map json) => | |
388 new ParameterInfo(json['name'], json['type'], json['declaredType']); | |
389 | |
390 Measurements parseMeasurements(Map json) { | |
391 if (json == null) return null; | |
392 var uri = json['sourceFile']; | |
393 var res = new Measurements(uri == null ? null : Uri.parse(uri)); | |
394 for (var key in json.keys) { | |
395 var value = json[key]; | |
396 if (value == null) continue; | |
397 if (key == 'entries') { | |
398 value.forEach((metricName, entries) { | |
399 var metric = Metric.fromJson(metricName); | |
400 for (var i = 0; i < entries.length; i += 2) { | |
401 res.record(metric, entries[i], entries[i + 1]); | |
402 } | |
403 }); | |
404 } else { | |
405 res.counters[Metric.fromJson(key)] = value; | |
406 } | |
407 } | |
408 return res; | |
409 } | |
410 | |
411 FunctionModifiers parseModifiers(Map<String, bool> json) { | |
412 return new FunctionModifiers( | |
413 isStatic: json['static'] == true, | |
414 isConst: json['const'] == true, | |
415 isFactory: json['factory'] == true, | |
416 isExternal: json['external'] == true); | |
417 } | |
418 | |
419 Info parseId(String serializedId) => registry.putIfAbsent(serializedId, () { | |
420 if (serializedId == null) { | |
421 return null; | |
422 } else if (serializedId.startsWith('function/')) { | |
423 return new FunctionInfo._(serializedId); | |
424 } else if (serializedId.startsWith('library/')) { | |
425 return new LibraryInfo._(serializedId); | |
426 } else if (serializedId.startsWith('class/')) { | |
427 return new ClassInfo._(serializedId); | |
428 } else if (serializedId.startsWith('field/')) { | |
429 return new FieldInfo._(serializedId); | |
430 } else if (serializedId.startsWith('constant/')) { | |
431 return new ConstantInfo._(serializedId); | |
432 } else if (serializedId.startsWith('typedef/')) { | |
433 return new TypedefInfo._(serializedId); | |
434 } else if (serializedId.startsWith('outputUnit/')) { | |
435 return new OutputUnitInfo._(serializedId); | |
436 } | |
437 assert(false); | |
438 }); | |
439 } | 164 } |
440 | 165 |
441 /// Info associated with a library element. | 166 /// Info associated with a library element. |
442 class LibraryInfo extends BasicInfo { | 167 class LibraryInfo extends BasicInfo { |
443 /// Canonical uri that identifies the library. | 168 /// Canonical uri that identifies the library. |
444 Uri uri; | 169 Uri uri; |
445 | 170 |
446 /// Top level functions defined within the library. | 171 /// Top level functions defined within the library. |
447 final List<FunctionInfo> topLevelFunctions = <FunctionInfo>[]; | 172 final List<FunctionInfo> topLevelFunctions = <FunctionInfo>[]; |
448 | 173 |
(...skipping 14 matching lines...) Expand all Loading... | |
463 | 188 |
464 /// Whether there is any information recorded for this library. | 189 /// Whether there is any information recorded for this library. |
465 bool get isEmpty => | 190 bool get isEmpty => |
466 topLevelFunctions.isEmpty && topLevelVariables.isEmpty && classes.isEmpty; | 191 topLevelFunctions.isEmpty && topLevelVariables.isEmpty && classes.isEmpty; |
467 | 192 |
468 LibraryInfo(String name, this.uri, OutputUnitInfo outputUnit, int size) | 193 LibraryInfo(String name, this.uri, OutputUnitInfo outputUnit, int size) |
469 : super(InfoKind.library, _id++, name, outputUnit, size, null); | 194 : super(InfoKind.library, _id++, name, outputUnit, size, null); |
470 | 195 |
471 LibraryInfo._(String serializedId) : super._fromId(serializedId); | 196 LibraryInfo._(String serializedId) : super._fromId(serializedId); |
472 | 197 |
473 Map toJson() => super.toJson() | 198 dynamic accept(InfoVisitor visitor) => visitor.visitLibrary(this); |
474 ..addAll({ | |
475 'children': [] | |
476 ..addAll(topLevelFunctions.map((f) => f.serializedId)) | |
477 ..addAll(topLevelVariables.map((v) => v.serializedId)) | |
478 ..addAll(classes.map((c) => c.serializedId)) | |
479 ..addAll(typedefs.map((t) => t.serializedId)), | |
480 'canonicalUri': '$uri', | |
481 }); | |
482 | |
483 void accept(InfoVisitor visitor) => visitor.visitLibrary(this); | |
484 } | 199 } |
485 | 200 |
486 /// Information about an output unit. Normally there is just one for the entire | 201 /// Information about an output unit. Normally there is just one for the entire |
487 /// program unless the application uses deferred imports, in which case there | 202 /// program unless the application uses deferred imports, in which case there |
488 /// would be an additional output unit per deferred chunk. | 203 /// would be an additional output unit per deferred chunk. |
489 class OutputUnitInfo extends BasicInfo { | 204 class OutputUnitInfo extends BasicInfo { |
490 static int _ids = 0; | 205 static int _ids = 0; |
491 OutputUnitInfo(String name, int size) | 206 OutputUnitInfo(String name, int size) |
492 : super(InfoKind.outputUnit, _ids++, name, null, size, null); | 207 : super(InfoKind.outputUnit, _ids++, name, null, size, null); |
493 | 208 |
494 OutputUnitInfo._(String serializedId) : super._fromId(serializedId); | 209 OutputUnitInfo._(String serializedId) : super._fromId(serializedId); |
495 | 210 |
496 void accept(InfoVisitor visitor) => visitor.visitOutput(this); | 211 dynamic accept(InfoVisitor visitor) => visitor.visitOutput(this); |
497 } | 212 } |
498 | 213 |
499 /// Information about a class element. | 214 /// Information about a class element. |
500 class ClassInfo extends BasicInfo { | 215 class ClassInfo extends BasicInfo { |
501 /// Whether the class is abstract. | 216 /// Whether the class is abstract. |
502 bool isAbstract; | 217 bool isAbstract; |
503 | 218 |
504 // TODO(sigmund): split static vs instance vs closures | 219 // TODO(sigmund): split static vs instance vs closures |
505 /// Functions (static or instance) defined in the class. | 220 /// Functions (static or instance) defined in the class. |
506 final List<FunctionInfo> functions = <FunctionInfo>[]; | 221 final List<FunctionInfo> functions = <FunctionInfo>[]; |
507 | 222 |
508 /// Fields defined in the class. | 223 /// Fields defined in the class. |
509 // TODO(sigmund): currently appears to only be populated with instance fields, | 224 // TODO(sigmund): currently appears to only be populated with instance fields, |
510 // but this should be fixed. | 225 // but this should be fixed. |
511 final List<FieldInfo> fields = <FieldInfo>[]; | 226 final List<FieldInfo> fields = <FieldInfo>[]; |
512 static int _ids = 0; | 227 static int _ids = 0; |
513 | 228 |
514 ClassInfo( | 229 ClassInfo( |
515 {String name, this.isAbstract, OutputUnitInfo outputUnit, int size: 0}) | 230 {String name, this.isAbstract, OutputUnitInfo outputUnit, int size: 0}) |
516 : super(InfoKind.clazz, _ids++, name, outputUnit, size, null); | 231 : super(InfoKind.clazz, _ids++, name, outputUnit, size, null); |
517 | 232 |
518 ClassInfo._(String serializedId) : super._fromId(serializedId); | 233 ClassInfo._(String serializedId) : super._fromId(serializedId); |
519 | 234 |
520 Map toJson() => super.toJson() | 235 dynamic accept(InfoVisitor visitor) => visitor.visitClass(this); |
521 ..addAll({ | |
522 // TODO(sigmund): change format, include only when abstract is true. | |
523 'modifiers': {'abstract': isAbstract}, | |
524 'children': [] | |
525 ..addAll(fields.map((f) => f.serializedId)) | |
526 ..addAll(functions.map((m) => m.serializedId)) | |
527 }); | |
528 | |
529 void accept(InfoVisitor visitor) => visitor.visitClass(this); | |
530 } | 236 } |
531 | 237 |
532 /// Information about a constant value. | 238 /// Information about a constant value. |
533 // TODO(sigmund): add dependency data for ConstantInfo | 239 // TODO(sigmund): add dependency data for ConstantInfo |
534 class ConstantInfo extends BasicInfo { | 240 class ConstantInfo extends BasicInfo { |
535 /// The actual generated code for the constant. | 241 /// The actual generated code for the constant. |
536 String code; | 242 String code; |
537 | 243 |
538 static int _ids = 0; | 244 static int _ids = 0; |
539 // TODO(sigmund): Add coverage support to constants? | 245 // TODO(sigmund): Add coverage support to constants? |
540 ConstantInfo({int size: 0, this.code, OutputUnitInfo outputUnit}) | 246 ConstantInfo({int size: 0, this.code, OutputUnitInfo outputUnit}) |
541 : super(InfoKind.constant, _ids++, null, outputUnit, size, null); | 247 : super(InfoKind.constant, _ids++, null, outputUnit, size, null); |
542 | 248 |
543 ConstantInfo._(String serializedId) : super._fromId(serializedId); | 249 ConstantInfo._(String serializedId) : super._fromId(serializedId); |
544 | 250 |
545 Map toJson() => super.toJson()..addAll({'code': code}); | 251 dynamic accept(InfoVisitor visitor) => visitor.visitConstant(this); |
546 | |
547 void accept(InfoVisitor visitor) => visitor.visitConstant(this); | |
548 } | 252 } |
549 | 253 |
550 /// Information about a field element. | 254 /// Information about a field element. |
551 class FieldInfo extends BasicInfo with CodeInfo { | 255 class FieldInfo extends BasicInfo with CodeInfo { |
552 /// The type of the field. | 256 /// The type of the field. |
553 String type; | 257 String type; |
554 | 258 |
555 /// The type inferred by dart2js's whole program analysis | 259 /// The type inferred by dart2js's whole program analysis |
556 String inferredType; | 260 String inferredType; |
557 | 261 |
(...skipping 17 matching lines...) Expand all Loading... | |
575 this.type, | 279 this.type, |
576 this.inferredType, | 280 this.inferredType, |
577 this.closures, | 281 this.closures, |
578 this.code, | 282 this.code, |
579 OutputUnitInfo outputUnit, | 283 OutputUnitInfo outputUnit, |
580 this.isConst}) | 284 this.isConst}) |
581 : super(InfoKind.field, _ids++, name, outputUnit, size, coverageId); | 285 : super(InfoKind.field, _ids++, name, outputUnit, size, coverageId); |
582 | 286 |
583 FieldInfo._(String serializedId) : super._fromId(serializedId); | 287 FieldInfo._(String serializedId) : super._fromId(serializedId); |
584 | 288 |
585 Map toJson() { | 289 dynamic accept(InfoVisitor visitor) => visitor.visitField(this); |
586 var result = super.toJson() | |
587 ..addAll({ | |
588 'children': closures.map((i) => i.serializedId).toList(), | |
589 'inferredType': inferredType, | |
590 'code': code, | |
591 'type': type, | |
592 }); | |
593 if (isConst) { | |
594 result['const'] = true; | |
595 if (initializer != null) result['initializer'] = initializer.serializedId; | |
596 } | |
597 return result; | |
598 } | |
599 | |
600 void accept(InfoVisitor visitor) => visitor.visitField(this); | |
601 } | 290 } |
602 | 291 |
603 /// Information about a typedef declaration. | 292 /// Information about a typedef declaration. |
604 class TypedefInfo extends BasicInfo { | 293 class TypedefInfo extends BasicInfo { |
605 /// The declared type. | 294 /// The declared type. |
606 String type; | 295 String type; |
607 | 296 |
608 static int _ids = 0; | 297 static int _ids = 0; |
609 TypedefInfo(String name, this.type, OutputUnitInfo outputUnit) | 298 TypedefInfo(String name, this.type, OutputUnitInfo outputUnit) |
610 : super(InfoKind.typedef, _ids++, name, outputUnit, 0, null); | 299 : super(InfoKind.typedef, _ids++, name, outputUnit, 0, null); |
611 | 300 |
612 TypedefInfo._(String serializedId) : super._fromId(serializedId); | 301 TypedefInfo._(String serializedId) : super._fromId(serializedId); |
613 | 302 |
614 Map toJson() => super.toJson()..['type'] = '$type'; | 303 dynamic accept(InfoVisitor visitor) => visitor.visitTypedef(this); |
615 | |
616 void accept(InfoVisitor visitor) => visitor.visitTypedef(this); | |
617 } | 304 } |
618 | 305 |
619 /// Information about a function or method. | 306 /// Information about a function or method. |
620 class FunctionInfo extends BasicInfo with CodeInfo { | 307 class FunctionInfo extends BasicInfo with CodeInfo { |
621 static const int TOP_LEVEL_FUNCTION_KIND = 0; | 308 static const int TOP_LEVEL_FUNCTION_KIND = 0; |
622 static const int CLOSURE_FUNCTION_KIND = 1; | 309 static const int CLOSURE_FUNCTION_KIND = 1; |
623 static const int METHOD_FUNCTION_KIND = 2; | 310 static const int METHOD_FUNCTION_KIND = 2; |
624 static const int CONSTRUCTOR_FUNCTION_KIND = 3; | 311 static const int CONSTRUCTOR_FUNCTION_KIND = 3; |
625 static int _ids = 0; | 312 static int _ids = 0; |
626 | 313 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
671 this.inferredReturnType, | 358 this.inferredReturnType, |
672 this.parameters, | 359 this.parameters, |
673 this.sideEffects, | 360 this.sideEffects, |
674 this.inlinedCount, | 361 this.inlinedCount, |
675 this.code, | 362 this.code, |
676 this.measurements}) | 363 this.measurements}) |
677 : super(InfoKind.function, _ids++, name, outputUnit, size, coverageId); | 364 : super(InfoKind.function, _ids++, name, outputUnit, size, coverageId); |
678 | 365 |
679 FunctionInfo._(String serializedId) : super._fromId(serializedId); | 366 FunctionInfo._(String serializedId) : super._fromId(serializedId); |
680 | 367 |
681 Map toJson() => super.toJson() | 368 dynamic accept(InfoVisitor visitor) => visitor.visitFunction(this); |
682 ..addAll({ | |
683 'children': closures.map((i) => i.serializedId).toList(), | |
684 'modifiers': modifiers.toJson(), | |
685 'returnType': returnType, | |
686 'inferredReturnType': inferredReturnType, | |
687 'parameters': parameters.map((p) => p.toJson()).toList(), | |
688 'sideEffects': sideEffects, | |
689 'inlinedCount': inlinedCount, | |
690 'code': code, | |
691 'type': type, | |
692 'measurements': measurements?.toJson(), | |
693 // Note: version 3.2 of dump-info serializes `uses` in a section called | |
694 // `holding` at the top-level. | |
695 }); | |
696 | |
697 void accept(InfoVisitor visitor) => visitor.visitFunction(this); | |
698 } | 369 } |
699 | 370 |
700 /// Information about how a dependency is used. | 371 /// Information about how a dependency is used. |
701 class DependencyInfo { | 372 class DependencyInfo { |
702 /// The dependency, either a FunctionInfo or FieldInfo. | 373 /// The dependency, either a FunctionInfo or FieldInfo. |
703 final Info target; | 374 final Info target; |
704 | 375 |
705 /// Either a selector mask indicating how this is used, or 'inlined'. | 376 /// Either a selector mask indicating how this is used, or 'inlined'. |
706 // TODO(sigmund): split mask into an enum or something more precise to really | 377 // TODO(sigmund): split mask into an enum or something more precise to really |
707 // describe the dependencies in detail. | 378 // describe the dependencies in detail. |
708 final String mask; | 379 final String mask; |
709 | 380 |
710 DependencyInfo(this.target, this.mask); | 381 DependencyInfo(this.target, this.mask); |
711 | |
712 Map toJson() => {'id': target.serializedId, 'mask': mask}; | |
713 } | 382 } |
714 | 383 |
715 /// Name and type information about a function parameter. | 384 /// Name and type information about a function parameter. |
716 class ParameterInfo { | 385 class ParameterInfo { |
717 final String name; | 386 final String name; |
718 final String type; | 387 final String type; |
719 final String declaredType; | 388 final String declaredType; |
720 | 389 |
721 ParameterInfo(this.name, this.type, this.declaredType); | 390 ParameterInfo(this.name, this.type, this.declaredType); |
722 | |
723 Map toJson() => {'name': name, 'type': type, 'declaredType': declaredType}; | |
724 } | 391 } |
725 | 392 |
726 /// Modifiers that may apply to methods. | 393 /// Modifiers that may apply to methods. |
727 class FunctionModifiers { | 394 class FunctionModifiers { |
728 final bool isStatic; | 395 final bool isStatic; |
729 final bool isConst; | 396 final bool isConst; |
730 final bool isFactory; | 397 final bool isFactory; |
731 final bool isExternal; | 398 final bool isExternal; |
732 | 399 |
733 FunctionModifiers( | 400 FunctionModifiers( |
734 {this.isStatic: false, | 401 {this.isStatic: false, |
735 this.isConst: false, | 402 this.isConst: false, |
736 this.isFactory: false, | 403 this.isFactory: false, |
737 this.isExternal: false}); | 404 this.isExternal: false}); |
738 | |
739 // TODO(sigmund): exclude false values (requires bumping the format version): | |
740 // Map toJson() { | |
741 // var res = <String, bool>{}; | |
742 // if (isStatic) res['static'] = true; | |
743 // if (isConst) res['const'] = true; | |
744 // if (isFactory) res['factory'] = true; | |
745 // if (isExternal) res['external'] = true; | |
746 // return res; | |
747 // } | |
748 Map toJson() => { | |
749 'static': isStatic, | |
750 'const': isConst, | |
751 'factory': isFactory, | |
752 'external': isExternal, | |
753 }; | |
754 } | 405 } |
755 | 406 |
756 /// Possible values of the `kind` field in the serialied infos. | 407 /// Possible values of the `kind` field in the serialied infos. |
757 enum InfoKind { | 408 enum InfoKind { |
758 library, | 409 library, |
759 clazz, | 410 clazz, |
760 function, | 411 function, |
761 field, | 412 field, |
762 constant, | 413 constant, |
763 outputUnit, | 414 outputUnit, |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
806 case 'outputUnit': | 457 case 'outputUnit': |
807 return InfoKind.outputUnit; | 458 return InfoKind.outputUnit; |
808 case 'typedef': | 459 case 'typedef': |
809 return InfoKind.typedef; | 460 return InfoKind.typedef; |
810 default: | 461 default: |
811 return null; | 462 return null; |
812 } | 463 } |
813 } | 464 } |
814 | 465 |
815 /// A simple visitor for information produced by the dart2js compiler. | 466 /// A simple visitor for information produced by the dart2js compiler. |
816 class InfoVisitor { | 467 abstract class InfoVisitor<T> { |
817 visitAll(AllInfo info) {} | 468 T visitAll(AllInfo info); |
818 visitProgram(ProgramInfo info) {} | 469 T visitProgram(ProgramInfo info); |
819 visitLibrary(LibraryInfo info) {} | 470 T visitLibrary(LibraryInfo info); |
820 visitClass(ClassInfo info) {} | 471 T visitClass(ClassInfo info); |
821 visitField(FieldInfo info) {} | 472 T visitField(FieldInfo info); |
822 visitConstant(ConstantInfo info) {} | 473 T visitConstant(ConstantInfo info); |
823 visitFunction(FunctionInfo info) {} | 474 T visitFunction(FunctionInfo info); |
824 visitTypedef(TypedefInfo info) {} | 475 T visitTypedef(TypedefInfo info); |
825 visitOutput(OutputUnitInfo info) {} | 476 T visitOutput(OutputUnitInfo info); |
826 } | 477 } |
827 | 478 |
828 /// A visitor that recursively walks each portion of the program. Because the | 479 /// A visitor that recursively walks each portion of the program. Because the |
829 /// info representation is redundant, this visitor only walks the structure of | 480 /// info representation is redundant, this visitor only walks the structure of |
830 /// the program and skips some redundant links. For example, even though | 481 /// the program and skips some redundant links. For example, even though |
831 /// visitAll contains references to functions, this visitor only recurses to | 482 /// visitAll contains references to functions, this visitor only recurses to |
832 /// visit libraries, then from each library we visit functions and classes, and | 483 /// visit libraries, then from each library we visit functions and classes, and |
833 /// so on. | 484 /// so on. |
834 class RecursiveInfoVisitor extends InfoVisitor { | 485 class RecursiveInfoVisitor extends InfoVisitor<Null> { |
Siggi Cherem (dart-lang)
2015/10/15 23:36:08
should we add <T> to the recursive visitor as well
Harry Terkelsen
2015/10/15 23:59:55
The default implementation won't work for any T be
| |
835 visitAll(AllInfo info) { | 486 visitAll(AllInfo info) { |
836 // Note: we don't visit functions, fields, classes, and typedefs because | 487 // Note: we don't visit functions, fields, classes, and typedefs because |
837 // they are reachable from the library info. | 488 // they are reachable from the library info. |
838 info.libraries.forEach(visitLibrary); | 489 info.libraries.forEach(visitLibrary); |
839 info.constants.forEach(visitConstant); | 490 info.constants.forEach(visitConstant); |
840 } | 491 } |
841 | 492 |
493 visitProgram(ProgramInfo info) {} | |
494 | |
842 visitLibrary(LibraryInfo info) { | 495 visitLibrary(LibraryInfo info) { |
843 info.topLevelFunctions.forEach(visitFunction); | 496 info.topLevelFunctions.forEach(visitFunction); |
844 info.topLevelVariables.forEach(visitField); | 497 info.topLevelVariables.forEach(visitField); |
845 info.classes.forEach(visitClass); | 498 info.classes.forEach(visitClass); |
846 info.typedefs.forEach(visitTypedef); | 499 info.typedefs.forEach(visitTypedef); |
847 } | 500 } |
848 | 501 |
849 visitClass(ClassInfo info) { | 502 visitClass(ClassInfo info) { |
850 info.functions.forEach(visitFunction); | 503 info.functions.forEach(visitFunction); |
851 info.fields.forEach(visitField); | 504 info.fields.forEach(visitField); |
852 } | 505 } |
853 | 506 |
854 visitField(FieldInfo info) { | 507 visitField(FieldInfo info) { |
855 info.closures.forEach(visitFunction); | 508 info.closures.forEach(visitFunction); |
856 } | 509 } |
857 | 510 |
511 visitConstant(ConstantInfo info) {} | |
512 | |
858 visitFunction(FunctionInfo info) { | 513 visitFunction(FunctionInfo info) { |
859 info.closures.forEach(visitFunction); | 514 info.closures.forEach(visitFunction); |
860 } | 515 } |
516 | |
517 visitTypedef(TypedefInfo info) {} | |
518 visitOutput(OutputUnitInfo info) {} | |
861 } | 519 } |
OLD | NEW |