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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/universe/selector_map.dart

Issue 12262035: Simplify the selector map and get rid of the partial type tree. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: iterateMatching -> computeMatching. Created 7 years, 10 months 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of universe; 5 part of universe;
6 6
7 // TODO(kasperl): It seems possible to rewrite this class to be more 7 class SelectorMap<T> {
8 // like the FunctionSet abstraction which is a lot simpler. 8 final Compiler compiler;
9 class SelectorMap<T> extends PartialTypeTree { 9 final Map<SourceString, SelectorMapNode<T>> nodes =
10 10 new Map<SourceString, SelectorMapNode<T>>();
11 SelectorMap(Compiler compiler) : super(compiler); 11 SelectorMap(this.compiler);
12
13 SelectorMapNode<T> newNode(ClassElement type) => new SelectorMapNode<T>(type);
14 12
15 T operator [](Selector selector) { 13 T operator [](Selector selector) {
16 SelectorMapNode<T> node = findNode(selectorType(selector), false); 14 SourceString name = selector.name;
17 if (node == null) return null; 15 SelectorMapNode node = nodes[name];
18 Link<SelectorValue<T>> selectors = node.selectorsByName[selector.name]; 16 return (node != null)
19 if (selectors == null) return null; 17 ? node.lookup(selector)
20 for (Link link = selectors; !link.isEmpty; link = link.tail) { 18 : null;
ngeoffray 2013/02/14 10:14:33 fits in one line?
21 SelectorValue<T> existing = link.head;
22 if (existing.selector.equalsUntyped(selector)) return existing.value;
23 }
24 return null;
25 } 19 }
26 20
27 // TODO(kasperl): Do we need to support removing selectors by
28 // passing null as the value?
29 void operator []=(Selector selector, T value) { 21 void operator []=(Selector selector, T value) {
30 ClassElement type = selectorType(selector);
31 SelectorMapNode<T> node = findNode(type, true);
32 SourceString name = selector.name; 22 SourceString name = selector.name;
33 Link<SelectorValue<T>> selectors = node.selectorsByName.putIfAbsent( 23 SelectorMapNode node = nodes.putIfAbsent(
34 name, () => const Link()); 24 name, () => new SelectorMapNode(name));
35 // Run through the linked list of selectors with the same name. If 25 node.update(selector, value);
36 // we find one that matches, we update the value in the mapping.
37 for (Link link = selectors; !link.isEmpty; link = link.tail) {
38 SelectorValue<T> existing = link.head;
39 // It is safe to ignore the type here, because all selector
40 // mappings that are stored in a single node have the same type.
41 if (existing.selector.equalsUntyped(selector)) {
42 existing.value = value;
43 return;
44 }
45 }
46 // We could not find an existing mapping for the selector, so
47 // we add a new one to the existing linked list.
48 SelectorValue<T> head = new SelectorValue<T>(selector, value);
49 node.selectorsByName[name] = selectors.prepend(head);
50 } 26 }
51 27
52 // TODO(kasperl): Share code with the [] operator?
53 bool containsKey(Selector selector) { 28 bool containsKey(Selector selector) {
54 SelectorMapNode<T> node = findNode(selectorType(selector), false); 29 SourceString name = selector.name;
55 if (node == null) return false; 30 SelectorMapNode node = nodes[name];
56 Link<SelectorValue<T>> selectors = node.selectorsByName[selector.name]; 31 return (node != null)
57 if (selectors == null) return false; 32 ? node.containsKey(selector)
58 for (Link link = selectors; !link.isEmpty; link = link.tail) { 33 : false;
59 SelectorValue<T> existing = link.head; 34 }
60 if (existing.selector.equalsUntyped(selector)) return true; 35
61 } 36 T remove(Selector selector) {
62 return false; 37 SourceString name = selector.name;
38 SelectorMapNode node = nodes[name];
39 return (node != null)
40 ? node.remove(selector)
41 : null;
63 } 42 }
64 43
65 /** 44 /**
66 * Visits all mappings for selectors that may be used to invoke the 45 * Visits all mappings for selectors that may be used to invoke the
67 * given [member] element. If the [visit] function ever returns false, 46 * given [member] element. If the [visit] function ever returns false,
68 * we abort the traversal early. 47 * we abort the traversal early.
69 */ 48 */
70 void visitMatching(Element member, bool visit(Selector selector, T value)) { 49 void visitMatching(Element member, bool visit(Selector selector, T value)) {
71 assert(member.isMember()); 50 assert(member.isMember());
72 if (root == null) return; 51 SourceString name = member.name;
73 // TODO(kasperl): Use visitHierachyMatching when possible. It is 52 SelectorMapNode node = nodes[name];
74 // currently broken in subtle ways when it comes to finding typed 53 if (node != null) {
75 // selectors where we only know the interface of the receiver. 54 node.visitMatching(member, compiler, visit);
76 visitAllMatching(member, visit); 55 }
56 }
57 }
58
59 class SelectorMapNode<T> {
60 final SourceString name;
61 final Map<Selector, T> selectors = new Map<Selector, T>();
62
63 // We start caching which selectors match which elements when the
64 // number of different selectors exceed a threshold. This way we
65 // avoid lots of repeated calls to the Selector.applies method.
66 static const int MAX_SELECTORS_NO_CACHE = 8;
67 Map<Element, List<Selector>> cache;
68
69 SelectorMapNode(this.name);
70
71 T lookup(Selector selector) {
72 assert(selector.name == name);
73 return selectors[selector];
77 } 74 }
78 75
79 void visitAllMatching(Element member, bool visit(selector, value)) { 76 void update(Selector selector, T value) {
80 root.visitRecursively((SelectorMapNode<T> node) { 77 assert(selector.name == name);
81 Link<SelectorValue<T>> selectors = node.selectorsByName[member.name]; 78 bool existing = selectors.containsKey(selector);
82 if (selectors == null) return true; 79 selectors[selector] = value;
83 for (Link link = selectors; !link.isEmpty; link = link.tail) { 80 if (existing) return;
84 SelectorValue<T> existing = link.head; 81 // The update has introduced a new selector in the map, so we need
85 Selector selector = existing.selector; 82 // to consider if we should start caching. At the very least, we
86 // Since we're running through the entire tree we have to use 83 // have to clear the cache because the new element may invalidate
87 // the applies method that takes types into account. 84 // existing cache entries.
88 if (selector.appliesUnnamed(member, compiler)) { 85 if (cache == null) {
89 if (!visit(selector, existing.value)) return false; 86 if (selectors.length > MAX_SELECTORS_NO_CACHE) {
90 } 87 cache = new Map<Element, List<Selector>>();
91 } 88 }
92 return true; 89 } else if (!cache.isEmpty) {
ngeoffray 2013/02/14 10:14:33 Remove this check?
93 }); 90 cache.clear();
91 }
94 } 92 }
95 93
96 void visitHierarchyMatching(Element member, bool visit(selector, value)) { 94 bool containsKey(Selector selector) {
97 visitHierarchy(member.getEnclosingClass(), (SelectorMapNode<T> node) { 95 assert(selector.name == name);
98 Link<SelectorValue<T>> selectors = node.selectorsByName[member.name]; 96 return selectors.containsKey(selector);
99 if (selectors == null) return true;
100 for (Link link = selectors; !link.isEmpty; link = link.tail) {
101 SelectorValue<T> existing = link.head;
102 Selector selector = existing.selector;
103 if (selector.appliesUntyped(member, compiler)) {
104 if (!visit(selector, existing.value)) return false;
105 }
106 }
107 return true;
108 });
109 } 97 }
110 98
99 T remove(Selector selector) {
100 assert(selector.name == name);
101 if (!selectors.containsKey(selector)) return null;
102 if (cache != null && !cache.isEmpty) cache.clear();
ngeoffray 2013/02/14 10:14:33 Remove this check?
103 return selectors.remove(selector);
104 }
105
106 void visitMatching(Element member, Compiler compiler,
107 bool visit(Selector selector, T value)) {
108 assert(member.name == name);
109 Iterable<Selector> matching = computeMatching(member, compiler);
110 for (Selector selector in matching) {
111 if (!visit(selector, selectors[selector])) return;
112 }
113 }
114
115 Iterable<Selector> computeMatching(Element member, Compiler compiler) {
116 // Probe the cache if it exists. Do this before creating the
117 // matching iterable to cut down on the overhead for cache hits.
ngeoffray 2013/02/14 10:14:33 Not sure I understand the last sentence. Looks lik
118 if (cache != null) {
119 List<Selector> cached = cache[member];
120 if (cached != null) return cached;
121 }
122 // Filter the selectors keys so we only have the ones that apply
123 // to the given member element.
124 Iterable<Selector> matching = selectors.keys.where(
125 (Selector selector) => selector.appliesUnnamed(member, compiler));
126 if (cache == null) return matching;
127 return cache[member] = matching.toList();
128 }
111 } 129 }
112
113 class SelectorMapNode<T> extends PartialTypeTreeNode {
114 final Map<SourceString, Link<SelectorValue<T>>> selectorsByName =
115 new Map<SourceString, Link<SelectorValue<T>>>();
116 SelectorMapNode(ClassElement type) : super(type);
117 }
118
119 class SelectorValue<T> {
120 final Selector selector;
121 T value;
122 SelectorValue(this.selector, this.value);
123 toString() => "$selector -> $value";
124 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698