| Index: sdk/lib/_internal/compiler/implementation/universe/function_set.dart
|
| diff --git a/sdk/lib/_internal/compiler/implementation/universe/function_set.dart b/sdk/lib/_internal/compiler/implementation/universe/function_set.dart
|
| index 7e119da6af2a21cbc4dd8bda37760fe23812ed1f..59b31c648561281ebe33b66709055cdb3fef4a97 100644
|
| --- a/sdk/lib/_internal/compiler/implementation/universe/function_set.dart
|
| +++ b/sdk/lib/_internal/compiler/implementation/universe/function_set.dart
|
| @@ -7,51 +7,45 @@ part of universe;
|
| // TODO(kasperl): This actually holds getters and setters just fine
|
| // too and stricly they aren't functions. Maybe this needs a better
|
| // name -- something like ElementSet seems a bit too generic.
|
| -class FunctionSet extends PartialTypeTree {
|
| +class FunctionSet {
|
| + final Compiler compiler;
|
| + final Map<SourceString, FunctionSetNode> nodes =
|
| + new Map<SourceString, FunctionSetNode>();
|
| + FunctionSet(this.compiler);
|
|
|
| - FunctionSet(Compiler compiler) : super(compiler);
|
| -
|
| - FunctionSetNode newSpecializedNode(ClassElement type)
|
| - => new FunctionSetNode(type);
|
| -
|
| - // TODO(kasperl): Allow static members too?
|
| void add(Element element) {
|
| assert(element.isMember());
|
| - FunctionSetNode node = findNode(element.getEnclosingClass(), true);
|
| - node.membersByName[element.name] = element;
|
| + SourceString name = element.name;
|
| + FunctionSetNode node = nodes.putIfAbsent(
|
| + name, () => new FunctionSetNode(name));
|
| + node.add(element);
|
| }
|
|
|
| - // TODO(kasperl): Allow static members too?
|
| void remove(Element element) {
|
| assert(element.isMember());
|
| - FunctionSetNode node = findNode(element.getEnclosingClass(), false);
|
| - if (node != null) node.membersByName.remove(element.name);
|
| + SourceString name = element.name;
|
| + FunctionSetNode node = nodes[name];
|
| + if (node != null) node.remove(element);
|
| }
|
|
|
| - // TODO(kasperl): Allow static members too?
|
| bool contains(Element element) {
|
| assert(element.isMember());
|
| - FunctionSetNode node = findNode(element.getEnclosingClass(), false);
|
| + SourceString name = element.name;
|
| + FunctionSetNode node = nodes[name];
|
| return (node != null)
|
| - ? node.membersByName.containsKey(element.name)
|
| + ? node.contains(element)
|
| : false;
|
| }
|
|
|
| - bool shouldVisitAll(Selector selector) {
|
| - // TODO(kasperl): For now, we use a different implementation for
|
| - // filtering if the tree contains interface subtypes.
|
| - return containsInterfaceSubtypes
|
| - && (selector.typeKind == TypedSelectorKind.INTERFACE
|
| - || selector.typeKind == TypedSelectorKind.UNKNOWN);
|
| - }
|
| -
|
| /**
|
| * Returns all elements that may be invoked with the given [selector].
|
| */
|
| - Set<Element> filterBySelector(Selector selector) {
|
| - return shouldVisitAll(selector)
|
| - ? filterAllBySelector(selector)
|
| - : filterHierarchyBySelector(selector);
|
| + Iterable<Element> filterBySelector(Selector selector) {
|
| + SourceString name = selector.name;
|
| + FunctionSetNode node = nodes[name];
|
| + return (node != null)
|
| + ? node.filter(selector, compiler)
|
| + : const <Element>[];
|
| }
|
|
|
| /**
|
| @@ -59,86 +53,93 @@ class FunctionSet extends PartialTypeTree {
|
| * [selector].
|
| */
|
| bool hasAnyElementMatchingSelector(Selector selector) {
|
| - return shouldVisitAll(selector)
|
| - ? hasAnyInAll(selector)
|
| - : hasAnyInHierarchy(selector);
|
| + return !filterBySelector(selector).isEmpty;
|
| }
|
|
|
| - Set<Element> filterAllBySelector(Selector selector) {
|
| - Set<Element> result = new Set<Element>();
|
| - if (root == null) return result;
|
| - root.visitRecursively((FunctionSetNode node) {
|
| - Element member = node.membersByName[selector.name];
|
| - // Since we're running through the entire tree we have to use
|
| - // the applies method that takes types into account.
|
| - if (member != null && selector.appliesUnnamed(member, compiler)) {
|
| - result.add(member);
|
| - }
|
| - return true;
|
| + void forEach(Function action) {
|
| + nodes.forEach((SourceString name, FunctionSetNode node) {
|
| + node.forEach(action);
|
| });
|
| - return result;
|
| }
|
| +}
|
|
|
| - Set<Element> filterHierarchyBySelector(Selector selector) {
|
| - Set<Element> result = new Set<Element>();
|
| - if (root == null) return result;
|
| - visitHierarchy(selectorType(selector), (FunctionSetNode node) {
|
| - Element member = node.membersByName[selector.name];
|
| - if (member != null && selector.appliesUntyped(member, compiler)) {
|
| - result.add(member);
|
| - }
|
| - return true;
|
| - });
|
| - return result;
|
| - }
|
| +class FunctionSetNode {
|
| + final SourceString name;
|
| + final Map<Selector, List<Element>> cache = new Map<Selector, List<Element>>();
|
|
|
| - bool hasAnyInAll(Selector selector) {
|
| - bool result = false;
|
| - if (root == null) return result;
|
| - root.visitRecursively((FunctionSetNode node) {
|
| - Element member = node.membersByName[selector.name];
|
| - // Since we're running through the entire tree we have to use
|
| - // the applies method that takes types into account.
|
| - if (member != null && selector.appliesUnnamed(member, compiler)) {
|
| - result = true;
|
| - // End the traversal.
|
| - return false;
|
| + // Initially, we keep the elements in a list because it is more
|
| + // compact than a hash set. Once we get enough elements, we change
|
| + // the representation to be a set to get faster contains checks.
|
| + static const int MAX_ELEMENTS_IN_LIST = 8;
|
| + Collection<Element> elements = <Element>[];
|
| + bool isList = true;
|
| +
|
| + FunctionSetNode(this.name);
|
| +
|
| + void add(Element element) {
|
| + assert(element.name == name);
|
| + // Even when the representation of the elements has changed to a
|
| + // set we try to avoid clearing the cache unless we have to. For
|
| + // that reason we keep the explicit contains check even though the
|
| + // add method ends up doing the work again (for sets).
|
| + if (!elements.contains(element)) {
|
| + if (isList && elements.length >= MAX_ELEMENTS_IN_LIST) {
|
| + elements = elements.toSet();
|
| + isList = false;
|
| }
|
| - return true;
|
| - });
|
| - return result;
|
| + elements.add(element);
|
| + cache.clear();
|
| + }
|
| }
|
|
|
| - bool hasAnyInHierarchy(Selector selector) {
|
| - bool result = false;
|
| - if (root == null) return result;
|
| - visitHierarchy(selectorType(selector), (FunctionSetNode node) {
|
| - Element member = node.membersByName[selector.name];
|
| - if (member != null && selector.appliesUntyped(member, compiler)) {
|
| - result = true;
|
| - // End the traversal.
|
| - return false;
|
| + void remove(Element element) {
|
| + assert(element.name == name);
|
| + if (isList) {
|
| + List list = elements;
|
| + int index = list.indexOf(element);
|
| + if (index < 0) return;
|
| + Element last = list.removeLast();
|
| + if (index != list.length) {
|
| + list[index] = last;
|
| }
|
| - return true;
|
| - });
|
| - return result;
|
| + cache.clear();
|
| + } else {
|
| + Set set = elements;
|
| + if (set.remove(element)) {
|
| + // To avoid wobbling between the two representations, we do
|
| + // not transition back to the list representation even if we
|
| + // end up with few enough elements at this point.
|
| + cache.clear();
|
| + }
|
| + }
|
| }
|
|
|
| - void forEach(Function f) {
|
| - if (root == null) return;
|
| - root.visitRecursively((FunctionSetNode node) {
|
| - node.membersByName.forEach(
|
| - (SourceString _, Element element) => f(element));
|
| - return true;
|
| - });
|
| + bool contains(Element element) {
|
| + assert(element.name == name);
|
| + return elements.contains(element);
|
| }
|
| -}
|
| -
|
| -class FunctionSetNode extends PartialTypeTreeNode {
|
|
|
| - final Map<SourceString, Element> membersByName;
|
| -
|
| - FunctionSetNode(ClassElement type) : super(type),
|
| - membersByName = new Map<SourceString, Element>();
|
| + void forEach(Function action) {
|
| + elements.forEach(action);
|
| + }
|
|
|
| + Iterable<Element> filter(Selector selector, Compiler compiler) {
|
| + assert(selector.name == name);
|
| + List<Element> result = cache[selector];
|
| + if (result != null) return result;
|
| + for (Element element in elements) {
|
| + if (selector.appliesUnnamed(element, compiler)) {
|
| + if (result == null) {
|
| + // Defer the allocation of the resulting list until we are
|
| + // sure we need it. This allows us to return immutable empty
|
| + // lists when the filtering produced no results.
|
| + result = <Element>[];
|
| + }
|
| + result.add(element);
|
| + }
|
| + }
|
| + if (result == null) result = const <Element>[];
|
| + cache[selector] = result;
|
| + return result;
|
| + }
|
| }
|
|
|