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

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

Issue 2692303002: Split InterceptorData (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
index 88f236c44aa69632ff894beaba96c46f5e6378cd..84bfec594f05d9a77292088da0c3c537890f5074 100644
--- a/pkg/compiler/lib/src/js_backend/interceptor_data.dart
+++ b/pkg/compiler/lib/src/js_backend/interceptor_data.dart
@@ -15,24 +15,52 @@ import 'backend_helpers.dart';
import 'namer.dart';
import 'native_data.dart';
-class InterceptorData {
+abstract class InterceptorData {
+ /// Returns `true` if [cls] is an intercepted class.
+ // TODO(johnniwinther): Rename this to `isInterceptedClass`.
+ bool isInterceptorClass(ClassElement element);
+
+ bool isInterceptedMethod(MemberElement element);
+ bool fieldHasInterceptedGetter(Element element);
+ bool fieldHasInterceptedSetter(Element element);
+ bool isInterceptedName(String name);
+ bool isInterceptedSelector(Selector selector);
+ bool isInterceptedMixinSelector(Selector selector, TypeMask mask);
+ Iterable<ClassElement> get interceptedClasses;
+ bool isMixedIntoInterceptedClass(ClassElement element);
+
+ /// 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);
+}
+
+abstract class InterceptorDataBuilder {
+ void addInterceptors(ClassElement cls);
+ void addInterceptorsForNativeClassMembers(ClassElement cls);
+ InterceptorData onResolutionComplete(ClosedWorld closedWorld);
+}
+
+class InterceptorDataImpl implements InterceptorData {
final NativeData _nativeData;
final BackendHelpers _helpers;
- final CommonElements _commonElements;
- ClosedWorld _closedWorld;
-
- /// A collection of selectors that must have a one shot interceptor generated.
- final Map<jsAst.Name, Selector> oneShotInterceptors =
- <jsAst.Name, Selector>{};
+ final ClosedWorld _closedWorld;
/// 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>>{};
+ final Map<String, Set<Element>> _interceptedElements;
+
+ /// Set of classes whose methods are intercepted.
+ final Set<ClassElement> _interceptedClasses;
+
+ /// 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;
/// The members of mixin classes that are mixed into an instantiated
- /// interceptor class. This is a cached subset of [interceptedElements].
+ /// 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
@@ -40,57 +68,46 @@ class InterceptorData {
///
/// 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 =
+ 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>();
+ final Map<String, Set<ClassElement>> _interceptedClassesCache =
+ new Map<String, Set<ClassElement>>();
- InterceptorData(this._nativeData, this._helpers, this._commonElements);
+ final Set<ClassElement> _noClasses = new Set<ClassElement>();
- void onResolutionComplete(ClosedWorld closedWorld) {
- _closedWorld = closedWorld;
- }
+ InterceptorDataImpl(
+ this._nativeData,
+ this._helpers,
+ this._closedWorld,
+ this._interceptedElements,
+ this._interceptedClasses,
+ this._classesMixedIntoInterceptedClasses);
bool isInterceptedMethod(MemberElement element) {
if (!element.isInstanceMember) return false;
if (element.isGenerativeConstructorBody) {
return _nativeData.isNativeOrExtendsNative(element.enclosingClass);
}
- return interceptedElements[element.name] != null;
+ return _interceptedElements[element.name] != null;
}
bool fieldHasInterceptedGetter(Element element) {
assert(element.isField);
- return interceptedElements[element.name] != null;
+ return _interceptedElements[element.name] != null;
}
bool fieldHasInterceptedSetter(Element element) {
assert(element.isField);
- return interceptedElements[element.name] != null;
+ return _interceptedElements[element.name] != null;
}
bool isInterceptedName(String name) {
- return interceptedElements[name] != null;
+ return _interceptedElements[name] != null;
}
bool isInterceptedSelector(Selector selector) {
- return interceptedElements[selector.name] != null;
+ return _interceptedElements[selector.name] != null;
}
/// Returns `true` iff [selector] matches an element defined in a class mixed
@@ -98,11 +115,11 @@ class InterceptorData {
/// 'dummy explicit receiver' optimization.
bool isInterceptedMixinSelector(Selector selector, TypeMask mask) {
Set<Element> elements =
- interceptedMixinElements.putIfAbsent(selector.name, () {
- Set<Element> elements = interceptedElements[selector.name];
+ _interceptedMixinElements.putIfAbsent(selector.name, () {
+ Set<Element> elements = _interceptedElements[selector.name];
if (elements == null) return null;
return elements
- .where((element) => classesMixedIntoInterceptedClasses
+ .where((element) => _classesMixedIntoInterceptedClasses
.contains(element.enclosingClass))
.toSet();
});
@@ -118,7 +135,7 @@ class InterceptorData {
/// True if the given class is an internal class used for type inference
/// and never exists at runtime.
- bool isCompileTimeOnlyClass(ClassElement class_) {
+ bool _isCompileTimeOnlyClass(ClassElement class_) {
return class_ == _helpers.jsPositiveIntClass ||
class_ == _helpers.jsUInt32Class ||
class_ == _helpers.jsUInt31Class ||
@@ -128,28 +145,24 @@ class InterceptorData {
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];
+ Set<Element> intercepted = _interceptedElements[name];
if (intercepted == null) return _noClasses;
- return interceptedClassesCache.putIfAbsent(name, () {
+ 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 (_isCompileTimeOnlyClass(classElement)) continue;
if (_nativeData.isNativeOrExtendsNative(classElement) ||
interceptedClasses.contains(classElement)) {
result.add(classElement);
}
- if (classesMixedIntoInterceptedClasses.contains(classElement)) {
+ if (_classesMixedIntoInterceptedClasses.contains(classElement)) {
Set<ClassElement> nativeSubclasses =
nativeSubclassesOfMixin(classElement);
if (nativeSubclasses != null) result.addAll(nativeSubclasses);
@@ -177,18 +190,47 @@ class InterceptorData {
if (element == null) return false;
if (_nativeData.isNativeOrExtendsNative(element)) return true;
if (interceptedClasses.contains(element)) return true;
- if (classesMixedIntoInterceptedClasses.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;
+ bool isMixedIntoInterceptedClass(ClassElement element) =>
+ _classesMixedIntoInterceptedClasses.contains(element);
+
+ Iterable<ClassElement> get interceptedClasses => _interceptedClasses;
+}
+
+class InterceptorDataBuilderImpl implements InterceptorDataBuilder {
+ final NativeData _nativeData;
+ final BackendHelpers _helpers;
+ final CommonElements _commonElements;
+
+ /// 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>>{};
+
+ /// 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>();
+
+ InterceptorDataBuilderImpl(
+ this._nativeData, this._helpers, this._commonElements);
+
+ InterceptorData onResolutionComplete(ClosedWorld closedWorld) {
+ return new InterceptorDataImpl(
+ _nativeData,
+ _helpers,
+ closedWorld,
+ _interceptedElements,
+ _interceptedClasses,
+ _classesMixedIntoInterceptedClasses);
}
void addInterceptorsForNativeClassMembers(ClassElement cls) {
@@ -199,7 +241,7 @@ class InterceptorData {
if (member.isSynthesized) return;
// All methods on [Object] are shadowed by [Interceptor].
if (classElement == _commonElements.objectClass) return;
- Set<Element> set = interceptedElements.putIfAbsent(
+ Set<Element> set = _interceptedElements.putIfAbsent(
member.name, () => new Set<Element>());
set.add(member);
}, includeSuperAndInjectedMembers: true);
@@ -208,7 +250,7 @@ class InterceptorData {
for (; cls != null; cls = cls.superclass) {
if (cls.isMixinApplication) {
MixinApplicationElement mixinApplication = cls;
- classesMixedIntoInterceptedClasses.add(mixinApplication.mixin);
+ _classesMixedIntoInterceptedClasses.add(mixinApplication.mixin);
}
}
}
@@ -218,17 +260,55 @@ class InterceptorData {
cls.forEachMember((ClassElement classElement, Element member) {
// All methods on [Object] are shadowed by [Interceptor].
if (classElement == _commonElements.objectClass) return;
- Set<Element> set = interceptedElements.putIfAbsent(
+ 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;
+class OneShotInterceptorData {
+ final InterceptorData _interceptorData;
+ final BackendHelpers _helpers;
+
+ OneShotInterceptorData(this._interceptorData, this._helpers);
+
+ /// A collection of selectors that must have a one shot interceptor generated.
+ final Map<jsAst.Name, Selector> _oneShotInterceptors =
+ <jsAst.Name, Selector>{};
+
+ Selector getOneShotInterceptorSelector(jsAst.Name name) =>
+ _oneShotInterceptors[name];
+
+ Iterable<jsAst.Name> get oneShotInterceptorNames =>
+ _oneShotInterceptors.keys.toList()..sort();
+
+ /// 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>>{};
+
+ Iterable<jsAst.Name> get specializedGetInterceptorNames =>
+ _specializedGetInterceptors.keys.toList()..sort();
+
+ Set<ClassElement> getSpecializedGetInterceptorsFor(jsAst.Name name) =>
+ _specializedGetInterceptors[name];
+
+ jsAst.Name registerOneShotInterceptor(Selector selector, Namer namer) {
+ Set<ClassElement> classes =
+ _interceptorData.getInterceptedClassesOn(selector.name);
+ jsAst.Name name = namer.nameForGetOneShotInterceptor(selector, classes);
+ if (!_oneShotInterceptors.containsKey(name)) {
+ registerSpecializedGetInterceptor(classes, namer);
+ _oneShotInterceptors[name] = selector;
+ }
+ return name;
}
void registerSpecializedGetInterceptor(
@@ -237,9 +317,9 @@ class InterceptorData {
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;
+ _specializedGetInterceptors[name] = _interceptorData.interceptedClasses;
} else {
- specializedGetInterceptors[name] = classes;
+ _specializedGetInterceptors[name] = classes;
}
}
}
« no previous file with comments | « pkg/compiler/lib/src/js_backend/backend.dart ('k') | pkg/compiler/lib/src/js_emitter/full_emitter/interceptor_emitter.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698