| 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 |