mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 10:49:00 +00:00
More refactoring of enqueuers
- refactor enqueuer/strategy/impact-visitor relations - make helper methods/fields private R=het@google.com Review URL: https://codereview.chromium.org/2535143003 .
This commit is contained in:
parent
04c66f8bab
commit
3af747810f
4 changed files with 224 additions and 296 deletions
|
@ -121,91 +121,82 @@ abstract class Enqueuer {
|
|||
|
||||
abstract class EnqueuerImpl extends Enqueuer {
|
||||
CompilerTask get task;
|
||||
EnqueuerStrategy get strategy;
|
||||
void processInstantiatedClassMembers(ClassElement cls);
|
||||
void processInstantiatedClassMember(ClassElement cls, Element member);
|
||||
void registerStaticUse(StaticUse staticUse);
|
||||
void registerStaticUseInternal(StaticUse staticUse);
|
||||
void registerTypeUse(TypeUse typeUse);
|
||||
void registerTypeUseInternal(TypeUse typeUse);
|
||||
void registerDynamicUse(DynamicUse dynamicUse);
|
||||
void handleUnseenSelectorInternal(DynamicUse dynamicUse);
|
||||
void processStaticUse(StaticUse staticUse);
|
||||
void processTypeUse(TypeUse typeUse);
|
||||
void processDynamicUse(DynamicUse dynamicUse);
|
||||
}
|
||||
|
||||
/// [Enqueuer] which is specific to resolution.
|
||||
class ResolutionEnqueuer extends EnqueuerImpl {
|
||||
static const ImpactUseCase IMPACT_USE =
|
||||
const ImpactUseCase('ResolutionEnqueuer');
|
||||
|
||||
final CompilerTask task;
|
||||
final String name;
|
||||
final Resolution resolution;
|
||||
final CompilerOptions options;
|
||||
final Resolution _resolution;
|
||||
final CompilerOptions _options;
|
||||
final Backend backend;
|
||||
final GlobalDependencyRegistry globalDependencies;
|
||||
final CommonElements commonElements;
|
||||
final GlobalDependencyRegistry _globalDependencies;
|
||||
final CommonElements _commonElements;
|
||||
final native.NativeEnqueuer nativeEnqueuer;
|
||||
|
||||
final EnqueuerStrategy strategy;
|
||||
final Map<String, Set<Element>> instanceMembersByName =
|
||||
final Map<String, Set<Element>> _instanceMembersByName =
|
||||
new Map<String, Set<Element>>();
|
||||
final Map<String, Set<Element>> instanceFunctionsByName =
|
||||
final Map<String, Set<Element>> _instanceFunctionsByName =
|
||||
new Map<String, Set<Element>>();
|
||||
final Set<ClassElement> _processedClasses = new Set<ClassElement>();
|
||||
Set<ClassElement> recentClasses = new Setlet<ClassElement>();
|
||||
Set<ClassElement> _recentClasses = new Setlet<ClassElement>();
|
||||
final ResolutionWorldBuilderImpl _universe;
|
||||
|
||||
bool queueIsClosed = false;
|
||||
|
||||
WorldImpactVisitor impactVisitor;
|
||||
WorldImpactVisitor _impactVisitor;
|
||||
|
||||
/// All declaration elements that have been processed by the resolver.
|
||||
final Set<AstElement> processedElements = new Set<AstElement>();
|
||||
|
||||
final Queue<WorkItem> _queue = new Queue<WorkItem>();
|
||||
|
||||
/// Queue of deferred resolution actions to execute when the resolution queue
|
||||
/// has been emptied.
|
||||
final Queue<_DeferredAction> _deferredQueue = new Queue<_DeferredAction>();
|
||||
|
||||
ResolutionEnqueuer(
|
||||
this.task,
|
||||
this.options,
|
||||
this.resolution,
|
||||
this._options,
|
||||
this._resolution,
|
||||
this.strategy,
|
||||
this.globalDependencies,
|
||||
this._globalDependencies,
|
||||
Backend backend,
|
||||
CommonElements commonElements,
|
||||
CacheStrategy cacheStrategy,
|
||||
[this.name = 'resolution enqueuer'])
|
||||
: this.backend = backend,
|
||||
this.commonElements = commonElements,
|
||||
this._commonElements = commonElements,
|
||||
this.nativeEnqueuer = backend.nativeResolutionEnqueuer(),
|
||||
processedElements = new Set<AstElement>(),
|
||||
queue = new Queue<ResolutionWorkItem>(),
|
||||
deferredQueue = new Queue<_DeferredAction>(),
|
||||
_universe = new ResolutionWorldBuilderImpl(
|
||||
backend, commonElements, cacheStrategy, const TypeMaskStrategy()) {
|
||||
impactVisitor = new EnqueuerImplImpactVisitor(this);
|
||||
_impactVisitor = new EnqueuerImplImpactVisitor(this);
|
||||
}
|
||||
|
||||
ResolutionWorldBuilder get universe => _universe;
|
||||
|
||||
OpenWorld get openWorld => universe.openWorld;
|
||||
OpenWorld get _openWorld => universe.openWorld;
|
||||
|
||||
bool get queueIsEmpty => queue.isEmpty;
|
||||
bool get queueIsEmpty => _queue.isEmpty;
|
||||
|
||||
DiagnosticReporter get reporter => resolution.reporter;
|
||||
|
||||
bool isClassProcessed(ClassElement cls) => _processedClasses.contains(cls);
|
||||
DiagnosticReporter get _reporter => _resolution.reporter;
|
||||
|
||||
Iterable<ClassElement> get processedClasses => _processedClasses;
|
||||
|
||||
/**
|
||||
* Documentation wanted -- johnniwinther
|
||||
*
|
||||
* Invariant: [element] must be a declaration element.
|
||||
*/
|
||||
void addToWorkList(Element element) {
|
||||
assert(invariant(element, element.isDeclaration));
|
||||
internalAddToWorkList(element);
|
||||
}
|
||||
|
||||
void applyImpact(WorldImpact worldImpact, {Element impactSource}) {
|
||||
if (worldImpact.isEmpty) return;
|
||||
impactStrategy.visitImpact(
|
||||
impactSource, worldImpact, impactVisitor, impactUse);
|
||||
}
|
||||
|
||||
void registerInstantiatedType(InterfaceType type) {
|
||||
_registerInstantiatedType(type, globalDependency: true);
|
||||
impactSource, worldImpact, _impactVisitor, impactUse);
|
||||
}
|
||||
|
||||
void _registerInstantiatedType(InterfaceType type,
|
||||
|
@ -216,7 +207,7 @@ class ResolutionEnqueuer extends EnqueuerImpl {
|
|||
bool isRedirection: false}) {
|
||||
task.measure(() {
|
||||
ClassElement cls = type.element;
|
||||
cls.ensureResolved(resolution);
|
||||
cls.ensureResolved(_resolution);
|
||||
bool isNative = backend.isNative(cls);
|
||||
_universe.registerTypeInstantiation(type,
|
||||
constructor: constructor,
|
||||
|
@ -226,7 +217,7 @@ class ResolutionEnqueuer extends EnqueuerImpl {
|
|||
applyImpact(backend.registerImplementedClass(cls, forResolution: true));
|
||||
});
|
||||
if (globalDependency && !mirrorUsage) {
|
||||
globalDependencies.registerDependency(type.element);
|
||||
_globalDependencies.registerDependency(type.element);
|
||||
}
|
||||
if (nativeUsage) {
|
||||
nativeEnqueuer.onInstantiatedType(type);
|
||||
|
@ -234,7 +225,7 @@ class ResolutionEnqueuer extends EnqueuerImpl {
|
|||
backend.registerInstantiatedType(type);
|
||||
// TODO(johnniwinther): Share this reasoning with [Universe].
|
||||
if (!cls.isAbstract || isNative || mirrorUsage) {
|
||||
processInstantiatedClass(cls);
|
||||
_processInstantiatedClass(cls);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -262,14 +253,14 @@ class ResolutionEnqueuer extends EnqueuerImpl {
|
|||
// 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 (backend.isNative(cls)) {
|
||||
openWorld.registerUsedElement(member);
|
||||
if (_universe.hasInvokedGetter(member, openWorld) ||
|
||||
_universe.hasInvocation(member, openWorld)) {
|
||||
addToWorkList(member);
|
||||
_openWorld.registerUsedElement(member);
|
||||
if (_universe.hasInvokedGetter(member, _openWorld) ||
|
||||
_universe.hasInvocation(member, _openWorld)) {
|
||||
_addToWorkList(member);
|
||||
return;
|
||||
}
|
||||
if (_universe.hasInvokedSetter(member, openWorld)) {
|
||||
addToWorkList(member);
|
||||
if (_universe.hasInvokedSetter(member, _openWorld)) {
|
||||
_addToWorkList(member);
|
||||
return;
|
||||
}
|
||||
// Native fields need to go into instanceMembersByName as they
|
||||
|
@ -278,78 +269,78 @@ class ResolutionEnqueuer extends EnqueuerImpl {
|
|||
// All field initializers must be resolved as they could
|
||||
// have an observable side-effect (and cannot be tree-shaken
|
||||
// away).
|
||||
addToWorkList(member);
|
||||
_addToWorkList(member);
|
||||
return;
|
||||
}
|
||||
} else if (member.isFunction) {
|
||||
FunctionElement function = member;
|
||||
function.computeType(resolution);
|
||||
function.computeType(_resolution);
|
||||
if (function.name == Identifiers.noSuchMethod_) {
|
||||
registerNoSuchMethod(function);
|
||||
_registerNoSuchMethod(function);
|
||||
}
|
||||
if (function.name == Identifiers.call && !cls.typeVariables.isEmpty) {
|
||||
_registerCallMethodWithFreeTypeVariables(function);
|
||||
}
|
||||
// If there is a property access with the same name as a method we
|
||||
// need to emit the method.
|
||||
if (_universe.hasInvokedGetter(function, openWorld)) {
|
||||
registerClosurizedMember(function);
|
||||
addToWorkList(function);
|
||||
if (_universe.hasInvokedGetter(function, _openWorld)) {
|
||||
_registerClosurizedMember(function);
|
||||
_addToWorkList(function);
|
||||
return;
|
||||
}
|
||||
// Store the member in [instanceFunctionsByName] to catch
|
||||
// getters on the function.
|
||||
instanceFunctionsByName
|
||||
_instanceFunctionsByName
|
||||
.putIfAbsent(memberName, () => new Set<Element>())
|
||||
.add(member);
|
||||
if (_universe.hasInvocation(function, openWorld)) {
|
||||
addToWorkList(function);
|
||||
if (_universe.hasInvocation(function, _openWorld)) {
|
||||
_addToWorkList(function);
|
||||
return;
|
||||
}
|
||||
} else if (member.isGetter) {
|
||||
FunctionElement getter = member;
|
||||
getter.computeType(resolution);
|
||||
if (_universe.hasInvokedGetter(getter, openWorld)) {
|
||||
addToWorkList(getter);
|
||||
getter.computeType(_resolution);
|
||||
if (_universe.hasInvokedGetter(getter, _openWorld)) {
|
||||
_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, openWorld)) {
|
||||
addToWorkList(getter);
|
||||
if (_universe.hasInvocation(getter, _openWorld)) {
|
||||
_addToWorkList(getter);
|
||||
return;
|
||||
}
|
||||
} else if (member.isSetter) {
|
||||
FunctionElement setter = member;
|
||||
setter.computeType(resolution);
|
||||
if (_universe.hasInvokedSetter(setter, openWorld)) {
|
||||
addToWorkList(setter);
|
||||
setter.computeType(_resolution);
|
||||
if (_universe.hasInvokedSetter(setter, _openWorld)) {
|
||||
_addToWorkList(setter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// The element is not yet used. Add it to the list of instance
|
||||
// members to still be processed.
|
||||
instanceMembersByName
|
||||
_instanceMembersByName
|
||||
.putIfAbsent(memberName, () => new Set<Element>())
|
||||
.add(member);
|
||||
}
|
||||
|
||||
void processInstantiatedClass(ClassElement cls) {
|
||||
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);
|
||||
cls.ensureResolved(_resolution);
|
||||
|
||||
void processClass(ClassElement superclass) {
|
||||
if (_processedClasses.contains(superclass)) return;
|
||||
|
||||
_processedClasses.add(superclass);
|
||||
recentClasses.add(superclass);
|
||||
superclass.ensureResolved(resolution);
|
||||
_recentClasses.add(superclass);
|
||||
superclass.ensureResolved(_resolution);
|
||||
superclass.implementation.forEachMember(processInstantiatedClassMember);
|
||||
resolution.ensureClassMembers(superclass);
|
||||
_resolution.ensureClassMembers(superclass);
|
||||
// We only tell the backend once that [superclass] was instantiated, so
|
||||
// any additional dependencies must be treated as global
|
||||
// dependencies.
|
||||
|
@ -365,15 +356,15 @@ class ResolutionEnqueuer extends EnqueuerImpl {
|
|||
});
|
||||
}
|
||||
|
||||
void registerDynamicUse(DynamicUse dynamicUse) {
|
||||
void processDynamicUse(DynamicUse dynamicUse) {
|
||||
task.measure(() {
|
||||
if (_universe.registerDynamicUse(dynamicUse)) {
|
||||
handleUnseenSelector(dynamicUse);
|
||||
_handleUnseenSelector(dynamicUse);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void processSet(
|
||||
void _processSet(
|
||||
Map<String, Set<Element>> map, String memberName, bool f(Element e)) {
|
||||
Set<Element> members = map[memberName];
|
||||
if (members == null) return;
|
||||
|
@ -388,35 +379,31 @@ class ResolutionEnqueuer extends EnqueuerImpl {
|
|||
map[memberName].addAll(remaining);
|
||||
}
|
||||
|
||||
processInstanceMembers(String n, bool f(Element e)) {
|
||||
processSet(instanceMembersByName, n, f);
|
||||
void _processInstanceMembers(String n, bool f(Element e)) {
|
||||
_processSet(_instanceMembersByName, n, f);
|
||||
}
|
||||
|
||||
processInstanceFunctions(String n, bool f(Element e)) {
|
||||
processSet(instanceFunctionsByName, n, f);
|
||||
void _processInstanceFunctions(String n, bool f(Element e)) {
|
||||
_processSet(_instanceFunctionsByName, n, f);
|
||||
}
|
||||
|
||||
void handleUnseenSelector(DynamicUse universeSelector) {
|
||||
strategy.processDynamicUse(this, universeSelector);
|
||||
}
|
||||
|
||||
void handleUnseenSelectorInternal(DynamicUse dynamicUse) {
|
||||
void _handleUnseenSelector(DynamicUse dynamicUse) {
|
||||
Selector selector = dynamicUse.selector;
|
||||
String methodName = selector.name;
|
||||
processInstanceMembers(methodName, (Element member) {
|
||||
if (dynamicUse.appliesUnnamed(member, openWorld)) {
|
||||
_processInstanceMembers(methodName, (Element member) {
|
||||
if (dynamicUse.appliesUnnamed(member, _openWorld)) {
|
||||
if (member.isFunction && selector.isGetter) {
|
||||
registerClosurizedMember(member);
|
||||
_registerClosurizedMember(member);
|
||||
}
|
||||
addToWorkList(member);
|
||||
_addToWorkList(member);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (selector.isGetter) {
|
||||
processInstanceFunctions(methodName, (Element member) {
|
||||
if (dynamicUse.appliesUnnamed(member, openWorld)) {
|
||||
registerClosurizedMember(member);
|
||||
_processInstanceFunctions(methodName, (Element member) {
|
||||
if (dynamicUse.appliesUnnamed(member, _openWorld)) {
|
||||
_registerClosurizedMember(member);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -424,16 +411,7 @@ class ResolutionEnqueuer extends EnqueuerImpl {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Documentation wanted -- johnniwinther
|
||||
*
|
||||
* Invariant: [element] must be a declaration element.
|
||||
*/
|
||||
void registerStaticUse(StaticUse staticUse) {
|
||||
strategy.processStaticUse(this, staticUse);
|
||||
}
|
||||
|
||||
void registerStaticUseInternal(StaticUse staticUse) {
|
||||
void processStaticUse(StaticUse staticUse) {
|
||||
Element element = staticUse.element;
|
||||
assert(invariant(element, element.isDeclaration,
|
||||
message: "Element ${element} is not the declaration."));
|
||||
|
@ -453,7 +431,7 @@ class ResolutionEnqueuer extends EnqueuerImpl {
|
|||
// enqueue.
|
||||
LocalFunctionElement closure = staticUse.element;
|
||||
if (closure.type.containsTypeVariables) {
|
||||
universe.closuresWithFreeTypeVariables.add(closure);
|
||||
_universe.closuresWithFreeTypeVariables.add(closure);
|
||||
}
|
||||
addElement = false;
|
||||
break;
|
||||
|
@ -479,15 +457,11 @@ class ResolutionEnqueuer extends EnqueuerImpl {
|
|||
break;
|
||||
}
|
||||
if (addElement) {
|
||||
addToWorkList(element);
|
||||
_addToWorkList(element);
|
||||
}
|
||||
}
|
||||
|
||||
void registerTypeUse(TypeUse typeUse) {
|
||||
strategy.processTypeUse(this, typeUse);
|
||||
}
|
||||
|
||||
void registerTypeUseInternal(TypeUse typeUse) {
|
||||
void processTypeUse(TypeUse typeUse) {
|
||||
DartType type = typeUse.type;
|
||||
switch (typeUse.kind) {
|
||||
case TypeUseKind.INSTANTIATION:
|
||||
|
@ -507,7 +481,7 @@ class ResolutionEnqueuer extends EnqueuerImpl {
|
|||
_registerIsCheck(type);
|
||||
break;
|
||||
case TypeUseKind.CHECKED_MODE_CHECK:
|
||||
if (options.enableTypeAssertions) {
|
||||
if (_options.enableTypeAssertions) {
|
||||
_registerIsCheck(type);
|
||||
}
|
||||
break;
|
||||
|
@ -517,7 +491,7 @@ class ResolutionEnqueuer extends EnqueuerImpl {
|
|||
}
|
||||
|
||||
void _registerIsCheck(DartType type) {
|
||||
type = _universe.registerIsCheck(type, resolution);
|
||||
type = _universe.registerIsCheck(type, _resolution);
|
||||
// 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.
|
||||
|
@ -530,9 +504,9 @@ class ResolutionEnqueuer extends EnqueuerImpl {
|
|||
_universe.callMethodsWithFreeTypeVariables.add(element);
|
||||
}
|
||||
|
||||
void registerClosurizedMember(TypedElement element) {
|
||||
void _registerClosurizedMember(TypedElement element) {
|
||||
assert(element.isInstanceMember);
|
||||
if (element.computeType(resolution).containsTypeVariables) {
|
||||
if (element.computeType(_resolution).containsTypeVariables) {
|
||||
applyImpact(backend.registerClosureWithFreeTypeVariables(element,
|
||||
forResolution: true));
|
||||
_universe.closuresWithFreeTypeVariables.add(element);
|
||||
|
@ -543,18 +517,20 @@ class ResolutionEnqueuer extends EnqueuerImpl {
|
|||
|
||||
void forEach(void f(WorkItem work)) {
|
||||
do {
|
||||
while (queue.isNotEmpty) {
|
||||
while (_queue.isNotEmpty) {
|
||||
// TODO(johnniwinther): Find an optimal process order.
|
||||
WorkItem work = queue.removeLast();
|
||||
WorkItem work = _queue.removeLast();
|
||||
if (!isProcessed(work.element)) {
|
||||
strategy.processWorkItem(f, work);
|
||||
registerProcessedElement(work.element);
|
||||
}
|
||||
}
|
||||
List recents = recentClasses.toList(growable: false);
|
||||
recentClasses.clear();
|
||||
if (!onQueueEmpty(recents)) recentClasses.addAll(recents);
|
||||
} while (queue.isNotEmpty || recentClasses.isNotEmpty);
|
||||
List recents = _recentClasses.toList(growable: false);
|
||||
_recentClasses.clear();
|
||||
if (!_onQueueEmpty(recents)) {
|
||||
_recentClasses.addAll(recents);
|
||||
}
|
||||
} while (_queue.isNotEmpty || _recentClasses.isNotEmpty);
|
||||
}
|
||||
|
||||
void logSummary(log(message)) {
|
||||
|
@ -564,20 +540,8 @@ class ResolutionEnqueuer extends EnqueuerImpl {
|
|||
|
||||
String toString() => 'Enqueuer($name)';
|
||||
|
||||
/// All declaration elements that have been processed by the resolver.
|
||||
final Set<AstElement> processedElements;
|
||||
|
||||
Iterable<Entity> get processedEntities => processedElements;
|
||||
|
||||
final Queue<ResolutionWorkItem> queue;
|
||||
|
||||
/// Queue of deferred resolution actions to execute when the resolution queue
|
||||
/// has been emptied.
|
||||
final Queue<_DeferredAction> deferredQueue;
|
||||
|
||||
static const ImpactUseCase IMPACT_USE =
|
||||
const ImpactUseCase('ResolutionEnqueuer');
|
||||
|
||||
ImpactUseCase get impactUse => IMPACT_USE;
|
||||
|
||||
bool get isResolutionQueue => true;
|
||||
|
@ -595,26 +559,25 @@ class ResolutionEnqueuer extends EnqueuerImpl {
|
|||
backend.onElementResolved(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) {
|
||||
if (element.isMalformed) return false;
|
||||
/// Adds [element] to the work list if it has not already been processed.
|
||||
///
|
||||
/// Invariant: [element] must be a declaration element.
|
||||
void _addToWorkList(Element element) {
|
||||
assert(invariant(element, element.isDeclaration));
|
||||
if (element.isMalformed) return;
|
||||
|
||||
assert(invariant(element, element is AnalyzableElement,
|
||||
message: 'Element $element is not analyzable.'));
|
||||
if (hasBeenProcessed(element)) return false;
|
||||
if (hasBeenProcessed(element)) return;
|
||||
if (queueIsClosed) {
|
||||
throw new SpannableAssertionFailure(
|
||||
element, "Resolution work list is closed. Trying to add $element.");
|
||||
}
|
||||
|
||||
openWorld.registerUsedElement(element);
|
||||
_openWorld.registerUsedElement(element);
|
||||
|
||||
ResolutionWorkItem workItem = resolution.createWorkItem(element);
|
||||
queue.add(workItem);
|
||||
ResolutionWorkItem workItem = _resolution.createWorkItem(element);
|
||||
_queue.add(workItem);
|
||||
|
||||
// Enable isolate support if we start using something from the isolate
|
||||
// library, or timers for the async library. We exclude constant fields,
|
||||
|
@ -623,13 +586,13 @@ class ResolutionEnqueuer extends EnqueuerImpl {
|
|||
if (!universe.hasIsolateSupport && (!element.isField || !element.isConst)) {
|
||||
String uri = library.canonicalUri.toString();
|
||||
if (uri == 'dart:isolate') {
|
||||
enableIsolateSupport();
|
||||
_enableIsolateSupport();
|
||||
} else if (uri == 'dart:async') {
|
||||
if (element.name == '_createTimer' ||
|
||||
element.name == '_createPeriodicTimer') {
|
||||
// The [:Timer:] class uses the event queue of the isolate
|
||||
// library, so we make sure that event queue is generated.
|
||||
enableIsolateSupport();
|
||||
_enableIsolateSupport();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -642,18 +605,16 @@ class ResolutionEnqueuer extends EnqueuerImpl {
|
|||
_universe.hasRuntimeTypeSupport = true;
|
||||
// TODO(ahe): Record precise dependency here.
|
||||
applyImpact(backend.registerRuntimeType());
|
||||
} else if (commonElements.isFunctionApplyMethod(element)) {
|
||||
} else if (_commonElements.isFunctionApplyMethod(element)) {
|
||||
_universe.hasFunctionApplySupport = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void registerNoSuchMethod(Element element) {
|
||||
void _registerNoSuchMethod(Element element) {
|
||||
backend.registerNoSuchMethod(element);
|
||||
}
|
||||
|
||||
void enableIsolateSupport() {
|
||||
void _enableIsolateSupport() {
|
||||
_universe.hasIsolateSupport = true;
|
||||
applyImpact(backend.enableIsolateSupport(forResolution: true));
|
||||
}
|
||||
|
@ -673,16 +634,16 @@ class ResolutionEnqueuer extends EnqueuerImpl {
|
|||
"Resolution work list is closed. "
|
||||
"Trying to add deferred action for $element");
|
||||
}
|
||||
deferredQueue.add(new _DeferredAction(element, action));
|
||||
_deferredQueue.add(new _DeferredAction(element, action));
|
||||
}
|
||||
|
||||
/// [onQueueEmpty] is called whenever the queue is drained. [recentClasses]
|
||||
/// [_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
|
||||
/// [_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
|
||||
/// 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) {
|
||||
bool _onQueueEmpty(Iterable<ClassElement> recentClasses) {
|
||||
_emptyDeferredQueue();
|
||||
|
||||
return backend.onQueueEmpty(this, recentClasses);
|
||||
|
@ -691,17 +652,17 @@ class ResolutionEnqueuer extends EnqueuerImpl {
|
|||
void emptyDeferredQueueForTesting() => _emptyDeferredQueue();
|
||||
|
||||
void _emptyDeferredQueue() {
|
||||
while (!deferredQueue.isEmpty) {
|
||||
_DeferredAction task = deferredQueue.removeFirst();
|
||||
reporter.withCurrentElement(task.element, task.action);
|
||||
while (!_deferredQueue.isEmpty) {
|
||||
_DeferredAction task = _deferredQueue.removeFirst();
|
||||
_reporter.withCurrentElement(task.element, task.action);
|
||||
}
|
||||
}
|
||||
|
||||
void forgetElement(Element element, Compiler compiler) {
|
||||
_universe.forgetElement(element, compiler);
|
||||
_processedClasses.remove(element);
|
||||
instanceMembersByName[element.name]?.remove(element);
|
||||
instanceFunctionsByName[element.name]?.remove(element);
|
||||
_instanceMembersByName[element.name]?.remove(element);
|
||||
_instanceFunctionsByName[element.name]?.remove(element);
|
||||
processedElements.remove(element);
|
||||
}
|
||||
}
|
||||
|
@ -755,7 +716,7 @@ class DirectEnqueuerStrategy extends EnqueuerStrategy {
|
|||
const DirectEnqueuerStrategy();
|
||||
void processStaticUse(EnqueuerImpl enqueuer, StaticUse staticUse) {
|
||||
if (staticUse.kind == StaticUseKind.DIRECT_USE) {
|
||||
enqueuer.registerStaticUseInternal(staticUse);
|
||||
enqueuer.processStaticUse(staticUse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -771,17 +732,17 @@ class TreeShakingEnqueuerStrategy extends EnqueuerStrategy {
|
|||
|
||||
@override
|
||||
void processStaticUse(EnqueuerImpl enqueuer, StaticUse staticUse) {
|
||||
enqueuer.registerStaticUseInternal(staticUse);
|
||||
enqueuer.processStaticUse(staticUse);
|
||||
}
|
||||
|
||||
@override
|
||||
void processTypeUse(EnqueuerImpl enqueuer, TypeUse typeUse) {
|
||||
enqueuer.registerTypeUseInternal(typeUse);
|
||||
enqueuer.processTypeUse(typeUse);
|
||||
}
|
||||
|
||||
@override
|
||||
void processDynamicUse(EnqueuerImpl enqueuer, DynamicUse dynamicUse) {
|
||||
enqueuer.handleUnseenSelectorInternal(dynamicUse);
|
||||
enqueuer.processDynamicUse(dynamicUse);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -792,17 +753,17 @@ class EnqueuerImplImpactVisitor implements WorldImpactVisitor {
|
|||
|
||||
@override
|
||||
void visitDynamicUse(DynamicUse dynamicUse) {
|
||||
enqueuer.registerDynamicUse(dynamicUse);
|
||||
enqueuer.strategy.processDynamicUse(enqueuer, dynamicUse);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitStaticUse(StaticUse staticUse) {
|
||||
enqueuer.registerStaticUse(staticUse);
|
||||
enqueuer.strategy.processStaticUse(enqueuer, staticUse);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitTypeUse(TypeUse typeUse) {
|
||||
enqueuer.registerTypeUse(typeUse);
|
||||
enqueuer.strategy.processTypeUse(enqueuer, typeUse);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,12 +48,12 @@ class CodegenEnqueuer extends EnqueuerImpl {
|
|||
@deprecated
|
||||
final Compiler _compiler; // TODO(ahe): Remove this dependency.
|
||||
final EnqueuerStrategy strategy;
|
||||
final Map<String, Set<Element>> instanceMembersByName =
|
||||
final Map<String, Set<Element>> _instanceMembersByName =
|
||||
new Map<String, Set<Element>>();
|
||||
final Map<String, Set<Element>> instanceFunctionsByName =
|
||||
final Map<String, Set<Element>> _instanceFunctionsByName =
|
||||
new Map<String, Set<Element>>();
|
||||
final Set<ClassElement> _processedClasses = new Set<ClassElement>();
|
||||
Set<ClassElement> recentClasses = new Setlet<ClassElement>();
|
||||
Set<ClassElement> _recentClasses = new Setlet<ClassElement>();
|
||||
final CodegenWorldBuilderImpl _universe =
|
||||
new CodegenWorldBuilderImpl(const TypeMaskStrategy());
|
||||
|
||||
|
@ -61,23 +61,34 @@ class CodegenEnqueuer extends EnqueuerImpl {
|
|||
final CompilerTask task;
|
||||
final native.NativeEnqueuer nativeEnqueuer;
|
||||
|
||||
WorldImpactVisitor impactVisitor;
|
||||
WorldImpactVisitor _impactVisitor;
|
||||
|
||||
final Queue<WorkItem> queue = new Queue<WorkItem>();
|
||||
final Map<Element, js.Expression> generatedCode = <Element, js.Expression>{};
|
||||
|
||||
final Set<Element> newlyEnqueuedElements;
|
||||
|
||||
final Set<DynamicUse> newlySeenSelectors;
|
||||
|
||||
bool _enabledNoSuchMethod = false;
|
||||
|
||||
static const ImpactUseCase IMPACT_USE =
|
||||
const ImpactUseCase('CodegenEnqueuer');
|
||||
|
||||
CodegenEnqueuer(this.task, Compiler compiler, this.strategy)
|
||||
: queue = new Queue<CodegenWorkItem>(),
|
||||
newlyEnqueuedElements = compiler.cacheStrategy.newSet(),
|
||||
: newlyEnqueuedElements = compiler.cacheStrategy.newSet(),
|
||||
newlySeenSelectors = compiler.cacheStrategy.newSet(),
|
||||
nativeEnqueuer = compiler.backend.nativeCodegenEnqueuer(),
|
||||
this.name = 'codegen enqueuer',
|
||||
this._compiler = compiler {
|
||||
impactVisitor = new EnqueuerImplImpactVisitor(this);
|
||||
_impactVisitor = new EnqueuerImplImpactVisitor(this);
|
||||
}
|
||||
|
||||
CodegenWorldBuilder get universe => _universe;
|
||||
|
||||
Backend get backend => _compiler.backend;
|
||||
Backend get _backend => _compiler.backend;
|
||||
|
||||
CompilerOptions get options => _compiler.options;
|
||||
CompilerOptions get _options => _compiler.options;
|
||||
|
||||
ClosedWorld get _world => _compiler.closedWorld;
|
||||
|
||||
|
@ -86,27 +97,26 @@ class CodegenEnqueuer extends EnqueuerImpl {
|
|||
/// Returns [:true:] if this enqueuer is the resolution enqueuer.
|
||||
bool get isResolutionQueue => false;
|
||||
|
||||
DiagnosticReporter get reporter => _compiler.reporter;
|
||||
|
||||
/**
|
||||
* Documentation wanted -- johnniwinther
|
||||
*
|
||||
* Invariant: [element] must be a declaration element.
|
||||
*/
|
||||
void addToWorkList(Element element) {
|
||||
void _addToWorkList(Element element) {
|
||||
assert(invariant(element, element.isDeclaration));
|
||||
// Don't generate code for foreign elements.
|
||||
if (backend.isForeign(element)) return;
|
||||
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) {
|
||||
if (!_options.enableTypeAssertions ||
|
||||
element.enclosingElement.isClosure) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.hasIncrementalSupport && !isProcessed(element)) {
|
||||
if (_options.hasIncrementalSupport && !isProcessed(element)) {
|
||||
newlyEnqueuedElements.add(element);
|
||||
}
|
||||
|
||||
|
@ -114,7 +124,7 @@ class CodegenEnqueuer extends EnqueuerImpl {
|
|||
throw new SpannableAssertionFailure(
|
||||
element, "Codegen work list is closed. Trying to add $element");
|
||||
}
|
||||
queue.add(new CodegenWorkItem(backend, element));
|
||||
queue.add(new CodegenWorkItem(_backend, element));
|
||||
// TODO(sigmund): add other missing dependencies (internals, selectors
|
||||
// enqueued after allocations).
|
||||
_compiler.dumpInfoTask
|
||||
|
@ -124,31 +134,27 @@ class CodegenEnqueuer extends EnqueuerImpl {
|
|||
void applyImpact(WorldImpact worldImpact, {Element impactSource}) {
|
||||
if (worldImpact.isEmpty) return;
|
||||
impactStrategy.visitImpact(
|
||||
impactSource, worldImpact, impactVisitor, impactUse);
|
||||
}
|
||||
|
||||
void registerInstantiatedType(InterfaceType type) {
|
||||
_registerInstantiatedType(type);
|
||||
impactSource, worldImpact, _impactVisitor, impactUse);
|
||||
}
|
||||
|
||||
void _registerInstantiatedType(InterfaceType type,
|
||||
{bool mirrorUsage: false, bool nativeUsage: false}) {
|
||||
task.measure(() {
|
||||
ClassElement cls = type.element;
|
||||
bool isNative = backend.isNative(cls);
|
||||
bool isNative = _backend.isNative(cls);
|
||||
_universe.registerTypeInstantiation(type,
|
||||
isNative: isNative,
|
||||
byMirrors: mirrorUsage, onImplemented: (ClassElement cls) {
|
||||
applyImpact(
|
||||
backend.registerImplementedClass(cls, forResolution: false));
|
||||
_backend.registerImplementedClass(cls, forResolution: false));
|
||||
});
|
||||
if (nativeUsage) {
|
||||
nativeEnqueuer.onInstantiatedType(type);
|
||||
}
|
||||
backend.registerInstantiatedType(type);
|
||||
_backend.registerInstantiatedType(type);
|
||||
// TODO(johnniwinther): Share this reasoning with [Universe].
|
||||
if (!cls.isAbstract || isNative || mirrorUsage) {
|
||||
processInstantiatedClass(cls);
|
||||
_processInstantiatedClass(cls);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -175,13 +181,13 @@ class CodegenEnqueuer extends EnqueuerImpl {
|
|||
// 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 (backend.isNative(cls)) {
|
||||
if (_backend.isNative(cls)) {
|
||||
if (_universe.hasInvokedGetter(member, _world) ||
|
||||
_universe.hasInvocation(member, _world)) {
|
||||
addToWorkList(member);
|
||||
_addToWorkList(member);
|
||||
return;
|
||||
} else if (universe.hasInvokedSetter(member, _world)) {
|
||||
addToWorkList(member);
|
||||
_addToWorkList(member);
|
||||
return;
|
||||
}
|
||||
// Native fields need to go into instanceMembersByName as they
|
||||
|
@ -190,52 +196,52 @@ class CodegenEnqueuer extends EnqueuerImpl {
|
|||
// All field initializers must be resolved as they could
|
||||
// have an observable side-effect (and cannot be tree-shaken
|
||||
// away).
|
||||
addToWorkList(member);
|
||||
_addToWorkList(member);
|
||||
return;
|
||||
}
|
||||
} else if (member.isFunction) {
|
||||
FunctionElement function = member;
|
||||
if (function.name == Identifiers.noSuchMethod_) {
|
||||
registerNoSuchMethod(function);
|
||||
_registerNoSuchMethod(function);
|
||||
}
|
||||
if (function.name == Identifiers.call && !cls.typeVariables.isEmpty) {
|
||||
registerCallMethodWithFreeTypeVariables(function);
|
||||
_registerCallMethodWithFreeTypeVariables(function);
|
||||
}
|
||||
// If there is a property access with the same name as a method we
|
||||
// need to emit the method.
|
||||
if (_universe.hasInvokedGetter(function, _world)) {
|
||||
registerClosurizedMember(function);
|
||||
addToWorkList(function);
|
||||
_registerClosurizedMember(function);
|
||||
_addToWorkList(function);
|
||||
return;
|
||||
}
|
||||
_registerInstanceMethod(function);
|
||||
if (_universe.hasInvocation(function, _world)) {
|
||||
addToWorkList(function);
|
||||
_addToWorkList(function);
|
||||
return;
|
||||
}
|
||||
} else if (member.isGetter) {
|
||||
FunctionElement getter = member;
|
||||
if (_universe.hasInvokedGetter(getter, _world)) {
|
||||
addToWorkList(getter);
|
||||
_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, _world)) {
|
||||
addToWorkList(getter);
|
||||
_addToWorkList(getter);
|
||||
return;
|
||||
}
|
||||
} else if (member.isSetter) {
|
||||
FunctionElement setter = member;
|
||||
if (_universe.hasInvokedSetter(setter, _world)) {
|
||||
addToWorkList(setter);
|
||||
_addToWorkList(setter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// The element is not yet used. Add it to the list of instance
|
||||
// members to still be processed.
|
||||
instanceMembersByName
|
||||
_instanceMembersByName
|
||||
.putIfAbsent(memberName, () => new Set<Element>())
|
||||
.add(member);
|
||||
}
|
||||
|
@ -243,14 +249,12 @@ class CodegenEnqueuer extends EnqueuerImpl {
|
|||
// Store the member in [instanceFunctionsByName] to catch
|
||||
// getters on the function.
|
||||
void _registerInstanceMethod(MethodElement element) {
|
||||
instanceFunctionsByName
|
||||
_instanceFunctionsByName
|
||||
.putIfAbsent(element.name, () => new Set<Element>())
|
||||
.add(element);
|
||||
}
|
||||
|
||||
void enableIsolateSupport() {}
|
||||
|
||||
void processInstantiatedClass(ClassElement cls) {
|
||||
void _processInstantiatedClass(ClassElement cls) {
|
||||
task.measure(() {
|
||||
if (_processedClasses.contains(cls)) return;
|
||||
|
||||
|
@ -266,12 +270,12 @@ class CodegenEnqueuer extends EnqueuerImpl {
|
|||
*/
|
||||
|
||||
_processedClasses.add(superclass);
|
||||
recentClasses.add(superclass);
|
||||
_recentClasses.add(superclass);
|
||||
superclass.implementation.forEachMember(processInstantiatedClassMember);
|
||||
// We only tell the backend once that [superclass] was instantiated, so
|
||||
// any additional dependencies must be treated as global
|
||||
// dependencies.
|
||||
applyImpact(backend.registerInstantiatedClass(superclass,
|
||||
applyImpact(_backend.registerInstantiatedClass(superclass,
|
||||
forResolution: false));
|
||||
}
|
||||
|
||||
|
@ -283,15 +287,15 @@ class CodegenEnqueuer extends EnqueuerImpl {
|
|||
});
|
||||
}
|
||||
|
||||
void registerDynamicUse(DynamicUse dynamicUse) {
|
||||
void processDynamicUse(DynamicUse dynamicUse) {
|
||||
task.measure(() {
|
||||
if (_universe.registerDynamicUse(dynamicUse)) {
|
||||
handleUnseenSelector(dynamicUse);
|
||||
_handleUnseenSelector(dynamicUse);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void processSet(
|
||||
void _processSet(
|
||||
Map<String, Set<Element>> map, String memberName, bool f(Element e)) {
|
||||
Set<Element> members = map[memberName];
|
||||
if (members == null) return;
|
||||
|
@ -306,35 +310,34 @@ class CodegenEnqueuer extends EnqueuerImpl {
|
|||
map[memberName].addAll(remaining);
|
||||
}
|
||||
|
||||
processInstanceMembers(String n, bool f(Element e)) {
|
||||
processSet(instanceMembersByName, n, f);
|
||||
void _processInstanceMembers(String n, bool f(Element e)) {
|
||||
_processSet(_instanceMembersByName, n, f);
|
||||
}
|
||||
|
||||
processInstanceFunctions(String n, bool f(Element e)) {
|
||||
processSet(instanceFunctionsByName, n, f);
|
||||
void _processInstanceFunctions(String n, bool f(Element e)) {
|
||||
_processSet(_instanceFunctionsByName, n, f);
|
||||
}
|
||||
|
||||
void _handleUnseenSelector(DynamicUse universeSelector) {
|
||||
strategy.processDynamicUse(this, universeSelector);
|
||||
}
|
||||
|
||||
void handleUnseenSelectorInternal(DynamicUse dynamicUse) {
|
||||
void _handleUnseenSelector(DynamicUse dynamicUse) {
|
||||
if (_options.hasIncrementalSupport) {
|
||||
newlySeenSelectors.add(dynamicUse);
|
||||
}
|
||||
Selector selector = dynamicUse.selector;
|
||||
String methodName = selector.name;
|
||||
processInstanceMembers(methodName, (Element member) {
|
||||
_processInstanceMembers(methodName, (Element member) {
|
||||
if (dynamicUse.appliesUnnamed(member, _world)) {
|
||||
if (member.isFunction && selector.isGetter) {
|
||||
registerClosurizedMember(member);
|
||||
_registerClosurizedMember(member);
|
||||
}
|
||||
addToWorkList(member);
|
||||
_addToWorkList(member);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (selector.isGetter) {
|
||||
processInstanceFunctions(methodName, (Element member) {
|
||||
_processInstanceFunctions(methodName, (Element member) {
|
||||
if (dynamicUse.appliesUnnamed(member, _world)) {
|
||||
registerClosurizedMember(member);
|
||||
_registerClosurizedMember(member);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -342,25 +345,16 @@ class CodegenEnqueuer extends EnqueuerImpl {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Documentation wanted -- johnniwinther
|
||||
*
|
||||
* Invariant: [element] must be a declaration element.
|
||||
*/
|
||||
void registerStaticUse(StaticUse staticUse) {
|
||||
strategy.processStaticUse(this, staticUse);
|
||||
}
|
||||
|
||||
void registerStaticUseInternal(StaticUse staticUse) {
|
||||
void processStaticUse(StaticUse staticUse) {
|
||||
Element element = staticUse.element;
|
||||
assert(invariant(element, element.isDeclaration,
|
||||
message: "Element ${element} is not the declaration."));
|
||||
_universe.registerStaticUse(staticUse);
|
||||
applyImpact(backend.registerStaticUse(element, forResolution: false));
|
||||
applyImpact(_backend.registerStaticUse(element, forResolution: false));
|
||||
bool addElement = true;
|
||||
switch (staticUse.kind) {
|
||||
case StaticUseKind.STATIC_TEAR_OFF:
|
||||
applyImpact(backend.registerGetOfStaticFunction());
|
||||
applyImpact(_backend.registerGetOfStaticFunction());
|
||||
break;
|
||||
case StaticUseKind.FIELD_GET:
|
||||
case StaticUseKind.FIELD_SET:
|
||||
|
@ -379,22 +373,18 @@ class CodegenEnqueuer extends EnqueuerImpl {
|
|||
case StaticUseKind.CONSTRUCTOR_INVOKE:
|
||||
case StaticUseKind.CONST_CONSTRUCTOR_INVOKE:
|
||||
case StaticUseKind.REDIRECTION:
|
||||
registerTypeUseInternal(new TypeUse.instantiation(staticUse.type));
|
||||
processTypeUse(new TypeUse.instantiation(staticUse.type));
|
||||
break;
|
||||
case StaticUseKind.DIRECT_INVOKE:
|
||||
_registerInstanceMethod(staticUse.element);
|
||||
break;
|
||||
}
|
||||
if (addElement) {
|
||||
addToWorkList(element);
|
||||
_addToWorkList(element);
|
||||
}
|
||||
}
|
||||
|
||||
void registerTypeUse(TypeUse typeUse) {
|
||||
strategy.processTypeUse(this, typeUse);
|
||||
}
|
||||
|
||||
void registerTypeUseInternal(TypeUse typeUse) {
|
||||
void processTypeUse(TypeUse typeUse) {
|
||||
DartType type = typeUse.type;
|
||||
switch (typeUse.kind) {
|
||||
case TypeUseKind.INSTANTIATION:
|
||||
|
@ -412,7 +402,7 @@ class CodegenEnqueuer extends EnqueuerImpl {
|
|||
_registerIsCheck(type);
|
||||
break;
|
||||
case TypeUseKind.CHECKED_MODE_CHECK:
|
||||
if (options.enableTypeAssertions) {
|
||||
if (_options.enableTypeAssertions) {
|
||||
_registerIsCheck(type);
|
||||
}
|
||||
break;
|
||||
|
@ -429,18 +419,18 @@ class CodegenEnqueuer extends EnqueuerImpl {
|
|||
assert(!type.isTypeVariable || !type.element.enclosingElement.isTypedef);
|
||||
}
|
||||
|
||||
void registerCallMethodWithFreeTypeVariables(Element element) {
|
||||
applyImpact(backend.registerCallMethodWithFreeTypeVariables(element,
|
||||
void _registerCallMethodWithFreeTypeVariables(Element element) {
|
||||
applyImpact(_backend.registerCallMethodWithFreeTypeVariables(element,
|
||||
forResolution: false));
|
||||
}
|
||||
|
||||
void registerClosurizedMember(TypedElement element) {
|
||||
void _registerClosurizedMember(TypedElement element) {
|
||||
assert(element.isInstanceMember);
|
||||
if (element.type.containsTypeVariables) {
|
||||
applyImpact(backend.registerClosureWithFreeTypeVariables(element,
|
||||
applyImpact(_backend.registerClosureWithFreeTypeVariables(element,
|
||||
forResolution: false));
|
||||
}
|
||||
applyImpact(backend.registerBoundClosure());
|
||||
applyImpact(_backend.registerBoundClosure());
|
||||
}
|
||||
|
||||
void forEach(void f(WorkItem work)) {
|
||||
|
@ -454,24 +444,24 @@ class CodegenEnqueuer extends EnqueuerImpl {
|
|||
// is currently a side-effect of calling `work.run`.
|
||||
}
|
||||
}
|
||||
List recents = recentClasses.toList(growable: false);
|
||||
recentClasses.clear();
|
||||
if (!onQueueEmpty(recents)) recentClasses.addAll(recents);
|
||||
} while (queue.isNotEmpty || recentClasses.isNotEmpty);
|
||||
List recents = _recentClasses.toList(growable: false);
|
||||
_recentClasses.clear();
|
||||
if (!_onQueueEmpty(recents)) _recentClasses.addAll(recents);
|
||||
} while (queue.isNotEmpty || _recentClasses.isNotEmpty);
|
||||
}
|
||||
|
||||
/// [onQueueEmpty] is called whenever the queue is drained. [recentClasses]
|
||||
/// [_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
|
||||
/// [_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
|
||||
/// 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 backend.onQueueEmpty(this, recentClasses);
|
||||
bool _onQueueEmpty(Iterable<ClassElement> recentClasses) {
|
||||
return _backend.onQueueEmpty(this, recentClasses);
|
||||
}
|
||||
|
||||
void logSummary(log(message)) {
|
||||
_logSpecificSummary(log);
|
||||
log('Compiled ${generatedCode.length} methods.');
|
||||
nativeEnqueuer.logSummary(log);
|
||||
}
|
||||
|
||||
|
@ -480,57 +470,34 @@ class CodegenEnqueuer extends EnqueuerImpl {
|
|||
void _forgetElement(Element element) {
|
||||
_universe.forgetElement(element, _compiler);
|
||||
_processedClasses.remove(element);
|
||||
instanceMembersByName[element.name]?.remove(element);
|
||||
instanceFunctionsByName[element.name]?.remove(element);
|
||||
_instanceMembersByName[element.name]?.remove(element);
|
||||
_instanceFunctionsByName[element.name]?.remove(element);
|
||||
}
|
||||
|
||||
final Queue<CodegenWorkItem> queue;
|
||||
final Map<Element, js.Expression> generatedCode = <Element, js.Expression>{};
|
||||
|
||||
final Set<Element> newlyEnqueuedElements;
|
||||
|
||||
final Set<DynamicUse> newlySeenSelectors;
|
||||
|
||||
bool enabledNoSuchMethod = false;
|
||||
|
||||
static const ImpactUseCase IMPACT_USE =
|
||||
const ImpactUseCase('CodegenEnqueuer');
|
||||
|
||||
ImpactUseCase get impactUse => IMPACT_USE;
|
||||
|
||||
bool isProcessed(Element member) =>
|
||||
member.isAbstract || generatedCode.containsKey(member);
|
||||
|
||||
void registerNoSuchMethod(Element element) {
|
||||
if (!enabledNoSuchMethod && backend.enabledNoSuchMethod) {
|
||||
applyImpact(backend.enableNoSuchMethod());
|
||||
enabledNoSuchMethod = true;
|
||||
void _registerNoSuchMethod(Element element) {
|
||||
if (!_enabledNoSuchMethod && _backend.enabledNoSuchMethod) {
|
||||
applyImpact(_backend.enableNoSuchMethod());
|
||||
_enabledNoSuchMethod = true;
|
||||
}
|
||||
}
|
||||
|
||||
void _logSpecificSummary(log(message)) {
|
||||
log('Compiled ${generatedCode.length} methods.');
|
||||
}
|
||||
|
||||
void forgetElement(Element element, Compiler compiler) {
|
||||
_forgetElement(element);
|
||||
generatedCode.remove(element);
|
||||
if (element is MemberElement) {
|
||||
for (Element closure in element.nestedClosures) {
|
||||
generatedCode.remove(closure);
|
||||
removeFromSet(instanceMembersByName, closure);
|
||||
removeFromSet(instanceFunctionsByName, closure);
|
||||
removeFromSet(_instanceMembersByName, closure);
|
||||
removeFromSet(_instanceFunctionsByName, closure);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handleUnseenSelector(DynamicUse dynamicUse) {
|
||||
if (options.hasIncrementalSupport) {
|
||||
newlySeenSelectors.add(dynamicUse);
|
||||
}
|
||||
_handleUnseenSelector(dynamicUse);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<Entity> get processedEntities => generatedCode.keys;
|
||||
|
||||
|
|
|
@ -139,7 +139,7 @@ abstract class ResolutionWorldBuilder implements WorldBuilder {
|
|||
/// variables.
|
||||
///
|
||||
/// A live function is one whose enclosing member function has been enqueued.
|
||||
Set<Element> get closuresWithFreeTypeVariables;
|
||||
Iterable<Element> get closuresWithFreeTypeVariables;
|
||||
|
||||
/// Set of (live) `call` methods whose signatures reference type variables.
|
||||
///
|
||||
|
|
|
@ -26,7 +26,7 @@ void checkInstantiated(Compiler compiler, ClassElement cls, bool expected) {
|
|||
ResolutionEnqueuer enqueuer = compiler.enqueuer.resolution;
|
||||
bool isInstantiated =
|
||||
enqueuer.universe.directlyInstantiatedClasses.contains(cls);
|
||||
bool isProcessed = enqueuer.isClassProcessed(cls);
|
||||
bool isProcessed = enqueuer.processedClasses.contains(cls);
|
||||
Expect.equals(expected, isInstantiated,
|
||||
'Unexpected instantiation state of class $cls.');
|
||||
Expect.equals(
|
||||
|
|
Loading…
Reference in a new issue