Index: runtime/lib/integers.cc |
=================================================================== |
--- runtime/lib/integers.cc (revision 3306) |
+++ runtime/lib/integers.cc (working copy) |
@@ -1,4 +1,4 @@ |
-// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
// for details. All rights reserved. Use of this source code is governed by a |
// BSD-style license that can be found in the LICENSE file. |
@@ -68,6 +68,20 @@ |
} |
+static bool Are63bitOperands(const Integer& op1, const Integer& op2) { |
+ if (op1.IsBigint() || op2.IsBigint()) { |
+ return false; |
+ } |
+ const int64_t limit = (static_cast<int64_t>(1)) << 62; |
+ const int64_t value1 = op1.AsInt64Value(); |
+ if ((-limit > value1) || (value1 >= limit)) { |
+ return false; |
+ } |
+ const int64_t value2 = op2.AsInt64Value(); |
+ return (-limit <= value2) && (value2 < limit); |
+} |
+ |
+ |
static RawInteger* IntegerBitOperation(Token::Kind kind, |
const Integer& op1_int, |
const Integer& op2_int) { |
@@ -202,53 +216,6 @@ |
} |
-// The result is invalid if it is outside the range |
-// Smi::kMinValue..Smi::kMaxValue. |
-static int64_t BinaryOpWithTwoSmis(Token::Kind operation, |
- const Smi& left, |
- const Smi& right) { |
- switch (operation) { |
- case Token::kADD: |
- // TODO(regis): We may need an overflow check in 64-bit mode. Revisit. |
- return left.Value() + right.Value(); |
- case Token::kSUB: |
- return left.Value() - right.Value(); |
- case Token::kMUL: { |
- // TODO(regis): Using Bigint here may be a performance issue. Revisit. |
- const Bigint& big_left = |
- Bigint::Handle(BigintOperations::NewFromSmi(left)); |
- const Bigint& big_right = |
- Bigint::Handle(BigintOperations::NewFromSmi(right)); |
- const Bigint& big_result = |
- Bigint::Handle(BigintOperations::Multiply(big_left, big_right)); |
- if (BigintOperations::FitsIntoInt64(big_result)) { |
- return BigintOperations::ToInt64(big_result); |
- } else { |
- // Overflow, return an invalid Smi. |
- return Smi::kMaxValue + 1; |
- } |
- } |
- case Token::kTRUNCDIV: |
- return left.Value() / right.Value(); |
- case Token::kMOD: { |
- intptr_t remainder = left.Value() % right.Value(); |
- if (remainder < 0) { |
- if (right.Value() < 0) { |
- return remainder - right.Value(); |
- } else { |
- return remainder + right.Value(); |
- } |
- } else { |
- return remainder; |
- } |
- } |
- default: |
- UNIMPLEMENTED(); |
- return 0; |
- } |
-} |
- |
- |
static RawBigint* BinaryOpWithTwoBigints(Token::Kind operation, |
const Bigint& left, |
const Bigint& right) { |
@@ -270,65 +237,80 @@ |
} |
-// TODO(srdjan): Implement correct overflow checking before allowing 64 bit |
-// operands. |
-static bool AreBoth64bitOperands(const Integer& op1, const Integer& op2) { |
- return false; |
-} |
- |
- |
static RawInteger* IntegerBinopHelper(Token::Kind operation, |
const Integer& left_int, |
const Integer& right_int) { |
- if (left_int.IsSmi() && right_int.IsSmi()) { |
+ // The result of any operation (except multiplication in 64-bit mode) between |
+ // two Smis will always fit in a 64-bit signed result (no overflow). |
+ if (((Smi::kBits < 32) || (operation != Token::kMUL)) && |
+ left_int.IsSmi() && right_int.IsSmi()) { |
Smi& left_smi = Smi::Handle(); |
Smi& right_smi = Smi::Handle(); |
left_smi ^= left_int.raw(); |
right_smi ^= right_int.raw(); |
- int64_t result = BinaryOpWithTwoSmis(operation, left_smi, right_smi); |
- if (Smi::IsValid64(result)) { |
- return Smi::New(result); |
- } else { |
- // TODO(regis): This is not going to work on x64. Check other operations. |
-#if defined(TARGET_ARCH_X64) |
- UNIMPLEMENTED(); |
- return 0; |
-#else |
- // Overflow to Mint. |
- return Mint::New(result); |
-#endif |
+ const intptr_t left_value = left_smi.Value(); |
+ const intptr_t right_value = right_smi.Value(); |
+ switch (operation) { |
+ case Token::kADD: |
+ return Integer::New(left_value + right_value); |
+ case Token::kSUB: |
+ return Integer::New(left_value - right_value); |
+ case Token::kMUL: { |
+ ASSERT(Smi::kBits < 32); // Do not use this code in 64-bit mode. |
+ return Integer::New(static_cast<int64_t>(left_value) * |
+ static_cast<int64_t>(right_value)); |
+ } |
+ case Token::kTRUNCDIV: |
+ return Integer::New(left_value / right_value); |
+ case Token::kMOD: { |
+ const intptr_t remainder = left_value % right_value; |
+ if (remainder < 0) { |
+ if (right_value < 0) { |
+ return Integer::New(remainder - right_value); |
+ } else { |
+ return Integer::New(remainder + right_value); |
+ } |
+ } else { |
+ return Integer::New(remainder); |
+ } |
+ } |
+ default: |
+ UNIMPLEMENTED(); |
} |
- } else if (AreBoth64bitOperands(left_int, right_int)) { |
- // TODO(srdjan): Test for overflow of result instead of operand |
- // types. |
- const int64_t a = left_int.AsInt64Value(); |
- const int64_t b = right_int.AsInt64Value(); |
+ UNREACHABLE(); |
+ return Integer::null(); |
+ } |
+ // The result of any operation (except multiplication) between two 63-bit |
+ // signed integers will fit in a 64-bit signed result. |
+ // In 64-bit mode, this case was already handled above. |
+ if ((Smi::kBits < 32) && (operation != Token::kMUL) && |
+ Are63bitOperands(left_int, right_int)) { |
+ const int64_t left_value = left_int.AsInt64Value(); |
+ const int64_t right_value = right_int.AsInt64Value(); |
switch (operation) { |
case Token::kADD: |
- return Integer::New(a + b); |
+ return Integer::New(left_value + right_value); |
case Token::kSUB: |
- return Integer::New(a - b); |
- case Token::kMUL: |
- return Integer::New(a * b); |
+ return Integer::New(left_value - right_value); |
case Token::kTRUNCDIV: |
- return Integer::New(a / b); |
+ return Integer::New(left_value / right_value); |
case Token::kMOD: { |
- int64_t remainder = a % b; |
- int64_t c = 0; |
+ const int64_t remainder = left_value % right_value; |
if (remainder < 0) { |
- if (b < 0) { |
- c = remainder - b; |
+ if (right_value < 0) { |
+ return Integer::New(remainder - right_value); |
} else { |
- c = remainder + b; |
+ return Integer::New(remainder + right_value); |
} |
} else { |
- c = remainder; |
+ return Integer::New(remainder); |
} |
- return Integer::New(c); |
} |
default: |
UNIMPLEMENTED(); |
} |
+ UNREACHABLE(); |
+ return Integer::null(); |
} |
const Bigint& left_big = Bigint::Handle(AsBigint(left_int)); |
const Bigint& right_big = Bigint::Handle(AsBigint(right_int)); |
@@ -456,32 +438,36 @@ |
static RawInteger* SmiShiftOperation(Token::Kind kind, |
const Smi& left, |
const Smi& right) { |
- ASSERT(right.Value() >= 0); |
intptr_t result = 0; |
+ const intptr_t left_value = left.Value(); |
+ const intptr_t right_value = right.Value(); |
+ ASSERT(right_value >= 0); |
switch (kind) { |
- case Token::kSHL: |
- if ((left.Value() == 0) || (right.Value() == 0)) { |
+ case Token::kSHL: { |
+ if ((left_value == 0) || (right_value == 0)) { |
return left.raw(); |
} |
{ // Check for overflow. |
- int cnt = HighestBit(left.Value()); |
- if ((cnt + right.Value()) >= Smi::kBits) { |
- if ((cnt + right.Value()) >= Mint::kBits) { |
+ int cnt = HighestBit(left_value); |
+ if ((cnt + right_value) >= Smi::kBits) { |
+ if ((cnt + right_value) >= Mint::kBits) { |
return BigintOperations::ShiftLeft( |
- Bigint::Handle(AsBigint(left)), right.Value()); |
+ Bigint::Handle(AsBigint(left)), right_value); |
} else { |
- int64_t left_64 = left.Value(); |
- return Integer::New(left_64 << right.Value()); |
+ int64_t left_64 = left_value; |
+ return Integer::New(left_64 << right_value); |
} |
} |
} |
- result = left.Value() << right.Value(); |
+ result = left_value << right_value; |
break; |
+ } |
case Token::kSHR: { |
- int shift_amount = (right.Value() > 0x1F) ? 0x1F : right.Value(); |
- result = left.Value() >> shift_amount; |
- break; |
- } |
+ const intptr_t shift_amount = |
+ (right_value >= kBitsPerWord) ? (kBitsPerWord - 1) : right_value; |
+ result = left_value >> shift_amount; |
+ break; |
+ } |
default: |
UNIMPLEMENTED(); |
} |