Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 /// Data collected by the dump-info task. | |
| 6 library compiler.src.lib.info; | |
| 7 | |
| 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 | |
| 10 // by using this library, tools can consume the information in the same way it | |
| 11 // is produced by the compiler. | |
| 12 // TODO(sigmund): make this a proper public API (export this explicitly at the | |
| 13 // lib folder level.) | |
| 14 | |
| 15 /// Common interface to many pieces of information generated by the compiler. | |
| 16 abstract class Info { | |
| 17 /// An identifier for the kind of information. | |
| 18 String get kind; | |
| 19 | |
| 20 /// An unique id used to create references to this info. | |
| 21 int get id; | |
| 22 | |
| 23 /// Serializes the information into a JSON format. | |
| 24 Map toJson(); | |
| 25 } | |
| 26 | |
| 27 /// Common information used for most kind of elements. | |
| 28 // TODO(sigmund): add more: | |
| 29 // - inputSize: bytes used in the Dart source program | |
| 30 // - transitiveSize: bytes including the size of dependencies that are only | |
| 31 // retained because of this element. | |
| 32 class BasicInfo implements Info { | |
| 33 final String kind; | |
| 34 final int id; | |
| 35 | |
| 36 /// Bytes used in the generated code for the corresponding element. | |
| 37 int size; | |
| 38 | |
| 39 String get serializedId => '$kind/$id'; | |
| 40 | |
| 41 // TODO(sigmund): make final (currently not final because we amend the name in | |
|
Johnni Winther
2015/07/27 10:14:42
'name in of' -> 'name of'
Siggi Cherem (dart-lang)
2015/07/27 20:10:59
Done.
| |
| 42 // of nested closures to record their enclosing element). | |
| 43 String name; | |
| 44 | |
| 45 /// If using deferred libraries, where the element associated with this info | |
| 46 /// is generated. | |
| 47 final OutputUnitInfo outputUnit; | |
| 48 | |
| 49 BasicInfo(this.kind, this.id, this.name, this.outputUnit, [this.size = 0]); | |
| 50 | |
| 51 Map toJson() { | |
| 52 var res = {'id': serializedId, 'kind': kind, 'name': name, 'size': size}; | |
| 53 // TODO(sigmund): omit this also when outputUnit.id == 0 | |
| 54 // (most code is by default in the main output unit) | |
| 55 if (outputUnit != null) res['outputUnit'] = outputUnit.serializedId; | |
| 56 return res; | |
| 57 } | |
| 58 } | |
| 59 | |
| 60 /// The entire information produced while compiling a program. | |
| 61 class AllInfo { | |
| 62 /// Summary information about the program. | |
| 63 ProgramInfo program; | |
| 64 | |
| 65 /// Information about each library processed by the compiler. | |
| 66 List<LibraryInfo> libraries = []; | |
| 67 | |
| 68 /// Information about each function (includes methods and getters in any | |
| 69 /// library) | |
| 70 List<FunctionInfo> functions = []; | |
| 71 | |
| 72 /// Information about type defs in the program. | |
| 73 List<TypedefInfo> typedefs = []; | |
| 74 | |
| 75 /// Information about each class (in any library). | |
| 76 List<ClassInfo> classes = []; | |
| 77 | |
| 78 /// Information about fields (in any class). | |
| 79 List<FieldInfo> fields = []; | |
| 80 | |
| 81 /// Information about output units (should be just one entry if not using | |
| 82 /// deferred loading). | |
| 83 List<OutputUnitInfo> outputUnits = []; | |
| 84 | |
| 85 /// Details about all deferred imports and what files would be loaded when the | |
| 86 /// import is resolved. | |
| 87 // TODO(sigmund): use a different format for dump-info. This currently emits | |
| 88 // the same map that is created for the `--deferred-map` flag. | |
| 89 Map<String, Map<String, dynamic>> deferredFiles; | |
| 90 | |
| 91 /// Major version indicating breaking changes in the format. A new version | |
| 92 /// means that an old deserialization algorithm will not work with the new | |
| 93 /// format. | |
| 94 final int version = 3; | |
| 95 | |
| 96 /// Minor version indicating non-breaking changes in the format. A change in | |
| 97 /// this version number means that the json parsing in this library from a | |
| 98 /// previous will continue to work after the change. This is typically | |
| 99 /// increased when adding new entries to the file format. | |
| 100 // Note: the dump-info.viewer app was written using a json parser version 3.2. | |
| 101 final int minorVersion = 3; | |
| 102 | |
| 103 AllInfo(); | |
| 104 | |
| 105 factory AllInfo.fromJson(Map map) { | |
| 106 // TODO(sigmund): implement | |
| 107 throw UnimplementedError('deserialization of dump-info not implemented'); | |
| 108 } | |
| 109 | |
| 110 Map _listAsJsonMap(List<Info> list) { | |
| 111 var map = <String, Map>{}; | |
| 112 for (var info in list) { | |
| 113 map['${info.id}'] = info.toJson(); | |
| 114 } | |
| 115 return map; | |
| 116 } | |
| 117 | |
| 118 Map _extractHoldingInfo() { | |
| 119 var map = <String, List>{}; | |
| 120 for (var f in functions) { | |
| 121 if (f.uses.isEmpty) continue; | |
| 122 map[f.serializedId] = f.uses.map((u) => u.toJson()).toList(); | |
| 123 } | |
| 124 return map; | |
| 125 } | |
| 126 | |
| 127 Map toJson() => { | |
| 128 'elements': { | |
|
Siggi Cherem (dart-lang)
2015/07/24 01:07:58
seems wasteful that this is indented so much by th
| |
| 129 'library': _listAsJsonMap(libraries), | |
| 130 'class': _listAsJsonMap(classes), | |
| 131 'function': _listAsJsonMap(functions), | |
| 132 'typedef': _listAsJsonMap(typedefs), | |
| 133 'field': _listAsJsonMap(fields), | |
| 134 }, | |
| 135 'holding': _extractHoldingInfo(), | |
| 136 'outputUnits': outputUnits.map((u) => u.toJson()).toList(), | |
| 137 'dump_version': version, | |
| 138 'deferredFiles': deferredFiles, | |
| 139 'dump_minor_version': '$minorVersion', | |
| 140 // TODO(sigmund): change viewer to accept an int? | |
| 141 'program': program.toJson(), | |
| 142 }; | |
| 143 } | |
| 144 | |
| 145 class ProgramInfo { | |
| 146 int size; | |
| 147 String dart2jsVersion; | |
| 148 DateTime compilationMoment; | |
| 149 Duration compilationDuration; | |
| 150 // TODO(sigmund): use Duration. | |
| 151 int toJsonDuration; | |
| 152 int dumpInfoDuration; | |
| 153 bool noSuchMethodEnabled; | |
| 154 bool minified; | |
| 155 | |
| 156 ProgramInfo( | |
| 157 {this.size, | |
| 158 this.dart2jsVersion, | |
| 159 this.compilationMoment, | |
| 160 this.compilationDuration, | |
| 161 this.toJsonDuration, | |
| 162 this.dumpInfoDuration, | |
| 163 this.noSuchMethodEnabled, | |
| 164 this.minified}); | |
| 165 | |
| 166 Map toJson() => { | |
| 167 'size': size, | |
| 168 'dart2jsVersion': dart2jsVersion, | |
| 169 'compilationMoment': '$compilationMoment', | |
| 170 'compilationDuration': '${compilationDuration}', | |
| 171 'toJsonDuration': toJsonDuration, | |
| 172 'dumpInfoDuration': '$dumpInfoDuration', | |
| 173 'noSuchMethodEnabled': noSuchMethodEnabled, | |
| 174 'minified': minified, | |
| 175 }; | |
| 176 } | |
| 177 | |
| 178 class LibraryInfo extends BasicInfo { | |
| 179 final Uri uri; | |
| 180 final List<FunctionInfo> topLevelFunctions = []; | |
| 181 final List<FieldInfo> topLevelVariables = []; | |
| 182 final List<ClassInfo> classes = []; | |
| 183 | |
| 184 static int _id = 0; | |
| 185 | |
| 186 bool get isEmpty => | |
| 187 topLevelFunctions.isEmpty && topLevelVariables.isEmpty && classes.isEmpty; | |
| 188 | |
| 189 LibraryInfo(String name, this.uri, OutputUnitInfo outputUnit, int size) | |
| 190 : super('library', _id++, name, outputUnit, size); | |
| 191 | |
| 192 Map toJson() => super.toJson() | |
| 193 ..addAll({ | |
| 194 'children': [] | |
| 195 ..addAll(topLevelFunctions.map((f) => f.serializedId)) | |
| 196 ..addAll(topLevelVariables.map((v) => v.serializedId)) | |
| 197 ..addAll(classes.map((c) => c.serializedId)), | |
| 198 'canonicalUri': '$uri', | |
| 199 }); | |
| 200 } | |
| 201 | |
| 202 class OutputUnitInfo extends BasicInfo { | |
| 203 static int _ids = 0; | |
| 204 OutputUnitInfo(String name, int size) | |
| 205 : super('outputUnit', _ids++, name, null, size); | |
| 206 } | |
| 207 | |
| 208 class ClassInfo extends BasicInfo { | |
| 209 final bool isAbstract; | |
| 210 | |
| 211 // TODO(sigmund): split static vs instance vs closures | |
| 212 final List<FunctionInfo> functions = []; | |
| 213 final List<FieldInfo> fields = []; | |
| 214 static int _ids = 0; | |
| 215 | |
| 216 ClassInfo( | |
| 217 {String name, this.isAbstract, OutputUnitInfo outputUnit, int size: 0}) | |
| 218 : super('class', _ids++, name, outputUnit, size); | |
| 219 | |
| 220 Map toJson() => super.toJson() | |
| 221 ..addAll({ | |
| 222 // TODO(sigmund): change format, include only when abstract is true. | |
| 223 'modifiers': {'abstract': isAbstract}, | |
| 224 'children': [] | |
| 225 ..addAll(fields.map((f) => f.serializedId)) | |
| 226 ..addAll(functions.map((m) => m.serializedId)) | |
| 227 }); | |
| 228 } | |
| 229 | |
| 230 class FieldInfo extends BasicInfo { | |
| 231 String type; | |
| 232 String inferredType; | |
| 233 List<FunctionInfo> closures; | |
| 234 String code; | |
| 235 | |
| 236 static int _ids = 0; | |
| 237 FieldInfo( | |
| 238 {String name, | |
| 239 int size, | |
| 240 this.type, | |
| 241 this.inferredType, | |
| 242 this.closures, | |
| 243 this.code, | |
| 244 OutputUnitInfo outputUnit}) | |
| 245 : super('field', _ids++, name, outputUnit, size); | |
| 246 | |
| 247 Map toJson() => super.toJson() | |
| 248 ..addAll({ | |
| 249 'children': closures.map((i) => i.serializedId).toList(), | |
| 250 'inferredType': inferredType, | |
| 251 'code': code, | |
| 252 'type': type, | |
| 253 }); | |
| 254 } | |
| 255 | |
| 256 class TypedefInfo extends BasicInfo { | |
| 257 String type; | |
| 258 | |
| 259 static int _ids = 0; | |
| 260 TypedefInfo(String name, this.type, OutputUnitInfo outputUnit) | |
| 261 : super('typedef', _ids++, name, outputUnit); | |
| 262 | |
| 263 Map toJson() => super.toJson()..['type'] = '$type'; | |
| 264 } | |
| 265 | |
| 266 class FunctionInfo extends BasicInfo { | |
| 267 static const int TOP_LEVEL_FUNCTION_KIND = 0; | |
| 268 static const int CLOSURE_FUNCTION_KIND = 1; | |
| 269 static const int METHOD_FUNCTION_KIND = 2; | |
| 270 static const int CONSTRUCTOR_FUNCTION_KIND = 3; | |
| 271 static int _ids = 0; | |
| 272 | |
| 273 /// Kind of function (top-level function, closure, method, or constructor). | |
| 274 final int functionKind; | |
| 275 | |
| 276 /// Modifiers applied to this function. | |
| 277 final FunctionModifiers modifiers; | |
| 278 | |
| 279 /// Nested closures that appear within the body of this function. | |
| 280 List<FunctionInfo> closures; | |
| 281 | |
| 282 /// The type of this function. | |
| 283 String type; | |
| 284 | |
| 285 /// The declared return type. | |
| 286 String returnType; | |
| 287 | |
| 288 /// The inferred return type. | |
| 289 String inferredReturnType; | |
| 290 | |
| 291 /// Name and type information for each parameter. | |
| 292 List<ParameterInfo> parameters; | |
| 293 | |
| 294 /// Side-effects. | |
| 295 // TODO(sigmund): serialize more precisely, not just a string representation. | |
| 296 String sideEffects; | |
| 297 | |
| 298 /// How many function calls were inlined into this function. | |
| 299 int inlinedCount; | |
| 300 | |
| 301 /// The actual generated code. | |
| 302 String code; | |
| 303 | |
| 304 /// How does this function depend on other functions or fields. | |
| 305 List<DependencyInfo> uses = []; | |
|
karlklose
2015/07/24 07:08:22
Please add type arguments to literals (several pla
Siggi Cherem (dart-lang)
2015/07/27 20:10:59
Done. We should chat more about this long term - i
| |
| 306 | |
| 307 FunctionInfo( | |
| 308 {String name, | |
| 309 OutputUnitInfo outputUnit, | |
| 310 int size, | |
| 311 this.functionKind, | |
| 312 this.modifiers, | |
| 313 this.closures, | |
| 314 this.type, | |
| 315 this.returnType, | |
| 316 this.inferredReturnType, | |
| 317 this.parameters, | |
| 318 this.sideEffects, | |
| 319 this.inlinedCount, | |
| 320 this.code}) | |
| 321 : super('function', _ids++, name, outputUnit, size); | |
| 322 | |
| 323 Map toJson() => super.toJson() | |
| 324 ..addAll({ | |
| 325 'children': closures.map((i) => i.serializedId).toList(), | |
| 326 'modifiers': modifiers.toJson(), | |
| 327 'returnType': returnType, | |
| 328 'inferredReturnType': inferredReturnType, | |
| 329 'parameters': parameters.map((p) => p.toJson()).toList(), | |
| 330 'sideEffects': sideEffects, | |
| 331 'inlinedCount': inlinedCount, | |
| 332 'code': code, | |
| 333 'type': type, | |
| 334 // Note: version 3.2 of dump-info serializes `uses` in a section called | |
| 335 // `holding` at the top-level. | |
| 336 }); | |
| 337 } | |
| 338 | |
| 339 /// Information about how a dependency is used. | |
| 340 class DependencyInfo { | |
| 341 /// The dependency, either a FunctionInfo or FieldInfo. | |
| 342 final Info target; | |
| 343 | |
| 344 /// Either a selector mask indicating how this is used, or 'inlined'. | |
| 345 final String mask; | |
|
karlklose
2015/07/24 07:08:22
Preferably we would have an enum that describes ex
Siggi Cherem (dart-lang)
2015/07/27 20:10:58
good point. I added a TODO for now. I'm thinking t
| |
| 346 | |
| 347 DependencyInfo(this.target, this.mask); | |
| 348 | |
| 349 Map toJson() => {'id': target.serializedId, 'mask': mask}; | |
| 350 } | |
| 351 | |
| 352 /// Name and type information about a function parameter. | |
| 353 class ParameterInfo { | |
| 354 final String name; | |
| 355 final String type; | |
| 356 final String declaredType; | |
| 357 | |
| 358 ParameterInfo(this.name, this.type, this.declaredType); | |
| 359 | |
| 360 Map toJson() => {'name': name, 'type': type, 'declaredType': declaredType}; | |
| 361 } | |
| 362 | |
| 363 /// Modifiers that may apply to methods. | |
| 364 class FunctionModifiers { | |
| 365 final bool isStatic; | |
| 366 final bool isConst; | |
| 367 final bool isFactory; | |
| 368 final bool isExternal; | |
| 369 | |
| 370 FunctionModifiers( | |
| 371 {this.isStatic: false, | |
| 372 this.isConst: false, | |
| 373 this.isFactory: false, | |
| 374 this.isExternal: false}); | |
| 375 | |
| 376 factory FunctionModifiers.fromJson(Map<String, bool> json) { | |
| 377 return new FunctionModifiers( | |
| 378 isStatic: json['static'] == true, | |
| 379 isConst: json['const'] == true, | |
| 380 isFactory: json['factory'] == true, | |
| 381 isExternal: json['external'] == true); | |
| 382 } | |
| 383 | |
| 384 // TODO(sigmund): exclude false values (requires bumping the format version): | |
| 385 // Map toJson() { | |
| 386 // var res = <String, bool>{}; | |
| 387 // if (isStatic) res['static'] = true; | |
| 388 // if (isConst) res['const'] = true; | |
| 389 // if (isFactory) res['factory'] = true; | |
| 390 // if (isExternal) res['external'] = true; | |
| 391 // return res; | |
| 392 // } | |
| 393 Map toJson() => { | |
| 394 'static': isStatic, | |
| 395 'const': isConst, | |
| 396 'factory': isFactory, | |
| 397 'external': isExternal, | |
| 398 }; | |
| 399 } | |
| OLD | NEW |