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

Unified Diff: pkg/compiler/lib/src/js_backend/interceptor_data.dart

Issue 2680823002: Extract InterceptorData from JavaScriptBackend. (Closed)
Patch Set: Created 3 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 side-by-side diff with in-line comments
Download patch
Index: pkg/compiler/lib/src/js_backend/interceptor_data.dart
diff --git a/pkg/compiler/lib/src/js_backend/interceptor_data.dart b/pkg/compiler/lib/src/js_backend/interceptor_data.dart
new file mode 100644
index 0000000000000000000000000000000000000000..8d908a31979073b479b2a84057b8c483c52ed75d
--- /dev/null
+++ b/pkg/compiler/lib/src/js_backend/interceptor_data.dart
@@ -0,0 +1,260 @@
+// Copyright (c) 2017, 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 js_backend.interceptor_data;
+
+import '../common/names.dart' show Identifiers;
+import '../core_types.dart' show CommonElements;
+import '../elements/elements.dart';
+import '../js/js.dart' as jsAst;
+import '../types/types.dart' show TypeMask;
+import '../universe/selector.dart';
+import '../world.dart' show ClosedWorld;
+import 'backend_helpers.dart';
+import 'namer.dart';
+import 'native_data.dart';
+
+class InterceptorData {
+ final NativeData _nativeData;
+ final BackendHelpers _helpers;
+ final CommonElements _commonElements;
+ ClosedWorld _closedWorld;
+
+ /**
Siggi Cherem (dart-lang) 2017/02/08 00:20:36 while we are at it, let's turn this into /// comme
Johnni Winther 2017/02/08 09:56:02 Done.
+ * A collection of selectors that must have a one shot interceptor
+ * generated.
+ */
+ final Map<jsAst.Name, Selector> oneShotInterceptors =
+ <jsAst.Name, Selector>{};
+
+ /**
+ * The members of instantiated interceptor classes: maps a member name to the
+ * list of members that have that name. This map is used by the codegen to
+ * know whether a send must be intercepted or not.
+ */
+ final Map<String, Set<Element>> interceptedElements =
+ <String, Set<Element>>{};
+
+ /**
+ * The members of mixin classes that are mixed into an instantiated
+ * interceptor class. This is a cached subset of [interceptedElements].
+ *
+ * Mixin methods are not specialized for the class they are mixed into.
+ * Methods mixed into intercepted classes thus always make use of the explicit
+ * receiver argument, even when mixed into non-interceptor classes.
+ *
+ * These members must be invoked with a correct explicit receiver even when
+ * the receiver is not an intercepted class.
+ */
+ final Map<String, Set<Element>> interceptedMixinElements =
+ new Map<String, Set<Element>>();
+
+ /**
+ * A map of specialized versions of the [getInterceptorMethod].
+ * Since [getInterceptorMethod] is a hot method at runtime, we're
+ * always specializing it based on the incoming type. The keys in
+ * the map are the names of these specialized versions. Note that
+ * the generic version that contains all possible type checks is
+ * also stored in this map.
+ */
+ final Map<jsAst.Name, Set<ClassElement>> specializedGetInterceptors =
+ <jsAst.Name, Set<ClassElement>>{};
+
+ /**
+ * Set of classes whose methods are intercepted.
+ */
+ final Set<ClassElement> _interceptedClasses = new Set<ClassElement>();
+
+ /**
+ * Set of classes used as mixins on intercepted (native and primitive)
+ * classes. Methods on these classes might also be mixed in to regular Dart
+ * (unintercepted) classes.
+ */
+ final Set<ClassElement> classesMixedIntoInterceptedClasses =
+ new Set<ClassElement>();
+
+ InterceptorData(this._nativeData, this._helpers, this._commonElements);
+
+ void onResolutionComplete(ClosedWorld closedWorld) {
+ _closedWorld = closedWorld;
+ }
+
+ bool isInterceptedMethod(MemberElement element) {
+ if (!element.isInstanceMember) return false;
+ if (element.isGenerativeConstructorBody) {
+ return _nativeData.isNativeOrExtendsNative(element.enclosingClass);
+ }
+ return interceptedElements[element.name] != null;
+ }
+
+ bool fieldHasInterceptedGetter(Element element) {
+ assert(element.isField);
+ return interceptedElements[element.name] != null;
+ }
+
+ bool fieldHasInterceptedSetter(Element element) {
+ assert(element.isField);
+ return interceptedElements[element.name] != null;
+ }
+
+ bool isInterceptedName(String name) {
+ return interceptedElements[name] != null;
+ }
+
+ bool isInterceptedSelector(Selector selector) {
+ return interceptedElements[selector.name] != null;
+ }
+
+ /**
+ * Returns `true` iff [selector] matches an element defined in a class mixed
+ * into an intercepted class. These selectors are not eligible for the 'dummy
+ * explicit receiver' optimization.
+ */
+ bool isInterceptedMixinSelector(Selector selector, TypeMask mask) {
+ Set<Element> elements =
+ interceptedMixinElements.putIfAbsent(selector.name, () {
+ Set<Element> elements = interceptedElements[selector.name];
+ if (elements == null) return null;
+ return elements
+ .where((element) => classesMixedIntoInterceptedClasses
+ .contains(element.enclosingClass))
+ .toSet();
+ });
+
+ if (elements == null) return false;
+ if (elements.isEmpty) return false;
+ return elements.any((element) {
+ return selector.applies(element) &&
+ (mask == null ||
+ mask.canHit(element as MemberElement, selector, _closedWorld));
+ });
+ }
+
+ /// True if the given class is an internal class used for type inference
+ /// and never exists at runtime.
+ bool isCompileTimeOnlyClass(ClassElement class_) {
+ return class_ == _helpers.jsPositiveIntClass ||
+ class_ == _helpers.jsUInt32Class ||
+ class_ == _helpers.jsUInt31Class ||
+ class_ == _helpers.jsFixedArrayClass ||
+ class_ == _helpers.jsUnmodifiableArrayClass ||
+ class_ == _helpers.jsMutableArrayClass ||
+ class_ == _helpers.jsExtendableArrayClass;
+ }
+
+ final Map<String, Set<ClassElement>> interceptedClassesCache =
+ new Map<String, Set<ClassElement>>();
+ final Set<ClassElement> _noClasses = new Set<ClassElement>();
+
+ /// Returns a set of interceptor classes that contain a member named [name]
+ ///
+ /// Returns an empty set if there is no class. Do not modify the returned set.
+ Set<ClassElement> getInterceptedClassesOn(String name) {
+ Set<Element> intercepted = interceptedElements[name];
+ if (intercepted == null) return _noClasses;
+ return interceptedClassesCache.putIfAbsent(name, () {
+ // Populate the cache by running through all the elements and
+ // determine if the given selector applies to them.
+ Set<ClassElement> result = new Set<ClassElement>();
+ for (Element element in intercepted) {
+ ClassElement classElement = element.enclosingClass;
+ if (isCompileTimeOnlyClass(classElement)) continue;
+ if (_nativeData.isNativeOrExtendsNative(classElement) ||
+ interceptedClasses.contains(classElement)) {
+ result.add(classElement);
+ }
+ if (classesMixedIntoInterceptedClasses.contains(classElement)) {
+ Set<ClassElement> nativeSubclasses =
+ nativeSubclassesOfMixin(classElement);
+ if (nativeSubclasses != null) result.addAll(nativeSubclasses);
+ }
+ }
+ return result;
+ });
+ }
+
+ Set<ClassElement> nativeSubclassesOfMixin(ClassElement mixin) {
+ Iterable<MixinApplicationElement> uses = _closedWorld.mixinUsesOf(mixin);
+ Set<ClassElement> result = null;
+ for (MixinApplicationElement use in uses) {
+ _closedWorld.forEachStrictSubclassOf(use, (ClassElement subclass) {
+ if (_nativeData.isNativeOrExtendsNative(subclass)) {
+ if (result == null) result = new Set<ClassElement>();
+ result.add(subclass);
+ }
+ });
+ }
+ return result;
+ }
+
+ bool isInterceptorClass(ClassElement element) {
+ if (element == null) return false;
+ if (_nativeData.isNativeOrExtendsNative(element)) return true;
+ if (interceptedClasses.contains(element)) return true;
+ if (classesMixedIntoInterceptedClasses.contains(element)) return true;
+ return false;
+ }
+
+ jsAst.Name registerOneShotInterceptor(Selector selector, Namer namer) {
+ Set<ClassElement> classes = getInterceptedClassesOn(selector.name);
+ jsAst.Name name = namer.nameForGetOneShotInterceptor(selector, classes);
+ if (!oneShotInterceptors.containsKey(name)) {
+ registerSpecializedGetInterceptor(classes, namer);
+ oneShotInterceptors[name] = selector;
+ }
+ return name;
+ }
+
+ void addInterceptorsForNativeClassMembers(ClassElement cls) {
+ cls.forEachMember((ClassElement classElement, Element member) {
+ if (member.name == Identifiers.call) {
+ return;
+ }
+ if (member.isSynthesized) return;
+ // All methods on [Object] are shadowed by [Interceptor].
+ if (classElement == _commonElements.objectClass) return;
+ Set<Element> set = interceptedElements.putIfAbsent(
+ member.name, () => new Set<Element>());
+ set.add(member);
+ }, includeSuperAndInjectedMembers: true);
+
+ // Walk superclass chain to find mixins.
+ for (; cls != null; cls = cls.superclass) {
+ if (cls.isMixinApplication) {
+ MixinApplicationElement mixinApplication = cls;
+ classesMixedIntoInterceptedClasses.add(mixinApplication.mixin);
+ }
+ }
+ }
+
+ void addInterceptors(ClassElement cls) {
+ if (_interceptedClasses.add(cls)) {
+ cls.forEachMember((ClassElement classElement, Element member) {
+ // All methods on [Object] are shadowed by [Interceptor].
+ if (classElement == _commonElements.objectClass) return;
+ Set<Element> set = interceptedElements.putIfAbsent(
+ member.name, () => new Set<Element>());
+ set.add(member);
+ }, includeSuperAndInjectedMembers: true);
+ }
+ _interceptedClasses.add(_helpers.jsInterceptorClass);
+ }
+
+ Set<ClassElement> get interceptedClasses {
+ assert(_closedWorld != null);
+ return _interceptedClasses;
+ }
+
+ void registerSpecializedGetInterceptor(
+ Set<ClassElement> classes, Namer namer) {
+ jsAst.Name name = namer.nameForGetInterceptor(classes);
+ if (classes.contains(_helpers.jsInterceptorClass)) {
+ // We can't use a specialized [getInterceptorMethod], so we make
+ // sure we emit the one with all checks.
+ specializedGetInterceptors[name] = interceptedClasses;
+ } else {
+ specializedGetInterceptors[name] = classes;
+ }
+ }
+}
« no previous file with comments | « pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart ('k') | pkg/compiler/lib/src/js_backend/namer.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698