| 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 collected by the dump-info task. | 5 /// Data collected by the dump-info task. |
| 6 library compiler.src.lib.info; | 6 library compiler.src.lib.info; |
| 7 | 7 |
| 8 // Note: this file intentionally doesn't import anything from the compiler. That | 8 // Note: this file intentionally doesn't import anything from the compiler. That |
| 9 // should make it easier for tools to depend on this library. The idea is that | 9 // should make it easier for tools to depend on this library. The idea is that |
| 10 // by using this library, tools can consume the information in the same way it | 10 // by using this library, tools can consume the information in the same way it |
| 11 // is produced by the compiler. | 11 // is produced by the compiler. |
| 12 // TODO(sigmund): make this a proper public API (export this explicitly at the | 12 // TODO(sigmund): make this a proper public API (export this explicitly at the |
| 13 // lib folder level.) | 13 // lib folder level.) |
| 14 | 14 |
| 15 /// Common interface to many pieces of information generated by the compiler. | 15 /// Common interface to many pieces of information generated by the compiler. |
| 16 abstract class Info { | 16 abstract class Info { |
| 17 /// An identifier for the kind of information. | 17 /// An identifier for the kind of information. |
| 18 String get kind; | 18 InfoKind get kind; |
| 19 | 19 |
| 20 /// Name of the element associated with this info. | 20 /// Name of the element associated with this info. |
| 21 String name; | 21 String name; |
| 22 | 22 |
| 23 /// An id to uniquely identify this info among infos of the same [kind]. | 23 /// An id to uniquely identify this info among infos of the same [kind]. |
| 24 int get id; | 24 int get id; |
| 25 | 25 |
| 26 /// A globally unique id combining [kind] and [id] together. | 26 /// A globally unique id combining [kind] and [id] together. |
| 27 String get serializedId; | 27 String get serializedId; |
| 28 | 28 |
| 29 /// Bytes used in the generated code for the corresponding element. | 29 /// Bytes used in the generated code for the corresponding element. |
| 30 int size; | 30 int size; |
| 31 | 31 |
| 32 /// Serializes the information into a JSON format. | 32 /// Serializes the information into a JSON format. |
| 33 // TODO(sigmund): refactor and put toJson outside the class, so we can have 2 | 33 // TODO(sigmund): refactor and put toJson outside the class, so we can have 2 |
| 34 // different serializer/deserializers at once. | 34 // different serializer/deserializers at once. |
| 35 Map toJson(); | 35 Map toJson(); |
| 36 |
| 37 void accept(InfoVisitor visitor); |
| 36 } | 38 } |
| 37 | 39 |
| 38 /// Common information used for most kind of elements. | 40 /// Common information used for most kind of elements. |
| 39 // TODO(sigmund): add more: | 41 // TODO(sigmund): add more: |
| 40 // - inputSize: bytes used in the Dart source program | 42 // - inputSize: bytes used in the Dart source program |
| 41 abstract class BasicInfo implements Info { | 43 abstract class BasicInfo implements Info { |
| 42 final String kind; | 44 final InfoKind kind; |
| 43 final int id; | 45 final int id; |
| 44 int size; | 46 int size; |
| 45 | 47 |
| 46 String get serializedId => '$kind/$id'; | 48 String get serializedId => '${_kindToString(kind)}/$id'; |
| 47 | 49 |
| 48 String name; | 50 String name; |
| 49 | 51 |
| 50 /// If using deferred libraries, where the element associated with this info | 52 /// If using deferred libraries, where the element associated with this info |
| 51 /// is generated. | 53 /// is generated. |
| 52 OutputUnitInfo outputUnit; | 54 OutputUnitInfo outputUnit; |
| 53 | 55 |
| 54 BasicInfo(this.kind, this.id, this.name, this.outputUnit, this.size); | 56 BasicInfo(this.kind, this.id, this.name, this.outputUnit, this.size); |
| 55 | 57 |
| 58 BasicInfo._fromId(String serializedId) |
| 59 : kind = _kindFromSerializedId(serializedId), |
| 60 id = _idFromSerializedId(serializedId); |
| 61 |
| 56 Map toJson() { | 62 Map toJson() { |
| 57 var res = {'id': serializedId, 'kind': kind, 'name': name, 'size': size}; | 63 var res = { |
| 64 'id': serializedId, |
| 65 'kind': _kindToString(kind), |
| 66 'name': name, |
| 67 'size': size, |
| 68 }; |
| 58 // TODO(sigmund): omit this also when outputUnit.id == 0 | 69 // TODO(sigmund): omit this also when outputUnit.id == 0 |
| 59 // (most code is by default in the main output unit) | 70 // (most code is by default in the main output unit) |
| 60 if (outputUnit != null) res['outputUnit'] = outputUnit.serializedId; | 71 if (outputUnit != null) res['outputUnit'] = outputUnit.serializedId; |
| 61 return res; | 72 return res; |
| 62 } | 73 } |
| 63 | 74 |
| 64 String toString() => '$serializedId $name [$size]'; | 75 String toString() => '$serializedId $name [$size]'; |
| 65 } | 76 } |
| 66 | 77 |
| 67 /// Info associated with elements containing executable code (like fields and | 78 /// Info associated with elements containing executable code (like fields and |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 110 | 121 |
| 111 /// Minor version indicating non-breaking changes in the format. A change in | 122 /// Minor version indicating non-breaking changes in the format. A change in |
| 112 /// this version number means that the json parsing in this library from a | 123 /// this version number means that the json parsing in this library from a |
| 113 /// previous will continue to work after the change. This is typically | 124 /// previous will continue to work after the change. This is typically |
| 114 /// increased when adding new entries to the file format. | 125 /// increased when adding new entries to the file format. |
| 115 // Note: the dump-info.viewer app was written using a json parser version 3.2. | 126 // Note: the dump-info.viewer app was written using a json parser version 3.2. |
| 116 final int minorVersion = 3; | 127 final int minorVersion = 3; |
| 117 | 128 |
| 118 AllInfo(); | 129 AllInfo(); |
| 119 | 130 |
| 131 static AllInfo parseFromJson(Map map) => new _ParseHelper().parseAll(map); |
| 132 |
| 120 Map _listAsJsonMap(List<Info> list) { | 133 Map _listAsJsonMap(List<Info> list) { |
| 121 var map = <String, Map>{}; | 134 var map = <String, Map>{}; |
| 122 for (var info in list) { | 135 for (var info in list) { |
| 123 map['${info.id}'] = info.toJson(); | 136 map['${info.id}'] = info.toJson(); |
| 124 } | 137 } |
| 125 return map; | 138 return map; |
| 126 } | 139 } |
| 127 | 140 |
| 128 Map _extractHoldingInfo() { | 141 Map _extractHoldingInfo() { |
| 129 var map = <String, List>{}; | 142 var map = <String, List>{}; |
| 130 void helper(CodeInfo info) { | 143 void helper(CodeInfo info) { |
| 131 if (info.uses.isEmpty) return; | 144 if (info.uses.isEmpty) return; |
| 132 map[info.serializedId] = info.uses.map((u) => u.toJson()).toList(); | 145 map[info.serializedId] = info.uses.map((u) => u.toJson()).toList(); |
| 133 } | 146 } |
| 134 functions.forEach(helper); | 147 functions.forEach(helper); |
| 135 fields.forEach(helper); | 148 fields.forEach(helper); |
| 136 return map; | 149 return map; |
| 137 } | 150 } |
| 138 | 151 |
| 139 // TODO(sigmund): implement fromJson | |
| 140 Map toJson() => { | 152 Map toJson() => { |
| 141 'elements': { | 153 'elements': { |
| 142 'library': _listAsJsonMap(libraries), | 154 'library': _listAsJsonMap(libraries), |
| 143 'class': _listAsJsonMap(classes), | 155 'class': _listAsJsonMap(classes), |
| 144 'function': _listAsJsonMap(functions), | 156 'function': _listAsJsonMap(functions), |
| 145 'typedef': _listAsJsonMap(typedefs), | 157 'typedef': _listAsJsonMap(typedefs), |
| 146 'field': _listAsJsonMap(fields), | 158 'field': _listAsJsonMap(fields), |
| 147 }, | 159 }, |
| 148 'holding': _extractHoldingInfo(), | 160 'holding': _extractHoldingInfo(), |
| 149 'outputUnits': outputUnits.map((u) => u.toJson()).toList(), | 161 'outputUnits': outputUnits.map((u) => u.toJson()).toList(), |
| 150 'dump_version': version, | 162 'dump_version': version, |
| 151 'deferredFiles': deferredFiles, | 163 'deferredFiles': deferredFiles, |
| 152 'dump_minor_version': '$minorVersion', | 164 'dump_minor_version': '$minorVersion', |
| 153 // TODO(sigmund): change viewer to accept an int? | 165 // TODO(sigmund): change viewer to accept an int? |
| 154 'program': program.toJson(), | 166 'program': program.toJson(), |
| 155 }; | 167 }; |
| 168 |
| 169 void accept(InfoVisitor visitor) => visitor.visitAll(this); |
| 156 } | 170 } |
| 157 | 171 |
| 158 class ProgramInfo { | 172 class ProgramInfo { |
| 159 int size; | 173 int size; |
| 160 String dart2jsVersion; | 174 String dart2jsVersion; |
| 161 DateTime compilationMoment; | 175 DateTime compilationMoment; |
| 162 Duration compilationDuration; | 176 Duration compilationDuration; |
| 163 // TODO(sigmund): use Duration. | 177 // TODO(sigmund): use Duration. |
| 164 int toJsonDuration; | 178 int toJsonDuration; |
| 165 int dumpInfoDuration; | 179 int dumpInfoDuration; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 179 Map toJson() => { | 193 Map toJson() => { |
| 180 'size': size, | 194 'size': size, |
| 181 'dart2jsVersion': dart2jsVersion, | 195 'dart2jsVersion': dart2jsVersion, |
| 182 'compilationMoment': '$compilationMoment', | 196 'compilationMoment': '$compilationMoment', |
| 183 'compilationDuration': '${compilationDuration}', | 197 'compilationDuration': '${compilationDuration}', |
| 184 'toJsonDuration': toJsonDuration, | 198 'toJsonDuration': toJsonDuration, |
| 185 'dumpInfoDuration': '$dumpInfoDuration', | 199 'dumpInfoDuration': '$dumpInfoDuration', |
| 186 'noSuchMethodEnabled': noSuchMethodEnabled, | 200 'noSuchMethodEnabled': noSuchMethodEnabled, |
| 187 'minified': minified, | 201 'minified': minified, |
| 188 }; | 202 }; |
| 203 |
| 204 void accept(InfoVisitor visitor) => visitor.visitProgram(this); |
| 189 } | 205 } |
| 190 | 206 |
| 207 // TODO(sigmund): add unit tests. |
| 208 class _ParseHelper { |
| 209 Map<String, Info> registry = {}; |
| 210 |
| 211 AllInfo parseAll(Map json) { |
| 212 var result = new AllInfo(); |
| 213 var elements = json['elements']; |
| 214 result.libraries.addAll(elements['library'].values.map(parseLibrary)); |
| 215 result.classes.addAll(elements['class'].values.map(parseClass)); |
| 216 result.functions.addAll(elements['function'].values.map(parseFunction)); |
| 217 result.fields.addAll(elements['field'].values.map(parseField)); |
| 218 result.typedefs.addAll(elements['typedef'].values.map(parseTypedef)); |
| 219 |
| 220 var idMap = {}; |
| 221 for (var f in result.functions) { |
| 222 idMap[f.serializedId] = f; |
| 223 } |
| 224 for (var f in result.fields) { |
| 225 idMap[f.serializedId] = f; |
| 226 } |
| 227 |
| 228 json['holding'].forEach((k, deps) { |
| 229 var src = idMap[k]; |
| 230 assert (src != null); |
| 231 for (var dep in deps) { |
| 232 var target = idMap[dep['id']]; |
| 233 assert (target != null); |
| 234 src.uses.add(new DependencyInfo(target, dep['mask'])); |
| 235 } |
| 236 }); |
| 237 |
| 238 result.program = parseProgram(json['program']); |
| 239 // todo: version, etc |
| 240 return result; |
| 241 } |
| 242 |
| 243 LibraryInfo parseLibrary(Map json) { |
| 244 var result = parseId(json['id']) |
| 245 ..name = json['name'] |
| 246 ..uri = Uri.parse(json['canonicalUri']) |
| 247 ..outputUnit = parseId(json['outputUnit']) |
| 248 ..size = json['size']; |
| 249 assert(result is LibraryInfo); |
| 250 for (var child in json['children'].map(parseId)) { |
| 251 if (child is FunctionInfo) { |
| 252 result.topLevelFunctions.add(child); |
| 253 } else if (child is FieldInfo) { |
| 254 result.topLevelVariables.add(child); |
| 255 } else if (child is ClassInfo) { |
| 256 result.classes.add(child); |
| 257 } else { |
| 258 assert(child is TypedefInfo); |
| 259 result.typedefs.add(child); |
| 260 } |
| 261 } |
| 262 return result; |
| 263 } |
| 264 |
| 265 ClassInfo parseClass(Map json) { |
| 266 var result = parseId(json['id']) |
| 267 ..name = json['name'] |
| 268 ..outputUnit = parseId(json['outputUnit']) |
| 269 ..size = json['size'] |
| 270 ..isAbstract = json['modifiers']['abstract'] == true; |
| 271 assert(result is ClassInfo); |
| 272 for (var child in json['children'].map(parseId)) { |
| 273 if (child is FunctionInfo) { |
| 274 result.functions.add(child); |
| 275 } else { |
| 276 assert(child is FieldInfo); |
| 277 result.fields.add(child); |
| 278 } |
| 279 } |
| 280 return result; |
| 281 } |
| 282 |
| 283 FieldInfo parseField(Map json) { |
| 284 return parseId(json['id']) |
| 285 ..name = json['name'] |
| 286 ..outputUnit = parseId(json['outputUnit']) |
| 287 ..size = json['size'] |
| 288 ..type = json['type'] |
| 289 ..inferredType = json['inferredType'] |
| 290 ..code = json['code'] |
| 291 ..closures = json['children'].map(parseId).toList(); |
| 292 } |
| 293 |
| 294 TypedefInfo parseTypedef(Map json) => parseId(json['id']) |
| 295 ..name = json['name'] |
| 296 ..type = json['type'] |
| 297 ..size = 0; |
| 298 |
| 299 ProgramInfo parseProgram(Map json) => |
| 300 new ProgramInfo()..size = json['size']; |
| 301 |
| 302 FunctionInfo parseFunction(Map json) { |
| 303 return parseId(json['id']) |
| 304 ..name = json['name'] |
| 305 ..outputUnit = parseId(json['outputUnit']) |
| 306 ..size = json['size'] |
| 307 ..type = json['type'] |
| 308 ..returnType = json['returnType'] |
| 309 ..inferredReturnType = json['inferredReturnType'] |
| 310 ..parameters = json['parameters'].map(parseParameter).toList() |
| 311 ..code = json['code'] |
| 312 ..sideEffects = json['sideEffects'] |
| 313 ..modifiers = parseModifiers(json['modifiers']) |
| 314 ..closures = json['children'].map(parseId).toList(); |
| 315 } |
| 316 |
| 317 ParameterInfo parseParameter(Map json) => |
| 318 new ParameterInfo(json['name'], json['type'], json['declaredType']); |
| 319 |
| 320 FunctionModifiers parseModifiers(Map<String, bool> json) { |
| 321 return new FunctionModifiers( |
| 322 isStatic: json['static'] == true, |
| 323 isConst: json['const'] == true, |
| 324 isFactory: json['factory'] == true, |
| 325 isExternal: json['external'] == true); |
| 326 } |
| 327 |
| 328 Info parseId(String serializedId) => registry.putIfAbsent(serializedId, () { |
| 329 if (serializedId == null) { |
| 330 return null; |
| 331 } else if (serializedId.startsWith('function/')) { |
| 332 return new FunctionInfo._(serializedId); |
| 333 } else if (serializedId.startsWith('library/')) { |
| 334 return new LibraryInfo._(serializedId); |
| 335 } else if (serializedId.startsWith('class/')) { |
| 336 return new ClassInfo._(serializedId); |
| 337 } else if (serializedId.startsWith('field/')) { |
| 338 return new FieldInfo._(serializedId); |
| 339 } else if (serializedId.startsWith('typedef/')) { |
| 340 return new TypedefInfo._(serializedId); |
| 341 } else if (serializedId.startsWith('outputUnit/')) { |
| 342 return new OutputUnitInfo._(serializedId); |
| 343 } |
| 344 assert(false); |
| 345 }); |
| 346 } |
| 347 |
| 348 /// Info associated with a library element. |
| 191 class LibraryInfo extends BasicInfo { | 349 class LibraryInfo extends BasicInfo { |
| 350 /// Canonical uri that identifies the library. |
| 192 Uri uri; | 351 Uri uri; |
| 352 |
| 353 /// Top level functions defined within the library. |
| 193 final List<FunctionInfo> topLevelFunctions = <FunctionInfo>[]; | 354 final List<FunctionInfo> topLevelFunctions = <FunctionInfo>[]; |
| 355 |
| 356 /// Top level fields defined within the library. |
| 194 final List<FieldInfo> topLevelVariables = <FieldInfo>[]; | 357 final List<FieldInfo> topLevelVariables = <FieldInfo>[]; |
| 358 |
| 359 /// Classes defined within the library. |
| 195 final List<ClassInfo> classes = <ClassInfo>[]; | 360 final List<ClassInfo> classes = <ClassInfo>[]; |
| 361 |
| 362 /// Typedefs defined within the library. |
| 196 final List<TypedefInfo> typedefs = <TypedefInfo>[]; | 363 final List<TypedefInfo> typedefs = <TypedefInfo>[]; |
| 197 | 364 |
| 198 static int _id = 0; | 365 static int _id = 0; |
| 199 | 366 |
| 367 /// Whether there is any information recorded for this library. |
| 200 bool get isEmpty => | 368 bool get isEmpty => |
| 201 topLevelFunctions.isEmpty && topLevelVariables.isEmpty && classes.isEmpty; | 369 topLevelFunctions.isEmpty && topLevelVariables.isEmpty && classes.isEmpty; |
| 202 | 370 |
| 203 LibraryInfo(String name, this.uri, OutputUnitInfo outputUnit, int size) | 371 LibraryInfo(String name, this.uri, OutputUnitInfo outputUnit, int size) |
| 204 : super('library', _id++, name, outputUnit, size); | 372 : super(InfoKind.library, _id++, name, outputUnit, size); |
| 373 |
| 374 LibraryInfo._(String serializedId) : super._fromId(serializedId); |
| 205 | 375 |
| 206 Map toJson() => super.toJson() | 376 Map toJson() => super.toJson() |
| 207 ..addAll({ | 377 ..addAll({ |
| 208 'children': [] | 378 'children': [] |
| 209 ..addAll(topLevelFunctions.map((f) => f.serializedId)) | 379 ..addAll(topLevelFunctions.map((f) => f.serializedId)) |
| 210 ..addAll(topLevelVariables.map((v) => v.serializedId)) | 380 ..addAll(topLevelVariables.map((v) => v.serializedId)) |
| 211 ..addAll(classes.map((c) => c.serializedId)) | 381 ..addAll(classes.map((c) => c.serializedId)) |
| 212 ..addAll(typedefs.map((t) => t.serializedId)), | 382 ..addAll(typedefs.map((t) => t.serializedId)), |
| 213 'canonicalUri': '$uri', | 383 'canonicalUri': '$uri', |
| 214 }); | 384 }); |
| 385 |
| 386 void accept(InfoVisitor visitor) => visitor.visitLibrary(this); |
| 215 } | 387 } |
| 216 | 388 |
| 389 /// Information about an output unit. Normally there is just one for the entire |
| 390 /// program unless the application uses deferred imports, in which case there |
| 391 /// would be an additional output unit per deferred chunk. |
| 217 class OutputUnitInfo extends BasicInfo { | 392 class OutputUnitInfo extends BasicInfo { |
| 218 static int _ids = 0; | 393 static int _ids = 0; |
| 219 OutputUnitInfo(String name, int size) | 394 OutputUnitInfo(String name, int size) |
| 220 : super('outputUnit', _ids++, name, null, size); | 395 : super(InfoKind.outputUnit, _ids++, name, null, size); |
| 396 |
| 397 OutputUnitInfo._(String serializedId) : super._fromId(serializedId); |
| 398 |
| 399 void accept(InfoVisitor visitor) => visitor.visitOutput(this); |
| 221 } | 400 } |
| 222 | 401 |
| 402 /// Information about a class element. |
| 223 class ClassInfo extends BasicInfo { | 403 class ClassInfo extends BasicInfo { |
| 404 /// Whether the class is abstract. |
| 224 bool isAbstract; | 405 bool isAbstract; |
| 225 | 406 |
| 226 // TODO(sigmund): split static vs instance vs closures | 407 // TODO(sigmund): split static vs instance vs closures |
| 408 /// Functions (static or instance) defined in the class. |
| 227 final List<FunctionInfo> functions = <FunctionInfo>[]; | 409 final List<FunctionInfo> functions = <FunctionInfo>[]; |
| 410 |
| 411 /// Fields defined in the class. |
| 412 // TODO(sigmund): currently appears to only be populated with instance fields, |
| 413 // but this should be fixed. |
| 228 final List<FieldInfo> fields = <FieldInfo>[]; | 414 final List<FieldInfo> fields = <FieldInfo>[]; |
| 229 static int _ids = 0; | 415 static int _ids = 0; |
| 230 | 416 |
| 231 ClassInfo( | 417 ClassInfo( |
| 232 {String name, this.isAbstract, OutputUnitInfo outputUnit, int size: 0}) | 418 {String name, this.isAbstract, OutputUnitInfo outputUnit, int size: 0}) |
| 233 : super('class', _ids++, name, outputUnit, size); | 419 : super(InfoKind.clazz, _ids++, name, outputUnit, size); |
| 420 |
| 421 ClassInfo._(String serializedId) : super._fromId(serializedId); |
| 234 | 422 |
| 235 Map toJson() => super.toJson() | 423 Map toJson() => super.toJson() |
| 236 ..addAll({ | 424 ..addAll({ |
| 237 // TODO(sigmund): change format, include only when abstract is true. | 425 // TODO(sigmund): change format, include only when abstract is true. |
| 238 'modifiers': {'abstract': isAbstract}, | 426 'modifiers': {'abstract': isAbstract}, |
| 239 'children': [] | 427 'children': [] |
| 240 ..addAll(fields.map((f) => f.serializedId)) | 428 ..addAll(fields.map((f) => f.serializedId)) |
| 241 ..addAll(functions.map((m) => m.serializedId)) | 429 ..addAll(functions.map((m) => m.serializedId)) |
| 242 }); | 430 }); |
| 431 |
| 432 void accept(InfoVisitor visitor) => visitor.visitClass(this); |
| 243 } | 433 } |
| 244 | 434 |
| 435 /// Information about a field element. |
| 245 class FieldInfo extends BasicInfo with CodeInfo { | 436 class FieldInfo extends BasicInfo with CodeInfo { |
| 437 /// The type of the field. |
| 246 String type; | 438 String type; |
| 439 |
| 440 /// The type inferred by dart2js's whole program analysis |
| 247 String inferredType; | 441 String inferredType; |
| 442 |
| 443 /// Nested closures seen in the field initializer. |
| 248 List<FunctionInfo> closures; | 444 List<FunctionInfo> closures; |
| 445 |
| 446 /// The actual generated code for the field. |
| 249 String code; | 447 String code; |
| 250 | 448 |
| 251 static int _ids = 0; | 449 static int _ids = 0; |
| 252 FieldInfo( | 450 FieldInfo( |
| 253 {String name, | 451 {String name, |
| 254 int size: 0, | 452 int size: 0, |
| 255 this.type, | 453 this.type, |
| 256 this.inferredType, | 454 this.inferredType, |
| 257 this.closures, | 455 this.closures, |
| 258 this.code, | 456 this.code, |
| 259 OutputUnitInfo outputUnit}) | 457 OutputUnitInfo outputUnit}) |
| 260 : super('field', _ids++, name, outputUnit, size); | 458 : super(InfoKind.field, _ids++, name, outputUnit, size); |
| 459 |
| 460 FieldInfo._(String serializedId) : super._fromId(serializedId); |
| 261 | 461 |
| 262 Map toJson() => super.toJson() | 462 Map toJson() => super.toJson() |
| 263 ..addAll({ | 463 ..addAll({ |
| 264 'children': closures.map((i) => i.serializedId).toList(), | 464 'children': closures.map((i) => i.serializedId).toList(), |
| 265 'inferredType': inferredType, | 465 'inferredType': inferredType, |
| 266 'code': code, | 466 'code': code, |
| 267 'type': type, | 467 'type': type, |
| 268 }); | 468 }); |
| 469 |
| 470 void accept(InfoVisitor visitor) => visitor.visitField(this); |
| 269 } | 471 } |
| 270 | 472 |
| 473 /// Information about a typedef declaration. |
| 271 class TypedefInfo extends BasicInfo { | 474 class TypedefInfo extends BasicInfo { |
| 475 /// The declared type. |
| 272 String type; | 476 String type; |
| 273 | 477 |
| 274 static int _ids = 0; | 478 static int _ids = 0; |
| 275 TypedefInfo(String name, this.type, OutputUnitInfo outputUnit) | 479 TypedefInfo(String name, this.type, OutputUnitInfo outputUnit) |
| 276 : super('typedef', _ids++, name, outputUnit, 0); | 480 : super(InfoKind.typedef, _ids++, name, outputUnit, 0); |
| 481 |
| 482 TypedefInfo._(String serializedId) : super._fromId(serializedId); |
| 277 | 483 |
| 278 Map toJson() => super.toJson()..['type'] = '$type'; | 484 Map toJson() => super.toJson()..['type'] = '$type'; |
| 485 |
| 486 void accept(InfoVisitor visitor) => visitor.visitTypedef(this); |
| 279 } | 487 } |
| 280 | 488 |
| 489 /// Information about a function or method. |
| 281 class FunctionInfo extends BasicInfo with CodeInfo { | 490 class FunctionInfo extends BasicInfo with CodeInfo { |
| 282 static const int TOP_LEVEL_FUNCTION_KIND = 0; | 491 static const int TOP_LEVEL_FUNCTION_KIND = 0; |
| 283 static const int CLOSURE_FUNCTION_KIND = 1; | 492 static const int CLOSURE_FUNCTION_KIND = 1; |
| 284 static const int METHOD_FUNCTION_KIND = 2; | 493 static const int METHOD_FUNCTION_KIND = 2; |
| 285 static const int CONSTRUCTOR_FUNCTION_KIND = 3; | 494 static const int CONSTRUCTOR_FUNCTION_KIND = 3; |
| 286 static int _ids = 0; | 495 static int _ids = 0; |
| 287 | 496 |
| 288 /// Kind of function (top-level function, closure, method, or constructor). | 497 /// Kind of function (top-level function, closure, method, or constructor). |
| 289 final int functionKind; | 498 int functionKind; |
| 290 | 499 |
| 291 /// Modifiers applied to this function. | 500 /// Modifiers applied to this function. |
| 292 final FunctionModifiers modifiers; | 501 FunctionModifiers modifiers; |
| 293 | 502 |
| 294 /// Nested closures that appear within the body of this function. | 503 /// Nested closures that appear within the body of this function. |
| 295 List<FunctionInfo> closures; | 504 List<FunctionInfo> closures; |
| 296 | 505 |
| 297 /// The type of this function. | 506 /// The type of this function. |
| 298 String type; | 507 String type; |
| 299 | 508 |
| 300 /// The declared return type. | 509 /// The declared return type. |
| 301 String returnType; | 510 String returnType; |
| 302 | 511 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 323 this.functionKind, | 532 this.functionKind, |
| 324 this.modifiers, | 533 this.modifiers, |
| 325 this.closures, | 534 this.closures, |
| 326 this.type, | 535 this.type, |
| 327 this.returnType, | 536 this.returnType, |
| 328 this.inferredReturnType, | 537 this.inferredReturnType, |
| 329 this.parameters, | 538 this.parameters, |
| 330 this.sideEffects, | 539 this.sideEffects, |
| 331 this.inlinedCount, | 540 this.inlinedCount, |
| 332 this.code}) | 541 this.code}) |
| 333 : super('function', _ids++, name, outputUnit, size); | 542 : super(InfoKind.function, _ids++, name, outputUnit, size); |
| 543 |
| 544 FunctionInfo._(String serializedId) : super._fromId(serializedId); |
| 334 | 545 |
| 335 Map toJson() => super.toJson() | 546 Map toJson() => super.toJson() |
| 336 ..addAll({ | 547 ..addAll({ |
| 337 'children': closures.map((i) => i.serializedId).toList(), | 548 'children': closures.map((i) => i.serializedId).toList(), |
| 338 'modifiers': modifiers.toJson(), | 549 'modifiers': modifiers.toJson(), |
| 339 'returnType': returnType, | 550 'returnType': returnType, |
| 340 'inferredReturnType': inferredReturnType, | 551 'inferredReturnType': inferredReturnType, |
| 341 'parameters': parameters.map((p) => p.toJson()).toList(), | 552 'parameters': parameters.map((p) => p.toJson()).toList(), |
| 342 'sideEffects': sideEffects, | 553 'sideEffects': sideEffects, |
| 343 'inlinedCount': inlinedCount, | 554 'inlinedCount': inlinedCount, |
| 344 'code': code, | 555 'code': code, |
| 345 'type': type, | 556 'type': type, |
| 346 // Note: version 3.2 of dump-info serializes `uses` in a section called | 557 // Note: version 3.2 of dump-info serializes `uses` in a section called |
| 347 // `holding` at the top-level. | 558 // `holding` at the top-level. |
| 348 }); | 559 }); |
| 560 |
| 561 void accept(InfoVisitor visitor) => visitor.visitFunction(this); |
| 349 } | 562 } |
| 350 | 563 |
| 351 /// Information about how a dependency is used. | 564 /// Information about how a dependency is used. |
| 352 class DependencyInfo { | 565 class DependencyInfo { |
| 353 /// The dependency, either a FunctionInfo or FieldInfo. | 566 /// The dependency, either a FunctionInfo or FieldInfo. |
| 354 final Info target; | 567 final Info target; |
| 355 | 568 |
| 356 /// Either a selector mask indicating how this is used, or 'inlined'. | 569 /// Either a selector mask indicating how this is used, or 'inlined'. |
| 357 // TODO(sigmund): split mask into an enum or something more precise to really | 570 // TODO(sigmund): split mask into an enum or something more precise to really |
| 358 // describe the dependencies in detail. | 571 // describe the dependencies in detail. |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 396 // if (isExternal) res['external'] = true; | 609 // if (isExternal) res['external'] = true; |
| 397 // return res; | 610 // return res; |
| 398 // } | 611 // } |
| 399 Map toJson() => { | 612 Map toJson() => { |
| 400 'static': isStatic, | 613 'static': isStatic, |
| 401 'const': isConst, | 614 'const': isConst, |
| 402 'factory': isFactory, | 615 'factory': isFactory, |
| 403 'external': isExternal, | 616 'external': isExternal, |
| 404 }; | 617 }; |
| 405 } | 618 } |
| 619 |
| 620 /// Possible values of the `kind` field in the serialied infos. |
| 621 enum InfoKind { |
| 622 library, |
| 623 clazz, |
| 624 function, |
| 625 field, |
| 626 outputUnit, |
| 627 typedef, |
| 628 } |
| 629 |
| 630 String _kindToString(InfoKind kind) { |
| 631 switch(kind) { |
| 632 case InfoKind.library: return 'library'; |
| 633 case InfoKind.clazz: return 'class'; |
| 634 case InfoKind.function: return 'function'; |
| 635 case InfoKind.field: return 'field'; |
| 636 case InfoKind.outputUnit: return 'outputUnit'; |
| 637 case InfoKind.typedef: return 'typedef'; |
| 638 default: return null; |
| 639 } |
| 640 } |
| 641 |
| 642 int _idFromSerializedId(String serialiedId) => |
| 643 int.parse(serializedId.substring(serializedId.indexOf('/') + 1)); |
| 644 |
| 645 String _kindFromSerializedId(String serializedId) => |
| 646 _kindFromString(serializedId.substring(0, serializedId.indexOf('/'))); |
| 647 |
| 648 InfoKind _kindFromString(String kind) { |
| 649 switch(kind) { |
| 650 case 'library': return InfoKind.library; |
| 651 case 'class': return InfoKind.clazz; |
| 652 case 'function': return InfoKind.function; |
| 653 case 'field': return InfoKind.field; |
| 654 case 'outputUnit': return InfoKind.outputUnit; |
| 655 case 'typedef': return InfoKind.typedef; |
| 656 default: return null; |
| 657 } |
| 658 } |
| 659 |
| 660 /// A simple visitor for information produced by the dart2js compiler. |
| 661 class InfoVisitor { |
| 662 visitAll(AllInfo info) {} |
| 663 visitProgram(ProgramInfo info) {} |
| 664 visitLibrary(LibraryInfo info) {} |
| 665 visitClass(ClassInfo info) {} |
| 666 visitField(FieldInfo info) {} |
| 667 visitFunction(FunctionInfo info) {} |
| 668 visitTypedef(TypedefInfo info) {} |
| 669 visitOutput(OutputUnitInfo info) {} |
| 670 } |
| 671 |
| 672 /// A visitor that recursively walks each portion of the program. Because the |
| 673 /// info representation is redundant, this visitor only walks the structure of |
| 674 /// the program and skips some redundant links. For example, even though |
| 675 /// visitAll contains references to functions, this visitor only recurses to |
| 676 /// visit libraries, then from each library we visit functions and classes, and |
| 677 /// so on. |
| 678 class RecursiveInfoVisitor extends InfoVisitor { |
| 679 visitAll(AllInfo info) { |
| 680 // Note: we don't visit functions, fields, classes, and typedefs because |
| 681 // they are reachable from the library info. |
| 682 info.libraries.forEach(visitLibrary); |
| 683 } |
| 684 |
| 685 visitLibrary(LibraryInfo info) { |
| 686 info.topLevelFunctions.forEach(visitFunction); |
| 687 info.topLevelVariables.forEach(visitField); |
| 688 info.classes.forEach(visitClass); |
| 689 info.typedefs.forEach(visitTypedef); |
| 690 } |
| 691 |
| 692 visitClass(ClassInfo info) { |
| 693 info.functions.forEach(visitFunction); |
| 694 info.fields.forEach(visitField); |
| 695 } |
| 696 |
| 697 visitField(FieldInfo info) { |
| 698 info.closures.forEach(visitFunction); |
| 699 } |
| 700 |
| 701 visitFunction(FunctionInfo info) { |
| 702 info.closures.forEach(visitFunction); |
| 703 } |
| 704 } |
| OLD | NEW |