| Index: runtime/vm/object.cc
|
| ===================================================================
|
| --- runtime/vm/object.cc (revision 43482)
|
| +++ runtime/vm/object.cc (working copy)
|
| @@ -16361,23 +16361,6 @@
|
| }
|
|
|
|
|
| -void Bigint::set_neg(const Bool& value) const {
|
| - StorePointer(&raw_ptr()->neg_, value.raw());
|
| -}
|
| -
|
| -
|
| -void Bigint::set_used(const Smi& value) const {
|
| - StoreSmi(&raw_ptr()->used_, value.raw());
|
| -}
|
| -
|
| -
|
| -void Bigint::set_digits(const TypedData& value) const {
|
| - // The VM expects digits_ to be a Uint32List (not null).
|
| - ASSERT(!value.IsNull() && (value.GetClassId() == kTypedDataUint32ArrayCid));
|
| - StorePointer(&raw_ptr()->digits_, value.raw());
|
| -}
|
| -
|
| -
|
| bool Bigint::Neg() const {
|
| return Bool::Handle(neg()).value();
|
| }
|
| @@ -16384,7 +16367,7 @@
|
|
|
|
|
| void Bigint::SetNeg(bool value) const {
|
| - set_neg(Bool::Get(value));
|
| + StorePointer(&raw_ptr()->neg_, Bool::Get(value).raw());
|
| }
|
|
|
|
|
| @@ -16394,7 +16377,7 @@
|
|
|
|
|
| void Bigint::SetUsed(intptr_t value) const {
|
| - set_used(Smi::Handle(Smi::New(value)));
|
| + StoreSmi(&raw_ptr()->used_, Smi::New(value));
|
| }
|
|
|
|
|
| @@ -16404,12 +16387,32 @@
|
| }
|
|
|
|
|
| -void Bigint::SetDigitAt(intptr_t index, uint32_t value) const {
|
| - const TypedData& typed_data = TypedData::Handle(digits());
|
| - typed_data.SetUint32(index << 2, value);
|
| +void Bigint::set_digits(const TypedData& value) const {
|
| + // The VM expects digits_ to be a Uint32List (not null).
|
| + ASSERT(!value.IsNull() && (value.GetClassId() == kTypedDataUint32ArrayCid));
|
| + StorePointer(&raw_ptr()->digits_, value.raw());
|
| }
|
|
|
|
|
| +RawTypedData* Bigint::NewDigits(intptr_t length, Heap::Space space) {
|
| + ASSERT(length > 0);
|
| + // Account for leading zero for 64-bit processing.
|
| + return TypedData::New(kTypedDataUint32ArrayCid, length + 1, space);
|
| +}
|
| +
|
| +
|
| +uint32_t Bigint::DigitAt(const TypedData& digits, intptr_t index) {
|
| + return digits.GetUint32(index << 2);
|
| +}
|
| +
|
| +
|
| +void Bigint::SetDigitAt(const TypedData& digits,
|
| + intptr_t index,
|
| + uint32_t value) {
|
| + digits.SetUint32(index << 2, value);
|
| +}
|
| +
|
| +
|
| bool Bigint::Equals(const Instance& other) const {
|
| if (this->raw() == other.raw()) {
|
| // Both handles point to the same raw instance.
|
| @@ -16468,8 +16471,8 @@
|
| NoGCScope no_gc;
|
| result ^= raw;
|
| }
|
| - result.set_neg(Bool::Get(false));
|
| - result.set_used(Smi::Handle(isolate, Smi::New(0)));
|
| + result.SetNeg(false);
|
| + result.SetUsed(0);
|
| result.set_digits(
|
| TypedData::Handle(isolate, TypedData::EmptyUint32Array(isolate)));
|
| return result.raw();
|
| @@ -16476,29 +16479,63 @@
|
| }
|
|
|
|
|
| +RawBigint* Bigint::New(bool neg, intptr_t used, const TypedData& digits,
|
| + Heap::Space space) {
|
| + ASSERT((used == 0) ||
|
| + (!digits.IsNull() && (digits.Length() >= (used + (used & 1)))));
|
| + Isolate* isolate = Isolate::Current();
|
| + ASSERT(isolate->object_store()->bigint_class() != Class::null());
|
| + Bigint& result = Bigint::Handle(isolate);
|
| + {
|
| + RawObject* raw = Object::Allocate(Bigint::kClassId,
|
| + Bigint::InstanceSize(),
|
| + space);
|
| + NoGCScope no_gc;
|
| + result ^= raw;
|
| + }
|
| + // Clamp the digits array.
|
| + while ((used > 0) && (digits.GetUint32((used - 1) << 2) == 0)) {
|
| + --used;
|
| + }
|
| + if (used > 0) {
|
| + if ((used & 1) != 0) {
|
| + // Set leading zero for 64-bit processing of digit pairs.
|
| + digits.SetUint32(used << 2, 0);
|
| + }
|
| + result.set_digits(digits);
|
| + } else {
|
| + neg = false;
|
| + result.set_digits(
|
| + TypedData::Handle(isolate, TypedData::EmptyUint32Array(isolate)));
|
| + }
|
| + result.SetNeg(neg);
|
| + result.SetUsed(used);
|
| + return result.raw();
|
| +}
|
| +
|
| +
|
| RawBigint* Bigint::NewFromInt64(int64_t value, Heap::Space space) {
|
| - const Bigint& result = Bigint::Handle(New(space));
|
| - result.EnsureLength(2, space);
|
| - result.SetUsed(2);
|
| + const TypedData& digits = TypedData::Handle(NewDigits(2, space));
|
| + bool neg;
|
| + uint64_t abs_value;
|
| if (value < 0) {
|
| - result.SetNeg(true);
|
| - value = -value; // No concern about overflow, since sign is captured.
|
| + neg = true;
|
| + abs_value = -value;
|
| + } else {
|
| + neg = false;
|
| + abs_value = value;
|
| }
|
| - result.SetDigitAt(0, static_cast<uint32_t>(value));
|
| - result.SetDigitAt(1, static_cast<uint32_t>(value >> 32)); // value >= 0.
|
| - result.Clamp();
|
| - return result.raw();
|
| + SetDigitAt(digits, 0, static_cast<uint32_t>(abs_value));
|
| + SetDigitAt(digits, 1, static_cast<uint32_t>(abs_value >> 32));
|
| + return New(neg, 2, digits, space);
|
| }
|
|
|
|
|
| RawBigint* Bigint::NewFromUint64(uint64_t value, Heap::Space space) {
|
| - const Bigint& result = Bigint::Handle(New(space));
|
| - result.EnsureLength(2, space);
|
| - result.SetUsed(2);
|
| - result.SetDigitAt(0, static_cast<uint32_t>(value));
|
| - result.SetDigitAt(1, static_cast<uint32_t>(value >> 32));
|
| - result.Clamp();
|
| - return result.raw();
|
| + const TypedData& digits = TypedData::Handle(NewDigits(2, space));
|
| + SetDigitAt(digits, 0, static_cast<uint32_t>(value));
|
| + SetDigitAt(digits, 1, static_cast<uint32_t>(value >> 32));
|
| + return New(false, 2, digits, space);
|
| }
|
|
|
|
|
| @@ -16506,95 +16543,52 @@
|
| Heap::Space space) {
|
| ASSERT(kBitsPerDigit == 32);
|
| ASSERT(shift >= 0);
|
| - const Bigint& result = Bigint::Handle(New(space));
|
| const intptr_t digit_shift = shift / kBitsPerDigit;
|
| const intptr_t bit_shift = shift % kBitsPerDigit;
|
| - result.EnsureLength(3 + digit_shift, space);
|
| - result.SetUsed(3 + digit_shift);
|
| + const intptr_t used = 3 + digit_shift;
|
| + const TypedData& digits = TypedData::Handle(NewDigits(used, space));
|
| + bool neg;
|
| uint64_t abs_value;
|
| if (value < 0) {
|
| - result.SetNeg(true);
|
| - abs_value = -value; // No concern about overflow, since sign is captured.
|
| + neg = true;
|
| + abs_value = -value;
|
| } else {
|
| + neg = false;
|
| abs_value = value;
|
| }
|
| for (intptr_t i = 0; i < digit_shift; i++) {
|
| - result.SetDigitAt(i, 0);
|
| + SetDigitAt(digits, i, 0);
|
| }
|
| - result.SetDigitAt(0 + digit_shift,
|
| - static_cast<uint32_t>(abs_value << bit_shift));
|
| - result.SetDigitAt(1 + digit_shift,
|
| - static_cast<uint32_t>(abs_value >> (32 - bit_shift)));
|
| - result.SetDigitAt(2 + digit_shift,
|
| + SetDigitAt(digits, 0 + digit_shift,
|
| + static_cast<uint32_t>(abs_value << bit_shift));
|
| + SetDigitAt(digits, 1 + digit_shift,
|
| + static_cast<uint32_t>(abs_value >> (32 - bit_shift)));
|
| + SetDigitAt(digits, 2 + digit_shift,
|
| (bit_shift == 0) ? 0
|
| : static_cast<uint32_t>(abs_value >> (64 - bit_shift)));
|
| - result.Clamp();
|
| - return result.raw();
|
| + return New(neg, used, digits, space);
|
| }
|
|
|
|
|
| -void Bigint::EnsureLength(intptr_t length, Heap::Space space) const {
|
| - ASSERT(length >= 0);
|
| - length++; // Account for leading zero for 64-bit processing.
|
| - TypedData& old_digits = TypedData::Handle(digits());
|
| - if (length > old_digits.Length()) {
|
| - TypedData& new_digits = TypedData::Handle(
|
| - TypedData::New(kTypedDataUint32ArrayCid, length + kExtraDigits, space));
|
| - set_digits(new_digits);
|
| - if (Used() > 0) {
|
| - TypedData::Copy(new_digits, TypedData::data_offset(),
|
| - old_digits, TypedData::data_offset(),
|
| - (Used() + 1)*kBytesPerDigit); // Copy leading zero.
|
| - }
|
| - }
|
| -}
|
| -
|
| -
|
| -void Bigint::Clamp() const {
|
| - intptr_t used = Used();
|
| - if (used > 0) {
|
| - if (DigitAt(used - 1) == 0) {
|
| - do {
|
| - --used;
|
| - } while ((used > 0) && (DigitAt(used - 1) == 0));
|
| - SetUsed(used);
|
| - }
|
| - SetDigitAt(used, 0); // Set leading zero for 64-bit processing.
|
| - }
|
| -}
|
| -
|
| -
|
| -bool Bigint::IsClamped() const {
|
| - intptr_t used = Used();
|
| - return (used == 0) || (DigitAt(used - 1) > 0);
|
| -}
|
| -
|
| -
|
| RawBigint* Bigint::NewFromCString(const char* str, Heap::Space space) {
|
| ASSERT(str != NULL);
|
| - // If the string starts with '-' recursively restart the whole operation
|
| - // without the character and then toggle the sign.
|
| + bool neg = false;
|
| + TypedData& digits = TypedData::Handle();
|
| if (str[0] == '-') {
|
| ASSERT(str[1] != '-');
|
| - const Bigint& result = Bigint::Handle(NewFromCString(&str[1], space));
|
| - result.SetNeg(!result.Neg()); // Toggle sign.
|
| - ASSERT(result.IsZero() || result.IsNegative());
|
| - ASSERT(result.IsClamped());
|
| - return result.raw();
|
| + neg = true;
|
| + str++;
|
| }
|
| -
|
| - // No overflow check needed since overflowing str_length implies that we take
|
| - // the branch to NewFromDecCString() which contains a check itself.
|
| + intptr_t used;
|
| const intptr_t str_length = strlen(str);
|
| if ((str_length >= 2) &&
|
| (str[0] == '0') &&
|
| ((str[1] == 'x') || (str[1] == 'X'))) {
|
| - const Bigint& result = Bigint::Handle(NewFromHexCString(&str[2], space));
|
| - ASSERT(result.IsClamped());
|
| - return result.raw();
|
| + digits = NewDigitsFromHexCString(&str[2], &used, space);
|
| } else {
|
| - return NewFromDecCString(str, space);
|
| + digits = NewDigitsFromDecCString(str, &used, space);
|
| }
|
| + return New(neg, used, digits, space);
|
| }
|
|
|
|
|
| @@ -16627,28 +16621,17 @@
|
| }
|
|
|
|
|
| -RawBigint* Bigint::NewFromHexCString(const char* str, Heap::Space space) {
|
| - // If the string starts with '-' recursively restart the whole operation
|
| - // without the character and then toggle the sign.
|
| - if (str[0] == '-') {
|
| - ASSERT(str[1] != '-');
|
| - const Bigint& result = Bigint::Handle(NewFromHexCString(&str[1], space));
|
| - if (!result.IsZero()) {
|
| - result.SetNeg(!result.Neg()); // Toggle sign.
|
| - }
|
| - ASSERT(result.IsClamped());
|
| - return result.raw();
|
| - }
|
| - const Bigint& result = Bigint::Handle(New(space));
|
| +RawTypedData* Bigint::NewDigitsFromHexCString(const char* str, intptr_t* used,
|
| + Heap::Space space) {
|
| const int kBitsPerHexDigit = 4;
|
| const int kHexDigitsPerDigit = 8;
|
| const int kBitsPerDigit = kBitsPerHexDigit * kHexDigitsPerDigit;
|
| intptr_t hex_i = strlen(str); // Terminating byte excluded.
|
| if ((hex_i <= 0) || (hex_i >= kMaxInt32)) {
|
| - FATAL("Fatal error in Bigint::NewFromHexCString: string too long or empty");
|
| + FATAL("Fatal error parsing hex bigint: string too long or empty");
|
| }
|
| - result.EnsureLength((hex_i + kHexDigitsPerDigit - 1) / kHexDigitsPerDigit,
|
| - space);
|
| + const intptr_t length = (hex_i + kHexDigitsPerDigit - 1) / kHexDigitsPerDigit;
|
| + const TypedData& digits = TypedData::Handle(NewDigits(length, space));
|
| intptr_t used_ = 0;
|
| uint32_t digit = 0;
|
| intptr_t bit_i = 0;
|
| @@ -16657,53 +16640,48 @@
|
| bit_i += kBitsPerHexDigit;
|
| if (bit_i == kBitsPerDigit) {
|
| bit_i = 0;
|
| - result.SetDigitAt(used_++, digit);
|
| + SetDigitAt(digits, used_++, digit);
|
| digit = 0;
|
| }
|
| }
|
| if (bit_i != 0) {
|
| - result.SetDigitAt(used_++, digit);
|
| + SetDigitAt(digits, used_++, digit);
|
| }
|
| - result.SetUsed(used_);
|
| - result.Clamp();
|
| - return result.raw();
|
| + *used = used_;
|
| + return digits.raw();
|
| }
|
|
|
|
|
| -RawBigint* Bigint::NewFromDecCString(const char* str, Heap::Space space) {
|
| +RawTypedData* Bigint::NewDigitsFromDecCString(const char* str, intptr_t* used,
|
| + Heap::Space space) {
|
| // Read 9 digits a time. 10^9 < 2^32.
|
| const int kDecDigitsPerIteration = 9;
|
| const uint32_t kTenMultiplier = 1000000000;
|
| ASSERT(kBitsPerDigit == 32);
|
| -
|
| const intptr_t str_length = strlen(str);
|
| if ((str_length <= 0) || (str_length >= kMaxInt32)) {
|
| - FATAL("Fatal error in Bigint::NewFromDecCString: string too long or empty");
|
| + FATAL("Fatal error parsing dec bigint: string too long or empty");
|
| }
|
| - intptr_t str_pos = 0;
|
| -
|
| - Bigint& result = Bigint::Handle(Bigint::New(space));
|
| // One decimal digit takes log2(10) bits, i.e. ~3.32192809489 bits.
|
| // That is a theoretical limit for large numbers.
|
| - // The extra digits allocated take care of variations (kExtraDigits).
|
| + // The extra 5 digits allocated take care of variations.
|
| const int64_t kLog10Dividend = 33219281;
|
| const int64_t kLog10Divisor = 10000000;
|
| -
|
| - result.EnsureLength((kLog10Dividend * str_length) /
|
| - (kLog10Divisor * kBitsPerDigit) + 1, space);
|
| -
|
| + const intptr_t length = (kLog10Dividend * str_length) /
|
| + (kLog10Divisor * kBitsPerDigit) + 5;
|
| + const TypedData& digits = TypedData::Handle(NewDigits(length, space));
|
| // Read first digit separately. This avoids a multiplication and addition.
|
| // The first digit might also not have kDecDigitsPerIteration decimal digits.
|
| const intptr_t lsdigit_length = str_length % kDecDigitsPerIteration;
|
| uint32_t digit = 0;
|
| + intptr_t str_pos = 0;
|
| for (intptr_t i = 0; i < lsdigit_length; i++) {
|
| char c = str[str_pos++];
|
| ASSERT(('0' <= c) && (c <= '9'));
|
| digit = digit * 10 + c - '0';
|
| }
|
| - result.SetDigitAt(0, digit);
|
| - intptr_t used = 1;
|
| -
|
| + SetDigitAt(digits, 0, digit);
|
| + intptr_t used_ = 1;
|
| // Read kDecDigitsPerIteration at a time, and store it in 'digit'.
|
| // Then multiply the temporary result by 10^kDecDigitsPerIteration and add
|
| // 'digit' to the new result.
|
| @@ -16715,17 +16693,16 @@
|
| digit = digit * 10 + c - '0';
|
| }
|
| // Multiply result with kTenMultiplier and add digit.
|
| - for (intptr_t i = 0; i < used; i++) {
|
| + for (intptr_t i = 0; i < used_; i++) {
|
| uint64_t product =
|
| - (static_cast<uint64_t>(result.DigitAt(i)) * kTenMultiplier) + digit;
|
| - result.SetDigitAt(i, static_cast<uint32_t>(product & kDigitMask));
|
| + (static_cast<uint64_t>(DigitAt(digits, i)) * kTenMultiplier) + digit;
|
| + SetDigitAt(digits, i, static_cast<uint32_t>(product & kDigitMask));
|
| digit = static_cast<uint32_t>(product >> kBitsPerDigit);
|
| }
|
| - result.SetDigitAt(used++, digit);
|
| + SetDigitAt(digits, used_++, digit);
|
| }
|
| - result.SetUsed(used);
|
| - result.Clamp();
|
| - return result.raw();
|
| + *used = used_;
|
| + return digits.raw();
|
| }
|
|
|
|
|
| @@ -16775,7 +16752,6 @@
|
|
|
| double Bigint::AsDoubleValue() const {
|
| ASSERT(kBitsPerDigit == 32);
|
| - ASSERT(IsClamped());
|
| const intptr_t used = Used();
|
| if (used == 0) {
|
| return 0.0;
|
|
|