| 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 // No overflow check needed since overflowing str_length implies that we take |
| 111 // the branch to FromDecimalCString() which contains a check itself. |
| 112 const intptr_t str_length = strlen(str); |
| 110 if ((str_length > 2) && | 113 if ((str_length > 2) && |
| 111 (str[0] == '0') && | 114 (str[0] == '0') && |
| 112 ((str[1] == 'x') || (str[1] == 'X'))) { | 115 ((str[1] == 'x') || (str[1] == 'X'))) { |
| 113 const Bigint& result = Bigint::Handle(FromHexCString(&str[2], space)); | 116 const Bigint& result = Bigint::Handle(FromHexCString(&str[2], space)); |
| 114 ASSERT(IsClamped(result)); | 117 ASSERT(IsClamped(result)); |
| 115 return result.raw(); | 118 return result.raw(); |
| 116 } else { | 119 } else { |
| 117 return FromDecimalCString(str, space); | 120 return FromDecimalCString(str, space); |
| 118 } | 121 } |
| 119 } | 122 } |
| 120 | 123 |
| 121 | 124 |
| 122 intptr_t BigintOperations::ComputeChunkLength(const char* hex_string) { | 125 intptr_t BigintOperations::ComputeChunkLength(const char* hex_string) { |
| 123 ASSERT(kDigitBitSize % 4 == 0); | 126 ASSERT(kDigitBitSize % 4 == 0); |
| 124 intptr_t hex_length = strlen(hex_string); | 127 const intptr_t hex_length = strlen(hex_string); |
| 128 if (hex_length < 0) { |
| 129 FATAL("Fatal error in BigintOperations::ComputeChunkLength: " |
| 130 "string too long"); |
| 131 } |
| 125 // Round up. | 132 // Round up. |
| 126 intptr_t bigint_length = ((hex_length - 1) / kHexCharsPerDigit) + 1; | 133 intptr_t bigint_length = ((hex_length - 1) / kHexCharsPerDigit) + 1; |
| 127 return bigint_length; | 134 return bigint_length; |
| 128 } | 135 } |
| 129 | 136 |
| 130 | 137 |
| 131 RawBigint* BigintOperations::FromHexCString(const char* hex_string, | 138 RawBigint* BigintOperations::FromHexCString(const char* hex_string, |
| 132 Heap::Space space) { | 139 Heap::Space space) { |
| 133 // If the string starts with '-' recursively restart the whole operation | 140 // If the string starts with '-' recursively restart the whole operation |
| 134 // without the character and then toggle the sign. | 141 // without the character and then toggle the sign. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 151 | 158 |
| 152 | 159 |
| 153 RawBigint* BigintOperations::FromDecimalCString(const char* str, | 160 RawBigint* BigintOperations::FromDecimalCString(const char* str, |
| 154 Heap::Space space) { | 161 Heap::Space space) { |
| 155 Isolate* isolate = Isolate::Current(); | 162 Isolate* isolate = Isolate::Current(); |
| 156 // Read 8 digits a time. 10^8 < 2^27. | 163 // Read 8 digits a time. 10^8 < 2^27. |
| 157 const int kDigitsPerIteration = 8; | 164 const int kDigitsPerIteration = 8; |
| 158 const Chunk kTenMultiplier = 100000000; | 165 const Chunk kTenMultiplier = 100000000; |
| 159 ASSERT(kDigitBitSize >= 27); | 166 ASSERT(kDigitBitSize >= 27); |
| 160 | 167 |
| 161 intptr_t str_length = strlen(str); | 168 const intptr_t str_length = strlen(str); |
| 169 if (str_length < 0) { |
| 170 FATAL("Fatal error in BigintOperations::FromDecimalCString: " |
| 171 "string too long"); |
| 172 } |
| 162 intptr_t str_pos = 0; | 173 intptr_t str_pos = 0; |
| 163 | 174 |
| 164 // Read first digit separately. This avoids a multiplication and addition. | 175 // Read first digit separately. This avoids a multiplication and addition. |
| 165 // The first digit might also not have kDigitsPerIteration decimal digits. | 176 // The first digit might also not have kDigitsPerIteration decimal digits. |
| 166 int first_digit_decimal_digits = str_length % kDigitsPerIteration; | 177 int first_digit_decimal_digits = str_length % kDigitsPerIteration; |
| 167 Chunk digit = 0; | 178 Chunk digit = 0; |
| 168 for (intptr_t i = 0; i < first_digit_decimal_digits; i++) { | 179 for (intptr_t i = 0; i < first_digit_decimal_digits; i++) { |
| 169 char c = str[str_pos++]; | 180 char c = str[str_pos++]; |
| 170 ASSERT(('0' <= c) && (c <= '9')); | 181 ASSERT(('0' <= c) && (c <= '9')); |
| 171 digit = digit * 10 + c - '0'; | 182 digit = digit * 10 + c - '0'; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 240 | 251 |
| 241 | 252 |
| 242 const char* BigintOperations::ToHexCString(intptr_t length, | 253 const char* BigintOperations::ToHexCString(intptr_t length, |
| 243 bool is_negative, | 254 bool is_negative, |
| 244 void* data, | 255 void* data, |
| 245 uword (*allocator)(intptr_t size)) { | 256 uword (*allocator)(intptr_t size)) { |
| 246 NoGCScope no_gc; | 257 NoGCScope no_gc; |
| 247 | 258 |
| 248 ASSERT(kDigitBitSize % 4 == 0); | 259 ASSERT(kDigitBitSize % 4 == 0); |
| 249 | 260 |
| 250 intptr_t chunk_length = length; | 261 // Conservative maximum chunk length. |
| 262 const intptr_t kMaxChunkLen = |
| 263 (kIntptrMax - 2 /* 0x */ |
| 264 - 1 /* trailing '\0' */ |
| 265 - 1 /* leading '-' */) / kHexCharsPerDigit; |
| 266 const intptr_t chunk_length = length; |
| 267 // Conservative check assuming leading bigint-digit also takes up |
| 268 // kHexCharsPerDigit. |
| 269 if (chunk_length > kMaxChunkLen) { |
| 270 FATAL("Fatal error in BigintOperations::ToHexCString: string too long"); |
| 271 } |
| 251 Chunk* chunk_data = reinterpret_cast<Chunk*>(data); | 272 Chunk* chunk_data = reinterpret_cast<Chunk*>(data); |
| 252 if (length == 0) { | 273 if (length == 0) { |
| 253 const char* zero = "0x0"; | 274 const char* zero = "0x0"; |
| 254 const int kLength = strlen(zero); | 275 const intptr_t kLength = strlen(zero); |
| 255 char* result = reinterpret_cast<char*>(allocator(kLength + 1)); | 276 char* result = reinterpret_cast<char*>(allocator(kLength + 1)); |
| 256 ASSERT(result != NULL); | 277 ASSERT(result != NULL); |
| 257 memmove(result, zero, kLength); | 278 memmove(result, zero, kLength); |
| 258 result[kLength] = '\0'; | 279 result[kLength] = '\0'; |
| 259 return result; | 280 return result; |
| 260 } | 281 } |
| 261 ASSERT(chunk_data != NULL); | 282 ASSERT(chunk_data != NULL); |
| 262 | 283 |
| 263 // Compute the number of hex-digits that are needed to represent the | 284 // Compute the number of hex-digits that are needed to represent the |
| 264 // leading bigint-digit. All other digits need exactly kHexCharsPerDigit | 285 // leading bigint-digit. All other digits need exactly kHexCharsPerDigit |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 323 const char* BigintOperations::ToDecimalCString( | 344 const char* BigintOperations::ToDecimalCString( |
| 324 const Bigint& bigint, uword (*allocator)(intptr_t size)) { | 345 const Bigint& bigint, uword (*allocator)(intptr_t size)) { |
| 325 // log10(2) ~= 0.30102999566398114. | 346 // log10(2) ~= 0.30102999566398114. |
| 326 const intptr_t kLog2Dividend = 30103; | 347 const intptr_t kLog2Dividend = 30103; |
| 327 const intptr_t kLog2Divisor = 100000; | 348 const intptr_t kLog2Divisor = 100000; |
| 328 // We remove a small constant for rounding imprecision, the \0 character and | 349 // We remove a small constant for rounding imprecision, the \0 character and |
| 329 // the negative sign. | 350 // the negative sign. |
| 330 const intptr_t kMaxAllowedDigitLength = | 351 const intptr_t kMaxAllowedDigitLength = |
| 331 (kIntptrMax - 10) / kLog2Dividend / kDigitBitSize * kLog2Divisor; | 352 (kIntptrMax - 10) / kLog2Dividend / kDigitBitSize * kLog2Divisor; |
| 332 | 353 |
| 333 intptr_t length = bigint.Length(); | 354 const intptr_t length = bigint.Length(); |
| 334 Isolate* isolate = Isolate::Current(); | 355 Isolate* isolate = Isolate::Current(); |
| 335 if (length >= kMaxAllowedDigitLength) { | 356 if (length >= kMaxAllowedDigitLength) { |
| 336 // Use the preallocated out of memory exception to avoid calling | 357 // Use the preallocated out of memory exception to avoid calling |
| 337 // into dart code or allocating any code. | 358 // into dart code or allocating any code. |
| 338 const Instance& exception = | 359 const Instance& exception = |
| 339 Instance::Handle(isolate->object_store()->out_of_memory()); | 360 Instance::Handle(isolate->object_store()->out_of_memory()); |
| 340 Exceptions::Throw(exception); | 361 Exceptions::Throw(exception); |
| 341 UNREACHABLE(); | 362 UNREACHABLE(); |
| 342 } | 363 } |
| 343 | 364 |
| (...skipping 990 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1334 | 1355 |
| 1335 | 1356 |
| 1336 void BigintOperations::FromHexCString(const char* hex_string, | 1357 void BigintOperations::FromHexCString(const char* hex_string, |
| 1337 const Bigint& value) { | 1358 const Bigint& value) { |
| 1338 ASSERT(hex_string[0] != '-'); | 1359 ASSERT(hex_string[0] != '-'); |
| 1339 intptr_t bigint_length = ComputeChunkLength(hex_string); | 1360 intptr_t bigint_length = ComputeChunkLength(hex_string); |
| 1340 // The bigint's least significant digit (lsd) is at position 0, whereas the | 1361 // The bigint's least significant digit (lsd) is at position 0, whereas the |
| 1341 // given string has it's lsd at the last position. | 1362 // given string has it's lsd at the last position. |
| 1342 // The hex_i index, pointing into the string, starts therefore at the end, | 1363 // The hex_i index, pointing into the string, starts therefore at the end, |
| 1343 // whereas the bigint-index (i) starts at 0. | 1364 // whereas the bigint-index (i) starts at 0. |
| 1344 intptr_t hex_length = strlen(hex_string); | 1365 const intptr_t hex_length = strlen(hex_string); |
| 1366 if (hex_length < 0) { |
| 1367 FATAL("Fatal error in BigintOperations::FromHexCString: string too long"); |
| 1368 } |
| 1345 intptr_t hex_i = hex_length - 1; | 1369 intptr_t hex_i = hex_length - 1; |
| 1346 for (intptr_t i = 0; i < bigint_length; i++) { | 1370 for (intptr_t i = 0; i < bigint_length; i++) { |
| 1347 Chunk digit = 0; | 1371 Chunk digit = 0; |
| 1348 int shift = 0; | 1372 int shift = 0; |
| 1349 for (int j = 0; j < kHexCharsPerDigit; j++) { | 1373 for (int j = 0; j < kHexCharsPerDigit; j++) { |
| 1350 // Reads a block of hexadecimal digits and stores it in 'digit'. | 1374 // Reads a block of hexadecimal digits and stores it in 'digit'. |
| 1351 // Ex: "0123456" with kHexCharsPerDigit == 3, hex_i == 6, reads "456". | 1375 // Ex: "0123456" with kHexCharsPerDigit == 3, hex_i == 6, reads "456". |
| 1352 if (hex_i < 0) { | 1376 if (hex_i < 0) { |
| 1353 break; | 1377 break; |
| 1354 } | 1378 } |
| (...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1748 int BigintOperations::CountBits(Chunk digit) { | 1772 int BigintOperations::CountBits(Chunk digit) { |
| 1749 int result = 0; | 1773 int result = 0; |
| 1750 while (digit != 0) { | 1774 while (digit != 0) { |
| 1751 digit >>= 1; | 1775 digit >>= 1; |
| 1752 result++; | 1776 result++; |
| 1753 } | 1777 } |
| 1754 return result; | 1778 return result; |
| 1755 } | 1779 } |
| 1756 | 1780 |
| 1757 } // namespace dart | 1781 } // namespace dart |
| OLD | NEW |