OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 dart2js.enqueue; | 5 library dart2js.enqueue; |
6 | 6 |
7 import 'dart:collection' show Queue; | 7 import 'dart:collection' show Queue; |
8 | 8 |
9 import 'cache_strategy.dart'; | 9 import 'cache_strategy.dart'; |
10 import 'common/backend_api.dart' show Backend; | 10 import 'common/backend_api.dart' show Backend; |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
47 | 47 |
48 String get name => 'Enqueue'; | 48 String get name => 'Enqueue'; |
49 | 49 |
50 EnqueueTask(Compiler compiler) | 50 EnqueueTask(Compiler compiler) |
51 : this.compiler = compiler, | 51 : this.compiler = compiler, |
52 super(compiler.measurer) { | 52 super(compiler.measurer) { |
53 _resolution = new ResolutionEnqueuer( | 53 _resolution = new ResolutionEnqueuer( |
54 this, | 54 this, |
55 compiler.options, | 55 compiler.options, |
56 compiler.resolution, | 56 compiler.resolution, |
57 compiler.enqueuerFilter, | |
58 compiler.options.analyzeOnly && compiler.options.analyzeMain | 57 compiler.options.analyzeOnly && compiler.options.analyzeMain |
59 ? const EnqueuerStrategy() | 58 ? const DirectEnqueuerStrategy() |
60 : const TreeShakingEnqueuerStrategy(), | 59 : const TreeShakingEnqueuerStrategy(), |
61 compiler.globalDependencies, | 60 compiler.globalDependencies, |
62 compiler.backend, | 61 compiler.backend, |
63 compiler.coreClasses, | 62 compiler.coreClasses, |
64 compiler.cacheStrategy); | 63 compiler.cacheStrategy); |
65 _codegen = compiler.backend.createCodegenEnqueuer(this, compiler); | 64 _codegen = compiler.backend.createCodegenEnqueuer(this, compiler); |
66 } | 65 } |
67 | 66 |
68 ResolutionEnqueuer get resolution => _resolution; | 67 ResolutionEnqueuer get resolution => _resolution; |
69 Enqueuer get codegen => _codegen; | 68 Enqueuer get codegen => _codegen; |
70 | 69 |
71 void forgetElement(Element element) { | 70 void forgetElement(Element element) { |
72 resolution.forgetElement(element, compiler); | 71 resolution.forgetElement(element, compiler); |
73 codegen.forgetElement(element, compiler); | 72 codegen.forgetElement(element, compiler); |
74 } | 73 } |
75 } | 74 } |
76 | 75 |
77 abstract class Enqueuer { | 76 abstract class Enqueuer { |
78 CompilerTask get task; | |
79 WorldBuilder get universe; | 77 WorldBuilder get universe; |
80 native.NativeEnqueuer get nativeEnqueuer; | 78 native.NativeEnqueuer get nativeEnqueuer; |
81 void forgetElement(Element element, Compiler compiler); | 79 void forgetElement(Element element, Compiler compiler); |
82 void processInstantiatedClassMembers(ClassElement cls); | 80 |
83 void processInstantiatedClassMember(ClassElement cls, Element member); | 81 // TODO(johnniwinther): Initialize [_impactStrategy] to `null`. |
84 void handleUnseenSelectorInternal(DynamicUse dynamicUse); | 82 ImpactStrategy _impactStrategy = const ImpactStrategy(); |
85 void registerStaticUse(StaticUse staticUse); | 83 |
86 void registerStaticUseInternal(StaticUse staticUse); | 84 ImpactStrategy get impactStrategy => _impactStrategy; |
87 void registerDynamicUse(DynamicUse dynamicUse); | 85 |
| 86 void open(ImpactStrategy impactStrategy) { |
| 87 _impactStrategy = impactStrategy; |
| 88 } |
| 89 |
| 90 void close() { |
| 91 // TODO(johnniwinther): Set [_impactStrategy] to `null` and [queueIsClosed] |
| 92 // to `false` here. |
| 93 _impactStrategy = const ImpactStrategy(); |
| 94 } |
88 | 95 |
89 /// Returns [:true:] if this enqueuer is the resolution enqueuer. | 96 /// Returns [:true:] if this enqueuer is the resolution enqueuer. |
90 bool get isResolutionQueue; | 97 bool get isResolutionQueue; |
91 | 98 |
92 bool queueIsClosed; | 99 bool queueIsClosed; |
93 | 100 |
94 bool get queueIsEmpty; | 101 bool get queueIsEmpty; |
95 | 102 |
96 ImpactUseCase get impactUse; | 103 ImpactUseCase get impactUse; |
97 | 104 |
98 /** | |
99 * Documentation wanted -- johnniwinther | |
100 * | |
101 * Invariant: [element] must be a declaration element. | |
102 */ | |
103 void addToWorkList(Element element); | |
104 | |
105 void enableIsolateSupport(); | |
106 | |
107 void registerInstantiatedType(InterfaceType type); | |
108 void forEach(void f(WorkItem work)); | 105 void forEach(void f(WorkItem work)); |
109 | 106 |
110 /// Apply the [worldImpact] to this enqueuer. If the [impactSource] is provide
d | 107 /// Apply the [worldImpact] to this enqueuer. If the [impactSource] is |
111 /// the impact strategy will remove it from the element impact cache, if it is | 108 /// provided the impact strategy will remove it from the element impact cache, |
112 /// no longer needed. | 109 /// if it is no longer needed. |
113 void applyImpact(ImpactStrategy impactStrategy, WorldImpact worldImpact, | 110 void applyImpact(WorldImpact worldImpact, {Element impactSource}); |
114 {Element impactSource}); | |
115 bool checkNoEnqueuedInvokedInstanceMethods(); | 111 bool checkNoEnqueuedInvokedInstanceMethods(); |
116 void logSummary(log(message)); | 112 void logSummary(log(message)); |
117 | 113 |
118 /// Returns [:true:] if [member] has been processed by this enqueuer. | 114 /// Returns [:true:] if [member] has been processed by this enqueuer. |
119 bool isProcessed(Element member); | 115 bool isProcessed(Element member); |
120 | 116 |
121 Iterable<Entity> get processedEntities; | 117 Iterable<Entity> get processedEntities; |
122 | 118 |
123 Iterable<ClassElement> get processedClasses; | 119 Iterable<ClassElement> get processedClasses; |
124 } | 120 } |
125 | 121 |
| 122 abstract class EnqueuerImpl extends Enqueuer { |
| 123 CompilerTask get task; |
| 124 void processInstantiatedClassMembers(ClassElement cls); |
| 125 void processInstantiatedClassMember(ClassElement cls, Element member); |
| 126 void registerStaticUse(StaticUse staticUse); |
| 127 void registerStaticUseInternal(StaticUse staticUse); |
| 128 void registerTypeUse(TypeUse typeUse); |
| 129 void registerTypeUseInternal(TypeUse typeUse); |
| 130 void registerDynamicUse(DynamicUse dynamicUse); |
| 131 void handleUnseenSelectorInternal(DynamicUse dynamicUse); |
| 132 } |
| 133 |
126 /// [Enqueuer] which is specific to resolution. | 134 /// [Enqueuer] which is specific to resolution. |
127 class ResolutionEnqueuer extends Enqueuer { | 135 class ResolutionEnqueuer extends EnqueuerImpl { |
128 final CompilerTask task; | 136 final CompilerTask task; |
129 final String name; | 137 final String name; |
130 final Resolution resolution; | 138 final Resolution resolution; |
131 final QueueFilter filter; | |
132 final CompilerOptions options; | 139 final CompilerOptions options; |
133 final Backend backend; | 140 final Backend backend; |
134 final GlobalDependencyRegistry globalDependencies; | 141 final GlobalDependencyRegistry globalDependencies; |
135 final CommonElements commonElements; | 142 final CommonElements commonElements; |
136 final native.NativeEnqueuer nativeEnqueuer; | 143 final native.NativeEnqueuer nativeEnqueuer; |
137 | 144 |
138 final EnqueuerStrategy strategy; | 145 final EnqueuerStrategy strategy; |
139 final Map<String, Set<Element>> instanceMembersByName = | 146 final Map<String, Set<Element>> instanceMembersByName = |
140 new Map<String, Set<Element>>(); | 147 new Map<String, Set<Element>>(); |
141 final Map<String, Set<Element>> instanceFunctionsByName = | 148 final Map<String, Set<Element>> instanceFunctionsByName = |
142 new Map<String, Set<Element>>(); | 149 new Map<String, Set<Element>>(); |
143 final Set<ClassElement> _processedClasses = new Set<ClassElement>(); | 150 final Set<ClassElement> _processedClasses = new Set<ClassElement>(); |
144 Set<ClassElement> recentClasses = new Setlet<ClassElement>(); | 151 Set<ClassElement> recentClasses = new Setlet<ClassElement>(); |
145 final ResolutionWorldBuilderImpl _universe; | 152 final ResolutionWorldBuilderImpl _universe; |
146 | 153 |
147 bool queueIsClosed = false; | 154 bool queueIsClosed = false; |
148 | 155 |
149 WorldImpactVisitor impactVisitor; | 156 WorldImpactVisitor impactVisitor; |
150 | 157 |
151 ImpactStrategy impactStrategy; | |
152 | |
153 ResolutionEnqueuer( | 158 ResolutionEnqueuer( |
154 this.task, | 159 this.task, |
155 this.options, | 160 this.options, |
156 this.resolution, | 161 this.resolution, |
157 this.filter, | |
158 this.strategy, | 162 this.strategy, |
159 this.globalDependencies, | 163 this.globalDependencies, |
160 Backend backend, | 164 Backend backend, |
161 CommonElements commonElements, | 165 CommonElements commonElements, |
162 CacheStrategy cacheStrategy, | 166 CacheStrategy cacheStrategy, |
163 [this.name = 'resolution enqueuer']) | 167 [this.name = 'resolution enqueuer']) |
164 : this.backend = backend, | 168 : this.backend = backend, |
165 this.commonElements = commonElements, | 169 this.commonElements = commonElements, |
166 this.nativeEnqueuer = backend.nativeResolutionEnqueuer(), | 170 this.nativeEnqueuer = backend.nativeResolutionEnqueuer(), |
167 processedElements = new Set<AstElement>(), | 171 processedElements = new Set<AstElement>(), |
168 queue = new Queue<ResolutionWorkItem>(), | 172 queue = new Queue<ResolutionWorkItem>(), |
169 deferredQueue = new Queue<_DeferredAction>(), | 173 deferredQueue = new Queue<_DeferredAction>(), |
170 _universe = new ResolutionWorldBuilderImpl( | 174 _universe = new ResolutionWorldBuilderImpl( |
171 backend, commonElements, cacheStrategy, const TypeMaskStrategy()) { | 175 backend, commonElements, cacheStrategy, const TypeMaskStrategy()) { |
172 impactVisitor = new _EnqueuerImpactVisitor(this); | 176 impactVisitor = new EnqueuerImplImpactVisitor(this); |
173 } | 177 } |
174 | 178 |
175 ResolutionWorldBuilder get universe => _universe; | 179 ResolutionWorldBuilder get universe => _universe; |
176 | 180 |
177 OpenWorld get openWorld => universe.openWorld; | 181 OpenWorld get openWorld => universe.openWorld; |
178 | 182 |
179 bool get queueIsEmpty => queue.isEmpty; | 183 bool get queueIsEmpty => queue.isEmpty; |
180 | 184 |
181 DiagnosticReporter get reporter => resolution.reporter; | 185 DiagnosticReporter get reporter => resolution.reporter; |
182 | 186 |
183 bool isClassProcessed(ClassElement cls) => _processedClasses.contains(cls); | 187 bool isClassProcessed(ClassElement cls) => _processedClasses.contains(cls); |
184 | 188 |
185 Iterable<ClassElement> get processedClasses => _processedClasses; | 189 Iterable<ClassElement> get processedClasses => _processedClasses; |
186 | 190 |
187 /** | 191 /** |
188 * Documentation wanted -- johnniwinther | 192 * Documentation wanted -- johnniwinther |
189 * | 193 * |
190 * Invariant: [element] must be a declaration element. | 194 * Invariant: [element] must be a declaration element. |
191 */ | 195 */ |
192 void addToWorkList(Element element) { | 196 void addToWorkList(Element element) { |
193 assert(invariant(element, element.isDeclaration)); | 197 assert(invariant(element, element.isDeclaration)); |
194 internalAddToWorkList(element); | 198 internalAddToWorkList(element); |
195 } | 199 } |
196 | 200 |
197 void applyImpact(ImpactStrategy impactStrategy, WorldImpact worldImpact, | 201 void applyImpact(WorldImpact worldImpact, {Element impactSource}) { |
198 {Element impactSource}) { | 202 if (worldImpact.isEmpty) return; |
199 impactStrategy.visitImpact( | 203 impactStrategy.visitImpact( |
200 impactSource, worldImpact, impactVisitor, impactUse); | 204 impactSource, worldImpact, impactVisitor, impactUse); |
201 } | 205 } |
202 | 206 |
203 void registerInstantiatedType(InterfaceType type) { | 207 void registerInstantiatedType(InterfaceType type) { |
204 _registerInstantiatedType(type, globalDependency: true); | 208 _registerInstantiatedType(type, globalDependency: true); |
205 } | 209 } |
206 | 210 |
207 void _registerInstantiatedType(InterfaceType type, | 211 void _registerInstantiatedType(InterfaceType type, |
208 {ConstructorElement constructor, | 212 {ConstructorElement constructor, |
209 bool mirrorUsage: false, | 213 bool mirrorUsage: false, |
210 bool nativeUsage: false, | 214 bool nativeUsage: false, |
211 bool globalDependency: false, | 215 bool globalDependency: false, |
212 bool isRedirection: false}) { | 216 bool isRedirection: false}) { |
213 task.measure(() { | 217 task.measure(() { |
214 ClassElement cls = type.element; | 218 ClassElement cls = type.element; |
215 cls.ensureResolved(resolution); | 219 cls.ensureResolved(resolution); |
216 bool isNative = backend.isNative(cls); | 220 bool isNative = backend.isNative(cls); |
217 _universe.registerTypeInstantiation(type, | 221 _universe.registerTypeInstantiation(type, |
218 constructor: constructor, | 222 constructor: constructor, |
219 isNative: isNative, | 223 isNative: isNative, |
220 byMirrors: mirrorUsage, | 224 byMirrors: mirrorUsage, |
221 isRedirection: isRedirection, onImplemented: (ClassElement cls) { | 225 isRedirection: isRedirection, onImplemented: (ClassElement cls) { |
222 backend.registerImplementedClass(cls, this); | 226 applyImpact(backend.registerImplementedClass(cls, forResolution: true)); |
223 }); | 227 }); |
224 if (globalDependency && !mirrorUsage) { | 228 if (globalDependency && !mirrorUsage) { |
225 globalDependencies.registerDependency(type.element); | 229 globalDependencies.registerDependency(type.element); |
226 } | 230 } |
227 if (nativeUsage) { | 231 if (nativeUsage) { |
228 nativeEnqueuer.onInstantiatedType(type); | 232 nativeEnqueuer.onInstantiatedType(type); |
229 } | 233 } |
230 backend.registerInstantiatedType(type); | 234 backend.registerInstantiatedType(type); |
231 // TODO(johnniwinther): Share this reasoning with [Universe]. | 235 // TODO(johnniwinther): Share this reasoning with [Universe]. |
232 if (!cls.isAbstract || isNative || mirrorUsage) { | 236 if (!cls.isAbstract || isNative || mirrorUsage) { |
233 processInstantiatedClass(cls); | 237 processInstantiatedClass(cls); |
234 } | 238 } |
235 }); | 239 }); |
236 } | 240 } |
237 | 241 |
238 bool checkNoEnqueuedInvokedInstanceMethods() { | 242 bool checkNoEnqueuedInvokedInstanceMethods() { |
239 return filter.checkNoEnqueuedInvokedInstanceMethods(this); | 243 return strategy.checkEnqueuerConsistency(this); |
240 } | 244 } |
241 | 245 |
242 void processInstantiatedClassMembers(ClassElement cls) { | 246 void processInstantiatedClassMembers(ClassElement cls) { |
243 strategy.processInstantiatedClass(this, cls); | 247 strategy.processInstantiatedClass(this, cls); |
244 } | 248 } |
245 | 249 |
246 void processInstantiatedClassMember(ClassElement cls, Element member) { | 250 void processInstantiatedClassMember(ClassElement cls, Element member) { |
247 assert(invariant(member, member.isDeclaration)); | 251 assert(invariant(member, member.isDeclaration)); |
248 if (isProcessed(member)) return; | 252 if (isProcessed(member)) return; |
249 if (!member.isInstanceMember) return; | 253 if (!member.isInstanceMember) return; |
(...skipping 27 matching lines...) Expand all Loading... |
277 addToWorkList(member); | 281 addToWorkList(member); |
278 return; | 282 return; |
279 } | 283 } |
280 } else if (member.isFunction) { | 284 } else if (member.isFunction) { |
281 FunctionElement function = member; | 285 FunctionElement function = member; |
282 function.computeType(resolution); | 286 function.computeType(resolution); |
283 if (function.name == Identifiers.noSuchMethod_) { | 287 if (function.name == Identifiers.noSuchMethod_) { |
284 registerNoSuchMethod(function); | 288 registerNoSuchMethod(function); |
285 } | 289 } |
286 if (function.name == Identifiers.call && !cls.typeVariables.isEmpty) { | 290 if (function.name == Identifiers.call && !cls.typeVariables.isEmpty) { |
287 registerCallMethodWithFreeTypeVariables(function); | 291 _registerCallMethodWithFreeTypeVariables(function); |
288 } | 292 } |
289 // If there is a property access with the same name as a method we | 293 // If there is a property access with the same name as a method we |
290 // need to emit the method. | 294 // need to emit the method. |
291 if (_universe.hasInvokedGetter(function, openWorld)) { | 295 if (_universe.hasInvokedGetter(function, openWorld)) { |
292 registerClosurizedMember(function); | 296 registerClosurizedMember(function); |
293 addToWorkList(function); | 297 addToWorkList(function); |
294 return; | 298 return; |
295 } | 299 } |
296 // Store the member in [instanceFunctionsByName] to catch | 300 // Store the member in [instanceFunctionsByName] to catch |
297 // getters on the function. | 301 // getters on the function. |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
342 if (_processedClasses.contains(superclass)) return; | 346 if (_processedClasses.contains(superclass)) return; |
343 | 347 |
344 _processedClasses.add(superclass); | 348 _processedClasses.add(superclass); |
345 recentClasses.add(superclass); | 349 recentClasses.add(superclass); |
346 superclass.ensureResolved(resolution); | 350 superclass.ensureResolved(resolution); |
347 superclass.implementation.forEachMember(processInstantiatedClassMember); | 351 superclass.implementation.forEachMember(processInstantiatedClassMember); |
348 resolution.ensureClassMembers(superclass); | 352 resolution.ensureClassMembers(superclass); |
349 // We only tell the backend once that [superclass] was instantiated, so | 353 // We only tell the backend once that [superclass] was instantiated, so |
350 // any additional dependencies must be treated as global | 354 // any additional dependencies must be treated as global |
351 // dependencies. | 355 // dependencies. |
352 backend.registerInstantiatedClass(superclass, this); | 356 applyImpact( |
| 357 backend.registerInstantiatedClass(superclass, forResolution: true)); |
353 } | 358 } |
354 | 359 |
355 ClassElement superclass = cls; | 360 ClassElement superclass = cls; |
356 while (superclass != null) { | 361 while (superclass != null) { |
357 processClass(superclass); | 362 processClass(superclass); |
358 superclass = superclass.superclass; | 363 superclass = superclass.superclass; |
359 } | 364 } |
360 }); | 365 }); |
361 } | 366 } |
362 | 367 |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
426 */ | 431 */ |
427 void registerStaticUse(StaticUse staticUse) { | 432 void registerStaticUse(StaticUse staticUse) { |
428 strategy.processStaticUse(this, staticUse); | 433 strategy.processStaticUse(this, staticUse); |
429 } | 434 } |
430 | 435 |
431 void registerStaticUseInternal(StaticUse staticUse) { | 436 void registerStaticUseInternal(StaticUse staticUse) { |
432 Element element = staticUse.element; | 437 Element element = staticUse.element; |
433 assert(invariant(element, element.isDeclaration, | 438 assert(invariant(element, element.isDeclaration, |
434 message: "Element ${element} is not the declaration.")); | 439 message: "Element ${element} is not the declaration.")); |
435 _universe.registerStaticUse(staticUse); | 440 _universe.registerStaticUse(staticUse); |
436 backend.registerStaticUse(this, element); | 441 applyImpact(backend.registerStaticUse(element, forResolution: true)); |
437 bool addElement = true; | 442 bool addElement = true; |
438 switch (staticUse.kind) { | 443 switch (staticUse.kind) { |
439 case StaticUseKind.STATIC_TEAR_OFF: | 444 case StaticUseKind.STATIC_TEAR_OFF: |
440 backend.registerGetOfStaticFunction(this); | 445 applyImpact(backend.registerGetOfStaticFunction()); |
441 break; | 446 break; |
442 case StaticUseKind.FIELD_GET: | 447 case StaticUseKind.FIELD_GET: |
443 case StaticUseKind.FIELD_SET: | 448 case StaticUseKind.FIELD_SET: |
444 case StaticUseKind.CLOSURE: | 449 case StaticUseKind.CLOSURE: |
445 // TODO(johnniwinther): Avoid this. Currently [FIELD_GET] and | 450 // TODO(johnniwinther): Avoid this. Currently [FIELD_GET] and |
446 // [FIELD_SET] contains [BoxFieldElement]s which we cannot enqueue. | 451 // [FIELD_SET] contains [BoxFieldElement]s which we cannot enqueue. |
447 // Also [CLOSURE] contains [LocalFunctionElement] which we cannot | 452 // Also [CLOSURE] contains [LocalFunctionElement] which we cannot |
448 // enqueue. | 453 // enqueue. |
449 LocalFunctionElement closure = staticUse.element; | 454 LocalFunctionElement closure = staticUse.element; |
450 if (closure.type.containsTypeVariables) { | 455 if (closure.type.containsTypeVariables) { |
451 universe.closuresWithFreeTypeVariables.add(closure); | 456 universe.closuresWithFreeTypeVariables.add(closure); |
452 } | 457 } |
453 addElement = false; | 458 addElement = false; |
454 break; | 459 break; |
455 case StaticUseKind.SUPER_FIELD_SET: | 460 case StaticUseKind.SUPER_FIELD_SET: |
456 case StaticUseKind.SUPER_TEAR_OFF: | 461 case StaticUseKind.SUPER_TEAR_OFF: |
457 case StaticUseKind.GENERAL: | 462 case StaticUseKind.GENERAL: |
| 463 case StaticUseKind.DIRECT_USE: |
458 break; | 464 break; |
459 case StaticUseKind.CONSTRUCTOR_INVOKE: | 465 case StaticUseKind.CONSTRUCTOR_INVOKE: |
460 case StaticUseKind.CONST_CONSTRUCTOR_INVOKE: | 466 case StaticUseKind.CONST_CONSTRUCTOR_INVOKE: |
461 _registerInstantiatedType(staticUse.type, | 467 _registerInstantiatedType(staticUse.type, |
462 constructor: staticUse.element, globalDependency: false); | 468 constructor: staticUse.element, globalDependency: false); |
463 break; | 469 break; |
464 case StaticUseKind.REDIRECTION: | 470 case StaticUseKind.REDIRECTION: |
465 _registerInstantiatedType(staticUse.type, | 471 _registerInstantiatedType(staticUse.type, |
466 constructor: staticUse.element, | 472 constructor: staticUse.element, |
467 globalDependency: false, | 473 globalDependency: false, |
468 isRedirection: true); | 474 isRedirection: true); |
469 break; | 475 break; |
470 case StaticUseKind.DIRECT_INVOKE: | 476 case StaticUseKind.DIRECT_INVOKE: |
471 invariant( | 477 invariant( |
472 element, 'Direct static use is not supported for resolution.'); | 478 element, 'Direct static use is not supported for resolution.'); |
473 break; | 479 break; |
474 } | 480 } |
475 if (addElement) { | 481 if (addElement) { |
476 addToWorkList(element); | 482 addToWorkList(element); |
477 } | 483 } |
478 } | 484 } |
479 | 485 |
480 void _registerTypeUse(TypeUse typeUse) { | 486 void registerTypeUse(TypeUse typeUse) { |
| 487 strategy.processTypeUse(this, typeUse); |
| 488 } |
| 489 |
| 490 void registerTypeUseInternal(TypeUse typeUse) { |
481 DartType type = typeUse.type; | 491 DartType type = typeUse.type; |
482 switch (typeUse.kind) { | 492 switch (typeUse.kind) { |
483 case TypeUseKind.INSTANTIATION: | 493 case TypeUseKind.INSTANTIATION: |
484 _registerInstantiatedType(type, globalDependency: false); | 494 _registerInstantiatedType(type, globalDependency: false); |
485 break; | 495 break; |
486 case TypeUseKind.MIRROR_INSTANTIATION: | 496 case TypeUseKind.MIRROR_INSTANTIATION: |
487 _registerInstantiatedType(type, | 497 _registerInstantiatedType(type, |
488 mirrorUsage: true, globalDependency: false); | 498 mirrorUsage: true, globalDependency: false); |
489 break; | 499 break; |
490 case TypeUseKind.NATIVE_INSTANTIATION: | 500 case TypeUseKind.NATIVE_INSTANTIATION: |
(...skipping 16 matching lines...) Expand all Loading... |
507 } | 517 } |
508 | 518 |
509 void _registerIsCheck(DartType type) { | 519 void _registerIsCheck(DartType type) { |
510 type = _universe.registerIsCheck(type, resolution); | 520 type = _universe.registerIsCheck(type, resolution); |
511 // Even in checked mode, type annotations for return type and argument | 521 // Even in checked mode, type annotations for return type and argument |
512 // types do not imply type checks, so there should never be a check | 522 // types do not imply type checks, so there should never be a check |
513 // against the type variable of a typedef. | 523 // against the type variable of a typedef. |
514 assert(!type.isTypeVariable || !type.element.enclosingElement.isTypedef); | 524 assert(!type.isTypeVariable || !type.element.enclosingElement.isTypedef); |
515 } | 525 } |
516 | 526 |
517 void registerCallMethodWithFreeTypeVariables(Element element) { | 527 void _registerCallMethodWithFreeTypeVariables(Element element) { |
518 backend.registerCallMethodWithFreeTypeVariables(element, this); | 528 applyImpact(backend.registerCallMethodWithFreeTypeVariables(element, |
| 529 forResolution: true)); |
519 _universe.callMethodsWithFreeTypeVariables.add(element); | 530 _universe.callMethodsWithFreeTypeVariables.add(element); |
520 } | 531 } |
521 | 532 |
522 void registerClosurizedMember(TypedElement element) { | 533 void registerClosurizedMember(TypedElement element) { |
523 assert(element.isInstanceMember); | 534 assert(element.isInstanceMember); |
524 if (element.computeType(resolution).containsTypeVariables) { | 535 if (element.computeType(resolution).containsTypeVariables) { |
525 backend.registerClosureWithFreeTypeVariables(element, this); | 536 applyImpact(backend.registerClosureWithFreeTypeVariables(element, |
| 537 forResolution: true)); |
526 _universe.closuresWithFreeTypeVariables.add(element); | 538 _universe.closuresWithFreeTypeVariables.add(element); |
527 } | 539 } |
528 backend.registerBoundClosure(this); | 540 applyImpact(backend.registerBoundClosure()); |
529 _universe.closurizedMembers.add(element); | 541 _universe.closurizedMembers.add(element); |
530 } | 542 } |
531 | 543 |
532 void forEach(void f(WorkItem work)) { | 544 void forEach(void f(WorkItem work)) { |
533 do { | 545 do { |
534 while (queue.isNotEmpty) { | 546 while (queue.isNotEmpty) { |
535 // TODO(johnniwinther): Find an optimal process order. | 547 // TODO(johnniwinther): Find an optimal process order. |
536 filter.processWorkItem(f, queue.removeLast()); | 548 WorkItem work = queue.removeLast(); |
| 549 if (!isProcessed(work.element)) { |
| 550 strategy.processWorkItem(f, work); |
| 551 registerProcessedElement(work.element); |
| 552 } |
537 } | 553 } |
538 List recents = recentClasses.toList(growable: false); | 554 List recents = recentClasses.toList(growable: false); |
539 recentClasses.clear(); | 555 recentClasses.clear(); |
540 if (!onQueueEmpty(recents)) recentClasses.addAll(recents); | 556 if (!onQueueEmpty(recents)) recentClasses.addAll(recents); |
541 } while (queue.isNotEmpty || recentClasses.isNotEmpty); | 557 } while (queue.isNotEmpty || recentClasses.isNotEmpty); |
542 } | 558 } |
543 | 559 |
544 void logSummary(log(message)) { | 560 void logSummary(log(message)) { |
545 log('Resolved ${processedElements.length} elements.'); | 561 log('Resolved ${processedElements.length} elements.'); |
546 nativeEnqueuer.logSummary(log); | 562 nativeEnqueuer.logSummary(log); |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
618 } | 634 } |
619 } | 635 } |
620 | 636 |
621 if (element.isGetter && element.name == Identifiers.runtimeType_) { | 637 if (element.isGetter && element.name == Identifiers.runtimeType_) { |
622 // Enable runtime type support if we discover a getter called runtimeType. | 638 // Enable runtime type support if we discover a getter called runtimeType. |
623 // We have to enable runtime type before hitting the codegen, so | 639 // We have to enable runtime type before hitting the codegen, so |
624 // that constructors know whether they need to generate code for | 640 // that constructors know whether they need to generate code for |
625 // runtime type. | 641 // runtime type. |
626 _universe.hasRuntimeTypeSupport = true; | 642 _universe.hasRuntimeTypeSupport = true; |
627 // TODO(ahe): Record precise dependency here. | 643 // TODO(ahe): Record precise dependency here. |
628 backend.registerRuntimeType(this); | 644 applyImpact(backend.registerRuntimeType()); |
629 } else if (commonElements.isFunctionApplyMethod(element)) { | 645 } else if (commonElements.isFunctionApplyMethod(element)) { |
630 _universe.hasFunctionApplySupport = true; | 646 _universe.hasFunctionApplySupport = true; |
631 } | 647 } |
632 | 648 |
633 return true; | 649 return true; |
634 } | 650 } |
635 | 651 |
636 void registerNoSuchMethod(Element element) { | 652 void registerNoSuchMethod(Element element) { |
637 backend.registerNoSuchMethod(element); | 653 backend.registerNoSuchMethod(element); |
638 } | 654 } |
639 | 655 |
640 void enableIsolateSupport() { | 656 void enableIsolateSupport() { |
641 _universe.hasIsolateSupport = true; | 657 _universe.hasIsolateSupport = true; |
642 backend.enableIsolateSupport(this); | 658 applyImpact(backend.enableIsolateSupport(forResolution: true)); |
643 } | 659 } |
644 | 660 |
645 /** | 661 /** |
646 * Adds an action to the deferred task queue. | 662 * Adds an action to the deferred task queue. |
647 * | 663 * |
648 * The action is performed the next time the resolution queue has been | 664 * The action is performed the next time the resolution queue has been |
649 * emptied. | 665 * emptied. |
650 * | 666 * |
651 * The queue is processed in FIFO order. | 667 * The queue is processed in FIFO order. |
652 */ | 668 */ |
(...skipping 30 matching lines...) Expand all Loading... |
683 | 699 |
684 void forgetElement(Element element, Compiler compiler) { | 700 void forgetElement(Element element, Compiler compiler) { |
685 _universe.forgetElement(element, compiler); | 701 _universe.forgetElement(element, compiler); |
686 _processedClasses.remove(element); | 702 _processedClasses.remove(element); |
687 instanceMembersByName[element.name]?.remove(element); | 703 instanceMembersByName[element.name]?.remove(element); |
688 instanceFunctionsByName[element.name]?.remove(element); | 704 instanceFunctionsByName[element.name]?.remove(element); |
689 processedElements.remove(element); | 705 processedElements.remove(element); |
690 } | 706 } |
691 } | 707 } |
692 | 708 |
693 /// Parameterizes filtering of which work items are enqueued. | 709 void removeFromSet(Map<String, Set<Element>> map, Element element) { |
694 class QueueFilter { | 710 Set<Element> set = map[element.name]; |
695 bool checkNoEnqueuedInvokedInstanceMethods(Enqueuer enqueuer) { | 711 if (set == null) return; |
| 712 set.remove(element); |
| 713 } |
| 714 |
| 715 /// Strategy used by the enqueuer to populate the world. |
| 716 class EnqueuerStrategy { |
| 717 const EnqueuerStrategy(); |
| 718 |
| 719 /// Process a class instantiated in live code. |
| 720 void processInstantiatedClass(EnqueuerImpl enqueuer, ClassElement cls) {} |
| 721 |
| 722 /// Process a static use of and element in live code. |
| 723 void processStaticUse(EnqueuerImpl enqueuer, StaticUse staticUse) {} |
| 724 |
| 725 /// Process a type use in live code. |
| 726 void processTypeUse(EnqueuerImpl enqueuer, TypeUse typeUse) {} |
| 727 |
| 728 /// Process a dynamic use for a call site in live code. |
| 729 void processDynamicUse(EnqueuerImpl enqueuer, DynamicUse dynamicUse) {} |
| 730 |
| 731 /// Check enqueuer consistency after the queue has been closed. |
| 732 bool checkEnqueuerConsistency(EnqueuerImpl enqueuer) { |
696 enqueuer.task.measure(() { | 733 enqueuer.task.measure(() { |
697 // Run through the classes and see if we need to compile methods. | 734 // Run through the classes and see if we need to enqueue more methods. |
698 for (ClassElement classElement | 735 for (ClassElement classElement |
699 in enqueuer.universe.directlyInstantiatedClasses) { | 736 in enqueuer.universe.directlyInstantiatedClasses) { |
700 for (ClassElement currentClass = classElement; | 737 for (ClassElement currentClass = classElement; |
701 currentClass != null; | 738 currentClass != null; |
702 currentClass = currentClass.superclass) { | 739 currentClass = currentClass.superclass) { |
703 enqueuer.processInstantiatedClassMembers(currentClass); | 740 enqueuer.processInstantiatedClassMembers(currentClass); |
704 } | 741 } |
705 } | 742 } |
706 }); | 743 }); |
707 return true; | 744 return true; |
708 } | 745 } |
709 | 746 |
| 747 /// Process [work] using [f]. |
710 void processWorkItem(void f(WorkItem work), WorkItem work) { | 748 void processWorkItem(void f(WorkItem work), WorkItem work) { |
711 f(work); | 749 f(work); |
712 } | 750 } |
713 } | 751 } |
714 | 752 |
715 void removeFromSet(Map<String, Set<Element>> map, Element element) { | 753 /// Strategy that only enqueues directly used elements. |
716 Set<Element> set = map[element.name]; | 754 class DirectEnqueuerStrategy extends EnqueuerStrategy { |
717 if (set == null) return; | 755 const DirectEnqueuerStrategy(); |
718 set.remove(element); | 756 void processStaticUse(EnqueuerImpl enqueuer, StaticUse staticUse) { |
| 757 if (staticUse.kind == StaticUseKind.DIRECT_USE) { |
| 758 enqueuer.registerStaticUseInternal(staticUse); |
| 759 } |
| 760 } |
719 } | 761 } |
720 | 762 |
721 /// Strategy used by the enqueuer to populate the world. | 763 /// Strategy used for tree-shaking. |
722 // TODO(johnniwinther): Merge this interface with [QueueFilter]. | 764 class TreeShakingEnqueuerStrategy extends EnqueuerStrategy { |
723 class EnqueuerStrategy { | |
724 const EnqueuerStrategy(); | |
725 | |
726 /// Process a class instantiated in live code. | |
727 void processInstantiatedClass(Enqueuer enqueuer, ClassElement cls) {} | |
728 | |
729 /// Process a static use of and element in live code. | |
730 void processStaticUse(Enqueuer enqueuer, StaticUse staticUse) {} | |
731 | |
732 /// Process a dynamic use for a call site in live code. | |
733 void processDynamicUse(Enqueuer enqueuer, DynamicUse dynamicUse) {} | |
734 } | |
735 | |
736 class TreeShakingEnqueuerStrategy implements EnqueuerStrategy { | |
737 const TreeShakingEnqueuerStrategy(); | 765 const TreeShakingEnqueuerStrategy(); |
738 | 766 |
739 @override | 767 @override |
740 void processInstantiatedClass(Enqueuer enqueuer, ClassElement cls) { | 768 void processInstantiatedClass(EnqueuerImpl enqueuer, ClassElement cls) { |
741 cls.implementation.forEachMember(enqueuer.processInstantiatedClassMember); | 769 cls.implementation.forEachMember(enqueuer.processInstantiatedClassMember); |
742 } | 770 } |
743 | 771 |
744 @override | 772 @override |
745 void processStaticUse(Enqueuer enqueuer, StaticUse staticUse) { | 773 void processStaticUse(EnqueuerImpl enqueuer, StaticUse staticUse) { |
746 enqueuer.registerStaticUseInternal(staticUse); | 774 enqueuer.registerStaticUseInternal(staticUse); |
747 } | 775 } |
748 | 776 |
749 @override | 777 @override |
750 void processDynamicUse(Enqueuer enqueuer, DynamicUse dynamicUse) { | 778 void processTypeUse(EnqueuerImpl enqueuer, TypeUse typeUse) { |
| 779 enqueuer.registerTypeUseInternal(typeUse); |
| 780 } |
| 781 |
| 782 @override |
| 783 void processDynamicUse(EnqueuerImpl enqueuer, DynamicUse dynamicUse) { |
751 enqueuer.handleUnseenSelectorInternal(dynamicUse); | 784 enqueuer.handleUnseenSelectorInternal(dynamicUse); |
752 } | 785 } |
753 } | 786 } |
754 | 787 |
755 class _EnqueuerImpactVisitor implements WorldImpactVisitor { | 788 class EnqueuerImplImpactVisitor implements WorldImpactVisitor { |
756 final ResolutionEnqueuer enqueuer; | 789 final EnqueuerImpl enqueuer; |
757 | 790 |
758 _EnqueuerImpactVisitor(this.enqueuer); | 791 EnqueuerImplImpactVisitor(this.enqueuer); |
759 | 792 |
760 @override | 793 @override |
761 void visitDynamicUse(DynamicUse dynamicUse) { | 794 void visitDynamicUse(DynamicUse dynamicUse) { |
762 enqueuer.registerDynamicUse(dynamicUse); | 795 enqueuer.registerDynamicUse(dynamicUse); |
763 } | 796 } |
764 | 797 |
765 @override | 798 @override |
766 void visitStaticUse(StaticUse staticUse) { | 799 void visitStaticUse(StaticUse staticUse) { |
767 enqueuer.registerStaticUse(staticUse); | 800 enqueuer.registerStaticUse(staticUse); |
768 } | 801 } |
769 | 802 |
770 @override | 803 @override |
771 void visitTypeUse(TypeUse typeUse) { | 804 void visitTypeUse(TypeUse typeUse) { |
772 enqueuer._registerTypeUse(typeUse); | 805 enqueuer.registerTypeUse(typeUse); |
773 } | 806 } |
774 } | 807 } |
775 | 808 |
776 typedef void _DeferredActionFunction(); | 809 typedef void _DeferredActionFunction(); |
777 | 810 |
778 class _DeferredAction { | 811 class _DeferredAction { |
779 final Element element; | 812 final Element element; |
780 final _DeferredActionFunction action; | 813 final _DeferredActionFunction action; |
781 | 814 |
782 _DeferredAction(this.element, this.action); | 815 _DeferredAction(this.element, this.action); |
783 } | 816 } |
OLD | NEW |