Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 Google Inc. All Rights Reserved. | 1 // Copyright 2012 Google Inc. All Rights Reserved. |
| 2 | 2 |
| 3 #include "vm/bigint_operations.h" | 3 #include "vm/bigint_operations.h" |
| 4 | 4 |
| 5 #include "platform/assert.h" | |
| 5 #include "platform/utils.h" | 6 #include "platform/utils.h" |
| 6 | 7 |
| 7 #include "vm/double_internals.h" | 8 #include "vm/double_internals.h" |
| 8 #include "vm/exceptions.h" | 9 #include "vm/exceptions.h" |
| 9 #include "vm/object_store.h" | 10 #include "vm/object_store.h" |
| 10 #include "vm/zone.h" | 11 #include "vm/zone.h" |
| 11 | 12 |
| 12 namespace dart { | 13 namespace dart { |
| 13 | 14 |
| 14 RawBigint* BigintOperations::NewFromSmi(const Smi& smi, Heap::Space space) { | 15 RawBigint* BigintOperations::NewFromSmi(const Smi& smi, Heap::Space space) { |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 99 // recursive call is not negative. | 100 // recursive call is not negative. |
| 100 // We don't catch leading '-'s for zero. Ex: "--0", or "---". | 101 // We don't catch leading '-'s for zero. Ex: "--0", or "---". |
| 101 if (str[0] == '-') { | 102 if (str[0] == '-') { |
| 102 const Bigint& result = Bigint::Handle(NewFromCString(&str[1], space)); | 103 const Bigint& result = Bigint::Handle(NewFromCString(&str[1], space)); |
| 103 result.ToggleSign(); | 104 result.ToggleSign(); |
| 104 ASSERT(result.IsZero() || result.IsNegative()); | 105 ASSERT(result.IsZero() || result.IsNegative()); |
| 105 ASSERT(IsClamped(result)); | 106 ASSERT(IsClamped(result)); |
| 106 return result.raw(); | 107 return result.raw(); |
| 107 } | 108 } |
| 108 | 109 |
| 109 intptr_t str_length = strlen(str); | 110 const intptr_t str_length = strlen(str); |
| 111 if (str_length < 0) { | |
| 112 FATAL("Fatal error in BigintOperations::NewFromCString: string too long"); | |
| 113 } | |
| 110 if ((str_length > 2) && | 114 if ((str_length > 2) && |
| 111 (str[0] == '0') && | 115 (str[0] == '0') && |
| 112 ((str[1] == 'x') || (str[1] == 'X'))) { | 116 ((str[1] == 'x') || (str[1] == 'X'))) { |
| 113 const Bigint& result = Bigint::Handle(FromHexCString(&str[2], space)); | 117 const Bigint& result = Bigint::Handle(FromHexCString(&str[2], space)); |
| 114 ASSERT(IsClamped(result)); | 118 ASSERT(IsClamped(result)); |
| 115 return result.raw(); | 119 return result.raw(); |
| 116 } else { | 120 } else { |
| 117 return FromDecimalCString(str, space); | 121 return FromDecimalCString(str, space); |
| 118 } | 122 } |
| 119 } | 123 } |
| 120 | 124 |
| 121 | 125 |
| 122 intptr_t BigintOperations::ComputeChunkLength(const char* hex_string) { | 126 intptr_t BigintOperations::ComputeChunkLength(const char* hex_string) { |
| 123 ASSERT(kDigitBitSize % 4 == 0); | 127 ASSERT(kDigitBitSize % 4 == 0); |
| 124 intptr_t hex_length = strlen(hex_string); | 128 const intptr_t hex_length = strlen(hex_string); |
| 129 if (hex_length < 0) { | |
| 130 FATAL("Fatal error in BigintOperations::ComputeChunkLength: " | |
| 131 "string too long"); | |
| 132 } | |
| 125 // Round up. | 133 // Round up. |
| 126 intptr_t bigint_length = ((hex_length - 1) / kHexCharsPerDigit) + 1; | 134 intptr_t bigint_length = ((hex_length - 1) / kHexCharsPerDigit) + 1; |
| 127 return bigint_length; | 135 return bigint_length; |
| 128 } | 136 } |
| 129 | 137 |
| 130 | 138 |
| 131 RawBigint* BigintOperations::FromHexCString(const char* hex_string, | 139 RawBigint* BigintOperations::FromHexCString(const char* hex_string, |
| 132 Heap::Space space) { | 140 Heap::Space space) { |
| 133 // If the string starts with '-' recursively restart the whole operation | 141 // If the string starts with '-' recursively restart the whole operation |
| 134 // without the character and then toggle the sign. | 142 // without the character and then toggle the sign. |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 151 | 159 |
| 152 | 160 |
| 153 RawBigint* BigintOperations::FromDecimalCString(const char* str, | 161 RawBigint* BigintOperations::FromDecimalCString(const char* str, |
| 154 Heap::Space space) { | 162 Heap::Space space) { |
| 155 Isolate* isolate = Isolate::Current(); | 163 Isolate* isolate = Isolate::Current(); |
| 156 // Read 8 digits a time. 10^8 < 2^27. | 164 // Read 8 digits a time. 10^8 < 2^27. |
| 157 const int kDigitsPerIteration = 8; | 165 const int kDigitsPerIteration = 8; |
| 158 const Chunk kTenMultiplier = 100000000; | 166 const Chunk kTenMultiplier = 100000000; |
| 159 ASSERT(kDigitBitSize >= 27); | 167 ASSERT(kDigitBitSize >= 27); |
| 160 | 168 |
| 161 intptr_t str_length = strlen(str); | 169 const intptr_t str_length = strlen(str); |
| 170 if (str_length < 0) { | |
| 171 FATAL("Fatal error in BigintOperations::FromDecimalCString: " | |
| 172 "string too long"); | |
| 173 } | |
| 162 intptr_t str_pos = 0; | 174 intptr_t str_pos = 0; |
| 163 | 175 |
| 164 // Read first digit separately. This avoids a multiplication and addition. | 176 // Read first digit separately. This avoids a multiplication and addition. |
| 165 // The first digit might also not have kDigitsPerIteration decimal digits. | 177 // The first digit might also not have kDigitsPerIteration decimal digits. |
| 166 int first_digit_decimal_digits = str_length % kDigitsPerIteration; | 178 int first_digit_decimal_digits = str_length % kDigitsPerIteration; |
| 167 Chunk digit = 0; | 179 Chunk digit = 0; |
| 168 for (intptr_t i = 0; i < first_digit_decimal_digits; i++) { | 180 for (intptr_t i = 0; i < first_digit_decimal_digits; i++) { |
| 169 char c = str[str_pos++]; | 181 char c = str[str_pos++]; |
| 170 ASSERT(('0' <= c) && (c <= '9')); | 182 ASSERT(('0' <= c) && (c <= '9')); |
| 171 digit = digit * 10 + c - '0'; | 183 digit = digit * 10 + c - '0'; |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 244 void* data, | 256 void* data, |
| 245 uword (*allocator)(intptr_t size)) { | 257 uword (*allocator)(intptr_t size)) { |
| 246 NoGCScope no_gc; | 258 NoGCScope no_gc; |
| 247 | 259 |
| 248 ASSERT(kDigitBitSize % 4 == 0); | 260 ASSERT(kDigitBitSize % 4 == 0); |
| 249 | 261 |
| 250 intptr_t chunk_length = length; | 262 intptr_t chunk_length = length; |
| 251 Chunk* chunk_data = reinterpret_cast<Chunk*>(data); | 263 Chunk* chunk_data = reinterpret_cast<Chunk*>(data); |
| 252 if (length == 0) { | 264 if (length == 0) { |
| 253 const char* zero = "0x0"; | 265 const char* zero = "0x0"; |
| 254 const int kLength = strlen(zero); | 266 const intptr_t kLength = strlen(zero); |
| 255 char* result = reinterpret_cast<char*>(allocator(kLength + 1)); | 267 char* result = reinterpret_cast<char*>(allocator(kLength + 1)); |
| 256 ASSERT(result != NULL); | 268 ASSERT(result != NULL); |
| 257 memmove(result, zero, kLength); | 269 memmove(result, zero, kLength); |
| 258 result[kLength] = '\0'; | 270 result[kLength] = '\0'; |
| 259 return result; | 271 return result; |
| 260 } | 272 } |
| 261 ASSERT(chunk_data != NULL); | 273 ASSERT(chunk_data != NULL); |
| 262 | 274 |
| 263 // Compute the number of hex-digits that are needed to represent the | 275 // Compute the number of hex-digits that are needed to represent the |
| 264 // leading bigint-digit. All other digits need exactly kHexCharsPerDigit | 276 // leading bigint-digit. All other digits need exactly kHexCharsPerDigit |
| 265 // characters. | 277 // characters. |
| 266 int leading_hex_digits = 0; | 278 int leading_hex_digits = 0; |
| 267 Chunk leading_digit = chunk_data[chunk_length - 1]; | 279 Chunk leading_digit = chunk_data[chunk_length - 1]; |
| 268 while (leading_digit != 0) { | 280 while (leading_digit != 0) { |
| 269 leading_hex_digits++; | 281 leading_hex_digits++; |
| 270 leading_digit >>= 4; | 282 leading_digit >>= 4; |
| 271 } | 283 } |
| 272 // Sum up the space that is needed for the string-representation. | 284 // Sum up the space that is needed for the string-representation. |
| 273 intptr_t required_size = 0; | 285 intptr_t required_size = 0; |
| 274 if (is_negative) { | 286 if (is_negative) { |
| 275 required_size++; // For the leading "-". | 287 required_size++; // For the leading "-". |
| 276 } | 288 } |
| 277 required_size += 2; // For the "0x". | 289 required_size += 2; // For the "0x". |
| 278 required_size += leading_hex_digits; | 290 required_size += leading_hex_digits; |
| 279 required_size += (chunk_length - 1) * kHexCharsPerDigit; | 291 required_size += (chunk_length - 1) * kHexCharsPerDigit; |
| 280 required_size++; // For the trailing '\0'. | 292 required_size++; // For the trailing '\0'. |
| 293 if (required_size < 0) { | |
| 294 FATAL("Fatal error in BigintOperations::ToHexCString: string too long"); | |
| 295 } | |
|
siva
2013/09/17 00:19:52
As discussed offline the overflow could happen bef
Michael Lippautz (Google)
2013/09/17 03:36:50
Done.
| |
| 281 char* result = reinterpret_cast<char*>(allocator(required_size)); | 296 char* result = reinterpret_cast<char*>(allocator(required_size)); |
| 282 // Print the number into the string. | 297 // Print the number into the string. |
| 283 // Start from the last position. | 298 // Start from the last position. |
| 284 intptr_t pos = required_size - 1; | 299 intptr_t pos = required_size - 1; |
| 285 result[pos--] = '\0'; | 300 result[pos--] = '\0'; |
| 286 for (intptr_t i = 0; i < (chunk_length - 1); i++) { | 301 for (intptr_t i = 0; i < (chunk_length - 1); i++) { |
| 287 // Print all non-leading characters (which are printed with | 302 // Print all non-leading characters (which are printed with |
| 288 // kHexCharsPerDigit characters. | 303 // kHexCharsPerDigit characters. |
| 289 Chunk digit = chunk_data[i]; | 304 Chunk digit = chunk_data[i]; |
| 290 for (int j = 0; j < kHexCharsPerDigit; j++) { | 305 for (int j = 0; j < kHexCharsPerDigit; j++) { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 344 // Approximate the size of the resulting string. We prefer overestimating | 359 // Approximate the size of the resulting string. We prefer overestimating |
| 345 // to not allocating enough. | 360 // to not allocating enough. |
| 346 int64_t bit_length = length * kDigitBitSize; | 361 int64_t bit_length = length * kDigitBitSize; |
| 347 ASSERT(bit_length > length); | 362 ASSERT(bit_length > length); |
| 348 int64_t decimal_length = (bit_length * kLog2Dividend / kLog2Divisor) + 1; | 363 int64_t decimal_length = (bit_length * kLog2Dividend / kLog2Divisor) + 1; |
| 349 // Add one byte for the trailing \0 character. | 364 // Add one byte for the trailing \0 character. |
| 350 int64_t required_size = decimal_length + 1; | 365 int64_t required_size = decimal_length + 1; |
| 351 if (bigint.IsNegative()) { | 366 if (bigint.IsNegative()) { |
| 352 required_size++; | 367 required_size++; |
| 353 } | 368 } |
| 354 ASSERT(required_size == static_cast<intptr_t>(required_size)); | 369 if (required_size != static_cast<intptr_t>(required_size)) { |
|
siva
2013/09/17 00:19:52
Ditto comment here too.
Michael Lippautz (Google)
2013/09/17 03:36:50
Removed the check, because it's already there (as
| |
| 370 FATAL("Fatal error in BigintOperations::ToDecimalCString: " | |
| 371 "string too long"); | |
| 372 } | |
| 355 // We will fill the result in the inverse order and then exchange at the end. | 373 // We will fill the result in the inverse order and then exchange at the end. |
| 356 char* result = | 374 char* result = |
| 357 reinterpret_cast<char*>(allocator(static_cast<intptr_t>(required_size))); | 375 reinterpret_cast<char*>(allocator(static_cast<intptr_t>(required_size))); |
| 358 ASSERT(result != NULL); | 376 ASSERT(result != NULL); |
| 359 int result_pos = 0; | 377 int result_pos = 0; |
| 360 | 378 |
| 361 // We divide the input into pieces of ~27 bits which can be efficiently | 379 // We divide the input into pieces of ~27 bits which can be efficiently |
| 362 // handled. | 380 // handled. |
| 363 const intptr_t kChunkDivisor = 100000000; | 381 const intptr_t kChunkDivisor = 100000000; |
| 364 const int kChunkDigits = 8; | 382 const int kChunkDigits = 8; |
| (...skipping 969 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1334 | 1352 |
| 1335 | 1353 |
| 1336 void BigintOperations::FromHexCString(const char* hex_string, | 1354 void BigintOperations::FromHexCString(const char* hex_string, |
| 1337 const Bigint& value) { | 1355 const Bigint& value) { |
| 1338 ASSERT(hex_string[0] != '-'); | 1356 ASSERT(hex_string[0] != '-'); |
| 1339 intptr_t bigint_length = ComputeChunkLength(hex_string); | 1357 intptr_t bigint_length = ComputeChunkLength(hex_string); |
| 1340 // The bigint's least significant digit (lsd) is at position 0, whereas the | 1358 // The bigint's least significant digit (lsd) is at position 0, whereas the |
| 1341 // given string has it's lsd at the last position. | 1359 // given string has it's lsd at the last position. |
| 1342 // The hex_i index, pointing into the string, starts therefore at the end, | 1360 // The hex_i index, pointing into the string, starts therefore at the end, |
| 1343 // whereas the bigint-index (i) starts at 0. | 1361 // whereas the bigint-index (i) starts at 0. |
| 1344 intptr_t hex_length = strlen(hex_string); | 1362 const intptr_t hex_length = strlen(hex_string); |
| 1363 if (hex_length < 0) { | |
| 1364 FATAL("Fatal error in BigintOperations::FromHexCString: string too long"); | |
| 1365 } | |
| 1345 intptr_t hex_i = hex_length - 1; | 1366 intptr_t hex_i = hex_length - 1; |
| 1346 for (intptr_t i = 0; i < bigint_length; i++) { | 1367 for (intptr_t i = 0; i < bigint_length; i++) { |
| 1347 Chunk digit = 0; | 1368 Chunk digit = 0; |
| 1348 int shift = 0; | 1369 int shift = 0; |
| 1349 for (int j = 0; j < kHexCharsPerDigit; j++) { | 1370 for (int j = 0; j < kHexCharsPerDigit; j++) { |
| 1350 // Reads a block of hexadecimal digits and stores it in 'digit'. | 1371 // Reads a block of hexadecimal digits and stores it in 'digit'. |
| 1351 // Ex: "0123456" with kHexCharsPerDigit == 3, hex_i == 6, reads "456". | 1372 // Ex: "0123456" with kHexCharsPerDigit == 3, hex_i == 6, reads "456". |
| 1352 if (hex_i < 0) { | 1373 if (hex_i < 0) { |
| 1353 break; | 1374 break; |
| 1354 } | 1375 } |
| (...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1748 int BigintOperations::CountBits(Chunk digit) { | 1769 int BigintOperations::CountBits(Chunk digit) { |
| 1749 int result = 0; | 1770 int result = 0; |
| 1750 while (digit != 0) { | 1771 while (digit != 0) { |
| 1751 digit >>= 1; | 1772 digit >>= 1; |
| 1752 result++; | 1773 result++; |
| 1753 } | 1774 } |
| 1754 return result; | 1775 return result; |
| 1755 } | 1776 } |
| 1756 | 1777 |
| 1757 } // namespace dart | 1778 } // namespace dart |
| OLD | NEW |