| OLD | NEW |
| 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 '../library_index.dart'; | 11 import '../library_index.dart'; |
| 12 | 12 |
| 13 Program transformProgram(CoreTypes coreTypes, Program program, | 13 Program transformProgram( |
| 14 CoreTypes coreTypes, ClassHierarchy hierarchy, Program program, |
| 14 {List<ProgramRoot> programRoots}) { | 15 {List<ProgramRoot> programRoots}) { |
| 15 new TreeShaker(coreTypes, program, programRoots: programRoots) | 16 new TreeShaker(coreTypes, hierarchy, program, programRoots: programRoots) |
| 16 .transform(program); | 17 .transform(program); |
| 17 return program; | 18 return program; |
| 18 } | 19 } |
| 19 | 20 |
| 20 enum ProgramRootKind { | 21 enum ProgramRootKind { |
| 21 /// The root is a class which will be instantiated by | 22 /// The root is a class which will be instantiated by |
| 22 /// external / non-Dart code. | 23 /// external / non-Dart code. |
| 23 ExternallyInstantiatedClass, | 24 ExternallyInstantiatedClass, |
| 24 | 25 |
| 25 /// The root is a setter function or a field. | 26 /// The root is a setter function or a field. |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 83 /// | 84 /// |
| 84 /// The tree shaker computes the following in a fixed-point iteration: | 85 /// The tree shaker computes the following in a fixed-point iteration: |
| 85 /// - a set of instantiated classes | 86 /// - a set of instantiated classes |
| 86 /// - for each member, a set of potential host classes | 87 /// - for each member, a set of potential host classes |
| 87 /// - a set of names used in dynamic dispatch not on `this` | 88 /// - a set of names used in dynamic dispatch not on `this` |
| 88 /// | 89 /// |
| 89 /// If the `dart:mirrors` library is used then nothing will be tree-shaken. | 90 /// If the `dart:mirrors` library is used then nothing will be tree-shaken. |
| 90 // | 91 // |
| 91 // TODO(asgerf): Tree shake unused instance fields. | 92 // TODO(asgerf): Tree shake unused instance fields. |
| 92 class TreeShaker { | 93 class TreeShaker { |
| 94 final CoreTypes coreTypes; |
| 95 final ClosedWorldClassHierarchy hierarchy; |
| 93 final Program program; | 96 final Program program; |
| 94 final ClosedWorldClassHierarchy hierarchy; | |
| 95 final CoreTypes coreTypes; | |
| 96 final bool strongMode; | 97 final bool strongMode; |
| 97 final List<ProgramRoot> programRoots; | 98 final List<ProgramRoot> programRoots; |
| 98 | 99 |
| 99 /// Map from classes to set of names that have been dispatched with that class | 100 /// Map from classes to set of names that have been dispatched with that class |
| 100 /// as the static receiver type (meaning any subtype of that class can be | 101 /// as the static receiver type (meaning any subtype of that class can be |
| 101 /// the potential concrete receiver). | 102 /// the potential concrete receiver). |
| 102 /// | 103 /// |
| 103 /// The map is implemented as a list, indexed by | 104 /// The map is implemented as a list, indexed by |
| 104 /// [ClassHierarchy.getClassIndex]. | 105 /// [ClassHierarchy.getClassIndex]. |
| 105 final List<Set<Name>> _dispatchedNames; | 106 final List<Set<Name>> _dispatchedNames; |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 162 | 163 |
| 163 Library _mirrorsLibrary; | 164 Library _mirrorsLibrary; |
| 164 | 165 |
| 165 /// Set to true if any use of the `dart:mirrors` API is found. | 166 /// Set to true if any use of the `dart:mirrors` API is found. |
| 166 bool isUsingMirrors = false; | 167 bool isUsingMirrors = false; |
| 167 | 168 |
| 168 /// If we have roots, we will shake, even if we encounter some elements from | 169 /// If we have roots, we will shake, even if we encounter some elements from |
| 169 /// the mirrors library. | 170 /// the mirrors library. |
| 170 bool get forceShaking => programRoots != null && programRoots.isNotEmpty; | 171 bool get forceShaking => programRoots != null && programRoots.isNotEmpty; |
| 171 | 172 |
| 172 TreeShaker(CoreTypes coreTypes, Program program, | 173 TreeShaker(CoreTypes coreTypes, ClassHierarchy hierarchy, Program program, |
| 173 {ClassHierarchy hierarchy, | 174 {bool strongMode: false, List<ProgramRoot> programRoots}) |
| 174 bool strongMode: false, | 175 : this._internal(coreTypes, hierarchy, program, strongMode, programRoots); |
| 175 List<ProgramRoot> programRoots}) | |
| 176 : this._internal(program, hierarchy ?? new ClassHierarchy(program), | |
| 177 coreTypes, strongMode, programRoots); | |
| 178 | 176 |
| 179 bool isMemberBodyUsed(Member member) { | 177 bool isMemberBodyUsed(Member member) { |
| 180 return _usedMembers.containsKey(member); | 178 return _usedMembers.containsKey(member); |
| 181 } | 179 } |
| 182 | 180 |
| 183 bool isMemberOverridden(Member member) { | 181 bool isMemberOverridden(Member member) { |
| 184 return _overriddenMembers.contains(member); | 182 return _overriddenMembers.contains(member); |
| 185 } | 183 } |
| 186 | 184 |
| 187 bool isMemberUsed(Member member) { | 185 bool isMemberUsed(Member member) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 202 } | 200 } |
| 203 | 201 |
| 204 /// Applies the tree shaking results to the program. | 202 /// Applies the tree shaking results to the program. |
| 205 /// | 203 /// |
| 206 /// This removes unused classes, members, and hierarchy data. | 204 /// This removes unused classes, members, and hierarchy data. |
| 207 void transform(Program program) { | 205 void transform(Program program) { |
| 208 if (isUsingMirrors) return; // Give up if using mirrors. | 206 if (isUsingMirrors) return; // Give up if using mirrors. |
| 209 new _TreeShakingTransformer(this).transform(program); | 207 new _TreeShakingTransformer(this).transform(program); |
| 210 } | 208 } |
| 211 | 209 |
| 212 TreeShaker._internal(this.program, ClosedWorldClassHierarchy hierarchy, | 210 TreeShaker._internal(this.coreTypes, this.hierarchy, this.program, |
| 213 this.coreTypes, this.strongMode, this.programRoots) | 211 this.strongMode, this.programRoots) |
| 214 : this.hierarchy = hierarchy, | 212 : this._dispatchedNames = new List<Set<Name>>(hierarchy.classes.length), |
| 215 this._dispatchedNames = new List<Set<Name>>(hierarchy.classes.length), | |
| 216 this._usedMembersWithHost = | 213 this._usedMembersWithHost = |
| 217 new List<Set<Member>>(hierarchy.classes.length), | 214 new List<Set<Member>>(hierarchy.classes.length), |
| 218 this._classRetention = new List<ClassRetention>.filled( | 215 this._classRetention = new List<ClassRetention>.filled( |
| 219 hierarchy.classes.length, ClassRetention.None) { | 216 hierarchy.classes.length, ClassRetention.None) { |
| 220 _visitor = new _TreeShakerVisitor(this); | 217 _visitor = new _TreeShakerVisitor(this); |
| 221 _covariantVisitor = new _ExternalTypeVisitor(this, isCovariant: true); | 218 _covariantVisitor = new _ExternalTypeVisitor(this, isCovariant: true); |
| 222 _contravariantVisitor = | 219 _contravariantVisitor = |
| 223 new _ExternalTypeVisitor(this, isContravariant: true); | 220 new _ExternalTypeVisitor(this, isContravariant: true); |
| 224 _invariantVisitor = new _ExternalTypeVisitor(this, | 221 _invariantVisitor = new _ExternalTypeVisitor(this, |
| 225 isCovariant: true, isContravariant: true); | 222 isCovariant: true, isContravariant: true); |
| (...skipping 857 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1083 classNode == coreTypes.futureClass || | 1080 classNode == coreTypes.futureClass || |
| 1084 classNode == coreTypes.streamClass || | 1081 classNode == coreTypes.streamClass || |
| 1085 classNode == coreTypes.listClass || | 1082 classNode == coreTypes.listClass || |
| 1086 classNode == coreTypes.mapClass; | 1083 classNode == coreTypes.mapClass; |
| 1087 } | 1084 } |
| 1088 } | 1085 } |
| 1089 | 1086 |
| 1090 /// Exception that is thrown to stop the tree shaking analysis when a use | 1087 /// Exception that is thrown to stop the tree shaking analysis when a use |
| 1091 /// of `dart:mirrors` is found. | 1088 /// of `dart:mirrors` is found. |
| 1092 class _UsingMirrorsException {} | 1089 class _UsingMirrorsException {} |
| OLD | NEW |