Chromium Code Reviews| 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 |