| 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.dart'; | 12 import 'common.dart'; |
| 13 import 'common/tasks.dart' show CompilerTask; | 13 import 'common/tasks.dart' show CompilerTask; |
| 14 import 'constants/values.dart' show ConstantValue, InterceptorConstantValue; | 14 import 'constants/values.dart' show ConstantValue, InterceptorConstantValue; |
| 15 import 'compiler.dart' show Compiler; | 15 import 'compiler.dart' show Compiler; |
| 16 import 'elements/elements.dart'; | 16 import 'elements/elements.dart'; |
| 17 import 'elements/visitor.dart'; | 17 import 'elements/visitor.dart'; |
| 18 import 'types/types.dart' show TypeMask; | 18 import 'types/types.dart' show TypeMask; |
| 19 import 'deferred_load.dart' show OutputUnit; | 19 import 'deferred_load.dart' show OutputUnit; |
| 20 import 'js_backend/js_backend.dart' show JavaScriptBackend; | 20 import 'js_backend/js_backend.dart' show JavaScriptBackend; |
| 21 import 'js_emitter/full_emitter/emitter.dart' as full show Emitter; | 21 import 'js_emitter/full_emitter/emitter.dart' as full show Emitter; |
| 22 import 'js/js.dart' as jsAst; | 22 import 'js/js.dart' as jsAst; |
| 23 import 'universe/use.dart' show | 23 import 'universe/universe.dart' show ReceiverConstraint; |
| 24 DynamicUse; | 24 import 'universe/world_impact.dart' show WorldImpact; |
| 25 import 'info/send_info.dart' show collectSendMeasurements; | 25 import 'info/send_info.dart' show collectSendMeasurements; |
| 26 | 26 |
| 27 class ElementInfoCollector extends BaseElementVisitor<Info, dynamic> { | 27 class ElementInfoCollector extends BaseElementVisitor<Info, dynamic> { |
| 28 final Compiler compiler; | 28 final Compiler compiler; |
| 29 | 29 |
| 30 final AllInfo result = new AllInfo(); | 30 final AllInfo result = new AllInfo(); |
| 31 final Map<Element, Info> _elementToInfo = <Element, Info>{}; | 31 final Map<Element, Info> _elementToInfo = <Element, Info>{}; |
| 32 final Map<ConstantValue, Info> _constantToInfo = <ConstantValue, Info>{}; | 32 final Map<ConstantValue, Info> _constantToInfo = <ConstantValue, Info>{}; |
| 33 final Map<OutputUnit, OutputUnitInfo> _outputToInfo = {}; | 33 final Map<OutputUnit, OutputUnitInfo> _outputToInfo = {}; |
| 34 | 34 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 45 result.constants.add(info); | 45 result.constants.add(info); |
| 46 }); | 46 }); |
| 47 compiler.libraryLoader.libraries.forEach(visit); | 47 compiler.libraryLoader.libraries.forEach(visit); |
| 48 } | 48 } |
| 49 | 49 |
| 50 Info visit(Element e, [_]) => e.accept(this, null); | 50 Info visit(Element e, [_]) => e.accept(this, null); |
| 51 | 51 |
| 52 /// Whether to emit information about [element]. | 52 /// Whether to emit information about [element]. |
| 53 /// | 53 /// |
| 54 /// By default we emit information for any element that contributes to the | 54 /// By default we emit information for any element that contributes to the |
| 55 /// output size. Either becuase the it is a function being emitted or inlined, | 55 /// output size. Either because the it is a function being emitted or inlined, |
| 56 /// or because it is an element that holds dependencies to other elements. | 56 /// or because it is an element that holds dependencies to other elements. |
| 57 bool shouldKeep(Element element) { | 57 bool shouldKeep(Element element) { |
| 58 return compiler.dumpInfoTask.selectorsFromElement.containsKey(element) || | 58 return compiler.dumpInfoTask.impacts.containsKey(element) || |
| 59 compiler.dumpInfoTask.inlineCount.containsKey(element); | 59 compiler.dumpInfoTask.inlineCount.containsKey(element); |
| 60 } | 60 } |
| 61 | 61 |
| 62 /// Visits [element] and produces it's corresponding info. | 62 /// Visits [element] and produces it's corresponding info. |
| 63 Info process(Element element) { | 63 Info process(Element element) { |
| 64 // TODO(sigmund): change the visit order to eliminate the need to check | 64 // TODO(sigmund): change the visit order to eliminate the need to check |
| 65 // whether or not an element has been processed. | 65 // whether or not an element has been processed. |
| 66 return _elementToInfo.putIfAbsent(element, () => visit(element)); | 66 return _elementToInfo.putIfAbsent(element, () => visit(element)); |
| 67 } | 67 } |
| 68 | 68 |
| (...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 342 if (outputUnit == null) { | 342 if (outputUnit == null) { |
| 343 assert(constant is InterceptorConstantValue); | 343 assert(constant is InterceptorConstantValue); |
| 344 return null; | 344 return null; |
| 345 } | 345 } |
| 346 return _infoFromOutputUnit(outputUnit); | 346 return _infoFromOutputUnit(outputUnit); |
| 347 } | 347 } |
| 348 } | 348 } |
| 349 | 349 |
| 350 class Selection { | 350 class Selection { |
| 351 final Element selectedElement; | 351 final Element selectedElement; |
| 352 final TypeMask mask; | 352 final ReceiverConstraint mask; |
| 353 Selection(this.selectedElement, this.mask); | 353 Selection(this.selectedElement, this.mask); |
| 354 } | 354 } |
| 355 | 355 |
| 356 /// Interface used to record information from different parts of the compiler so | 356 /// Interface used to record information from different parts of the compiler so |
| 357 /// we can emit them in the dump-info task. | 357 /// we can emit them in the dump-info task. |
| 358 // TODO(sigmund,het): move more features here. Ideally the dump-info task | 358 // TODO(sigmund,het): move more features here. Ideally the dump-info task |
| 359 // shouldn't reach into internals of other parts of the compiler. For example, | 359 // shouldn't reach into internals of other parts of the compiler. For example, |
| 360 // we currently reach into the full emitter and as a result we don't support | 360 // we currently reach into the full emitter and as a result we don't support |
| 361 // dump-info when using the startup-emitter (issue #24190). | 361 // dump-info when using the startup-emitter (issue #24190). |
| 362 abstract class InfoReporter { | 362 abstract class InfoReporter { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 379 final Set<jsAst.Node> _tracking = new Set<jsAst.Node>(); | 379 final Set<jsAst.Node> _tracking = new Set<jsAst.Node>(); |
| 380 // A mapping from Dart Elements to Javascript AST Nodes. | 380 // A mapping from Dart Elements to Javascript AST Nodes. |
| 381 final Map<Element, List<jsAst.Node>> _elementToNodes = | 381 final Map<Element, List<jsAst.Node>> _elementToNodes = |
| 382 <Element, List<jsAst.Node>>{}; | 382 <Element, List<jsAst.Node>>{}; |
| 383 final Map<ConstantValue, jsAst.Node> _constantToNode = | 383 final Map<ConstantValue, jsAst.Node> _constantToNode = |
| 384 <ConstantValue, jsAst.Node>{}; | 384 <ConstantValue, jsAst.Node>{}; |
| 385 // A mapping from Javascript AST Nodes to the size of their | 385 // A mapping from Javascript AST Nodes to the size of their |
| 386 // pretty-printed contents. | 386 // pretty-printed contents. |
| 387 final Map<jsAst.Node, int> _nodeToSize = <jsAst.Node, int>{}; | 387 final Map<jsAst.Node, int> _nodeToSize = <jsAst.Node, int>{}; |
| 388 | 388 |
| 389 final Map<Element, Set<DynamicUse>> selectorsFromElement = {}; | |
| 390 final Map<Element, int> inlineCount = <Element, int>{}; | 389 final Map<Element, int> inlineCount = <Element, int>{}; |
| 391 // A mapping from an element to a list of elements that are | 390 // A mapping from an element to a list of elements that are |
| 392 // inlined inside of it. | 391 // inlined inside of it. |
| 393 final Map<Element, List<Element>> inlineMap = <Element, List<Element>>{}; | 392 final Map<Element, List<Element>> inlineMap = <Element, List<Element>>{}; |
| 394 | 393 |
| 394 final Map<Element, WorldImpact> impacts = <Element, WorldImpact>{}; |
| 395 |
| 395 /// Register the size of the generated output. | 396 /// Register the size of the generated output. |
| 396 void reportSize(int programSize) { | 397 void reportSize(int programSize) { |
| 397 _programSize = programSize; | 398 _programSize = programSize; |
| 398 } | 399 } |
| 399 | 400 |
| 400 void reportInlined(Element element, Element inlinedFrom) { | 401 void reportInlined(Element element, Element inlinedFrom) { |
| 401 inlineCount.putIfAbsent(element, () => 0); | 402 inlineCount.putIfAbsent(element, () => 0); |
| 402 inlineCount[element] += 1; | 403 inlineCount[element] += 1; |
| 403 inlineMap.putIfAbsent(inlinedFrom, () => new List<Element>()); | 404 inlineMap.putIfAbsent(inlinedFrom, () => new List<Element>()); |
| 404 inlineMap[inlinedFrom].add(element); | 405 inlineMap[inlinedFrom].add(element); |
| 405 } | 406 } |
| 406 | 407 |
| 407 /** | |
| 408 * Registers that a function uses a selector in the | |
| 409 * function body | |
| 410 */ | |
| 411 void elementUsesSelector(Element element, DynamicUse selector) { | |
| 412 if (compiler.dumpInfo) { | |
| 413 selectorsFromElement | |
| 414 .putIfAbsent(element, () => new Set<DynamicUse>()) | |
| 415 .add(selector); | |
| 416 } | |
| 417 } | |
| 418 | |
| 419 final Map<Element, Set<Element>> _dependencies = {}; | 408 final Map<Element, Set<Element>> _dependencies = {}; |
| 420 void registerDependency(Element source, Element target) { | 409 void registerDependency(Element source, Element target) { |
| 421 _dependencies.putIfAbsent(source, () => new Set()).add(target); | 410 _dependencies.putIfAbsent(source, () => new Set()).add(target); |
| 422 } | 411 } |
| 423 | 412 |
| 413 void registerImpact(Element element, WorldImpact impact) { |
| 414 if (compiler.dumpInfo) { |
| 415 impacts[element] = impact; |
| 416 } |
| 417 } |
| 418 |
| 424 /** | 419 /** |
| 425 * Returns an iterable of [Selection]s that are used by | 420 * Returns an iterable of [Selection]s that are used by |
| 426 * [element]. Each [Selection] contains an element that is | 421 * [element]. Each [Selection] contains an element that is |
| 427 * used and the selector that selected the element. | 422 * used and the selector that selected the element. |
| 428 */ | 423 */ |
| 429 Iterable<Selection> getRetaining(Element element) { | 424 Iterable<Selection> getRetaining(Element element) { |
| 430 if (!selectorsFromElement.containsKey(element)) { | 425 var impact = impacts[element]; |
| 431 return const <Selection>[]; | 426 if (impact == null) return const <Selection>[]; |
| 432 } else { | 427 |
| 433 return selectorsFromElement[element].expand((DynamicUse selector) { | 428 var selections = <Selection>[]; |
| 434 return compiler.world.allFunctions | 429 selections.addAll(impact.dynamicUses.expand((dynamicUse) { |
| 435 .filter(selector.selector, selector.mask) | 430 return compiler.world.allFunctions |
| 436 .map((element) { | 431 .filter(dynamicUse.selector, dynamicUse.mask) |
| 437 return new Selection(element, selector.mask); | 432 .map((e) => new Selection(e, dynamicUse.mask)); |
| 438 }); | 433 })); |
| 439 }); | 434 selections.addAll(impact.staticUses |
| 440 } | 435 .map((staticUse) => new Selection(staticUse.element, null))); |
| 436 return selections; |
| 441 } | 437 } |
| 442 | 438 |
| 443 // Returns true if we care about tracking the size of | 439 // Returns true if we care about tracking the size of |
| 444 // this node. | 440 // this node. |
| 445 bool isTracking(jsAst.Node code) { | 441 bool isTracking(jsAst.Node code) { |
| 446 if (compiler.dumpInfo) { | 442 if (compiler.dumpInfo) { |
| 447 return _tracking.contains(code); | 443 return _tracking.contains(code); |
| 448 } else { | 444 } else { |
| 449 return false; | 445 return false; |
| 450 } | 446 } |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 575 | 571 |
| 576 ChunkedConversionSink<Object> sink = encoder.startChunkedConversion( | 572 ChunkedConversionSink<Object> sink = encoder.startChunkedConversion( |
| 577 new StringConversionSink.fromStringSink(buffer)); | 573 new StringConversionSink.fromStringSink(buffer)); |
| 578 sink.add(new AllInfoJsonCodec().encode(result)); | 574 sink.add(new AllInfoJsonCodec().encode(result)); |
| 579 reporter.reportInfo(NO_LOCATION_SPANNABLE, MessageKind.GENERIC, { | 575 reporter.reportInfo(NO_LOCATION_SPANNABLE, MessageKind.GENERIC, { |
| 580 'text': "View the dumped .info.json file at " | 576 'text': "View the dumped .info.json file at " |
| 581 "https://dart-lang.github.io/dump-info-visualizer" | 577 "https://dart-lang.github.io/dump-info-visualizer" |
| 582 }); | 578 }); |
| 583 } | 579 } |
| 584 } | 580 } |
| OLD | NEW |