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 '../common/backend_api.dart' show Backend; | 9 import '../common/backend_api.dart' show Backend; |
| 10 import '../common/codegen.dart' show CodegenWorkItem; | 10 import '../common/codegen.dart' show CodegenWorkItem; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 47 final String name; | 47 final String name; |
| 48 @deprecated | 48 @deprecated |
| 49 final Compiler _compiler; // TODO(ahe): Remove this dependency. | 49 final Compiler _compiler; // TODO(ahe): Remove this dependency. |
| 50 final EnqueuerStrategy strategy; | 50 final EnqueuerStrategy strategy; |
| 51 final Map<String, Set<Element>> instanceMembersByName = | 51 final Map<String, Set<Element>> instanceMembersByName = |
| 52 new Map<String, Set<Element>>(); | 52 new Map<String, Set<Element>>(); |
| 53 final Map<String, Set<Element>> instanceFunctionsByName = | 53 final Map<String, Set<Element>> instanceFunctionsByName = |
| 54 new Map<String, Set<Element>>(); | 54 new Map<String, Set<Element>>(); |
| 55 final Set<ClassElement> _processedClasses = new Set<ClassElement>(); | 55 final Set<ClassElement> _processedClasses = new Set<ClassElement>(); |
| 56 Set<ClassElement> recentClasses = new Setlet<ClassElement>(); | 56 Set<ClassElement> recentClasses = new Setlet<ClassElement>(); |
| 57 final Universe universe = new Universe(const TypeMaskStrategy()); | 57 final CodegenUniverseImpl _universe = |
| 58 new CodegenUniverseImpl(const TypeMaskStrategy()); | |
| 58 | 59 |
| 59 static final TRACE_MIRROR_ENQUEUING = | 60 static final TRACE_MIRROR_ENQUEUING = |
| 60 const bool.fromEnvironment("TRACE_MIRROR_ENQUEUING"); | 61 const bool.fromEnvironment("TRACE_MIRROR_ENQUEUING"); |
| 61 | 62 |
| 62 bool queueIsClosed = false; | 63 bool queueIsClosed = false; |
| 63 EnqueueTask task; | 64 EnqueueTask task; |
| 64 native.NativeEnqueuer nativeEnqueuer; // Set by EnqueueTask | 65 native.NativeEnqueuer nativeEnqueuer; // Set by EnqueueTask |
| 65 | 66 |
| 66 bool hasEnqueuedReflectiveElements = false; | 67 bool hasEnqueuedReflectiveElements = false; |
| 67 bool hasEnqueuedReflectiveStaticFields = false; | 68 bool hasEnqueuedReflectiveStaticFields = false; |
| 68 | 69 |
| 69 WorldImpactVisitor impactVisitor; | 70 WorldImpactVisitor impactVisitor; |
| 70 | 71 |
| 71 CodegenEnqueuer(Compiler compiler, this.strategy) | 72 CodegenEnqueuer(Compiler compiler, this.strategy) |
| 72 : queue = new Queue<CodegenWorkItem>(), | 73 : queue = new Queue<CodegenWorkItem>(), |
| 73 newlyEnqueuedElements = compiler.cacheStrategy.newSet(), | 74 newlyEnqueuedElements = compiler.cacheStrategy.newSet(), |
| 74 newlySeenSelectors = compiler.cacheStrategy.newSet(), | 75 newlySeenSelectors = compiler.cacheStrategy.newSet(), |
| 75 this.name = 'codegen enqueuer', | 76 this.name = 'codegen enqueuer', |
| 76 this._compiler = compiler { | 77 this._compiler = compiler { |
| 77 impactVisitor = new _EnqueuerImpactVisitor(this); | 78 impactVisitor = new _EnqueuerImpactVisitor(this); |
| 78 } | 79 } |
| 79 | 80 |
| 81 CodegenUniverse get universe => _universe; | |
| 82 | |
| 80 Backend get backend => _compiler.backend; | 83 Backend get backend => _compiler.backend; |
| 81 | 84 |
| 82 CompilerOptions get options => _compiler.options; | 85 CompilerOptions get options => _compiler.options; |
| 83 | 86 |
| 84 Registry get globalDependencies => _compiler.globalDependencies; | 87 Registry get globalDependencies => _compiler.globalDependencies; |
| 85 | 88 |
| 86 Registry get mirrorDependencies => _compiler.mirrorDependencies; | 89 Registry get mirrorDependencies => _compiler.mirrorDependencies; |
| 87 | 90 |
| 88 ClassWorld get _world => _compiler.closedWorld; | 91 ClassWorld get _world => _compiler.closedWorld; |
| 89 | 92 |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 134 /// Apply the [worldImpact] of processing [element] to this enqueuer. | 137 /// Apply the [worldImpact] of processing [element] to this enqueuer. |
| 135 void applyImpact(Element element, WorldImpact worldImpact) { | 138 void applyImpact(Element element, WorldImpact worldImpact) { |
| 136 _compiler.impactStrategy | 139 _compiler.impactStrategy |
| 137 .visitImpact(element, worldImpact, impactVisitor, impactUse); | 140 .visitImpact(element, worldImpact, impactVisitor, impactUse); |
| 138 } | 141 } |
| 139 | 142 |
| 140 void registerInstantiatedType(InterfaceType type, {bool mirrorUsage: false}) { | 143 void registerInstantiatedType(InterfaceType type, {bool mirrorUsage: false}) { |
| 141 task.measure(() { | 144 task.measure(() { |
| 142 ClassElement cls = type.element; | 145 ClassElement cls = type.element; |
| 143 bool isNative = backend.isNative(cls); | 146 bool isNative = backend.isNative(cls); |
| 144 universe.registerTypeInstantiation(type, | 147 _universe.registerTypeInstantiation(type, |
| 145 isNative: isNative, | 148 isNative: isNative, |
| 146 byMirrors: mirrorUsage, onImplemented: (ClassElement cls) { | 149 byMirrors: mirrorUsage, onImplemented: (ClassElement cls) { |
| 147 backend.registerImplementedClass(cls, this, globalDependencies); | 150 backend.registerImplementedClass(cls, this, globalDependencies); |
| 148 }); | 151 }); |
| 149 // TODO(johnniwinther): Share this reasoning with [Universe]. | 152 // TODO(johnniwinther): Share this reasoning with [Universe]. |
| 150 if (!cls.isAbstract || isNative || mirrorUsage) { | 153 if (!cls.isAbstract || isNative || mirrorUsage) { |
| 151 processInstantiatedClass(cls); | 154 processInstantiatedClass(cls); |
| 152 } | 155 } |
| 153 }); | 156 }); |
| 154 } | 157 } |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 169 | 172 |
| 170 if (member.isField) { | 173 if (member.isField) { |
| 171 // The obvious thing to test here would be "member.isNative", | 174 // The obvious thing to test here would be "member.isNative", |
| 172 // however, that only works after metadata has been parsed/analyzed, | 175 // however, that only works after metadata has been parsed/analyzed, |
| 173 // and that may not have happened yet. | 176 // and that may not have happened yet. |
| 174 // So instead we use the enclosing class, which we know have had | 177 // So instead we use the enclosing class, which we know have had |
| 175 // its metadata parsed and analyzed. | 178 // its metadata parsed and analyzed. |
| 176 // Note: this assumes that there are no non-native fields on native | 179 // Note: this assumes that there are no non-native fields on native |
| 177 // classes, which may not be the case when a native class is subclassed. | 180 // classes, which may not be the case when a native class is subclassed. |
| 178 if (backend.isNative(cls)) { | 181 if (backend.isNative(cls)) { |
| 179 if (universe.hasInvokedGetter(member, _world) || | 182 if (_universe.hasInvokedGetter(member, _world) || |
| 180 universe.hasInvocation(member, _world)) { | 183 _universe.hasInvocation(member, _world)) { |
| 181 addToWorkList(member); | 184 addToWorkList(member); |
| 182 return; | 185 return; |
| 183 } | 186 } |
| 184 if (universe.hasInvokedSetter(member, _world)) { | 187 if (_universe.hasInvokedSetter(member, _world)) { |
| 185 addToWorkList(member); | 188 addToWorkList(member); |
| 186 return; | 189 return; |
| 187 } | 190 } |
| 188 // Native fields need to go into instanceMembersByName as they | 191 // Native fields need to go into instanceMembersByName as they |
| 189 // are virtual instantiation points and escape points. | 192 // are virtual instantiation points and escape points. |
| 190 } else { | 193 } else { |
| 191 // All field initializers must be resolved as they could | 194 // All field initializers must be resolved as they could |
| 192 // have an observable side-effect (and cannot be tree-shaken | 195 // have an observable side-effect (and cannot be tree-shaken |
| 193 // away). | 196 // away). |
| 194 addToWorkList(member); | 197 addToWorkList(member); |
| 195 return; | 198 return; |
| 196 } | 199 } |
| 197 } else if (member.isFunction) { | 200 } else if (member.isFunction) { |
| 198 FunctionElement function = member; | 201 FunctionElement function = member; |
| 199 if (function.name == Identifiers.noSuchMethod_) { | 202 if (function.name == Identifiers.noSuchMethod_) { |
| 200 registerNoSuchMethod(function); | 203 registerNoSuchMethod(function); |
| 201 } | 204 } |
| 202 if (function.name == Identifiers.call && !cls.typeVariables.isEmpty) { | 205 if (function.name == Identifiers.call && !cls.typeVariables.isEmpty) { |
| 203 registerCallMethodWithFreeTypeVariables(function); | 206 registerCallMethodWithFreeTypeVariables(function); |
| 204 } | 207 } |
| 205 // If there is a property access with the same name as a method we | 208 // If there is a property access with the same name as a method we |
| 206 // need to emit the method. | 209 // need to emit the method. |
| 207 if (universe.hasInvokedGetter(function, _world)) { | 210 if (_universe.hasInvokedGetter(function, _world)) { |
| 208 registerClosurizedMember(function); | 211 registerClosurizedMember(function); |
| 209 addToWorkList(function); | 212 addToWorkList(function); |
| 210 return; | 213 return; |
| 211 } | 214 } |
| 212 // Store the member in [instanceFunctionsByName] to catch | 215 // Store the member in [instanceFunctionsByName] to catch |
| 213 // getters on the function. | 216 // getters on the function. |
| 214 instanceFunctionsByName | 217 instanceFunctionsByName |
| 215 .putIfAbsent(memberName, () => new Set<Element>()) | 218 .putIfAbsent(memberName, () => new Set<Element>()) |
| 216 .add(member); | 219 .add(member); |
| 217 if (universe.hasInvocation(function, _world)) { | 220 if (_universe.hasInvocation(function, _world)) { |
| 218 addToWorkList(function); | 221 addToWorkList(function); |
| 219 return; | 222 return; |
| 220 } | 223 } |
| 221 } else if (member.isGetter) { | 224 } else if (member.isGetter) { |
| 222 FunctionElement getter = member; | 225 FunctionElement getter = member; |
| 223 if (universe.hasInvokedGetter(getter, _world)) { | 226 if (_universe.hasInvokedGetter(getter, _world)) { |
| 224 addToWorkList(getter); | 227 addToWorkList(getter); |
| 225 return; | 228 return; |
| 226 } | 229 } |
| 227 // We don't know what selectors the returned closure accepts. If | 230 // We don't know what selectors the returned closure accepts. If |
| 228 // the set contains any selector we have to assume that it matches. | 231 // the set contains any selector we have to assume that it matches. |
| 229 if (universe.hasInvocation(getter, _world)) { | 232 if (_universe.hasInvocation(getter, _world)) { |
| 230 addToWorkList(getter); | 233 addToWorkList(getter); |
| 231 return; | 234 return; |
| 232 } | 235 } |
| 233 } else if (member.isSetter) { | 236 } else if (member.isSetter) { |
| 234 FunctionElement setter = member; | 237 FunctionElement setter = member; |
| 235 if (universe.hasInvokedSetter(setter, _world)) { | 238 if (_universe.hasInvokedSetter(setter, _world)) { |
| 236 addToWorkList(setter); | 239 addToWorkList(setter); |
| 237 return; | 240 return; |
| 238 } | 241 } |
| 239 } | 242 } |
| 240 | 243 |
| 241 // The element is not yet used. Add it to the list of instance | 244 // The element is not yet used. Add it to the list of instance |
| 242 // members to still be processed. | 245 // members to still be processed. |
| 243 instanceMembersByName | 246 instanceMembersByName |
| 244 .putIfAbsent(memberName, () => new Set<Element>()) | 247 .putIfAbsent(memberName, () => new Set<Element>()) |
| 245 .add(member); | 248 .add(member); |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 274 ClassElement superclass = cls; | 277 ClassElement superclass = cls; |
| 275 while (superclass != null) { | 278 while (superclass != null) { |
| 276 processClass(superclass); | 279 processClass(superclass); |
| 277 superclass = superclass.superclass; | 280 superclass = superclass.superclass; |
| 278 } | 281 } |
| 279 }); | 282 }); |
| 280 } | 283 } |
| 281 | 284 |
| 282 void registerDynamicUse(DynamicUse dynamicUse) { | 285 void registerDynamicUse(DynamicUse dynamicUse) { |
| 283 task.measure(() { | 286 task.measure(() { |
| 284 if (universe.registerDynamicUse(dynamicUse)) { | 287 if (_universe.registerDynamicUse(dynamicUse)) { |
| 285 handleUnseenSelector(dynamicUse); | 288 handleUnseenSelector(dynamicUse); |
| 286 } | 289 } |
| 287 }); | 290 }); |
| 288 } | 291 } |
| 289 | 292 |
| 290 void logEnqueueReflectiveAction(action, [msg = ""]) { | 293 void logEnqueueReflectiveAction(action, [msg = ""]) { |
| 291 if (TRACE_MIRROR_ENQUEUING) { | 294 if (TRACE_MIRROR_ENQUEUING) { |
| 292 print("MIRROR_ENQUEUE (C): $action $msg"); | 295 print("MIRROR_ENQUEUE (C): $action $msg"); |
| 293 } | 296 } |
| 294 } | 297 } |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 503 * Invariant: [element] must be a declaration element. | 506 * Invariant: [element] must be a declaration element. |
| 504 */ | 507 */ |
| 505 void registerStaticUse(StaticUse staticUse) { | 508 void registerStaticUse(StaticUse staticUse) { |
| 506 strategy.processStaticUse(this, staticUse); | 509 strategy.processStaticUse(this, staticUse); |
| 507 } | 510 } |
| 508 | 511 |
| 509 void registerStaticUseInternal(StaticUse staticUse) { | 512 void registerStaticUseInternal(StaticUse staticUse) { |
| 510 Element element = staticUse.element; | 513 Element element = staticUse.element; |
| 511 assert(invariant(element, element.isDeclaration, | 514 assert(invariant(element, element.isDeclaration, |
| 512 message: "Element ${element} is not the declaration.")); | 515 message: "Element ${element} is not the declaration.")); |
| 513 universe.registerStaticUse(staticUse); | 516 _universe.registerStaticUse(staticUse); |
| 514 backend.registerStaticUse(element, this); | 517 backend.registerStaticUse(element, this); |
| 515 bool addElement = true; | 518 bool addElement = true; |
| 516 switch (staticUse.kind) { | 519 switch (staticUse.kind) { |
| 517 case StaticUseKind.STATIC_TEAR_OFF: | 520 case StaticUseKind.STATIC_TEAR_OFF: |
| 518 backend.registerGetOfStaticFunction(this); | 521 backend.registerGetOfStaticFunction(this); |
| 519 break; | 522 break; |
| 520 case StaticUseKind.FIELD_GET: | 523 case StaticUseKind.FIELD_GET: |
| 521 case StaticUseKind.FIELD_SET: | 524 case StaticUseKind.FIELD_SET: |
| 522 case StaticUseKind.CLOSURE: | 525 case StaticUseKind.CLOSURE: |
| 523 // TODO(johnniwinther): Avoid this. Currently [FIELD_GET] and | 526 // TODO(johnniwinther): Avoid this. Currently [FIELD_GET] and |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 552 if (options.enableTypeAssertions) { | 555 if (options.enableTypeAssertions) { |
| 553 _registerIsCheck(type); | 556 _registerIsCheck(type); |
| 554 } | 557 } |
| 555 break; | 558 break; |
| 556 case TypeUseKind.TYPE_LITERAL: | 559 case TypeUseKind.TYPE_LITERAL: |
| 557 break; | 560 break; |
| 558 } | 561 } |
| 559 } | 562 } |
| 560 | 563 |
| 561 void _registerIsCheck(DartType type) { | 564 void _registerIsCheck(DartType type) { |
| 562 type = universe.registerIsCheck(type, _compiler); | 565 type = _universe.registerIsCheck(type, _compiler); |
| 563 // Even in checked mode, type annotations for return type and argument | 566 // Even in checked mode, type annotations for return type and argument |
| 564 // types do not imply type checks, so there should never be a check | 567 // types do not imply type checks, so there should never be a check |
| 565 // against the type variable of a typedef. | 568 // against the type variable of a typedef. |
| 566 assert(!type.isTypeVariable || !type.element.enclosingElement.isTypedef); | 569 assert(!type.isTypeVariable || !type.element.enclosingElement.isTypedef); |
| 567 } | 570 } |
| 568 | 571 |
| 569 void registerCallMethodWithFreeTypeVariables(Element element) { | 572 void registerCallMethodWithFreeTypeVariables(Element element) { |
| 570 backend.registerCallMethodWithFreeTypeVariables( | 573 backend.registerCallMethodWithFreeTypeVariables( |
| 571 element, this, globalDependencies); | 574 element, this, globalDependencies); |
| 572 universe.callMethodsWithFreeTypeVariables.add(element); | |
|
Harry Terkelsen
2016/09/19 18:07:10
where is this being registered now?
Johnni Winther
2016/09/21 09:13:04
This and closurizedMembers below are only used in
| |
| 573 } | 575 } |
| 574 | 576 |
| 575 void registerClosurizedMember(TypedElement element) { | 577 void registerClosurizedMember(TypedElement element) { |
| 576 assert(element.isInstanceMember); | 578 assert(element.isInstanceMember); |
| 577 if (element.type.containsTypeVariables) { | 579 if (element.type.containsTypeVariables) { |
| 578 backend.registerClosureWithFreeTypeVariables( | 580 backend.registerClosureWithFreeTypeVariables( |
| 579 element, this, globalDependencies); | 581 element, this, globalDependencies); |
| 580 } | 582 } |
| 581 backend.registerBoundClosure(this); | 583 backend.registerBoundClosure(this); |
| 582 universe.closurizedMembers.add(element); | |
| 583 } | 584 } |
| 584 | 585 |
| 585 void forEach(void f(WorkItem work)) { | 586 void forEach(void f(WorkItem work)) { |
| 586 do { | 587 do { |
| 587 while (queue.isNotEmpty) { | 588 while (queue.isNotEmpty) { |
| 588 // TODO(johnniwinther): Find an optimal process order. | 589 // TODO(johnniwinther): Find an optimal process order. |
| 589 filter.processWorkItem(f, queue.removeLast()); | 590 filter.processWorkItem(f, queue.removeLast()); |
| 590 } | 591 } |
| 591 List recents = recentClasses.toList(growable: false); | 592 List recents = recentClasses.toList(growable: false); |
| 592 recentClasses.clear(); | 593 recentClasses.clear(); |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 605 } | 606 } |
| 606 | 607 |
| 607 void logSummary(log(message)) { | 608 void logSummary(log(message)) { |
| 608 _logSpecificSummary(log); | 609 _logSpecificSummary(log); |
| 609 nativeEnqueuer.logSummary(log); | 610 nativeEnqueuer.logSummary(log); |
| 610 } | 611 } |
| 611 | 612 |
| 612 String toString() => 'Enqueuer($name)'; | 613 String toString() => 'Enqueuer($name)'; |
| 613 | 614 |
| 614 void _forgetElement(Element element) { | 615 void _forgetElement(Element element) { |
| 615 universe.forgetElement(element, _compiler); | 616 _universe.forgetElement(element, _compiler); |
| 616 _processedClasses.remove(element); | 617 _processedClasses.remove(element); |
| 617 instanceMembersByName[element.name]?.remove(element); | 618 instanceMembersByName[element.name]?.remove(element); |
| 618 instanceFunctionsByName[element.name]?.remove(element); | 619 instanceFunctionsByName[element.name]?.remove(element); |
| 619 } | 620 } |
| 620 | 621 |
| 621 final Queue<CodegenWorkItem> queue; | 622 final Queue<CodegenWorkItem> queue; |
| 622 final Map<Element, js.Expression> generatedCode = <Element, js.Expression>{}; | 623 final Map<Element, js.Expression> generatedCode = <Element, js.Expression>{}; |
| 623 | 624 |
| 624 final Set<Element> newlyEnqueuedElements; | 625 final Set<Element> newlyEnqueuedElements; |
| 625 | 626 |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 700 @override | 701 @override |
| 701 void visitStaticUse(StaticUse staticUse) { | 702 void visitStaticUse(StaticUse staticUse) { |
| 702 enqueuer.registerStaticUse(staticUse); | 703 enqueuer.registerStaticUse(staticUse); |
| 703 } | 704 } |
| 704 | 705 |
| 705 @override | 706 @override |
| 706 void visitTypeUse(TypeUse typeUse) { | 707 void visitTypeUse(TypeUse typeUse) { |
| 707 enqueuer.registerTypeUse(typeUse); | 708 enqueuer.registerTypeUse(typeUse); |
| 708 } | 709 } |
| 709 } | 710 } |
| OLD | NEW |