| 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 |