| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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.backend; | 5 library js_backend.backend; |
| 6 | 6 |
| 7 import 'dart:async' show Future; | 7 import 'dart:async' show Future; |
| 8 | 8 |
| 9 import 'package:js_runtime/shared/embedded_names.dart' as embeddedNames; | 9 import 'package:js_runtime/shared/embedded_names.dart' as embeddedNames; |
| 10 | 10 |
| (...skipping 768 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 779 * Returns `true` if [member] is called from a subclass via `super`. | 779 * Returns `true` if [member] is called from a subclass via `super`. |
| 780 */ | 780 */ |
| 781 bool isAliasedSuperMember(FunctionElement member) { | 781 bool isAliasedSuperMember(FunctionElement member) { |
| 782 return aliasedSuperMembers.contains(member); | 782 return aliasedSuperMembers.contains(member); |
| 783 } | 783 } |
| 784 | 784 |
| 785 /// Returns `true` if [element] is part of JsInterop. | 785 /// Returns `true` if [element] is part of JsInterop. |
| 786 @override | 786 @override |
| 787 bool isJsInterop(Element element) => nativeData.isJsInterop(element); | 787 bool isJsInterop(Element element) => nativeData.isJsInterop(element); |
| 788 | 788 |
| 789 /// Returns `true` if [element] is a JsInterop class. |
| 790 bool isJsInteropClass(ClassElement element) => isJsInterop(element); |
| 791 |
| 792 /// Returns `true` if [element] is a JsInterop method. |
| 793 bool isJsInteropMethod(MethodElement element) => isJsInterop(element); |
| 794 |
| 789 /// Whether [element] corresponds to a native JavaScript construct either | 795 /// Whether [element] corresponds to a native JavaScript construct either |
| 790 /// through the native mechanism (`@Native(...)` or the `native` pseudo | 796 /// through the native mechanism (`@Native(...)` or the `native` pseudo |
| 791 /// keyword) which is only allowed for internal libraries or via the typed | 797 /// keyword) which is only allowed for internal libraries or via the typed |
| 792 /// JavaScriptInterop mechanism which is allowed for user libraries. | 798 /// JavaScriptInterop mechanism which is allowed for user libraries. |
| 793 @override | 799 @override |
| 794 bool isNative(Entity element) => nativeData.isNative(element); | 800 bool isNative(Entity element) => nativeData.isNative(element); |
| 795 | 801 |
| 796 /// Returns the [NativeBehavior] for calling the native [method]. | 802 /// Returns the [NativeBehavior] for calling the native [method]. |
| 797 native.NativeBehavior getNativeMethodBehavior(MethodElement method) { | 803 native.NativeBehavior getNativeMethodBehavior(MethodElement method) { |
| 798 return nativeData.getNativeMethodBehavior(method); | 804 return nativeData.getNativeMethodBehavior(method); |
| (...skipping 823 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1622 } | 1628 } |
| 1623 | 1629 |
| 1624 String getCheckedModeHelperNameInternal(ResolutionDartType type, | 1630 String getCheckedModeHelperNameInternal(ResolutionDartType type, |
| 1625 {bool typeCast, bool nativeCheckOnly}) { | 1631 {bool typeCast, bool nativeCheckOnly}) { |
| 1626 assert(type.kind != ResolutionTypeKind.TYPEDEF); | 1632 assert(type.kind != ResolutionTypeKind.TYPEDEF); |
| 1627 if (type.isMalformed) { | 1633 if (type.isMalformed) { |
| 1628 // The same error is thrown for type test and type cast of a malformed | 1634 // The same error is thrown for type test and type cast of a malformed |
| 1629 // type so we only need one check method. | 1635 // type so we only need one check method. |
| 1630 return 'checkMalformedType'; | 1636 return 'checkMalformedType'; |
| 1631 } | 1637 } |
| 1632 Element element = type.element; | 1638 |
| 1639 if (type.isVoid) { |
| 1640 assert(!typeCast); // Cannot cast to void. |
| 1641 if (nativeCheckOnly) return null; |
| 1642 return 'voidTypeCheck'; |
| 1643 } |
| 1644 |
| 1645 if (type.isTypeVariable) { |
| 1646 return typeCast |
| 1647 ? 'subtypeOfRuntimeTypeCast' |
| 1648 : 'assertSubtypeOfRuntimeType'; |
| 1649 } |
| 1650 |
| 1651 if (type.isFunctionType) return null; |
| 1652 |
| 1653 assert(invariant(NO_LOCATION_SPANNABLE, type.isInterfaceType, |
| 1654 message: "Unexpected type: $type (${type.kind})")); |
| 1655 ClassElement element = type.element; |
| 1633 bool nativeCheck = | 1656 bool nativeCheck = |
| 1634 nativeCheckOnly || emitter.nativeEmitter.requiresNativeIsCheck(element); | 1657 nativeCheckOnly || emitter.nativeEmitter.requiresNativeIsCheck(element); |
| 1635 | 1658 |
| 1636 // TODO(13955), TODO(9731). The test for non-primitive types should use an | 1659 // TODO(13955), TODO(9731). The test for non-primitive types should use an |
| 1637 // interceptor. The interceptor should be an argument to HTypeConversion so | 1660 // interceptor. The interceptor should be an argument to HTypeConversion so |
| 1638 // that it can be optimized by standard interceptor optimizations. | 1661 // that it can be optimized by standard interceptor optimizations. |
| 1639 nativeCheck = true; | 1662 nativeCheck = true; |
| 1640 | 1663 |
| 1641 if (type.isVoid) { | 1664 var suffix = typeCast ? 'TypeCast' : 'TypeCheck'; |
| 1642 assert(!typeCast); // Cannot cast to void. | 1665 if (element == helpers.jsStringClass || |
| 1643 if (nativeCheckOnly) return null; | |
| 1644 return 'voidTypeCheck'; | |
| 1645 } else if (element == helpers.jsStringClass || | |
| 1646 element == commonElements.stringClass) { | 1666 element == commonElements.stringClass) { |
| 1647 if (nativeCheckOnly) return null; | 1667 if (nativeCheckOnly) return null; |
| 1648 return typeCast ? 'stringTypeCast' : 'stringTypeCheck'; | 1668 return 'string$suffix'; |
| 1649 } else if (element == helpers.jsDoubleClass || | 1669 } |
| 1670 |
| 1671 if (element == helpers.jsDoubleClass || |
| 1650 element == commonElements.doubleClass) { | 1672 element == commonElements.doubleClass) { |
| 1651 if (nativeCheckOnly) return null; | 1673 if (nativeCheckOnly) return null; |
| 1652 return typeCast ? 'doubleTypeCast' : 'doubleTypeCheck'; | 1674 return 'double$suffix'; |
| 1653 } else if (element == helpers.jsNumberClass || | 1675 } |
| 1676 |
| 1677 if (element == helpers.jsNumberClass || |
| 1654 element == commonElements.numClass) { | 1678 element == commonElements.numClass) { |
| 1655 if (nativeCheckOnly) return null; | 1679 if (nativeCheckOnly) return null; |
| 1656 return typeCast ? 'numTypeCast' : 'numTypeCheck'; | 1680 return 'num$suffix'; |
| 1657 } else if (element == helpers.jsBoolClass || | 1681 } |
| 1658 element == commonElements.boolClass) { | 1682 |
| 1683 if (element == helpers.jsBoolClass || element == commonElements.boolClass) { |
| 1659 if (nativeCheckOnly) return null; | 1684 if (nativeCheckOnly) return null; |
| 1660 return typeCast ? 'boolTypeCast' : 'boolTypeCheck'; | 1685 return 'bool$suffix'; |
| 1661 } else if (element == helpers.jsIntClass || | 1686 } |
| 1687 |
| 1688 if (element == helpers.jsIntClass || |
| 1662 element == commonElements.intClass || | 1689 element == commonElements.intClass || |
| 1663 element == helpers.jsUInt32Class || | 1690 element == helpers.jsUInt32Class || |
| 1664 element == helpers.jsUInt31Class || | 1691 element == helpers.jsUInt31Class || |
| 1665 element == helpers.jsPositiveIntClass) { | 1692 element == helpers.jsPositiveIntClass) { |
| 1666 if (nativeCheckOnly) return null; | 1693 if (nativeCheckOnly) return null; |
| 1667 return typeCast ? 'intTypeCast' : 'intTypeCheck'; | 1694 return 'int$suffix'; |
| 1668 } else if (commonElements.isNumberOrStringSupertype(element)) { | 1695 } |
| 1669 if (nativeCheck) { | 1696 |
| 1670 return typeCast | 1697 if (commonElements.isNumberOrStringSupertype(element)) { |
| 1671 ? 'numberOrStringSuperNativeTypeCast' | 1698 return nativeCheck |
| 1672 : 'numberOrStringSuperNativeTypeCheck'; | 1699 ? 'numberOrStringSuperNative$suffix' |
| 1673 } else { | 1700 : 'numberOrStringSuper$suffix'; |
| 1674 return typeCast | 1701 } |
| 1675 ? 'numberOrStringSuperTypeCast' | 1702 |
| 1676 : 'numberOrStringSuperTypeCheck'; | 1703 if (commonElements.isStringOnlySupertype(element)) { |
| 1677 } | 1704 return nativeCheck ? 'stringSuperNative$suffix' : 'stringSuper$suffix'; |
| 1678 } else if (commonElements.isStringOnlySupertype(element)) { | 1705 } |
| 1679 if (nativeCheck) { | 1706 |
| 1680 return typeCast | 1707 if ((element == commonElements.listClass || |
| 1681 ? 'stringSuperNativeTypeCast' | |
| 1682 : 'stringSuperNativeTypeCheck'; | |
| 1683 } else { | |
| 1684 return typeCast ? 'stringSuperTypeCast' : 'stringSuperTypeCheck'; | |
| 1685 } | |
| 1686 } else if ((element == commonElements.listClass || | |
| 1687 element == helpers.jsArrayClass) && | 1708 element == helpers.jsArrayClass) && |
| 1688 type.treatAsRaw) { | 1709 type.treatAsRaw) { |
| 1689 if (nativeCheckOnly) return null; | 1710 if (nativeCheckOnly) return null; |
| 1690 return typeCast ? 'listTypeCast' : 'listTypeCheck'; | 1711 return 'list$suffix'; |
| 1712 } |
| 1713 |
| 1714 if (commonElements.isListSupertype(element)) { |
| 1715 return nativeCheck ? 'listSuperNative$suffix' : 'listSuper$suffix'; |
| 1716 } |
| 1717 |
| 1718 if (type.isInterfaceType && !type.treatAsRaw) { |
| 1719 return typeCast ? 'subtypeCast' : 'assertSubtype'; |
| 1720 } |
| 1721 |
| 1722 if (nativeCheck) { |
| 1723 // TODO(karlklose): can we get rid of this branch when we use |
| 1724 // interceptors? |
| 1725 return 'intercepted$suffix'; |
| 1691 } else { | 1726 } else { |
| 1692 if (commonElements.isListSupertype(element)) { | 1727 return 'property$suffix'; |
| 1693 if (nativeCheck) { | |
| 1694 return typeCast | |
| 1695 ? 'listSuperNativeTypeCast' | |
| 1696 : 'listSuperNativeTypeCheck'; | |
| 1697 } else { | |
| 1698 return typeCast ? 'listSuperTypeCast' : 'listSuperTypeCheck'; | |
| 1699 } | |
| 1700 } else { | |
| 1701 if (type.isInterfaceType && !type.treatAsRaw) { | |
| 1702 return typeCast ? 'subtypeCast' : 'assertSubtype'; | |
| 1703 } else if (type.isTypeVariable) { | |
| 1704 return typeCast | |
| 1705 ? 'subtypeOfRuntimeTypeCast' | |
| 1706 : 'assertSubtypeOfRuntimeType'; | |
| 1707 } else if (type.isFunctionType) { | |
| 1708 return null; | |
| 1709 } else { | |
| 1710 if (nativeCheck) { | |
| 1711 // TODO(karlklose): can we get rid of this branch when we use | |
| 1712 // interceptors? | |
| 1713 return typeCast ? 'interceptedTypeCast' : 'interceptedTypeCheck'; | |
| 1714 } else { | |
| 1715 return typeCast ? 'propertyTypeCast' : 'propertyTypeCheck'; | |
| 1716 } | |
| 1717 } | |
| 1718 } | |
| 1719 } | 1728 } |
| 1720 } | 1729 } |
| 1721 | 1730 |
| 1722 void _registerCheckedModeHelpers(WorldImpactBuilder impactBuilder) { | 1731 void _registerCheckedModeHelpers(WorldImpactBuilder impactBuilder) { |
| 1723 // We register all the helpers in the resolution queue. | 1732 // We register all the helpers in the resolution queue. |
| 1724 // TODO(13155): Find a way to register fewer helpers. | 1733 // TODO(13155): Find a way to register fewer helpers. |
| 1725 List<Element> staticUses = <Element>[]; | 1734 List<Element> staticUses = <Element>[]; |
| 1726 for (CheckedModeHelper helper in checkedModeHelpers) { | 1735 for (CheckedModeHelper helper in checkedModeHelpers) { |
| 1727 staticUses.add(helper.getStaticUse(compiler).element); | 1736 staticUses.add(helper.getStaticUse(compiler).element); |
| 1728 } | 1737 } |
| (...skipping 1326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3055 if (type is ResolutionFunctionType) { | 3064 if (type is ResolutionFunctionType) { |
| 3056 registerBackendImpact(transformed, impacts.functionTypeCheck); | 3065 registerBackendImpact(transformed, impacts.functionTypeCheck); |
| 3057 } | 3066 } |
| 3058 if (type.element != null && backend.isNative(type.element)) { | 3067 if (type.element != null && backend.isNative(type.element)) { |
| 3059 registerBackendImpact(transformed, impacts.nativeTypeCheck); | 3068 registerBackendImpact(transformed, impacts.nativeTypeCheck); |
| 3060 } | 3069 } |
| 3061 } | 3070 } |
| 3062 | 3071 |
| 3063 void onIsCheckForCodegen( | 3072 void onIsCheckForCodegen( |
| 3064 ResolutionDartType type, TransformedWorldImpact transformed) { | 3073 ResolutionDartType type, TransformedWorldImpact transformed) { |
| 3074 if (type.isDynamic) return; |
| 3065 type = type.unaliased; | 3075 type = type.unaliased; |
| 3066 registerBackendImpact(transformed, impacts.typeCheck); | 3076 registerBackendImpact(transformed, impacts.typeCheck); |
| 3067 | 3077 |
| 3068 bool inCheckedMode = backend.compiler.options.enableTypeAssertions; | 3078 bool inCheckedMode = backend.compiler.options.enableTypeAssertions; |
| 3069 // [registerIsCheck] is also called for checked mode checks, so we | 3079 // [registerIsCheck] is also called for checked mode checks, so we |
| 3070 // need to register checked mode helpers. | 3080 // need to register checked mode helpers. |
| 3071 if (inCheckedMode) { | 3081 if (inCheckedMode) { |
| 3072 // All helpers are added to resolution queue in enqueueHelpers. These | 3082 // All helpers are added to resolution queue in enqueueHelpers. These |
| 3073 // calls to [enqueue] with the resolution enqueuer serve as assertions | 3083 // calls to [enqueue] with the resolution enqueuer serve as assertions |
| 3074 // that the helper was in fact added. | 3084 // that the helper was in fact added. |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3286 @override | 3296 @override |
| 3287 bool isNativeClass(ClassElement element) { | 3297 bool isNativeClass(ClassElement element) { |
| 3288 return helpers.backend.isNative(element); | 3298 return helpers.backend.isNative(element); |
| 3289 } | 3299 } |
| 3290 | 3300 |
| 3291 @override | 3301 @override |
| 3292 bool isNativeMember(MemberElement element) { | 3302 bool isNativeMember(MemberElement element) { |
| 3293 return helpers.backend.isNative(element); | 3303 return helpers.backend.isNative(element); |
| 3294 } | 3304 } |
| 3295 } | 3305 } |
| OLD | NEW |