Chromium Code Reviews| 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 |