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 part of dart2js; | 5 part of dart2js; |
6 | 6 |
7 typedef ItemCompilationContext ItemCompilationContextCreator(); | 7 typedef ItemCompilationContext ItemCompilationContextCreator(); |
8 | 8 |
9 class EnqueueTask extends CompilerTask { | 9 class EnqueueTask extends CompilerTask { |
10 final ResolutionEnqueuer resolution; | 10 final ResolutionEnqueuer resolution; |
11 final CodegenEnqueuer codegen; | 11 final CodegenEnqueuer codegen; |
12 | 12 |
13 /// A reverse map from name to *all* elements with that name, not | |
14 /// just instance members of instantiated classes. | |
15 final Map<String, Link<Element>> allElementsByName | |
16 = new Map<String, Link<Element>>(); | |
17 | |
18 void ensureAllElementsByName() { | |
19 if (!allElementsByName.isEmpty) return; | |
20 | |
21 void addMemberByName(Element element) { | |
22 element = element.declaration; | |
23 String name = element.name; | |
24 ScopeContainerElement container = null; | |
25 if (element.isLibrary) { | |
26 LibraryElement library = element; | |
27 container = library; | |
28 // TODO(ahe): Is this right? Is this necessary? | |
29 name = library.getLibraryOrScriptName(); | |
30 } else if (element.isClass) { | |
31 ClassElement cls = element; | |
32 cls.ensureResolved(compiler); | |
33 container = cls; | |
34 for (var link = cls.computeTypeParameters(compiler); | |
35 !link.isEmpty; | |
36 link = link.tail) { | |
37 addMemberByName(link.head.element); | |
38 } | |
39 } | |
40 allElementsByName[name] = allElementsByName.putIfAbsent( | |
41 name, () => const Link<Element>()).prepend(element); | |
42 if (container != null) { | |
43 container.forEachLocalMember(addMemberByName); | |
44 } | |
45 } | |
46 | |
47 compiler.libraryLoader.libraries.forEach(addMemberByName); | |
48 } | |
49 | |
50 String get name => 'Enqueue'; | 13 String get name => 'Enqueue'; |
51 | 14 |
52 EnqueueTask(Compiler compiler) | 15 EnqueueTask(Compiler compiler) |
53 : resolution = new ResolutionEnqueuer( | 16 : resolution = new ResolutionEnqueuer( |
54 compiler, compiler.backend.createItemCompilationContext), | 17 compiler, compiler.backend.createItemCompilationContext), |
55 codegen = new CodegenEnqueuer( | 18 codegen = new CodegenEnqueuer( |
56 compiler, compiler.backend.createItemCompilationContext), | 19 compiler, compiler.backend.createItemCompilationContext), |
57 super(compiler) { | 20 super(compiler) { |
58 codegen.task = this; | 21 codegen.task = this; |
59 resolution.task = this; | 22 resolution.task = this; |
60 | 23 |
61 codegen.nativeEnqueuer = compiler.backend.nativeCodegenEnqueuer(codegen); | 24 codegen.nativeEnqueuer = compiler.backend.nativeCodegenEnqueuer(codegen); |
62 resolution.nativeEnqueuer = | 25 resolution.nativeEnqueuer = |
63 compiler.backend.nativeResolutionEnqueuer(resolution); | 26 compiler.backend.nativeResolutionEnqueuer(resolution); |
64 } | 27 } |
65 } | 28 } |
66 | 29 |
67 abstract class Enqueuer { | 30 abstract class Enqueuer { |
68 final String name; | 31 final String name; |
69 final Compiler compiler; // TODO(ahe): Remove this dependency. | 32 final Compiler compiler; // TODO(ahe): Remove this dependency. |
70 final ItemCompilationContextCreator itemCompilationContextCreator; | 33 final ItemCompilationContextCreator itemCompilationContextCreator; |
71 final Map<String, Link<Element>> instanceMembersByName | 34 final Map<String, Link<Element>> instanceMembersByName |
72 = new Map<String, Link<Element>>(); | 35 = new Map<String, Link<Element>>(); |
73 final Map<String, Link<Element>> instanceFunctionsByName | 36 final Map<String, Link<Element>> instanceFunctionsByName |
74 = new Map<String, Link<Element>>(); | 37 = new Map<String, Link<Element>>(); |
75 final Set<ClassElement> seenClasses = new Set<ClassElement>(); | 38 final Set<ClassElement> seenClasses = new Set<ClassElement>(); |
| 39 Set<ClassElement> recentClasses = new Setlet<ClassElement>(); |
76 final Universe universe = new Universe(); | 40 final Universe universe = new Universe(); |
77 | 41 |
| 42 static final TRACE_MIRROR_ENQUEUING = |
| 43 const bool.fromEnvironment("TRACE_MIRROR_ENQUEUING"); |
| 44 |
78 bool queueIsClosed = false; | 45 bool queueIsClosed = false; |
79 EnqueueTask task; | 46 EnqueueTask task; |
80 native.NativeEnqueuer nativeEnqueuer; // Set by EnqueueTask | 47 native.NativeEnqueuer nativeEnqueuer; // Set by EnqueueTask |
81 | 48 |
82 bool hasEnqueuedEverything = false; | 49 bool hasEnqueuedReflectiveElements = false; |
83 bool hasEnqueuedReflectiveStaticFields = false; | 50 bool hasEnqueuedReflectiveStaticFields = false; |
84 | 51 |
85 Enqueuer(this.name, this.compiler, this.itemCompilationContextCreator); | 52 Enqueuer(this.name, this.compiler, this.itemCompilationContextCreator); |
86 | 53 |
87 Queue<WorkItem> get queue; | 54 Queue<WorkItem> get queue; |
88 bool get queueIsEmpty => queue.isEmpty; | 55 bool get queueIsEmpty => queue.isEmpty; |
89 | 56 |
90 /// Returns [:true:] if this enqueuer is the resolution enqueuer. | 57 /// Returns [:true:] if this enqueuer is the resolution enqueuer. |
91 bool get isResolutionQueue => false; | 58 bool get isResolutionQueue => false; |
92 | 59 |
93 /// Returns [:true:] if [member] has been processed by this enqueuer. | 60 /// Returns [:true:] if [member] has been processed by this enqueuer. |
94 bool isProcessed(Element member); | 61 bool isProcessed(Element member); |
95 | 62 |
96 /** | 63 /** |
97 * Documentation wanted -- johnniwinther | 64 * Documentation wanted -- johnniwinther |
98 * | 65 * |
99 * Invariant: [element] must be a declaration element. | 66 * Invariant: [element] must be a declaration element. |
100 */ | 67 */ |
101 void addToWorkList(Element element) { | 68 void addToWorkList(Element element) { |
102 assert(invariant(element, element.isDeclaration)); | 69 assert(invariant(element, element.isDeclaration)); |
103 internalAddToWorkList(element); | 70 internalAddToWorkList(element); |
104 } | 71 } |
105 | 72 |
106 /** | 73 /** |
107 * Adds [element] to the work list if it has not already been processed. | 74 * Adds [element] to the work list if it has not already been processed. |
108 */ | 75 */ |
109 void internalAddToWorkList(Element element); | 76 void internalAddToWorkList(Element element); |
110 | 77 |
111 void registerInstantiatedType(InterfaceType type, Registry registry) { | 78 void registerInstantiatedType(InterfaceType type, Registry registry, |
| 79 {mirrorUsage: false}) { |
112 task.measure(() { | 80 task.measure(() { |
113 ClassElement cls = type.element; | 81 ClassElement cls = type.element; |
114 registry.registerDependency(cls); | 82 registry.registerDependency(cls); |
115 cls.ensureResolved(compiler); | 83 cls.ensureResolved(compiler); |
116 universe.instantiatedTypes.add(type); | 84 universe.instantiatedTypes.add(type); |
117 if (!cls.isAbstract | 85 if (!cls.isAbstract |
118 // We can't use the closed-world assumption with native abstract | 86 // We can't use the closed-world assumption with native abstract |
119 // classes; a native abstract class may have non-abstract subclasses | 87 // classes; a native abstract class may have non-abstract subclasses |
120 // not declared to the program. Instances of these classes are | 88 // not declared to the program. Instances of these classes are |
121 // indistinguishable from the abstract class. | 89 // indistinguishable from the abstract class. |
122 || cls.isNative) { | 90 || cls.isNative |
| 91 // Likewise, if this registration comes from the mirror system, |
| 92 // all bets are off. |
| 93 // TODO(herhut): Track classes required by mirrors seperately. |
| 94 || mirrorUsage) { |
123 universe.instantiatedClasses.add(cls); | 95 universe.instantiatedClasses.add(cls); |
124 } | 96 } |
125 onRegisterInstantiatedClass(cls); | 97 onRegisterInstantiatedClass(cls); |
126 }); | 98 }); |
127 } | 99 } |
128 | 100 |
129 void registerInstantiatedClass(ClassElement cls, Registry registry) { | 101 void registerInstantiatedClass(ClassElement cls, Registry registry, |
| 102 {mirrorUsage: false}) { |
130 cls.ensureResolved(compiler); | 103 cls.ensureResolved(compiler); |
131 registerInstantiatedType(cls.rawType, registry); | 104 registerInstantiatedType(cls.rawType, registry, mirrorUsage: mirrorUsage); |
132 } | 105 } |
133 | 106 |
134 bool checkNoEnqueuedInvokedInstanceMethods() { | 107 bool checkNoEnqueuedInvokedInstanceMethods() { |
135 task.measure(() { | 108 task.measure(() { |
136 // Run through the classes and see if we need to compile methods. | 109 // Run through the classes and see if we need to compile methods. |
137 for (ClassElement classElement in universe.instantiatedClasses) { | 110 for (ClassElement classElement in universe.instantiatedClasses) { |
138 for (ClassElement currentClass = classElement; | 111 for (ClassElement currentClass = classElement; |
139 currentClass != null; | 112 currentClass != null; |
140 currentClass = currentClass.superclass) { | 113 currentClass = currentClass.superclass) { |
141 processInstantiatedClass(currentClass); | 114 processInstantiatedClass(currentClass); |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
253 task.measure(() { | 226 task.measure(() { |
254 if (seenClasses.contains(cls)) return; | 227 if (seenClasses.contains(cls)) return; |
255 // The class must be resolved to compute the set of all | 228 // The class must be resolved to compute the set of all |
256 // supertypes. | 229 // supertypes. |
257 cls.ensureResolved(compiler); | 230 cls.ensureResolved(compiler); |
258 | 231 |
259 void processClass(ClassElement cls) { | 232 void processClass(ClassElement cls) { |
260 if (seenClasses.contains(cls)) return; | 233 if (seenClasses.contains(cls)) return; |
261 | 234 |
262 seenClasses.add(cls); | 235 seenClasses.add(cls); |
| 236 recentClasses.add(cls); |
263 cls.ensureResolved(compiler); | 237 cls.ensureResolved(compiler); |
264 cls.implementation.forEachMember(processInstantiatedClassMember); | 238 cls.implementation.forEachMember(processInstantiatedClassMember); |
265 if (isResolutionQueue) { | 239 if (isResolutionQueue) { |
266 compiler.resolver.checkClass(cls); | 240 compiler.resolver.checkClass(cls); |
267 } | 241 } |
268 // We only tell the backend once that [cls] was instantiated, so | 242 // We only tell the backend once that [cls] was instantiated, so |
269 // any additional dependencies must be treated as global | 243 // any additional dependencies must be treated as global |
270 // dependencies. | 244 // dependencies. |
271 compiler.backend.registerInstantiatedClass( | 245 compiler.backend.registerInstantiatedClass( |
272 cls, this, compiler.globalDependencies); | 246 cls, this, compiler.globalDependencies); |
(...skipping 28 matching lines...) Expand all Loading... |
301 registerNewSelector(selector, universe.invokedGetters); | 275 registerNewSelector(selector, universe.invokedGetters); |
302 }); | 276 }); |
303 } | 277 } |
304 | 278 |
305 void registerInvokedSetter(Selector selector) { | 279 void registerInvokedSetter(Selector selector) { |
306 task.measure(() { | 280 task.measure(() { |
307 registerNewSelector(selector, universe.invokedSetters); | 281 registerNewSelector(selector, universe.invokedSetters); |
308 }); | 282 }); |
309 } | 283 } |
310 | 284 |
311 void pretendElementWasUsed(Element element, Registry registry) { | 285 /** |
312 if (!compiler.backend.isNeededForReflection(element)) return; | 286 * Decides whether an element should be included to satisfy requirements |
313 if (Elements.isUnresolved(element)) { | 287 * of the mirror system. [includedEnclosing] provides a hint whether the |
314 // Ignore. | 288 * enclosing element was included. |
315 } else if (element.isSynthesized | 289 * |
316 && element.library.isPlatformLibrary) { | 290 * The actual implementation depends on the current compiler phase. |
317 // TODO(ahe): Work-around for http://dartbug.com/11205. | 291 */ |
318 } else if (element.isConstructor) { | 292 bool shouldIncludeElementDueToMirrors(Element element, |
319 ClassElement cls = element.declaration.enclosingClass; | 293 {bool includedEnclosing}); |
320 registerInstantiatedType(cls.rawType, registry); | 294 |
321 registerStaticUse(element.declaration); | 295 void logEnqueueReflectiveAction(action, [msg = ""]) { |
322 } else if (element.isClass) { | 296 if (TRACE_MIRROR_ENQUEUING) { |
323 ClassElement cls = element.declaration; | 297 print("MIRROR_ENQUEUE (${isResolutionQueue ? "R" : "C"}): $action $msg"); |
324 registerInstantiatedClass(cls, registry); | 298 } |
325 // Make sure that even abstract classes are considered instantiated. | 299 } |
326 universe.instantiatedClasses.add(cls); | 300 |
327 } else if (element.impliesType) { | 301 /// Enqeue the constructor [ctor] if it is required for reflection. |
328 // Don't enqueue typedefs, and type variables. | 302 /// |
329 } else if (Elements.isStaticOrTopLevel(element)) { | 303 /// [enclosingWasIncluded] provides a hint whether the enclosing element was |
330 registerStaticUse(element.declaration); | 304 /// needed for reflection. |
331 } else if (element.isInstanceMember) { | 305 void enqueueReflectiveConstructor(ConstructorElement ctor, |
332 Selector selector = new Selector.fromElement(element, compiler); | 306 bool enclosingWasIncluded) { |
333 registerSelectorUse(selector); | 307 if (shouldIncludeElementDueToMirrors(ctor, |
334 if (element.isField) { | 308 includedEnclosing: enclosingWasIncluded)) { |
335 Selector selector = | 309 logEnqueueReflectiveAction(ctor); |
336 new Selector.setter(element.name, element.library); | 310 ClassElement cls = ctor.declaration.enclosingClass; |
337 registerInvokedSetter(selector); | 311 registerInstantiatedType(cls.rawType, compiler.mirrorDependencies, |
| 312 mirrorUsage: true); |
| 313 registerStaticUse(ctor.declaration); |
| 314 } |
| 315 } |
| 316 |
| 317 /// Enqeue the member [element] if it is required for reflection. |
| 318 /// |
| 319 /// [enclosingWasIncluded] provides a hint whether the enclosing element was |
| 320 /// needed for reflection. |
| 321 void enqueueReflectiveMember(Element element, bool enclosingWasIncluded) { |
| 322 if (shouldIncludeElementDueToMirrors(element, |
| 323 includedEnclosing: enclosingWasIncluded) |
| 324 // Do not enqueue typedefs. |
| 325 && !element.impliesType) { |
| 326 logEnqueueReflectiveAction(element); |
| 327 if (Elements.isStaticOrTopLevel(element)) { |
| 328 registerStaticUse(element.declaration); |
| 329 } else if (element.isInstanceMember) { |
| 330 // We need to enqueue all members matching this one in subclasses, as |
| 331 // well. |
| 332 // TODO(herhut): Use TypedSelector.subtype for enqueueing |
| 333 Selector selector = new Selector.fromElement(element, compiler); |
| 334 registerSelectorUse(selector); |
| 335 if (element.isField) { |
| 336 Selector selector = |
| 337 new Selector.setter(element.name, element.library); |
| 338 registerInvokedSetter(selector); |
| 339 } |
338 } | 340 } |
339 } | 341 } |
340 } | 342 } |
341 | 343 |
342 void enqueueEverything() { | 344 /// Enqeue the member [element] if it is required for reflection. |
343 if (hasEnqueuedEverything) return; | 345 /// |
344 compiler.log('Enqueuing everything'); | 346 /// [enclosingWasIncluded] provides a hint whether the enclosing element was |
345 task.ensureAllElementsByName(); | 347 /// needed for reflection. |
346 for (Link link in task.allElementsByName.values) { | 348 void enqueueReflectiveElementsInClass(ClassElement cls, |
347 for (Element element in link) { | 349 Iterable<ClassElement> recents, |
348 pretendElementWasUsed(element, compiler.mirrorDependencies); | 350 bool enclosingWasIncluded) { |
| 351 if (cls.library.isInternalLibrary || cls.isInjected) return; |
| 352 bool includeClass = shouldIncludeElementDueToMirrors(cls, |
| 353 includedEnclosing: enclosingWasIncluded); |
| 354 if (includeClass) { |
| 355 logEnqueueReflectiveAction(cls, "register"); |
| 356 ClassElement decl = cls.declaration; |
| 357 registerInstantiatedClass(decl, compiler.mirrorDependencies, |
| 358 mirrorUsage: true); |
| 359 } |
| 360 // If the class is never instantiated, we know nothing of it can possibly |
| 361 // be reflected upon. |
| 362 // TODO(herhut): Add a warning if a mirrors annotation cannot hit. |
| 363 if (recents.contains(cls.declaration)) { |
| 364 logEnqueueReflectiveAction(cls, "members"); |
| 365 cls.constructors.forEach((Element element) { |
| 366 enqueueReflectiveConstructor(element, includeClass); |
| 367 }); |
| 368 cls.forEachClassMember((Member member) { |
| 369 enqueueReflectiveMember(member.element, includeClass); |
| 370 }); |
| 371 } |
| 372 } |
| 373 |
| 374 /// Enqeue special classes that might not be visible by normal means or that |
| 375 /// would not normally be enqueued: |
| 376 /// |
| 377 /// [Closure] is treated specially as it is the superclass of all closures. |
| 378 /// Although it is in an internal library, we mark it as reflectable. Note |
| 379 /// that none of its methods are reflectable, unless reflectable by |
| 380 /// inheritance. |
| 381 void enqueueReflectiveSpecialClasses() { |
| 382 Iterable<ClassElement> classes = |
| 383 compiler.backend.classesRequiredForReflection; |
| 384 for (ClassElement cls in classes) { |
| 385 if (compiler.backend.referencedFromMirrorSystem(cls)) { |
| 386 logEnqueueReflectiveAction(cls); |
| 387 registerInstantiatedClass(cls, compiler.mirrorDependencies, |
| 388 mirrorUsage: true); |
349 } | 389 } |
350 } | 390 } |
351 hasEnqueuedEverything = true; | 391 } |
352 hasEnqueuedReflectiveStaticFields = true; | 392 |
| 393 /// Enqeue all local members of the library [lib] if they are required for |
| 394 /// reflection. |
| 395 void enqueueReflectiveElementsInLibrary(LibraryElement lib, |
| 396 Iterable<ClassElement> recents) { |
| 397 bool includeLibrary = shouldIncludeElementDueToMirrors(lib, |
| 398 includedEnclosing: false); |
| 399 lib.forEachLocalMember((Element member) { |
| 400 if (member.isClass) { |
| 401 enqueueReflectiveElementsInClass(member, recents, includeLibrary); |
| 402 } else { |
| 403 enqueueReflectiveMember(member, includeLibrary); |
| 404 } |
| 405 }); |
| 406 } |
| 407 |
| 408 /// Enqueue all elements that are matched by the mirrors used |
| 409 /// annotation or, in lack thereof, all elements. |
| 410 void enqueueReflectiveElements(Iterable<ClassElement> recents) { |
| 411 if (!hasEnqueuedReflectiveElements) { |
| 412 logEnqueueReflectiveAction("!START enqueueAll"); |
| 413 // First round of enqueuing, visit everything that is visible to |
| 414 // also pick up static top levels, etc. |
| 415 // Also, during the first round, consider all classes that have been seen |
| 416 // as recently seen, as we do not know how many rounds of resolution might |
| 417 // have run before tree shaking is disabled and thus everything is |
| 418 // enqueued. |
| 419 recents = seenClasses.toSet(); |
| 420 compiler.log('Enqueuing everything'); |
| 421 for (LibraryElement lib in compiler.libraryLoader.libraries) { |
| 422 enqueueReflectiveElementsInLibrary(lib, recents); |
| 423 } |
| 424 enqueueReflectiveSpecialClasses(); |
| 425 hasEnqueuedReflectiveElements = true; |
| 426 hasEnqueuedReflectiveStaticFields = true; |
| 427 logEnqueueReflectiveAction("!DONE enqueueAll"); |
| 428 } else if (recents.isNotEmpty) { |
| 429 // Keep looking at new classes until fixpoint is reached. |
| 430 logEnqueueReflectiveAction("!START enqueueRecents"); |
| 431 recents.forEach((ClassElement cls) { |
| 432 enqueueReflectiveElementsInClass(cls, recents, |
| 433 shouldIncludeElementDueToMirrors(cls.library, |
| 434 includedEnclosing: false)); |
| 435 }); |
| 436 logEnqueueReflectiveAction("!DONE enqueueRecents"); |
| 437 } |
353 } | 438 } |
354 | 439 |
355 /// Enqueue the static fields that have been marked as used by reflective | 440 /// Enqueue the static fields that have been marked as used by reflective |
356 /// usage through `MirrorsUsed`. | 441 /// usage through `MirrorsUsed`. |
357 void enqueueReflectiveStaticFields(Iterable<Element> elements) { | 442 void enqueueReflectiveStaticFields(Iterable<Element> elements) { |
358 if (hasEnqueuedReflectiveStaticFields) return; | 443 if (hasEnqueuedReflectiveStaticFields) return; |
359 hasEnqueuedReflectiveStaticFields = true; | 444 hasEnqueuedReflectiveStaticFields = true; |
360 for (Element element in elements) { | 445 for (Element element in elements) { |
361 pretendElementWasUsed(element, compiler.mirrorDependencies); | 446 enqueueReflectiveMember(element, true); |
362 } | 447 } |
363 } | 448 } |
364 | 449 |
365 processLink(Map<String, Link<Element>> map, | 450 processLink(Map<String, Link<Element>> map, |
366 String memberName, | 451 String memberName, |
367 bool f(Element e)) { | 452 bool f(Element e)) { |
368 Link<Element> members = map[memberName]; | 453 Link<Element> members = map[memberName]; |
369 if (members != null) { | 454 if (members != null) { |
370 // [f] might add elements to [: map[memberName] :] during the loop below | 455 // [f] might add elements to [: map[memberName] :] during the loop below |
371 // so we create a new list for [: map[memberName] :] and prepend the | 456 // so we create a new list for [: map[memberName] :] and prepend the |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
510 universe.closurizedMembers.add(element); | 595 universe.closurizedMembers.add(element); |
511 } | 596 } |
512 | 597 |
513 void registerIfGeneric(Element element, Registry registry) { | 598 void registerIfGeneric(Element element, Registry registry) { |
514 if (element.computeType(compiler).containsTypeVariables) { | 599 if (element.computeType(compiler).containsTypeVariables) { |
515 compiler.backend.registerGenericClosure(element, this, registry); | 600 compiler.backend.registerGenericClosure(element, this, registry); |
516 universe.genericClosures.add(element); | 601 universe.genericClosures.add(element); |
517 } | 602 } |
518 } | 603 } |
519 | 604 |
520 void registerClosure(Element element, Registry registry) { | 605 void registerClosure(FunctionElement element, Registry registry) { |
| 606 universe.allClosures.add(element); |
521 registerIfGeneric(element, registry); | 607 registerIfGeneric(element, registry); |
522 } | 608 } |
523 | 609 |
524 void forEach(f(WorkItem work)) { | 610 void forEach(f(WorkItem work)) { |
525 do { | 611 do { |
526 while (!queue.isEmpty) { | 612 while (queue.isNotEmpty) { |
527 // TODO(johnniwinther): Find an optimal process order. | 613 // TODO(johnniwinther): Find an optimal process order. |
528 f(queue.removeLast()); | 614 f(queue.removeLast()); |
529 } | 615 } |
530 onQueueEmpty(); | 616 List recents = recentClasses.toList(growable: false); |
531 } while (!queue.isEmpty); | 617 recentClasses.clear(); |
| 618 if (!onQueueEmpty(recents)) recentClasses.addAll(recents); |
| 619 } while (queue.isNotEmpty || recentClasses.isNotEmpty); |
532 } | 620 } |
533 | 621 |
534 void onQueueEmpty() { | 622 /// [onQueueEmpty] is called whenever the queue is drained. [recentClasses] |
535 compiler.backend.onQueueEmpty(this); | 623 /// contains the set of all classes seen for the first time since |
| 624 /// [onQueueEmpty] was called last. A return value of [true] indicates that |
| 625 /// the [recentClasses] have been processed and may be cleared. If [false] is |
| 626 /// returned, [onQueueEmpty] will be called once the queue is empty again (or |
| 627 /// still empty) and [recentClasses] will be a superset of the current value. |
| 628 bool onQueueEmpty(Iterable<ClassElement> recentClasses) { |
| 629 return compiler.backend.onQueueEmpty(this, recentClasses); |
536 } | 630 } |
537 | 631 |
538 void logSummary(log(message)) { | 632 void logSummary(log(message)) { |
539 _logSpecificSummary(log); | 633 _logSpecificSummary(log); |
540 nativeEnqueuer.logSummary(log); | 634 nativeEnqueuer.logSummary(log); |
541 } | 635 } |
542 | 636 |
543 /// Log summary specific to the concrete enqueuer. | 637 /// Log summary specific to the concrete enqueuer. |
544 void _logSpecificSummary(log(message)); | 638 void _logSpecificSummary(log(message)); |
545 | 639 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
585 resolvedElements.add(element); | 679 resolvedElements.add(element); |
586 } | 680 } |
587 | 681 |
588 /// Returns [:true:] if [element] has actually been used. | 682 /// Returns [:true:] if [element] has actually been used. |
589 bool isLive(Element element) { | 683 bool isLive(Element element) { |
590 if (seenClasses.contains(element)) return true; | 684 if (seenClasses.contains(element)) return true; |
591 if (hasBeenResolved(element)) return true; | 685 if (hasBeenResolved(element)) return true; |
592 return false; | 686 return false; |
593 } | 687 } |
594 | 688 |
| 689 /** |
| 690 * Decides whether an element should be included to satisfy requirements |
| 691 * of the mirror system. |
| 692 * |
| 693 * During resolution, we have to resort to matching elements against the |
| 694 * [MirrorsUsed] pattern, as we do not have a complete picture of the world, |
| 695 * yet. |
| 696 */ |
| 697 bool shouldIncludeElementDueToMirrors(Element element, |
| 698 {bool includedEnclosing}) { |
| 699 return includedEnclosing || compiler.backend.requiredByMirrorSystem(element)
; |
| 700 } |
| 701 |
595 void internalAddToWorkList(Element element) { | 702 void internalAddToWorkList(Element element) { |
596 assert(invariant(element, element is AnalyzableElement, | 703 assert(invariant(element, element is AnalyzableElement, |
597 message: 'Element $element is not analyzable.')); | 704 message: 'Element $element is not analyzable.')); |
598 if (hasBeenResolved(element)) return; | 705 if (hasBeenResolved(element)) return; |
599 if (queueIsClosed) { | 706 if (queueIsClosed) { |
600 throw new SpannableAssertionFailure(element, | 707 throw new SpannableAssertionFailure(element, |
601 "Resolution work list is closed. Trying to add $element."); | 708 "Resolution work list is closed. Trying to add $element."); |
602 } | 709 } |
603 | 710 |
604 compiler.world.registerUsedElement(element); | 711 compiler.world.registerUsedElement(element); |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
663 */ | 770 */ |
664 void addDeferredAction(Element element, DeferredAction action) { | 771 void addDeferredAction(Element element, DeferredAction action) { |
665 if (queueIsClosed) { | 772 if (queueIsClosed) { |
666 throw new SpannableAssertionFailure(element, | 773 throw new SpannableAssertionFailure(element, |
667 "Resolution work list is closed. " | 774 "Resolution work list is closed. " |
668 "Trying to add deferred action for $element"); | 775 "Trying to add deferred action for $element"); |
669 } | 776 } |
670 deferredTaskQueue.add(new DeferredTask(element, action)); | 777 deferredTaskQueue.add(new DeferredTask(element, action)); |
671 } | 778 } |
672 | 779 |
673 void onQueueEmpty() { | 780 bool onQueueEmpty(Iterable<ClassElement> recentClasses) { |
674 emptyDeferredTaskQueue(); | 781 emptyDeferredTaskQueue(); |
675 super.onQueueEmpty(); | 782 return super.onQueueEmpty(recentClasses); |
676 } | 783 } |
677 | 784 |
678 void emptyDeferredTaskQueue() { | 785 void emptyDeferredTaskQueue() { |
679 while (!deferredTaskQueue.isEmpty) { | 786 while (!deferredTaskQueue.isEmpty) { |
680 DeferredTask task = deferredTaskQueue.removeFirst(); | 787 DeferredTask task = deferredTaskQueue.removeFirst(); |
681 compiler.withCurrentElement(task.element, task.action); | 788 compiler.withCurrentElement(task.element, task.action); |
682 } | 789 } |
683 } | 790 } |
684 | 791 |
685 void registerJsCall(Send node, ResolverVisitor resolver) { | 792 void registerJsCall(Send node, ResolverVisitor resolver) { |
(...skipping 15 matching lines...) Expand all Loading... |
701 | 808 |
702 CodegenEnqueuer(Compiler compiler, | 809 CodegenEnqueuer(Compiler compiler, |
703 ItemCompilationContext itemCompilationContextCreator()) | 810 ItemCompilationContext itemCompilationContextCreator()) |
704 : queue = new Queue<CodegenWorkItem>(), | 811 : queue = new Queue<CodegenWorkItem>(), |
705 newlyEnqueuedElements = compiler.cacheStrategy.newSet(), | 812 newlyEnqueuedElements = compiler.cacheStrategy.newSet(), |
706 super('codegen enqueuer', compiler, itemCompilationContextCreator); | 813 super('codegen enqueuer', compiler, itemCompilationContextCreator); |
707 | 814 |
708 bool isProcessed(Element member) => | 815 bool isProcessed(Element member) => |
709 member.isAbstract || generatedCode.containsKey(member); | 816 member.isAbstract || generatedCode.containsKey(member); |
710 | 817 |
| 818 /** |
| 819 * Decides whether an element should be included to satisfy requirements |
| 820 * of the mirror system. |
| 821 * |
| 822 * For code generation, we rely on the precomputed set of elements that takes |
| 823 * subtyping constraints into account. |
| 824 */ |
| 825 bool shouldIncludeElementDueToMirrors(Element element, |
| 826 {bool includedEnclosing}) { |
| 827 return compiler.backend.isAccessibleByReflection(element); |
| 828 } |
| 829 |
711 void internalAddToWorkList(Element element) { | 830 void internalAddToWorkList(Element element) { |
712 if (compiler.hasIncrementalSupport) { | 831 if (compiler.hasIncrementalSupport) { |
713 newlyEnqueuedElements.add(element); | 832 newlyEnqueuedElements.add(element); |
714 } | 833 } |
715 // Don't generate code for foreign elements. | 834 // Don't generate code for foreign elements. |
716 if (element.isForeign(compiler)) return; | 835 if (element.isForeign(compiler)) return; |
717 | 836 |
718 // Codegen inlines field initializers. It only needs to generate | 837 // Codegen inlines field initializers. It only needs to generate |
719 // code for checked setters. | 838 // code for checked setters. |
720 if (element.isField && element.isInstanceMember) { | 839 if (element.isField && element.isInstanceMember) { |
721 if (!compiler.enableTypeAssertions | 840 if (!compiler.enableTypeAssertions |
722 || element.enclosingElement.isClosure) { | 841 || element.enclosingElement.isClosure) { |
723 return; | 842 return; |
724 } | 843 } |
725 } | 844 } |
726 | 845 |
727 if (queueIsClosed) { | 846 if (queueIsClosed) { |
728 throw new SpannableAssertionFailure(element, | 847 throw new SpannableAssertionFailure(element, |
729 "Codegen work list is closed. Trying to add $element"); | 848 "Codegen work list is closed. Trying to add $element"); |
730 } | 849 } |
731 CodegenWorkItem workItem = new CodegenWorkItem( | 850 CodegenWorkItem workItem = new CodegenWorkItem( |
732 element, itemCompilationContextCreator()); | 851 element, itemCompilationContextCreator()); |
733 queue.add(workItem); | 852 queue.add(workItem); |
734 } | 853 } |
735 | 854 |
736 void _logSpecificSummary(log(message)) { | 855 void _logSpecificSummary(log(message)) { |
737 log('Compiled ${generatedCode.length} methods.'); | 856 log('Compiled ${generatedCode.length} methods.'); |
738 } | 857 } |
739 } | 858 } |
OLD | NEW |