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 3801 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3823 RawFunction* Class::LookupConstructorAllowPrivate(const String& name) const { | 3822 RawFunction* Class::LookupConstructorAllowPrivate(const String& name) const { |
3824 return LookupFunctionAllowPrivate(name, kConstructor); | 3823 return LookupFunctionAllowPrivate(name, kConstructor); |
3825 } | 3824 } |
3826 | 3825 |
3827 | 3826 |
3828 RawFunction* Class::LookupFactory(const String& name) const { | 3827 RawFunction* Class::LookupFactory(const String& name) const { |
3829 return LookupFunction(name, kFactory); | 3828 return LookupFunction(name, kFactory); |
3830 } | 3829 } |
3831 | 3830 |
3832 | 3831 |
| 3832 RawFunction* Class::LookupFactoryAllowPrivate(const String& name) const { |
| 3833 return LookupFunctionAllowPrivate(name, kFactory); |
| 3834 } |
| 3835 |
| 3836 |
3833 RawFunction* Class::LookupFunction(const String& name) const { | 3837 RawFunction* Class::LookupFunction(const String& name) const { |
3834 return LookupFunction(name, kAny); | 3838 return LookupFunction(name, kAny); |
3835 } | 3839 } |
3836 | 3840 |
3837 | 3841 |
3838 RawFunction* Class::LookupFunctionAllowPrivate(const String& name) const { | 3842 RawFunction* Class::LookupFunctionAllowPrivate(const String& name) const { |
3839 return LookupFunctionAllowPrivate(name, kAny); | 3843 return LookupFunctionAllowPrivate(name, kAny); |
3840 } | 3844 } |
3841 | 3845 |
3842 | 3846 |
(...skipping 7821 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11664 cls = Function::Handle(GetTargetAt(i)).Owner(); | 11668 cls = Function::Handle(GetTargetAt(i)).Owner(); |
11665 if (cls.id() != owner_cid) { | 11669 if (cls.id() != owner_cid) { |
11666 return false; | 11670 return false; |
11667 } | 11671 } |
11668 } | 11672 } |
11669 } | 11673 } |
11670 return true; | 11674 return true; |
11671 } | 11675 } |
11672 | 11676 |
11673 | 11677 |
11674 bool ICData::AllReceiversAreNumbers() const { | |
11675 if (NumberOfChecks() == 0) return false; | |
11676 Class& cls = Class::Handle(); | |
11677 const intptr_t len = NumberOfChecks(); | |
11678 for (intptr_t i = 0; i < len; i++) { | |
11679 if (IsUsedAt(i)) { | |
11680 cls = Function::Handle(GetTargetAt(i)).Owner(); | |
11681 const intptr_t cid = cls.id(); | |
11682 if ((cid != kSmiCid) && | |
11683 (cid != kMintCid) && | |
11684 (cid != kBigintCid) && | |
11685 (cid != kDoubleCid)) { | |
11686 return false; | |
11687 } | |
11688 } | |
11689 } | |
11690 return true; | |
11691 } | |
11692 | |
11693 | |
11694 bool ICData::HasReceiverClassId(intptr_t class_id) const { | 11678 bool ICData::HasReceiverClassId(intptr_t class_id) const { |
11695 ASSERT(NumArgsTested() > 0); | 11679 ASSERT(NumArgsTested() > 0); |
11696 const intptr_t len = NumberOfChecks(); | 11680 const intptr_t len = NumberOfChecks(); |
11697 for (intptr_t i = 0; i < len; i++) { | 11681 for (intptr_t i = 0; i < len; i++) { |
11698 if (IsUsedAt(i)) { | 11682 if (IsUsedAt(i)) { |
11699 const intptr_t test_class_id = GetReceiverClassIdAt(i); | 11683 const intptr_t test_class_id = GetReceiverClassIdAt(i); |
11700 if (test_class_id == class_id) { | 11684 if (test_class_id == class_id) { |
11701 return true; | 11685 return true; |
11702 } | 11686 } |
11703 } | 11687 } |
(...skipping 1497 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13201 private: | 13185 private: |
13202 bool has_pointers_; | 13186 bool has_pointers_; |
13203 | 13187 |
13204 DISALLOW_COPY_AND_ASSIGN(CheckForPointers); | 13188 DISALLOW_COPY_AND_ASSIGN(CheckForPointers); |
13205 }; | 13189 }; |
13206 #endif // DEBUG | 13190 #endif // DEBUG |
13207 | 13191 |
13208 | 13192 |
13209 bool Instance::CheckAndCanonicalizeFields(const char** error_str) const { | 13193 bool Instance::CheckAndCanonicalizeFields(const char** error_str) const { |
13210 const Class& cls = Class::Handle(this->clazz()); | 13194 const Class& cls = Class::Handle(this->clazz()); |
13211 if ((cls.id() >= kNumPredefinedCids)) { | 13195 if (cls.id() >= kNumPredefinedCids) { |
13212 // Iterate over all fields, canonicalize numbers and strings, expect all | 13196 // Iterate over all fields, canonicalize numbers and strings, expect all |
13213 // other instances to be canonical otherwise report error (return false). | 13197 // other instances to be canonical otherwise report error (return false). |
13214 Object& obj = Object::Handle(); | 13198 Object& obj = Object::Handle(); |
13215 intptr_t end_field_offset = cls.instance_size() - kWordSize; | 13199 intptr_t end_field_offset = cls.instance_size() - kWordSize; |
13216 for (intptr_t field_offset = 0; | 13200 for (intptr_t field_offset = 0; |
13217 field_offset <= end_field_offset; | 13201 field_offset <= end_field_offset; |
13218 field_offset += kWordSize) { | 13202 field_offset += kWordSize) { |
13219 obj = *this->FieldAddrAtOffset(field_offset); | 13203 obj = *this->FieldAddrAtOffset(field_offset); |
13220 if (obj.IsInstance() && !obj.IsSmi() && !obj.IsCanonical()) { | 13204 if (obj.IsInstance() && !obj.IsSmi() && !obj.IsCanonical()) { |
13221 if (obj.IsNumber() || obj.IsString()) { | 13205 if (obj.IsNumber() || obj.IsString()) { |
(...skipping 2199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
15421 Exceptions::ThrowByType(Exceptions::kJavascriptIntegerOverflowError, | 15405 Exceptions::ThrowByType(Exceptions::kJavascriptIntegerOverflowError, |
15422 exc_args); | 15406 exc_args); |
15423 } | 15407 } |
15424 | 15408 |
15425 | 15409 |
15426 RawInteger* Integer::New(const String& str, Heap::Space space) { | 15410 RawInteger* Integer::New(const String& str, Heap::Space space) { |
15427 // We are not supposed to have integers represented as two byte strings. | 15411 // We are not supposed to have integers represented as two byte strings. |
15428 ASSERT(str.IsOneByteString()); | 15412 ASSERT(str.IsOneByteString()); |
15429 int64_t value; | 15413 int64_t value; |
15430 if (!OS::StringToInt64(str.ToCString(), &value)) { | 15414 if (!OS::StringToInt64(str.ToCString(), &value)) { |
15431 const Bigint& big = Bigint::Handle(Bigint::New(str, space)); | 15415 const Bigint& big = Bigint::Handle( |
15432 ASSERT(!BigintOperations::FitsIntoSmi(big)); | 15416 Bigint::NewFromCString(str.ToCString(), space)); |
15433 ASSERT(!BigintOperations::FitsIntoInt64(big)); | 15417 ASSERT(!big.FitsIntoSmi()); |
| 15418 ASSERT(!big.FitsIntoInt64()); |
15434 if (FLAG_throw_on_javascript_int_overflow) { | 15419 if (FLAG_throw_on_javascript_int_overflow) { |
15435 ThrowJavascriptIntegerOverflow(big); | 15420 ThrowJavascriptIntegerOverflow(big); |
15436 } | 15421 } |
15437 return big.raw(); | 15422 return big.raw(); |
15438 } | 15423 } |
15439 return Integer::New(value, space); | 15424 return Integer::New(value, space); |
15440 } | 15425 } |
15441 | 15426 |
15442 | 15427 |
15443 // This is called from LiteralToken::New() in the parser, so we can't | 15428 // This is called from LiteralToken::New() in the parser, so we can't |
15444 // raise an exception for javascript overflow here. Instead we do it in | 15429 // raise an exception for javascript overflow here. Instead we do it in |
15445 // Parser::CurrentIntegerLiteral(), which is the point in the parser where | 15430 // Parser::CurrentIntegerLiteral(), which is the point in the parser where |
15446 // integer literals escape, so we can call Parser::ErrorMsg(). | 15431 // integer literals escape, so we can call Parser::ErrorMsg(). |
15447 RawInteger* Integer::NewCanonical(const String& str) { | 15432 RawInteger* Integer::NewCanonical(const String& str) { |
15448 // We are not supposed to have integers represented as two byte strings. | 15433 // We are not supposed to have integers represented as two byte strings. |
15449 ASSERT(str.IsOneByteString()); | 15434 ASSERT(str.IsOneByteString()); |
15450 int64_t value; | 15435 int64_t value; |
15451 if (!OS::StringToInt64(str.ToCString(), &value)) { | 15436 if (!OS::StringToInt64(str.ToCString(), &value)) { |
15452 const Bigint& big = Bigint::Handle(Bigint::NewCanonical(str)); | 15437 const Bigint& big = Bigint::Handle(Bigint::NewCanonical(str)); |
15453 ASSERT(!BigintOperations::FitsIntoSmi(big)); | 15438 ASSERT(!big.FitsIntoSmi()); |
15454 ASSERT(!BigintOperations::FitsIntoInt64(big)); | 15439 ASSERT(!big.FitsIntoInt64()); |
15455 return big.raw(); | 15440 return big.raw(); |
15456 } | 15441 } |
15457 if (Smi::IsValid(value)) { | 15442 if (Smi::IsValid(value)) { |
15458 return Smi::New(static_cast<intptr_t>(value)); | 15443 return Smi::New(static_cast<intptr_t>(value)); |
15459 } | 15444 } |
15460 return Mint::NewCanonical(value); | 15445 return Mint::NewCanonical(value); |
15461 } | 15446 } |
15462 | 15447 |
15463 | 15448 |
15464 // dart2js represents integers as double precision floats, which can represent | 15449 // dart2js represents integers as double precision floats, which can represent |
(...skipping 16 matching lines...) Expand all Loading... |
15481 if (is_smi) { | 15466 if (is_smi) { |
15482 return Smi::New(static_cast<intptr_t>(value)); | 15467 return Smi::New(static_cast<intptr_t>(value)); |
15483 } | 15468 } |
15484 return Mint::New(value, space); | 15469 return Mint::New(value, space); |
15485 } | 15470 } |
15486 | 15471 |
15487 | 15472 |
15488 RawInteger* Integer::NewFromUint64(uint64_t value, Heap::Space space) { | 15473 RawInteger* Integer::NewFromUint64(uint64_t value, Heap::Space space) { |
15489 if (value > static_cast<uint64_t>(Mint::kMaxValue)) { | 15474 if (value > static_cast<uint64_t>(Mint::kMaxValue)) { |
15490 if (FLAG_throw_on_javascript_int_overflow) { | 15475 if (FLAG_throw_on_javascript_int_overflow) { |
15491 const Integer &i = | 15476 const Integer &i = Integer::Handle(Bigint::NewFromUint64(value, space)); |
15492 Integer::Handle(BigintOperations::NewFromUint64(value, space)); | |
15493 ThrowJavascriptIntegerOverflow(i); | 15477 ThrowJavascriptIntegerOverflow(i); |
15494 } | 15478 } |
15495 return BigintOperations::NewFromUint64(value, space); | 15479 return Bigint::NewFromUint64(value, space); |
15496 } else { | 15480 } else { |
15497 return Integer::New(value, space); | 15481 return Integer::New(value, space); |
15498 } | 15482 } |
15499 } | 15483 } |
15500 | 15484 |
15501 | 15485 |
| 15486 bool Integer::Equals(const Instance& other) const { |
| 15487 // Integer is an abstract class. |
| 15488 UNREACHABLE(); |
| 15489 return false; |
| 15490 } |
| 15491 |
| 15492 |
| 15493 bool Integer::IsZero() const { |
| 15494 // Integer is an abstract class. |
| 15495 UNREACHABLE(); |
| 15496 return false; |
| 15497 } |
| 15498 |
| 15499 |
| 15500 bool Integer::IsNegative() const { |
| 15501 // Integer is an abstract class. |
| 15502 UNREACHABLE(); |
| 15503 return false; |
| 15504 } |
| 15505 |
| 15506 |
15502 double Integer::AsDoubleValue() const { | 15507 double Integer::AsDoubleValue() const { |
15503 UNIMPLEMENTED(); | 15508 // Integer is an abstract class. |
| 15509 UNREACHABLE(); |
15504 return 0.0; | 15510 return 0.0; |
15505 } | 15511 } |
15506 | 15512 |
15507 | 15513 |
15508 int64_t Integer::AsInt64Value() const { | 15514 int64_t Integer::AsInt64Value() const { |
15509 UNIMPLEMENTED(); | 15515 // Integer is an abstract class. |
| 15516 UNREACHABLE(); |
15510 return 0; | 15517 return 0; |
15511 } | 15518 } |
15512 | 15519 |
15513 | 15520 |
15514 uint32_t Integer::AsTruncatedUint32Value() const { | 15521 uint32_t Integer::AsTruncatedUint32Value() const { |
15515 UNIMPLEMENTED(); | 15522 // Integer is an abstract class. |
| 15523 UNREACHABLE(); |
15516 return 0; | 15524 return 0; |
15517 } | 15525 } |
15518 | 15526 |
15519 | 15527 |
| 15528 bool Integer::FitsIntoSmi() const { |
| 15529 // Integer is an abstract class. |
| 15530 UNREACHABLE(); |
| 15531 return false; |
| 15532 } |
| 15533 |
| 15534 |
15520 int Integer::CompareWith(const Integer& other) const { | 15535 int Integer::CompareWith(const Integer& other) const { |
15521 UNIMPLEMENTED(); | 15536 // Integer is an abstract class. |
| 15537 UNREACHABLE(); |
15522 return 0; | 15538 return 0; |
15523 } | 15539 } |
15524 | 15540 |
15525 | 15541 |
15526 // Returns true if the signed Integer does not fit into a | 15542 // Returns true if the signed Integer does not fit into a |
15527 // Javascript integer. | 15543 // Javascript integer. |
15528 bool Integer::CheckJavascriptIntegerOverflow() const { | 15544 bool Integer::CheckJavascriptIntegerOverflow() const { |
15529 // Always overflow if the value doesn't fit into an int64_t. | 15545 // Always overflow if the value doesn't fit into an int64_t. |
15530 int64_t value = 1ULL << 63; | 15546 int64_t value = 1ULL << 63; |
15531 if (IsSmi()) { | 15547 if (IsSmi()) { |
15532 value = AsInt64Value(); | 15548 value = AsInt64Value(); |
15533 } else if (IsMint()) { | 15549 } else if (IsMint()) { |
15534 Mint& mint = Mint::Handle(); | 15550 Mint& mint = Mint::Handle(); |
15535 mint ^= raw(); | 15551 mint ^= raw(); |
15536 value = mint.value(); | 15552 value = mint.value(); |
15537 } else { | 15553 } else { |
15538 ASSERT(IsBigint()); | 15554 ASSERT(IsBigint()); |
15539 Bigint& big_value = Bigint::Handle(); | 15555 if (Bigint::Cast(*this).FitsIntoInt64()) { |
15540 big_value ^= raw(); | 15556 value = AsInt64Value(); |
15541 if (BigintOperations::FitsIntoInt64(big_value)) { | |
15542 value = BigintOperations::ToInt64(big_value); | |
15543 } | 15557 } |
15544 } | 15558 } |
15545 return !IsJavascriptInt(value); | 15559 return !IsJavascriptInt(value); |
15546 } | 15560 } |
15547 | 15561 |
15548 | 15562 |
15549 RawInteger* Integer::AsValidInteger() const { | 15563 RawInteger* Integer::AsValidInteger() const { |
15550 if (FLAG_throw_on_javascript_int_overflow && | 15564 if (FLAG_throw_on_javascript_int_overflow && |
15551 CheckJavascriptIntegerOverflow()) { | 15565 CheckJavascriptIntegerOverflow()) { |
15552 ThrowJavascriptIntegerOverflow(*this); | 15566 ThrowJavascriptIntegerOverflow(*this); |
15553 } | 15567 } |
15554 if (IsSmi()) return raw(); | 15568 if (IsSmi()) return raw(); |
15555 if (IsMint()) { | 15569 if (IsMint()) { |
15556 Mint& mint = Mint::Handle(); | 15570 Mint& mint = Mint::Handle(); |
15557 mint ^= raw(); | 15571 mint ^= raw(); |
15558 if (Smi::IsValid(mint.value())) { | 15572 if (Smi::IsValid(mint.value())) { |
15559 return Smi::New(static_cast<intptr_t>(mint.value())); | 15573 return Smi::New(static_cast<intptr_t>(mint.value())); |
15560 } else { | 15574 } else { |
15561 return raw(); | 15575 return raw(); |
15562 } | 15576 } |
15563 } | 15577 } |
15564 ASSERT(IsBigint()); | 15578 ASSERT(IsBigint()); |
15565 Bigint& big_value = Bigint::Handle(); | 15579 if (Bigint::Cast(*this).FitsIntoInt64()) { |
15566 big_value ^= raw(); | 15580 const int64_t value = AsInt64Value(); |
15567 if (BigintOperations::FitsIntoSmi(big_value)) { | 15581 if (Smi::IsValid(value)) { |
15568 return BigintOperations::ToSmi(big_value); | 15582 return Smi::New(value); |
15569 } else if (BigintOperations::FitsIntoInt64(big_value)) { | 15583 } |
15570 return Mint::New(BigintOperations::ToInt64(big_value)); | 15584 return Mint::New(value); |
15571 } else { | |
15572 return big_value.raw(); | |
15573 } | 15585 } |
| 15586 return raw(); |
15574 } | 15587 } |
15575 | 15588 |
15576 | 15589 |
15577 RawInteger* Integer::ArithmeticOp(Token::Kind operation, | 15590 RawInteger* Integer::ArithmeticOp(Token::Kind operation, |
15578 const Integer& other) const { | 15591 const Integer& other) const { |
15579 // In 32-bit mode, the result of any operation between two Smis will fit in a | 15592 // In 32-bit mode, the result of any operation between two Smis will fit in a |
15580 // 32-bit signed result, except the product of two Smis, which will be 64-bit. | 15593 // 32-bit signed result, except the product of two Smis, which will be 64-bit. |
15581 // In 64-bit mode, the result of any operation between two Smis will fit in a | 15594 // In 64-bit mode, the result of any operation between two Smis will fit in a |
15582 // 64-bit signed result, except the product of two Smis (see below). | 15595 // 64-bit signed result, except the product of two Smis (see below). |
15583 if (IsSmi() && other.IsSmi()) { | 15596 if (IsSmi() && other.IsSmi()) { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
15616 } else { | 15629 } else { |
15617 return Integer::New(remainder + right_value); | 15630 return Integer::New(remainder + right_value); |
15618 } | 15631 } |
15619 } | 15632 } |
15620 return Integer::New(remainder); | 15633 return Integer::New(remainder); |
15621 } | 15634 } |
15622 default: | 15635 default: |
15623 UNIMPLEMENTED(); | 15636 UNIMPLEMENTED(); |
15624 } | 15637 } |
15625 } | 15638 } |
15626 // In 32-bit mode, the result of any operation (except multiplication) between | 15639 if (!IsBigint() && !other.IsBigint()) { |
15627 // two 63-bit signed integers will fit in a 64-bit signed result. | |
15628 // For the multiplication result to fit, the sum of the highest bits of the | |
15629 // absolute values of the operands must be smaller than 62. | |
15630 // In 64-bit mode, 63-bit signed integers are Smis, already processed above. | |
15631 if ((Smi::kBits < 32) && !IsBigint() && !other.IsBigint()) { | |
15632 const int64_t left_value = AsInt64Value(); | 15640 const int64_t left_value = AsInt64Value(); |
15633 const int64_t right_value = other.AsInt64Value(); | 15641 const int64_t right_value = other.AsInt64Value(); |
15634 if (operation == Token::kMUL) { | 15642 switch (operation) { |
15635 if ((Utils::HighestBit(left_value) + | 15643 case Token::kADD: { |
15636 Utils::HighestBit(right_value)) < 62) { | 15644 if (((left_value < 0) != (right_value < 0)) || |
15637 return Integer::New(left_value * right_value); | 15645 ((left_value + right_value) < 0) == (left_value < 0)) { |
| 15646 return Integer::New(left_value + right_value); |
| 15647 } |
| 15648 break; |
15638 } | 15649 } |
15639 // Perform a Bigint multiplication below. | 15650 case Token::kSUB: { |
15640 } else if (Utils::IsInt(63, left_value) && Utils::IsInt(63, right_value)) { | 15651 if (((left_value < 0) == (right_value < 0)) || |
15641 switch (operation) { | 15652 ((left_value - right_value) < 0) == (left_value < 0)) { |
15642 case Token::kADD: | 15653 return Integer::New(left_value - right_value); |
15643 return Integer::New(left_value + right_value); | 15654 } |
15644 case Token::kSUB: | 15655 break; |
15645 return Integer::New(left_value - right_value); | 15656 } |
15646 case Token::kTRUNCDIV: | 15657 case Token::kMUL: { |
15647 return Integer::New(left_value / right_value); | 15658 if ((Utils::HighestBit(left_value) + |
| 15659 Utils::HighestBit(right_value)) < 62) { |
| 15660 return Integer::New(left_value * right_value); |
| 15661 } |
| 15662 break; |
| 15663 } |
| 15664 case Token::kTRUNCDIV: { |
| 15665 if ((left_value != Mint::kMinValue) || (right_value != -1)) { |
| 15666 return Integer::New(left_value / right_value); |
| 15667 } |
| 15668 break; |
| 15669 } |
15648 case Token::kMOD: { | 15670 case Token::kMOD: { |
15649 const int64_t remainder = left_value % right_value; | 15671 const int64_t remainder = left_value % right_value; |
15650 if (remainder < 0) { | 15672 if (remainder < 0) { |
15651 if (right_value < 0) { | 15673 if (right_value < 0) { |
15652 return Integer::New(remainder - right_value); | 15674 return Integer::New(remainder - right_value); |
15653 } else { | 15675 } else { |
15654 return Integer::New(remainder + right_value); | 15676 return Integer::New(remainder + right_value); |
15655 } | 15677 } |
15656 } | 15678 } |
15657 return Integer::New(remainder); | 15679 return Integer::New(remainder); |
15658 } | 15680 } |
15659 default: | 15681 default: |
15660 UNIMPLEMENTED(); | 15682 UNIMPLEMENTED(); |
15661 } | |
15662 } | 15683 } |
15663 } | 15684 } |
15664 const Bigint& left_big = Bigint::Handle(AsBigint()); | 15685 return Integer::null(); // Notify caller that a bigint operation is required. |
15665 const Bigint& right_big = Bigint::Handle(other.AsBigint()); | |
15666 const Bigint& result = | |
15667 Bigint::Handle(left_big.BigArithmeticOp(operation, right_big)); | |
15668 return Integer::Handle(result.AsValidInteger()).raw(); | |
15669 } | 15686 } |
15670 | 15687 |
15671 | 15688 |
15672 static bool Are64bitOperands(const Integer& op1, const Integer& op2) { | 15689 static bool Are64bitOperands(const Integer& op1, const Integer& op2) { |
15673 return !op1.IsBigint() && !op2.IsBigint(); | 15690 return !op1.IsBigint() && !op2.IsBigint(); |
15674 } | 15691 } |
15675 | 15692 |
15676 | 15693 |
15677 RawInteger* Integer::BitOp(Token::Kind kind, const Integer& other) const { | 15694 RawInteger* Integer::BitOp(Token::Kind kind, const Integer& other) const { |
15678 if (IsSmi() && other.IsSmi()) { | 15695 if (IsSmi() && other.IsSmi()) { |
(...skipping 21 matching lines...) Expand all Loading... |
15700 switch (kind) { | 15717 switch (kind) { |
15701 case Token::kBIT_AND: | 15718 case Token::kBIT_AND: |
15702 return Integer::New(a & b); | 15719 return Integer::New(a & b); |
15703 case Token::kBIT_OR: | 15720 case Token::kBIT_OR: |
15704 return Integer::New(a | b); | 15721 return Integer::New(a | b); |
15705 case Token::kBIT_XOR: | 15722 case Token::kBIT_XOR: |
15706 return Integer::New(a ^ b); | 15723 return Integer::New(a ^ b); |
15707 default: | 15724 default: |
15708 UNIMPLEMENTED(); | 15725 UNIMPLEMENTED(); |
15709 } | 15726 } |
15710 } else { | |
15711 Bigint& op1 = Bigint::Handle(AsBigint()); | |
15712 Bigint& op2 = Bigint::Handle(other.AsBigint()); | |
15713 switch (kind) { | |
15714 case Token::kBIT_AND: | |
15715 return BigintOperations::BitAnd(op1, op2); | |
15716 case Token::kBIT_OR: | |
15717 return BigintOperations::BitOr(op1, op2); | |
15718 case Token::kBIT_XOR: | |
15719 return BigintOperations::BitXor(op1, op2); | |
15720 default: | |
15721 UNIMPLEMENTED(); | |
15722 } | |
15723 } | 15727 } |
15724 return Integer::null(); | 15728 return Integer::null(); // Notify caller that a bigint operation is required. |
15725 } | 15729 } |
15726 | 15730 |
15727 | 15731 |
15728 // TODO(srdjan): Clarify handling of negative right operand in a shift op. | 15732 // TODO(srdjan): Clarify handling of negative right operand in a shift op. |
15729 RawInteger* Smi::ShiftOp(Token::Kind kind, | 15733 RawInteger* Smi::ShiftOp(Token::Kind kind, |
15730 const Smi& other, | 15734 const Smi& other, |
15731 const bool silent) const { | 15735 const bool silent) const { |
15732 intptr_t result = 0; | 15736 intptr_t result = 0; |
15733 const intptr_t left_value = Value(); | 15737 const intptr_t left_value = Value(); |
15734 const intptr_t right_value = other.Value(); | 15738 const intptr_t right_value = other.Value(); |
15735 ASSERT(right_value >= 0); | 15739 ASSERT(right_value >= 0); |
15736 switch (kind) { | 15740 switch (kind) { |
15737 case Token::kSHL: { | 15741 case Token::kSHL: { |
15738 if ((left_value == 0) || (right_value == 0)) { | 15742 if ((left_value == 0) || (right_value == 0)) { |
15739 return raw(); | 15743 return raw(); |
15740 } | 15744 } |
15741 { // Check for overflow. | 15745 { // Check for overflow. |
15742 int cnt = Utils::HighestBit(left_value); | 15746 int cnt = Utils::HighestBit(left_value); |
15743 if ((cnt + right_value) >= Smi::kBits) { | 15747 if ((cnt + right_value) >= Smi::kBits) { |
15744 if ((cnt + right_value) >= Mint::kBits) { | 15748 if ((cnt + right_value) >= Mint::kBits) { |
15745 return BigintOperations::ShiftLeft( | 15749 return Bigint::NewFromShiftedInt64(left_value, right_value); |
15746 Bigint::Handle(BigintOperations::NewFromSmi(*this)), | |
15747 right_value); | |
15748 } else { | 15750 } else { |
15749 int64_t left_64 = left_value; | 15751 int64_t left_64 = left_value; |
15750 return Integer::New(left_64 << right_value, Heap::kNew, silent); | 15752 return Integer::New(left_64 << right_value, Heap::kNew, silent); |
15751 } | 15753 } |
15752 } | 15754 } |
15753 } | 15755 } |
15754 result = left_value << right_value; | 15756 result = left_value << right_value; |
15755 break; | 15757 break; |
15756 } | 15758 } |
15757 case Token::kSHR: { | 15759 case Token::kSHR: { |
(...skipping 26 matching lines...) Expand all Loading... |
15784 int64_t Smi::AsInt64Value() const { | 15786 int64_t Smi::AsInt64Value() const { |
15785 return this->Value(); | 15787 return this->Value(); |
15786 } | 15788 } |
15787 | 15789 |
15788 | 15790 |
15789 uint32_t Smi::AsTruncatedUint32Value() const { | 15791 uint32_t Smi::AsTruncatedUint32Value() const { |
15790 return this->Value() & 0xFFFFFFFF; | 15792 return this->Value() & 0xFFFFFFFF; |
15791 } | 15793 } |
15792 | 15794 |
15793 | 15795 |
15794 static bool FitsIntoSmi(const Integer& integer) { | |
15795 if (integer.IsSmi()) { | |
15796 return true; | |
15797 } | |
15798 if (integer.IsMint()) { | |
15799 int64_t mint_value = integer.AsInt64Value(); | |
15800 return Smi::IsValid(mint_value); | |
15801 } | |
15802 if (integer.IsBigint()) { | |
15803 return BigintOperations::FitsIntoSmi(Bigint::Cast(integer)); | |
15804 } | |
15805 UNREACHABLE(); | |
15806 return false; | |
15807 } | |
15808 | |
15809 | |
15810 int Smi::CompareWith(const Integer& other) const { | 15796 int Smi::CompareWith(const Integer& other) const { |
15811 if (other.IsSmi()) { | 15797 if (other.IsSmi()) { |
15812 const Smi& other_smi = Smi::Cast(other); | 15798 const Smi& other_smi = Smi::Cast(other); |
15813 if (this->Value() < other_smi.Value()) { | 15799 if (this->Value() < other_smi.Value()) { |
15814 return -1; | 15800 return -1; |
15815 } else if (this->Value() > other_smi.Value()) { | 15801 } else if (this->Value() > other_smi.Value()) { |
15816 return 1; | 15802 return 1; |
15817 } else { | 15803 } else { |
15818 return 0; | 15804 return 0; |
15819 } | 15805 } |
15820 } | 15806 } |
15821 ASSERT(!FitsIntoSmi(other)); | 15807 ASSERT(!other.FitsIntoSmi()); |
15822 if (other.IsMint() || other.IsBigint()) { | 15808 if (other.IsMint() || other.IsBigint()) { |
15823 if (this->IsNegative() == other.IsNegative()) { | 15809 if (this->IsNegative() == other.IsNegative()) { |
15824 return this->IsNegative() ? 1 : -1; | 15810 return this->IsNegative() ? 1 : -1; |
15825 } | 15811 } |
15826 return this->IsNegative() ? -1 : 1; | 15812 return this->IsNegative() ? -1 : 1; |
15827 } | 15813 } |
15828 UNREACHABLE(); | 15814 UNREACHABLE(); |
15829 return 0; | 15815 return 0; |
15830 } | 15816 } |
15831 | 15817 |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
15925 int64_t Mint::AsInt64Value() const { | 15911 int64_t Mint::AsInt64Value() const { |
15926 return this->value(); | 15912 return this->value(); |
15927 } | 15913 } |
15928 | 15914 |
15929 | 15915 |
15930 uint32_t Mint::AsTruncatedUint32Value() const { | 15916 uint32_t Mint::AsTruncatedUint32Value() const { |
15931 return this->value() & 0xFFFFFFFF; | 15917 return this->value() & 0xFFFFFFFF; |
15932 } | 15918 } |
15933 | 15919 |
15934 | 15920 |
| 15921 bool Mint::FitsIntoSmi() const { |
| 15922 return Smi::IsValid(AsInt64Value()); |
| 15923 } |
| 15924 |
| 15925 |
15935 int Mint::CompareWith(const Integer& other) const { | 15926 int Mint::CompareWith(const Integer& other) const { |
15936 ASSERT(!FitsIntoSmi(*this)); | 15927 ASSERT(!FitsIntoSmi()); |
15937 if (other.IsMint() || other.IsSmi()) { | 15928 if (other.IsMint() || other.IsSmi()) { |
15938 int64_t a = AsInt64Value(); | 15929 int64_t a = AsInt64Value(); |
15939 int64_t b = other.AsInt64Value(); | 15930 int64_t b = other.AsInt64Value(); |
15940 if (a < b) { | 15931 if (a < b) { |
15941 return -1; | 15932 return -1; |
15942 } else if (a > b) { | 15933 } else if (a > b) { |
15943 return 1; | 15934 return 1; |
15944 } else { | 15935 } else { |
15945 return 0; | 15936 return 0; |
15946 } | 15937 } |
15947 } | 15938 } |
15948 if (other.IsBigint()) { | 15939 ASSERT(other.IsBigint()); |
15949 ASSERT(!BigintOperations::FitsIntoInt64(Bigint::Cast(other))); | 15940 ASSERT(!Bigint::Cast(other).FitsIntoInt64()); |
15950 if (this->IsNegative() == other.IsNegative()) { | 15941 if (this->IsNegative() == other.IsNegative()) { |
15951 return this->IsNegative() ? 1 : -1; | 15942 return this->IsNegative() ? 1 : -1; |
15952 } | |
15953 return this->IsNegative() ? -1 : 1; | |
15954 } | 15943 } |
15955 UNREACHABLE(); | 15944 return this->IsNegative() ? -1 : 1; |
15956 return 0; | |
15957 } | 15945 } |
15958 | 15946 |
15959 | 15947 |
15960 const char* Mint::ToCString() const { | 15948 const char* Mint::ToCString() const { |
15961 const char* kFormat = "%lld"; | 15949 const char* kFormat = "%lld"; |
15962 // Calculate the size of the string. | 15950 // Calculate the size of the string. |
15963 intptr_t len = OS::SNPrint(NULL, 0, kFormat, value()) + 1; | 15951 intptr_t len = OS::SNPrint(NULL, 0, kFormat, value()) + 1; |
15964 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); | 15952 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); |
15965 OS::SNPrint(chars, len, kFormat, value()); | 15953 OS::SNPrint(chars, len, kFormat, value()); |
15966 return chars; | 15954 return chars; |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
16097 DoubleToCString(value(), buffer, kBufferSize); | 16085 DoubleToCString(value(), buffer, kBufferSize); |
16098 return buffer; | 16086 return buffer; |
16099 } | 16087 } |
16100 | 16088 |
16101 | 16089 |
16102 void Double::PrintJSONImpl(JSONStream* stream, bool ref) const { | 16090 void Double::PrintJSONImpl(JSONStream* stream, bool ref) const { |
16103 Number::PrintJSONImpl(stream, ref); | 16091 Number::PrintJSONImpl(stream, ref); |
16104 } | 16092 } |
16105 | 16093 |
16106 | 16094 |
16107 RawBigint* Integer::AsBigint() const { | 16095 void Bigint::set_neg(const Bool& value) const { |
16108 ASSERT(!IsNull()); | 16096 StorePointer(&raw_ptr()->neg_, value.raw()); |
16109 if (IsSmi()) { | |
16110 Smi& smi = Smi::Handle(); | |
16111 smi ^= raw(); | |
16112 return BigintOperations::NewFromSmi(smi); | |
16113 } else if (IsMint()) { | |
16114 Mint& mint = Mint::Handle(); | |
16115 mint ^= raw(); | |
16116 return BigintOperations::NewFromInt64(mint.value()); | |
16117 } else { | |
16118 ASSERT(IsBigint()); | |
16119 Bigint& big = Bigint::Handle(); | |
16120 big ^= raw(); | |
16121 ASSERT(!BigintOperations::FitsIntoSmi(big)); | |
16122 return big.raw(); | |
16123 } | |
16124 } | 16097 } |
16125 | 16098 |
16126 | 16099 |
16127 RawBigint* Bigint::BigArithmeticOp(Token::Kind operation, | 16100 void Bigint::set_used(const Smi& value) const { |
16128 const Bigint& other) const { | 16101 raw_ptr()->used_ = value.raw(); |
16129 switch (operation) { | 16102 } |
16130 case Token::kADD: | 16103 |
16131 return BigintOperations::Add(*this, other); | 16104 |
16132 case Token::kSUB: | 16105 void Bigint::set_digits(const TypedData& value) const { |
16133 return BigintOperations::Subtract(*this, other); | 16106 StorePointer(&raw_ptr()->digits_, value.raw()); |
16134 case Token::kMUL: | 16107 } |
16135 return BigintOperations::Multiply(*this, other); | 16108 |
16136 case Token::kTRUNCDIV: | 16109 |
16137 return BigintOperations::Divide(*this, other); | 16110 bool Bigint::Neg() const { |
16138 case Token::kMOD: | 16111 return Bool::Handle(neg()).value(); |
16139 return BigintOperations::Modulo(*this, other); | 16112 } |
16140 default: | 16113 |
16141 UNIMPLEMENTED(); | 16114 |
16142 return Bigint::null(); | 16115 void Bigint::SetNeg(bool value) const { |
16143 } | 16116 set_neg(Bool::Get(value)); |
| 16117 } |
| 16118 |
| 16119 |
| 16120 intptr_t Bigint::Used() const { |
| 16121 return Smi::Value(used()); |
| 16122 } |
| 16123 |
| 16124 |
| 16125 void Bigint::SetUsed(intptr_t value) const { |
| 16126 set_used(Smi::Handle(Smi::New(value))); |
| 16127 } |
| 16128 |
| 16129 |
| 16130 uint32_t Bigint::DigitAt(intptr_t index) const { |
| 16131 const TypedData& typed_data = TypedData::Handle(digits()); |
| 16132 return typed_data.GetUint32(index << 2); |
| 16133 } |
| 16134 |
| 16135 |
| 16136 void Bigint::SetDigitAt(intptr_t index, uint32_t value) const { |
| 16137 const TypedData& typed_data = TypedData::Handle(digits()); |
| 16138 typed_data.SetUint32(index << 2, value); |
16144 } | 16139 } |
16145 | 16140 |
16146 | 16141 |
16147 bool Bigint::Equals(const Instance& other) const { | 16142 bool Bigint::Equals(const Instance& other) const { |
16148 if (this->raw() == other.raw()) { | 16143 if (this->raw() == other.raw()) { |
16149 // Both handles point to the same raw instance. | 16144 // Both handles point to the same raw instance. |
16150 return true; | 16145 return true; |
16151 } | 16146 } |
16152 | 16147 |
16153 if (!other.IsBigint() || other.IsNull()) { | 16148 if (!other.IsBigint() || other.IsNull()) { |
16154 return false; | 16149 return false; |
16155 } | 16150 } |
16156 | 16151 |
16157 const Bigint& other_bgi = Bigint::Cast(other); | 16152 const Bigint& other_bgi = Bigint::Cast(other); |
16158 | 16153 |
16159 if (this->IsNegative() != other_bgi.IsNegative()) { | 16154 if (this->Neg() != other_bgi.Neg()) { |
16160 return false; | 16155 return false; |
16161 } | 16156 } |
16162 | 16157 |
16163 intptr_t len = this->Length(); | 16158 const intptr_t used = this->Used(); |
16164 if (len != other_bgi.Length()) { | 16159 if (used != other_bgi.Used()) { |
16165 return false; | 16160 return false; |
16166 } | 16161 } |
16167 | 16162 |
16168 for (intptr_t i = 0; i < len; i++) { | 16163 for (intptr_t i = 0; i < used; i++) { |
16169 if (this->GetChunkAt(i) != other_bgi.GetChunkAt(i)) { | 16164 if (this->DigitAt(i) != other_bgi.DigitAt(i)) { |
16170 return false; | 16165 return false; |
16171 } | 16166 } |
16172 } | 16167 } |
16173 return true; | 16168 return true; |
16174 } | 16169 } |
16175 | 16170 |
16176 | 16171 |
16177 RawBigint* Bigint::New(const String& str, Heap::Space space) { | 16172 bool Bigint::CheckAndCanonicalizeFields(const char** error_str) const { |
16178 const Bigint& result = Bigint::Handle( | 16173 // Bool field neg should always be canonical. |
16179 BigintOperations::NewFromCString(str.ToCString(), space)); | 16174 ASSERT(Bool::Handle(neg()).IsCanonical()); |
16180 ASSERT(!BigintOperations::FitsIntoInt64(result)); | 16175 // Smi field used is canonical by definition. |
| 16176 if (Used() > 0) { |
| 16177 // Canonicalize TypedData field digits. |
| 16178 TypedData& digits_ = TypedData::Handle(digits()); |
| 16179 digits_ ^= digits_.CheckAndCanonicalize(NULL); |
| 16180 ASSERT(!digits_.IsNull()); |
| 16181 set_digits(digits_); |
| 16182 } else { |
| 16183 ASSERT(digits() == TypedData::null()); |
| 16184 } |
| 16185 return true; |
| 16186 } |
| 16187 |
| 16188 |
| 16189 RawBigint* Bigint::New(Heap::Space space) { |
| 16190 ASSERT(Isolate::Current()->object_store()->bigint_class() != Class::null()); |
| 16191 Bigint& result = Bigint::Handle(); |
| 16192 { |
| 16193 RawObject* raw = Object::Allocate(Bigint::kClassId, |
| 16194 Bigint::InstanceSize(), |
| 16195 space); |
| 16196 NoGCScope no_gc; |
| 16197 result ^= raw; |
| 16198 } |
| 16199 result.set_neg(Bool::Get(false)); |
| 16200 result.set_used(Smi::Handle(Smi::New(0))); |
16181 return result.raw(); | 16201 return result.raw(); |
16182 } | 16202 } |
16183 | 16203 |
16184 | 16204 |
| 16205 RawBigint* Bigint::NewFromInt64(int64_t value, Heap::Space space) { |
| 16206 const Bigint& result = Bigint::Handle(New(space)); |
| 16207 result.EnsureLength(2, space); |
| 16208 result.SetUsed(2); |
| 16209 if (value < 0) { |
| 16210 result.SetNeg(true); |
| 16211 value = -value; // No concern about overflow, since sign is captured. |
| 16212 } |
| 16213 result.SetDigitAt(0, static_cast<uint32_t>(value)); |
| 16214 result.SetDigitAt(1, static_cast<uint32_t>(value >> 32)); // value >= 0. |
| 16215 result.Clamp(); |
| 16216 return result.raw(); |
| 16217 } |
| 16218 |
| 16219 |
| 16220 RawBigint* Bigint::NewFromUint64(uint64_t value, Heap::Space space) { |
| 16221 const Bigint& result = Bigint::Handle(New(space)); |
| 16222 result.EnsureLength(2, space); |
| 16223 result.SetUsed(2); |
| 16224 result.SetDigitAt(0, static_cast<uint32_t>(value)); |
| 16225 result.SetDigitAt(1, static_cast<uint32_t>(value >> 32)); |
| 16226 result.Clamp(); |
| 16227 return result.raw(); |
| 16228 } |
| 16229 |
| 16230 |
| 16231 RawBigint* Bigint::NewFromShiftedInt64(int64_t value, intptr_t shift, |
| 16232 Heap::Space space) { |
| 16233 ASSERT(kBitsPerDigit == 32); |
| 16234 ASSERT(shift >= 0); |
| 16235 const Bigint& result = Bigint::Handle(New(space)); |
| 16236 const intptr_t digit_shift = shift / kBitsPerDigit; |
| 16237 const intptr_t bit_shift = shift % kBitsPerDigit; |
| 16238 result.EnsureLength(3 + digit_shift, space); |
| 16239 result.SetUsed(3 + digit_shift); |
| 16240 uint64_t abs_value; |
| 16241 if (value < 0) { |
| 16242 result.SetNeg(true); |
| 16243 abs_value = -value; // No concern about overflow, since sign is captured. |
| 16244 } else { |
| 16245 abs_value = value; |
| 16246 } |
| 16247 for (intptr_t i = 0; i < digit_shift; i++) { |
| 16248 result.SetDigitAt(i, 0); |
| 16249 } |
| 16250 result.SetDigitAt(0 + digit_shift, |
| 16251 static_cast<uint32_t>(abs_value << bit_shift)); |
| 16252 result.SetDigitAt(1 + digit_shift, |
| 16253 static_cast<uint32_t>(abs_value >> (32 - bit_shift))); |
| 16254 result.SetDigitAt(2 + digit_shift, |
| 16255 (bit_shift == 0) ? 0 |
| 16256 : static_cast<uint32_t>(abs_value >> (64 - bit_shift))); |
| 16257 result.Clamp(); |
| 16258 return result.raw(); |
| 16259 } |
| 16260 |
| 16261 |
| 16262 void Bigint::EnsureLength(intptr_t length, Heap::Space space) const { |
| 16263 ASSERT(length >= 0); |
| 16264 TypedData& old_digits = TypedData::Handle(digits()); |
| 16265 if ((length > 0) && (old_digits.IsNull() || (length > old_digits.Length()))) { |
| 16266 TypedData& new_digits = TypedData::Handle( |
| 16267 TypedData::New(kTypedDataUint32ArrayCid, length + kExtraDigits, space)); |
| 16268 if (!old_digits.IsNull()) { |
| 16269 TypedData::Copy(new_digits, TypedData::data_offset(), |
| 16270 old_digits, TypedData::data_offset(), |
| 16271 old_digits.LengthInBytes()); |
| 16272 } |
| 16273 set_digits(new_digits); |
| 16274 } |
| 16275 } |
| 16276 |
| 16277 |
| 16278 void Bigint::Clamp() const { |
| 16279 intptr_t used = Used(); |
| 16280 while ((used > 0) && (DigitAt(used - 1) == 0)) { |
| 16281 --used; |
| 16282 } |
| 16283 SetUsed(used); |
| 16284 } |
| 16285 |
| 16286 |
| 16287 bool Bigint::IsClamped() const { |
| 16288 intptr_t used = Used(); |
| 16289 return (used == 0) || (DigitAt(used - 1) > 0); |
| 16290 } |
| 16291 |
| 16292 |
| 16293 RawBigint* Bigint::NewFromCString(const char* str, Heap::Space space) { |
| 16294 ASSERT(str != NULL); |
| 16295 if (str[0] == '\0') { |
| 16296 return NewFromInt64(0, space); |
| 16297 } |
| 16298 |
| 16299 // If the string starts with '-' recursively restart the whole operation |
| 16300 // without the character and then toggle the sign. |
| 16301 // This allows multiple leading '-' (which will cancel each other out), but |
| 16302 // we have added an assert, to make sure that the returned result of the |
| 16303 // recursive call is not negative. |
| 16304 // We don't catch leading '-'s for zero. Ex: "--0", or "---". |
| 16305 if (str[0] == '-') { |
| 16306 const Bigint& result = Bigint::Handle(NewFromCString(&str[1], space)); |
| 16307 result.SetNeg(!result.Neg()); // Toggle sign. |
| 16308 ASSERT(result.IsZero() || result.IsNegative()); |
| 16309 ASSERT(result.IsClamped()); |
| 16310 return result.raw(); |
| 16311 } |
| 16312 |
| 16313 // No overflow check needed since overflowing str_length implies that we take |
| 16314 // the branch to NewFromDecCString() which contains a check itself. |
| 16315 const intptr_t str_length = strlen(str); |
| 16316 if ((str_length > 2) && |
| 16317 (str[0] == '0') && |
| 16318 ((str[1] == 'x') || (str[1] == 'X'))) { |
| 16319 const Bigint& result = Bigint::Handle(NewFromHexCString(&str[2], space)); |
| 16320 ASSERT(result.IsClamped()); |
| 16321 return result.raw(); |
| 16322 } else { |
| 16323 return NewFromDecCString(str, space); |
| 16324 } |
| 16325 } |
| 16326 |
| 16327 |
16185 RawBigint* Bigint::NewCanonical(const String& str) { | 16328 RawBigint* Bigint::NewCanonical(const String& str) { |
16186 const Bigint& value = Bigint::Handle( | 16329 const Bigint& value = Bigint::Handle( |
16187 BigintOperations::NewFromCString(str.ToCString(), Heap::kOld)); | 16330 Bigint::NewFromCString(str.ToCString(), Heap::kOld)); |
16188 ASSERT(!BigintOperations::FitsIntoInt64(value)); | |
16189 const Class& cls = | 16331 const Class& cls = |
16190 Class::Handle(Isolate::Current()->object_store()->bigint_class()); | 16332 Class::Handle(Isolate::Current()->object_store()->bigint_class()); |
16191 const Array& constants = Array::Handle(cls.constants()); | 16333 const Array& constants = Array::Handle(cls.constants()); |
16192 const intptr_t constants_len = constants.Length(); | 16334 const intptr_t constants_len = constants.Length(); |
16193 // Linear search to see whether this value is already present in the | 16335 // Linear search to see whether this value is already present in the |
16194 // list of canonicalized constants. | 16336 // list of canonicalized constants. |
16195 Bigint& canonical_value = Bigint::Handle(); | 16337 Bigint& canonical_value = Bigint::Handle(); |
16196 intptr_t index = 0; | 16338 intptr_t index = 0; |
16197 while (index < constants_len) { | 16339 while (index < constants_len) { |
16198 canonical_value ^= constants.At(index); | 16340 canonical_value ^= constants.At(index); |
16199 if (canonical_value.IsNull()) { | 16341 if (canonical_value.IsNull()) { |
16200 break; | 16342 break; |
16201 } | 16343 } |
16202 if (canonical_value.Equals(value)) { | 16344 if (canonical_value.Equals(value)) { |
16203 return canonical_value.raw(); | 16345 return canonical_value.raw(); |
16204 } | 16346 } |
16205 index++; | 16347 index++; |
16206 } | 16348 } |
16207 // The value needs to be added to the constants list. Grow the list if | 16349 // The value needs to be added to the constants list. Grow the list if |
16208 // it is full. | 16350 // it is full. |
16209 cls.InsertCanonicalConstant(index, value); | 16351 cls.InsertCanonicalConstant(index, value); |
16210 value.SetCanonical(); | 16352 value.SetCanonical(); |
16211 return value.raw(); | 16353 return value.raw(); |
16212 } | 16354 } |
16213 | 16355 |
16214 | 16356 |
| 16357 RawBigint* Bigint::NewFromHexCString(const char* str, Heap::Space space) { |
| 16358 // TODO(regis): Do we need to check for max length? |
| 16359 // If the string starts with '-' recursively restart the whole operation |
| 16360 // without the character and then toggle the sign. |
| 16361 // This allows multiple leading '-' (which will cancel each other out), but |
| 16362 // we have added an assert, to make sure that the returned result of the |
| 16363 // recursive call is not negative. |
| 16364 // We don't catch leading '-'s for zero. Ex: "--0", or "---". |
| 16365 if (str[0] == '-') { |
| 16366 const Bigint& result = Bigint::Handle(NewFromHexCString(&str[1], space)); |
| 16367 result.SetNeg(!result.Neg()); // Toggle sign. |
| 16368 ASSERT(result.IsZero() || result.IsNegative()); |
| 16369 ASSERT(result.IsClamped()); |
| 16370 return result.raw(); |
| 16371 } |
| 16372 const Bigint& result = Bigint::Handle(New(space)); |
| 16373 const int kBitsPerHexDigit = 4; |
| 16374 const int kHexDigitsPerDigit = 8; |
| 16375 const int kBitsPerDigit = kBitsPerHexDigit * kHexDigitsPerDigit; |
| 16376 intptr_t hex_i = strlen(str); // Terminating byte excluded. |
| 16377 result.EnsureLength((hex_i + kHexDigitsPerDigit - 1) / kHexDigitsPerDigit, |
| 16378 space); |
| 16379 intptr_t used_ = 0; |
| 16380 uint32_t digit = 0; |
| 16381 intptr_t bit_i = 0; |
| 16382 while (--hex_i >= 0) { |
| 16383 digit += Utils::HexDigitToInt(str[hex_i]) << bit_i; |
| 16384 bit_i += kBitsPerHexDigit; |
| 16385 if (bit_i == kBitsPerDigit) { |
| 16386 bit_i = 0; |
| 16387 result.SetDigitAt(used_++, digit); |
| 16388 digit = 0; |
| 16389 } |
| 16390 } |
| 16391 if (bit_i != 0) { |
| 16392 result.SetDigitAt(used_++, digit); |
| 16393 } |
| 16394 result.SetUsed(used_); |
| 16395 result.Clamp(); |
| 16396 return result.raw(); |
| 16397 } |
| 16398 |
| 16399 |
| 16400 RawBigint* Bigint::NewFromDecCString(const char* str, Heap::Space space) { |
| 16401 // Read 9 digits a time. 10^9 < 2^32. |
| 16402 const int kDecDigitsPerIteration = 9; |
| 16403 const uint32_t kTenMultiplier = 1000000000; |
| 16404 ASSERT(kBitsPerDigit == 32); |
| 16405 |
| 16406 const intptr_t str_length = strlen(str); |
| 16407 if (str_length < 0) { // TODO(regis): Pick a smaller limit. |
| 16408 FATAL("Fatal error in Bigint::NewFromDecCString: string too long"); |
| 16409 } |
| 16410 intptr_t str_pos = 0; |
| 16411 |
| 16412 Bigint& result = Bigint::Handle(Bigint::New(space)); |
| 16413 // One decimal digit takes log2(10) bits, i.e. ~3.32192809489 bits. |
| 16414 // That is a theoretical limit for large numbers. |
| 16415 // The extra digits allocated take care of variations (kExtraDigits). |
| 16416 const int64_t kLog10Dividend = 33219281; |
| 16417 const int64_t kLog10Divisor = 10000000; |
| 16418 result.EnsureLength((kLog10Dividend * str_length) / |
| 16419 (kLog10Divisor * kBitsPerDigit), space); |
| 16420 |
| 16421 // Read first digit separately. This avoids a multiplication and addition. |
| 16422 // The first digit might also not have kDecDigitsPerIteration decimal digits. |
| 16423 const intptr_t lsdigit_length = str_length % kDecDigitsPerIteration; |
| 16424 uint32_t digit = 0; |
| 16425 for (intptr_t i = 0; i < lsdigit_length; i++) { |
| 16426 char c = str[str_pos++]; |
| 16427 ASSERT(('0' <= c) && (c <= '9')); |
| 16428 digit = digit * 10 + c - '0'; |
| 16429 } |
| 16430 result.SetDigitAt(0, digit); |
| 16431 intptr_t used = 1; |
| 16432 |
| 16433 // Read kDecDigitsPerIteration at a time, and store it in 'digit'. |
| 16434 // Then multiply the temporary result by 10^kDecDigitsPerIteration and add |
| 16435 // 'digit' to the new result. |
| 16436 while (str_pos < str_length - 1) { |
| 16437 digit = 0; |
| 16438 for (intptr_t i = 0; i < kDecDigitsPerIteration; i++) { |
| 16439 char c = str[str_pos++]; |
| 16440 ASSERT(('0' <= c) && (c <= '9')); |
| 16441 digit = digit * 10 + c - '0'; |
| 16442 } |
| 16443 // Multiply result with kTenMultiplier and add digit. |
| 16444 for (intptr_t i = 0; i < used; i++) { |
| 16445 uint64_t product = |
| 16446 (static_cast<uint64_t>(result.DigitAt(i)) * kTenMultiplier) + digit; |
| 16447 result.SetDigitAt(i, static_cast<uint32_t>(product & kDigitMask)); |
| 16448 digit = static_cast<uint32_t>(product >> kBitsPerDigit); |
| 16449 } |
| 16450 result.SetDigitAt(used++, digit); |
| 16451 } |
| 16452 result.SetUsed(used); |
| 16453 result.Clamp(); |
| 16454 return result.raw(); |
| 16455 } |
| 16456 |
| 16457 |
| 16458 static double Uint64ToDouble(uint64_t x) { |
| 16459 #if _WIN64 |
| 16460 // For static_cast<double>(x) MSVC x64 generates |
| 16461 // |
| 16462 // cvtsi2sd xmm0, rax |
| 16463 // test rax, rax |
| 16464 // jns done |
| 16465 // addsd xmm0, static_cast<double>(2^64) |
| 16466 // done: |
| 16467 // |
| 16468 // while GCC -m64 generates |
| 16469 // |
| 16470 // test rax, rax |
| 16471 // js negative |
| 16472 // cvtsi2sd xmm0, rax |
| 16473 // jmp done |
| 16474 // negative: |
| 16475 // mov rdx, rax |
| 16476 // shr rdx, 1 |
| 16477 // and eax, 0x1 |
| 16478 // or rdx, rax |
| 16479 // cvtsi2sd xmm0, rdx |
| 16480 // addsd xmm0, xmm0 |
| 16481 // done: |
| 16482 // |
| 16483 // which results in a different rounding. |
| 16484 // |
| 16485 // For consistency between platforms fallback to GCC style converstion |
| 16486 // on Win64. |
| 16487 // |
| 16488 const int64_t y = static_cast<int64_t>(x); |
| 16489 if (y > 0) { |
| 16490 return static_cast<double>(y); |
| 16491 } else { |
| 16492 const double half = static_cast<double>( |
| 16493 static_cast<int64_t>(x >> 1) | (y & 1)); |
| 16494 return half + half; |
| 16495 } |
| 16496 #else |
| 16497 return static_cast<double>(x); |
| 16498 #endif |
| 16499 } |
| 16500 |
| 16501 |
16215 double Bigint::AsDoubleValue() const { | 16502 double Bigint::AsDoubleValue() const { |
16216 return Double::Handle(BigintOperations::ToDouble(*this)).value(); | 16503 ASSERT(kBitsPerDigit == 32); |
| 16504 ASSERT(IsClamped()); |
| 16505 const intptr_t used = Used(); |
| 16506 if (used == 0) { |
| 16507 return 0.0; |
| 16508 } |
| 16509 if (used <= 2) { |
| 16510 const uint64_t digit1 = (used > 1) ? DigitAt(1) : 0; |
| 16511 const uint64_t abs_value = (digit1 << 32) + DigitAt(0); |
| 16512 const double abs_double_value = Uint64ToDouble(abs_value); |
| 16513 return Neg() ? -abs_double_value : abs_double_value; |
| 16514 } |
| 16515 |
| 16516 static const int kPhysicalSignificandSize = 52; |
| 16517 // The significand size has an additional hidden bit. |
| 16518 static const int kSignificandSize = kPhysicalSignificandSize + 1; |
| 16519 static const int kExponentBias = 0x3FF + kPhysicalSignificandSize; |
| 16520 static const int kMaxExponent = 0x7FF - kExponentBias; |
| 16521 static const uint64_t kOne64 = 1; |
| 16522 static const uint64_t kInfinityBits = |
| 16523 DART_2PART_UINT64_C(0x7FF00000, 00000000); |
| 16524 |
| 16525 // A double is composed of an exponent e and a significand s. Its value equals |
| 16526 // s * 2^e. The significand has 53 bits of which the first one must always be |
| 16527 // 1 (at least for then numbers we are working with here) and is therefore |
| 16528 // omitted. The physical size of the significand is thus 52 bits. |
| 16529 // The exponent has 11 bits and is biased by 0x3FF + 52. For example an |
| 16530 // exponent e = 10 is written as 0x3FF + 52 + 10 (in the 11 bits that are |
| 16531 // reserved for the exponent). |
| 16532 // When converting the given bignum to a double we have to pay attention to |
| 16533 // the rounding. In particular we have to decide which double to pick if an |
| 16534 // input lies exactly between two doubles. As usual with double operations |
| 16535 // we pick the double with an even significand in such cases. |
| 16536 // |
| 16537 // General approach of this algorithm: Get 54 bits (one more than the |
| 16538 // significand size) of the bigint. If the last bit is then 1, then (without |
| 16539 // knowledge of the remaining bits) we could have a half-way number. |
| 16540 // If the second-to-last bit is odd then we know that we have to round up: |
| 16541 // if the remaining bits are not zero then the input lies closer to the higher |
| 16542 // double. If the remaining bits are zero then we have a half-way case and |
| 16543 // we need to round up too (rounding to the even double). |
| 16544 // If the second-to-last bit is even then we need to look at the remaining |
| 16545 // bits to determine if any of them is not zero. If that's the case then the |
| 16546 // number lies closer to the next-higher double. Otherwise we round the |
| 16547 // half-way case down to even. |
| 16548 |
| 16549 if (((used - 1) * kBitsPerDigit) > (kMaxExponent + kSignificandSize)) { |
| 16550 // Does not fit into a double. |
| 16551 const double infinity = bit_cast<double>(kInfinityBits); |
| 16552 return Neg() ? -infinity : infinity; |
| 16553 } |
| 16554 |
| 16555 intptr_t digit_index = used - 1; |
| 16556 // In order to round correctly we need to look at half-way cases. Therefore we |
| 16557 // get kSignificandSize + 1 bits. If the last bit is 1 then we have to look |
| 16558 // at the remaining bits to know if we have to round up. |
| 16559 int needed_bits = kSignificandSize + 1; |
| 16560 ASSERT((kBitsPerDigit < needed_bits) && (2 * kBitsPerDigit >= needed_bits)); |
| 16561 bool discarded_bits_were_zero = true; |
| 16562 |
| 16563 const uint32_t firstDigit = DigitAt(digit_index--); |
| 16564 ASSERT(firstDigit > 0); |
| 16565 uint64_t twice_significand_floor = firstDigit; |
| 16566 intptr_t twice_significant_exponent = (digit_index + 1) * kBitsPerDigit; |
| 16567 needed_bits -= Utils::HighestBit(firstDigit) + 1; |
| 16568 |
| 16569 if (needed_bits >= kBitsPerDigit) { |
| 16570 twice_significand_floor <<= kBitsPerDigit; |
| 16571 twice_significand_floor |= DigitAt(digit_index--); |
| 16572 twice_significant_exponent -= kBitsPerDigit; |
| 16573 needed_bits -= kBitsPerDigit; |
| 16574 } |
| 16575 if (needed_bits > 0) { |
| 16576 ASSERT(needed_bits <= kBitsPerDigit); |
| 16577 uint32_t digit = DigitAt(digit_index--); |
| 16578 int discarded_bits_count = kBitsPerDigit - needed_bits; |
| 16579 twice_significand_floor <<= needed_bits; |
| 16580 twice_significand_floor |= digit >> discarded_bits_count; |
| 16581 twice_significant_exponent -= needed_bits; |
| 16582 uint64_t discarded_bits_mask = (kOne64 << discarded_bits_count) - 1; |
| 16583 discarded_bits_were_zero = ((digit & discarded_bits_mask) == 0); |
| 16584 } |
| 16585 ASSERT((twice_significand_floor >> kSignificandSize) == 1); |
| 16586 |
| 16587 // We might need to round up the significand later. |
| 16588 uint64_t significand = twice_significand_floor >> 1; |
| 16589 const intptr_t exponent = twice_significant_exponent + 1; |
| 16590 |
| 16591 if (exponent >= kMaxExponent) { |
| 16592 // Infinity. |
| 16593 // Does not fit into a double. |
| 16594 const double infinity = bit_cast<double>(kInfinityBits); |
| 16595 return Neg() ? -infinity : infinity; |
| 16596 } |
| 16597 |
| 16598 if ((twice_significand_floor & 1) == 1) { |
| 16599 bool round_up = false; |
| 16600 |
| 16601 if ((significand & 1) != 0 || !discarded_bits_were_zero) { |
| 16602 // Even if the remaining bits are zero we still need to round up since we |
| 16603 // want to round to even for half-way cases. |
| 16604 round_up = true; |
| 16605 } else { |
| 16606 // Could be a half-way case. See if the remaining bits are non-zero. |
| 16607 for (intptr_t i = 0; i <= digit_index; i++) { |
| 16608 if (DigitAt(i) != 0) { |
| 16609 round_up = true; |
| 16610 break; |
| 16611 } |
| 16612 } |
| 16613 } |
| 16614 |
| 16615 if (round_up) { |
| 16616 significand++; |
| 16617 // It might be that we just went from 53 bits to 54 bits. |
| 16618 // Example: After adding 1 to 1FFF..FF (with 53 bits set to 1) we have |
| 16619 // 2000..00 (= 2 ^ 54). When adding the exponent and significand together |
| 16620 // this will increase the exponent by 1 which is exactly what we want. |
| 16621 } |
| 16622 } |
| 16623 |
| 16624 ASSERT(((significand >> (kSignificandSize - 1)) == 1) || |
| 16625 (significand == (kOne64 << kSignificandSize))); |
| 16626 // The significand still has the hidden bit. We simply decrement the biased |
| 16627 // exponent by one instead of playing around with the significand. |
| 16628 const uint64_t biased_exponent = exponent + kExponentBias - 1; |
| 16629 // Note that we must use the plus operator instead of bit-or. |
| 16630 const uint64_t double_bits = |
| 16631 (biased_exponent << kPhysicalSignificandSize) + significand; |
| 16632 |
| 16633 const double value = bit_cast<double>(double_bits); |
| 16634 return Neg() ? -value : value; |
| 16635 } |
| 16636 |
| 16637 |
| 16638 bool Bigint::FitsIntoSmi() const { |
| 16639 return FitsIntoInt64() && Smi::IsValid(AsInt64Value()); |
| 16640 } |
| 16641 |
| 16642 |
| 16643 bool Bigint::FitsIntoInt64() const { |
| 16644 ASSERT(Bigint::kBitsPerDigit == 32); |
| 16645 const intptr_t used = Used(); |
| 16646 if (used < 2) return true; |
| 16647 if (used > 2) return false; |
| 16648 const uint64_t digit1 = DigitAt(1); |
| 16649 const uint64_t value = (digit1 << 32) + DigitAt(0); |
| 16650 uint64_t limit = Mint::kMaxValue; |
| 16651 if (Neg()) { |
| 16652 limit++; |
| 16653 } |
| 16654 return value <= limit; |
16217 } | 16655 } |
16218 | 16656 |
16219 | 16657 |
16220 int64_t Bigint::AsInt64Value() const { | 16658 int64_t Bigint::AsInt64Value() const { |
16221 if (!BigintOperations::FitsIntoInt64(*this)) { | 16659 ASSERT(FitsIntoInt64()); |
16222 UNREACHABLE(); | 16660 const intptr_t used = Used(); |
16223 } | 16661 if (used == 0) return 0; |
16224 return BigintOperations::ToInt64(*this); | 16662 const int64_t digit1 = (used > 1) ? DigitAt(1) : 0; |
| 16663 const int64_t value = (digit1 << 32) + DigitAt(0); |
| 16664 return Neg() ? -value : value; |
| 16665 } |
| 16666 |
| 16667 |
| 16668 bool Bigint::FitsIntoUint64() const { |
| 16669 ASSERT(Bigint::kBitsPerDigit == 32); |
| 16670 return !Neg() && (Used() <= 2); |
| 16671 } |
| 16672 |
| 16673 |
| 16674 uint64_t Bigint::AsUint64Value() const { |
| 16675 ASSERT(FitsIntoUint64()); |
| 16676 const intptr_t used = Used(); |
| 16677 if (used == 0) return 0; |
| 16678 const uint64_t digit1 = (used > 1) ? DigitAt(1) : 0; |
| 16679 return (digit1 << 32) + DigitAt(0); |
16225 } | 16680 } |
16226 | 16681 |
16227 | 16682 |
16228 uint32_t Bigint::AsTruncatedUint32Value() const { | 16683 uint32_t Bigint::AsTruncatedUint32Value() const { |
16229 return BigintOperations::TruncateToUint32(*this); | 16684 // Note: the previous implementation of Bigint returned the absolute value |
| 16685 // truncated to 32 bits, which is not consistent with Smi and Mint behavior. |
| 16686 ASSERT(Bigint::kBitsPerDigit == 32); |
| 16687 const intptr_t used = Used(); |
| 16688 if (used == 0) return 0; |
| 16689 const uint32_t digit0 = DigitAt(0); |
| 16690 return Neg() ? -digit0 : digit0; |
16230 } | 16691 } |
16231 | 16692 |
16232 | 16693 |
16233 // For positive values: Smi < Mint < Bigint. | 16694 // For positive values: Smi < Mint < Bigint. |
16234 int Bigint::CompareWith(const Integer& other) const { | 16695 int Bigint::CompareWith(const Integer& other) const { |
16235 ASSERT(!FitsIntoSmi(*this)); | 16696 ASSERT(!FitsIntoSmi()); |
16236 ASSERT(!BigintOperations::FitsIntoInt64(*this)); | 16697 ASSERT(!FitsIntoInt64()); |
16237 if (other.IsBigint()) { | 16698 if (other.IsBigint() && (IsNegative() == other.IsNegative())) { |
16238 return BigintOperations::Compare(*this, Bigint::Cast(other)); | 16699 const Bigint& other_bgi = Bigint::Cast(other); |
16239 } | 16700 int64_t result = Used() - other_bgi.Used(); |
16240 if (this->IsNegative() == other.IsNegative()) { | 16701 if (result == 0) { |
16241 return this->IsNegative() ? -1 : 1; | 16702 for (intptr_t i = Used(); --i >= 0; ) { |
| 16703 result = DigitAt(i); |
| 16704 result -= other_bgi.DigitAt(i); |
| 16705 if (result != 0) break; |
| 16706 } |
| 16707 } |
| 16708 if (IsNegative()) { |
| 16709 result = -result; |
| 16710 } |
| 16711 return result > 0 ? 1 : result < 0 ? -1 : 0; |
16242 } | 16712 } |
16243 return this->IsNegative() ? -1 : 1; | 16713 return this->IsNegative() ? -1 : 1; |
16244 } | 16714 } |
16245 | 16715 |
16246 | 16716 |
16247 RawBigint* Bigint::Allocate(intptr_t length, Heap::Space space) { | 16717 const char* Bigint::ToDecCString(uword (*allocator)(intptr_t size)) const { |
16248 if (length < 0 || length > kMaxElements) { | 16718 // log10(2) ~= 0.30102999566398114. |
16249 // This should be caught before we reach here. | 16719 const intptr_t kLog2Dividend = 30103; |
16250 FATAL1("Fatal error in Bigint::Allocate: invalid length %" Pd "\n", length); | 16720 const intptr_t kLog2Divisor = 100000; |
16251 } | 16721 intptr_t used = Used(); |
16252 ASSERT(Isolate::Current()->object_store()->bigint_class() != Class::null()); | 16722 const intptr_t kMaxUsed = |
16253 Bigint& result = Bigint::Handle(); | 16723 kIntptrMax / kBitsPerDigit / kLog2Dividend * kLog2Divisor; |
16254 { | 16724 if (used > kMaxUsed) { |
16255 RawObject* raw = Object::Allocate(Bigint::kClassId, | 16725 // Throw out of memory exception. |
16256 Bigint::InstanceSize(length), | 16726 Isolate* isolate = Isolate::Current(); |
16257 space); | 16727 const Instance& exception = |
16258 NoGCScope no_gc; | 16728 Instance::Handle(isolate->object_store()->out_of_memory()); |
16259 result ^= raw; | 16729 Exceptions::Throw(isolate, exception); |
16260 result.raw_ptr()->allocated_length_ = length; // Chunk length allocated. | 16730 UNREACHABLE(); |
16261 result.raw_ptr()->signed_length_ = length; // Chunk length in use. | 16731 } |
16262 } | 16732 const int64_t bit_len = used * kBitsPerDigit; |
16263 return result.raw(); | 16733 const int64_t dec_len = (bit_len * kLog2Dividend / kLog2Divisor) + 1; |
| 16734 // Add one byte for the minus sign and for the trailing \0 character. |
| 16735 const int64_t len = (Neg() ? 1 : 0) + dec_len + 1; |
| 16736 char* chars = reinterpret_cast<char*>(allocator(len)); |
| 16737 intptr_t pos = 0; |
| 16738 const intptr_t kDivisor = 100000000; |
| 16739 const intptr_t kDigits = 8; |
| 16740 ASSERT(pow(10.0, kDigits) == kDivisor); |
| 16741 ASSERT(kDivisor < kDigitBase); |
| 16742 ASSERT(Smi::IsValid(kDivisor)); |
| 16743 // Allocate a copy of the digits. |
| 16744 const TypedData& rest_digits = TypedData::Handle( |
| 16745 TypedData::New(kTypedDataUint32ArrayCid, used)); |
| 16746 for (intptr_t i = 0; i < used; i++) { |
| 16747 rest_digits.SetUint32(i << 2, DigitAt(i)); |
| 16748 } |
| 16749 if (used == 0) { |
| 16750 chars[pos++] = '0'; |
| 16751 } |
| 16752 while (used > 0) { |
| 16753 uint32_t remainder = 0; |
| 16754 for (intptr_t i = used - 1; i >= 0; i--) { |
| 16755 uint64_t dividend = (static_cast<uint64_t>(remainder) << kBitsPerDigit) + |
| 16756 rest_digits.GetUint32(i << 2); |
| 16757 uint32_t quotient = static_cast<uint32_t>(dividend / kDivisor); |
| 16758 remainder = static_cast<uint32_t>( |
| 16759 dividend - static_cast<uint64_t>(quotient) * kDivisor); |
| 16760 rest_digits.SetUint32(i << 2, quotient); |
| 16761 } |
| 16762 // Clamp rest_digits. |
| 16763 while ((used > 0) && (rest_digits.GetUint32((used - 1) << 2) == 0)) { |
| 16764 used--; |
| 16765 } |
| 16766 for (intptr_t i = 0; i < kDigits; i++) { |
| 16767 chars[pos++] = '0' + (remainder % 10); |
| 16768 remainder /= 10; |
| 16769 } |
| 16770 ASSERT(remainder == 0); |
| 16771 } |
| 16772 // Remove leading zeros. |
| 16773 while ((pos > 1) && (chars[pos - 1] == '0')) { |
| 16774 pos--; |
| 16775 } |
| 16776 if (Neg()) { |
| 16777 chars[pos++] = '-'; |
| 16778 } |
| 16779 // Reverse the string. |
| 16780 intptr_t i = 0; |
| 16781 intptr_t j = pos - 1; |
| 16782 while (i < j) { |
| 16783 char tmp = chars[i]; |
| 16784 chars[i] = chars[j]; |
| 16785 chars[j] = tmp; |
| 16786 i++; |
| 16787 j--; |
| 16788 } |
| 16789 chars[pos] = '\0'; |
| 16790 return chars; |
| 16791 } |
| 16792 |
| 16793 |
| 16794 const char* Bigint::ToHexCString(uword (*allocator)(intptr_t size)) const { |
| 16795 NoGCScope no_gc; // TODO(regis): Is this necessary? |
| 16796 |
| 16797 const intptr_t used = Used(); |
| 16798 if (used == 0) { |
| 16799 const char* zero = "0x0"; |
| 16800 const size_t len = strlen(zero) + 1; |
| 16801 char* chars = reinterpret_cast<char*>(allocator(len)); |
| 16802 strncpy(chars, zero, len); |
| 16803 return chars; |
| 16804 } |
| 16805 const int kBitsPerHexDigit = 4; |
| 16806 const int kHexDigitsPerDigit = 8; |
| 16807 const intptr_t kMaxUsed = (kIntptrMax - 4) / kHexDigitsPerDigit; |
| 16808 if (used > kMaxUsed) { |
| 16809 // Throw out of memory exception. |
| 16810 Isolate* isolate = Isolate::Current(); |
| 16811 const Instance& exception = |
| 16812 Instance::Handle(isolate->object_store()->out_of_memory()); |
| 16813 Exceptions::Throw(isolate, exception); |
| 16814 UNREACHABLE(); |
| 16815 } |
| 16816 intptr_t hex_len = (used - 1) * kHexDigitsPerDigit; |
| 16817 // The most significant digit may use fewer than kHexDigitsPerDigit digits. |
| 16818 uint32_t digit = DigitAt(used - 1); |
| 16819 ASSERT(digit != 0); // Value must be clamped. |
| 16820 while (digit != 0) { |
| 16821 hex_len++; |
| 16822 digit >>= kBitsPerHexDigit; |
| 16823 } |
| 16824 // Add bytes for '0x', for the minus sign, and for the trailing \0 character. |
| 16825 const int32_t len = (Neg() ? 1 : 0) + 2 + hex_len + 1; |
| 16826 char* chars = reinterpret_cast<char*>(allocator(len)); |
| 16827 intptr_t pos = len; |
| 16828 chars[--pos] = '\0'; |
| 16829 for (intptr_t i = 0; i < (used - 1); i++) { |
| 16830 digit = DigitAt(i); |
| 16831 for (intptr_t j = 0; j < kHexDigitsPerDigit; j++) { |
| 16832 chars[--pos] = Utils::IntToHexDigit(digit & 0xf); |
| 16833 digit >>= kBitsPerHexDigit; |
| 16834 } |
| 16835 } |
| 16836 digit = DigitAt(used - 1); |
| 16837 while (digit != 0) { |
| 16838 chars[--pos] = Utils::IntToHexDigit(digit & 0xf); |
| 16839 digit >>= kBitsPerHexDigit; |
| 16840 } |
| 16841 chars[--pos] = 'x'; |
| 16842 chars[--pos] = '0'; |
| 16843 if (Neg()) { |
| 16844 chars[--pos] = '-'; |
| 16845 } |
| 16846 ASSERT(pos == 0); |
| 16847 return chars; |
16264 } | 16848 } |
16265 | 16849 |
16266 | 16850 |
16267 static uword BigintAllocator(intptr_t size) { | 16851 static uword BigintAllocator(intptr_t size) { |
16268 Zone* zone = Isolate::Current()->current_zone(); | 16852 Zone* zone = Isolate::Current()->current_zone(); |
16269 return zone->AllocUnsafe(size); | 16853 return zone->AllocUnsafe(size); |
16270 } | 16854 } |
16271 | 16855 |
16272 | 16856 |
16273 const char* Bigint::ToCString() const { | 16857 const char* Bigint::ToCString() const { |
16274 return BigintOperations::ToDecimalCString(*this, &BigintAllocator); | 16858 return ToDecCString(&BigintAllocator); |
16275 } | 16859 } |
16276 | 16860 |
16277 | 16861 |
16278 void Bigint::PrintJSONImpl(JSONStream* stream, bool ref) const { | 16862 void Bigint::PrintJSONImpl(JSONStream* stream, bool ref) const { |
16279 Number::PrintJSONImpl(stream, ref); | 16863 Number::PrintJSONImpl(stream, ref); |
16280 } | 16864 } |
16281 | 16865 |
16282 | 16866 |
16283 // Synchronize with implementation in compiler (intrinsifier). | 16867 // Synchronize with implementation in compiler (intrinsifier). |
16284 class StringHasher : ValueObject { | 16868 class StringHasher : ValueObject { |
(...skipping 2177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
18462 } | 19046 } |
18463 // TODO(koda): Ensure VM classes only produce Smi hash codes, and remove | 19047 // TODO(koda): Ensure VM classes only produce Smi hash codes, and remove |
18464 // non-Smi cases once Dart-side implementation is complete. | 19048 // non-Smi cases once Dart-side implementation is complete. |
18465 Isolate* isolate = Isolate::Current(); | 19049 Isolate* isolate = Isolate::Current(); |
18466 REUSABLE_INSTANCE_HANDLESCOPE(isolate); | 19050 REUSABLE_INSTANCE_HANDLESCOPE(isolate); |
18467 Instance& hash_code = isolate->InstanceHandle(); | 19051 Instance& hash_code = isolate->InstanceHandle(); |
18468 hash_code ^= Instance::Cast(obj).HashCode(); | 19052 hash_code ^= Instance::Cast(obj).HashCode(); |
18469 if (hash_code.IsSmi()) { | 19053 if (hash_code.IsSmi()) { |
18470 // May waste some bits on 64-bit, to ensure consistency with non-Smi case. | 19054 // May waste some bits on 64-bit, to ensure consistency with non-Smi case. |
18471 return static_cast<uword>(Smi::Cast(hash_code).Value() & 0xFFFFFFFF); | 19055 return static_cast<uword>(Smi::Cast(hash_code).Value() & 0xFFFFFFFF); |
| 19056 // TODO(regis): Same as Smi::AsTruncatedUint32Value(), simplify? |
18472 } else if (hash_code.IsInteger()) { | 19057 } else if (hash_code.IsInteger()) { |
18473 return static_cast<uword>( | 19058 return static_cast<uword>( |
18474 Integer::Cast(hash_code).AsTruncatedUint32Value()); | 19059 Integer::Cast(hash_code).AsTruncatedUint32Value()); |
18475 } else { | 19060 } else { |
18476 return 0; | 19061 return 0; |
18477 } | 19062 } |
18478 } | 19063 } |
18479 }; | 19064 }; |
18480 typedef EnumIndexHashMap<DefaultHashTraits> EnumIndexDefaultMap; | 19065 typedef EnumIndexHashMap<DefaultHashTraits> EnumIndexDefaultMap; |
18481 | 19066 |
(...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
18904 8, // kTypedDataInt64ArrayCid. | 19489 8, // kTypedDataInt64ArrayCid. |
18905 8, // kTypedDataUint64ArrayCid. | 19490 8, // kTypedDataUint64ArrayCid. |
18906 4, // kTypedDataFloat32ArrayCid. | 19491 4, // kTypedDataFloat32ArrayCid. |
18907 8, // kTypedDataFloat64ArrayCid. | 19492 8, // kTypedDataFloat64ArrayCid. |
18908 16, // kTypedDataFloat32x4ArrayCid. | 19493 16, // kTypedDataFloat32x4ArrayCid. |
18909 16, // kTypedDataInt32x4ArrayCid. | 19494 16, // kTypedDataInt32x4ArrayCid. |
18910 16, // kTypedDataFloat64x2ArrayCid, | 19495 16, // kTypedDataFloat64x2ArrayCid, |
18911 }; | 19496 }; |
18912 | 19497 |
18913 | 19498 |
| 19499 bool TypedData::CanonicalizeEquals(const Instance& other) const { |
| 19500 if (this->raw() == other.raw()) { |
| 19501 // Both handles point to the same raw instance. |
| 19502 return true; |
| 19503 } |
| 19504 |
| 19505 if (!other.IsTypedData() || other.IsNull()) { |
| 19506 return false; |
| 19507 } |
| 19508 |
| 19509 const TypedData& other_typed_data = TypedData::Cast(other); |
| 19510 |
| 19511 if (this->ElementType() != other_typed_data.ElementType()) { |
| 19512 return false; |
| 19513 } |
| 19514 |
| 19515 const intptr_t len = this->LengthInBytes(); |
| 19516 if (len != other_typed_data.LengthInBytes()) { |
| 19517 return false; |
| 19518 } |
| 19519 |
| 19520 return (len == 0) || |
| 19521 (memcmp(DataAddr(0), other_typed_data.DataAddr(0), len) == 0); |
| 19522 } |
| 19523 |
| 19524 |
18914 RawTypedData* TypedData::New(intptr_t class_id, | 19525 RawTypedData* TypedData::New(intptr_t class_id, |
18915 intptr_t len, | 19526 intptr_t len, |
18916 Heap::Space space) { | 19527 Heap::Space space) { |
18917 if (len < 0 || len > TypedData::MaxElements(class_id)) { | 19528 if (len < 0 || len > TypedData::MaxElements(class_id)) { |
18918 FATAL1("Fatal error in TypedData::New: invalid len %" Pd "\n", len); | 19529 FATAL1("Fatal error in TypedData::New: invalid len %" Pd "\n", len); |
18919 } | 19530 } |
18920 TypedData& result = TypedData::Handle(); | 19531 TypedData& result = TypedData::Handle(); |
18921 { | 19532 { |
18922 intptr_t lengthInBytes = len * ElementSizeInBytes(class_id); | 19533 const intptr_t lengthInBytes = len * ElementSizeInBytes(class_id); |
18923 RawObject* raw = Object::Allocate(class_id, | 19534 RawObject* raw = Object::Allocate(class_id, |
18924 TypedData::InstanceSize(lengthInBytes), | 19535 TypedData::InstanceSize(lengthInBytes), |
18925 space); | 19536 space); |
18926 NoGCScope no_gc; | 19537 NoGCScope no_gc; |
18927 result ^= raw; | 19538 result ^= raw; |
18928 result.SetLength(len); | 19539 result.SetLength(len); |
18929 if (len > 0) { | 19540 if (len > 0) { |
18930 memset(result.DataAddr(0), 0, lengthInBytes); | 19541 memset(result.DataAddr(0), 0, lengthInBytes); |
18931 } | 19542 } |
18932 } | 19543 } |
(...skipping 766 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
19699 return tag_label.ToCString(); | 20310 return tag_label.ToCString(); |
19700 } | 20311 } |
19701 | 20312 |
19702 | 20313 |
19703 void UserTag::PrintJSONImpl(JSONStream* stream, bool ref) const { | 20314 void UserTag::PrintJSONImpl(JSONStream* stream, bool ref) const { |
19704 Instance::PrintJSONImpl(stream, ref); | 20315 Instance::PrintJSONImpl(stream, ref); |
19705 } | 20316 } |
19706 | 20317 |
19707 | 20318 |
19708 } // namespace dart | 20319 } // namespace dart |
OLD | NEW |