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

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

Issue 2712983002: Add LookupTable class for finding classes and members by name.
Patch Set: Created 3 years, 9 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
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 import '../lookup_table.dart';
11 12
12 Program transformProgram(Program program, {List<ProgramRoot> programRoots}) { 13 Program transformProgram(Program program, {List<ProgramRoot> programRoots}) {
13 new TreeShaker(program, programRoots: programRoots).transform(program); 14 new TreeShaker(program, programRoots: programRoots).transform(program);
14 return program; 15 return program;
15 } 16 }
16 17
17 enum ProgramRootKind { 18 enum ProgramRootKind {
18 /// The root is a class which will be instantiated by 19 /// The root is a class which will be instantiated by
19 /// external / non-Dart code. 20 /// external / non-Dart code.
20 ExternallyInstantiatedClass, 21 ExternallyInstantiatedClass,
(...skipping 21 matching lines...) Expand all
42 43
43 /// The name of the member inside the library (or class, optional). 44 /// The name of the member inside the library (or class, optional).
44 final String member; 45 final String member;
45 46
46 /// The kind of this program root. 47 /// The kind of this program root.
47 final ProgramRootKind kind; 48 final ProgramRootKind kind;
48 49
49 ProgramRoot(this.library, this.klass, this.member, this.kind); 50 ProgramRoot(this.library, this.klass, this.member, this.kind);
50 51
51 String toString() => "ProgramRoot($library, $klass, $member, $kind)"; 52 String toString() => "ProgramRoot($library, $klass, $member, $kind)";
53
54 String get disambiguatedName {
55 if (kind == ProgramRootKind.Getter) return 'get:$member';
56 if (kind == ProgramRootKind.Setter) return 'set:$member';
57 return member;
58 }
59
60 Member getMember(LookupTable table) {
61 assert(klass != null);
62 assert(member != null);
63 return table.getMember(
64 library, klass ?? LookupTable.topLevel, disambiguatedName);
65 }
66
67 Class getClass(LookupTable table) {
68 assert(klass != null);
69 return table.getClass(library, klass);
70 }
52 } 71 }
53 72
54 /// Tree shaking based on class hierarchy analysis. 73 /// Tree shaking based on class hierarchy analysis.
55 /// 74 ///
56 /// Any dynamic dispatch not on `this` is conservatively assumed to target 75 /// Any dynamic dispatch not on `this` is conservatively assumed to target
57 /// any instantiated class that implements a member matching the selector. 76 /// any instantiated class that implements a member matching the selector.
58 /// 77 ///
59 /// Member bodies are analyzed relative to a given "host class" which is the 78 /// Member bodies are analyzed relative to a given "host class" which is the
60 /// concrete type of `this` (or null if in static context), so dispatches on 79 /// concrete type of `this` (or null if in static context), so dispatches on
61 /// `this` can be resolved more precisely. 80 /// `this` can be resolved more precisely.
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
196 this._usedMembersWithHost = 215 this._usedMembersWithHost =
197 new List<Set<Member>>(hierarchy.classes.length), 216 new List<Set<Member>>(hierarchy.classes.length),
198 this._classRetention = new List<ClassRetention>.filled( 217 this._classRetention = new List<ClassRetention>.filled(
199 hierarchy.classes.length, ClassRetention.None) { 218 hierarchy.classes.length, ClassRetention.None) {
200 _visitor = new _TreeShakerVisitor(this); 219 _visitor = new _TreeShakerVisitor(this);
201 _covariantVisitor = new _ExternalTypeVisitor(this, isCovariant: true); 220 _covariantVisitor = new _ExternalTypeVisitor(this, isCovariant: true);
202 _contravariantVisitor = 221 _contravariantVisitor =
203 new _ExternalTypeVisitor(this, isContravariant: true); 222 new _ExternalTypeVisitor(this, isContravariant: true);
204 _invariantVisitor = new _ExternalTypeVisitor(this, 223 _invariantVisitor = new _ExternalTypeVisitor(this,
205 isCovariant: true, isContravariant: true); 224 isCovariant: true, isContravariant: true);
206 _mirrorsLibrary = coreTypes.getCoreLibrary('dart:mirrors'); 225 _mirrorsLibrary = coreTypes.getLibrary('dart:mirrors');
207 try { 226 try {
208 _build(); 227 _build();
209 } on _UsingMirrorsException { 228 } on _UsingMirrorsException {
210 isUsingMirrors = true; 229 isUsingMirrors = true;
211 } 230 }
212 } 231 }
213 232
214 void _build() { 233 void _build() {
215 if (program.mainMethod == null) { 234 if (program.mainMethod == null) {
216 throw 'Cannot perform tree shaking on a program without a main method'; 235 throw 'Cannot perform tree shaking on a program without a main method';
217 } 236 }
218 if (program.mainMethod.function.positionalParameters.length > 0) { 237 if (program.mainMethod.function.positionalParameters.length > 0) {
219 // The main method takes a List<String> as argument. 238 // The main method takes a List<String> as argument.
220 _addInstantiatedExternalSubclass(coreTypes.listClass); 239 _addInstantiatedExternalSubclass(coreTypes.listClass);
221 _addInstantiatedExternalSubclass(coreTypes.stringClass); 240 _addInstantiatedExternalSubclass(coreTypes.stringClass);
222 } 241 }
223 _addDispatchedName(hierarchy.rootClass, new Name('noSuchMethod')); 242 _addDispatchedName(hierarchy.rootClass, new Name('noSuchMethod'));
224 _addPervasiveUses(); 243 _addPervasiveUses();
225 _addUsedMember(null, program.mainMethod); 244 _addUsedMember(null, program.mainMethod);
226 programRoots?.forEach(_addUsedRoot); 245 if (programRoots != null) {
246 var table = new LookupTable(program, programRoots.map((r) => r.library));
247 for (var root in programRoots) {
248 _addUsedRoot(root, table);
249 }
250 }
227 251
228 _iterateWorklist(); 252 _iterateWorklist();
229 253
230 // Mark overridden members in order to preserve abstract members as 254 // Mark overridden members in order to preserve abstract members as
231 // necessary. 255 // necessary.
232 if (strongMode) { 256 if (strongMode) {
233 for (int i = hierarchy.classes.length - 1; i >= 0; --i) { 257 for (int i = hierarchy.classes.length - 1; i >= 0; --i) {
234 Class class_ = hierarchy.classes[i]; 258 Class class_ = hierarchy.classes[i];
235 if (isHierarchyUsed(class_)) { 259 if (isHierarchyUsed(class_)) {
236 hierarchy.forEachOverridePair(class_, 260 hierarchy.forEachOverridePair(class_,
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
410 /// Ensures that all annotations on the class are analyzed. 434 /// Ensures that all annotations on the class are analyzed.
411 void _propagateClassNamespaceLevel( 435 void _propagateClassNamespaceLevel(
412 Class classNode, ClassRetention oldRetention) { 436 Class classNode, ClassRetention oldRetention) {
413 if (oldRetention.index >= ClassRetention.Namespace.index) { 437 if (oldRetention.index >= ClassRetention.Namespace.index) {
414 return; 438 return;
415 } 439 }
416 visitList(classNode.annotations, _visitor); 440 visitList(classNode.annotations, _visitor);
417 } 441 }
418 442
419 /// Registers the given root as being used. 443 /// Registers the given root as being used.
420 void _addUsedRoot(ProgramRoot root) { 444 void _addUsedRoot(ProgramRoot root, LookupTable table) {
421 Library rootLibrary = _findLibraryRoot(root, program);
422
423 if (root.kind == ProgramRootKind.ExternallyInstantiatedClass) { 445 if (root.kind == ProgramRootKind.ExternallyInstantiatedClass) {
424 Class rootClass = _findClassRoot(root, rootLibrary); 446 Class class_ = root.getClass(table);
425 447
426 // This is a class which will be instantiated by non-Dart code (whether it 448 // This is a class which will be instantiated by non-Dart code (whether it
427 // has a valid generative construtor or not). 449 // has a valid generative construtor or not).
428 _addInstantiatedClass(rootClass); 450 _addInstantiatedClass(class_);
429 451
430 // We keep all the constructors of externally instantiated classes. 452 // We keep all the constructors of externally instantiated classes.
431 // Sometimes the runtime might do a constructor call and sometimes it 453 // Sometimes the runtime might do a constructor call and sometimes it
432 // might just allocate the class without invoking the constructor. 454 // might just allocate the class without invoking the constructor.
433 // So we try to be on the safe side here! 455 // So we try to be on the safe side here!
434 for (var constructor in rootClass.constructors) { 456 for (var constructor in class_.constructors) {
435 _addUsedMember(rootClass, constructor); 457 _addUsedMember(class_, constructor);
436 } 458 }
437 459
438 // We keep all factory constructors as well for the same reason. 460 // We keep all factory constructors as well for the same reason.
439 for (var member in rootClass.procedures) { 461 for (var member in class_.procedures) {
440 if (member.isStatic && member.kind == ProcedureKind.Factory) { 462 if (member.isStatic && member.kind == ProcedureKind.Factory) {
441 _addUsedMember(rootClass, member); 463 _addUsedMember(class_, member);
442 } 464 }
443 } 465 }
444 } else { 466 } else {
445 if (root.klass != null) { 467 var member = root.getMember(table);
446 // For class members we mark the Field/Procedure/Constructor as used. 468 _addUsedMember(member.enclosingClass, member);
447 // We also mark it as instantiated if it's a constructor. 469 if (member is Constructor) {
448 Class rootClass = _findClassRoot(root, rootLibrary); 470 _addInstantiatedClass(member.enclosingClass);
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 } 471 }
459 } 472 }
460 } 473 }
461 474
462 /// Registers the given class as being used in a type annotation. 475 /// Registers the given class as being used in a type annotation.
463 void _addClassUsedInType(Class classNode) { 476 void _addClassUsedInType(Class classNode) {
464 int index = hierarchy.getClassIndex(classNode); 477 int index = hierarchy.getClassIndex(classNode);
465 ClassRetention retention = _classRetention[index]; 478 ClassRetention retention = _classRetention[index];
466 if (retention.index < ClassRetention.Hierarchy.index) { 479 if (retention.index < ClassRetention.Hierarchy.index) {
467 _classRetention[index] = ClassRetention.Hierarchy; 480 _classRetention[index] = ClassRetention.Hierarchy;
(...skipping 595 matching lines...) Expand 10 before | Expand all | Expand 10 after
1063 classNode == coreTypes.futureClass || 1076 classNode == coreTypes.futureClass ||
1064 classNode == coreTypes.streamClass || 1077 classNode == coreTypes.streamClass ||
1065 classNode == coreTypes.listClass || 1078 classNode == coreTypes.listClass ||
1066 classNode == coreTypes.mapClass; 1079 classNode == coreTypes.mapClass;
1067 } 1080 }
1068 } 1081 }
1069 1082
1070 /// Exception that is thrown to stop the tree shaking analysis when a use 1083 /// Exception that is thrown to stop the tree shaking analysis when a use
1071 /// of `dart:mirrors` is found. 1084 /// of `dart:mirrors` is found.
1072 class _UsingMirrorsException {} 1085 class _UsingMirrorsException {}
1073
1074 Library _findLibraryRoot(ProgramRoot root, Program program) {
1075 for (var library in program.libraries) {
1076 if (library.importUri.toString() == root.library) {
1077 return library;
1078 }
1079 }
1080
1081 throw "$root not found!";
1082 }
1083
1084 Class _findClassRoot(ProgramRoot root, Library rootLibrary) {
1085 for (var klass in rootLibrary.classes) {
1086 if (klass.name == root.klass) {
1087 return klass;
1088 }
1089 }
1090 throw "$root not found!";
1091 }
1092
1093 Member _findMemberRoot(ProgramRoot root, Iterable<Member> membersToSearch) {
1094 for (var member in membersToSearch) {
1095 if (member.name.name == root.member) {
1096 switch (root.kind) {
1097 case ProgramRootKind.Constructor:
1098 if (member is Procedure && member.kind == ProcedureKind.Factory ||
1099 member is Constructor) {
1100 return member;
1101 }
1102 break;
1103 case ProgramRootKind.Setter:
1104 if (member is Procedure && member.kind == ProcedureKind.Setter ||
1105 member is Field) {
1106 return member;
1107 }
1108 break;
1109 case ProgramRootKind.Getter:
1110 if (member is Procedure && member.kind == ProcedureKind.Getter ||
1111 member is Field) {
1112 return member;
1113 }
1114 break;
1115 case ProgramRootKind.Other:
1116 return member;
1117 default:
1118 }
1119 }
1120 }
1121 throw "$root not found!";
1122 }
OLDNEW
« no previous file with comments | « pkg/kernel/lib/transformations/mixin_full_resolution.dart ('k') | pkg/kernel/lib/type_propagation/builder.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698