Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 library dart2js.ir_nodes; | 4 library dart2js.ir_nodes; |
| 5 | 5 |
| 6 import 'dart:collection'; | 6 import 'dart:collection'; |
| 7 import 'cps_fragment.dart' show CpsFragment; | 7 import 'cps_fragment.dart' show CpsFragment; |
| 8 import 'cps_ir_nodes_sexpr.dart'; | 8 import 'cps_ir_nodes_sexpr.dart'; |
| 9 import '../constants/values.dart' as values; | 9 import '../constants/values.dart' as values; |
| 10 import '../dart_types.dart' show DartType, InterfaceType, TypeVariableType; | 10 import '../dart_types.dart' show DartType, InterfaceType, TypeVariableType; |
| (...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 253 bool get isSafeForElimination; | 253 bool get isSafeForElimination; |
| 254 | 254 |
| 255 /// True if time-of-evaluation is irrelevant for the given primitive, | 255 /// True if time-of-evaluation is irrelevant for the given primitive, |
| 256 /// assuming its inputs are the same values. | 256 /// assuming its inputs are the same values. |
| 257 bool get isSafeForReordering; | 257 bool get isSafeForReordering; |
| 258 | 258 |
| 259 /// The source information associated with this primitive. | 259 /// The source information associated with this primitive. |
| 260 // TODO(johnniwinther): Require source information for all primitives. | 260 // TODO(johnniwinther): Require source information for all primitives. |
| 261 SourceInformation get sourceInformation => null; | 261 SourceInformation get sourceInformation => null; |
| 262 | 262 |
| 263 /// If this is a [Refinement], [BoundsCheck] or [NullCheck] node, returns the | 263 /// If this is a [Refinement], [BoundsCheck] or [ReceiverCheck] node, returns the |
|
Siggi Cherem (dart-lang)
2016/02/05 18:19:39
nit: 80 col
asgerf
2016/02/09 12:19:54
Done.
| |
| 264 /// value being refined, the indexable object being checked, or the value | 264 /// value being refined, the indexable object being checked, or the value |
| 265 /// that was checked to be non-null, respectively. | 265 /// that was checked to be non-null, respectively. |
| 266 /// | 266 /// |
| 267 /// Those instructions all return the corresponding operand directly, and | 267 /// Those instructions all return the corresponding operand directly, and |
| 268 /// this getter can be used to get (closer to) where the value came from. | 268 /// this getter can be used to get (closer to) where the value came from. |
| 269 // | 269 // |
| 270 // TODO(asgerf): Also do this for [TypeCast]? | 270 // TODO(asgerf): Also do this for [TypeCast]? |
| 271 Primitive get effectiveDefinition => this; | 271 Primitive get effectiveDefinition => this; |
| 272 | 272 |
| 273 /// Like [effectiveDefinition] but only unfolds [Refinement] nodes. | 273 /// Like [effectiveDefinition] but only unfolds [Refinement] nodes. |
| (...skipping 521 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 795 /// and the [length] reference may be null if there is no upper bound or | 795 /// and the [length] reference may be null if there is no upper bound or |
| 796 /// emptiness check. | 796 /// emptiness check. |
| 797 /// | 797 /// |
| 798 /// If a separate code motion guard for the index is required, e.g. because it | 798 /// If a separate code motion guard for the index is required, e.g. because it |
| 799 /// must be known to be non-negative in an operator that does not involve | 799 /// must be known to be non-negative in an operator that does not involve |
| 800 /// [object], a [Refinement] can be created for it with the non-negative integer | 800 /// [object], a [Refinement] can be created for it with the non-negative integer |
| 801 /// type. | 801 /// type. |
| 802 class BoundsCheck extends Primitive { | 802 class BoundsCheck extends Primitive { |
| 803 final Reference<Primitive> object; | 803 final Reference<Primitive> object; |
| 804 Reference<Primitive> index; | 804 Reference<Primitive> index; |
| 805 Reference<Primitive> length; // FIXME write docs for length | 805 Reference<Primitive> length; |
| 806 int checks; | 806 int checks; |
| 807 final SourceInformation sourceInformation; | 807 final SourceInformation sourceInformation; |
| 808 | 808 |
| 809 /// If true, check that `index >= 0`. | 809 /// If true, check that `index >= 0`. |
| 810 bool get hasLowerBoundCheck => checks & LOWER_BOUND != 0; | 810 bool get hasLowerBoundCheck => checks & LOWER_BOUND != 0; |
| 811 | 811 |
| 812 /// If true, check that `index < object.length`. | 812 /// If true, check that `index < object.length`. |
| 813 bool get hasUpperBoundCheck => checks & UPPER_BOUND != 0; | 813 bool get hasUpperBoundCheck => checks & UPPER_BOUND != 0; |
| 814 | 814 |
| 815 /// If true, check that `object.length !== 0`. | 815 /// If true, check that `object.length !== 0`. |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 869 } | 869 } |
| 870 } | 870 } |
| 871 | 871 |
| 872 bool get isSafeForElimination => checks == NONE; | 872 bool get isSafeForElimination => checks == NONE; |
| 873 bool get isSafeForReordering => false; | 873 bool get isSafeForReordering => false; |
| 874 bool get hasValue => true; // Can be referenced to restrict code motion. | 874 bool get hasValue => true; // Can be referenced to restrict code motion. |
| 875 | 875 |
| 876 Primitive get effectiveDefinition => object.definition.effectiveDefinition; | 876 Primitive get effectiveDefinition => object.definition.effectiveDefinition; |
| 877 } | 877 } |
| 878 | 878 |
| 879 /// Throw an exception if [value] is `null`. | 879 /// Throw a [NoSuchMethodError] if [value] cannot respond to [selector]. |
| 880 /// | 880 /// |
| 881 /// Returns [value] so this can be used to restrict code motion. | 881 /// Returns [value] so this can be used to restrict code motion. |
| 882 /// | 882 /// |
| 883 /// In the simplest form this compiles to `value.toString;`. | 883 /// The check can take one of three forms: |
| 884 /// | 884 /// |
| 885 /// [selector] holds the selector that is the cause of the null check. This is | 885 /// value.toString; |
| 886 /// usually a method that was inlined where [value] the receiver. | 886 /// value.selectorName; |
| 887 /// value.selectorName(); (should only be used if check always fails) | |
| 887 /// | 888 /// |
| 888 /// If [selector] is set and [useSelector] is true, `toString` is replaced with | 889 /// The first two forms are used when it is known that only null fails the |
| 889 /// the (possibly minified) invocation name of the selector. This can be | 890 /// check. Additionally, the check may be guarded by a [condition], allowing |
| 890 /// shorter and generate a more meaningful error message, but is expensive if | 891 /// for three more forms: |
| 891 /// [value] is non-null and does not have that property at runtime. | |
| 892 /// | 892 /// |
| 893 /// If [condition] is set, it is assumed that [condition] is true if and only | 893 /// if (condition) value.toString; (this form is valid but unused) |
| 894 /// if [value] is null. The check then compiles to: | 894 /// if (condition) value.selectorName; |
| 895 /// if (condition) value.selectorName(); | |
| 895 /// | 896 /// |
| 896 /// if (condition) value.toString; (or .selector if non-null) | 897 /// The condition must be true if and only if the check should fail. It should |
| 898 /// ideally be of a form understood by JS engines, e.g. a `typeof` test. | |
| 897 /// | 899 /// |
| 898 /// The latter form is useful when [condition] is a form understood by the JS | 900 /// If [useSelector] is false, the first form instead becomes `value.toString;`. |
|
Siggi Cherem (dart-lang)
2016/02/05 18:19:39
nit: since there are 2 groups, it's not entirely c
asgerf
2016/02/09 12:19:54
Yeah that wasn't very clear. I've rephrased the co
| |
| 899 /// runtime, such as a `typeof` test. | 901 /// This form is faster when the value is non-null and the accessed property has |
| 900 class NullCheck extends Primitive { | 902 /// been removed by tree shaking. |
| 903 /// | |
| 904 /// [selector] may not be one of the selectors implemented by the null object. | |
| 905 class ReceiverCheck extends Primitive { | |
| 901 final Reference<Primitive> value; | 906 final Reference<Primitive> value; |
| 902 final Selector selector; | 907 final Selector selector; |
| 903 final bool useSelector; | 908 final SourceInformation sourceInformation; |
| 904 final Reference<Primitive> condition; | 909 final Reference<Primitive> condition; |
| 905 final SourceInformation sourceInformation; | 910 final int _flags; |
| 906 | 911 |
| 907 NullCheck(Primitive value, this.sourceInformation, | 912 static const int _USE_SELECTOR = 1 << 0; |
| 908 {Primitive condition, | 913 static const int _NULL_CHECK = 1 << 1; |
| 909 this.selector, | |
| 910 this.useSelector: false}) | |
| 911 : this.value = new Reference<Primitive>(value), | |
| 912 this.condition = | |
| 913 condition == null ? null : new Reference<Primitive>(condition); | |
| 914 | 914 |
| 915 NullCheck.guarded(Primitive condition, Primitive value, this.selector, | 915 /// True if the selector name should be used in the check; otherwise |
| 916 this.sourceInformation) | 916 /// `toString` will be used. |
| 917 : this.condition = new Reference<Primitive>(condition), | 917 bool get useSelector => _flags & _USE_SELECTOR != 0; |
| 918 this.value = new Reference<Primitive>(value), | 918 |
| 919 this.useSelector = true; | 919 /// True if null is the only possible input that cannot respond to [selector]. |
| 920 bool get isNullCheck => _flags & _NULL_CHECK != 0; | |
| 921 | |
| 922 | |
| 923 /// Constructor for creating checks in arbitrary configurations. | |
| 924 /// | |
| 925 /// Consider using one of the named constructors instead. | |
| 926 /// | |
| 927 /// [useSelector] and [isNullCheck] are mandatory named arguments. | |
| 928 ReceiverCheck(Primitive value, this.selector, this.sourceInformation, | |
| 929 {Primitive condition, bool useSelector, bool isNullCheck}) | |
| 930 : value = new Reference<Primitive>(value), | |
| 931 condition = _optionalReference(condition), | |
| 932 _flags = (useSelector ? _USE_SELECTOR : 0) | | |
| 933 (isNullCheck ? _NULL_CHECK : 0); | |
| 934 | |
| 935 /// Simplified constructor for building null checks. | |
| 936 /// | |
| 937 /// Null must be the only possible input value that does not respond to | |
| 938 /// [selector]. | |
| 939 ReceiverCheck.nullCheck( | |
| 940 Primitive value, | |
| 941 Selector selector, | |
| 942 SourceInformation sourceInformation, | |
| 943 {Primitive condition}) | |
| 944 : this(value, | |
| 945 selector, | |
| 946 sourceInformation, | |
| 947 condition: condition, | |
| 948 useSelector: condition != null, | |
| 949 isNullCheck: true); | |
| 950 | |
| 951 /// Simplified constructor for building the general check of form: | |
| 952 /// | |
| 953 /// if (condition) value.selectorName(); | |
| 954 /// | |
| 955 ReceiverCheck.generalCheck( | |
| 956 Primitive value, | |
| 957 Selector selector, | |
| 958 SourceInformation sourceInformation, | |
| 959 Primitive condition) | |
| 960 : this(value, | |
| 961 selector, | |
| 962 sourceInformation, | |
| 963 condition: condition, | |
| 964 useSelector: true, | |
| 965 isNullCheck: false); | |
| 920 | 966 |
| 921 bool get isSafeForElimination => false; | 967 bool get isSafeForElimination => false; |
| 922 bool get isSafeForReordering => false; | 968 bool get isSafeForReordering => false; |
| 923 bool get hasValue => true; | 969 bool get hasValue => true; |
| 924 | 970 |
| 925 accept(Visitor visitor) => visitor.visitNullCheck(this); | 971 accept(Visitor visitor) => visitor.visitReceiverCheck(this); |
| 926 | 972 |
| 927 void setParentPointers() { | 973 void setParentPointers() { |
| 928 value.parent = this; | 974 value.parent = this; |
| 929 if (condition != null) { | 975 if (condition != null) { |
| 930 condition.parent = this; | 976 condition.parent = this; |
| 931 } | 977 } |
| 932 } | 978 } |
| 933 | 979 |
| 934 Primitive get effectiveDefinition => value.definition.effectiveDefinition; | 980 Primitive get effectiveDefinition => value.definition.effectiveDefinition; |
| 981 | |
| 982 String get nullCheckString => isNullCheck ? 'null-check' : 'general-check'; | |
| 983 String get useSelectorString => useSelector ? 'use-selector' : 'no-selector'; | |
| 984 String get flagString => '$nullCheckString $useSelectorString'; | |
| 935 } | 985 } |
| 936 | 986 |
| 937 /// An "is" type test. | 987 /// An "is" type test. |
| 938 /// | 988 /// |
| 939 /// Returns `true` if [value] is an instance of [dartType]. | 989 /// Returns `true` if [value] is an instance of [dartType]. |
| 940 /// | 990 /// |
| 941 /// [type] must not be the [Object], `dynamic` or [Null] types (though it might | 991 /// [type] must not be the [Object], `dynamic` or [Null] types (though it might |
| 942 /// be a type variable containing one of these types). This design is chosen | 992 /// be a type variable containing one of these types). This design is chosen |
| 943 /// to simplify code generation for type tests. | 993 /// to simplify code generation for type tests. |
| 944 class TypeTest extends Primitive { | 994 class TypeTest extends Primitive { |
| (...skipping 975 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1920 return visitor.visitYield(this); | 1970 return visitor.visitYield(this); |
| 1921 } | 1971 } |
| 1922 | 1972 |
| 1923 bool get hasValue => true; | 1973 bool get hasValue => true; |
| 1924 | 1974 |
| 1925 void setParentPointers() { | 1975 void setParentPointers() { |
| 1926 input.parent = this; | 1976 input.parent = this; |
| 1927 } | 1977 } |
| 1928 } | 1978 } |
| 1929 | 1979 |
| 1980 Reference<Primitive> _reference(Primitive definition) { | |
| 1981 return new Reference<Primitive>(definition); | |
| 1982 } | |
| 1983 | |
| 1984 Reference<Primitive> _optionalReference(Primitive definition) { | |
| 1985 return definition == null | |
| 1986 ? null | |
| 1987 : new Reference<Primitive>(definition); | |
| 1988 } | |
| 1989 | |
| 1930 List<Reference<Primitive>> _referenceList(Iterable<Primitive> definitions) { | 1990 List<Reference<Primitive>> _referenceList(Iterable<Primitive> definitions) { |
| 1931 return definitions.map((e) => new Reference<Primitive>(e)).toList(); | 1991 return definitions.map((e) => new Reference<Primitive>(e)).toList(); |
| 1932 } | 1992 } |
| 1933 | 1993 |
| 1934 void _setParentsOnNodes(List<Node> nodes, Node parent) { | 1994 void _setParentsOnNodes(List<Node> nodes, Node parent) { |
| 1935 for (Node node in nodes) { | 1995 for (Node node in nodes) { |
| 1936 node.parent = parent; | 1996 node.parent = parent; |
| 1937 } | 1997 } |
| 1938 } | 1998 } |
| 1939 | 1999 |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2067 T visitCreateInvocationMirror(CreateInvocationMirror node); | 2127 T visitCreateInvocationMirror(CreateInvocationMirror node); |
| 2068 T visitTypeTest(TypeTest node); | 2128 T visitTypeTest(TypeTest node); |
| 2069 T visitTypeTestViaFlag(TypeTestViaFlag node); | 2129 T visitTypeTestViaFlag(TypeTestViaFlag node); |
| 2070 T visitApplyBuiltinOperator(ApplyBuiltinOperator node); | 2130 T visitApplyBuiltinOperator(ApplyBuiltinOperator node); |
| 2071 T visitApplyBuiltinMethod(ApplyBuiltinMethod node); | 2131 T visitApplyBuiltinMethod(ApplyBuiltinMethod node); |
| 2072 T visitGetLength(GetLength node); | 2132 T visitGetLength(GetLength node); |
| 2073 T visitGetIndex(GetIndex node); | 2133 T visitGetIndex(GetIndex node); |
| 2074 T visitSetIndex(SetIndex node); | 2134 T visitSetIndex(SetIndex node); |
| 2075 T visitRefinement(Refinement node); | 2135 T visitRefinement(Refinement node); |
| 2076 T visitBoundsCheck(BoundsCheck node); | 2136 T visitBoundsCheck(BoundsCheck node); |
| 2077 T visitNullCheck(NullCheck node); | 2137 T visitReceiverCheck(ReceiverCheck node); |
| 2078 T visitForeignCode(ForeignCode node); | 2138 T visitForeignCode(ForeignCode node); |
| 2079 } | 2139 } |
| 2080 | 2140 |
| 2081 /// Recursively visits all children of a CPS term. | 2141 /// Recursively visits all children of a CPS term. |
| 2082 /// | 2142 /// |
| 2083 /// The user of the class is responsible for avoiding stack overflows from | 2143 /// The user of the class is responsible for avoiding stack overflows from |
| 2084 /// deep recursion, e.g. by overriding methods to cut off recursion at certain | 2144 /// deep recursion, e.g. by overriding methods to cut off recursion at certain |
| 2085 /// points. | 2145 /// points. |
| 2086 /// | 2146 /// |
| 2087 /// All recursive invocations occur through the [visit] method, which the | 2147 /// All recursive invocations occur through the [visit] method, which the |
| (...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2390 processBoundsCheck(node); | 2450 processBoundsCheck(node); |
| 2391 processReference(node.object); | 2451 processReference(node.object); |
| 2392 if (node.index != null) { | 2452 if (node.index != null) { |
| 2393 processReference(node.index); | 2453 processReference(node.index); |
| 2394 } | 2454 } |
| 2395 if (node.length != null) { | 2455 if (node.length != null) { |
| 2396 processReference(node.length); | 2456 processReference(node.length); |
| 2397 } | 2457 } |
| 2398 } | 2458 } |
| 2399 | 2459 |
| 2400 processNullCheck(NullCheck node) {} | 2460 processNullCheck(ReceiverCheck node) {} |
| 2401 visitNullCheck(NullCheck node) { | 2461 visitReceiverCheck(ReceiverCheck node) { |
| 2402 processNullCheck(node); | 2462 processNullCheck(node); |
| 2403 processReference(node.value); | 2463 processReference(node.value); |
| 2404 if (node.condition != null) { | 2464 if (node.condition != null) { |
| 2405 processReference(node.condition); | 2465 processReference(node.condition); |
| 2406 } | 2466 } |
| 2407 } | 2467 } |
| 2408 } | 2468 } |
| 2409 | 2469 |
| 2410 typedef void StackAction(); | 2470 typedef void StackAction(); |
| 2411 | 2471 |
| (...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2751 return new BoundsCheck.noCheck(getCopy(node.object), | 2811 return new BoundsCheck.noCheck(getCopy(node.object), |
| 2752 node.sourceInformation); | 2812 node.sourceInformation); |
| 2753 } else { | 2813 } else { |
| 2754 return new BoundsCheck(getCopy(node.object), getCopy(node.index), | 2814 return new BoundsCheck(getCopy(node.object), getCopy(node.index), |
| 2755 node.length == null ? null : getCopy(node.length), | 2815 node.length == null ? null : getCopy(node.length), |
| 2756 node.checks, | 2816 node.checks, |
| 2757 node.sourceInformation); | 2817 node.sourceInformation); |
| 2758 } | 2818 } |
| 2759 } | 2819 } |
| 2760 | 2820 |
| 2761 Definition visitNullCheck(NullCheck node) { | 2821 Definition visitReceiverCheck(ReceiverCheck node) { |
| 2762 return new NullCheck(getCopy(node.value), node.sourceInformation, | 2822 return new ReceiverCheck(getCopy(node.value), |
| 2823 node.selector, | |
| 2824 node.sourceInformation, | |
| 2763 condition: node.condition == null ? null : getCopy(node.condition), | 2825 condition: node.condition == null ? null : getCopy(node.condition), |
| 2764 selector: node.selector, | 2826 useSelector: node.useSelector, |
| 2765 useSelector: node.useSelector); | 2827 isNullCheck: node.isNullCheck); |
| 2766 } | 2828 } |
| 2767 | 2829 |
| 2768 Definition visitForeignCode(ForeignCode node) { | 2830 Definition visitForeignCode(ForeignCode node) { |
| 2769 return new ForeignCode(node.codeTemplate, node.storedType, | 2831 return new ForeignCode(node.codeTemplate, node.storedType, |
| 2770 getList(node.arguments), | 2832 getList(node.arguments), |
| 2771 node.nativeBehavior, | 2833 node.nativeBehavior, |
| 2772 dependency: node.dependency); | 2834 dependency: node.dependency); |
| 2773 } | 2835 } |
| 2774 } | 2836 } |
| 2775 | 2837 |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2906 plug(new Branch.loose(_definitions.getCopy(node.condition), | 2968 plug(new Branch.loose(_definitions.getCopy(node.condition), |
| 2907 _copies[node.trueContinuation.definition], | 2969 _copies[node.trueContinuation.definition], |
| 2908 _copies[node.falseContinuation.definition]) | 2970 _copies[node.falseContinuation.definition]) |
| 2909 ..isStrictCheck = node.isStrictCheck); | 2971 ..isStrictCheck = node.isStrictCheck); |
| 2910 } | 2972 } |
| 2911 | 2973 |
| 2912 visitUnreachable(Unreachable node) { | 2974 visitUnreachable(Unreachable node) { |
| 2913 plug(new Unreachable()); | 2975 plug(new Unreachable()); |
| 2914 } | 2976 } |
| 2915 } | 2977 } |
| OLD | NEW |