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

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, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright 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) < sizeof(intptr_t) * 8)) {
Ivan Posva 2012/02/28 01:38:34 8 -> kBitsPerByte
siva 2012/02/28 18:22:18 Done.
346 return true;
347 }
348
349 uintptr_t limit;
350 if (bigint.IsNegative()) {
351 limit = static_cast<uintptr_t>(-Smi::kMinValue);
352 } else {
353 limit = static_cast<uintptr_t>(Smi::kMaxValue);
354 }
355 bool bigint_is_greater = false;
356 // Consume the least-significant digits of the bigint.
357 // If bigint_is_greater is set, then the processed sub-part of the bigint is
358 // greater than the corresponding part of the limit.
359 for (int i = 0; i < bigint_length - 1; i++) {
360 Chunk limit_digit = static_cast<Chunk>(limit & kDigitMask);
361 Chunk bigint_digit = bigint.GetChunkAt(i);
362 if (limit_digit < bigint_digit) {
363 bigint_is_greater = true;
364 } else if (limit_digit > bigint_digit) {
365 bigint_is_greater = false;
366 } // else don't change the boolean.
367 limit >>= kDigitBitSize;
368
369 // Bail out if the bigint is definitely too big.
370 if (limit == 0) {
371 return false;
372 }
373 }
374 Chunk most_significant_digit = bigint.GetChunkAt(bigint_length - 1);
375 if (limit > most_significant_digit) {
376 return true;
377 }
378 if (limit < most_significant_digit) {
259 return false; 379 return false;
260 } 380 }
261 return true; 381 return !bigint_is_greater;
262 } 382 }
263 383
264 384
265 RawSmi* BigintOperations::ToSmi(const Bigint& bigint) { 385 RawSmi* BigintOperations::ToSmi(const Bigint& bigint) {
Ivan Posva 2012/02/28 01:38:34 Will we need a FitsIntoMint and ToMint as well?
siva 2012/02/28 18:22:18 They are FitsIntoInt64 and ToInt64 respectively.
266 ASSERT(FitsIntoSmi(bigint)); 386 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; 387 intptr_t value = 0;
272 ASSERT(n <= static_cast<int>(sizeof value)); 388 for (int i = bigint.Length() - 1; i >= 0; i--) {
273 for (int i = 0; i < n; ++i) { 389 value <<= kDigitBitSize;
274 value <<= 8; 390 value += static_cast<intptr_t>(bigint.GetChunkAt(i));
275 value |= bytes[i];
276 } 391 }
277 if (bigint.IsNegative()) { 392 if (bigint.IsNegative()) {
278 value = -value; 393 value = -value;
279 } 394 }
280 return Smi::New(value); 395 return Smi::New(value);
281 } 396 }
282 397
283 398
284 RawDouble* BigintOperations::ToDouble(const Bigint& bigint) { 399 RawDouble* BigintOperations::ToDouble(const Bigint& bigint) {
285 // TODO(floitsch/benl): This is a quick and dirty implementation to unblock 400 // 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. 401 // other areas of the code. It does not handle all bit-twiddling correctly.
402 const double shift_value = (1 << kDigitBitSize);
287 double value = 0.0; 403 double value = 0.0;
288 for (int i = bigint.NumberOfBits() - 1; i >= 0; --i) { 404 for (int i = bigint.Length() - 1; i >= 0; i--) {
289 value *= 2; 405 value *= shift_value;
290 value += static_cast<double>(bigint.Bit(i)); 406 value += static_cast<double>(bigint.GetChunkAt(i));
291 } 407 }
292 if (bigint.IsNegative()) { 408 if (bigint.IsNegative()) {
293 value = -value; 409 value = -value;
294 } 410 }
295 return Double::New(value); 411 return Double::New(value);
296 } 412 }
297 413
298 414
299 bool BigintOperations::FitsIntoInt64(const Bigint& bigint) { 415 bool BigintOperations::FitsIntoInt64(const Bigint& bigint) {
300 const BIGNUM *bn = bigint.BNAddr(); 416 intptr_t bigint_length = bigint.Length();
301 int bits = BN_num_bits(bn); 417 if (bigint_length == 0) {
302 if (bits <= 63) return true; 418 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 } 419 }
312 return true; 420 if ((bigint_length < 3) &&
421 (static_cast<size_t>(kDigitBitSize) < sizeof(intptr_t) * 8)) {
422 return true;
423 }
424
425 uint64_t limit;
426 if (bigint.IsNegative()) {
427 limit = static_cast<uint64_t>(Mint::kMinValue);
428 } else {
429 limit = static_cast<uint64_t>(Mint::kMaxValue);
430 }
431 bool bigint_is_greater = false;
432 // Consume the least-significant digits of the bigint.
433 // If bigint_is_greater is set, then the processed sub-part of the bigint is
434 // greater than the corresponding part of the limit.
435 for (int i = 0; i < bigint_length - 1; i++) {
436 Chunk limit_digit = static_cast<Chunk>(limit & kDigitMask);
437 Chunk bigint_digit = bigint.GetChunkAt(i);
438 if (limit_digit < bigint_digit) {
439 bigint_is_greater = true;
440 } else if (limit_digit > bigint_digit) {
441 bigint_is_greater = false;
442 } // else don't change the boolean.
443 limit >>= kDigitBitSize;
444
445 // Bail out if the bigint is definitely too big.
446 if (limit == 0) {
447 return false;
448 }
449 }
450 Chunk most_significant_digit = bigint.GetChunkAt(bigint_length - 1);
451 if (limit > most_significant_digit) {
452 return true;
453 }
454 if (limit < most_significant_digit) {
455 return false;
456 }
457 return !bigint_is_greater;
313 } 458 }
314 459
315 460
316 uint64_t BigintOperations::AbsToUint64(const Bigint& bigint) { 461 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; 462 uint64_t value = 0;
322 ASSERT(n <= static_cast<int>(sizeof value)); 463 for (int i = bigint.Length() - 1; i >= 0; i--) {
323 for (int i = 0; i < n; ++i) { 464 value <<= kDigitBitSize;
324 value <<= 8; 465 value += static_cast<intptr_t>(bigint.GetChunkAt(i));
325 value |= bytes[i];
326 } 466 }
327 return value; 467 return value;
328 } 468 }
329 469
330 470
331 int64_t BigintOperations::ToInt64(const Bigint& bigint) { 471 int64_t BigintOperations::ToInt64(const Bigint& bigint) {
332 ASSERT(FitsIntoInt64(bigint)); 472 ASSERT(FitsIntoInt64(bigint));
333 int64_t value = AbsToUint64(bigint); 473 int64_t value = AbsToUint64(bigint);
334 if (bigint.IsNegative()) { 474 if (bigint.IsNegative()) {
335 value = -value; 475 value = -value;
336 } 476 }
337 return value; 477 return value;
338 } 478 }
339 479
340 480
341 bool BigintOperations::FitsIntoUint64(const Bigint& bigint) { 481 bool BigintOperations::FitsIntoUint64(const Bigint& bigint) {
342 const BIGNUM *bn = bigint.BNAddr();
343 if (bigint.IsNegative()) return false; 482 if (bigint.IsNegative()) return false;
344 int bits = BN_num_bits(bn); 483 intptr_t b_length = bigint.Length();
345 if (bits > 64) return false; 484 int num_bits = CountBits(bigint.GetChunkAt(b_length - 1));
485 num_bits += (kDigitBitSize * (b_length - 1));
486 if (num_bits > 64) return false;
346 return true; 487 return true;
347 } 488 }
348 489
349 490
350 uint64_t BigintOperations::ToUint64(const Bigint& bigint) { 491 uint64_t BigintOperations::ToUint64(const Bigint& bigint) {
351 ASSERT(FitsIntoUint64(bigint)); 492 ASSERT(FitsIntoUint64(bigint));
352 return AbsToUint64(bigint); 493 return AbsToUint64(bigint);
353 } 494 }
354 495
355 496
356 RawBigint* BigintOperations::Add(const Bigint& a, const Bigint& b) { 497 RawBigint* BigintOperations::Multiply(const Bigint& a, const Bigint& b) {
357 int status = BN_add(TmpBN(), a.BNAddr(), b.BNAddr()); 498 ASSERT(IsClamped(a));
358 if (status == 0) { 499 ASSERT(IsClamped(b));
359 GrowableArray<const Object*> exception_arguments; 500
360 exception_arguments.Add( 501 intptr_t a_length = a.Length();
361 &Object::ZoneHandle(String::New("BigintOperations::Add"))); 502 intptr_t b_length = b.Length();
362 Exceptions::ThrowByType(Exceptions::kInternalError, exception_arguments); 503 intptr_t result_length = a_length + b_length;
363 } 504 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length));
364 const Bigint& result = Bigint::Handle(Bigint::New(TmpBN())); 505
506 if (a.IsNegative() != b.IsNegative()) {
507 result.ToggleSign();
508 }
509
510 // Comba multiplication: compute each column separately.
511 // Example: r = a2a1a0 * b2b1b0.
512 // r = 1 * a0b0 +
513 // 10 * (a1b0 + a0b1) +
514 // 100 * (a2b0 + a1b1 + a0b2) +
515 // 1000 * (a2b1 + a1b2) +
516 // 10000 * a2b2
517 //
518 // Each column will be accumulated in an integer of type DoubleChunk. We
519 // must guarantee that the column-sum will not overflow.
520 //
521 // In the worst case we have to accumulate k = Min(a.length, b.length)
522 // products plus the carry from the previous round.
523 // Each bigint-digit is smaller than beta = 2^kDigitBitSize.
524 // Each product is at most (beta - 1)^2.
525 // If we want to use Comba multiplication the following condition must hold:
526 // k * (beta - 1)^2 + (2^(kDoubleChunkBitSize - kDigitBitSize) - 1) <
527 // 2^kDoubleChunkBitSize.
528 const DoubleChunk square =
529 static_cast<DoubleChunk>(kDigitMaxValue) * kDigitMaxValue;
530 const DoubleChunk kDoubleChunkMaxValue = static_cast<DoubleChunk>(-1);
531 const DoubleChunk left_over_carry = kDoubleChunkMaxValue >> kDigitBitSize;
532 const intptr_t kMaxDigits = (kDoubleChunkMaxValue - left_over_carry) / square;
533 if (Utils::Minimum(a_length, b_length) > kMaxDigits) {
534 UNIMPLEMENTED();
535 }
536
537 DoubleChunk accumulator = 0; // Accumulates the result of one column.
538 for (intptr_t i = 0; i < result_length; i++) {
539 // Example: r = a2a1a0 * b2b1b0.
540 // For i == 0, compute a0b0.
541 // i == 1, a1b0 + a0b1 + overflow from i == 0.
542 // i == 2, a2b0 + a1b1 + a0b2 + overflow from i == 1.
543 // ...
544 // The indices into a and b are such that their sum equals i.
545 intptr_t a_index = Utils::Minimum(a_length - 1, i);
546 intptr_t b_index = i - a_index;
547 ASSERT(a_index + b_index == i);
548
549 // Instead of testing for a_index >= 0 && b_index < b_length we compute the
550 // number of iterations first.
551 intptr_t iterations = Utils::Minimum(b_length - b_index, a_index + 1);
552 for (intptr_t j = 0; j < iterations; j++) {
553 DoubleChunk chunk_a = a.GetChunkAt(a_index);
554 DoubleChunk chunk_b = b.GetChunkAt(b_index);
555 accumulator += chunk_a * chunk_b;
556 a_index--;
557 b_index++;
558 }
559 result.SetChunkAt(i, static_cast<Chunk>(accumulator & kDigitMask));
560 accumulator >>= kDigitBitSize;
561 }
562 ASSERT(accumulator == 0);
563
564 Clamp(result);
365 return result.raw(); 565 return result.raw();
366 } 566 }
367 567
368 568
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) { 569 RawBigint* BigintOperations::Divide(const Bigint& a, const Bigint& b) {
396 int status = BN_div(TmpBN(), NULL, a.BNAddr(), b.BNAddr(), TmpBNCtx()); 570 Bigint& quotient = Bigint::Handle();
397 if (status == 0) { 571 Bigint& remainder = Bigint::Handle();
398 GrowableArray<const Object*> exception_arguments; 572 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(); 573 return quotient.raw();
405 } 574 }
406 575
407 576
408 RawBigint* BigintOperations::Modulo(const Bigint& a, const Bigint& b) { 577 RawBigint* BigintOperations::Modulo(const Bigint& a, const Bigint& b) {
409 int status = BN_nnmod(TmpBN(), a.BNAddr(), b.BNAddr(), TmpBNCtx()); 578 Bigint& quotient = Bigint::Handle();
410 if (status == 0) { 579 Bigint& modulo = Bigint::Handle();
411 GrowableArray<const Object*> exception_arguments; 580 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(); 581 return modulo.raw();
418 } 582 }
419 583
420 584
421 RawBigint* BigintOperations::Remainder(const Bigint& a, const Bigint& b) { 585 RawBigint* BigintOperations::Remainder(const Bigint& a, const Bigint& b) {
422 int status = BN_div(NULL, TmpBN(), a.BNAddr(), b.BNAddr(), TmpBNCtx()); 586 Bigint& quotient = Bigint::Handle();
423 if (status == 0) { 587 Bigint& remainder = Bigint::Handle();
424 GrowableArray<const Object*> exception_arguments; 588 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(); 589 return remainder.raw();
431 } 590 }
432 591
433 592
434 RawBigint* BigintOperations::ShiftLeft(const Bigint& bigint, intptr_t amount) { 593 RawBigint* BigintOperations::ShiftLeft(const Bigint& bigint, intptr_t amount) {
435 int status = BN_lshift(TmpBN(), bigint.BNAddr(), amount); 594 ASSERT(IsClamped(bigint));
436 if (status == 0) { 595 ASSERT(amount >= 0);
437 GrowableArray<const Object*> exception_arguments; 596 intptr_t bigint_length = bigint.Length();
438 exception_arguments.Add( 597 if (bigint.IsZero()) {
439 &Object::ZoneHandle(String::New("BigintOperations::ShiftLeft"))); 598 return Zero();
440 Exceptions::ThrowByType(Exceptions::kInternalError, exception_arguments); 599 }
441 } 600 // TODO(floitsch): can we reuse the input?
442 const Bigint& result = Bigint::Handle(Bigint::New(TmpBN())); 601 if (amount == 0) {
443 return result.raw(); 602 return Copy(bigint);
603 }
604 intptr_t digit_shift = amount / kDigitBitSize;
605 intptr_t bit_shift = amount % kDigitBitSize;
606 if (bit_shift == 0) {
607 const Bigint& result =
608 Bigint::Handle(Bigint::Allocate(bigint_length + digit_shift));
609 for (intptr_t i = 0; i < digit_shift; i++) {
610 result.SetChunkAt(i, 0);
611 }
612 for (intptr_t i = 0; i < bigint_length; i++) {
613 result.SetChunkAt(i + digit_shift, bigint.GetChunkAt(i));
614 }
615 if (bigint.IsNegative()) {
616 result.ToggleSign();
617 }
618 return result.raw();
619 } else {
620 const Bigint& result =
621 Bigint::Handle(Bigint::Allocate(bigint_length + digit_shift + 1));
622 for (intptr_t i = 0; i < digit_shift; i++) {
623 result.SetChunkAt(i, 0);
624 }
625 Chunk carry = 0;
626 for (intptr_t i = 0; i < bigint_length; i++) {
627 Chunk digit = bigint.GetChunkAt(i);
628 Chunk shifted_digit = ((digit << bit_shift) & kDigitMask) + carry;
629 result.SetChunkAt(i + digit_shift, shifted_digit);
630 carry = digit >> (kDigitBitSize - bit_shift);
631 }
632 result.SetChunkAt(bigint_length + digit_shift, carry);
633 if (bigint.IsNegative()) {
634 result.ToggleSign();
635 }
636 Clamp(result);
637 return result.raw();
638 }
444 } 639 }
445 640
446 641
447 RawBigint* BigintOperations::ShiftRight(const Bigint& bigint, intptr_t amount) { 642 RawBigint* BigintOperations::ShiftRight(const Bigint& bigint, intptr_t amount) {
643 ASSERT(IsClamped(bigint));
448 ASSERT(amount >= 0); 644 ASSERT(amount >= 0);
449 int status = BN_rshift(TmpBN(), bigint.BNAddr(), amount); 645 intptr_t bigint_length = bigint.Length();
450 if (status == 0) { 646 if (bigint.IsZero()) {
451 GrowableArray<const Object*> exception_arguments; 647 return Zero();
452 exception_arguments.Add( 648 }
453 &Object::ZoneHandle(String::New("BigintOperations::ShiftRight"))); 649 // TODO(floitsch): can we reuse the input?
454 Exceptions::ThrowByType(Exceptions::kInternalError, exception_arguments); 650 if (amount == 0) {
455 } 651 return Copy(bigint);
456 // OpenSSL doesn't take account of sign when shifting - this fixes it. 652 }
653 intptr_t digit_shift = amount / kDigitBitSize;
654 intptr_t bit_shift = amount % kDigitBitSize;
655 if (digit_shift >= bigint_length) {
656 return bigint.IsNegative() ? MinusOne() : Zero();
657 }
658
659 const Bigint& result =
660 Bigint::Handle(Bigint::Allocate(bigint_length - digit_shift));
661 if (bit_shift == 0) {
662 for (intptr_t i = 0; i < bigint_length - digit_shift; i++) {
663 result.SetChunkAt(i, bigint.GetChunkAt(i + digit_shift));
664 }
665 } else {
666 Chunk carry = 0;
667 for (intptr_t i = bigint_length - 1; i >= digit_shift; i--) {
668 Chunk digit = bigint.GetChunkAt(i);
669 Chunk shifted_digit = (digit >> bit_shift) + carry;
670 result.SetChunkAt(i - digit_shift, shifted_digit);
671 carry = (digit << (kDigitBitSize - bit_shift)) & kDigitMask;
672 }
673 Clamp(result);
674 }
675
457 if (bigint.IsNegative()) { 676 if (bigint.IsNegative()) {
458 for (intptr_t i = 0; i < amount; ++i) { 677 result.ToggleSign();
459 if (bigint.IsBitSet(i)) { 678 // If the input is negative then the result needs to be rounded down.
460 int status = BN_sub_word(TmpBN(), 1); 679 // Example: -5 >> 2 => -2
461 ASSERT(status == 1); 680 bool needs_rounding = false;
681 for (intptr_t i = 0; i < digit_shift; i++) {
682 if (bigint.GetChunkAt(i) != 0) {
683 needs_rounding = true;
462 break; 684 break;
463 } 685 }
464 } 686 }
465 } 687 if (!needs_rounding && (bit_shift > 0)) {
466 const Bigint& result = Bigint::Handle(Bigint::New(TmpBN())); 688 Chunk digit = bigint.GetChunkAt(digit_shift);
689 needs_rounding = (digit << (kChunkBitSize - bit_shift)) != 0;
690 }
691 if (needs_rounding) {
692 Bigint& one = Bigint::Handle(One());
693 return Subtract(result, one);
694 }
695 }
696
467 return result.raw(); 697 return result.raw();
468 } 698 }
469 699
470 /* Bit operations are complicated by negatives: BIGNUMs don't use 2's 700
471 * complement, but instead store the absolute value and a sign 701 RawBigint* BigintOperations::BitAnd(const Bigint& a, const Bigint& b) {
472 * indicator. However bit operations are defined on 2's complement 702 ASSERT(IsClamped(a));
473 * representations. This function handles the necessary 703 ASSERT(IsClamped(b));
474 * invert-and-carry operations to deal with the fact that -x = ~x + 1 704
475 * both on the operands and result. The actual operation performed is 705 if (a.IsZero() || b.IsZero()) {
476 * specified by the truth table |tt|, which is in the order of input 706 return Zero();
477 * bits (00, 01, 10, 11). 707 }
478 */ 708 if (a.IsNegative() && !b.IsNegative()) {
479 RawBigint* BigintOperations::BitTT(const Bigint& a, const Bigint& b, 709 return BitAnd(b, a);
480 bool tt[4]) { 710 }
481 BN_zero(TmpBN()); 711 if ((a.IsNegative() == b.IsNegative()) && (a.Length() < b.Length())) {
482 int n; 712 return BitAnd(b, a);
483 int rflip = 0; 713 }
484 int rborrow = 0; 714
485 // There's probably a clever way to figure out why these are what 715 intptr_t a_length = a.Length();
486 // they are, but I confess I worked them out pragmatically. 716 intptr_t b_length = b.Length();
487 if (a.IsNegative() && b.IsNegative()) { 717 intptr_t min_length = Utils::Minimum(a_length, b_length);
488 if (tt[3]) { 718 intptr_t max_length = Utils::Maximum(a_length, b_length);
489 rflip = -1; 719 if (!b.IsNegative()) {
490 rborrow = -1; 720 ASSERT(!a.IsNegative());
491 } 721 intptr_t result_length = min_length;
492 if (tt[2] != tt[3]) { 722 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length));
493 n = Utils::Maximum(a.NumberOfBits(), b.NumberOfBits()); 723
724 for (intptr_t i = 0; i < min_length; i++) {
725 result.SetChunkAt(i, a.GetChunkAt(i) & b.GetChunkAt(i));
726 }
727 Clamp(result);
728 return result.raw();
729 }
730
731 // Bigints encode negative values by storing the absolute value and the sign
732 // separately. To do bit operations we need to simulate numbers that are
733 // implemented as two's complement.
734 // The negation of a positive number x would be encoded as follows in
735 // two's complement: n = ~(x - 1).
736 // The inverse transformation is hence (~n) + 1.
737
738 if (!a.IsNegative()) {
739 ASSERT(b.IsNegative());
740 // The result will be positive.
741 intptr_t result_length = a_length;
742 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length));
743 Chunk borrow = 1;
744 for (intptr_t i = 0; i < min_length; i++) {
745 Chunk b_digit = b.GetChunkAt(i) - borrow;
746 result.SetChunkAt(i, a.GetChunkAt(i) & (~b_digit) & kDigitMask);
747 borrow = b_digit >> (kChunkBitSize - 1);
748 }
749 for (intptr_t i = min_length; i < a_length; i++) {
750 result.SetChunkAt(i, a.GetChunkAt(i) & (kDigitMaxValue - borrow));
751 borrow = 0;
752 }
753 Clamp(result);
754 return result.raw();
755 }
756
757 ASSERT(a.IsNegative());
758 ASSERT(b.IsNegative());
759 // The result will be negative.
760 // We need to convert a and b to two's complement. Do the bit-operation there,
761 // and transform the resulting bits from two's complement back to separated
762 // magnitude and sign.
763 // a & b is therefore computed as ~((~(a - 1)) & (~(b - 1))) + 1 which is
764 // equal to ((a-1) | (b-1)) + 1.
765 intptr_t result_length = max_length + 1;
766 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length));
767 result.ToggleSign();
768 Chunk a_borrow = 1;
769 Chunk b_borrow = 1;
770 Chunk result_carry = 1;
771 ASSERT(a_length >= b_length);
772 for (intptr_t i = 0; i < b_length; i++) {
773 Chunk a_digit = a.GetChunkAt(i) - a_borrow;
774 Chunk b_digit = b.GetChunkAt(i) - b_borrow;
775 Chunk result_chunk = ((a_digit | b_digit) & kDigitMask) + result_carry;
776 result.SetChunkAt(i, result_chunk & kDigitMask);
777 a_borrow = a_digit >> (kChunkBitSize - 1);
778 b_borrow = b_digit >> (kChunkBitSize - 1);
779 result_carry = result_chunk >> kDigitBitSize;
780 }
781 for (intptr_t i = b_length; i < a_length; i++) {
782 Chunk a_digit = a.GetChunkAt(i) - a_borrow;
783 Chunk b_digit = -b_borrow;
784 Chunk result_chunk = ((a_digit | b_digit) & kDigitMask) + result_carry;
785 result.SetChunkAt(i, result_chunk & kDigitMask);
786 a_borrow = a_digit >> (kChunkBitSize - 1);
787 b_borrow = 0;
788 result_carry = result_chunk >> kDigitBitSize;
789 }
790 Chunk a_digit = -a_borrow;
791 Chunk b_digit = -b_borrow;
792 Chunk result_chunk = ((a_digit | b_digit) & kDigitMask) + result_carry;
793 result.SetChunkAt(a_length, result_chunk & kDigitMask);
794 Clamp(result);
795 return result.raw();
796 }
797
798
799 RawBigint* BigintOperations::BitOr(const Bigint& a, const Bigint& b) {
800 ASSERT(IsClamped(a));
801 ASSERT(IsClamped(b));
802
803 if (a.IsNegative() && !b.IsNegative()) {
804 return BitOr(b, a);
805 }
806 if ((a.IsNegative() == b.IsNegative()) && (a.Length() < b.Length())) {
807 return BitOr(b, a);
808 }
809
810 intptr_t a_length = a.Length();
811 intptr_t b_length = b.Length();
812 intptr_t min_length = Utils::Minimum(a_length, b_length);
813 intptr_t max_length = Utils::Maximum(a_length, b_length);
814 if (!b.IsNegative()) {
815 ASSERT(!a.IsNegative());
816 intptr_t result_length = max_length;
817 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length));
818
819 ASSERT(a_length >= b_length);
820 for (intptr_t i = 0; i < b_length; i++) {
821 result.SetChunkAt(i, a.GetChunkAt(i) | b.GetChunkAt(i));
822 }
823 for (intptr_t i = b_length; i < a_length; i++) {
824 result.SetChunkAt(i, a.GetChunkAt(i));
825 }
826 return result.raw();
827 }
828
829 // Bigints encode negative values by storing the absolute value and the sign
830 // separately. To do bit operations we need to simulate numbers that are
831 // implemented as two's complement.
832 // The negation of a positive number x would be encoded as follows in
833 // two's complement: n = ~(x - 1).
834 // The inverse transformation is hence (~n) + 1.
835
836 if (!a.IsNegative()) {
837 ASSERT(b.IsNegative());
838 if (a.IsZero()) {
839 return Copy(b);
840 }
841 // The result will be negative.
842 // We need to convert b to two's complement. Do the bit-operation there,
843 // and transform the resulting bits from two's complement back to separated
844 // magnitude and sign.
845 // a | b is therefore computed as ~((a & (~(b - 1))) + 1 which is
846 // equal to ((~a) & (b-1)) + 1.
847 intptr_t result_length = b_length;
848 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length));
849 result.ToggleSign();
850 Chunk borrow = 1;
851 Chunk result_carry = 1;
852 for (intptr_t i = 0; i < min_length; i++) {
853 Chunk a_digit = a.GetChunkAt(i);
854 Chunk b_digit = b.GetChunkAt(i) - borrow;
855 Chunk result_digit = ((~a_digit) & b_digit & kDigitMask) + result_carry;
856 result.SetChunkAt(i, result_digit & kDigitMask);
857 borrow = b_digit >> (kChunkBitSize - 1);
858 result_carry = result_digit >> kDigitBitSize;
859 }
860 ASSERT(result_carry == 0);
861 for (intptr_t i = min_length; i < b_length; i++) {
862 Chunk b_digit = b.GetChunkAt(i) - borrow;
863 Chunk result_digit = (b_digit & kDigitMask) + result_carry;
864 result.SetChunkAt(i, result_digit & kDigitMask);
865 borrow = b_digit >> (kChunkBitSize - 1);
866 result_carry = result_digit >> kDigitBitSize;
867 }
868 ASSERT(result_carry == 0);
869 Clamp(result);
870 return result.raw();
871 }
872
873 ASSERT(a.IsNegative());
874 ASSERT(b.IsNegative());
875 // The result will be negative.
876 // We need to convert a and b to two's complement. Do the bit-operation there,
877 // and transform the resulting bits from two's complement back to separated
878 // magnitude and sign.
879 // a & b is therefore computed as ~((~(a - 1)) | (~(b - 1))) + 1 which is
880 // equal to ((a-1) & (b-1)) + 1.
881 intptr_t result_length = min_length + 1;
882 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length));
883 result.ToggleSign();
884 Chunk a_borrow = 1;
885 Chunk b_borrow = 1;
886 Chunk result_carry = 1;
887 ASSERT(a_length >= b_length);
888 for (intptr_t i = 0; i < b_length; i++) {
889 Chunk a_digit = a.GetChunkAt(i) - a_borrow;
890 Chunk b_digit = b.GetChunkAt(i) - b_borrow;
891 Chunk result_chunk = ((a_digit & b_digit) & kDigitMask) + result_carry;
892 result.SetChunkAt(i, result_chunk & kDigitMask);
893 a_borrow = a_digit >> (kChunkBitSize - 1);
894 b_borrow = b_digit >> (kChunkBitSize - 1);
895 result_carry = result_chunk >> kDigitBitSize;
896 }
897 result.SetChunkAt(a_length, result_carry);
898 Clamp(result);
899 return result.raw();
900 }
901
902
903 RawBigint* BigintOperations::BitXor(const Bigint& a, const Bigint& b) {
904 ASSERT(IsClamped(a));
905 ASSERT(IsClamped(b));
906
907 if (a.IsZero()) {
908 return Copy(b);
909 }
910 if (b.IsZero()) {
911 return Copy(a);
912 }
913 if (a.IsNegative() && !b.IsNegative()) {
914 return BitXor(b, a);
915 }
916 if ((a.IsNegative() == b.IsNegative()) && (a.Length() < b.Length())) {
917 return BitXor(b, a);
918 }
919
920 intptr_t a_length = a.Length();
921 intptr_t b_length = b.Length();
922 intptr_t min_length = Utils::Minimum(a_length, b_length);
923 intptr_t max_length = Utils::Maximum(a_length, b_length);
924 if (!b.IsNegative()) {
925 ASSERT(!a.IsNegative());
926 intptr_t result_length = max_length;
927 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length));
928
929 ASSERT(a_length >= b_length);
930 for (intptr_t i = 0; i < b_length; i++) {
931 result.SetChunkAt(i, a.GetChunkAt(i) ^ b.GetChunkAt(i));
932 }
933 for (intptr_t i = b_length; i < a_length; i++) {
934 result.SetChunkAt(i, a.GetChunkAt(i));
935 }
936 Clamp(result);
937 return result.raw();
938 }
939
940 // Bigints encode negative values by storing the absolute value and the sign
941 // separately. To do bit operations we need to simulate numbers that are
942 // implemented as two's complement.
943 // The negation of a positive number x would be encoded as follows in
944 // two's complement: n = ~(x - 1).
945 // The inverse transformation is hence (~n) + 1.
946
947 if (!a.IsNegative()) {
948 ASSERT(b.IsNegative());
949 // The result will be negative.
950 // We need to convert b to two's complement. Do the bit-operation there,
951 // and transform the resulting bits from two's complement back to separated
952 // magnitude and sign.
953 // a ^ b is therefore computed as ~((a ^ (~(b - 1))) + 1.
954 intptr_t result_length = max_length + 1;
955 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length));
956 result.ToggleSign();
957 Chunk borrow = 1;
958 Chunk result_carry = 1;
959 for (intptr_t i = 0; i < min_length; i++) {
960 Chunk a_digit = a.GetChunkAt(i);
961 Chunk b_digit = b.GetChunkAt(i) - borrow;
962 Chunk result_digit =
963 ((~(a_digit ^ ~b_digit)) & kDigitMask) + result_carry;
964 result.SetChunkAt(i, result_digit & kDigitMask);
965 borrow = b_digit >> (kChunkBitSize - 1);
966 result_carry = result_digit >> kDigitBitSize;
967 }
968 for (intptr_t i = min_length; i < a_length; i++) {
969 Chunk a_digit = a.GetChunkAt(i);
970 Chunk b_digit = -borrow;
971 Chunk result_digit =
972 ((~(a_digit ^ ~b_digit)) & kDigitMask) + result_carry;
973 result.SetChunkAt(i, result_digit & kDigitMask);
974 borrow = b_digit >> (kChunkBitSize - 1);
975 result_carry = result_digit >> kDigitBitSize;
976 }
977 for (intptr_t i = min_length; i < b_length; i++) {
978 // a_digit = 0.
979 Chunk b_digit = b.GetChunkAt(i) - borrow;
980 Chunk result_digit = (b_digit & kDigitMask) + result_carry;
981 result.SetChunkAt(i, result_digit & kDigitMask);
982 borrow = b_digit >> (kChunkBitSize - 1);
983 result_carry = result_digit >> kDigitBitSize;
984 }
985 result.SetChunkAt(max_length, result_carry);
986 Clamp(result);
987 return result.raw();
988 }
989
990 ASSERT(a.IsNegative());
991 ASSERT(b.IsNegative());
992 // The result will be positive.
993 // We need to convert a and b to two's complement, do the bit-operation there,
994 // and simply store the result.
995 // a ^ b is therefore computed as (~(a - 1)) ^ (~(b - 1)).
996 intptr_t result_length = max_length;
997 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length));
998 Chunk a_borrow = 1;
999 Chunk b_borrow = 1;
1000 ASSERT(a_length >= b_length);
1001 for (intptr_t i = 0; i < b_length; i++) {
1002 Chunk a_digit = a.GetChunkAt(i) - a_borrow;
1003 Chunk b_digit = b.GetChunkAt(i) - b_borrow;
1004 Chunk result_chunk = (~a_digit) ^ (~b_digit);
1005 result.SetChunkAt(i, result_chunk & kDigitMask);
1006 a_borrow = a_digit >> (kChunkBitSize - 1);
1007 b_borrow = b_digit >> (kChunkBitSize - 1);
1008 }
1009 ASSERT(b_borrow == 0);
1010 for (intptr_t i = b_length; i < a_length; i++) {
1011 Chunk a_digit = a.GetChunkAt(i) - a_borrow;
1012 result.SetChunkAt(i, (~a_digit) & kDigitMask);
1013 a_borrow = a_digit >> (kChunkBitSize - 1);
1014 }
1015 ASSERT(a_borrow == 0);
1016 Clamp(result);
1017 return result.raw();
1018 }
1019
1020
1021 RawBigint* BigintOperations::BitNot(const Bigint& bigint) {
1022 if (bigint.IsZero()) {
1023 return MinusOne();
1024 }
1025 const Bigint& one_bigint = Bigint::Handle(One());
1026 if (bigint.IsNegative()) {
1027 return UnsignedSubtract(bigint, one_bigint);
1028 } else {
1029 const Bigint& result = Bigint::Handle(UnsignedAdd(bigint, one_bigint));
1030 result.ToggleSign();
1031 return result.raw();
1032 }
1033 }
1034
1035
1036 int BigintOperations::Compare(const Bigint& a, const Bigint& b) {
1037 bool a_is_negative = a.IsNegative();
1038 bool b_is_negative = b.IsNegative();
1039 if (a_is_negative != b_is_negative) {
1040 return a_is_negative ? -1 : 1;
1041 }
1042
1043 if (a_is_negative) {
1044 return -UnsignedCompare(a, b);
1045 }
1046 return UnsignedCompare(a, b);
1047 }
1048
1049
1050 RawBigint* BigintOperations::AddSubtract(const Bigint& a,
1051 const Bigint& b,
1052 bool negate_b) {
1053 ASSERT(IsClamped(a));
1054 ASSERT(IsClamped(b));
1055 Bigint& result = Bigint::Handle();
1056 // We perform the subtraction by simulating a negation of the b-argument.
1057 bool b_is_negative = negate_b ? !b.IsNegative() : b.IsNegative();
1058
1059 // If both are of the same sign, then we can compute the unsigned addition
1060 // and then simply adjust the sign (if necessary).
1061 // Ex: -3 + -5 -> -(3 + 5)
1062 if (a.IsNegative() == b_is_negative) {
1063 result = UnsignedAdd(a, b);
1064 result.SetSign(b_is_negative);
1065 ASSERT(IsClamped(result));
1066 return result.raw();
1067 }
1068
1069 // The signs differ.
1070 // Take the number with small magnitude and subtract its absolute value from
1071 // the absolute value of the other number. Then adjust the sign, if necessary.
1072 // The sign is the same as for the number with the greater magnitude.
1073 // Ex: -8 + 3 -> -(8 - 3)
1074 // 8 + -3 -> (8 - 3)
1075 // -3 + 8 -> (8 - 3)
1076 // 3 + -8 -> -(8 - 3)
1077 int comp = UnsignedCompare(a, b);
1078 if (comp < 0) {
1079 result = UnsignedSubtract(b, a);
1080 result.SetSign(b_is_negative);
1081 } else if (comp > 0) {
1082 result = UnsignedSubtract(a, b);
1083 result.SetSign(a.IsNegative());
1084 } else {
1085 return Zero();
1086 }
1087 ASSERT(IsClamped(result));
1088 return result.raw();
1089 }
1090
1091
1092 int BigintOperations::UnsignedCompare(const Bigint& a, const Bigint& b) {
1093 ASSERT(IsClamped(a));
1094 ASSERT(IsClamped(b));
1095 intptr_t a_length = a.Length();
1096 intptr_t b_length = b.Length();
1097 if (a_length < b_length) return -1;
1098 if (a_length > b_length) return 1;
1099 for (intptr_t i = a_length - 1; i >= 0; i--) {
1100 Chunk digit_a = a.GetChunkAt(i);
1101 Chunk digit_b = b.GetChunkAt(i);
1102 if (digit_a < digit_b) return -1;
1103 if (digit_a > digit_b) return 1;
1104 // Else look at the next digit.
1105 }
1106 return 0; // They are equal.
1107 }
1108
1109
1110 int BigintOperations::UnsignedCompareNonClamped(
1111 const Bigint& a, const Bigint& b) {
1112 intptr_t a_length = a.Length();
1113 intptr_t b_length = b.Length();
1114 while (a_length > b_length) {
1115 if (a.GetChunkAt(a_length - 1) != 0) return 1;
1116 a_length--;
1117 }
1118 while (b_length > a_length) {
1119 if (b.GetChunkAt(b_length - 1) != 0) return -1;
1120 b_length--;
1121 }
1122 for (intptr_t i = a_length - 1; i >= 0; i--) {
1123 Chunk digit_a = a.GetChunkAt(i);
1124 Chunk digit_b = b.GetChunkAt(i);
1125 if (digit_a < digit_b) return -1;
1126 if (digit_a > digit_b) return 1;
1127 // Else look at the next digit.
1128 }
1129 return 0; // They are equal.
1130 }
1131
1132
1133 RawBigint* BigintOperations::UnsignedAdd(const Bigint& a, const Bigint& b) {
1134 ASSERT(IsClamped(a));
1135 ASSERT(IsClamped(b));
1136
1137 intptr_t a_length = a.Length();
1138 intptr_t b_length = b.Length();
1139 if (a_length < b_length) {
1140 return UnsignedAdd(b, a);
1141 }
1142
1143 // We might request too much space, in which case we will adjust the length
1144 // afterwards.
1145 intptr_t result_length = a_length + 1;
1146 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length));
1147
1148 Chunk carry = 0;
1149 // b has fewer digits than a.
1150 ASSERT(b_length <= a_length);
1151 for (intptr_t i = 0; i < b_length; i++) {
1152 Chunk sum = a.GetChunkAt(i) + b.GetChunkAt(i) + carry;
1153 result.SetChunkAt(i, sum & kDigitMask);
1154 carry = sum >> kDigitBitSize;
1155 }
1156 // Copy over the remaining digits of a, but don't forget the carry.
1157 for (intptr_t i = b_length; i < a_length; i++) {
1158 Chunk sum = a.GetChunkAt(i) + carry;
1159 result.SetChunkAt(i, sum & kDigitMask);
1160 carry = sum >> kDigitBitSize;
1161 }
1162 // Shrink the result if there was no overflow. Otherwise apply the carry.
1163 if (carry == 0) {
1164 // TODO(floitsch): We change the size of bigint-objects here.
1165 result.SetLength(a_length);
1166 } else {
1167 result.SetChunkAt(a_length, carry);
1168 }
1169 ASSERT(IsClamped(result));
1170 return result.raw();
1171 }
1172
1173
1174 RawBigint* BigintOperations::UnsignedSubtract(const Bigint& a,
1175 const Bigint& b) {
1176 ASSERT(IsClamped(a));
1177 ASSERT(IsClamped(b));
1178 ASSERT(UnsignedCompare(a, b) >= 0);
1179
1180 const int kSignBitPos = Bigint::kChunkSize * kBitsPerByte - 1;
1181
1182 intptr_t a_length = a.Length();
1183 intptr_t b_length = b.Length();
1184
1185 // We might request too much space, in which case we will adjust the length
1186 // afterwards.
1187 intptr_t result_length = a_length;
1188 const Bigint& result = Bigint::Handle(Bigint::Allocate(result_length));
1189
1190 Chunk borrow = 0;
1191 ASSERT(b_length <= a_length);
1192 for (intptr_t i = 0; i < b_length; i++) {
1193 Chunk difference = a.GetChunkAt(i) - b.GetChunkAt(i) - borrow;
1194 result.SetChunkAt(i, difference & kDigitMask);
1195 borrow = difference >> kSignBitPos;
1196 ASSERT((borrow == 0) || (borrow == 1));
1197 }
1198 // Copy over the remaining digits of a, but don't forget the borrow.
1199 for (intptr_t i = b_length; i < a_length; i++) {
1200 Chunk difference = a.GetChunkAt(i) - borrow;
1201 result.SetChunkAt(i, difference & kDigitMask);
1202 borrow = (difference >> kSignBitPos);
1203 ASSERT((borrow == 0) || (borrow == 1));
1204 }
1205 ASSERT(borrow == 0);
1206 Clamp(result);
1207 return result.raw();
1208 }
1209
1210
1211 RawBigint* BigintOperations::MultiplyWithDigit(
1212 const Bigint& bigint, Chunk digit) {
1213 // TODO(floitsch): implement MultiplyWithDigit.
1214 ASSERT(digit <= kDigitMaxValue);
1215 if (digit == 0) return Zero();
1216
1217 Bigint& tmp = Bigint::Handle(Bigint::Allocate(1));
1218 tmp.SetChunkAt(0, digit);
1219 return Multiply(bigint, tmp);
1220 }
1221
1222
1223 void BigintOperations::DivideRemainder(
1224 const Bigint& a, const Bigint& b, Bigint* quotient, Bigint* remainder) {
1225 // TODO(floitsch): This function is very memory-intensive since all
1226 // intermediate bigint results are allocated in new memory. It would be
1227 // much more efficient to reuse the space of temporary intermediate variables.
1228 ASSERT(IsClamped(a));
1229 ASSERT(IsClamped(b));
1230 ASSERT(!b.IsZero());
1231
1232 int comp = UnsignedCompare(a, b);
1233 if (comp < 0) {
1234 (*quotient) ^= Zero();
1235 (*remainder) ^= Copy(a); // TODO(floitsch): can we reuse the input?
1236 return;
1237 } else if (comp == 0) {
1238 (*quotient) ^= One();
1239 quotient->SetSign(a.IsNegative() != b.IsNegative());
1240 (*remainder) ^= Zero();
1241 return;
1242 }
1243
1244 // High level description:
1245 // The algorithm is basically the algorithm that is taught in school:
1246 // Let a the dividend and b the divisor. We are looking for
1247 // the quotient q = truncate(a / b), and
1248 // the remainder r = a - q * b.
1249 // School algorithm:
1250 // q = 0
1251 // n = number_of_digits(a) - number_of_digits(b)
1252 // for (i = n; i >= 0; i--) {
1253 // Maximize k such that k*y*10^i is less than or equal to a and
1254 // (k + 1)*y*10^i is greater.
1255 // q = q + k * 10^i // Add new digit to result.
1256 // a = a - k * b * 10^i
1257 // }
1258 // r = a
1259 //
1260 // Instead of working in base 10 we work in base kDigitBitSize.
1261
1262 intptr_t b_length = b.Length();
1263 int normalization_shift =
1264 kDigitBitSize - CountBits(b.GetChunkAt(b_length - 1));
1265 Bigint& dividend = Bigint::Handle(ShiftLeft(a, normalization_shift));
1266 const Bigint& divisor = Bigint::Handle(ShiftLeft(b, normalization_shift));
1267 dividend.SetSign(false);
1268 divisor.SetSign(false);
1269
1270 intptr_t dividend_length = dividend.Length();
1271 intptr_t divisor_length = b_length;
1272 ASSERT(divisor_length == divisor.Length());
1273
1274 intptr_t quotient_length = dividend_length - divisor_length + 1;
1275 *quotient ^= Bigint::Allocate(quotient_length);
1276 quotient->SetSign(a.IsNegative() != b.IsNegative());
1277
1278 intptr_t quotient_pos = dividend_length - divisor_length;
1279 // Find the first quotient-digit.
1280 // The first digit must be computed separately from the other digits because
1281 // the preconditions for the loop are not yet satisfied.
1282 // For simplicity use a shifted divisor, so that the comparison and
1283 // subtraction are easier.
1284 int divisor_shift_amount = dividend_length - divisor_length;
1285 Bigint& shifted_divisor =
1286 Bigint::Handle(DigitsShiftLeft(divisor, divisor_shift_amount));
1287 Chunk first_quotient_digit = 0;
1288 while (UnsignedCompare(dividend, shifted_divisor) >= 0) {
1289 first_quotient_digit++;
1290 dividend ^= Subtract(dividend, shifted_divisor);
1291 }
1292 quotient->SetChunkAt(quotient_pos--, first_quotient_digit);
1293
1294 // Find the remainder of the digits.
1295
1296 Chunk first_divisor_digit = divisor.GetChunkAt(divisor_length - 1);
1297 // The short divisor only represents the first two digits of the divisor.
1298 // If the divisor has only one digit, then the second part is zeroed out.
1299 Bigint& short_divisor = Bigint::Handle(Bigint::Allocate(2));
1300 if (divisor_length > 1) {
1301 short_divisor.SetChunkAt(0, divisor.GetChunkAt(divisor_length - 2));
1302 } else {
1303 short_divisor.SetChunkAt(0, 0);
1304 }
1305 short_divisor.SetChunkAt(1, first_divisor_digit);
1306 // The following bigint will be used inside the loop. It is allocated outside
1307 // the loop to avoid repeated allocations.
1308 Bigint& target = Bigint::Handle(Bigint::Allocate(3));
1309 // The dividend_length here must be from the initial dividend.
1310 for (intptr_t i = dividend_length - 1; i >= divisor_length; i--) {
1311 // Invariant: let t = i - divisor_length
1312 // then dividend / (divisor << (t * kDigitBitSize)) <= kDigitMaxValue.
1313 // Ex: dividend: 53451232, and divisor: 535 (with t == 5) is ok.
1314 // dividend: 56822123, and divisor: 563 (with t == 5) is bad.
1315 // dividend: 6822123, and divisor: 563 (with t == 5) is ok.
1316
1317 // The dividend has changed. So recompute its length.
1318 dividend_length = dividend.Length();
1319 Chunk dividend_digit;
1320 if (i > dividend_length) {
1321 quotient->SetChunkAt(quotient_pos--, 0);
1322 continue;
1323 } else if (i == dividend_length) {
1324 dividend_digit = 0;
494 } else { 1325 } else {
495 n = Utils::Minimum(a.NumberOfBits(), b.NumberOfBits()); 1326 ASSERT(i + 1 == dividend_length);
496 } 1327 dividend_digit = dividend.GetChunkAt(i);
497 } else if (a.IsNegative() || b.IsNegative()) { 1328 }
498 if (tt[2]) { 1329 Chunk quotient_digit;
499 rflip = rborrow = -1; 1330 // Compute an estimate of the quotient_digit. The estimate will never
500 } 1331 // be too small.
501 n = Utils::Maximum(a.NumberOfBits(), b.NumberOfBits()); 1332 if (dividend_digit == first_divisor_digit) {
502 } else { 1333 // Small shortcut: the else-branch would compute a value > kDigitMaxValue.
503 if (tt[2]) { 1334 // However, by hypothesis, we know that the quotient_digit must fit into
504 n = Utils::Maximum(a.NumberOfBits(), b.NumberOfBits()); 1335 // a digit. Avoid going through repeated iterations of the adjustment
1336 // loop by directly assigning kDigitMaxValue to the quotient_digit.
1337 // Ex: 51235 / 523.
1338 // 51 / 5 would yield 10 (if computed in the else branch).
1339 // However we know that 9 is the maximal value.
1340 quotient_digit = kDigitMaxValue;
505 } else { 1341 } else {
506 n = Utils::Minimum(a.NumberOfBits(), b.NumberOfBits()); 1342 // Compute the estimate by using two digits of the dividend and one of
507 } 1343 // the divisor.
508 } 1344 // Ex: 32421 / 535
509 bool aflip = false; 1345 // 32 / 5 -> 6
510 int acarry = 0; 1346 // The estimate would hence be 6.
511 if (a.IsNegative()) { 1347 DoubleChunk two_dividend_digits = dividend_digit;
512 aflip = true; 1348 two_dividend_digits <<= kDigitBitSize;
513 acarry = 1; 1349 two_dividend_digits += dividend.GetChunkAt(i - 1);
514 } 1350 DoubleChunk q = two_dividend_digits / first_divisor_digit;
515 bool bflip = false; 1351 if (q > kDigitMaxValue) q = kDigitMaxValue;
516 int bcarry = 0; 1352 quotient_digit = static_cast<Chunk>(q);
517 if (b.IsNegative()) { 1353 }
518 bflip = true; 1354
519 bcarry = 1; 1355 // Refine estimation.
520 } 1356 quotient_digit++; // The following loop will start by decrementing.
521 for (int i = 0 ; i < n ; ++i) { 1357 Bigint& estimation_product = Bigint::Handle();
522 int ab = (a.Bit(i) ^ (aflip ? 1 : 0)) + acarry; 1358 target.SetChunkAt(0, ((i - 2) < 0) ? 0 : dividend.GetChunkAt(i - 2));
523 ASSERT(ab <= 2 && ab >= 0); 1359 target.SetChunkAt(1, ((i - 1) < 0) ? 0 : dividend.GetChunkAt(i - 1));
524 int bb = (b.Bit(i) ^ (bflip ? 1 : 0)) + bcarry; 1360 target.SetChunkAt(2, dividend_digit);
525 ASSERT(bb <= 2 && bb >= 0); 1361 do {
526 int r = tt[(ab & 1) + ((bb & 1) << 1)]; 1362 quotient_digit = (quotient_digit - 1) & kDigitMask;
527 r = r + rborrow; 1363 estimation_product ^= MultiplyWithDigit(short_divisor, quotient_digit);
528 ASSERT(r >= -1 && r <= 1); 1364 } while (UnsignedCompareNonClamped(estimation_product, target) > 0);
529 if ((r ^ rflip) & 1) { 1365 // At this point the quotient_digit is fairly accurate.
530 int status = BN_set_bit(TmpBN(), i); 1366 // At the worst it is off by one.
531 ASSERT(status == 1); 1367 // Remove a multiple of the divisor. If the estimate is incorrect we will
532 } 1368 // subtract the divisor another time.
533 acarry = ab >> 1; 1369 // Let t = i - divisor_length.
534 bcarry = bb >> 1; 1370 // dividend -= (quotient_digit * divisor) << (t * kDigitBitSize);
535 rborrow = r >> 1; 1371 shifted_divisor ^= MultiplyWithDigit(divisor, quotient_digit);
536 } 1372 shifted_divisor ^= DigitsShiftLeft(shifted_divisor, i - divisor_length);
537 if (rborrow) { 1373 dividend = Subtract(dividend, shifted_divisor);
538 int status = BN_set_bit(TmpBN(), n); 1374 if (dividend.IsNegative()) {
539 ASSERT(status == 1); 1375 // The estimation was still too big.
540 } 1376 quotient_digit--;
541 if (rflip) { 1377 // TODO(floitsch): allocate space for the shifted_divisor once and reuse
542 // FIXME(benl): can be changed to use BN_set_negative() on more 1378 // it at every iteration.
543 // recent OpenSSL releases (> 1.0.0). 1379 shifted_divisor ^= DigitsShiftLeft(divisor, i - divisor_length);
544 ASSERT(!BN_is_zero(TmpBN())); 1380 // TODO(floitsch): reuse the space of the previous dividend.
545 TmpBN()->neg = 1; 1381 dividend = Add(dividend, shifted_divisor);
546 } 1382 }
547 const Bigint& result = Bigint::Handle(Bigint::New(TmpBN())); 1383 quotient->SetChunkAt(quotient_pos--, quotient_digit);
548 return result.raw(); 1384 }
549 } 1385 ASSERT(quotient_pos == -1);
550 1386 Clamp(*quotient);
551 1387 *remainder ^= ShiftRight(dividend, normalization_shift);
552 RawSmi* BigintOperations::BitOpWithSmi(Token::Kind kind, 1388 remainder->SetSign(a.IsNegative());
553 const Bigint& bigint, 1389 }
554 const Smi& smi) { 1390
555 ASSERT((kind == Token::kBIT_OR) || (kind == Token::kBIT_AND)); 1391
556 intptr_t smi_value = smi.Value(); 1392 void BigintOperations::Clamp(const Bigint& bigint) {
557 intptr_t big_value = 0; 1393 intptr_t length = bigint.Length();
558 // We take Smi::kBits + 1 (one more bit), in case bigint is negative. 1394 while (length > 0 && (bigint.GetChunkAt(length - 1) == 0)) {
559 ASSERT((Smi::kBits + 1) <= (sizeof(big_value) * kBitsPerByte)); 1395 length--;
560 intptr_t num_bits = bigint.NumberOfBits(); 1396 }
561 int n = Utils::Minimum(num_bits, Smi::kBits + 1); 1397 // TODO(floitsch): We change the size of bigint-objects here.
562 for (int i = n - 1; i >= 0; i--) { 1398 bigint.SetLength(length);
563 big_value <<= 1; 1399 }
564 big_value += bigint.Bit(i); 1400
565 } 1401
566 if (bigint.IsNegative()) { 1402 RawBigint* BigintOperations::Copy(const Bigint& bigint) {
567 big_value = -big_value; 1403 intptr_t bigint_length = bigint.Length();
568 } 1404 Bigint& copy = Bigint::Handle(Bigint::Allocate(bigint_length));
569 intptr_t result; 1405 for (intptr_t i = 0; i < bigint_length; i++) {
570 if (kind == Token::kBIT_OR) { 1406 copy.SetChunkAt(i, bigint.GetChunkAt(i));
571 result = smi_value | big_value; 1407 }
572 } else { 1408 copy.SetSign(bigint.IsNegative());
573 result = smi_value & big_value; 1409 return copy.raw();
574 } 1410 }
575 ASSERT(Smi::IsValid(result)); 1411
576 return Smi::New(result); 1412
577 } 1413 int BigintOperations::CountBits(Chunk digit) {
578 1414 int result = 0;
579 1415 while (digit != 0) {
580 RawBigint* BigintOperations::BitAnd(const Bigint& a, const Bigint& b) { 1416 digit >>= 1;
581 static bool tt_and[] = { false, false, false, true }; 1417 result++;
582 return BitTT(a, b, tt_and); 1418 }
583 } 1419 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 } 1420 }
636 1421
637 } // namespace dart 1422 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698