Index: pkg/compiler/lib/src/js_backend/enqueuer.dart |
diff --git a/pkg/compiler/lib/src/js_backend/enqueuer.dart b/pkg/compiler/lib/src/js_backend/enqueuer.dart |
index d95c529c0948a3b43cd3d2183e4a7d0558e63894..b7710eb6f8415c5d8b396639d125e6243c757a8e 100644 |
--- a/pkg/compiler/lib/src/js_backend/enqueuer.dart |
+++ b/pkg/compiler/lib/src/js_backend/enqueuer.dart |
@@ -6,9 +6,10 @@ library dart2js.js.enqueue; |
import 'dart:collection' show Queue; |
+import '../common/backend_api.dart' show Backend; |
import '../common/codegen.dart' show CodegenWorkItem; |
+import '../common/registry.dart' show Registry; |
import '../common/names.dart' show Identifiers; |
-import '../common/resolution.dart' show Resolution; |
import '../common/work.dart' show WorkItem; |
import '../common.dart'; |
import '../compiler.dart' show Compiler; |
@@ -30,6 +31,7 @@ import '../elements/elements.dart' |
import '../enqueue.dart'; |
import '../js/js.dart' as js; |
import '../native/native.dart' as native; |
+import '../options.dart'; |
import '../types/types.dart' show TypeMaskStrategy; |
import '../universe/selector.dart' show Selector; |
import '../universe/universe.dart'; |
@@ -38,11 +40,13 @@ import '../universe/use.dart' |
import '../universe/world_impact.dart' |
show ImpactUseCase, WorldImpact, WorldImpactVisitor; |
import '../util/util.dart' show Setlet; |
+import '../world.dart'; |
/// [Enqueuer] which is specific to code generation. |
class CodegenEnqueuer implements Enqueuer { |
final String name; |
- final Compiler compiler; // TODO(ahe): Remove this dependency. |
+ @deprecated |
+ final Compiler _compiler; // TODO(ahe): Remove this dependency. |
final EnqueuerStrategy strategy; |
final Map<String, Set<Element>> instanceMembersByName = |
new Map<String, Set<Element>>(); |
@@ -69,25 +73,28 @@ class CodegenEnqueuer implements Enqueuer { |
newlyEnqueuedElements = compiler.cacheStrategy.newSet(), |
newlySeenSelectors = compiler.cacheStrategy.newSet(), |
this.name = 'codegen enqueuer', |
- this.compiler = compiler { |
+ this._compiler = compiler { |
impactVisitor = new _EnqueuerImpactVisitor(this); |
} |
- // TODO(johnniwinther): Move this to [ResolutionEnqueuer]. |
- Resolution get resolution => compiler.resolution; |
+ Backend get backend => _compiler.backend; |
+ |
+ CompilerOptions get options => _compiler.options; |
+ |
+ Registry get globalDependencies => _compiler.globalDependencies; |
+ |
+ Registry get mirrorDependencies => _compiler.mirrorDependencies; |
+ |
+ ClassWorld get _world => _compiler.closedWorld; |
bool get queueIsEmpty => queue.isEmpty; |
/// Returns [:true:] if this enqueuer is the resolution enqueuer. |
bool get isResolutionQueue => false; |
- QueueFilter get filter => compiler.enqueuerFilter; |
- |
- DiagnosticReporter get reporter => compiler.reporter; |
- |
- bool isClassProcessed(ClassElement cls) => _processedClasses.contains(cls); |
+ QueueFilter get filter => _compiler.enqueuerFilter; |
- Iterable<ClassElement> get processedClasses => _processedClasses; |
+ DiagnosticReporter get reporter => _compiler.reporter; |
/** |
* Documentation wanted -- johnniwinther |
@@ -96,30 +103,48 @@ class CodegenEnqueuer implements Enqueuer { |
*/ |
void addToWorkList(Element element) { |
assert(invariant(element, element.isDeclaration)); |
- if (internalAddToWorkList(element) && compiler.options.dumpInfo) { |
+ // Don't generate code for foreign elements. |
+ if (backend.isForeign(element)) return; |
+ |
+ // Codegen inlines field initializers. It only needs to generate |
+ // code for checked setters. |
+ if (element.isField && element.isInstanceMember) { |
+ if (!options.enableTypeAssertions || element.enclosingElement.isClosure) { |
+ return; |
+ } |
+ } |
+ |
+ if (options.hasIncrementalSupport && !isProcessed(element)) { |
+ newlyEnqueuedElements.add(element); |
+ } |
+ |
+ if (queueIsClosed) { |
+ throw new SpannableAssertionFailure( |
+ element, "Codegen work list is closed. Trying to add $element"); |
+ } |
+ queue.add(new CodegenWorkItem(_compiler, element)); |
+ if (options.dumpInfo) { |
// TODO(sigmund): add other missing dependencies (internals, selectors |
// enqueued after allocations), also enable only for the codegen enqueuer. |
- compiler.dumpInfoTask |
- .registerDependency(compiler.currentElement, element); |
+ _compiler.dumpInfoTask |
+ .registerDependency(_compiler.currentElement, element); |
} |
} |
/// Apply the [worldImpact] of processing [element] to this enqueuer. |
void applyImpact(Element element, WorldImpact worldImpact) { |
- compiler.impactStrategy |
+ _compiler.impactStrategy |
.visitImpact(element, worldImpact, impactVisitor, impactUse); |
} |
void registerInstantiatedType(InterfaceType type, {bool mirrorUsage: false}) { |
task.measure(() { |
ClassElement cls = type.element; |
- cls.ensureResolved(resolution); |
- bool isNative = compiler.backend.isNative(cls); |
+ bool isNative = backend.isNative(cls); |
universe.registerTypeInstantiation(type, |
isNative: isNative, |
byMirrors: mirrorUsage, onImplemented: (ClassElement cls) { |
- compiler.backend |
- .registerImplementedClass(cls, this, compiler.globalDependencies); |
+ backend.registerImplementedClass(cls, this, globalDependencies); |
}); |
// TODO(johnniwinther): Share this reasoning with [Universe]. |
if (!cls.isAbstract || isNative || mirrorUsage) { |
@@ -150,14 +175,12 @@ class CodegenEnqueuer implements Enqueuer { |
// its metadata parsed and analyzed. |
// Note: this assumes that there are no non-native fields on native |
// classes, which may not be the case when a native class is subclassed. |
- if (compiler.backend.isNative(cls)) { |
- compiler.world.registerUsedElement(member); |
- if (universe.hasInvokedGetter(member, compiler.world) || |
- universe.hasInvocation(member, compiler.world)) { |
+ if (backend.isNative(cls)) { |
+ if (universe.hasInvokedGetter(member, _world) || |
+ universe.hasInvocation(member, _world)) { |
addToWorkList(member); |
return; |
- } |
- if (universe.hasInvokedSetter(member, compiler.world)) { |
+ } else if (universe.hasInvokedSetter(member, _world)) { |
addToWorkList(member); |
return; |
} |
@@ -172,7 +195,6 @@ class CodegenEnqueuer implements Enqueuer { |
} |
} else if (member.isFunction) { |
FunctionElement function = member; |
- function.computeType(resolution); |
if (function.name == Identifiers.noSuchMethod_) { |
registerNoSuchMethod(function); |
} |
@@ -181,7 +203,7 @@ class CodegenEnqueuer implements Enqueuer { |
} |
// If there is a property access with the same name as a method we |
// need to emit the method. |
- if (universe.hasInvokedGetter(function, compiler.world)) { |
+ if (universe.hasInvokedGetter(function, _world)) { |
registerClosurizedMember(function); |
addToWorkList(function); |
return; |
@@ -191,27 +213,25 @@ class CodegenEnqueuer implements Enqueuer { |
instanceFunctionsByName |
.putIfAbsent(memberName, () => new Set<Element>()) |
.add(member); |
- if (universe.hasInvocation(function, compiler.world)) { |
+ if (universe.hasInvocation(function, _world)) { |
addToWorkList(function); |
return; |
} |
} else if (member.isGetter) { |
FunctionElement getter = member; |
- getter.computeType(resolution); |
- if (universe.hasInvokedGetter(getter, compiler.world)) { |
+ if (universe.hasInvokedGetter(getter, _world)) { |
addToWorkList(getter); |
return; |
} |
// We don't know what selectors the returned closure accepts. If |
// the set contains any selector we have to assume that it matches. |
- if (universe.hasInvocation(getter, compiler.world)) { |
+ if (universe.hasInvocation(getter, _world)) { |
addToWorkList(getter); |
return; |
} |
} else if (member.isSetter) { |
FunctionElement setter = member; |
- setter.computeType(resolution); |
- if (universe.hasInvokedSetter(setter, compiler.world)) { |
+ if (universe.hasInvokedSetter(setter, _world)) { |
addToWorkList(setter); |
return; |
} |
@@ -229,35 +249,25 @@ class CodegenEnqueuer implements Enqueuer { |
void processInstantiatedClass(ClassElement cls) { |
task.measure(() { |
if (_processedClasses.contains(cls)) return; |
- // The class must be resolved to compute the set of all |
- // supertypes. |
- cls.ensureResolved(resolution); |
void processClass(ClassElement superclass) { |
if (_processedClasses.contains(superclass)) return; |
// TODO(johnniwinther): Re-insert this invariant when unittests don't |
// fail. There is already a similar invariant on the members. |
- /*if (!isResolutionQueue) { |
- assert(invariant(superclass, |
+ /*assert(invariant(superclass, |
superclass.isClosure || |
- compiler.enqueuer.resolution.isClassProcessed(superclass), |
+ _compiler.enqueuer.resolution.isClassProcessed(superclass), |
message: "Class $superclass has not been " |
"processed in resolution.")); |
- }*/ |
+ */ |
_processedClasses.add(superclass); |
recentClasses.add(superclass); |
- superclass.ensureResolved(resolution); |
superclass.implementation.forEachMember(processInstantiatedClassMember); |
- if (isResolutionQueue && |
- !compiler.serialization.isDeserialized(superclass)) { |
- compiler.resolver.checkClass(superclass); |
- } |
// We only tell the backend once that [superclass] was instantiated, so |
// any additional dependencies must be treated as global |
// dependencies. |
- compiler.backend.registerInstantiatedClass( |
- superclass, this, compiler.globalDependencies); |
+ backend.registerInstantiatedClass(superclass, this, globalDependencies); |
} |
ClassElement superclass = cls; |
@@ -278,7 +288,7 @@ class CodegenEnqueuer implements Enqueuer { |
void logEnqueueReflectiveAction(action, [msg = ""]) { |
if (TRACE_MIRROR_ENQUEUING) { |
- print("MIRROR_ENQUEUE (${isResolutionQueue ? "R" : "C"}): $action $msg"); |
+ print("MIRROR_ENQUEUE (C): $action $msg"); |
} |
} |
@@ -292,8 +302,7 @@ class CodegenEnqueuer implements Enqueuer { |
includedEnclosing: enclosingWasIncluded)) { |
logEnqueueReflectiveAction(ctor); |
ClassElement cls = ctor.declaration.enclosingClass; |
- compiler.backend.registerInstantiatedType( |
- cls.rawType, this, compiler.mirrorDependencies, |
+ backend.registerInstantiatedType(cls.rawType, this, mirrorDependencies, |
mirrorUsage: true); |
registerStaticUse(new StaticUse.foreignUse(ctor.declaration)); |
} |
@@ -308,9 +317,7 @@ class CodegenEnqueuer implements Enqueuer { |
includedEnclosing: enclosingWasIncluded)) { |
logEnqueueReflectiveAction(element); |
if (element.isTypedef) { |
- TypedefElement typedef = element; |
- typedef.ensureResolved(resolution); |
- compiler.world.allTypedefs.add(element); |
+ // Do nothing. |
} else if (Elements.isStaticOrTopLevel(element)) { |
registerStaticUse(new StaticUse.foreignUse(element.declaration)); |
} else if (element.isInstanceMember) { |
@@ -343,9 +350,7 @@ class CodegenEnqueuer implements Enqueuer { |
if (includeClass) { |
logEnqueueReflectiveAction(cls, "register"); |
ClassElement decl = cls.declaration; |
- decl.ensureResolved(resolution); |
- compiler.backend.registerInstantiatedType( |
- decl.rawType, this, compiler.mirrorDependencies, |
+ backend.registerInstantiatedType(decl.rawType, this, mirrorDependencies, |
mirrorUsage: true); |
} |
// If the class is never instantiated, we know nothing of it can possibly |
@@ -370,14 +375,11 @@ class CodegenEnqueuer implements Enqueuer { |
/// that none of its methods are reflectable, unless reflectable by |
/// inheritance. |
void enqueueReflectiveSpecialClasses() { |
- Iterable<ClassElement> classes = |
- compiler.backend.classesRequiredForReflection; |
+ Iterable<ClassElement> classes = backend.classesRequiredForReflection; |
for (ClassElement cls in classes) { |
- if (compiler.backend.referencedFromMirrorSystem(cls)) { |
+ if (backend.referencedFromMirrorSystem(cls)) { |
logEnqueueReflectiveAction(cls); |
- cls.ensureResolved(resolution); |
- compiler.backend.registerInstantiatedType( |
- cls.rawType, this, compiler.mirrorDependencies, |
+ backend.registerInstantiatedType(cls.rawType, this, mirrorDependencies, |
mirrorUsage: true); |
} |
} |
@@ -412,7 +414,7 @@ class CodegenEnqueuer implements Enqueuer { |
// enqueued. |
recents = _processedClasses.toSet(); |
reporter.log('Enqueuing everything'); |
- for (LibraryElement lib in compiler.libraryLoader.libraries) { |
+ for (LibraryElement lib in _compiler.libraryLoader.libraries) { |
enqueueReflectiveElementsInLibrary(lib, recents); |
} |
enqueueReflectiveSpecialClasses(); |
@@ -474,7 +476,7 @@ class CodegenEnqueuer implements Enqueuer { |
Selector selector = dynamicUse.selector; |
String methodName = selector.name; |
processInstanceMembers(methodName, (Element member) { |
- if (dynamicUse.appliesUnnamed(member, compiler.world)) { |
+ if (dynamicUse.appliesUnnamed(member, _world)) { |
if (member.isFunction && selector.isGetter) { |
registerClosurizedMember(member); |
} |
@@ -485,7 +487,7 @@ class CodegenEnqueuer implements Enqueuer { |
}); |
if (selector.isGetter) { |
processInstanceFunctions(methodName, (Element member) { |
- if (dynamicUse.appliesUnnamed(member, compiler.world)) { |
+ if (dynamicUse.appliesUnnamed(member, _world)) { |
registerClosurizedMember(member); |
return true; |
} |
@@ -508,11 +510,11 @@ class CodegenEnqueuer implements Enqueuer { |
assert(invariant(element, element.isDeclaration, |
message: "Element ${element} is not the declaration.")); |
universe.registerStaticUse(staticUse); |
- compiler.backend.registerStaticUse(element, this); |
+ backend.registerStaticUse(element, this); |
bool addElement = true; |
switch (staticUse.kind) { |
case StaticUseKind.STATIC_TEAR_OFF: |
- compiler.backend.registerGetOfStaticFunction(this); |
+ backend.registerGetOfStaticFunction(this); |
break; |
case StaticUseKind.FIELD_GET: |
case StaticUseKind.FIELD_SET: |
@@ -546,7 +548,7 @@ class CodegenEnqueuer implements Enqueuer { |
_registerIsCheck(type); |
break; |
case TypeUseKind.CHECKED_MODE_CHECK: |
- if (compiler.options.enableTypeAssertions) { |
+ if (options.enableTypeAssertions) { |
_registerIsCheck(type); |
} |
break; |
@@ -556,7 +558,7 @@ class CodegenEnqueuer implements Enqueuer { |
} |
void _registerIsCheck(DartType type) { |
- type = universe.registerIsCheck(type, compiler); |
+ type = universe.registerIsCheck(type, _compiler); |
// Even in checked mode, type annotations for return type and argument |
// types do not imply type checks, so there should never be a check |
// against the type variable of a typedef. |
@@ -564,18 +566,18 @@ class CodegenEnqueuer implements Enqueuer { |
} |
void registerCallMethodWithFreeTypeVariables(Element element) { |
- compiler.backend.registerCallMethodWithFreeTypeVariables( |
- element, this, compiler.globalDependencies); |
+ backend.registerCallMethodWithFreeTypeVariables( |
+ element, this, globalDependencies); |
universe.callMethodsWithFreeTypeVariables.add(element); |
} |
void registerClosurizedMember(TypedElement element) { |
assert(element.isInstanceMember); |
- if (element.computeType(resolution).containsTypeVariables) { |
- compiler.backend.registerClosureWithFreeTypeVariables( |
- element, this, compiler.globalDependencies); |
+ if (element.type.containsTypeVariables) { |
+ backend.registerClosureWithFreeTypeVariables( |
+ element, this, globalDependencies); |
} |
- compiler.backend.registerBoundClosure(this); |
+ backend.registerBoundClosure(this); |
universe.closurizedMembers.add(element); |
} |
@@ -598,7 +600,7 @@ class CodegenEnqueuer implements Enqueuer { |
/// 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); |
+ return backend.onQueueEmpty(this, recentClasses); |
} |
void logSummary(log(message)) { |
@@ -609,7 +611,7 @@ class CodegenEnqueuer implements Enqueuer { |
String toString() => 'Enqueuer($name)'; |
void _forgetElement(Element element) { |
- universe.forgetElement(element, compiler); |
+ universe.forgetElement(element, _compiler); |
_processedClasses.remove(element); |
instanceMembersByName[element.name]?.remove(element); |
instanceFunctionsByName[element.name]?.remove(element); |
@@ -641,42 +643,12 @@ class CodegenEnqueuer implements Enqueuer { |
*/ |
bool shouldIncludeElementDueToMirrors(Element element, |
{bool includedEnclosing}) { |
- return compiler.backend.isAccessibleByReflection(element); |
- } |
- |
- /** |
- * Adds [element] to the work list if it has not already been processed. |
- * |
- * Returns [true] if the element was actually added to the queue. |
- */ |
- bool internalAddToWorkList(Element element) { |
- // Don't generate code for foreign elements. |
- if (compiler.backend.isForeign(element)) return false; |
- |
- // Codegen inlines field initializers. It only needs to generate |
- // code for checked setters. |
- if (element.isField && element.isInstanceMember) { |
- if (!compiler.options.enableTypeAssertions || |
- element.enclosingElement.isClosure) { |
- return false; |
- } |
- } |
- |
- if (compiler.options.hasIncrementalSupport && !isProcessed(element)) { |
- newlyEnqueuedElements.add(element); |
- } |
- |
- if (queueIsClosed) { |
- throw new SpannableAssertionFailure( |
- element, "Codegen work list is closed. Trying to add $element"); |
- } |
- queue.add(new CodegenWorkItem(compiler, element)); |
- return true; |
+ return backend.isAccessibleByReflection(element); |
} |
void registerNoSuchMethod(Element element) { |
- if (!enabledNoSuchMethod && compiler.backend.enabledNoSuchMethod) { |
- compiler.backend.enableNoSuchMethod(this); |
+ if (!enabledNoSuchMethod && backend.enabledNoSuchMethod) { |
+ backend.enableNoSuchMethod(this); |
enabledNoSuchMethod = true; |
} |
} |
@@ -698,7 +670,7 @@ class CodegenEnqueuer implements Enqueuer { |
} |
void handleUnseenSelector(DynamicUse dynamicUse) { |
- if (compiler.options.hasIncrementalSupport) { |
+ if (options.hasIncrementalSupport) { |
newlySeenSelectors.add(dynamicUse); |
} |
_handleUnseenSelector(dynamicUse); |