Chromium Code Reviews| Index: pkg/compiler/lib/src/universe/function_set.dart |
| diff --git a/pkg/compiler/lib/src/universe/function_set.dart b/pkg/compiler/lib/src/universe/function_set.dart |
| index 11baf76ddd1b3fe4b939fd1bc13fd9cb03408c34..5777dc4303e87c84cb44be748e5acb8c8d3f1814 100644 |
| --- a/pkg/compiler/lib/src/universe/function_set.dart |
| +++ b/pkg/compiler/lib/src/universe/function_set.dart |
| @@ -48,30 +48,26 @@ class FunctionSet { |
| * Returns an object that allows iterating over all the functions |
| * that may be invoked with the given [selector]. |
| */ |
| - Iterable<Element> filter(Selector selector) { |
| - return query(selector).functions; |
| + Iterable<Element> filter(Selector selector, TypeMask mask) { |
| + return query(selector, mask).functions; |
| } |
| - TypeMask receiverType(Selector selector) { |
| - return query(selector).computeMask(compiler.world); |
| + TypeMask receiverType(Selector selector, TypeMask mask) { |
| + return query(selector, mask).computeMask(compiler.world); |
| } |
| - FunctionSetQuery query(Selector selector) { |
| + FunctionSetQuery query(Selector selector, TypeMask mask) { |
| String name = selector.name; |
| FunctionSetNode node = nodes[name]; |
| FunctionSetNode noSuchMethods = nodes[Compiler.NO_SUCH_METHOD]; |
| if (node != null) { |
| - return node.query(selector, compiler, noSuchMethods); |
| + return node.query(selector, mask, compiler, noSuchMethods); |
| } |
| // If there is no method that matches [selector] we know we can |
| // only hit [:noSuchMethod:]. |
| if (noSuchMethods == null) return const FunctionSetQuery(const <Element>[]); |
| - selector = (selector.mask == null) |
| - ? compiler.noSuchMethodSelector |
| - : new TypedSelector(selector.mask, compiler.noSuchMethodSelector, |
| - compiler.world); |
| - |
| - return noSuchMethods.query(selector, compiler, null); |
| + return noSuchMethods.query( |
| + compiler.noSuchMethodSelector, mask, compiler, null); |
| } |
| void forEach(Function action) { |
| @@ -81,11 +77,37 @@ class FunctionSet { |
| } |
| } |
| +class SelectorMask { |
| + final Selector selector; |
| + final TypeMask mask; |
| + final int hashCode; |
| + |
| + SelectorMask(Selector selector, TypeMask mask) |
| + : this.selector = selector, |
| + this.mask = mask, |
| + this.hashCode = |
| + Hashing.mixHashCodeBits(selector.hashCode, mask.hashCode); |
| + |
| + String get name => selector.name; |
| + |
| + bool applies(Element element, ClassWorld classWorld) { |
| + if (!selector.appliesUnnamed(element, classWorld)) return false; |
| + if (mask == null) return true; |
| + return mask.canHit(element, selector, classWorld); |
| + } |
| + |
| + bool operator ==(other) { |
| + if (identical(this, other)) return true; |
| + return selector == other.selector && mask == other.mask; |
| + } |
| + |
| + String toString() => '($selector,$mask)'; |
| +} |
| class FunctionSetNode { |
| final String name; |
| - final Map<Selector, FunctionSetQuery> cache = |
| - new Map<Selector, FunctionSetQuery>(); |
| + final Map<SelectorMask, FunctionSetQuery> cache = |
| + <SelectorMask, FunctionSetQuery>{}; |
| // Initially, we keep the elements in a list because it is more |
| // compact than a hash set. Once we get enough elements, we change |
| @@ -142,24 +164,28 @@ class FunctionSetNode { |
| elements.forEach(action); |
| } |
| - TypeMask getNonNullTypeMaskOfSelector(Selector selector, Compiler compiler) { |
| + TypeMask getNonNullTypeMaskOfSelector(TypeMask mask, ClassWorld classWorld) { |
| // TODO(ngeoffray): We should probably change untyped selector |
| // to always be a subclass of Object. |
| - return selector.mask != null |
| - ? selector.mask |
| - : new TypeMask.subclass(compiler.objectClass, compiler.world); |
| + return mask != null |
| + ? mask |
| + : new TypeMask.subclass(classWorld.objectClass, classWorld); |
| } |
| FunctionSetQuery query(Selector selector, |
|
herhut
2015/06/24 15:19:29
As discussed, it would be nice to move this over t
Johnni Winther
2015/06/25 07:25:28
Added a TODO.
|
| + TypeMask mask, |
| Compiler compiler, |
| FunctionSetNode noSuchMethods) { |
| + mask = getNonNullTypeMaskOfSelector(mask, compiler.world); |
| + SelectorMask selectorMask = new SelectorMask(selector, mask); |
| ClassWorld classWorld = compiler.world; |
| assert(selector.name == name); |
| - FunctionSetQuery result = cache[selector]; |
| + FunctionSetQuery result = cache[selectorMask]; |
| if (result != null) return result; |
| + |
| Setlet<Element> functions; |
| for (Element element in elements) { |
| - if (selector.appliesUnnamed(element, classWorld)) { |
| + if (selectorMask.applies(element, classWorld)) { |
| if (functions == null) { |
| // Defer the allocation of the functions set until we are |
| // sure we need it. This allows us to return immutable empty |
| @@ -170,15 +196,14 @@ class FunctionSetNode { |
| } |
| } |
| - TypeMask mask = getNonNullTypeMaskOfSelector(selector, compiler); |
| // If we cannot ensure a method will be found at runtime, we also |
| // add [noSuchMethod] implementations that apply to [mask] as |
| // potential targets. |
| if (noSuchMethods != null |
| && mask.needsNoSuchMethodHandling(selector, classWorld)) { |
| FunctionSetQuery noSuchMethodQuery = noSuchMethods.query( |
| - new TypedSelector( |
| - mask, compiler.noSuchMethodSelector, classWorld), |
| + compiler.noSuchMethodSelector, |
| + mask, |
| compiler, |
| null); |
| if (!noSuchMethodQuery.functions.isEmpty) { |
| @@ -189,14 +214,15 @@ class FunctionSetNode { |
| } |
| } |
| } |
| - cache[selector] = result = (functions != null) |
| - ? newQuery(functions, selector, compiler) |
| + cache[selectorMask] = result = (functions != null) |
| + ? newQuery(functions, selector, mask, compiler) |
| : const FunctionSetQuery(const <Element>[]); |
| return result; |
| } |
| FunctionSetQuery newQuery(Iterable<Element> functions, |
| Selector selector, |
| + TypeMask mask, |
| Compiler compiler) { |
| return new FullFunctionSetQuery(functions); |
| } |