blob: 21f90a50ae5cca14b39096785297b09cf3465473 [file] [log] [blame]
 // Copyright 2011 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_CONVERSIONS_INL_H_ #define V8_CONVERSIONS_INL_H_ #include // Required for DBL_MAX and on Win32 for finite() #include // Required for INT_MAX etc. #include #include #include "src/globals.h" // Required for V8_INFINITY // ---------------------------------------------------------------------------- // Extra POSIX/ANSI functions for Win32/MSVC. #include "src/base/bits.h" #include "src/base/platform/platform.h" #include "src/conversions.h" #include "src/double.h" #include "src/objects-inl.h" namespace v8 { namespace internal { // The fast double-to-unsigned-int conversion routine does not guarantee // rounding towards zero, or any reasonable value if the argument is larger // than what fits in an unsigned 32-bit integer. inline unsigned int FastD2UI(double x) { // 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; #ifndef V8_TARGET_BIG_ENDIAN Address mantissa_ptr = reinterpret_cast
(&x); #else Address mantissa_ptr = reinterpret_cast
(&x) + kInt32Size; #endif // Copy least significant 32 bits of mantissa. memcpy(&result, mantissa_ptr, sizeof(result)); return negative ? ~result + 1 : result; } // Large number (outside uint32 range), Infinity or NaN. return 0x80000000u; // Return integer indefinite. } inline float DoubleToFloat32(double x) { // TODO(yangguo): This static_cast is implementation-defined behaviour in C++, // so we may need to do the conversion manually instead to match the spec. volatile float f = static_cast(x); return f; } inline double DoubleToInteger(double x) { if (std::isnan(x)) return 0; if (!std::isfinite(x) || x == 0) return x; return (x >= 0) ? std::floor(x) : std::ceil(x); } int32_t DoubleToInt32(double x) { int32_t i = FastD2I(x); if (FastI2D(i) == x) return i; Double d(x); int exponent = d.Exponent(); if (exponent < 0) { if (exponent <= -Double::kSignificandSize) return 0; return d.Sign() * static_cast(d.Significand() >> -exponent); } else { if (exponent > 31) return 0; return d.Sign() * static_cast(d.Significand() << exponent); } } bool DoubleToSmiInteger(double value, int* smi_int_value) { if (IsMinusZero(value)) return false; int i = FastD2IChecked(value); if (value != i || !Smi::IsValid(i)) return false; *smi_int_value = i; return true; } bool IsSmiDouble(double value) { return !IsMinusZero(value) && value >= Smi::kMinValue && value <= Smi::kMaxValue && value == FastI2D(FastD2I(value)); } bool IsInt32Double(double value) { return !IsMinusZero(value) && value >= kMinInt && value <= kMaxInt && value == FastI2D(FastD2I(value)); } bool IsUint32Double(double value) { return !IsMinusZero(value) && value >= 0 && value <= kMaxUInt32 && value == FastUI2D(FastD2UI(value)); } bool DoubleToUint32IfEqualToSelf(double value, uint32_t* uint32_value) { const double k2Pow52 = 4503599627370496.0; const uint32_t kValidTopBits = 0x43300000; const uint64_t kBottomBitMask = V8_2PART_UINT64_C(0x00000000, FFFFFFFF); // 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 // 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(shifted_value); if ((result >> 32) == kValidTopBits) { *uint32_value = result & kBottomBitMask; return FastUI2D(result & kBottomBitMask) == value; } return false; } int32_t NumberToInt32(Object* number) { if (number->IsSmi()) return Smi::ToInt(number); return DoubleToInt32(number->Number()); } uint32_t NumberToUint32(Object* number) { if (number->IsSmi()) return Smi::ToInt(number); return DoubleToUint32(number->Number()); } uint32_t PositiveNumberToUint32(Object* number) { if (number->IsSmi()) { int value = Smi::ToInt(number); if (value <= 0) return 0; return value; } DCHECK(number->IsHeapNumber()); double value = number->Number(); // 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::max(); if (value < max) return static_cast(value); return max; } int64_t NumberToInt64(Object* number) { if (number->IsSmi()) return Smi::ToInt(number); double d = number->Number(); if (std::isnan(d)) return 0; if (d >= static_cast(std::numeric_limits::max())) { return std::numeric_limits::max(); } if (d <= static_cast(std::numeric_limits::min())) { return std::numeric_limits::min(); } return static_cast(d); } uint64_t PositiveNumberToUint64(Object* number) { if (number->IsSmi()) { int value = Smi::ToInt(number); if (value <= 0) return 0; return value; } DCHECK(number->IsHeapNumber()); double value = number->Number(); // 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::max(); if (value < max) return static_cast(value); return max; } bool TryNumberToSize(Object* number, size_t* result) { // Do not create handles in this function! Don't use SealHandleScope because // the function can be used concurrently. if (number->IsSmi()) { int value = Smi::ToInt(number); DCHECK(static_cast(Smi::kMaxValue) <= std::numeric_limits::max()); if (value >= 0) { *result = static_cast(value); return true; } return false; } else { DCHECK(number->IsHeapNumber()); double value = HeapNumber::cast(number)->value(); // 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(std::numeric_limits::max()); if (value >= 0 && value < maxSize) { *result = static_cast(value); return true; } else { return false; } } } size_t NumberToSize(Object* number) { size_t result = 0; bool is_valid = TryNumberToSize(number, &result); CHECK(is_valid); return result; } uint32_t DoubleToUint32(double x) { return static_cast(DoubleToInt32(x)); } } // namespace internal } // namespace v8 #endif // V8_CONVERSIONS_INL_H_