Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 library universe.function_set; | 5 library universe.function_set; |
| 6 | 6 |
| 7 import '../common/names.dart' show Identifiers, Selectors; | 7 import '../common/names.dart' show Identifiers, Selectors; |
| 8 import '../elements/entities.dart'; | 8 import '../elements/entities.dart'; |
| 9 import '../types/types.dart'; | 9 import '../types/types.dart'; |
| 10 import '../util/util.dart' show Hashing, Setlet; | 10 import '../util/util.dart' show Hashing, Setlet; |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 28 void remove(MemberEntity element) { | 28 void remove(MemberEntity element) { |
| 29 assert(element.isInstanceMember); | 29 assert(element.isInstanceMember); |
| 30 assert(!element.isAbstract); | 30 assert(!element.isAbstract); |
| 31 String name = element.name; | 31 String name = element.name; |
| 32 FunctionSetNode node = nodes[name]; | 32 FunctionSetNode node = nodes[name]; |
| 33 if (node != null) { | 33 if (node != null) { |
| 34 node.remove(element); | 34 node.remove(element); |
| 35 } | 35 } |
| 36 } | 36 } |
| 37 | 37 |
| 38 FunctionSet close(ClosedWorld closedWorld) { | 38 FunctionSet close() { |
| 39 return new FunctionSet(closedWorld, nodes); | 39 return new FunctionSet(nodes); |
| 40 } | 40 } |
| 41 } | 41 } |
| 42 | 42 |
| 43 // TODO(kasperl): This actually holds getters and setters just fine | 43 // TODO(kasperl): This actually holds getters and setters just fine |
| 44 // too and stricly they aren't functions. Maybe this needs a better | 44 // too and stricly they aren't functions. Maybe this needs a better |
| 45 // name -- something like ElementSet seems a bit too generic. | 45 // name -- something like ElementSet seems a bit too generic. |
| 46 class FunctionSet { | 46 class FunctionSet { |
| 47 final ClosedWorld closedWorld; | 47 final Map<String, FunctionSetNode> _nodes; |
| 48 final Map<String, FunctionSetNode> nodes; | |
| 49 | 48 |
| 50 FunctionSet(this.closedWorld, this.nodes); | 49 FunctionSet(this._nodes); |
| 51 | 50 |
| 52 bool contains(MemberEntity element) { | 51 bool contains(MemberEntity element) { |
| 53 assert(element.isInstanceMember); | 52 assert(element.isInstanceMember); |
| 54 assert(!element.isAbstract); | 53 assert(!element.isAbstract); |
| 55 String name = element.name; | 54 String name = element.name; |
| 56 FunctionSetNode node = nodes[name]; | 55 FunctionSetNode node = _nodes[name]; |
| 57 return (node != null) ? node.contains(element) : false; | 56 return (node != null) ? node.contains(element) : false; |
| 58 } | 57 } |
| 59 | 58 |
| 60 /// Returns all the functions that may be invoked with the [selector] on a | 59 /// Returns all the functions that may be invoked with the [selector] on a |
| 61 /// receiver with the given [constraint]. The returned elements may include | 60 /// receiver with the given [constraint]. The returned elements may include |
| 62 /// noSuchMethod handlers that are potential targets indirectly through the | 61 /// noSuchMethod handlers that are potential targets indirectly through the |
| 63 /// noSuchMethod mechanism. | 62 /// noSuchMethod mechanism. |
| 64 Iterable<MemberEntity> filter( | 63 Iterable<MemberEntity> filter(Selector selector, |
| 65 Selector selector, ReceiverConstraint constraint) { | 64 ReceiverConstraint constraint, ClosedWorld closedWorld) { |
| 66 return query(selector, constraint).functions; | 65 return query(selector, constraint, closedWorld).functions; |
| 67 } | 66 } |
| 68 | 67 |
| 69 /// Returns the mask for the potential receivers of a dynamic call to | 68 /// Returns the mask for the potential receivers of a dynamic call to |
| 70 /// [selector] on [constraint]. | 69 /// [selector] on [constraint]. |
| 71 /// | 70 /// |
| 72 /// This will narrow the constraints of [constraint] to a [TypeMask] of the | 71 /// This will narrow the constraints of [constraint] to a [TypeMask] of the |
| 73 /// set of classes that actually implement the selected member or implement | 72 /// set of classes that actually implement the selected member or implement |
| 74 /// the handling 'noSuchMethod' where the selected member is unimplemented. | 73 /// the handling 'noSuchMethod' where the selected member is unimplemented. |
| 75 TypeMask receiverType(Selector selector, ReceiverConstraint constraint) { | 74 TypeMask receiverType(Selector selector, ReceiverConstraint constraint, |
| 76 return query(selector, constraint).computeMask(closedWorld); | 75 ClosedWorld closedWorld) { |
| 76 return query(selector, constraint, closedWorld).computeMask(closedWorld); | |
| 77 } | 77 } |
| 78 | 78 |
| 79 SelectorMask _createSelectorMask(Selector selector, | 79 SelectorMask _createSelectorMask(Selector selector, |
| 80 ReceiverConstraint constraint, ClosedWorld closedWorld) { | 80 ReceiverConstraint constraint, ClosedWorld closedWorld) { |
| 81 return constraint != null | 81 return constraint != null |
| 82 ? new SelectorMask(selector, constraint) | 82 ? new SelectorMask(selector, constraint) |
| 83 : new SelectorMask( | 83 : new SelectorMask( |
| 84 selector, | 84 selector, |
| 85 new TypeMask.subclass( | 85 new TypeMask.subclass( |
| 86 closedWorld.commonElements.objectClass, closedWorld)); | 86 closedWorld.commonElements.objectClass, closedWorld)); |
| 87 } | 87 } |
| 88 | 88 |
| 89 /// Returns the set of functions that can be the target of a call to | 89 /// Returns the set of functions that can be the target of a call to |
| 90 /// [selector] on a receiver constrained by [constraint] including | 90 /// [selector] on a receiver constrained by [constraint] including |
| 91 /// 'noSuchMethod' methods where applicable. | 91 /// 'noSuchMethod' methods where applicable. |
| 92 FunctionSetQuery query(Selector selector, ReceiverConstraint constraint) { | 92 FunctionSetQuery query(Selector selector, ReceiverConstraint constraint, |
| 93 ClosedWorld closedWorld) { | |
| 93 String name = selector.name; | 94 String name = selector.name; |
| 94 SelectorMask selectorMask = | 95 SelectorMask selectorMask = |
| 95 _createSelectorMask(selector, constraint, closedWorld); | 96 _createSelectorMask(selector, constraint, closedWorld); |
| 96 SelectorMask noSuchMethodMask = | 97 SelectorMask noSuchMethodMask = |
| 97 new SelectorMask(Selectors.noSuchMethod_, selectorMask.constraint); | 98 new SelectorMask(Selectors.noSuchMethod_, selectorMask.constraint); |
| 98 FunctionSetNode node = nodes[name]; | 99 FunctionSetNode node = _nodes[name]; |
| 99 FunctionSetNode noSuchMethods = nodes[Identifiers.noSuchMethod_]; | 100 FunctionSetNode noSuchMethods = _nodes[Identifiers.noSuchMethod_]; |
| 100 if (node != null) { | 101 if (node != null) { |
| 101 return node.query( | 102 return node.query( |
| 102 selectorMask, closedWorld, noSuchMethods, noSuchMethodMask); | 103 selectorMask, closedWorld, noSuchMethods, noSuchMethodMask); |
| 103 } | 104 } |
| 104 // If there is no method that matches [selector] we know we can | 105 // If there is no method that matches [selector] we know we can |
| 105 // only hit [:noSuchMethod:]. | 106 // only hit [:noSuchMethod:]. |
| 106 if (noSuchMethods == null) { | 107 if (noSuchMethods == null) { |
| 107 return const EmptyFunctionSetQuery(); | 108 return const EmptyFunctionSetQuery(); |
| 108 } | 109 } |
| 109 return noSuchMethods.query(noSuchMethodMask, closedWorld); | 110 return noSuchMethods.query(noSuchMethodMask, closedWorld); |
| 110 } | 111 } |
| 111 | 112 |
| 112 void forEach(Function action) { | 113 void forEach(void action(MemberEntity member)) { |
| 113 nodes.forEach((String name, FunctionSetNode node) { | 114 _nodes.forEach((String name, FunctionSetNode node) { |
| 114 node.forEach(action); | 115 node.forEach(action); |
| 115 }); | 116 }); |
| 116 } | 117 } |
| 117 } | 118 } |
| 118 | 119 |
| 119 /// A selector/constraint pair representing the dynamic invocation of [selector] | 120 /// A selector/constraint pair representing the dynamic invocation of [selector] |
| 120 /// on a receiver constrained by [constraint]. | 121 /// on a receiver constrained by [constraint]. |
| 121 class SelectorMask { | 122 class SelectorMask { |
| 122 final Selector selector; | 123 final Selector selector; |
| 123 final ReceiverConstraint constraint; | 124 final ReceiverConstraint constraint; |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 151 } | 152 } |
| 152 | 153 |
| 153 /// A node in the [FunctionSet] caching all [FunctionSetQuery] object for | 154 /// A node in the [FunctionSet] caching all [FunctionSetQuery] object for |
| 154 /// selectors with the same [name]. | 155 /// selectors with the same [name]. |
| 155 class FunctionSetNode { | 156 class FunctionSetNode { |
| 156 final String name; | 157 final String name; |
| 157 final Map<SelectorMask, FunctionSetQuery> cache = | 158 final Map<SelectorMask, FunctionSetQuery> cache = |
| 158 <SelectorMask, FunctionSetQuery>{}; | 159 <SelectorMask, FunctionSetQuery>{}; |
| 159 | 160 |
| 160 // Initially, we keep the elements in a list because it is more | 161 // Initially, we keep the elements in a list because it is more |
| 161 // compact than a hash set. Once we get enough elements, we change | 162 // compact than a hash set. Once we get enough elements, we change |
|
Siggi Cherem (dart-lang)
2017/05/03 17:03:24
do you know if this is still the case, or does has
Johnni Winther
2017/05/08 09:10:53
I think this is built in now, I'll check at update
| |
| 162 // the representation to be a set to get faster contains checks. | 163 // the representation to be a set to get faster contains checks. |
| 163 static const int MAX_ELEMENTS_IN_LIST = 8; | 164 static const int MAX_ELEMENTS_IN_LIST = 8; |
| 164 var elements = <MemberEntity>[]; | 165 Iterable<MemberEntity> elements = <MemberEntity>[]; |
| 165 bool isList = true; | 166 bool isList = true; |
| 166 | 167 |
| 167 FunctionSetNode(this.name); | 168 FunctionSetNode(this.name); |
| 168 | 169 |
| 169 void add(MemberEntity element) { | 170 void add(MemberEntity element) { |
| 170 assert(element.name == name); | 171 assert(element.name == name); |
| 171 // We try to avoid clearing the cache unless we have to. For that | 172 // We try to avoid clearing the cache unless we have to. For that |
| 172 // reason we keep the explicit contains check even though the add | 173 // reason we keep the explicit contains check even though the add |
| 173 // method ends up doing the work again (for sets). | 174 // method ends up doing the work again (for sets). |
| 174 if (!elements.contains(element)) { | 175 if (!elements.contains(element)) { |
| 175 if (isList && elements.length >= MAX_ELEMENTS_IN_LIST) { | 176 if (isList && elements.length >= MAX_ELEMENTS_IN_LIST) { |
| 176 elements = elements.toSet(); | 177 elements = elements.toSet(); |
| 177 isList = false; | 178 isList = false; |
| 178 } | 179 } |
| 179 elements.add(element); | 180 if (isList) { |
| 181 List list = elements; | |
| 182 list.add(element); | |
| 183 } else { | |
| 184 Set set = elements; | |
| 185 set.add(element); | |
| 186 } | |
| 180 if (!cache.isEmpty) cache.clear(); | 187 if (!cache.isEmpty) cache.clear(); |
| 181 } | 188 } |
| 182 } | 189 } |
| 183 | 190 |
| 184 void remove(MemberEntity element) { | 191 void remove(MemberEntity element) { |
| 185 assert(element.name == name); | 192 assert(element.name == name); |
| 186 if (isList) { | 193 if (isList) { |
| 187 List list = elements; | 194 List list = elements; |
| 188 int index = list.indexOf(element); | 195 int index = list.indexOf(element); |
| 189 if (index < 0) return; | 196 if (index < 0) return; |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 201 if (!cache.isEmpty) cache.clear(); | 208 if (!cache.isEmpty) cache.clear(); |
| 202 } | 209 } |
| 203 } | 210 } |
| 204 } | 211 } |
| 205 | 212 |
| 206 bool contains(MemberEntity element) { | 213 bool contains(MemberEntity element) { |
| 207 assert(element.name == name); | 214 assert(element.name == name); |
| 208 return elements.contains(element); | 215 return elements.contains(element); |
| 209 } | 216 } |
| 210 | 217 |
| 211 void forEach(Function action) { | 218 void forEach(void action(MemberEntity member)) { |
| 212 elements.forEach(action); | 219 elements.forEach(action); |
| 213 } | 220 } |
| 214 | 221 |
| 215 /// Returns the set of functions that can be the target of [selectorMask] | 222 /// Returns the set of functions that can be the target of [selectorMask] |
| 216 /// including no such method handling where applicable. | 223 /// including no such method handling where applicable. |
| 217 FunctionSetQuery query(SelectorMask selectorMask, ClosedWorld closedWorld, | 224 FunctionSetQuery query(SelectorMask selectorMask, ClosedWorld closedWorld, |
| 218 [FunctionSetNode noSuchMethods, SelectorMask noSuchMethodMask]) { | 225 [FunctionSetNode noSuchMethods, SelectorMask noSuchMethodMask]) { |
| 219 assert(selectorMask.name == name); | 226 assert(selectorMask.name == name); |
| 220 FunctionSetQuery result = cache[selectorMask]; | 227 FunctionSetQuery result = cache[selectorMask]; |
| 221 if (result != null) return result; | 228 if (result != null) return result; |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 302 } else if (closedWorld.isInstantiated(cls)) { | 309 } else if (closedWorld.isInstantiated(cls)) { |
| 303 return new TypeMask.nonNullSubclass(cls, closedWorld); | 310 return new TypeMask.nonNullSubclass(cls, closedWorld); |
| 304 } else { | 311 } else { |
| 305 // TODO(johnniwinther): Avoid the need for this case. | 312 // TODO(johnniwinther): Avoid the need for this case. |
| 306 return const TypeMask.empty(); | 313 return const TypeMask.empty(); |
| 307 } | 314 } |
| 308 }), | 315 }), |
| 309 closedWorld); | 316 closedWorld); |
| 310 } | 317 } |
| 311 } | 318 } |
| OLD | NEW |