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 'common/names.dart' show Identifiers; | 9 import 'common/names.dart' show Identifiers; |
10 import 'common/resolution.dart' show Resolution; | 10 import 'common/resolution.dart' show Resolution; |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 class ResolutionEnqueuer extends Enqueuer { | 124 class ResolutionEnqueuer extends Enqueuer { |
125 final String name; | 125 final String name; |
126 final Compiler compiler; // TODO(ahe): Remove this dependency. | 126 final Compiler compiler; // TODO(ahe): Remove this dependency. |
127 final EnqueuerStrategy strategy; | 127 final EnqueuerStrategy strategy; |
128 final Map<String, Set<Element>> instanceMembersByName = | 128 final Map<String, Set<Element>> instanceMembersByName = |
129 new Map<String, Set<Element>>(); | 129 new Map<String, Set<Element>>(); |
130 final Map<String, Set<Element>> instanceFunctionsByName = | 130 final Map<String, Set<Element>> instanceFunctionsByName = |
131 new Map<String, Set<Element>>(); | 131 new Map<String, Set<Element>>(); |
132 final Set<ClassElement> _processedClasses = new Set<ClassElement>(); | 132 final Set<ClassElement> _processedClasses = new Set<ClassElement>(); |
133 Set<ClassElement> recentClasses = new Setlet<ClassElement>(); | 133 Set<ClassElement> recentClasses = new Setlet<ClassElement>(); |
134 final Universe universe = new Universe(const TypeMaskStrategy()); | 134 final ResolutionUniverseImpl _universe = |
| 135 new ResolutionUniverseImpl(const TypeMaskStrategy()); |
135 | 136 |
136 static final TRACE_MIRROR_ENQUEUING = | 137 static final TRACE_MIRROR_ENQUEUING = |
137 const bool.fromEnvironment("TRACE_MIRROR_ENQUEUING"); | 138 const bool.fromEnvironment("TRACE_MIRROR_ENQUEUING"); |
138 | 139 |
139 bool queueIsClosed = false; | 140 bool queueIsClosed = false; |
140 | 141 |
141 bool hasEnqueuedReflectiveElements = false; | 142 bool hasEnqueuedReflectiveElements = false; |
142 bool hasEnqueuedReflectiveStaticFields = false; | 143 bool hasEnqueuedReflectiveStaticFields = false; |
143 | 144 |
144 WorldImpactVisitor impactVisitor; | 145 WorldImpactVisitor impactVisitor; |
145 | 146 |
146 ResolutionEnqueuer(Compiler compiler, this.strategy) | 147 ResolutionEnqueuer(Compiler compiler, this.strategy) |
147 : this.name = 'resolution enqueuer', | 148 : this.name = 'resolution enqueuer', |
148 this.compiler = compiler, | 149 this.compiler = compiler, |
149 processedElements = new Set<AstElement>(), | 150 processedElements = new Set<AstElement>(), |
150 queue = new Queue<ResolutionWorkItem>(), | 151 queue = new Queue<ResolutionWorkItem>(), |
151 deferredQueue = new Queue<_DeferredAction>() { | 152 deferredQueue = new Queue<_DeferredAction>() { |
152 impactVisitor = new _EnqueuerImpactVisitor(this); | 153 impactVisitor = new _EnqueuerImpactVisitor(this); |
153 } | 154 } |
154 | 155 |
155 // TODO(johnniwinther): Move this to [ResolutionEnqueuer]. | 156 // TODO(johnniwinther): Move this to [ResolutionEnqueuer]. |
156 Resolution get resolution => compiler.resolution; | 157 Resolution get resolution => compiler.resolution; |
157 | 158 |
| 159 ResolutionUniverse get universe => _universe; |
| 160 |
158 bool get queueIsEmpty => queue.isEmpty; | 161 bool get queueIsEmpty => queue.isEmpty; |
159 | 162 |
160 QueueFilter get filter => compiler.enqueuerFilter; | 163 QueueFilter get filter => compiler.enqueuerFilter; |
161 | 164 |
162 DiagnosticReporter get reporter => compiler.reporter; | 165 DiagnosticReporter get reporter => compiler.reporter; |
163 | 166 |
164 bool isClassProcessed(ClassElement cls) => _processedClasses.contains(cls); | 167 bool isClassProcessed(ClassElement cls) => _processedClasses.contains(cls); |
165 | 168 |
166 Iterable<ClassElement> get processedClasses => _processedClasses; | 169 Iterable<ClassElement> get processedClasses => _processedClasses; |
167 | 170 |
(...skipping 16 matching lines...) Expand all Loading... |
184 void applyImpact(Element element, WorldImpact worldImpact) { | 187 void applyImpact(Element element, WorldImpact worldImpact) { |
185 compiler.impactStrategy | 188 compiler.impactStrategy |
186 .visitImpact(element, worldImpact, impactVisitor, impactUse); | 189 .visitImpact(element, worldImpact, impactVisitor, impactUse); |
187 } | 190 } |
188 | 191 |
189 void registerInstantiatedType(InterfaceType type, {bool mirrorUsage: false}) { | 192 void registerInstantiatedType(InterfaceType type, {bool mirrorUsage: false}) { |
190 task.measure(() { | 193 task.measure(() { |
191 ClassElement cls = type.element; | 194 ClassElement cls = type.element; |
192 cls.ensureResolved(resolution); | 195 cls.ensureResolved(resolution); |
193 bool isNative = compiler.backend.isNative(cls); | 196 bool isNative = compiler.backend.isNative(cls); |
194 universe.registerTypeInstantiation(type, | 197 _universe.registerTypeInstantiation(type, |
195 isNative: isNative, | 198 isNative: isNative, |
196 byMirrors: mirrorUsage, onImplemented: (ClassElement cls) { | 199 byMirrors: mirrorUsage, onImplemented: (ClassElement cls) { |
197 compiler.backend | 200 compiler.backend |
198 .registerImplementedClass(cls, this, compiler.globalDependencies); | 201 .registerImplementedClass(cls, this, compiler.globalDependencies); |
199 }); | 202 }); |
200 // TODO(johnniwinther): Share this reasoning with [Universe]. | 203 // TODO(johnniwinther): Share this reasoning with [Universe]. |
201 if (!cls.isAbstract || isNative || mirrorUsage) { | 204 if (!cls.isAbstract || isNative || mirrorUsage) { |
202 processInstantiatedClass(cls); | 205 processInstantiatedClass(cls); |
203 } | 206 } |
204 }); | 207 }); |
(...skipping 16 matching lines...) Expand all Loading... |
221 if (member.isField) { | 224 if (member.isField) { |
222 // The obvious thing to test here would be "member.isNative", | 225 // The obvious thing to test here would be "member.isNative", |
223 // however, that only works after metadata has been parsed/analyzed, | 226 // however, that only works after metadata has been parsed/analyzed, |
224 // and that may not have happened yet. | 227 // and that may not have happened yet. |
225 // So instead we use the enclosing class, which we know have had | 228 // So instead we use the enclosing class, which we know have had |
226 // its metadata parsed and analyzed. | 229 // its metadata parsed and analyzed. |
227 // Note: this assumes that there are no non-native fields on native | 230 // Note: this assumes that there are no non-native fields on native |
228 // classes, which may not be the case when a native class is subclassed. | 231 // classes, which may not be the case when a native class is subclassed. |
229 if (compiler.backend.isNative(cls)) { | 232 if (compiler.backend.isNative(cls)) { |
230 compiler.openWorld.registerUsedElement(member); | 233 compiler.openWorld.registerUsedElement(member); |
231 if (universe.hasInvokedGetter(member, compiler.openWorld) || | 234 if (_universe.hasInvokedGetter(member, compiler.openWorld) || |
232 universe.hasInvocation(member, compiler.openWorld)) { | 235 _universe.hasInvocation(member, compiler.openWorld)) { |
233 addToWorkList(member); | 236 addToWorkList(member); |
234 return; | 237 return; |
235 } | 238 } |
236 if (universe.hasInvokedSetter(member, compiler.openWorld)) { | 239 if (_universe.hasInvokedSetter(member, compiler.openWorld)) { |
237 addToWorkList(member); | 240 addToWorkList(member); |
238 return; | 241 return; |
239 } | 242 } |
240 // Native fields need to go into instanceMembersByName as they | 243 // Native fields need to go into instanceMembersByName as they |
241 // are virtual instantiation points and escape points. | 244 // are virtual instantiation points and escape points. |
242 } else { | 245 } else { |
243 // All field initializers must be resolved as they could | 246 // All field initializers must be resolved as they could |
244 // have an observable side-effect (and cannot be tree-shaken | 247 // have an observable side-effect (and cannot be tree-shaken |
245 // away). | 248 // away). |
246 addToWorkList(member); | 249 addToWorkList(member); |
247 return; | 250 return; |
248 } | 251 } |
249 } else if (member.isFunction) { | 252 } else if (member.isFunction) { |
250 FunctionElement function = member; | 253 FunctionElement function = member; |
251 function.computeType(resolution); | 254 function.computeType(resolution); |
252 if (function.name == Identifiers.noSuchMethod_) { | 255 if (function.name == Identifiers.noSuchMethod_) { |
253 registerNoSuchMethod(function); | 256 registerNoSuchMethod(function); |
254 } | 257 } |
255 if (function.name == Identifiers.call && !cls.typeVariables.isEmpty) { | 258 if (function.name == Identifiers.call && !cls.typeVariables.isEmpty) { |
256 registerCallMethodWithFreeTypeVariables(function); | 259 registerCallMethodWithFreeTypeVariables(function); |
257 } | 260 } |
258 // If there is a property access with the same name as a method we | 261 // If there is a property access with the same name as a method we |
259 // need to emit the method. | 262 // need to emit the method. |
260 if (universe.hasInvokedGetter(function, compiler.openWorld)) { | 263 if (_universe.hasInvokedGetter(function, compiler.openWorld)) { |
261 registerClosurizedMember(function); | 264 registerClosurizedMember(function); |
262 addToWorkList(function); | 265 addToWorkList(function); |
263 return; | 266 return; |
264 } | 267 } |
265 // Store the member in [instanceFunctionsByName] to catch | 268 // Store the member in [instanceFunctionsByName] to catch |
266 // getters on the function. | 269 // getters on the function. |
267 instanceFunctionsByName | 270 instanceFunctionsByName |
268 .putIfAbsent(memberName, () => new Set<Element>()) | 271 .putIfAbsent(memberName, () => new Set<Element>()) |
269 .add(member); | 272 .add(member); |
270 if (universe.hasInvocation(function, compiler.openWorld)) { | 273 if (_universe.hasInvocation(function, compiler.openWorld)) { |
271 addToWorkList(function); | 274 addToWorkList(function); |
272 return; | 275 return; |
273 } | 276 } |
274 } else if (member.isGetter) { | 277 } else if (member.isGetter) { |
275 FunctionElement getter = member; | 278 FunctionElement getter = member; |
276 getter.computeType(resolution); | 279 getter.computeType(resolution); |
277 if (universe.hasInvokedGetter(getter, compiler.openWorld)) { | 280 if (_universe.hasInvokedGetter(getter, compiler.openWorld)) { |
278 addToWorkList(getter); | 281 addToWorkList(getter); |
279 return; | 282 return; |
280 } | 283 } |
281 // We don't know what selectors the returned closure accepts. If | 284 // We don't know what selectors the returned closure accepts. If |
282 // the set contains any selector we have to assume that it matches. | 285 // the set contains any selector we have to assume that it matches. |
283 if (universe.hasInvocation(getter, compiler.openWorld)) { | 286 if (_universe.hasInvocation(getter, compiler.openWorld)) { |
284 addToWorkList(getter); | 287 addToWorkList(getter); |
285 return; | 288 return; |
286 } | 289 } |
287 } else if (member.isSetter) { | 290 } else if (member.isSetter) { |
288 FunctionElement setter = member; | 291 FunctionElement setter = member; |
289 setter.computeType(resolution); | 292 setter.computeType(resolution); |
290 if (universe.hasInvokedSetter(setter, compiler.openWorld)) { | 293 if (_universe.hasInvokedSetter(setter, compiler.openWorld)) { |
291 addToWorkList(setter); | 294 addToWorkList(setter); |
292 return; | 295 return; |
293 } | 296 } |
294 } | 297 } |
295 | 298 |
296 // The element is not yet used. Add it to the list of instance | 299 // The element is not yet used. Add it to the list of instance |
297 // members to still be processed. | 300 // members to still be processed. |
298 instanceMembersByName | 301 instanceMembersByName |
299 .putIfAbsent(memberName, () => new Set<Element>()) | 302 .putIfAbsent(memberName, () => new Set<Element>()) |
300 .add(member); | 303 .add(member); |
(...skipping 26 matching lines...) Expand all Loading... |
327 ClassElement superclass = cls; | 330 ClassElement superclass = cls; |
328 while (superclass != null) { | 331 while (superclass != null) { |
329 processClass(superclass); | 332 processClass(superclass); |
330 superclass = superclass.superclass; | 333 superclass = superclass.superclass; |
331 } | 334 } |
332 }); | 335 }); |
333 } | 336 } |
334 | 337 |
335 void registerDynamicUse(DynamicUse dynamicUse) { | 338 void registerDynamicUse(DynamicUse dynamicUse) { |
336 task.measure(() { | 339 task.measure(() { |
337 if (universe.registerDynamicUse(dynamicUse)) { | 340 if (_universe.registerDynamicUse(dynamicUse)) { |
338 handleUnseenSelector(dynamicUse); | 341 handleUnseenSelector(dynamicUse); |
339 } | 342 } |
340 }); | 343 }); |
341 } | 344 } |
342 | 345 |
343 void logEnqueueReflectiveAction(action, [msg = ""]) { | 346 void logEnqueueReflectiveAction(action, [msg = ""]) { |
344 if (TRACE_MIRROR_ENQUEUING) { | 347 if (TRACE_MIRROR_ENQUEUING) { |
345 print("MIRROR_ENQUEUE (R): $action $msg"); | 348 print("MIRROR_ENQUEUE (R): $action $msg"); |
346 } | 349 } |
347 } | 350 } |
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
563 * Invariant: [element] must be a declaration element. | 566 * Invariant: [element] must be a declaration element. |
564 */ | 567 */ |
565 void registerStaticUse(StaticUse staticUse) { | 568 void registerStaticUse(StaticUse staticUse) { |
566 strategy.processStaticUse(this, staticUse); | 569 strategy.processStaticUse(this, staticUse); |
567 } | 570 } |
568 | 571 |
569 void registerStaticUseInternal(StaticUse staticUse) { | 572 void registerStaticUseInternal(StaticUse staticUse) { |
570 Element element = staticUse.element; | 573 Element element = staticUse.element; |
571 assert(invariant(element, element.isDeclaration, | 574 assert(invariant(element, element.isDeclaration, |
572 message: "Element ${element} is not the declaration.")); | 575 message: "Element ${element} is not the declaration.")); |
573 universe.registerStaticUse(staticUse); | 576 _universe.registerStaticUse(staticUse); |
574 compiler.backend.registerStaticUse(element, this); | 577 compiler.backend.registerStaticUse(element, this); |
575 bool addElement = true; | 578 bool addElement = true; |
576 switch (staticUse.kind) { | 579 switch (staticUse.kind) { |
577 case StaticUseKind.STATIC_TEAR_OFF: | 580 case StaticUseKind.STATIC_TEAR_OFF: |
578 compiler.backend.registerGetOfStaticFunction(this); | 581 compiler.backend.registerGetOfStaticFunction(this); |
579 break; | 582 break; |
580 case StaticUseKind.FIELD_GET: | 583 case StaticUseKind.FIELD_GET: |
581 case StaticUseKind.FIELD_SET: | 584 case StaticUseKind.FIELD_SET: |
582 case StaticUseKind.CLOSURE: | 585 case StaticUseKind.CLOSURE: |
583 // TODO(johnniwinther): Avoid this. Currently [FIELD_GET] and | 586 // TODO(johnniwinther): Avoid this. Currently [FIELD_GET] and |
(...skipping 28 matching lines...) Expand all Loading... |
612 if (compiler.options.enableTypeAssertions) { | 615 if (compiler.options.enableTypeAssertions) { |
613 _registerIsCheck(type); | 616 _registerIsCheck(type); |
614 } | 617 } |
615 break; | 618 break; |
616 case TypeUseKind.TYPE_LITERAL: | 619 case TypeUseKind.TYPE_LITERAL: |
617 break; | 620 break; |
618 } | 621 } |
619 } | 622 } |
620 | 623 |
621 void _registerIsCheck(DartType type) { | 624 void _registerIsCheck(DartType type) { |
622 type = universe.registerIsCheck(type, compiler); | 625 type = _universe.registerIsCheck(type, compiler); |
623 // Even in checked mode, type annotations for return type and argument | 626 // Even in checked mode, type annotations for return type and argument |
624 // types do not imply type checks, so there should never be a check | 627 // types do not imply type checks, so there should never be a check |
625 // against the type variable of a typedef. | 628 // against the type variable of a typedef. |
626 assert(!type.isTypeVariable || !type.element.enclosingElement.isTypedef); | 629 assert(!type.isTypeVariable || !type.element.enclosingElement.isTypedef); |
627 } | 630 } |
628 | 631 |
629 void registerCallMethodWithFreeTypeVariables(Element element) { | 632 void registerCallMethodWithFreeTypeVariables(Element element) { |
630 compiler.backend.registerCallMethodWithFreeTypeVariables( | 633 compiler.backend.registerCallMethodWithFreeTypeVariables( |
631 element, this, compiler.globalDependencies); | 634 element, this, compiler.globalDependencies); |
632 universe.callMethodsWithFreeTypeVariables.add(element); | 635 _universe.callMethodsWithFreeTypeVariables.add(element); |
633 } | 636 } |
634 | 637 |
635 void registerClosurizedMember(TypedElement element) { | 638 void registerClosurizedMember(TypedElement element) { |
636 assert(element.isInstanceMember); | 639 assert(element.isInstanceMember); |
637 if (element.computeType(resolution).containsTypeVariables) { | 640 if (element.computeType(resolution).containsTypeVariables) { |
638 compiler.backend.registerClosureWithFreeTypeVariables( | 641 compiler.backend.registerClosureWithFreeTypeVariables( |
639 element, this, compiler.globalDependencies); | 642 element, this, compiler.globalDependencies); |
| 643 _universe.closuresWithFreeTypeVariables.add(element); |
640 } | 644 } |
641 compiler.backend.registerBoundClosure(this); | 645 compiler.backend.registerBoundClosure(this); |
642 universe.closurizedMembers.add(element); | 646 _universe.closurizedMembers.add(element); |
643 } | 647 } |
644 | 648 |
645 void forEach(void f(WorkItem work)) { | 649 void forEach(void f(WorkItem work)) { |
646 do { | 650 do { |
647 while (queue.isNotEmpty) { | 651 while (queue.isNotEmpty) { |
648 // TODO(johnniwinther): Find an optimal process order. | 652 // TODO(johnniwinther): Find an optimal process order. |
649 filter.processWorkItem(f, queue.removeLast()); | 653 filter.processWorkItem(f, queue.removeLast()); |
650 } | 654 } |
651 List recents = recentClasses.toList(growable: false); | 655 List recents = recentClasses.toList(growable: false); |
652 recentClasses.clear(); | 656 recentClasses.clear(); |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
802 void emptyDeferredQueueForTesting() => _emptyDeferredQueue(); | 806 void emptyDeferredQueueForTesting() => _emptyDeferredQueue(); |
803 | 807 |
804 void _emptyDeferredQueue() { | 808 void _emptyDeferredQueue() { |
805 while (!deferredQueue.isEmpty) { | 809 while (!deferredQueue.isEmpty) { |
806 _DeferredAction task = deferredQueue.removeFirst(); | 810 _DeferredAction task = deferredQueue.removeFirst(); |
807 reporter.withCurrentElement(task.element, task.action); | 811 reporter.withCurrentElement(task.element, task.action); |
808 } | 812 } |
809 } | 813 } |
810 | 814 |
811 void forgetElement(Element element) { | 815 void forgetElement(Element element) { |
812 universe.forgetElement(element, compiler); | 816 _universe.forgetElement(element, compiler); |
813 _processedClasses.remove(element); | 817 _processedClasses.remove(element); |
814 instanceMembersByName[element.name]?.remove(element); | 818 instanceMembersByName[element.name]?.remove(element); |
815 instanceFunctionsByName[element.name]?.remove(element); | 819 instanceFunctionsByName[element.name]?.remove(element); |
816 processedElements.remove(element); | 820 processedElements.remove(element); |
817 } | 821 } |
818 } | 822 } |
819 | 823 |
820 /// Parameterizes filtering of which work items are enqueued. | 824 /// Parameterizes filtering of which work items are enqueued. |
821 class QueueFilter { | 825 class QueueFilter { |
822 bool checkNoEnqueuedInvokedInstanceMethods(Enqueuer enqueuer) { | 826 bool checkNoEnqueuedInvokedInstanceMethods(Enqueuer enqueuer) { |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
901 } | 905 } |
902 | 906 |
903 typedef void _DeferredActionFunction(); | 907 typedef void _DeferredActionFunction(); |
904 | 908 |
905 class _DeferredAction { | 909 class _DeferredAction { |
906 final Element element; | 910 final Element element; |
907 final _DeferredActionFunction action; | 911 final _DeferredActionFunction action; |
908 | 912 |
909 _DeferredAction(this.element, this.action); | 913 _DeferredAction(this.element, this.action); |
910 } | 914 } |
OLD | NEW |