Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(295)

Side by Side Diff: sdk/lib/_internal/compiler/implementation/dump_info.dart

Issue 430913002: Better dependency tracking (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: fixed final critiques Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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' show 7 import 'dart:convert' show
8 HtmlEscape, 8 HtmlEscape,
9 JsonEncoder, 9 JsonEncoder,
10 StringConversionSink, 10 StringConversionSink,
11 ChunkedConversionSink; 11 ChunkedConversionSink;
12 12
13 import 'elements/elements.dart'; 13 import 'elements/elements.dart';
14 import 'elements/visitor.dart'; 14 import 'elements/visitor.dart';
15 import 'dart2jslib.dart' show 15 import 'dart2jslib.dart' show
16 Compiler, 16 Compiler,
17 CompilerTask, 17 CompilerTask,
18 CodeBuffer; 18 CodeBuffer;
19 import 'dart_types.dart' show DartType; 19 import 'dart_types.dart' show DartType;
20 import 'types/types.dart' show TypeMask; 20 import 'types/types.dart' show TypeMask;
21 import 'util/util.dart' show modifiersToString; 21 import 'util/util.dart' show modifiersToString, SpannableAssertionFailure;
22 import 'deferred_load.dart' show OutputUnit; 22 import 'deferred_load.dart' show OutputUnit;
23 import 'js_backend/js_backend.dart' show JavaScriptBackend; 23 import 'js_backend/js_backend.dart' show JavaScriptBackend;
24 import 'js/js.dart' as jsAst; 24 import 'js/js.dart' as jsAst;
25 import 'compilation_info.dart' show CompilationInformation; 25 import 'universe/universe.dart' show Selector;
26 26
27 /// Maps elements to an id. Supports lookups in 27 /// Maps elements to an id. Supports lookups in
28 /// both directions. 28 /// both directions.
29 class ElementMapper { 29 class ElementMapper {
30 Map<int, Element> _idToElement = {}; 30 Map<int, Element> _idToElement = {};
31 Map<Element, int> _elementToId = {}; 31 Map<Element, int> _elementToId = {};
32 int _idCounter = 0; 32 int _idCounter = 0;
33 String name; 33 String name;
34 34
35 ElementMapper(this.name); 35 ElementMapper(this.name);
36 36
37 Iterable<Element> get elements => _elementToId.keys;
38
37 String add(Element e) { 39 String add(Element e) {
38 if (_elementToId.containsKey(e)) { 40 if (_elementToId.containsKey(e)) {
39 return name + "/${_elementToId[e]}"; 41 return name + "/${_elementToId[e]}";
40 } 42 }
41 43
42 _idToElement[_idCounter] = e; 44 _idToElement[_idCounter] = e;
43 _elementToId[e] = _idCounter; 45 _elementToId[e] = _idCounter;
44 _idCounter += 1; 46 _idCounter += 1;
45 return name + "/${_idCounter - 1}"; 47 return name + "/${_idCounter - 1}";
46 } 48 }
47 } 49 }
48 50
49 class DividedElementMapper { 51 class DividedElementMapper {
50 // Mappers for specific kinds of elements. 52 // Mappers for specific kinds of elements.
51 ElementMapper _library = new ElementMapper('library'); 53 ElementMapper _library = new ElementMapper('library');
52 ElementMapper _typedef = new ElementMapper('typedef'); 54 ElementMapper _typedef = new ElementMapper('typedef');
53 ElementMapper _field = new ElementMapper('field'); 55 ElementMapper _field = new ElementMapper('field');
54 ElementMapper _class = new ElementMapper('class'); 56 ElementMapper _class = new ElementMapper('class');
55 ElementMapper _function = new ElementMapper('function'); 57 ElementMapper _function = new ElementMapper('function');
56 58
59 Iterable<Element> get functions => _function.elements;
60
57 // Convert this database of elements into JSON for rendering 61 // Convert this database of elements into JSON for rendering
58 Map<String, dynamic> _toJson(ElementToJsonVisitor elementToJson) { 62 Map<String, dynamic> _toJson(ElementToJsonVisitor elementToJson) {
59 Map<String, dynamic> json = {}; 63 Map<String, dynamic> json = {};
60 var m = [_library, _typedef, _field, _class, _function]; 64 var m = [_library, _typedef, _field, _class, _function];
61 for (ElementMapper mapper in m) { 65 for (ElementMapper mapper in m) {
62 Map<String, dynamic> innerMapper = {}; 66 Map<String, dynamic> innerMapper = {};
63 mapper._idToElement.forEach((k, v) { 67 mapper._idToElement.forEach((k, v) {
64 // All these elements are already cached in the 68 // All these elements are already cached in the
65 // jsonCache, so this is just an access. 69 // jsonCache, so this is just an access.
66 var elementJson = elementToJson.process(v); 70 var elementJson = elementToJson.process(v);
67 if (elementJson != null) { 71 if (elementJson != null) {
68 innerMapper["$k"] = elementJson; 72 innerMapper["$k"] = elementJson;
69 } 73 }
70 }); 74 });
71 json[mapper.name] = innerMapper; 75 json[mapper.name] = innerMapper;
72 } 76 }
73 return json; 77 return json;
74 } 78 }
75 } 79 }
76 80
77 class ElementToJsonVisitor extends ElementVisitor<Map<String, dynamic>> { 81 class ElementToJsonVisitor extends ElementVisitor<Map<String, dynamic>> {
78 DividedElementMapper mapper = new DividedElementMapper(); 82 DividedElementMapper mapper = new DividedElementMapper();
79 Compiler compiler; 83 Compiler compiler;
80 84
81 CompilationInformation compilationInfo;
82
83 Map<Element, Map<String, dynamic>> jsonCache = {}; 85 Map<Element, Map<String, dynamic>> jsonCache = {};
84 Map<Element, jsAst.Expression> codeCache; 86 Map<Element, jsAst.Expression> codeCache;
85 87
86 int programSize; 88 int programSize;
87 DateTime compilationMoment; 89 DateTime compilationMoment;
88 String dart2jsVersion; 90 String dart2jsVersion;
89 Duration compilationDuration; 91 Duration compilationDuration;
90 Duration dumpInfoDuration; 92 Duration dumpInfoDuration;
91 93
92 ElementToJsonVisitor(Compiler compiler) { 94 ElementToJsonVisitor(Compiler compiler) {
93 this.compiler = compiler; 95 this.compiler = compiler;
94 this.compilationInfo = compiler.enqueuer.codegen.compilationInfo;
95 96
96 programSize = compiler.assembledCode.length; 97 programSize = compiler.assembledCode.length;
97 compilationMoment = new DateTime.now(); 98 compilationMoment = new DateTime.now();
98 dart2jsVersion = compiler.hasBuildId ? compiler.buildId : null; 99 dart2jsVersion = compiler.hasBuildId ? compiler.buildId : null;
99 compilationDuration = compiler.totalCompileTime.elapsed; 100 compilationDuration = compiler.totalCompileTime.elapsed;
100 101
101 for (var library in compiler.libraryLoader.libraries.toList()) { 102 for (var library in compiler.libraryLoader.libraries.toList()) {
102 library.accept(this); 103 library.accept(this);
103 } 104 }
104 105
105 dumpInfoDuration = new DateTime.now().difference(compilationMoment); 106 dumpInfoDuration = new DateTime.now().difference(compilationMoment);
106 } 107 }
107 108
108 // If keeping the element is in question (like if a function has a size 109 // If keeping the element is in question (like if a function has a size
109 // of zero), only keep it if it holds dependencies to elsewhere. 110 // of zero), only keep it if it holds dependencies to elsewhere.
110 bool shouldKeep(Element element) { 111 bool shouldKeep(Element element) {
111 return compilationInfo.addsToWorkListMap.containsKey(element) || 112 return compiler.dumpInfoTask.selectorsFromElement.containsKey(element);
112 compilationInfo.enqueuesMap.containsKey(element);
113 } 113 }
114 114
115 Map<String, dynamic> toJson() { 115 Map<String, dynamic> toJson() {
116 return mapper._toJson(this); 116 return mapper._toJson(this);
117 } 117 }
118 118
119 // Memoization of the JSON creating process. 119 // Memoization of the JSON creating process.
120 Map<String, dynamic> process(Element element) { 120 Map<String, dynamic> process(Element element) {
121 return jsonCache.putIfAbsent(element, () => element.accept(this)); 121 return jsonCache.putIfAbsent(element, () => element.accept(this));
122 } 122 }
123 123
124 // Returns the id of an [element] if it has already been processed.
125 // If the element has not been processed, this function does not
126 // process it, and simply returns null instead.
127 String idOf(Element element) {
128 if (jsonCache.containsKey(element) && jsonCache[element] != null) {
129 return jsonCache[element]['id'];
130 } else {
131 return null;
132 }
133 }
134
124 Map<String, dynamic> visitElement(Element element) { 135 Map<String, dynamic> visitElement(Element element) {
125 return null; 136 return null;
126 } 137 }
127 138
128 Map<String, dynamic> visitConstructorBodyElement(ConstructorBodyElement e) { 139 Map<String, dynamic> visitConstructorBodyElement(ConstructorBodyElement e) {
129 return visitFunctionElement(e.constructor); 140 return visitFunctionElement(e.constructor);
130 } 141 }
131 142
132 Map<String, dynamic> visitLibraryElement(LibraryElement element) { 143 Map<String, dynamic> visitLibraryElement(LibraryElement element) {
133 var id = mapper._library.add(element); 144 var id = mapper._library.add(element);
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after
341 final Set<jsAst.Node> _tracking = new Set<jsAst.Node>(); 352 final Set<jsAst.Node> _tracking = new Set<jsAst.Node>();
342 // A mapping from Dart Elements to Javascript AST Nodes. 353 // A mapping from Dart Elements to Javascript AST Nodes.
343 final Map<Element, List<jsAst.Node>> _elementToNodes = 354 final Map<Element, List<jsAst.Node>> _elementToNodes =
344 <Element, List<jsAst.Node>>{}; 355 <Element, List<jsAst.Node>>{};
345 // A mapping from Javascript AST Nodes to the size of their 356 // A mapping from Javascript AST Nodes to the size of their
346 // pretty-printed contents. 357 // pretty-printed contents.
347 final Map<jsAst.Node, int> _nodeToSize = <jsAst.Node, int>{}; 358 final Map<jsAst.Node, int> _nodeToSize = <jsAst.Node, int>{};
348 final Map<jsAst.Node, int> _nodeBeforeSize = <jsAst.Node, int>{}; 359 final Map<jsAst.Node, int> _nodeBeforeSize = <jsAst.Node, int>{};
349 final Map<Element, int> _fieldNameToSize = <Element, int>{}; 360 final Map<Element, int> _fieldNameToSize = <Element, int>{};
350 361
362 final Map<Element, Set<Selector>> selectorsFromElement = {};
363
364 /**
365 * Registers that a function uses a selector in the
366 * function body
367 */
368 void elementUsesSelector(Element element, Selector selector) {
369 if (compiler.dumpInfo) {
370 selectorsFromElement
371 .putIfAbsent(element, () => new Set<Selector>())
372 .add(selector);
373 }
374 }
375
376 /**
377 * Returns an iterable of [Element]s that are used by
378 * [element].
379 */
380 Iterable<Element> getRetaining(Element element) {
381 if (!selectorsFromElement.containsKey(element)) {
382 return const <Element>[];
383 } else {
384 return selectorsFromElement[element].expand(
385 (s) => compiler.world.allFunctions.filter(s));
386 }
387 }
388
351 /** 389 /**
352 * A callback that can be called before a jsAst [node] is 390 * A callback that can be called before a jsAst [node] is
353 * pretty-printed. The size of the code buffer ([aftersize]) 391 * pretty-printed. The size of the code buffer ([aftersize])
354 * is also passed. 392 * is also passed.
355 */ 393 */
356 void enteringAst(jsAst.Node node, int beforeSize) { 394 void enteringAst(jsAst.Node node, int beforeSize) {
357 if (isTracking(node)) { 395 if (isTracking(node)) {
358 _nodeBeforeSize[node] = beforeSize; 396 _nodeBeforeSize[node] = beforeSize;
359 } 397 }
360 } 398 }
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
456 dumpInfoJson(jsonBuffer); 494 dumpInfoJson(jsonBuffer);
457 compiler.outputProvider('', 'info.json') 495 compiler.outputProvider('', 'info.json')
458 ..add(jsonBuffer.toString()) 496 ..add(jsonBuffer.toString())
459 ..close(); 497 ..close();
460 }); 498 });
461 } 499 }
462 500
463 501
464 void dumpInfoJson(StringSink buffer) { 502 void dumpInfoJson(StringSink buffer) {
465 JsonEncoder encoder = const JsonEncoder(); 503 JsonEncoder encoder = const JsonEncoder();
466
467 // `A` uses and depends on the functions `Bs`.
468 // A Bs
469 Map<String, List<String>> holding = <String, List<String>>{};
470
471 DateTime startToJsonTime = new DateTime.now(); 504 DateTime startToJsonTime = new DateTime.now();
472 505
473 CompilationInformation compilationInfo = 506 Map<String, List<String>> holding = <String, List<String>>{};
474 infoCollector.compiler.enqueuer.codegen.compilationInfo; 507 for (Element fn in infoCollector.mapper.functions) {
475 compilationInfo.addsToWorkListMap.forEach((func, deps) { 508 Iterable<Element> pulling = getRetaining(fn);
476 if (func != null) { 509 // Don't bother recording an empty list of dependencies.
477 var funcJson = infoCollector.process(func); 510 if (pulling.length > 0) {
478 if (funcJson != null) { 511 String fnId = infoCollector.idOf(fn);
479 var funcId = funcJson['id']; 512 // Some dart2js builtin functions are not
480 513 // recorded. Don't register these.
481 List<String> heldList = <String>[]; 514 if (fnId != null) {
482 515 holding[fnId] = pulling
483 for (var held in deps) { 516 .map((a) => infoCollector.idOf(a))
484 // "process" to get the ids of the elements. 517 // Filter non-null ids for the same reason as above.
485 var heldJson = infoCollector.process(held); 518 .where((a) => a != null)
486 if (heldJson != null) { 519 .toList();
487 var heldId = heldJson['id'];
488 heldList.add(heldId);
489 }
490 }
491 holding[funcId] = heldList;
492 } 520 }
493 } 521 }
494 }); 522 }
495 523
496 Map<String, dynamic> outJson = { 524 Map<String, dynamic> outJson = {
497 'elements': infoCollector.toJson(), 525 'elements': infoCollector.toJson(),
498 'holding': holding, 526 'holding': holding,
499 'dump_version': 1, 527 'dump_version': 1,
500 }; 528 };
501 529
502 Duration toJsonDuration = new DateTime.now().difference(startToJsonTime); 530 Duration toJsonDuration = new DateTime.now().difference(startToJsonTime);
503 531
504 Map<String, dynamic> generalProgramInfo = <String, dynamic> { 532 Map<String, dynamic> generalProgramInfo = <String, dynamic> {
505 'size': infoCollector.programSize, 533 'size': infoCollector.programSize,
506 'dart2jsVersion': infoCollector.dart2jsVersion, 534 'dart2jsVersion': infoCollector.dart2jsVersion,
507 'compilationMoment': infoCollector.compilationMoment.toString(), 535 'compilationMoment': infoCollector.compilationMoment.toString(),
508 'compilationDuration': infoCollector.compilationDuration.toString(), 536 'compilationDuration': infoCollector.compilationDuration.toString(),
509 'toJsonDuration': toJsonDuration.toString(), 537 'toJsonDuration': toJsonDuration.toString(),
510 'dumpInfoDuration': infoCollector.dumpInfoDuration.toString(), 538 'dumpInfoDuration': infoCollector.dumpInfoDuration.toString(),
511 'noSuchMethodEnabled': compiler.enabledNoSuchMethod 539 'noSuchMethodEnabled': compiler.enabledNoSuchMethod
512 }; 540 };
513 541
514 outJson['program'] = generalProgramInfo; 542 outJson['program'] = generalProgramInfo;
515 543
516 ChunkedConversionSink<Object> sink = 544 ChunkedConversionSink<Object> sink =
517 encoder.startChunkedConversion( 545 encoder.startChunkedConversion(
518 new StringConversionSink.fromStringSink(buffer)); 546 new StringConversionSink.fromStringSink(buffer));
519 sink.add(outJson); 547 sink.add(outJson);
520 } 548 }
521 } 549 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698