conversions-inl.h 8.63 KB
Newer Older
1
// Copyright 2011 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5 6
#ifndef V8_NUMBERS_CONVERSIONS_INL_H_
#define V8_NUMBERS_CONVERSIONS_INL_H_
7

8 9
#include <float.h>   // Required for DBL_MAX and on Win32 for finite()
#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 16

// ----------------------------------------------------------------------------
// Extra POSIX/ANSI functions for Win32/MSVC.

17
#include "src/base/bits.h"
18
#include "src/base/platform/platform.h"
19
#include "src/base/platform/wrappers.h"
20 21
#include "src/numbers/conversions.h"
#include "src/numbers/double.h"
22
#include "src/objects/heap-number-inl.h"
23
#include "src/objects/objects-inl.h"
24

25 26
namespace v8 {
namespace internal {
27

28
// The fast double-to-unsigned-int conversion routine does not guarantee
29 30
// rounding towards zero, or any reasonable value if the argument is larger
// than what fits in an unsigned 32-bit integer.
31
inline unsigned int FastD2UI(double x) {
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
  // There is no unsigned version of lrint, so there is no fast path
  // in this function as there is in FastD2I. Using lrint doesn't work
  // for values of 2^31 and above.

  // Convert "small enough" doubles to uint32_t by fixing the 32
  // least significant non-fractional bits in the low 32 bits of the
  // double, and reading them from there.
  const double k2Pow52 = 4503599627370496.0;
  bool negative = x < 0;
  if (negative) {
    x = -x;
  }
  if (x < k2Pow52) {
    x += k2Pow52;
    uint32_t result;
47
#ifndef V8_TARGET_BIG_ENDIAN
48
    void* mantissa_ptr = reinterpret_cast<void*>(&x);
49
#else
50 51
    void* mantissa_ptr =
        reinterpret_cast<void*>(reinterpret_cast<Address>(&x) + kInt32Size);
52
#endif
53
    // Copy least significant 32 bits of mantissa.
54
    base::Memcpy(&result, mantissa_ptr, sizeof(result));
55 56 57 58 59 60
    return negative ? ~result + 1 : result;
  }
  // Large number (outside uint32 range), Infinity or NaN.
  return 0x80000000u;  // Return integer indefinite.
}

61
inline float DoubleToFloat32(double x) {
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
  using limits = std::numeric_limits<float>;
  if (x > limits::max()) {
    // kRoundingThreshold is the maximum double that rounds down to
    // the maximum representable float. Its mantissa bits are:
    // 1111111111111111111111101111111111111111111111111111
    // [<--- float range --->]
    // Note the zero-bit right after the float mantissa range, which
    // determines the rounding-down.
    static const double kRoundingThreshold = 3.4028235677973362e+38;
    if (x <= kRoundingThreshold) return limits::max();
    return limits::infinity();
  }
  if (x < limits::lowest()) {
    // Same as above, mirrored to negative numbers.
    static const double kRoundingThreshold = -3.4028235677973362e+38;
    if (x >= kRoundingThreshold) return limits::lowest();
    return -limits::infinity();
  }
80
  return static_cast<float>(x);
81 82
}

83
inline double DoubleToInteger(double x) {
84
  if (std::isnan(x)) return 0;
85 86 87
  if (!std::isfinite(x)) return x;
  // ToInteger normalizes -0 to +0.
  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.
92
int32_t DoubleToInt32(double x) {
93 94 95 96
  if ((std::isfinite(x)) && (x <= INT_MAX) && (x >= INT_MIN)) {
    int32_t i = static_cast<int32_t>(x);
    if (FastI2D(i) == x) return i;
  }
97 98
  Double d(x);
  int exponent = d.Exponent();
99
  uint64_t bits;
100 101
  if (exponent < 0) {
    if (exponent <= -Double::kSignificandSize) return 0;
102
    bits = d.Significand() >> -exponent;
103 104
  } else {
    if (exponent > 31) return 0;
105 106 107 108
    // Masking to a 32-bit value ensures that the result of the
    // static_cast<int64_t> below is not the minimal int64_t value,
    // which would overflow on multiplication with d.Sign().
    bits = (d.Significand() << exponent) & 0xFFFFFFFFul;
109
  }
110
  return static_cast<int32_t>(d.Sign() * static_cast<int64_t>(bits));
111 112
}

113
bool DoubleToSmiInteger(double value, int* smi_int_value) {
114 115 116
  if (!IsSmiDouble(value)) return false;
  *smi_int_value = FastD2I(value);
  DCHECK(Smi::IsValid(*smi_int_value));
117 118
  return true;
}
119

120
bool IsSmiDouble(double value) {
121 122
  return value >= Smi::kMinValue && value <= Smi::kMaxValue &&
         !IsMinusZero(value) && value == FastI2D(FastD2I(value));
123 124 125
}

bool IsInt32Double(double value) {
126 127
  return value >= kMinInt && value <= kMaxInt && !IsMinusZero(value) &&
         value == FastI2D(FastD2I(value));
128 129 130 131 132 133 134
}

bool IsUint32Double(double value) {
  return !IsMinusZero(value) && value >= 0 && value <= kMaxUInt32 &&
         value == FastUI2D(FastD2UI(value));
}

135
bool DoubleToUint32IfEqualToSelf(double value, uint32_t* uint32_value) {
136 137
  const double k2Pow52 = 4503599627370496.0;
  const uint32_t kValidTopBits = 0x43300000;
138
  const uint64_t kBottomBitMask = 0x0000'0000'FFFF'FFFF;
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160

  // Add 2^52 to the double, to place valid uint32 values in the low-significant
  // bits of the exponent, by effectively setting the (implicit) top bit of the
  // significand. Note that this addition also normalises 0.0 and -0.0.
  double shifted_value = value + k2Pow52;

  // At this point, a valid uint32 valued double will be represented as:
  //
  // sign = 0
  // exponent = 52
  // significand = 1. 00...00 <value>
  //       implicit^          ^^^^^^^ 32 bits
  //                  ^^^^^^^^^^^^^^^ 52 bits
  //
  // Therefore, we can first check the top 32 bits to make sure that the sign,
  // exponent and remaining significand bits are valid, and only then check the
  // value in the bottom 32 bits.

  uint64_t result = bit_cast<uint64_t>(shifted_value);
  if ((result >> 32) == kValidTopBits) {
    *uint32_value = result & kBottomBitMask;
    return FastUI2D(result & kBottomBitMask) == value;
161 162 163
  }
  return false;
}
164

165
int32_t NumberToInt32(Object number) {
166 167
  if (number.IsSmi()) return Smi::ToInt(number);
  return DoubleToInt32(number.Number());
168 169
}

170
uint32_t NumberToUint32(Object number) {
171 172
  if (number.IsSmi()) return Smi::ToInt(number);
  return DoubleToUint32(number.Number());
173 174
}

175
uint32_t PositiveNumberToUint32(Object number) {
176
  if (number.IsSmi()) {
jgruber's avatar
jgruber committed
177
    int value = Smi::ToInt(number);
178 179 180
    if (value <= 0) return 0;
    return value;
  }
181 182
  DCHECK(number.IsHeapNumber());
  double value = number.Number();
183 184 185 186 187 188 189
  // Catch all values smaller than 1 and use the double-negation trick for NANs.
  if (!(value >= 1)) return 0;
  uint32_t max = std::numeric_limits<uint32_t>::max();
  if (value < max) return static_cast<uint32_t>(value);
  return max;
}

190
int64_t NumberToInt64(Object number) {
191 192
  if (number.IsSmi()) return Smi::ToInt(number);
  double d = number.Number();
193 194 195 196 197 198 199 200
  if (std::isnan(d)) return 0;
  if (d >= static_cast<double>(std::numeric_limits<int64_t>::max())) {
    return std::numeric_limits<int64_t>::max();
  }
  if (d <= static_cast<double>(std::numeric_limits<int64_t>::min())) {
    return std::numeric_limits<int64_t>::min();
  }
  return static_cast<int64_t>(d);
201
}
202

203
uint64_t PositiveNumberToUint64(Object number) {
204
  if (number.IsSmi()) {
205 206 207 208
    int value = Smi::ToInt(number);
    if (value <= 0) return 0;
    return value;
  }
209 210
  DCHECK(number.IsHeapNumber());
  double value = number.Number();
211 212 213 214 215 216 217
  // Catch all values smaller than 1 and use the double-negation trick for NANs.
  if (!(value >= 1)) return 0;
  uint64_t max = std::numeric_limits<uint64_t>::max();
  if (value < max) return static_cast<uint64_t>(value);
  return max;
}

218
bool TryNumberToSize(Object number, size_t* result) {
219 220
  // Do not create handles in this function! Don't use SealHandleScope because
  // the function can be used concurrently.
221
  if (number.IsSmi()) {
jgruber's avatar
jgruber committed
222
    int value = Smi::ToInt(number);
223 224 225 226 227 228 229 230
    DCHECK(static_cast<unsigned>(Smi::kMaxValue) <=
           std::numeric_limits<size_t>::max());
    if (value >= 0) {
      *result = static_cast<size_t>(value);
      return true;
    }
    return false;
  } else {
231 232
    DCHECK(number.IsHeapNumber());
    double value = HeapNumber::cast(number).value();
233 234 235 236 237 238
    // If value is compared directly to the limit, the limit will be
    // casted to a double and could end up as limit + 1,
    // because a double might not have enough mantissa bits for it.
    // So we might as well cast the limit first, and use < instead of <=.
    double maxSize = static_cast<double>(std::numeric_limits<size_t>::max());
    if (value >= 0 && value < maxSize) {
239 240 241 242 243 244 245 246
      *result = static_cast<size_t>(value);
      return true;
    } else {
      return false;
    }
  }
}

247
size_t NumberToSize(Object number) {
248
  size_t result = 0;
249
  bool is_valid = TryNumberToSize(number, &result);
250 251 252 253
  CHECK(is_valid);
  return result;
}

254 255 256 257
uint32_t DoubleToUint32(double x) {
  return static_cast<uint32_t>(DoubleToInt32(x));
}

258 259
}  // namespace internal
}  // namespace v8
260

261
#endif  // V8_NUMBERS_CONVERSIONS_INL_H_