LCOV - code coverage report
Current view: top level - src - conversions-inl.h (source / functions) Hit Total Coverage
Test: app.info Lines: 59 60 98.3 %
Date: 2019-04-17 Functions: 5 5 100.0 %

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

Generated by: LCOV version 1.10