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

Side by Side 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 library js_backend.interceptor_data;
6
7 import '../common/names.dart' show Identifiers;
8 import '../core_types.dart' show CommonElements;
9 import '../elements/elements.dart';
10 import '../js/js.dart' as jsAst;
11 import '../types/types.dart' show TypeMask;
12 import '../universe/selector.dart';
13 import '../world.dart' show ClosedWorld;
14 import 'backend_helpers.dart';
15 import 'namer.dart';
16 import 'native_data.dart';
17
18 class InterceptorData {
19 final NativeData _nativeData;
20 final BackendHelpers _helpers;
21 final CommonElements _commonElements;
22 ClosedWorld _closedWorld;
23
24 /**
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.
25 * A collection of selectors that must have a one shot interceptor
26 * generated.
27 */
28 final Map<jsAst.Name, Selector> oneShotInterceptors =
29 <jsAst.Name, Selector>{};
30
31 /**
32 * The members of instantiated interceptor classes: maps a member name to the
33 * list of members that have that name. This map is used by the codegen to
34 * know whether a send must be intercepted or not.
35 */
36 final Map<String, Set<Element>> interceptedElements =
37 <String, Set<Element>>{};
38
39 /**
40 * The members of mixin classes that are mixed into an instantiated
41 * interceptor class. This is a cached subset of [interceptedElements].
42 *
43 * Mixin methods are not specialized for the class they are mixed into.
44 * Methods mixed into intercepted classes thus always make use of the explicit
45 * receiver argument, even when mixed into non-interceptor classes.
46 *
47 * These members must be invoked with a correct explicit receiver even when
48 * the receiver is not an intercepted class.
49 */
50 final Map<String, Set<Element>> interceptedMixinElements =
51 new Map<String, Set<Element>>();
52
53 /**
54 * A map of specialized versions of the [getInterceptorMethod].
55 * Since [getInterceptorMethod] is a hot method at runtime, we're
56 * always specializing it based on the incoming type. The keys in
57 * the map are the names of these specialized versions. Note that
58 * the generic version that contains all possible type checks is
59 * also stored in this map.
60 */
61 final Map<jsAst.Name, Set<ClassElement>> specializedGetInterceptors =
62 <jsAst.Name, Set<ClassElement>>{};
63
64 /**
65 * Set of classes whose methods are intercepted.
66 */
67 final Set<ClassElement> _interceptedClasses = new Set<ClassElement>();
68
69 /**
70 * Set of classes used as mixins on intercepted (native and primitive)
71 * classes. Methods on these classes might also be mixed in to regular Dart
72 * (unintercepted) classes.
73 */
74 final Set<ClassElement> classesMixedIntoInterceptedClasses =
75 new Set<ClassElement>();
76
77 InterceptorData(this._nativeData, this._helpers, this._commonElements);
78
79 void onResolutionComplete(ClosedWorld closedWorld) {
80 _closedWorld = closedWorld;
81 }
82
83 bool isInterceptedMethod(MemberElement element) {
84 if (!element.isInstanceMember) return false;
85 if (element.isGenerativeConstructorBody) {
86 return _nativeData.isNativeOrExtendsNative(element.enclosingClass);
87 }
88 return interceptedElements[element.name] != null;
89 }
90
91 bool fieldHasInterceptedGetter(Element element) {
92 assert(element.isField);
93 return interceptedElements[element.name] != null;
94 }
95
96 bool fieldHasInterceptedSetter(Element element) {
97 assert(element.isField);
98 return interceptedElements[element.name] != null;
99 }
100
101 bool isInterceptedName(String name) {
102 return interceptedElements[name] != null;
103 }
104
105 bool isInterceptedSelector(Selector selector) {
106 return interceptedElements[selector.name] != null;
107 }
108
109 /**
110 * Returns `true` iff [selector] matches an element defined in a class mixed
111 * into an intercepted class. These selectors are not eligible for the 'dummy
112 * explicit receiver' optimization.
113 */
114 bool isInterceptedMixinSelector(Selector selector, TypeMask mask) {
115 Set<Element> elements =
116 interceptedMixinElements.putIfAbsent(selector.name, () {
117 Set<Element> elements = interceptedElements[selector.name];
118 if (elements == null) return null;
119 return elements
120 .where((element) => classesMixedIntoInterceptedClasses
121 .contains(element.enclosingClass))
122 .toSet();
123 });
124
125 if (elements == null) return false;
126 if (elements.isEmpty) return false;
127 return elements.any((element) {
128 return selector.applies(element) &&
129 (mask == null ||
130 mask.canHit(element as MemberElement, selector, _closedWorld));
131 });
132 }
133
134 /// True if the given class is an internal class used for type inference
135 /// and never exists at runtime.
136 bool isCompileTimeOnlyClass(ClassElement class_) {
137 return class_ == _helpers.jsPositiveIntClass ||
138 class_ == _helpers.jsUInt32Class ||
139 class_ == _helpers.jsUInt31Class ||
140 class_ == _helpers.jsFixedArrayClass ||
141 class_ == _helpers.jsUnmodifiableArrayClass ||
142 class_ == _helpers.jsMutableArrayClass ||
143 class_ == _helpers.jsExtendableArrayClass;
144 }
145
146 final Map<String, Set<ClassElement>> interceptedClassesCache =
147 new Map<String, Set<ClassElement>>();
148 final Set<ClassElement> _noClasses = new Set<ClassElement>();
149
150 /// Returns a set of interceptor classes that contain a member named [name]
151 ///
152 /// Returns an empty set if there is no class. Do not modify the returned set.
153 Set<ClassElement> getInterceptedClassesOn(String name) {
154 Set<Element> intercepted = interceptedElements[name];
155 if (intercepted == null) return _noClasses;
156 return interceptedClassesCache.putIfAbsent(name, () {
157 // Populate the cache by running through all the elements and
158 // determine if the given selector applies to them.
159 Set<ClassElement> result = new Set<ClassElement>();
160 for (Element element in intercepted) {
161 ClassElement classElement = element.enclosingClass;
162 if (isCompileTimeOnlyClass(classElement)) continue;
163 if (_nativeData.isNativeOrExtendsNative(classElement) ||
164 interceptedClasses.contains(classElement)) {
165 result.add(classElement);
166 }
167 if (classesMixedIntoInterceptedClasses.contains(classElement)) {
168 Set<ClassElement> nativeSubclasses =
169 nativeSubclassesOfMixin(classElement);
170 if (nativeSubclasses != null) result.addAll(nativeSubclasses);
171 }
172 }
173 return result;
174 });
175 }
176
177 Set<ClassElement> nativeSubclassesOfMixin(ClassElement mixin) {
178 Iterable<MixinApplicationElement> uses = _closedWorld.mixinUsesOf(mixin);
179 Set<ClassElement> result = null;
180 for (MixinApplicationElement use in uses) {
181 _closedWorld.forEachStrictSubclassOf(use, (ClassElement subclass) {
182 if (_nativeData.isNativeOrExtendsNative(subclass)) {
183 if (result == null) result = new Set<ClassElement>();
184 result.add(subclass);
185 }
186 });
187 }
188 return result;
189 }
190
191 bool isInterceptorClass(ClassElement element) {
192 if (element == null) return false;
193 if (_nativeData.isNativeOrExtendsNative(element)) return true;
194 if (interceptedClasses.contains(element)) return true;
195 if (classesMixedIntoInterceptedClasses.contains(element)) return true;
196 return false;
197 }
198
199 jsAst.Name registerOneShotInterceptor(Selector selector, Namer namer) {
200 Set<ClassElement> classes = getInterceptedClassesOn(selector.name);
201 jsAst.Name name = namer.nameForGetOneShotInterceptor(selector, classes);
202 if (!oneShotInterceptors.containsKey(name)) {
203 registerSpecializedGetInterceptor(classes, namer);
204 oneShotInterceptors[name] = selector;
205 }
206 return name;
207 }
208
209 void addInterceptorsForNativeClassMembers(ClassElement cls) {
210 cls.forEachMember((ClassElement classElement, Element member) {
211 if (member.name == Identifiers.call) {
212 return;
213 }
214 if (member.isSynthesized) return;
215 // All methods on [Object] are shadowed by [Interceptor].
216 if (classElement == _commonElements.objectClass) return;
217 Set<Element> set = interceptedElements.putIfAbsent(
218 member.name, () => new Set<Element>());
219 set.add(member);
220 }, includeSuperAndInjectedMembers: true);
221
222 // Walk superclass chain to find mixins.
223 for (; cls != null; cls = cls.superclass) {
224 if (cls.isMixinApplication) {
225 MixinApplicationElement mixinApplication = cls;
226 classesMixedIntoInterceptedClasses.add(mixinApplication.mixin);
227 }
228 }
229 }
230
231 void addInterceptors(ClassElement cls) {
232 if (_interceptedClasses.add(cls)) {
233 cls.forEachMember((ClassElement classElement, Element member) {
234 // All methods on [Object] are shadowed by [Interceptor].
235 if (classElement == _commonElements.objectClass) return;
236 Set<Element> set = interceptedElements.putIfAbsent(
237 member.name, () => new Set<Element>());
238 set.add(member);
239 }, includeSuperAndInjectedMembers: true);
240 }
241 _interceptedClasses.add(_helpers.jsInterceptorClass);
242 }
243
244 Set<ClassElement> get interceptedClasses {
245 assert(_closedWorld != null);
246 return _interceptedClasses;
247 }
248
249 void registerSpecializedGetInterceptor(
250 Set<ClassElement> classes, Namer namer) {
251 jsAst.Name name = namer.nameForGetInterceptor(classes);
252 if (classes.contains(_helpers.jsInterceptorClass)) {
253 // We can't use a specialized [getInterceptorMethod], so we make
254 // sure we emit the one with all checks.
255 specializedGetInterceptors[name] = interceptedClasses;
256 } else {
257 specializedGetInterceptors[name] = classes;
258 }
259 }
260 }
OLDNEW
« 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