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" |
11 #include "vm/bigint_operations.h" | |
12 #include "vm/bit_vector.h" | 11 #include "vm/bit_vector.h" |
13 #include "vm/bootstrap.h" | 12 #include "vm/bootstrap.h" |
14 #include "vm/class_finalizer.h" | 13 #include "vm/class_finalizer.h" |
15 #include "vm/code_generator.h" | 14 #include "vm/code_generator.h" |
16 #include "vm/code_observers.h" | 15 #include "vm/code_observers.h" |
17 #include "vm/code_patcher.h" | 16 #include "vm/code_patcher.h" |
18 #include "vm/compiler.h" | 17 #include "vm/compiler.h" |
19 #include "vm/compiler_stats.h" | 18 #include "vm/compiler_stats.h" |
20 #include "vm/dart.h" | 19 #include "vm/dart.h" |
21 #include "vm/dart_api_state.h" | 20 #include "vm/dart_api_state.h" |
(...skipping 3839 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3861 RawFunction* Class::LookupConstructorAllowPrivate(const String& name) const { | 3860 RawFunction* Class::LookupConstructorAllowPrivate(const String& name) const { |
3862 return LookupFunctionAllowPrivate(name, kConstructor); | 3861 return LookupFunctionAllowPrivate(name, kConstructor); |
3863 } | 3862 } |
3864 | 3863 |
3865 | 3864 |
3866 RawFunction* Class::LookupFactory(const String& name) const { | 3865 RawFunction* Class::LookupFactory(const String& name) const { |
3867 return LookupFunction(name, kFactory); | 3866 return LookupFunction(name, kFactory); |
3868 } | 3867 } |
3869 | 3868 |
3870 | 3869 |
3870 RawFunction* Class::LookupFactoryAllowPrivate(const String& name) const { | |
3871 return LookupFunctionAllowPrivate(name, kFactory); | |
3872 } | |
3873 | |
3874 | |
3871 RawFunction* Class::LookupFunction(const String& name) const { | 3875 RawFunction* Class::LookupFunction(const String& name) const { |
3872 return LookupFunction(name, kAny); | 3876 return LookupFunction(name, kAny); |
3873 } | 3877 } |
3874 | 3878 |
3875 | 3879 |
3876 RawFunction* Class::LookupFunctionAllowPrivate(const String& name) const { | 3880 RawFunction* Class::LookupFunctionAllowPrivate(const String& name) const { |
3877 return LookupFunctionAllowPrivate(name, kAny); | 3881 return LookupFunctionAllowPrivate(name, kAny); |
3878 } | 3882 } |
3879 | 3883 |
3880 | 3884 |
(...skipping 7864 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
11745 cls = Function::Handle(GetTargetAt(i)).Owner(); | 11749 cls = Function::Handle(GetTargetAt(i)).Owner(); |
11746 if (cls.id() != owner_cid) { | 11750 if (cls.id() != owner_cid) { |
11747 return false; | 11751 return false; |
11748 } | 11752 } |
11749 } | 11753 } |
11750 } | 11754 } |
11751 return true; | 11755 return true; |
11752 } | 11756 } |
11753 | 11757 |
11754 | 11758 |
11755 bool ICData::AllReceiversAreNumbers() const { | |
11756 if (NumberOfChecks() == 0) return false; | |
11757 Class& cls = Class::Handle(); | |
11758 const intptr_t len = NumberOfChecks(); | |
11759 for (intptr_t i = 0; i < len; i++) { | |
11760 if (IsUsedAt(i)) { | |
11761 cls = Function::Handle(GetTargetAt(i)).Owner(); | |
11762 const intptr_t cid = cls.id(); | |
11763 if ((cid != kSmiCid) && | |
11764 (cid != kMintCid) && | |
11765 (cid != kBigintCid) && | |
11766 (cid != kDoubleCid)) { | |
11767 return false; | |
11768 } | |
11769 } | |
11770 } | |
11771 return true; | |
11772 } | |
11773 | |
11774 | |
11775 bool ICData::HasReceiverClassId(intptr_t class_id) const { | 11759 bool ICData::HasReceiverClassId(intptr_t class_id) const { |
11776 ASSERT(NumArgsTested() > 0); | 11760 ASSERT(NumArgsTested() > 0); |
11777 const intptr_t len = NumberOfChecks(); | 11761 const intptr_t len = NumberOfChecks(); |
11778 for (intptr_t i = 0; i < len; i++) { | 11762 for (intptr_t i = 0; i < len; i++) { |
11779 if (IsUsedAt(i)) { | 11763 if (IsUsedAt(i)) { |
11780 const intptr_t test_class_id = GetReceiverClassIdAt(i); | 11764 const intptr_t test_class_id = GetReceiverClassIdAt(i); |
11781 if (test_class_id == class_id) { | 11765 if (test_class_id == class_id) { |
11782 return true; | 11766 return true; |
11783 } | 11767 } |
11784 } | 11768 } |
(...skipping 1495 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
13280 private: | 13264 private: |
13281 bool has_pointers_; | 13265 bool has_pointers_; |
13282 | 13266 |
13283 DISALLOW_COPY_AND_ASSIGN(CheckForPointers); | 13267 DISALLOW_COPY_AND_ASSIGN(CheckForPointers); |
13284 }; | 13268 }; |
13285 #endif // DEBUG | 13269 #endif // DEBUG |
13286 | 13270 |
13287 | 13271 |
13288 bool Instance::CheckAndCanonicalizeFields(const char** error_str) const { | 13272 bool Instance::CheckAndCanonicalizeFields(const char** error_str) const { |
13289 const Class& cls = Class::Handle(this->clazz()); | 13273 const Class& cls = Class::Handle(this->clazz()); |
13290 if ((cls.id() >= kNumPredefinedCids)) { | 13274 if (cls.id() >= kNumPredefinedCids) { |
13291 // Iterate over all fields, canonicalize numbers and strings, expect all | 13275 // Iterate over all fields, canonicalize numbers and strings, expect all |
13292 // other instances to be canonical otherwise report error (return false). | 13276 // other instances to be canonical otherwise report error (return false). |
13293 Object& obj = Object::Handle(); | 13277 Object& obj = Object::Handle(); |
13294 intptr_t end_field_offset = cls.instance_size() - kWordSize; | 13278 intptr_t end_field_offset = cls.instance_size() - kWordSize; |
13295 for (intptr_t field_offset = 0; | 13279 for (intptr_t field_offset = 0; |
13296 field_offset <= end_field_offset; | 13280 field_offset <= end_field_offset; |
13297 field_offset += kWordSize) { | 13281 field_offset += kWordSize) { |
13298 obj = *this->FieldAddrAtOffset(field_offset); | 13282 obj = *this->FieldAddrAtOffset(field_offset); |
13299 if (obj.IsInstance() && !obj.IsSmi() && !obj.IsCanonical()) { | 13283 if (obj.IsInstance() && !obj.IsSmi() && !obj.IsCanonical()) { |
13300 if (obj.IsNumber() || obj.IsString()) { | 13284 if (obj.IsNumber() || obj.IsString()) { |
(...skipping 2196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
15497 Exceptions::ThrowByType(Exceptions::kJavascriptIntegerOverflowError, | 15481 Exceptions::ThrowByType(Exceptions::kJavascriptIntegerOverflowError, |
15498 exc_args); | 15482 exc_args); |
15499 } | 15483 } |
15500 | 15484 |
15501 | 15485 |
15502 RawInteger* Integer::New(const String& str, Heap::Space space) { | 15486 RawInteger* Integer::New(const String& str, Heap::Space space) { |
15503 // We are not supposed to have integers represented as two byte strings. | 15487 // We are not supposed to have integers represented as two byte strings. |
15504 ASSERT(str.IsOneByteString()); | 15488 ASSERT(str.IsOneByteString()); |
15505 int64_t value; | 15489 int64_t value; |
15506 if (!OS::StringToInt64(str.ToCString(), &value)) { | 15490 if (!OS::StringToInt64(str.ToCString(), &value)) { |
15507 const Bigint& big = Bigint::Handle(Bigint::New(str, space)); | 15491 const Bigint& big = Bigint::Handle( |
15508 ASSERT(!BigintOperations::FitsIntoSmi(big)); | 15492 Bigint::NewFromCString(str.ToCString(), space)); |
15509 ASSERT(!BigintOperations::FitsIntoInt64(big)); | 15493 ASSERT(!big.FitsIntoSmi()); |
15494 ASSERT(!big.FitsIntoInt64()); | |
15510 if (FLAG_throw_on_javascript_int_overflow) { | 15495 if (FLAG_throw_on_javascript_int_overflow) { |
15511 ThrowJavascriptIntegerOverflow(big); | 15496 ThrowJavascriptIntegerOverflow(big); |
15512 } | 15497 } |
15513 return big.raw(); | 15498 return big.raw(); |
15514 } | 15499 } |
15515 return Integer::New(value, space); | 15500 return Integer::New(value, space); |
15516 } | 15501 } |
15517 | 15502 |
15518 | 15503 |
15519 // This is called from LiteralToken::New() in the parser, so we can't | 15504 // This is called from LiteralToken::New() in the parser, so we can't |
15520 // raise an exception for javascript overflow here. Instead we do it in | 15505 // raise an exception for javascript overflow here. Instead we do it in |
15521 // Parser::CurrentIntegerLiteral(), which is the point in the parser where | 15506 // Parser::CurrentIntegerLiteral(), which is the point in the parser where |
15522 // integer literals escape, so we can call Parser::ErrorMsg(). | 15507 // integer literals escape, so we can call Parser::ErrorMsg(). |
15523 RawInteger* Integer::NewCanonical(const String& str) { | 15508 RawInteger* Integer::NewCanonical(const String& str) { |
15524 // We are not supposed to have integers represented as two byte strings. | 15509 // We are not supposed to have integers represented as two byte strings. |
15525 ASSERT(str.IsOneByteString()); | 15510 ASSERT(str.IsOneByteString()); |
15526 int64_t value; | 15511 int64_t value; |
15527 if (!OS::StringToInt64(str.ToCString(), &value)) { | 15512 if (!OS::StringToInt64(str.ToCString(), &value)) { |
15528 const Bigint& big = Bigint::Handle(Bigint::NewCanonical(str)); | 15513 const Bigint& big = Bigint::Handle(Bigint::NewCanonical(str)); |
15529 ASSERT(!BigintOperations::FitsIntoSmi(big)); | 15514 ASSERT(!big.FitsIntoSmi()); |
15530 ASSERT(!BigintOperations::FitsIntoInt64(big)); | 15515 ASSERT(!big.FitsIntoInt64()); |
15531 return big.raw(); | 15516 return big.raw(); |
15532 } | 15517 } |
15533 if (Smi::IsValid(value)) { | 15518 if (Smi::IsValid(value)) { |
15534 return Smi::New(static_cast<intptr_t>(value)); | 15519 return Smi::New(static_cast<intptr_t>(value)); |
15535 } | 15520 } |
15536 return Mint::NewCanonical(value); | 15521 return Mint::NewCanonical(value); |
15537 } | 15522 } |
15538 | 15523 |
15539 | 15524 |
15540 // dart2js represents integers as double precision floats, which can represent | 15525 // dart2js represents integers as double precision floats, which can represent |
(...skipping 16 matching lines...) Expand all Loading... | |
15557 if (is_smi) { | 15542 if (is_smi) { |
15558 return Smi::New(static_cast<intptr_t>(value)); | 15543 return Smi::New(static_cast<intptr_t>(value)); |
15559 } | 15544 } |
15560 return Mint::New(value, space); | 15545 return Mint::New(value, space); |
15561 } | 15546 } |
15562 | 15547 |
15563 | 15548 |
15564 RawInteger* Integer::NewFromUint64(uint64_t value, Heap::Space space) { | 15549 RawInteger* Integer::NewFromUint64(uint64_t value, Heap::Space space) { |
15565 if (value > static_cast<uint64_t>(Mint::kMaxValue)) { | 15550 if (value > static_cast<uint64_t>(Mint::kMaxValue)) { |
15566 if (FLAG_throw_on_javascript_int_overflow) { | 15551 if (FLAG_throw_on_javascript_int_overflow) { |
15567 const Integer &i = | 15552 const Integer &i = Integer::Handle(Bigint::NewFromUint64(value, space)); |
15568 Integer::Handle(BigintOperations::NewFromUint64(value, space)); | |
15569 ThrowJavascriptIntegerOverflow(i); | 15553 ThrowJavascriptIntegerOverflow(i); |
15570 } | 15554 } |
15571 return BigintOperations::NewFromUint64(value, space); | 15555 return Bigint::NewFromUint64(value, space); |
15572 } else { | 15556 } else { |
15573 return Integer::New(value, space); | 15557 return Integer::New(value, space); |
15574 } | 15558 } |
15575 } | 15559 } |
15576 | 15560 |
15577 | 15561 |
15562 bool Integer::Equals(const Instance& other) const { | |
15563 // Integer is an abstract class. | |
15564 UNREACHABLE(); | |
15565 return false; | |
15566 } | |
15567 | |
15568 | |
15569 bool Integer::IsZero() const { | |
15570 // Integer is an abstract class. | |
15571 UNREACHABLE(); | |
15572 return false; | |
15573 } | |
15574 | |
15575 | |
15576 bool Integer::IsNegative() const { | |
15577 // Integer is an abstract class. | |
15578 UNREACHABLE(); | |
15579 return false; | |
15580 } | |
15581 | |
15582 | |
15578 double Integer::AsDoubleValue() const { | 15583 double Integer::AsDoubleValue() const { |
15579 UNIMPLEMENTED(); | 15584 // Integer is an abstract class. |
15585 UNREACHABLE(); | |
15580 return 0.0; | 15586 return 0.0; |
15581 } | 15587 } |
15582 | 15588 |
15583 | 15589 |
15584 int64_t Integer::AsInt64Value() const { | 15590 int64_t Integer::AsInt64Value() const { |
15585 UNIMPLEMENTED(); | 15591 // Integer is an abstract class. |
15592 UNREACHABLE(); | |
15586 return 0; | 15593 return 0; |
15587 } | 15594 } |
15588 | 15595 |
15589 | 15596 |
15590 uint32_t Integer::AsTruncatedUint32Value() const { | 15597 uint32_t Integer::AsTruncatedUint32Value() const { |
15591 UNIMPLEMENTED(); | 15598 // Integer is an abstract class. |
15599 UNREACHABLE(); | |
15592 return 0; | 15600 return 0; |
15593 } | 15601 } |
15594 | 15602 |
15595 | 15603 |
15604 bool Integer::FitsIntoSmi() const { | |
15605 // Integer is an abstract class. | |
15606 UNREACHABLE(); | |
15607 return false; | |
15608 } | |
15609 | |
15610 | |
15596 int Integer::CompareWith(const Integer& other) const { | 15611 int Integer::CompareWith(const Integer& other) const { |
15597 UNIMPLEMENTED(); | 15612 // Integer is an abstract class. |
15613 UNREACHABLE(); | |
15598 return 0; | 15614 return 0; |
15599 } | 15615 } |
15600 | 15616 |
15601 | 15617 |
15602 // Returns true if the signed Integer does not fit into a | 15618 // Returns true if the signed Integer does not fit into a |
15603 // Javascript integer. | 15619 // Javascript integer. |
15604 bool Integer::CheckJavascriptIntegerOverflow() const { | 15620 bool Integer::CheckJavascriptIntegerOverflow() const { |
15605 // Always overflow if the value doesn't fit into an int64_t. | 15621 // Always overflow if the value doesn't fit into an int64_t. |
15606 int64_t value = 1ULL << 63; | 15622 int64_t value = 1ULL << 63; |
15607 if (IsSmi()) { | 15623 if (IsSmi()) { |
15608 value = AsInt64Value(); | 15624 value = AsInt64Value(); |
15609 } else if (IsMint()) { | 15625 } else if (IsMint()) { |
15610 Mint& mint = Mint::Handle(); | 15626 Mint& mint = Mint::Handle(); |
15611 mint ^= raw(); | 15627 mint ^= raw(); |
15612 value = mint.value(); | 15628 value = mint.value(); |
15613 } else { | 15629 } else { |
15614 ASSERT(IsBigint()); | 15630 ASSERT(IsBigint()); |
srdjan
2014/09/09 20:22:01
Is the assert needed? I assume Bigint::Cast has on
regis
2014/09/09 21:19:38
Correct. Assert removed here and below.
| |
15615 Bigint& big_value = Bigint::Handle(); | 15631 if (Bigint::Cast(*this).FitsIntoInt64()) { |
15616 big_value ^= raw(); | 15632 value = AsInt64Value(); |
15617 if (BigintOperations::FitsIntoInt64(big_value)) { | |
15618 value = BigintOperations::ToInt64(big_value); | |
15619 } | 15633 } |
15620 } | 15634 } |
15621 return !IsJavascriptInt(value); | 15635 return !IsJavascriptInt(value); |
15622 } | 15636 } |
15623 | 15637 |
15624 | 15638 |
15625 RawInteger* Integer::AsValidInteger() const { | 15639 RawInteger* Integer::AsValidInteger() const { |
15626 if (FLAG_throw_on_javascript_int_overflow && | 15640 if (FLAG_throw_on_javascript_int_overflow && |
15627 CheckJavascriptIntegerOverflow()) { | 15641 CheckJavascriptIntegerOverflow()) { |
15628 ThrowJavascriptIntegerOverflow(*this); | 15642 ThrowJavascriptIntegerOverflow(*this); |
15629 } | 15643 } |
15630 if (IsSmi()) return raw(); | 15644 if (IsSmi()) return raw(); |
15631 if (IsMint()) { | 15645 if (IsMint()) { |
15632 Mint& mint = Mint::Handle(); | 15646 Mint& mint = Mint::Handle(); |
15633 mint ^= raw(); | 15647 mint ^= raw(); |
15634 if (Smi::IsValid(mint.value())) { | 15648 if (Smi::IsValid(mint.value())) { |
15635 return Smi::New(static_cast<intptr_t>(mint.value())); | 15649 return Smi::New(static_cast<intptr_t>(mint.value())); |
15636 } else { | 15650 } else { |
15637 return raw(); | 15651 return raw(); |
15638 } | 15652 } |
15639 } | 15653 } |
15640 ASSERT(IsBigint()); | 15654 ASSERT(IsBigint()); |
15641 Bigint& big_value = Bigint::Handle(); | 15655 if (Bigint::Cast(*this).FitsIntoInt64()) { |
15642 big_value ^= raw(); | 15656 const int64_t value = AsInt64Value(); |
15643 if (BigintOperations::FitsIntoSmi(big_value)) { | 15657 if (Smi::IsValid(value)) { |
15644 return BigintOperations::ToSmi(big_value); | 15658 return Smi::New(value); |
15645 } else if (BigintOperations::FitsIntoInt64(big_value)) { | 15659 } |
15646 return Mint::New(BigintOperations::ToInt64(big_value)); | 15660 return Mint::New(value); |
15647 } else { | |
15648 return big_value.raw(); | |
15649 } | 15661 } |
15662 return raw(); | |
15650 } | 15663 } |
15651 | 15664 |
15652 | 15665 |
15653 RawInteger* Integer::ArithmeticOp(Token::Kind operation, | 15666 RawInteger* Integer::ArithmeticOp(Token::Kind operation, |
15654 const Integer& other) const { | 15667 const Integer& other) const { |
15655 // In 32-bit mode, the result of any operation between two Smis will fit in a | 15668 // In 32-bit mode, the result of any operation between two Smis will fit in a |
15656 // 32-bit signed result, except the product of two Smis, which will be 64-bit. | 15669 // 32-bit signed result, except the product of two Smis, which will be 64-bit. |
15657 // In 64-bit mode, the result of any operation between two Smis will fit in a | 15670 // In 64-bit mode, the result of any operation between two Smis will fit in a |
15658 // 64-bit signed result, except the product of two Smis (see below). | 15671 // 64-bit signed result, except the product of two Smis (see below). |
15659 if (IsSmi() && other.IsSmi()) { | 15672 if (IsSmi() && other.IsSmi()) { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
15692 } else { | 15705 } else { |
15693 return Integer::New(remainder + right_value); | 15706 return Integer::New(remainder + right_value); |
15694 } | 15707 } |
15695 } | 15708 } |
15696 return Integer::New(remainder); | 15709 return Integer::New(remainder); |
15697 } | 15710 } |
15698 default: | 15711 default: |
15699 UNIMPLEMENTED(); | 15712 UNIMPLEMENTED(); |
15700 } | 15713 } |
15701 } | 15714 } |
15702 // In 32-bit mode, the result of any operation (except multiplication) between | 15715 if (!IsBigint() && !other.IsBigint()) { |
15703 // two 63-bit signed integers will fit in a 64-bit signed result. | |
15704 // For the multiplication result to fit, the sum of the highest bits of the | |
15705 // absolute values of the operands must be smaller than 62. | |
15706 // In 64-bit mode, 63-bit signed integers are Smis, already processed above. | |
15707 if ((Smi::kBits < 32) && !IsBigint() && !other.IsBigint()) { | |
15708 const int64_t left_value = AsInt64Value(); | 15716 const int64_t left_value = AsInt64Value(); |
15709 const int64_t right_value = other.AsInt64Value(); | 15717 const int64_t right_value = other.AsInt64Value(); |
15710 if (operation == Token::kMUL) { | 15718 switch (operation) { |
15711 if ((Utils::HighestBit(left_value) + | 15719 case Token::kADD: { |
15712 Utils::HighestBit(right_value)) < 62) { | 15720 if (((left_value < 0) != (right_value < 0)) || |
15713 return Integer::New(left_value * right_value); | 15721 ((left_value + right_value) < 0) == (left_value < 0)) { |
15722 return Integer::New(left_value + right_value); | |
15723 } | |
15724 break; | |
15714 } | 15725 } |
15715 // Perform a Bigint multiplication below. | 15726 case Token::kSUB: { |
15716 } else if (Utils::IsInt(63, left_value) && Utils::IsInt(63, right_value)) { | 15727 if (((left_value < 0) == (right_value < 0)) || |
15717 switch (operation) { | 15728 ((left_value - right_value) < 0) == (left_value < 0)) { |
15718 case Token::kADD: | 15729 return Integer::New(left_value - right_value); |
15719 return Integer::New(left_value + right_value); | 15730 } |
15720 case Token::kSUB: | 15731 break; |
15721 return Integer::New(left_value - right_value); | 15732 } |
15722 case Token::kTRUNCDIV: | 15733 case Token::kMUL: { |
15723 return Integer::New(left_value / right_value); | 15734 if ((Utils::HighestBit(left_value) + |
15735 Utils::HighestBit(right_value)) < 62) { | |
15736 return Integer::New(left_value * right_value); | |
15737 } | |
15738 break; | |
15739 } | |
15740 case Token::kTRUNCDIV: { | |
15741 if ((left_value != Mint::kMinValue) || (right_value != -1)) { | |
15742 return Integer::New(left_value / right_value); | |
15743 } | |
15744 break; | |
15745 } | |
15724 case Token::kMOD: { | 15746 case Token::kMOD: { |
15725 const int64_t remainder = left_value % right_value; | 15747 const int64_t remainder = left_value % right_value; |
15726 if (remainder < 0) { | 15748 if (remainder < 0) { |
15727 if (right_value < 0) { | 15749 if (right_value < 0) { |
15728 return Integer::New(remainder - right_value); | 15750 return Integer::New(remainder - right_value); |
15729 } else { | 15751 } else { |
15730 return Integer::New(remainder + right_value); | 15752 return Integer::New(remainder + right_value); |
15731 } | 15753 } |
15732 } | 15754 } |
15733 return Integer::New(remainder); | 15755 return Integer::New(remainder); |
15734 } | 15756 } |
15735 default: | 15757 default: |
15736 UNIMPLEMENTED(); | 15758 UNIMPLEMENTED(); |
15737 } | |
15738 } | 15759 } |
15739 } | 15760 } |
15740 const Bigint& left_big = Bigint::Handle(AsBigint()); | 15761 return Integer::null(); // Notify caller that a bigint operation is required. |
15741 const Bigint& right_big = Bigint::Handle(other.AsBigint()); | |
15742 const Bigint& result = | |
15743 Bigint::Handle(left_big.BigArithmeticOp(operation, right_big)); | |
15744 return Integer::Handle(result.AsValidInteger()).raw(); | |
15745 } | 15762 } |
15746 | 15763 |
15747 | 15764 |
15748 static bool Are64bitOperands(const Integer& op1, const Integer& op2) { | 15765 static bool Are64bitOperands(const Integer& op1, const Integer& op2) { |
15749 return !op1.IsBigint() && !op2.IsBigint(); | 15766 return !op1.IsBigint() && !op2.IsBigint(); |
15750 } | 15767 } |
15751 | 15768 |
15752 | 15769 |
15753 RawInteger* Integer::BitOp(Token::Kind kind, const Integer& other) const { | 15770 RawInteger* Integer::BitOp(Token::Kind kind, const Integer& other) const { |
15754 if (IsSmi() && other.IsSmi()) { | 15771 if (IsSmi() && other.IsSmi()) { |
(...skipping 21 matching lines...) Expand all Loading... | |
15776 switch (kind) { | 15793 switch (kind) { |
15777 case Token::kBIT_AND: | 15794 case Token::kBIT_AND: |
15778 return Integer::New(a & b); | 15795 return Integer::New(a & b); |
15779 case Token::kBIT_OR: | 15796 case Token::kBIT_OR: |
15780 return Integer::New(a | b); | 15797 return Integer::New(a | b); |
15781 case Token::kBIT_XOR: | 15798 case Token::kBIT_XOR: |
15782 return Integer::New(a ^ b); | 15799 return Integer::New(a ^ b); |
15783 default: | 15800 default: |
15784 UNIMPLEMENTED(); | 15801 UNIMPLEMENTED(); |
15785 } | 15802 } |
15786 } else { | |
15787 Bigint& op1 = Bigint::Handle(AsBigint()); | |
15788 Bigint& op2 = Bigint::Handle(other.AsBigint()); | |
15789 switch (kind) { | |
15790 case Token::kBIT_AND: | |
15791 return BigintOperations::BitAnd(op1, op2); | |
15792 case Token::kBIT_OR: | |
15793 return BigintOperations::BitOr(op1, op2); | |
15794 case Token::kBIT_XOR: | |
15795 return BigintOperations::BitXor(op1, op2); | |
15796 default: | |
15797 UNIMPLEMENTED(); | |
15798 } | |
15799 } | 15803 } |
15800 return Integer::null(); | 15804 return Integer::null(); // Notify caller that a bigint operation is required. |
15801 } | 15805 } |
15802 | 15806 |
15803 | 15807 |
15804 // TODO(srdjan): Clarify handling of negative right operand in a shift op. | 15808 // TODO(srdjan): Clarify handling of negative right operand in a shift op. |
15805 RawInteger* Smi::ShiftOp(Token::Kind kind, | 15809 RawInteger* Smi::ShiftOp(Token::Kind kind, |
15806 const Smi& other, | 15810 const Smi& other, |
15807 const bool silent) const { | 15811 const bool silent) const { |
15808 intptr_t result = 0; | 15812 intptr_t result = 0; |
15809 const intptr_t left_value = Value(); | 15813 const intptr_t left_value = Value(); |
15810 const intptr_t right_value = other.Value(); | 15814 const intptr_t right_value = other.Value(); |
15811 ASSERT(right_value >= 0); | 15815 ASSERT(right_value >= 0); |
15812 switch (kind) { | 15816 switch (kind) { |
15813 case Token::kSHL: { | 15817 case Token::kSHL: { |
15814 if ((left_value == 0) || (right_value == 0)) { | 15818 if ((left_value == 0) || (right_value == 0)) { |
15815 return raw(); | 15819 return raw(); |
15816 } | 15820 } |
15817 { // Check for overflow. | 15821 { // Check for overflow. |
15818 int cnt = Utils::HighestBit(left_value); | 15822 int cnt = Utils::HighestBit(left_value); |
15819 if ((cnt + right_value) >= Smi::kBits) { | 15823 if ((cnt + right_value) >= Smi::kBits) { |
15820 if ((cnt + right_value) >= Mint::kBits) { | 15824 if ((cnt + right_value) >= Mint::kBits) { |
15821 return BigintOperations::ShiftLeft( | 15825 return Bigint::NewFromShiftedInt64(left_value, right_value); |
15822 Bigint::Handle(BigintOperations::NewFromSmi(*this)), | |
15823 right_value); | |
15824 } else { | 15826 } else { |
15825 int64_t left_64 = left_value; | 15827 int64_t left_64 = left_value; |
15826 return Integer::New(left_64 << right_value, Heap::kNew, silent); | 15828 return Integer::New(left_64 << right_value, Heap::kNew, silent); |
15827 } | 15829 } |
15828 } | 15830 } |
15829 } | 15831 } |
15830 result = left_value << right_value; | 15832 result = left_value << right_value; |
15831 break; | 15833 break; |
15832 } | 15834 } |
15833 case Token::kSHR: { | 15835 case Token::kSHR: { |
(...skipping 26 matching lines...) Expand all Loading... | |
15860 int64_t Smi::AsInt64Value() const { | 15862 int64_t Smi::AsInt64Value() const { |
15861 return this->Value(); | 15863 return this->Value(); |
15862 } | 15864 } |
15863 | 15865 |
15864 | 15866 |
15865 uint32_t Smi::AsTruncatedUint32Value() const { | 15867 uint32_t Smi::AsTruncatedUint32Value() const { |
15866 return this->Value() & 0xFFFFFFFF; | 15868 return this->Value() & 0xFFFFFFFF; |
15867 } | 15869 } |
15868 | 15870 |
15869 | 15871 |
15870 static bool FitsIntoSmi(const Integer& integer) { | |
15871 if (integer.IsSmi()) { | |
15872 return true; | |
15873 } | |
15874 if (integer.IsMint()) { | |
15875 int64_t mint_value = integer.AsInt64Value(); | |
15876 return Smi::IsValid(mint_value); | |
15877 } | |
15878 if (integer.IsBigint()) { | |
15879 return BigintOperations::FitsIntoSmi(Bigint::Cast(integer)); | |
15880 } | |
15881 UNREACHABLE(); | |
15882 return false; | |
15883 } | |
15884 | |
15885 | |
15886 int Smi::CompareWith(const Integer& other) const { | 15872 int Smi::CompareWith(const Integer& other) const { |
15887 if (other.IsSmi()) { | 15873 if (other.IsSmi()) { |
15888 const Smi& other_smi = Smi::Cast(other); | 15874 const Smi& other_smi = Smi::Cast(other); |
15889 if (this->Value() < other_smi.Value()) { | 15875 if (this->Value() < other_smi.Value()) { |
15890 return -1; | 15876 return -1; |
15891 } else if (this->Value() > other_smi.Value()) { | 15877 } else if (this->Value() > other_smi.Value()) { |
15892 return 1; | 15878 return 1; |
15893 } else { | 15879 } else { |
15894 return 0; | 15880 return 0; |
15895 } | 15881 } |
15896 } | 15882 } |
15897 ASSERT(!FitsIntoSmi(other)); | 15883 ASSERT(!other.FitsIntoSmi()); |
15898 if (other.IsMint() || other.IsBigint()) { | 15884 if (other.IsMint() || other.IsBigint()) { |
15899 if (this->IsNegative() == other.IsNegative()) { | 15885 if (this->IsNegative() == other.IsNegative()) { |
15900 return this->IsNegative() ? 1 : -1; | 15886 return this->IsNegative() ? 1 : -1; |
15901 } | 15887 } |
15902 return this->IsNegative() ? -1 : 1; | 15888 return this->IsNegative() ? -1 : 1; |
15903 } | 15889 } |
15904 UNREACHABLE(); | 15890 UNREACHABLE(); |
15905 return 0; | 15891 return 0; |
15906 } | 15892 } |
15907 | 15893 |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
16002 int64_t Mint::AsInt64Value() const { | 15988 int64_t Mint::AsInt64Value() const { |
16003 return this->value(); | 15989 return this->value(); |
16004 } | 15990 } |
16005 | 15991 |
16006 | 15992 |
16007 uint32_t Mint::AsTruncatedUint32Value() const { | 15993 uint32_t Mint::AsTruncatedUint32Value() const { |
16008 return this->value() & 0xFFFFFFFF; | 15994 return this->value() & 0xFFFFFFFF; |
16009 } | 15995 } |
16010 | 15996 |
16011 | 15997 |
15998 bool Mint::FitsIntoSmi() const { | |
15999 return Smi::IsValid(AsInt64Value()); | |
16000 } | |
16001 | |
16002 | |
16012 int Mint::CompareWith(const Integer& other) const { | 16003 int Mint::CompareWith(const Integer& other) const { |
16013 ASSERT(!FitsIntoSmi(*this)); | 16004 ASSERT(!FitsIntoSmi()); |
16014 if (other.IsMint() || other.IsSmi()) { | 16005 if (other.IsMint() || other.IsSmi()) { |
16015 int64_t a = AsInt64Value(); | 16006 int64_t a = AsInt64Value(); |
16016 int64_t b = other.AsInt64Value(); | 16007 int64_t b = other.AsInt64Value(); |
16017 if (a < b) { | 16008 if (a < b) { |
16018 return -1; | 16009 return -1; |
16019 } else if (a > b) { | 16010 } else if (a > b) { |
16020 return 1; | 16011 return 1; |
16021 } else { | 16012 } else { |
16022 return 0; | 16013 return 0; |
16023 } | 16014 } |
16024 } | 16015 } |
16025 if (other.IsBigint()) { | 16016 ASSERT(other.IsBigint()); |
16026 ASSERT(!BigintOperations::FitsIntoInt64(Bigint::Cast(other))); | 16017 ASSERT(!Bigint::Cast(other).FitsIntoInt64()); |
16027 if (this->IsNegative() == other.IsNegative()) { | 16018 if (this->IsNegative() == other.IsNegative()) { |
16028 return this->IsNegative() ? 1 : -1; | 16019 return this->IsNegative() ? 1 : -1; |
16029 } | |
16030 return this->IsNegative() ? -1 : 1; | |
16031 } | 16020 } |
16032 UNREACHABLE(); | 16021 return this->IsNegative() ? -1 : 1; |
16033 return 0; | |
16034 } | 16022 } |
16035 | 16023 |
16036 | 16024 |
16037 const char* Mint::ToCString() const { | 16025 const char* Mint::ToCString() const { |
16038 const char* kFormat = "%lld"; | 16026 const char* kFormat = "%lld"; |
16039 // Calculate the size of the string. | 16027 // Calculate the size of the string. |
16040 intptr_t len = OS::SNPrint(NULL, 0, kFormat, value()) + 1; | 16028 intptr_t len = OS::SNPrint(NULL, 0, kFormat, value()) + 1; |
16041 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); | 16029 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); |
16042 OS::SNPrint(chars, len, kFormat, value()); | 16030 OS::SNPrint(chars, len, kFormat, value()); |
16043 return chars; | 16031 return chars; |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
16182 // "Double". Return "double" instead. | 16170 // "Double". Return "double" instead. |
16183 AddTypeProperties(&jsobj, "double", "double", ref); | 16171 AddTypeProperties(&jsobj, "double", "double", ref); |
16184 PrintSharedInstanceJSON(&jsobj, ref); | 16172 PrintSharedInstanceJSON(&jsobj, ref); |
16185 ObjectIdRing* ring = Isolate::Current()->object_id_ring(); | 16173 ObjectIdRing* ring = Isolate::Current()->object_id_ring(); |
16186 const intptr_t id = ring->GetIdForObject(raw()); | 16174 const intptr_t id = ring->GetIdForObject(raw()); |
16187 jsobj.AddPropertyF("id", "objects/%" Pd "", id); | 16175 jsobj.AddPropertyF("id", "objects/%" Pd "", id); |
16188 jsobj.AddProperty("valueAsString", ToCString()); | 16176 jsobj.AddProperty("valueAsString", ToCString()); |
16189 } | 16177 } |
16190 | 16178 |
16191 | 16179 |
16192 RawBigint* Integer::AsBigint() const { | 16180 void Bigint::set_neg(const Bool& value) const { |
16193 ASSERT(!IsNull()); | 16181 StorePointer(&raw_ptr()->neg_, value.raw()); |
16194 if (IsSmi()) { | |
16195 Smi& smi = Smi::Handle(); | |
16196 smi ^= raw(); | |
16197 return BigintOperations::NewFromSmi(smi); | |
16198 } else if (IsMint()) { | |
16199 Mint& mint = Mint::Handle(); | |
16200 mint ^= raw(); | |
16201 return BigintOperations::NewFromInt64(mint.value()); | |
16202 } else { | |
16203 ASSERT(IsBigint()); | |
16204 Bigint& big = Bigint::Handle(); | |
16205 big ^= raw(); | |
16206 ASSERT(!BigintOperations::FitsIntoSmi(big)); | |
16207 return big.raw(); | |
16208 } | |
16209 } | 16182 } |
16210 | 16183 |
16211 | 16184 |
16212 RawBigint* Bigint::BigArithmeticOp(Token::Kind operation, | 16185 void Bigint::set_used(const Smi& value) const { |
16213 const Bigint& other) const { | 16186 raw_ptr()->used_ = value.raw(); |
16214 switch (operation) { | 16187 } |
16215 case Token::kADD: | 16188 |
16216 return BigintOperations::Add(*this, other); | 16189 |
16217 case Token::kSUB: | 16190 void Bigint::set_digits(const TypedData& value) const { |
16218 return BigintOperations::Subtract(*this, other); | 16191 StorePointer(&raw_ptr()->digits_, value.raw()); |
16219 case Token::kMUL: | 16192 } |
16220 return BigintOperations::Multiply(*this, other); | 16193 |
16221 case Token::kTRUNCDIV: | 16194 |
16222 return BigintOperations::Divide(*this, other); | 16195 bool Bigint::Neg() const { |
16223 case Token::kMOD: | 16196 return Bool::Handle(neg()).value(); |
16224 return BigintOperations::Modulo(*this, other); | 16197 } |
16225 default: | 16198 |
16226 UNIMPLEMENTED(); | 16199 |
16227 return Bigint::null(); | 16200 void Bigint::SetNeg(bool value) const { |
16228 } | 16201 set_neg(Bool::Get(value)); |
16202 } | |
16203 | |
16204 | |
16205 intptr_t Bigint::Used() const { | |
16206 return Smi::Value(used()); | |
16207 } | |
16208 | |
16209 | |
16210 void Bigint::SetUsed(intptr_t value) const { | |
16211 set_used(Smi::Handle(Smi::New(value))); | |
16212 } | |
16213 | |
16214 | |
16215 uint32_t Bigint::DigitAt(intptr_t index) const { | |
16216 const TypedData& typed_data = TypedData::Handle(digits()); | |
16217 return typed_data.GetUint32(index << 2); | |
16218 } | |
16219 | |
16220 | |
16221 void Bigint::SetDigitAt(intptr_t index, uint32_t value) const { | |
16222 const TypedData& typed_data = TypedData::Handle(digits()); | |
16223 typed_data.SetUint32(index << 2, value); | |
16229 } | 16224 } |
16230 | 16225 |
16231 | 16226 |
16232 bool Bigint::Equals(const Instance& other) const { | 16227 bool Bigint::Equals(const Instance& other) const { |
16233 if (this->raw() == other.raw()) { | 16228 if (this->raw() == other.raw()) { |
16234 // Both handles point to the same raw instance. | 16229 // Both handles point to the same raw instance. |
16235 return true; | 16230 return true; |
16236 } | 16231 } |
16237 | 16232 |
16238 if (!other.IsBigint() || other.IsNull()) { | 16233 if (!other.IsBigint() || other.IsNull()) { |
16239 return false; | 16234 return false; |
16240 } | 16235 } |
16241 | 16236 |
16242 const Bigint& other_bgi = Bigint::Cast(other); | 16237 const Bigint& other_bgi = Bigint::Cast(other); |
16243 | 16238 |
16244 if (this->IsNegative() != other_bgi.IsNegative()) { | 16239 if (this->Neg() != other_bgi.Neg()) { |
16245 return false; | 16240 return false; |
16246 } | 16241 } |
16247 | 16242 |
16248 intptr_t len = this->Length(); | 16243 const intptr_t used = this->Used(); |
16249 if (len != other_bgi.Length()) { | 16244 if (used != other_bgi.Used()) { |
16250 return false; | 16245 return false; |
16251 } | 16246 } |
16252 | 16247 |
16253 for (intptr_t i = 0; i < len; i++) { | 16248 for (intptr_t i = 0; i < used; i++) { |
16254 if (this->GetChunkAt(i) != other_bgi.GetChunkAt(i)) { | 16249 if (this->DigitAt(i) != other_bgi.DigitAt(i)) { |
16255 return false; | 16250 return false; |
16256 } | 16251 } |
16257 } | 16252 } |
16258 return true; | 16253 return true; |
16259 } | 16254 } |
16260 | 16255 |
16261 | 16256 |
16262 RawBigint* Bigint::New(const String& str, Heap::Space space) { | 16257 bool Bigint::CheckAndCanonicalizeFields(const char** error_str) const { |
16263 const Bigint& result = Bigint::Handle( | 16258 // Bool field neg should always be canonical. |
16264 BigintOperations::NewFromCString(str.ToCString(), space)); | 16259 ASSERT(Bool::Handle(neg()).IsCanonical()); |
16265 ASSERT(!BigintOperations::FitsIntoInt64(result)); | 16260 // Smi field used is canonical by definition. |
16261 if (Used() > 0) { | |
16262 // Canonicalize TypedData field digits. | |
16263 TypedData& digits_ = TypedData::Handle(digits()); | |
16264 digits_ ^= digits_.CheckAndCanonicalize(NULL); | |
16265 ASSERT(!digits_.IsNull()); | |
16266 set_digits(digits_); | |
16267 } else { | |
16268 ASSERT(digits() == TypedData::null()); | |
16269 } | |
16270 return true; | |
16271 } | |
16272 | |
16273 | |
16274 RawBigint* Bigint::New(Heap::Space space) { | |
16275 ASSERT(Isolate::Current()->object_store()->bigint_class() != Class::null()); | |
16276 Bigint& result = Bigint::Handle(); | |
16277 { | |
16278 RawObject* raw = Object::Allocate(Bigint::kClassId, | |
16279 Bigint::InstanceSize(), | |
16280 space); | |
16281 NoGCScope no_gc; | |
16282 result ^= raw; | |
16283 } | |
16284 result.set_neg(Bool::Get(false)); | |
16285 result.set_used(Smi::Handle(Smi::New(0))); | |
16266 return result.raw(); | 16286 return result.raw(); |
16267 } | 16287 } |
16268 | 16288 |
16269 | 16289 |
16290 RawBigint* Bigint::NewFromInt64(int64_t value, Heap::Space space) { | |
16291 const Bigint& result = Bigint::Handle(New(space)); | |
16292 result.EnsureLength(2, space); | |
16293 result.SetUsed(2); | |
16294 if (value < 0) { | |
16295 result.SetNeg(true); | |
16296 value = -value; // No concern about overflow, since sign is captured. | |
16297 } | |
16298 result.SetDigitAt(0, static_cast<uint32_t>(value)); | |
16299 result.SetDigitAt(1, static_cast<uint32_t>(value >> 32)); // value >= 0. | |
16300 result.Clamp(); | |
16301 return result.raw(); | |
16302 } | |
16303 | |
16304 | |
16305 RawBigint* Bigint::NewFromUint64(uint64_t value, Heap::Space space) { | |
16306 const Bigint& result = Bigint::Handle(New(space)); | |
16307 result.EnsureLength(2, space); | |
16308 result.SetUsed(2); | |
16309 result.SetDigitAt(0, static_cast<uint32_t>(value)); | |
16310 result.SetDigitAt(1, static_cast<uint32_t>(value >> 32)); | |
16311 result.Clamp(); | |
16312 return result.raw(); | |
16313 } | |
16314 | |
16315 | |
16316 RawBigint* Bigint::NewFromShiftedInt64(int64_t value, intptr_t shift, | |
16317 Heap::Space space) { | |
16318 ASSERT(kBitsPerDigit == 32); | |
16319 ASSERT(shift >= 0); | |
16320 const Bigint& result = Bigint::Handle(New(space)); | |
16321 const intptr_t digit_shift = shift / kBitsPerDigit; | |
16322 const intptr_t bit_shift = shift % kBitsPerDigit; | |
16323 result.EnsureLength(3 + digit_shift, space); | |
16324 result.SetUsed(3 + digit_shift); | |
16325 uint64_t abs_value; | |
16326 if (value < 0) { | |
16327 result.SetNeg(true); | |
16328 abs_value = -value; // No concern about overflow, since sign is captured. | |
16329 } else { | |
16330 abs_value = value; | |
16331 } | |
16332 for (intptr_t i = 0; i < digit_shift; i++) { | |
16333 result.SetDigitAt(i, 0); | |
16334 } | |
16335 result.SetDigitAt(0 + digit_shift, | |
16336 static_cast<uint32_t>(abs_value << bit_shift)); | |
16337 result.SetDigitAt(1 + digit_shift, | |
16338 static_cast<uint32_t>(abs_value >> (32 - bit_shift))); | |
16339 result.SetDigitAt(2 + digit_shift, | |
16340 (bit_shift == 0) ? 0 | |
16341 : static_cast<uint32_t>(abs_value >> (64 - bit_shift))); | |
16342 result.Clamp(); | |
16343 return result.raw(); | |
16344 } | |
16345 | |
16346 | |
16347 void Bigint::EnsureLength(intptr_t length, Heap::Space space) const { | |
16348 ASSERT(length >= 0); | |
16349 TypedData& old_digits = TypedData::Handle(digits()); | |
16350 if ((length > 0) && (old_digits.IsNull() || (length > old_digits.Length()))) { | |
16351 TypedData& new_digits = TypedData::Handle( | |
16352 TypedData::New(kTypedDataUint32ArrayCid, length + kExtraDigits, space)); | |
16353 if (!old_digits.IsNull()) { | |
16354 TypedData::Copy(new_digits, TypedData::data_offset(), | |
16355 old_digits, TypedData::data_offset(), | |
16356 old_digits.LengthInBytes()); | |
16357 } | |
16358 set_digits(new_digits); | |
16359 } | |
16360 } | |
16361 | |
16362 | |
16363 void Bigint::Clamp() const { | |
16364 intptr_t used = Used(); | |
16365 while ((used > 0) && (DigitAt(used - 1) == 0)) { | |
16366 --used; | |
16367 } | |
16368 SetUsed(used); | |
16369 } | |
16370 | |
16371 | |
16372 bool Bigint::IsClamped() const { | |
16373 intptr_t used = Used(); | |
16374 return (used == 0) || (DigitAt(used - 1) > 0); | |
16375 } | |
16376 | |
16377 | |
16378 RawBigint* Bigint::NewFromCString(const char* str, Heap::Space space) { | |
16379 ASSERT(str != NULL); | |
16380 if (str[0] == '\0') { | |
16381 return NewFromInt64(0, space); | |
16382 } | |
16383 | |
16384 // If the string starts with '-' recursively restart the whole operation | |
16385 // without the character and then toggle the sign. | |
16386 // This allows multiple leading '-' (which will cancel each other out), but | |
16387 // we have added an assert, to make sure that the returned result of the | |
16388 // recursive call is not negative. | |
16389 // We don't catch leading '-'s for zero. Ex: "--0", or "---". | |
16390 if (str[0] == '-') { | |
16391 const Bigint& result = Bigint::Handle(NewFromCString(&str[1], space)); | |
16392 result.SetNeg(!result.Neg()); // Toggle sign. | |
16393 ASSERT(result.IsZero() || result.IsNegative()); | |
16394 ASSERT(result.IsClamped()); | |
16395 return result.raw(); | |
16396 } | |
16397 | |
16398 // No overflow check needed since overflowing str_length implies that we take | |
16399 // the branch to NewFromDecCString() which contains a check itself. | |
16400 const intptr_t str_length = strlen(str); | |
16401 if ((str_length > 2) && | |
16402 (str[0] == '0') && | |
16403 ((str[1] == 'x') || (str[1] == 'X'))) { | |
16404 const Bigint& result = Bigint::Handle(NewFromHexCString(&str[2], space)); | |
16405 ASSERT(result.IsClamped()); | |
16406 return result.raw(); | |
16407 } else { | |
16408 return NewFromDecCString(str, space); | |
16409 } | |
16410 } | |
16411 | |
16412 | |
16270 RawBigint* Bigint::NewCanonical(const String& str) { | 16413 RawBigint* Bigint::NewCanonical(const String& str) { |
16271 const Bigint& value = Bigint::Handle( | 16414 const Bigint& value = Bigint::Handle( |
16272 BigintOperations::NewFromCString(str.ToCString(), Heap::kOld)); | 16415 Bigint::NewFromCString(str.ToCString(), Heap::kOld)); |
16273 ASSERT(!BigintOperations::FitsIntoInt64(value)); | |
16274 const Class& cls = | 16416 const Class& cls = |
16275 Class::Handle(Isolate::Current()->object_store()->bigint_class()); | 16417 Class::Handle(Isolate::Current()->object_store()->bigint_class()); |
16276 const Array& constants = Array::Handle(cls.constants()); | 16418 const Array& constants = Array::Handle(cls.constants()); |
16277 const intptr_t constants_len = constants.Length(); | 16419 const intptr_t constants_len = constants.Length(); |
16278 // Linear search to see whether this value is already present in the | 16420 // Linear search to see whether this value is already present in the |
16279 // list of canonicalized constants. | 16421 // list of canonicalized constants. |
16280 Bigint& canonical_value = Bigint::Handle(); | 16422 Bigint& canonical_value = Bigint::Handle(); |
16281 intptr_t index = 0; | 16423 intptr_t index = 0; |
16282 while (index < constants_len) { | 16424 while (index < constants_len) { |
16283 canonical_value ^= constants.At(index); | 16425 canonical_value ^= constants.At(index); |
16284 if (canonical_value.IsNull()) { | 16426 if (canonical_value.IsNull()) { |
16285 break; | 16427 break; |
16286 } | 16428 } |
16287 if (canonical_value.Equals(value)) { | 16429 if (canonical_value.Equals(value)) { |
16288 return canonical_value.raw(); | 16430 return canonical_value.raw(); |
16289 } | 16431 } |
16290 index++; | 16432 index++; |
16291 } | 16433 } |
16292 // The value needs to be added to the constants list. Grow the list if | 16434 // The value needs to be added to the constants list. Grow the list if |
16293 // it is full. | 16435 // it is full. |
16294 cls.InsertCanonicalConstant(index, value); | 16436 cls.InsertCanonicalConstant(index, value); |
16295 value.SetCanonical(); | 16437 value.SetCanonical(); |
16296 return value.raw(); | 16438 return value.raw(); |
16297 } | 16439 } |
16298 | 16440 |
16299 | 16441 |
16442 RawBigint* Bigint::NewFromHexCString(const char* str, Heap::Space space) { | |
16443 // TODO(regis): Do we need to check for max length? | |
16444 // If the string starts with '-' recursively restart the whole operation | |
16445 // without the character and then toggle the sign. | |
16446 // This allows multiple leading '-' (which will cancel each other out), but | |
16447 // we have added an assert, to make sure that the returned result of the | |
16448 // recursive call is not negative. | |
16449 // We don't catch leading '-'s for zero. Ex: "--0", or "---". | |
16450 if (str[0] == '-') { | |
16451 const Bigint& result = Bigint::Handle(NewFromHexCString(&str[1], space)); | |
16452 result.SetNeg(!result.Neg()); // Toggle sign. | |
16453 ASSERT(result.IsZero() || result.IsNegative()); | |
16454 ASSERT(result.IsClamped()); | |
16455 return result.raw(); | |
16456 } | |
16457 const Bigint& result = Bigint::Handle(New(space)); | |
16458 const int kBitsPerHexDigit = 4; | |
16459 const int kHexDigitsPerDigit = 8; | |
16460 const int kBitsPerDigit = kBitsPerHexDigit * kHexDigitsPerDigit; | |
16461 intptr_t hex_i = strlen(str); // Terminating byte excluded. | |
16462 result.EnsureLength((hex_i + kHexDigitsPerDigit - 1) / kHexDigitsPerDigit, | |
16463 space); | |
16464 intptr_t used_ = 0; | |
16465 uint32_t digit = 0; | |
16466 intptr_t bit_i = 0; | |
16467 while (--hex_i >= 0) { | |
16468 digit += Utils::HexDigitToInt(str[hex_i]) << bit_i; | |
16469 bit_i += kBitsPerHexDigit; | |
16470 if (bit_i == kBitsPerDigit) { | |
16471 bit_i = 0; | |
16472 result.SetDigitAt(used_++, digit); | |
16473 digit = 0; | |
16474 } | |
16475 } | |
16476 if (bit_i != 0) { | |
16477 result.SetDigitAt(used_++, digit); | |
16478 } | |
16479 result.SetUsed(used_); | |
16480 result.Clamp(); | |
16481 return result.raw(); | |
16482 } | |
16483 | |
16484 | |
16485 RawBigint* Bigint::NewFromDecCString(const char* str, Heap::Space space) { | |
16486 // Read 9 digits a time. 10^9 < 2^32. | |
16487 const int kDecDigitsPerIteration = 9; | |
16488 const uint32_t kTenMultiplier = 1000000000; | |
16489 ASSERT(kBitsPerDigit == 32); | |
16490 | |
16491 const intptr_t str_length = strlen(str); | |
16492 if (str_length < 0) { // TODO(regis): Pick a smaller limit. | |
16493 FATAL("Fatal error in Bigint::NewFromDecCString: string too long"); | |
16494 } | |
16495 intptr_t str_pos = 0; | |
16496 | |
16497 Bigint& result = Bigint::Handle(Bigint::New(space)); | |
16498 // One decimal digit takes log2(10) bits, i.e. ~3.32192809489 bits. | |
16499 // That is a theoretical limit for large numbers. | |
16500 // The extra digits allocated take care of variations (kExtraDigits). | |
16501 const int64_t kLog10Dividend = 33219281; | |
16502 const int64_t kLog10Divisor = 10000000; | |
16503 result.EnsureLength((kLog10Dividend * str_length) / | |
16504 (kLog10Divisor * kBitsPerDigit), space); | |
16505 | |
16506 // Read first digit separately. This avoids a multiplication and addition. | |
16507 // The first digit might also not have kDecDigitsPerIteration decimal digits. | |
16508 const intptr_t lsdigit_length = str_length % kDecDigitsPerIteration; | |
16509 uint32_t digit = 0; | |
16510 for (intptr_t i = 0; i < lsdigit_length; i++) { | |
16511 char c = str[str_pos++]; | |
16512 ASSERT(('0' <= c) && (c <= '9')); | |
16513 digit = digit * 10 + c - '0'; | |
16514 } | |
16515 result.SetDigitAt(0, digit); | |
16516 intptr_t used = 1; | |
16517 | |
16518 // Read kDecDigitsPerIteration at a time, and store it in 'digit'. | |
16519 // Then multiply the temporary result by 10^kDecDigitsPerIteration and add | |
16520 // 'digit' to the new result. | |
16521 while (str_pos < str_length - 1) { | |
16522 digit = 0; | |
16523 for (intptr_t i = 0; i < kDecDigitsPerIteration; i++) { | |
16524 char c = str[str_pos++]; | |
16525 ASSERT(('0' <= c) && (c <= '9')); | |
16526 digit = digit * 10 + c - '0'; | |
16527 } | |
16528 // Multiply result with kTenMultiplier and add digit. | |
16529 for (intptr_t i = 0; i < used; i++) { | |
16530 uint64_t product = | |
16531 (static_cast<uint64_t>(result.DigitAt(i)) * kTenMultiplier) + digit; | |
16532 result.SetDigitAt(i, static_cast<uint32_t>(product & kDigitMask)); | |
16533 digit = static_cast<uint32_t>(product >> kBitsPerDigit); | |
16534 } | |
16535 result.SetDigitAt(used++, digit); | |
16536 } | |
16537 result.SetUsed(used); | |
16538 result.Clamp(); | |
16539 return result.raw(); | |
16540 } | |
16541 | |
16542 | |
16543 static double Uint64ToDouble(uint64_t x) { | |
16544 #if _WIN64 | |
16545 // For static_cast<double>(x) MSVC x64 generates | |
16546 // | |
16547 // cvtsi2sd xmm0, rax | |
16548 // test rax, rax | |
16549 // jns done | |
16550 // addsd xmm0, static_cast<double>(2^64) | |
16551 // done: | |
16552 // | |
16553 // while GCC -m64 generates | |
16554 // | |
16555 // test rax, rax | |
16556 // js negative | |
16557 // cvtsi2sd xmm0, rax | |
16558 // jmp done | |
16559 // negative: | |
16560 // mov rdx, rax | |
16561 // shr rdx, 1 | |
16562 // and eax, 0x1 | |
16563 // or rdx, rax | |
16564 // cvtsi2sd xmm0, rdx | |
16565 // addsd xmm0, xmm0 | |
16566 // done: | |
16567 // | |
16568 // which results in a different rounding. | |
16569 // | |
16570 // For consistency between platforms fallback to GCC style converstion | |
16571 // on Win64. | |
16572 // | |
16573 const int64_t y = static_cast<int64_t>(x); | |
16574 if (y > 0) { | |
16575 return static_cast<double>(y); | |
16576 } else { | |
16577 const double half = static_cast<double>( | |
16578 static_cast<int64_t>(x >> 1) | (y & 1)); | |
16579 return half + half; | |
16580 } | |
16581 #else | |
16582 return static_cast<double>(x); | |
16583 #endif | |
16584 } | |
16585 | |
16586 | |
16300 double Bigint::AsDoubleValue() const { | 16587 double Bigint::AsDoubleValue() const { |
16301 return Double::Handle(BigintOperations::ToDouble(*this)).value(); | 16588 ASSERT(kBitsPerDigit == 32); |
16589 ASSERT(IsClamped()); | |
16590 const intptr_t used = Used(); | |
16591 if (used == 0) { | |
16592 return 0.0; | |
16593 } | |
16594 if (used <= 2) { | |
16595 const uint64_t digit1 = (used > 1) ? DigitAt(1) : 0; | |
16596 const uint64_t abs_value = (digit1 << 32) + DigitAt(0); | |
16597 const double abs_double_value = Uint64ToDouble(abs_value); | |
16598 return Neg() ? -abs_double_value : abs_double_value; | |
16599 } | |
16600 | |
16601 static const int kPhysicalSignificandSize = 52; | |
16602 // The significand size has an additional hidden bit. | |
16603 static const int kSignificandSize = kPhysicalSignificandSize + 1; | |
16604 static const int kExponentBias = 0x3FF + kPhysicalSignificandSize; | |
16605 static const int kMaxExponent = 0x7FF - kExponentBias; | |
16606 static const uint64_t kOne64 = 1; | |
16607 static const uint64_t kInfinityBits = | |
16608 DART_2PART_UINT64_C(0x7FF00000, 00000000); | |
16609 | |
16610 // A double is composed of an exponent e and a significand s. Its value equals | |
16611 // s * 2^e. The significand has 53 bits of which the first one must always be | |
16612 // 1 (at least for then numbers we are working with here) and is therefore | |
16613 // omitted. The physical size of the significand is thus 52 bits. | |
16614 // The exponent has 11 bits and is biased by 0x3FF + 52. For example an | |
16615 // exponent e = 10 is written as 0x3FF + 52 + 10 (in the 11 bits that are | |
16616 // reserved for the exponent). | |
16617 // When converting the given bignum to a double we have to pay attention to | |
16618 // the rounding. In particular we have to decide which double to pick if an | |
16619 // input lies exactly between two doubles. As usual with double operations | |
16620 // we pick the double with an even significand in such cases. | |
16621 // | |
16622 // General approach of this algorithm: Get 54 bits (one more than the | |
16623 // significand size) of the bigint. If the last bit is then 1, then (without | |
16624 // knowledge of the remaining bits) we could have a half-way number. | |
16625 // If the second-to-last bit is odd then we know that we have to round up: | |
16626 // if the remaining bits are not zero then the input lies closer to the higher | |
16627 // double. If the remaining bits are zero then we have a half-way case and | |
16628 // we need to round up too (rounding to the even double). | |
16629 // If the second-to-last bit is even then we need to look at the remaining | |
16630 // bits to determine if any of them is not zero. If that's the case then the | |
16631 // number lies closer to the next-higher double. Otherwise we round the | |
16632 // half-way case down to even. | |
16633 | |
16634 if (((used - 1) * kBitsPerDigit) > (kMaxExponent + kSignificandSize)) { | |
16635 // Does not fit into a double. | |
16636 const double infinity = bit_cast<double>(kInfinityBits); | |
16637 return Neg() ? -infinity : infinity; | |
16638 } | |
16639 | |
16640 intptr_t digit_index = used - 1; | |
16641 // In order to round correctly we need to look at half-way cases. Therefore we | |
16642 // get kSignificandSize + 1 bits. If the last bit is 1 then we have to look | |
16643 // at the remaining bits to know if we have to round up. | |
16644 int needed_bits = kSignificandSize + 1; | |
16645 ASSERT((kBitsPerDigit < needed_bits) && (2 * kBitsPerDigit >= needed_bits)); | |
16646 bool discarded_bits_were_zero = true; | |
16647 | |
16648 const uint32_t firstDigit = DigitAt(digit_index--); | |
16649 ASSERT(firstDigit > 0); | |
16650 uint64_t twice_significand_floor = firstDigit; | |
16651 intptr_t twice_significant_exponent = (digit_index + 1) * kBitsPerDigit; | |
16652 needed_bits -= Utils::HighestBit(firstDigit) + 1; | |
16653 | |
16654 if (needed_bits >= kBitsPerDigit) { | |
16655 twice_significand_floor <<= kBitsPerDigit; | |
16656 twice_significand_floor |= DigitAt(digit_index--); | |
16657 twice_significant_exponent -= kBitsPerDigit; | |
16658 needed_bits -= kBitsPerDigit; | |
16659 } | |
16660 if (needed_bits > 0) { | |
16661 ASSERT(needed_bits <= kBitsPerDigit); | |
16662 uint32_t digit = DigitAt(digit_index--); | |
16663 int discarded_bits_count = kBitsPerDigit - needed_bits; | |
16664 twice_significand_floor <<= needed_bits; | |
16665 twice_significand_floor |= digit >> discarded_bits_count; | |
16666 twice_significant_exponent -= needed_bits; | |
16667 uint64_t discarded_bits_mask = (kOne64 << discarded_bits_count) - 1; | |
16668 discarded_bits_were_zero = ((digit & discarded_bits_mask) == 0); | |
16669 } | |
16670 ASSERT((twice_significand_floor >> kSignificandSize) == 1); | |
16671 | |
16672 // We might need to round up the significand later. | |
16673 uint64_t significand = twice_significand_floor >> 1; | |
16674 const intptr_t exponent = twice_significant_exponent + 1; | |
16675 | |
16676 if (exponent >= kMaxExponent) { | |
16677 // Infinity. | |
16678 // Does not fit into a double. | |
16679 const double infinity = bit_cast<double>(kInfinityBits); | |
16680 return Neg() ? -infinity : infinity; | |
16681 } | |
16682 | |
16683 if ((twice_significand_floor & 1) == 1) { | |
16684 bool round_up = false; | |
16685 | |
16686 if ((significand & 1) != 0 || !discarded_bits_were_zero) { | |
16687 // Even if the remaining bits are zero we still need to round up since we | |
16688 // want to round to even for half-way cases. | |
16689 round_up = true; | |
16690 } else { | |
16691 // Could be a half-way case. See if the remaining bits are non-zero. | |
16692 for (intptr_t i = 0; i <= digit_index; i++) { | |
16693 if (DigitAt(i) != 0) { | |
16694 round_up = true; | |
16695 break; | |
16696 } | |
16697 } | |
16698 } | |
16699 | |
16700 if (round_up) { | |
16701 significand++; | |
16702 // It might be that we just went from 53 bits to 54 bits. | |
16703 // Example: After adding 1 to 1FFF..FF (with 53 bits set to 1) we have | |
16704 // 2000..00 (= 2 ^ 54). When adding the exponent and significand together | |
16705 // this will increase the exponent by 1 which is exactly what we want. | |
16706 } | |
16707 } | |
16708 | |
16709 ASSERT(((significand >> (kSignificandSize - 1)) == 1) || | |
16710 (significand == (kOne64 << kSignificandSize))); | |
16711 // The significand still has the hidden bit. We simply decrement the biased | |
16712 // exponent by one instead of playing around with the significand. | |
16713 const uint64_t biased_exponent = exponent + kExponentBias - 1; | |
16714 // Note that we must use the plus operator instead of bit-or. | |
16715 const uint64_t double_bits = | |
16716 (biased_exponent << kPhysicalSignificandSize) + significand; | |
16717 | |
16718 const double value = bit_cast<double>(double_bits); | |
16719 return Neg() ? -value : value; | |
16720 } | |
16721 | |
16722 | |
16723 bool Bigint::FitsIntoSmi() const { | |
16724 return FitsIntoInt64() && Smi::IsValid(AsInt64Value()); | |
16725 } | |
16726 | |
16727 | |
16728 bool Bigint::FitsIntoInt64() const { | |
16729 ASSERT(Bigint::kBitsPerDigit == 32); | |
16730 const intptr_t used = Used(); | |
16731 if (used < 2) return true; | |
16732 if (used > 2) return false; | |
16733 const uint64_t digit1 = DigitAt(1); | |
16734 const uint64_t value = (digit1 << 32) + DigitAt(0); | |
16735 uint64_t limit = Mint::kMaxValue; | |
16736 if (Neg()) { | |
16737 limit++; | |
16738 } | |
16739 return value <= limit; | |
16302 } | 16740 } |
16303 | 16741 |
16304 | 16742 |
16305 int64_t Bigint::AsInt64Value() const { | 16743 int64_t Bigint::AsInt64Value() const { |
16306 if (!BigintOperations::FitsIntoInt64(*this)) { | 16744 ASSERT(FitsIntoInt64()); |
16307 UNREACHABLE(); | 16745 const intptr_t used = Used(); |
16308 } | 16746 if (used == 0) return 0; |
16309 return BigintOperations::ToInt64(*this); | 16747 const int64_t digit1 = (used > 1) ? DigitAt(1) : 0; |
16748 const int64_t value = (digit1 << 32) + DigitAt(0); | |
16749 return Neg() ? -value : value; | |
16750 } | |
16751 | |
16752 | |
16753 bool Bigint::FitsIntoUint64() const { | |
16754 ASSERT(Bigint::kBitsPerDigit == 32); | |
16755 return !Neg() && (Used() <= 2); | |
16756 } | |
16757 | |
16758 | |
16759 uint64_t Bigint::AsUint64Value() const { | |
16760 ASSERT(FitsIntoUint64()); | |
16761 const intptr_t used = Used(); | |
16762 if (used == 0) return 0; | |
16763 const uint64_t digit1 = (used > 1) ? DigitAt(1) : 0; | |
16764 return (digit1 << 32) + DigitAt(0); | |
16310 } | 16765 } |
16311 | 16766 |
16312 | 16767 |
16313 uint32_t Bigint::AsTruncatedUint32Value() const { | 16768 uint32_t Bigint::AsTruncatedUint32Value() const { |
16314 return BigintOperations::TruncateToUint32(*this); | 16769 // Note: the previous implementation of Bigint returned the absolute value |
16770 // truncated to 32 bits, which is not consistent with Smi and Mint behavior. | |
16771 ASSERT(Bigint::kBitsPerDigit == 32); | |
16772 const intptr_t used = Used(); | |
16773 if (used == 0) return 0; | |
16774 const uint32_t digit0 = DigitAt(0); | |
16775 return Neg() ? -digit0 : digit0; | |
16315 } | 16776 } |
16316 | 16777 |
16317 | 16778 |
16318 // For positive values: Smi < Mint < Bigint. | 16779 // For positive values: Smi < Mint < Bigint. |
16319 int Bigint::CompareWith(const Integer& other) const { | 16780 int Bigint::CompareWith(const Integer& other) const { |
16320 ASSERT(!FitsIntoSmi(*this)); | 16781 ASSERT(!FitsIntoSmi()); |
16321 ASSERT(!BigintOperations::FitsIntoInt64(*this)); | 16782 ASSERT(!FitsIntoInt64()); |
16322 if (other.IsBigint()) { | 16783 if (other.IsBigint() && (IsNegative() == other.IsNegative())) { |
16323 return BigintOperations::Compare(*this, Bigint::Cast(other)); | 16784 const Bigint& other_bgi = Bigint::Cast(other); |
16324 } | 16785 int64_t result = Used() - other_bgi.Used(); |
16325 if (this->IsNegative() == other.IsNegative()) { | 16786 if (result == 0) { |
16326 return this->IsNegative() ? -1 : 1; | 16787 for (intptr_t i = Used(); --i >= 0; ) { |
16788 result = DigitAt(i); | |
16789 result -= other_bgi.DigitAt(i); | |
16790 if (result != 0) break; | |
16791 } | |
16792 } | |
16793 if (IsNegative()) { | |
16794 result = -result; | |
16795 } | |
16796 return result > 0 ? 1 : result < 0 ? -1 : 0; | |
16327 } | 16797 } |
16328 return this->IsNegative() ? -1 : 1; | 16798 return this->IsNegative() ? -1 : 1; |
16329 } | 16799 } |
16330 | 16800 |
16331 | 16801 |
16332 RawBigint* Bigint::Allocate(intptr_t length, Heap::Space space) { | 16802 const char* Bigint::ToDecCString(uword (*allocator)(intptr_t size)) const { |
16333 if (length < 0 || length > kMaxElements) { | 16803 // log10(2) ~= 0.30102999566398114. |
16334 // This should be caught before we reach here. | 16804 const intptr_t kLog2Dividend = 30103; |
16335 FATAL1("Fatal error in Bigint::Allocate: invalid length %" Pd "\n", length); | 16805 const intptr_t kLog2Divisor = 100000; |
16336 } | 16806 intptr_t used = Used(); |
16337 ASSERT(Isolate::Current()->object_store()->bigint_class() != Class::null()); | 16807 const intptr_t kMaxUsed = |
16338 Bigint& result = Bigint::Handle(); | 16808 kIntptrMax / kBitsPerDigit / kLog2Dividend * kLog2Divisor; |
16339 { | 16809 if (used > kMaxUsed) { |
16340 RawObject* raw = Object::Allocate(Bigint::kClassId, | 16810 // Throw out of memory exception. |
16341 Bigint::InstanceSize(length), | 16811 Isolate* isolate = Isolate::Current(); |
16342 space); | 16812 const Instance& exception = |
16343 NoGCScope no_gc; | 16813 Instance::Handle(isolate->object_store()->out_of_memory()); |
16344 result ^= raw; | 16814 Exceptions::Throw(isolate, exception); |
16345 result.raw_ptr()->allocated_length_ = length; // Chunk length allocated. | 16815 UNREACHABLE(); |
16346 result.raw_ptr()->signed_length_ = length; // Chunk length in use. | 16816 } |
16347 } | 16817 const int64_t bit_len = used * kBitsPerDigit; |
16348 return result.raw(); | 16818 const int64_t dec_len = (bit_len * kLog2Dividend / kLog2Divisor) + 1; |
16819 // Add one byte for the minus sign and for the trailing \0 character. | |
16820 const int64_t len = (Neg() ? 1 : 0) + dec_len + 1; | |
16821 char* chars = reinterpret_cast<char*>(allocator(len)); | |
16822 intptr_t pos = 0; | |
16823 const intptr_t kDivisor = 100000000; | |
16824 const intptr_t kDigits = 8; | |
16825 ASSERT(pow(10.0, kDigits) == kDivisor); | |
16826 ASSERT(kDivisor < kDigitBase); | |
16827 ASSERT(Smi::IsValid(kDivisor)); | |
16828 // Allocate a copy of the digits. | |
16829 const TypedData& rest_digits = TypedData::Handle( | |
16830 TypedData::New(kTypedDataUint32ArrayCid, used)); | |
16831 for (intptr_t i = 0; i < used; i++) { | |
16832 rest_digits.SetUint32(i << 2, DigitAt(i)); | |
16833 } | |
16834 if (used == 0) { | |
16835 chars[pos++] = '0'; | |
16836 } | |
16837 while (used > 0) { | |
16838 uint32_t remainder = 0; | |
16839 for (intptr_t i = used - 1; i >= 0; i--) { | |
16840 uint64_t dividend = (static_cast<uint64_t>(remainder) << kBitsPerDigit) + | |
16841 rest_digits.GetUint32(i << 2); | |
16842 uint32_t quotient = static_cast<uint32_t>(dividend / kDivisor); | |
16843 remainder = static_cast<uint32_t>( | |
16844 dividend - static_cast<uint64_t>(quotient) * kDivisor); | |
16845 rest_digits.SetUint32(i << 2, quotient); | |
16846 } | |
16847 // Clamp rest_digits. | |
16848 while ((used > 0) && (rest_digits.GetUint32((used - 1) << 2) == 0)) { | |
16849 used--; | |
16850 } | |
16851 for (intptr_t i = 0; i < kDigits; i++) { | |
16852 chars[pos++] = '0' + (remainder % 10); | |
16853 remainder /= 10; | |
16854 } | |
16855 ASSERT(remainder == 0); | |
16856 } | |
16857 // Remove leading zeros. | |
16858 while ((pos > 1) && (chars[pos - 1] == '0')) { | |
16859 pos--; | |
16860 } | |
16861 if (Neg()) { | |
16862 chars[pos++] = '-'; | |
16863 } | |
16864 // Reverse the string. | |
16865 intptr_t i = 0; | |
16866 intptr_t j = pos - 1; | |
16867 while (i < j) { | |
16868 char tmp = chars[i]; | |
16869 chars[i] = chars[j]; | |
16870 chars[j] = tmp; | |
16871 i++; | |
16872 j--; | |
16873 } | |
16874 chars[pos] = '\0'; | |
16875 return chars; | |
16876 } | |
16877 | |
16878 | |
16879 const char* Bigint::ToHexCString(uword (*allocator)(intptr_t size)) const { | |
16880 NoGCScope no_gc; // TODO(regis): Is this necessary? | |
16881 | |
16882 const intptr_t used = Used(); | |
16883 if (used == 0) { | |
16884 const char* zero = "0x0"; | |
16885 const size_t len = strlen(zero) + 1; | |
16886 char* chars = reinterpret_cast<char*>(allocator(len)); | |
16887 strncpy(chars, zero, len); | |
16888 return chars; | |
16889 } | |
16890 const int kBitsPerHexDigit = 4; | |
16891 const int kHexDigitsPerDigit = 8; | |
16892 const intptr_t kMaxUsed = (kIntptrMax - 4) / kHexDigitsPerDigit; | |
16893 if (used > kMaxUsed) { | |
16894 // Throw out of memory exception. | |
16895 Isolate* isolate = Isolate::Current(); | |
16896 const Instance& exception = | |
16897 Instance::Handle(isolate->object_store()->out_of_memory()); | |
16898 Exceptions::Throw(isolate, exception); | |
16899 UNREACHABLE(); | |
16900 } | |
16901 intptr_t hex_len = (used - 1) * kHexDigitsPerDigit; | |
16902 // The most significant digit may use fewer than kHexDigitsPerDigit digits. | |
16903 uint32_t digit = DigitAt(used - 1); | |
16904 ASSERT(digit != 0); // Value must be clamped. | |
16905 while (digit != 0) { | |
16906 hex_len++; | |
16907 digit >>= kBitsPerHexDigit; | |
16908 } | |
16909 // Add bytes for '0x', for the minus sign, and for the trailing \0 character. | |
16910 const int32_t len = (Neg() ? 1 : 0) + 2 + hex_len + 1; | |
16911 char* chars = reinterpret_cast<char*>(allocator(len)); | |
16912 intptr_t pos = len; | |
16913 chars[--pos] = '\0'; | |
16914 for (intptr_t i = 0; i < (used - 1); i++) { | |
16915 digit = DigitAt(i); | |
16916 for (intptr_t j = 0; j < kHexDigitsPerDigit; j++) { | |
16917 chars[--pos] = Utils::IntToHexDigit(digit & 0xf); | |
16918 digit >>= kBitsPerHexDigit; | |
16919 } | |
16920 } | |
16921 digit = DigitAt(used - 1); | |
16922 while (digit != 0) { | |
16923 chars[--pos] = Utils::IntToHexDigit(digit & 0xf); | |
16924 digit >>= kBitsPerHexDigit; | |
16925 } | |
16926 chars[--pos] = 'x'; | |
16927 chars[--pos] = '0'; | |
16928 if (Neg()) { | |
16929 chars[--pos] = '-'; | |
16930 } | |
16931 ASSERT(pos == 0); | |
16932 return chars; | |
16349 } | 16933 } |
16350 | 16934 |
16351 | 16935 |
16352 static uword BigintAllocator(intptr_t size) { | 16936 static uword BigintAllocator(intptr_t size) { |
16353 Zone* zone = Isolate::Current()->current_zone(); | 16937 Zone* zone = Isolate::Current()->current_zone(); |
16354 return zone->AllocUnsafe(size); | 16938 return zone->AllocUnsafe(size); |
16355 } | 16939 } |
16356 | 16940 |
16357 | 16941 |
16358 const char* Bigint::ToCString() const { | 16942 const char* Bigint::ToCString() const { |
16359 return BigintOperations::ToDecimalCString(*this, &BigintAllocator); | 16943 return ToDecCString(&BigintAllocator); |
16360 } | 16944 } |
16361 | 16945 |
16362 | 16946 |
16363 void Bigint::PrintJSONImpl(JSONStream* stream, bool ref) const { | 16947 void Bigint::PrintJSONImpl(JSONStream* stream, bool ref) const { |
16364 Integer::PrintJSONImpl(stream, ref); | 16948 Integer::PrintJSONImpl(stream, ref); |
16365 } | 16949 } |
16366 | 16950 |
16367 | 16951 |
16368 // Synchronize with implementation in compiler (intrinsifier). | 16952 // Synchronize with implementation in compiler (intrinsifier). |
16369 class StringHasher : ValueObject { | 16953 class StringHasher : ValueObject { |
(...skipping 2181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
18551 } | 19135 } |
18552 // TODO(koda): Ensure VM classes only produce Smi hash codes, and remove | 19136 // TODO(koda): Ensure VM classes only produce Smi hash codes, and remove |
18553 // non-Smi cases once Dart-side implementation is complete. | 19137 // non-Smi cases once Dart-side implementation is complete. |
18554 Isolate* isolate = Isolate::Current(); | 19138 Isolate* isolate = Isolate::Current(); |
18555 REUSABLE_INSTANCE_HANDLESCOPE(isolate); | 19139 REUSABLE_INSTANCE_HANDLESCOPE(isolate); |
18556 Instance& hash_code = isolate->InstanceHandle(); | 19140 Instance& hash_code = isolate->InstanceHandle(); |
18557 hash_code ^= Instance::Cast(obj).HashCode(); | 19141 hash_code ^= Instance::Cast(obj).HashCode(); |
18558 if (hash_code.IsSmi()) { | 19142 if (hash_code.IsSmi()) { |
18559 // May waste some bits on 64-bit, to ensure consistency with non-Smi case. | 19143 // May waste some bits on 64-bit, to ensure consistency with non-Smi case. |
18560 return static_cast<uword>(Smi::Cast(hash_code).Value() & 0xFFFFFFFF); | 19144 return static_cast<uword>(Smi::Cast(hash_code).Value() & 0xFFFFFFFF); |
19145 // TODO(regis): Same as Smi::AsTruncatedUint32Value(), simplify? | |
18561 } else if (hash_code.IsInteger()) { | 19146 } else if (hash_code.IsInteger()) { |
18562 return static_cast<uword>( | 19147 return static_cast<uword>( |
18563 Integer::Cast(hash_code).AsTruncatedUint32Value()); | 19148 Integer::Cast(hash_code).AsTruncatedUint32Value()); |
18564 } else { | 19149 } else { |
18565 return 0; | 19150 return 0; |
18566 } | 19151 } |
18567 } | 19152 } |
18568 }; | 19153 }; |
18569 typedef EnumIndexHashMap<DefaultHashTraits> EnumIndexDefaultMap; | 19154 typedef EnumIndexHashMap<DefaultHashTraits> EnumIndexDefaultMap; |
18570 | 19155 |
(...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
18993 8, // kTypedDataInt64ArrayCid. | 19578 8, // kTypedDataInt64ArrayCid. |
18994 8, // kTypedDataUint64ArrayCid. | 19579 8, // kTypedDataUint64ArrayCid. |
18995 4, // kTypedDataFloat32ArrayCid. | 19580 4, // kTypedDataFloat32ArrayCid. |
18996 8, // kTypedDataFloat64ArrayCid. | 19581 8, // kTypedDataFloat64ArrayCid. |
18997 16, // kTypedDataFloat32x4ArrayCid. | 19582 16, // kTypedDataFloat32x4ArrayCid. |
18998 16, // kTypedDataInt32x4ArrayCid. | 19583 16, // kTypedDataInt32x4ArrayCid. |
18999 16, // kTypedDataFloat64x2ArrayCid, | 19584 16, // kTypedDataFloat64x2ArrayCid, |
19000 }; | 19585 }; |
19001 | 19586 |
19002 | 19587 |
19588 bool TypedData::CanonicalizeEquals(const Instance& other) const { | |
19589 if (this->raw() == other.raw()) { | |
19590 // Both handles point to the same raw instance. | |
19591 return true; | |
19592 } | |
19593 | |
19594 if (!other.IsTypedData() || other.IsNull()) { | |
19595 return false; | |
19596 } | |
19597 | |
19598 const TypedData& other_typed_data = TypedData::Cast(other); | |
19599 | |
19600 if (this->ElementType() != other_typed_data.ElementType()) { | |
19601 return false; | |
19602 } | |
19603 | |
19604 const intptr_t len = this->LengthInBytes(); | |
19605 if (len != other_typed_data.LengthInBytes()) { | |
19606 return false; | |
19607 } | |
19608 | |
19609 return (len == 0) || | |
19610 (memcmp(DataAddr(0), other_typed_data.DataAddr(0), len) == 0); | |
19611 } | |
19612 | |
19613 | |
19003 RawTypedData* TypedData::New(intptr_t class_id, | 19614 RawTypedData* TypedData::New(intptr_t class_id, |
19004 intptr_t len, | 19615 intptr_t len, |
19005 Heap::Space space) { | 19616 Heap::Space space) { |
19006 if (len < 0 || len > TypedData::MaxElements(class_id)) { | 19617 if (len < 0 || len > TypedData::MaxElements(class_id)) { |
19007 FATAL1("Fatal error in TypedData::New: invalid len %" Pd "\n", len); | 19618 FATAL1("Fatal error in TypedData::New: invalid len %" Pd "\n", len); |
19008 } | 19619 } |
19009 TypedData& result = TypedData::Handle(); | 19620 TypedData& result = TypedData::Handle(); |
19010 { | 19621 { |
19011 intptr_t lengthInBytes = len * ElementSizeInBytes(class_id); | 19622 const intptr_t lengthInBytes = len * ElementSizeInBytes(class_id); |
19012 RawObject* raw = Object::Allocate(class_id, | 19623 RawObject* raw = Object::Allocate(class_id, |
19013 TypedData::InstanceSize(lengthInBytes), | 19624 TypedData::InstanceSize(lengthInBytes), |
19014 space); | 19625 space); |
19015 NoGCScope no_gc; | 19626 NoGCScope no_gc; |
19016 result ^= raw; | 19627 result ^= raw; |
19017 result.SetLength(len); | 19628 result.SetLength(len); |
19018 if (len > 0) { | 19629 if (len > 0) { |
19019 memset(result.DataAddr(0), 0, lengthInBytes); | 19630 memset(result.DataAddr(0), 0, lengthInBytes); |
19020 } | 19631 } |
19021 } | 19632 } |
(...skipping 768 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
19790 return tag_label.ToCString(); | 20401 return tag_label.ToCString(); |
19791 } | 20402 } |
19792 | 20403 |
19793 | 20404 |
19794 void UserTag::PrintJSONImpl(JSONStream* stream, bool ref) const { | 20405 void UserTag::PrintJSONImpl(JSONStream* stream, bool ref) const { |
19795 Instance::PrintJSONImpl(stream, ref); | 20406 Instance::PrintJSONImpl(stream, ref); |
19796 } | 20407 } |
19797 | 20408 |
19798 | 20409 |
19799 } // namespace dart | 20410 } // namespace dart |
OLD | NEW |