| 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 0b4b0bc9990cddaea99aa8426fa507bc4e1e7696..5f8dedd36783087462b216921ff5359afc8b719a 100644
|
| --- a/pkg/compiler/lib/src/universe/function_set.dart
|
| +++ b/pkg/compiler/lib/src/universe/function_set.dart
|
| @@ -13,6 +13,8 @@ class FunctionSet {
|
| new Map<String, FunctionSetNode>();
|
| FunctionSet(this.compiler);
|
|
|
| + ClassWorld get classWorld => compiler.world;
|
| +
|
| FunctionSetNode newNode(String name)
|
| => new FunctionSetNode(name);
|
|
|
| @@ -44,30 +46,50 @@ class FunctionSet {
|
| : false;
|
| }
|
|
|
| - /**
|
| - * Returns an object that allows iterating over all the functions
|
| - * that may be invoked with the given [selector].
|
| - */
|
| + /// Returns an object that allows iterating over all the functions
|
| + /// that may be invoked with the given [selector].
|
| Iterable<Element> filter(Selector selector, TypeMask mask) {
|
| return query(selector, mask).functions;
|
| }
|
|
|
| + /// Returns the mask for the potential receivers of a dynamic call to
|
| + /// [selector] on [mask].
|
| + ///
|
| + /// This will reduce the set of classes in [mask] to a [TypeMask] of the set
|
| + /// of classes that actually implement the selected member or implement the
|
| + /// handling 'noSuchMethod' where the selected member is unimplemented.
|
| TypeMask receiverType(Selector selector, TypeMask mask) {
|
| - return query(selector, mask).computeMask(compiler.world);
|
| + return query(selector, mask).computeMask(classWorld);
|
| + }
|
| +
|
| + SelectorMask _createSelectorMask(
|
| + Selector selector, TypeMask mask, ClassWorld classWorld) {
|
| + return mask != null
|
| + ? new SelectorMask(selector, mask)
|
| + : new SelectorMask(selector,
|
| + new TypeMask.subclass(classWorld.objectClass, classWorld));
|
| }
|
|
|
| + /// Returns the set of functions that can be the target of a call to
|
| + /// [selector] on a receiver of type [mask] including 'noSuchMethod' methods
|
| + /// where applicable.
|
| FunctionSetQuery query(Selector selector, TypeMask mask) {
|
| String name = selector.name;
|
| + SelectorMask selectorMask = _createSelectorMask(selector, mask, classWorld);
|
| + SelectorMask noSuchMethodMask =
|
| + new SelectorMask(Selectors.noSuchMethod_, selectorMask.mask);
|
| FunctionSetNode node = nodes[name];
|
| FunctionSetNode noSuchMethods = nodes[Identifiers.noSuchMethod_];
|
| if (node != null) {
|
| - return node.query(selector, mask, compiler, noSuchMethods);
|
| + return node.query(
|
| + selectorMask, classWorld, noSuchMethods, noSuchMethodMask);
|
| }
|
| // If there is no method that matches [selector] we know we can
|
| // only hit [:noSuchMethod:].
|
| - if (noSuchMethods == null) return const FunctionSetQuery(const <Element>[]);
|
| - return noSuchMethods.query(
|
| - Selectors.noSuchMethod_, mask, compiler, null);
|
| + if (noSuchMethods == null) {
|
| + return const EmptyFunctionSetQuery();
|
| + }
|
| + return noSuchMethods.query(noSuchMethodMask, classWorld);
|
| }
|
|
|
| void forEach(Function action) {
|
| @@ -77,6 +99,8 @@ class FunctionSet {
|
| }
|
| }
|
|
|
| +/// A selector/mask pair representing the dynamic invocation of [selector] on
|
| +/// a receiver of type [mask].
|
| class SelectorMask {
|
| final Selector selector;
|
| final TypeMask mask;
|
| @@ -86,16 +110,21 @@ class SelectorMask {
|
| : this.selector = selector,
|
| this.mask = mask,
|
| this.hashCode =
|
| - Hashing.mixHashCodeBits(selector.hashCode, mask.hashCode);
|
| + Hashing.mixHashCodeBits(selector.hashCode, mask.hashCode) {
|
| + assert(mask != null);
|
| + }
|
|
|
| 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 needsNoSuchMethodHandling(ClassWorld classWorld) {
|
| + return mask.needsNoSuchMethodHandling(selector, classWorld);
|
| + }
|
| +
|
| bool operator ==(other) {
|
| if (identical(this, other)) return true;
|
| return selector == other.selector && mask == other.mask;
|
| @@ -104,6 +133,8 @@ class SelectorMask {
|
| String toString() => '($selector,$mask)';
|
| }
|
|
|
| +/// A node in the [FunctionSet] caching all [FunctionSetQuery] object for
|
| +/// selectors with the same [name].
|
| class FunctionSetNode {
|
| final String name;
|
| final Map<SelectorMask, FunctionSetQuery> cache =
|
| @@ -164,24 +195,13 @@ class FunctionSetNode {
|
| elements.forEach(action);
|
| }
|
|
|
| - TypeMask getNonNullTypeMaskOfSelector(TypeMask mask, ClassWorld classWorld) {
|
| - // TODO(ngeoffray): We should probably change untyped selector
|
| - // to always be a subclass of Object.
|
| - return mask != null
|
| - ? mask
|
| - : new TypeMask.subclass(classWorld.objectClass, classWorld);
|
| - }
|
| -
|
| - // TODO(johnniwinther): Use [SelectorMask] instead of [Selector] and
|
| - // [TypeMask].
|
| - FunctionSetQuery query(Selector selector,
|
| - 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);
|
| + /// Returns the set of functions that can be the target of [selectorMask]
|
| + /// including no such method handling where applicable.
|
| + FunctionSetQuery query(SelectorMask selectorMask,
|
| + ClassWorld classWorld,
|
| + [FunctionSetNode noSuchMethods,
|
| + SelectorMask noSuchMethodMask]) {
|
| + assert(selectorMask.name == name);
|
| FunctionSetQuery result = cache[selectorMask];
|
| if (result != null) return result;
|
|
|
| @@ -201,13 +221,10 @@ class FunctionSetNode {
|
| // 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(
|
| - Selectors.noSuchMethod_,
|
| - mask,
|
| - compiler,
|
| - null);
|
| + if (noSuchMethods != null &&
|
| + selectorMask.needsNoSuchMethodHandling(classWorld)) {
|
| + FunctionSetQuery noSuchMethodQuery =
|
| + noSuchMethods.query(noSuchMethodMask, classWorld);
|
| if (!noSuchMethodQuery.functions.isEmpty) {
|
| if (functions == null) {
|
| functions = new Setlet<Element>.from(noSuchMethodQuery.functions);
|
| @@ -217,31 +234,43 @@ class FunctionSetNode {
|
| }
|
| }
|
| cache[selectorMask] = result = (functions != null)
|
| - ? newQuery(functions, selector, mask, compiler)
|
| - : const FunctionSetQuery(const <Element>[]);
|
| + ? new FullFunctionSetQuery(functions)
|
| + : const EmptyFunctionSetQuery();
|
| return result;
|
| }
|
| +}
|
|
|
| - FunctionSetQuery newQuery(Iterable<Element> functions,
|
| - Selector selector,
|
| - TypeMask mask,
|
| - Compiler compiler) {
|
| - return new FullFunctionSetQuery(functions);
|
| - }
|
| +/// A set of functions that are the potential targets of all call sites sharing
|
| +/// the same receiver mask and selector.
|
| +abstract class FunctionSetQuery {
|
| + const FunctionSetQuery();
|
| +
|
| + /// Compute the type of all potential receivers of this function set.
|
| + TypeMask computeMask(ClassWorld classWorld);
|
| +
|
| + /// Returns all potential targets of this function set.
|
| + Iterable<Element> get functions;
|
| }
|
|
|
| -class FunctionSetQuery {
|
| - final Iterable<Element> functions;
|
| +class EmptyFunctionSetQuery implements FunctionSetQuery {
|
| + const EmptyFunctionSetQuery();
|
| +
|
| + @override
|
| TypeMask computeMask(ClassWorld classWorld) => const TypeMask.nonNullEmpty();
|
| - const FunctionSetQuery(this.functions);
|
| +
|
| + @override
|
| + Iterable<Element> get functions => const <Element>[];
|
| }
|
|
|
| -class FullFunctionSetQuery extends FunctionSetQuery {
|
| +class FullFunctionSetQuery implements FunctionSetQuery {
|
| + @override
|
| + final Iterable<Element> functions;
|
| +
|
| TypeMask _mask;
|
|
|
| - /**
|
| - * Compute the type of all potential receivers of this function set.
|
| - */
|
| + FullFunctionSetQuery(this.functions);
|
| +
|
| + @override
|
| TypeMask computeMask(ClassWorld classWorld) {
|
| assert(classWorld.hasAnyStrictSubclass(classWorld.objectClass));
|
| if (_mask != null) return _mask;
|
| @@ -259,6 +288,4 @@ class FullFunctionSetQuery extends FunctionSetQuery {
|
| }),
|
| classWorld);
|
| }
|
| -
|
| - FullFunctionSetQuery(functions) : super(functions);
|
| }
|
|
|