1 // Copyright 2011 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 #ifndef V8_NUMBERS_CONVERSIONS_INL_H_
6 #define V8_NUMBERS_CONVERSIONS_INL_H_
7
8 #include <float.h> // Required for DBL_MAX and on Win32 for finite()
9 #include <limits.h> // Required for INT_MAX etc.
10 #include <stdarg.h>
11 #include <cmath>
12 #include "src/common/globals.h" // Required for V8_INFINITY
13
14 // ----------------------------------------------------------------------------
15 // Extra POSIX/ANSI functions for Win32/MSVC.
16
17 #include "src/base/bits.h"
18 #include "src/base/numbers/double.h"
19 #include "src/base/platform/platform.h"
20 #include "src/base/platform/wrappers.h"
21 #include "src/numbers/conversions.h"
22 #include "src/objects/heap-number-inl.h"
23 #include "src/objects/objects-inl.h"
24
25 namespace v8 {
26 namespace internal {
27
28 // The fast double-to-unsigned-int conversion routine does not guarantee
29 // rounding towards zero, or any reasonable value if the argument is larger
30 // than what fits in an unsigned 32-bit integer.
FastD2UI(double x)31 inline unsigned int FastD2UI(double x) {
32 // There is no unsigned version of lrint, so there is no fast path
33 // in this function as there is in FastD2I. Using lrint doesn't work
34 // for values of 2^31 and above.
35
36 // Convert "small enough" doubles to uint32_t by fixing the 32
37 // least significant non-fractional bits in the low 32 bits of the
38 // double, and reading them from there.
39 const double k2Pow52 = 4503599627370496.0;
40 bool negative = x < 0;
41 if (negative) {
42 x = -x;
43 }
44 if (x < k2Pow52) {
45 x += k2Pow52;
46 uint32_t result;
47 #ifndef V8_TARGET_BIG_ENDIAN
48 void* mantissa_ptr = reinterpret_cast<void*>(&x);
49 #else
50 void* mantissa_ptr =
51 reinterpret_cast<void*>(reinterpret_cast<Address>(&x) + kInt32Size);
52 #endif
53 // Copy least significant 32 bits of mantissa.
54 memcpy(&result, mantissa_ptr, sizeof(result));
55 return negative ? ~result + 1 : result;
56 }
57 // Large number (outside uint32 range), Infinity or NaN.
58 return 0x80000000u; // Return integer indefinite.
59 }
60
DoubleToFloat32(double x)61 inline float DoubleToFloat32(double x) {
62 using limits = std::numeric_limits<float>;
63 if (x > limits::max()) {
64 // kRoundingThreshold is the maximum double that rounds down to
65 // the maximum representable float. Its mantissa bits are:
66 // 1111111111111111111111101111111111111111111111111111
67 // [<--- float range --->]
68 // Note the zero-bit right after the float mantissa range, which
69 // determines the rounding-down.
70 static const double kRoundingThreshold = 3.4028235677973362e+38;
71 if (x <= kRoundingThreshold) return limits::max();
72 return limits::infinity();
73 }
74 if (x < limits::lowest()) {
75 // Same as above, mirrored to negative numbers.
76 static const double kRoundingThreshold = -3.4028235677973362e+38;
77 if (x >= kRoundingThreshold) return limits::lowest();
78 return -limits::infinity();
79 }
80 return static_cast<float>(x);
81 }
82
DoubleToInteger(double x)83 inline double DoubleToInteger(double x) {
84 if (std::isnan(x)) return 0;
85 if (!std::isfinite(x)) return x;
86 // ToInteger normalizes -0 to +0.
87 if (x == 0.0) return 0;
88 return (x >= 0) ? std::floor(x) : std::ceil(x);
89 }
90
91 // Implements most of https://tc39.github.io/ecma262/#sec-toint32.
DoubleToInt32(double x)92 int32_t DoubleToInt32(double x) {
93 if ((std::isfinite(x)) && (x <= INT_MAX) && (x >= INT_MIN)) {
94 // All doubles within these limits are trivially convertable to an int.
95 return static_cast<int32_t>(x);
96 }
97 base::Double d(x);
98 int exponent = d.Exponent();
99 uint64_t bits;
100 if (exponent < 0) {
101 if (exponent <= -base::Double::kSignificandSize) return 0;
102 bits = d.Significand() >> -exponent;
103 } else {
104 if (exponent > 31) return 0;
105 // Masking to a 32-bit value ensures that the result of the
106 // static_cast<int64_t> below is not the minimal int64_t value,
107 // which would overflow on multiplication with d.Sign().
108 bits = (d.Significand() << exponent) & 0xFFFFFFFFul;
109 }
110 return static_cast<int32_t>(d.Sign() * static_cast<int64_t>(bits));
111 }
112
113 // Implements https://heycam.github.io/webidl/#abstract-opdef-converttoint for
114 // the general case (step 1 and steps 8 to 12). Support for Clamp and
115 // EnforceRange will come in the future.
DoubleToWebIDLInt64(double x)116 inline int64_t DoubleToWebIDLInt64(double x) {
117 if ((std::isfinite(x)) && (x <= kMaxSafeInteger) && (x >= kMinSafeInteger)) {
118 // All doubles within these limits are trivially convertable to an int.
119 return static_cast<int64_t>(x);
120 }
121 base::Double d(x);
122 int exponent = d.Exponent();
123 uint64_t bits;
124 if (exponent < 0) {
125 if (exponent <= -base::Double::kSignificandSize) return 0;
126 bits = d.Significand() >> -exponent;
127 } else {
128 if (exponent > 63) return 0;
129 bits = (d.Significand() << exponent);
130 int64_t bits_int64 = static_cast<int64_t>(bits);
131 if (bits_int64 == std::numeric_limits<int64_t>::min()) {
132 return bits_int64;
133 }
134 }
135 return static_cast<int64_t>(d.Sign() * static_cast<int64_t>(bits));
136 }
137
DoubleToWebIDLUint64(double x)138 inline uint64_t DoubleToWebIDLUint64(double x) {
139 return static_cast<uint64_t>(DoubleToWebIDLInt64(x));
140 }
141
DoubleToSmiInteger(double value,int * smi_int_value)142 bool DoubleToSmiInteger(double value, int* smi_int_value) {
143 if (!IsSmiDouble(value)) return false;
144 *smi_int_value = FastD2I(value);
145 DCHECK(Smi::IsValid(*smi_int_value));
146 return true;
147 }
148
IsSmiDouble(double value)149 bool IsSmiDouble(double value) {
150 return value >= Smi::kMinValue && value <= Smi::kMaxValue &&
151 !IsMinusZero(value) && value == FastI2D(FastD2I(value));
152 }
153
IsInt32Double(double value)154 bool IsInt32Double(double value) {
155 return value >= kMinInt && value <= kMaxInt && !IsMinusZero(value) &&
156 value == FastI2D(FastD2I(value));
157 }
158
IsUint32Double(double value)159 bool IsUint32Double(double value) {
160 return !IsMinusZero(value) && value >= 0 && value <= kMaxUInt32 &&
161 value == FastUI2D(FastD2UI(value));
162 }
163
DoubleToUint32IfEqualToSelf(double value,uint32_t * uint32_value)164 bool DoubleToUint32IfEqualToSelf(double value, uint32_t* uint32_value) {
165 const double k2Pow52 = 4503599627370496.0;
166 const uint32_t kValidTopBits = 0x43300000;
167 const uint64_t kBottomBitMask = 0x0000'0000'FFFF'FFFF;
168
169 // Add 2^52 to the double, to place valid uint32 values in the low-significant
170 // bits of the exponent, by effectively setting the (implicit) top bit of the
171 // significand. Note that this addition also normalises 0.0 and -0.0.
172 double shifted_value = value + k2Pow52;
173
174 // At this point, a valid uint32 valued double will be represented as:
175 //
176 // sign = 0
177 // exponent = 52
178 // significand = 1. 00...00 <value>
179 // implicit^ ^^^^^^^ 32 bits
180 // ^^^^^^^^^^^^^^^ 52 bits
181 //
182 // Therefore, we can first check the top 32 bits to make sure that the sign,
183 // exponent and remaining significand bits are valid, and only then check the
184 // value in the bottom 32 bits.
185
186 uint64_t result = bit_cast<uint64_t>(shifted_value);
187 if ((result >> 32) == kValidTopBits) {
188 *uint32_value = result & kBottomBitMask;
189 return FastUI2D(result & kBottomBitMask) == value;
190 }
191 return false;
192 }
193
194 int32_t NumberToInt32(Object number) {
195 if (number.IsSmi()) return Smi::ToInt(number);
196 return DoubleToInt32(HeapNumber::cast(number).value());
197 }
198
199 uint32_t NumberToUint32(Object number) {
200 if (number.IsSmi()) return Smi::ToInt(number);
201 return DoubleToUint32(HeapNumber::cast(number).value());
202 }
203
204 uint32_t PositiveNumberToUint32(Object number) {
205 if (number.IsSmi()) {
206 int value = Smi::ToInt(number);
207 if (value <= 0) return 0;
208 return value;
209 }
210 double value = HeapNumber::cast(number).value();
211 // Catch all values smaller than 1 and use the double-negation trick for NANs.
212 if (!(value >= 1)) return 0;
213 uint32_t max = std::numeric_limits<uint32_t>::max();
214 if (value < max) return static_cast<uint32_t>(value);
215 return max;
216 }
217
218 int64_t NumberToInt64(Object number) {
219 if (number.IsSmi()) return Smi::ToInt(number);
220 double d = HeapNumber::cast(number).value();
221 if (std::isnan(d)) return 0;
222 if (d >= static_cast<double>(std::numeric_limits<int64_t>::max())) {
223 return std::numeric_limits<int64_t>::max();
224 }
225 if (d <= static_cast<double>(std::numeric_limits<int64_t>::min())) {
226 return std::numeric_limits<int64_t>::min();
227 }
228 return static_cast<int64_t>(d);
229 }
230
231 uint64_t PositiveNumberToUint64(Object number) {
232 if (number.IsSmi()) {
233 int value = Smi::ToInt(number);
234 if (value <= 0) return 0;
235 return value;
236 }
237 double value = HeapNumber::cast(number).value();
238 // Catch all values smaller than 1 and use the double-negation trick for NANs.
239 if (!(value >= 1)) return 0;
240 uint64_t max = std::numeric_limits<uint64_t>::max();
241 if (value < max) return static_cast<uint64_t>(value);
242 return max;
243 }
244
245 bool TryNumberToSize(Object number, size_t* result) {
246 // Do not create handles in this function! Don't use SealHandleScope because
247 // the function can be used concurrently.
248 if (number.IsSmi()) {
249 int value = Smi::ToInt(number);
250 DCHECK(static_cast<unsigned>(Smi::kMaxValue) <=
251 std::numeric_limits<size_t>::max());
252 if (value >= 0) {
253 *result = static_cast<size_t>(value);
254 return true;
255 }
256 return false;
257 } else {
258 double value = HeapNumber::cast(number).value();
259 // If value is compared directly to the limit, the limit will be
260 // casted to a double and could end up as limit + 1,
261 // because a double might not have enough mantissa bits for it.
262 // So we might as well cast the limit first, and use < instead of <=.
263 double maxSize = static_cast<double>(std::numeric_limits<size_t>::max());
264 if (value >= 0 && value < maxSize) {
265 *result = static_cast<size_t>(value);
266 return true;
267 } else {
268 return false;
269 }
270 }
271 }
272
NumberToSize(Object number)273 size_t NumberToSize(Object number) {
274 size_t result = 0;
275 bool is_valid = TryNumberToSize(number, &result);
276 CHECK(is_valid);
277 return result;
278 }
279
DoubleToUint32(double x)280 uint32_t DoubleToUint32(double x) {
281 return static_cast<uint32_t>(DoubleToInt32(x));
282 }
283
284 } // namespace internal
285 } // namespace v8
286
287 #endif // V8_NUMBERS_CONVERSIONS_INL_H_
288