Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(108)

Side by Side Diff: sdk/lib/_internal/compiler/implementation/enqueue.dart

Issue 694353007: Move dart2js from sdk/lib/_internal/compiler to pkg/compiler (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 part of dart2js;
6
7 typedef ItemCompilationContext ItemCompilationContextCreator();
8
9 class EnqueueTask extends CompilerTask {
10 final ResolutionEnqueuer resolution;
11 final CodegenEnqueuer codegen;
12
13 String get name => 'Enqueue';
14
15 EnqueueTask(Compiler compiler)
16 : resolution = new ResolutionEnqueuer(
17 compiler, compiler.backend.createItemCompilationContext),
18 codegen = new CodegenEnqueuer(
19 compiler, compiler.backend.createItemCompilationContext),
20 super(compiler) {
21 codegen.task = this;
22 resolution.task = this;
23
24 codegen.nativeEnqueuer = compiler.backend.nativeCodegenEnqueuer(codegen);
25 resolution.nativeEnqueuer =
26 compiler.backend.nativeResolutionEnqueuer(resolution);
27 }
28
29 void forgetElement(Element element) {
30 resolution.forgetElement(element);
31 codegen.forgetElement(element);
32 }
33 }
34
35 abstract class Enqueuer {
36 final String name;
37 final Compiler compiler; // TODO(ahe): Remove this dependency.
38 final ItemCompilationContextCreator itemCompilationContextCreator;
39 final Map<String, Set<Element>> instanceMembersByName
40 = new Map<String, Set<Element>>();
41 final Map<String, Set<Element>> instanceFunctionsByName
42 = new Map<String, Set<Element>>();
43 final Set<ClassElement> _processedClasses = new Set<ClassElement>();
44 Set<ClassElement> recentClasses = new Setlet<ClassElement>();
45 final Universe universe = new Universe();
46
47 static final TRACE_MIRROR_ENQUEUING =
48 const bool.fromEnvironment("TRACE_MIRROR_ENQUEUING");
49
50 bool queueIsClosed = false;
51 EnqueueTask task;
52 native.NativeEnqueuer nativeEnqueuer; // Set by EnqueueTask
53
54 bool hasEnqueuedReflectiveElements = false;
55 bool hasEnqueuedReflectiveStaticFields = false;
56
57 Enqueuer(this.name, this.compiler, this.itemCompilationContextCreator);
58
59 Queue<WorkItem> get queue;
60 bool get queueIsEmpty => queue.isEmpty;
61
62 /// Returns [:true:] if this enqueuer is the resolution enqueuer.
63 bool get isResolutionQueue => false;
64
65 QueueFilter get filter => compiler.enqueuerFilter;
66
67 /// Returns [:true:] if [member] has been processed by this enqueuer.
68 bool isProcessed(Element member);
69
70 /**
71 * Documentation wanted -- johnniwinther
72 *
73 * Invariant: [element] must be a declaration element.
74 */
75 void addToWorkList(Element element) {
76 assert(invariant(element, element.isDeclaration));
77 internalAddToWorkList(element);
78 }
79
80 /**
81 * Adds [element] to the work list if it has not already been processed.
82 *
83 * Returns [true] if the element was actually added to the queue.
84 */
85 bool internalAddToWorkList(Element element);
86
87 void registerInstantiatedType(InterfaceType type, Registry registry,
88 {bool mirrorUsage: false}) {
89 task.measure(() {
90 ClassElement cls = type.element;
91 registry.registerDependency(cls);
92 cls.ensureResolved(compiler);
93 universe.registerTypeInstantiation(type, byMirrors: mirrorUsage);
94 processInstantiatedClass(cls);
95 });
96 }
97
98 void registerInstantiatedClass(ClassElement cls, Registry registry,
99 {bool mirrorUsage: false}) {
100 cls.ensureResolved(compiler);
101 registerInstantiatedType(cls.rawType, registry, mirrorUsage: mirrorUsage);
102 }
103
104 bool checkNoEnqueuedInvokedInstanceMethods() {
105 return filter.checkNoEnqueuedInvokedInstanceMethods(this);
106 }
107
108 void processInstantiatedClassMembers(ClassElement cls) {
109 cls.implementation.forEachMember(processInstantiatedClassMember);
110 }
111
112 void processInstantiatedClassMember(ClassElement cls, Element member) {
113 assert(invariant(member, member.isDeclaration));
114 if (isProcessed(member)) return;
115 if (!member.isInstanceMember) return;
116
117 String memberName = member.name;
118
119 if (member.kind == ElementKind.FIELD) {
120 // The obvious thing to test here would be "member.isNative",
121 // however, that only works after metadata has been parsed/analyzed,
122 // and that may not have happened yet.
123 // So instead we use the enclosing class, which we know have had
124 // its metadata parsed and analyzed.
125 // Note: this assumes that there are no non-native fields on native
126 // classes, which may not be the case when a native class is subclassed.
127 if (cls.isNative) {
128 compiler.world.registerUsedElement(member);
129 nativeEnqueuer.handleFieldAnnotations(member);
130 if (universe.hasInvokedGetter(member, compiler.world) ||
131 universe.hasInvocation(member, compiler.world)) {
132 nativeEnqueuer.registerFieldLoad(member);
133 // In handleUnseenSelector we can't tell if the field is loaded or
134 // stored. We need the basic algorithm to be Church-Rosser, since the
135 // resolution 'reduction' order is different to the codegen order. So
136 // register that the field is also stored. In other words: if we
137 // don't register the store here during resolution, the store could be
138 // registered during codegen on the handleUnseenSelector path, and
139 // cause the set of codegen elements to include unresolved elements.
140 nativeEnqueuer.registerFieldStore(member);
141 addToWorkList(member);
142 return;
143 }
144 if (universe.hasInvokedSetter(member, compiler.world)) {
145 nativeEnqueuer.registerFieldStore(member);
146 // See comment after registerFieldLoad above.
147 nativeEnqueuer.registerFieldLoad(member);
148 addToWorkList(member);
149 return;
150 }
151 // Native fields need to go into instanceMembersByName as they
152 // are virtual instantiation points and escape points.
153 } else {
154 // All field initializers must be resolved as they could
155 // have an observable side-effect (and cannot be tree-shaken
156 // away).
157 addToWorkList(member);
158 return;
159 }
160 } else if (member.kind == ElementKind.FUNCTION) {
161 FunctionElement function = member;
162 function.computeSignature(compiler);
163 if (function.name == Compiler.NO_SUCH_METHOD) {
164 enableNoSuchMethod(function);
165 }
166 if (function.name == Compiler.CALL_OPERATOR_NAME &&
167 !cls.typeVariables.isEmpty) {
168 registerCallMethodWithFreeTypeVariables(
169 function, compiler.globalDependencies);
170 }
171 // If there is a property access with the same name as a method we
172 // need to emit the method.
173 if (universe.hasInvokedGetter(function, compiler.world)) {
174 registerClosurizedMember(function, compiler.globalDependencies);
175 addToWorkList(function);
176 return;
177 }
178 // Store the member in [instanceFunctionsByName] to catch
179 // getters on the function.
180 instanceFunctionsByName.putIfAbsent(memberName, () => new Set<Element>())
181 .add(member);
182 if (universe.hasInvocation(function, compiler.world)) {
183 addToWorkList(function);
184 return;
185 }
186 } else if (member.kind == ElementKind.GETTER) {
187 FunctionElement getter = member;
188 getter.computeSignature(compiler);
189 if (universe.hasInvokedGetter(getter, compiler.world)) {
190 addToWorkList(getter);
191 return;
192 }
193 // We don't know what selectors the returned closure accepts. If
194 // the set contains any selector we have to assume that it matches.
195 if (universe.hasInvocation(getter, compiler.world)) {
196 addToWorkList(getter);
197 return;
198 }
199 } else if (member.kind == ElementKind.SETTER) {
200 FunctionElement setter = member;
201 setter.computeSignature(compiler);
202 if (universe.hasInvokedSetter(setter, compiler.world)) {
203 addToWorkList(setter);
204 return;
205 }
206 }
207
208 // The element is not yet used. Add it to the list of instance
209 // members to still be processed.
210 instanceMembersByName.putIfAbsent(memberName, () => new Set<Element>())
211 .add(member);
212 }
213
214 void enableNoSuchMethod(Element element) {}
215 void enableIsolateSupport() {}
216
217 void processInstantiatedClass(ClassElement cls) {
218 task.measure(() {
219 if (_processedClasses.contains(cls)) return;
220 // The class must be resolved to compute the set of all
221 // supertypes.
222 cls.ensureResolved(compiler);
223
224 void processClass(ClassElement cls) {
225 if (_processedClasses.contains(cls)) return;
226
227 _processedClasses.add(cls);
228 recentClasses.add(cls);
229 cls.ensureResolved(compiler);
230 cls.implementation.forEachMember(processInstantiatedClassMember);
231 if (isResolutionQueue) {
232 compiler.resolver.checkClass(cls);
233 }
234 // We only tell the backend once that [cls] was instantiated, so
235 // any additional dependencies must be treated as global
236 // dependencies.
237 compiler.backend.registerInstantiatedClass(
238 cls, this, compiler.globalDependencies);
239 }
240 processClass(cls);
241 for (Link<DartType> supertypes = cls.allSupertypes;
242 !supertypes.isEmpty; supertypes = supertypes.tail) {
243 processClass(supertypes.head.element);
244 }
245 });
246 }
247
248 void registerNewSelector(Selector selector,
249 Map<String, Set<Selector>> selectorsMap) {
250 String name = selector.name;
251 Set<Selector> selectors =
252 selectorsMap.putIfAbsent(name, () => new Setlet<Selector>());
253 if (!selectors.contains(selector)) {
254 selectors.add(selector);
255 handleUnseenSelector(name, selector);
256 }
257 }
258
259 void registerInvocation(Selector selector) {
260 task.measure(() {
261 registerNewSelector(selector, universe.invokedNames);
262 });
263 }
264
265 void registerInvokedGetter(Selector selector) {
266 task.measure(() {
267 registerNewSelector(selector, universe.invokedGetters);
268 });
269 }
270
271 void registerInvokedSetter(Selector selector) {
272 task.measure(() {
273 registerNewSelector(selector, universe.invokedSetters);
274 });
275 }
276
277 /**
278 * Decides whether an element should be included to satisfy requirements
279 * of the mirror system. [includedEnclosing] provides a hint whether the
280 * enclosing element was included.
281 *
282 * The actual implementation depends on the current compiler phase.
283 */
284 bool shouldIncludeElementDueToMirrors(Element element,
285 {bool includedEnclosing});
286
287 void logEnqueueReflectiveAction(action, [msg = ""]) {
288 if (TRACE_MIRROR_ENQUEUING) {
289 print("MIRROR_ENQUEUE (${isResolutionQueue ? "R" : "C"}): $action $msg");
290 }
291 }
292
293 /// Enqeue the constructor [ctor] if it is required for reflection.
294 ///
295 /// [enclosingWasIncluded] provides a hint whether the enclosing element was
296 /// needed for reflection.
297 void enqueueReflectiveConstructor(ConstructorElement ctor,
298 bool enclosingWasIncluded) {
299 if (shouldIncludeElementDueToMirrors(ctor,
300 includedEnclosing: enclosingWasIncluded)) {
301 logEnqueueReflectiveAction(ctor);
302 ClassElement cls = ctor.declaration.enclosingClass;
303 registerInstantiatedType(cls.rawType, compiler.mirrorDependencies,
304 mirrorUsage: true);
305 registerStaticUse(ctor.declaration);
306 }
307 }
308
309 /// Enqeue the member [element] if it is required for reflection.
310 ///
311 /// [enclosingWasIncluded] provides a hint whether the enclosing element was
312 /// needed for reflection.
313 void enqueueReflectiveMember(Element element, bool enclosingWasIncluded) {
314 if (shouldIncludeElementDueToMirrors(element,
315 includedEnclosing: enclosingWasIncluded)) {
316 logEnqueueReflectiveAction(element);
317 if (element.isTypedef) {
318 TypedefElement typedef = element;
319 typedef.ensureResolved(compiler);
320 compiler.world.allTypedefs.add(element);
321 } else if (Elements.isStaticOrTopLevel(element)) {
322 registerStaticUse(element.declaration);
323 } else if (element.isInstanceMember) {
324 // We need to enqueue all members matching this one in subclasses, as
325 // well.
326 // TODO(herhut): Use TypedSelector.subtype for enqueueing
327 Selector selector = new Selector.fromElement(element);
328 registerSelectorUse(selector);
329 if (element.isField) {
330 Selector selector =
331 new Selector.setter(element.name, element.library);
332 registerInvokedSetter(selector);
333 }
334 }
335 }
336 }
337
338 /// Enqeue the member [element] if it is required for reflection.
339 ///
340 /// [enclosingWasIncluded] provides a hint whether the enclosing element was
341 /// needed for reflection.
342 void enqueueReflectiveElementsInClass(ClassElement cls,
343 Iterable<ClassElement> recents,
344 bool enclosingWasIncluded) {
345 if (cls.library.isInternalLibrary || cls.isInjected) return;
346 bool includeClass = shouldIncludeElementDueToMirrors(cls,
347 includedEnclosing: enclosingWasIncluded);
348 if (includeClass) {
349 logEnqueueReflectiveAction(cls, "register");
350 ClassElement decl = cls.declaration;
351 registerInstantiatedClass(decl, compiler.mirrorDependencies,
352 mirrorUsage: true);
353 }
354 // If the class is never instantiated, we know nothing of it can possibly
355 // be reflected upon.
356 // TODO(herhut): Add a warning if a mirrors annotation cannot hit.
357 if (recents.contains(cls.declaration)) {
358 logEnqueueReflectiveAction(cls, "members");
359 cls.constructors.forEach((Element element) {
360 enqueueReflectiveConstructor(element, includeClass);
361 });
362 cls.forEachClassMember((Member member) {
363 enqueueReflectiveMember(member.element, includeClass);
364 });
365 }
366 }
367
368 /// Enqeue special classes that might not be visible by normal means or that
369 /// would not normally be enqueued:
370 ///
371 /// [Closure] is treated specially as it is the superclass of all closures.
372 /// Although it is in an internal library, we mark it as reflectable. Note
373 /// that none of its methods are reflectable, unless reflectable by
374 /// inheritance.
375 void enqueueReflectiveSpecialClasses() {
376 Iterable<ClassElement> classes =
377 compiler.backend.classesRequiredForReflection;
378 for (ClassElement cls in classes) {
379 if (compiler.backend.referencedFromMirrorSystem(cls)) {
380 logEnqueueReflectiveAction(cls);
381 registerInstantiatedClass(cls, compiler.mirrorDependencies,
382 mirrorUsage: true);
383 }
384 }
385 }
386
387 /// Enqeue all local members of the library [lib] if they are required for
388 /// reflection.
389 void enqueueReflectiveElementsInLibrary(LibraryElement lib,
390 Iterable<ClassElement> recents) {
391 bool includeLibrary = shouldIncludeElementDueToMirrors(lib,
392 includedEnclosing: false);
393 lib.forEachLocalMember((Element member) {
394 if (member.isClass) {
395 enqueueReflectiveElementsInClass(member, recents, includeLibrary);
396 } else {
397 enqueueReflectiveMember(member, includeLibrary);
398 }
399 });
400 }
401
402 /// Enqueue all elements that are matched by the mirrors used
403 /// annotation or, in lack thereof, all elements.
404 void enqueueReflectiveElements(Iterable<ClassElement> recents) {
405 if (!hasEnqueuedReflectiveElements) {
406 logEnqueueReflectiveAction("!START enqueueAll");
407 // First round of enqueuing, visit everything that is visible to
408 // also pick up static top levels, etc.
409 // Also, during the first round, consider all classes that have been seen
410 // as recently seen, as we do not know how many rounds of resolution might
411 // have run before tree shaking is disabled and thus everything is
412 // enqueued.
413 recents = _processedClasses.toSet();
414 compiler.log('Enqueuing everything');
415 for (LibraryElement lib in compiler.libraryLoader.libraries) {
416 enqueueReflectiveElementsInLibrary(lib, recents);
417 }
418 enqueueReflectiveSpecialClasses();
419 hasEnqueuedReflectiveElements = true;
420 hasEnqueuedReflectiveStaticFields = true;
421 logEnqueueReflectiveAction("!DONE enqueueAll");
422 } else if (recents.isNotEmpty) {
423 // Keep looking at new classes until fixpoint is reached.
424 logEnqueueReflectiveAction("!START enqueueRecents");
425 recents.forEach((ClassElement cls) {
426 enqueueReflectiveElementsInClass(cls, recents,
427 shouldIncludeElementDueToMirrors(cls.library,
428 includedEnclosing: false));
429 });
430 logEnqueueReflectiveAction("!DONE enqueueRecents");
431 }
432 }
433
434 /// Enqueue the static fields that have been marked as used by reflective
435 /// usage through `MirrorsUsed`.
436 void enqueueReflectiveStaticFields(Iterable<Element> elements) {
437 if (hasEnqueuedReflectiveStaticFields) return;
438 hasEnqueuedReflectiveStaticFields = true;
439 for (Element element in elements) {
440 enqueueReflectiveMember(element, true);
441 }
442 }
443
444 void processSet(
445 Map<String, Set<Element>> map,
446 String memberName,
447 bool f(Element e)) {
448 Set<Element> members = map[memberName];
449 if (members == null) return;
450 // [f] might add elements to [: map[memberName] :] during the loop below
451 // so we create a new list for [: map[memberName] :] and prepend the
452 // [remaining] members after the loop.
453 map[memberName] = new Set<Element>();
454 Set<Element> remaining = new Set<Element>();
455 for (Element member in members) {
456 if (!f(member)) remaining.add(member);
457 }
458 map[memberName].addAll(remaining);
459 }
460
461 processInstanceMembers(String n, bool f(Element e)) {
462 processSet(instanceMembersByName, n, f);
463 }
464
465 processInstanceFunctions(String n, bool f(Element e)) {
466 processSet(instanceFunctionsByName, n, f);
467 }
468
469 void handleUnseenSelector(String methodName, Selector selector) {
470 processInstanceMembers(methodName, (Element member) {
471 if (selector.appliesUnnamed(member, compiler.world)) {
472 if (member.isFunction && selector.isGetter) {
473 registerClosurizedMember(member, compiler.globalDependencies);
474 }
475 if (member.isField && member.enclosingClass.isNative) {
476 if (selector.isGetter || selector.isCall) {
477 nativeEnqueuer.registerFieldLoad(member);
478 // We have to also handle storing to the field because we only get
479 // one look at each member and there might be a store we have not
480 // seen yet.
481 // TODO(sra): Process fields for storing separately.
482 nativeEnqueuer.registerFieldStore(member);
483 } else {
484 assert(selector.isSetter);
485 nativeEnqueuer.registerFieldStore(member);
486 // We have to also handle loading from the field because we only get
487 // one look at each member and there might be a load we have not
488 // seen yet.
489 // TODO(sra): Process fields for storing separately.
490 nativeEnqueuer.registerFieldLoad(member);
491 }
492 }
493 addToWorkList(member);
494 return true;
495 }
496 return false;
497 });
498 if (selector.isGetter) {
499 processInstanceFunctions(methodName, (Element member) {
500 if (selector.appliesUnnamed(member, compiler.world)) {
501 registerClosurizedMember(member, compiler.globalDependencies);
502 return true;
503 }
504 return false;
505 });
506 }
507 }
508
509 /**
510 * Documentation wanted -- johnniwinther
511 *
512 * Invariant: [element] must be a declaration element.
513 */
514 void registerStaticUse(Element element) {
515 if (element == null) return;
516 assert(invariant(element, element.isDeclaration));
517 addToWorkList(element);
518 compiler.backend.registerStaticUse(element, this);
519 }
520
521 void registerGetOfStaticFunction(FunctionElement element) {
522 registerStaticUse(element);
523 compiler.backend.registerGetOfStaticFunction(this);
524 universe.staticFunctionsNeedingGetter.add(element);
525 }
526
527 void registerDynamicInvocation(Selector selector) {
528 assert(selector != null);
529 registerInvocation(selector);
530 }
531
532 void registerSelectorUse(Selector selector) {
533 if (selector.isGetter) {
534 registerInvokedGetter(selector);
535 } else if (selector.isSetter) {
536 registerInvokedSetter(selector);
537 } else {
538 registerInvocation(selector);
539 }
540 }
541
542 void registerDynamicGetter(Selector selector) {
543 registerInvokedGetter(selector);
544 }
545
546 void registerDynamicSetter(Selector selector) {
547 registerInvokedSetter(selector);
548 }
549
550 void registerGetterForSuperMethod(Element element) {
551 universe.methodsNeedingSuperGetter.add(element);
552 }
553
554 void registerFieldGetter(Element element) {
555 universe.fieldGetters.add(element);
556 }
557
558 void registerFieldSetter(Element element) {
559 universe.fieldSetters.add(element);
560 }
561
562 void registerIsCheck(DartType type, Registry registry) {
563 type = universe.registerIsCheck(type, compiler);
564 // Even in checked mode, type annotations for return type and argument
565 // types do not imply type checks, so there should never be a check
566 // against the type variable of a typedef.
567 assert(type.kind != TypeKind.TYPE_VARIABLE ||
568 !type.element.enclosingElement.isTypedef);
569 }
570
571 /**
572 * If a factory constructor is used with type arguments, we lose track
573 * which arguments could be used to create instances of classes that use their
574 * type variables as expressions, so we have to remember if we saw such a use.
575 */
576 void registerFactoryWithTypeArguments(Registry registry) {
577 universe.usingFactoryWithTypeArguments = true;
578 }
579
580 void registerCallMethodWithFreeTypeVariables(
581 Element element,
582 Registry registry) {
583 compiler.backend.registerCallMethodWithFreeTypeVariables(
584 element, this, registry);
585 universe.callMethodsWithFreeTypeVariables.add(element);
586 }
587
588 void registerClosurizedMember(Element element, Registry registry) {
589 assert(element.isInstanceMember);
590 registerClosureIfFreeTypeVariables(element, registry);
591 compiler.backend.registerBoundClosure(this);
592 universe.closurizedMembers.add(element);
593 }
594
595 void registerClosureIfFreeTypeVariables(Element element, Registry registry) {
596 if (element.computeType(compiler).containsTypeVariables) {
597 compiler.backend.registerClosureWithFreeTypeVariables(
598 element, this, registry);
599 universe.closuresWithFreeTypeVariables.add(element);
600 }
601 }
602
603 void registerClosure(LocalFunctionElement element, Registry registry) {
604 universe.allClosures.add(element);
605 registerClosureIfFreeTypeVariables(element, registry);
606 }
607
608 void forEach(void f(WorkItem work)) {
609 do {
610 while (queue.isNotEmpty) {
611 // TODO(johnniwinther): Find an optimal process order.
612 filter.processWorkItem(f, queue.removeLast());
613 }
614 List recents = recentClasses.toList(growable: false);
615 recentClasses.clear();
616 if (!onQueueEmpty(recents)) recentClasses.addAll(recents);
617 } while (queue.isNotEmpty || recentClasses.isNotEmpty);
618 }
619
620 /// [onQueueEmpty] is called whenever the queue is drained. [recentClasses]
621 /// contains the set of all classes seen for the first time since
622 /// [onQueueEmpty] was called last. A return value of [true] indicates that
623 /// the [recentClasses] have been processed and may be cleared. If [false] is
624 /// returned, [onQueueEmpty] will be called once the queue is empty again (or
625 /// still empty) and [recentClasses] will be a superset of the current value.
626 bool onQueueEmpty(Iterable<ClassElement> recentClasses) {
627 return compiler.backend.onQueueEmpty(this, recentClasses);
628 }
629
630 void logSummary(log(message)) {
631 _logSpecificSummary(log);
632 nativeEnqueuer.logSummary(log);
633 }
634
635 /// Log summary specific to the concrete enqueuer.
636 void _logSpecificSummary(log(message));
637
638 String toString() => 'Enqueuer($name)';
639
640 void forgetElement(Element element) {
641 universe.forgetElement(element, compiler);
642 _processedClasses.remove(element);
643 }
644 }
645
646 /// [Enqueuer] which is specific to resolution.
647 class ResolutionEnqueuer extends Enqueuer {
648 /**
649 * Map from declaration elements to the [TreeElements] object holding the
650 * resolution mapping for the element implementation.
651 *
652 * Invariant: Key elements are declaration elements.
653 */
654 final Set<AstElement> resolvedElements;
655
656 final Queue<ResolutionWorkItem> queue;
657
658 /**
659 * A deferred task queue for the resolution phase which is processed
660 * when the resolution queue has been emptied.
661 */
662 final Queue<DeferredTask> deferredTaskQueue;
663
664 ResolutionEnqueuer(Compiler compiler,
665 ItemCompilationContext itemCompilationContextCreator())
666 : super('resolution enqueuer', compiler, itemCompilationContextCreator),
667 resolvedElements = new Set<AstElement>(),
668 queue = new Queue<ResolutionWorkItem>(),
669 deferredTaskQueue = new Queue<DeferredTask>();
670
671 bool get isResolutionQueue => true;
672
673 bool isProcessed(Element member) => resolvedElements.contains(member);
674
675 /// Returns `true` if [element] has been processed by the resolution enqueuer.
676 bool hasBeenResolved(Element element) {
677 return resolvedElements.contains(element.analyzableElement.declaration);
678 }
679
680 /// Registers [element] as resolved for the resolution enqueuer.
681 void registerResolvedElement(AstElement element) {
682 resolvedElements.add(element);
683 }
684
685 /**
686 * Decides whether an element should be included to satisfy requirements
687 * of the mirror system.
688 *
689 * During resolution, we have to resort to matching elements against the
690 * [MirrorsUsed] pattern, as we do not have a complete picture of the world,
691 * yet.
692 */
693 bool shouldIncludeElementDueToMirrors(Element element,
694 {bool includedEnclosing}) {
695 return includedEnclosing || compiler.backend.requiredByMirrorSystem(element) ;
696 }
697
698 bool internalAddToWorkList(Element element) {
699 assert(invariant(element, element is AnalyzableElement,
700 message: 'Element $element is not analyzable.'));
701 if (hasBeenResolved(element)) return false;
702 if (queueIsClosed) {
703 throw new SpannableAssertionFailure(element,
704 "Resolution work list is closed. Trying to add $element.");
705 }
706
707 compiler.world.registerUsedElement(element);
708
709 queue.add(new ResolutionWorkItem(element, itemCompilationContextCreator()));
710
711 // Enable isolate support if we start using something from the isolate
712 // library, or timers for the async library. We exclude constant fields,
713 // which are ending here because their initializing expression is compiled.
714 LibraryElement library = element.library;
715 if (!compiler.hasIsolateSupport &&
716 (!element.isField || !element.isConst)) {
717 String uri = library.canonicalUri.toString();
718 if (uri == 'dart:isolate') {
719 enableIsolateSupport();
720 } else if (uri == 'dart:async') {
721 if (element.name == '_createTimer' ||
722 element.name == '_createPeriodicTimer') {
723 // The [:Timer:] class uses the event queue of the isolate
724 // library, so we make sure that event queue is generated.
725 enableIsolateSupport();
726 }
727 }
728 }
729
730 if (element.isGetter && element.name == Compiler.RUNTIME_TYPE) {
731 // Enable runtime type support if we discover a getter called runtimeType.
732 // We have to enable runtime type before hitting the codegen, so
733 // that constructors know whether they need to generate code for
734 // runtime type.
735 compiler.enabledRuntimeType = true;
736 // TODO(ahe): Record precise dependency here.
737 compiler.backend.registerRuntimeType(this, compiler.globalDependencies);
738 } else if (element == compiler.functionApplyMethod) {
739 compiler.enabledFunctionApply = true;
740 }
741
742 nativeEnqueuer.registerElement(element);
743 return true;
744 }
745
746 void enableIsolateSupport() {
747 compiler.hasIsolateSupport = true;
748 compiler.backend.enableIsolateSupport(this);
749 }
750
751 void enableNoSuchMethod(Element element) {
752 if (compiler.enabledNoSuchMethod) return;
753 if (compiler.backend.isDefaultNoSuchMethodImplementation(element)) return;
754
755 compiler.enabledNoSuchMethod = true;
756 compiler.backend.enableNoSuchMethod(element, this);
757 }
758
759 /**
760 * Adds an action to the deferred task queue.
761 *
762 * The action is performed the next time the resolution queue has been
763 * emptied.
764 *
765 * The queue is processed in FIFO order.
766 */
767 void addDeferredAction(Element element, DeferredAction action) {
768 if (queueIsClosed) {
769 throw new SpannableAssertionFailure(element,
770 "Resolution work list is closed. "
771 "Trying to add deferred action for $element");
772 }
773 deferredTaskQueue.add(new DeferredTask(element, action));
774 }
775
776 bool onQueueEmpty(Iterable<ClassElement> recentClasses) {
777 emptyDeferredTaskQueue();
778 return super.onQueueEmpty(recentClasses);
779 }
780
781 void emptyDeferredTaskQueue() {
782 while (!deferredTaskQueue.isEmpty) {
783 DeferredTask task = deferredTaskQueue.removeFirst();
784 compiler.withCurrentElement(task.element, task.action);
785 }
786 }
787
788 void registerJsCall(Send node, ResolverVisitor resolver) {
789 nativeEnqueuer.registerJsCall(node, resolver);
790 }
791
792 void registerJsEmbeddedGlobalCall(Send node, ResolverVisitor resolver) {
793 nativeEnqueuer.registerJsEmbeddedGlobalCall(node, resolver);
794 }
795
796 void _logSpecificSummary(log(message)) {
797 log('Resolved ${resolvedElements.length} elements.');
798 }
799
800 void forgetElement(Element element) {
801 super.forgetElement(element);
802 resolvedElements.remove(element);
803 }
804 }
805
806 /// [Enqueuer] which is specific to code generation.
807 class CodegenEnqueuer extends Enqueuer {
808 final Queue<CodegenWorkItem> queue;
809 final Map<Element, js.Expression> generatedCode =
810 new Map<Element, js.Expression>();
811
812 final Set<Element> newlyEnqueuedElements;
813
814 CodegenEnqueuer(Compiler compiler,
815 ItemCompilationContext itemCompilationContextCreator())
816 : queue = new Queue<CodegenWorkItem>(),
817 newlyEnqueuedElements = compiler.cacheStrategy.newSet(),
818 super('codegen enqueuer', compiler, itemCompilationContextCreator);
819
820 bool isProcessed(Element member) =>
821 member.isAbstract || generatedCode.containsKey(member);
822
823 /**
824 * Decides whether an element should be included to satisfy requirements
825 * of the mirror system.
826 *
827 * For code generation, we rely on the precomputed set of elements that takes
828 * subtyping constraints into account.
829 */
830 bool shouldIncludeElementDueToMirrors(Element element,
831 {bool includedEnclosing}) {
832 return compiler.backend.isAccessibleByReflection(element);
833 }
834
835 bool internalAddToWorkList(Element element) {
836 // Don't generate code for foreign elements.
837 if (element.isForeign(compiler.backend)) return false;
838
839 // Codegen inlines field initializers. It only needs to generate
840 // code for checked setters.
841 if (element.isField && element.isInstanceMember) {
842 if (!compiler.enableTypeAssertions
843 || element.enclosingElement.isClosure) {
844 return false;
845 }
846 }
847
848 if (compiler.hasIncrementalSupport && !isProcessed(element)) {
849 newlyEnqueuedElements.add(element);
850 }
851
852 if (queueIsClosed) {
853 throw new SpannableAssertionFailure(element,
854 "Codegen work list is closed. Trying to add $element");
855 }
856 CodegenWorkItem workItem = new CodegenWorkItem(
857 element, itemCompilationContextCreator());
858 queue.add(workItem);
859 return true;
860 }
861
862 void _logSpecificSummary(log(message)) {
863 log('Compiled ${generatedCode.length} methods.');
864 }
865
866 void forgetElement(Element element) {
867 super.forgetElement(element);
868 generatedCode.remove(element);
869 if (element is MemberElement) {
870 for (Element closure in element.nestedClosures) {
871 generatedCode.remove(closure);
872 removeFromSet(instanceMembersByName, closure);
873 removeFromSet(instanceFunctionsByName, closure);
874 }
875 }
876 }
877 }
878
879 /// Parameterizes filtering of which work items are enqueued.
880 class QueueFilter {
881 bool checkNoEnqueuedInvokedInstanceMethods(Enqueuer enqueuer) {
882 enqueuer.task.measure(() {
883 // Run through the classes and see if we need to compile methods.
884 for (ClassElement classElement in
885 enqueuer.universe.directlyInstantiatedClasses) {
886 for (ClassElement currentClass = classElement;
887 currentClass != null;
888 currentClass = currentClass.superclass) {
889 enqueuer.processInstantiatedClassMembers(currentClass);
890 }
891 }
892 });
893 return true;
894 }
895
896 void processWorkItem(void f(WorkItem work), WorkItem work) {
897 f(work);
898 }
899 }
900
901 void removeFromSet(Map<String, Set<Element>> map, Element element) {
902 Set<Element> set = map[element.name];
903 if (set == null) return;
904 set.remove(element);
905 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698