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

Side by Side Diff: pkg/kernel/lib/transformations/treeshaker.dart

Issue 2668893004: VM: [Kernel] Add --embedder-entry-points-manifest to dartk/transform and pass it to the treeshaker (Closed)
Patch Set: Add missing bin/util.dart Created 3 years, 10 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
« no previous file with comments | « pkg/kernel/lib/target/vm.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2016, 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 kernel.tree_shaker; 5 library kernel.tree_shaker;
6 6
7 import '../ast.dart'; 7 import '../ast.dart';
8 import '../class_hierarchy.dart'; 8 import '../class_hierarchy.dart';
9 import '../core_types.dart'; 9 import '../core_types.dart';
10 import '../type_environment.dart'; 10 import '../type_environment.dart';
11 11
12 Program transformProgram(Program program) { 12 Program transformProgram(Program program, {List<ProgramRoot> programRoots}) {
13 new TreeShaker(program).transform(program); 13 new TreeShaker(program, programRoots: programRoots).transform(program);
14 return program; 14 return program;
15 } 15 }
16 16
17 enum ProgramRootKind {
18 /// The root is a class which will be instantiated by
19 /// external / non-Dart code.
20 ExternallyInstantiatedClass,
21
22 /// The root is a setter function or a field.
23 Setter,
24
25 /// The root is a getter function or a field.
26 Getter,
27
28 /// The root is some kind of constructor.
29 Constructor,
30
31 /// The root is a field, normal procedure or constructor.
32 Other,
33 }
34
35 /// A program root which the vm or embedder uses and needs to be retained.
36 class ProgramRoot {
37 /// The library the root is contained in.
38 final String library;
39
40 /// The name of the class inside the library (optional).
41 final String klass;
42
43 /// The name of the member inside the library (or class, optional).
44 final String member;
45
46 /// The kind of this program root.
47 final ProgramRootKind kind;
48
49 ProgramRoot(this.library, this.klass, this.member, this.kind);
50
51 String toString() => "ProgramRoot($library, $klass, $member, $kind)";
52 }
53
17 /// Tree shaking based on class hierarchy analysis. 54 /// Tree shaking based on class hierarchy analysis.
18 /// 55 ///
19 /// Any dynamic dispatch not on `this` is conservatively assumed to target 56 /// Any dynamic dispatch not on `this` is conservatively assumed to target
20 /// any instantiated class that implements a member matching the selector. 57 /// any instantiated class that implements a member matching the selector.
21 /// 58 ///
22 /// Member bodies are analyzed relative to a given "host class" which is the 59 /// Member bodies are analyzed relative to a given "host class" which is the
23 /// concrete type of `this` (or null if in static context), so dispatches on 60 /// concrete type of `this` (or null if in static context), so dispatches on
24 /// `this` can be resolved more precisely. 61 /// `this` can be resolved more precisely.
25 /// 62 ///
26 /// The tree shaker computes the following in a fixed-point iteration: 63 /// The tree shaker computes the following in a fixed-point iteration:
27 /// - a set of instantiated classes 64 /// - a set of instantiated classes
28 /// - for each member, a set of potential host classes 65 /// - for each member, a set of potential host classes
29 /// - a set of names used in dynamic dispatch not on `this` 66 /// - a set of names used in dynamic dispatch not on `this`
30 /// 67 ///
31 /// If the `dart:mirrors` library is used then nothing will be tree-shaken. 68 /// If the `dart:mirrors` library is used then nothing will be tree-shaken.
32 // 69 //
33 // TODO(asgerf): Shake off parts of the core libraries based on the Target.
34 // TODO(asgerf): Tree shake unused instance fields. 70 // TODO(asgerf): Tree shake unused instance fields.
35 class TreeShaker { 71 class TreeShaker {
36 final Program program; 72 final Program program;
37 final ClassHierarchy hierarchy; 73 final ClassHierarchy hierarchy;
38 final CoreTypes coreTypes; 74 final CoreTypes coreTypes;
39 final bool strongMode; 75 final bool strongMode;
76 final List<ProgramRoot> programRoots;
40 77
41 /// Map from classes to set of names that have been dispatched with that class 78 /// Map from classes to set of names that have been dispatched with that class
42 /// as the static receiver type (meaning any subtype of that class can be 79 /// as the static receiver type (meaning any subtype of that class can be
43 /// the potential concrete receiver). 80 /// the potential concrete receiver).
44 /// 81 ///
45 /// The map is implemented as a list, indexed by 82 /// The map is implemented as a list, indexed by
46 /// [ClassHierarchy.getClassIndex]. 83 /// [ClassHierarchy.getClassIndex].
47 final List<Set<Name>> _dispatchedNames; 84 final List<Set<Name>> _dispatchedNames;
48 85
49 /// Map from names to the set of classes that might be the concrete receiver 86 /// Map from names to the set of classes that might be the concrete receiver
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
100 /// AST visitor for analyzing type annotations on external members. 137 /// AST visitor for analyzing type annotations on external members.
101 _ExternalTypeVisitor _covariantVisitor; 138 _ExternalTypeVisitor _covariantVisitor;
102 _ExternalTypeVisitor _contravariantVisitor; 139 _ExternalTypeVisitor _contravariantVisitor;
103 _ExternalTypeVisitor _invariantVisitor; 140 _ExternalTypeVisitor _invariantVisitor;
104 141
105 Library _mirrorsLibrary; 142 Library _mirrorsLibrary;
106 143
107 /// Set to true if any use of the `dart:mirrors` API is found. 144 /// Set to true if any use of the `dart:mirrors` API is found.
108 bool isUsingMirrors = false; 145 bool isUsingMirrors = false;
109 146
147 /// If we have roots, we will shake, even if we encounter some elements from
148 /// the mirrors library.
149 bool get forceShaking => programRoots != null && programRoots.isNotEmpty;
150
110 TreeShaker(Program program, 151 TreeShaker(Program program,
111 {ClassHierarchy hierarchy, CoreTypes coreTypes, bool strongMode: false}) 152 {ClassHierarchy hierarchy,
153 CoreTypes coreTypes,
154 bool strongMode: false,
155 List<ProgramRoot> programRoots})
112 : this._internal(program, hierarchy ?? new ClassHierarchy(program), 156 : this._internal(program, hierarchy ?? new ClassHierarchy(program),
113 coreTypes ?? new CoreTypes(program), strongMode); 157 coreTypes ?? new CoreTypes(program), strongMode, programRoots);
114 158
115 bool isMemberBodyUsed(Member member) { 159 bool isMemberBodyUsed(Member member) {
116 return _usedMembers.containsKey(member); 160 return _usedMembers.containsKey(member);
117 } 161 }
118 162
119 bool isMemberOverridden(Member member) { 163 bool isMemberOverridden(Member member) {
120 return _overriddenMembers.contains(member); 164 return _overriddenMembers.contains(member);
121 } 165 }
122 166
123 bool isMemberUsed(Member member) { 167 bool isMemberUsed(Member member) {
(...skipping 14 matching lines...) Expand all
138 } 182 }
139 183
140 /// Applies the tree shaking results to the program. 184 /// Applies the tree shaking results to the program.
141 /// 185 ///
142 /// This removes unused classes, members, and hierarchy data. 186 /// This removes unused classes, members, and hierarchy data.
143 void transform(Program program) { 187 void transform(Program program) {
144 if (isUsingMirrors) return; // Give up if using mirrors. 188 if (isUsingMirrors) return; // Give up if using mirrors.
145 new _TreeShakingTransformer(this).transform(program); 189 new _TreeShakingTransformer(this).transform(program);
146 } 190 }
147 191
148 TreeShaker._internal( 192 TreeShaker._internal(this.program, ClassHierarchy hierarchy, this.coreTypes,
149 this.program, ClassHierarchy hierarchy, this.coreTypes, this.strongMode) 193 this.strongMode, this.programRoots)
150 : this.hierarchy = hierarchy, 194 : this.hierarchy = hierarchy,
151 this._dispatchedNames = new List<Set<Name>>(hierarchy.classes.length), 195 this._dispatchedNames = new List<Set<Name>>(hierarchy.classes.length),
152 this._usedMembersWithHost = 196 this._usedMembersWithHost =
153 new List<Set<Member>>(hierarchy.classes.length), 197 new List<Set<Member>>(hierarchy.classes.length),
154 this._classRetention = new List<ClassRetention>.filled( 198 this._classRetention = new List<ClassRetention>.filled(
155 hierarchy.classes.length, ClassRetention.None) { 199 hierarchy.classes.length, ClassRetention.None) {
156 _visitor = new _TreeShakerVisitor(this); 200 _visitor = new _TreeShakerVisitor(this);
157 _covariantVisitor = new _ExternalTypeVisitor(this, isCovariant: true); 201 _covariantVisitor = new _ExternalTypeVisitor(this, isCovariant: true);
158 _contravariantVisitor = 202 _contravariantVisitor =
159 new _ExternalTypeVisitor(this, isContravariant: true); 203 new _ExternalTypeVisitor(this, isContravariant: true);
(...skipping 12 matching lines...) Expand all
172 throw 'Cannot perform tree shaking on a program without a main method'; 216 throw 'Cannot perform tree shaking on a program without a main method';
173 } 217 }
174 if (program.mainMethod.function.positionalParameters.length > 0) { 218 if (program.mainMethod.function.positionalParameters.length > 0) {
175 // The main method takes a List<String> as argument. 219 // The main method takes a List<String> as argument.
176 _addInstantiatedExternalSubclass(coreTypes.listClass); 220 _addInstantiatedExternalSubclass(coreTypes.listClass);
177 _addInstantiatedExternalSubclass(coreTypes.stringClass); 221 _addInstantiatedExternalSubclass(coreTypes.stringClass);
178 } 222 }
179 _addDispatchedName(hierarchy.rootClass, new Name('noSuchMethod')); 223 _addDispatchedName(hierarchy.rootClass, new Name('noSuchMethod'));
180 _addPervasiveUses(); 224 _addPervasiveUses();
181 _addUsedMember(null, program.mainMethod); 225 _addUsedMember(null, program.mainMethod);
226 programRoots?.forEach(_addUsedRoot);
227
182 _iterateWorklist(); 228 _iterateWorklist();
183 229
184 // Mark overridden members in order to preserve abstract members as 230 // Mark overridden members in order to preserve abstract members as
185 // necessary. 231 // necessary.
186 if (strongMode) { 232 if (strongMode) {
187 for (int i = hierarchy.classes.length - 1; i >= 0; --i) { 233 for (int i = hierarchy.classes.length - 1; i >= 0; --i) {
188 Class class_ = hierarchy.classes[i]; 234 Class class_ = hierarchy.classes[i];
189 if (isHierarchyUsed(class_)) { 235 if (isHierarchyUsed(class_)) {
190 hierarchy.forEachOverridePair(class_, 236 hierarchy.forEachOverridePair(class_,
191 (Member ownMember, Member superMember, bool isSetter) { 237 (Member ownMember, Member superMember, bool isSetter) {
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
363 /// 409 ///
364 /// Ensures that all annotations on the class are analyzed. 410 /// Ensures that all annotations on the class are analyzed.
365 void _propagateClassNamespaceLevel( 411 void _propagateClassNamespaceLevel(
366 Class classNode, ClassRetention oldRetention) { 412 Class classNode, ClassRetention oldRetention) {
367 if (oldRetention.index >= ClassRetention.Namespace.index) { 413 if (oldRetention.index >= ClassRetention.Namespace.index) {
368 return; 414 return;
369 } 415 }
370 visitList(classNode.annotations, _visitor); 416 visitList(classNode.annotations, _visitor);
371 } 417 }
372 418
419 /// Registers the given root as being used.
420 void _addUsedRoot(ProgramRoot root) {
421 Library rootLibrary = _findLibraryRoot(root, program);
422
423 if (root.kind == ProgramRootKind.ExternallyInstantiatedClass) {
424 Class rootClass = _findClassRoot(root, rootLibrary);
425
426 // This is a class which will be instantiated by non-Dart code (whether it
427 // has a valid generative construtor or not).
428 _addInstantiatedClass(rootClass);
429
430 // We keep all the constructors of externally instantiated classes.
431 // Sometimes the runtime might do a constructor call and sometimes it
432 // might just allocate the class without invoking the constructor.
433 // So we try to be on the safe side here!
434 for (var constructor in rootClass.constructors) {
435 _addUsedMember(rootClass, constructor);
436 }
437
438 // We keep all factory constructors as well for the same reason.
439 for (var member in rootClass.procedures) {
440 if (member.isStatic && member.kind == ProcedureKind.Factory) {
441 _addUsedMember(rootClass, member);
442 }
443 }
444 } else {
445 if (root.klass != null) {
446 // For class members we mark the Field/Procedure/Constructor as used.
447 // We also mark it as instantiated if it's a constructor.
448 Class rootClass = _findClassRoot(root, rootLibrary);
449 Member rootMember = _findMemberRoot(root, rootClass.members);
450 _addUsedMember(rootClass, rootMember);
451 if (rootMember is Constructor) {
452 _addInstantiatedClass(rootClass);
453 }
454 } else {
455 // For library members we mark the Field/Procedure as used.
456 Member rootMember = _findMemberRoot(root, rootLibrary.members);
457 _addUsedMember(null, rootMember);
458 }
459 }
460 }
461
373 /// Registers the given class as being used in a type annotation. 462 /// Registers the given class as being used in a type annotation.
374 void _addClassUsedInType(Class classNode) { 463 void _addClassUsedInType(Class classNode) {
375 int index = hierarchy.getClassIndex(classNode); 464 int index = hierarchy.getClassIndex(classNode);
376 ClassRetention retention = _classRetention[index]; 465 ClassRetention retention = _classRetention[index];
377 if (retention.index < ClassRetention.Hierarchy.index) { 466 if (retention.index < ClassRetention.Hierarchy.index) {
378 _classRetention[index] = ClassRetention.Hierarchy; 467 _classRetention[index] = ClassRetention.Hierarchy;
379 _propagateClassHierarchyLevel(classNode, retention); 468 _propagateClassHierarchyLevel(classNode, retention);
380 } 469 }
381 } 470 }
382 471
(...skipping 10 matching lines...) Expand all
393 } 482 }
394 } 483 }
395 484
396 /// Registers the given member as being used, in the following sense: 485 /// Registers the given member as being used, in the following sense:
397 /// - Fields are used if they can be read or written or their initializer is 486 /// - Fields are used if they can be read or written or their initializer is
398 /// evaluated. 487 /// evaluated.
399 /// - Constructors are used if they can be invoked, either directly or through 488 /// - Constructors are used if they can be invoked, either directly or through
400 /// the initializer list of another constructor. 489 /// the initializer list of another constructor.
401 /// - Procedures are used if they can be invoked or torn off. 490 /// - Procedures are used if they can be invoked or torn off.
402 void _addUsedMember(Class host, Member member) { 491 void _addUsedMember(Class host, Member member) {
403 if (member.enclosingLibrary == _mirrorsLibrary) { 492 if (!forceShaking && member.enclosingLibrary == _mirrorsLibrary) {
404 throw new _UsingMirrorsException(); 493 throw new _UsingMirrorsException();
405 } 494 }
406 if (host != null) { 495 if (host != null) {
407 // Check if the member has been seen with this host before. 496 // Check if the member has been seen with this host before.
408 int index = hierarchy.getClassIndex(host); 497 int index = hierarchy.getClassIndex(host);
409 Set<Member> members = _usedMembersWithHost[index] ??= new Set<Member>(); 498 Set<Member> members = _usedMembersWithHost[index] ??= new Set<Member>();
410 if (!members.add(member)) return; 499 if (!members.add(member)) return;
411 _usedMembers.putIfAbsent(member, _makeIncompleteSummary); 500 _usedMembers.putIfAbsent(member, _makeIncompleteSummary);
412 } else { 501 } else {
413 // Check if the member has been seen before. 502 // Check if the member has been seen before.
(...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after
801 final TreeShaker shaker; 890 final TreeShaker shaker;
802 891
803 _TreeShakingTransformer(this.shaker); 892 _TreeShakingTransformer(this.shaker);
804 893
805 Member _translateInterfaceTarget(Member target) { 894 Member _translateInterfaceTarget(Member target) {
806 return target != null && shaker.isMemberUsed(target) ? target : null; 895 return target != null && shaker.isMemberUsed(target) ? target : null;
807 } 896 }
808 897
809 void transform(Program program) { 898 void transform(Program program) {
810 for (var library in program.libraries) { 899 for (var library in program.libraries) {
811 if (library.importUri.scheme == 'dart') { 900 if (!shaker.forceShaking && library.importUri.scheme == 'dart') {
812 // The backend expects certain things to be present in the core 901 // The backend expects certain things to be present in the core
813 // libraries, so we currently don't shake off anything there. 902 // libraries, so we currently don't shake off anything there.
814 continue; 903 continue;
815 } 904 }
816 library.transformChildren(this); 905 library.transformChildren(this);
817 // Note: we can't shake off empty libraries yet since we don't check if 906 // Note: we can't shake off empty libraries yet since we don't check if
818 // there are private names that use the library. 907 // there are private names that use the library.
819 } 908 }
820 for (Expression node in shaker._typedCalls) { 909 for (Expression node in shaker._typedCalls) {
821 // We should not leave dangling references, so if the target of a typed 910 // We should not leave dangling references, so if the target of a typed
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
972 classNode == coreTypes.futureClass || 1061 classNode == coreTypes.futureClass ||
973 classNode == coreTypes.streamClass || 1062 classNode == coreTypes.streamClass ||
974 classNode == coreTypes.listClass || 1063 classNode == coreTypes.listClass ||
975 classNode == coreTypes.mapClass; 1064 classNode == coreTypes.mapClass;
976 } 1065 }
977 } 1066 }
978 1067
979 /// Exception that is thrown to stop the tree shaking analysis when a use 1068 /// Exception that is thrown to stop the tree shaking analysis when a use
980 /// of `dart:mirrors` is found. 1069 /// of `dart:mirrors` is found.
981 class _UsingMirrorsException {} 1070 class _UsingMirrorsException {}
1071
1072 Library _findLibraryRoot(ProgramRoot root, Program program) {
1073 for (var library in program.libraries) {
1074 if (library.importUri.toString() == root.library) {
1075 return library;
1076 }
1077 }
1078
1079 throw "$root not found!";
1080 }
1081
1082 Class _findClassRoot(ProgramRoot root, Library rootLibrary) {
1083 for (var klass in rootLibrary.classes) {
1084 if (klass.name == root.klass) {
1085 return klass;
1086 }
1087 }
1088 throw "$root not found!";
1089 }
1090
1091 Member _findMemberRoot(ProgramRoot root, Iterable<Member> membersToSearch) {
1092 for (var member in membersToSearch) {
1093 if (member.name.name == root.member) {
1094 switch (root.kind) {
1095 case ProgramRootKind.Constructor:
1096 if (member is Procedure && member.kind == ProcedureKind.Factory ||
1097 member is Constructor) {
1098 return member;
1099 }
1100 break;
1101 case ProgramRootKind.Setter:
1102 if (member is Procedure && member.kind == ProcedureKind.Setter ||
1103 member is Field) {
1104 return member;
1105 }
1106 break;
1107 case ProgramRootKind.Getter:
1108 if (member is Procedure && member.kind == ProcedureKind.Getter ||
1109 member is Field) {
1110 return member;
1111 }
1112 break;
1113 case ProgramRootKind.Other:
1114 return member;
1115 default:
1116 }
1117 }
1118 }
1119 throw "$root not found!";
1120 }
OLDNEW
« no previous file with comments | « pkg/kernel/lib/target/vm.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698