Chromium Code Reviews| 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.js.enqueue; | 5 library dart2js.js.enqueue; |
| 6 | 6 |
| 7 import 'dart:collection' show Queue; | 7 import 'dart:collection' show Queue; |
| 8 | 8 |
| 9 import '../cache_strategy.dart' show CacheStrategy; | 9 import '../cache_strategy.dart' show CacheStrategy; |
| 10 import '../common/backend_api.dart' show Backend; | 10 import '../common/backend_api.dart' show Backend; |
| 11 import '../common/codegen.dart' show CodegenWorkItem; | 11 import '../common/codegen.dart' show CodegenWorkItem; |
| 12 import '../common/tasks.dart' show CompilerTask; | 12 import '../common/tasks.dart' show CompilerTask; |
| 13 import '../common/work.dart' show WorkItem; | 13 import '../common/work.dart' show WorkItem; |
| 14 import '../common.dart'; | 14 import '../common.dart'; |
| 15 import '../compiler.dart' show Compiler; | 15 import '../compiler.dart' show Compiler; |
| 16 import '../dart_types.dart' show DartType, InterfaceType; | 16 import '../dart_types.dart' show DartType, InterfaceType; |
| 17 import '../elements/elements.dart' | 17 import '../elements/elements.dart' show Element, Entity, TypedElement; |
| 18 show ClassElement, Element, Entity, MemberElement, TypedElement; | |
| 19 import '../elements/entities.dart'; | 18 import '../elements/entities.dart'; |
| 20 import '../enqueue.dart'; | 19 import '../enqueue.dart'; |
| 21 import '../js/js.dart' as js; | |
| 22 import '../native/native.dart' as native; | 20 import '../native/native.dart' as native; |
| 23 import '../options.dart'; | 21 import '../options.dart'; |
| 24 import '../types/types.dart' show TypeMaskStrategy; | 22 import '../types/types.dart' show TypeMaskStrategy; |
| 25 import '../universe/world_builder.dart'; | 23 import '../universe/world_builder.dart'; |
| 26 import '../universe/use.dart' | 24 import '../universe/use.dart' |
| 27 show DynamicUse, StaticUse, StaticUseKind, TypeUse, TypeUseKind; | 25 show DynamicUse, StaticUse, StaticUseKind, TypeUse, TypeUseKind; |
| 28 import '../universe/world_impact.dart' | 26 import '../universe/world_impact.dart' |
| 29 show ImpactUseCase, WorldImpact, WorldImpactVisitor; | 27 show ImpactUseCase, WorldImpact, WorldImpactVisitor; |
| 30 import '../util/enumset.dart'; | 28 import '../util/enumset.dart'; |
| 31 import '../util/util.dart' show Setlet; | 29 import '../util/util.dart' show Setlet; |
| 32 | 30 |
| 33 /// [Enqueuer] which is specific to code generation. | 31 /// [Enqueuer] which is specific to code generation. |
| 34 class CodegenEnqueuer extends EnqueuerImpl { | 32 class CodegenEnqueuer extends EnqueuerImpl { |
| 35 final String name; | 33 final String name; |
| 36 final EnqueuerStrategy strategy; | 34 final EnqueuerStrategy strategy; |
| 37 | 35 |
| 38 Set<ClassElement> _recentClasses = new Setlet<ClassElement>(); | 36 Set<ClassEntity> _recentClasses = new Setlet<ClassEntity>(); |
| 39 final CodegenWorldBuilderImpl _universe; | 37 final CodegenWorldBuilderImpl _universe; |
| 40 | 38 |
| 41 bool queueIsClosed = false; | 39 bool queueIsClosed = false; |
| 42 final CompilerTask task; | 40 final CompilerTask task; |
| 43 final native.NativeEnqueuer nativeEnqueuer; | 41 final native.NativeEnqueuer nativeEnqueuer; |
| 44 final Backend _backend; | 42 final Backend _backend; |
| 45 final CompilerOptions _options; | 43 final CompilerOptions _options; |
| 46 | 44 |
| 47 WorldImpactVisitor _impactVisitor; | 45 WorldImpactVisitor _impactVisitor; |
| 48 | 46 |
| 49 final Queue<WorkItem> _queue = new Queue<WorkItem>(); | 47 final Queue<WorkItem> _queue = new Queue<WorkItem>(); |
| 50 final Map<Element, js.Expression> generatedCode = <Element, js.Expression>{}; | |
| 51 | 48 |
| 52 final Set<Element> newlyEnqueuedElements; | 49 /// All declaration elements that have been processed by codegen. |
| 50 final Set<Entity> _processedEntities = new Set<Entity>(); | |
| 51 | |
| 52 final Set<Entity> newlyEnqueuedElements; | |
| 53 | 53 |
| 54 final Set<DynamicUse> newlySeenSelectors; | 54 final Set<DynamicUse> newlySeenSelectors; |
| 55 | 55 |
| 56 static const ImpactUseCase IMPACT_USE = | 56 static const ImpactUseCase IMPACT_USE = |
| 57 const ImpactUseCase('CodegenEnqueuer'); | 57 const ImpactUseCase('CodegenEnqueuer'); |
| 58 | 58 |
| 59 CodegenEnqueuer(this.task, CacheStrategy cacheStrategy, Backend backend, | 59 CodegenEnqueuer(this.task, CacheStrategy cacheStrategy, Backend backend, |
| 60 this._options, this.strategy) | 60 this._options, this.strategy) |
| 61 : _universe = | 61 : _universe = |
| 62 new CodegenWorldBuilderImpl(backend, const TypeMaskStrategy()), | 62 new CodegenWorldBuilderImpl(backend, const TypeMaskStrategy()), |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 77 | 77 |
| 78 /** | 78 /** |
| 79 * Documentation wanted -- johnniwinther | 79 * Documentation wanted -- johnniwinther |
| 80 * | 80 * |
| 81 * Invariant: [element] must be a declaration element. | 81 * Invariant: [element] must be a declaration element. |
| 82 */ | 82 */ |
| 83 void _addToWorkList(Element element) { | 83 void _addToWorkList(Element element) { |
| 84 assert(invariant(element, element.isDeclaration)); | 84 assert(invariant(element, element.isDeclaration)); |
| 85 // Don't generate code for foreign elements. | 85 // Don't generate code for foreign elements. |
| 86 if (_backend.isForeign(element)) return; | 86 if (_backend.isForeign(element)) return; |
| 87 if (element.isAbstract) return; | |
| 87 | 88 |
| 88 // Codegen inlines field initializers. It only needs to generate | 89 // Codegen inlines field initializers. It only needs to generate |
| 89 // code for checked setters. | 90 // code for checked setters. |
| 90 if (element.isField && element.isInstanceMember) { | 91 if (element.isField && element.isInstanceMember) { |
| 91 if (!_options.enableTypeAssertions || | 92 if (!_options.enableTypeAssertions || |
| 92 element.enclosingElement.isClosure) { | 93 element.enclosingElement.isClosure) { |
| 93 return; | 94 return; |
| 94 } | 95 } |
| 95 } | 96 } |
| 96 | 97 |
| 97 if (_options.hasIncrementalSupport && !isProcessed(element)) { | 98 if (_options.hasIncrementalSupport && |
| 99 !_processedEntities.contains(element)) { | |
| 98 newlyEnqueuedElements.add(element); | 100 newlyEnqueuedElements.add(element); |
| 99 } | 101 } |
| 100 | 102 |
| 101 if (queueIsClosed) { | 103 if (queueIsClosed) { |
| 102 throw new SpannableAssertionFailure( | 104 throw new SpannableAssertionFailure( |
| 103 element, "Codegen work list is closed. Trying to add $element"); | 105 element, "Codegen work list is closed. Trying to add $element"); |
| 104 } | 106 } |
| 105 _queue.add(new CodegenWorkItem(_backend, element)); | 107 _queue.add(new CodegenWorkItem(_backend, element)); |
| 106 applyImpact(_backend.registerUsedElement(element, forResolution: false)); | 108 applyImpact(_backend.registerUsedElement(element, forResolution: false)); |
| 107 } | 109 } |
| 108 | 110 |
| 109 void applyImpact(WorldImpact worldImpact, {Element impactSource}) { | 111 void applyImpact(WorldImpact worldImpact, {var impactSource}) { |
|
Siggi Cherem (dart-lang)
2016/12/20 19:26:34
var => Entity?
Johnni Winther
2016/12/21 09:43:40
No. The plan it to allow for any key; elements, bu
| |
| 110 if (worldImpact.isEmpty) return; | 112 if (worldImpact.isEmpty) return; |
| 111 impactStrategy.visitImpact( | 113 impactStrategy.visitImpact( |
| 112 impactSource, worldImpact, _impactVisitor, impactUse); | 114 impactSource, worldImpact, _impactVisitor, impactUse); |
| 113 } | 115 } |
| 114 | 116 |
| 115 void _registerInstantiatedType(InterfaceType type, | 117 void _registerInstantiatedType(InterfaceType type, |
| 116 {bool mirrorUsage: false, bool nativeUsage: false}) { | 118 {bool mirrorUsage: false, bool nativeUsage: false}) { |
| 117 task.measure(() { | 119 task.measure(() { |
| 118 _universe.registerTypeInstantiation(type, _applyClassUse, | 120 _universe.registerTypeInstantiation(type, _applyClassUse, |
| 119 byMirrors: mirrorUsage); | 121 byMirrors: mirrorUsage); |
| 120 if (nativeUsage) { | 122 if (nativeUsage) { |
| 121 nativeEnqueuer.onInstantiatedType(type); | 123 nativeEnqueuer.onInstantiatedType(type); |
| 122 } | 124 } |
| 123 _backend.registerInstantiatedType(type); | 125 _backend.registerInstantiatedType(type); |
| 124 }); | 126 }); |
| 125 } | 127 } |
| 126 | 128 |
| 127 bool checkNoEnqueuedInvokedInstanceMethods() { | 129 bool checkNoEnqueuedInvokedInstanceMethods() { |
| 128 return strategy.checkEnqueuerConsistency(this); | 130 return strategy.checkEnqueuerConsistency(this); |
| 129 } | 131 } |
| 130 | 132 |
| 131 void checkClass(ClassElement cls) { | 133 void checkClass(ClassEntity cls) { |
| 132 _universe.processClassMembers(cls, (MemberElement member, useSet) { | 134 _universe.processClassMembers(cls, (MemberEntity member, useSet) { |
| 133 if (useSet.isNotEmpty) { | 135 if (useSet.isNotEmpty) { |
| 134 _backend.compiler.reporter.internalError(member, | 136 _backend.compiler.reporter.internalError(member, |
| 135 'Unenqueued use of $member: ${useSet.iterable(MemberUse.values)}'); | 137 'Unenqueued use of $member: ${useSet.iterable(MemberUse.values)}'); |
| 136 } | 138 } |
| 137 }); | 139 }); |
| 138 } | 140 } |
| 139 | 141 |
| 140 /// Callback for applying the use of a [cls]. | 142 /// Callback for applying the use of a [cls]. |
| 141 void _applyClassUse(ClassEntity cls, EnumSet<ClassUse> useSet) { | 143 void _applyClassUse(ClassEntity cls, EnumSet<ClassUse> useSet) { |
| 142 if (useSet.contains(ClassUse.INSTANTIATED)) { | 144 if (useSet.contains(ClassUse.INSTANTIATED)) { |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 170 task.measure(() { | 172 task.measure(() { |
| 171 if (_universe.registerDynamicUse(dynamicUse, _applyMemberUse)) { | 173 if (_universe.registerDynamicUse(dynamicUse, _applyMemberUse)) { |
| 172 if (_options.hasIncrementalSupport) { | 174 if (_options.hasIncrementalSupport) { |
| 173 newlySeenSelectors.add(dynamicUse); | 175 newlySeenSelectors.add(dynamicUse); |
| 174 } | 176 } |
| 175 } | 177 } |
| 176 }); | 178 }); |
| 177 } | 179 } |
| 178 | 180 |
| 179 void processStaticUse(StaticUse staticUse) { | 181 void processStaticUse(StaticUse staticUse) { |
| 180 Element element = staticUse.element; | |
| 181 assert(invariant(element, element.isDeclaration, | |
| 182 message: "Element ${element} is not the declaration.")); | |
| 183 _universe.registerStaticUse(staticUse, _applyMemberUse); | 182 _universe.registerStaticUse(staticUse, _applyMemberUse); |
| 184 switch (staticUse.kind) { | 183 switch (staticUse.kind) { |
| 185 case StaticUseKind.CONSTRUCTOR_INVOKE: | 184 case StaticUseKind.CONSTRUCTOR_INVOKE: |
| 186 case StaticUseKind.CONST_CONSTRUCTOR_INVOKE: | 185 case StaticUseKind.CONST_CONSTRUCTOR_INVOKE: |
| 187 case StaticUseKind.REDIRECTION: | 186 case StaticUseKind.REDIRECTION: |
| 188 processTypeUse(new TypeUse.instantiation(staticUse.type)); | 187 processTypeUse(new TypeUse.instantiation(staticUse.type)); |
| 189 break; | 188 break; |
| 190 default: | 189 default: |
| 191 break; | 190 break; |
| 192 } | 191 } |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 234 forResolution: false)); | 233 forResolution: false)); |
| 235 } | 234 } |
| 236 applyImpact(_backend.registerBoundClosure()); | 235 applyImpact(_backend.registerBoundClosure()); |
| 237 } | 236 } |
| 238 | 237 |
| 239 void forEach(void f(WorkItem work)) { | 238 void forEach(void f(WorkItem work)) { |
| 240 do { | 239 do { |
| 241 while (_queue.isNotEmpty) { | 240 while (_queue.isNotEmpty) { |
| 242 // TODO(johnniwinther): Find an optimal process order. | 241 // TODO(johnniwinther): Find an optimal process order. |
| 243 WorkItem work = _queue.removeLast(); | 242 WorkItem work = _queue.removeLast(); |
| 244 if (!isProcessed(work.element)) { | 243 if (!_processedEntities.contains(work.element)) { |
| 245 strategy.processWorkItem(f, work); | 244 strategy.processWorkItem(f, work); |
| 246 // TODO(johnniwinther): Register the processed element here. This | 245 // TODO(johnniwinther): Register the processed element here. This |
| 247 // is currently a side-effect of calling `work.run`. | 246 // is currently a side-effect of calling `work.run`. |
| 247 _processedEntities.add(work.element); | |
| 248 } | 248 } |
| 249 } | 249 } |
| 250 List recents = _recentClasses.toList(growable: false); | 250 List recents = _recentClasses.toList(growable: false); |
| 251 _recentClasses.clear(); | 251 _recentClasses.clear(); |
| 252 if (!_onQueueEmpty(recents)) _recentClasses.addAll(recents); | 252 if (!_onQueueEmpty(recents)) _recentClasses.addAll(recents); |
| 253 } while (_queue.isNotEmpty || _recentClasses.isNotEmpty); | 253 } while (_queue.isNotEmpty || _recentClasses.isNotEmpty); |
| 254 } | 254 } |
| 255 | 255 |
| 256 /// [_onQueueEmpty] is called whenever the queue is drained. [recentClasses] | 256 /// [_onQueueEmpty] is called whenever the queue is drained. [recentClasses] |
| 257 /// contains the set of all classes seen for the first time since | 257 /// contains the set of all classes seen for the first time since |
| 258 /// [_onQueueEmpty] was called last. A return value of [true] indicates that | 258 /// [_onQueueEmpty] was called last. A return value of [true] indicates that |
| 259 /// the [recentClasses] have been processed and may be cleared. If [false] is | 259 /// the [recentClasses] have been processed and may be cleared. If [false] is |
| 260 /// returned, [_onQueueEmpty] will be called once the queue is empty again (or | 260 /// returned, [_onQueueEmpty] will be called once the queue is empty again (or |
| 261 /// still empty) and [recentClasses] will be a superset of the current value. | 261 /// still empty) and [recentClasses] will be a superset of the current value. |
| 262 bool _onQueueEmpty(Iterable<ClassElement> recentClasses) { | 262 bool _onQueueEmpty(Iterable<ClassEntity> recentClasses) { |
| 263 return _backend.onQueueEmpty(this, recentClasses); | 263 return _backend.onQueueEmpty(this, recentClasses); |
| 264 } | 264 } |
| 265 | 265 |
| 266 void logSummary(log(message)) { | 266 void logSummary(log(message)) { |
| 267 log('Compiled ${generatedCode.length} methods.'); | 267 log('Compiled ${_processedEntities.length} methods.'); |
| 268 nativeEnqueuer.logSummary(log); | 268 nativeEnqueuer.logSummary(log); |
| 269 } | 269 } |
| 270 | 270 |
| 271 String toString() => 'Enqueuer($name)'; | 271 String toString() => 'Enqueuer($name)'; |
| 272 | 272 |
| 273 ImpactUseCase get impactUse => IMPACT_USE; | 273 ImpactUseCase get impactUse => IMPACT_USE; |
| 274 | 274 |
| 275 bool isProcessed(Element member) => | 275 void forgetEntity(Entity entity, Compiler compiler) { |
| 276 member.isAbstract || generatedCode.containsKey(member); | 276 _universe.forgetElement(entity, compiler); |
| 277 | 277 _processedEntities.remove(entity); |
| 278 void forgetEntity(Element element, Compiler compiler) { | |
| 279 _universe.forgetElement(element, compiler); | |
| 280 generatedCode.remove(element); | |
| 281 if (element is MemberElement) { | |
| 282 for (Element closure in element.nestedClosures) { | |
| 283 generatedCode.remove(closure); | |
| 284 } | |
| 285 } | |
| 286 } | 278 } |
| 287 | 279 |
| 288 @override | 280 @override |
| 289 Iterable<Entity> get processedEntities => generatedCode.keys; | 281 Iterable<Entity> get processedEntities => _processedEntities; |
| 290 | 282 |
| 291 @override | 283 @override |
| 292 Iterable<ClassEntity> get processedClasses => _universe.processedClasses; | 284 Iterable<ClassEntity> get processedClasses => _universe.processedClasses; |
| 293 } | 285 } |
| OLD | NEW |