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