| 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 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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, | 57 compiler.enqueuerFilter, |
| 58 compiler.options.analyzeOnly && compiler.options.analyzeMain | 58 compiler.options.analyzeOnly && compiler.options.analyzeMain |
| 59 ? const EnqueuerStrategy() | 59 ? const DirectEnqueuerStrategy() |
| 60 : const TreeShakingEnqueuerStrategy(), | 60 : const TreeShakingEnqueuerStrategy(), |
| 61 compiler.globalDependencies, | 61 compiler.globalDependencies, |
| 62 compiler.backend, | 62 compiler.backend, |
| 63 compiler.coreClasses, | 63 compiler.coreClasses, |
| 64 compiler.cacheStrategy); | 64 compiler.cacheStrategy); |
| 65 _codegen = compiler.backend.createCodegenEnqueuer(this, compiler); | 65 _codegen = compiler.backend.createCodegenEnqueuer(this, compiler); |
| 66 } | 66 } |
| 67 | 67 |
| 68 ResolutionEnqueuer get resolution => _resolution; | 68 ResolutionEnqueuer get resolution => _resolution; |
| 69 Enqueuer get codegen => _codegen; | 69 Enqueuer get codegen => _codegen; |
| 70 | 70 |
| 71 void forgetElement(Element element) { | 71 void forgetElement(Element element) { |
| 72 resolution.forgetElement(element, compiler); | 72 resolution.forgetElement(element, compiler); |
| 73 codegen.forgetElement(element, compiler); | 73 codegen.forgetElement(element, compiler); |
| 74 } | 74 } |
| 75 } | 75 } |
| 76 | 76 |
| 77 abstract class Enqueuer { | 77 abstract class Enqueuer { |
| 78 CompilerTask get task; | |
| 79 WorldBuilder get universe; | 78 WorldBuilder get universe; |
| 80 native.NativeEnqueuer get nativeEnqueuer; | 79 native.NativeEnqueuer get nativeEnqueuer; |
| 81 void forgetElement(Element element, Compiler compiler); | 80 void forgetElement(Element element, Compiler compiler); |
| 82 | 81 |
| 83 // TODO(johnniwinther): Initialize [_impactStrategy] to `null`. | 82 // TODO(johnniwinther): Initialize [_impactStrategy] to `null`. |
| 84 ImpactStrategy _impactStrategy = const ImpactStrategy(); | 83 ImpactStrategy _impactStrategy = const ImpactStrategy(); |
| 85 | 84 |
| 86 ImpactStrategy get impactStrategy => _impactStrategy; | 85 ImpactStrategy get impactStrategy => _impactStrategy; |
| 87 | 86 |
| 88 void open(ImpactStrategy impactStrategy) { | 87 void open(ImpactStrategy impactStrategy) { |
| 89 _impactStrategy = impactStrategy; | 88 _impactStrategy = impactStrategy; |
| 90 } | 89 } |
| 91 | 90 |
| 92 void close() { | 91 void close() { |
| 93 // TODO(johnniwinther): Set [_impactStrategy] to `null` and [queueIsClosed] | 92 // TODO(johnniwinther): Set [_impactStrategy] to `null` and [queueIsClosed] |
| 94 // to `false` here. | 93 // to `false` here. |
| 95 _impactStrategy = const ImpactStrategy(); | 94 _impactStrategy = const ImpactStrategy(); |
| 96 } | 95 } |
| 97 | 96 |
| 98 void processInstantiatedClassMembers(ClassElement cls); | |
| 99 void processInstantiatedClassMember(ClassElement cls, Element member); | |
| 100 void handleUnseenSelectorInternal(DynamicUse dynamicUse); | |
| 101 void registerStaticUse(StaticUse staticUse); | |
| 102 void registerStaticUseInternal(StaticUse staticUse); | |
| 103 void registerDynamicUse(DynamicUse dynamicUse); | |
| 104 | |
| 105 /// Returns [:true:] if this enqueuer is the resolution enqueuer. | 97 /// Returns [:true:] if this enqueuer is the resolution enqueuer. |
| 106 bool get isResolutionQueue; | 98 bool get isResolutionQueue; |
| 107 | 99 |
| 108 bool queueIsClosed; | 100 bool queueIsClosed; |
| 109 | 101 |
| 110 bool get queueIsEmpty; | 102 bool get queueIsEmpty; |
| 111 | 103 |
| 112 ImpactUseCase get impactUse; | 104 ImpactUseCase get impactUse; |
| 113 | 105 |
| 114 /** | |
| 115 * Documentation wanted -- johnniwinther | |
| 116 * | |
| 117 * Invariant: [element] must be a declaration element. | |
| 118 */ | |
| 119 void addToWorkList(Element element); | |
| 120 | |
| 121 void enableIsolateSupport(); | |
| 122 | |
| 123 void registerInstantiatedType(InterfaceType type); | |
| 124 void forEach(void f(WorkItem work)); | 106 void forEach(void f(WorkItem work)); |
| 125 | 107 |
| 126 /// Apply the [worldImpact] to this enqueuer. If the [impactSource] is provide
d | 108 /// Apply the [worldImpact] to this enqueuer. If the [impactSource] is |
| 127 /// the impact strategy will remove it from the element impact cache, if it is | 109 /// provided the impact strategy will remove it from the element impact cache, |
| 128 /// no longer needed. | 110 /// if it is no longer needed. |
| 129 void applyImpact(WorldImpact worldImpact, {Element impactSource}); | 111 void applyImpact(WorldImpact worldImpact, {Element impactSource}); |
| 130 bool checkNoEnqueuedInvokedInstanceMethods(); | 112 bool checkNoEnqueuedInvokedInstanceMethods(); |
| 131 void logSummary(log(message)); | 113 void logSummary(log(message)); |
| 132 | 114 |
| 133 /// Returns [:true:] if [member] has been processed by this enqueuer. | 115 /// Returns [:true:] if [member] has been processed by this enqueuer. |
| 134 bool isProcessed(Element member); | 116 bool isProcessed(Element member); |
| 135 | 117 |
| 136 Iterable<Entity> get processedEntities; | 118 Iterable<Entity> get processedEntities; |
| 137 | 119 |
| 138 Iterable<ClassElement> get processedClasses; | 120 Iterable<ClassElement> get processedClasses; |
| 139 } | 121 } |
| 140 | 122 |
| 123 abstract class EnqueuerImpl extends Enqueuer { |
| 124 CompilerTask get task; |
| 125 void processInstantiatedClassMembers(ClassElement cls); |
| 126 void processInstantiatedClassMember(ClassElement cls, Element member); |
| 127 void registerStaticUse(StaticUse staticUse); |
| 128 void registerStaticUseInternal(StaticUse staticUse); |
| 129 void registerTypeUse(TypeUse typeUse); |
| 130 void registerTypeUseInternal(TypeUse typeUse); |
| 131 void registerDynamicUse(DynamicUse dynamicUse); |
| 132 void handleUnseenSelectorInternal(DynamicUse dynamicUse); |
| 133 } |
| 134 |
| 141 /// [Enqueuer] which is specific to resolution. | 135 /// [Enqueuer] which is specific to resolution. |
| 142 class ResolutionEnqueuer extends Enqueuer { | 136 class ResolutionEnqueuer extends EnqueuerImpl { |
| 143 final CompilerTask task; | 137 final CompilerTask task; |
| 144 final String name; | 138 final String name; |
| 145 final Resolution resolution; | 139 final Resolution resolution; |
| 146 final QueueFilter filter; | 140 final QueueFilter filter; |
| 147 final CompilerOptions options; | 141 final CompilerOptions options; |
| 148 final Backend backend; | 142 final Backend backend; |
| 149 final GlobalDependencyRegistry globalDependencies; | 143 final GlobalDependencyRegistry globalDependencies; |
| 150 final CommonElements commonElements; | 144 final CommonElements commonElements; |
| 151 final native.NativeEnqueuer nativeEnqueuer; | 145 final native.NativeEnqueuer nativeEnqueuer; |
| 152 | 146 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 175 CacheStrategy cacheStrategy, | 169 CacheStrategy cacheStrategy, |
| 176 [this.name = 'resolution enqueuer']) | 170 [this.name = 'resolution enqueuer']) |
| 177 : this.backend = backend, | 171 : this.backend = backend, |
| 178 this.commonElements = commonElements, | 172 this.commonElements = commonElements, |
| 179 this.nativeEnqueuer = backend.nativeResolutionEnqueuer(), | 173 this.nativeEnqueuer = backend.nativeResolutionEnqueuer(), |
| 180 processedElements = new Set<AstElement>(), | 174 processedElements = new Set<AstElement>(), |
| 181 queue = new Queue<ResolutionWorkItem>(), | 175 queue = new Queue<ResolutionWorkItem>(), |
| 182 deferredQueue = new Queue<_DeferredAction>(), | 176 deferredQueue = new Queue<_DeferredAction>(), |
| 183 _universe = new ResolutionWorldBuilderImpl( | 177 _universe = new ResolutionWorldBuilderImpl( |
| 184 backend, commonElements, cacheStrategy, const TypeMaskStrategy()) { | 178 backend, commonElements, cacheStrategy, const TypeMaskStrategy()) { |
| 185 impactVisitor = new _EnqueuerImpactVisitor(this); | 179 impactVisitor = new EnqueuerImplImpactVisitor(this); |
| 186 } | 180 } |
| 187 | 181 |
| 188 ResolutionWorldBuilder get universe => _universe; | 182 ResolutionWorldBuilder get universe => _universe; |
| 189 | 183 |
| 190 OpenWorld get openWorld => universe.openWorld; | 184 OpenWorld get openWorld => universe.openWorld; |
| 191 | 185 |
| 192 bool get queueIsEmpty => queue.isEmpty; | 186 bool get queueIsEmpty => queue.isEmpty; |
| 193 | 187 |
| 194 DiagnosticReporter get reporter => resolution.reporter; | 188 DiagnosticReporter get reporter => resolution.reporter; |
| 195 | 189 |
| (...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 462 // enqueue. | 456 // enqueue. |
| 463 LocalFunctionElement closure = staticUse.element; | 457 LocalFunctionElement closure = staticUse.element; |
| 464 if (closure.type.containsTypeVariables) { | 458 if (closure.type.containsTypeVariables) { |
| 465 universe.closuresWithFreeTypeVariables.add(closure); | 459 universe.closuresWithFreeTypeVariables.add(closure); |
| 466 } | 460 } |
| 467 addElement = false; | 461 addElement = false; |
| 468 break; | 462 break; |
| 469 case StaticUseKind.SUPER_FIELD_SET: | 463 case StaticUseKind.SUPER_FIELD_SET: |
| 470 case StaticUseKind.SUPER_TEAR_OFF: | 464 case StaticUseKind.SUPER_TEAR_OFF: |
| 471 case StaticUseKind.GENERAL: | 465 case StaticUseKind.GENERAL: |
| 466 case StaticUseKind.DIRECT_USE: |
| 472 break; | 467 break; |
| 473 case StaticUseKind.CONSTRUCTOR_INVOKE: | 468 case StaticUseKind.CONSTRUCTOR_INVOKE: |
| 474 case StaticUseKind.CONST_CONSTRUCTOR_INVOKE: | 469 case StaticUseKind.CONST_CONSTRUCTOR_INVOKE: |
| 475 _registerInstantiatedType(staticUse.type, | 470 _registerInstantiatedType(staticUse.type, |
| 476 constructor: staticUse.element, globalDependency: false); | 471 constructor: staticUse.element, globalDependency: false); |
| 477 break; | 472 break; |
| 478 case StaticUseKind.REDIRECTION: | 473 case StaticUseKind.REDIRECTION: |
| 479 _registerInstantiatedType(staticUse.type, | 474 _registerInstantiatedType(staticUse.type, |
| 480 constructor: staticUse.element, | 475 constructor: staticUse.element, |
| 481 globalDependency: false, | 476 globalDependency: false, |
| 482 isRedirection: true); | 477 isRedirection: true); |
| 483 break; | 478 break; |
| 484 case StaticUseKind.DIRECT_INVOKE: | 479 case StaticUseKind.DIRECT_INVOKE: |
| 485 invariant( | 480 invariant( |
| 486 element, 'Direct static use is not supported for resolution.'); | 481 element, 'Direct static use is not supported for resolution.'); |
| 487 break; | 482 break; |
| 488 } | 483 } |
| 489 if (addElement) { | 484 if (addElement) { |
| 490 addToWorkList(element); | 485 addToWorkList(element); |
| 491 } | 486 } |
| 492 } | 487 } |
| 493 | 488 |
| 494 void _registerTypeUse(TypeUse typeUse) { | 489 void registerTypeUse(TypeUse typeUse) { |
| 490 strategy.processTypeUse(this, typeUse); |
| 491 } |
| 492 |
| 493 void registerTypeUseInternal(TypeUse typeUse) { |
| 495 DartType type = typeUse.type; | 494 DartType type = typeUse.type; |
| 496 switch (typeUse.kind) { | 495 switch (typeUse.kind) { |
| 497 case TypeUseKind.INSTANTIATION: | 496 case TypeUseKind.INSTANTIATION: |
| 498 _registerInstantiatedType(type, globalDependency: false); | 497 _registerInstantiatedType(type, globalDependency: false); |
| 499 break; | 498 break; |
| 500 case TypeUseKind.MIRROR_INSTANTIATION: | 499 case TypeUseKind.MIRROR_INSTANTIATION: |
| 501 _registerInstantiatedType(type, | 500 _registerInstantiatedType(type, |
| 502 mirrorUsage: true, globalDependency: false); | 501 mirrorUsage: true, globalDependency: false); |
| 503 break; | 502 break; |
| 504 case TypeUseKind.NATIVE_INSTANTIATION: | 503 case TypeUseKind.NATIVE_INSTANTIATION: |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 701 _universe.forgetElement(element, compiler); | 700 _universe.forgetElement(element, compiler); |
| 702 _processedClasses.remove(element); | 701 _processedClasses.remove(element); |
| 703 instanceMembersByName[element.name]?.remove(element); | 702 instanceMembersByName[element.name]?.remove(element); |
| 704 instanceFunctionsByName[element.name]?.remove(element); | 703 instanceFunctionsByName[element.name]?.remove(element); |
| 705 processedElements.remove(element); | 704 processedElements.remove(element); |
| 706 } | 705 } |
| 707 } | 706 } |
| 708 | 707 |
| 709 /// Parameterizes filtering of which work items are enqueued. | 708 /// Parameterizes filtering of which work items are enqueued. |
| 710 class QueueFilter { | 709 class QueueFilter { |
| 711 bool checkNoEnqueuedInvokedInstanceMethods(Enqueuer enqueuer) { | 710 bool checkNoEnqueuedInvokedInstanceMethods(EnqueuerImpl enqueuer) { |
| 712 enqueuer.task.measure(() { | 711 enqueuer.task.measure(() { |
| 713 // Run through the classes and see if we need to compile methods. | 712 // Run through the classes and see if we need to compile methods. |
| 714 for (ClassElement classElement | 713 for (ClassElement classElement |
| 715 in enqueuer.universe.directlyInstantiatedClasses) { | 714 in enqueuer.universe.directlyInstantiatedClasses) { |
| 716 for (ClassElement currentClass = classElement; | 715 for (ClassElement currentClass = classElement; |
| 717 currentClass != null; | 716 currentClass != null; |
| 718 currentClass = currentClass.superclass) { | 717 currentClass = currentClass.superclass) { |
| 719 enqueuer.processInstantiatedClassMembers(currentClass); | 718 enqueuer.processInstantiatedClassMembers(currentClass); |
| 720 } | 719 } |
| 721 } | 720 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 733 if (set == null) return; | 732 if (set == null) return; |
| 734 set.remove(element); | 733 set.remove(element); |
| 735 } | 734 } |
| 736 | 735 |
| 737 /// Strategy used by the enqueuer to populate the world. | 736 /// Strategy used by the enqueuer to populate the world. |
| 738 // TODO(johnniwinther): Merge this interface with [QueueFilter]. | 737 // TODO(johnniwinther): Merge this interface with [QueueFilter]. |
| 739 class EnqueuerStrategy { | 738 class EnqueuerStrategy { |
| 740 const EnqueuerStrategy(); | 739 const EnqueuerStrategy(); |
| 741 | 740 |
| 742 /// Process a class instantiated in live code. | 741 /// Process a class instantiated in live code. |
| 743 void processInstantiatedClass(Enqueuer enqueuer, ClassElement cls) {} | 742 void processInstantiatedClass(EnqueuerImpl enqueuer, ClassElement cls) {} |
| 744 | 743 |
| 745 /// Process a static use of and element in live code. | 744 /// Process a static use of and element in live code. |
| 746 void processStaticUse(Enqueuer enqueuer, StaticUse staticUse) {} | 745 void processStaticUse(EnqueuerImpl enqueuer, StaticUse staticUse) {} |
| 746 |
| 747 /// Process a type use in live code. |
| 748 void processTypeUse(EnqueuerImpl enqueuer, TypeUse typeUse) {} |
| 747 | 749 |
| 748 /// Process a dynamic use for a call site in live code. | 750 /// Process a dynamic use for a call site in live code. |
| 749 void processDynamicUse(Enqueuer enqueuer, DynamicUse dynamicUse) {} | 751 void processDynamicUse(EnqueuerImpl enqueuer, DynamicUse dynamicUse) {} |
| 750 } | 752 } |
| 751 | 753 |
| 754 /// Strategy that only enqueues directly used elements. |
| 755 class DirectEnqueuerStrategy extends EnqueuerStrategy { |
| 756 const DirectEnqueuerStrategy(); |
| 757 void processStaticUse(EnqueuerImpl enqueuer, StaticUse staticUse) { |
| 758 if (staticUse.kind == StaticUseKind.DIRECT_USE) { |
| 759 enqueuer.registerStaticUseInternal(staticUse); |
| 760 } |
| 761 } |
| 762 } |
| 763 |
| 764 /// Strategy used for tree-shaking. |
| 752 class TreeShakingEnqueuerStrategy implements EnqueuerStrategy { | 765 class TreeShakingEnqueuerStrategy implements EnqueuerStrategy { |
| 753 const TreeShakingEnqueuerStrategy(); | 766 const TreeShakingEnqueuerStrategy(); |
| 754 | 767 |
| 755 @override | 768 @override |
| 756 void processInstantiatedClass(Enqueuer enqueuer, ClassElement cls) { | 769 void processInstantiatedClass(EnqueuerImpl enqueuer, ClassElement cls) { |
| 757 cls.implementation.forEachMember(enqueuer.processInstantiatedClassMember); | 770 cls.implementation.forEachMember(enqueuer.processInstantiatedClassMember); |
| 758 } | 771 } |
| 759 | 772 |
| 760 @override | 773 @override |
| 761 void processStaticUse(Enqueuer enqueuer, StaticUse staticUse) { | 774 void processStaticUse(EnqueuerImpl enqueuer, StaticUse staticUse) { |
| 762 enqueuer.registerStaticUseInternal(staticUse); | 775 enqueuer.registerStaticUseInternal(staticUse); |
| 763 } | 776 } |
| 764 | 777 |
| 765 @override | 778 @override |
| 766 void processDynamicUse(Enqueuer enqueuer, DynamicUse dynamicUse) { | 779 void processTypeUse(EnqueuerImpl enqueuer, TypeUse typeUse) { |
| 780 enqueuer.registerTypeUseInternal(typeUse); |
| 781 } |
| 782 |
| 783 @override |
| 784 void processDynamicUse(EnqueuerImpl enqueuer, DynamicUse dynamicUse) { |
| 767 enqueuer.handleUnseenSelectorInternal(dynamicUse); | 785 enqueuer.handleUnseenSelectorInternal(dynamicUse); |
| 768 } | 786 } |
| 769 } | 787 } |
| 770 | 788 |
| 771 class _EnqueuerImpactVisitor implements WorldImpactVisitor { | 789 class EnqueuerImplImpactVisitor implements WorldImpactVisitor { |
| 772 final ResolutionEnqueuer enqueuer; | 790 final EnqueuerImpl enqueuer; |
| 773 | 791 |
| 774 _EnqueuerImpactVisitor(this.enqueuer); | 792 EnqueuerImplImpactVisitor(this.enqueuer); |
| 775 | 793 |
| 776 @override | 794 @override |
| 777 void visitDynamicUse(DynamicUse dynamicUse) { | 795 void visitDynamicUse(DynamicUse dynamicUse) { |
| 778 enqueuer.registerDynamicUse(dynamicUse); | 796 enqueuer.registerDynamicUse(dynamicUse); |
| 779 } | 797 } |
| 780 | 798 |
| 781 @override | 799 @override |
| 782 void visitStaticUse(StaticUse staticUse) { | 800 void visitStaticUse(StaticUse staticUse) { |
| 783 enqueuer.registerStaticUse(staticUse); | 801 enqueuer.registerStaticUse(staticUse); |
| 784 } | 802 } |
| 785 | 803 |
| 786 @override | 804 @override |
| 787 void visitTypeUse(TypeUse typeUse) { | 805 void visitTypeUse(TypeUse typeUse) { |
| 788 enqueuer._registerTypeUse(typeUse); | 806 enqueuer.registerTypeUse(typeUse); |
| 789 } | 807 } |
| 790 } | 808 } |
| 791 | 809 |
| 792 typedef void _DeferredActionFunction(); | 810 typedef void _DeferredActionFunction(); |
| 793 | 811 |
| 794 class _DeferredAction { | 812 class _DeferredAction { |
| 795 final Element element; | 813 final Element element; |
| 796 final _DeferredActionFunction action; | 814 final _DeferredActionFunction action; |
| 797 | 815 |
| 798 _DeferredAction(this.element, this.action); | 816 _DeferredAction(this.element, this.action); |
| 799 } | 817 } |
| OLD | NEW |