| Index: pkg/fletchc/lib/src/dynamic_call_enqueuer.dart
|
| diff --git a/pkg/fletchc/lib/src/dynamic_call_enqueuer.dart b/pkg/fletchc/lib/src/dynamic_call_enqueuer.dart
|
| deleted file mode 100644
|
| index 99066c64581589f25f0cd6beb00206e1c6a77d49..0000000000000000000000000000000000000000
|
| --- a/pkg/fletchc/lib/src/dynamic_call_enqueuer.dart
|
| +++ /dev/null
|
| @@ -1,297 +0,0 @@
|
| -// Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file
|
| -// for details. All rights reserved. Use of this source code is governed by a
|
| -// BSD-style license that can be found in the LICENSE.md file.
|
| -
|
| -library fletchc.dynamic_call_enqueuer;
|
| -
|
| -import 'dart:collection' show
|
| - Queue;
|
| -
|
| -import 'package:compiler/src/universe/selector.dart' show
|
| - Selector;
|
| -
|
| -import 'package:compiler/src/universe/use.dart' show
|
| - DynamicUse;
|
| -
|
| -import 'package:compiler/src/dart_types.dart' show
|
| - DartType,
|
| - InterfaceType,
|
| - TypeKind;
|
| -
|
| -import 'package:compiler/src/elements/elements.dart' show
|
| - ClassElement,
|
| - Element,
|
| - FunctionElement,
|
| - LibraryElement,
|
| - MemberElement,
|
| - Name;
|
| -
|
| -import 'package:compiler/src/common/names.dart' show
|
| - Identifiers,
|
| - Names;
|
| -
|
| -import 'package:compiler/src/util/util.dart' show
|
| - Hashing;
|
| -
|
| -import 'fletch_compiler_implementation.dart' show
|
| - FletchCompilerImplementation;
|
| -
|
| -import 'fletch_enqueuer.dart' show
|
| - shouldReportEnqueuingOfElement;
|
| -
|
| -import 'fletch_registry.dart' show
|
| - ClosureKind;
|
| -
|
| -abstract class UsageRecorder {
|
| - void recordElementUsage(Element element, Selector selector);
|
| -
|
| - void recordClosurizationUsage(Closurization closurization, Selector selector);
|
| -
|
| - void recordTypeTest(ClassElement element, InterfaceType type);
|
| -}
|
| -
|
| -/// Implements the dynamic part of the tree-shaking algorithm.
|
| -///
|
| -/// By "dynamic" part we mean the part that is about matching instantiated
|
| -/// classes with called instance methods.
|
| -class DynamicCallEnqueuer {
|
| - final FletchCompilerImplementation compiler;
|
| -
|
| - final Set<ClassElement> instantiatedClasses = new Set<ClassElement>();
|
| -
|
| - final Queue<ClassElement> pendingInstantiatedClasses =
|
| - new Queue<ClassElement>();
|
| -
|
| - final Set<Selector> enqueuedSelectors = new Set<Selector>();
|
| -
|
| - final Queue<Selector> pendingSelectors = new Queue<Selector>();
|
| -
|
| - /// Set of functions that have been closurized
|
| - final Set<Closurization> implicitClosurizations = new Set<Closurization>();
|
| -
|
| - /// Queue of functions that have been closurized and have yet to be
|
| - /// processed
|
| - final Queue<Closurization> pendingImplicitClosurizations =
|
| - new Queue<Closurization>();
|
| -
|
| - final Set<InterfaceType> typeTests = new Set<InterfaceType>();
|
| -
|
| - final Queue<InterfaceType> pendingTypeTests = new Queue<InterfaceType>();
|
| -
|
| - DynamicCallEnqueuer(this.compiler);
|
| -
|
| - void registerInstantiatedType(InterfaceType type) {
|
| - ClassElement cls = type.element.declaration;
|
| - if (instantiatedClasses.add(cls)) {
|
| - pendingInstantiatedClasses.addLast(cls);
|
| - }
|
| - }
|
| -
|
| - void enqueueApplicableMembers(
|
| - ClassElement cls,
|
| - Selector selector,
|
| - UsageRecorder recorder) {
|
| - Element member = cls.lookupByName(selector.memberName);
|
| - if (member == null) return;
|
| - if (!member.isInstanceMember) return;
|
| - if (selector.isGetter) {
|
| - if (member.isField || member.isGetter) {
|
| - recorder.recordElementUsage(member, selector);
|
| - } else {
|
| - // Tear-off.
|
| - compiler.reportVerboseInfo(member, "enqueued as tear-off");
|
| - // This lets the backend generate the tear-off getter because it is
|
| - // told that [member] is used as a getter.
|
| - recorder.recordElementUsage(member, selector);
|
| - // This registers [member] as an instantiated closure class.
|
| - enqueueClosure(member, ClosureKind.tearOff);
|
| - }
|
| - } else if (selector.isSetter) {
|
| - if (member.isField || member.isSetter) {
|
| - recorder.recordElementUsage(member, selector);
|
| - }
|
| - } else if (member.isFunction && selector.signatureApplies(member)) {
|
| - recorder.recordElementUsage(member, selector);
|
| - } else if (member.isGetter || member.isField) {
|
| - // A getter/field can be invoked as a method, for example, if the getter
|
| - // returns a closure.
|
| - recorder.recordElementUsage(member, selector);
|
| - }
|
| - }
|
| -
|
| - void enqueueClosureIfApplicable(
|
| - Closurization closurization,
|
| - Selector selector,
|
| - UsageRecorder recorder) {
|
| - FunctionElement function = closurization.function;
|
| - if ((selector.isGetter || selector.isCall) &&
|
| - selector.memberName == Names.call &&
|
| - selector.signatureApplies(function)) {
|
| - recorder.recordClosurizationUsage(closurization, selector);
|
| - }
|
| - }
|
| -
|
| - void enqueueApplicableTypeTests(
|
| - ClassElement cls,
|
| - InterfaceType type,
|
| - UsageRecorder recorder) {
|
| - if (cls == type.element) {
|
| - recorder.recordTypeTest(cls, type);
|
| - return;
|
| - }
|
| - for (DartType supertype in cls.allSupertypes) {
|
| - if (supertype.element == type.element) {
|
| - recorder.recordTypeTest(cls, type);
|
| - return;
|
| - }
|
| - }
|
| - }
|
| -
|
| - void enqueueInstanceMethods(UsageRecorder recorder) {
|
| - // TODO(ahe): Implement a faster way to iterate through selectors. For
|
| - // example, use the same approach as dart2js uses where selectors are
|
| - // grouped by name. This applies both to enqueuedSelectors and
|
| - // pendingSelectors.
|
| - while (pendingInstantiatedClasses.isNotEmpty) {
|
| - ClassElement cls = pendingInstantiatedClasses.removeFirst();
|
| - if (shouldReportEnqueuingOfElement(compiler, cls)) {
|
| - compiler.reportVerboseInfo(cls, "was instantiated");
|
| - }
|
| - for (Selector selector in enqueuedSelectors) {
|
| - // TODO(ahe): As we iterate over enqueuedSelectors, we may end up
|
| - // processing calling _enqueueApplicableMembers twice for newly
|
| - // instantiated classes. Once here, and then once more in the while
|
| - // loop below.
|
| - enqueueApplicableMembers(cls, selector, recorder);
|
| - }
|
| - for (InterfaceType type in typeTests) {
|
| - enqueueApplicableTypeTests(cls, type, recorder);
|
| - }
|
| - }
|
| - while (pendingImplicitClosurizations.isNotEmpty) {
|
| - Closurization closurization = pendingImplicitClosurizations.removeFirst();
|
| - if (shouldReportEnqueuingOfElement(compiler, closurization.function)) {
|
| - compiler.reportVerboseInfo(closurization.function, "was closurized");
|
| - }
|
| - for (Selector selector in enqueuedSelectors) {
|
| - enqueueClosureIfApplicable(closurization, selector, recorder);
|
| - }
|
| - // TODO(ahe): Also enqueue type tests here.
|
| - }
|
| - while (pendingSelectors.isNotEmpty) {
|
| - Selector selector = pendingSelectors.removeFirst();
|
| - for (ClassElement cls in instantiatedClasses) {
|
| - enqueueApplicableMembers(cls, selector, recorder);
|
| - }
|
| - for (Closurization closurization in implicitClosurizations) {
|
| - enqueueClosureIfApplicable(closurization, selector, recorder);
|
| - }
|
| - }
|
| - while(!pendingTypeTests.isEmpty) {
|
| - InterfaceType type = pendingTypeTests.removeFirst();
|
| - for (ClassElement cls in instantiatedClasses) {
|
| - enqueueApplicableTypeTests(cls, type, recorder);
|
| - }
|
| - // TODO(ahe): Also enqueue type tests for closures.
|
| - }
|
| - }
|
| -
|
| - void enqueueSelector(DynamicUse use) {
|
| - assert(use.mask == null);
|
| - Selector selector = use.selector;
|
| - if (enqueuedSelectors.add(selector)) {
|
| - pendingSelectors.add(selector);
|
| - }
|
| - }
|
| -
|
| - void enqueueClosure(FunctionElement function, ClosureKind kind) {
|
| - Closurization closurization = new Closurization(function, kind);
|
| - if (implicitClosurizations.add(closurization)) {
|
| - pendingImplicitClosurizations.add(closurization);
|
| - }
|
| - }
|
| -
|
| - void forgetElement(Element element) {
|
| - void revisitClass(ClassElement cls) {
|
| - if (instantiatedClasses.remove(cls)) {
|
| - // [cls] was already instantiated, now we need to make sure enqueue its
|
| - // members again in [enqueueInstanceMethods] above.
|
| - pendingInstantiatedClasses.add(cls);
|
| - }
|
| - }
|
| - if (!instantiatedClasses.remove(element)) {
|
| - // If a class is removed, the incremental compiler will first forget its
|
| - // members. This can move the class to pendingInstantiatedClasses.
|
| - pendingInstantiatedClasses.remove(element);
|
| - }
|
| - if (element.isInstanceMember) {
|
| - ClassElement modifiedClass = element.enclosingClass;
|
| - revisitClass(modifiedClass);
|
| - MemberElement member = element;
|
| - for (ClassElement cls in instantiatedClasses) {
|
| - // TODO(ahe): Make O(1).
|
| - if (cls.lookupByName(member.memberName) == member) {
|
| - revisitClass(cls);
|
| - // Once we have found one class that implements [member], we're
|
| - // done. When we later call [enqueueInstanceMethods] (via
|
| - // [FletchEnqueuer.processQueue]) the method will be enqueued again
|
| - // (if it exists).
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - List<Closurization> toBeRemoved = <Closurization>[];
|
| - for (Closurization closurization in implicitClosurizations) {
|
| - if (closurization.function == element) {
|
| - toBeRemoved.add(closurization);
|
| - }
|
| - }
|
| - implicitClosurizations.removeAll(toBeRemoved);
|
| - }
|
| -
|
| - void enqueueTypeTest(DartType type) {
|
| - type = type.asRaw();
|
| - switch (type.kind) {
|
| - case TypeKind.INTERFACE:
|
| - enqueueRawInterfaceType(type);
|
| - break;
|
| -
|
| - default:
|
| - // Ignored.
|
| - break;
|
| - }
|
| - }
|
| -
|
| - void enqueueRawInterfaceType(InterfaceType type) {
|
| - assert(type.isRaw);
|
| - if (typeTests.add(type)) {
|
| - pendingTypeTests.add(type);
|
| - }
|
| - }
|
| -}
|
| -
|
| -/// Track that [function] is used as a closure. This can happen for various
|
| -/// reasons, see [ClosureKind] for more details. In practical terms, this means
|
| -/// that we need a class whose `call` method invokes [function]. For
|
| -/// [ClosureKind.functionLike], the class is a normal class with source
|
| -/// code. For most other kinds, the class is synthetic and doesn't have a
|
| -/// corresponding element.
|
| -class Closurization {
|
| - final FunctionElement function;
|
| -
|
| - final ClosureKind kind;
|
| -
|
| - final int hashCode;
|
| -
|
| - Closurization(FunctionElement function, ClosureKind kind)
|
| - : function = function,
|
| - kind = kind,
|
| - hashCode = Hashing.mixHashCodeBits(function.hashCode, kind.hashCode);
|
| -
|
| - bool operator ==(other) {
|
| - return other is Closurization &&
|
| - function == other.function && kind == other.kind;
|
| - }
|
| -
|
| - String toString() => "Closurization($function, $kind)";
|
| -}
|
|
|