| 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 '../common_elements.dart' show ElementEnvironment; | 8 import '../common_elements.dart' show ElementEnvironment; |
| 9 import '../elements/entities.dart'; | 9 import '../elements/entities.dart'; |
| 10 import '../native/behavior.dart' show NativeBehavior; | 10 import '../native/behavior.dart' show NativeBehavior; |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 139 void setJsInteropLibraryName(LibraryEntity element, String name); | 139 void setJsInteropLibraryName(LibraryEntity element, String name); |
| 140 | 140 |
| 141 /// Marks [element] as having an `@Anonymous` annotation. | 141 /// Marks [element] as having an `@Anonymous` annotation. |
| 142 void markJsInteropClassAsAnonymous(ClassEntity element); | 142 void markJsInteropClassAsAnonymous(ClassEntity element); |
| 143 | 143 |
| 144 /// Sets the explicit js interop [name] for the class [element]. | 144 /// Sets the explicit js interop [name] for the class [element]. |
| 145 void setJsInteropClassName(ClassEntity element, String name); | 145 void setJsInteropClassName(ClassEntity element, String name); |
| 146 | 146 |
| 147 /// Sets the explicit js interop [name] for the member [element]. | 147 /// Sets the explicit js interop [name] for the member [element]. |
| 148 void setJsInteropMemberName(MemberEntity element, String name); | 148 void setJsInteropMemberName(MemberEntity element, String name); |
| 149 |
| 150 /// Closes this builder and creates the resulting [NativeData] object. |
| 151 NativeData close(); |
| 149 } | 152 } |
| 150 | 153 |
| 151 class NativeBasicDataBuilderImpl implements NativeBasicDataBuilder { | 154 class NativeBasicDataBuilderImpl implements NativeBasicDataBuilder { |
| 152 /// Tag info for native JavaScript classes names. See | 155 /// Tag info for native JavaScript classes names. See |
| 153 /// [setNativeClassTagInfo]. | 156 /// [setNativeClassTagInfo]. |
| 154 Map<ClassEntity, NativeClassTag> nativeClassTagInfo = | 157 Map<ClassEntity, NativeClassTag> nativeClassTagInfo = |
| 155 <ClassEntity, NativeClassTag>{}; | 158 <ClassEntity, NativeClassTag>{}; |
| 156 | 159 |
| 157 /// The JavaScript libraries implemented via typed JavaScript interop. | 160 /// The JavaScript libraries implemented via typed JavaScript interop. |
| 158 Set<LibraryEntity> jsInteropLibraries = new Set<LibraryEntity>(); | 161 Set<LibraryEntity> jsInteropLibraries = new Set<LibraryEntity>(); |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 244 /// Returns `true` if [element] or any of its superclasses is native. | 247 /// Returns `true` if [element] or any of its superclasses is native. |
| 245 bool isNativeOrExtendsNative(ClassEntity element) { | 248 bool isNativeOrExtendsNative(ClassEntity element) { |
| 246 if (element == null) return false; | 249 if (element == null) return false; |
| 247 if (isNativeClass(element) || isJsInteropClass(element)) { | 250 if (isNativeClass(element) || isJsInteropClass(element)) { |
| 248 return true; | 251 return true; |
| 249 } | 252 } |
| 250 return isNativeOrExtendsNative(_env.getSuperClass(element)); | 253 return isNativeOrExtendsNative(_env.getSuperClass(element)); |
| 251 } | 254 } |
| 252 } | 255 } |
| 253 | 256 |
| 254 class NativeDataImpl implements NativeDataBuilder, NativeData { | 257 class NativeDataBuilderImpl implements NativeDataBuilder { |
| 255 /// Prefix used to escape JS names that are not valid Dart names | |
| 256 /// when using JSInterop. | |
| 257 static const String _jsInteropEscapePrefix = r'JS$'; | |
| 258 | |
| 259 final NativeBasicData _nativeBasicData; | 258 final NativeBasicData _nativeBasicData; |
| 260 | 259 |
| 261 /// The JavaScript names for native JavaScript elements implemented. | 260 /// The JavaScript names for native JavaScript elements implemented. |
| 262 Map<MemberEntity, String> nativeMemberName = <MemberEntity, String>{}; | 261 Map<MemberEntity, String> nativeMemberName = <MemberEntity, String>{}; |
| 263 | 262 |
| 264 /// Cache for [NativeBehavior]s for calling native methods. | 263 /// Cache for [NativeBehavior]s for calling native methods. |
| 265 Map<FunctionEntity, NativeBehavior> nativeMethodBehavior = | 264 Map<FunctionEntity, NativeBehavior> nativeMethodBehavior = |
| 266 <FunctionEntity, NativeBehavior>{}; | 265 <FunctionEntity, NativeBehavior>{}; |
| 267 | 266 |
| 268 /// Cache for [NativeBehavior]s for reading from native fields. | 267 /// Cache for [NativeBehavior]s for reading from native fields. |
| 269 Map<MemberEntity, NativeBehavior> nativeFieldLoadBehavior = | 268 Map<MemberEntity, NativeBehavior> nativeFieldLoadBehavior = |
| 270 <FieldEntity, NativeBehavior>{}; | 269 <FieldEntity, NativeBehavior>{}; |
| 271 | 270 |
| 272 /// Cache for [NativeBehavior]s for writing to native fields. | 271 /// Cache for [NativeBehavior]s for writing to native fields. |
| 273 Map<MemberEntity, NativeBehavior> nativeFieldStoreBehavior = | 272 Map<MemberEntity, NativeBehavior> nativeFieldStoreBehavior = |
| 274 <FieldEntity, NativeBehavior>{}; | 273 <FieldEntity, NativeBehavior>{}; |
| 275 | 274 |
| 276 /// The JavaScript names for elements implemented via typed JavaScript | 275 /// The JavaScript names for libraries implemented via typed JavaScript |
| 277 /// interop. | 276 /// interop. |
| 278 Map<LibraryEntity, String> jsInteropLibraryNames = <LibraryEntity, String>{}; | 277 Map<LibraryEntity, String> jsInteropLibraryNames = <LibraryEntity, String>{}; |
| 278 |
| 279 /// JavaScript interop classes annotated with `@anonymous` |
| 279 Set<ClassEntity> anonymousJsInteropClasses = new Set<ClassEntity>(); | 280 Set<ClassEntity> anonymousJsInteropClasses = new Set<ClassEntity>(); |
| 281 |
| 282 /// The JavaScript names for classes implemented via typed JavaScript |
| 283 /// interop. |
| 280 Map<ClassEntity, String> jsInteropClassNames = <ClassEntity, String>{}; | 284 Map<ClassEntity, String> jsInteropClassNames = <ClassEntity, String>{}; |
| 281 | 285 |
| 282 /// The JavaScript names for elements implemented via typed JavaScript | 286 /// The JavaScript names for members implemented via typed JavaScript |
| 283 /// interop. | 287 /// interop. |
| 284 Map<MemberEntity, String> jsInteropMemberNames = <MemberEntity, String>{}; | 288 Map<MemberEntity, String> jsInteropMemberNames = <MemberEntity, String>{}; |
| 285 | 289 |
| 286 NativeDataImpl(this._nativeBasicData); | 290 NativeDataBuilderImpl(this._nativeBasicData); |
| 287 | 291 |
| 288 /// Sets the native [name] for the member [element]. This name is used for | 292 /// Sets the native [name] for the member [element]. This name is used for |
| 289 /// [element] in the generated JavaScript. | 293 /// [element] in the generated JavaScript. |
| 290 void setNativeMemberName(MemberEntity element, String name) { | 294 void setNativeMemberName(MemberEntity element, String name) { |
| 291 // TODO(johnniwinther): Avoid setting this more than once. The enqueuer | 295 // TODO(johnniwinther): Avoid setting this more than once. The enqueuer |
| 292 // might enqueue [element] several times (before processing it) and computes | 296 // might enqueue [element] several times (before processing it) and computes |
| 293 // name on each call to `internalAddToWorkList`. | 297 // name on each call to `internalAddToWorkList`. |
| 294 assert(invariant(element, | 298 assert(invariant(element, |
| 295 nativeMemberName[element] == null || nativeMemberName[element] == name, | 299 nativeMemberName[element] == null || nativeMemberName[element] == name, |
| 296 message: "Native member name set inconsistently on $element: " | 300 message: "Native member name set inconsistently on $element: " |
| (...skipping 19 matching lines...) Expand all Loading... |
| 316 | 320 |
| 317 /// Sets the explicit js interop [name] for the library [element]. | 321 /// Sets the explicit js interop [name] for the library [element]. |
| 318 void setJsInteropLibraryName(LibraryEntity element, String name) { | 322 void setJsInteropLibraryName(LibraryEntity element, String name) { |
| 319 assert(invariant(element, _nativeBasicData.isJsInteropLibrary(element), | 323 assert(invariant(element, _nativeBasicData.isJsInteropLibrary(element), |
| 320 message: | 324 message: |
| 321 'Library $element is not js interop but given a js interop name.')); | 325 'Library $element is not js interop but given a js interop name.')); |
| 322 jsInteropLibraryNames[element] = name; | 326 jsInteropLibraryNames[element] = name; |
| 323 } | 327 } |
| 324 | 328 |
| 325 @override | 329 @override |
| 326 bool isAnonymousJsInteropClass(ClassEntity element) { | |
| 327 return anonymousJsInteropClasses.contains(element); | |
| 328 } | |
| 329 | |
| 330 @override | |
| 331 void markJsInteropClassAsAnonymous(ClassEntity element) { | 330 void markJsInteropClassAsAnonymous(ClassEntity element) { |
| 332 anonymousJsInteropClasses.add(element); | 331 anonymousJsInteropClasses.add(element); |
| 333 } | 332 } |
| 334 | 333 |
| 335 /// Sets the explicit js interop [name] for the class [element]. | 334 /// Sets the explicit js interop [name] for the class [element]. |
| 336 void setJsInteropClassName(ClassEntity element, String name) { | 335 void setJsInteropClassName(ClassEntity element, String name) { |
| 337 assert(invariant(element, _nativeBasicData.isJsInteropClass(element), | 336 assert(invariant(element, _nativeBasicData.isJsInteropClass(element), |
| 338 message: | 337 message: |
| 339 'Class $element is not js interop but given a js interop name.')); | 338 'Class $element is not js interop but given a js interop name.')); |
| 340 jsInteropClassNames[element] = name; | 339 jsInteropClassNames[element] = name; |
| 341 } | 340 } |
| 342 | 341 |
| 343 @override | 342 @override |
| 344 void markAsJsInteropMember(MemberEntity element) { | 343 void markAsJsInteropMember(MemberEntity element) { |
| 345 jsInteropMemberNames[element] = null; | 344 jsInteropMemberNames[element] = null; |
| 346 } | 345 } |
| 347 | 346 |
| 348 /// Returns `true` if [element] is explicitly marked as part of JsInterop. | |
| 349 bool _isJsInteropMember(MemberEntity element) { | |
| 350 return jsInteropMemberNames.containsKey(element); | |
| 351 } | |
| 352 | |
| 353 /// Sets the explicit js interop [name] for the member [element]. | 347 /// Sets the explicit js interop [name] for the member [element]. |
| 354 void setJsInteropMemberName(MemberEntity element, String name) { | 348 void setJsInteropMemberName(MemberEntity element, String name) { |
| 355 assert(invariant(element, _isJsInteropMember(element), | 349 assert(invariant(element, jsInteropMemberNames.containsKey(element), |
| 356 message: | 350 message: |
| 357 'Member $element is not js interop but given a js interop name.')); | 351 'Member $element is not js interop but given a js interop name.')); |
| 358 jsInteropMemberNames[element] = name; | 352 jsInteropMemberNames[element] = name; |
| 359 } | 353 } |
| 360 | 354 |
| 355 @override |
| 356 NativeData close() => new NativeDataImpl( |
| 357 _nativeBasicData, |
| 358 nativeMemberName, |
| 359 nativeMethodBehavior, |
| 360 nativeFieldLoadBehavior, |
| 361 nativeFieldStoreBehavior, |
| 362 jsInteropLibraryNames, |
| 363 anonymousJsInteropClasses, |
| 364 jsInteropClassNames, |
| 365 jsInteropMemberNames); |
| 366 } |
| 367 |
| 368 class NativeDataImpl implements NativeData { |
| 369 /// Prefix used to escape JS names that are not valid Dart names |
| 370 /// when using JSInterop. |
| 371 static const String _jsInteropEscapePrefix = r'JS$'; |
| 372 |
| 373 final NativeBasicData _nativeBasicData; |
| 374 |
| 375 /// The JavaScript names for native JavaScript elements implemented. |
| 376 final Map<MemberEntity, String> nativeMemberName; |
| 377 |
| 378 /// Cache for [NativeBehavior]s for calling native methods. |
| 379 final Map<FunctionEntity, NativeBehavior> nativeMethodBehavior; |
| 380 |
| 381 /// Cache for [NativeBehavior]s for reading from native fields. |
| 382 final Map<MemberEntity, NativeBehavior> nativeFieldLoadBehavior; |
| 383 |
| 384 /// Cache for [NativeBehavior]s for writing to native fields. |
| 385 final Map<MemberEntity, NativeBehavior> nativeFieldStoreBehavior; |
| 386 |
| 387 /// The JavaScript names for libraries implemented via typed JavaScript |
| 388 /// interop. |
| 389 final Map<LibraryEntity, String> jsInteropLibraryNames; |
| 390 |
| 391 /// JavaScript interop classes annotated with `@anonymous` |
| 392 final Set<ClassEntity> anonymousJsInteropClasses; |
| 393 |
| 394 /// The JavaScript names for classes implemented via typed JavaScript |
| 395 /// interop. |
| 396 final Map<ClassEntity, String> jsInteropClassNames; |
| 397 |
| 398 /// The JavaScript names for members implemented via typed JavaScript |
| 399 /// interop. |
| 400 final Map<MemberEntity, String> jsInteropMemberNames; |
| 401 |
| 402 NativeDataImpl( |
| 403 this._nativeBasicData, |
| 404 this.nativeMemberName, |
| 405 this.nativeMethodBehavior, |
| 406 this.nativeFieldLoadBehavior, |
| 407 this.nativeFieldStoreBehavior, |
| 408 this.jsInteropLibraryNames, |
| 409 this.anonymousJsInteropClasses, |
| 410 this.jsInteropClassNames, |
| 411 this.jsInteropMemberNames); |
| 412 |
| 413 @override |
| 414 bool isAnonymousJsInteropClass(ClassEntity element) { |
| 415 return anonymousJsInteropClasses.contains(element); |
| 416 } |
| 417 |
| 361 /// Returns `true` if [cls] is a native class. | 418 /// Returns `true` if [cls] is a native class. |
| 362 bool isNativeClass(ClassEntity element) => | 419 bool isNativeClass(ClassEntity element) => |
| 363 _nativeBasicData.isNativeClass(element); | 420 _nativeBasicData.isNativeClass(element); |
| 364 | 421 |
| 365 /// Returns the list of non-directive native tag words for [cls]. | 422 /// Returns the list of non-directive native tag words for [cls]. |
| 366 List<String> getNativeTagsOfClass(ClassEntity cls) => | 423 List<String> getNativeTagsOfClass(ClassEntity cls) => |
| 367 _nativeBasicData.getNativeTagsOfClass(cls); | 424 _nativeBasicData.getNativeTagsOfClass(cls); |
| 368 | 425 |
| 369 /// Returns `true` if [cls] has a `!nonleaf` tag word. | 426 /// Returns `true` if [cls] has a `!nonleaf` tag word. |
| 370 bool hasNativeTagsForcedNonLeaf(ClassEntity cls) => | 427 bool hasNativeTagsForcedNonLeaf(ClassEntity cls) => |
| (...skipping 21 matching lines...) Expand all Loading... |
| 392 /// Returns the explicit js interop name for class [element]. | 449 /// Returns the explicit js interop name for class [element]. |
| 393 String getJsInteropClassName(ClassEntity element) { | 450 String getJsInteropClassName(ClassEntity element) { |
| 394 return jsInteropClassNames[element]; | 451 return jsInteropClassNames[element]; |
| 395 } | 452 } |
| 396 | 453 |
| 397 /// Returns the explicit js interop name for member [element]. | 454 /// Returns the explicit js interop name for member [element]. |
| 398 String getJsInteropMemberName(MemberEntity element) { | 455 String getJsInteropMemberName(MemberEntity element) { |
| 399 return jsInteropMemberNames[element]; | 456 return jsInteropMemberNames[element]; |
| 400 } | 457 } |
| 401 | 458 |
| 459 /// Returns `true` if [element] is explicitly marked as part of JsInterop. |
| 460 bool _isJsInteropMember(MemberEntity element) { |
| 461 return jsInteropMemberNames.containsKey(element); |
| 462 } |
| 463 |
| 402 /// Returns `true` if [element] is a JsInterop method. | 464 /// Returns `true` if [element] is a JsInterop method. |
| 403 bool isJsInteropMember(MemberEntity element) { | 465 bool isJsInteropMember(MemberEntity element) { |
| 404 if (element.isFunction || | 466 if (element.isFunction || |
| 405 element.isConstructor || | 467 element.isConstructor || |
| 406 element.isGetter || | 468 element.isGetter || |
| 407 element.isSetter) { | 469 element.isSetter) { |
| 408 FunctionEntity function = element; | 470 FunctionEntity function = element; |
| 409 if (!function.isExternal) return false; | 471 if (!function.isExternal) return false; |
| 410 | 472 |
| 411 if (_isJsInteropMember(function)) return true; | 473 if (_isJsInteropMember(function)) return true; |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 558 int get hashCode => Hashing.listHash(names, isNonLeaf.hashCode); | 620 int get hashCode => Hashing.listHash(names, isNonLeaf.hashCode); |
| 559 | 621 |
| 560 bool operator ==(other) { | 622 bool operator ==(other) { |
| 561 if (identical(this, other)) return true; | 623 if (identical(this, other)) return true; |
| 562 if (other is! NativeClassTag) return false; | 624 if (other is! NativeClassTag) return false; |
| 563 return equalElements(names, other.names) && isNonLeaf == other.isNonLeaf; | 625 return equalElements(names, other.names) && isNonLeaf == other.isNonLeaf; |
| 564 } | 626 } |
| 565 | 627 |
| 566 String toString() => text; | 628 String toString() => text; |
| 567 } | 629 } |
| OLD | NEW |