• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_CONVERSIONS_INL_H_
6 #define V8_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/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/platform/platform.h"
19 #include "src/conversions.h"
20 #include "src/double.h"
21 #include "src/objects-inl.h"
22 
23 namespace v8 {
24 namespace internal {
25 
26 // The fast double-to-unsigned-int conversion routine does not guarantee
27 // rounding towards zero, or any reasonable value if the argument is larger
28 // than what fits in an unsigned 32-bit integer.
FastD2UI(double x)29 inline unsigned int FastD2UI(double x) {
30   // There is no unsigned version of lrint, so there is no fast path
31   // in this function as there is in FastD2I. Using lrint doesn't work
32   // for values of 2^31 and above.
33 
34   // Convert "small enough" doubles to uint32_t by fixing the 32
35   // least significant non-fractional bits in the low 32 bits of the
36   // double, and reading them from there.
37   const double k2Pow52 = 4503599627370496.0;
38   bool negative = x < 0;
39   if (negative) {
40     x = -x;
41   }
42   if (x < k2Pow52) {
43     x += k2Pow52;
44     uint32_t result;
45 #ifndef V8_TARGET_BIG_ENDIAN
46     void* mantissa_ptr = reinterpret_cast<void*>(&x);
47 #else
48     void* mantissa_ptr =
49         reinterpret_cast<void*>(reinterpret_cast<Address>(&x) + kInt32Size);
50 #endif
51     // Copy least significant 32 bits of mantissa.
52     memcpy(&result, mantissa_ptr, sizeof(result));
53     return negative ? ~result + 1 : result;
54   }
55   // Large number (outside uint32 range), Infinity or NaN.
56   return 0x80000000u;  // Return integer indefinite.
57 }
58 
59 
DoubleToFloat32(double x)60 inline float DoubleToFloat32(double x) {
61   // TODO(yangguo): This static_cast is implementation-defined behaviour in C++,
62   // so we may need to do the conversion manually instead to match the spec.
63   volatile float f = static_cast<float>(x);
64   return f;
65 }
66 
67 
DoubleToInteger(double x)68 inline double DoubleToInteger(double x) {
69   if (std::isnan(x)) return 0;
70   if (!std::isfinite(x) || x == 0) return x;
71   return (x >= 0) ? std::floor(x) : std::ceil(x);
72 }
73 
74 
DoubleToInt32(double x)75 int32_t DoubleToInt32(double x) {
76   if ((std::isfinite(x)) && (x <= INT_MAX) && (x >= INT_MIN)) {
77     int32_t i = static_cast<int32_t>(x);
78     if (FastI2D(i) == x) return i;
79   }
80   Double d(x);
81   int exponent = d.Exponent();
82   if (exponent < 0) {
83     if (exponent <= -Double::kSignificandSize) return 0;
84     return d.Sign() * static_cast<int32_t>(d.Significand() >> -exponent);
85   } else {
86     if (exponent > 31) return 0;
87     return d.Sign() * static_cast<int32_t>(d.Significand() << exponent);
88   }
89 }
90 
DoubleToSmiInteger(double value,int * smi_int_value)91 bool DoubleToSmiInteger(double value, int* smi_int_value) {
92   if (!IsSmiDouble(value)) return false;
93   *smi_int_value = FastD2I(value);
94   DCHECK(Smi::IsValid(*smi_int_value));
95   return true;
96 }
97 
IsSmiDouble(double value)98 bool IsSmiDouble(double value) {
99   return value >= Smi::kMinValue && value <= Smi::kMaxValue &&
100          !IsMinusZero(value) && value == FastI2D(FastD2I(value));
101 }
102 
103 
IsInt32Double(double value)104 bool IsInt32Double(double value) {
105   return value >= kMinInt && value <= kMaxInt && !IsMinusZero(value) &&
106          value == FastI2D(FastD2I(value));
107 }
108 
109 
IsUint32Double(double value)110 bool IsUint32Double(double value) {
111   return !IsMinusZero(value) && value >= 0 && value <= kMaxUInt32 &&
112          value == FastUI2D(FastD2UI(value));
113 }
114 
DoubleToUint32IfEqualToSelf(double value,uint32_t * uint32_value)115 bool DoubleToUint32IfEqualToSelf(double value, uint32_t* uint32_value) {
116   const double k2Pow52 = 4503599627370496.0;
117   const uint32_t kValidTopBits = 0x43300000;
118   const uint64_t kBottomBitMask = V8_2PART_UINT64_C(0x00000000, FFFFFFFF);
119 
120   // Add 2^52 to the double, to place valid uint32 values in the low-significant
121   // bits of the exponent, by effectively setting the (implicit) top bit of the
122   // significand. Note that this addition also normalises 0.0 and -0.0.
123   double shifted_value = value + k2Pow52;
124 
125   // At this point, a valid uint32 valued double will be represented as:
126   //
127   // sign = 0
128   // exponent = 52
129   // significand = 1. 00...00 <value>
130   //       implicit^          ^^^^^^^ 32 bits
131   //                  ^^^^^^^^^^^^^^^ 52 bits
132   //
133   // Therefore, we can first check the top 32 bits to make sure that the sign,
134   // exponent and remaining significand bits are valid, and only then check the
135   // value in the bottom 32 bits.
136 
137   uint64_t result = bit_cast<uint64_t>(shifted_value);
138   if ((result >> 32) == kValidTopBits) {
139     *uint32_value = result & kBottomBitMask;
140     return FastUI2D(result & kBottomBitMask) == value;
141   }
142   return false;
143 }
144 
NumberToInt32(Object * number)145 int32_t NumberToInt32(Object* number) {
146   if (number->IsSmi()) return Smi::ToInt(number);
147   return DoubleToInt32(number->Number());
148 }
149 
NumberToUint32(Object * number)150 uint32_t NumberToUint32(Object* number) {
151   if (number->IsSmi()) return Smi::ToInt(number);
152   return DoubleToUint32(number->Number());
153 }
154 
PositiveNumberToUint32(Object * number)155 uint32_t PositiveNumberToUint32(Object* number) {
156   if (number->IsSmi()) {
157     int value = Smi::ToInt(number);
158     if (value <= 0) return 0;
159     return value;
160   }
161   DCHECK(number->IsHeapNumber());
162   double value = number->Number();
163   // Catch all values smaller than 1 and use the double-negation trick for NANs.
164   if (!(value >= 1)) return 0;
165   uint32_t max = std::numeric_limits<uint32_t>::max();
166   if (value < max) return static_cast<uint32_t>(value);
167   return max;
168 }
169 
NumberToInt64(Object * number)170 int64_t NumberToInt64(Object* number) {
171   if (number->IsSmi()) return Smi::ToInt(number);
172   double d = number->Number();
173   if (std::isnan(d)) return 0;
174   if (d >= static_cast<double>(std::numeric_limits<int64_t>::max())) {
175     return std::numeric_limits<int64_t>::max();
176   }
177   if (d <= static_cast<double>(std::numeric_limits<int64_t>::min())) {
178     return std::numeric_limits<int64_t>::min();
179   }
180   return static_cast<int64_t>(d);
181 }
182 
PositiveNumberToUint64(Object * number)183 uint64_t PositiveNumberToUint64(Object* number) {
184   if (number->IsSmi()) {
185     int value = Smi::ToInt(number);
186     if (value <= 0) return 0;
187     return value;
188   }
189   DCHECK(number->IsHeapNumber());
190   double value = number->Number();
191   // Catch all values smaller than 1 and use the double-negation trick for NANs.
192   if (!(value >= 1)) return 0;
193   uint64_t max = std::numeric_limits<uint64_t>::max();
194   if (value < max) return static_cast<uint64_t>(value);
195   return max;
196 }
197 
TryNumberToSize(Object * number,size_t * result)198 bool TryNumberToSize(Object* number, size_t* result) {
199   // Do not create handles in this function! Don't use SealHandleScope because
200   // the function can be used concurrently.
201   if (number->IsSmi()) {
202     int value = Smi::ToInt(number);
203     DCHECK(static_cast<unsigned>(Smi::kMaxValue) <=
204            std::numeric_limits<size_t>::max());
205     if (value >= 0) {
206       *result = static_cast<size_t>(value);
207       return true;
208     }
209     return false;
210   } else {
211     DCHECK(number->IsHeapNumber());
212     double value = HeapNumber::cast(number)->value();
213     // If value is compared directly to the limit, the limit will be
214     // casted to a double and could end up as limit + 1,
215     // because a double might not have enough mantissa bits for it.
216     // So we might as well cast the limit first, and use < instead of <=.
217     double maxSize = static_cast<double>(std::numeric_limits<size_t>::max());
218     if (value >= 0 && value < maxSize) {
219       *result = static_cast<size_t>(value);
220       return true;
221     } else {
222       return false;
223     }
224   }
225 }
226 
NumberToSize(Object * number)227 size_t NumberToSize(Object* number) {
228   size_t result = 0;
229   bool is_valid = TryNumberToSize(number, &result);
230   CHECK(is_valid);
231   return result;
232 }
233 
234 
DoubleToUint32(double x)235 uint32_t DoubleToUint32(double x) {
236   return static_cast<uint32_t>(DoubleToInt32(x));
237 }
238 
239 }  // namespace internal
240 }  // namespace v8
241 
242 #endif  // V8_CONVERSIONS_INL_H_
243