| 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 import 'dart:math' show min, max; |
| 7 | 7 |
| 8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
| 9 import 'package:analyzer/dart/ast/ast.dart'; | 9 import 'package:analyzer/dart/ast/ast.dart'; |
| 10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; | 10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; |
| (...skipping 3328 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3339 return bitwise('# ^ #'); | 3339 return bitwise('# ^ #'); |
| 3340 | 3340 |
| 3341 case TokenType.GT_GT: | 3341 case TokenType.GT_GT: |
| 3342 int shiftCount = _asIntInRange(right, 0, 31); | 3342 int shiftCount = _asIntInRange(right, 0, 31); |
| 3343 if (_is31BitUnsigned(left) && shiftCount != null) { | 3343 if (_is31BitUnsigned(left) && shiftCount != null) { |
| 3344 return binary('# >> #'); | 3344 return binary('# >> #'); |
| 3345 } | 3345 } |
| 3346 if (_isDefinitelyNonNegative(left) && shiftCount != null) { | 3346 if (_isDefinitelyNonNegative(left) && shiftCount != null) { |
| 3347 return binary('# >>> #'); | 3347 return binary('# >>> #'); |
| 3348 } | 3348 } |
| 3349 // TODO(sra): If the context selects out only bits that can't be | 3349 // If the context selects out only bits that can't be affected by the |
| 3350 // affected by the sign position we can use any JavaScript shift. | 3350 // sign position we can use any JavaScript shift, `(x >> 6) & 3`. |
| 3351 // E.g. `(x >> 6) & 3`. | 3351 if (shiftCount != null && |
| 3352 _parentMasksToWidth(node, 31 - shiftCount)) { |
| 3353 return binary('# >> #'); |
| 3354 } |
| 3352 return _emitSend(left, op.lexeme, [right]); | 3355 return _emitSend(left, op.lexeme, [right]); |
| 3353 | 3356 |
| 3354 case TokenType.LT_LT: | 3357 case TokenType.LT_LT: |
| 3355 if (_is31BitUnsigned(node)) { | 3358 if (_is31BitUnsigned(node)) { |
| 3356 // Result is 31 bit unsigned which implies the shift count was small | 3359 // Result is 31 bit unsigned which implies the shift count was small |
| 3357 // enough not to pollute the sign bit. | 3360 // enough not to pollute the sign bit. |
| 3358 return binary('# << #'); | 3361 return binary('# << #'); |
| 3359 } | 3362 } |
| 3360 if (_asIntInRange(right, 0, 31) != null) { | 3363 if (_asIntInRange(right, 0, 31) != null) { |
| 3361 return _coerceBitOperationResultToUnsigned(node, binary('# << #')); | 3364 return _coerceBitOperationResultToUnsigned(node, binary('# << #')); |
| 3362 } | 3365 } |
| 3363 return _emitSend(left, op.lexeme, [right]); | 3366 return _emitSend(left, op.lexeme, [right]); |
| 3364 | 3367 |
| 3365 default: | 3368 default: |
| 3366 // TODO(vsm): When do Dart ops not map to JS? | 3369 // TODO(vsm): When do Dart ops not map to JS? |
| 3367 return binary('# $op #'); | 3370 return binary('# $op #'); |
| 3368 } | 3371 } |
| 3369 } | 3372 } |
| 3370 | 3373 |
| 3371 return _emitSend(left, op.lexeme, [right]); | 3374 return _emitSend(left, op.lexeme, [right]); |
| 3372 } | 3375 } |
| 3373 | 3376 |
| 3374 /// Bit operations are coerced to values on [0, 2^32). The coercion changes | 3377 /// Bit operations are coerced to values on [0, 2^32). The coercion changes |
| 3375 /// the interpretation of the 32-bit value from signed to unsigned. Most | 3378 /// the interpretation of the 32-bit value from signed to unsigned. Most |
| 3376 /// JavaScript operations interpret their operands as signed and generate | 3379 /// JavaScript operations interpret their operands as signed and generate |
| 3377 /// signed results. | 3380 /// signed results. |
| 3378 JS.Expression _coerceBitOperationResultToUnsigned( | 3381 JS.Expression _coerceBitOperationResultToUnsigned( |
| 3379 Expression node, JS.Expression operation) { | 3382 Expression node, JS.Expression uncoerced) { |
| 3380 // Don't coerce if the parent will coerce. | 3383 // Don't coerce if the parent will coerce. |
| 3381 AstNode parent = _parentOperation(node); | 3384 AstNode parent = _parentOperation(node); |
| 3382 if (_nodeIsBitwiseOperation(parent)) return operation; | 3385 if (_nodeIsBitwiseOperation(parent)) return uncoerced; |
| 3383 | 3386 |
| 3384 // Don't do a no-op coerce if the most significant bit is zero. | 3387 // Don't do a no-op coerce if the most significant bit is zero. |
| 3385 if (_is31BitUnsigned(node)) return operation; | 3388 if (_is31BitUnsigned(node)) return uncoerced; |
| 3386 | 3389 |
| 3387 // TODO(sra): If the consumer of the expression is '==' or '!=' to a | 3390 // If the consumer of the expression is '==' or '!=' with a constant that |
| 3388 // constant that fits in 31 bits, adding a coercion does not change the | 3391 // fits in 31 bits, adding a coercion does not change the result of the |
| 3389 // result of the comparision, e.g. `a & ~b == 0`. | 3392 // comparision, e.g. `a & ~b == 0`. |
| 3390 return js.call('# >>> 0', operation); | 3393 if (parent is BinaryExpression) { |
| 3394 var tokenType = parent.operator.type; |
| 3395 Expression left = parent.leftOperand; |
| 3396 Expression right = parent.rightOperand; |
| 3397 if (tokenType == TokenType.EQ_EQ || tokenType == TokenType.BANG_EQ) { |
| 3398 const int MAX = 0x7fffffff; |
| 3399 if (_asIntInRange(right, 0, MAX) != null) return uncoerced; |
| 3400 if (_asIntInRange(left, 0, MAX) != null) return uncoerced; |
| 3401 } else if (tokenType == TokenType.GT_GT) { |
| 3402 if (_isDefinitelyNonNegative(left) && |
| 3403 _asIntInRange(right, 0, 31) != null) { |
| 3404 // Parent will generate `# >>> n`. |
| 3405 return uncoerced; |
| 3406 } |
| 3407 } |
| 3408 } |
| 3409 return js.call('# >>> 0', uncoerced); |
| 3391 } | 3410 } |
| 3392 | 3411 |
| 3393 AstNode _parentOperation(AstNode node) { | 3412 AstNode _parentOperation(AstNode node) { |
| 3394 node = node.parent; | 3413 node = node.parent; |
| 3395 while (node is ParenthesizedExpression) node = node.parent; | 3414 while (node is ParenthesizedExpression) node = node.parent; |
| 3396 return node; | 3415 return node; |
| 3397 } | 3416 } |
| 3398 | 3417 |
| 3399 bool _nodeIsBitwiseOperation(AstNode node) { | 3418 bool _nodeIsBitwiseOperation(AstNode node) { |
| 3400 if (node is BinaryExpression) { | 3419 if (node is BinaryExpression) { |
| 3401 switch (node.operator.type) { | 3420 switch (node.operator.type) { |
| 3402 case TokenType.AMPERSAND: | 3421 case TokenType.AMPERSAND: |
| 3403 case TokenType.BAR: | 3422 case TokenType.BAR: |
| 3404 case TokenType.CARET: | 3423 case TokenType.CARET: |
| 3405 return true; | 3424 return true; |
| 3406 } | 3425 } |
| 3407 return false; | 3426 return false; |
| 3408 } | 3427 } |
| 3409 if (node is PrefixExpression) { | 3428 if (node is PrefixExpression) { |
| 3410 return node.operator.type == TokenType.TILDE; | 3429 return node.operator.type == TokenType.TILDE; |
| 3411 } | 3430 } |
| 3412 return false; | 3431 return false; |
| 3413 } | 3432 } |
| 3414 | 3433 |
| 3415 Expression _skipParentheses(Expression expr) { | |
| 3416 while (expr is ParenthesizedExpression) { | |
| 3417 ParenthesizedExpression parenExpr = expr; | |
| 3418 expr = parenExpr.expression; | |
| 3419 } | |
| 3420 return expr; | |
| 3421 } | |
| 3422 | |
| 3423 int _asIntInRange(Expression expr, int low, int high) { | 3434 int _asIntInRange(Expression expr, int low, int high) { |
| 3424 expr = _skipParentheses(expr); | 3435 expr = expr.unParenthesized; |
| 3425 if (expr is IntegerLiteral) { | 3436 if (expr is IntegerLiteral) { |
| 3426 if (expr.value >= low && expr.value <= high) return expr.value; | 3437 if (expr.value >= low && expr.value <= high) return expr.value; |
| 3438 return null; |
| 3439 } |
| 3440 int finishIdentifier(SimpleIdentifier identifier) { |
| 3441 Element staticElement = identifier.staticElement; |
| 3442 if (staticElement is PropertyAccessorElement && staticElement.isGetter) { |
| 3443 PropertyInducingElement variable = staticElement.variable; |
| 3444 int value = variable?.constantValue?.toIntValue(); |
| 3445 if (value != null && value >= low && value <= high) return value; |
| 3446 } |
| 3447 return null; |
| 3448 } |
| 3449 if (expr is SimpleIdentifier) { |
| 3450 return finishIdentifier(expr); |
| 3451 } else if (expr is PrefixedIdentifier && !expr.isDeferred) { |
| 3452 return finishIdentifier(expr.identifier); |
| 3427 } | 3453 } |
| 3428 return null; | 3454 return null; |
| 3429 } | 3455 } |
| 3430 | 3456 |
| 3431 bool _isDefinitelyNonNegative(Expression expr) { | 3457 bool _isDefinitelyNonNegative(Expression expr) { |
| 3432 expr = _skipParentheses(expr); | 3458 expr = expr.unParenthesized; |
| 3433 if (expr is IntegerLiteral) { | 3459 if (expr is IntegerLiteral) { |
| 3434 return expr.value >= 0; | 3460 return expr.value >= 0; |
| 3435 } | 3461 } |
| 3436 if (_nodeIsBitwiseOperation(expr)) return true; | 3462 if (_nodeIsBitwiseOperation(expr)) return true; |
| 3437 // TODO(sra): Lengths of known list types etc. | 3463 // TODO(sra): Lengths of known list types etc. |
| 3438 return false; | 3464 return false; |
| 3439 } | 3465 } |
| 3440 | 3466 |
| 3467 /// Does the parent of [node] mask the result to [width] bits or fewer? |
| 3468 bool _parentMasksToWidth(AstNode node, int width) { |
| 3469 AstNode parent = _parentOperation(node); |
| 3470 if (parent == null) return false; |
| 3471 if (_nodeIsBitwiseOperation(parent)) { |
| 3472 if (parent is BinaryExpression && |
| 3473 parent.operator.type == TokenType.AMPERSAND) { |
| 3474 Expression left = parent.leftOperand; |
| 3475 Expression right = parent.rightOperand; |
| 3476 final int MAX = (1 << width) - 1; |
| 3477 if (_asIntInRange(right, 0, MAX) != null) return true; |
| 3478 if (_asIntInRange(left, 0, MAX) != null) return true; |
| 3479 } |
| 3480 return _parentMasksToWidth(parent, width); |
| 3481 } |
| 3482 return false; |
| 3483 } |
| 3484 |
| 3441 /// Determines if the result of evaluating [expr] will be an non-negative | 3485 /// Determines if the result of evaluating [expr] will be an non-negative |
| 3442 /// value that fits in 31 bits. | 3486 /// value that fits in 31 bits. |
| 3443 bool _is31BitUnsigned(Expression expr) { | 3487 bool _is31BitUnsigned(Expression expr) { |
| 3444 const int MAX = 32; // Includes larger and negative values. | 3488 const int MAX = 32; // Includes larger and negative values. |
| 3445 /// Determines how many bits are required to hold result of evaluation | 3489 /// Determines how many bits are required to hold result of evaluation |
| 3446 /// [expr]. [depth] is used to bound exploration of huge expressions. | 3490 /// [expr]. [depth] is used to bound exploration of huge expressions. |
| 3447 int bitWidth(Expression expr, int depth) { | 3491 int bitWidth(Expression expr, int depth) { |
| 3448 if (expr is IntegerLiteral) { | 3492 if (expr is IntegerLiteral) { |
| 3449 return expr.value >= 0 ? expr.value.bitLength : MAX; | 3493 return expr.value >= 0 ? expr.value.bitLength : MAX; |
| 3450 } | 3494 } |
| 3451 if (++depth > 5) return MAX; | 3495 if (++depth > 5) return MAX; |
| 3452 if (expr is BinaryExpression) { | 3496 if (expr is BinaryExpression) { |
| 3453 var left = _skipParentheses(expr.leftOperand); | 3497 var left = expr.leftOperand.unParenthesized; |
| 3454 var right = _skipParentheses(expr.rightOperand); | 3498 var right = expr.rightOperand.unParenthesized; |
| 3455 switch (expr.operator.type) { | 3499 switch (expr.operator.type) { |
| 3456 case TokenType.AMPERSAND: | 3500 case TokenType.AMPERSAND: |
| 3457 return min(bitWidth(left, depth), bitWidth(right, depth)); | 3501 return min(bitWidth(left, depth), bitWidth(right, depth)); |
| 3458 | 3502 |
| 3459 case TokenType.BAR: | 3503 case TokenType.BAR: |
| 3460 case TokenType.CARET: | 3504 case TokenType.CARET: |
| 3461 return max(bitWidth(left, depth), bitWidth(right, depth)); | 3505 return max(bitWidth(left, depth), bitWidth(right, depth)); |
| 3462 | 3506 |
| 3463 case TokenType.GT_GT: | 3507 case TokenType.GT_GT: |
| 3464 int shiftValue = _asIntInRange(right, 0, 31); | 3508 int shiftValue = _asIntInRange(right, 0, 31); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 3478 if (rightWidth <= 5) { | 3522 if (rightWidth <= 5) { |
| 3479 // e.g. `1 << (x & 7)` has a rightWidth of 3, so shifts by up to | 3523 // e.g. `1 << (x & 7)` has a rightWidth of 3, so shifts by up to |
| 3480 // (1 << 3) - 1 == 7 bits. | 3524 // (1 << 3) - 1 == 7 bits. |
| 3481 return min(MAX, leftWidth + ((1 << rightWidth) - 1)); | 3525 return min(MAX, leftWidth + ((1 << rightWidth) - 1)); |
| 3482 } | 3526 } |
| 3483 return MAX; | 3527 return MAX; |
| 3484 default: | 3528 default: |
| 3485 return MAX; | 3529 return MAX; |
| 3486 } | 3530 } |
| 3487 } | 3531 } |
| 3532 int value = _asIntInRange(expr, 0, 0x7fffffff); |
| 3533 if (value != null) return value.bitLength; |
| 3488 return MAX; | 3534 return MAX; |
| 3489 } | 3535 } |
| 3490 return bitWidth(expr, 0) < 32; | 3536 return bitWidth(expr, 0) < 32; |
| 3491 } | 3537 } |
| 3492 | 3538 |
| 3493 /// If the type [t] is [int] or [double], or a type parameter | 3539 /// If the type [t] is [int] or [double], or a type parameter |
| 3494 /// bounded by [int], [double] or [num] returns [num]. | 3540 /// bounded by [int], [double] or [num] returns [num]. |
| 3495 /// Otherwise returns [t]. | 3541 /// Otherwise returns [t]. |
| 3496 DartType _canonicalizeNumTypes(DartType t) { | 3542 DartType _canonicalizeNumTypes(DartType t) { |
| 3497 var numType = types.numType; | 3543 var numType = types.numType; |
| (...skipping 1232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4730 } | 4776 } |
| 4731 | 4777 |
| 4732 bool isLibraryPrefix(Expression node) => | 4778 bool isLibraryPrefix(Expression node) => |
| 4733 node is SimpleIdentifier && node.staticElement is PrefixElement; | 4779 node is SimpleIdentifier && node.staticElement is PrefixElement; |
| 4734 | 4780 |
| 4735 LibraryElement _getLibrary(AnalysisContext c, String uri) => | 4781 LibraryElement _getLibrary(AnalysisContext c, String uri) => |
| 4736 c.computeLibraryElement(c.sourceFactory.forUri(uri)); | 4782 c.computeLibraryElement(c.sourceFactory.forUri(uri)); |
| 4737 | 4783 |
| 4738 bool _isDartRuntime(LibraryElement l) => | 4784 bool _isDartRuntime(LibraryElement l) => |
| 4739 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; | 4785 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; |
| OLD | NEW |