| 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" |
| (...skipping 16390 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 16401 result.EnsureLength(2, space); | 16401 result.EnsureLength(2, space); |
| 16402 result.SetUsed(2); | 16402 result.SetUsed(2); |
| 16403 result.SetDigitAt(0, static_cast<uint32_t>(value)); | 16403 result.SetDigitAt(0, static_cast<uint32_t>(value)); |
| 16404 result.SetDigitAt(1, static_cast<uint32_t>(value >> 32)); | 16404 result.SetDigitAt(1, static_cast<uint32_t>(value >> 32)); |
| 16405 result.Clamp(); | 16405 result.Clamp(); |
| 16406 return result.raw(); | 16406 return result.raw(); |
| 16407 } | 16407 } |
| 16408 | 16408 |
| 16409 | 16409 |
| 16410 RawBigint* Bigint::NewFromShiftedInt64(int64_t value, intptr_t shift, | 16410 RawBigint* Bigint::NewFromShiftedInt64(int64_t value, intptr_t shift, |
| 16411 Heap::Space space) { | 16411 Heap::Space space) { |
| 16412 ASSERT(kBitsPerDigit == 32); | 16412 ASSERT(kBitsPerDigit == 32); |
| 16413 ASSERT(shift >= 0); | 16413 ASSERT(shift >= 0); |
| 16414 const Bigint& result = Bigint::Handle(New(space)); | 16414 const Bigint& result = Bigint::Handle(New(space)); |
| 16415 const intptr_t digit_shift = shift / kBitsPerDigit; | 16415 const intptr_t digit_shift = shift / kBitsPerDigit; |
| 16416 const intptr_t bit_shift = shift % kBitsPerDigit; | 16416 const intptr_t bit_shift = shift % kBitsPerDigit; |
| 16417 result.EnsureLength(3 + digit_shift, space); | 16417 result.EnsureLength(3 + digit_shift, space); |
| 16418 result.SetUsed(3 + digit_shift); | 16418 result.SetUsed(3 + digit_shift); |
| 16419 uint64_t abs_value; | 16419 uint64_t abs_value; |
| 16420 if (value < 0) { | 16420 if (value < 0) { |
| 16421 result.SetNeg(true); | 16421 result.SetNeg(true); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 16433 result.SetDigitAt(2 + digit_shift, | 16433 result.SetDigitAt(2 + digit_shift, |
| 16434 (bit_shift == 0) ? 0 | 16434 (bit_shift == 0) ? 0 |
| 16435 : static_cast<uint32_t>(abs_value >> (64 - bit_shift))); | 16435 : static_cast<uint32_t>(abs_value >> (64 - bit_shift))); |
| 16436 result.Clamp(); | 16436 result.Clamp(); |
| 16437 return result.raw(); | 16437 return result.raw(); |
| 16438 } | 16438 } |
| 16439 | 16439 |
| 16440 | 16440 |
| 16441 void Bigint::EnsureLength(intptr_t length, Heap::Space space) const { | 16441 void Bigint::EnsureLength(intptr_t length, Heap::Space space) const { |
| 16442 ASSERT(length >= 0); | 16442 ASSERT(length >= 0); |
| 16443 length++; // Account for leading zero for 64-bit processing. |
| 16443 TypedData& old_digits = TypedData::Handle(digits()); | 16444 TypedData& old_digits = TypedData::Handle(digits()); |
| 16444 if ((length > 0) && (length > old_digits.Length())) { | 16445 if (length > old_digits.Length()) { |
| 16445 TypedData& new_digits = TypedData::Handle( | 16446 TypedData& new_digits = TypedData::Handle( |
| 16446 TypedData::New(kTypedDataUint32ArrayCid, length + kExtraDigits, space)); | 16447 TypedData::New(kTypedDataUint32ArrayCid, length + kExtraDigits, space)); |
| 16447 if (old_digits.Length() > 0) { | 16448 set_digits(new_digits); |
| 16449 if (Used() > 0) { |
| 16448 TypedData::Copy(new_digits, TypedData::data_offset(), | 16450 TypedData::Copy(new_digits, TypedData::data_offset(), |
| 16449 old_digits, TypedData::data_offset(), | 16451 old_digits, TypedData::data_offset(), |
| 16450 old_digits.LengthInBytes()); | 16452 (Used() + 1)*kBytesPerDigit); // Copy leading zero. |
| 16451 } | 16453 } |
| 16452 set_digits(new_digits); | |
| 16453 } | 16454 } |
| 16454 } | 16455 } |
| 16455 | 16456 |
| 16456 | 16457 |
| 16457 void Bigint::Clamp() const { | 16458 void Bigint::Clamp() const { |
| 16458 intptr_t used = Used(); | 16459 intptr_t used = Used(); |
| 16459 while ((used > 0) && (DigitAt(used - 1) == 0)) { | 16460 if (used > 0) { |
| 16460 --used; | 16461 if (DigitAt(used - 1) == 0) { |
| 16462 do { |
| 16463 --used; |
| 16464 } while ((used > 0) && (DigitAt(used - 1) == 0)); |
| 16465 SetUsed(used); |
| 16466 } |
| 16467 SetDigitAt(used, 0); // Set leading zero for 64-bit processing. |
| 16461 } | 16468 } |
| 16462 SetUsed(used); | |
| 16463 } | 16469 } |
| 16464 | 16470 |
| 16465 | 16471 |
| 16466 bool Bigint::IsClamped() const { | 16472 bool Bigint::IsClamped() const { |
| 16467 intptr_t used = Used(); | 16473 intptr_t used = Used(); |
| 16468 return (used == 0) || (DigitAt(used - 1) > 0); | 16474 return (used == 0) || (DigitAt(used - 1) > 0); |
| 16469 } | 16475 } |
| 16470 | 16476 |
| 16471 | 16477 |
| 16472 RawBigint* Bigint::NewFromCString(const char* str, Heap::Space space) { | 16478 RawBigint* Bigint::NewFromCString(const char* str, Heap::Space space) { |
| 16473 ASSERT(str != NULL); | 16479 ASSERT(str != NULL); |
| 16474 if (str[0] == '\0') { | |
| 16475 return NewFromInt64(0, space); | |
| 16476 } | |
| 16477 | |
| 16478 // If the string starts with '-' recursively restart the whole operation | 16480 // If the string starts with '-' recursively restart the whole operation |
| 16479 // without the character and then toggle the sign. | 16481 // without the character and then toggle the sign. |
| 16480 // This allows multiple leading '-' (which will cancel each other out), but | |
| 16481 // we have added an assert, to make sure that the returned result of the | |
| 16482 // recursive call is not negative. | |
| 16483 // We don't catch leading '-'s for zero. Ex: "--0", or "---". | |
| 16484 if (str[0] == '-') { | 16482 if (str[0] == '-') { |
| 16483 ASSERT(str[1] != '-'); |
| 16485 const Bigint& result = Bigint::Handle(NewFromCString(&str[1], space)); | 16484 const Bigint& result = Bigint::Handle(NewFromCString(&str[1], space)); |
| 16486 result.SetNeg(!result.Neg()); // Toggle sign. | 16485 result.SetNeg(!result.Neg()); // Toggle sign. |
| 16487 ASSERT(result.IsZero() || result.IsNegative()); | 16486 ASSERT(result.IsZero() || result.IsNegative()); |
| 16488 ASSERT(result.IsClamped()); | 16487 ASSERT(result.IsClamped()); |
| 16489 return result.raw(); | 16488 return result.raw(); |
| 16490 } | 16489 } |
| 16491 | 16490 |
| 16492 // No overflow check needed since overflowing str_length implies that we take | 16491 // No overflow check needed since overflowing str_length implies that we take |
| 16493 // the branch to NewFromDecCString() which contains a check itself. | 16492 // the branch to NewFromDecCString() which contains a check itself. |
| 16494 const intptr_t str_length = strlen(str); | 16493 const intptr_t str_length = strlen(str); |
| 16495 if ((str_length > 2) && | 16494 if ((str_length >= 2) && |
| 16496 (str[0] == '0') && | 16495 (str[0] == '0') && |
| 16497 ((str[1] == 'x') || (str[1] == 'X'))) { | 16496 ((str[1] == 'x') || (str[1] == 'X'))) { |
| 16498 const Bigint& result = Bigint::Handle(NewFromHexCString(&str[2], space)); | 16497 const Bigint& result = Bigint::Handle(NewFromHexCString(&str[2], space)); |
| 16499 ASSERT(result.IsClamped()); | 16498 ASSERT(result.IsClamped()); |
| 16500 return result.raw(); | 16499 return result.raw(); |
| 16501 } else { | 16500 } else { |
| 16502 return NewFromDecCString(str, space); | 16501 return NewFromDecCString(str, space); |
| 16503 } | 16502 } |
| 16504 } | 16503 } |
| 16505 | 16504 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 16527 } | 16526 } |
| 16528 // The value needs to be added to the constants list. Grow the list if | 16527 // The value needs to be added to the constants list. Grow the list if |
| 16529 // it is full. | 16528 // it is full. |
| 16530 cls.InsertCanonicalConstant(index, value); | 16529 cls.InsertCanonicalConstant(index, value); |
| 16531 value.SetCanonical(); | 16530 value.SetCanonical(); |
| 16532 return value.raw(); | 16531 return value.raw(); |
| 16533 } | 16532 } |
| 16534 | 16533 |
| 16535 | 16534 |
| 16536 RawBigint* Bigint::NewFromHexCString(const char* str, Heap::Space space) { | 16535 RawBigint* Bigint::NewFromHexCString(const char* str, Heap::Space space) { |
| 16537 // TODO(regis): Do we need to check for max length? | |
| 16538 // If the string starts with '-' recursively restart the whole operation | 16536 // If the string starts with '-' recursively restart the whole operation |
| 16539 // without the character and then toggle the sign. | 16537 // without the character and then toggle the sign. |
| 16540 // This allows multiple leading '-' (which will cancel each other out), but | |
| 16541 // we have added an assert, to make sure that the returned result of the | |
| 16542 // recursive call is not negative. | |
| 16543 // We don't catch leading '-'s for zero. Ex: "--0", or "---". | |
| 16544 if (str[0] == '-') { | 16538 if (str[0] == '-') { |
| 16539 ASSERT(str[1] != '-'); |
| 16545 const Bigint& result = Bigint::Handle(NewFromHexCString(&str[1], space)); | 16540 const Bigint& result = Bigint::Handle(NewFromHexCString(&str[1], space)); |
| 16546 result.SetNeg(!result.Neg()); // Toggle sign. | 16541 if (!result.IsZero()) { |
| 16547 ASSERT(result.IsZero() || result.IsNegative()); | 16542 result.SetNeg(!result.Neg()); // Toggle sign. |
| 16543 } |
| 16548 ASSERT(result.IsClamped()); | 16544 ASSERT(result.IsClamped()); |
| 16549 return result.raw(); | 16545 return result.raw(); |
| 16550 } | 16546 } |
| 16551 const Bigint& result = Bigint::Handle(New(space)); | 16547 const Bigint& result = Bigint::Handle(New(space)); |
| 16552 const int kBitsPerHexDigit = 4; | 16548 const int kBitsPerHexDigit = 4; |
| 16553 const int kHexDigitsPerDigit = 8; | 16549 const int kHexDigitsPerDigit = 8; |
| 16554 const int kBitsPerDigit = kBitsPerHexDigit * kHexDigitsPerDigit; | 16550 const int kBitsPerDigit = kBitsPerHexDigit * kHexDigitsPerDigit; |
| 16555 intptr_t hex_i = strlen(str); // Terminating byte excluded. | 16551 intptr_t hex_i = strlen(str); // Terminating byte excluded. |
| 16552 if ((hex_i <= 0) || (hex_i >= kMaxInt32)) { |
| 16553 FATAL("Fatal error in Bigint::NewFromHexCString: string too long or empty"); |
| 16554 } |
| 16556 result.EnsureLength((hex_i + kHexDigitsPerDigit - 1) / kHexDigitsPerDigit, | 16555 result.EnsureLength((hex_i + kHexDigitsPerDigit - 1) / kHexDigitsPerDigit, |
| 16557 space); | 16556 space); |
| 16558 intptr_t used_ = 0; | 16557 intptr_t used_ = 0; |
| 16559 uint32_t digit = 0; | 16558 uint32_t digit = 0; |
| 16560 intptr_t bit_i = 0; | 16559 intptr_t bit_i = 0; |
| 16561 while (--hex_i >= 0) { | 16560 while (--hex_i >= 0) { |
| 16562 digit += Utils::HexDigitToInt(str[hex_i]) << bit_i; | 16561 digit += Utils::HexDigitToInt(str[hex_i]) << bit_i; |
| 16563 bit_i += kBitsPerHexDigit; | 16562 bit_i += kBitsPerHexDigit; |
| 16564 if (bit_i == kBitsPerDigit) { | 16563 if (bit_i == kBitsPerDigit) { |
| 16565 bit_i = 0; | 16564 bit_i = 0; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 16576 } | 16575 } |
| 16577 | 16576 |
| 16578 | 16577 |
| 16579 RawBigint* Bigint::NewFromDecCString(const char* str, Heap::Space space) { | 16578 RawBigint* Bigint::NewFromDecCString(const char* str, Heap::Space space) { |
| 16580 // Read 9 digits a time. 10^9 < 2^32. | 16579 // Read 9 digits a time. 10^9 < 2^32. |
| 16581 const int kDecDigitsPerIteration = 9; | 16580 const int kDecDigitsPerIteration = 9; |
| 16582 const uint32_t kTenMultiplier = 1000000000; | 16581 const uint32_t kTenMultiplier = 1000000000; |
| 16583 ASSERT(kBitsPerDigit == 32); | 16582 ASSERT(kBitsPerDigit == 32); |
| 16584 | 16583 |
| 16585 const intptr_t str_length = strlen(str); | 16584 const intptr_t str_length = strlen(str); |
| 16586 if (str_length < 0) { // TODO(regis): Pick a smaller limit. | 16585 if ((str_length <= 0) || (str_length >= kMaxInt32)) { |
| 16587 FATAL("Fatal error in Bigint::NewFromDecCString: string too long"); | 16586 FATAL("Fatal error in Bigint::NewFromDecCString: string too long or empty"); |
| 16588 } | 16587 } |
| 16589 intptr_t str_pos = 0; | 16588 intptr_t str_pos = 0; |
| 16590 | 16589 |
| 16591 Bigint& result = Bigint::Handle(Bigint::New(space)); | 16590 Bigint& result = Bigint::Handle(Bigint::New(space)); |
| 16592 // One decimal digit takes log2(10) bits, i.e. ~3.32192809489 bits. | 16591 // One decimal digit takes log2(10) bits, i.e. ~3.32192809489 bits. |
| 16593 // That is a theoretical limit for large numbers. | 16592 // That is a theoretical limit for large numbers. |
| 16594 // The extra digits allocated take care of variations (kExtraDigits). | 16593 // The extra digits allocated take care of variations (kExtraDigits). |
| 16595 const int64_t kLog10Dividend = 33219281; | 16594 const int64_t kLog10Dividend = 33219281; |
| 16596 const int64_t kLog10Divisor = 10000000; | 16595 const int64_t kLog10Divisor = 10000000; |
| 16596 |
| 16597 result.EnsureLength((kLog10Dividend * str_length) / | 16597 result.EnsureLength((kLog10Dividend * str_length) / |
| 16598 (kLog10Divisor * kBitsPerDigit) + 1, space); | 16598 (kLog10Divisor * kBitsPerDigit) + 1, space); |
| 16599 | 16599 |
| 16600 // Read first digit separately. This avoids a multiplication and addition. | 16600 // Read first digit separately. This avoids a multiplication and addition. |
| 16601 // The first digit might also not have kDecDigitsPerIteration decimal digits. | 16601 // The first digit might also not have kDecDigitsPerIteration decimal digits. |
| 16602 const intptr_t lsdigit_length = str_length % kDecDigitsPerIteration; | 16602 const intptr_t lsdigit_length = str_length % kDecDigitsPerIteration; |
| 16603 uint32_t digit = 0; | 16603 uint32_t digit = 0; |
| 16604 for (intptr_t i = 0; i < lsdigit_length; i++) { | 16604 for (intptr_t i = 0; i < lsdigit_length; i++) { |
| 16605 char c = str[str_pos++]; | 16605 char c = str[str_pos++]; |
| 16606 ASSERT(('0' <= c) && (c <= '9')); | 16606 ASSERT(('0' <= c) && (c <= '9')); |
| (...skipping 2539 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 19146 return 0; | 19146 return 0; |
| 19147 } | 19147 } |
| 19148 // TODO(koda): Ensure VM classes only produce Smi hash codes, and remove | 19148 // TODO(koda): Ensure VM classes only produce Smi hash codes, and remove |
| 19149 // non-Smi cases once Dart-side implementation is complete. | 19149 // non-Smi cases once Dart-side implementation is complete. |
| 19150 Isolate* isolate = Isolate::Current(); | 19150 Isolate* isolate = Isolate::Current(); |
| 19151 REUSABLE_INSTANCE_HANDLESCOPE(isolate); | 19151 REUSABLE_INSTANCE_HANDLESCOPE(isolate); |
| 19152 Instance& hash_code = isolate->InstanceHandle(); | 19152 Instance& hash_code = isolate->InstanceHandle(); |
| 19153 hash_code ^= Instance::Cast(obj).HashCode(); | 19153 hash_code ^= Instance::Cast(obj).HashCode(); |
| 19154 if (hash_code.IsSmi()) { | 19154 if (hash_code.IsSmi()) { |
| 19155 // May waste some bits on 64-bit, to ensure consistency with non-Smi case. | 19155 // May waste some bits on 64-bit, to ensure consistency with non-Smi case. |
| 19156 return static_cast<uword>(Smi::Cast(hash_code).Value() & 0xFFFFFFFF); | 19156 return static_cast<uword>(Smi::Cast(hash_code).AsTruncatedUint32Value()); |
| 19157 // TODO(regis): Same as Smi::AsTruncatedUint32Value(), simplify? | |
| 19158 } else if (hash_code.IsInteger()) { | 19157 } else if (hash_code.IsInteger()) { |
| 19159 return static_cast<uword>( | 19158 return static_cast<uword>( |
| 19160 Integer::Cast(hash_code).AsTruncatedUint32Value()); | 19159 Integer::Cast(hash_code).AsTruncatedUint32Value()); |
| 19161 } else { | 19160 } else { |
| 19162 return 0; | 19161 return 0; |
| 19163 } | 19162 } |
| 19164 } | 19163 } |
| 19165 }; | 19164 }; |
| 19166 typedef EnumIndexHashMap<DefaultHashTraits> EnumIndexDefaultMap; | 19165 typedef EnumIndexHashMap<DefaultHashTraits> EnumIndexDefaultMap; |
| 19167 | 19166 |
| (...skipping 1253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 20421 return tag_label.ToCString(); | 20420 return tag_label.ToCString(); |
| 20422 } | 20421 } |
| 20423 | 20422 |
| 20424 | 20423 |
| 20425 void UserTag::PrintJSONImpl(JSONStream* stream, bool ref) const { | 20424 void UserTag::PrintJSONImpl(JSONStream* stream, bool ref) const { |
| 20426 Instance::PrintJSONImpl(stream, ref); | 20425 Instance::PrintJSONImpl(stream, ref); |
| 20427 } | 20426 } |
| 20428 | 20427 |
| 20429 | 20428 |
| 20430 } // namespace dart | 20429 } // namespace dart |
| OLD | NEW |