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

Unified Diff: pkg/compiler/lib/src/universe/call_structure.dart

Issue 1346593002: Move Selector and CallStructure into parts. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 5 years, 3 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | pkg/compiler/lib/src/universe/selector.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/universe/call_structure.dart
diff --git a/pkg/compiler/lib/src/universe/call_structure.dart b/pkg/compiler/lib/src/universe/call_structure.dart
index 4530400e1cbaffc794effa09c6a3e22e636bd033..12e4fd895b3de2c407a2a5da0610908e6d863ea3 100644
--- a/pkg/compiler/lib/src/universe/call_structure.dart
+++ b/pkg/compiler/lib/src/universe/call_structure.dart
@@ -1,390 +1,8 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library universe;
-
-import 'dart:collection';
-
-import '../common/names.dart' show
- Identifiers,
- Names,
- Selectors;
-import '../compiler.dart' show
- Compiler;
-import '../diagnostics/invariant.dart' show
- invariant;
-import '../diagnostics/spannable.dart' show
- SpannableAssertionFailure;
-import '../elements/elements.dart';
-import '../dart_types.dart';
-import '../tree/tree.dart';
-import '../types/types.dart';
-import '../util/util.dart';
-import '../world.dart' show
- ClassWorld,
- World;
-
-part 'function_set.dart';
-part 'side_effects.dart';
-
-class UniverseSelector {
- final Selector selector;
- final ReceiverMask mask;
-
- UniverseSelector(this.selector, this.mask);
-
- bool appliesUnnamed(Element element, ClassWorld world) {
- return selector.appliesUnnamed(element, world) &&
- (mask == null || mask.canHit(element, selector, world));
- }
-
- String toString() => '$selector,$mask';
-}
-
-/// A potential receiver for a dynamic call site.
-abstract class ReceiverMask {
- /// Returns whether [element] is a potential target when being
- /// invoked on this receiver mask. [selector] is used to ensure library
- /// privacy is taken into account.
- bool canHit(Element element, Selector selector, ClassWorld classWorld);
-}
-
-/// A set of potential receivers for the dynamic call sites of the same
-/// selector.
-///
-/// For instance for these calls
-///
-/// new A().foo(a, b);
-/// new B().foo(0, 42);
-///
-/// the receiver mask set for dynamic calls to 'foo' with to positional
-/// arguments will contain receiver masks abstracting `new A()` and `new B()`.
-abstract class ReceiverMaskSet {
- /// Returns `true` if [selector] applies to any of the potential receivers
- /// in this set given the closed [world].
- bool applies(Element element, Selector selector, ClassWorld world);
-
- /// Returns `true` if any potential receivers in this set given the closed
- /// [world] have no implementation matching [selector].
- ///
- /// For instance for this code snippet
- ///
- /// class A {}
- /// class B { foo() {} }
- /// m(b) => (b ? new A() : new B()).foo();
- ///
- /// the potential receiver `new A()` have no implementation of `foo` and thus
- /// needs to handle the call though its `noSuchMethod` handler.
- bool needsNoSuchMethodHandling(Selector selector, ClassWorld world);
-}
-
-/// A mutable [ReceiverMaskSet] used in [Universe].
-abstract class UniverseReceiverMaskSet extends ReceiverMaskSet {
- /// Adds [mask] to this set of potential receivers. Return `true` if the
- /// set expanded due to the new mask.
- bool addReceiverMask(ReceiverMask mask);
-}
-
-/// Strategy for computing potential receivers of dynamic call sites.
-abstract class ReceiverMaskStrategy {
- /// Create a [UniverseReceiverMaskSet] to represent the potential receiver for
- /// a dynamic call site with [selector].
- UniverseReceiverMaskSet createReceiverMaskSet(Selector selector);
-}
-
-class Universe {
- /// The set of all directly instantiated classes, that is, classes with a
- /// generative constructor that has been called directly and not only through
- /// a super-call.
- ///
- /// Invariant: Elements are declaration elements.
- // TODO(johnniwinther): [_directlyInstantiatedClasses] and
- // [_instantiatedTypes] sets should be merged.
- final Set<ClassElement> _directlyInstantiatedClasses =
- new Set<ClassElement>();
-
- /// The set of all directly instantiated types, that is, the types of the
- /// directly instantiated classes.
- ///
- /// See [_directlyInstantiatedClasses].
- final Set<DartType> _instantiatedTypes = new Set<DartType>();
-
- /// The set of all instantiated classes, either directly, as superclasses or
- /// as supertypes.
- ///
- /// Invariant: Elements are declaration elements.
- final Set<ClassElement> _allInstantiatedClasses = new Set<ClassElement>();
-
- /// The set of all referenced static fields.
- ///
- /// Invariant: Elements are declaration elements.
- final Set<FieldElement> allReferencedStaticFields = new Set<FieldElement>();
-
- /**
- * Documentation wanted -- johnniwinther
- *
- * Invariant: Elements are declaration elements.
- */
- final Set<FunctionElement> staticFunctionsNeedingGetter =
- new Set<FunctionElement>();
- final Set<FunctionElement> methodsNeedingSuperGetter =
- new Set<FunctionElement>();
- final Map<String, Map<Selector, ReceiverMaskSet>> _invokedNames =
- <String, Map<Selector, ReceiverMaskSet>>{};
- final Map<String, Map<Selector, ReceiverMaskSet>> _invokedGetters =
- <String, Map<Selector, ReceiverMaskSet>>{};
- final Map<String, Map<Selector, ReceiverMaskSet>> _invokedSetters =
- <String, Map<Selector, ReceiverMaskSet>>{};
-
- /**
- * Fields accessed. Currently only the codegen knows this
- * information. The resolver is too conservative when seeing a
- * getter and only registers an invoked getter.
- */
- final Set<Element> fieldGetters = new Set<Element>();
-
- /**
- * Fields set. See comment in [fieldGetters].
- */
- final Set<Element> fieldSetters = new Set<Element>();
- final Set<DartType> isChecks = new Set<DartType>();
-
- /**
- * Set of (live) [:call:] methods whose signatures reference type variables.
- *
- * A live [:call:] method is one whose enclosing class has been instantiated.
- */
- final Set<Element> callMethodsWithFreeTypeVariables = new Set<Element>();
-
- /**
- * Set of (live) local functions (closures) whose signatures reference type
- * variables.
- *
- * A live function is one whose enclosing member function has been enqueued.
- */
- final Set<Element> closuresWithFreeTypeVariables = new Set<Element>();
-
- /**
- * Set of all closures in the program. Used by the mirror tracking system
- * to find all live closure instances.
- */
- final Set<LocalFunctionElement> allClosures = new Set<LocalFunctionElement>();
-
- /**
- * Set of methods in instantiated classes that are potentially
- * closurized.
- */
- final Set<Element> closurizedMembers = new Set<Element>();
-
- final ReceiverMaskStrategy receiverMaskStrategy;
-
- Universe(this.receiverMaskStrategy);
-
- /// All directly instantiated classes, that is, classes with a generative
- /// constructor that has been called directly and not only through a
- /// super-call.
- // TODO(johnniwinther): Improve semantic precision.
- Iterable<ClassElement> get directlyInstantiatedClasses {
- return _directlyInstantiatedClasses;
- }
-
- /// All instantiated classes, either directly, as superclasses or as
- /// supertypes.
- // TODO(johnniwinther): Improve semantic precision.
- Iterable<ClassElement> get allInstantiatedClasses {
- return _allInstantiatedClasses;
- }
-
- /// All directly instantiated types, that is, the types of the directly
- /// instantiated classes.
- ///
- /// See [directlyInstantiatedClasses].
- // TODO(johnniwinther): Improve semantic precision.
- Iterable<DartType> get instantiatedTypes => _instantiatedTypes;
-
- /// Returns `true` if [cls] is considered to be instantiated, either directly,
- /// through subclasses or through subtypes. The latter case only contains
- /// spurious information from instatiations through factory constructors and
- /// mixins.
- // TODO(johnniwinther): Improve semantic precision.
- bool isInstantiated(ClassElement cls) {
- return _allInstantiatedClasses.contains(cls);
- }
-
- /// Register [type] as (directly) instantiated.
- ///
- /// If [byMirrors] is `true`, the instantiation is through mirrors.
- // TODO(johnniwinther): Fully enforce the separation between exact, through
- // subclass and through subtype instantiated types/classes.
- // TODO(johnniwinther): Support unknown type arguments for generic types.
- void registerTypeInstantiation(InterfaceType type,
- {bool byMirrors: false}) {
- _instantiatedTypes.add(type);
- ClassElement cls = type.element;
- if (!cls.isAbstract
- // We can't use the closed-world assumption with native abstract
- // classes; a native abstract class may have non-abstract subclasses
- // not declared to the program. Instances of these classes are
- // indistinguishable from the abstract class.
- || cls.isNative
- // Likewise, if this registration comes from the mirror system,
- // all bets are off.
- // TODO(herhut): Track classes required by mirrors seperately.
- || byMirrors) {
- _directlyInstantiatedClasses.add(cls);
- }
-
- // TODO(johnniwinther): Replace this by separate more specific mappings.
- if (!_allInstantiatedClasses.add(cls)) return;
- cls.allSupertypes.forEach((InterfaceType supertype) {
- _allInstantiatedClasses.add(supertype.element);
- });
- }
-
- bool _hasMatchingSelector(Map<Selector, ReceiverMaskSet> selectors,
- Element member,
- World world) {
- if (selectors == null) return false;
- for (Selector selector in selectors.keys) {
- if (selector.appliesUnnamed(member, world)) {
- ReceiverMaskSet masks = selectors[selector];
- if (masks.applies(member, selector, world)) {
- return true;
- }
- }
- }
- return false;
- }
-
- bool hasInvocation(Element member, World world) {
- return _hasMatchingSelector(_invokedNames[member.name], member, world);
- }
-
- bool hasInvokedGetter(Element member, World world) {
- return _hasMatchingSelector(_invokedGetters[member.name], member, world);
- }
-
- bool hasInvokedSetter(Element member, World world) {
- return _hasMatchingSelector(_invokedSetters[member.name], member, world);
- }
-
- bool registerInvocation(UniverseSelector selector) {
- return _registerNewSelector(selector, _invokedNames);
- }
-
- bool registerInvokedGetter(UniverseSelector selector) {
- return _registerNewSelector(selector, _invokedGetters);
- }
-
- bool registerInvokedSetter(UniverseSelector selector) {
- return _registerNewSelector(selector, _invokedSetters);
- }
-
- bool _registerNewSelector(
- UniverseSelector universeSelector,
- Map<String, Map<Selector, ReceiverMaskSet>> selectorMap) {
- Selector selector = universeSelector.selector;
- String name = selector.name;
- ReceiverMask mask = universeSelector.mask;
- Map<Selector, ReceiverMaskSet> selectors = selectorMap.putIfAbsent(
- name, () => new Maplet<Selector, ReceiverMaskSet>());
- UniverseReceiverMaskSet masks = selectors.putIfAbsent(
- selector, () => receiverMaskStrategy.createReceiverMaskSet(selector));
- return masks.addReceiverMask(mask);
- }
-
- Map<Selector, ReceiverMaskSet> _asUnmodifiable(
- Map<Selector, ReceiverMaskSet> map) {
- if (map == null) return null;
- return new UnmodifiableMapView(map);
- }
-
- Map<Selector, ReceiverMaskSet> invocationsByName(String name) {
- return _asUnmodifiable(_invokedNames[name]);
- }
-
- Map<Selector, ReceiverMaskSet> getterInvocationsByName(String name) {
- return _asUnmodifiable(_invokedGetters[name]);
- }
-
- Map<Selector, ReceiverMaskSet> setterInvocationsByName(String name) {
- return _asUnmodifiable(_invokedSetters[name]);
- }
-
- void forEachInvokedName(
- f(String name, Map<Selector, ReceiverMaskSet> selectors)) {
- _invokedNames.forEach(f);
- }
-
- void forEachInvokedGetter(
- f(String name, Map<Selector, ReceiverMaskSet> selectors)) {
- _invokedGetters.forEach(f);
- }
-
- void forEachInvokedSetter(
- f(String name, Map<Selector, ReceiverMaskSet> selectors)) {
- _invokedSetters.forEach(f);
- }
-
- DartType registerIsCheck(DartType type, Compiler compiler) {
- type = type.unalias(compiler);
- // Even in checked mode, type annotations for return type and argument
- // types do not imply type checks, so there should never be a check
- // against the type variable of a typedef.
- isChecks.add(type);
- return type;
- }
-
- void registerStaticFieldUse(FieldElement staticField) {
- assert(Elements.isStaticOrTopLevel(staticField) && staticField.isField);
- assert(staticField.isDeclaration);
-
- allReferencedStaticFields.add(staticField);
- }
-
- void forgetElement(Element element, Compiler compiler) {
- allClosures.remove(element);
- slowDirectlyNestedClosures(element).forEach(compiler.forgetElement);
- closurizedMembers.remove(element);
- fieldSetters.remove(element);
- fieldGetters.remove(element);
- _directlyInstantiatedClasses.remove(element);
- _allInstantiatedClasses.remove(element);
- if (element is ClassElement) {
- assert(invariant(
- element, element.thisType.isRaw,
- message: 'Generic classes not supported (${element.thisType}).'));
- _instantiatedTypes
- ..remove(element.rawType)
- ..remove(element.thisType);
- }
- }
-
- // TODO(ahe): Replace this method with something that is O(1), for example,
- // by using a map.
- List<LocalFunctionElement> slowDirectlyNestedClosures(Element element) {
- // Return new list to guard against concurrent modifications.
- return new List<LocalFunctionElement>.from(
- allClosures.where((LocalFunctionElement closure) {
- return closure.executableContext == element;
- }));
- }
-}
-
-class SelectorKind {
- final String name;
- final int hashCode;
- const SelectorKind(this.name, this.hashCode);
-
- static const SelectorKind GETTER = const SelectorKind('getter', 0);
- static const SelectorKind SETTER = const SelectorKind('setter', 1);
- static const SelectorKind CALL = const SelectorKind('call', 2);
- static const SelectorKind OPERATOR = const SelectorKind('operator', 3);
- static const SelectorKind INDEX = const SelectorKind('index', 4);
-
- String toString() => name;
-}
+part of universe;
/// The structure of the arguments at a call-site.
// TODO(johnniwinther): Should these be cached?
@@ -662,255 +280,3 @@ class NamedCallStructure extends CallStructure {
return 'arity=$argumentCount, named=[${namedArguments.join(', ')}]';
}
}
-
-class Selector {
- final SelectorKind kind;
- final Name memberName;
- final CallStructure callStructure;
-
- final int hashCode;
-
- int get argumentCount => callStructure.argumentCount;
- int get namedArgumentCount => callStructure.namedArgumentCount;
- int get positionalArgumentCount => callStructure.positionalArgumentCount;
- List<String> get namedArguments => callStructure.namedArguments;
-
- String get name => memberName.text;
-
- LibraryElement get library => memberName.library;
-
- static const Name INDEX_NAME = const PublicName("[]");
- static const Name INDEX_SET_NAME = const PublicName("[]=");
- static const Name CALL_NAME = Names.call;
-
- Selector.internal(this.kind,
- this.memberName,
- this.callStructure,
- this.hashCode) {
- assert(kind == SelectorKind.INDEX ||
- (memberName != INDEX_NAME && memberName != INDEX_SET_NAME));
- assert(kind == SelectorKind.OPERATOR ||
- kind == SelectorKind.INDEX ||
- !Elements.isOperatorName(memberName.text) ||
- identical(memberName.text, '??'));
- assert(kind == SelectorKind.CALL ||
- kind == SelectorKind.GETTER ||
- kind == SelectorKind.SETTER ||
- Elements.isOperatorName(memberName.text) ||
- identical(memberName.text, '??'));
- }
-
- // TODO(johnniwinther): Extract caching.
- static Map<int, List<Selector>> canonicalizedValues =
- new Map<int, List<Selector>>();
-
- factory Selector(SelectorKind kind,
- Name name,
- CallStructure callStructure) {
- // TODO(johnniwinther): Maybe use equality instead of implicit hashing.
- int hashCode = computeHashCode(kind, name, callStructure);
- List<Selector> list = canonicalizedValues.putIfAbsent(hashCode,
- () => <Selector>[]);
- for (int i = 0; i < list.length; i++) {
- Selector existing = list[i];
- if (existing.match(kind, name, callStructure)) {
- assert(existing.hashCode == hashCode);
- return existing;
- }
- }
- Selector result = new Selector.internal(
- kind, name, callStructure, hashCode);
- list.add(result);
- return result;
- }
-
- factory Selector.fromElement(Element element) {
- Name name = new Name(element.name, element.library);
- if (element.isFunction) {
- if (name == INDEX_NAME) {
- return new Selector.index();
- } else if (name == INDEX_SET_NAME) {
- return new Selector.indexSet();
- }
- FunctionSignature signature =
- element.asFunctionElement().functionSignature;
- int arity = signature.parameterCount;
- List<String> namedArguments = null;
- if (signature.optionalParametersAreNamed) {
- namedArguments =
- signature.orderedOptionalParameters.map((e) => e.name).toList();
- }
- if (element.isOperator) {
- // Operators cannot have named arguments, however, that doesn't prevent
- // a user from declaring such an operator.
- return new Selector(
- SelectorKind.OPERATOR,
- name,
- new CallStructure(arity, namedArguments));
- } else {
- return new Selector.call(
- name, new CallStructure(arity, namedArguments));
- }
- } else if (element.isSetter) {
- return new Selector.setter(name);
- } else if (element.isGetter) {
- return new Selector.getter(name);
- } else if (element.isField) {
- return new Selector.getter(name);
- } else if (element.isConstructor) {
- return new Selector.callConstructor(name);
- } else {
- throw new SpannableAssertionFailure(
- element, "Can't get selector from $element");
- }
- }
-
- factory Selector.getter(Name name)
- => new Selector(SelectorKind.GETTER,
- name.getter,
- CallStructure.NO_ARGS);
-
- factory Selector.setter(Name name)
- => new Selector(SelectorKind.SETTER,
- name.setter,
- CallStructure.ONE_ARG);
-
- factory Selector.unaryOperator(String name) => new Selector(
- SelectorKind.OPERATOR,
- new PublicName(Elements.constructOperatorName(name, true)),
- CallStructure.NO_ARGS);
-
- factory Selector.binaryOperator(String name) => new Selector(
- SelectorKind.OPERATOR,
- new PublicName(Elements.constructOperatorName(name, false)),
- CallStructure.ONE_ARG);
-
- factory Selector.index()
- => new Selector(SelectorKind.INDEX, INDEX_NAME,
- CallStructure.ONE_ARG);
-
- factory Selector.indexSet()
- => new Selector(SelectorKind.INDEX, INDEX_SET_NAME,
- CallStructure.TWO_ARGS);
-
- factory Selector.call(Name name, CallStructure callStructure)
- => new Selector(SelectorKind.CALL, name, callStructure);
-
- factory Selector.callClosure(int arity, [List<String> namedArguments])
- => new Selector(SelectorKind.CALL, CALL_NAME,
- new CallStructure(arity, namedArguments));
-
- factory Selector.callClosureFrom(Selector selector)
- => new Selector(SelectorKind.CALL, CALL_NAME, selector.callStructure);
-
- factory Selector.callConstructor(Name name,
- [int arity = 0,
- List<String> namedArguments])
- => new Selector(SelectorKind.CALL, name,
- new CallStructure(arity, namedArguments));
-
- factory Selector.callDefaultConstructor()
- => new Selector(
- SelectorKind.CALL,
- const PublicName(''),
- CallStructure.NO_ARGS);
-
- bool get isGetter => kind == SelectorKind.GETTER;
- bool get isSetter => kind == SelectorKind.SETTER;
- bool get isCall => kind == SelectorKind.CALL;
- bool get isClosureCall => isCall && memberName == CALL_NAME;
-
- bool get isIndex => kind == SelectorKind.INDEX && argumentCount == 1;
- bool get isIndexSet => kind == SelectorKind.INDEX && argumentCount == 2;
-
- bool get isOperator => kind == SelectorKind.OPERATOR;
- bool get isUnaryOperator => isOperator && argumentCount == 0;
-
- /** Check whether this is a call to 'assert'. */
- bool get isAssert => isCall && identical(name, "assert");
-
- /**
- * The member name for invocation mirrors created from this selector.
- */
- String get invocationMirrorMemberName =>
- isSetter ? '$name=' : name;
-
- int get invocationMirrorKind {
- const int METHOD = 0;
- const int GETTER = 1;
- const int SETTER = 2;
- int kind = METHOD;
- if (isGetter) {
- kind = GETTER;
- } else if (isSetter) {
- kind = SETTER;
- }
- return kind;
- }
-
- bool appliesUnnamed(Element element, World world) {
- assert(sameNameHack(element, world));
- return appliesUntyped(element, world);
- }
-
- bool appliesUntyped(Element element, World world) {
- assert(sameNameHack(element, world));
- if (Elements.isUnresolved(element)) return false;
- if (memberName.isPrivate && memberName.library != element.library) {
- // TODO(johnniwinther): Maybe this should be
- // `memberName != element.memberName`.
- return false;
- }
- if (world.isForeign(element)) return true;
- if (element.isSetter) return isSetter;
- if (element.isGetter) return isGetter || isCall;
- if (element.isField) {
- return isSetter
- ? !element.isFinal && !element.isConst
- : isGetter || isCall;
- }
- if (isGetter) return true;
- if (isSetter) return false;
- return signatureApplies(element);
- }
-
- bool signatureApplies(FunctionElement function) {
- if (Elements.isUnresolved(function)) return false;
- return callStructure.signatureApplies(function.functionSignature);
- }
-
- bool sameNameHack(Element element, World world) {
- // TODO(ngeoffray): Remove workaround checks.
- return element.isConstructor ||
- name == element.name ||
- name == 'assert' && world.isAssertMethod(element);
- }
-
- bool applies(Element element, World world) {
- if (!sameNameHack(element, world)) return false;
- return appliesUnnamed(element, world);
- }
-
- bool match(SelectorKind kind,
- Name memberName,
- CallStructure callStructure) {
- return this.kind == kind
- && this.memberName == memberName
- && this.callStructure.match(callStructure);
- }
-
- static int computeHashCode(SelectorKind kind,
- Name name,
- CallStructure callStructure) {
- // Add bits from name and kind.
- int hash = Hashing.mixHashCodeBits(name.hashCode, kind.hashCode);
- // Add bits from the call structure.
- return Hashing.mixHashCodeBits(hash, callStructure.hashCode);
- }
-
- String toString() {
- return 'Selector($kind, $name, ${callStructure.structureToString()})';
- }
-
- Selector toCallSelector() => new Selector.callClosureFrom(this);
-}
« no previous file with comments | « no previous file | pkg/compiler/lib/src/universe/selector.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698