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

Unified Diff: sdk/lib/_internal/compiler/implementation/enqueue.dart

Issue 340783011: Take inheritance into account when computing the elements accessible by mirrors. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 6 months 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 side-by-side diff with in-line comments
Download patch
Index: sdk/lib/_internal/compiler/implementation/enqueue.dart
diff --git a/sdk/lib/_internal/compiler/implementation/enqueue.dart b/sdk/lib/_internal/compiler/implementation/enqueue.dart
index 4ce3d5c93c3f325271104ded7e08941fb0829eba..8c34277e3aa891797e14455561cc840abda14fac 100644
--- a/sdk/lib/_internal/compiler/implementation/enqueue.dart
+++ b/sdk/lib/_internal/compiler/implementation/enqueue.dart
@@ -73,13 +73,16 @@ abstract class Enqueuer {
final Map<String, Link<Element>> instanceFunctionsByName
= new Map<String, Link<Element>>();
final Set<ClassElement> seenClasses = new Set<ClassElement>();
+ Set<ClassElement> recentClasses = new Setlet<ClassElement>();
final Universe universe = new Universe();
+ static final TRACE_MIRROR_ENQUEUING = false;
floitsch 2014/06/27 08:59:15 should we start making these things const X.fromEn
herhut 2014/06/27 12:34:35 I did not know it was that easy to read an environ
+
bool queueIsClosed = false;
EnqueueTask task;
native.NativeEnqueuer nativeEnqueuer; // Set by EnqueueTask
- bool hasEnqueuedEverything = false;
+ bool hasEnqueuedReflectiveElements = false;
bool hasEnqueuedReflectiveStaticFields = false;
Enqueuer(this.name, this.compiler, this.itemCompilationContextCreator);
@@ -108,7 +111,8 @@ abstract class Enqueuer {
*/
void internalAddToWorkList(Element element);
- void registerInstantiatedType(InterfaceType type, Registry registry) {
+ void registerInstantiatedType(InterfaceType type, Registry registry,
+ {mirrorUsage: false}) {
karlklose 2014/06/27 07:45:57 Only use registerInstantiatedType for types that a
herhut 2014/06/27 12:34:35 This only replicated what the original implementat
task.measure(() {
ClassElement cls = type.element;
registry.registerDependency(cls);
@@ -119,16 +123,20 @@ abstract class Enqueuer {
// classes; a native abstract class may have non-abstract subclasses
// not declared to the program. Instances of these classes are
// indistinguishable from the abstract class.
- || cls.isNative) {
+ || cls.isNative
+ // Likewise, if this registration comes from the mirror system,
+ // all bets are off.
+ || mirrorUsage) {
universe.instantiatedClasses.add(cls);
}
onRegisterInstantiatedClass(cls);
});
}
- void registerInstantiatedClass(ClassElement cls, Registry registry) {
+ void registerInstantiatedClass(ClassElement cls, Registry registry,
+ {mirrorUsage: false}) {
cls.ensureResolved(compiler);
- registerInstantiatedType(cls.rawType, registry);
+ registerInstantiatedType(cls.rawType, registry, mirrorUsage: mirrorUsage);
}
bool checkNoEnqueuedInvokedInstanceMethods() {
@@ -260,6 +268,7 @@ abstract class Enqueuer {
if (seenClasses.contains(cls)) return;
seenClasses.add(cls);
+ recentClasses.add(cls);
cls.ensureResolved(compiler);
cls.implementation.forEachMember(processInstantiatedClassMember);
if (isResolutionQueue) {
@@ -308,48 +317,130 @@ abstract class Enqueuer {
});
}
- void pretendElementWasUsed(Element element, Registry registry) {
- if (!compiler.backend.isNeededForReflection(element)) return;
- if (Elements.isUnresolved(element)) {
- // Ignore.
- } else if (element.isSynthesized
- && element.library.isPlatformLibrary) {
- // TODO(ahe): Work-around for http://dartbug.com/11205.
- } else if (element.isConstructor) {
- ClassElement cls = element.declaration.enclosingClass;
- registerInstantiatedType(cls.rawType, registry);
- registerStaticUse(element.declaration);
- } else if (element.isClass) {
- ClassElement cls = element.declaration;
- registerInstantiatedClass(cls, registry);
- // Make sure that even abstract classes are considered instantiated.
- universe.instantiatedClasses.add(cls);
- } else if (element.impliesType) {
- // Don't enqueue typedefs, and type variables.
- } else if (Elements.isStaticOrTopLevel(element)) {
- registerStaticUse(element.declaration);
- } else if (element.isInstanceMember) {
- Selector selector = new Selector.fromElement(element, compiler);
- registerSelectorUse(selector);
- if (element.isField) {
- Selector selector =
- new Selector.setter(element.name, element.library);
- registerInvokedSetter(selector);
+ /**
+ * Decides whether an element should be included to satisfy requirements
+ * of the mirror system.
+ *
+ * The actual implementation depends on the current compiler phase.
+ */
+ bool includeElementDueToMirrors(bool includeEnclosing, Element element);
Johnni Winther 2014/06/27 07:43:01 Rename to [shouldIncludeElementDueToMirror] to ind
Johnni Winther 2014/06/27 07:43:01 Make [includeEnclosing] a named parameter.
herhut 2014/06/27 12:34:36 Done.
herhut 2014/06/27 12:34:36 Done.
+
+ void logEnqueueReflectiveAction(action, [msg = ""]) {
+ if (TRACE_MIRROR_ENQUEUING) {
+ print("MIRROR_ENQUEUE (${isResolutionQueue ? "R" : "B"}): $action $msg");
karlklose 2014/06/27 07:45:57 'R' -> 'resolution'? What is 'B'?
herhut 2014/06/27 12:34:36 Backend. Probably C for codegen is better. I have
+ }
+ }
+
+ void enqueueReflectiveConstructor(ConstructorElement ctor, bool add) {
Johnni Winther 2014/06/27 07:43:00 Add comment. I guess it is a helper method for [en
Johnni Winther 2014/06/27 07:43:01 Make [add] named.
karlklose 2014/06/27 07:45:57 Could you add a comment about the semantics of 'ad
floitsch 2014/06/27 08:59:15 nit: s/add/forceAdd/ I'm guessing that's the mean
herhut 2014/06/27 12:34:36 Done.
herhut 2014/06/27 12:34:36 Done.
herhut 2014/06/27 12:34:36 Done.
herhut 2014/06/27 12:34:37 Done.
+ if (includeElementDueToMirrors(add, ctor)) {
+ logEnqueueReflectiveAction(ctor);
+ ClassElement cls = ctor.declaration.enclosingClass;
+ registerInstantiatedType(cls.rawType, compiler.mirrorDependencies);
Johnni Winther 2014/06/27 07:43:01 Shouldn't this call have `mirrorUsage: true` ?
karlklose 2014/06/27 07:45:57 I am not sure we should register this type here.
herhut 2014/06/27 12:34:35 It will not have an effect currently but it is mor
herhut 2014/06/27 12:34:36 This implements what was done before. I will redo
+ registerStaticUse(ctor.declaration);
+ }
+ }
+
+ void enqueueReflectiveMember(Element element, bool add) {
Johnni Winther 2014/06/27 07:43:00 Make [add] named.
Johnni Winther 2014/06/27 07:43:01 Add comment.
herhut 2014/06/27 12:34:35 Done.
herhut 2014/06/27 12:34:36 Done.
+ add = includeElementDueToMirrors(add, element);
karlklose 2014/06/27 07:45:57 Inline call to includeElementsDueToMirrors? (Also
herhut 2014/06/27 12:34:36 Below I have to pass the result on to the processi
+ if (add && !element.impliesType) {
floitsch 2014/06/27 08:59:15 Keep comment exlpaining what "impliesType" means.
herhut 2014/06/27 12:34:36 Done.
+ logEnqueueReflectiveAction(element);
+ if (Elements.isStaticOrTopLevel(element)) {
+ registerStaticUse(element.declaration);
+ } else if (element.isInstanceMember) {
+ // We need to enqueue all members matching this one in subclasses, as
+ // well.
+ // TODO(herhut): Use TypedSelector.subtype for enqueueing
+ Selector selector = new Selector.fromElement(element, compiler);
+ registerSelectorUse(selector);
+ if (element.isField) {
+ Selector selector =
+ new Selector.setter(element.name, element.library);
+ registerInvokedSetter(selector);
+ }
}
}
}
- void enqueueEverything() {
- if (hasEnqueuedEverything) return;
- compiler.log('Enqueuing everything');
- task.ensureAllElementsByName();
- for (Link link in task.allElementsByName.values) {
- for (Element element in link) {
- pretendElementWasUsed(element, compiler.mirrorDependencies);
+ void enqueueReflectiveElementsInClass(ClassElement cls,
Johnni Winther 2014/06/27 07:43:00 Add comment.
herhut 2014/06/27 12:34:36 Done.
+ Iterable<ClassElement> recents,
+ bool add) {
Johnni Winther 2014/06/27 07:43:00 Make [add] named.
herhut 2014/06/27 12:34:37 Done.
+ if (cls.library.isInternalLibrary) return;
+ if (cls.isInjected) return;
Johnni Winther 2014/06/27 07:43:00 Merge conditions.
herhut 2014/06/27 12:34:36 Done.
+ add = includeElementDueToMirrors(add, cls);
+ if (add) {
+ logEnqueueReflectiveAction(cls, "register");
+ ClassElement decl = cls.declaration;
+ registerInstantiatedClass(decl, compiler.mirrorDependencies,
+ mirrorUsage: true);
+ }
+ // If the class is never instantiated, we know nothing of it can possibly
+ // be reflected upon.
+ // TODO(herhut): Add a warning if a mirrors annotation cannot hit.
+ if (recents.contains(cls.declaration)) {
+ logEnqueueReflectiveAction(cls, "members");
+ cls.constructors.forEach((Element element) {
+ enqueueReflectiveConstructor(element, add);
+ });
+ cls.forEachClassMember((Member member) {
+ enqueueReflectiveMember(member.element, add);
+ });
+ }
+ }
+
+ void enqueueReflectiveSpecialClasses() {
Johnni Winther 2014/06/27 07:43:00 Add comment.
herhut 2014/06/27 12:34:36 Done.
+ // [Closure] is treated specially as it is the superclass of all closures.
+ // Although it is in an internal library, we mark it as reflectable. Note
+ // that none of its methods are reflectable, unless reflectable by
+ // inheritance.
+ ClassElement closureClass = compiler.closureClass;
+ if (compiler.backend.referencedFromMirrorSystem(closureClass)) {
+ logEnqueueReflectiveAction(closureClass);
+ registerInstantiatedClass(closureClass, compiler.mirrorDependencies,
+ mirrorUsage: true);
+ }
+ }
+
+ void enqueueReflectiveElementsInLibrary(LibraryElement lib,
Johnni Winther 2014/06/27 07:43:00 Add comment.
herhut 2014/06/27 12:34:36 Done.
+ Iterable<ClassElement> recents,
+ bool add) {
+ add = includeElementDueToMirrors(add, lib);
+ lib.forEachLocalMember((Element member) {
+ if (member.isClass) {
+ enqueueReflectiveElementsInClass(member, recents, add);
+ } else {
+ enqueueReflectiveMember(member, add);
+ }
+ });
+ }
+
+ /// Enqueue all elements that are matched by the mirrors used
+ /// annotation or, in lack thereof, all elements.
+ void enqueueReflectiveElements(Iterable<ClassElement> recents) {
+ if (!hasEnqueuedReflectiveElements) {
+ logEnqueueReflectiveAction("!START enqueueAll");
+ // First round of enqueuing, visit everything that is visible to
+ // also pick up static top levels, etc.
+ // Also, during the first round, consider all classes that have been seen
+ // as recently seen, as a couple of rounds of resolution might have run
floitsch 2014/06/27 08:59:15 maybe? ... as treeshaking might only be disabled
herhut 2014/06/27 12:34:35 Rephrased: Also, during the first round, consider
+ // before treeshaking is disabled and we thus enqueue everything.
+ recents = seenClasses.toSet();
+ compiler.log('Enqueuing everything');
+ for (LibraryElement lib in compiler.libraries.values) {
+ enqueueReflectiveElementsInLibrary(lib, recents, false);
}
+ enqueueReflectiveSpecialClasses();
+ hasEnqueuedReflectiveElements = true;
+ hasEnqueuedReflectiveStaticFields = true;
+ logEnqueueReflectiveAction("!DONE enqueueAll");
+ } else if (recents.isNotEmpty) {
+ // Keep looking at new classes until fixpoint is reached.
+ logEnqueueReflectiveAction("!START enqueueRecents");
+ recents.forEach((ClassElement cls) {
+ enqueueReflectiveElementsInClass(cls, recents,
+ includeElementDueToMirrors(false, cls.library));
+ });
+ logEnqueueReflectiveAction("!DONE enqueueRecents");
}
- hasEnqueuedEverything = true;
- hasEnqueuedReflectiveStaticFields = true;
}
/// Enqueue the static fields that have been marked as used by reflective
@@ -358,7 +449,7 @@ abstract class Enqueuer {
if (hasEnqueuedReflectiveStaticFields) return;
hasEnqueuedReflectiveStaticFields = true;
for (Element element in elements) {
- pretendElementWasUsed(element, compiler.mirrorDependencies);
+ enqueueReflectiveMember(element, true);
}
}
@@ -529,21 +620,30 @@ abstract class Enqueuer {
}
void registerClosure(Element element, Registry registry) {
Johnni Winther 2014/06/27 07:43:00 Change [Element] to [FunctionElement].
herhut 2014/06/27 12:34:36 Done.
+ universe.allClosures.add(element);
registerIfGeneric(element, registry);
}
void forEach(f(WorkItem work)) {
do {
- while (!queue.isEmpty) {
+ while (queue.isNotEmpty) {
// TODO(johnniwinther): Find an optimal process order.
f(queue.removeLast());
}
- onQueueEmpty();
- } while (!queue.isEmpty);
+ List recents = recentClasses.toList(growable: false);
+ recentClasses.clear();
+ if (!onQueueEmpty(recents)) recentClasses.addAll(recents);
+ } while (queue.isNotEmpty || recentClasses.isNotEmpty);
}
- void onQueueEmpty() {
- compiler.backend.onQueueEmpty(this);
+ /// [onQueueEmpty] is called whenever the queue is drained. [recentClasses]
+ /// contains the set of all classes seen for the first time since
+ /// [onQueueEmpty] was called last. A return value of [true] indicates that
+ /// the [recentClasses] have been processed and may be cleared. If [false] is
+ /// returned, [onQueueEmpty] will be called once the queue is empty again (or
+ /// still empty) and [recentClasses] will be a superset of the current value.
+ bool onQueueEmpty(Iterable<ClassElement> recentClasses) {
+ return compiler.backend.onQueueEmpty(this, recentClasses);
}
void logSummary(log(message)) {
@@ -603,6 +703,18 @@ class ResolutionEnqueuer extends Enqueuer {
return false;
}
+ /**
+ * Decides whether an element should be included to satisfy requirements
+ * of the mirror system.
+ *
+ * During resoltion, we have to resort to matching elements against the
Johnni Winther 2014/06/27 07:43:01 'resoltion' -> 'resolution'.
karlklose 2014/06/27 07:45:57 'resoltion' -> 'resolution'.
herhut 2014/06/27 12:34:36 Done.
herhut 2014/06/27 12:34:37 Done.
+ * [MirrorsUsed] pattern, as we do not have a complete picture of the world,
+ * yet.
+ */
+ bool includeElementDueToMirrors(bool includeEnclosing, Element element) {
karlklose 2014/06/27 07:45:57 Does it make sense to move functionality like this
herhut 2014/06/27 12:34:36 Yes, this is also on the list of further refactori
+ return includeEnclosing || compiler.backend.requiredByMirrorSystem(element);
+ }
+
void internalAddToWorkList(Element element) {
assert(invariant(element, element is AnalyzableElement,
message: 'Element $element is not analyzable.'));
@@ -689,9 +801,9 @@ class ResolutionEnqueuer extends Enqueuer {
deferredTaskQueue.add(new DeferredTask(element, action));
}
- void onQueueEmpty() {
+ bool onQueueEmpty(Iterable<ClassElement> recentClasses) {
emptyDeferredTaskQueue();
- super.onQueueEmpty();
+ return super.onQueueEmpty(recentClasses);
}
void emptyDeferredTaskQueue() {
@@ -727,6 +839,17 @@ class CodegenEnqueuer extends Enqueuer {
bool isProcessed(Element member) =>
member.isAbstract || generatedCode.containsKey(member);
+ /**
+ * Decides whether an element should be included to satisfy requirements
+ * of the mirror system.
+ *
+ * For code generation, we rely on the precomputed set of elements that takes
+ * subtyping constraints into account.
+ */
+ bool includeElementDueToMirrors(bool includeEnclosing, Element element) {
+ return compiler.backend.isAccessibleByReflection(element);
+ }
+
void internalAddToWorkList(Element element) {
if (compiler.hasIncrementalSupport) {
newlyEnqueuedElements.add(element);

Powered by Google App Engine
This is Rietveld 408576698