Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 library dump_info; | 5 library dump_info; |
| 6 | 6 |
| 7 import 'dart:convert' | 7 import 'dart:convert' |
| 8 show HtmlEscape, JsonEncoder, StringConversionSink, ChunkedConversionSink; | 8 show HtmlEscape, JsonEncoder, StringConversionSink, ChunkedConversionSink; |
| 9 | 9 |
| 10 import 'package:dart2js_info/info.dart'; | 10 import 'package:dart2js_info/info.dart'; |
| 11 | 11 |
| 12 import 'common/tasks.dart' show | 12 import 'common/tasks.dart' show |
| 13 CompilerTask; | 13 CompilerTask; |
| 14 import 'constants/values.dart' show ConstantValue; | |
| 14 import 'compiler.dart' show | 15 import 'compiler.dart' show |
| 15 Compiler; | 16 Compiler; |
| 16 import 'diagnostics/messages.dart' show | 17 import 'diagnostics/messages.dart' show |
| 17 MessageKind; | 18 MessageKind; |
| 18 import 'diagnostics/spannable.dart' show | 19 import 'diagnostics/spannable.dart' show |
| 19 NO_LOCATION_SPANNABLE; | 20 NO_LOCATION_SPANNABLE; |
| 20 import 'elements/elements.dart'; | 21 import 'elements/elements.dart'; |
| 21 import 'elements/visitor.dart'; | 22 import 'elements/visitor.dart'; |
| 22 import 'types/types.dart' show | 23 import 'types/types.dart' show |
| 23 TypeMask; | 24 TypeMask; |
| 24 import 'deferred_load.dart' show | 25 import 'deferred_load.dart' show |
| 25 OutputUnit; | 26 OutputUnit; |
| 26 import 'js_backend/js_backend.dart' show | 27 import 'js_backend/js_backend.dart' show |
| 27 JavaScriptBackend; | 28 JavaScriptBackend; |
| 28 import 'js_emitter/full_emitter/emitter.dart' as full show | 29 import 'js_emitter/full_emitter/emitter.dart' as full show |
| 29 Emitter; | 30 Emitter; |
| 30 import 'js/js.dart' as jsAst; | 31 import 'js/js.dart' as jsAst; |
| 31 import 'universe/universe.dart' show | 32 import 'universe/universe.dart' show |
| 32 Selector, | 33 Selector, |
| 33 UniverseSelector; | 34 UniverseSelector; |
| 34 | 35 |
| 35 class ElementInfoCollector extends BaseElementVisitor<Info, dynamic> { | 36 class ElementInfoCollector extends BaseElementVisitor<Info, dynamic> { |
| 36 final Compiler compiler; | 37 final Compiler compiler; |
| 37 | 38 |
| 38 final AllInfo result = new AllInfo(); | 39 final AllInfo result = new AllInfo(); |
| 39 final Map<Element, Info> _elementToInfo = <Element, Info>{}; | 40 final Map<Element, Info> _elementToInfo = <Element, Info>{}; |
| 41 final Map<ConstantValue, Info> _constantToInfo = <ConstantValue, Info>{}; | |
| 40 final Map<OutputUnit, OutputUnitInfo> _outputToInfo = {}; | 42 final Map<OutputUnit, OutputUnitInfo> _outputToInfo = {}; |
| 41 | 43 |
| 42 ElementInfoCollector(this.compiler); | 44 ElementInfoCollector(this.compiler); |
| 43 | 45 |
| 44 void run() => compiler.libraryLoader.libraries.forEach(visit); | 46 void run() { |
| 47 compiler.dumpInfoTask._constantToNode.forEach((constant, node) { | |
| 48 // TODO(sigmund): add dependencies on other constants | |
| 49 var size = compiler.dumpInfoTask._nodeToSize[node]; | |
| 50 var code = jsAst.prettyPrint(node, compiler).getText(); | |
| 51 var info = new ConstantInfo(size: size, code: code); | |
| 52 _constantToInfo[constant] = info; | |
| 53 result.constants.add(info); | |
| 54 | |
| 55 }); | |
| 56 compiler.libraryLoader.libraries.forEach(visit); | |
| 57 } | |
| 45 | 58 |
| 46 Info visit(Element e, [_]) => e.accept(this, null); | 59 Info visit(Element e, [_]) => e.accept(this, null); |
| 47 | 60 |
| 48 /// Whether to emit information about [element]. | 61 /// Whether to emit information about [element]. |
| 49 /// | 62 /// |
| 50 /// By default we emit information for any element that contributes to the | 63 /// By default we emit information for any element that contributes to the |
| 51 /// output size. Either becuase the it is a function being emitted or inlined, | 64 /// output size. Either becuase the it is a function being emitted or inlined, |
| 52 /// or because it is an element that holds dependencies to other elements. | 65 /// or because it is an element that holds dependencies to other elements. |
| 53 bool shouldKeep(Element element) { | 66 bool shouldKeep(Element element) { |
| 54 return compiler.dumpInfoTask.selectorsFromElement.containsKey(element) || | 67 return compiler.dumpInfoTask.selectorsFromElement.containsKey(element) || |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 108 _unitInfoForElement(element)); | 121 _unitInfoForElement(element)); |
| 109 _elementToInfo[element] = info; | 122 _elementToInfo[element] = info; |
| 110 result.typedefs.add(info); | 123 result.typedefs.add(info); |
| 111 return info; | 124 return info; |
| 112 } | 125 } |
| 113 | 126 |
| 114 FieldInfo visitFieldElement(FieldElement element, _) { | 127 FieldInfo visitFieldElement(FieldElement element, _) { |
| 115 TypeMask inferredType = | 128 TypeMask inferredType = |
| 116 compiler.typesTask.getGuaranteedTypeOfElement(element); | 129 compiler.typesTask.getGuaranteedTypeOfElement(element); |
| 117 // If a field has an empty inferred type it is never used. | 130 // If a field has an empty inferred type it is never used. |
| 118 if (inferredType == null || inferredType.isEmpty || element.isConst) { | 131 if (inferredType == null || inferredType.isEmpty) return null; |
| 119 return null; | |
| 120 } | |
| 121 | 132 |
| 122 int size = compiler.dumpInfoTask.sizeOf(element); | 133 int size = compiler.dumpInfoTask.sizeOf(element); |
| 123 String code; | 134 String code = compiler.dumpInfoTask.codeOf(element); |
| 124 StringBuffer emittedCode = compiler.dumpInfoTask.codeOf(element); | 135 if (code != null) size += code.length; |
|
Siggi Cherem (dart-lang)
2015/08/19 04:21:08
FYI - these lines related to `codeOf` were just cl
| |
| 125 if (emittedCode != null) { | |
| 126 size += emittedCode.length; | |
| 127 code = emittedCode.toString(); | |
| 128 } | |
| 129 | 136 |
| 130 FieldInfo info = new FieldInfo( | 137 FieldInfo info = new FieldInfo( |
| 131 name: element.name, | 138 name: element.name, |
| 132 // We use element.hashCode because it is globally unique and it is | 139 // We use element.hashCode because it is globally unique and it is |
| 133 // available while we are doing codegen. | 140 // available while we are doing codegen. |
| 134 coverageId: '${element.hashCode}', | 141 coverageId: '${element.hashCode}', |
| 135 type: '${element.type}', | 142 type: '${element.type}', |
| 136 inferredType: '$inferredType', | 143 inferredType: '$inferredType', |
| 137 size: size, | 144 size: size, |
| 138 code: code, | 145 code: code, |
| 139 outputUnit: _unitInfoForElement(element)); | 146 outputUnit: _unitInfoForElement(element), |
| 147 isConst: element.isConst); | |
| 140 _elementToInfo[element] = info; | 148 _elementToInfo[element] = info; |
| 149 if (element.isConst) { | |
| 150 var value = compiler.backend.constantCompilerTask | |
| 151 .getConstantValueForVariable(element); | |
| 152 if (value != null) { | |
| 153 info.initializer = _constantToInfo[value]; | |
| 154 } | |
| 155 } | |
| 141 | 156 |
| 142 List<FunctionInfo> nestedClosures = <FunctionInfo>[]; | 157 List<FunctionInfo> nestedClosures = <FunctionInfo>[]; |
| 143 for (Element closure in element.nestedClosures) { | 158 for (Element closure in element.nestedClosures) { |
| 144 Info child = this.process(closure); | 159 Info child = this.process(closure); |
| 145 if (child != null) { | 160 if (child != null) { |
| 146 ClassInfo parent = this.process(closure.enclosingElement); | 161 ClassInfo parent = this.process(closure.enclosingElement); |
| 147 if (parent != null) { | 162 if (parent != null) { |
| 148 child.name = "${parent.name}.${child.name}"; | 163 child.name = "${parent.name}.${child.name}"; |
| 149 } | 164 } |
| 150 nestedClosures.add(child); | 165 nestedClosures.add(child); |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 235 ? "${element.enclosingElement.name}" | 250 ? "${element.enclosingElement.name}" |
| 236 : "${element.enclosingElement.name}.${element.name}"; | 251 : "${element.enclosingElement.name}.${element.name}"; |
| 237 kind = FunctionInfo.CONSTRUCTOR_FUNCTION_KIND; | 252 kind = FunctionInfo.CONSTRUCTOR_FUNCTION_KIND; |
| 238 } | 253 } |
| 239 | 254 |
| 240 FunctionModifiers modifiers = new FunctionModifiers( | 255 FunctionModifiers modifiers = new FunctionModifiers( |
| 241 isStatic: element.isStatic, | 256 isStatic: element.isStatic, |
| 242 isConst: element.isConst, | 257 isConst: element.isConst, |
| 243 isFactory: element.isFactoryConstructor, | 258 isFactory: element.isFactoryConstructor, |
| 244 isExternal: element.isPatched); | 259 isExternal: element.isPatched); |
| 245 StringBuffer emittedCode = compiler.dumpInfoTask.codeOf(element); | 260 String code = compiler.dumpInfoTask.codeOf(element); |
| 246 String code = emittedCode == null ? null : '$emittedCode'; | |
| 247 | 261 |
| 248 List<ParameterInfo> parameters = <ParameterInfo>[]; | 262 List<ParameterInfo> parameters = <ParameterInfo>[]; |
| 249 if (element.hasFunctionSignature) { | 263 if (element.hasFunctionSignature) { |
| 250 FunctionSignature signature = element.functionSignature; | 264 FunctionSignature signature = element.functionSignature; |
| 251 signature.forEachParameter((parameter) { | 265 signature.forEachParameter((parameter) { |
| 252 parameters.add(new ParameterInfo( | 266 parameters.add(new ParameterInfo( |
| 253 parameter.name, | 267 parameter.name, |
| 254 '${compiler.typesTask.getGuaranteedTypeOfElement(parameter)}', | 268 '${compiler.typesTask.getGuaranteedTypeOfElement(parameter)}', |
| 255 '${parameter.node.type}')); | 269 '${parameter.node.type}')); |
| 256 }); | 270 }); |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 340 /// The size of the generated output. | 354 /// The size of the generated output. |
| 341 int _programSize; | 355 int _programSize; |
| 342 | 356 |
| 343 // A set of javascript AST nodes that we care about the size of. | 357 // A set of javascript AST nodes that we care about the size of. |
| 344 // This set is automatically populated when registerElementAst() | 358 // This set is automatically populated when registerElementAst() |
| 345 // is called. | 359 // is called. |
| 346 final Set<jsAst.Node> _tracking = new Set<jsAst.Node>(); | 360 final Set<jsAst.Node> _tracking = new Set<jsAst.Node>(); |
| 347 // A mapping from Dart Elements to Javascript AST Nodes. | 361 // A mapping from Dart Elements to Javascript AST Nodes. |
| 348 final Map<Element, List<jsAst.Node>> _elementToNodes = | 362 final Map<Element, List<jsAst.Node>> _elementToNodes = |
| 349 <Element, List<jsAst.Node>>{}; | 363 <Element, List<jsAst.Node>>{}; |
| 364 final Map<ConstantValue, jsAst.Node> _constantToNode = | |
| 365 <ConstantValue, jsAst.Node>{}; | |
| 350 // A mapping from Javascript AST Nodes to the size of their | 366 // A mapping from Javascript AST Nodes to the size of their |
| 351 // pretty-printed contents. | 367 // pretty-printed contents. |
| 352 final Map<jsAst.Node, int> _nodeToSize = <jsAst.Node, int>{}; | 368 final Map<jsAst.Node, int> _nodeToSize = <jsAst.Node, int>{}; |
| 353 | 369 |
| 354 final Map<Element, Set<UniverseSelector>> selectorsFromElement = {}; | 370 final Map<Element, Set<UniverseSelector>> selectorsFromElement = {}; |
| 355 final Map<Element, int> inlineCount = <Element, int>{}; | 371 final Map<Element, int> inlineCount = <Element, int>{}; |
| 356 // A mapping from an element to a list of elements that are | 372 // A mapping from an element to a list of elements that are |
| 357 // inlined inside of it. | 373 // inlined inside of it. |
| 358 final Map<Element, List<Element>> inlineMap = <Element, List<Element>>{}; | 374 final Map<Element, List<Element>> inlineMap = <Element, List<Element>>{}; |
| 359 | 375 |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 419 // dart Element `element`. | 435 // dart Element `element`. |
| 420 void registerElementAst(Element element, jsAst.Node code) { | 436 void registerElementAst(Element element, jsAst.Node code) { |
| 421 if (compiler.dumpInfo) { | 437 if (compiler.dumpInfo) { |
| 422 _elementToNodes | 438 _elementToNodes |
| 423 .putIfAbsent(element, () => new List<jsAst.Node>()) | 439 .putIfAbsent(element, () => new List<jsAst.Node>()) |
| 424 .add(code); | 440 .add(code); |
| 425 _tracking.add(code); | 441 _tracking.add(code); |
| 426 } | 442 } |
| 427 } | 443 } |
| 428 | 444 |
| 445 void registerConstantAst(ConstantValue constant, jsAst.Node code) { | |
| 446 if (compiler.dumpInfo) { | |
| 447 assert(_constantToNode[constant] == null || | |
| 448 _constantToNode[constant] == code); | |
| 449 _constantToNode[constant] = code; | |
| 450 _tracking.add(code); | |
| 451 } | |
| 452 } | |
| 453 | |
| 429 // Records the size of a dart AST node after it has been | 454 // Records the size of a dart AST node after it has been |
| 430 // pretty-printed into the output buffer. | 455 // pretty-printed into the output buffer. |
| 431 void recordAstSize(jsAst.Node node, int size) { | 456 void recordAstSize(jsAst.Node node, int size) { |
| 432 if (isTracking(node)) { | 457 if (isTracking(node)) { |
| 433 //TODO: should I be incrementing here instead? | 458 //TODO: should I be incrementing here instead? |
| 434 _nodeToSize[node] = size; | 459 _nodeToSize[node] = size; |
| 435 } | 460 } |
| 436 } | 461 } |
| 437 | 462 |
| 438 // Returns the size of the source code that | 463 // Returns the size of the source code that |
| 439 // was generated for an element. If no source | 464 // was generated for an element. If no source |
| 440 // code was produced, return 0. | 465 // code was produced, return 0. |
| 441 int sizeOf(Element element) { | 466 int sizeOf(Element element) { |
| 442 if (_elementToNodes.containsKey(element)) { | 467 if (_elementToNodes.containsKey(element)) { |
| 443 return _elementToNodes[element].map(sizeOfNode).fold(0, (a, b) => a + b); | 468 return _elementToNodes[element].map(sizeOfNode).fold(0, (a, b) => a + b); |
| 444 } else { | 469 } else { |
| 445 return 0; | 470 return 0; |
| 446 } | 471 } |
| 447 } | 472 } |
| 448 | 473 |
| 449 int sizeOfNode(jsAst.Node node) { | 474 int sizeOfNode(jsAst.Node node) => _nodeToSize[node] ?? 0; |
| 450 if (_nodeToSize.containsKey(node)) { | |
| 451 return _nodeToSize[node]; | |
| 452 } else { | |
| 453 return 0; | |
| 454 } | |
| 455 } | |
| 456 | 475 |
| 457 StringBuffer codeOf(Element element) { | 476 String codeOf(Element element) { |
| 458 List<jsAst.Node> code = _elementToNodes[element]; | 477 List<jsAst.Node> code = _elementToNodes[element]; |
| 459 if (code == null) return null; | 478 if (code == null) return null; |
| 460 // Concatenate rendered ASTs. | 479 // Concatenate rendered ASTs. |
| 461 StringBuffer sb = new StringBuffer(); | 480 StringBuffer sb = new StringBuffer(); |
| 462 for (jsAst.Node ast in code) { | 481 for (jsAst.Node ast in code) { |
| 463 sb.writeln(jsAst.prettyPrint(ast, compiler).getText()); | 482 sb.writeln(jsAst.prettyPrint(ast, compiler).getText()); |
| 464 } | 483 } |
| 465 return sb; | 484 return sb.toString(); |
| 466 } | 485 } |
| 467 | 486 |
| 468 void collectInfo() { | 487 void collectInfo() { |
| 469 infoCollector = new ElementInfoCollector(compiler)..run(); | 488 infoCollector = new ElementInfoCollector(compiler)..run(); |
| 470 } | 489 } |
| 471 | 490 |
| 472 void dumpInfo() { | 491 void dumpInfo() { |
| 473 measure(() { | 492 measure(() { |
| 474 if (infoCollector == null) { | 493 if (infoCollector == null) { |
| 475 collectInfo(); | 494 collectInfo(); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 539 | 558 |
| 540 ChunkedConversionSink<Object> sink = encoder.startChunkedConversion( | 559 ChunkedConversionSink<Object> sink = encoder.startChunkedConversion( |
| 541 new StringConversionSink.fromStringSink(buffer)); | 560 new StringConversionSink.fromStringSink(buffer)); |
| 542 sink.add(result.toJson()); | 561 sink.add(result.toJson()); |
| 543 compiler.reportInfo(NO_LOCATION_SPANNABLE, MessageKind.GENERIC, { | 562 compiler.reportInfo(NO_LOCATION_SPANNABLE, MessageKind.GENERIC, { |
| 544 'text': "View the dumped .info.json file at " | 563 'text': "View the dumped .info.json file at " |
| 545 "https://dart-lang.github.io/dump-info-visualizer" | 564 "https://dart-lang.github.io/dump-info-visualizer" |
| 546 }); | 565 }); |
| 547 } | 566 } |
| 548 } | 567 } |
| OLD | NEW |