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

Side by Side Diff: vm/bigint_operations.cc

Issue 9481019: Changes to get rid of dependency on openssl in the dart VM. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/runtime/
Patch Set: Created 8 years, 9 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
« no previous file with comments | « vm/bigint_operations.h ('k') | vm/bigint_operations_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright 2012 Google Inc. All Rights Reserved.
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.
4 2
5 #include "vm/bigint_operations.h" 3 #include "vm/bigint_operations.h"
6 4
7 #include <openssl/crypto.h> 5 #include "platform/utils.h"
8 6
9 #include "platform/utils.h"
10 #include "vm/bigint_store.h"
11 #include "vm/double_internals.h" 7 #include "vm/double_internals.h"
12 #include "vm/exceptions.h" 8 #include "vm/exceptions.h"
13 #include "vm/zone.h" 9 #include "vm/zone.h"
14 10
15 namespace dart { 11 namespace dart {
16 12
17 bool Bigint::IsZero() const { return BN_is_zero(BNAddr()); }
18 bool Bigint::IsNegative() const { return !!BNAddr()->neg; }
19
20
21 void Bigint::SetSign(bool is_negative) const {
22 BIGNUM* bn = MutableBNAddr();
23 // Danger Will Robinson! Use of OpenSSL internals!
24 // FIXME(benl): can be changed to use BN_set_negative() on more
25 // recent OpenSSL releases (> 1.0.0).
26 if (!is_negative || BN_is_zero(bn)) {
27 bn->neg = 0;
28 } else {
29 bn->neg = 1;
30 }
31 }
32
33
34 BIGNUM* BigintOperations::TmpBN() {
35 BigintStore* store = BigintStore::Get();
36 if (store->bn_ == NULL) {
37 store->bn_ = BN_new();
38 }
39 return store->bn_;
40 }
41
42
43 BN_CTX* BigintOperations::TmpBNCtx() {
44 BigintStore* store = BigintStore::Get();
45 if (store->bn_ctx_ == NULL) {
46 store->bn_ctx_ = BN_CTX_new();
47 }
48 return store->bn_ctx_;
49 }
50
51
52 RawBigint* BigintOperations::NewFromSmi(const Smi& smi, Heap::Space space) { 13 RawBigint* BigintOperations::NewFromSmi(const Smi& smi, Heap::Space space) {
53 intptr_t value = smi.Value(); 14 intptr_t value = smi.Value();
54 bool is_negative = value < 0; 15 if (value == 0) {
16 return Zero();
17 }
55 18
19 bool is_negative = (value < 0);
56 if (is_negative) { 20 if (is_negative) {
57 value = -value; 21 value = -value;
58 } 22 }
23 // Assert that there are no overflows. Smis reserve a bit for themselves, but
24 // protect against future changes.
25 ASSERT(-Smi::kMinValue > 0);
59 26
60 BN_set_word(TmpBN(), value); 27 // A single digit of a Bigint might not be sufficient to store a Smi.
28 // Count number of needed Digits.
29 intptr_t digit_count = 0;
30 intptr_t count_value = value;
31 while (count_value > 0) {
32 digit_count++;
33 count_value >>= kDigitBitSize;
34 }
61 35
62 const Bigint& result = Bigint::Handle(Bigint::New(TmpBN(), space)); 36 // Allocate a bigint of the correct size and copy the bits.
37 const Bigint& result = Bigint::Handle(Bigint::Allocate(digit_count, space));
38 for (int i = 0; i < digit_count; i++) {
39 result.SetChunkAt(i, static_cast<Chunk>(value & kDigitMask));
40 value >>= kDigitBitSize;
41 }
63 result.SetSign(is_negative); 42 result.SetSign(is_negative);
64 43 ASSERT(IsClamped(result));
65 return result.raw(); 44 return result.raw();
66 } 45 }
67 46
68 47
69 RawBigint* BigintOperations::NewFromInt64(int64_t value, Heap::Space space) { 48 RawBigint* BigintOperations::NewFromInt64(int64_t value, Heap::Space space) {
70 bool is_negative = value < 0; 49 bool is_negative = value < 0;
71 50
72 if (is_negative) { 51 if (is_negative) {
73 value = -value; 52 value = -value;
74 } 53 }
75 54
76 const Bigint& result = Bigint::Handle(NewFromUint64(value, space)); 55 const Bigint& result = Bigint::Handle(NewFromUint64(value, space));
77 result.SetSign(is_negative); 56 result.SetSign(is_negative);
78 57
79 return result.raw(); 58 return result.raw();
80 } 59 }
81 60
82 61
83 RawBigint* BigintOperations::NewFromUint64(uint64_t value, Heap::Space space) { 62 RawBigint* BigintOperations::NewFromUint64(uint64_t value, Heap::Space space) {
84 const int kNumBytes = sizeof(value); 63 if (value == 0) {
85 unsigned char pch[kNumBytes]; 64 return Zero();
86 for (int i = kNumBytes - 1; i >= 0; i--) {
87 unsigned char c = value & 0xFF;
88 value >>=8;
89 pch[i] = c;
90 } 65 }
91 BN_bin2bn(pch, kNumBytes, TmpBN()); 66 // A single digit of a Bigint might not be sufficient to store the value.
92 return Bigint::New(TmpBN(), space); 67 // Count number of needed Digits.
68 intptr_t digit_count = 0;
69 uint64_t count_value = value;
70 while (count_value > 0) {
71 digit_count++;
72 count_value >>= kDigitBitSize;
73 }
74
75 // Allocate a bigint of the correct size and copy the bits.
76 const Bigint& result = Bigint::Handle(Bigint::Allocate(digit_count, space));
77 for (int i = 0; i < digit_count; i++) {
78 result.SetChunkAt(i, static_cast<Chunk>(value & kDigitMask));
79 value >>= kDigitBitSize;
80 }
81 result.SetSign(false);
82 ASSERT(IsClamped(result));
83 return result.raw();
93 } 84 }
94 85
95 86
96 RawBigint* BigintOperations::NewFromCString(const char* str, 87 RawBigint* BigintOperations::NewFromCString(const char* str,
97 Heap::Space space) { 88 Heap::Space space) {
98 ASSERT(str != NULL); 89 ASSERT(str != NULL);
99 if (str[0] == '\0') { 90 if (str[0] == '\0') {
100 return NewFromInt64(0, space); 91 return Zero();
101 } 92 }
102 93
103 // If the string starts with '-' recursively restart the whole operation 94 // If the string starts with '-' recursively restart the whole operation
104 // without the character and then toggle the sign. 95 // without the character and then toggle the sign.
105 // This allows multiple leading '-' (which will cancel each other out), but 96 // This allows multiple leading '-' (which will cancel each other out), but
106 // we have added an assert, to make sure that the returned result of the 97 // we have added an assert, to make sure that the returned result of the
107 // recursive call is not negative. 98 // recursive call is not negative.
108 // We don't catch leading '-'s for zero. Ex: "--0", or "---". 99 // We don't catch leading '-'s for zero. Ex: "--0", or "---".
109 if (str[0] == '-') { 100 if (str[0] == '-') {
110 const Bigint& result = Bigint::Handle(NewFromCString(&str[1], space)); 101 const Bigint& result = Bigint::Handle(NewFromCString(&str[1], space));
111 if (!result.IsNull()) { 102 result.ToggleSign();
112 result.ToggleSign(); 103 ASSERT(result.IsZero() || result.IsNegative());
113 // FIXME(benl): this will fail if there is more than one leading '-'. 104 ASSERT(IsClamped(result));
114 ASSERT(result.IsZero() || result.IsNegative());
115 }
116 return result.raw(); 105 return result.raw();
117 } 106 }
118 107
119 intptr_t str_length = strlen(str); 108 intptr_t str_length = strlen(str);
120 if ((str_length > 2) && 109 if ((str_length > 2) &&
121 (str[0] == '0') && 110 (str[0] == '0') &&
122 ((str[1] == 'x') || (str[1] == 'X'))) { 111 ((str[1] == 'x') || (str[1] == 'X'))) {
123 const Bigint& result = Bigint::Handle(FromHexCString(&str[2], space)); 112 const Bigint& result = Bigint::Handle(FromHexCString(&str[2], space));
113 ASSERT(IsClamped(result));
124 return result.raw(); 114 return result.raw();
125 } else { 115 } else {
126 return FromDecimalCString(str, space); 116 return FromDecimalCString(str);
127 } 117 }
128 } 118 }
129 119
130 120
121 RawBigint* BigintOperations::FromHexCString(const char* hex_string,
122 Heap::Space space) {
123 // If the string starts with '-' recursively restart the whole operation
124 // without the character and then toggle the sign.
125 // This allows multiple leading '-' (which will cancel each other out), but
126 // we have added an assert, to make sure that the returned result of the
127 // recursive call is not negative.
128 // We don't catch leading '-'s for zero. Ex: "--0", or "---".
129 if (hex_string[0] == '-') {
130 const Bigint& value = Bigint::Handle(FromHexCString(&hex_string[1], space));
131 value.ToggleSign();
132 ASSERT(value.IsZero() || value.IsNegative());
133 ASSERT(IsClamped(value));
134 return value.raw();
135 }
136
137 ASSERT(kDigitBitSize % 4 == 0);
138 const int kHexCharsPerDigit = kDigitBitSize / 4;
139
140 intptr_t hex_length = strlen(hex_string);
141 // Round up.
142 intptr_t bigint_length = ((hex_length - 1) / kHexCharsPerDigit) + 1;
143 const Bigint& result =
144 Bigint::Handle(Bigint::Allocate(bigint_length, space));
145 // The bigint's least significant digit (lsd) is at position 0, whereas the
146 // given string has it's lsd at the last position.
147 // The hex_i index, pointing into the string, starts therefore at the end,
148 // whereas the bigint-index (i) starts at 0.
149 intptr_t hex_i = hex_length - 1;
150 for (intptr_t i = 0; i < bigint_length; i++) {
151 Chunk digit = 0;
152 int shift = 0;
153 for (int j = 0; j < kHexCharsPerDigit; j++) {
154 // Reads a block of hexadecimal digits and stores it in 'digit'.
155 // Ex: "0123456" with kHexCharsPerDigit == 3, hex_i == 6, reads "456".
156 if (hex_i < 0) {
157 break;
158 }
159 ASSERT(hex_i >= 0);
160 char c = hex_string[hex_i--];
161 ASSERT(Utils::IsHexDigit(c));
162 digit += static_cast<Chunk>(Utils::HexDigitToInt(c)) << shift;
163 shift += 4;
164 }
165 result.SetChunkAt(i, digit);
166 }
167 ASSERT(hex_i == -1);
168 Clamp(result);
169 return result.raw();
170 }
171
172
173 RawBigint* BigintOperations::FromDecimalCString(const char* str,
174 Heap::Space space) {
175 // Read 8 digits a time. 10^8 < 2^27.
176 const int kDigitsPerIteration = 8;
177 const Chunk kTenMultiplier = 100000000;
178 ASSERT(kDigitBitSize >= 27);
179
180 intptr_t str_length = strlen(str);
181 intptr_t str_pos = 0;
182
183 // Read first digit separately. This avoids a multiplication and addition.
184 // The first digit might also not have kDigitsPerIteration decimal digits.
185 int first_digit_decimal_digits = str_length % kDigitsPerIteration;
186 Chunk digit = 0;
187 for (intptr_t i = 0; i < first_digit_decimal_digits; i++) {
188 char c = str[str_pos++];
189 ASSERT(('0' <= c) && (c <= '9'));
190 digit = digit * 10 + c - '0';
191 }
192 Bigint& result = Bigint::Handle(Bigint::Allocate(1, space));
193 result.SetChunkAt(0, digit);
194 Clamp(result); // Multiplication requires the inputs to be clamped.
195
196 // Read kDigitsPerIteration at a time, and store it in 'increment'.
197 // Then multiply the temporary result by 10^kDigitsPerIteration and add
198 // 'increment' to the new result.
199 const Bigint& increment = Bigint::Handle(Bigint::Allocate(1, space));
200 while (str_pos < str_length - 1) {
201 Chunk digit = 0;
202 for (intptr_t i = 0; i < kDigitsPerIteration; i++) {
203 char c = str[str_pos++];
204 ASSERT(('0' <= c) && (c <= '9'));
205 digit = digit * 10 + c - '0';
206 }
207 result ^= MultiplyWithDigit(result, kTenMultiplier);
208 if (digit != 0) {
209 increment.SetChunkAt(0, digit);
210 result ^= Add(result, increment);
211 }
212 }
213 Clamp(result);
214 return result.raw();
215 }
216
217
131 RawBigint* BigintOperations::NewFromDouble(double d, Heap::Space space) { 218 RawBigint* BigintOperations::NewFromDouble(double d, Heap::Space space) {
132 if ((-1.0 < d) && (d < 1.0)) { 219 if ((-1.0 < d) && (d < 1.0)) {
133 // Shortcut for small numbers. Also makes the right-shift below 220 // Shortcut for small numbers. Also makes the right-shift below
134 // well specified. 221 // well specified.
135 Smi& zero = Smi::Handle(Smi::New(0)); 222 Smi& zero = Smi::Handle(Smi::New(0));
136 return NewFromSmi(zero, space); 223 return NewFromSmi(zero, space);
137 } 224 }
138 DoubleInternals internals = DoubleInternals(d); 225 DoubleInternals internals = DoubleInternals(d);
139 if (internals.IsSpecial()) { 226 if (internals.IsSpecial()) {
140 GrowableArray<const Object*> exception_arguments; 227 GrowableArray<const Object*> exception_arguments;
(...skipping 19 matching lines...) Expand all
160 Bigint::Handle(NewFromInt64(static_cast<int64_t>(significand), space)); 247 Bigint::Handle(NewFromInt64(static_cast<int64_t>(significand), space));
161 result.SetSign(sign < 0); 248 result.SetSign(sign < 0);
162 if (exponent > 0) { 249 if (exponent > 0) {
163 return ShiftLeft(result, exponent); 250 return ShiftLeft(result, exponent);
164 } else { 251 } else {
165 return result.raw(); 252 return result.raw();
166 } 253 }
167 } 254 }
168 255
169 256
170 RawBigint* BigintOperations::FromHexCString(const char* hex_string, 257 const char* BigintOperations::ToHexCString(intptr_t length,
171 Heap::Space space) { 258 bool is_negative,
172 BIGNUM *bn = TmpBN(); 259 void* data,
173 BN_hex2bn(&bn, hex_string); 260 uword (*allocator)(intptr_t size)) {
174 ASSERT(bn == TmpBN()); 261 NoGCScope no_gc;
175 const Bigint& result = Bigint::Handle(Bigint::New(TmpBN(), space));
176 return result.raw();
177 }
178 262
263 ASSERT(kDigitBitSize % 4 == 0);
264 const int kHexCharsPerDigit = kDigitBitSize / 4;
179 265
180 RawBigint* BigintOperations::FromDecimalCString(const char* str, 266 intptr_t chunk_length = length;
181 Heap::Space space) { 267 Chunk* chunk_data = reinterpret_cast<Chunk*>(data);
182 BIGNUM *bn = TmpBN(); 268 if (length == 0) {
183 int len = BN_dec2bn(&bn, str); 269 const char* zero = "0x0";
184 if (len == 0) { 270 const int kLength = strlen(zero);
185 return Bigint::null(); 271 char* result = reinterpret_cast<char*>(allocator(kLength + 1));
272 ASSERT(result != NULL);
273 memmove(result, zero, kLength);
274 result[kLength] = '\0';
275 return result;
186 } 276 }
187 ASSERT(bn == TmpBN()); 277 ASSERT(chunk_data != NULL);
188 const Bigint& result = Bigint::Handle(Bigint::New(TmpBN(), space));
189 return result.raw();
190 }
191 278
192 279 // Compute the number of hex-digits that are needed to represent the
193 const char* BigintOperations::ToHexCString(const BIGNUM *bn, 280 // leading bigint-digit. All other digits need exactly kHexCharsPerDigit
194 uword (*allocator)(intptr_t size)) { 281 // characters.
195 char* str = BN_bn2hex(bn); 282 int leading_hex_digits = 0;
196 char* to_free = str; 283 Chunk leading_digit = chunk_data[chunk_length - 1];
197 intptr_t neg = 0; 284 while (leading_digit != 0) {
198 if (str[0] == '-') { 285 leading_hex_digits++;
199 ++str; 286 leading_digit >>= 4;
200 neg = 1;
201 } 287 }
202 if (str[0] == '0' && str[1] != '\0') { 288 // Sum up the space that is needed for the string-representation.
203 ++str; 289 intptr_t required_size = 0;
290 if (is_negative) {
291 required_size++; // For the leading "-".
204 } 292 }
205 intptr_t length = strlen(str) + 3 + neg; 293 required_size += 2; // For the "0x".
206 char *result = reinterpret_cast<char*>(allocator(length)); 294 required_size += leading_hex_digits;
207 if (neg) { 295 required_size += (chunk_length - 1) * kHexCharsPerDigit;
208 result[0] = '-'; 296 required_size++; // For the trailing '\0'.
209 result[1] = '0'; 297 char* result = reinterpret_cast<char*>(allocator(required_size));
210 result[2] = 'x'; 298 // Print the number into the string.
211 // memcpy would suffice 299 // Start from the last position.
212 memmove(result + 3, str, length - 3); 300 intptr_t pos = required_size - 1;
213 } else { 301 result[pos--] = '\0';
214 result[0] = '0'; 302 for (intptr_t i = 0; i < (chunk_length - 1); i++) {
215 result[1] = 'x'; 303 // Print all non-leading characters (which are printed with
216 // memcpy would suffice 304 // kHexCharsPerDigit characters.
217 memmove(result + 2, str, length - 2); 305 Chunk digit = chunk_data[i];
306 for (int j = 0; j < kHexCharsPerDigit; j++) {
307 result[pos--] = Utils::IntToHexDigit(static_cast<int>(digit & 0xF));
308 digit >>= 4;
309 }
218 } 310 }
219 OPENSSL_free(to_free); 311 // Print the leading digit.
220 return result; 312 leading_digit = chunk_data[chunk_length - 1];
221 } 313 while (leading_digit != 0) {
222 314 result[pos--] = Utils::IntToHexDigit(static_cast<int>(leading_digit & 0xF));
223 315 leading_digit >>= 4;
224 const char* BigintOperations::ToDecCString(const Bigint& bigint, 316 }
225 uword (*allocator)(intptr_t size)) { 317 result[pos--] = 'x';
226 return ToDecCString(bigint.BNAddr(), allocator); 318 result[pos--] = '0';
227 } 319 if (is_negative) {
228 320 result[pos--] = '-';
229 321 }
230 const char* BigintOperations::ToDecCString(const BIGNUM *bn, 322 ASSERT(pos == -1);
231 uword (*allocator)(intptr_t size)) {
232 char* str = BN_bn2dec(bn);
233 intptr_t length = strlen(str) + 1; // '\0'-terminated.
234 char* result = reinterpret_cast<char*>(allocator(length));
235 memmove(result, str, length);
236 OPENSSL_free(str);
237 return result; 323 return result;
238 } 324 }
239 325
240 326
241 const char* BigintOperations::ToHexCString(const Bigint& bigint, 327 const char* BigintOperations::ToHexCString(const Bigint& bigint,
242 uword (*allocator)(intptr_t size)) { 328 uword (*allocator)(intptr_t size)) {
243 return ToHexCString(bigint.BNAddr(), allocator); 329 NoGCScope no_gc;
330
331 intptr_t length = bigint.Length();
332 return ToHexCString(length,
333 bigint.IsNegative(),
334 length ? bigint.ChunkAddr(0) : NULL,
335 allocator);
244 } 336 }
245 337
246 338
247 bool BigintOperations::FitsIntoSmi(const Bigint& bigint) { 339 bool BigintOperations::FitsIntoSmi(const Bigint& bigint) {
248 ASSERT(!bigint.IsNull()); 340 intptr_t bigint_length = bigint.Length();
249 const BIGNUM *bn = bigint.BNAddr(); 341 if (bigint_length == 0) {
250 int bits = BN_num_bits(bn);
251 // Special case for kMinValue as the absolute value is 1 bit longer
252 // than anything else
253 if (bits == Smi::kBits + 1 && BN_abs_is_word(bn, -Smi::kMinValue)
254 && bigint.IsNegative()) {
255 return true; 342 return true;
256 } 343 }
257 // All other cases must have no more bits than the size of an Smi 344 if ((bigint_length == 1) &&
258 if (bits > Smi::kBits) { 345 (static_cast<size_t>(kDigitBitSize) <
346 (sizeof(intptr_t) * kBitsPerByte))) {
347 return true;
348 }
349
350 uintptr_t limit;
351 if (bigint.IsNegative()) {
352 limit = static_cast<uintptr_t>(-Smi::kMinValue);
353 } else {
354 limit = static_cast<uintptr_t>(Smi::kMaxValue);
355 }
356 bool bigint_is_greater = false;
357 // Consume the least-significant digits of the bigint.
358 // If bigint_is_greater is set, then the processed sub-part of the bigint is
359 // greater than the corresponding part of the limit.
360 for (int i = 0; i < bigint_length - 1; i++) {
361 Chunk limit_digit = static_cast<Chunk>(limit & kDigitMask);
362 Chunk bigint_digit = bigint.GetChunkAt(i);
363 if (limit_digit < bigint_digit) {
364 bigint_is_greater = true;
365 } else if (limit_digit > bigint_digit) {
366 bigint_is_greater = false;
367 } // else don't change the boolean.
368 limit >>= kDigitBitSize;
369
370 // Bail out if the bigint is definitely too big.
371 if (limit == 0) {
372 return false;
373 }
374 }
375 Chunk most_significant_digit = bigint.GetChunkAt(bigint_length - 1);
376 if (limit > most_significant_digit) {
377 return true;
378 }
379 if (limit < most_significant_digit) {
259 return false; 380 return false;
260 } 381 }
261 return true; 382 return !bigint_is_greater;
262 } 383 }
263 384
264 385
265 RawSmi* BigintOperations::ToSmi(const Bigint& bigint) { 386 RawSmi* BigintOperations::ToSmi(const Bigint& bigint) {
266 ASSERT(FitsIntoSmi(bigint)); 387 ASSERT(FitsIntoSmi(bigint));
267 unsigned char bytes[kBitsPerWord / kBitsPerByte];
268 ASSERT(BN_num_bytes(bigint.BNAddr()) <= static_cast<int>(sizeof bytes));
269 int n = BN_bn2bin(bigint.BNAddr(), bytes);
270 ASSERT(n >= 0);
271 intptr_t value = 0; 388 intptr_t value = 0;
272 ASSERT(n <= static_cast<int>(sizeof value)); 389 for (int i = bigint.Length() - 1; i >= 0; i--) {
273 for (int i = 0; i < n; ++i) { 390 value <<= kDigitBitSize;
274 value <<= 8; 391 value += static_cast<intptr_t>(bigint.GetChunkAt(i));
275 value |= bytes[i];
276 } 392 }
277 if (bigint.IsNegative()) { 393 if (bigint.IsNegative()) {
278 value = -value; 394 value = -value;
279 } 395 }
280 return Smi::New(value); 396 return Smi::New(value);
281 } 397 }
282 398
283 399
284 RawDouble* BigintOperations::ToDouble(const Bigint& bigint) { 400 RawDouble* BigintOperations::ToDouble(const Bigint& bigint) {
285 // TODO(floitsch/benl): This is a quick and dirty implementation to unblock 401 // TODO(floitsch/benl): This is a quick and dirty implementation to unblock
286 // other areas of the code. It does not handle all bit-twiddling correctly. 402 // other areas of the code. It does not handle all bit-twiddling correctly.
403 const double shift_value = (1 << kDigitBitSize);
287 double value = 0.0; 404 double value = 0.0;
288 for (int i = bigint.NumberOfBits() - 1; i >= 0; --i) { 405 for (int i = bigint.Length() - 1; i >= 0; i--) {
289 value *= 2; 406 value *= shift_value;
290 value += static_cast<double>(bigint.Bit(i)); 407 value += static_cast<double>(bigint.GetChunkAt(i));
291 } 408 }
292 if (bigint.IsNegative()) { 409 if (bigint.IsNegative()) {
293 value = -value; 410 value = -value;
294 } 411 }
295 return Double::New(value); 412 return Double::New(value);
296 } 413 }
297 414
298 415
299 bool BigintOperations::FitsIntoInt64(const Bigint& bigint) { 416 bool BigintOperations::FitsIntoMint(const Bigint& bigint) {
300 const BIGNUM *bn = bigint.BNAddr(); 417 intptr_t bigint_length = bigint.Length();
301 int bits = BN_num_bits(bn); 418 if (bigint_length == 0) {
302 if (bits <= 63) return true; 419 return true;
303 if (bits > 64) return false;
304 if (!bigint.IsNegative()) return false;
305 // Special case for negative values, since Int64 representation may lose
306 // one bit.
307 ASSERT(bigint.Bit(63) != 0);
308 for (int i = 0; i < 63; i++) {
309 // Verify that all 63 least significant bits are 0.
310 if (bigint.Bit(i) != 0) return false;
311 } 420 }
312 return true; 421 if ((bigint_length < 3) &&
422 (static_cast<size_t>(kDigitBitSize) <
423 (sizeof(intptr_t) * kBitsPerByte))) {
424 return true;
425 }
426
427 uint64_t limit;
428 if (bigint.IsNegative()) {
429 limit = static_cast<uint64_t>(Mint::kMinValue);
430 } else {
431 limit = static_cast<uint64_t>(Mint::kMaxValue);
432 }
433 bool bigint_is_greater = false;
434 // Consume the least-significant digits of the bigint.
435 // If bigint_is_greater is set, then the processed sub-part of the bigint is
436 // greater than the corresponding part of the limit.
437 for (int i = 0; i < bigint_length - 1; i++) {
438 Chunk limit_digit = static_cast<Chunk>(limit & kDigitMask);
439 Chunk bigint_digit = bigint.GetChunkAt(i);
440 if (limit_digit < bigint_digit) {
441 bigint_is_greater = true;
442 } else if (limit_digit > bigint_digit) {
443 bigint_is_greater = false;
444 } // else don't change the boolean.
445 limit >>= kDigitBitSize;
446
447 // Bail out if the bigint is definitely too big.
448 if (limit == 0) {
449 return false;
450 }
451 }
452 Chunk most_significant_digit = bigint.GetChunkAt(bigint_length - 1);
453 if (limit > most_significant_digit) {
454 return true;
455 }
456 if (limit < most_significant_digit) {
457 return false;
458 }
459 return !bigint_is_greater;
313 } 460 }
314 461
315 462
316 uint64_t BigintOperations::AbsToUint64(const Bigint& bigint) { 463 uint64_t BigintOperations::AbsToUint64(const Bigint& bigint) {
317 unsigned char bytes[8];
318 ASSERT(BN_num_bytes(bigint.BNAddr()) <= static_cast<int>(sizeof bytes));
319 int n = BN_bn2bin(bigint.BNAddr(), bytes);
320 ASSERT(n >= 0);
321 uint64_t value = 0; 464 uint64_t value = 0;
322 ASSERT(n <= static_cast<int>(sizeof value)); 465 for (int i = bigint.Length() - 1; i >= 0; i--) {
323 for (int i = 0; i < n; ++i) { 466 value <<= kDigitBitSize;
324 value <<= 8; 467 value += static_cast<intptr_t>(bigint.GetChunkAt(i));
325 value |= bytes[i];
326 } 468 }
327 return value; 469 return value;
328 } 470 }
329 471
330 472
331 int64_t BigintOperations::ToInt64(const Bigint& bigint) { 473 int64_t BigintOperations::ToMint(const Bigint& bigint) {
332 ASSERT(FitsIntoInt64(bigint)); 474 ASSERT(FitsIntoMint(bigint));
333 int64_t value = AbsToUint64(bigint); 475 int64_t value = AbsToUint64(bigint);
334 if (bigint.IsNegative()) { 476 if (bigint.IsNegative()) {
335 value = -value; 477 value = -value;
336 } 478 }
337 return value; 479 return value;
338 } 480 }
339 481
340 482
341 bool BigintOperations::FitsIntoUint64(const Bigint& bigint) { 483 bool BigintOperations::FitsIntoUint64(const Bigint& bigint) {
342 const BIGNUM *bn = bigint.BNAddr();
343 if (bigint.IsNegative()) return false; 484 if (bigint.IsNegative()) return false;
344 int bits = BN_num_bits(bn); 485 intptr_t b_length = bigint.Length();
345 if (bits > 64) return false; 486 int num_bits = CountBits(bigint.GetChunkAt(b_length - 1));
487 num_bits += (kDigitBitSize * (b_length - 1));
488 if (num_bits > 64) return false;
346 return true; 489 return true;
347 } 490 }
348 491
349 492
350 uint64_t BigintOperations::ToUint64(const Bigint& bigint) { 493 uint64_t BigintOperations::ToUint64(const Bigint& bigint) {
351 ASSERT(FitsIntoUint64(bigint)); 494 ASSERT(FitsIntoUint64(bigint));
352 return AbsToUint64(bigint); 495 return AbsToUint64(bigint);
353 } 496 }
354 497
355 498
356 RawBigint* BigintOperations::Add(const Bigint& a, const Bigint& b) { 499 RawBigint* BigintOperations::Multiply(const Bigint& a, const Bigint& b) {
357 int status = BN_add(TmpBN(), a.BNAddr(), b.BNAddr()); 500 ASSERT(IsClamped(a));
358 if (status == 0) { 501 ASSERT(IsClamped(b));
359 GrowableArray<const Object*> exception_arguments; 502
360 exception_arguments.Add( 503 intptr_t a_length = a.Length();
361 &Object::ZoneHandle(String::New("BigintOperations::Add"))); 504 intptr_t b_length = b.Length();
362 Exceptions::ThrowByType(Exceptions::kInternalError, exception_arguments); 505 intptr_t result_length = a_length + b_length;
363 } 506 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length));
364 const Bigint& result = Bigint::Handle(Bigint::New(TmpBN())); 507
508 if (a.IsNegative() != b.IsNegative()) {
509 result.ToggleSign();
510 }
511
512 // Comba multiplication: compute each column separately.
513 // Example: r = a2a1a0 * b2b1b0.
514 // r = 1 * a0b0 +
515 // 10 * (a1b0 + a0b1) +
516 // 100 * (a2b0 + a1b1 + a0b2) +
517 // 1000 * (a2b1 + a1b2) +
518 // 10000 * a2b2
519 //
520 // Each column will be accumulated in an integer of type DoubleChunk. We
521 // must guarantee that the column-sum will not overflow.
522 //
523 // In the worst case we have to accumulate k = Min(a.length, b.length)
524 // products plus the carry from the previous round.
525 // Each bigint-digit is smaller than beta = 2^kDigitBitSize.
526 // Each product is at most (beta - 1)^2.
527 // If we want to use Comba multiplication the following condition must hold:
528 // k * (beta - 1)^2 + (2^(kDoubleChunkBitSize - kDigitBitSize) - 1) <
529 // 2^kDoubleChunkBitSize.
530 const DoubleChunk square =
531 static_cast<DoubleChunk>(kDigitMaxValue) * kDigitMaxValue;
532 const DoubleChunk kDoubleChunkMaxValue = static_cast<DoubleChunk>(-1);
533 const DoubleChunk left_over_carry = kDoubleChunkMaxValue >> kDigitBitSize;
534 const intptr_t kMaxDigits = (kDoubleChunkMaxValue - left_over_carry) / square;
535 if (Utils::Minimum(a_length, b_length) > kMaxDigits) {
536 UNIMPLEMENTED();
537 }
538
539 DoubleChunk accumulator = 0; // Accumulates the result of one column.
540 for (intptr_t i = 0; i < result_length; i++) {
541 // Example: r = a2a1a0 * b2b1b0.
542 // For i == 0, compute a0b0.
543 // i == 1, a1b0 + a0b1 + overflow from i == 0.
544 // i == 2, a2b0 + a1b1 + a0b2 + overflow from i == 1.
545 // ...
546 // The indices into a and b are such that their sum equals i.
547 intptr_t a_index = Utils::Minimum(a_length - 1, i);
548 intptr_t b_index = i - a_index;
549 ASSERT(a_index + b_index == i);
550
551 // Instead of testing for a_index >= 0 && b_index < b_length we compute the
552 // number of iterations first.
553 intptr_t iterations = Utils::Minimum(b_length - b_index, a_index + 1);
554 for (intptr_t j = 0; j < iterations; j++) {
555 DoubleChunk chunk_a = a.GetChunkAt(a_index);
556 DoubleChunk chunk_b = b.GetChunkAt(b_index);
557 accumulator += chunk_a * chunk_b;
558 a_index--;
559 b_index++;
560 }
561 result.SetChunkAt(i, static_cast<Chunk>(accumulator & kDigitMask));
562 accumulator >>= kDigitBitSize;
563 }
564 ASSERT(accumulator == 0);
565
566 Clamp(result);
365 return result.raw(); 567 return result.raw();
366 } 568 }
367 569
368 570
369 RawBigint* BigintOperations::Subtract(const Bigint& a, const Bigint& b) {
370 int status = BN_sub(TmpBN(), a.BNAddr(), b.BNAddr());
371 if (status == 0) {
372 GrowableArray<const Object*> exception_arguments;
373 exception_arguments.Add(
374 &Object::ZoneHandle(String::New("BigintOperations::Subtract")));
375 Exceptions::ThrowByType(Exceptions::kInternalError, exception_arguments);
376 }
377 const Bigint& result = Bigint::Handle(Bigint::New(TmpBN()));
378 return result.raw();
379 }
380
381
382 RawBigint* BigintOperations::Multiply(const Bigint& a, const Bigint& b) {
383 int status = BN_mul(TmpBN(), a.BNAddr(), b.BNAddr(), TmpBNCtx());
384 if (status == 0) {
385 GrowableArray<const Object*> exception_arguments;
386 exception_arguments.Add(
387 &Object::ZoneHandle(String::New("BigintOperations::Multiply")));
388 Exceptions::ThrowByType(Exceptions::kInternalError, exception_arguments);
389 }
390 const Bigint& result = Bigint::Handle(Bigint::New(TmpBN()));
391 return result.raw();
392 }
393
394
395 RawBigint* BigintOperations::Divide(const Bigint& a, const Bigint& b) { 571 RawBigint* BigintOperations::Divide(const Bigint& a, const Bigint& b) {
396 int status = BN_div(TmpBN(), NULL, a.BNAddr(), b.BNAddr(), TmpBNCtx()); 572 Bigint& quotient = Bigint::Handle();
397 if (status == 0) { 573 Bigint& remainder = Bigint::Handle();
398 GrowableArray<const Object*> exception_arguments; 574 DivideRemainder(a, b, &quotient, &remainder);
399 exception_arguments.Add(
400 &Object::ZoneHandle(String::New("BigintOperations::Divide")));
401 Exceptions::ThrowByType(Exceptions::kInternalError, exception_arguments);
402 }
403 const Bigint& quotient = Bigint::Handle(Bigint::New(TmpBN()));
404 return quotient.raw(); 575 return quotient.raw();
405 } 576 }
406 577
407 578
408 RawBigint* BigintOperations::Modulo(const Bigint& a, const Bigint& b) { 579 RawBigint* BigintOperations::Modulo(const Bigint& a, const Bigint& b) {
409 int status = BN_nnmod(TmpBN(), a.BNAddr(), b.BNAddr(), TmpBNCtx()); 580 Bigint& quotient = Bigint::Handle();
410 if (status == 0) { 581 Bigint& modulo = Bigint::Handle();
411 GrowableArray<const Object*> exception_arguments; 582 DivideRemainder(a, b, &quotient, &modulo);
412 exception_arguments.Add(
413 &Object::ZoneHandle(String::New("BigintOperations::Modulo")));
414 Exceptions::ThrowByType(Exceptions::kInternalError, exception_arguments);
415 }
416 const Bigint& modulo = Bigint::Handle(Bigint::New(TmpBN()));
417 return modulo.raw(); 583 return modulo.raw();
418 } 584 }
419 585
420 586
421 RawBigint* BigintOperations::Remainder(const Bigint& a, const Bigint& b) { 587 RawBigint* BigintOperations::Remainder(const Bigint& a, const Bigint& b) {
422 int status = BN_div(NULL, TmpBN(), a.BNAddr(), b.BNAddr(), TmpBNCtx()); 588 Bigint& quotient = Bigint::Handle();
423 if (status == 0) { 589 Bigint& remainder = Bigint::Handle();
424 GrowableArray<const Object*> exception_arguments; 590 DivideRemainder(a, b, &quotient, &remainder);
425 exception_arguments.Add(
426 &Object::ZoneHandle(String::New("BigintOperations::Remainder")));
427 Exceptions::ThrowByType(Exceptions::kInternalError, exception_arguments);
428 }
429 const Bigint& remainder = Bigint::Handle(Bigint::New(TmpBN()));
430 return remainder.raw(); 591 return remainder.raw();
431 } 592 }
432 593
433 594
434 RawBigint* BigintOperations::ShiftLeft(const Bigint& bigint, intptr_t amount) { 595 RawBigint* BigintOperations::ShiftLeft(const Bigint& bigint, intptr_t amount) {
435 int status = BN_lshift(TmpBN(), bigint.BNAddr(), amount); 596 ASSERT(IsClamped(bigint));
436 if (status == 0) { 597 ASSERT(amount >= 0);
437 GrowableArray<const Object*> exception_arguments; 598 intptr_t bigint_length = bigint.Length();
438 exception_arguments.Add( 599 if (bigint.IsZero()) {
439 &Object::ZoneHandle(String::New("BigintOperations::ShiftLeft"))); 600 return Zero();
440 Exceptions::ThrowByType(Exceptions::kInternalError, exception_arguments); 601 }
441 } 602 // TODO(floitsch): can we reuse the input?
442 const Bigint& result = Bigint::Handle(Bigint::New(TmpBN())); 603 if (amount == 0) {
443 return result.raw(); 604 return Copy(bigint);
605 }
606 intptr_t digit_shift = amount / kDigitBitSize;
607 intptr_t bit_shift = amount % kDigitBitSize;
608 if (bit_shift == 0) {
609 const Bigint& result =
610 Bigint::Handle(Bigint::Allocate(bigint_length + digit_shift));
611 for (intptr_t i = 0; i < digit_shift; i++) {
612 result.SetChunkAt(i, 0);
613 }
614 for (intptr_t i = 0; i < bigint_length; i++) {
615 result.SetChunkAt(i + digit_shift, bigint.GetChunkAt(i));
616 }
617 if (bigint.IsNegative()) {
618 result.ToggleSign();
619 }
620 return result.raw();
621 } else {
622 const Bigint& result =
623 Bigint::Handle(Bigint::Allocate(bigint_length + digit_shift + 1));
624 for (intptr_t i = 0; i < digit_shift; i++) {
625 result.SetChunkAt(i, 0);
626 }
627 Chunk carry = 0;
628 for (intptr_t i = 0; i < bigint_length; i++) {
629 Chunk digit = bigint.GetChunkAt(i);
630 Chunk shifted_digit = ((digit << bit_shift) & kDigitMask) + carry;
631 result.SetChunkAt(i + digit_shift, shifted_digit);
632 carry = digit >> (kDigitBitSize - bit_shift);
633 }
634 result.SetChunkAt(bigint_length + digit_shift, carry);
635 if (bigint.IsNegative()) {
636 result.ToggleSign();
637 }
638 Clamp(result);
639 return result.raw();
640 }
444 } 641 }
445 642
446 643
447 RawBigint* BigintOperations::ShiftRight(const Bigint& bigint, intptr_t amount) { 644 RawBigint* BigintOperations::ShiftRight(const Bigint& bigint, intptr_t amount) {
645 ASSERT(IsClamped(bigint));
448 ASSERT(amount >= 0); 646 ASSERT(amount >= 0);
449 int status = BN_rshift(TmpBN(), bigint.BNAddr(), amount); 647 intptr_t bigint_length = bigint.Length();
450 if (status == 0) { 648 if (bigint.IsZero()) {
451 GrowableArray<const Object*> exception_arguments; 649 return Zero();
452 exception_arguments.Add( 650 }
453 &Object::ZoneHandle(String::New("BigintOperations::ShiftRight"))); 651 // TODO(floitsch): can we reuse the input?
454 Exceptions::ThrowByType(Exceptions::kInternalError, exception_arguments); 652 if (amount == 0) {
455 } 653 return Copy(bigint);
456 // OpenSSL doesn't take account of sign when shifting - this fixes it. 654 }
655 intptr_t digit_shift = amount / kDigitBitSize;
656 intptr_t bit_shift = amount % kDigitBitSize;
657 if (digit_shift >= bigint_length) {
658 return bigint.IsNegative() ? MinusOne() : Zero();
659 }
660
661 const Bigint& result =
662 Bigint::Handle(Bigint::Allocate(bigint_length - digit_shift));
663 if (bit_shift == 0) {
664 for (intptr_t i = 0; i < bigint_length - digit_shift; i++) {
665 result.SetChunkAt(i, bigint.GetChunkAt(i + digit_shift));
666 }
667 } else {
668 Chunk carry = 0;
669 for (intptr_t i = bigint_length - 1; i >= digit_shift; i--) {
670 Chunk digit = bigint.GetChunkAt(i);
671 Chunk shifted_digit = (digit >> bit_shift) + carry;
672 result.SetChunkAt(i - digit_shift, shifted_digit);
673 carry = (digit << (kDigitBitSize - bit_shift)) & kDigitMask;
674 }
675 Clamp(result);
676 }
677
457 if (bigint.IsNegative()) { 678 if (bigint.IsNegative()) {
458 for (intptr_t i = 0; i < amount; ++i) { 679 result.ToggleSign();
459 if (bigint.IsBitSet(i)) { 680 // If the input is negative then the result needs to be rounded down.
460 int status = BN_sub_word(TmpBN(), 1); 681 // Example: -5 >> 2 => -2
461 ASSERT(status == 1); 682 bool needs_rounding = false;
683 for (intptr_t i = 0; i < digit_shift; i++) {
684 if (bigint.GetChunkAt(i) != 0) {
685 needs_rounding = true;
462 break; 686 break;
463 } 687 }
464 } 688 }
465 } 689 if (!needs_rounding && (bit_shift > 0)) {
466 const Bigint& result = Bigint::Handle(Bigint::New(TmpBN())); 690 Chunk digit = bigint.GetChunkAt(digit_shift);
691 needs_rounding = (digit << (kChunkBitSize - bit_shift)) != 0;
692 }
693 if (needs_rounding) {
694 Bigint& one = Bigint::Handle(One());
695 return Subtract(result, one);
696 }
697 }
698
467 return result.raw(); 699 return result.raw();
468 } 700 }
469 701
470 /* Bit operations are complicated by negatives: BIGNUMs don't use 2's 702
471 * complement, but instead store the absolute value and a sign 703 RawBigint* BigintOperations::BitAnd(const Bigint& a, const Bigint& b) {
472 * indicator. However bit operations are defined on 2's complement 704 ASSERT(IsClamped(a));
473 * representations. This function handles the necessary 705 ASSERT(IsClamped(b));
474 * invert-and-carry operations to deal with the fact that -x = ~x + 1 706
475 * both on the operands and result. The actual operation performed is 707 if (a.IsZero() || b.IsZero()) {
476 * specified by the truth table |tt|, which is in the order of input 708 return Zero();
477 * bits (00, 01, 10, 11). 709 }
478 */ 710 if (a.IsNegative() && !b.IsNegative()) {
479 RawBigint* BigintOperations::BitTT(const Bigint& a, const Bigint& b, 711 return BitAnd(b, a);
480 bool tt[4]) { 712 }
481 BN_zero(TmpBN()); 713 if ((a.IsNegative() == b.IsNegative()) && (a.Length() < b.Length())) {
482 int n; 714 return BitAnd(b, a);
483 int rflip = 0; 715 }
484 int rborrow = 0; 716
485 // There's probably a clever way to figure out why these are what 717 intptr_t a_length = a.Length();
486 // they are, but I confess I worked them out pragmatically. 718 intptr_t b_length = b.Length();
487 if (a.IsNegative() && b.IsNegative()) { 719 intptr_t min_length = Utils::Minimum(a_length, b_length);
488 if (tt[3]) { 720 intptr_t max_length = Utils::Maximum(a_length, b_length);
489 rflip = -1; 721 if (!b.IsNegative()) {
490 rborrow = -1; 722 ASSERT(!a.IsNegative());
491 } 723 intptr_t result_length = min_length;
492 if (tt[2] != tt[3]) { 724 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length));
493 n = Utils::Maximum(a.NumberOfBits(), b.NumberOfBits()); 725
726 for (intptr_t i = 0; i < min_length; i++) {
727 result.SetChunkAt(i, a.GetChunkAt(i) & b.GetChunkAt(i));
728 }
729 Clamp(result);
730 return result.raw();
731 }
732
733 // Bigints encode negative values by storing the absolute value and the sign
734 // separately. To do bit operations we need to simulate numbers that are
735 // implemented as two's complement.
736 // The negation of a positive number x would be encoded as follows in
737 // two's complement: n = ~(x - 1).
738 // The inverse transformation is hence (~n) + 1.
739
740 if (!a.IsNegative()) {
741 ASSERT(b.IsNegative());
742 // The result will be positive.
743 intptr_t result_length = a_length;
744 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length));
745 Chunk borrow = 1;
746 for (intptr_t i = 0; i < min_length; i++) {
747 Chunk b_digit = b.GetChunkAt(i) - borrow;
748 result.SetChunkAt(i, a.GetChunkAt(i) & (~b_digit) & kDigitMask);
749 borrow = b_digit >> (kChunkBitSize - 1);
750 }
751 for (intptr_t i = min_length; i < a_length; i++) {
752 result.SetChunkAt(i, a.GetChunkAt(i) & (kDigitMaxValue - borrow));
753 borrow = 0;
754 }
755 Clamp(result);
756 return result.raw();
757 }
758
759 ASSERT(a.IsNegative());
760 ASSERT(b.IsNegative());
761 // The result will be negative.
762 // We need to convert a and b to two's complement. Do the bit-operation there,
763 // and transform the resulting bits from two's complement back to separated
764 // magnitude and sign.
765 // a & b is therefore computed as ~((~(a - 1)) & (~(b - 1))) + 1 which is
766 // equal to ((a-1) | (b-1)) + 1.
767 intptr_t result_length = max_length + 1;
768 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length));
769 result.ToggleSign();
770 Chunk a_borrow = 1;
771 Chunk b_borrow = 1;
772 Chunk result_carry = 1;
773 ASSERT(a_length >= b_length);
774 for (intptr_t i = 0; i < b_length; i++) {
775 Chunk a_digit = a.GetChunkAt(i) - a_borrow;
776 Chunk b_digit = b.GetChunkAt(i) - b_borrow;
777 Chunk result_chunk = ((a_digit | b_digit) & kDigitMask) + result_carry;
778 result.SetChunkAt(i, result_chunk & kDigitMask);
779 a_borrow = a_digit >> (kChunkBitSize - 1);
780 b_borrow = b_digit >> (kChunkBitSize - 1);
781 result_carry = result_chunk >> kDigitBitSize;
782 }
783 for (intptr_t i = b_length; i < a_length; i++) {
784 Chunk a_digit = a.GetChunkAt(i) - a_borrow;
785 Chunk b_digit = -b_borrow;
786 Chunk result_chunk = ((a_digit | b_digit) & kDigitMask) + result_carry;
787 result.SetChunkAt(i, result_chunk & kDigitMask);
788 a_borrow = a_digit >> (kChunkBitSize - 1);
789 b_borrow = 0;
790 result_carry = result_chunk >> kDigitBitSize;
791 }
792 Chunk a_digit = -a_borrow;
793 Chunk b_digit = -b_borrow;
794 Chunk result_chunk = ((a_digit | b_digit) & kDigitMask) + result_carry;
795 result.SetChunkAt(a_length, result_chunk & kDigitMask);
796 Clamp(result);
797 return result.raw();
798 }
799
800
801 RawBigint* BigintOperations::BitOr(const Bigint& a, const Bigint& b) {
802 ASSERT(IsClamped(a));
803 ASSERT(IsClamped(b));
804
805 if (a.IsNegative() && !b.IsNegative()) {
806 return BitOr(b, a);
807 }
808 if ((a.IsNegative() == b.IsNegative()) && (a.Length() < b.Length())) {
809 return BitOr(b, a);
810 }
811
812 intptr_t a_length = a.Length();
813 intptr_t b_length = b.Length();
814 intptr_t min_length = Utils::Minimum(a_length, b_length);
815 intptr_t max_length = Utils::Maximum(a_length, b_length);
816 if (!b.IsNegative()) {
817 ASSERT(!a.IsNegative());
818 intptr_t result_length = max_length;
819 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length));
820
821 ASSERT(a_length >= b_length);
822 for (intptr_t i = 0; i < b_length; i++) {
823 result.SetChunkAt(i, a.GetChunkAt(i) | b.GetChunkAt(i));
824 }
825 for (intptr_t i = b_length; i < a_length; i++) {
826 result.SetChunkAt(i, a.GetChunkAt(i));
827 }
828 return result.raw();
829 }
830
831 // Bigints encode negative values by storing the absolute value and the sign
832 // separately. To do bit operations we need to simulate numbers that are
833 // implemented as two's complement.
834 // The negation of a positive number x would be encoded as follows in
835 // two's complement: n = ~(x - 1).
836 // The inverse transformation is hence (~n) + 1.
837
838 if (!a.IsNegative()) {
839 ASSERT(b.IsNegative());
840 if (a.IsZero()) {
841 return Copy(b);
842 }
843 // The result will be negative.
844 // We need to convert b to two's complement. Do the bit-operation there,
845 // and transform the resulting bits from two's complement back to separated
846 // magnitude and sign.
847 // a | b is therefore computed as ~((a & (~(b - 1))) + 1 which is
848 // equal to ((~a) & (b-1)) + 1.
849 intptr_t result_length = b_length;
850 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length));
851 result.ToggleSign();
852 Chunk borrow = 1;
853 Chunk result_carry = 1;
854 for (intptr_t i = 0; i < min_length; i++) {
855 Chunk a_digit = a.GetChunkAt(i);
856 Chunk b_digit = b.GetChunkAt(i) - borrow;
857 Chunk result_digit = ((~a_digit) & b_digit & kDigitMask) + result_carry;
858 result.SetChunkAt(i, result_digit & kDigitMask);
859 borrow = b_digit >> (kChunkBitSize - 1);
860 result_carry = result_digit >> kDigitBitSize;
861 }
862 ASSERT(result_carry == 0);
863 for (intptr_t i = min_length; i < b_length; i++) {
864 Chunk b_digit = b.GetChunkAt(i) - borrow;
865 Chunk result_digit = (b_digit & kDigitMask) + result_carry;
866 result.SetChunkAt(i, result_digit & kDigitMask);
867 borrow = b_digit >> (kChunkBitSize - 1);
868 result_carry = result_digit >> kDigitBitSize;
869 }
870 ASSERT(result_carry == 0);
871 Clamp(result);
872 return result.raw();
873 }
874
875 ASSERT(a.IsNegative());
876 ASSERT(b.IsNegative());
877 // The result will be negative.
878 // We need to convert a and b to two's complement. Do the bit-operation there,
879 // and transform the resulting bits from two's complement back to separated
880 // magnitude and sign.
881 // a & b is therefore computed as ~((~(a - 1)) | (~(b - 1))) + 1 which is
882 // equal to ((a-1) & (b-1)) + 1.
883 intptr_t result_length = min_length + 1;
884 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length));
885 result.ToggleSign();
886 Chunk a_borrow = 1;
887 Chunk b_borrow = 1;
888 Chunk result_carry = 1;
889 ASSERT(a_length >= b_length);
890 for (intptr_t i = 0; i < b_length; i++) {
891 Chunk a_digit = a.GetChunkAt(i) - a_borrow;
892 Chunk b_digit = b.GetChunkAt(i) - b_borrow;
893 Chunk result_chunk = ((a_digit & b_digit) & kDigitMask) + result_carry;
894 result.SetChunkAt(i, result_chunk & kDigitMask);
895 a_borrow = a_digit >> (kChunkBitSize - 1);
896 b_borrow = b_digit >> (kChunkBitSize - 1);
897 result_carry = result_chunk >> kDigitBitSize;
898 }
899 result.SetChunkAt(a_length, result_carry);
900 Clamp(result);
901 return result.raw();
902 }
903
904
905 RawBigint* BigintOperations::BitXor(const Bigint& a, const Bigint& b) {
906 ASSERT(IsClamped(a));
907 ASSERT(IsClamped(b));
908
909 if (a.IsZero()) {
910 return Copy(b);
911 }
912 if (b.IsZero()) {
913 return Copy(a);
914 }
915 if (a.IsNegative() && !b.IsNegative()) {
916 return BitXor(b, a);
917 }
918 if ((a.IsNegative() == b.IsNegative()) && (a.Length() < b.Length())) {
919 return BitXor(b, a);
920 }
921
922 intptr_t a_length = a.Length();
923 intptr_t b_length = b.Length();
924 intptr_t min_length = Utils::Minimum(a_length, b_length);
925 intptr_t max_length = Utils::Maximum(a_length, b_length);
926 if (!b.IsNegative()) {
927 ASSERT(!a.IsNegative());
928 intptr_t result_length = max_length;
929 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length));
930
931 ASSERT(a_length >= b_length);
932 for (intptr_t i = 0; i < b_length; i++) {
933 result.SetChunkAt(i, a.GetChunkAt(i) ^ b.GetChunkAt(i));
934 }
935 for (intptr_t i = b_length; i < a_length; i++) {
936 result.SetChunkAt(i, a.GetChunkAt(i));
937 }
938 Clamp(result);
939 return result.raw();
940 }
941
942 // Bigints encode negative values by storing the absolute value and the sign
943 // separately. To do bit operations we need to simulate numbers that are
944 // implemented as two's complement.
945 // The negation of a positive number x would be encoded as follows in
946 // two's complement: n = ~(x - 1).
947 // The inverse transformation is hence (~n) + 1.
948
949 if (!a.IsNegative()) {
950 ASSERT(b.IsNegative());
951 // The result will be negative.
952 // We need to convert b to two's complement. Do the bit-operation there,
953 // and transform the resulting bits from two's complement back to separated
954 // magnitude and sign.
955 // a ^ b is therefore computed as ~((a ^ (~(b - 1))) + 1.
956 intptr_t result_length = max_length + 1;
957 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length));
958 result.ToggleSign();
959 Chunk borrow = 1;
960 Chunk result_carry = 1;
961 for (intptr_t i = 0; i < min_length; i++) {
962 Chunk a_digit = a.GetChunkAt(i);
963 Chunk b_digit = b.GetChunkAt(i) - borrow;
964 Chunk result_digit =
965 ((~(a_digit ^ ~b_digit)) & kDigitMask) + result_carry;
966 result.SetChunkAt(i, result_digit & kDigitMask);
967 borrow = b_digit >> (kChunkBitSize - 1);
968 result_carry = result_digit >> kDigitBitSize;
969 }
970 for (intptr_t i = min_length; i < a_length; i++) {
971 Chunk a_digit = a.GetChunkAt(i);
972 Chunk b_digit = -borrow;
973 Chunk result_digit =
974 ((~(a_digit ^ ~b_digit)) & kDigitMask) + result_carry;
975 result.SetChunkAt(i, result_digit & kDigitMask);
976 borrow = b_digit >> (kChunkBitSize - 1);
977 result_carry = result_digit >> kDigitBitSize;
978 }
979 for (intptr_t i = min_length; i < b_length; i++) {
980 // a_digit = 0.
981 Chunk b_digit = b.GetChunkAt(i) - borrow;
982 Chunk result_digit = (b_digit & kDigitMask) + result_carry;
983 result.SetChunkAt(i, result_digit & kDigitMask);
984 borrow = b_digit >> (kChunkBitSize - 1);
985 result_carry = result_digit >> kDigitBitSize;
986 }
987 result.SetChunkAt(max_length, result_carry);
988 Clamp(result);
989 return result.raw();
990 }
991
992 ASSERT(a.IsNegative());
993 ASSERT(b.IsNegative());
994 // The result will be positive.
995 // We need to convert a and b to two's complement, do the bit-operation there,
996 // and simply store the result.
997 // a ^ b is therefore computed as (~(a - 1)) ^ (~(b - 1)).
998 intptr_t result_length = max_length;
999 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length));
1000 Chunk a_borrow = 1;
1001 Chunk b_borrow = 1;
1002 ASSERT(a_length >= b_length);
1003 for (intptr_t i = 0; i < b_length; i++) {
1004 Chunk a_digit = a.GetChunkAt(i) - a_borrow;
1005 Chunk b_digit = b.GetChunkAt(i) - b_borrow;
1006 Chunk result_chunk = (~a_digit) ^ (~b_digit);
1007 result.SetChunkAt(i, result_chunk & kDigitMask);
1008 a_borrow = a_digit >> (kChunkBitSize - 1);
1009 b_borrow = b_digit >> (kChunkBitSize - 1);
1010 }
1011 ASSERT(b_borrow == 0);
1012 for (intptr_t i = b_length; i < a_length; i++) {
1013 Chunk a_digit = a.GetChunkAt(i) - a_borrow;
1014 result.SetChunkAt(i, (~a_digit) & kDigitMask);
1015 a_borrow = a_digit >> (kChunkBitSize - 1);
1016 }
1017 ASSERT(a_borrow == 0);
1018 Clamp(result);
1019 return result.raw();
1020 }
1021
1022
1023 RawBigint* BigintOperations::BitNot(const Bigint& bigint) {
1024 if (bigint.IsZero()) {
1025 return MinusOne();
1026 }
1027 const Bigint& one_bigint = Bigint::Handle(One());
1028 if (bigint.IsNegative()) {
1029 return UnsignedSubtract(bigint, one_bigint);
1030 } else {
1031 const Bigint& result = Bigint::Handle(UnsignedAdd(bigint, one_bigint));
1032 result.ToggleSign();
1033 return result.raw();
1034 }
1035 }
1036
1037
1038 int BigintOperations::Compare(const Bigint& a, const Bigint& b) {
1039 bool a_is_negative = a.IsNegative();
1040 bool b_is_negative = b.IsNegative();
1041 if (a_is_negative != b_is_negative) {
1042 return a_is_negative ? -1 : 1;
1043 }
1044
1045 if (a_is_negative) {
1046 return -UnsignedCompare(a, b);
1047 }
1048 return UnsignedCompare(a, b);
1049 }
1050
1051
1052 RawBigint* BigintOperations::AddSubtract(const Bigint& a,
1053 const Bigint& b,
1054 bool negate_b) {
1055 ASSERT(IsClamped(a));
1056 ASSERT(IsClamped(b));
1057 Bigint& result = Bigint::Handle();
1058 // We perform the subtraction by simulating a negation of the b-argument.
1059 bool b_is_negative = negate_b ? !b.IsNegative() : b.IsNegative();
1060
1061 // If both are of the same sign, then we can compute the unsigned addition
1062 // and then simply adjust the sign (if necessary).
1063 // Ex: -3 + -5 -> -(3 + 5)
1064 if (a.IsNegative() == b_is_negative) {
1065 result = UnsignedAdd(a, b);
1066 result.SetSign(b_is_negative);
1067 ASSERT(IsClamped(result));
1068 return result.raw();
1069 }
1070
1071 // The signs differ.
1072 // Take the number with small magnitude and subtract its absolute value from
1073 // the absolute value of the other number. Then adjust the sign, if necessary.
1074 // The sign is the same as for the number with the greater magnitude.
1075 // Ex: -8 + 3 -> -(8 - 3)
1076 // 8 + -3 -> (8 - 3)
1077 // -3 + 8 -> (8 - 3)
1078 // 3 + -8 -> -(8 - 3)
1079 int comp = UnsignedCompare(a, b);
1080 if (comp < 0) {
1081 result = UnsignedSubtract(b, a);
1082 result.SetSign(b_is_negative);
1083 } else if (comp > 0) {
1084 result = UnsignedSubtract(a, b);
1085 result.SetSign(a.IsNegative());
1086 } else {
1087 return Zero();
1088 }
1089 ASSERT(IsClamped(result));
1090 return result.raw();
1091 }
1092
1093
1094 int BigintOperations::UnsignedCompare(const Bigint& a, const Bigint& b) {
1095 ASSERT(IsClamped(a));
1096 ASSERT(IsClamped(b));
1097 intptr_t a_length = a.Length();
1098 intptr_t b_length = b.Length();
1099 if (a_length < b_length) return -1;
1100 if (a_length > b_length) return 1;
1101 for (intptr_t i = a_length - 1; i >= 0; i--) {
1102 Chunk digit_a = a.GetChunkAt(i);
1103 Chunk digit_b = b.GetChunkAt(i);
1104 if (digit_a < digit_b) return -1;
1105 if (digit_a > digit_b) return 1;
1106 // Else look at the next digit.
1107 }
1108 return 0; // They are equal.
1109 }
1110
1111
1112 int BigintOperations::UnsignedCompareNonClamped(
1113 const Bigint& a, const Bigint& b) {
1114 intptr_t a_length = a.Length();
1115 intptr_t b_length = b.Length();
1116 while (a_length > b_length) {
1117 if (a.GetChunkAt(a_length - 1) != 0) return 1;
1118 a_length--;
1119 }
1120 while (b_length > a_length) {
1121 if (b.GetChunkAt(b_length - 1) != 0) return -1;
1122 b_length--;
1123 }
1124 for (intptr_t i = a_length - 1; i >= 0; i--) {
1125 Chunk digit_a = a.GetChunkAt(i);
1126 Chunk digit_b = b.GetChunkAt(i);
1127 if (digit_a < digit_b) return -1;
1128 if (digit_a > digit_b) return 1;
1129 // Else look at the next digit.
1130 }
1131 return 0; // They are equal.
1132 }
1133
1134
1135 RawBigint* BigintOperations::UnsignedAdd(const Bigint& a, const Bigint& b) {
1136 ASSERT(IsClamped(a));
1137 ASSERT(IsClamped(b));
1138
1139 intptr_t a_length = a.Length();
1140 intptr_t b_length = b.Length();
1141 if (a_length < b_length) {
1142 return UnsignedAdd(b, a);
1143 }
1144
1145 // We might request too much space, in which case we will adjust the length
1146 // afterwards.
1147 intptr_t result_length = a_length + 1;
1148 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length));
1149
1150 Chunk carry = 0;
1151 // b has fewer digits than a.
1152 ASSERT(b_length <= a_length);
1153 for (intptr_t i = 0; i < b_length; i++) {
1154 Chunk sum = a.GetChunkAt(i) + b.GetChunkAt(i) + carry;
1155 result.SetChunkAt(i, sum & kDigitMask);
1156 carry = sum >> kDigitBitSize;
1157 }
1158 // Copy over the remaining digits of a, but don't forget the carry.
1159 for (intptr_t i = b_length; i < a_length; i++) {
1160 Chunk sum = a.GetChunkAt(i) + carry;
1161 result.SetChunkAt(i, sum & kDigitMask);
1162 carry = sum >> kDigitBitSize;
1163 }
1164 // Shrink the result if there was no overflow. Otherwise apply the carry.
1165 if (carry == 0) {
1166 // TODO(floitsch): We change the size of bigint-objects here.
1167 result.SetLength(a_length);
1168 } else {
1169 result.SetChunkAt(a_length, carry);
1170 }
1171 ASSERT(IsClamped(result));
1172 return result.raw();
1173 }
1174
1175
1176 RawBigint* BigintOperations::UnsignedSubtract(const Bigint& a,
1177 const Bigint& b) {
1178 ASSERT(IsClamped(a));
1179 ASSERT(IsClamped(b));
1180 ASSERT(UnsignedCompare(a, b) >= 0);
1181
1182 const int kSignBitPos = Bigint::kChunkSize * kBitsPerByte - 1;
1183
1184 intptr_t a_length = a.Length();
1185 intptr_t b_length = b.Length();
1186
1187 // We might request too much space, in which case we will adjust the length
1188 // afterwards.
1189 intptr_t result_length = a_length;
1190 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length));
1191
1192 Chunk borrow = 0;
1193 ASSERT(b_length <= a_length);
1194 for (intptr_t i = 0; i < b_length; i++) {
1195 Chunk difference = a.GetChunkAt(i) - b.GetChunkAt(i) - borrow;
1196 result.SetChunkAt(i, difference & kDigitMask);
1197 borrow = difference >> kSignBitPos;
1198 ASSERT((borrow == 0) || (borrow == 1));
1199 }
1200 // Copy over the remaining digits of a, but don't forget the borrow.
1201 for (intptr_t i = b_length; i < a_length; i++) {
1202 Chunk difference = a.GetChunkAt(i) - borrow;
1203 result.SetChunkAt(i, difference & kDigitMask);
1204 borrow = (difference >> kSignBitPos);
1205 ASSERT((borrow == 0) || (borrow == 1));
1206 }
1207 ASSERT(borrow == 0);
1208 Clamp(result);
1209 return result.raw();
1210 }
1211
1212
1213 RawBigint* BigintOperations::MultiplyWithDigit(
1214 const Bigint& bigint, Chunk digit) {
1215 // TODO(floitsch): implement MultiplyWithDigit.
1216 ASSERT(digit <= kDigitMaxValue);
1217 if (digit == 0) return Zero();
1218
1219 Bigint& tmp = Bigint::Handle(Bigint::Allocate(1));
1220 tmp.SetChunkAt(0, digit);
1221 return Multiply(bigint, tmp);
1222 }
1223
1224
1225 void BigintOperations::DivideRemainder(
1226 const Bigint& a, const Bigint& b, Bigint* quotient, Bigint* remainder) {
1227 // TODO(floitsch): This function is very memory-intensive since all
1228 // intermediate bigint results are allocated in new memory. It would be
1229 // much more efficient to reuse the space of temporary intermediate variables.
1230 ASSERT(IsClamped(a));
1231 ASSERT(IsClamped(b));
1232 ASSERT(!b.IsZero());
1233
1234 int comp = UnsignedCompare(a, b);
1235 if (comp < 0) {
1236 (*quotient) ^= Zero();
1237 (*remainder) ^= Copy(a); // TODO(floitsch): can we reuse the input?
1238 return;
1239 } else if (comp == 0) {
1240 (*quotient) ^= One();
1241 quotient->SetSign(a.IsNegative() != b.IsNegative());
1242 (*remainder) ^= Zero();
1243 return;
1244 }
1245
1246 // High level description:
1247 // The algorithm is basically the algorithm that is taught in school:
1248 // Let a the dividend and b the divisor. We are looking for
1249 // the quotient q = truncate(a / b), and
1250 // the remainder r = a - q * b.
1251 // School algorithm:
1252 // q = 0
1253 // n = number_of_digits(a) - number_of_digits(b)
1254 // for (i = n; i >= 0; i--) {
1255 // Maximize k such that k*y*10^i is less than or equal to a and
1256 // (k + 1)*y*10^i is greater.
1257 // q = q + k * 10^i // Add new digit to result.
1258 // a = a - k * b * 10^i
1259 // }
1260 // r = a
1261 //
1262 // Instead of working in base 10 we work in base kDigitBitSize.
1263
1264 intptr_t b_length = b.Length();
1265 int normalization_shift =
1266 kDigitBitSize - CountBits(b.GetChunkAt(b_length - 1));
1267 Bigint& dividend = Bigint::Handle(ShiftLeft(a, normalization_shift));
1268 const Bigint& divisor = Bigint::Handle(ShiftLeft(b, normalization_shift));
1269 dividend.SetSign(false);
1270 divisor.SetSign(false);
1271
1272 intptr_t dividend_length = dividend.Length();
1273 intptr_t divisor_length = b_length;
1274 ASSERT(divisor_length == divisor.Length());
1275
1276 intptr_t quotient_length = dividend_length - divisor_length + 1;
1277 *quotient ^= Bigint::Allocate(quotient_length);
1278 quotient->SetSign(a.IsNegative() != b.IsNegative());
1279
1280 intptr_t quotient_pos = dividend_length - divisor_length;
1281 // Find the first quotient-digit.
1282 // The first digit must be computed separately from the other digits because
1283 // the preconditions for the loop are not yet satisfied.
1284 // For simplicity use a shifted divisor, so that the comparison and
1285 // subtraction are easier.
1286 int divisor_shift_amount = dividend_length - divisor_length;
1287 Bigint& shifted_divisor =
1288 Bigint::Handle(DigitsShiftLeft(divisor, divisor_shift_amount));
1289 Chunk first_quotient_digit = 0;
1290 while (UnsignedCompare(dividend, shifted_divisor) >= 0) {
1291 first_quotient_digit++;
1292 dividend ^= Subtract(dividend, shifted_divisor);
1293 }
1294 quotient->SetChunkAt(quotient_pos--, first_quotient_digit);
1295
1296 // Find the remainder of the digits.
1297
1298 Chunk first_divisor_digit = divisor.GetChunkAt(divisor_length - 1);
1299 // The short divisor only represents the first two digits of the divisor.
1300 // If the divisor has only one digit, then the second part is zeroed out.
1301 Bigint& short_divisor = Bigint::Handle(Bigint::Allocate(2));
1302 if (divisor_length > 1) {
1303 short_divisor.SetChunkAt(0, divisor.GetChunkAt(divisor_length - 2));
1304 } else {
1305 short_divisor.SetChunkAt(0, 0);
1306 }
1307 short_divisor.SetChunkAt(1, first_divisor_digit);
1308 // The following bigint will be used inside the loop. It is allocated outside
1309 // the loop to avoid repeated allocations.
1310 Bigint& target = Bigint::Handle(Bigint::Allocate(3));
1311 // The dividend_length here must be from the initial dividend.
1312 for (intptr_t i = dividend_length - 1; i >= divisor_length; i--) {
1313 // Invariant: let t = i - divisor_length
1314 // then dividend / (divisor << (t * kDigitBitSize)) <= kDigitMaxValue.
1315 // Ex: dividend: 53451232, and divisor: 535 (with t == 5) is ok.
1316 // dividend: 56822123, and divisor: 563 (with t == 5) is bad.
1317 // dividend: 6822123, and divisor: 563 (with t == 5) is ok.
1318
1319 // The dividend has changed. So recompute its length.
1320 dividend_length = dividend.Length();
1321 Chunk dividend_digit;
1322 if (i > dividend_length) {
1323 quotient->SetChunkAt(quotient_pos--, 0);
1324 continue;
1325 } else if (i == dividend_length) {
1326 dividend_digit = 0;
494 } else { 1327 } else {
495 n = Utils::Minimum(a.NumberOfBits(), b.NumberOfBits()); 1328 ASSERT(i + 1 == dividend_length);
496 } 1329 dividend_digit = dividend.GetChunkAt(i);
497 } else if (a.IsNegative() || b.IsNegative()) { 1330 }
498 if (tt[2]) { 1331 Chunk quotient_digit;
499 rflip = rborrow = -1; 1332 // Compute an estimate of the quotient_digit. The estimate will never
500 } 1333 // be too small.
501 n = Utils::Maximum(a.NumberOfBits(), b.NumberOfBits()); 1334 if (dividend_digit == first_divisor_digit) {
502 } else { 1335 // Small shortcut: the else-branch would compute a value > kDigitMaxValue.
503 if (tt[2]) { 1336 // However, by hypothesis, we know that the quotient_digit must fit into
504 n = Utils::Maximum(a.NumberOfBits(), b.NumberOfBits()); 1337 // a digit. Avoid going through repeated iterations of the adjustment
1338 // loop by directly assigning kDigitMaxValue to the quotient_digit.
1339 // Ex: 51235 / 523.
1340 // 51 / 5 would yield 10 (if computed in the else branch).
1341 // However we know that 9 is the maximal value.
1342 quotient_digit = kDigitMaxValue;
505 } else { 1343 } else {
506 n = Utils::Minimum(a.NumberOfBits(), b.NumberOfBits()); 1344 // Compute the estimate by using two digits of the dividend and one of
507 } 1345 // the divisor.
508 } 1346 // Ex: 32421 / 535
509 bool aflip = false; 1347 // 32 / 5 -> 6
510 int acarry = 0; 1348 // The estimate would hence be 6.
511 if (a.IsNegative()) { 1349 DoubleChunk two_dividend_digits = dividend_digit;
512 aflip = true; 1350 two_dividend_digits <<= kDigitBitSize;
513 acarry = 1; 1351 two_dividend_digits += dividend.GetChunkAt(i - 1);
514 } 1352 DoubleChunk q = two_dividend_digits / first_divisor_digit;
515 bool bflip = false; 1353 if (q > kDigitMaxValue) q = kDigitMaxValue;
516 int bcarry = 0; 1354 quotient_digit = static_cast<Chunk>(q);
517 if (b.IsNegative()) { 1355 }
518 bflip = true; 1356
519 bcarry = 1; 1357 // Refine estimation.
520 } 1358 quotient_digit++; // The following loop will start by decrementing.
521 for (int i = 0 ; i < n ; ++i) { 1359 Bigint& estimation_product = Bigint::Handle();
522 int ab = (a.Bit(i) ^ (aflip ? 1 : 0)) + acarry; 1360 target.SetChunkAt(0, ((i - 2) < 0) ? 0 : dividend.GetChunkAt(i - 2));
523 ASSERT(ab <= 2 && ab >= 0); 1361 target.SetChunkAt(1, ((i - 1) < 0) ? 0 : dividend.GetChunkAt(i - 1));
524 int bb = (b.Bit(i) ^ (bflip ? 1 : 0)) + bcarry; 1362 target.SetChunkAt(2, dividend_digit);
525 ASSERT(bb <= 2 && bb >= 0); 1363 do {
526 int r = tt[(ab & 1) + ((bb & 1) << 1)]; 1364 quotient_digit = (quotient_digit - 1) & kDigitMask;
527 r = r + rborrow; 1365 estimation_product ^= MultiplyWithDigit(short_divisor, quotient_digit);
528 ASSERT(r >= -1 && r <= 1); 1366 } while (UnsignedCompareNonClamped(estimation_product, target) > 0);
529 if ((r ^ rflip) & 1) { 1367 // At this point the quotient_digit is fairly accurate.
530 int status = BN_set_bit(TmpBN(), i); 1368 // At the worst it is off by one.
531 ASSERT(status == 1); 1369 // Remove a multiple of the divisor. If the estimate is incorrect we will
532 } 1370 // subtract the divisor another time.
533 acarry = ab >> 1; 1371 // Let t = i - divisor_length.
534 bcarry = bb >> 1; 1372 // dividend -= (quotient_digit * divisor) << (t * kDigitBitSize);
535 rborrow = r >> 1; 1373 shifted_divisor ^= MultiplyWithDigit(divisor, quotient_digit);
536 } 1374 shifted_divisor ^= DigitsShiftLeft(shifted_divisor, i - divisor_length);
537 if (rborrow) { 1375 dividend = Subtract(dividend, shifted_divisor);
538 int status = BN_set_bit(TmpBN(), n); 1376 if (dividend.IsNegative()) {
539 ASSERT(status == 1); 1377 // The estimation was still too big.
540 } 1378 quotient_digit--;
541 if (rflip) { 1379 // TODO(floitsch): allocate space for the shifted_divisor once and reuse
542 // FIXME(benl): can be changed to use BN_set_negative() on more 1380 // it at every iteration.
543 // recent OpenSSL releases (> 1.0.0). 1381 shifted_divisor ^= DigitsShiftLeft(divisor, i - divisor_length);
544 ASSERT(!BN_is_zero(TmpBN())); 1382 // TODO(floitsch): reuse the space of the previous dividend.
545 TmpBN()->neg = 1; 1383 dividend = Add(dividend, shifted_divisor);
546 } 1384 }
547 const Bigint& result = Bigint::Handle(Bigint::New(TmpBN())); 1385 quotient->SetChunkAt(quotient_pos--, quotient_digit);
548 return result.raw(); 1386 }
549 } 1387 ASSERT(quotient_pos == -1);
550 1388 Clamp(*quotient);
551 1389 *remainder ^= ShiftRight(dividend, normalization_shift);
552 RawSmi* BigintOperations::BitOpWithSmi(Token::Kind kind, 1390 remainder->SetSign(a.IsNegative());
553 const Bigint& bigint, 1391 }
554 const Smi& smi) { 1392
555 ASSERT((kind == Token::kBIT_OR) || (kind == Token::kBIT_AND)); 1393
556 intptr_t smi_value = smi.Value(); 1394 void BigintOperations::Clamp(const Bigint& bigint) {
557 intptr_t big_value = 0; 1395 intptr_t length = bigint.Length();
558 // We take Smi::kBits + 1 (one more bit), in case bigint is negative. 1396 while (length > 0 && (bigint.GetChunkAt(length - 1) == 0)) {
559 ASSERT((Smi::kBits + 1) <= (sizeof(big_value) * kBitsPerByte)); 1397 length--;
560 intptr_t num_bits = bigint.NumberOfBits(); 1398 }
561 int n = Utils::Minimum(num_bits, Smi::kBits + 1); 1399 // TODO(floitsch): We change the size of bigint-objects here.
562 for (int i = n - 1; i >= 0; i--) { 1400 bigint.SetLength(length);
563 big_value <<= 1; 1401 }
564 big_value += bigint.Bit(i); 1402
565 } 1403
566 if (bigint.IsNegative()) { 1404 RawBigint* BigintOperations::Copy(const Bigint& bigint) {
567 big_value = -big_value; 1405 intptr_t bigint_length = bigint.Length();
568 } 1406 Bigint& copy = Bigint::Handle(Bigint::Allocate(bigint_length));
569 intptr_t result; 1407 for (intptr_t i = 0; i < bigint_length; i++) {
570 if (kind == Token::kBIT_OR) { 1408 copy.SetChunkAt(i, bigint.GetChunkAt(i));
571 result = smi_value | big_value; 1409 }
572 } else { 1410 copy.SetSign(bigint.IsNegative());
573 result = smi_value & big_value; 1411 return copy.raw();
574 } 1412 }
575 ASSERT(Smi::IsValid(result)); 1413
576 return Smi::New(result); 1414
577 } 1415 int BigintOperations::CountBits(Chunk digit) {
578 1416 int result = 0;
579 1417 while (digit != 0) {
580 RawBigint* BigintOperations::BitAnd(const Bigint& a, const Bigint& b) { 1418 digit >>= 1;
581 static bool tt_and[] = { false, false, false, true }; 1419 result++;
582 return BitTT(a, b, tt_and); 1420 }
583 } 1421 return result;
584
585
586 RawInteger* BigintOperations::BitAndWithSmi(const Bigint& bigint,
587 const Smi& smi) {
588 if (smi.IsNegative()) {
589 Bigint& other = Bigint::Handle(NewFromSmi(smi));
590 return BitAnd(bigint, other);
591 }
592 return BitOpWithSmi(Token::kBIT_AND, bigint, smi);
593 }
594
595
596 RawBigint* BigintOperations::BitOr(const Bigint& a, const Bigint& b) {
597 static bool tt_or[] = { false, true, true, true };
598 return BitTT(a, b, tt_or);
599 }
600
601
602 RawInteger* BigintOperations::BitOrWithSmi(const Bigint& bigint,
603 const Smi& smi) {
604 if (!smi.IsNegative()) {
605 Bigint& other = Bigint::Handle(NewFromSmi(smi));
606 return BitOr(bigint, other);
607 }
608 return BitOpWithSmi(Token::kBIT_OR, bigint, smi);
609 }
610
611
612 RawBigint* BigintOperations::BitXor(const Bigint& a, const Bigint& b) {
613 static bool tt_xor[] = { false, true, true, false };
614 return BitTT(a, b, tt_xor);
615 }
616
617
618 RawInteger* BigintOperations::BitXorWithSmi(const Bigint& bigint,
619 const Smi& smi) {
620 Bigint& other = Bigint::Handle(NewFromSmi(smi));
621 return BitXor(bigint, other);
622 }
623
624
625 RawBigint* BigintOperations::BitNot(const Bigint& bigint) {
626 const Bigint& one_bigint = Bigint::Handle(One());
627 const Bigint& result = Bigint::Handle(Add(bigint, one_bigint));
628 result.ToggleSign();
629 return result.raw();
630 }
631
632
633 int BigintOperations::Compare(const Bigint& a, const Bigint& b) {
634 return BN_cmp(a.BNAddr(), b.BNAddr());
635 } 1422 }
636 1423
637 } // namespace dart 1424 } // namespace dart
OLDNEW
« no previous file with comments | « vm/bigint_operations.h ('k') | vm/bigint_operations_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698