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

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 3801 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698