Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(319)

Side by Side Diff: runtime/vm/object.cc

Issue 509153003: New bigint implementation in the vm. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698