v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
conversions-inl.h
Go to the documentation of this file.
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
9// Include the non-inl header before the rest of the headers.
10
11#include <float.h> // Required for DBL_MAX and on Win32 for finite()
12#include <limits.h> // Required for INT_MAX etc.
13#include <stdarg.h>
14#include <cmath>
15#include "src/common/globals.h" // Required for V8_INFINITY
16
17// ----------------------------------------------------------------------------
18// Extra POSIX/ANSI functions for Win32/MSVC.
19
20#include "src/base/bits.h"
25#include "src/objects/smi-inl.h"
26
27namespace v8 {
28namespace internal {
29
30// The fast double-to-unsigned-int conversion routine does not guarantee
31// rounding towards zero, or any reasonable value if the argument is larger
32// than what fits in an unsigned 32-bit integer.
33inline unsigned int FastD2UI(double x) {
34 // There is no unsigned version of lrint, so there is no fast path
35 // in this function as there is in FastD2I. Using lrint doesn't work
36 // for values of 2^31 and above.
37
38 // Convert "small enough" doubles to uint32_t by fixing the 32
39 // least significant non-fractional bits in the low 32 bits of the
40 // double, and reading them from there.
41 const double k2Pow52 = 4503599627370496.0;
42 bool negative = x < 0;
43 if (negative) {
44 x = -x;
45 }
46 if (x < k2Pow52) {
47 x += k2Pow52;
48 uint32_t result;
49#ifndef V8_TARGET_BIG_ENDIAN
50 void* mantissa_ptr = reinterpret_cast<void*>(&x);
51#else
52 void* mantissa_ptr =
53 reinterpret_cast<void*>(reinterpret_cast<Address>(&x) + kInt32Size);
54#endif
55 // Copy least significant 32 bits of mantissa.
56 memcpy(&result, mantissa_ptr, sizeof(result));
57 return negative ? ~result + 1 : result;
58 }
59 // Large number (outside uint32 range), Infinity or NaN.
60 return 0x80000000u; // Return integer indefinite.
61}
62
63// Adopted from https://gist.github.com/rygorous/2156668
64inline uint16_t DoubleToFloat16(double value) {
65 uint64_t in = base::bit_cast<uint64_t>(value);
66 uint16_t out = 0;
67
68 // Take the absolute value of the input.
69 uint64_t sign = in & kFP64SignMask;
70 in ^= sign;
71
73 // Result is infinity or NaN.
74 out = (in > kFP64Infinity) ? kFP16qNaN // NaN->qNaN
75 : kFP16Infinity; // Inf->Inf
76 } else {
77 // Result is a (de)normalized number or zero.
78
79 if (in < kFP16DenormalThreshold) {
80 // Result is a denormal or zero. Use the magic value and FP addition to
81 // align 10 mantissa bits at the bottom of the float. Depends on FP
82 // addition being round-to-nearest-even.
83 double temp = base::bit_cast<double>(in) +
86 } else {
87 // Result is not a denormal.
88
89 // Remember if the result mantissa will be odd before rounding.
90 uint64_t mant_odd = (in >> (kFP64MantissaBits - kFP16MantissaBits)) & 1;
91
92 // Update the exponent and round to nearest even.
93 //
94 // Rounding to nearest even is handled in two parts. First, adding
95 // kFP64To16RebiasExponentAndRound has the effect of rebiasing the
96 // exponent and that if any of the lower 41 bits of the mantissa are set,
97 // the 11th mantissa bit from the front becomes set. Second, adding
98 // mant_odd ensures ties are rounded to even.
100 in += mant_odd;
101
102 out = in >> (kFP64MantissaBits - kFP16MantissaBits);
103 }
104 }
105
106 out |= sign >> 48;
107 return out;
108}
109
110inline float DoubleToFloat32(double x) {
111 using limits = std::numeric_limits<float>;
112 if (x > limits::max()) {
113 // kRoundingThreshold is the maximum double that rounds down to
114 // the maximum representable float. Its mantissa bits are:
115 // 1111111111111111111111101111111111111111111111111111
116 // [<--- float range --->]
117 // Note the zero-bit right after the float mantissa range, which
118 // determines the rounding-down.
119 static const double kRoundingThreshold = 3.4028235677973362e+38;
120 if (x <= kRoundingThreshold) return limits::max();
121 return limits::infinity();
122 }
123 if (x < limits::lowest()) {
124 // Same as above, mirrored to negative numbers.
125 static const double kRoundingThreshold = -3.4028235677973362e+38;
126 if (x >= kRoundingThreshold) return limits::lowest();
127 return -limits::infinity();
128 }
129 return static_cast<float>(x);
130}
131
132// #sec-tointegerorinfinity
133inline double DoubleToInteger(double x) {
134 // ToIntegerOrInfinity normalizes -0 to +0. Special case 0 for performance.
135 if (std::isnan(x) || x == 0.0) return 0;
136 if (!std::isfinite(x)) return x;
137 // Add 0.0 in the truncation case to ensure this doesn't return -0.
138 return ((x > 0) ? std::floor(x) : std::ceil(x)) + 0.0;
139}
140
141// Implements most of https://tc39.github.io/ecma262/#sec-toint32.
142int32_t DoubleToInt32(double x) {
143 if ((std::isfinite(x)) && (x <= INT_MAX) && (x >= INT_MIN)) {
144 // All doubles within these limits are trivially convertable to an int.
145 return static_cast<int32_t>(x);
146 }
147 base::Double d(x);
148 int exponent = d.Exponent();
149 uint64_t bits;
150 if (exponent < 0) {
151 if (exponent <= -base::Double::kSignificandSize) return 0;
152 bits = d.Significand() >> -exponent;
153 } else {
154 if (exponent > 31) return 0;
155 // Masking to a 32-bit value ensures that the result of the
156 // static_cast<int64_t> below is not the minimal int64_t value,
157 // which would overflow on multiplication with d.Sign().
158 bits = (d.Significand() << exponent) & 0xFFFFFFFFul;
159 }
160 return static_cast<int32_t>(d.Sign() * static_cast<int64_t>(bits));
161}
162
163// Implements https://heycam.github.io/webidl/#abstract-opdef-converttoint for
164// the general case (step 1 and steps 8 to 12). Support for Clamp and
165// EnforceRange will come in the future.
166inline int64_t DoubleToWebIDLInt64(double x) {
167 if ((std::isfinite(x)) && (x <= kMaxSafeInteger) && (x >= kMinSafeInteger)) {
168 // All doubles within these limits are trivially convertable to an int.
169 return static_cast<int64_t>(x);
170 }
171 base::Double d(x);
172 int exponent = d.Exponent();
173 uint64_t bits;
174 if (exponent < 0) {
175 if (exponent <= -base::Double::kSignificandSize) return 0;
176 bits = d.Significand() >> -exponent;
177 } else {
178 if (exponent > 63) return 0;
179 bits = (d.Significand() << exponent);
180 int64_t bits_int64 = static_cast<int64_t>(bits);
181 if (bits_int64 == std::numeric_limits<int64_t>::min()) {
182 return bits_int64;
183 }
184 }
185 return static_cast<int64_t>(d.Sign() * static_cast<int64_t>(bits));
186}
187
188inline uint64_t DoubleToWebIDLUint64(double x) {
189 return static_cast<uint64_t>(DoubleToWebIDLInt64(x));
190}
191
192bool DoubleToSmiInteger(double value, int* smi_int_value) {
193 if (!IsSmiDouble(value)) return false;
194 *smi_int_value = FastD2I(value);
195 DCHECK(Smi::IsValid(*smi_int_value));
196 return true;
197}
198
199bool IsSmiDouble(double value) {
200 return value >= Smi::kMinValue && value <= Smi::kMaxValue &&
201 !IsMinusZero(value) && value == FastI2D(FastD2I(value));
202}
203
204bool IsInt32Double(double value) {
205 return value >= kMinInt && value <= kMaxInt && !IsMinusZero(value) &&
206 value == FastI2D(FastD2I(value));
207}
208
209bool IsUint32Double(double value) {
210 return !IsMinusZero(value) && value >= 0 && value <= kMaxUInt32 &&
211 value == FastUI2D(FastD2UI(value));
212}
213
214bool DoubleToUint32IfEqualToSelf(double value, uint32_t* uint32_value) {
215 const double k2Pow52 = 4503599627370496.0;
216 const uint32_t kValidTopBits = 0x43300000;
217 const uint64_t kBottomBitMask = 0x0000'0000'FFFF'FFFF;
218
219 // Add 2^52 to the double, to place valid uint32 values in the low-significant
220 // bits of the exponent, by effectively setting the (implicit) top bit of the
221 // significand. Note that this addition also normalises 0.0 and -0.0.
222 double shifted_value = value + k2Pow52;
223
224 // At this point, a valid uint32 valued double will be represented as:
225 //
226 // sign = 0
227 // exponent = 52
228 // significand = 1. 00...00 <value>
229 // implicit^ ^^^^^^^ 32 bits
230 // ^^^^^^^^^^^^^^^ 52 bits
231 //
232 // Therefore, we can first check the top 32 bits to make sure that the sign,
233 // exponent and remaining significand bits are valid, and only then check the
234 // value in the bottom 32 bits.
235
236 uint64_t result = base::bit_cast<uint64_t>(shifted_value);
237 if ((result >> 32) == kValidTopBits) {
238 *uint32_value = result & kBottomBitMask;
239 return FastUI2D(result & kBottomBitMask) == value;
240 }
241 return false;
242}
243
245 if (IsSmi(number)) return Smi::ToInt(number);
246 return DoubleToInt32(Cast<HeapNumber>(number)->value());
247}
248
250 if (IsSmi(number)) return Smi::ToInt(number);
251 return DoubleToUint32(Cast<HeapNumber>(number)->value());
252}
253
255 if (IsSmi(number)) {
256 int value = Smi::ToInt(number);
257 if (value <= 0) return 0;
258 return value;
259 }
260 double value = Cast<HeapNumber>(number)->value();
261 // Catch all values smaller than 1 and use the double-negation trick for NANs.
262 if (!(value >= 1)) return 0;
263 uint32_t max = std::numeric_limits<uint32_t>::max();
264 if (value < max) return static_cast<uint32_t>(value);
265 return max;
266}
267
269 if (IsSmi(number)) return Smi::ToInt(number);
270 double d = Cast<HeapNumber>(number)->value();
271 if (std::isnan(d)) return 0;
272 if (d >= static_cast<double>(std::numeric_limits<int64_t>::max())) {
273 return std::numeric_limits<int64_t>::max();
274 }
275 if (d <= static_cast<double>(std::numeric_limits<int64_t>::min())) {
276 return std::numeric_limits<int64_t>::min();
277 }
278 return static_cast<int64_t>(d);
279}
280
282 if (IsSmi(number)) {
283 int value = Smi::ToInt(number);
284 if (value <= 0) return 0;
285 return value;
286 }
287 double value = Cast<HeapNumber>(number)->value();
288 // Catch all values smaller than 1 and use the double-negation trick for NANs.
289 if (!(value >= 1)) return 0;
290 uint64_t max = std::numeric_limits<uint64_t>::max();
291 if (value < max) return static_cast<uint64_t>(value);
292 return max;
293}
294
295bool TryNumberToSize(Tagged<Object> number, size_t* result) {
296 // Do not create handles in this function! Don't use SealHandleScope because
297 // the function can be used concurrently.
298 if (IsSmi(number)) {
299 int value = Smi::ToInt(number);
300 DCHECK(static_cast<unsigned>(Smi::kMaxValue) <=
301 std::numeric_limits<size_t>::max());
302 if (value >= 0) {
303 *result = static_cast<size_t>(value);
304 return true;
305 }
306 return false;
307 } else {
308 double value = Cast<HeapNumber>(number)->value();
309 // If value is compared directly to the limit, the limit will be
310 // casted to a double and could end up as limit + 1,
311 // because a double might not have enough mantissa bits for it.
312 // So we might as well cast the limit first, and use < instead of <=.
313 double maxSize = static_cast<double>(std::numeric_limits<size_t>::max());
314 if (value >= 0 && value < maxSize) {
315 size_t size = static_cast<size_t>(value);
316#ifdef V8_ENABLE_SANDBOX
317 if (size > kMaxSafeBufferSizeForSandbox) {
318 return false;
319 }
320#endif
321 *result = size;
322 return true;
323 } else {
324 return false;
325 }
326 }
327}
328
330 size_t result = 0;
331 bool is_valid = TryNumberToSize(number, &result);
332 CHECK(is_valid);
333 return result;
334}
335
336uint32_t DoubleToUint32(double x) {
337 return static_cast<uint32_t>(DoubleToInt32(x));
338}
339
340} // namespace internal
341} // namespace v8
342
343#endif // V8_NUMBERS_CONVERSIONS_INL_H_
static constexpr int kSignificandSize
Definition double.h:33
static constexpr int ToInt(const Tagged< Object > object)
Definition smi.h:33
static bool constexpr IsValid(T value)
Definition smi.h:67
static constexpr int kMinValue
Definition smi.h:100
static constexpr int kMaxValue
Definition smi.h:101
ZoneVector< RpoNumber > & result
int x
V8_INLINE Dest bit_cast(Source const &source)
Definition macros.h:95
bool IsUint32Double(double value)
constexpr int kMinInt
Definition globals.h:375
uint32_t DoubleToUint32(double x)
constexpr double kMaxSafeInteger
Definition globals.h:1985
constexpr uint64_t kFP64SignMask
Definition conversions.h:30
uint32_t PositiveNumberToUint32(Tagged< Object > number)
bool DoubleToUint32IfEqualToSelf(double value, uint32_t *uint32_value)
bool DoubleToSmiInteger(double value, int *smi_int_value)
bool IsSmiDouble(double value)
unsigned int FastD2UI(double x)
int64_t NumberToInt64(Tagged< Object > number)
double DoubleToInteger(double x)
bool IsInt32Double(double value)
V8_INLINE constexpr bool IsSmi(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:665
double FastI2D(int x)
constexpr int kFP16MantissaBits
Definition conversions.h:39
constexpr uint64_t kFP64Infinity
Definition conversions.h:32
constexpr uint64_t kFP16InfinityAndNaNInfimum
Definition conversions.h:33
uint32_t NumberToUint32(Tagged< Object > number)
int32_t NumberToInt32(Tagged< Object > number)
constexpr int kInt32Size
Definition globals.h:401
constexpr uint16_t kFP16Infinity
Definition conversions.h:41
int32_t DoubleToInt32(double x)
constexpr uint64_t kFP16DenormalThreshold
Definition conversions.h:36
int FastD2I(double x)
float DoubleToFloat32(double x)
uint64_t DoubleToWebIDLUint64(double x)
uint16_t DoubleToFloat16(double value)
return value
Definition map-inl.h:893
double FastUI2D(unsigned x)
static bool IsMinusZero(double value)
constexpr int kFP64MantissaBits
Definition conversions.h:28
uint64_t PositiveNumberToUint64(Tagged< Object > number)
int64_t DoubleToWebIDLInt64(double x)
constexpr int kMaxInt
Definition globals.h:374
constexpr double kMinSafeInteger
Definition globals.h:1987
constexpr uint16_t kFP16qNaN
Definition conversions.h:40
size_t NumberToSize(Tagged< Object > number)
constexpr uint64_t kFP64To16RebiasExponentAndRound
Definition conversions.h:53
bool TryNumberToSize(Tagged< Object > number, size_t *result)
constexpr uint32_t kMaxUInt32
Definition globals.h:387
constexpr uint64_t kFP64To16DenormalMagic
Definition conversions.h:59
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
#define CHECK(condition)
Definition logging.h:124
#define DCHECK(condition)
Definition logging.h:482