OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 #include "vm/object.h" | 5 #include "vm/object.h" |
6 | 6 |
7 #include "include/dart_api.h" | 7 #include "include/dart_api.h" |
8 #include "platform/assert.h" | 8 #include "platform/assert.h" |
9 #include "vm/assembler.h" | 9 #include "vm/assembler.h" |
10 #include "vm/cpu.h" | 10 #include "vm/cpu.h" |
(...skipping 16343 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
16354 // "Double". Return "double" instead. | 16354 // "Double". Return "double" instead. |
16355 AddTypeProperties(&jsobj, "double", "double", ref); | 16355 AddTypeProperties(&jsobj, "double", "double", ref); |
16356 PrintSharedInstanceJSON(&jsobj, ref); | 16356 PrintSharedInstanceJSON(&jsobj, ref); |
16357 ObjectIdRing* ring = Isolate::Current()->object_id_ring(); | 16357 ObjectIdRing* ring = Isolate::Current()->object_id_ring(); |
16358 const intptr_t id = ring->GetIdForObject(raw()); | 16358 const intptr_t id = ring->GetIdForObject(raw()); |
16359 jsobj.AddPropertyF("id", "objects/%" Pd "", id); | 16359 jsobj.AddPropertyF("id", "objects/%" Pd "", id); |
16360 jsobj.AddProperty("valueAsString", ToCString()); | 16360 jsobj.AddProperty("valueAsString", ToCString()); |
16361 } | 16361 } |
16362 | 16362 |
16363 | 16363 |
16364 void Bigint::set_neg(const Bool& value) const { | |
16365 StorePointer(&raw_ptr()->neg_, value.raw()); | |
16366 } | |
16367 | |
16368 | |
16369 void Bigint::set_used(const Smi& value) const { | |
16370 StoreSmi(&raw_ptr()->used_, value.raw()); | |
16371 } | |
16372 | |
16373 | |
16374 void Bigint::set_digits(const TypedData& value) const { | |
16375 // The VM expects digits_ to be a Uint32List (not null). | |
16376 ASSERT(!value.IsNull() && (value.GetClassId() == kTypedDataUint32ArrayCid)); | |
16377 StorePointer(&raw_ptr()->digits_, value.raw()); | |
16378 } | |
16379 | |
16380 | |
16381 bool Bigint::Neg() const { | 16364 bool Bigint::Neg() const { |
16382 return Bool::Handle(neg()).value(); | 16365 return Bool::Handle(neg()).value(); |
16383 } | 16366 } |
16384 | 16367 |
16385 | 16368 |
16386 void Bigint::SetNeg(bool value) const { | 16369 void Bigint::SetNeg(bool value) const { |
16387 set_neg(Bool::Get(value)); | 16370 StorePointer(&raw_ptr()->neg_, Bool::Get(value).raw()); |
16388 } | 16371 } |
16389 | 16372 |
16390 | 16373 |
16391 intptr_t Bigint::Used() const { | 16374 intptr_t Bigint::Used() const { |
16392 return Smi::Value(used()); | 16375 return Smi::Value(used()); |
16393 } | 16376 } |
16394 | 16377 |
16395 | 16378 |
16396 void Bigint::SetUsed(intptr_t value) const { | 16379 void Bigint::SetUsed(intptr_t value) const { |
16397 set_used(Smi::Handle(Smi::New(value))); | 16380 StoreSmi(&raw_ptr()->used_, Smi::New(value)); |
16398 } | 16381 } |
16399 | 16382 |
16400 | 16383 |
16401 uint32_t Bigint::DigitAt(intptr_t index) const { | 16384 uint32_t Bigint::DigitAt(intptr_t index) const { |
16402 const TypedData& typed_data = TypedData::Handle(digits()); | 16385 const TypedData& typed_data = TypedData::Handle(digits()); |
16403 return typed_data.GetUint32(index << 2); | 16386 return typed_data.GetUint32(index << 2); |
16404 } | 16387 } |
16405 | 16388 |
16406 | 16389 |
16407 void Bigint::SetDigitAt(intptr_t index, uint32_t value) const { | 16390 void Bigint::set_digits(const TypedData& value) const { |
16408 const TypedData& typed_data = TypedData::Handle(digits()); | 16391 // The VM expects digits_ to be a Uint32List (not null). |
16409 typed_data.SetUint32(index << 2, value); | 16392 ASSERT(!value.IsNull() && (value.GetClassId() == kTypedDataUint32ArrayCid)); |
| 16393 StorePointer(&raw_ptr()->digits_, value.raw()); |
| 16394 } |
| 16395 |
| 16396 |
| 16397 RawTypedData* Bigint::NewDigits(intptr_t length, Heap::Space space) { |
| 16398 ASSERT(length > 0); |
| 16399 // Account for leading zero for 64-bit processing. |
| 16400 return TypedData::New(kTypedDataUint32ArrayCid, length + 1, space); |
| 16401 } |
| 16402 |
| 16403 |
| 16404 uint32_t Bigint::DigitAt(const TypedData& digits, intptr_t index) { |
| 16405 return digits.GetUint32(index << 2); |
| 16406 } |
| 16407 |
| 16408 |
| 16409 void Bigint::SetDigitAt(const TypedData& digits, |
| 16410 intptr_t index, |
| 16411 uint32_t value) { |
| 16412 digits.SetUint32(index << 2, value); |
16410 } | 16413 } |
16411 | 16414 |
16412 | 16415 |
16413 bool Bigint::Equals(const Instance& other) const { | 16416 bool Bigint::Equals(const Instance& other) const { |
16414 if (this->raw() == other.raw()) { | 16417 if (this->raw() == other.raw()) { |
16415 // Both handles point to the same raw instance. | 16418 // Both handles point to the same raw instance. |
16416 return true; | 16419 return true; |
16417 } | 16420 } |
16418 | 16421 |
16419 if (!other.IsBigint() || other.IsNull()) { | 16422 if (!other.IsBigint() || other.IsNull()) { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
16461 Isolate* isolate = Isolate::Current(); | 16464 Isolate* isolate = Isolate::Current(); |
16462 ASSERT(isolate->object_store()->bigint_class() != Class::null()); | 16465 ASSERT(isolate->object_store()->bigint_class() != Class::null()); |
16463 Bigint& result = Bigint::Handle(isolate); | 16466 Bigint& result = Bigint::Handle(isolate); |
16464 { | 16467 { |
16465 RawObject* raw = Object::Allocate(Bigint::kClassId, | 16468 RawObject* raw = Object::Allocate(Bigint::kClassId, |
16466 Bigint::InstanceSize(), | 16469 Bigint::InstanceSize(), |
16467 space); | 16470 space); |
16468 NoGCScope no_gc; | 16471 NoGCScope no_gc; |
16469 result ^= raw; | 16472 result ^= raw; |
16470 } | 16473 } |
16471 result.set_neg(Bool::Get(false)); | 16474 result.SetNeg(false); |
16472 result.set_used(Smi::Handle(isolate, Smi::New(0))); | 16475 result.SetUsed(0); |
16473 result.set_digits( | 16476 result.set_digits( |
16474 TypedData::Handle(isolate, TypedData::EmptyUint32Array(isolate))); | 16477 TypedData::Handle(isolate, TypedData::EmptyUint32Array(isolate))); |
16475 return result.raw(); | 16478 return result.raw(); |
16476 } | 16479 } |
16477 | 16480 |
16478 | 16481 |
| 16482 RawBigint* Bigint::New(bool neg, intptr_t used, const TypedData& digits, |
| 16483 Heap::Space space) { |
| 16484 ASSERT((used == 0) || |
| 16485 (!digits.IsNull() && (digits.Length() >= (used + (used & 1))))); |
| 16486 Isolate* isolate = Isolate::Current(); |
| 16487 ASSERT(isolate->object_store()->bigint_class() != Class::null()); |
| 16488 Bigint& result = Bigint::Handle(isolate); |
| 16489 { |
| 16490 RawObject* raw = Object::Allocate(Bigint::kClassId, |
| 16491 Bigint::InstanceSize(), |
| 16492 space); |
| 16493 NoGCScope no_gc; |
| 16494 result ^= raw; |
| 16495 } |
| 16496 // Clamp the digits array. |
| 16497 while ((used > 0) && (digits.GetUint32((used - 1) << 2) == 0)) { |
| 16498 --used; |
| 16499 } |
| 16500 if (used > 0) { |
| 16501 if ((used & 1) != 0) { |
| 16502 // Set leading zero for 64-bit processing of digit pairs. |
| 16503 digits.SetUint32(used << 2, 0); |
| 16504 } |
| 16505 result.set_digits(digits); |
| 16506 } else { |
| 16507 neg = false; |
| 16508 result.set_digits( |
| 16509 TypedData::Handle(isolate, TypedData::EmptyUint32Array(isolate))); |
| 16510 } |
| 16511 result.SetNeg(neg); |
| 16512 result.SetUsed(used); |
| 16513 return result.raw(); |
| 16514 } |
| 16515 |
| 16516 |
16479 RawBigint* Bigint::NewFromInt64(int64_t value, Heap::Space space) { | 16517 RawBigint* Bigint::NewFromInt64(int64_t value, Heap::Space space) { |
16480 const Bigint& result = Bigint::Handle(New(space)); | 16518 const TypedData& digits = TypedData::Handle(NewDigits(2, space)); |
16481 result.EnsureLength(2, space); | 16519 bool neg; |
16482 result.SetUsed(2); | 16520 uint64_t abs_value; |
16483 if (value < 0) { | 16521 if (value < 0) { |
16484 result.SetNeg(true); | 16522 neg = true; |
16485 value = -value; // No concern about overflow, since sign is captured. | 16523 abs_value = -value; |
| 16524 } else { |
| 16525 neg = false; |
| 16526 abs_value = value; |
16486 } | 16527 } |
16487 result.SetDigitAt(0, static_cast<uint32_t>(value)); | 16528 SetDigitAt(digits, 0, static_cast<uint32_t>(abs_value)); |
16488 result.SetDigitAt(1, static_cast<uint32_t>(value >> 32)); // value >= 0. | 16529 SetDigitAt(digits, 1, static_cast<uint32_t>(abs_value >> 32)); |
16489 result.Clamp(); | 16530 return New(neg, 2, digits, space); |
16490 return result.raw(); | |
16491 } | 16531 } |
16492 | 16532 |
16493 | 16533 |
16494 RawBigint* Bigint::NewFromUint64(uint64_t value, Heap::Space space) { | 16534 RawBigint* Bigint::NewFromUint64(uint64_t value, Heap::Space space) { |
16495 const Bigint& result = Bigint::Handle(New(space)); | 16535 const TypedData& digits = TypedData::Handle(NewDigits(2, space)); |
16496 result.EnsureLength(2, space); | 16536 SetDigitAt(digits, 0, static_cast<uint32_t>(value)); |
16497 result.SetUsed(2); | 16537 SetDigitAt(digits, 1, static_cast<uint32_t>(value >> 32)); |
16498 result.SetDigitAt(0, static_cast<uint32_t>(value)); | 16538 return New(false, 2, digits, space); |
16499 result.SetDigitAt(1, static_cast<uint32_t>(value >> 32)); | |
16500 result.Clamp(); | |
16501 return result.raw(); | |
16502 } | 16539 } |
16503 | 16540 |
16504 | 16541 |
16505 RawBigint* Bigint::NewFromShiftedInt64(int64_t value, intptr_t shift, | 16542 RawBigint* Bigint::NewFromShiftedInt64(int64_t value, intptr_t shift, |
16506 Heap::Space space) { | 16543 Heap::Space space) { |
16507 ASSERT(kBitsPerDigit == 32); | 16544 ASSERT(kBitsPerDigit == 32); |
16508 ASSERT(shift >= 0); | 16545 ASSERT(shift >= 0); |
16509 const Bigint& result = Bigint::Handle(New(space)); | |
16510 const intptr_t digit_shift = shift / kBitsPerDigit; | 16546 const intptr_t digit_shift = shift / kBitsPerDigit; |
16511 const intptr_t bit_shift = shift % kBitsPerDigit; | 16547 const intptr_t bit_shift = shift % kBitsPerDigit; |
16512 result.EnsureLength(3 + digit_shift, space); | 16548 const intptr_t used = 3 + digit_shift; |
16513 result.SetUsed(3 + digit_shift); | 16549 const TypedData& digits = TypedData::Handle(NewDigits(used, space)); |
| 16550 bool neg; |
16514 uint64_t abs_value; | 16551 uint64_t abs_value; |
16515 if (value < 0) { | 16552 if (value < 0) { |
16516 result.SetNeg(true); | 16553 neg = true; |
16517 abs_value = -value; // No concern about overflow, since sign is captured. | 16554 abs_value = -value; |
16518 } else { | 16555 } else { |
| 16556 neg = false; |
16519 abs_value = value; | 16557 abs_value = value; |
16520 } | 16558 } |
16521 for (intptr_t i = 0; i < digit_shift; i++) { | 16559 for (intptr_t i = 0; i < digit_shift; i++) { |
16522 result.SetDigitAt(i, 0); | 16560 SetDigitAt(digits, i, 0); |
16523 } | 16561 } |
16524 result.SetDigitAt(0 + digit_shift, | 16562 SetDigitAt(digits, 0 + digit_shift, |
16525 static_cast<uint32_t>(abs_value << bit_shift)); | 16563 static_cast<uint32_t>(abs_value << bit_shift)); |
16526 result.SetDigitAt(1 + digit_shift, | 16564 SetDigitAt(digits, 1 + digit_shift, |
16527 static_cast<uint32_t>(abs_value >> (32 - bit_shift))); | 16565 static_cast<uint32_t>(abs_value >> (32 - bit_shift))); |
16528 result.SetDigitAt(2 + digit_shift, | 16566 SetDigitAt(digits, 2 + digit_shift, |
16529 (bit_shift == 0) ? 0 | 16567 (bit_shift == 0) ? 0 |
16530 : static_cast<uint32_t>(abs_value >> (64 - bit_shift))); | 16568 : static_cast<uint32_t>(abs_value >> (64 - bit_shift))); |
16531 result.Clamp(); | 16569 return New(neg, used, digits, space); |
16532 return result.raw(); | |
16533 } | |
16534 | |
16535 | |
16536 void Bigint::EnsureLength(intptr_t length, Heap::Space space) const { | |
16537 ASSERT(length >= 0); | |
16538 length++; // Account for leading zero for 64-bit processing. | |
16539 TypedData& old_digits = TypedData::Handle(digits()); | |
16540 if (length > old_digits.Length()) { | |
16541 TypedData& new_digits = TypedData::Handle( | |
16542 TypedData::New(kTypedDataUint32ArrayCid, length + kExtraDigits, space)); | |
16543 set_digits(new_digits); | |
16544 if (Used() > 0) { | |
16545 TypedData::Copy(new_digits, TypedData::data_offset(), | |
16546 old_digits, TypedData::data_offset(), | |
16547 (Used() + 1)*kBytesPerDigit); // Copy leading zero. | |
16548 } | |
16549 } | |
16550 } | |
16551 | |
16552 | |
16553 void Bigint::Clamp() const { | |
16554 intptr_t used = Used(); | |
16555 if (used > 0) { | |
16556 if (DigitAt(used - 1) == 0) { | |
16557 do { | |
16558 --used; | |
16559 } while ((used > 0) && (DigitAt(used - 1) == 0)); | |
16560 SetUsed(used); | |
16561 } | |
16562 SetDigitAt(used, 0); // Set leading zero for 64-bit processing. | |
16563 } | |
16564 } | |
16565 | |
16566 | |
16567 bool Bigint::IsClamped() const { | |
16568 intptr_t used = Used(); | |
16569 return (used == 0) || (DigitAt(used - 1) > 0); | |
16570 } | 16570 } |
16571 | 16571 |
16572 | 16572 |
16573 RawBigint* Bigint::NewFromCString(const char* str, Heap::Space space) { | 16573 RawBigint* Bigint::NewFromCString(const char* str, Heap::Space space) { |
16574 ASSERT(str != NULL); | 16574 ASSERT(str != NULL); |
16575 // If the string starts with '-' recursively restart the whole operation | 16575 bool neg = false; |
16576 // without the character and then toggle the sign. | 16576 TypedData& digits = TypedData::Handle(); |
16577 if (str[0] == '-') { | 16577 if (str[0] == '-') { |
16578 ASSERT(str[1] != '-'); | 16578 ASSERT(str[1] != '-'); |
16579 const Bigint& result = Bigint::Handle(NewFromCString(&str[1], space)); | 16579 neg = true; |
16580 result.SetNeg(!result.Neg()); // Toggle sign. | 16580 str++; |
16581 ASSERT(result.IsZero() || result.IsNegative()); | |
16582 ASSERT(result.IsClamped()); | |
16583 return result.raw(); | |
16584 } | 16581 } |
16585 | 16582 intptr_t used; |
16586 // No overflow check needed since overflowing str_length implies that we take | |
16587 // the branch to NewFromDecCString() which contains a check itself. | |
16588 const intptr_t str_length = strlen(str); | 16583 const intptr_t str_length = strlen(str); |
16589 if ((str_length >= 2) && | 16584 if ((str_length >= 2) && |
16590 (str[0] == '0') && | 16585 (str[0] == '0') && |
16591 ((str[1] == 'x') || (str[1] == 'X'))) { | 16586 ((str[1] == 'x') || (str[1] == 'X'))) { |
16592 const Bigint& result = Bigint::Handle(NewFromHexCString(&str[2], space)); | 16587 digits = NewDigitsFromHexCString(&str[2], &used, space); |
16593 ASSERT(result.IsClamped()); | |
16594 return result.raw(); | |
16595 } else { | 16588 } else { |
16596 return NewFromDecCString(str, space); | 16589 digits = NewDigitsFromDecCString(str, &used, space); |
16597 } | 16590 } |
| 16591 return New(neg, used, digits, space); |
16598 } | 16592 } |
16599 | 16593 |
16600 | 16594 |
16601 RawBigint* Bigint::NewCanonical(const String& str) { | 16595 RawBigint* Bigint::NewCanonical(const String& str) { |
16602 const Bigint& value = Bigint::Handle( | 16596 const Bigint& value = Bigint::Handle( |
16603 Bigint::NewFromCString(str.ToCString(), Heap::kOld)); | 16597 Bigint::NewFromCString(str.ToCString(), Heap::kOld)); |
16604 const Class& cls = | 16598 const Class& cls = |
16605 Class::Handle(Isolate::Current()->object_store()->bigint_class()); | 16599 Class::Handle(Isolate::Current()->object_store()->bigint_class()); |
16606 const Array& constants = Array::Handle(cls.constants()); | 16600 const Array& constants = Array::Handle(cls.constants()); |
16607 const intptr_t constants_len = constants.Length(); | 16601 const intptr_t constants_len = constants.Length(); |
(...skipping 12 matching lines...) Expand all Loading... |
16620 index++; | 16614 index++; |
16621 } | 16615 } |
16622 // The value needs to be added to the constants list. Grow the list if | 16616 // The value needs to be added to the constants list. Grow the list if |
16623 // it is full. | 16617 // it is full. |
16624 cls.InsertCanonicalConstant(index, value); | 16618 cls.InsertCanonicalConstant(index, value); |
16625 value.SetCanonical(); | 16619 value.SetCanonical(); |
16626 return value.raw(); | 16620 return value.raw(); |
16627 } | 16621 } |
16628 | 16622 |
16629 | 16623 |
16630 RawBigint* Bigint::NewFromHexCString(const char* str, Heap::Space space) { | 16624 RawTypedData* Bigint::NewDigitsFromHexCString(const char* str, intptr_t* used, |
16631 // If the string starts with '-' recursively restart the whole operation | 16625 Heap::Space space) { |
16632 // without the character and then toggle the sign. | |
16633 if (str[0] == '-') { | |
16634 ASSERT(str[1] != '-'); | |
16635 const Bigint& result = Bigint::Handle(NewFromHexCString(&str[1], space)); | |
16636 if (!result.IsZero()) { | |
16637 result.SetNeg(!result.Neg()); // Toggle sign. | |
16638 } | |
16639 ASSERT(result.IsClamped()); | |
16640 return result.raw(); | |
16641 } | |
16642 const Bigint& result = Bigint::Handle(New(space)); | |
16643 const int kBitsPerHexDigit = 4; | 16626 const int kBitsPerHexDigit = 4; |
16644 const int kHexDigitsPerDigit = 8; | 16627 const int kHexDigitsPerDigit = 8; |
16645 const int kBitsPerDigit = kBitsPerHexDigit * kHexDigitsPerDigit; | 16628 const int kBitsPerDigit = kBitsPerHexDigit * kHexDigitsPerDigit; |
16646 intptr_t hex_i = strlen(str); // Terminating byte excluded. | 16629 intptr_t hex_i = strlen(str); // Terminating byte excluded. |
16647 if ((hex_i <= 0) || (hex_i >= kMaxInt32)) { | 16630 if ((hex_i <= 0) || (hex_i >= kMaxInt32)) { |
16648 FATAL("Fatal error in Bigint::NewFromHexCString: string too long or empty"); | 16631 FATAL("Fatal error parsing hex bigint: string too long or empty"); |
16649 } | 16632 } |
16650 result.EnsureLength((hex_i + kHexDigitsPerDigit - 1) / kHexDigitsPerDigit, | 16633 const intptr_t length = (hex_i + kHexDigitsPerDigit - 1) / kHexDigitsPerDigit; |
16651 space); | 16634 const TypedData& digits = TypedData::Handle(NewDigits(length, space)); |
16652 intptr_t used_ = 0; | 16635 intptr_t used_ = 0; |
16653 uint32_t digit = 0; | 16636 uint32_t digit = 0; |
16654 intptr_t bit_i = 0; | 16637 intptr_t bit_i = 0; |
16655 while (--hex_i >= 0) { | 16638 while (--hex_i >= 0) { |
16656 digit += Utils::HexDigitToInt(str[hex_i]) << bit_i; | 16639 digit += Utils::HexDigitToInt(str[hex_i]) << bit_i; |
16657 bit_i += kBitsPerHexDigit; | 16640 bit_i += kBitsPerHexDigit; |
16658 if (bit_i == kBitsPerDigit) { | 16641 if (bit_i == kBitsPerDigit) { |
16659 bit_i = 0; | 16642 bit_i = 0; |
16660 result.SetDigitAt(used_++, digit); | 16643 SetDigitAt(digits, used_++, digit); |
16661 digit = 0; | 16644 digit = 0; |
16662 } | 16645 } |
16663 } | 16646 } |
16664 if (bit_i != 0) { | 16647 if (bit_i != 0) { |
16665 result.SetDigitAt(used_++, digit); | 16648 SetDigitAt(digits, used_++, digit); |
16666 } | 16649 } |
16667 result.SetUsed(used_); | 16650 *used = used_; |
16668 result.Clamp(); | 16651 return digits.raw(); |
16669 return result.raw(); | |
16670 } | 16652 } |
16671 | 16653 |
16672 | 16654 |
16673 RawBigint* Bigint::NewFromDecCString(const char* str, Heap::Space space) { | 16655 RawTypedData* Bigint::NewDigitsFromDecCString(const char* str, intptr_t* used, |
| 16656 Heap::Space space) { |
16674 // Read 9 digits a time. 10^9 < 2^32. | 16657 // Read 9 digits a time. 10^9 < 2^32. |
16675 const int kDecDigitsPerIteration = 9; | 16658 const int kDecDigitsPerIteration = 9; |
16676 const uint32_t kTenMultiplier = 1000000000; | 16659 const uint32_t kTenMultiplier = 1000000000; |
16677 ASSERT(kBitsPerDigit == 32); | 16660 ASSERT(kBitsPerDigit == 32); |
16678 | |
16679 const intptr_t str_length = strlen(str); | 16661 const intptr_t str_length = strlen(str); |
16680 if ((str_length <= 0) || (str_length >= kMaxInt32)) { | 16662 if ((str_length <= 0) || (str_length >= kMaxInt32)) { |
16681 FATAL("Fatal error in Bigint::NewFromDecCString: string too long or empty"); | 16663 FATAL("Fatal error parsing dec bigint: string too long or empty"); |
16682 } | 16664 } |
16683 intptr_t str_pos = 0; | |
16684 | |
16685 Bigint& result = Bigint::Handle(Bigint::New(space)); | |
16686 // One decimal digit takes log2(10) bits, i.e. ~3.32192809489 bits. | 16665 // One decimal digit takes log2(10) bits, i.e. ~3.32192809489 bits. |
16687 // That is a theoretical limit for large numbers. | 16666 // That is a theoretical limit for large numbers. |
16688 // The extra digits allocated take care of variations (kExtraDigits). | 16667 // The extra 5 digits allocated take care of variations. |
16689 const int64_t kLog10Dividend = 33219281; | 16668 const int64_t kLog10Dividend = 33219281; |
16690 const int64_t kLog10Divisor = 10000000; | 16669 const int64_t kLog10Divisor = 10000000; |
16691 | 16670 const intptr_t length = (kLog10Dividend * str_length) / |
16692 result.EnsureLength((kLog10Dividend * str_length) / | 16671 (kLog10Divisor * kBitsPerDigit) + 5; |
16693 (kLog10Divisor * kBitsPerDigit) + 1, space); | 16672 const TypedData& digits = TypedData::Handle(NewDigits(length, space)); |
16694 | |
16695 // Read first digit separately. This avoids a multiplication and addition. | 16673 // Read first digit separately. This avoids a multiplication and addition. |
16696 // The first digit might also not have kDecDigitsPerIteration decimal digits. | 16674 // The first digit might also not have kDecDigitsPerIteration decimal digits. |
16697 const intptr_t lsdigit_length = str_length % kDecDigitsPerIteration; | 16675 const intptr_t lsdigit_length = str_length % kDecDigitsPerIteration; |
16698 uint32_t digit = 0; | 16676 uint32_t digit = 0; |
| 16677 intptr_t str_pos = 0; |
16699 for (intptr_t i = 0; i < lsdigit_length; i++) { | 16678 for (intptr_t i = 0; i < lsdigit_length; i++) { |
16700 char c = str[str_pos++]; | 16679 char c = str[str_pos++]; |
16701 ASSERT(('0' <= c) && (c <= '9')); | 16680 ASSERT(('0' <= c) && (c <= '9')); |
16702 digit = digit * 10 + c - '0'; | 16681 digit = digit * 10 + c - '0'; |
16703 } | 16682 } |
16704 result.SetDigitAt(0, digit); | 16683 SetDigitAt(digits, 0, digit); |
16705 intptr_t used = 1; | 16684 intptr_t used_ = 1; |
16706 | |
16707 // Read kDecDigitsPerIteration at a time, and store it in 'digit'. | 16685 // Read kDecDigitsPerIteration at a time, and store it in 'digit'. |
16708 // Then multiply the temporary result by 10^kDecDigitsPerIteration and add | 16686 // Then multiply the temporary result by 10^kDecDigitsPerIteration and add |
16709 // 'digit' to the new result. | 16687 // 'digit' to the new result. |
16710 while (str_pos < str_length - 1) { | 16688 while (str_pos < str_length - 1) { |
16711 digit = 0; | 16689 digit = 0; |
16712 for (intptr_t i = 0; i < kDecDigitsPerIteration; i++) { | 16690 for (intptr_t i = 0; i < kDecDigitsPerIteration; i++) { |
16713 char c = str[str_pos++]; | 16691 char c = str[str_pos++]; |
16714 ASSERT(('0' <= c) && (c <= '9')); | 16692 ASSERT(('0' <= c) && (c <= '9')); |
16715 digit = digit * 10 + c - '0'; | 16693 digit = digit * 10 + c - '0'; |
16716 } | 16694 } |
16717 // Multiply result with kTenMultiplier and add digit. | 16695 // Multiply result with kTenMultiplier and add digit. |
16718 for (intptr_t i = 0; i < used; i++) { | 16696 for (intptr_t i = 0; i < used_; i++) { |
16719 uint64_t product = | 16697 uint64_t product = |
16720 (static_cast<uint64_t>(result.DigitAt(i)) * kTenMultiplier) + digit; | 16698 (static_cast<uint64_t>(DigitAt(digits, i)) * kTenMultiplier) + digit; |
16721 result.SetDigitAt(i, static_cast<uint32_t>(product & kDigitMask)); | 16699 SetDigitAt(digits, i, static_cast<uint32_t>(product & kDigitMask)); |
16722 digit = static_cast<uint32_t>(product >> kBitsPerDigit); | 16700 digit = static_cast<uint32_t>(product >> kBitsPerDigit); |
16723 } | 16701 } |
16724 result.SetDigitAt(used++, digit); | 16702 SetDigitAt(digits, used_++, digit); |
16725 } | 16703 } |
16726 result.SetUsed(used); | 16704 *used = used_; |
16727 result.Clamp(); | 16705 return digits.raw(); |
16728 return result.raw(); | |
16729 } | 16706 } |
16730 | 16707 |
16731 | 16708 |
16732 static double Uint64ToDouble(uint64_t x) { | 16709 static double Uint64ToDouble(uint64_t x) { |
16733 #if _WIN64 | 16710 #if _WIN64 |
16734 // For static_cast<double>(x) MSVC x64 generates | 16711 // For static_cast<double>(x) MSVC x64 generates |
16735 // | 16712 // |
16736 // cvtsi2sd xmm0, rax | 16713 // cvtsi2sd xmm0, rax |
16737 // test rax, rax | 16714 // test rax, rax |
16738 // jns done | 16715 // jns done |
(...skipping 29 matching lines...) Expand all Loading... |
16768 return half + half; | 16745 return half + half; |
16769 } | 16746 } |
16770 #else | 16747 #else |
16771 return static_cast<double>(x); | 16748 return static_cast<double>(x); |
16772 #endif | 16749 #endif |
16773 } | 16750 } |
16774 | 16751 |
16775 | 16752 |
16776 double Bigint::AsDoubleValue() const { | 16753 double Bigint::AsDoubleValue() const { |
16777 ASSERT(kBitsPerDigit == 32); | 16754 ASSERT(kBitsPerDigit == 32); |
16778 ASSERT(IsClamped()); | |
16779 const intptr_t used = Used(); | 16755 const intptr_t used = Used(); |
16780 if (used == 0) { | 16756 if (used == 0) { |
16781 return 0.0; | 16757 return 0.0; |
16782 } | 16758 } |
16783 if (used <= 2) { | 16759 if (used <= 2) { |
16784 const uint64_t digit1 = (used > 1) ? DigitAt(1) : 0; | 16760 const uint64_t digit1 = (used > 1) ? DigitAt(1) : 0; |
16785 const uint64_t abs_value = (digit1 << 32) + DigitAt(0); | 16761 const uint64_t abs_value = (digit1 << 32) + DigitAt(0); |
16786 const double abs_double_value = Uint64ToDouble(abs_value); | 16762 const double abs_double_value = Uint64ToDouble(abs_value); |
16787 return Neg() ? -abs_double_value : abs_double_value; | 16763 return Neg() ? -abs_double_value : abs_double_value; |
16788 } | 16764 } |
(...skipping 3776 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
20565 return tag_label.ToCString(); | 20541 return tag_label.ToCString(); |
20566 } | 20542 } |
20567 | 20543 |
20568 | 20544 |
20569 void UserTag::PrintJSONImpl(JSONStream* stream, bool ref) const { | 20545 void UserTag::PrintJSONImpl(JSONStream* stream, bool ref) const { |
20570 Instance::PrintJSONImpl(stream, ref); | 20546 Instance::PrintJSONImpl(stream, ref); |
20571 } | 20547 } |
20572 | 20548 |
20573 | 20549 |
20574 } // namespace dart | 20550 } // namespace dart |
OLD | NEW |