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 } else if (universe.hasInvokedSetter(member, _world)) { | 186 } else if (universe.hasInvokedSetter(member, _world)) { |
184 addToWorkList(member); | 187 addToWorkList(member); |
185 return; | 188 return; |
186 } | 189 } |
187 // Native fields need to go into instanceMembersByName as they | 190 // Native fields need to go into instanceMembersByName as they |
188 // are virtual instantiation points and escape points. | 191 // are virtual instantiation points and escape points. |
189 } else { | 192 } else { |
190 // All field initializers must be resolved as they could | 193 // All field initializers must be resolved as they could |
191 // have an observable side-effect (and cannot be tree-shaken | 194 // have an observable side-effect (and cannot be tree-shaken |
192 // away). | 195 // away). |
193 addToWorkList(member); | 196 addToWorkList(member); |
194 return; | 197 return; |
195 } | 198 } |
196 } else if (member.isFunction) { | 199 } else if (member.isFunction) { |
197 FunctionElement function = member; | 200 FunctionElement function = member; |
198 if (function.name == Identifiers.noSuchMethod_) { | 201 if (function.name == Identifiers.noSuchMethod_) { |
199 registerNoSuchMethod(function); | 202 registerNoSuchMethod(function); |
200 } | 203 } |
201 if (function.name == Identifiers.call && !cls.typeVariables.isEmpty) { | 204 if (function.name == Identifiers.call && !cls.typeVariables.isEmpty) { |
202 registerCallMethodWithFreeTypeVariables(function); | 205 registerCallMethodWithFreeTypeVariables(function); |
203 } | 206 } |
204 // If there is a property access with the same name as a method we | 207 // If there is a property access with the same name as a method we |
205 // need to emit the method. | 208 // need to emit the method. |
206 if (universe.hasInvokedGetter(function, _world)) { | 209 if (_universe.hasInvokedGetter(function, _world)) { |
207 registerClosurizedMember(function); | 210 registerClosurizedMember(function); |
208 addToWorkList(function); | 211 addToWorkList(function); |
209 return; | 212 return; |
210 } | 213 } |
211 // Store the member in [instanceFunctionsByName] to catch | 214 // Store the member in [instanceFunctionsByName] to catch |
212 // getters on the function. | 215 // getters on the function. |
213 instanceFunctionsByName | 216 instanceFunctionsByName |
214 .putIfAbsent(memberName, () => new Set<Element>()) | 217 .putIfAbsent(memberName, () => new Set<Element>()) |
215 .add(member); | 218 .add(member); |
216 if (universe.hasInvocation(function, _world)) { | 219 if (_universe.hasInvocation(function, _world)) { |
217 addToWorkList(function); | 220 addToWorkList(function); |
218 return; | 221 return; |
219 } | 222 } |
220 } else if (member.isGetter) { | 223 } else if (member.isGetter) { |
221 FunctionElement getter = member; | 224 FunctionElement getter = member; |
222 if (universe.hasInvokedGetter(getter, _world)) { | 225 if (_universe.hasInvokedGetter(getter, _world)) { |
223 addToWorkList(getter); | 226 addToWorkList(getter); |
224 return; | 227 return; |
225 } | 228 } |
226 // We don't know what selectors the returned closure accepts. If | 229 // We don't know what selectors the returned closure accepts. If |
227 // the set contains any selector we have to assume that it matches. | 230 // the set contains any selector we have to assume that it matches. |
228 if (universe.hasInvocation(getter, _world)) { | 231 if (_universe.hasInvocation(getter, _world)) { |
229 addToWorkList(getter); | 232 addToWorkList(getter); |
230 return; | 233 return; |
231 } | 234 } |
232 } else if (member.isSetter) { | 235 } else if (member.isSetter) { |
233 FunctionElement setter = member; | 236 FunctionElement setter = member; |
234 if (universe.hasInvokedSetter(setter, _world)) { | 237 if (_universe.hasInvokedSetter(setter, _world)) { |
235 addToWorkList(setter); | 238 addToWorkList(setter); |
236 return; | 239 return; |
237 } | 240 } |
238 } | 241 } |
239 | 242 |
240 // The element is not yet used. Add it to the list of instance | 243 // The element is not yet used. Add it to the list of instance |
241 // members to still be processed. | 244 // members to still be processed. |
242 instanceMembersByName | 245 instanceMembersByName |
243 .putIfAbsent(memberName, () => new Set<Element>()) | 246 .putIfAbsent(memberName, () => new Set<Element>()) |
244 .add(member); | 247 .add(member); |
(...skipping 28 matching lines...) Expand all Loading... |
273 ClassElement superclass = cls; | 276 ClassElement superclass = cls; |
274 while (superclass != null) { | 277 while (superclass != null) { |
275 processClass(superclass); | 278 processClass(superclass); |
276 superclass = superclass.superclass; | 279 superclass = superclass.superclass; |
277 } | 280 } |
278 }); | 281 }); |
279 } | 282 } |
280 | 283 |
281 void registerDynamicUse(DynamicUse dynamicUse) { | 284 void registerDynamicUse(DynamicUse dynamicUse) { |
282 task.measure(() { | 285 task.measure(() { |
283 if (universe.registerDynamicUse(dynamicUse)) { | 286 if (_universe.registerDynamicUse(dynamicUse)) { |
284 handleUnseenSelector(dynamicUse); | 287 handleUnseenSelector(dynamicUse); |
285 } | 288 } |
286 }); | 289 }); |
287 } | 290 } |
288 | 291 |
289 void logEnqueueReflectiveAction(action, [msg = ""]) { | 292 void logEnqueueReflectiveAction(action, [msg = ""]) { |
290 if (TRACE_MIRROR_ENQUEUING) { | 293 if (TRACE_MIRROR_ENQUEUING) { |
291 print("MIRROR_ENQUEUE (C): $action $msg"); | 294 print("MIRROR_ENQUEUE (C): $action $msg"); |
292 } | 295 } |
293 } | 296 } |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
502 * Invariant: [element] must be a declaration element. | 505 * Invariant: [element] must be a declaration element. |
503 */ | 506 */ |
504 void registerStaticUse(StaticUse staticUse) { | 507 void registerStaticUse(StaticUse staticUse) { |
505 strategy.processStaticUse(this, staticUse); | 508 strategy.processStaticUse(this, staticUse); |
506 } | 509 } |
507 | 510 |
508 void registerStaticUseInternal(StaticUse staticUse) { | 511 void registerStaticUseInternal(StaticUse staticUse) { |
509 Element element = staticUse.element; | 512 Element element = staticUse.element; |
510 assert(invariant(element, element.isDeclaration, | 513 assert(invariant(element, element.isDeclaration, |
511 message: "Element ${element} is not the declaration.")); | 514 message: "Element ${element} is not the declaration.")); |
512 universe.registerStaticUse(staticUse); | 515 _universe.registerStaticUse(staticUse); |
513 backend.registerStaticUse(element, this); | 516 backend.registerStaticUse(element, this); |
514 bool addElement = true; | 517 bool addElement = true; |
515 switch (staticUse.kind) { | 518 switch (staticUse.kind) { |
516 case StaticUseKind.STATIC_TEAR_OFF: | 519 case StaticUseKind.STATIC_TEAR_OFF: |
517 backend.registerGetOfStaticFunction(this); | 520 backend.registerGetOfStaticFunction(this); |
518 break; | 521 break; |
519 case StaticUseKind.FIELD_GET: | 522 case StaticUseKind.FIELD_GET: |
520 case StaticUseKind.FIELD_SET: | 523 case StaticUseKind.FIELD_SET: |
521 case StaticUseKind.CLOSURE: | 524 case StaticUseKind.CLOSURE: |
522 // TODO(johnniwinther): Avoid this. Currently [FIELD_GET] and | 525 // TODO(johnniwinther): Avoid this. Currently [FIELD_GET] and |
(...skipping 28 matching lines...) Expand all Loading... |
551 if (options.enableTypeAssertions) { | 554 if (options.enableTypeAssertions) { |
552 _registerIsCheck(type); | 555 _registerIsCheck(type); |
553 } | 556 } |
554 break; | 557 break; |
555 case TypeUseKind.TYPE_LITERAL: | 558 case TypeUseKind.TYPE_LITERAL: |
556 break; | 559 break; |
557 } | 560 } |
558 } | 561 } |
559 | 562 |
560 void _registerIsCheck(DartType type) { | 563 void _registerIsCheck(DartType type) { |
561 type = universe.registerIsCheck(type, _compiler); | 564 type = _universe.registerIsCheck(type, _compiler); |
562 // Even in checked mode, type annotations for return type and argument | 565 // Even in checked mode, type annotations for return type and argument |
563 // types do not imply type checks, so there should never be a check | 566 // types do not imply type checks, so there should never be a check |
564 // against the type variable of a typedef. | 567 // against the type variable of a typedef. |
565 assert(!type.isTypeVariable || !type.element.enclosingElement.isTypedef); | 568 assert(!type.isTypeVariable || !type.element.enclosingElement.isTypedef); |
566 } | 569 } |
567 | 570 |
568 void registerCallMethodWithFreeTypeVariables(Element element) { | 571 void registerCallMethodWithFreeTypeVariables(Element element) { |
569 backend.registerCallMethodWithFreeTypeVariables( | 572 backend.registerCallMethodWithFreeTypeVariables( |
570 element, this, globalDependencies); | 573 element, this, globalDependencies); |
571 universe.callMethodsWithFreeTypeVariables.add(element); | |
572 } | 574 } |
573 | 575 |
574 void registerClosurizedMember(TypedElement element) { | 576 void registerClosurizedMember(TypedElement element) { |
575 assert(element.isInstanceMember); | 577 assert(element.isInstanceMember); |
576 if (element.type.containsTypeVariables) { | 578 if (element.type.containsTypeVariables) { |
577 backend.registerClosureWithFreeTypeVariables( | 579 backend.registerClosureWithFreeTypeVariables( |
578 element, this, globalDependencies); | 580 element, this, globalDependencies); |
579 } | 581 } |
580 backend.registerBoundClosure(this); | 582 backend.registerBoundClosure(this); |
581 universe.closurizedMembers.add(element); | |
582 } | 583 } |
583 | 584 |
584 void forEach(void f(WorkItem work)) { | 585 void forEach(void f(WorkItem work)) { |
585 do { | 586 do { |
586 while (queue.isNotEmpty) { | 587 while (queue.isNotEmpty) { |
587 // TODO(johnniwinther): Find an optimal process order. | 588 // TODO(johnniwinther): Find an optimal process order. |
588 filter.processWorkItem(f, queue.removeLast()); | 589 filter.processWorkItem(f, queue.removeLast()); |
589 } | 590 } |
590 List recents = recentClasses.toList(growable: false); | 591 List recents = recentClasses.toList(growable: false); |
591 recentClasses.clear(); | 592 recentClasses.clear(); |
(...skipping 12 matching lines...) Expand all Loading... |
604 } | 605 } |
605 | 606 |
606 void logSummary(log(message)) { | 607 void logSummary(log(message)) { |
607 _logSpecificSummary(log); | 608 _logSpecificSummary(log); |
608 nativeEnqueuer.logSummary(log); | 609 nativeEnqueuer.logSummary(log); |
609 } | 610 } |
610 | 611 |
611 String toString() => 'Enqueuer($name)'; | 612 String toString() => 'Enqueuer($name)'; |
612 | 613 |
613 void _forgetElement(Element element) { | 614 void _forgetElement(Element element) { |
614 universe.forgetElement(element, _compiler); | 615 _universe.forgetElement(element, _compiler); |
615 _processedClasses.remove(element); | 616 _processedClasses.remove(element); |
616 instanceMembersByName[element.name]?.remove(element); | 617 instanceMembersByName[element.name]?.remove(element); |
617 instanceFunctionsByName[element.name]?.remove(element); | 618 instanceFunctionsByName[element.name]?.remove(element); |
618 } | 619 } |
619 | 620 |
620 final Queue<CodegenWorkItem> queue; | 621 final Queue<CodegenWorkItem> queue; |
621 final Map<Element, js.Expression> generatedCode = <Element, js.Expression>{}; | 622 final Map<Element, js.Expression> generatedCode = <Element, js.Expression>{}; |
622 | 623 |
623 final Set<Element> newlyEnqueuedElements; | 624 final Set<Element> newlyEnqueuedElements; |
624 | 625 |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
699 @override | 700 @override |
700 void visitStaticUse(StaticUse staticUse) { | 701 void visitStaticUse(StaticUse staticUse) { |
701 enqueuer.registerStaticUse(staticUse); | 702 enqueuer.registerStaticUse(staticUse); |
702 } | 703 } |
703 | 704 |
704 @override | 705 @override |
705 void visitTypeUse(TypeUse typeUse) { | 706 void visitTypeUse(TypeUse typeUse) { |
706 enqueuer.registerTypeUse(typeUse); | 707 enqueuer.registerTypeUse(typeUse); |
707 } | 708 } |
708 } | 709 } |
OLD | NEW |