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

Unified Diff: pkg/compiler/lib/src/js_backend/enqueuer.dart

Issue 2587913004: Move class/member computation from CodegenEnqueuer to CodegenWorldBuilder. (Closed)
Patch Set: Cleanup. Created 4 years 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: 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 4784df02cf69b31160c2a68d7a8e4d8efb5820ac..673d186adcd58f3a2c891b9e6ca9d5883fa5a7e3 100644
--- a/pkg/compiler/lib/src/js_backend/enqueuer.dart
+++ b/pkg/compiler/lib/src/js_backend/enqueuer.dart
@@ -9,49 +9,34 @@ import 'dart:collection' show Queue;
import '../cache_strategy.dart' show CacheStrategy;
import '../common/backend_api.dart' show Backend;
import '../common/codegen.dart' show CodegenWorkItem;
-import '../common/names.dart' show Identifiers;
import '../common/tasks.dart' show CompilerTask;
import '../common/work.dart' show WorkItem;
import '../common.dart';
import '../compiler.dart' show Compiler;
import '../dart_types.dart' show DartType, InterfaceType;
-import '../dump_info.dart';
import '../elements/elements.dart'
- show
- ClassElement,
- Element,
- Entity,
- FunctionElement,
- MemberElement,
- MethodElement,
- TypedElement;
+ show ClassElement, Element, Entity, MemberElement, TypedElement;
import '../elements/entities.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/world_builder.dart';
import '../universe/use.dart'
show DynamicUse, StaticUse, StaticUseKind, TypeUse, TypeUseKind;
import '../universe/world_impact.dart'
show ImpactUseCase, WorldImpact, WorldImpactVisitor;
+import '../util/enumset.dart';
import '../util/util.dart' show Setlet;
-import '../world.dart';
/// [Enqueuer] which is specific to code generation.
class CodegenEnqueuer extends EnqueuerImpl {
final String name;
final EnqueuerStrategy strategy;
- final Map<String, Set<Element>> _instanceMembersByName =
- new Map<String, Set<Element>>();
- final Map<String, Set<Element>> _instanceFunctionsByName =
- new Map<String, Set<Element>>();
- final Set<ClassElement> _processedClasses = new Set<ClassElement>();
+
Set<ClassElement> _recentClasses = new Setlet<ClassElement>();
- final CodegenWorldBuilderImpl _universe =
- new CodegenWorldBuilderImpl(const TypeMaskStrategy());
+ final CodegenWorldBuilderImpl _universe;
bool queueIsClosed = false;
final CompilerTask task;
@@ -68,14 +53,14 @@ class CodegenEnqueuer extends EnqueuerImpl {
final Set<DynamicUse> newlySeenSelectors;
- bool _enabledNoSuchMethod = false;
-
static const ImpactUseCase IMPACT_USE =
const ImpactUseCase('CodegenEnqueuer');
CodegenEnqueuer(this.task, CacheStrategy cacheStrategy, Backend backend,
this._options, this.strategy)
- : newlyEnqueuedElements = cacheStrategy.newSet(),
+ : _universe =
+ new CodegenWorldBuilderImpl(backend, const TypeMaskStrategy()),
+ newlyEnqueuedElements = cacheStrategy.newSet(),
newlySeenSelectors = cacheStrategy.newSet(),
nativeEnqueuer = backend.nativeCodegenEnqueuer(),
this._backend = backend,
@@ -85,10 +70,6 @@ class CodegenEnqueuer extends EnqueuerImpl {
CodegenWorldBuilder get universe => _universe;
- // TODO(johnniwinther): Remove these hacks:
- ClosedWorld get _world => _backend.compiler.closedWorld;
- DumpInfoTask get _dumpInfoTask => _backend.compiler.dumpInfoTask;
-
bool get queueIsEmpty => _queue.isEmpty;
/// Returns [:true:] if this enqueuer is the resolution enqueuer.
@@ -122,9 +103,7 @@ class CodegenEnqueuer extends EnqueuerImpl {
element, "Codegen work list is closed. Trying to add $element");
}
_queue.add(new CodegenWorkItem(_backend, element));
- // TODO(sigmund): add other missing dependencies (internals, selectors
- // enqueued after allocations).
- _dumpInfoTask.registerDependency(element);
+ applyImpact(_backend.registerUsedElement(element, forResolution: false));
}
void applyImpact(WorldImpact worldImpact, {Element impactSource}) {
@@ -136,22 +115,12 @@ class CodegenEnqueuer extends EnqueuerImpl {
void _registerInstantiatedType(InterfaceType type,
{bool mirrorUsage: false, bool nativeUsage: false}) {
task.measure(() {
- ClassElement cls = type.element;
- bool isNative = _backend.isNative(cls);
- _universe.registerTypeInstantiation(type,
- isNative: isNative,
- byMirrors: mirrorUsage, onImplemented: (ClassElement cls) {
- applyImpact(
- _backend.registerImplementedClass(cls, forResolution: false));
- });
+ _universe.registerTypeInstantiation(type, _applyClassUse,
+ byMirrors: mirrorUsage);
if (nativeUsage) {
nativeEnqueuer.onInstantiatedType(type);
}
_backend.registerInstantiatedType(type);
- // TODO(johnniwinther): Share this reasoning with [Universe].
- if (!cls.isAbstract || isNative || mirrorUsage) {
- _processInstantiatedClass(cls);
- }
});
}
@@ -160,224 +129,67 @@ class CodegenEnqueuer extends EnqueuerImpl {
}
void checkClass(ClassElement cls) {
- cls.implementation.forEachMember(processInstantiatedClassMember);
- }
-
- void processInstantiatedClassMember(ClassElement cls, Element member) {
- assert(invariant(member, member.isDeclaration));
- if (isProcessed(member)) return;
- if (!member.isInstanceMember) return;
- String memberName = member.name;
-
- if (member.isField) {
- // The obvious thing to test here would be "member.isNative",
- // however, that only works after metadata has been parsed/analyzed,
- // and that may not have happened yet.
- // So instead we use the enclosing class, which we know have had
- // 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 (_universe.hasInvokedGetter(member, _world) ||
- _universe.hasInvocation(member, _world)) {
- _addToWorkList(member);
- return;
- } else if (universe.hasInvokedSetter(member, _world)) {
- _addToWorkList(member);
- return;
- }
- // Native fields need to go into instanceMembersByName as they
- // are virtual instantiation points and escape points.
- } else {
- // All field initializers must be resolved as they could
- // have an observable side-effect (and cannot be tree-shaken
- // away).
- _addToWorkList(member);
- return;
- }
- } else if (member.isFunction) {
- FunctionElement function = member;
- if (function.name == Identifiers.noSuchMethod_) {
- _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, _world)) {
- _registerClosurizedMember(function);
- _addToWorkList(function);
- return;
- }
- _registerInstanceMethod(function);
- if (_universe.hasInvocation(function, _world)) {
- _addToWorkList(function);
- return;
- }
- } else if (member.isGetter) {
- FunctionElement getter = member;
- 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, _world)) {
- _addToWorkList(getter);
- return;
- }
- } else if (member.isSetter) {
- FunctionElement setter = member;
- if (_universe.hasInvokedSetter(setter, _world)) {
- _addToWorkList(setter);
- return;
- }
- }
-
- // The element is not yet used. Add it to the list of instance
- // members to still be processed.
- _instanceMembersByName
- .putIfAbsent(memberName, () => new Set<Element>())
- .add(member);
- }
-
- // Store the member in [instanceFunctionsByName] to catch
- // getters on the function.
- void _registerInstanceMethod(MethodElement element) {
- _instanceFunctionsByName
- .putIfAbsent(element.name, () => new Set<Element>())
- .add(element);
- }
-
- void _processInstantiatedClass(ClassElement cls) {
- task.measure(() {
- if (_processedClasses.contains(cls)) return;
-
- 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.
- /*assert(invariant(superclass,
- superclass.isClosure ||
- _compiler.enqueuer.resolution.isClassProcessed(superclass),
- message: "Class $superclass has not been "
- "processed in resolution."));
- */
-
- _processedClasses.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,
- forResolution: false));
- }
-
- ClassElement superclass = cls;
- while (superclass != null) {
- processClass(superclass);
- superclass = superclass.superclass;
- }
- });
- }
-
- void processDynamicUse(DynamicUse dynamicUse) {
- task.measure(() {
- if (_universe.registerDynamicUse(dynamicUse)) {
- _handleUnseenSelector(dynamicUse);
+ _universe.processClassMembers(cls, (MemberElement member, useSet) {
+ if (useSet.isNotEmpty) {
+ _backend.compiler.reporter.internalError(member,
+ 'Unenqueued use of $member: ${useSet.iterable(MemberUse.values)}');
}
});
}
- void _processSet(
- Map<String, Set<Element>> map, String memberName, bool f(Element e)) {
- Set<Element> members = map[memberName];
- if (members == null) return;
- // [f] might add elements to [: map[memberName] :] during the loop below
- // so we create a new list for [: map[memberName] :] and prepend the
- // [remaining] members after the loop.
- map[memberName] = new Set<Element>();
- Set<Element> remaining = new Set<Element>();
- for (Element member in members) {
- if (!f(member)) remaining.add(member);
+ /// Callback for applying the use of a [cls].
+ void _applyClassUse(ClassEntity cls, EnumSet<ClassUse> useSet) {
+ if (useSet.contains(ClassUse.INSTANTIATED)) {
+ _recentClasses.add(cls);
+ _universe.processClassMembers(cls, _applyMemberUse);
+ // We only tell the backend once that [cls] was instantiated, so
+ // any additional dependencies must be treated as global
+ // dependencies.
+ applyImpact(
+ _backend.registerInstantiatedClass(cls, forResolution: false));
+ }
+ if (useSet.contains(ClassUse.IMPLEMENTED)) {
+ applyImpact(_backend.registerImplementedClass(cls, forResolution: false));
}
- map[memberName].addAll(remaining);
- }
-
- void _processInstanceMembers(String n, bool f(Element e)) {
- _processSet(_instanceMembersByName, n, f);
}
- void _processInstanceFunctions(String n, bool f(Element e)) {
- _processSet(_instanceFunctionsByName, n, f);
+ /// Callback for applying the use of a [member].
+ void _applyMemberUse(Entity member, EnumSet<MemberUse> useSet) {
+ if (useSet.contains(MemberUse.NORMAL)) {
+ _addToWorkList(member);
+ }
+ if (useSet.contains(MemberUse.CLOSURIZE_INSTANCE)) {
+ _registerClosurizedMember(member);
+ }
+ if (useSet.contains(MemberUse.CLOSURIZE_STATIC)) {
+ applyImpact(_backend.registerGetOfStaticFunction());
+ }
}
- void _handleUnseenSelector(DynamicUse dynamicUse) {
- if (_options.hasIncrementalSupport) {
- newlySeenSelectors.add(dynamicUse);
- }
- Selector selector = dynamicUse.selector;
- String methodName = selector.name;
- _processInstanceMembers(methodName, (Element member) {
- if (dynamicUse.appliesUnnamed(member, _world)) {
- if (member.isFunction && selector.isGetter) {
- _registerClosurizedMember(member);
+ void processDynamicUse(DynamicUse dynamicUse) {
+ task.measure(() {
+ if (_universe.registerDynamicUse(dynamicUse, _applyMemberUse)) {
+ if (_options.hasIncrementalSupport) {
+ newlySeenSelectors.add(dynamicUse);
}
- _addToWorkList(member);
- return true;
}
- return false;
});
- if (selector.isGetter) {
- _processInstanceFunctions(methodName, (Element member) {
- if (dynamicUse.appliesUnnamed(member, _world)) {
- _registerClosurizedMember(member);
- return true;
- }
- return false;
- });
- }
}
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.registerUsedElement(element, forResolution: false));
- bool addElement = true;
+ _universe.registerStaticUse(staticUse, _applyMemberUse);
switch (staticUse.kind) {
- case StaticUseKind.STATIC_TEAR_OFF:
- applyImpact(_backend.registerGetOfStaticFunction());
- break;
- case StaticUseKind.FIELD_GET:
- case StaticUseKind.FIELD_SET:
- case StaticUseKind.CLOSURE:
- // TODO(johnniwinther): Avoid this. Currently [FIELD_GET] and
- // [FIELD_SET] contains [BoxFieldElement]s which we cannot enqueue.
- // Also [CLOSURE] contains [LocalFunctionElement] which we cannot
- // enqueue.
- addElement = false;
- break;
- case StaticUseKind.SUPER_FIELD_SET:
- case StaticUseKind.SUPER_TEAR_OFF:
- case StaticUseKind.GENERAL:
- case StaticUseKind.DIRECT_USE:
- break;
case StaticUseKind.CONSTRUCTOR_INVOKE:
case StaticUseKind.CONST_CONSTRUCTOR_INVOKE:
case StaticUseKind.REDIRECTION:
processTypeUse(new TypeUse.instantiation(staticUse.type));
break;
- case StaticUseKind.DIRECT_INVOKE:
- _registerInstanceMethod(staticUse.element);
+ default:
break;
}
- if (addElement) {
- _addToWorkList(element);
- }
}
void processTypeUse(TypeUse typeUse) {
@@ -415,11 +227,6 @@ class CodegenEnqueuer extends EnqueuerImpl {
assert(!type.isTypeVariable || !type.element.enclosingElement.isTypedef);
}
- void _registerCallMethodWithFreeTypeVariables(Element element) {
- applyImpact(_backend.registerCallMethodWithFreeTypeVariables(element,
- forResolution: false));
- }
-
void _registerClosurizedMember(TypedElement element) {
assert(element.isInstanceMember);
if (element.type.containsTypeVariables) {
@@ -468,24 +275,12 @@ class CodegenEnqueuer extends EnqueuerImpl {
bool isProcessed(Element member) =>
member.isAbstract || generatedCode.containsKey(member);
- void _registerNoSuchMethod(Element element) {
- if (!_enabledNoSuchMethod && _backend.enabledNoSuchMethod) {
- applyImpact(_backend.enableNoSuchMethod());
- _enabledNoSuchMethod = true;
- }
- }
-
void forgetEntity(Element element, Compiler compiler) {
_universe.forgetElement(element, compiler);
- _processedClasses.remove(element);
- _instanceMembersByName[element.name]?.remove(element);
- _instanceFunctionsByName[element.name]?.remove(element);
generatedCode.remove(element);
if (element is MemberElement) {
for (Element closure in element.nestedClosures) {
generatedCode.remove(closure);
- removeFromSet(_instanceMembersByName, closure);
- removeFromSet(_instanceFunctionsByName, closure);
}
}
}
@@ -494,11 +289,5 @@ class CodegenEnqueuer extends EnqueuerImpl {
Iterable<Entity> get processedEntities => generatedCode.keys;
@override
- Iterable<ClassEntity> get processedClasses => _processedClasses;
-}
-
-void removeFromSet(Map<String, Set<Element>> map, Element element) {
- Set<Element> set = map[element.name];
- if (set == null) return;
- set.remove(element);
+ Iterable<ClassEntity> get processedClasses => _universe.processedClasses;
}

Powered by Google App Engine
This is Rietveld 408576698