Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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.native_data; | 5 library js_backend.native_data; |
| 6 | 6 |
| 7 import '../common.dart'; | 7 import '../common.dart'; |
| 8 import '../elements/elements.dart' show ClassElement; | 8 import '../elements/elements.dart' show ClassElement; |
| 9 import '../elements/entities.dart'; | 9 import '../elements/entities.dart'; |
| 10 import '../native/behavior.dart' show NativeBehavior; | 10 import '../native/behavior.dart' show NativeBehavior; |
| 11 import '../util/util.dart'; | 11 import '../util/util.dart'; |
| 12 | 12 |
| 13 /// Basic information for native classes and methods and js-interop | 13 /// Basic information for native classes and js-interop libraries and classes. |
| 14 /// classes. | |
| 15 /// | 14 /// |
| 16 /// This information is computed during loading using [NativeClassDataBuilder]. | 15 /// This information is computed during loading using [NativeBasicDataBuilder]. |
| 17 abstract class NativeClassData { | 16 abstract class NativeBasicData { |
| 18 /// Returns `true` if [cls] corresponds to a native JavaScript class. | 17 /// Returns `true` if [cls] corresponds to a native JavaScript class. |
| 19 /// | 18 /// |
| 20 /// A class is marked as native either through the `@Native(...)` annotation | 19 /// A class is marked as native either through the `@Native(...)` annotation |
| 21 /// allowed for internal libraries or via the typed JavaScriptInterop | 20 /// allowed for internal libraries or via the typed JavaScriptInterop |
| 22 /// mechanism allowed for user libraries. | 21 /// mechanism allowed for user libraries. |
| 23 bool isNativeClass(ClassEntity element); | 22 bool isNativeClass(ClassEntity element); |
| 24 | 23 |
| 25 /// Returns the list of non-directive native tag words for [cls]. | 24 /// Returns the list of non-directive native tag words for [cls]. |
| 26 List<String> getNativeTagsOfClass(ClassEntity cls); | 25 List<String> getNativeTagsOfClass(ClassEntity cls); |
| 27 | 26 |
| 28 /// Returns `true` if [cls] has a `!nonleaf` tag word. | 27 /// Returns `true` if [cls] has a `!nonleaf` tag word. |
| 29 bool hasNativeTagsForcedNonLeaf(ClassEntity cls); | 28 bool hasNativeTagsForcedNonLeaf(ClassEntity cls); |
| 30 | 29 |
| 31 /// Returns `true` if [element] or any of its superclasses is native. | 30 /// Returns `true` if [element] or any of its superclasses is native. |
| 32 bool isNativeOrExtendsNative(ClassEntity element); | 31 bool isNativeOrExtendsNative(ClassEntity element); |
| 33 | 32 |
| 34 /// Returns `true` if [element] is a JsInterop library. | 33 /// Returns `true` if [element] is a JsInterop library. |
| 35 bool isJsInteropLibrary(LibraryEntity element); | 34 bool isJsInteropLibrary(LibraryEntity element); |
| 36 | 35 |
| 37 /// Returns `true` if [element] is a JsInterop class. | 36 /// Returns `true` if [element] is a JsInterop class. |
| 38 bool isJsInteropClass(ClassEntity element); | 37 bool isJsInteropClass(ClassEntity element); |
| 39 } | 38 } |
| 40 | 39 |
| 41 /// Additional element information for native classes and methods and js-interop | 40 /// Additional element information for native classes and methods and js-interop |
| 42 /// methods. | 41 /// methods. |
| 43 /// | 42 /// |
| 44 /// This information is computed during resolution using [NativeDataBuilder]. | 43 /// This information is computed during resolution using [NativeDataBuilder]. |
| 45 abstract class NativeData extends NativeClassData { | 44 abstract class NativeData extends NativeBasicData { |
| 46 /// Returns `true` if [element] corresponds to a native JavaScript member. | 45 /// Returns `true` if [element] corresponds to a native JavaScript member. |
| 47 /// | 46 /// |
| 48 /// A member is marked as native either through the native mechanism | 47 /// A member is marked as native either through the native mechanism |
| 49 /// (`@Native(...)` or the `native` pseudo keyword) allowed for internal | 48 /// (`@Native(...)` or the `native` pseudo keyword) allowed for internal |
| 50 /// libraries or via the typed JavaScriptInterop mechanism allowed for user | 49 /// libraries or via the typed JavaScriptInterop mechanism allowed for user |
| 51 /// libraries. | 50 /// libraries. |
| 52 bool isNativeMember(MemberEntity element); | 51 bool isNativeMember(MemberEntity element); |
| 53 | 52 |
| 54 /// Returns the [NativeBehavior] for calling the native [method]. | 53 /// Returns the [NativeBehavior] for calling the native [method]. |
| 55 NativeBehavior getNativeMethodBehavior(FunctionEntity method); | 54 NativeBehavior getNativeMethodBehavior(FunctionEntity method); |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 84 String getJsInteropClassName(ClassEntity element); | 83 String getJsInteropClassName(ClassEntity element); |
| 85 | 84 |
| 86 /// Returns the explicit js interop name for member [element]. | 85 /// Returns the explicit js interop name for member [element]. |
| 87 String getJsInteropMemberName(MemberEntity element); | 86 String getJsInteropMemberName(MemberEntity element); |
| 88 | 87 |
| 89 /// Apply JS$ escaping scheme to convert possible escaped Dart names into | 88 /// Apply JS$ escaping scheme to convert possible escaped Dart names into |
| 90 /// JS names. | 89 /// JS names. |
| 91 String computeUnescapedJSInteropName(String name); | 90 String computeUnescapedJSInteropName(String name); |
| 92 } | 91 } |
| 93 | 92 |
| 94 abstract class NativeClassDataBuilder { | 93 abstract class NativeBasicDataBuilder { |
| 95 /// Sets the native tag info for [cls]. | 94 /// Sets the native tag info for [cls]. |
| 96 /// | 95 /// |
| 97 /// The tag info string contains comma-separated 'words' which are either | 96 /// The tag info string contains comma-separated 'words' which are either |
| 98 /// dispatch tags (having JavaScript identifier syntax) and directives that | 97 /// dispatch tags (having JavaScript identifier syntax) and directives that |
| 99 /// begin with `!`. | 98 /// begin with `!`. |
| 100 void setNativeClassTagInfo(ClassEntity cls, String tagInfo); | 99 void setNativeClassTagInfo(ClassEntity cls, String tagInfo); |
| 101 | 100 |
| 102 /// Marks [element] as an explicit part of JsInterop. The js interop name is | 101 /// Marks [element] as an explicit part of JsInterop. The js interop name is |
| 103 /// expected to be computed later. | 102 /// expected to be computed later. |
| 104 void markAsJsInteropLibrary(LibraryEntity element); | 103 void markAsJsInteropLibrary(LibraryEntity element); |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 129 /// Sets the explicit js interop [name] for the library [element]. | 128 /// Sets the explicit js interop [name] for the library [element]. |
| 130 void setJsInteropLibraryName(LibraryEntity element, String name); | 129 void setJsInteropLibraryName(LibraryEntity element, String name); |
| 131 | 130 |
| 132 /// Sets the explicit js interop [name] for the class [element]. | 131 /// Sets the explicit js interop [name] for the class [element]. |
| 133 void setJsInteropClassName(ClassEntity element, String name); | 132 void setJsInteropClassName(ClassEntity element, String name); |
| 134 | 133 |
| 135 /// Sets the explicit js interop [name] for the member [element]. | 134 /// Sets the explicit js interop [name] for the member [element]. |
| 136 void setJsInteropMemberName(MemberEntity element, String name); | 135 void setJsInteropMemberName(MemberEntity element, String name); |
| 137 } | 136 } |
| 138 | 137 |
| 139 class NativeClassDataImpl implements NativeClassDataBuilder, NativeClassData { | 138 class NativeBasicDataImpl implements NativeBasicDataBuilder, NativeBasicData { |
| 140 /// Tag info for native JavaScript classes names. See | 139 /// Tag info for native JavaScript classes names. See |
| 141 /// [setNativeClassTagInfo]. | 140 /// [setNativeClassTagInfo]. |
| 142 Map<ClassEntity, NativeClassTag> nativeClassTagInfo = | 141 Map<ClassEntity, NativeClassTag> nativeClassTagInfo = |
| 143 <ClassEntity, NativeClassTag>{}; | 142 <ClassEntity, NativeClassTag>{}; |
| 144 | 143 |
| 145 /// The JavaScript libraries implemented via typed JavaScript interop. | 144 /// The JavaScript libraries implemented via typed JavaScript interop. |
| 146 Set<LibraryEntity> jsInteropLibraries = new Set<LibraryEntity>(); | 145 Set<LibraryEntity> jsInteropLibraries = new Set<LibraryEntity>(); |
| 147 | 146 |
| 148 /// The JavaScript classes implemented via typed JavaScript interop. | 147 /// The JavaScript classes implemented via typed JavaScript interop. |
| 149 Set<ClassEntity> jsInteropClasses = new Set<ClassEntity>(); | 148 Set<ClassEntity> jsInteropClasses = new Set<ClassEntity>(); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 214 assert(element.isResolved); | 213 assert(element.isResolved); |
| 215 return isNativeOrExtendsNative(element.superclass); | 214 return isNativeOrExtendsNative(element.superclass); |
| 216 } | 215 } |
| 217 } | 216 } |
| 218 | 217 |
| 219 class NativeDataImpl implements NativeDataBuilder, NativeData { | 218 class NativeDataImpl implements NativeDataBuilder, NativeData { |
| 220 /// Prefix used to escape JS names that are not valid Dart names | 219 /// Prefix used to escape JS names that are not valid Dart names |
| 221 /// when using JSInterop. | 220 /// when using JSInterop. |
| 222 static const String _jsInteropEscapePrefix = r'JS$'; | 221 static const String _jsInteropEscapePrefix = r'JS$'; |
| 223 | 222 |
| 224 final NativeClassData _nativeClassData; | 223 final NativeBasicData _nativeBaseData; |
|
Siggi Cherem (dart-lang)
2017/03/17 23:50:55
should the variable be BasicData too? I have a fee
| |
| 225 | 224 |
| 226 /// The JavaScript names for native JavaScript elements implemented. | 225 /// The JavaScript names for native JavaScript elements implemented. |
| 227 Map<MemberEntity, String> nativeMemberName = <MemberEntity, String>{}; | 226 Map<MemberEntity, String> nativeMemberName = <MemberEntity, String>{}; |
| 228 | 227 |
| 229 /// Cache for [NativeBehavior]s for calling native methods. | 228 /// Cache for [NativeBehavior]s for calling native methods. |
| 230 Map<FunctionEntity, NativeBehavior> nativeMethodBehavior = | 229 Map<FunctionEntity, NativeBehavior> nativeMethodBehavior = |
| 231 <FunctionEntity, NativeBehavior>{}; | 230 <FunctionEntity, NativeBehavior>{}; |
| 232 | 231 |
| 233 /// Cache for [NativeBehavior]s for reading from native fields. | 232 /// Cache for [NativeBehavior]s for reading from native fields. |
| 234 Map<MemberEntity, NativeBehavior> nativeFieldLoadBehavior = | 233 Map<MemberEntity, NativeBehavior> nativeFieldLoadBehavior = |
| 235 <FieldEntity, NativeBehavior>{}; | 234 <FieldEntity, NativeBehavior>{}; |
| 236 | 235 |
| 237 /// Cache for [NativeBehavior]s for writing to native fields. | 236 /// Cache for [NativeBehavior]s for writing to native fields. |
| 238 Map<MemberEntity, NativeBehavior> nativeFieldStoreBehavior = | 237 Map<MemberEntity, NativeBehavior> nativeFieldStoreBehavior = |
| 239 <FieldEntity, NativeBehavior>{}; | 238 <FieldEntity, NativeBehavior>{}; |
| 240 | 239 |
| 241 /// The JavaScript names for elements implemented via typed JavaScript | 240 /// The JavaScript names for elements implemented via typed JavaScript |
| 242 /// interop. | 241 /// interop. |
| 243 Map<LibraryEntity, String> jsInteropLibraryNames = <LibraryEntity, String>{}; | 242 Map<LibraryEntity, String> jsInteropLibraryNames = <LibraryEntity, String>{}; |
| 244 Map<ClassEntity, String> jsInteropClassNames = <ClassEntity, String>{}; | 243 Map<ClassEntity, String> jsInteropClassNames = <ClassEntity, String>{}; |
| 245 | 244 |
| 246 /// The JavaScript names for elements implemented via typed JavaScript | 245 /// The JavaScript names for elements implemented via typed JavaScript |
| 247 /// interop. | 246 /// interop. |
| 248 Map<MemberEntity, String> jsInteropMemberNames = <MemberEntity, String>{}; | 247 Map<MemberEntity, String> jsInteropMemberNames = <MemberEntity, String>{}; |
| 249 | 248 |
| 250 NativeDataImpl(this._nativeClassData); | 249 NativeDataImpl(this._nativeBaseData); |
| 251 | 250 |
| 252 /// Sets the native [name] for the member [element]. This name is used for | 251 /// Sets the native [name] for the member [element]. This name is used for |
| 253 /// [element] in the generated JavaScript. | 252 /// [element] in the generated JavaScript. |
| 254 void setNativeMemberName(MemberEntity element, String name) { | 253 void setNativeMemberName(MemberEntity element, String name) { |
| 255 // TODO(johnniwinther): Avoid setting this more than once. The enqueuer | 254 // TODO(johnniwinther): Avoid setting this more than once. The enqueuer |
| 256 // might enqueue [element] several times (before processing it) and computes | 255 // might enqueue [element] several times (before processing it) and computes |
| 257 // name on each call to `internalAddToWorkList`. | 256 // name on each call to `internalAddToWorkList`. |
| 258 assert(invariant(element, | 257 assert(invariant(element, |
| 259 nativeMemberName[element] == null || nativeMemberName[element] == name, | 258 nativeMemberName[element] == null || nativeMemberName[element] == name, |
| 260 message: "Native member name set inconsistently on $element: " | 259 message: "Native member name set inconsistently on $element: " |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 273 nativeFieldLoadBehavior[field] = behavior; | 272 nativeFieldLoadBehavior[field] = behavior; |
| 274 } | 273 } |
| 275 | 274 |
| 276 /// Registers the [behavior] for writing to the native [field]. | 275 /// Registers the [behavior] for writing to the native [field]. |
| 277 void setNativeFieldStoreBehavior(FieldEntity field, NativeBehavior behavior) { | 276 void setNativeFieldStoreBehavior(FieldEntity field, NativeBehavior behavior) { |
| 278 nativeFieldStoreBehavior[field] = behavior; | 277 nativeFieldStoreBehavior[field] = behavior; |
| 279 } | 278 } |
| 280 | 279 |
| 281 /// Sets the explicit js interop [name] for the library [element]. | 280 /// Sets the explicit js interop [name] for the library [element]. |
| 282 void setJsInteropLibraryName(LibraryEntity element, String name) { | 281 void setJsInteropLibraryName(LibraryEntity element, String name) { |
| 283 assert(invariant(element, _nativeClassData.isJsInteropLibrary(element), | 282 assert(invariant(element, _nativeBaseData.isJsInteropLibrary(element), |
| 284 message: | 283 message: |
| 285 'Library $element is not js interop but given a js interop name.')); | 284 'Library $element is not js interop but given a js interop name.')); |
| 286 jsInteropLibraryNames[element] = name; | 285 jsInteropLibraryNames[element] = name; |
| 287 } | 286 } |
| 288 | 287 |
| 289 /// Sets the explicit js interop [name] for the class [element]. | 288 /// Sets the explicit js interop [name] for the class [element]. |
| 290 void setJsInteropClassName(ClassEntity element, String name) { | 289 void setJsInteropClassName(ClassEntity element, String name) { |
| 291 assert(invariant(element, _nativeClassData.isJsInteropClass(element), | 290 assert(invariant(element, _nativeBaseData.isJsInteropClass(element), |
| 292 message: | 291 message: |
| 293 'Class $element is not js interop but given a js interop name.')); | 292 'Class $element is not js interop but given a js interop name.')); |
| 294 jsInteropClassNames[element] = name; | 293 jsInteropClassNames[element] = name; |
| 295 } | 294 } |
| 296 | 295 |
| 297 @override | 296 @override |
| 298 void markAsJsInteropMember(MemberEntity element) { | 297 void markAsJsInteropMember(MemberEntity element) { |
| 299 jsInteropMemberNames[element] = null; | 298 jsInteropMemberNames[element] = null; |
| 300 } | 299 } |
| 301 | 300 |
| 302 /// Returns `true` if [element] is explicitly marked as part of JsInterop. | 301 /// Returns `true` if [element] is explicitly marked as part of JsInterop. |
| 303 bool _isJsInteropMember(MemberEntity element) { | 302 bool _isJsInteropMember(MemberEntity element) { |
| 304 return jsInteropMemberNames.containsKey(element); | 303 return jsInteropMemberNames.containsKey(element); |
| 305 } | 304 } |
| 306 | 305 |
| 307 /// Sets the explicit js interop [name] for the member [element]. | 306 /// Sets the explicit js interop [name] for the member [element]. |
| 308 void setJsInteropMemberName(MemberEntity element, String name) { | 307 void setJsInteropMemberName(MemberEntity element, String name) { |
| 309 assert(invariant(element, _isJsInteropMember(element), | 308 assert(invariant(element, _isJsInteropMember(element), |
| 310 message: | 309 message: |
| 311 'Member $element is not js interop but given a js interop name.')); | 310 'Member $element is not js interop but given a js interop name.')); |
| 312 jsInteropMemberNames[element] = name; | 311 jsInteropMemberNames[element] = name; |
| 313 } | 312 } |
| 314 | 313 |
| 315 /// Returns `true` if [cls] is a native class. | 314 /// Returns `true` if [cls] is a native class. |
| 316 bool isNativeClass(ClassEntity element) => | 315 bool isNativeClass(ClassEntity element) => |
| 317 _nativeClassData.isNativeClass(element); | 316 _nativeBaseData.isNativeClass(element); |
| 318 | 317 |
| 319 /// Returns the list of non-directive native tag words for [cls]. | 318 /// Returns the list of non-directive native tag words for [cls]. |
| 320 List<String> getNativeTagsOfClass(ClassEntity cls) => | 319 List<String> getNativeTagsOfClass(ClassEntity cls) => |
| 321 _nativeClassData.getNativeTagsOfClass(cls); | 320 _nativeBaseData.getNativeTagsOfClass(cls); |
| 322 | 321 |
| 323 /// Returns `true` if [cls] has a `!nonleaf` tag word. | 322 /// Returns `true` if [cls] has a `!nonleaf` tag word. |
| 324 bool hasNativeTagsForcedNonLeaf(ClassEntity cls) => | 323 bool hasNativeTagsForcedNonLeaf(ClassEntity cls) => |
| 325 _nativeClassData.hasNativeTagsForcedNonLeaf(cls); | 324 _nativeBaseData.hasNativeTagsForcedNonLeaf(cls); |
| 326 | 325 |
| 327 /// Returns `true` if [element] is a JsInterop library. | 326 /// Returns `true` if [element] is a JsInterop library. |
| 328 bool isJsInteropLibrary(LibraryEntity element) => | 327 bool isJsInteropLibrary(LibraryEntity element) => |
| 329 _nativeClassData.isJsInteropLibrary(element); | 328 _nativeBaseData.isJsInteropLibrary(element); |
| 330 | 329 |
| 331 /// Returns `true` if [element] is a JsInterop class. | 330 /// Returns `true` if [element] is a JsInterop class. |
| 332 bool isJsInteropClass(ClassEntity element) => | 331 bool isJsInteropClass(ClassEntity element) => |
| 333 _nativeClassData.isJsInteropClass(element); | 332 _nativeBaseData.isJsInteropClass(element); |
| 334 | 333 |
| 335 /// Returns `true` if [element] or any of its superclasses is native. | 334 /// Returns `true` if [element] or any of its superclasses is native. |
| 336 bool isNativeOrExtendsNative(ClassEntity element) => | 335 bool isNativeOrExtendsNative(ClassEntity element) => |
| 337 _nativeClassData.isNativeOrExtendsNative(element); | 336 _nativeBaseData.isNativeOrExtendsNative(element); |
| 338 | 337 |
| 339 /// Returns the explicit js interop name for library [element]. | 338 /// Returns the explicit js interop name for library [element]. |
| 340 String getJsInteropLibraryName(LibraryEntity element) { | 339 String getJsInteropLibraryName(LibraryEntity element) { |
| 341 return jsInteropLibraryNames[element]; | 340 return jsInteropLibraryNames[element]; |
| 342 } | 341 } |
| 343 | 342 |
| 344 /// Returns the explicit js interop name for class [element]. | 343 /// Returns the explicit js interop name for class [element]. |
| 345 String getJsInteropClassName(ClassEntity element) { | 344 String getJsInteropClassName(ClassEntity element) { |
| 346 return jsInteropClassNames[element]; | 345 return jsInteropClassNames[element]; |
| 347 } | 346 } |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 510 int get hashCode => Hashing.listHash(names, isNonLeaf.hashCode); | 509 int get hashCode => Hashing.listHash(names, isNonLeaf.hashCode); |
| 511 | 510 |
| 512 bool operator ==(other) { | 511 bool operator ==(other) { |
| 513 if (identical(this, other)) return true; | 512 if (identical(this, other)) return true; |
| 514 if (other is! NativeClassTag) return false; | 513 if (other is! NativeClassTag) return false; |
| 515 return equalElements(names, other.names) && isNonLeaf == other.isNonLeaf; | 514 return equalElements(names, other.names) && isNonLeaf == other.isNonLeaf; |
| 516 } | 515 } |
| 517 | 516 |
| 518 String toString() => text; | 517 String toString() => text; |
| 519 } | 518 } |
| OLD | NEW |