| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 part of native; | 5 part of native; |
| 6 | 6 |
| 7 /// This class is a temporary work-around until we get a more powerful DartType. | 7 /// This class is a temporary work-around until we get a more powerful DartType. |
| 8 class SpecialType { | 8 class SpecialType { |
| 9 final String name; | 9 final String name; |
| 10 const SpecialType._(this.name); | 10 const SpecialType._(this.name); |
| (...skipping 627 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 638 resolver, | 638 resolver, |
| 639 isBuiltin: false, | 639 isBuiltin: false, |
| 640 validTags: const ['returns', 'creates']); | 640 validTags: const ['returns', 'creates']); |
| 641 | 641 |
| 642 return behavior; | 642 return behavior; |
| 643 } | 643 } |
| 644 | 644 |
| 645 static NativeBehavior ofMethod(FunctionElement method, Compiler compiler) { | 645 static NativeBehavior ofMethod(FunctionElement method, Compiler compiler) { |
| 646 FunctionType type = method.computeType(compiler.resolution); | 646 FunctionType type = method.computeType(compiler.resolution); |
| 647 var behavior = new NativeBehavior(); | 647 var behavior = new NativeBehavior(); |
| 648 behavior.typesReturned.add(type.returnType); | 648 var returnType = type.returnType; |
| 649 bool isInterop = compiler.backend.isJsInterop(method); |
| 650 // Note: For dart:html and other internal libraries we maintain, we can |
| 651 // trust the return type and use it to limit what we enqueue. We have to |
| 652 // be more conservative about JS interop types and assume they can return |
| 653 // anything (unless the user provides the experimental flag to trust the |
| 654 // type of js-interop APIs). We do restrict the allocation effects and say |
| 655 // that interop calls create only interop types (which may be unsound if |
| 656 // an interop call returns a DOM type and declares a dynamic return type, |
| 657 // but otherwise we would include a lot of code by default). |
| 658 // TODO(sigmund,sra): consider doing something better for numeric types. |
| 659 behavior.typesReturned.add( |
| 660 !isInterop || compiler.trustJSInteropTypeAnnotations ? returnType |
| 661 : const DynamicType()); |
| 649 if (!type.returnType.isVoid) { | 662 if (!type.returnType.isVoid) { |
| 650 // Declared types are nullable. | 663 // Declared types are nullable. |
| 651 behavior.typesReturned.add(compiler.coreTypes.nullType); | 664 behavior.typesReturned.add(compiler.coreTypes.nullType); |
| 652 } | 665 } |
| 653 behavior._capture(type, compiler.resolution); | 666 behavior._capture(type, compiler.resolution, |
| 667 isInterop: isInterop, compiler: compiler); |
| 654 | 668 |
| 655 // TODO(sra): Optional arguments are currently missing from the | 669 // TODO(sra): Optional arguments are currently missing from the |
| 656 // DartType. This should be fixed so the following work-around can be | 670 // DartType. This should be fixed so the following work-around can be |
| 657 // removed. | 671 // removed. |
| 658 method.functionSignature.forEachOptionalParameter( | 672 method.functionSignature.forEachOptionalParameter( |
| 659 (ParameterElement parameter) { | 673 (ParameterElement parameter) { |
| 660 behavior._escape(parameter.type, compiler.resolution); | 674 behavior._escape(parameter.type, compiler.resolution); |
| 661 }); | 675 }); |
| 662 | 676 |
| 663 behavior._overrideWithAnnotations(method, compiler); | 677 behavior._overrideWithAnnotations(method, compiler); |
| 664 return behavior; | 678 return behavior; |
| 665 } | 679 } |
| 666 | 680 |
| 667 static NativeBehavior ofFieldLoad(MemberElement field, Compiler compiler) { | 681 static NativeBehavior ofFieldLoad(MemberElement field, Compiler compiler) { |
| 668 Resolution resolution = compiler.resolution; | 682 Resolution resolution = compiler.resolution; |
| 669 DartType type = field.computeType(resolution); | 683 DartType type = field.computeType(resolution); |
| 670 var behavior = new NativeBehavior(); | 684 var behavior = new NativeBehavior(); |
| 671 behavior.typesReturned.add(type); | 685 bool isInterop = compiler.backend.isJsInterop(field); |
| 686 // TODO(sigmund,sra): consider doing something better for numeric types. |
| 687 behavior.typesReturned.add( |
| 688 !isInterop || compiler.trustJSInteropTypeAnnotations ? type |
| 689 : const DynamicType()); |
| 672 // Declared types are nullable. | 690 // Declared types are nullable. |
| 673 behavior.typesReturned.add(resolution.coreTypes.nullType); | 691 behavior.typesReturned.add(resolution.coreTypes.nullType); |
| 674 behavior._capture(type, resolution); | 692 behavior._capture(type, resolution, |
| 693 isInterop: isInterop, compiler: compiler); |
| 675 behavior._overrideWithAnnotations(field, compiler); | 694 behavior._overrideWithAnnotations(field, compiler); |
| 676 return behavior; | 695 return behavior; |
| 677 } | 696 } |
| 678 | 697 |
| 679 static NativeBehavior ofFieldStore(MemberElement field, Compiler compiler) { | 698 static NativeBehavior ofFieldStore(MemberElement field, Compiler compiler) { |
| 680 Resolution resolution = compiler.resolution; | 699 Resolution resolution = compiler.resolution; |
| 681 DartType type = field.computeType(resolution); | 700 DartType type = field.computeType(resolution); |
| 682 var behavior = new NativeBehavior(); | 701 var behavior = new NativeBehavior(); |
| 683 behavior._escape(type, resolution); | 702 behavior._escape(type, resolution); |
| 684 // We don't override the default behaviour - the annotations apply to | 703 // We don't override the default behaviour - the annotations apply to |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 758 _escape(functionType.returnType, resolution); | 777 _escape(functionType.returnType, resolution); |
| 759 for (DartType parameter in functionType.parameterTypes) { | 778 for (DartType parameter in functionType.parameterTypes) { |
| 760 _capture(parameter, resolution); | 779 _capture(parameter, resolution); |
| 761 } | 780 } |
| 762 } | 781 } |
| 763 } | 782 } |
| 764 | 783 |
| 765 /// Models the behavior of Dart code receiving instances and methods of [type] | 784 /// Models the behavior of Dart code receiving instances and methods of [type] |
| 766 /// from native code. We usually start the analysis by capturing a native | 785 /// from native code. We usually start the analysis by capturing a native |
| 767 /// method that has been used. | 786 /// method that has been used. |
| 768 void _capture(DartType type, Resolution resolution) { | 787 /// |
| 788 /// We assume that JS-interop APIs cannot instantiate Dart types or |
| 789 /// non-JSInterop native types. |
| 790 void _capture(DartType type, Resolution resolution, |
| 791 {bool isInterop: false, Compiler compiler}) { |
| 769 type.computeUnaliased(resolution); | 792 type.computeUnaliased(resolution); |
| 770 type = type.unaliased; | 793 type = type.unaliased; |
| 771 if (type is FunctionType) { | 794 if (type is FunctionType) { |
| 772 FunctionType functionType = type; | 795 FunctionType functionType = type; |
| 773 _capture(functionType.returnType, resolution); | 796 _capture(functionType.returnType, resolution, |
| 797 isInterop: isInterop, compiler: compiler); |
| 774 for (DartType parameter in functionType.parameterTypes) { | 798 for (DartType parameter in functionType.parameterTypes) { |
| 775 _escape(parameter, resolution); | 799 _escape(parameter, resolution); |
| 776 } | 800 } |
| 777 } else { | 801 } else { |
| 778 typesInstantiated.add(type); | 802 DartType instantiated = null; |
| 803 JavaScriptBackend backend = compiler?.backend; |
| 804 if (!isInterop) { |
| 805 typesInstantiated.add(type); |
| 806 } else { |
| 807 if (type.element != null && backend.isNative(type.element)) { |
| 808 // Any declared native or interop type (isNative implies isJsInterop) |
| 809 // is assumed to be allocated. |
| 810 typesInstantiated.add(type); |
| 811 } |
| 812 |
| 813 if (!compiler.trustJSInteropTypeAnnotations || |
| 814 type.isDynamic || type.isObject) { |
| 815 // By saying that only JS-interop types can be created, we prevent |
| 816 // pulling in every other native type (e.g. all of dart:html) when a |
| 817 // JS interop API returns dynamic or when we don't trust the type |
| 818 // annotations. This means that to some degree we still use the return |
| 819 // type to decide whether to include native types, even if we don't |
| 820 // trust the type annotation. |
| 821 typesInstantiated.add( |
| 822 backend.helpers.jsJavaScriptObjectClass.thisType); |
| 823 } else { |
| 824 // Otherwise, when the declared type is a Dart type, we do not |
| 825 // register an allocation because we assume it cannot be instantiated |
| 826 // from within the JS-interop code. It must have escaped from another |
| 827 // API. |
| 828 } |
| 829 } |
| 779 } | 830 } |
| 780 } | 831 } |
| 781 | 832 |
| 782 static dynamic _parseType( | 833 static dynamic _parseType( |
| 783 String typeString, | 834 String typeString, |
| 784 Parsing parsing, | 835 Parsing parsing, |
| 785 lookup(name), | 836 lookup(name), |
| 786 locationNodeOrElement) { | 837 locationNodeOrElement) { |
| 787 DiagnosticReporter reporter = parsing.reporter; | 838 DiagnosticReporter reporter = parsing.reporter; |
| 788 if (typeString == '=Object') return SpecialType.JsObject; | 839 if (typeString == '=Object') return SpecialType.JsObject; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 810 MessageKind.GENERIC, | 861 MessageKind.GENERIC, |
| 811 {'text': "Type '$typeString' not found."}); | 862 {'text': "Type '$typeString' not found."}); |
| 812 return const DynamicType(); | 863 return const DynamicType(); |
| 813 } | 864 } |
| 814 | 865 |
| 815 static _errorNode(locationNodeOrElement, Parsing parsing) { | 866 static _errorNode(locationNodeOrElement, Parsing parsing) { |
| 816 if (locationNodeOrElement is Node) return locationNodeOrElement; | 867 if (locationNodeOrElement is Node) return locationNodeOrElement; |
| 817 return locationNodeOrElement.parseNode(parsing); | 868 return locationNodeOrElement.parseNode(parsing); |
| 818 } | 869 } |
| 819 } | 870 } |
| OLD | NEW |