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 |