File: | out/../deps/v8/src/objects/bigint.cc |
Warning: | line 1103, column 57 The result of the left shift is undefined due to shifting by '65', which is greater or equal to the width of type 'uint64_t' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | // Copyright 2017 the V8 project authors. All rights reserved. | |||
2 | // Use of this source code is governed by a BSD-style license that can be | |||
3 | // found in the LICENSE file. | |||
4 | ||||
5 | // Parts of the implementation below: | |||
6 | ||||
7 | // Copyright (c) 2014 the Dart project authors. Please see the AUTHORS file [1] | |||
8 | // for details. All rights reserved. Use of this source code is governed by a | |||
9 | // BSD-style license that can be found in the LICENSE file [2]. | |||
10 | // | |||
11 | // [1] https://github.com/dart-lang/sdk/blob/master/AUTHORS | |||
12 | // [2] https://github.com/dart-lang/sdk/blob/master/LICENSE | |||
13 | ||||
14 | // Copyright 2009 The Go Authors. All rights reserved. | |||
15 | // Use of this source code is governed by a BSD-style | |||
16 | // license that can be found in the LICENSE file [3]. | |||
17 | // | |||
18 | // [3] https://golang.org/LICENSE | |||
19 | ||||
20 | #include "src/objects/bigint.h" | |||
21 | ||||
22 | #include "src/base/numbers/double.h" | |||
23 | #include "src/bigint/bigint.h" | |||
24 | #include "src/execution/isolate-inl.h" | |||
25 | #include "src/heap/factory.h" | |||
26 | #include "src/heap/heap-write-barrier-inl.h" | |||
27 | #include "src/numbers/conversions.h" | |||
28 | #include "src/objects/heap-number-inl.h" | |||
29 | #include "src/objects/instance-type-inl.h" | |||
30 | #include "src/objects/objects-inl.h" | |||
31 | #include "src/objects/smi.h" | |||
32 | ||||
33 | namespace v8 { | |||
34 | namespace internal { | |||
35 | ||||
36 | // The MutableBigInt class is an implementation detail designed to prevent | |||
37 | // accidental mutation of a BigInt after its construction. Step-by-step | |||
38 | // construction of a BigInt must happen in terms of MutableBigInt, the | |||
39 | // final result is then passed through MutableBigInt::MakeImmutable and not | |||
40 | // modified further afterwards. | |||
41 | // Many of the functions in this class use arguments of type {BigIntBase}, | |||
42 | // indicating that they will be used in a read-only capacity, and both | |||
43 | // {BigInt} and {MutableBigInt} objects can be passed in. | |||
44 | class MutableBigInt : public FreshlyAllocatedBigInt { | |||
45 | public: | |||
46 | // Bottleneck for converting MutableBigInts to BigInts. | |||
47 | static MaybeHandle<BigInt> MakeImmutable(MaybeHandle<MutableBigInt> maybe); | |||
48 | template <typename Isolate = v8::internal::Isolate> | |||
49 | static Handle<BigInt> MakeImmutable(Handle<MutableBigInt> result); | |||
50 | ||||
51 | static void Canonicalize(MutableBigInt result); | |||
52 | ||||
53 | // Allocation helpers. | |||
54 | template <typename IsolateT> | |||
55 | static MaybeHandle<MutableBigInt> New( | |||
56 | IsolateT* isolate, int length, | |||
57 | AllocationType allocation = AllocationType::kYoung); | |||
58 | static Handle<BigInt> NewFromInt(Isolate* isolate, int value); | |||
59 | static Handle<BigInt> NewFromDouble(Isolate* isolate, double value); | |||
60 | void InitializeDigits(int length, byte value = 0); | |||
61 | static Handle<MutableBigInt> Copy(Isolate* isolate, | |||
62 | Handle<BigIntBase> source); | |||
63 | template <typename IsolateT> | |||
64 | static Handle<BigInt> Zero( | |||
65 | IsolateT* isolate, AllocationType allocation = AllocationType::kYoung) { | |||
66 | // TODO(jkummerow): Consider caching a canonical zero-BigInt. | |||
67 | return MakeImmutable<IsolateT>( | |||
68 | New(isolate, 0, allocation).ToHandleChecked()); | |||
69 | } | |||
70 | ||||
71 | static Handle<MutableBigInt> Cast(Handle<FreshlyAllocatedBigInt> bigint) { | |||
72 | SLOW_DCHECK(bigint->IsBigInt())((void)0); | |||
73 | return Handle<MutableBigInt>::cast(bigint); | |||
74 | } | |||
75 | static MutableBigInt cast(Object o) { | |||
76 | SLOW_DCHECK(o.IsBigInt())((void)0); | |||
77 | return MutableBigInt(o.ptr()); | |||
78 | } | |||
79 | static MutableBigInt unchecked_cast(Object o) { | |||
80 | return MutableBigInt(o.ptr()); | |||
81 | } | |||
82 | ||||
83 | // Internal helpers. | |||
84 | static MaybeHandle<MutableBigInt> AbsoluteAddOne( | |||
85 | Isolate* isolate, Handle<BigIntBase> x, bool sign, | |||
86 | MutableBigInt result_storage = MutableBigInt()); | |||
87 | static Handle<MutableBigInt> AbsoluteSubOne(Isolate* isolate, | |||
88 | Handle<BigIntBase> x); | |||
89 | ||||
90 | // Specialized helpers for shift operations. | |||
91 | static MaybeHandle<BigInt> LeftShiftByAbsolute(Isolate* isolate, | |||
92 | Handle<BigIntBase> x, | |||
93 | Handle<BigIntBase> y); | |||
94 | static Handle<BigInt> RightShiftByAbsolute(Isolate* isolate, | |||
95 | Handle<BigIntBase> x, | |||
96 | Handle<BigIntBase> y); | |||
97 | static Handle<BigInt> RightShiftByMaximum(Isolate* isolate, bool sign); | |||
98 | static Maybe<digit_t> ToShiftAmount(Handle<BigIntBase> x); | |||
99 | ||||
100 | static double ToDouble(Handle<BigIntBase> x); | |||
101 | enum Rounding { kRoundDown, kTie, kRoundUp }; | |||
102 | static Rounding DecideRounding(Handle<BigIntBase> x, int mantissa_bits_unset, | |||
103 | int digit_index, uint64_t current_digit); | |||
104 | ||||
105 | // Returns the least significant 64 bits, simulating two's complement | |||
106 | // representation. | |||
107 | static uint64_t GetRawBits(BigIntBase x, bool* lossless); | |||
108 | ||||
109 | static inline bool digit_ismax(digit_t x) { | |||
110 | return static_cast<digit_t>(~x) == 0; | |||
111 | } | |||
112 | ||||
113 | // Internal field setters. Non-mutable BigInts don't have these. | |||
114 | #include "src/objects/object-macros.h" | |||
115 | inline void set_sign(bool new_sign) { | |||
116 | int32_t bitfield = RELAXED_READ_INT32_FIELD(*this, kBitfieldOffset); | |||
117 | bitfield = SignBits::update(bitfield, new_sign); | |||
118 | RELAXED_WRITE_INT32_FIELD(*this, kBitfieldOffset, bitfield); | |||
119 | } | |||
120 | inline void set_length(int new_length, ReleaseStoreTag) { | |||
121 | int32_t bitfield = RELAXED_READ_INT32_FIELD(*this, kBitfieldOffset); | |||
122 | bitfield = LengthBits::update(bitfield, new_length); | |||
123 | RELEASE_WRITE_INT32_FIELD(*this, kBitfieldOffset, bitfield); | |||
124 | } | |||
125 | inline void initialize_bitfield(bool sign, int length) { | |||
126 | int32_t bitfield = LengthBits::encode(length) | SignBits::encode(sign); | |||
127 | WriteField<int32_t>(kBitfieldOffset, bitfield); | |||
128 | } | |||
129 | inline void set_digit(int n, digit_t value) { | |||
130 | SLOW_DCHECK(0 <= n && n < length())((void)0); | |||
131 | WriteField<digit_t>(kDigitsOffset + n * kDigitSize, value); | |||
132 | } | |||
133 | ||||
134 | void set_64_bits(uint64_t bits); | |||
135 | ||||
136 | bool IsMutableBigInt() const { return IsBigInt(); } | |||
137 | ||||
138 | static_assert(std::is_same<bigint::digit_t, BigIntBase::digit_t>::value, | |||
139 | "We must be able to call BigInt library functions"); | |||
140 | ||||
141 | NEVER_READ_ONLY_SPACE | |||
142 | ||||
143 | OBJECT_CONSTRUCTORS(MutableBigInt, FreshlyAllocatedBigInt); | |||
144 | }; | |||
145 | ||||
146 | OBJECT_CONSTRUCTORS_IMPL(MutableBigInt, FreshlyAllocatedBigInt) | |||
147 | NEVER_READ_ONLY_SPACE_IMPL(MutableBigInt) | |||
148 | ||||
149 | #include "src/base/platform/wrappers.h" | |||
150 | #include "src/objects/object-macros-undef.h" | |||
151 | ||||
152 | bigint::Digits GetDigits(BigIntBase bigint) { | |||
153 | return bigint::Digits( | |||
154 | reinterpret_cast<bigint::digit_t*>( | |||
155 | bigint.ptr() + BigIntBase::kDigitsOffset - kHeapObjectTag), | |||
156 | bigint.length()); | |||
157 | } | |||
158 | bigint::Digits GetDigits(Handle<BigIntBase> bigint) { | |||
159 | return GetDigits(*bigint); | |||
160 | } | |||
161 | ||||
162 | bigint::RWDigits GetRWDigits(MutableBigInt bigint) { | |||
163 | return bigint::RWDigits( | |||
164 | reinterpret_cast<bigint::digit_t*>( | |||
165 | bigint.ptr() + BigIntBase::kDigitsOffset - kHeapObjectTag), | |||
166 | bigint.length()); | |||
167 | } | |||
168 | bigint::RWDigits GetRWDigits(Handle<MutableBigInt> bigint) { | |||
169 | return GetRWDigits(*bigint); | |||
170 | } | |||
171 | ||||
172 | template <typename T, typename Isolate> | |||
173 | MaybeHandle<T> ThrowBigIntTooBig(Isolate* isolate) { | |||
174 | // If the result of a BigInt computation is truncated to 64 bit, Turbofan | |||
175 | // can sometimes truncate intermediate results already, which can prevent | |||
176 | // those from exceeding the maximum length, effectively preventing a | |||
177 | // RangeError from being thrown. As this is a performance optimization, this | |||
178 | // behavior is accepted. To prevent the correctness fuzzer from detecting this | |||
179 | // difference, we crash the program. | |||
180 | if (FLAG_correctness_fuzzer_suppressions) { | |||
181 | FATAL("Aborting on invalid BigInt length")V8_Fatal("Aborting on invalid BigInt length"); | |||
182 | } | |||
183 | THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kBigIntTooBig), T)do { auto* __isolate__ = (isolate); return __isolate__->template Throw<T>(__isolate__->factory()->NewRangeError(MessageTemplate ::kBigIntTooBig)); } while (false); | |||
184 | } | |||
185 | ||||
186 | template <typename IsolateT> | |||
187 | MaybeHandle<MutableBigInt> MutableBigInt::New(IsolateT* isolate, int length, | |||
188 | AllocationType allocation) { | |||
189 | if (length > BigInt::kMaxLength) { | |||
190 | return ThrowBigIntTooBig<MutableBigInt>(isolate); | |||
191 | } | |||
192 | Handle<MutableBigInt> result = | |||
193 | Cast(isolate->factory()->NewBigInt(length, allocation)); | |||
194 | result->initialize_bitfield(false, length); | |||
195 | #if DEBUG | |||
196 | result->InitializeDigits(length, 0xBF); | |||
197 | #endif | |||
198 | return result; | |||
199 | } | |||
200 | ||||
201 | Handle<BigInt> MutableBigInt::NewFromInt(Isolate* isolate, int value) { | |||
202 | if (value == 0) return Zero(isolate); | |||
203 | Handle<MutableBigInt> result = Cast(isolate->factory()->NewBigInt(1)); | |||
204 | bool sign = value < 0; | |||
205 | result->initialize_bitfield(sign, 1); | |||
206 | if (!sign) { | |||
207 | result->set_digit(0, value); | |||
208 | } else { | |||
209 | if (value == kMinInt) { | |||
210 | STATIC_ASSERT(kMinInt == -kMaxInt - 1)static_assert(kMinInt == -kMaxInt - 1, "kMinInt == -kMaxInt - 1" ); | |||
211 | result->set_digit(0, static_cast<BigInt::digit_t>(kMaxInt) + 1); | |||
212 | } else { | |||
213 | result->set_digit(0, -value); | |||
214 | } | |||
215 | } | |||
216 | return MakeImmutable(result); | |||
217 | } | |||
218 | ||||
219 | Handle<BigInt> MutableBigInt::NewFromDouble(Isolate* isolate, double value) { | |||
220 | DCHECK_EQ(value, std::floor(value))((void) 0); | |||
221 | if (value == 0) return Zero(isolate); | |||
222 | ||||
223 | bool sign = value < 0; // -0 was already handled above. | |||
224 | uint64_t double_bits = bit_cast<uint64_t>(value); | |||
225 | int raw_exponent = | |||
226 | static_cast<int>(double_bits >> base::Double::kPhysicalSignificandSize) & | |||
227 | 0x7FF; | |||
228 | DCHECK_NE(raw_exponent, 0x7FF)((void) 0); | |||
229 | DCHECK_GE(raw_exponent, 0x3FF)((void) 0); | |||
230 | int exponent = raw_exponent - 0x3FF; | |||
231 | int digits = exponent / kDigitBits + 1; | |||
232 | Handle<MutableBigInt> result = Cast(isolate->factory()->NewBigInt(digits)); | |||
233 | result->initialize_bitfield(sign, digits); | |||
234 | ||||
235 | // We construct a BigInt from the double {value} by shifting its mantissa | |||
236 | // according to its exponent and mapping the bit pattern onto digits. | |||
237 | // | |||
238 | // <----------- bitlength = exponent + 1 -----------> | |||
239 | // <----- 52 ------> <------ trailing zeroes ------> | |||
240 | // mantissa: 1yyyyyyyyyyyyyyyyy 0000000000000000000000000000000 | |||
241 | // digits: 0001xxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | |||
242 | // <--> <------> | |||
243 | // msd_topbit kDigitBits | |||
244 | // | |||
245 | uint64_t mantissa = | |||
246 | (double_bits & base::Double::kSignificandMask) | base::Double::kHiddenBit; | |||
247 | const int kMantissaTopBit = base::Double::kSignificandSize - 1; // 0-indexed. | |||
248 | // 0-indexed position of most significant bit in the most significant digit. | |||
249 | int msd_topbit = exponent % kDigitBits; | |||
250 | // Number of unused bits in {mantissa}. We'll keep them shifted to the | |||
251 | // left (i.e. most significant part) of the underlying uint64_t. | |||
252 | int remaining_mantissa_bits = 0; | |||
253 | // Next digit under construction. | |||
254 | digit_t digit; | |||
255 | ||||
256 | // First, build the MSD by shifting the mantissa appropriately. | |||
257 | if (msd_topbit < kMantissaTopBit) { | |||
258 | remaining_mantissa_bits = kMantissaTopBit - msd_topbit; | |||
259 | digit = mantissa >> remaining_mantissa_bits; | |||
260 | mantissa = mantissa << (64 - remaining_mantissa_bits); | |||
261 | } else { | |||
262 | DCHECK_GE(msd_topbit, kMantissaTopBit)((void) 0); | |||
263 | digit = mantissa << (msd_topbit - kMantissaTopBit); | |||
264 | mantissa = 0; | |||
265 | } | |||
266 | result->set_digit(digits - 1, digit); | |||
267 | // Then fill in the rest of the digits. | |||
268 | for (int digit_index = digits - 2; digit_index >= 0; digit_index--) { | |||
269 | if (remaining_mantissa_bits > 0) { | |||
270 | remaining_mantissa_bits -= kDigitBits; | |||
271 | if (sizeof(digit) == 4) { | |||
272 | digit = mantissa >> 32; | |||
273 | mantissa = mantissa << 32; | |||
274 | } else { | |||
275 | DCHECK_EQ(sizeof(digit), 8)((void) 0); | |||
276 | digit = mantissa; | |||
277 | mantissa = 0; | |||
278 | } | |||
279 | } else { | |||
280 | digit = 0; | |||
281 | } | |||
282 | result->set_digit(digit_index, digit); | |||
283 | } | |||
284 | return MakeImmutable(result); | |||
285 | } | |||
286 | ||||
287 | Handle<MutableBigInt> MutableBigInt::Copy(Isolate* isolate, | |||
288 | Handle<BigIntBase> source) { | |||
289 | int length = source->length(); | |||
290 | // Allocating a BigInt of the same length as an existing BigInt cannot throw. | |||
291 | Handle<MutableBigInt> result = New(isolate, length).ToHandleChecked(); | |||
292 | memcpy(reinterpret_cast<void*>(result->address() + BigIntBase::kHeaderSize), | |||
293 | reinterpret_cast<void*>(source->address() + BigIntBase::kHeaderSize), | |||
294 | BigInt::SizeFor(length) - BigIntBase::kHeaderSize); | |||
295 | return result; | |||
296 | } | |||
297 | ||||
298 | void MutableBigInt::InitializeDigits(int length, byte value) { | |||
299 | memset(reinterpret_cast<void*>(ptr() + kDigitsOffset - kHeapObjectTag), value, | |||
300 | length * kDigitSize); | |||
301 | } | |||
302 | ||||
303 | MaybeHandle<BigInt> MutableBigInt::MakeImmutable( | |||
304 | MaybeHandle<MutableBigInt> maybe) { | |||
305 | Handle<MutableBigInt> result; | |||
306 | if (!maybe.ToHandle(&result)) return MaybeHandle<BigInt>(); | |||
307 | return MakeImmutable(result); | |||
308 | } | |||
309 | ||||
310 | template <typename IsolateT> | |||
311 | Handle<BigInt> MutableBigInt::MakeImmutable(Handle<MutableBigInt> result) { | |||
312 | MutableBigInt::Canonicalize(*result); | |||
313 | return Handle<BigInt>::cast(result); | |||
314 | } | |||
315 | ||||
316 | void MutableBigInt::Canonicalize(MutableBigInt result) { | |||
317 | // Check if we need to right-trim any leading zero-digits. | |||
318 | int old_length = result.length(); | |||
319 | int new_length = old_length; | |||
320 | while (new_length > 0 && result.digit(new_length - 1) == 0) new_length--; | |||
321 | int to_trim = old_length - new_length; | |||
322 | if (to_trim != 0) { | |||
323 | int size_delta = to_trim * MutableBigInt::kDigitSize; | |||
324 | Address new_end = result.address() + BigInt::SizeFor(new_length); | |||
325 | Heap* heap = result.GetHeap(); | |||
326 | if (!heap->IsLargeObject(result)) { | |||
327 | // We do not create a filler for objects in large object space. | |||
328 | // TODO(hpayer): We should shrink the large object page if the size | |||
329 | // of the object changed significantly. | |||
330 | heap->CreateFillerObjectAt(new_end, size_delta, ClearRecordedSlots::kNo); | |||
331 | } | |||
332 | result.set_length(new_length, kReleaseStore); | |||
333 | ||||
334 | // Canonicalize -0n. | |||
335 | if (new_length == 0) { | |||
336 | result.set_sign(false); | |||
337 | // TODO(jkummerow): If we cache a canonical 0n, return that here. | |||
338 | } | |||
339 | } | |||
340 | DCHECK_IMPLIES(result.length() > 0,((void) 0) | |||
341 | result.digit(result.length() - 1) != 0)((void) 0); // MSD is non-zero. | |||
342 | } | |||
343 | ||||
344 | template <typename IsolateT> | |||
345 | Handle<BigInt> BigInt::Zero(IsolateT* isolate, AllocationType allocation) { | |||
346 | return MutableBigInt::Zero(isolate, allocation); | |||
347 | } | |||
348 | template Handle<BigInt> BigInt::Zero(Isolate* isolate, | |||
349 | AllocationType allocation); | |||
350 | template Handle<BigInt> BigInt::Zero(LocalIsolate* isolate, | |||
351 | AllocationType allocation); | |||
352 | ||||
353 | Handle<BigInt> BigInt::UnaryMinus(Isolate* isolate, Handle<BigInt> x) { | |||
354 | // Special case: There is no -0n. | |||
355 | if (x->is_zero()) { | |||
356 | return x; | |||
357 | } | |||
358 | Handle<MutableBigInt> result = MutableBigInt::Copy(isolate, x); | |||
359 | result->set_sign(!x->sign()); | |||
360 | return MutableBigInt::MakeImmutable(result); | |||
361 | } | |||
362 | ||||
363 | MaybeHandle<BigInt> BigInt::BitwiseNot(Isolate* isolate, Handle<BigInt> x) { | |||
364 | MaybeHandle<MutableBigInt> result; | |||
365 | if (x->sign()) { | |||
366 | // ~(-x) == ~(~(x-1)) == x-1 | |||
367 | result = MutableBigInt::AbsoluteSubOne(isolate, x); | |||
368 | } else { | |||
369 | // ~x == -x-1 == -(x+1) | |||
370 | result = MutableBigInt::AbsoluteAddOne(isolate, x, true); | |||
371 | } | |||
372 | return MutableBigInt::MakeImmutable(result); | |||
373 | } | |||
374 | ||||
375 | MaybeHandle<BigInt> BigInt::Exponentiate(Isolate* isolate, Handle<BigInt> base, | |||
376 | Handle<BigInt> exponent) { | |||
377 | // 1. If exponent is < 0, throw a RangeError exception. | |||
378 | if (exponent->sign()) { | |||
379 | THROW_NEW_ERROR(isolate,do { auto* __isolate__ = (isolate); return __isolate__->template Throw<BigInt>(__isolate__->factory()->NewRangeError (MessageTemplate::kBigIntNegativeExponent)); } while (false) | |||
380 | NewRangeError(MessageTemplate::kBigIntNegativeExponent),do { auto* __isolate__ = (isolate); return __isolate__->template Throw<BigInt>(__isolate__->factory()->NewRangeError (MessageTemplate::kBigIntNegativeExponent)); } while (false) | |||
381 | BigInt)do { auto* __isolate__ = (isolate); return __isolate__->template Throw<BigInt>(__isolate__->factory()->NewRangeError (MessageTemplate::kBigIntNegativeExponent)); } while (false); | |||
382 | } | |||
383 | // 2. If base is 0n and exponent is 0n, return 1n. | |||
384 | if (exponent->is_zero()) { | |||
385 | return MutableBigInt::NewFromInt(isolate, 1); | |||
386 | } | |||
387 | // 3. Return a BigInt representing the mathematical value of base raised | |||
388 | // to the power exponent. | |||
389 | if (base->is_zero()) return base; | |||
390 | if (base->length() == 1 && base->digit(0) == 1) { | |||
391 | // (-1) ** even_number == 1. | |||
392 | if (base->sign() && (exponent->digit(0) & 1) == 0) { | |||
393 | return UnaryMinus(isolate, base); | |||
394 | } | |||
395 | // (-1) ** odd_number == -1; 1 ** anything == 1. | |||
396 | return base; | |||
397 | } | |||
398 | // For all bases >= 2, very large exponents would lead to unrepresentable | |||
399 | // results. | |||
400 | STATIC_ASSERT(kMaxLengthBits < std::numeric_limits<digit_t>::max())static_assert(kMaxLengthBits < std::numeric_limits<digit_t >::max(), "kMaxLengthBits < std::numeric_limits<digit_t>::max()" ); | |||
401 | if (exponent->length() > 1) { | |||
402 | return ThrowBigIntTooBig<BigInt>(isolate); | |||
403 | } | |||
404 | digit_t exp_value = exponent->digit(0); | |||
405 | if (exp_value == 1) return base; | |||
406 | if (exp_value >= kMaxLengthBits) { | |||
407 | return ThrowBigIntTooBig<BigInt>(isolate); | |||
408 | } | |||
409 | STATIC_ASSERT(kMaxLengthBits <= kMaxInt)static_assert(kMaxLengthBits <= kMaxInt, "kMaxLengthBits <= kMaxInt" ); | |||
410 | int n = static_cast<int>(exp_value); | |||
411 | if (base->length() == 1 && base->digit(0) == 2) { | |||
412 | // Fast path for 2^n. | |||
413 | int needed_digits = 1 + (n / kDigitBits); | |||
414 | Handle<MutableBigInt> result; | |||
415 | if (!MutableBigInt::New(isolate, needed_digits).ToHandle(&result)) { | |||
416 | return MaybeHandle<BigInt>(); | |||
417 | } | |||
418 | result->InitializeDigits(needed_digits); | |||
419 | // All bits are zero. Now set the n-th bit. | |||
420 | digit_t msd = static_cast<digit_t>(1) << (n % kDigitBits); | |||
421 | result->set_digit(needed_digits - 1, msd); | |||
422 | // Result is negative for odd powers of -2n. | |||
423 | if (base->sign()) result->set_sign((n & 1) != 0); | |||
424 | return MutableBigInt::MakeImmutable(result); | |||
425 | } | |||
426 | Handle<BigInt> result; | |||
427 | Handle<BigInt> running_square = base; | |||
428 | // This implicitly sets the result's sign correctly. | |||
429 | if (n & 1) result = base; | |||
430 | n >>= 1; | |||
431 | for (; n != 0; n >>= 1) { | |||
432 | MaybeHandle<BigInt> maybe_result = | |||
433 | Multiply(isolate, running_square, running_square); | |||
434 | if (!maybe_result.ToHandle(&running_square)) return maybe_result; | |||
435 | if (n & 1) { | |||
436 | if (result.is_null()) { | |||
437 | result = running_square; | |||
438 | } else { | |||
439 | maybe_result = Multiply(isolate, result, running_square); | |||
440 | if (!maybe_result.ToHandle(&result)) return maybe_result; | |||
441 | } | |||
442 | } | |||
443 | } | |||
444 | return result; | |||
445 | } | |||
446 | ||||
447 | MaybeHandle<BigInt> BigInt::Multiply(Isolate* isolate, Handle<BigInt> x, | |||
448 | Handle<BigInt> y) { | |||
449 | if (x->is_zero()) return x; | |||
450 | if (y->is_zero()) return y; | |||
451 | int result_length = bigint::MultiplyResultLength(GetDigits(x), GetDigits(y)); | |||
452 | Handle<MutableBigInt> result; | |||
453 | if (!MutableBigInt::New(isolate, result_length).ToHandle(&result)) { | |||
454 | return MaybeHandle<BigInt>(); | |||
455 | } | |||
456 | DisallowGarbageCollection no_gc; | |||
457 | bigint::Status status = isolate->bigint_processor()->Multiply( | |||
458 | GetRWDigits(result), GetDigits(x), GetDigits(y)); | |||
459 | if (status == bigint::Status::kInterrupted) { | |||
460 | AllowGarbageCollection terminating_anyway; | |||
461 | isolate->TerminateExecution(); | |||
462 | return {}; | |||
463 | } | |||
464 | result->set_sign(x->sign() != y->sign()); | |||
465 | return MutableBigInt::MakeImmutable(result); | |||
466 | } | |||
467 | ||||
468 | MaybeHandle<BigInt> BigInt::Divide(Isolate* isolate, Handle<BigInt> x, | |||
469 | Handle<BigInt> y) { | |||
470 | // 1. If y is 0n, throw a RangeError exception. | |||
471 | if (y->is_zero()) { | |||
472 | THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kBigIntDivZero),do { auto* __isolate__ = (isolate); return __isolate__->template Throw<BigInt>(__isolate__->factory()->NewRangeError (MessageTemplate::kBigIntDivZero)); } while (false) | |||
473 | BigInt)do { auto* __isolate__ = (isolate); return __isolate__->template Throw<BigInt>(__isolate__->factory()->NewRangeError (MessageTemplate::kBigIntDivZero)); } while (false); | |||
474 | } | |||
475 | // 2. Let quotient be the mathematical value of x divided by y. | |||
476 | // 3. Return a BigInt representing quotient rounded towards 0 to the next | |||
477 | // integral value. | |||
478 | if (bigint::Compare(GetDigits(x), GetDigits(y)) < 0) { | |||
479 | return Zero(isolate); | |||
480 | } | |||
481 | bool result_sign = x->sign() != y->sign(); | |||
482 | if (y->length() == 1 && y->digit(0) == 1) { | |||
483 | return result_sign == x->sign() ? x : UnaryMinus(isolate, x); | |||
484 | } | |||
485 | Handle<MutableBigInt> quotient; | |||
486 | int result_length = bigint::DivideResultLength(GetDigits(x), GetDigits(y)); | |||
487 | if (!MutableBigInt::New(isolate, result_length).ToHandle("ient)) { | |||
488 | return {}; | |||
489 | } | |||
490 | DisallowGarbageCollection no_gc; | |||
491 | bigint::Status status = isolate->bigint_processor()->Divide( | |||
492 | GetRWDigits(quotient), GetDigits(x), GetDigits(y)); | |||
493 | if (status == bigint::Status::kInterrupted) { | |||
494 | AllowGarbageCollection terminating_anyway; | |||
495 | isolate->TerminateExecution(); | |||
496 | return {}; | |||
497 | } | |||
498 | quotient->set_sign(result_sign); | |||
499 | return MutableBigInt::MakeImmutable(quotient); | |||
500 | } | |||
501 | ||||
502 | MaybeHandle<BigInt> BigInt::Remainder(Isolate* isolate, Handle<BigInt> x, | |||
503 | Handle<BigInt> y) { | |||
504 | // 1. If y is 0n, throw a RangeError exception. | |||
505 | if (y->is_zero()) { | |||
506 | THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kBigIntDivZero),do { auto* __isolate__ = (isolate); return __isolate__->template Throw<BigInt>(__isolate__->factory()->NewRangeError (MessageTemplate::kBigIntDivZero)); } while (false) | |||
507 | BigInt)do { auto* __isolate__ = (isolate); return __isolate__->template Throw<BigInt>(__isolate__->factory()->NewRangeError (MessageTemplate::kBigIntDivZero)); } while (false); | |||
508 | } | |||
509 | // 2. Return the BigInt representing x modulo y. | |||
510 | // See https://github.com/tc39/proposal-bigint/issues/84 though. | |||
511 | if (bigint::Compare(GetDigits(x), GetDigits(y)) < 0) return x; | |||
512 | if (y->length() == 1 && y->digit(0) == 1) return Zero(isolate); | |||
513 | Handle<MutableBigInt> remainder; | |||
514 | int result_length = bigint::ModuloResultLength(GetDigits(y)); | |||
515 | if (!MutableBigInt::New(isolate, result_length).ToHandle(&remainder)) { | |||
516 | return {}; | |||
517 | } | |||
518 | DisallowGarbageCollection no_gc; | |||
519 | bigint::Status status = isolate->bigint_processor()->Modulo( | |||
520 | GetRWDigits(remainder), GetDigits(x), GetDigits(y)); | |||
521 | if (status == bigint::Status::kInterrupted) { | |||
522 | AllowGarbageCollection terminating_anyway; | |||
523 | isolate->TerminateExecution(); | |||
524 | return {}; | |||
525 | } | |||
526 | remainder->set_sign(x->sign()); | |||
527 | return MutableBigInt::MakeImmutable(remainder); | |||
528 | } | |||
529 | ||||
530 | MaybeHandle<BigInt> BigInt::Add(Isolate* isolate, Handle<BigInt> x, | |||
531 | Handle<BigInt> y) { | |||
532 | if (x->is_zero()) return y; | |||
533 | if (y->is_zero()) return x; | |||
534 | bool xsign = x->sign(); | |||
535 | bool ysign = y->sign(); | |||
536 | int result_length = | |||
537 | bigint::AddSignedResultLength(x->length(), y->length(), xsign == ysign); | |||
538 | Handle<MutableBigInt> result; | |||
539 | if (!MutableBigInt::New(isolate, result_length).ToHandle(&result)) { | |||
540 | // Allocation fails when {result_length} exceeds the max BigInt size. | |||
541 | return {}; | |||
542 | } | |||
543 | DisallowGarbageCollection no_gc; | |||
544 | bool result_sign = bigint::AddSigned(GetRWDigits(result), GetDigits(x), xsign, | |||
545 | GetDigits(y), ysign); | |||
546 | result->set_sign(result_sign); | |||
547 | return MutableBigInt::MakeImmutable(result); | |||
548 | } | |||
549 | ||||
550 | MaybeHandle<BigInt> BigInt::Subtract(Isolate* isolate, Handle<BigInt> x, | |||
551 | Handle<BigInt> y) { | |||
552 | if (y->is_zero()) return x; | |||
553 | if (x->is_zero()) return UnaryMinus(isolate, y); | |||
554 | bool xsign = x->sign(); | |||
555 | bool ysign = y->sign(); | |||
556 | int result_length = bigint::SubtractSignedResultLength( | |||
557 | x->length(), y->length(), xsign == ysign); | |||
558 | Handle<MutableBigInt> result; | |||
559 | if (!MutableBigInt::New(isolate, result_length).ToHandle(&result)) { | |||
560 | // Allocation fails when {result_length} exceeds the max BigInt size. | |||
561 | return {}; | |||
562 | } | |||
563 | DisallowGarbageCollection no_gc; | |||
564 | bool result_sign = bigint::SubtractSigned(GetRWDigits(result), GetDigits(x), | |||
565 | xsign, GetDigits(y), ysign); | |||
566 | result->set_sign(result_sign); | |||
567 | return MutableBigInt::MakeImmutable(result); | |||
568 | } | |||
569 | ||||
570 | MaybeHandle<BigInt> BigInt::LeftShift(Isolate* isolate, Handle<BigInt> x, | |||
571 | Handle<BigInt> y) { | |||
572 | if (y->is_zero() || x->is_zero()) return x; | |||
573 | if (y->sign()) return MutableBigInt::RightShiftByAbsolute(isolate, x, y); | |||
574 | return MutableBigInt::LeftShiftByAbsolute(isolate, x, y); | |||
575 | } | |||
576 | ||||
577 | MaybeHandle<BigInt> BigInt::SignedRightShift(Isolate* isolate, Handle<BigInt> x, | |||
578 | Handle<BigInt> y) { | |||
579 | if (y->is_zero() || x->is_zero()) return x; | |||
580 | if (y->sign()) return MutableBigInt::LeftShiftByAbsolute(isolate, x, y); | |||
581 | return MutableBigInt::RightShiftByAbsolute(isolate, x, y); | |||
582 | } | |||
583 | ||||
584 | MaybeHandle<BigInt> BigInt::UnsignedRightShift(Isolate* isolate, | |||
585 | Handle<BigInt> x, | |||
586 | Handle<BigInt> y) { | |||
587 | THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kBigIntShr), BigInt)do { auto* __isolate__ = (isolate); return __isolate__->template Throw<BigInt>(__isolate__->factory()->NewTypeError (MessageTemplate::kBigIntShr)); } while (false); | |||
588 | } | |||
589 | ||||
590 | namespace { | |||
591 | ||||
592 | // Produces comparison result for {left_negative} == sign(x) != sign(y). | |||
593 | ComparisonResult UnequalSign(bool left_negative) { | |||
594 | return left_negative ? ComparisonResult::kLessThan | |||
595 | : ComparisonResult::kGreaterThan; | |||
596 | } | |||
597 | ||||
598 | // Produces result for |x| > |y|, with {both_negative} == sign(x) == sign(y); | |||
599 | ComparisonResult AbsoluteGreater(bool both_negative) { | |||
600 | return both_negative ? ComparisonResult::kLessThan | |||
601 | : ComparisonResult::kGreaterThan; | |||
602 | } | |||
603 | ||||
604 | // Produces result for |x| < |y|, with {both_negative} == sign(x) == sign(y). | |||
605 | ComparisonResult AbsoluteLess(bool both_negative) { | |||
606 | return both_negative ? ComparisonResult::kGreaterThan | |||
607 | : ComparisonResult::kLessThan; | |||
608 | } | |||
609 | ||||
610 | } // namespace | |||
611 | ||||
612 | // (Never returns kUndefined.) | |||
613 | ComparisonResult BigInt::CompareToBigInt(Handle<BigInt> x, Handle<BigInt> y) { | |||
614 | bool x_sign = x->sign(); | |||
615 | if (x_sign != y->sign()) return UnequalSign(x_sign); | |||
616 | ||||
617 | int result = bigint::Compare(GetDigits(x), GetDigits(y)); | |||
618 | if (result > 0) return AbsoluteGreater(x_sign); | |||
619 | if (result < 0) return AbsoluteLess(x_sign); | |||
620 | return ComparisonResult::kEqual; | |||
621 | } | |||
622 | ||||
623 | bool BigInt::EqualToBigInt(BigInt x, BigInt y) { | |||
624 | if (x.sign() != y.sign()) return false; | |||
625 | if (x.length() != y.length()) return false; | |||
626 | for (int i = 0; i < x.length(); i++) { | |||
627 | if (x.digit(i) != y.digit(i)) return false; | |||
628 | } | |||
629 | return true; | |||
630 | } | |||
631 | ||||
632 | MaybeHandle<BigInt> BigInt::BitwiseAnd(Isolate* isolate, Handle<BigInt> x, | |||
633 | Handle<BigInt> y) { | |||
634 | bool x_sign = x->sign(); | |||
635 | bool y_sign = y->sign(); | |||
636 | Handle<MutableBigInt> result; | |||
637 | if (!x_sign && !y_sign) { | |||
638 | int result_length = | |||
639 | bigint::BitwiseAnd_PosPos_ResultLength(x->length(), y->length()); | |||
640 | result = MutableBigInt::New(isolate, result_length).ToHandleChecked(); | |||
641 | bigint::BitwiseAnd_PosPos(GetRWDigits(result), GetDigits(x), GetDigits(y)); | |||
642 | DCHECK(!result->sign())((void) 0); | |||
643 | } else if (x_sign && y_sign) { | |||
644 | int result_length = | |||
645 | bigint::BitwiseAnd_NegNeg_ResultLength(x->length(), y->length()); | |||
646 | if (!MutableBigInt::New(isolate, result_length).ToHandle(&result)) { | |||
647 | return {}; | |||
648 | } | |||
649 | bigint::BitwiseAnd_NegNeg(GetRWDigits(result), GetDigits(x), GetDigits(y)); | |||
650 | result->set_sign(true); | |||
651 | } else { | |||
652 | if (x_sign) std::swap(x, y); | |||
653 | int result_length = bigint::BitwiseAnd_PosNeg_ResultLength(x->length()); | |||
654 | result = MutableBigInt::New(isolate, result_length).ToHandleChecked(); | |||
655 | bigint::BitwiseAnd_PosNeg(GetRWDigits(result), GetDigits(x), GetDigits(y)); | |||
656 | DCHECK(!result->sign())((void) 0); | |||
657 | } | |||
658 | return MutableBigInt::MakeImmutable(result); | |||
659 | } | |||
660 | ||||
661 | MaybeHandle<BigInt> BigInt::BitwiseXor(Isolate* isolate, Handle<BigInt> x, | |||
662 | Handle<BigInt> y) { | |||
663 | bool x_sign = x->sign(); | |||
664 | bool y_sign = y->sign(); | |||
665 | Handle<MutableBigInt> result; | |||
666 | if (!x_sign && !y_sign) { | |||
667 | int result_length = | |||
668 | bigint::BitwiseXor_PosPos_ResultLength(x->length(), y->length()); | |||
669 | result = MutableBigInt::New(isolate, result_length).ToHandleChecked(); | |||
670 | bigint::BitwiseXor_PosPos(GetRWDigits(result), GetDigits(x), GetDigits(y)); | |||
671 | DCHECK(!result->sign())((void) 0); | |||
672 | } else if (x_sign && y_sign) { | |||
673 | int result_length = | |||
674 | bigint::BitwiseXor_NegNeg_ResultLength(x->length(), y->length()); | |||
675 | result = MutableBigInt::New(isolate, result_length).ToHandleChecked(); | |||
676 | bigint::BitwiseXor_NegNeg(GetRWDigits(result), GetDigits(x), GetDigits(y)); | |||
677 | DCHECK(!result->sign())((void) 0); | |||
678 | } else { | |||
679 | if (x_sign) std::swap(x, y); | |||
680 | int result_length = | |||
681 | bigint::BitwiseXor_PosNeg_ResultLength(x->length(), y->length()); | |||
682 | if (!MutableBigInt::New(isolate, result_length).ToHandle(&result)) { | |||
683 | return {}; | |||
684 | } | |||
685 | bigint::BitwiseXor_PosNeg(GetRWDigits(result), GetDigits(x), GetDigits(y)); | |||
686 | result->set_sign(true); | |||
687 | } | |||
688 | return MutableBigInt::MakeImmutable(result); | |||
689 | } | |||
690 | ||||
691 | MaybeHandle<BigInt> BigInt::BitwiseOr(Isolate* isolate, Handle<BigInt> x, | |||
692 | Handle<BigInt> y) { | |||
693 | bool x_sign = x->sign(); | |||
694 | bool y_sign = y->sign(); | |||
695 | int result_length = bigint::BitwiseOrResultLength(x->length(), y->length()); | |||
696 | Handle<MutableBigInt> result = | |||
697 | MutableBigInt::New(isolate, result_length).ToHandleChecked(); | |||
698 | if (!x_sign && !y_sign) { | |||
699 | bigint::BitwiseOr_PosPos(GetRWDigits(result), GetDigits(x), GetDigits(y)); | |||
700 | DCHECK(!result->sign())((void) 0); | |||
701 | } else if (x_sign && y_sign) { | |||
702 | bigint::BitwiseOr_NegNeg(GetRWDigits(result), GetDigits(x), GetDigits(y)); | |||
703 | result->set_sign(true); | |||
704 | } else { | |||
705 | if (x_sign) std::swap(x, y); | |||
706 | bigint::BitwiseOr_PosNeg(GetRWDigits(result), GetDigits(x), GetDigits(y)); | |||
707 | result->set_sign(true); | |||
708 | } | |||
709 | return MutableBigInt::MakeImmutable(result); | |||
710 | } | |||
711 | ||||
712 | MaybeHandle<BigInt> BigInt::Increment(Isolate* isolate, Handle<BigInt> x) { | |||
713 | if (x->sign()) { | |||
714 | Handle<MutableBigInt> result = MutableBigInt::AbsoluteSubOne(isolate, x); | |||
715 | result->set_sign(true); | |||
716 | return MutableBigInt::MakeImmutable(result); | |||
717 | } else { | |||
718 | return MutableBigInt::MakeImmutable( | |||
719 | MutableBigInt::AbsoluteAddOne(isolate, x, false)); | |||
720 | } | |||
721 | } | |||
722 | ||||
723 | MaybeHandle<BigInt> BigInt::Decrement(Isolate* isolate, Handle<BigInt> x) { | |||
724 | MaybeHandle<MutableBigInt> result; | |||
725 | if (x->sign()) { | |||
726 | result = MutableBigInt::AbsoluteAddOne(isolate, x, true); | |||
727 | } else if (x->is_zero()) { | |||
728 | // TODO(jkummerow): Consider caching a canonical -1n BigInt. | |||
729 | return MutableBigInt::NewFromInt(isolate, -1); | |||
730 | } else { | |||
731 | result = MutableBigInt::AbsoluteSubOne(isolate, x); | |||
732 | } | |||
733 | return MutableBigInt::MakeImmutable(result); | |||
734 | } | |||
735 | ||||
736 | Maybe<ComparisonResult> BigInt::CompareToString(Isolate* isolate, | |||
737 | Handle<BigInt> x, | |||
738 | Handle<String> y) { | |||
739 | // a. Let ny be StringToBigInt(y); | |||
740 | MaybeHandle<BigInt> maybe_ny = StringToBigInt(isolate, y); | |||
741 | // b. If ny is NaN, return undefined. | |||
742 | Handle<BigInt> ny; | |||
743 | if (!maybe_ny.ToHandle(&ny)) { | |||
744 | if (isolate->has_pending_exception()) { | |||
745 | return Nothing<ComparisonResult>(); | |||
746 | } else { | |||
747 | return Just(ComparisonResult::kUndefined); | |||
748 | } | |||
749 | } | |||
750 | // c. Return BigInt::lessThan(x, ny). | |||
751 | return Just(CompareToBigInt(x, ny)); | |||
752 | } | |||
753 | ||||
754 | Maybe<bool> BigInt::EqualToString(Isolate* isolate, Handle<BigInt> x, | |||
755 | Handle<String> y) { | |||
756 | // a. Let n be StringToBigInt(y). | |||
757 | MaybeHandle<BigInt> maybe_n = StringToBigInt(isolate, y); | |||
758 | // b. If n is NaN, return false. | |||
759 | Handle<BigInt> n; | |||
760 | if (!maybe_n.ToHandle(&n)) { | |||
761 | if (isolate->has_pending_exception()) { | |||
762 | return Nothing<bool>(); | |||
763 | } else { | |||
764 | return Just(false); | |||
765 | } | |||
766 | } | |||
767 | // c. Return the result of x == n. | |||
768 | return Just(EqualToBigInt(*x, *n)); | |||
769 | } | |||
770 | ||||
771 | bool BigInt::EqualToNumber(Handle<BigInt> x, Handle<Object> y) { | |||
772 | DCHECK(y->IsNumber())((void) 0); | |||
773 | // a. If x or y are any of NaN, +∞, or -∞, return false. | |||
774 | // b. If the mathematical value of x is equal to the mathematical value of y, | |||
775 | // return true, otherwise return false. | |||
776 | if (y->IsSmi()) { | |||
777 | int value = Smi::ToInt(*y); | |||
778 | if (value == 0) return x->is_zero(); | |||
779 | // Any multi-digit BigInt is bigger than a Smi. | |||
780 | STATIC_ASSERT(sizeof(digit_t) >= sizeof(value))static_assert(sizeof(digit_t) >= sizeof(value), "sizeof(digit_t) >= sizeof(value)" ); | |||
781 | return (x->length() == 1) && (x->sign() == (value < 0)) && | |||
782 | (x->digit(0) == | |||
783 | static_cast<digit_t>(std::abs(static_cast<int64_t>(value)))); | |||
784 | } | |||
785 | DCHECK(y->IsHeapNumber())((void) 0); | |||
786 | double value = Handle<HeapNumber>::cast(y)->value(); | |||
787 | return CompareToDouble(x, value) == ComparisonResult::kEqual; | |||
788 | } | |||
789 | ||||
790 | ComparisonResult BigInt::CompareToNumber(Handle<BigInt> x, Handle<Object> y) { | |||
791 | DCHECK(y->IsNumber())((void) 0); | |||
792 | if (y->IsSmi()) { | |||
793 | bool x_sign = x->sign(); | |||
794 | int y_value = Smi::ToInt(*y); | |||
795 | bool y_sign = (y_value < 0); | |||
796 | if (x_sign != y_sign) return UnequalSign(x_sign); | |||
797 | ||||
798 | if (x->is_zero()) { | |||
799 | DCHECK(!y_sign)((void) 0); | |||
800 | return y_value == 0 ? ComparisonResult::kEqual | |||
801 | : ComparisonResult::kLessThan; | |||
802 | } | |||
803 | // Any multi-digit BigInt is bigger than a Smi. | |||
804 | STATIC_ASSERT(sizeof(digit_t) >= sizeof(y_value))static_assert(sizeof(digit_t) >= sizeof(y_value), "sizeof(digit_t) >= sizeof(y_value)" ); | |||
805 | if (x->length() > 1) return AbsoluteGreater(x_sign); | |||
806 | ||||
807 | digit_t abs_value = std::abs(static_cast<int64_t>(y_value)); | |||
808 | digit_t x_digit = x->digit(0); | |||
809 | if (x_digit > abs_value) return AbsoluteGreater(x_sign); | |||
810 | if (x_digit < abs_value) return AbsoluteLess(x_sign); | |||
811 | return ComparisonResult::kEqual; | |||
812 | } | |||
813 | DCHECK(y->IsHeapNumber())((void) 0); | |||
814 | double value = Handle<HeapNumber>::cast(y)->value(); | |||
815 | return CompareToDouble(x, value); | |||
816 | } | |||
817 | ||||
818 | ComparisonResult BigInt::CompareToDouble(Handle<BigInt> x, double y) { | |||
819 | if (std::isnan(y)) return ComparisonResult::kUndefined; | |||
820 | if (y == V8_INFINITYstd::numeric_limits<double>::infinity()) return ComparisonResult::kLessThan; | |||
821 | if (y == -V8_INFINITYstd::numeric_limits<double>::infinity()) return ComparisonResult::kGreaterThan; | |||
822 | bool x_sign = x->sign(); | |||
823 | // Note that this is different from the double's sign bit for -0. That's | |||
824 | // intentional because -0 must be treated like 0. | |||
825 | bool y_sign = (y < 0); | |||
826 | if (x_sign != y_sign) return UnequalSign(x_sign); | |||
827 | if (y == 0) { | |||
828 | DCHECK(!x_sign)((void) 0); | |||
829 | return x->is_zero() ? ComparisonResult::kEqual | |||
830 | : ComparisonResult::kGreaterThan; | |||
831 | } | |||
832 | if (x->is_zero()) { | |||
833 | DCHECK(!y_sign)((void) 0); | |||
834 | return ComparisonResult::kLessThan; | |||
835 | } | |||
836 | uint64_t double_bits = bit_cast<uint64_t>(y); | |||
837 | int raw_exponent = | |||
838 | static_cast<int>(double_bits >> base::Double::kPhysicalSignificandSize) & | |||
839 | 0x7FF; | |||
840 | uint64_t mantissa = double_bits & base::Double::kSignificandMask; | |||
841 | // Non-finite doubles are handled above. | |||
842 | DCHECK_NE(raw_exponent, 0x7FF)((void) 0); | |||
843 | int exponent = raw_exponent - 0x3FF; | |||
844 | if (exponent < 0) { | |||
845 | // The absolute value of the double is less than 1. Only 0n has an | |||
846 | // absolute value smaller than that, but we've already covered that case. | |||
847 | DCHECK(!x->is_zero())((void) 0); | |||
848 | return AbsoluteGreater(x_sign); | |||
849 | } | |||
850 | int x_length = x->length(); | |||
851 | digit_t x_msd = x->digit(x_length - 1); | |||
852 | int msd_leading_zeros = base::bits::CountLeadingZeros(x_msd); | |||
853 | int x_bitlength = x_length * kDigitBits - msd_leading_zeros; | |||
854 | int y_bitlength = exponent + 1; | |||
855 | if (x_bitlength < y_bitlength) return AbsoluteLess(x_sign); | |||
856 | if (x_bitlength > y_bitlength) return AbsoluteGreater(x_sign); | |||
857 | ||||
858 | // At this point, we know that signs and bit lengths (i.e. position of | |||
859 | // the most significant bit in exponent-free representation) are identical. | |||
860 | // {x} is not zero, {y} is finite and not denormal. | |||
861 | // Now we virtually convert the double to an integer by shifting its | |||
862 | // mantissa according to its exponent, so it will align with the BigInt {x}, | |||
863 | // and then we compare them bit for bit until we find a difference or the | |||
864 | // least significant bit. | |||
865 | // <----- 52 ------> <-- virtual trailing zeroes --> | |||
866 | // y / mantissa: 1yyyyyyyyyyyyyyyyy 0000000000000000000000000000000 | |||
867 | // x / digits: 0001xxxx xxxxxxxx xxxxxxxx ... | |||
868 | // <--> <------> | |||
869 | // msd_topbit kDigitBits | |||
870 | // | |||
871 | mantissa |= base::Double::kHiddenBit; | |||
872 | const int kMantissaTopBit = 52; // 0-indexed. | |||
873 | // 0-indexed position of {x}'s most significant bit within the {msd}. | |||
874 | int msd_topbit = kDigitBits - 1 - msd_leading_zeros; | |||
875 | DCHECK_EQ(msd_topbit, (x_bitlength - 1) % kDigitBits)((void) 0); | |||
876 | // Shifted chunk of {mantissa} for comparing with {digit}. | |||
877 | digit_t compare_mantissa; | |||
878 | // Number of unprocessed bits in {mantissa}. We'll keep them shifted to | |||
879 | // the left (i.e. most significant part) of the underlying uint64_t. | |||
880 | int remaining_mantissa_bits = 0; | |||
881 | ||||
882 | // First, compare the most significant digit against the beginning of | |||
883 | // the mantissa. | |||
884 | if (msd_topbit < kMantissaTopBit) { | |||
885 | remaining_mantissa_bits = (kMantissaTopBit - msd_topbit); | |||
886 | compare_mantissa = mantissa >> remaining_mantissa_bits; | |||
887 | mantissa = mantissa << (64 - remaining_mantissa_bits); | |||
888 | } else { | |||
889 | DCHECK_GE(msd_topbit, kMantissaTopBit)((void) 0); | |||
890 | compare_mantissa = mantissa << (msd_topbit - kMantissaTopBit); | |||
891 | mantissa = 0; | |||
892 | } | |||
893 | if (x_msd > compare_mantissa) return AbsoluteGreater(x_sign); | |||
894 | if (x_msd < compare_mantissa) return AbsoluteLess(x_sign); | |||
895 | ||||
896 | // Then, compare additional digits against any remaining mantissa bits. | |||
897 | for (int digit_index = x_length - 2; digit_index >= 0; digit_index--) { | |||
898 | if (remaining_mantissa_bits > 0) { | |||
899 | remaining_mantissa_bits -= kDigitBits; | |||
900 | if (sizeof(mantissa) != sizeof(x_msd)) { | |||
901 | compare_mantissa = mantissa >> (64 - kDigitBits); | |||
902 | // "& 63" to appease compilers. kDigitBits is 32 here anyway. | |||
903 | mantissa = mantissa << (kDigitBits & 63); | |||
904 | } else { | |||
905 | compare_mantissa = mantissa; | |||
906 | mantissa = 0; | |||
907 | } | |||
908 | } else { | |||
909 | compare_mantissa = 0; | |||
910 | } | |||
911 | digit_t digit = x->digit(digit_index); | |||
912 | if (digit > compare_mantissa) return AbsoluteGreater(x_sign); | |||
913 | if (digit < compare_mantissa) return AbsoluteLess(x_sign); | |||
914 | } | |||
915 | ||||
916 | // Integer parts are equal; check whether {y} has a fractional part. | |||
917 | if (mantissa != 0) { | |||
918 | DCHECK_GT(remaining_mantissa_bits, 0)((void) 0); | |||
919 | return AbsoluteLess(x_sign); | |||
920 | } | |||
921 | return ComparisonResult::kEqual; | |||
922 | } | |||
923 | ||||
924 | MaybeHandle<String> BigInt::ToString(Isolate* isolate, Handle<BigInt> bigint, | |||
925 | int radix, ShouldThrow should_throw) { | |||
926 | if (bigint->is_zero()) { | |||
927 | return isolate->factory()->zero_string(); | |||
928 | } | |||
929 | const bool sign = bigint->sign(); | |||
930 | int chars_allocated; | |||
931 | int chars_written; | |||
932 | Handle<SeqOneByteString> result; | |||
933 | if (bigint->length() == 1 && radix == 10) { | |||
934 | // Fast path for the most common case, to avoid call/dispatch overhead. | |||
935 | // The logic is the same as what the full implementation does below, | |||
936 | // just inlined and specialized for the preconditions. | |||
937 | // Microbenchmarks rejoice! | |||
938 | digit_t digit = bigint->digit(0); | |||
939 | int bit_length = kDigitBits - base::bits::CountLeadingZeros(digit); | |||
940 | constexpr int kShift = 7; | |||
941 | // This is Math.log2(10) * (1 << kShift), scaled just far enough to | |||
942 | // make the computations below always precise (after rounding). | |||
943 | constexpr int kShiftedBitsPerChar = 425; | |||
944 | chars_allocated = (bit_length << kShift) / kShiftedBitsPerChar + 1 + sign; | |||
945 | result = isolate->factory() | |||
946 | ->NewRawOneByteString(chars_allocated) | |||
947 | .ToHandleChecked(); | |||
948 | DisallowGarbageCollection no_gc; | |||
949 | uint8_t* start = result->GetChars(no_gc); | |||
950 | uint8_t* out = start + chars_allocated; | |||
951 | while (digit != 0) { | |||
952 | *(--out) = '0' + (digit % 10); | |||
953 | digit /= 10; | |||
954 | } | |||
955 | if (sign) *(--out) = '-'; | |||
956 | if (out == start) { | |||
957 | chars_written = chars_allocated; | |||
958 | } else { | |||
959 | DCHECK_LT(start, out)((void) 0); | |||
960 | // The result is one character shorter than predicted. This is | |||
961 | // unavoidable, e.g. a 4-bit BigInt can be as big as "10" or as small as | |||
962 | // "9", so we must allocate 2 characters for it, and will only later find | |||
963 | // out whether all characters were used. | |||
964 | chars_written = chars_allocated - static_cast<int>(out - start); | |||
965 | std::memmove(start, out, chars_written); | |||
966 | } | |||
967 | } else { | |||
968 | // Generic path, handles anything. | |||
969 | DCHECK(radix >= 2 && radix <= 36)((void) 0); | |||
970 | chars_allocated = | |||
971 | bigint::ToStringResultLength(GetDigits(bigint), radix, sign); | |||
972 | if (chars_allocated > String::kMaxLength) { | |||
973 | if (should_throw == kThrowOnError) { | |||
974 | THROW_NEW_ERROR(isolate, NewInvalidStringLengthError(), String)do { auto* __isolate__ = (isolate); return __isolate__->template Throw<String>(__isolate__->factory()->NewInvalidStringLengthError ()); } while (false); | |||
975 | } else { | |||
976 | return {}; | |||
977 | } | |||
978 | } | |||
979 | result = isolate->factory() | |||
980 | ->NewRawOneByteString(chars_allocated) | |||
981 | .ToHandleChecked(); | |||
982 | chars_written = chars_allocated; | |||
983 | DisallowGarbageCollection no_gc; | |||
984 | char* characters = reinterpret_cast<char*>(result->GetChars(no_gc)); | |||
985 | bigint::Status status = isolate->bigint_processor()->ToString( | |||
986 | characters, &chars_written, GetDigits(bigint), radix, sign); | |||
987 | if (status == bigint::Status::kInterrupted) { | |||
988 | AllowGarbageCollection terminating_anyway; | |||
989 | isolate->TerminateExecution(); | |||
990 | return {}; | |||
991 | } | |||
992 | } | |||
993 | ||||
994 | // Right-trim any over-allocation (which can happen due to conservative | |||
995 | // estimates). | |||
996 | if (chars_written < chars_allocated) { | |||
997 | result->set_length(chars_written, kReleaseStore); | |||
998 | int string_size = SeqOneByteString::SizeFor(chars_allocated); | |||
999 | int needed_size = SeqOneByteString::SizeFor(chars_written); | |||
1000 | if (needed_size < string_size && !isolate->heap()->IsLargeObject(*result)) { | |||
1001 | Address new_end = result->address() + needed_size; | |||
1002 | isolate->heap()->CreateFillerObjectAt( | |||
1003 | new_end, (string_size - needed_size), ClearRecordedSlots::kNo); | |||
1004 | } | |||
1005 | } | |||
1006 | #if DEBUG | |||
1007 | // Verify that all characters have been written. | |||
1008 | DCHECK(result->length() == chars_written)((void) 0); | |||
1009 | DisallowGarbageCollection no_gc; | |||
1010 | uint8_t* chars = result->GetChars(no_gc); | |||
1011 | for (int i = 0; i < chars_written; i++) { | |||
1012 | DCHECK_NE(chars[i], bigint::kStringZapValue)((void) 0); | |||
1013 | } | |||
1014 | #endif | |||
1015 | return result; | |||
1016 | } | |||
1017 | ||||
1018 | MaybeHandle<BigInt> BigInt::FromNumber(Isolate* isolate, | |||
1019 | Handle<Object> number) { | |||
1020 | DCHECK(number->IsNumber())((void) 0); | |||
1021 | if (number->IsSmi()) { | |||
1022 | return MutableBigInt::NewFromInt(isolate, Smi::ToInt(*number)); | |||
1023 | } | |||
1024 | double value = HeapNumber::cast(*number).value(); | |||
1025 | if (!std::isfinite(value) || (DoubleToInteger(value) != value)) { | |||
1026 | THROW_NEW_ERROR(isolate,do { auto* __isolate__ = (isolate); return __isolate__->template Throw<BigInt>(__isolate__->factory()->NewRangeError (MessageTemplate::kBigIntFromNumber, number)); } while (false ) | |||
1027 | NewRangeError(MessageTemplate::kBigIntFromNumber, number),do { auto* __isolate__ = (isolate); return __isolate__->template Throw<BigInt>(__isolate__->factory()->NewRangeError (MessageTemplate::kBigIntFromNumber, number)); } while (false ) | |||
1028 | BigInt)do { auto* __isolate__ = (isolate); return __isolate__->template Throw<BigInt>(__isolate__->factory()->NewRangeError (MessageTemplate::kBigIntFromNumber, number)); } while (false ); | |||
1029 | } | |||
1030 | return MutableBigInt::NewFromDouble(isolate, value); | |||
1031 | } | |||
1032 | ||||
1033 | MaybeHandle<BigInt> BigInt::FromObject(Isolate* isolate, Handle<Object> obj) { | |||
1034 | if (obj->IsJSReceiver()) { | |||
1035 | ASSIGN_RETURN_ON_EXCEPTION(do { if (!(JSReceiver::ToPrimitive(isolate, Handle<JSReceiver >::cast(obj), ToPrimitiveHint::kNumber)).ToHandle(&obj )) { ((void) 0); return MaybeHandle<BigInt>(); } } while (false) | |||
1036 | isolate, obj,do { if (!(JSReceiver::ToPrimitive(isolate, Handle<JSReceiver >::cast(obj), ToPrimitiveHint::kNumber)).ToHandle(&obj )) { ((void) 0); return MaybeHandle<BigInt>(); } } while (false) | |||
1037 | JSReceiver::ToPrimitive(isolate, Handle<JSReceiver>::cast(obj),do { if (!(JSReceiver::ToPrimitive(isolate, Handle<JSReceiver >::cast(obj), ToPrimitiveHint::kNumber)).ToHandle(&obj )) { ((void) 0); return MaybeHandle<BigInt>(); } } while (false) | |||
1038 | ToPrimitiveHint::kNumber),do { if (!(JSReceiver::ToPrimitive(isolate, Handle<JSReceiver >::cast(obj), ToPrimitiveHint::kNumber)).ToHandle(&obj )) { ((void) 0); return MaybeHandle<BigInt>(); } } while (false) | |||
1039 | BigInt)do { if (!(JSReceiver::ToPrimitive(isolate, Handle<JSReceiver >::cast(obj), ToPrimitiveHint::kNumber)).ToHandle(&obj )) { ((void) 0); return MaybeHandle<BigInt>(); } } while (false); | |||
1040 | } | |||
1041 | ||||
1042 | if (obj->IsBoolean()) { | |||
1043 | return MutableBigInt::NewFromInt(isolate, obj->BooleanValue(isolate)); | |||
1044 | } | |||
1045 | if (obj->IsBigInt()) { | |||
1046 | return Handle<BigInt>::cast(obj); | |||
1047 | } | |||
1048 | if (obj->IsString()) { | |||
1049 | Handle<BigInt> n; | |||
1050 | if (!StringToBigInt(isolate, Handle<String>::cast(obj)).ToHandle(&n)) { | |||
1051 | if (isolate->has_pending_exception()) { | |||
1052 | return MaybeHandle<BigInt>(); | |||
1053 | } else { | |||
1054 | Handle<String> str = Handle<String>::cast(obj); | |||
1055 | constexpr int kMaxRenderedLength = 1000; | |||
1056 | if (str->length() > kMaxRenderedLength) { | |||
1057 | Factory* factory = isolate->factory(); | |||
1058 | Handle<String> prefix = | |||
1059 | factory->NewProperSubString(str, 0, kMaxRenderedLength); | |||
1060 | Handle<SeqTwoByteString> ellipsis = | |||
1061 | factory->NewRawTwoByteString(1).ToHandleChecked(); | |||
1062 | ellipsis->SeqTwoByteStringSet(0, 0x2026); | |||
1063 | str = factory->NewConsString(prefix, ellipsis).ToHandleChecked(); | |||
1064 | } | |||
1065 | THROW_NEW_ERROR(isolate,do { auto* __isolate__ = (isolate); return __isolate__->template Throw<BigInt>(__isolate__->factory()->NewSyntaxError (MessageTemplate::kBigIntFromObject, str)); } while (false) | |||
1066 | NewSyntaxError(MessageTemplate::kBigIntFromObject, str),do { auto* __isolate__ = (isolate); return __isolate__->template Throw<BigInt>(__isolate__->factory()->NewSyntaxError (MessageTemplate::kBigIntFromObject, str)); } while (false) | |||
1067 | BigInt)do { auto* __isolate__ = (isolate); return __isolate__->template Throw<BigInt>(__isolate__->factory()->NewSyntaxError (MessageTemplate::kBigIntFromObject, str)); } while (false); | |||
1068 | } | |||
1069 | } | |||
1070 | return n; | |||
1071 | } | |||
1072 | ||||
1073 | THROW_NEW_ERROR(do { auto* __isolate__ = (isolate); return __isolate__->template Throw<BigInt>(__isolate__->factory()->NewTypeError (MessageTemplate::kBigIntFromObject, obj)); } while (false) | |||
1074 | isolate, NewTypeError(MessageTemplate::kBigIntFromObject, obj), BigInt)do { auto* __isolate__ = (isolate); return __isolate__->template Throw<BigInt>(__isolate__->factory()->NewTypeError (MessageTemplate::kBigIntFromObject, obj)); } while (false); | |||
1075 | } | |||
1076 | ||||
1077 | Handle<Object> BigInt::ToNumber(Isolate* isolate, Handle<BigInt> x) { | |||
1078 | if (x->is_zero()) return Handle<Smi>(Smi::zero(), isolate); | |||
1079 | if (x->length() == 1 && x->digit(0) < Smi::kMaxValue) { | |||
| ||||
1080 | int value = static_cast<int>(x->digit(0)); | |||
1081 | if (x->sign()) value = -value; | |||
1082 | return Handle<Smi>(Smi::FromInt(value), isolate); | |||
1083 | } | |||
1084 | double result = MutableBigInt::ToDouble(x); | |||
1085 | return isolate->factory()->NewHeapNumber(result); | |||
1086 | } | |||
1087 | ||||
1088 | double MutableBigInt::ToDouble(Handle<BigIntBase> x) { | |||
1089 | if (x->is_zero()) return 0.0; | |||
1090 | int x_length = x->length(); | |||
1091 | digit_t x_msd = x->digit(x_length - 1); | |||
1092 | int msd_leading_zeros = base::bits::CountLeadingZeros(x_msd); | |||
1093 | int x_bitlength = x_length * kDigitBits - msd_leading_zeros; | |||
1094 | if (x_bitlength > 1024) return x->sign() ? -V8_INFINITYstd::numeric_limits<double>::infinity() : V8_INFINITYstd::numeric_limits<double>::infinity(); | |||
1095 | uint64_t exponent = x_bitlength - 1; | |||
1096 | // We need the most significant bit shifted to the position of a double's | |||
1097 | // "hidden bit". We also need to hide that MSB, so we shift it out. | |||
1098 | uint64_t current_digit = x_msd; | |||
1099 | int digit_index = x_length - 1; | |||
1100 | int shift = msd_leading_zeros + 1 + (64 - kDigitBits); | |||
1101 | DCHECK_LE(1, shift)((void) 0); | |||
1102 | DCHECK_LE(shift, 64)((void) 0); | |||
1103 | uint64_t mantissa = (shift
| |||
| ||||
1104 | mantissa >>= 12; | |||
1105 | int mantissa_bits_unset = shift - 12; | |||
1106 | // If not all mantissa bits are defined yet, get more digits as needed. | |||
1107 | if (mantissa_bits_unset >= kDigitBits && digit_index > 0) { | |||
1108 | digit_index--; | |||
1109 | current_digit = static_cast<uint64_t>(x->digit(digit_index)); | |||
1110 | mantissa |= (current_digit << (mantissa_bits_unset - kDigitBits)); | |||
1111 | mantissa_bits_unset -= kDigitBits; | |||
1112 | } | |||
1113 | if (mantissa_bits_unset > 0 && digit_index > 0) { | |||
1114 | DCHECK_LT(mantissa_bits_unset, kDigitBits)((void) 0); | |||
1115 | digit_index--; | |||
1116 | current_digit = static_cast<uint64_t>(x->digit(digit_index)); | |||
1117 | mantissa |= (current_digit >> (kDigitBits - mantissa_bits_unset)); | |||
1118 | mantissa_bits_unset -= kDigitBits; | |||
1119 | } | |||
1120 | // If there are unconsumed digits left, we may have to round. | |||
1121 | Rounding rounding = | |||
1122 | DecideRounding(x, mantissa_bits_unset, digit_index, current_digit); | |||
1123 | if (rounding == kRoundUp || (rounding == kTie && (mantissa & 1) == 1)) { | |||
1124 | mantissa++; | |||
1125 | // Incrementing the mantissa can overflow the mantissa bits. In that case | |||
1126 | // the new mantissa will be all zero (plus hidden bit). | |||
1127 | if ((mantissa >> base::Double::kPhysicalSignificandSize) != 0) { | |||
1128 | mantissa = 0; | |||
1129 | exponent++; | |||
1130 | // Incrementing the exponent can overflow too. | |||
1131 | if (exponent > 1023) { | |||
1132 | return x->sign() ? -V8_INFINITYstd::numeric_limits<double>::infinity() : V8_INFINITYstd::numeric_limits<double>::infinity(); | |||
1133 | } | |||
1134 | } | |||
1135 | } | |||
1136 | // Assemble the result. | |||
1137 | uint64_t sign_bit = x->sign() ? (static_cast<uint64_t>(1) << 63) : 0; | |||
1138 | exponent = (exponent + 0x3FF) << base::Double::kPhysicalSignificandSize; | |||
1139 | uint64_t double_bits = sign_bit | exponent | mantissa; | |||
1140 | return bit_cast<double>(double_bits); | |||
1141 | } | |||
1142 | ||||
1143 | // This is its own function to simplify control flow. The meaning of the | |||
1144 | // parameters is defined by {ToDouble}'s local variable usage. | |||
1145 | MutableBigInt::Rounding MutableBigInt::DecideRounding(Handle<BigIntBase> x, | |||
1146 | int mantissa_bits_unset, | |||
1147 | int digit_index, | |||
1148 | uint64_t current_digit) { | |||
1149 | if (mantissa_bits_unset > 0) return kRoundDown; | |||
1150 | int top_unconsumed_bit; | |||
1151 | if (mantissa_bits_unset < 0) { | |||
1152 | // There are unconsumed bits in {current_digit}. | |||
1153 | top_unconsumed_bit = -mantissa_bits_unset - 1; | |||
1154 | } else { | |||
1155 | DCHECK_EQ(mantissa_bits_unset, 0)((void) 0); | |||
1156 | // {current_digit} fit the mantissa exactly; look at the next digit. | |||
1157 | if (digit_index == 0) return kRoundDown; | |||
1158 | digit_index--; | |||
1159 | current_digit = static_cast<uint64_t>(x->digit(digit_index)); | |||
1160 | top_unconsumed_bit = kDigitBits - 1; | |||
1161 | } | |||
1162 | // If the most significant remaining bit is 0, round down. | |||
1163 | uint64_t bitmask = static_cast<uint64_t>(1) << top_unconsumed_bit; | |||
1164 | if ((current_digit & bitmask) == 0) { | |||
1165 | return kRoundDown; | |||
1166 | } | |||
1167 | // If any other remaining bit is set, round up. | |||
1168 | bitmask -= 1; | |||
1169 | if ((current_digit & bitmask) != 0) return kRoundUp; | |||
1170 | while (digit_index > 0) { | |||
1171 | digit_index--; | |||
1172 | if (x->digit(digit_index) != 0) return kRoundUp; | |||
1173 | } | |||
1174 | return kTie; | |||
1175 | } | |||
1176 | ||||
1177 | void BigInt::BigIntShortPrint(std::ostream& os) { | |||
1178 | if (sign()) os << "-"; | |||
1179 | int len = length(); | |||
1180 | if (len == 0) { | |||
1181 | os << "0"; | |||
1182 | return; | |||
1183 | } | |||
1184 | if (len > 1) os << "..."; | |||
1185 | os << digit(0); | |||
1186 | } | |||
1187 | ||||
1188 | // Internal helpers. | |||
1189 | ||||
1190 | // Adds 1 to the absolute value of {x} and sets the result's sign to {sign}. | |||
1191 | // {result_storage} is optional; if present, it will be used to store the | |||
1192 | // result, otherwise a new BigInt will be allocated for the result. | |||
1193 | // {result_storage} and {x} may refer to the same BigInt for in-place | |||
1194 | // modification. | |||
1195 | MaybeHandle<MutableBigInt> MutableBigInt::AbsoluteAddOne( | |||
1196 | Isolate* isolate, Handle<BigIntBase> x, bool sign, | |||
1197 | MutableBigInt result_storage) { | |||
1198 | int input_length = x->length(); | |||
1199 | // The addition will overflow into a new digit if all existing digits are | |||
1200 | // at maximum. | |||
1201 | bool will_overflow = true; | |||
1202 | for (int i = 0; i < input_length; i++) { | |||
1203 | if (!digit_ismax(x->digit(i))) { | |||
1204 | will_overflow = false; | |||
1205 | break; | |||
1206 | } | |||
1207 | } | |||
1208 | int result_length = input_length + will_overflow; | |||
1209 | Handle<MutableBigInt> result(result_storage, isolate); | |||
1210 | if (result_storage.is_null()) { | |||
1211 | if (!New(isolate, result_length).ToHandle(&result)) { | |||
1212 | return MaybeHandle<MutableBigInt>(); | |||
1213 | } | |||
1214 | } else { | |||
1215 | DCHECK(result->length() == result_length)((void) 0); | |||
1216 | } | |||
1217 | if (input_length == 0) { | |||
1218 | result->set_digit(0, 1); | |||
1219 | } else if (input_length == 1 && !will_overflow) { | |||
1220 | result->set_digit(0, x->digit(0) + 1); | |||
1221 | } else { | |||
1222 | bigint::AddOne(GetRWDigits(result), GetDigits(x)); | |||
1223 | } | |||
1224 | result->set_sign(sign); | |||
1225 | return result; | |||
1226 | } | |||
1227 | ||||
1228 | // Subtracts 1 from the absolute value of {x}. {x} must not be zero. | |||
1229 | Handle<MutableBigInt> MutableBigInt::AbsoluteSubOne(Isolate* isolate, | |||
1230 | Handle<BigIntBase> x) { | |||
1231 | DCHECK(!x->is_zero())((void) 0); | |||
1232 | int length = x->length(); | |||
1233 | Handle<MutableBigInt> result = New(isolate, length).ToHandleChecked(); | |||
1234 | if (length == 1) { | |||
1235 | result->set_digit(0, x->digit(0) - 1); | |||
1236 | } else { | |||
1237 | bigint::SubtractOne(GetRWDigits(result), GetDigits(x)); | |||
1238 | } | |||
1239 | return result; | |||
1240 | } | |||
1241 | ||||
1242 | MaybeHandle<BigInt> MutableBigInt::LeftShiftByAbsolute(Isolate* isolate, | |||
1243 | Handle<BigIntBase> x, | |||
1244 | Handle<BigIntBase> y) { | |||
1245 | Maybe<digit_t> maybe_shift = ToShiftAmount(y); | |||
1246 | if (maybe_shift.IsNothing()) { | |||
1247 | return ThrowBigIntTooBig<BigInt>(isolate); | |||
1248 | } | |||
1249 | digit_t shift = maybe_shift.FromJust(); | |||
1250 | const int result_length = bigint::LeftShift_ResultLength( | |||
1251 | x->length(), x->digit(x->length() - 1), shift); | |||
1252 | if (result_length > kMaxLength) { | |||
1253 | return ThrowBigIntTooBig<BigInt>(isolate); | |||
1254 | } | |||
1255 | Handle<MutableBigInt> result; | |||
1256 | if (!New(isolate, result_length).ToHandle(&result)) { | |||
1257 | return MaybeHandle<BigInt>(); | |||
1258 | } | |||
1259 | bigint::LeftShift(GetRWDigits(result), GetDigits(x), shift); | |||
1260 | result->set_sign(x->sign()); | |||
1261 | return MakeImmutable(result); | |||
1262 | } | |||
1263 | ||||
1264 | Handle<BigInt> MutableBigInt::RightShiftByAbsolute(Isolate* isolate, | |||
1265 | Handle<BigIntBase> x, | |||
1266 | Handle<BigIntBase> y) { | |||
1267 | const bool sign = x->sign(); | |||
1268 | Maybe<digit_t> maybe_shift = ToShiftAmount(y); | |||
1269 | if (maybe_shift.IsNothing()) { | |||
1270 | return RightShiftByMaximum(isolate, sign); | |||
1271 | } | |||
1272 | const digit_t shift = maybe_shift.FromJust(); | |||
1273 | bigint::RightShiftState state; | |||
1274 | const int result_length = | |||
1275 | bigint::RightShift_ResultLength(GetDigits(x), sign, shift, &state); | |||
1276 | DCHECK_LE(result_length, x->length())((void) 0); | |||
1277 | if (result_length <= 0) { | |||
1278 | return RightShiftByMaximum(isolate, sign); | |||
1279 | } | |||
1280 | Handle<MutableBigInt> result = New(isolate, result_length).ToHandleChecked(); | |||
1281 | bigint::RightShift(GetRWDigits(result), GetDigits(x), shift, state); | |||
1282 | if (sign) result->set_sign(true); | |||
1283 | return MakeImmutable(result); | |||
1284 | } | |||
1285 | ||||
1286 | Handle<BigInt> MutableBigInt::RightShiftByMaximum(Isolate* isolate, bool sign) { | |||
1287 | if (sign) { | |||
1288 | // TODO(jkummerow): Consider caching a canonical -1n BigInt. | |||
1289 | return NewFromInt(isolate, -1); | |||
1290 | } else { | |||
1291 | return Zero(isolate); | |||
1292 | } | |||
1293 | } | |||
1294 | ||||
1295 | // Returns the value of {x} if it is less than the maximum bit length of | |||
1296 | // a BigInt, or Nothing otherwise. | |||
1297 | Maybe<BigInt::digit_t> MutableBigInt::ToShiftAmount(Handle<BigIntBase> x) { | |||
1298 | if (x->length() > 1) return Nothing<digit_t>(); | |||
1299 | digit_t value = x->digit(0); | |||
1300 | STATIC_ASSERT(kMaxLengthBits < std::numeric_limits<digit_t>::max())static_assert(kMaxLengthBits < std::numeric_limits<digit_t >::max(), "kMaxLengthBits < std::numeric_limits<digit_t>::max()" ); | |||
1301 | if (value > kMaxLengthBits) return Nothing<digit_t>(); | |||
1302 | return Just(value); | |||
1303 | } | |||
1304 | ||||
1305 | void Terminate(Isolate* isolate) { isolate->TerminateExecution(); } | |||
1306 | // {LocalIsolate} doesn't support interruption or termination. | |||
1307 | void Terminate(LocalIsolate* isolate) { UNREACHABLE()V8_Fatal("unreachable code"); } | |||
1308 | ||||
1309 | template <typename IsolateT> | |||
1310 | MaybeHandle<BigInt> BigInt::Allocate(IsolateT* isolate, | |||
1311 | bigint::FromStringAccumulator* accumulator, | |||
1312 | bool negative, AllocationType allocation) { | |||
1313 | int digits = accumulator->ResultLength(); | |||
1314 | DCHECK_LE(digits, kMaxLength)((void) 0); | |||
1315 | Handle<MutableBigInt> result = | |||
1316 | MutableBigInt::New(isolate, digits, allocation).ToHandleChecked(); | |||
1317 | bigint::Status status = | |||
1318 | isolate->bigint_processor()->FromString(GetRWDigits(result), accumulator); | |||
1319 | if (status == bigint::Status::kInterrupted) { | |||
1320 | Terminate(isolate); | |||
1321 | return {}; | |||
1322 | } | |||
1323 | if (digits > 0) result->set_sign(negative); | |||
1324 | return MutableBigInt::MakeImmutable(result); | |||
1325 | } | |||
1326 | template MaybeHandle<BigInt> BigInt::Allocate(Isolate*, | |||
1327 | bigint::FromStringAccumulator*, | |||
1328 | bool, AllocationType); | |||
1329 | template MaybeHandle<BigInt> BigInt::Allocate(LocalIsolate*, | |||
1330 | bigint::FromStringAccumulator*, | |||
1331 | bool, AllocationType); | |||
1332 | ||||
1333 | // The serialization format MUST NOT CHANGE without updating the format | |||
1334 | // version in value-serializer.cc! | |||
1335 | uint32_t BigInt::GetBitfieldForSerialization() const { | |||
1336 | // In order to make the serialization format the same on 32/64 bit builds, | |||
1337 | // we convert the length-in-digits to length-in-bytes for serialization. | |||
1338 | // Being able to do this depends on having enough LengthBits: | |||
1339 | STATIC_ASSERT(kMaxLength * kDigitSize <= LengthBits::kMax)static_assert(kMaxLength * kDigitSize <= LengthBits::kMax, "kMaxLength * kDigitSize <= LengthBits::kMax"); | |||
1340 | int bytelength = length() * kDigitSize; | |||
1341 | return SignBits::encode(sign()) | LengthBits::encode(bytelength); | |||
1342 | } | |||
1343 | ||||
1344 | int BigInt::DigitsByteLengthForBitfield(uint32_t bitfield) { | |||
1345 | return LengthBits::decode(bitfield); | |||
1346 | } | |||
1347 | ||||
1348 | // The serialization format MUST NOT CHANGE without updating the format | |||
1349 | // version in value-serializer.cc! | |||
1350 | void BigInt::SerializeDigits(uint8_t* storage) { | |||
1351 | void* digits = | |||
1352 | reinterpret_cast<void*>(ptr() + kDigitsOffset - kHeapObjectTag); | |||
1353 | #if defined(V8_TARGET_LITTLE_ENDIAN1) | |||
1354 | int bytelength = length() * kDigitSize; | |||
1355 | memcpy(storage, digits, bytelength); | |||
1356 | #elif defined(V8_TARGET_BIG_ENDIAN) | |||
1357 | digit_t* digit_storage = reinterpret_cast<digit_t*>(storage); | |||
1358 | const digit_t* digit = reinterpret_cast<const digit_t*>(digits); | |||
1359 | for (int i = 0; i < length(); i++) { | |||
1360 | *digit_storage = ByteReverse(*digit); | |||
1361 | digit_storage++; | |||
1362 | digit++; | |||
1363 | } | |||
1364 | #endif // V8_TARGET_BIG_ENDIAN | |||
1365 | } | |||
1366 | ||||
1367 | // The serialization format MUST NOT CHANGE without updating the format | |||
1368 | // version in value-serializer.cc! | |||
1369 | MaybeHandle<BigInt> BigInt::FromSerializedDigits( | |||
1370 | Isolate* isolate, uint32_t bitfield, | |||
1371 | base::Vector<const uint8_t> digits_storage) { | |||
1372 | int bytelength = LengthBits::decode(bitfield); | |||
1373 | DCHECK(digits_storage.length() == bytelength)((void) 0); | |||
1374 | bool sign = SignBits::decode(bitfield); | |||
1375 | int length = (bytelength + kDigitSize - 1) / kDigitSize; // Round up. | |||
1376 | Handle<MutableBigInt> result = | |||
1377 | MutableBigInt::Cast(isolate->factory()->NewBigInt(length)); | |||
1378 | result->initialize_bitfield(sign, length); | |||
1379 | void* digits = | |||
1380 | reinterpret_cast<void*>(result->ptr() + kDigitsOffset - kHeapObjectTag); | |||
1381 | #if defined(V8_TARGET_LITTLE_ENDIAN1) | |||
1382 | memcpy(digits, digits_storage.begin(), bytelength); | |||
1383 | void* padding_start = | |||
1384 | reinterpret_cast<void*>(reinterpret_cast<Address>(digits) + bytelength); | |||
1385 | memset(padding_start, 0, length * kDigitSize - bytelength); | |||
1386 | #elif defined(V8_TARGET_BIG_ENDIAN) | |||
1387 | digit_t* digit = reinterpret_cast<digit_t*>(digits); | |||
1388 | const digit_t* digit_storage = | |||
1389 | reinterpret_cast<const digit_t*>(digits_storage.begin()); | |||
1390 | for (int i = 0; i < bytelength / kDigitSize; i++) { | |||
1391 | *digit = ByteReverse(*digit_storage); | |||
1392 | digit_storage++; | |||
1393 | digit++; | |||
1394 | } | |||
1395 | if (bytelength % kDigitSize) { | |||
1396 | *digit = 0; | |||
1397 | byte* digit_byte = reinterpret_cast<byte*>(digit); | |||
1398 | digit_byte += sizeof(*digit) - 1; | |||
1399 | const byte* digit_storage_byte = | |||
1400 | reinterpret_cast<const byte*>(digit_storage); | |||
1401 | for (int i = 0; i < bytelength % kDigitSize; i++) { | |||
1402 | *digit_byte = *digit_storage_byte; | |||
1403 | digit_byte--; | |||
1404 | digit_storage_byte++; | |||
1405 | } | |||
1406 | } | |||
1407 | #endif // V8_TARGET_BIG_ENDIAN | |||
1408 | return MutableBigInt::MakeImmutable(result); | |||
1409 | } | |||
1410 | ||||
1411 | Handle<BigInt> BigInt::AsIntN(Isolate* isolate, uint64_t n, Handle<BigInt> x) { | |||
1412 | if (x->is_zero() || n > kMaxLengthBits) return x; | |||
1413 | if (n == 0) return MutableBigInt::Zero(isolate); | |||
1414 | int needed_length = | |||
1415 | bigint::AsIntNResultLength(GetDigits(x), x->sign(), static_cast<int>(n)); | |||
1416 | if (needed_length == -1) return x; | |||
1417 | Handle<MutableBigInt> result = | |||
1418 | MutableBigInt::New(isolate, needed_length).ToHandleChecked(); | |||
1419 | bool negative = bigint::AsIntN(GetRWDigits(result), GetDigits(x), x->sign(), | |||
1420 | static_cast<int>(n)); | |||
1421 | result->set_sign(negative); | |||
1422 | return MutableBigInt::MakeImmutable(result); | |||
1423 | } | |||
1424 | ||||
1425 | MaybeHandle<BigInt> BigInt::AsUintN(Isolate* isolate, uint64_t n, | |||
1426 | Handle<BigInt> x) { | |||
1427 | if (x->is_zero()) return x; | |||
1428 | if (n == 0) return MutableBigInt::Zero(isolate); | |||
1429 | Handle<MutableBigInt> result; | |||
1430 | if (x->sign()) { | |||
1431 | if (n > kMaxLengthBits) { | |||
1432 | return ThrowBigIntTooBig<BigInt>(isolate); | |||
1433 | } | |||
1434 | int result_length = bigint::AsUintN_Neg_ResultLength(static_cast<int>(n)); | |||
1435 | result = MutableBigInt::New(isolate, result_length).ToHandleChecked(); | |||
1436 | bigint::AsUintN_Neg(GetRWDigits(result), GetDigits(x), static_cast<int>(n)); | |||
1437 | } else { | |||
1438 | if (n >= kMaxLengthBits) return x; | |||
1439 | int result_length = | |||
1440 | bigint::AsUintN_Pos_ResultLength(GetDigits(x), static_cast<int>(n)); | |||
1441 | if (result_length < 0) return x; | |||
1442 | result = MutableBigInt::New(isolate, result_length).ToHandleChecked(); | |||
1443 | bigint::AsUintN_Pos(GetRWDigits(result), GetDigits(x), static_cast<int>(n)); | |||
1444 | } | |||
1445 | DCHECK(!result->sign())((void) 0); | |||
1446 | return MutableBigInt::MakeImmutable(result); | |||
1447 | } | |||
1448 | ||||
1449 | Handle<BigInt> BigInt::FromInt64(Isolate* isolate, int64_t n) { | |||
1450 | if (n == 0) return MutableBigInt::Zero(isolate); | |||
1451 | STATIC_ASSERT(kDigitBits == 64 || kDigitBits == 32)static_assert(kDigitBits == 64 || kDigitBits == 32, "kDigitBits == 64 || kDigitBits == 32" ); | |||
1452 | int length = 64 / kDigitBits; | |||
1453 | Handle<MutableBigInt> result = | |||
1454 | MutableBigInt::Cast(isolate->factory()->NewBigInt(length)); | |||
1455 | bool sign = n < 0; | |||
1456 | result->initialize_bitfield(sign, length); | |||
1457 | uint64_t absolute; | |||
1458 | if (!sign) { | |||
1459 | absolute = static_cast<uint64_t>(n); | |||
1460 | } else { | |||
1461 | if (n == std::numeric_limits<int64_t>::min()) { | |||
1462 | absolute = static_cast<uint64_t>(std::numeric_limits<int64_t>::max()) + 1; | |||
1463 | } else { | |||
1464 | absolute = static_cast<uint64_t>(-n); | |||
1465 | } | |||
1466 | } | |||
1467 | result->set_64_bits(absolute); | |||
1468 | return MutableBigInt::MakeImmutable(result); | |||
1469 | } | |||
1470 | ||||
1471 | Handle<BigInt> BigInt::FromUint64(Isolate* isolate, uint64_t n) { | |||
1472 | if (n == 0) return MutableBigInt::Zero(isolate); | |||
1473 | STATIC_ASSERT(kDigitBits == 64 || kDigitBits == 32)static_assert(kDigitBits == 64 || kDigitBits == 32, "kDigitBits == 64 || kDigitBits == 32" ); | |||
1474 | int length = 64 / kDigitBits; | |||
1475 | Handle<MutableBigInt> result = | |||
1476 | MutableBigInt::Cast(isolate->factory()->NewBigInt(length)); | |||
1477 | result->initialize_bitfield(false, length); | |||
1478 | result->set_64_bits(n); | |||
1479 | return MutableBigInt::MakeImmutable(result); | |||
1480 | } | |||
1481 | ||||
1482 | MaybeHandle<BigInt> BigInt::FromWords64(Isolate* isolate, int sign_bit, | |||
1483 | int words64_count, | |||
1484 | const uint64_t* words) { | |||
1485 | if (words64_count < 0 || words64_count > kMaxLength / (64 / kDigitBits)) { | |||
1486 | return ThrowBigIntTooBig<BigInt>(isolate); | |||
1487 | } | |||
1488 | if (words64_count == 0) return MutableBigInt::Zero(isolate); | |||
1489 | STATIC_ASSERT(kDigitBits == 64 || kDigitBits == 32)static_assert(kDigitBits == 64 || kDigitBits == 32, "kDigitBits == 64 || kDigitBits == 32" ); | |||
1490 | int length = (64 / kDigitBits) * words64_count; | |||
1491 | DCHECK_GT(length, 0)((void) 0); | |||
1492 | if (kDigitBits == 32 && words[words64_count - 1] <= (1ULL << 32)) length--; | |||
1493 | ||||
1494 | Handle<MutableBigInt> result; | |||
1495 | if (!MutableBigInt::New(isolate, length).ToHandle(&result)) { | |||
1496 | return MaybeHandle<BigInt>(); | |||
1497 | } | |||
1498 | ||||
1499 | result->set_sign(sign_bit); | |||
1500 | if (kDigitBits == 64) { | |||
1501 | for (int i = 0; i < length; ++i) { | |||
1502 | result->set_digit(i, static_cast<digit_t>(words[i])); | |||
1503 | } | |||
1504 | } else { | |||
1505 | for (int i = 0; i < length; i += 2) { | |||
1506 | digit_t lo = static_cast<digit_t>(words[i / 2]); | |||
1507 | digit_t hi = static_cast<digit_t>(words[i / 2] >> 32); | |||
1508 | result->set_digit(i, lo); | |||
1509 | if (i + 1 < length) result->set_digit(i + 1, hi); | |||
1510 | } | |||
1511 | } | |||
1512 | ||||
1513 | return MutableBigInt::MakeImmutable(result); | |||
1514 | } | |||
1515 | ||||
1516 | int BigInt::Words64Count() { | |||
1517 | STATIC_ASSERT(kDigitBits == 64 || kDigitBits == 32)static_assert(kDigitBits == 64 || kDigitBits == 32, "kDigitBits == 64 || kDigitBits == 32" ); | |||
1518 | return length() / (64 / kDigitBits) + | |||
1519 | (kDigitBits == 32 && length() % 2 == 1 ? 1 : 0); | |||
1520 | } | |||
1521 | ||||
1522 | void BigInt::ToWordsArray64(int* sign_bit, int* words64_count, | |||
1523 | uint64_t* words) { | |||
1524 | DCHECK_NE(sign_bit, nullptr)((void) 0); | |||
1525 | DCHECK_NE(words64_count, nullptr)((void) 0); | |||
1526 | *sign_bit = sign(); | |||
1527 | int available_words = *words64_count; | |||
1528 | *words64_count = Words64Count(); | |||
1529 | if (available_words == 0) return; | |||
1530 | DCHECK_NE(words, nullptr)((void) 0); | |||
1531 | ||||
1532 | int len = length(); | |||
1533 | if (kDigitBits == 64) { | |||
1534 | for (int i = 0; i < len && i < available_words; ++i) words[i] = digit(i); | |||
1535 | } else { | |||
1536 | for (int i = 0; i < len && available_words > 0; i += 2) { | |||
1537 | uint64_t lo = digit(i); | |||
1538 | uint64_t hi = (i + 1) < len ? digit(i + 1) : 0; | |||
1539 | words[i / 2] = lo | (hi << 32); | |||
1540 | available_words--; | |||
1541 | } | |||
1542 | } | |||
1543 | } | |||
1544 | ||||
1545 | uint64_t MutableBigInt::GetRawBits(BigIntBase x, bool* lossless) { | |||
1546 | if (lossless != nullptr) *lossless = true; | |||
1547 | if (x.is_zero()) return 0; | |||
1548 | int len = x.length(); | |||
1549 | STATIC_ASSERT(kDigitBits == 64 || kDigitBits == 32)static_assert(kDigitBits == 64 || kDigitBits == 32, "kDigitBits == 64 || kDigitBits == 32" ); | |||
1550 | if (lossless != nullptr && len > 64 / kDigitBits) *lossless = false; | |||
1551 | uint64_t raw = static_cast<uint64_t>(x.digit(0)); | |||
1552 | if (kDigitBits == 32 && len > 1) { | |||
1553 | raw |= static_cast<uint64_t>(x.digit(1)) << 32; | |||
1554 | } | |||
1555 | // Simulate two's complement. MSVC dislikes "-raw". | |||
1556 | return x.sign() ? ((~raw) + 1u) : raw; | |||
1557 | } | |||
1558 | ||||
1559 | int64_t BigInt::AsInt64(bool* lossless) { | |||
1560 | uint64_t raw = MutableBigInt::GetRawBits(*this, lossless); | |||
1561 | int64_t result = static_cast<int64_t>(raw); | |||
1562 | if (lossless != nullptr && (result < 0) != sign()) *lossless = false; | |||
1563 | return result; | |||
1564 | } | |||
1565 | ||||
1566 | uint64_t BigInt::AsUint64(bool* lossless) { | |||
1567 | uint64_t result = MutableBigInt::GetRawBits(*this, lossless); | |||
1568 | if (lossless != nullptr && sign()) *lossless = false; | |||
1569 | return result; | |||
1570 | } | |||
1571 | ||||
1572 | void MutableBigInt::set_64_bits(uint64_t bits) { | |||
1573 | STATIC_ASSERT(kDigitBits == 64 || kDigitBits == 32)static_assert(kDigitBits == 64 || kDigitBits == 32, "kDigitBits == 64 || kDigitBits == 32" ); | |||
1574 | if (kDigitBits == 64) { | |||
1575 | set_digit(0, static_cast<digit_t>(bits)); | |||
1576 | } else { | |||
1577 | set_digit(0, static_cast<digit_t>(bits & 0xFFFFFFFFu)); | |||
1578 | set_digit(1, static_cast<digit_t>(bits >> 32)); | |||
1579 | } | |||
1580 | } | |||
1581 | ||||
1582 | #ifdef OBJECT_PRINT1 | |||
1583 | void BigIntBase::BigIntBasePrint(std::ostream& os) { | |||
1584 | DisallowGarbageCollection no_gc; | |||
1585 | PrintHeader(os, "BigInt"); | |||
1586 | int len = length(); | |||
1587 | os << "\n- length: " << len; | |||
1588 | os << "\n- sign: " << sign(); | |||
1589 | if (len > 0) { | |||
1590 | os << "\n- digits:"; | |||
1591 | for (int i = 0; i < len; i++) { | |||
1592 | os << "\n 0x" << std::hex << digit(i); | |||
1593 | } | |||
1594 | } | |||
1595 | os << std::dec << "\n"; | |||
1596 | } | |||
1597 | #endif // OBJECT_PRINT | |||
1598 | ||||
1599 | void MutableBigInt_AbsoluteAddAndCanonicalize(Address result_addr, | |||
1600 | Address x_addr, Address y_addr) { | |||
1601 | BigInt x = BigInt::cast(Object(x_addr)); | |||
1602 | BigInt y = BigInt::cast(Object(y_addr)); | |||
1603 | MutableBigInt result = MutableBigInt::cast(Object(result_addr)); | |||
1604 | ||||
1605 | bigint::Add(GetRWDigits(result), GetDigits(x), GetDigits(y)); | |||
1606 | MutableBigInt::Canonicalize(result); | |||
1607 | } | |||
1608 | ||||
1609 | int32_t MutableBigInt_AbsoluteCompare(Address x_addr, Address y_addr) { | |||
1610 | BigInt x = BigInt::cast(Object(x_addr)); | |||
1611 | BigInt y = BigInt::cast(Object(y_addr)); | |||
1612 | ||||
1613 | return bigint::Compare(GetDigits(x), GetDigits(y)); | |||
1614 | } | |||
1615 | ||||
1616 | void MutableBigInt_AbsoluteSubAndCanonicalize(Address result_addr, | |||
1617 | Address x_addr, Address y_addr) { | |||
1618 | BigInt x = BigInt::cast(Object(x_addr)); | |||
1619 | BigInt y = BigInt::cast(Object(y_addr)); | |||
1620 | MutableBigInt result = MutableBigInt::cast(Object(result_addr)); | |||
1621 | ||||
1622 | bigint::Subtract(GetRWDigits(result), GetDigits(x), GetDigits(y)); | |||
1623 | MutableBigInt::Canonicalize(result); | |||
1624 | } | |||
1625 | ||||
1626 | } // namespace internal | |||
1627 | } // namespace v8 |