text: // 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 <float.h>         // Required for DBL_MAX and on Win32 for finite()
  #include <limits.h>        // Required for INT_MAX etc.
  #include <stdarg.h>
  #include <cmath>
  #include "src/globals.h"       // Required for V8_INFINITY
  #include "src/unicode-cache-inl.h"
  
  // ----------------------------------------------------------------------------
  // 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"
  #include "src/strtod.h"
  
  namespace v8 {
  namespace internal {
  
  inline double JunkStringValue() {
    return bit_cast<double, uint64_t>(kQuietNaNMask);
  }
  
  
  inline double SignedZero(bool negative) {
    return negative ? uint64_to_double(Double::kSignMask) : 0.0;
  }
  
  
  // 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<Address>(&x);
  #else
      Address mantissa_ptr = reinterpret_cast<Address>(&x) + kIntSize;
  #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<float>(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<int32_t>(d.Significand() >> -exponent);
    } else {
      if (exponent > 31) return 0;
      return d.Sign() * static_cast<int32_t>(d.Significand() << exponent);
    }
  }
  
  
  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));
  }
  
  
  int32_t NumberToInt32(Object* number) {
    if (number->IsSmi()) return Smi::cast(number)->value();
    return DoubleToInt32(number->Number());
  }
  
  
  uint32_t NumberToUint32(Object* number) {
    if (number->IsSmi()) return Smi::cast(number)->value();
    return DoubleToUint32(number->Number());
  }
  
  
  bool TryNumberToSize(Isolate* isolate, Object* number, size_t* result) {
    SealHandleScope shs(isolate);
    if (number->IsSmi()) {
      int value = Smi::cast(number)->value();
      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 {
      DCHECK(number->IsHeapNumber());
      double value = HeapNumber::cast(number)->value();
      if (value >= 0 && value <= std::numeric_limits<size_t>::max()) {
        *result = static_cast<size_t>(value);
        return true;
      } else {
        return false;
      }
    }
  }
  
  
  size_t NumberToSize(Isolate* isolate, Object* number) {
    size_t result = 0;
    bool is_valid = TryNumberToSize(isolate, number, &result);
    CHECK(is_valid);
    return result;
  }
  
  
  uint32_t DoubleToUint32(double x) {
    return static_cast<uint32_t>(DoubleToInt32(x));
  }
  
  
  template <class Iterator, class EndMark>
  bool SubStringEquals(Iterator* current,
                       EndMark end,
                       const char* substring) {
    DCHECK(**current == *substring);
    for (substring++; *substring != '\0'; substring++) {
      ++*current;
      if (*current == end || **current != *substring) return false;
    }
    ++*current;
    return true;
  }
  
  
  // Returns true if a nonspace character has been found and false if the
  // end was been reached before finding a nonspace character.
  template <class Iterator, class EndMark>
  inline bool AdvanceToNonspace(UnicodeCache* unicode_cache,
                                Iterator* current,
                                EndMark end) {
    while (*current != end) {
      if (!unicode_cache->IsWhiteSpaceOrLineTerminator(**current)) return true;
      ++*current;
    }
    return false;
  }
  
  
  // Parsing integers with radix 2, 4, 8, 16, 32. Assumes current != end.
  template <int radix_log_2, class Iterator, class EndMark>
  double InternalStringToIntDouble(UnicodeCache* unicode_cache,
                                   Iterator current,
                                   EndMark end,
                                   bool negative,
                                   bool allow_trailing_junk) {
    DCHECK(current != end);
  
    // Skip leading 0s.
    while (*current == '0') {
      ++current;
      if (current == end) return SignedZero(negative);
    }
  
    int64_t number = 0;
    int exponent = 0;
    const int radix = (1 << radix_log_2);
  
    do {
      int digit;
      if (*current >= '0' && *current <= '9' && *current < '0' + radix) {
        digit = static_cast<char>(*current) - '0';
      } else if (radix > 10 && *current >= 'a' && *current < 'a' + radix - 10) {
        digit = static_cast<char>(*current) - 'a' + 10;
      } else if (radix > 10 && *current >= 'A' && *current < 'A' + radix - 10) {
        digit = static_cast<char>(*current) - 'A' + 10;
      } else {
        if (allow_trailing_junk ||
            !AdvanceToNonspace(unicode_cache, &current, end)) {
          break;
        } else {
          return JunkStringValue();
        }
      }
  
      number = number * radix + digit;
      int overflow = static_cast<int>(number >> 53);
      if (overflow != 0) {
        // Overflow occurred. Need to determine which direction to round the
        // result.
        int overflow_bits_count = 1;
        while (overflow > 1) {
          overflow_bits_count++;
          overflow >>= 1;
        }
  
        int dropped_bits_mask = ((1 << overflow_bits_count) - 1);
        int dropped_bits = static_cast<int>(number) & dropped_bits_mask;
        number >>= overflow_bits_count;
        exponent = overflow_bits_count;
  
        bool zero_tail = true;
        while (true) {
          ++current;
          if (current == end || !isDigit(*current, radix)) break;
          zero_tail = zero_tail && *current == '0';
          exponent += radix_log_2;
        }
  
        if (!allow_trailing_junk &&
            AdvanceToNonspace(unicode_cache, &current, end)) {
          return JunkStringValue();
        }
  
        int middle_value = (1 << (overflow_bits_count - 1));
        if (dropped_bits > middle_value) {
          number++;  // Rounding up.
        } else if (dropped_bits == middle_value) {
          // Rounding to even to consistency with decimals: half-way case rounds
          // up if significant part is odd and down otherwise.
          if ((number & 1) != 0 || !zero_tail) {
            number++;  // Rounding up.
          }
        }
  
        // Rounding up may cause overflow.
        if ((number & (static_cast<int64_t>(1) << 53)) != 0) {
          exponent++;
          number >>= 1;
        }
        break;
      }
      ++current;
    } while (current != end);
  
    DCHECK(number < ((int64_t)1 << 53));
    DCHECK(static_cast<int64_t>(static_cast<double>(number)) == number);
  
    if (exponent == 0) {
      if (negative) {
        if (number == 0) return -0.0;
        number = -number;
      }
      return static_cast<double>(number);
    }
  
    DCHECK(number != 0);
    return std::ldexp(static_cast<double>(negative ? -number : number), exponent);
  }
  
  
  template <class Iterator, class EndMark>
  double InternalStringToInt(UnicodeCache* unicode_cache,
                             Iterator current,
                             EndMark end,
                             int radix) {
    const bool allow_trailing_junk = true;
    const double empty_string_val = JunkStringValue();
  
    if (!AdvanceToNonspace(unicode_cache, &current, end)) {
      return empty_string_val;
    }
  
    bool negative = false;
    bool leading_zero = false;
  
    if (*current == '+') {
      // Ignore leading sign; skip following spaces.
      ++current;
      if (current == end) {
        return JunkStringValue();
      }
    } else if (*current == '-') {
      ++current;
      if (current == end) {
        return JunkStringValue();
      }
      negative = true;
    }
  
    if (radix == 0) {
      // Radix detection.
      radix = 10;
      if (*current == '0') {
        ++current;
        if (current == end) return SignedZero(negative);
        if (*current == 'x' || *current == 'X') {
          radix = 16;
          ++current;
          if (current == end) return JunkStringValue();
        } else {
          leading_zero = true;
        }
      }
    } else if (radix == 16) {
      if (*current == '0') {
        // Allow "0x" prefix.
        ++current;
        if (current == end) return SignedZero(negative);
        if (*current == 'x' || *current == 'X') {
          ++current;
          if (current == end) return JunkStringValue();
        } else {
          leading_zero = true;
        }
      }
    }
  
    if (radix < 2 || radix > 36) return JunkStringValue();
  
    // Skip leading zeros.
    while (*current == '0') {
      leading_zero = true;
      ++current;
      if (current == end) return SignedZero(negative);
    }
  
    if (!leading_zero && !isDigit(*current, radix)) {
      return JunkStringValue();
    }
  
    if (base::bits::IsPowerOfTwo32(radix)) {
      switch (radix) {
        case 2:
          return InternalStringToIntDouble<1>(
              unicode_cache, current, end, negative, allow_trailing_junk);
        case 4:
          return InternalStringToIntDouble<2>(
              unicode_cache, current, end, negative, allow_trailing_junk);
        case 8:
          return InternalStringToIntDouble<3>(
              unicode_cache, current, end, negative, allow_trailing_junk);
  
        case 16:
          return InternalStringToIntDouble<4>(
              unicode_cache, current, end, negative, allow_trailing_junk);
  
        case 32:
          return InternalStringToIntDouble<5>(
              unicode_cache, current, end, negative, allow_trailing_junk);
        default:
          UNREACHABLE();
      }
    }
  
    if (radix == 10) {
      // Parsing with strtod.
      const int kMaxSignificantDigits = 309;  // Doubles are less than 1.8e308.
      // The buffer may contain up to kMaxSignificantDigits + 1 digits and a zero
      // end.
      const int kBufferSize = kMaxSignificantDigits + 2;
      char buffer[kBufferSize];
      int buffer_pos = 0;
      while (*current >= '0' && *current <= '9') {
        if (buffer_pos <= kMaxSignificantDigits) {
          // If the number has more than kMaxSignificantDigits it will be parsed
          // as infinity.
          DCHECK(buffer_pos < kBufferSize);
          buffer[buffer_pos++] = static_cast<char>(*current);
        }
        ++current;
        if (current == end) break;
      }
  
      if (!allow_trailing_junk &&
          AdvanceToNonspace(unicode_cache, &current, end)) {
        return JunkStringValue();
      }
  
      SLOW_DCHECK(buffer_pos < kBufferSize);
      buffer[buffer_pos] = '\0';
      Vector<const char> buffer_vector(buffer, buffer_pos);
      return negative ? -Strtod(buffer_vector, 0) : Strtod(buffer_vector, 0);
    }
  
    // The following code causes accumulating rounding error for numbers greater
    // than ~2^56. It's explicitly allowed in the spec: "if R is not 2, 4, 8, 10,
    // 16, or 32, then mathInt may be an implementation-dependent approximation to
    // the mathematical integer value" (15.1.2.2).
  
    int lim_0 = '0' + (radix < 10 ? radix : 10);
    int lim_a = 'a' + (radix - 10);
    int lim_A = 'A' + (radix - 10);
  
    // NOTE: The code for computing the value may seem a bit complex at
    // first glance. It is structured to use 32-bit multiply-and-add
    // loops as long as possible to avoid loosing precision.
  
    double v = 0.0;
    bool done = false;
    do {
      // Parse the longest part of the string starting at index j
      // possible while keeping the multiplier, and thus the part
      // itself, within 32 bits.
      unsigned int part = 0, multiplier = 1;
      while (true) {
        int d;
        if (*current >= '0' && *current < lim_0) {
          d = *current - '0';
        } else if (*current >= 'a' && *current < lim_a) {
          d = *current - 'a' + 10;
        } else if (*current >= 'A' && *current < lim_A) {
          d = *current - 'A' + 10;
        } else {
          done = true;
          break;
        }
  
        // Update the value of the part as long as the multiplier fits
        // in 32 bits. When we can't guarantee that the next iteration
        // will not overflow the multiplier, we stop parsing the part
        // by leaving the loop.
        const unsigned int kMaximumMultiplier = 0xffffffffU / 36;
        uint32_t m = multiplier * radix;
        if (m > kMaximumMultiplier) break;
        part = part * radix + d;
        multiplier = m;
        DCHECK(multiplier > part);
  
        ++current;
        if (current == end) {
          done = true;
          break;
        }
      }
  
      // Update the value and skip the part in the string.
      v = v * multiplier + part;
    } while (!done);
  
    if (!allow_trailing_junk &&
        AdvanceToNonspace(unicode_cache, &current, end)) {
      return JunkStringValue();
    }
  
    return negative ? -v : v;
  }
  
  
  // Converts a string to a double value. Assumes the Iterator supports
  // the following operations:
  // 1. current == end (other ops are not allowed), current != end.
  // 2. *current - gets the current character in the sequence.
  // 3. ++current (advances the position).
  template <class Iterator, class EndMark>
  double InternalStringToDouble(UnicodeCache* unicode_cache,
                                Iterator current,
                                EndMark end,
                                int flags,
                                double empty_string_val) {
    // To make sure that iterator dereferencing is valid the following
    // convention is used:
    // 1. Each '++current' statement is followed by check for equality to 'end'.
    // 2. If AdvanceToNonspace returned false then current == end.
    // 3. If 'current' becomes be equal to 'end' the function returns or goes to
    // 'parsing_done'.
    // 4. 'current' is not dereferenced after the 'parsing_done' label.
    // 5. Code before 'parsing_done' may rely on 'current != end'.
    if (!AdvanceToNonspace(unicode_cache, &current, end)) {
      return empty_string_val;
    }
  
    const bool allow_trailing_junk = (flags & ALLOW_TRAILING_JUNK) != 0;
  
    // The longest form of simplified number is: "-<significant digits>'.1eXXX\0".
    const int kBufferSize = kMaxSignificantDigits + 10;
    char buffer[kBufferSize];  // NOLINT: size is known at compile time.
    int buffer_pos = 0;
  
    // Exponent will be adjusted if insignificant digits of the integer part
    // or insignificant leading zeros of the fractional part are dropped.
    int exponent = 0;
    int significant_digits = 0;
    int insignificant_digits = 0;
    bool nonzero_digit_dropped = false;
  
    enum Sign {
      NONE,
      NEGATIVE,
      POSITIVE
    };
  
    Sign sign = NONE;
  
    if (*current == '+') {
      // Ignore leading sign.
      ++current;
      if (current == end) return JunkStringValue();
      sign = POSITIVE;
    } else if (*current == '-') {
      ++current;
      if (current == end) return JunkStringValue();
      sign = NEGATIVE;
    }
  
    static const char kInfinityString[] = "Infinity";
    if (*current == kInfinityString[0]) {
      if (!SubStringEquals(&current, end, kInfinityString)) {
        return JunkStringValue();
      }
  
      if (!allow_trailing_junk &&
          AdvanceToNonspace(unicode_cache, &current, end)) {
        return JunkStringValue();
      }
  
      DCHECK(buffer_pos == 0);
      return (sign == NEGATIVE) ? -V8_INFINITY : V8_INFINITY;
    }
  
    bool leading_zero = false;
    if (*current == '0') {
      ++current;
      if (current == end) return SignedZero(sign == NEGATIVE);
  
      leading_zero = true;
  
      // It could be hexadecimal value.
      if ((flags & ALLOW_HEX) && (*current == 'x' || *current == 'X')) {
        ++current;
        if (current == end || !isDigit(*current, 16) || sign != NONE) {
          return JunkStringValue();  // "0x".
        }
  
        return InternalStringToIntDouble<4>(unicode_cache,
                                            current,
                                            end,
                                            false,
                                            allow_trailing_junk);
  
      // It could be an explicit octal value.
      } else if ((flags & ALLOW_OCTAL) && (*current == 'o' || *current == 'O')) {
        ++current;
        if (current == end || !isDigit(*current, 8) || sign != NONE) {
          return JunkStringValue();  // "0o".
        }
  
        return InternalStringToIntDouble<3>(unicode_cache,
                                            current,
                                            end,
                                            false,
                                            allow_trailing_junk);
  
      // It could be a binary value.
      } else if ((flags & ALLOW_BINARY) && (*current == 'b' || *current == 'B')) {
        ++current;
        if (current == end || !isBinaryDigit(*current) || sign != NONE) {
          return JunkStringValue();  // "0b".
        }
  
        return InternalStringToIntDouble<1>(unicode_cache,
                                            current,
                                            end,
                                            false,
                                            allow_trailing_junk);
      }
  
      // Ignore leading zeros in the integer part.
      while (*current == '0') {
        ++current;
        if (current == end) return SignedZero(sign == NEGATIVE);
      }
    }
  
    bool octal = leading_zero && (flags & ALLOW_IMPLICIT_OCTAL) != 0;
  
    // Copy significant digits of the integer part (if any) to the buffer.
    while (*current >= '0' && *current <= '9') {
      if (significant_digits < kMaxSignificantDigits) {
        DCHECK(buffer_pos < kBufferSize);
        buffer[buffer_pos++] = static_cast<char>(*current);
        significant_digits++;
        // Will later check if it's an octal in the buffer.
      } else {
        insignificant_digits++;  // Move the digit into the exponential part.
        nonzero_digit_dropped = nonzero_digit_dropped || *current != '0';
      }
      octal = octal && *current < '8';
      ++current;
      if (current == end) goto parsing_done;
    }
  
    if (significant_digits == 0) {
      octal = false;
    }
  
    if (*current == '.') {
      if (octal && !allow_trailing_junk) return JunkStringValue();
      if (octal) goto parsing_done;
  
      ++current;
      if (current == end) {
        if (significant_digits == 0 && !leading_zero) {
          return JunkStringValue();
        } else {
          goto parsing_done;
        }
      }
  
      if (significant_digits == 0) {
        // octal = false;
        // Integer part consists of 0 or is absent. Significant digits start after
        // leading zeros (if any).
        while (*current == '0') {
          ++current;
          if (current == end) return SignedZero(sign == NEGATIVE);
          exponent--;  // Move this 0 into the exponent.
        }
      }
  
      // There is a fractional part.  We don't emit a '.', but adjust the exponent
      // instead.
      while (*current >= '0' && *current <= '9') {
        if (significant_digits < kMaxSignificantDigits) {
          DCHECK(buffer_pos < kBufferSize);
          buffer[buffer_pos++] = static_cast<char>(*current);
          significant_digits++;
          exponent--;
        } else {
          // Ignore insignificant digits in the fractional part.
          nonzero_digit_dropped = nonzero_digit_dropped || *current != '0';
        }
        ++current;
        if (current == end) goto parsing_done;
      }
    }
  
    if (!leading_zero && exponent == 0 && significant_digits == 0) {
      // If leading_zeros is true then the string contains zeros.
      // If exponent < 0 then string was [+-]\.0*...
      // If significant_digits != 0 the string is not equal to 0.
      // Otherwise there are no digits in the string.
      return JunkStringValue();
    }
  
    // Parse exponential part.
    if (*current == 'e' || *current == 'E') {
      if (octal) return JunkStringValue();
      ++current;
      if (current == end) {
        if (allow_trailing_junk) {
          goto parsing_done;
        } else {
          return JunkStringValue();
        }
      }
      char sign = '+';
      if (*current == '+' || *current == '-') {
        sign = static_cast<char>(*current);
        ++current;
        if (current == end) {
          if (allow_trailing_junk) {
            goto parsing_done;
          } else {
            return JunkStringValue();
          }
        }
      }
  
      if (current == end || *current < '0' || *current > '9') {
        if (allow_trailing_junk) {
          goto parsing_done;
        } else {
          return JunkStringValue();
        }
      }
  
      const int max_exponent = INT_MAX / 2;
      DCHECK(-max_exponent / 2 <= exponent && exponent <= max_exponent / 2);
      int num = 0;
      do {
        // Check overflow.
        int digit = *current - '0';
        if (num >= max_exponent / 10
            && !(num == max_exponent / 10 && digit <= max_exponent % 10)) {
          num = max_exponent;
        } else {
          num = num * 10 + digit;
        }
        ++current;
      } while (current != end && *current >= '0' && *current <= '9');
  
      exponent += (sign == '-' ? -num : num);
    }
  
    if (!allow_trailing_junk &&
        AdvanceToNonspace(unicode_cache, &current, end)) {
      return JunkStringValue();
    }
  
    parsing_done:
    exponent += insignificant_digits;
  
    if (octal) {
      return InternalStringToIntDouble<3>(unicode_cache,
                                          buffer,
                                          buffer + buffer_pos,
                                          sign == NEGATIVE,
                                          allow_trailing_junk);
    }
  
    if (nonzero_digit_dropped) {
      buffer[buffer_pos++] = '1';
      exponent--;
    }
  
    SLOW_DCHECK(buffer_pos < kBufferSize);
    buffer[buffer_pos] = '\0';
  
    double converted = Strtod(Vector<const char>(buffer, buffer_pos), exponent);
    return (sign == NEGATIVE) ? -converted : converted;
  }
  
  }  // namespace internal
  }  // namespace v8
  
  #endif  // V8_CONVERSIONS_INL_H_
  