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

Side by Side Diff: pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart

Issue 1668913002: dart2js cps: More aggressive operator specialization. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 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) 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
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
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
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698