| Index: runtime/vm/object.cc
|
| diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
|
| index aebbc47d1bf9c7652db59a4dd1f2bcdecf509b1f..3c6906c14abdf2c0f74e1ae5099245c51c726b0f 100644
|
| --- a/runtime/vm/object.cc
|
| +++ b/runtime/vm/object.cc
|
| @@ -8727,6 +8727,131 @@ int Integer::CompareWith(const Integer& other) const {
|
| }
|
|
|
|
|
| +// Return the most compact presentation of an integer.
|
| +RawInteger* Integer::AsInteger(const Integer& value) {
|
| + if (value.IsSmi()) return value.raw();
|
| + if (value.IsMint()) {
|
| + Mint& mint = Mint::Handle();
|
| + mint ^= value.raw();
|
| + if (Smi::IsValid64(mint.value())) {
|
| + return Smi::New(mint.value());
|
| + } else {
|
| + return value.raw();
|
| + }
|
| + }
|
| + ASSERT(value.IsBigint());
|
| + Bigint& big_value = Bigint::Handle();
|
| + big_value ^= value.raw();
|
| + if (BigintOperations::FitsIntoSmi(big_value)) {
|
| + return BigintOperations::ToSmi(big_value);
|
| + } else if (BigintOperations::FitsIntoMint(big_value)) {
|
| + return Mint::New(BigintOperations::ToMint(big_value));
|
| + } else {
|
| + return big_value.raw();
|
| + }
|
| +}
|
| +
|
| +
|
| +RawInteger* Integer::BinaryOp(Token::Kind operation,
|
| + const Integer& left,
|
| + const Integer& right) {
|
| + // In 32-bit mode, the result of any operation between two Smis will fit in a
|
| + // 32-bit signed result, except the product of two Smis, which will be 64-bit.
|
| + // In 64-bit mode, the result of any operation between two Smis will fit in a
|
| + // 64-bit signed result, except the product of two Smis (unless the Smis are
|
| + // 32-bit or less).
|
| + if (left.IsSmi() && right.IsSmi()) {
|
| + Smi& left_smi = Smi::Handle();
|
| + Smi& right_smi = Smi::Handle();
|
| + left_smi ^= left.raw();
|
| + right_smi ^= right.raw();
|
| + 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: {
|
| + if (Smi::kBits < 32) {
|
| + // In 32-bit mode, the product of two Smis fits in a 64-bit result.
|
| + return Integer::New(static_cast<int64_t>(left_value) *
|
| + static_cast<int64_t>(right_value));
|
| + } else {
|
| + // In 64-bit mode, the product of two 32-bit signed integers fits in a
|
| + // 64-bit result.
|
| + ASSERT(sizeof(intptr_t) == sizeof(int64_t));
|
| + if (Utils::IsInt(32, left_value) && Utils::IsInt(32, right_value)) {
|
| + return Integer::New(left_value * right_value);
|
| + }
|
| + }
|
| + // Perform a Bigint multiplication below.
|
| + break;
|
| + }
|
| + 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);
|
| + }
|
| + }
|
| + return Integer::New(remainder);
|
| + }
|
| + default:
|
| + UNIMPLEMENTED();
|
| + }
|
| + }
|
| + // In 32-bit mode, the result of any operation between two 63-bit signed
|
| + // integers (or 32-bit for multiplication) will fit in a 64-bit signed result.
|
| + // In 64-bit mode, 63-bit signed integers are Smis, already processed above.
|
| + if ((Smi::kBits < 32) && !left.IsBigint() && !right.IsBigint()) {
|
| + const int64_t left_value = left.AsInt64Value();
|
| + if (Utils::IsInt(63, left_value)) {
|
| + const int64_t right_value = right.AsInt64Value();
|
| + if (Utils::IsInt(63, right_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: {
|
| + if (Utils::IsInt(32, left_value) && Utils::IsInt(32, right_value)) {
|
| + return Integer::New(left_value * right_value);
|
| + }
|
| + // Perform a Bigint multiplication below.
|
| + break;
|
| + }
|
| + case Token::kTRUNCDIV:
|
| + return Integer::New(left_value / right_value);
|
| + case Token::kMOD: {
|
| + const int64_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);
|
| + }
|
| + }
|
| + return Integer::New(remainder);
|
| + }
|
| + default:
|
| + UNIMPLEMENTED();
|
| + }
|
| + }
|
| + }
|
| + }
|
| + const Bigint& left_big = Bigint::Handle(Bigint::AsBigint(left));
|
| + const Bigint& right_big = Bigint::Handle(Bigint::AsBigint(right));
|
| + const Bigint& result =
|
| + Bigint::Handle(Bigint::BinaryOp(operation, left_big, right_big));
|
| + return Integer::Handle(AsInteger(result)).raw();
|
| +}
|
| +
|
| +
|
| bool Smi::Equals(const Instance& other) const {
|
| if (other.IsNull() || !other.IsSmi()) {
|
| return false;
|
| @@ -9029,6 +9154,48 @@ const char* Double::ToCString() const {
|
| }
|
|
|
|
|
| +// Returns value in form of a RawBigint.
|
| +RawBigint* Bigint::AsBigint(const Integer& value) {
|
| + ASSERT(!value.IsNull());
|
| + if (value.IsSmi()) {
|
| + Smi& smi = Smi::Handle();
|
| + smi ^= value.raw();
|
| + return BigintOperations::NewFromSmi(smi);
|
| + } else if (value.IsMint()) {
|
| + Mint& mint = Mint::Handle();
|
| + mint ^= value.raw();
|
| + return BigintOperations::NewFromInt64(mint.value());
|
| + } else {
|
| + ASSERT(value.IsBigint());
|
| + Bigint& big = Bigint::Handle();
|
| + big ^= value.raw();
|
| + ASSERT(!BigintOperations::FitsIntoSmi(big));
|
| + return big.raw();
|
| + }
|
| +}
|
| +
|
| +
|
| +RawBigint* Bigint::BinaryOp(Token::Kind operation,
|
| + const Bigint& left,
|
| + const Bigint& right) {
|
| + switch (operation) {
|
| + case Token::kADD:
|
| + return BigintOperations::Add(left, right);
|
| + case Token::kSUB:
|
| + return BigintOperations::Subtract(left, right);
|
| + case Token::kMUL:
|
| + return BigintOperations::Multiply(left, right);
|
| + case Token::kTRUNCDIV:
|
| + return BigintOperations::Divide(left, right);
|
| + case Token::kMOD:
|
| + return BigintOperations::Modulo(left, right);
|
| + default:
|
| + UNIMPLEMENTED();
|
| + return Bigint::null();
|
| + }
|
| +}
|
| +
|
| +
|
| bool Bigint::Equals(const Instance& other) const {
|
| if (this->raw() == other.raw()) {
|
| // Both handles point to the same raw instance.
|
|
|