Extract string->double and double->string conversions for use in the preparser.
authorlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 5 Jul 2011 11:54:11 +0000 (11:54 +0000)
committerlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 5 Jul 2011 11:54:11 +0000 (11:54 +0000)
Review URL: http://codereview.chromium.org/7308004

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8534 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

19 files changed:
src/SConscript
src/bignum.cc
src/cached-powers.cc
src/conversions-inl.h
src/conversions.cc
src/conversions.h
src/diy-fp.cc
src/diy-fp.h
src/hydrogen-instructions.h
src/json-parser.h
src/liveobjectlist.cc
src/preparser.cc
src/strtod.cc
src/utils.cc
src/utils.h
src/v8conversions.cc [new file with mode: 0644]
src/v8conversions.h [new file with mode: 0644]
src/v8utils.cc [new file with mode: 0644]
src/v8utils.h

index 5b2f272a52ca982920fdbd927018eafd34b8dce3..4b0ba163410751e370c82cb7057c4ddb3ac7f03b 100755 (executable)
@@ -126,7 +126,9 @@ SOURCES = {
     utils.cc
     v8-counters.cc
     v8.cc
+    v8conversions.cc
     v8threads.cc
+    v8utils.cc
     variables.cc
     version.cc
     zone.cc
@@ -229,13 +231,18 @@ SOURCES = {
 PREPARSER_SOURCES = {
   'all': Split("""
     allocation.cc
+    bignum.cc
+    cached-powers.cc
+    conversions.cc
     hashmap.cc
     preparse-data.cc
     preparser.cc
     preparser-api.cc
     scanner-base.cc
+    strtod.cc
     token.cc
     unicode.cc
+    utils.cc
     """)
 }
 
index a97397455020e280bfc9ed9272b341faa487dac0..9436322ed49b38080875e1a5eceef7861fbc3745 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include "v8.h"
-
-#include "bignum.h"
+#include "../include/v8stdint.h"
 #include "utils.h"
+#include "bignum.h"
 
 namespace v8 {
 namespace internal {
index 43dbc7855e42b50e4800580d6cf9b6386c1d291b..30a67a661b411c24b285824d289c80fca8e59f37 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <stdarg.h>
+#include <math.h>
 #include <limits.h>
 
-#include "v8.h"
-
+#include "../include/v8stdint.h"
+#include "globals.h"
+#include "checks.h"
 #include "cached-powers.h"
 
 namespace v8 {
@@ -147,7 +149,9 @@ void PowersOfTenCache::GetCachedPowerForBinaryExponentRange(
     DiyFp* power,
     int* decimal_exponent) {
   int kQ = DiyFp::kSignificandSize;
-  double k = ceiling((min_exponent + kQ - 1) * kD_1_LOG2_10);
+  // Some platforms return incorrect sign on 0 result. We can ignore that here,
+  // which means we can avoid depending on platform.h.
+  double k = ceil((min_exponent + kQ - 1) * kD_1_LOG2_10);
   int foo = kCachedPowersOffset;
   int index =
       (foo + static_cast<int>(k) - 1) / kDecimalExponentDistance + 1;
index cb7dbf88d2a32d7f132fcc5e9e76da60102b461e..bb24a9c2b76e9b06054c89ca47e2de6f6ec26c06 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
 #ifndef V8_CONVERSIONS_INL_H_
 #define V8_CONVERSIONS_INL_H_
 
+#include <limits.h>        // Required for INT_MAX etc.
 #include <math.h>
-#include <float.h>         // required for DBL_MAX and on Win32 for finite()
+#include <float.h>         // Required for DBL_MAX and on Win32 for finite()
 #include <stdarg.h>
 
 // ----------------------------------------------------------------------------
 // Extra POSIX/ANSI functions for Win32/MSVC.
 
 #include "conversions.h"
+#include "strtod.h"
 #include "platform.h"
 
 namespace v8 {
@@ -77,18 +79,6 @@ static inline double DoubleToInteger(double x) {
 }
 
 
-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());
-}
-
-
 int32_t DoubleToInt32(double x) {
   int32_t i = FastD2I(x);
   if (FastI2D(i) == x) return i;
@@ -101,6 +91,572 @@ int32_t DoubleToInt32(double x) {
 }
 
 
+template <class Iterator, class EndMark>
+static bool SubStringEquals(Iterator* current,
+                            EndMark end,
+                            const char* substring) {
+  ASSERT(**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>
+static inline bool AdvanceToNonspace(UnicodeCache* unicode_cache,
+                                     Iterator* current,
+                                     EndMark end) {
+  while (*current != end) {
+    if (!unicode_cache->IsWhiteSpace(**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>
+static double InternalStringToIntDouble(UnicodeCache* unicode_cache,
+                                        Iterator current,
+                                        EndMark end,
+                                        bool negative,
+                                        bool allow_trailing_junk) {
+  ASSERT(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 JUNK_STRING_VALUE;
+      }
+    }
+
+    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 JUNK_STRING_VALUE;
+      }
+
+      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 & ((int64_t)1 << 53)) != 0) {
+        exponent++;
+        number >>= 1;
+      }
+      break;
+    }
+    ++current;
+  } while (current != end);
+
+  ASSERT(number < ((int64_t)1 << 53));
+  ASSERT(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);
+  }
+
+  ASSERT(number != 0);
+  // The double could be constructed faster from number (mantissa), exponent
+  // and sign. Assuming it's a rare case more simple code is used.
+  return static_cast<double>(negative ? -number : number) * pow(2.0, exponent);
+}
+
+
+template <class Iterator, class EndMark>
+static double InternalStringToInt(UnicodeCache* unicode_cache,
+                                  Iterator current,
+                                  EndMark end,
+                                  int radix) {
+  const bool allow_trailing_junk = true;
+  const double empty_string_val = JUNK_STRING_VALUE;
+
+  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 JUNK_STRING_VALUE;
+    }
+  } else if (*current == '-') {
+    ++current;
+    if (current == end) {
+      return JUNK_STRING_VALUE;
+    }
+    negative = true;
+  }
+
+  if (radix == 0) {
+    // Radix detection.
+    if (*current == '0') {
+      ++current;
+      if (current == end) return SignedZero(negative);
+      if (*current == 'x' || *current == 'X') {
+        radix = 16;
+        ++current;
+        if (current == end) return JUNK_STRING_VALUE;
+      } else {
+        radix = 8;
+        leading_zero = true;
+      }
+    } else {
+      radix = 10;
+    }
+  } 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 JUNK_STRING_VALUE;
+      } else {
+        leading_zero = true;
+      }
+    }
+  }
+
+  if (radix < 2 || radix > 36) return JUNK_STRING_VALUE;
+
+  // Skip leading zeros.
+  while (*current == '0') {
+    leading_zero = true;
+    ++current;
+    if (current == end) return SignedZero(negative);
+  }
+
+  if (!leading_zero && !isDigit(*current, radix)) {
+    return JUNK_STRING_VALUE;
+  }
+
+  if (IsPowerOf2(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.
+        ASSERT(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 JUNK_STRING_VALUE;
+    }
+
+    ASSERT(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;
+      ASSERT(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 JUNK_STRING_VALUE;
+  }
+
+  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>
+static 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;
+  bool fractional_part = false;
+
+  bool negative = false;
+
+  if (*current == '+') {
+    // Ignore leading sign.
+    ++current;
+    if (current == end) return JUNK_STRING_VALUE;
+  } else if (*current == '-') {
+    ++current;
+    if (current == end) return JUNK_STRING_VALUE;
+    negative = true;
+  }
+
+  static const char kInfinitySymbol[] = "Infinity";
+  if (*current == kInfinitySymbol[0]) {
+    if (!SubStringEquals(&current, end, kInfinitySymbol)) {
+      return JUNK_STRING_VALUE;
+    }
+
+    if (!allow_trailing_junk &&
+        AdvanceToNonspace(unicode_cache, &current, end)) {
+      return JUNK_STRING_VALUE;
+    }
+
+    ASSERT(buffer_pos == 0);
+    return negative ? -V8_INFINITY : V8_INFINITY;
+  }
+
+  bool leading_zero = false;
+  if (*current == '0') {
+    ++current;
+    if (current == end) return SignedZero(negative);
+
+    leading_zero = true;
+
+    // It could be hexadecimal value.
+    if ((flags & ALLOW_HEX) && (*current == 'x' || *current == 'X')) {
+      ++current;
+      if (current == end || !isDigit(*current, 16)) {
+        return JUNK_STRING_VALUE;  // "0x".
+      }
+
+      return InternalStringToIntDouble<4>(unicode_cache,
+                                          current,
+                                          end,
+                                          negative,
+                                          allow_trailing_junk);
+    }
+
+    // Ignore leading zeros in the integer part.
+    while (*current == '0') {
+      ++current;
+      if (current == end) return SignedZero(negative);
+    }
+  }
+
+  bool octal = leading_zero && (flags & ALLOW_OCTALS) != 0;
+
+  // Copy significant digits of the integer part (if any) to the buffer.
+  while (*current >= '0' && *current <= '9') {
+    if (significant_digits < kMaxSignificantDigits) {
+      ASSERT(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 JUNK_STRING_VALUE;
+    if (octal) goto parsing_done;
+
+    ++current;
+    if (current == end) {
+      if (significant_digits == 0 && !leading_zero) {
+        return JUNK_STRING_VALUE;
+      } 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(negative);
+        exponent--;  // Move this 0 into the exponent.
+      }
+    }
+
+    // We don't emit a '.', but adjust the exponent instead.
+    fractional_part = true;
+
+    // There is a fractional part.
+    while (*current >= '0' && *current <= '9') {
+      if (significant_digits < kMaxSignificantDigits) {
+        ASSERT(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 JUNK_STRING_VALUE;
+  }
+
+  // Parse exponential part.
+  if (*current == 'e' || *current == 'E') {
+    if (octal) return JUNK_STRING_VALUE;
+    ++current;
+    if (current == end) {
+      if (allow_trailing_junk) {
+        goto parsing_done;
+      } else {
+        return JUNK_STRING_VALUE;
+      }
+    }
+    char sign = '+';
+    if (*current == '+' || *current == '-') {
+      sign = static_cast<char>(*current);
+      ++current;
+      if (current == end) {
+        if (allow_trailing_junk) {
+          goto parsing_done;
+        } else {
+          return JUNK_STRING_VALUE;
+        }
+      }
+    }
+
+    if (current == end || *current < '0' || *current > '9') {
+      if (allow_trailing_junk) {
+        goto parsing_done;
+      } else {
+        return JUNK_STRING_VALUE;
+      }
+    }
+
+    const int max_exponent = INT_MAX / 2;
+    ASSERT(-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 JUNK_STRING_VALUE;
+  }
+
+  parsing_done:
+  exponent += insignificant_digits;
+
+  if (octal) {
+    return InternalStringToIntDouble<3>(unicode_cache,
+                                        buffer,
+                                        buffer + buffer_pos,
+                                        negative,
+                                        allow_trailing_junk);
+  }
+
+  if (nonzero_digit_dropped) {
+    buffer[buffer_pos++] = '1';
+    exponent--;
+  }
+
+  ASSERT(buffer_pos < kBufferSize);
+  buffer[buffer_pos] = '\0';
+
+  double converted = Strtod(Vector<const char>(buffer, buffer_pos), exponent);
+  return negative ? -converted : converted;
+}
+
 } }  // namespace v8::internal
 
 #endif  // V8_CONVERSIONS_INL_H_
index 353b6810f5ba8e474223966eadbe7bf7d31d8d74..232eda08c933cf7bf6418e58edf1a0c2e66ee2c2 100644 (file)
 #include <stdarg.h>
 #include <limits.h>
 
-#include "v8.h"
-
 #include "conversions-inl.h"
 #include "dtoa.h"
-#include "factory.h"
 #include "scanner-base.h"
 #include "strtod.h"
+#include "utils.h"
 
 namespace v8 {
 namespace internal {
 
-namespace {
-
-// C++-style iterator adaptor for StringInputBuffer
-// (unlike C++ iterators the end-marker has different type).
-class StringInputBufferIterator {
- public:
-  class EndMarker {};
-
-  explicit StringInputBufferIterator(StringInputBuffer* buffer);
-
-  int operator*() const;
-  void operator++();
-  bool operator==(EndMarker const&) const { return end_; }
-  bool operator!=(EndMarker const& m) const { return !end_; }
-
- private:
-  StringInputBuffer* const buffer_;
-  int current_;
-  bool end_;
-};
-
-
-StringInputBufferIterator::StringInputBufferIterator(
-    StringInputBuffer* buffer) : buffer_(buffer) {
-  ++(*this);
-}
-
-int StringInputBufferIterator::operator*() const {
-  return current_;
-}
-
-
-void StringInputBufferIterator::operator++() {
-  end_ = !buffer_->has_more();
-  if (!end_) {
-    current_ = buffer_->GetNext();
-  }
-}
-}
-
-
-template <class Iterator, class EndMark>
-static bool SubStringEquals(Iterator* current,
-                            EndMark end,
-                            const char* substring) {
-  ASSERT(**current == *substring);
-  for (substring++; *substring != '\0'; substring++) {
-    ++*current;
-    if (*current == end || **current != *substring) return false;
-  }
-  ++*current;
-  return true;
-}
-
-
-// Maximum number of significant digits in decimal representation.
-// The longest possible double in decimal representation is
-// (2^53 - 1) * 2 ^ -1074 that is (2 ^ 53 - 1) * 5 ^ 1074 / 10 ^ 1074
-// (768 digits). If we parse a number whose first digits are equal to a
-// mean of 2 adjacent doubles (that could have up to 769 digits) the result
-// must be rounded to the bigger one unless the tail consists of zeros, so
-// we don't need to preserve all the digits.
-const int kMaxSignificantDigits = 772;
-
-
-static const double JUNK_STRING_VALUE = OS::nan_value();
-
-
-// Returns true if a nonspace found and false if the end has reached.
-template <class Iterator, class EndMark>
-static inline bool AdvanceToNonspace(UnicodeCache* unicode_cache,
-                                     Iterator* current,
-                                     EndMark end) {
-  while (*current != end) {
-    if (!unicode_cache->IsWhiteSpace(**current)) return true;
-    ++*current;
-  }
-  return false;
-}
-
-
-static bool isDigit(int x, int radix) {
-  return (x >= '0' && x <= '9' && x < '0' + radix)
-      || (radix > 10 && x >= 'a' && x < 'a' + radix - 10)
-      || (radix > 10 && x >= 'A' && x < 'A' + radix - 10);
-}
-
-
-static double SignedZero(bool negative) {
-  return negative ? -0.0 : 0.0;
-}
-
-
-// Parsing integers with radix 2, 4, 8, 16, 32. Assumes current != end.
-template <int radix_log_2, class Iterator, class EndMark>
-static double InternalStringToIntDouble(UnicodeCache* unicode_cache,
-                                        Iterator current,
-                                        EndMark end,
-                                        bool negative,
-                                        bool allow_trailing_junk) {
-  ASSERT(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 JUNK_STRING_VALUE;
-      }
-    }
-
-    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 JUNK_STRING_VALUE;
-      }
-
-      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 & ((int64_t)1 << 53)) != 0) {
-        exponent++;
-        number >>= 1;
-      }
-      break;
-    }
-    ++current;
-  } while (current != end);
-
-  ASSERT(number < ((int64_t)1 << 53));
-  ASSERT(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);
-  }
-
-  ASSERT(number != 0);
-  // The double could be constructed faster from number (mantissa), exponent
-  // and sign. Assuming it's a rare case more simple code is used.
-  return static_cast<double>(negative ? -number : number) * pow(2.0, exponent);
-}
-
-
-template <class Iterator, class EndMark>
-static double InternalStringToInt(UnicodeCache* unicode_cache,
-                                  Iterator current,
-                                  EndMark end,
-                                  int radix) {
-  const bool allow_trailing_junk = true;
-  const double empty_string_val = JUNK_STRING_VALUE;
-
-  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 JUNK_STRING_VALUE;
-    }
-  } else if (*current == '-') {
-    ++current;
-    if (current == end) {
-      return JUNK_STRING_VALUE;
-    }
-    negative = true;
-  }
-
-  if (radix == 0) {
-    // Radix detection.
-    if (*current == '0') {
-      ++current;
-      if (current == end) return SignedZero(negative);
-      if (*current == 'x' || *current == 'X') {
-        radix = 16;
-        ++current;
-        if (current == end) return JUNK_STRING_VALUE;
-      } else {
-        radix = 8;
-        leading_zero = true;
-      }
-    } else {
-      radix = 10;
-    }
-  } 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 JUNK_STRING_VALUE;
-      } else {
-        leading_zero = true;
-      }
-    }
-  }
-
-  if (radix < 2 || radix > 36) return JUNK_STRING_VALUE;
-
-  // Skip leading zeros.
-  while (*current == '0') {
-    leading_zero = true;
-    ++current;
-    if (current == end) return SignedZero(negative);
-  }
-
-  if (!leading_zero && !isDigit(*current, radix)) {
-    return JUNK_STRING_VALUE;
-  }
-
-  if (IsPowerOf2(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.
-        ASSERT(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 JUNK_STRING_VALUE;
-    }
-
-    ASSERT(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;
-      ASSERT(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 JUNK_STRING_VALUE;
-  }
-
-  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>
-static 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;
-  bool fractional_part = false;
-
-  bool negative = false;
-
-  if (*current == '+') {
-    // Ignore leading sign.
-    ++current;
-    if (current == end) return JUNK_STRING_VALUE;
-  } else if (*current == '-') {
-    ++current;
-    if (current == end) return JUNK_STRING_VALUE;
-    negative = true;
-  }
-
-  static const char kInfinitySymbol[] = "Infinity";
-  if (*current == kInfinitySymbol[0]) {
-    if (!SubStringEquals(&current, end, kInfinitySymbol)) {
-      return JUNK_STRING_VALUE;
-    }
-
-    if (!allow_trailing_junk &&
-        AdvanceToNonspace(unicode_cache, &current, end)) {
-      return JUNK_STRING_VALUE;
-    }
-
-    ASSERT(buffer_pos == 0);
-    return negative ? -V8_INFINITY : V8_INFINITY;
-  }
-
-  bool leading_zero = false;
-  if (*current == '0') {
-    ++current;
-    if (current == end) return SignedZero(negative);
-
-    leading_zero = true;
-
-    // It could be hexadecimal value.
-    if ((flags & ALLOW_HEX) && (*current == 'x' || *current == 'X')) {
-      ++current;
-      if (current == end || !isDigit(*current, 16)) {
-        return JUNK_STRING_VALUE;  // "0x".
-      }
-
-      return InternalStringToIntDouble<4>(unicode_cache,
-                                          current,
-                                          end,
-                                          negative,
-                                          allow_trailing_junk);
-    }
-
-    // Ignore leading zeros in the integer part.
-    while (*current == '0') {
-      ++current;
-      if (current == end) return SignedZero(negative);
-    }
-  }
-
-  bool octal = leading_zero && (flags & ALLOW_OCTALS) != 0;
-
-  // Copy significant digits of the integer part (if any) to the buffer.
-  while (*current >= '0' && *current <= '9') {
-    if (significant_digits < kMaxSignificantDigits) {
-      ASSERT(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 JUNK_STRING_VALUE;
-    if (octal) goto parsing_done;
-
-    ++current;
-    if (current == end) {
-      if (significant_digits == 0 && !leading_zero) {
-        return JUNK_STRING_VALUE;
-      } 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(negative);
-        exponent--;  // Move this 0 into the exponent.
-      }
-    }
-
-    // We don't emit a '.', but adjust the exponent instead.
-    fractional_part = true;
-
-    // There is a fractional part.
-    while (*current >= '0' && *current <= '9') {
-      if (significant_digits < kMaxSignificantDigits) {
-        ASSERT(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 JUNK_STRING_VALUE;
-  }
-
-  // Parse exponential part.
-  if (*current == 'e' || *current == 'E') {
-    if (octal) return JUNK_STRING_VALUE;
-    ++current;
-    if (current == end) {
-      if (allow_trailing_junk) {
-        goto parsing_done;
-      } else {
-        return JUNK_STRING_VALUE;
-      }
-    }
-    char sign = '+';
-    if (*current == '+' || *current == '-') {
-      sign = static_cast<char>(*current);
-      ++current;
-      if (current == end) {
-        if (allow_trailing_junk) {
-          goto parsing_done;
-        } else {
-          return JUNK_STRING_VALUE;
-        }
-      }
-    }
-
-    if (current == end || *current < '0' || *current > '9') {
-      if (allow_trailing_junk) {
-        goto parsing_done;
-      } else {
-        return JUNK_STRING_VALUE;
-      }
-    }
-
-    const int max_exponent = INT_MAX / 2;
-    ASSERT(-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 JUNK_STRING_VALUE;
-  }
-
-  parsing_done:
-  exponent += insignificant_digits;
-
-  if (octal) {
-    return InternalStringToIntDouble<3>(unicode_cache,
-                                        buffer,
-                                        buffer + buffer_pos,
-                                        negative,
-                                        allow_trailing_junk);
-  }
-
-  if (nonzero_digit_dropped) {
-    buffer[buffer_pos++] = '1';
-    exponent--;
-  }
-
-  ASSERT(buffer_pos < kBufferSize);
-  buffer[buffer_pos] = '\0';
-
-  double converted = Strtod(Vector<const char>(buffer, buffer_pos), exponent);
-  return negative ? -converted : converted;
-}
-
-
-double StringToDouble(UnicodeCache* unicode_cache,
-                      String* str, int flags, double empty_string_val) {
-  StringShape shape(str);
-  if (shape.IsSequentialAscii()) {
-    const char* begin = SeqAsciiString::cast(str)->GetChars();
-    const char* end = begin + str->length();
-    return InternalStringToDouble(unicode_cache, begin, end, flags,
-                                  empty_string_val);
-  } else if (shape.IsSequentialTwoByte()) {
-    const uc16* begin = SeqTwoByteString::cast(str)->GetChars();
-    const uc16* end = begin + str->length();
-    return InternalStringToDouble(unicode_cache, begin, end, flags,
-                                  empty_string_val);
-  } else {
-    StringInputBuffer buffer(str);
-    return InternalStringToDouble(unicode_cache,
-                                  StringInputBufferIterator(&buffer),
-                                  StringInputBufferIterator::EndMarker(),
-                                  flags,
-                                  empty_string_val);
-  }
-}
-
-
-double StringToInt(UnicodeCache* unicode_cache,
-                   String* str,
-                   int radix) {
-  StringShape shape(str);
-  if (shape.IsSequentialAscii()) {
-    const char* begin = SeqAsciiString::cast(str)->GetChars();
-    const char* end = begin + str->length();
-    return InternalStringToInt(unicode_cache, begin, end, radix);
-  } else if (shape.IsSequentialTwoByte()) {
-    const uc16* begin = SeqTwoByteString::cast(str)->GetChars();
-    const uc16* end = begin + str->length();
-    return InternalStringToInt(unicode_cache, begin, end, radix);
-  } else {
-    StringInputBuffer buffer(str);
-    return InternalStringToInt(unicode_cache,
-                               StringInputBufferIterator(&buffer),
-                               StringInputBufferIterator::EndMarker(),
-                               radix);
-  }
-}
 
 
 double StringToDouble(UnicodeCache* unicode_cache,
@@ -750,7 +72,7 @@ const char* DoubleToCString(double v, Vector<char> buffer) {
     case FP_INFINITE: return (v < 0.0 ? "-Infinity" : "Infinity");
     case FP_ZERO: return "0";
     default: {
-      StringBuilder builder(buffer.start(), buffer.length());
+      SimpleStringBuilder builder(buffer.start(), buffer.length());
       int decimal_point;
       int sign;
       const int kV8DtoaBufferCapacity = kBase10MaximalLength + 1;
@@ -791,7 +113,7 @@ const char* DoubleToCString(double v, Vector<char> buffer) {
         builder.AddCharacter((decimal_point >= 0) ? '+' : '-');
         int exponent = decimal_point - 1;
         if (exponent < 0) exponent = -exponent;
-        builder.AddFormatted("%d", exponent);
+        builder.AddDecimalInteger(exponent);
       }
     return builder.Finalize();
     }
@@ -869,7 +191,7 @@ char* DoubleToFixedCString(double value, int f) {
 
   unsigned rep_length =
       zero_prefix_length + decimal_rep_length + zero_postfix_length;
-  StringBuilder rep_builder(rep_length + 1);
+  SimpleStringBuilder rep_builder(rep_length + 1);
   rep_builder.AddPadding('0', zero_prefix_length);
   rep_builder.AddString(decimal_rep);
   rep_builder.AddPadding('0', zero_postfix_length);
@@ -878,7 +200,7 @@ char* DoubleToFixedCString(double value, int f) {
   // Create the result string by appending a minus and putting in a
   // decimal point if needed.
   unsigned result_size = decimal_point + f + 2;
-  StringBuilder builder(result_size + 1);
+  SimpleStringBuilder builder(result_size + 1);
   if (negative) builder.AddCharacter('-');
   builder.AddSubstring(rep, decimal_point);
   if (f > 0) {
@@ -904,7 +226,7 @@ static char* CreateExponentialRepresentation(char* decimal_rep,
   // letter 'e', a minus or a plus depending on the exponent, and a
   // three digit exponent.
   unsigned result_size = significant_digits + 7;
-  StringBuilder builder(result_size + 1);
+  SimpleStringBuilder builder(result_size + 1);
 
   if (negative) builder.AddCharacter('-');
   builder.AddCharacter(decimal_rep[0]);
@@ -917,7 +239,7 @@ static char* CreateExponentialRepresentation(char* decimal_rep,
 
   builder.AddCharacter('e');
   builder.AddCharacter(negative_exponent ? '-' : '+');
-  builder.AddFormatted("%d", exponent);
+  builder.AddDecimalInteger(exponent);
   return builder.Finalize();
 }
 
@@ -1009,7 +331,7 @@ char* DoubleToPrecisionCString(double value, int p) {
     unsigned result_size = (decimal_point <= 0)
         ? -decimal_point + p + 3
         : p + 2;
-    StringBuilder builder(result_size + 1);
+    SimpleStringBuilder builder(result_size + 1);
     if (negative) builder.AddCharacter('-');
     if (decimal_point <= 0) {
       builder.AddString("0.");
@@ -1101,7 +423,7 @@ char* DoubleToRadixCString(double value, int radix) {
   // If the number has a decimal part, leave room for the period.
   if (decimal_pos > 0) result_size++;
   // Allocate result and fill in the parts.
-  StringBuilder builder(result_size + 1);
+  SimpleStringBuilder builder(result_size + 1);
   builder.AddSubstring(integer_buffer + integer_pos + 1, integer_part_size);
   if (decimal_pos > 0) builder.AddCharacter('.');
   builder.AddSubstring(decimal_buffer, decimal_pos);
index 4cbeeca828d3ca991df1d22c5555f60c72d941bd..c3e27b2025f519610848fa65d04735a99a1c62cc 100644 (file)
 #ifndef V8_CONVERSIONS_H_
 #define V8_CONVERSIONS_H_
 
+#include <limits>
+
 #include "scanner-base.h"
 
 namespace v8 {
 namespace internal {
 
+// Maximum number of significant digits in decimal representation.
+// The longest possible double in decimal representation is
+// (2^53 - 1) * 2 ^ -1074 that is (2 ^ 53 - 1) * 5 ^ 1074 / 10 ^ 1074
+// (768 digits). If we parse a number whose first digits are equal to a
+// mean of 2 adjacent doubles (that could have up to 769 digits) the result
+// must be rounded to the bigger one unless the tail consists of zeros, so
+// we don't need to preserve all the digits.
+const int kMaxSignificantDigits = 772;
+
+static const double JUNK_STRING_VALUE =
+    std::numeric_limits<double>::quiet_NaN();
+
+static bool isDigit(int x, int radix) {
+  return (x >= '0' && x <= '9' && x < '0' + radix)
+      || (radix > 10 && x >= 'a' && x < 'a' + radix - 10)
+      || (radix > 10 && x >= 'A' && x < 'A' + radix - 10);
+}
+
+
+static double SignedZero(bool negative) {
+  return negative ? -0.0 : 0.0;
+}
+
 
 // The fast double-to-(unsigned-)int conversion routine does not guarantee
 // rounding towards zero.
@@ -87,16 +112,7 @@ enum ConversionFlags {
 };
 
 
-// Convert from Number object to C integer.
-static inline int32_t NumberToInt32(Object* number);
-static inline uint32_t NumberToUint32(Object* number);
-
-
 // Converts a string into a double value according to ECMA-262 9.3.1
-double StringToDouble(UnicodeCache* unicode_cache,
-                      String* str,
-                      int flags,
-                      double empty_string_val = 0);
 double StringToDouble(UnicodeCache* unicode_cache,
                       Vector<const char> str,
                       int flags,
@@ -111,9 +127,6 @@ double StringToDouble(UnicodeCache* unicode_cache,
                       int flags,
                       double empty_string_val = 0);
 
-// Converts a string into an integer.
-double StringToInt(UnicodeCache* unicode_cache, String* str, int radix);
-
 // Converts a double to a string value according to ECMA-262 9.8.1.
 // The buffer should be large enough for any floating point number.
 // 100 characters is enough.
index c54bd1d326f31c73af9aea6c24b51fe7173e0330..49138777088bb47c637f3955c2b385846fa04adb 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -25,8 +25,9 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include "v8.h"
-
+#include "../include/v8stdint.h"
+#include "globals.h"
+#include "checks.h"
 #include "diy-fp.h"
 
 namespace v8 {
index cfe05ef7428b6b130ab4a0e2109f413f7856306f..26ff1a20bfc15fc252b02a718f69258262cc032e 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -80,7 +80,7 @@ class DiyFp {
 
     // This method is mainly called for normalizing boundaries. In general
     // boundaries need to be shifted by 10 bits. We thus optimize for this case.
-    const uint64_t k10MSBits = V8_2PART_UINT64_C(0xFFC00000, 00000000);
+    const uint64_t k10MSBits = static_cast<uint64_t>(0x3FF) << 54;
     while ((f & k10MSBits) == 0) {
       f <<= 10;
       e -= 10;
@@ -106,7 +106,7 @@ class DiyFp {
   void set_e(int new_value) { e_ = new_value; }
 
  private:
-  static const uint64_t kUint64MSB = V8_2PART_UINT64_C(0x80000000, 00000000);
+  static const uint64_t kUint64MSB = static_cast<uint64_t>(1) << 63;
 
   uint64_t f_;
   int e_;
index 9b44ad945f7c73640336bf777b69059f1592f2e5..cc32b93831ebe2efebdb2b6cb6d6d3b39cb3b65a 100644 (file)
@@ -35,7 +35,8 @@
 #include "data-flow.h"
 #include "small-pointer-list.h"
 #include "string-stream.h"
-#include "utils.h"
+#include "v8conversions.h"
+#include "v8utils.h"
 #include "zone.h"
 
 namespace v8 {
index 1f30170a1e2d528f2f7375ca7a1a9daeb9b828e2..3ef5afbb895f403bad7e007342fdaaf6a78ea8b4 100644 (file)
@@ -31,7 +31,7 @@
 #include "v8.h"
 
 #include "char-predicates-inl.h"
-#include "conversions.h"
+#include "v8conversions.h"
 #include "messages.h"
 #include "spaces-inl.h"
 #include "token.h"
index 4a9034c4801df9aaf33274eec11d4910d0cfbfc7..e382a06456bcdc17528701289e77141d80bf6afc 100644 (file)
@@ -2585,4 +2585,3 @@ void LiveObjectList::VerifyNotInFromSpace() {
 } }  // namespace v8::internal
 
 #endif  // LIVE_OBJECT_LIST
-
index da83f96aebada421911206773fddd6c64236aa25..c741b4655a0556d4450c94608a69ad6316d4e9fa 100644 (file)
@@ -38,6 +38,8 @@
 #include "preparse-data.h"
 #include "preparser.h"
 
+#include "conversions-inl.h"
+
 namespace v8 {
 namespace preparser {
 
index cedbff91ea5fd7b5f0fe63f434c654513117befe..b32abd97d7929ef83d6e4765b5feea7970ba48be 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <stdarg.h>
-#include <limits.h>
+#include <limits>
 
-#include "v8.h"
+#ifndef V8_INFINITY
+#define V8_INFINITY std::numeric_limits<double>::infinity()
+#endif
+
+#include "utils.h"
 
 #include "strtod.h"
 #include "bignum.h"
index b466301ca5f3dc613be5b62ab0d063285b660908..89ef4c6e3e389397e79e55b55efcd4b557260475 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <stdarg.h>
-
-#include "v8.h"
-
-#include "platform.h"
-
-#include "sys/stat.h"
+#include "../include/v8stdint.h"
+#include "checks.h"
+#include "utils.h"
 
 namespace v8 {
 namespace internal {
 
 
-void PrintF(const char* format, ...) {
-  va_list arguments;
-  va_start(arguments, format);
-  OS::VPrint(format, arguments);
-  va_end(arguments);
-}
-
-
-void PrintF(FILE* out, const char* format, ...) {
-  va_list arguments;
-  va_start(arguments, format);
-  OS::VFPrint(out, format, arguments);
-  va_end(arguments);
-}
-
-
-void Flush(FILE* out) {
-  fflush(out);
-}
-
-
-char* ReadLine(const char* prompt) {
-  char* result = NULL;
-  char line_buf[256];
-  int offset = 0;
-  bool keep_going = true;
-  fprintf(stdout, "%s", prompt);
-  fflush(stdout);
-  while (keep_going) {
-    if (fgets(line_buf, sizeof(line_buf), stdin) == NULL) {
-      // fgets got an error. Just give up.
-      if (result != NULL) {
-        DeleteArray(result);
-      }
-      return NULL;
-    }
-    int len = StrLength(line_buf);
-    if (len > 1 &&
-        line_buf[len - 2] == '\\' &&
-        line_buf[len - 1] == '\n') {
-      // When we read a line that ends with a "\" we remove the escape and
-      // append the remainder.
-      line_buf[len - 2] = '\n';
-      line_buf[len - 1] = 0;
-      len -= 1;
-    } else if ((len > 0) && (line_buf[len - 1] == '\n')) {
-      // Since we read a new line we are done reading the line. This
-      // will exit the loop after copying this buffer into the result.
-      keep_going = false;
-    }
-    if (result == NULL) {
-      // Allocate the initial result and make room for the terminating '\0'
-      result = NewArray<char>(len + 1);
-    } else {
-      // Allocate a new result with enough room for the new addition.
-      int new_len = offset + len + 1;
-      char* new_result = NewArray<char>(new_len);
-      // Copy the existing input into the new array and set the new
-      // array as the result.
-      memcpy(new_result, result, offset * kCharSize);
-      DeleteArray(result);
-      result = new_result;
-    }
-    // Copy the newly read line into the result.
-    memcpy(result + offset, line_buf, len * kCharSize);
-    offset += len;
-  }
-  ASSERT(result != NULL);
-  result[offset] = '\0';
-  return result;
-}
-
-
-char* ReadCharsFromFile(const char* filename,
-                        int* size,
-                        int extra_space,
-                        bool verbose) {
-  FILE* file = OS::FOpen(filename, "rb");
-  if (file == NULL || fseek(file, 0, SEEK_END) != 0) {
-    if (verbose) {
-      OS::PrintError("Cannot read from file %s.\n", filename);
-    }
-    return NULL;
-  }
-
-  // Get the size of the file and rewind it.
-  *size = ftell(file);
-  rewind(file);
-
-  char* result = NewArray<char>(*size + extra_space);
-  for (int i = 0; i < *size;) {
-    int read = static_cast<int>(fread(&result[i], 1, *size - i, file));
-    if (read <= 0) {
-      fclose(file);
-      DeleteArray(result);
-      return NULL;
-    }
-    i += read;
-  }
-  fclose(file);
-  return result;
-}
-
-
-byte* ReadBytes(const char* filename, int* size, bool verbose) {
-  char* chars = ReadCharsFromFile(filename, size, 0, verbose);
-  return reinterpret_cast<byte*>(chars);
-}
-
-
-Vector<const char> ReadFile(const char* filename,
-                            bool* exists,
-                            bool verbose) {
-  int size;
-  char* result = ReadCharsFromFile(filename, &size, 1, verbose);
-  if (!result) {
-    *exists = false;
-    return Vector<const char>::empty();
-  }
-  result[size] = '\0';
-  *exists = true;
-  return Vector<const char>(result, size);
-}
-
-
-int WriteCharsToFile(const char* str, int size, FILE* f) {
-  int total = 0;
-  while (total < size) {
-    int write = static_cast<int>(fwrite(str, 1, size - total, f));
-    if (write == 0) {
-      return total;
-    }
-    total += write;
-    str += write;
-  }
-  return total;
-}
-
-
-int AppendChars(const char* filename,
-                const char* str,
-                int size,
-                bool verbose) {
-  FILE* f = OS::FOpen(filename, "ab");
-  if (f == NULL) {
-    if (verbose) {
-      OS::PrintError("Cannot open file %s for writing.\n", filename);
-    }
-    return 0;
-  }
-  int written = WriteCharsToFile(str, size, f);
-  fclose(f);
-  return written;
-}
-
-
-int WriteChars(const char* filename,
-               const char* str,
-               int size,
-               bool verbose) {
-  FILE* f = OS::FOpen(filename, "wb");
-  if (f == NULL) {
-    if (verbose) {
-      OS::PrintError("Cannot open file %s for writing.\n", filename);
-    }
-    return 0;
-  }
-  int written = WriteCharsToFile(str, size, f);
-  fclose(f);
-  return written;
-}
-
-
-int WriteBytes(const char* filename,
-               const byte* bytes,
-               int size,
-               bool verbose) {
-  const char* str = reinterpret_cast<const char*>(bytes);
-  return WriteChars(filename, str, size, verbose);
-}
-
-
-StringBuilder::StringBuilder(int size) {
+SimpleStringBuilder::SimpleStringBuilder(int size) {
   buffer_ = Vector<char>::New(size);
   position_ = 0;
 }
 
 
-void StringBuilder::AddString(const char* s) {
+void SimpleStringBuilder::AddString(const char* s) {
   AddSubstring(s, StrLength(s));
 }
 
 
-void StringBuilder::AddSubstring(const char* s, int n) {
+void SimpleStringBuilder::AddSubstring(const char* s, int n) {
   ASSERT(!is_finalized() && position_ + n < buffer_.length());
   ASSERT(static_cast<size_t>(n) <= strlen(s));
   memcpy(&buffer_[position_], s, n * kCharSize);
@@ -238,33 +53,32 @@ void StringBuilder::AddSubstring(const char* s, int n) {
 }
 
 
-void StringBuilder::AddFormatted(const char* format, ...) {
-  va_list arguments;
-  va_start(arguments, format);
-  AddFormattedList(format, arguments);
-  va_end(arguments);
-}
-
-
-void StringBuilder::AddFormattedList(const char* format, va_list list) {
-  ASSERT(!is_finalized() && position_ < buffer_.length());
-  int n = OS::VSNPrintF(buffer_ + position_, format, list);
-  if (n < 0 || n >= (buffer_.length() - position_)) {
-    position_ = buffer_.length();
-  } else {
-    position_ += n;
+void SimpleStringBuilder::AddPadding(char c, int count) {
+  for (int i = 0; i < count; i++) {
+    AddCharacter(c);
   }
 }
 
 
-void StringBuilder::AddPadding(char c, int count) {
-  for (int i = 0; i < count; i++) {
-    AddCharacter(c);
+void SimpleStringBuilder::AddDecimalInteger(int32_t value) {
+  uint32_t number = static_cast<uint32_t>(value);
+  if (value < 0) {
+    AddCharacter('-');
+    number = static_cast<uint32_t>(-value);
+  }
+  int digits = 1;
+  for (uint32_t factor = 10; digits < 10; digits++, factor *= 10) {
+    if (factor > number) break;
+  }
+  position_ += digits;
+  for (int i = 1; i <= digits; i++) {
+    buffer_[position_ - i] = '0' + static_cast<char>(number % 10);
+    number /= 10;
   }
 }
 
 
-char* StringBuilder::Finalize() {
+char* SimpleStringBuilder::Finalize() {
   ASSERT(!is_finalized() && position_ < buffer_.length());
   buffer_[position_] = '\0';
   // Make sure nobody managed to add a 0-character to the
@@ -275,97 +89,4 @@ char* StringBuilder::Finalize() {
   return buffer_.start();
 }
 
-
-MemoryMappedExternalResource::MemoryMappedExternalResource(const char* filename)
-    : filename_(NULL),
-      data_(NULL),
-      length_(0),
-      remove_file_on_cleanup_(false) {
-  Init(filename);
-}
-
-
-MemoryMappedExternalResource::
-    MemoryMappedExternalResource(const char* filename,
-                                 bool remove_file_on_cleanup)
-    : filename_(NULL),
-      data_(NULL),
-      length_(0),
-      remove_file_on_cleanup_(remove_file_on_cleanup) {
-  Init(filename);
-}
-
-
-MemoryMappedExternalResource::~MemoryMappedExternalResource() {
-  // Release the resources if we had successfully acquired them:
-  if (file_ != NULL) {
-    delete file_;
-    if (remove_file_on_cleanup_) {
-      OS::Remove(filename_);
-    }
-    DeleteArray<char>(filename_);
-  }
-}
-
-
-void MemoryMappedExternalResource::Init(const char* filename) {
-  file_ = OS::MemoryMappedFile::open(filename);
-  if (file_ != NULL) {
-    filename_ = StrDup(filename);
-    data_ = reinterpret_cast<char*>(file_->memory());
-    length_ = file_->size();
-  }
-}
-
-
-bool MemoryMappedExternalResource::EnsureIsAscii(bool abort_if_failed) const {
-  bool is_ascii = true;
-
-  int line_no = 1;
-  const char* start_of_line = data_;
-  const char* end = data_ + length_;
-  for (const char* p = data_; p < end; p++) {
-    char c = *p;
-    if ((c & 0x80) != 0) {
-      // Non-ascii detected:
-      is_ascii = false;
-
-      // Report the error and abort if appropriate:
-      if (abort_if_failed) {
-        int char_no = static_cast<int>(p - start_of_line) - 1;
-
-        ASSERT(filename_ != NULL);
-        PrintF("\n\n\n"
-               "Abort: Non-Ascii character 0x%.2x in file %s line %d char %d",
-               c, filename_, line_no, char_no);
-
-        // Allow for some context up to kNumberOfLeadingContextChars chars
-        // before the offending non-ascii char to help the user see where
-        // the offending char is.
-        const int kNumberOfLeadingContextChars = 10;
-        const char* err_context = p - kNumberOfLeadingContextChars;
-        if (err_context < data_) {
-          err_context = data_;
-        }
-        // Compute the length of the error context and print it.
-        int err_context_length = static_cast<int>(p - err_context);
-        if (err_context_length != 0) {
-          PrintF(" after \"%.*s\"", err_context_length, err_context);
-        }
-        PrintF(".\n\n\n");
-        OS::Abort();
-      }
-
-      break;  // Non-ascii detected.  No need to continue scanning.
-    }
-    if (c == '\n') {
-      start_of_line = p;
-      line_no++;
-    }
-  }
-
-  return is_ascii;
-}
-
-
 } }  // namespace v8::internal
index 331c01add80495ea94b7a7331a2687bb07771796..ecdf1c70e7623038d99d77afc57764a9c74dfd98 100644 (file)
@@ -822,6 +822,69 @@ class EmbeddedContainer<ElementType, 0> {
 };
 
 
+// Helper class for building result strings in a character buffer. The
+// purpose of the class is to use safe operations that checks the
+// buffer bounds on all operations in debug mode.
+// This simple base class does not allow formatted output.
+class SimpleStringBuilder {
+ public:
+  // Create a string builder with a buffer of the given size. The
+  // buffer is allocated through NewArray<char> and must be
+  // deallocated by the caller of Finalize().
+  explicit SimpleStringBuilder(int size);
+
+  SimpleStringBuilder(char* buffer, int size)
+      : buffer_(buffer, size), position_(0) { }
+
+  ~SimpleStringBuilder() { if (!is_finalized()) Finalize(); }
+
+  int size() const { return buffer_.length(); }
+
+  // Get the current position in the builder.
+  int position() const {
+    ASSERT(!is_finalized());
+    return position_;
+  }
+
+  // Reset the position.
+  void Reset() { position_ = 0; }
+
+  // Add a single character to the builder. It is not allowed to add
+  // 0-characters; use the Finalize() method to terminate the string
+  // instead.
+  void AddCharacter(char c) {
+    ASSERT(c != '\0');
+    ASSERT(!is_finalized() && position_ < buffer_.length());
+    buffer_[position_++] = c;
+  }
+
+  // Add an entire string to the builder. Uses strlen() internally to
+  // compute the length of the input string.
+  void AddString(const char* s);
+
+  // Add the first 'n' characters of the given string 's' to the
+  // builder. The input string must have enough characters.
+  void AddSubstring(const char* s, int n);
+
+  // Add character padding to the builder. If count is non-positive,
+  // nothing is added to the builder.
+  void AddPadding(char c, int count);
+
+  // Add the decimal representation of the value.
+  void AddDecimalInteger(int value);
+
+  // Finalize the string by 0-terminating it and returning the buffer.
+  char* Finalize();
+
+ protected:
+  Vector<char> buffer_;
+  int position_;
+
+  bool is_finalized() const { return position_ < 0; }
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(SimpleStringBuilder);
+};
+
 } }  // namespace v8::internal
 
 #endif  // V8_UTILS_H_
diff --git a/src/v8conversions.cc b/src/v8conversions.cc
new file mode 100644 (file)
index 0000000..96056ec
--- /dev/null
@@ -0,0 +1,129 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdarg.h>
+#include <limits.h>
+
+#include "v8.h"
+
+#include "conversions-inl.h"
+#include "v8conversions.h"
+#include "dtoa.h"
+#include "factory.h"
+#include "scanner-base.h"
+#include "strtod.h"
+
+namespace v8 {
+namespace internal {
+
+namespace {
+
+// C++-style iterator adaptor for StringInputBuffer
+// (unlike C++ iterators the end-marker has different type).
+class StringInputBufferIterator {
+ public:
+  class EndMarker {};
+
+  explicit StringInputBufferIterator(StringInputBuffer* buffer);
+
+  int operator*() const;
+  void operator++();
+  bool operator==(EndMarker const&) const { return end_; }
+  bool operator!=(EndMarker const& m) const { return !end_; }
+
+ private:
+  StringInputBuffer* const buffer_;
+  int current_;
+  bool end_;
+};
+
+
+StringInputBufferIterator::StringInputBufferIterator(
+    StringInputBuffer* buffer) : buffer_(buffer) {
+  ++(*this);
+}
+
+int StringInputBufferIterator::operator*() const {
+  return current_;
+}
+
+
+void StringInputBufferIterator::operator++() {
+  end_ = !buffer_->has_more();
+  if (!end_) {
+    current_ = buffer_->GetNext();
+  }
+}
+}  // End anonymous namespace.
+
+
+double StringToDouble(UnicodeCache* unicode_cache,
+                      String* str, int flags, double empty_string_val) {
+  StringShape shape(str);
+  if (shape.IsSequentialAscii()) {
+    const char* begin = SeqAsciiString::cast(str)->GetChars();
+    const char* end = begin + str->length();
+    return InternalStringToDouble(unicode_cache, begin, end, flags,
+                                  empty_string_val);
+  } else if (shape.IsSequentialTwoByte()) {
+    const uc16* begin = SeqTwoByteString::cast(str)->GetChars();
+    const uc16* end = begin + str->length();
+    return InternalStringToDouble(unicode_cache, begin, end, flags,
+                                  empty_string_val);
+  } else {
+    StringInputBuffer buffer(str);
+    return InternalStringToDouble(unicode_cache,
+                                  StringInputBufferIterator(&buffer),
+                                  StringInputBufferIterator::EndMarker(),
+                                  flags,
+                                  empty_string_val);
+  }
+}
+
+
+double StringToInt(UnicodeCache* unicode_cache,
+                   String* str,
+                   int radix) {
+  StringShape shape(str);
+  if (shape.IsSequentialAscii()) {
+    const char* begin = SeqAsciiString::cast(str)->GetChars();
+    const char* end = begin + str->length();
+    return InternalStringToInt(unicode_cache, begin, end, radix);
+  } else if (shape.IsSequentialTwoByte()) {
+    const uc16* begin = SeqTwoByteString::cast(str)->GetChars();
+    const uc16* end = begin + str->length();
+    return InternalStringToInt(unicode_cache, begin, end, radix);
+  } else {
+    StringInputBuffer buffer(str);
+    return InternalStringToInt(unicode_cache,
+                               StringInputBufferIterator(&buffer),
+                               StringInputBufferIterator::EndMarker(),
+                               radix);
+  }
+}
+
+} }  // namespace v8::internal
diff --git a/src/v8conversions.h b/src/v8conversions.h
new file mode 100644 (file)
index 0000000..1840e3a
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_V8CONVERSIONS_H_
+#define V8_V8CONVERSIONS_H_
+
+#include "conversions.h"
+
+namespace v8 {
+namespace internal {
+
+// Convert from Number object to C integer.
+static inline int32_t NumberToInt32(Object* number) {
+  if (number->IsSmi()) return Smi::cast(number)->value();
+  return DoubleToInt32(number->Number());
+}
+
+
+static inline uint32_t NumberToUint32(Object* number) {
+  if (number->IsSmi()) return Smi::cast(number)->value();
+  return DoubleToUint32(number->Number());
+}
+
+
+// Converts a string into a double value according to ECMA-262 9.3.1
+double StringToDouble(UnicodeCache* unicode_cache,
+                      String* str,
+                      int flags,
+                      double empty_string_val = 0);
+
+// Converts a string into an integer.
+double StringToInt(UnicodeCache* unicode_cache, String* str, int radix);
+
+} }  // namespace v8::internal
+
+#endif  // V8_V8CONVERSIONS_H_
diff --git a/src/v8utils.cc b/src/v8utils.cc
new file mode 100644 (file)
index 0000000..89f9d95
--- /dev/null
@@ -0,0 +1,334 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdarg.h>
+
+#include "v8.h"
+
+#include "platform.h"
+
+#include "sys/stat.h"
+
+namespace v8 {
+namespace internal {
+
+
+void PrintF(const char* format, ...) {
+  va_list arguments;
+  va_start(arguments, format);
+  OS::VPrint(format, arguments);
+  va_end(arguments);
+}
+
+
+void PrintF(FILE* out, const char* format, ...) {
+  va_list arguments;
+  va_start(arguments, format);
+  OS::VFPrint(out, format, arguments);
+  va_end(arguments);
+}
+
+
+void Flush(FILE* out) {
+  fflush(out);
+}
+
+
+char* ReadLine(const char* prompt) {
+  char* result = NULL;
+  char line_buf[256];
+  int offset = 0;
+  bool keep_going = true;
+  fprintf(stdout, "%s", prompt);
+  fflush(stdout);
+  while (keep_going) {
+    if (fgets(line_buf, sizeof(line_buf), stdin) == NULL) {
+      // fgets got an error. Just give up.
+      if (result != NULL) {
+        DeleteArray(result);
+      }
+      return NULL;
+    }
+    int len = StrLength(line_buf);
+    if (len > 1 &&
+        line_buf[len - 2] == '\\' &&
+        line_buf[len - 1] == '\n') {
+      // When we read a line that ends with a "\" we remove the escape and
+      // append the remainder.
+      line_buf[len - 2] = '\n';
+      line_buf[len - 1] = 0;
+      len -= 1;
+    } else if ((len > 0) && (line_buf[len - 1] == '\n')) {
+      // Since we read a new line we are done reading the line. This
+      // will exit the loop after copying this buffer into the result.
+      keep_going = false;
+    }
+    if (result == NULL) {
+      // Allocate the initial result and make room for the terminating '\0'
+      result = NewArray<char>(len + 1);
+    } else {
+      // Allocate a new result with enough room for the new addition.
+      int new_len = offset + len + 1;
+      char* new_result = NewArray<char>(new_len);
+      // Copy the existing input into the new array and set the new
+      // array as the result.
+      memcpy(new_result, result, offset * kCharSize);
+      DeleteArray(result);
+      result = new_result;
+    }
+    // Copy the newly read line into the result.
+    memcpy(result + offset, line_buf, len * kCharSize);
+    offset += len;
+  }
+  ASSERT(result != NULL);
+  result[offset] = '\0';
+  return result;
+}
+
+
+char* ReadCharsFromFile(const char* filename,
+                        int* size,
+                        int extra_space,
+                        bool verbose) {
+  FILE* file = OS::FOpen(filename, "rb");
+  if (file == NULL || fseek(file, 0, SEEK_END) != 0) {
+    if (verbose) {
+      OS::PrintError("Cannot read from file %s.\n", filename);
+    }
+    return NULL;
+  }
+
+  // Get the size of the file and rewind it.
+  *size = ftell(file);
+  rewind(file);
+
+  char* result = NewArray<char>(*size + extra_space);
+  for (int i = 0; i < *size;) {
+    int read = static_cast<int>(fread(&result[i], 1, *size - i, file));
+    if (read <= 0) {
+      fclose(file);
+      DeleteArray(result);
+      return NULL;
+    }
+    i += read;
+  }
+  fclose(file);
+  return result;
+}
+
+
+byte* ReadBytes(const char* filename, int* size, bool verbose) {
+  char* chars = ReadCharsFromFile(filename, size, 0, verbose);
+  return reinterpret_cast<byte*>(chars);
+}
+
+
+Vector<const char> ReadFile(const char* filename,
+                            bool* exists,
+                            bool verbose) {
+  int size;
+  char* result = ReadCharsFromFile(filename, &size, 1, verbose);
+  if (!result) {
+    *exists = false;
+    return Vector<const char>::empty();
+  }
+  result[size] = '\0';
+  *exists = true;
+  return Vector<const char>(result, size);
+}
+
+
+int WriteCharsToFile(const char* str, int size, FILE* f) {
+  int total = 0;
+  while (total < size) {
+    int write = static_cast<int>(fwrite(str, 1, size - total, f));
+    if (write == 0) {
+      return total;
+    }
+    total += write;
+    str += write;
+  }
+  return total;
+}
+
+
+int AppendChars(const char* filename,
+                const char* str,
+                int size,
+                bool verbose) {
+  FILE* f = OS::FOpen(filename, "ab");
+  if (f == NULL) {
+    if (verbose) {
+      OS::PrintError("Cannot open file %s for writing.\n", filename);
+    }
+    return 0;
+  }
+  int written = WriteCharsToFile(str, size, f);
+  fclose(f);
+  return written;
+}
+
+
+int WriteChars(const char* filename,
+               const char* str,
+               int size,
+               bool verbose) {
+  FILE* f = OS::FOpen(filename, "wb");
+  if (f == NULL) {
+    if (verbose) {
+      OS::PrintError("Cannot open file %s for writing.\n", filename);
+    }
+    return 0;
+  }
+  int written = WriteCharsToFile(str, size, f);
+  fclose(f);
+  return written;
+}
+
+
+int WriteBytes(const char* filename,
+               const byte* bytes,
+               int size,
+               bool verbose) {
+  const char* str = reinterpret_cast<const char*>(bytes);
+  return WriteChars(filename, str, size, verbose);
+}
+
+
+
+void StringBuilder::AddFormatted(const char* format, ...) {
+  va_list arguments;
+  va_start(arguments, format);
+  AddFormattedList(format, arguments);
+  va_end(arguments);
+}
+
+
+void StringBuilder::AddFormattedList(const char* format, va_list list) {
+  ASSERT(!is_finalized() && position_ < buffer_.length());
+  int n = OS::VSNPrintF(buffer_ + position_, format, list);
+  if (n < 0 || n >= (buffer_.length() - position_)) {
+    position_ = buffer_.length();
+  } else {
+    position_ += n;
+  }
+}
+
+
+MemoryMappedExternalResource::MemoryMappedExternalResource(const char* filename)
+    : filename_(NULL),
+      data_(NULL),
+      length_(0),
+      remove_file_on_cleanup_(false) {
+  Init(filename);
+}
+
+
+MemoryMappedExternalResource::
+    MemoryMappedExternalResource(const char* filename,
+                                 bool remove_file_on_cleanup)
+    : filename_(NULL),
+      data_(NULL),
+      length_(0),
+      remove_file_on_cleanup_(remove_file_on_cleanup) {
+  Init(filename);
+}
+
+
+MemoryMappedExternalResource::~MemoryMappedExternalResource() {
+  // Release the resources if we had successfully acquired them:
+  if (file_ != NULL) {
+    delete file_;
+    if (remove_file_on_cleanup_) {
+      OS::Remove(filename_);
+    }
+    DeleteArray<char>(filename_);
+  }
+}
+
+
+void MemoryMappedExternalResource::Init(const char* filename) {
+  file_ = OS::MemoryMappedFile::open(filename);
+  if (file_ != NULL) {
+    filename_ = StrDup(filename);
+    data_ = reinterpret_cast<char*>(file_->memory());
+    length_ = file_->size();
+  }
+}
+
+
+bool MemoryMappedExternalResource::EnsureIsAscii(bool abort_if_failed) const {
+  bool is_ascii = true;
+
+  int line_no = 1;
+  const char* start_of_line = data_;
+  const char* end = data_ + length_;
+  for (const char* p = data_; p < end; p++) {
+    char c = *p;
+    if ((c & 0x80) != 0) {
+      // Non-ascii detected:
+      is_ascii = false;
+
+      // Report the error and abort if appropriate:
+      if (abort_if_failed) {
+        int char_no = static_cast<int>(p - start_of_line) - 1;
+
+        ASSERT(filename_ != NULL);
+        PrintF("\n\n\n"
+               "Abort: Non-Ascii character 0x%.2x in file %s line %d char %d",
+               c, filename_, line_no, char_no);
+
+        // Allow for some context up to kNumberOfLeadingContextChars chars
+        // before the offending non-ascii char to help the user see where
+        // the offending char is.
+        const int kNumberOfLeadingContextChars = 10;
+        const char* err_context = p - kNumberOfLeadingContextChars;
+        if (err_context < data_) {
+          err_context = data_;
+        }
+        // Compute the length of the error context and print it.
+        int err_context_length = static_cast<int>(p - err_context);
+        if (err_context_length != 0) {
+          PrintF(" after \"%.*s\"", err_context_length, err_context);
+        }
+        PrintF(".\n\n\n");
+        OS::Abort();
+      }
+
+      break;  // Non-ascii detected.  No need to continue scanning.
+    }
+    if (c == '\n') {
+      start_of_line = p;
+      line_no++;
+    }
+  }
+
+  return is_ascii;
+}
+
+
+} }  // namespace v8::internal
index 93fc1fda52f204568c5831efe825b4a608e5389e..498e23dc7b19b068d4d0b6564d5c6bdc0f74bdfb 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -190,71 +190,6 @@ Vector<const char> ReadFile(const char* filename,
                             bool verbose = true);
 
 
-// Helper class for building result strings in a character buffer. The
-// purpose of the class is to use safe operations that checks the
-// buffer bounds on all operations in debug mode.
-class StringBuilder {
- public:
-  // Create a string builder with a buffer of the given size. The
-  // buffer is allocated through NewArray<char> and must be
-  // deallocated by the caller of Finalize().
-  explicit StringBuilder(int size);
-
-  StringBuilder(char* buffer, int size)
-      : buffer_(buffer, size), position_(0) { }
-
-  ~StringBuilder() { if (!is_finalized()) Finalize(); }
-
-  int size() const { return buffer_.length(); }
-
-  // Get the current position in the builder.
-  int position() const {
-    ASSERT(!is_finalized());
-    return position_;
-  }
-
-  // Reset the position.
-  void Reset() { position_ = 0; }
-
-  // Add a single character to the builder. It is not allowed to add
-  // 0-characters; use the Finalize() method to terminate the string
-  // instead.
-  void AddCharacter(char c) {
-    ASSERT(c != '\0');
-    ASSERT(!is_finalized() && position_ < buffer_.length());
-    buffer_[position_++] = c;
-  }
-
-  // Add an entire string to the builder. Uses strlen() internally to
-  // compute the length of the input string.
-  void AddString(const char* s);
-
-  // Add the first 'n' characters of the given string 's' to the
-  // builder. The input string must have enough characters.
-  void AddSubstring(const char* s, int n);
-
-  // Add formatted contents to the builder just like printf().
-  void AddFormatted(const char* format, ...);
-
-  // Add formatted contents like printf based on a va_list.
-  void AddFormattedList(const char* format, va_list list);
-
-  // Add character padding to the builder. If count is non-positive,
-  // nothing is added to the builder.
-  void AddPadding(char c, int count);
-
-  // Finalize the string by 0-terminating it and returning the buffer.
-  char* Finalize();
-
- private:
-  Vector<char> buffer_;
-  int position_;
-
-  bool is_finalized() const { return position_ < 0; }
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder);
-};
-
 
 // Copy from ASCII/16bit chars to ASCII/16bit chars.
 template <typename sourcechar, typename sinkchar>
@@ -313,6 +248,19 @@ class MemoryMappedExternalResource: public
   bool remove_file_on_cleanup_;
 };
 
+class StringBuilder : public SimpleStringBuilder {
+ public:
+  explicit StringBuilder(int size) : SimpleStringBuilder(size) { }
+  StringBuilder(char* buffer, int size) : SimpleStringBuilder(buffer, size) { }
+
+  // Add formatted contents to the builder just like printf().
+  void AddFormatted(const char* format, ...);
+
+  // Add formatted contents like printf based on a va_list.
+  void AddFormattedList(const char* format, va_list list);
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder);
+};
 
 } }  // namespace v8::internal