OLD | NEW |
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library js_backend.interceptor_data; | 5 library js_backend.interceptor_data; |
6 | 6 |
7 import '../common/names.dart' show Identifiers; | 7 import '../common/names.dart' show Identifiers; |
8 import '../common_elements.dart' show CommonElements, ElementEnvironment; | 8 import '../common_elements.dart' show CommonElements, ElementEnvironment; |
9 import '../elements/elements.dart' show MemberElement; | 9 import '../elements/elements.dart' show MemberElement; |
10 import '../elements/entities.dart'; | 10 import '../elements/entities.dart'; |
11 import '../elements/types.dart'; | 11 import '../elements/types.dart'; |
12 import '../js/js.dart' as jsAst; | 12 import '../js/js.dart' as jsAst; |
13 import '../types/types.dart' show TypeMask; | 13 import '../types/types.dart' show TypeMask; |
14 import '../universe/selector.dart'; | 14 import '../universe/selector.dart'; |
15 import '../world.dart' show ClosedWorld; | 15 import '../world.dart' show ClosedWorld; |
16 import 'backend_helpers.dart'; | |
17 import 'namer.dart'; | 16 import 'namer.dart'; |
18 import 'native_data.dart'; | 17 import 'native_data.dart'; |
19 | 18 |
20 abstract class InterceptorData { | 19 abstract class InterceptorData { |
21 /// Returns `true` if [cls] is an intercepted class. | 20 /// Returns `true` if [cls] is an intercepted class. |
22 bool isInterceptedClass(ClassEntity element); | 21 bool isInterceptedClass(ClassEntity element); |
23 | 22 |
24 bool isInterceptedMethod(MemberEntity element); | 23 bool isInterceptedMethod(MemberEntity element); |
25 bool fieldHasInterceptedGetter(FieldEntity element); | 24 bool fieldHasInterceptedGetter(FieldEntity element); |
26 bool fieldHasInterceptedSetter(FieldEntity element); | 25 bool fieldHasInterceptedSetter(FieldEntity element); |
(...skipping 15 matching lines...) Expand all Loading... |
42 } | 41 } |
43 | 42 |
44 abstract class InterceptorDataBuilder { | 43 abstract class InterceptorDataBuilder { |
45 void addInterceptors(ClassEntity cls); | 44 void addInterceptors(ClassEntity cls); |
46 void addInterceptorsForNativeClassMembers(ClassEntity cls); | 45 void addInterceptorsForNativeClassMembers(ClassEntity cls); |
47 InterceptorData onResolutionComplete(ClosedWorld closedWorld); | 46 InterceptorData onResolutionComplete(ClosedWorld closedWorld); |
48 } | 47 } |
49 | 48 |
50 class InterceptorDataImpl implements InterceptorData { | 49 class InterceptorDataImpl implements InterceptorData { |
51 final NativeBasicData _nativeData; | 50 final NativeBasicData _nativeData; |
52 final BackendHelpers _helpers; | 51 final CommonElements _commonElements; |
53 final ClosedWorld _closedWorld; | 52 final ClosedWorld _closedWorld; |
54 | 53 |
55 /// The members of instantiated interceptor classes: maps a member name to the | 54 /// The members of instantiated interceptor classes: maps a member name to the |
56 /// list of members that have that name. This map is used by the codegen to | 55 /// list of members that have that name. This map is used by the codegen to |
57 /// know whether a send must be intercepted or not. | 56 /// know whether a send must be intercepted or not. |
58 final Map<String, Set<MemberEntity>> _interceptedElements; | 57 final Map<String, Set<MemberEntity>> _interceptedElements; |
59 | 58 |
60 /// Set of classes whose methods are intercepted. | 59 /// Set of classes whose methods are intercepted. |
61 final Set<ClassEntity> _interceptedClasses; | 60 final Set<ClassEntity> _interceptedClasses; |
62 | 61 |
(...skipping 14 matching lines...) Expand all Loading... |
77 final Map<String, Set<MemberEntity>> _interceptedMixinElements = | 76 final Map<String, Set<MemberEntity>> _interceptedMixinElements = |
78 new Map<String, Set<MemberEntity>>(); | 77 new Map<String, Set<MemberEntity>>(); |
79 | 78 |
80 final Map<String, Set<ClassEntity>> _interceptedClassesCache = | 79 final Map<String, Set<ClassEntity>> _interceptedClassesCache = |
81 new Map<String, Set<ClassEntity>>(); | 80 new Map<String, Set<ClassEntity>>(); |
82 | 81 |
83 final Set<ClassEntity> _noClasses = new Set<ClassEntity>(); | 82 final Set<ClassEntity> _noClasses = new Set<ClassEntity>(); |
84 | 83 |
85 InterceptorDataImpl( | 84 InterceptorDataImpl( |
86 this._nativeData, | 85 this._nativeData, |
87 this._helpers, | 86 this._commonElements, |
88 this._closedWorld, | 87 this._closedWorld, |
89 this._interceptedElements, | 88 this._interceptedElements, |
90 this._interceptedClasses, | 89 this._interceptedClasses, |
91 this._classesMixedIntoInterceptedClasses); | 90 this._classesMixedIntoInterceptedClasses); |
92 | 91 |
93 bool isInterceptedMethod(MemberElement element) { | 92 bool isInterceptedMethod(MemberElement element) { |
94 if (!element.isInstanceMember) return false; | 93 if (!element.isInstanceMember) return false; |
95 if (element.isGenerativeConstructorBody) { | 94 if (element.isGenerativeConstructorBody) { |
96 return _nativeData.isNativeOrExtendsNative(element.enclosingClass); | 95 return _nativeData.isNativeOrExtendsNative(element.enclosingClass); |
97 } | 96 } |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
132 if (elements.isEmpty) return false; | 131 if (elements.isEmpty) return false; |
133 return elements.any((element) { | 132 return elements.any((element) { |
134 return selector.applies(element) && | 133 return selector.applies(element) && |
135 (mask == null || mask.canHit(element, selector, _closedWorld)); | 134 (mask == null || mask.canHit(element, selector, _closedWorld)); |
136 }); | 135 }); |
137 } | 136 } |
138 | 137 |
139 /// True if the given class is an internal class used for type inference | 138 /// True if the given class is an internal class used for type inference |
140 /// and never exists at runtime. | 139 /// and never exists at runtime. |
141 bool _isCompileTimeOnlyClass(ClassEntity class_) { | 140 bool _isCompileTimeOnlyClass(ClassEntity class_) { |
142 return class_ == _helpers.jsPositiveIntClass || | 141 return class_ == _commonElements.jsPositiveIntClass || |
143 class_ == _helpers.jsUInt32Class || | 142 class_ == _commonElements.jsUInt32Class || |
144 class_ == _helpers.jsUInt31Class || | 143 class_ == _commonElements.jsUInt31Class || |
145 class_ == _helpers.jsFixedArrayClass || | 144 class_ == _commonElements.jsFixedArrayClass || |
146 class_ == _helpers.jsUnmodifiableArrayClass || | 145 class_ == _commonElements.jsUnmodifiableArrayClass || |
147 class_ == _helpers.jsMutableArrayClass || | 146 class_ == _commonElements.jsMutableArrayClass || |
148 class_ == _helpers.jsExtendableArrayClass; | 147 class_ == _commonElements.jsExtendableArrayClass; |
149 } | 148 } |
150 | 149 |
151 /// Returns a set of interceptor classes that contain a member named [name] | 150 /// Returns a set of interceptor classes that contain a member named [name] |
152 /// | 151 /// |
153 /// Returns an empty set if there is no class. Do not modify the returned set. | 152 /// Returns an empty set if there is no class. Do not modify the returned set. |
154 Set<ClassEntity> getInterceptedClassesOn(String name) { | 153 Set<ClassEntity> getInterceptedClassesOn(String name) { |
155 Set<MemberEntity> intercepted = _interceptedElements[name]; | 154 Set<MemberEntity> intercepted = _interceptedElements[name]; |
156 if (intercepted == null) return _noClasses; | 155 if (intercepted == null) return _noClasses; |
157 return _interceptedClassesCache.putIfAbsent(name, () { | 156 return _interceptedClassesCache.putIfAbsent(name, () { |
158 // Populate the cache by running through all the elements and | 157 // Populate the cache by running through all the elements and |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
209 if (!type.treatAsRaw) return false; | 208 if (!type.treatAsRaw) return false; |
210 InterfaceType interfaceType = type; | 209 InterfaceType interfaceType = type; |
211 ClassEntity classElement = interfaceType.element; | 210 ClassEntity classElement = interfaceType.element; |
212 if (isInterceptedClass(classElement)) return false; | 211 if (isInterceptedClass(classElement)) return false; |
213 return _closedWorld.hasOnlySubclasses(classElement); | 212 return _closedWorld.hasOnlySubclasses(classElement); |
214 } | 213 } |
215 } | 214 } |
216 | 215 |
217 class InterceptorDataBuilderImpl implements InterceptorDataBuilder { | 216 class InterceptorDataBuilderImpl implements InterceptorDataBuilder { |
218 final NativeBasicData _nativeData; | 217 final NativeBasicData _nativeData; |
219 final BackendHelpers _helpers; | |
220 final ElementEnvironment _elementEnvironment; | 218 final ElementEnvironment _elementEnvironment; |
221 final CommonElements _commonElements; | 219 final CommonElements _commonElements; |
222 | 220 |
223 /// The members of instantiated interceptor classes: maps a member name to the | 221 /// The members of instantiated interceptor classes: maps a member name to the |
224 /// list of members that have that name. This map is used by the codegen to | 222 /// list of members that have that name. This map is used by the codegen to |
225 /// know whether a send must be intercepted or not. | 223 /// know whether a send must be intercepted or not. |
226 final Map<String, Set<MemberEntity>> _interceptedElements = | 224 final Map<String, Set<MemberEntity>> _interceptedElements = |
227 <String, Set<MemberEntity>>{}; | 225 <String, Set<MemberEntity>>{}; |
228 | 226 |
229 /// Set of classes whose methods are intercepted. | 227 /// Set of classes whose methods are intercepted. |
230 final Set<ClassEntity> _interceptedClasses = new Set<ClassEntity>(); | 228 final Set<ClassEntity> _interceptedClasses = new Set<ClassEntity>(); |
231 | 229 |
232 /// Set of classes used as mixins on intercepted (native and primitive) | 230 /// Set of classes used as mixins on intercepted (native and primitive) |
233 /// classes. Methods on these classes might also be mixed in to regular Dart | 231 /// classes. Methods on these classes might also be mixed in to regular Dart |
234 /// (unintercepted) classes. | 232 /// (unintercepted) classes. |
235 final Set<ClassEntity> _classesMixedIntoInterceptedClasses = | 233 final Set<ClassEntity> _classesMixedIntoInterceptedClasses = |
236 new Set<ClassEntity>(); | 234 new Set<ClassEntity>(); |
237 | 235 |
238 InterceptorDataBuilderImpl(this._nativeData, this._helpers, | 236 InterceptorDataBuilderImpl( |
239 this._elementEnvironment, this._commonElements); | 237 this._nativeData, this._elementEnvironment, this._commonElements); |
240 | 238 |
241 InterceptorData onResolutionComplete(ClosedWorld closedWorld) { | 239 InterceptorData onResolutionComplete(ClosedWorld closedWorld) { |
242 return new InterceptorDataImpl( | 240 return new InterceptorDataImpl( |
243 _nativeData, | 241 _nativeData, |
244 _helpers, | 242 _commonElements, |
245 closedWorld, | 243 closedWorld, |
246 _interceptedElements, | 244 _interceptedElements, |
247 _interceptedClasses, | 245 _interceptedClasses, |
248 _classesMixedIntoInterceptedClasses); | 246 _classesMixedIntoInterceptedClasses); |
249 } | 247 } |
250 | 248 |
251 void addInterceptorsForNativeClassMembers(ClassEntity cls) { | 249 void addInterceptorsForNativeClassMembers(ClassEntity cls) { |
252 _elementEnvironment.forEachClassMember(cls, | 250 _elementEnvironment.forEachClassMember(cls, |
253 (ClassEntity cls, MemberEntity member) { | 251 (ClassEntity cls, MemberEntity member) { |
254 if (member.name == Identifiers.call) return; | 252 if (member.name == Identifiers.call) return; |
(...skipping 14 matching lines...) Expand all Loading... |
269 if (_interceptedClasses.add(cls)) { | 267 if (_interceptedClasses.add(cls)) { |
270 _elementEnvironment.forEachClassMember(cls, | 268 _elementEnvironment.forEachClassMember(cls, |
271 (ClassEntity cls, MemberEntity member) { | 269 (ClassEntity cls, MemberEntity member) { |
272 // All methods on [Object] are shadowed by [Interceptor]. | 270 // All methods on [Object] are shadowed by [Interceptor]. |
273 if (cls == _commonElements.objectClass) return; | 271 if (cls == _commonElements.objectClass) return; |
274 Set<MemberEntity> set = _interceptedElements.putIfAbsent( | 272 Set<MemberEntity> set = _interceptedElements.putIfAbsent( |
275 member.name, () => new Set<MemberEntity>()); | 273 member.name, () => new Set<MemberEntity>()); |
276 set.add(member); | 274 set.add(member); |
277 }); | 275 }); |
278 } | 276 } |
279 _interceptedClasses.add(_helpers.jsInterceptorClass); | 277 _interceptedClasses.add(_commonElements.jsInterceptorClass); |
280 } | 278 } |
281 } | 279 } |
282 | 280 |
283 class OneShotInterceptorData { | 281 class OneShotInterceptorData { |
284 final InterceptorData _interceptorData; | 282 final InterceptorData _interceptorData; |
285 final BackendHelpers _helpers; | 283 final CommonElements _commonElements; |
286 | 284 |
287 OneShotInterceptorData(this._interceptorData, this._helpers); | 285 OneShotInterceptorData(this._interceptorData, this._commonElements); |
288 | 286 |
289 /// A collection of selectors that must have a one shot interceptor generated. | 287 /// A collection of selectors that must have a one shot interceptor generated. |
290 final Map<jsAst.Name, Selector> _oneShotInterceptors = | 288 final Map<jsAst.Name, Selector> _oneShotInterceptors = |
291 <jsAst.Name, Selector>{}; | 289 <jsAst.Name, Selector>{}; |
292 | 290 |
293 Selector getOneShotInterceptorSelector(jsAst.Name name) => | 291 Selector getOneShotInterceptorSelector(jsAst.Name name) => |
294 _oneShotInterceptors[name]; | 292 _oneShotInterceptors[name]; |
295 | 293 |
296 Iterable<jsAst.Name> get oneShotInterceptorNames => | 294 Iterable<jsAst.Name> get oneShotInterceptorNames => |
297 _oneShotInterceptors.keys.toList()..sort(); | 295 _oneShotInterceptors.keys.toList()..sort(); |
(...skipping 20 matching lines...) Expand all Loading... |
318 if (!_oneShotInterceptors.containsKey(name)) { | 316 if (!_oneShotInterceptors.containsKey(name)) { |
319 registerSpecializedGetInterceptor(classes, namer); | 317 registerSpecializedGetInterceptor(classes, namer); |
320 _oneShotInterceptors[name] = selector; | 318 _oneShotInterceptors[name] = selector; |
321 } | 319 } |
322 return name; | 320 return name; |
323 } | 321 } |
324 | 322 |
325 void registerSpecializedGetInterceptor( | 323 void registerSpecializedGetInterceptor( |
326 Set<ClassEntity> classes, Namer namer) { | 324 Set<ClassEntity> classes, Namer namer) { |
327 jsAst.Name name = namer.nameForGetInterceptor(classes); | 325 jsAst.Name name = namer.nameForGetInterceptor(classes); |
328 if (classes.contains(_helpers.jsInterceptorClass)) { | 326 if (classes.contains(_commonElements.jsInterceptorClass)) { |
329 // We can't use a specialized [getInterceptorMethod], so we make | 327 // We can't use a specialized [getInterceptorMethod], so we make |
330 // sure we emit the one with all checks. | 328 // sure we emit the one with all checks. |
331 _specializedGetInterceptors[name] = _interceptorData.interceptedClasses; | 329 _specializedGetInterceptors[name] = _interceptorData.interceptedClasses; |
332 } else { | 330 } else { |
333 _specializedGetInterceptors[name] = classes; | 331 _specializedGetInterceptors[name] = classes; |
334 } | 332 } |
335 } | 333 } |
336 } | 334 } |
OLD | NEW |