Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(392)

Side by Side Diff: pkg/compiler/lib/src/native/behavior.dart

Issue 2686533002: Refactor computation of NativeBehavior. (Closed)
Patch Set: Rebased Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 import '../common.dart'; 5 import '../common.dart';
6 import '../common/backend_api.dart' show ForeignResolver; 6 import '../common/backend_api.dart' show BackendClasses, ForeignResolver;
7 import '../common/resolution.dart' show ParsingContext, Resolution; 7 import '../common/resolution.dart' show ParsingContext, Resolution;
8 import '../compiler.dart' show Compiler; 8 import '../compiler.dart' show Compiler;
9 import '../compile_time_constants.dart' show ConstantEnvironment;
9 import '../constants/expressions.dart'; 10 import '../constants/expressions.dart';
10 import '../constants/values.dart'; 11 import '../constants/values.dart';
11 import '../core_types.dart' show CommonElements; 12 import '../core_types.dart' show CommonElements;
13 import '../elements/elements.dart';
12 import '../elements/resolution_types.dart'; 14 import '../elements/resolution_types.dart';
13 import '../elements/elements.dart'; 15 import '../elements/types.dart';
14 import '../js/js.dart' as js; 16 import '../js/js.dart' as js;
15 import '../js_backend/js_backend.dart'; 17 import '../js_backend/js_backend.dart';
18 import '../js_backend/backend_helpers.dart';
19 import '../options.dart';
16 import '../tree/tree.dart'; 20 import '../tree/tree.dart';
17 import '../universe/side_effects.dart' show SideEffects; 21 import '../universe/side_effects.dart' show SideEffects;
18 import '../util/util.dart'; 22 import '../util/util.dart';
19 import 'enqueue.dart';
20 import 'js.dart'; 23 import 'js.dart';
21 24
22 typedef dynamic /*DartType|SpecialType*/ TypeLookup(String typeString); 25 typedef dynamic /*DartType|SpecialType*/ TypeLookup(String typeString);
23 26
24 /// This class is a temporary work-around until we get a more powerful DartType. 27 /// This class is a temporary work-around until we get a more powerful DartType.
25 class SpecialType { 28 class SpecialType {
26 final String name; 29 final String name;
27 const SpecialType._(this.name); 30 const SpecialType._(this.name);
28 31
29 /// The type Object, but no subtypes: 32 /// The type Object, but no subtypes:
(...skipping 725 matching lines...) Expand 10 before | Expand all | Expand 10 after
755 758
756 ResolutionDartType lookup(String name) { 759 ResolutionDartType lookup(String name) {
757 Element e = element.buildScope().lookup(name); 760 Element e = element.buildScope().lookup(name);
758 if (e == null) return null; 761 if (e == null) return null;
759 if (e is! ClassElement) return null; 762 if (e is! ClassElement) return null;
760 ClassElement cls = e; 763 ClassElement cls = e;
761 cls.ensureResolved(compiler.resolution); 764 cls.ensureResolved(compiler.resolution);
762 return cls.thisType; 765 return cls.thisType;
763 } 766 }
764 767
765 return ofMethod(element, type, metadata, lookup, compiler, 768 BehaviorComputer computer = new BehaviorComputerImpl(compiler);
769 return computer.ofMethod(type, metadata, lookup,
766 isJsInterop: compiler.backend.isJsInterop(element)); 770 isJsInterop: compiler.backend.isJsInterop(element));
767 } 771 }
768 772
769 static NativeBehavior ofMethod(
770 Spannable spannable,
771 ResolutionFunctionType type,
772 List<ConstantExpression> metadata,
773 TypeLookup lookupType,
774 Compiler compiler,
775 {bool isJsInterop}) {
776 var behavior = new NativeBehavior();
777 var returnType = type.returnType;
778 // Note: For dart:html and other internal libraries we maintain, we can
779 // trust the return type and use it to limit what we enqueue. We have to
780 // be more conservative about JS interop types and assume they can return
781 // anything (unless the user provides the experimental flag to trust the
782 // type of js-interop APIs). We do restrict the allocation effects and say
783 // that interop calls create only interop types (which may be unsound if
784 // an interop call returns a DOM type and declares a dynamic return type,
785 // but otherwise we would include a lot of code by default).
786 // TODO(sigmund,sra): consider doing something better for numeric types.
787 behavior.typesReturned.add(
788 !isJsInterop || compiler.options.trustJSInteropTypeAnnotations
789 ? returnType
790 : const ResolutionDynamicType());
791 if (!type.returnType.isVoid) {
792 // Declared types are nullable.
793 behavior.typesReturned.add(compiler.commonElements.nullType);
794 }
795 behavior._capture(type, compiler.resolution,
796 isInterop: isJsInterop, compiler: compiler);
797
798 for (ResolutionDartType type in type.optionalParameterTypes) {
799 behavior._escape(type, compiler.resolution);
800 }
801 for (ResolutionDartType type in type.namedParameterTypes) {
802 behavior._escape(type, compiler.resolution);
803 }
804
805 behavior._overrideWithAnnotations(
806 spannable, metadata, lookupType, compiler);
807 return behavior;
808 }
809
810 static NativeBehavior ofFieldElementLoad( 773 static NativeBehavior ofFieldElementLoad(
811 MemberElement element, Compiler compiler) { 774 MemberElement element, Compiler compiler) {
812 Resolution resolution = compiler.resolution; 775 Resolution resolution = compiler.resolution;
813 ResolutionDartType type = element.computeType(resolution); 776 ResolutionDartType type = element.computeType(resolution);
814 List<ConstantExpression> metadata = <ConstantExpression>[]; 777 List<ConstantExpression> metadata = <ConstantExpression>[];
815 for (MetadataAnnotation annotation in element.implementation.metadata) { 778 for (MetadataAnnotation annotation in element.implementation.metadata) {
816 annotation.ensureResolved(compiler.resolution); 779 annotation.ensureResolved(compiler.resolution);
817 metadata.add(annotation.constant); 780 metadata.add(annotation.constant);
818 } 781 }
819 782
820 ResolutionDartType lookup(String name) { 783 ResolutionDartType lookup(String name) {
821 Element e = element.buildScope().lookup(name); 784 Element e = element.buildScope().lookup(name);
822 if (e == null) return null; 785 if (e == null) return null;
823 if (e is! ClassElement) return null; 786 if (e is! ClassElement) return null;
824 ClassElement cls = e; 787 ClassElement cls = e;
825 cls.ensureResolved(compiler.resolution); 788 cls.ensureResolved(compiler.resolution);
826 return cls.thisType; 789 return cls.thisType;
827 } 790 }
828 791
829 return ofFieldLoad(element, type, metadata, lookup, compiler, 792 BehaviorComputer computer = new BehaviorComputerImpl(compiler);
793 return computer.ofFieldLoad(type, metadata, lookup,
830 isJsInterop: compiler.backend.isJsInterop(element)); 794 isJsInterop: compiler.backend.isJsInterop(element));
831 } 795 }
832 796
833 static NativeBehavior ofFieldLoad( 797 static NativeBehavior ofFieldElementStore(
834 Spannable spannable, 798 MemberElement field, Compiler compiler) {
835 ResolutionDartType type, 799 BehaviorComputer computer = new BehaviorComputerImpl(compiler);
836 List<ConstantExpression> metadata, 800 ResolutionDartType type = field.computeType(compiler.resolution);
837 TypeLookup lookupType, 801 return computer.ofFieldStore(type);
838 Compiler compiler,
839 {bool isJsInterop}) {
840 Resolution resolution = compiler.resolution;
841 var behavior = new NativeBehavior();
842 // TODO(sigmund,sra): consider doing something better for numeric types.
843 behavior.typesReturned.add(
844 !isJsInterop || compiler.options.trustJSInteropTypeAnnotations
845 ? type
846 : const ResolutionDynamicType());
847 // Declared types are nullable.
848 behavior.typesReturned.add(resolution.commonElements.nullType);
849 behavior._capture(type, resolution,
850 isInterop: isJsInterop, compiler: compiler);
851 behavior._overrideWithAnnotations(
852 spannable, metadata, lookupType, compiler);
853 return behavior;
854 } 802 }
855 803
856 static NativeBehavior ofFieldElementStore( 804 static dynamic /*DartType|SpecialType*/ _parseType(String typeString,
857 MemberElement field, Resolution resolution) { 805 Spannable spannable, DiagnosticReporter reporter, TypeLookup lookupType) {
858 ResolutionDartType type = field.computeType(resolution); 806 if (typeString == '=Object') return SpecialType.JsObject;
859 return ofFieldStore(type, resolution); 807 if (typeString == 'dynamic') {
808 return const ResolutionDynamicType();
809 }
810 var type = lookupType(typeString);
811 if (type != null) return type;
812
813 int index = typeString.indexOf('<');
814 if (index < 1) {
815 reporter.reportErrorMessage(spannable, MessageKind.GENERIC,
816 {'text': "Type '$typeString' not found."});
817 return const ResolutionDynamicType();
818 }
819 type = lookupType(typeString.substring(0, index));
820 if (type != null) {
821 // TODO(sra): Parse type parameters.
822 return type;
823 }
824 reporter.reportErrorMessage(spannable, MessageKind.GENERIC,
825 {'text': "Type '$typeString' not found."});
826 return const ResolutionDynamicType();
860 } 827 }
828 }
861 829
862 static NativeBehavior ofFieldStore( 830 abstract class BehaviorComputer {
Siggi Cherem (dart-lang) 2017/02/08 17:00:28 nit: rename as BehaviorBuilder or BehaviorFactory
Johnni Winther 2017/02/10 09:11:45 Done.
863 ResolutionDartType type, Resolution resolution) { 831 CommonElements get commonElements;
864 var behavior = new NativeBehavior(); 832 BackendClasses get backendClasses;
865 behavior._escape(type, resolution); 833 BackendHelpers get helpers;
866 // We don't override the default behaviour - the annotations apply to 834 DiagnosticReporter get reporter;
867 // loading the field. 835 ConstantEnvironment get constants;
868 return behavior; 836 bool get trustJSInteropTypeAnnotations;
869 } 837
838 Resolution get resolution => null;
839
840 NativeBehavior _behavior;
870 841
871 void _overrideWithAnnotations( 842 void _overrideWithAnnotations(
872 Spannable spannable, 843 Iterable<ConstantExpression> metadata, TypeLookup lookupType) {
873 Iterable<ConstantExpression> metadata,
874 TypeLookup lookupType,
875 Compiler compiler) {
876 if (metadata.isEmpty) return; 844 if (metadata.isEmpty) return;
877 845
878 NativeEnqueuer enqueuer = compiler.enqueuer.resolution.nativeEnqueuer; 846 List creates =
879 var creates = _collect(spannable, metadata, compiler, 847 _collect(metadata, helpers.annotationCreatesClass, lookupType);
880 enqueuer.annotationCreatesClass, lookupType); 848 List returns =
881 var returns = _collect(spannable, metadata, compiler, 849 _collect(metadata, helpers.annotationReturnsClass, lookupType);
882 enqueuer.annotationReturnsClass, lookupType);
883 850
884 if (creates != null) { 851 if (creates != null) {
885 typesInstantiated 852 _behavior.typesInstantiated
886 ..clear() 853 ..clear()
887 ..addAll(creates); 854 ..addAll(creates);
888 } 855 }
889 if (returns != null) { 856 if (returns != null) {
890 typesReturned 857 _behavior.typesReturned
891 ..clear() 858 ..clear()
892 ..addAll(returns); 859 ..addAll(returns);
893 } 860 }
894 } 861 }
895 862
896 /** 863 /**
897 * Returns a list of type constraints from the annotations of 864 * Returns a list of type constraints from the annotations of
898 * [annotationClass]. 865 * [annotationClass].
899 * Returns `null` if no constraints. 866 * Returns `null` if no constraints.
900 */ 867 */
901 static _collect(Spannable spannable, Iterable<ConstantExpression> metadata, 868 List _collect(Iterable<ConstantExpression> metadata, Element annotationClass,
902 Compiler compiler, Element annotationClass, TypeLookup lookupType) { 869 TypeLookup lookupType) {
903 DiagnosticReporter reporter = compiler.reporter;
904 var types = null; 870 var types = null;
905 for (ConstantExpression constant in metadata) { 871 for (ConstantExpression constant in metadata) {
906 ConstantValue value = compiler.constants.getConstantValue(constant); 872 ConstantValue value = constants.getConstantValue(constant);
907 if (!value.isConstructedObject) continue; 873 if (!value.isConstructedObject) continue;
908 ConstructedConstantValue constructedObject = value; 874 ConstructedConstantValue constructedObject = value;
909 if (constructedObject.type.element != annotationClass) continue; 875 if (constructedObject.type.element != annotationClass) continue;
910 876
911 Iterable<ConstantValue> fields = constructedObject.fields.values; 877 Iterable<ConstantValue> fields = constructedObject.fields.values;
912 // TODO(sra): Better validation of the constant. 878 // TODO(sra): Better validation of the constant.
913 if (fields.length != 1 || !fields.single.isString) { 879 if (fields.length != 1 || !fields.single.isString) {
914 reporter.internalError(spannable, 880 reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
915 'Annotations needs one string: ${constant.toStructuredText()}'); 881 'Annotations needs one string: ${constant.toStructuredText()}');
916 } 882 }
917 StringConstantValue specStringConstant = fields.single; 883 StringConstantValue specStringConstant = fields.single;
918 String specString = specStringConstant.toDartString().slowToString(); 884 String specString = specStringConstant.toDartString().slowToString();
919 for (final typeString in specString.split('|')) { 885 for (final typeString in specString.split('|')) {
920 var type = _parseType(typeString, spannable, reporter, lookupType); 886 var type = NativeBehavior._parseType(
887 typeString, CURRENT_ELEMENT_SPANNABLE, reporter, lookupType);
921 if (types == null) types = []; 888 if (types == null) types = [];
922 types.add(type); 889 types.add(type);
923 } 890 }
924 } 891 }
925 return types; 892 return types;
926 } 893 }
927 894
928 /// Models the behavior of having intances of [type] escape from Dart code 895 /// Models the behavior of having intances of [type] escape from Dart code
929 /// into native code. 896 /// into native code.
930 void _escape(ResolutionDartType type, Resolution resolution) { 897 void _escape(DartType type) {
931 type.computeUnaliased(resolution); 898 if (type is ResolutionDartType) {
899 type.computeUnaliased(resolution);
900 }
932 type = type.unaliased; 901 type = type.unaliased;
933 if (type is ResolutionFunctionType) { 902 if (type is FunctionType) {
934 ResolutionFunctionType functionType = type; 903 FunctionType functionType = type;
935 // A function might be called from native code, passing us novel 904 // A function might be called from native code, passing us novel
936 // parameters. 905 // parameters.
937 _escape(functionType.returnType, resolution); 906 _escape(functionType.returnType);
938 for (ResolutionDartType parameter in functionType.parameterTypes) { 907 for (DartType parameter in functionType.parameterTypes) {
939 _capture(parameter, resolution); 908 _capture(parameter);
940 } 909 }
941 } 910 }
942 } 911 }
943 912
944 /// Models the behavior of Dart code receiving instances and methods of [type] 913 /// Models the behavior of Dart code receiving instances and methods of [type]
945 /// from native code. We usually start the analysis by capturing a native 914 /// from native code. We usually start the analysis by capturing a native
946 /// method that has been used. 915 /// method that has been used.
947 /// 916 ///
948 /// We assume that JS-interop APIs cannot instantiate Dart types or 917 /// We assume that JS-interop APIs cannot instantiate Dart types or
949 /// non-JSInterop native types. 918 /// non-JSInterop native types.
950 void _capture(ResolutionDartType type, Resolution resolution, 919 void _capture(DartType type, {bool isInterop: false}) {
951 {bool isInterop: false, Compiler compiler}) { 920 if (type is ResolutionDartType) {
952 type.computeUnaliased(resolution); 921 type.computeUnaliased(resolution);
922 }
953 type = type.unaliased; 923 type = type.unaliased;
954 if (type is ResolutionFunctionType) { 924 if (type is FunctionType) {
955 ResolutionFunctionType functionType = type; 925 FunctionType functionType = type;
956 _capture(functionType.returnType, resolution, 926 _capture(functionType.returnType, isInterop: isInterop);
957 isInterop: isInterop, compiler: compiler); 927 for (DartType parameter in functionType.parameterTypes) {
958 for (ResolutionDartType parameter in functionType.parameterTypes) { 928 _escape(parameter);
959 _escape(parameter, resolution);
960 } 929 }
961 } else { 930 } else {
962 JavaScriptBackend backend = compiler?.backend;
963 if (!isInterop) { 931 if (!isInterop) {
964 typesInstantiated.add(type); 932 _behavior.typesInstantiated.add(type);
965 } else { 933 } else {
966 if (type.element != null && backend.isNative(type.element)) { 934 if (type is InterfaceType &&
935 backendClasses.isNativeClass(type.element)) {
967 // Any declared native or interop type (isNative implies isJsInterop) 936 // Any declared native or interop type (isNative implies isJsInterop)
968 // is assumed to be allocated. 937 // is assumed to be allocated.
969 typesInstantiated.add(type); 938 _behavior.typesInstantiated.add(type);
970 } 939 }
971 940
972 if (!compiler.options.trustJSInteropTypeAnnotations || 941 if (!trustJSInteropTypeAnnotations ||
973 type.isDynamic || 942 type.isDynamic ||
974 type.isObject) { 943 type == commonElements.objectType) {
975 // By saying that only JS-interop types can be created, we prevent 944 // By saying that only JS-interop types can be created, we prevent
976 // pulling in every other native type (e.g. all of dart:html) when a 945 // pulling in every other native type (e.g. all of dart:html) when a
977 // JS interop API returns dynamic or when we don't trust the type 946 // JS interop API returns dynamic or when we don't trust the type
978 // annotations. This means that to some degree we still use the return 947 // annotations. This means that to some degree we still use the return
979 // type to decide whether to include native types, even if we don't 948 // type to decide whether to include native types, even if we don't
980 // trust the type annotation. 949 // trust the type annotation.
981 ClassElement cls = backend.helpers.jsJavaScriptObjectClass; 950 ClassElement cls = helpers.jsJavaScriptObjectClass;
982 cls.ensureResolved(resolution); 951 cls.ensureResolved(resolution);
983 typesInstantiated.add(cls.thisType); 952 _behavior.typesInstantiated.add(cls.thisType);
984 } else { 953 } else {
985 // Otherwise, when the declared type is a Dart type, we do not 954 // Otherwise, when the declared type is a Dart type, we do not
986 // register an allocation because we assume it cannot be instantiated 955 // register an allocation because we assume it cannot be instantiated
987 // from within the JS-interop code. It must have escaped from another 956 // from within the JS-interop code. It must have escaped from another
988 // API. 957 // API.
989 } 958 }
990 } 959 }
991 } 960 }
992 } 961 }
993 962
994 static dynamic /*DartType|SpecialType*/ _parseType(String typeString, 963 NativeBehavior ofFieldLoad(DartType type,
Siggi Cherem (dart-lang) 2017/02/08 17:00:28 Let's rename these now that they are no longer on
Johnni Winther 2017/02/10 09:11:45 Done.
995 Spannable spannable, DiagnosticReporter reporter, TypeLookup lookupType) { 964 Iterable<ConstantExpression> metadata, TypeLookup lookupType,
996 if (typeString == '=Object') return SpecialType.JsObject; 965 {bool isJsInterop}) {
997 if (typeString == 'dynamic') { 966 _behavior = new NativeBehavior();
998 return const ResolutionDynamicType(); 967 // TODO(sigmund,sra): consider doing something better for numeric types.
968 _behavior.typesReturned.add(!isJsInterop || trustJSInteropTypeAnnotations
969 ? type
970 : commonElements.dynamicType);
971 // Declared types are nullable.
972 _behavior.typesReturned.add(commonElements.nullType);
973 _capture(type, isInterop: isJsInterop);
974 _overrideWithAnnotations(metadata, lookupType);
975 return _behavior;
976 }
977
978 NativeBehavior ofFieldStore(DartType type) {
979 _behavior = new NativeBehavior();
980 _escape(type);
981 // We don't override the default behaviour - the annotations apply to
982 // loading the field.
983 return _behavior;
984 }
985
986 NativeBehavior ofMethod(FunctionType type, List<ConstantExpression> metadata,
987 TypeLookup lookupType,
988 {bool isJsInterop}) {
989 _behavior = new NativeBehavior();
990 DartType returnType = type.returnType;
991 // Note: For dart:html and other internal libraries we maintain, we can
992 // trust the return type and use it to limit what we enqueue. We have to
993 // be more conservative about JS interop types and assume they can return
994 // anything (unless the user provides the experimental flag to trust the
995 // type of js-interop APIs). We do restrict the allocation effects and say
996 // that interop calls create only interop types (which may be unsound if
997 // an interop call returns a DOM type and declares a dynamic return type,
998 // but otherwise we would include a lot of code by default).
999 // TODO(sigmund,sra): consider doing something better for numeric types.
1000 _behavior.typesReturned.add(!isJsInterop || trustJSInteropTypeAnnotations
1001 ? returnType
1002 : commonElements.dynamicType);
1003 if (!type.returnType.isVoid) {
1004 // Declared types are nullable.
1005 _behavior.typesReturned.add(commonElements.nullType);
999 } 1006 }
1000 var type = lookupType(typeString); 1007 _capture(type, isInterop: isJsInterop);
1001 if (type != null) return type;
1002 1008
1003 int index = typeString.indexOf('<'); 1009 for (DartType type in type.optionalParameterTypes) {
1004 if (index < 1) { 1010 _escape(type);
1005 reporter.reportErrorMessage(spannable, MessageKind.GENERIC,
1006 {'text': "Type '$typeString' not found."});
1007 return const ResolutionDynamicType();
1008 } 1011 }
1009 type = lookupType(typeString.substring(0, index)); 1012 for (DartType type in type.namedParameterTypes) {
1010 if (type != null) { 1013 _escape(type);
1011 // TODO(sra): Parse type parameters.
1012 return type;
1013 } 1014 }
1014 reporter.reportErrorMessage(spannable, MessageKind.GENERIC, 1015
1015 {'text': "Type '$typeString' not found."}); 1016 _overrideWithAnnotations(metadata, lookupType);
1016 return const ResolutionDynamicType(); 1017 return _behavior;
1017 } 1018 }
1018 } 1019 }
1020
1021 class BehaviorComputerImpl extends BehaviorComputer {
Siggi Cherem (dart-lang) 2017/02/08 17:00:28 nit: rename to ResolverBehaviorBuilder? (so the ne
Johnni Winther 2017/02/10 09:11:45 Done.
1022 final Compiler compiler;
1023
1024 BehaviorComputerImpl(this.compiler);
1025
1026 @override
1027 CommonElements get commonElements => compiler.commonElements;
1028
1029 @override
1030 bool get trustJSInteropTypeAnnotations =>
1031 compiler.options.trustJSInteropTypeAnnotations;
1032
1033 @override
1034 ConstantEnvironment get constants => compiler.constants;
1035
1036 @override
1037 DiagnosticReporter get reporter => compiler.reporter;
1038
1039 @override
1040 BackendHelpers get helpers {
1041 JavaScriptBackend backend = compiler.backend;
1042 return backend.helpers;
1043 }
1044
1045 @override
1046 BackendClasses get backendClasses => compiler.backend.backendClasses;
1047
1048 @override
1049 Resolution get resolution => compiler.resolution;
1050 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698