OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 'dart:collection' show HashMap, HashSet; | 5 import 'dart:collection' show HashMap, HashSet; |
| 6 import 'dart:math' show min, max; |
6 | 7 |
7 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
8 import 'package:analyzer/dart/ast/ast.dart'; | 9 import 'package:analyzer/dart/ast/ast.dart'; |
9 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; | 10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; |
10 import 'package:analyzer/dart/element/element.dart'; | 11 import 'package:analyzer/dart/element/element.dart'; |
11 import 'package:analyzer/dart/element/type.dart'; | 12 import 'package:analyzer/dart/element/type.dart'; |
12 import 'package:analyzer/src/dart/ast/token.dart' show StringToken; | 13 import 'package:analyzer/src/dart/ast/token.dart' show StringToken; |
13 //TODO(leafp): Remove deprecated dependency | 14 //TODO(leafp): Remove deprecated dependency |
14 //ignore: DEPRECATED_MEMBER_USE | 15 //ignore: DEPRECATED_MEMBER_USE |
15 import 'package:analyzer/src/generated/element.dart' | 16 import 'package:analyzer/src/generated/element.dart' |
(...skipping 2829 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2845 case TokenType.AMPERSAND: | 2846 case TokenType.AMPERSAND: |
2846 return bitwise('# & #'); | 2847 return bitwise('# & #'); |
2847 | 2848 |
2848 case TokenType.BAR: | 2849 case TokenType.BAR: |
2849 return bitwise('# | #'); | 2850 return bitwise('# | #'); |
2850 | 2851 |
2851 case TokenType.CARET: | 2852 case TokenType.CARET: |
2852 return bitwise('# ^ #'); | 2853 return bitwise('# ^ #'); |
2853 | 2854 |
2854 case TokenType.GT_GT: | 2855 case TokenType.GT_GT: |
2855 // TODO(sra): Detect when JS shift does the right thing. | 2856 int shiftCount = _asIntInRange(right, 0, 31); |
| 2857 if (_is31BitUnsigned(left) && shiftCount != null) { |
| 2858 return binary('# >> #'); |
| 2859 } |
| 2860 if (_isDefinitelyNonNegative(left) && shiftCount != null) { |
| 2861 return binary('# >>> #'); |
| 2862 } |
| 2863 // TODO(sra): If the context selects out only bits that can't be |
| 2864 // affected by the sign position we can use any JavaScript shift. |
| 2865 // E.g. `(x >> 6) & 3`. |
2856 return _emitSend(left, op.lexeme, [right]); | 2866 return _emitSend(left, op.lexeme, [right]); |
2857 | 2867 |
2858 case TokenType.LT_LT: | 2868 case TokenType.LT_LT: |
2859 // TODO(sra): Detect when JS shift does the right thing. | 2869 if (_is31BitUnsigned(node)) { |
| 2870 // Result is 31 bit unsigned which implies the shift count was small |
| 2871 // enough not to pollute the sign bit. |
| 2872 return binary('# << #'); |
| 2873 } |
| 2874 if (_asIntInRange(right, 0, 31) != null) { |
| 2875 return _coerceBitOperationResultToUnsigned(node, binary('# << #')); |
| 2876 } |
2860 return _emitSend(left, op.lexeme, [right]); | 2877 return _emitSend(left, op.lexeme, [right]); |
2861 | 2878 |
2862 default: | 2879 default: |
2863 // TODO(vsm): When do Dart ops not map to JS? | 2880 // TODO(vsm): When do Dart ops not map to JS? |
2864 return binary('# $op #'); | 2881 return binary('# $op #'); |
2865 } | 2882 } |
2866 } | 2883 } |
2867 | 2884 |
2868 return _emitSend(left, op.lexeme, [right]); | 2885 return _emitSend(left, op.lexeme, [right]); |
2869 } | 2886 } |
2870 | 2887 |
2871 /// Bit operations are coerced to values on [0, 2^32). The coercion changes | 2888 /// Bit operations are coerced to values on [0, 2^32). The coercion changes |
2872 /// the interpretation of the 32-bit value from signed to unsigned. Most | 2889 /// the interpretation of the 32-bit value from signed to unsigned. Most |
2873 /// JavaScript operations interpret their operands as signed and generate | 2890 /// JavaScript operations interpret their operands as signed and generate |
2874 /// signed results. | 2891 /// signed results. |
2875 JS.Expression _coerceBitOperationResultToUnsigned( | 2892 JS.Expression _coerceBitOperationResultToUnsigned( |
2876 Expression node, JS.Expression operation) { | 2893 Expression node, JS.Expression operation) { |
| 2894 // Don't coerce if the parent will coerce. |
| 2895 AstNode parent = _parentOperation(node); |
| 2896 if (_nodeIsBitwiseOperation(parent)) return operation; |
| 2897 |
| 2898 // Don't do a no-op coerce if the most significant bit is zero. |
| 2899 if (_is31BitUnsigned(node)) return operation; |
| 2900 |
| 2901 // TODO(sra): If the consumer of the expression is '==' or '!=' to a |
| 2902 // constant that fits in 31 bits, adding a coercion does not change the |
| 2903 // result of the comparision, e.g. `a & ~b == 0`. |
2877 return js.call('# >>> 0', operation); | 2904 return js.call('# >>> 0', operation); |
2878 } | 2905 } |
2879 | 2906 |
| 2907 AstNode _parentOperation(AstNode node) { |
| 2908 node = node.parent; |
| 2909 while (node is ParenthesizedExpression) node = node.parent; |
| 2910 return node; |
| 2911 } |
| 2912 |
| 2913 bool _nodeIsBitwiseOperation(AstNode node) { |
| 2914 if (node is BinaryExpression) { |
| 2915 switch (node.operator.type) { |
| 2916 case TokenType.AMPERSAND: |
| 2917 case TokenType.BAR: |
| 2918 case TokenType.CARET: |
| 2919 return true; |
| 2920 } |
| 2921 return false; |
| 2922 } |
| 2923 if (node is PrefixExpression) { |
| 2924 return node.operator.type == TokenType.TILDE; |
| 2925 } |
| 2926 return false; |
| 2927 } |
| 2928 |
| 2929 Expression _skipParentheses(Expression expr) { |
| 2930 while (expr is ParenthesizedExpression) { |
| 2931 ParenthesizedExpression parenExpr = expr; |
| 2932 expr = parenExpr.expression; |
| 2933 } |
| 2934 return expr; |
| 2935 } |
| 2936 |
| 2937 int _asIntInRange(Expression expr, int low, int high) { |
| 2938 expr = _skipParentheses(expr); |
| 2939 if (expr is IntegerLiteral) { |
| 2940 if (expr.value >= low && expr.value <= high) return expr.value; |
| 2941 } |
| 2942 return null; |
| 2943 } |
| 2944 |
| 2945 bool _isDefinitelyNonNegative(Expression expr) { |
| 2946 expr = _skipParentheses(expr); |
| 2947 if (expr is IntegerLiteral) { |
| 2948 return expr.value >= 0; |
| 2949 } |
| 2950 if (_nodeIsBitwiseOperation(expr)) return true; |
| 2951 // TODO(sra): Lengths of known list types etc. |
| 2952 return false; |
| 2953 } |
| 2954 |
| 2955 /// Determines if the result of evaluating [expr] will be an non-negative |
| 2956 /// value that fits in 31 bits. |
| 2957 bool _is31BitUnsigned(Expression expr) { |
| 2958 const int MAX = 32; // Includes larger and negative values. |
| 2959 /// Determines how many bits are required to hold result of evaluation |
| 2960 /// [expr]. [depth] is used to bound exploration of huge expressions. |
| 2961 int bitWidth(Expression expr, int depth) { |
| 2962 if (expr is IntegerLiteral) { |
| 2963 return expr.value >= 0 ? expr.value.bitLength : MAX; |
| 2964 } |
| 2965 if (++depth > 5) return MAX; |
| 2966 if (expr is BinaryExpression) { |
| 2967 var left = _skipParentheses(expr.leftOperand); |
| 2968 var right = _skipParentheses(expr.rightOperand); |
| 2969 switch (expr.operator.type) { |
| 2970 case TokenType.AMPERSAND: |
| 2971 return min(bitWidth(left, depth), bitWidth(right, depth)); |
| 2972 |
| 2973 case TokenType.BAR: |
| 2974 case TokenType.CARET: |
| 2975 return max(bitWidth(left, depth), bitWidth(right, depth)); |
| 2976 |
| 2977 case TokenType.GT_GT: |
| 2978 int shiftValue = _asIntInRange(right, 0, 31); |
| 2979 if (shiftValue != null) { |
| 2980 int leftWidth = bitWidth(left, depth); |
| 2981 return leftWidth == MAX ? MAX : max(0, leftWidth - shiftValue); |
| 2982 } |
| 2983 return MAX; |
| 2984 |
| 2985 case TokenType.LT_LT: |
| 2986 int leftWidth = bitWidth(left, depth); |
| 2987 int shiftValue = _asIntInRange(right, 0, 31); |
| 2988 if (shiftValue != null) { |
| 2989 return min(MAX, leftWidth + shiftValue); |
| 2990 } |
| 2991 int rightWidth = bitWidth(right, depth); |
| 2992 if (rightWidth <= 5) { |
| 2993 // e.g. `1 << (x & 7)` has a rightWidth of 3, so shifts by up to |
| 2994 // (1 << 3) - 1 == 7 bits. |
| 2995 return min(MAX, leftWidth + ((1 << rightWidth) - 1)); |
| 2996 } |
| 2997 return MAX; |
| 2998 default: |
| 2999 return MAX; |
| 3000 } |
| 3001 } |
| 3002 return MAX; |
| 3003 } |
| 3004 return bitWidth(expr, 0) < 32; |
| 3005 } |
| 3006 |
2880 /// If the type [t] is [int] or [double], or a type parameter | 3007 /// If the type [t] is [int] or [double], or a type parameter |
2881 /// bounded by [int], [double] or [num] returns [num]. | 3008 /// bounded by [int], [double] or [num] returns [num]. |
2882 /// Otherwise returns [t]. | 3009 /// Otherwise returns [t]. |
2883 DartType _canonicalizeNumTypes(DartType t) { | 3010 DartType _canonicalizeNumTypes(DartType t) { |
2884 var numType = types.numType; | 3011 var numType = types.numType; |
2885 if (rules.isSubtypeOf(t, numType)) return numType; | 3012 if (rules.isSubtypeOf(t, numType)) return numType; |
2886 return t; | 3013 return t; |
2887 } | 3014 } |
2888 | 3015 |
2889 bool _canUsePrimitiveEquality(Expression left, Expression right) { | 3016 bool _canUsePrimitiveEquality(Expression left, Expression right) { |
(...skipping 1059 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3949 } | 4076 } |
3950 | 4077 |
3951 bool isLibraryPrefix(Expression node) => | 4078 bool isLibraryPrefix(Expression node) => |
3952 node is SimpleIdentifier && node.staticElement is PrefixElement; | 4079 node is SimpleIdentifier && node.staticElement is PrefixElement; |
3953 | 4080 |
3954 LibraryElement _getLibrary(AnalysisContext c, String uri) => | 4081 LibraryElement _getLibrary(AnalysisContext c, String uri) => |
3955 c.computeLibraryElement(c.sourceFactory.forUri(uri)); | 4082 c.computeLibraryElement(c.sourceFactory.forUri(uri)); |
3956 | 4083 |
3957 bool _isDartRuntime(LibraryElement l) => | 4084 bool _isDartRuntime(LibraryElement l) => |
3958 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; | 4085 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; |
OLD | NEW |