LCOV - code coverage report
Current view: top level - src - conversions.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 186 190 97.9 %
Date: 2017-04-26 Functions: 13 14 92.9 %

          Line data    Source code
       1             : // Copyright 2011 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/conversions.h"
       6             : 
       7             : #include <limits.h>
       8             : #include <stdarg.h>
       9             : #include <cmath>
      10             : 
      11             : #include "src/allocation.h"
      12             : #include "src/assert-scope.h"
      13             : #include "src/char-predicates-inl.h"
      14             : #include "src/codegen.h"
      15             : #include "src/conversions-inl.h"
      16             : #include "src/dtoa.h"
      17             : #include "src/factory.h"
      18             : #include "src/handles.h"
      19             : #include "src/list-inl.h"
      20             : #include "src/strtod.h"
      21             : #include "src/utils.h"
      22             : 
      23             : #ifndef _STLP_VENDOR_CSTD
      24             : // STLPort doesn't import fpclassify into the std namespace.
      25             : using std::fpclassify;
      26             : #endif
      27             : 
      28             : namespace v8 {
      29             : namespace internal {
      30             : 
      31             : 
      32             : namespace {
      33             : 
      34             : // C++-style iterator adaptor for StringCharacterStream
      35             : // (unlike C++ iterators the end-marker has different type).
      36             : class StringCharacterStreamIterator {
      37             :  public:
      38             :   class EndMarker {};
      39             : 
      40             :   explicit StringCharacterStreamIterator(StringCharacterStream* stream);
      41             : 
      42             :   uint16_t operator*() const;
      43             :   void operator++();
      44             :   bool operator==(EndMarker const&) const { return end_; }
      45             :   bool operator!=(EndMarker const& m) const { return !end_; }
      46             : 
      47             :  private:
      48             :   StringCharacterStream* const stream_;
      49             :   uint16_t current_;
      50             :   bool end_;
      51             : };
      52             : 
      53             : 
      54             : StringCharacterStreamIterator::StringCharacterStreamIterator(
      55             :     StringCharacterStream* stream) : stream_(stream) {
      56             :   ++(*this);
      57             : }
      58             : 
      59             : uint16_t StringCharacterStreamIterator::operator*() const {
      60             :   return current_;
      61             : }
      62             : 
      63             : 
      64             : void StringCharacterStreamIterator::operator++() {
      65             :   end_ = !stream_->HasMore();
      66             :   if (!end_) {
      67             :     current_ = stream_->GetNext();
      68             :   }
      69             : }
      70             : }  // End anonymous namespace.
      71             : 
      72             : 
      73        7448 : double StringToDouble(UnicodeCache* unicode_cache,
      74             :                       const char* str, int flags, double empty_string_val) {
      75             :   // We cast to const uint8_t* here to avoid instantiating the
      76             :   // InternalStringToDouble() template for const char* as well.
      77             :   const uint8_t* start = reinterpret_cast<const uint8_t*>(str);
      78        7448 :   const uint8_t* end = start + StrLength(str);
      79             :   return InternalStringToDouble(unicode_cache, start, end, flags,
      80        7448 :                                 empty_string_val);
      81             : }
      82             : 
      83             : 
      84     3450719 : double StringToDouble(UnicodeCache* unicode_cache,
      85             :                       Vector<const uint8_t> str,
      86             :                       int flags,
      87             :                       double empty_string_val) {
      88             :   // We cast to const uint8_t* here to avoid instantiating the
      89             :   // InternalStringToDouble() template for const char* as well.
      90     3450719 :   const uint8_t* start = reinterpret_cast<const uint8_t*>(str.start());
      91     3694956 :   const uint8_t* end = start + str.length();
      92             :   return InternalStringToDouble(unicode_cache, start, end, flags,
      93     3694956 :                                 empty_string_val);
      94             : }
      95             : 
      96             : 
      97           0 : double StringToDouble(UnicodeCache* unicode_cache,
      98             :                       Vector<const uc16> str,
      99             :                       int flags,
     100             :                       double empty_string_val) {
     101     2476805 :   const uc16* end = str.start() + str.length();
     102             :   return InternalStringToDouble(unicode_cache, str.start(), end, flags,
     103     2476805 :                                 empty_string_val);
     104             : }
     105             : 
     106             : 
     107             : // Converts a string into an integer.
     108      273039 : double StringToInt(UnicodeCache* unicode_cache,
     109             :                    Vector<const uint8_t> vector,
     110             :                    int radix) {
     111             :   return InternalStringToInt(
     112      273039 :       unicode_cache, vector.start(), vector.start() + vector.length(), radix);
     113             : }
     114             : 
     115             : 
     116     1831338 : double StringToInt(UnicodeCache* unicode_cache,
     117             :                    Vector<const uc16> vector,
     118             :                    int radix) {
     119             :   return InternalStringToInt(
     120     1831338 :       unicode_cache, vector.start(), vector.start() + vector.length(), radix);
     121             : }
     122             : 
     123             : 
     124     2924992 : const char* DoubleToCString(double v, Vector<char> buffer) {
     125     2924992 :   switch (fpclassify(v)) {
     126             :     case FP_NAN: return "NaN";
     127       41052 :     case FP_INFINITE: return (v < 0.0 ? "-Infinity" : "Infinity");
     128      163252 :     case FP_ZERO: return "0";
     129             :     default: {
     130     2664721 :       SimpleStringBuilder builder(buffer.start(), buffer.length());
     131             :       int decimal_point;
     132             :       int sign;
     133             :       const int kV8DtoaBufferCapacity = kBase10MaximalLength + 1;
     134             :       char decimal_rep[kV8DtoaBufferCapacity];
     135             :       int length;
     136             : 
     137             :       DoubleToAscii(v, DTOA_SHORTEST, 0,
     138             :                     Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
     139     2664721 :                     &sign, &length, &decimal_point);
     140             : 
     141     2664721 :       if (sign) builder.AddCharacter('-');
     142             : 
     143     2664721 :       if (length <= decimal_point && decimal_point <= 21) {
     144             :         // ECMA-262 section 9.8.1 step 6.
     145     1163199 :         builder.AddString(decimal_rep);
     146     1163199 :         builder.AddPadding('0', decimal_point - length);
     147             : 
     148     1501522 :       } else if (0 < decimal_point && decimal_point <= 21) {
     149             :         // ECMA-262 section 9.8.1 step 7.
     150     1007441 :         builder.AddSubstring(decimal_rep, decimal_point);
     151             :         builder.AddCharacter('.');
     152     1007441 :         builder.AddString(decimal_rep + decimal_point);
     153             : 
     154      494081 :       } else if (decimal_point <= 0 && decimal_point > -6) {
     155             :         // ECMA-262 section 9.8.1 step 8.
     156       29686 :         builder.AddString("0.");
     157       29686 :         builder.AddPadding('0', -decimal_point);
     158       29686 :         builder.AddString(decimal_rep);
     159             : 
     160             :       } else {
     161             :         // ECMA-262 section 9.8.1 step 9 and 10 combined.
     162      464395 :         builder.AddCharacter(decimal_rep[0]);
     163      464395 :         if (length != 1) {
     164             :           builder.AddCharacter('.');
     165      461377 :           builder.AddString(decimal_rep + 1);
     166             :         }
     167             :         builder.AddCharacter('e');
     168      464395 :         builder.AddCharacter((decimal_point >= 0) ? '+' : '-');
     169      464395 :         int exponent = decimal_point - 1;
     170      464395 :         if (exponent < 0) exponent = -exponent;
     171      464395 :         builder.AddDecimalInteger(exponent);
     172             :       }
     173     2664721 :       return builder.Finalize();
     174             :     }
     175             :   }
     176             : }
     177             : 
     178             : 
     179    51590683 : const char* IntToCString(int n, Vector<char> buffer) {
     180             :   bool negative = false;
     181    51590683 :   if (n < 0) {
     182             :     // We must not negate the most negative int.
     183     1665646 :     if (n == kMinInt) return DoubleToCString(n, buffer);
     184             :     negative = true;
     185     1652934 :     n = -n;
     186             :   }
     187             :   // Build the string backwards from the least significant digit.
     188    51577971 :   int i = buffer.length();
     189   103155942 :   buffer[--i] = '\0';
     190   251797847 :   do {
     191   503595694 :     buffer[--i] = '0' + (n % 10);
     192   251797847 :     n /= 10;
     193             :   } while (n);
     194    53230905 :   if (negative) buffer[--i] = '-';
     195    51577971 :   return buffer.start() + i;
     196             : }
     197             : 
     198             : 
     199        4615 : char* DoubleToFixedCString(double value, int f) {
     200             :   const int kMaxDigitsBeforePoint = 21;
     201             :   const double kFirstNonFixed = 1e21;
     202             :   const int kMaxDigitsAfterPoint = 20;
     203             :   DCHECK(f >= 0);
     204             :   DCHECK(f <= kMaxDigitsAfterPoint);
     205             : 
     206             :   bool negative = false;
     207             :   double abs_value = value;
     208        4615 :   if (value < 0) {
     209        1503 :     abs_value = -value;
     210             :     negative = true;
     211             :   }
     212             : 
     213             :   // If abs_value has more than kMaxDigitsBeforePoint digits before the point
     214             :   // use the non-fixed conversion routine.
     215        4615 :   if (abs_value >= kFirstNonFixed) {
     216             :     char arr[100];
     217             :     Vector<char> buffer(arr, arraysize(arr));
     218         118 :     return StrDup(DoubleToCString(value, buffer));
     219             :   }
     220             : 
     221             :   // Find a sufficiently precise decimal representation of n.
     222             :   int decimal_point;
     223             :   int sign;
     224             :   // Add space for the '\0' byte.
     225             :   const int kDecimalRepCapacity =
     226             :       kMaxDigitsBeforePoint + kMaxDigitsAfterPoint + 1;
     227             :   char decimal_rep[kDecimalRepCapacity];
     228             :   int decimal_rep_length;
     229             :   DoubleToAscii(value, DTOA_FIXED, f,
     230             :                 Vector<char>(decimal_rep, kDecimalRepCapacity),
     231        4497 :                 &sign, &decimal_rep_length, &decimal_point);
     232             : 
     233             :   // Create a representation that is padded with zeros if needed.
     234             :   int zero_prefix_length = 0;
     235             :   int zero_postfix_length = 0;
     236             : 
     237        4497 :   if (decimal_point <= 0) {
     238        1780 :     zero_prefix_length = -decimal_point + 1;
     239        1780 :     decimal_point = 1;
     240             :   }
     241             : 
     242        4497 :   if (zero_prefix_length + decimal_rep_length < decimal_point + f) {
     243        2023 :     zero_postfix_length = decimal_point + f - decimal_rep_length -
     244        2023 :                           zero_prefix_length;
     245             :   }
     246             : 
     247             :   unsigned rep_length =
     248        4497 :       zero_prefix_length + decimal_rep_length + zero_postfix_length;
     249        4497 :   SimpleStringBuilder rep_builder(rep_length + 1);
     250        4497 :   rep_builder.AddPadding('0', zero_prefix_length);
     251        4497 :   rep_builder.AddString(decimal_rep);
     252        4497 :   rep_builder.AddPadding('0', zero_postfix_length);
     253        4497 :   char* rep = rep_builder.Finalize();
     254             : 
     255             :   // Create the result string by appending a minus and putting in a
     256             :   // decimal point if needed.
     257        4497 :   unsigned result_size = decimal_point + f + 2;
     258        4497 :   SimpleStringBuilder builder(result_size + 1);
     259        4497 :   if (negative) builder.AddCharacter('-');
     260        4497 :   builder.AddSubstring(rep, decimal_point);
     261        4497 :   if (f > 0) {
     262             :     builder.AddCharacter('.');
     263        3275 :     builder.AddSubstring(rep + decimal_point, f);
     264             :   }
     265             :   DeleteArray(rep);
     266        4497 :   return builder.Finalize();
     267             : }
     268             : 
     269             : 
     270        8127 : static char* CreateExponentialRepresentation(char* decimal_rep,
     271             :                                              int exponent,
     272             :                                              bool negative,
     273             :                                              int significant_digits) {
     274             :   bool negative_exponent = false;
     275        8127 :   if (exponent < 0) {
     276             :     negative_exponent = true;
     277        3155 :     exponent = -exponent;
     278             :   }
     279             : 
     280             :   // Leave room in the result for appending a minus, for a period, the
     281             :   // letter 'e', a minus or a plus depending on the exponent, and a
     282             :   // three digit exponent.
     283        8127 :   unsigned result_size = significant_digits + 7;
     284        8127 :   SimpleStringBuilder builder(result_size + 1);
     285             : 
     286        8127 :   if (negative) builder.AddCharacter('-');
     287        8127 :   builder.AddCharacter(decimal_rep[0]);
     288        8127 :   if (significant_digits != 1) {
     289             :     builder.AddCharacter('.');
     290        6725 :     builder.AddString(decimal_rep + 1);
     291             :     int rep_length = StrLength(decimal_rep);
     292        6725 :     builder.AddPadding('0', significant_digits - rep_length);
     293             :   }
     294             : 
     295             :   builder.AddCharacter('e');
     296        8127 :   builder.AddCharacter(negative_exponent ? '-' : '+');
     297        8127 :   builder.AddDecimalInteger(exponent);
     298       16254 :   return builder.Finalize();
     299             : }
     300             : 
     301             : 
     302        6551 : char* DoubleToExponentialCString(double value, int f) {
     303             :   const int kMaxDigitsAfterPoint = 20;
     304             :   // f might be -1 to signal that f was undefined in JavaScript.
     305             :   DCHECK(f >= -1 && f <= kMaxDigitsAfterPoint);
     306             : 
     307             :   bool negative = false;
     308        6551 :   if (value < 0) {
     309        2966 :     value = -value;
     310             :     negative = true;
     311             :   }
     312             : 
     313             :   // Find a sufficiently precise decimal representation of n.
     314             :   int decimal_point;
     315             :   int sign;
     316             :   // f corresponds to the digits after the point. There is always one digit
     317             :   // before the point. The number of requested_digits equals hence f + 1.
     318             :   // And we have to add one character for the null-terminator.
     319             :   const int kV8DtoaBufferCapacity = kMaxDigitsAfterPoint + 1 + 1;
     320             :   // Make sure that the buffer is big enough, even if we fall back to the
     321             :   // shortest representation (which happens when f equals -1).
     322             :   DCHECK(kBase10MaximalLength <= kMaxDigitsAfterPoint + 1);
     323             :   char decimal_rep[kV8DtoaBufferCapacity];
     324             :   int decimal_rep_length;
     325             : 
     326        6551 :   if (f == -1) {
     327             :     DoubleToAscii(value, DTOA_SHORTEST, 0,
     328             :                   Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
     329        2061 :                   &sign, &decimal_rep_length, &decimal_point);
     330        2061 :     f = decimal_rep_length - 1;
     331             :   } else {
     332             :     DoubleToAscii(value, DTOA_PRECISION, f + 1,
     333             :                   Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
     334        4490 :                   &sign, &decimal_rep_length, &decimal_point);
     335             :   }
     336             :   DCHECK(decimal_rep_length > 0);
     337             :   DCHECK(decimal_rep_length <= f + 1);
     338             : 
     339        6551 :   int exponent = decimal_point - 1;
     340             :   char* result =
     341        6551 :       CreateExponentialRepresentation(decimal_rep, exponent, negative, f+1);
     342             : 
     343        6551 :   return result;
     344             : }
     345             : 
     346             : 
     347        4683 : char* DoubleToPrecisionCString(double value, int p) {
     348             :   const int kMinimalDigits = 1;
     349             :   const int kMaximalDigits = 21;
     350             :   DCHECK(p >= kMinimalDigits && p <= kMaximalDigits);
     351             :   USE(kMinimalDigits);
     352             : 
     353             :   bool negative = false;
     354        4683 :   if (value < 0) {
     355        2297 :     value = -value;
     356             :     negative = true;
     357             :   }
     358             : 
     359             :   // Find a sufficiently precise decimal representation of n.
     360             :   int decimal_point;
     361             :   int sign;
     362             :   // Add one for the terminating null character.
     363             :   const int kV8DtoaBufferCapacity = kMaximalDigits + 1;
     364             :   char decimal_rep[kV8DtoaBufferCapacity];
     365             :   int decimal_rep_length;
     366             : 
     367             :   DoubleToAscii(value, DTOA_PRECISION, p,
     368             :                 Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
     369        4683 :                 &sign, &decimal_rep_length, &decimal_point);
     370             :   DCHECK(decimal_rep_length <= p);
     371             : 
     372        4683 :   int exponent = decimal_point - 1;
     373             : 
     374             :   char* result = NULL;
     375             : 
     376        4683 :   if (exponent < -6 || exponent >= p) {
     377             :     result =
     378        1576 :         CreateExponentialRepresentation(decimal_rep, exponent, negative, p);
     379             :   } else {
     380             :     // Use fixed notation.
     381             :     //
     382             :     // Leave room in the result for appending a minus, a period and in
     383             :     // the case where decimal_point is not positive for a zero in
     384             :     // front of the period.
     385             :     unsigned result_size = (decimal_point <= 0)
     386        1113 :         ? -decimal_point + p + 3
     387        4220 :         : p + 2;
     388        3107 :     SimpleStringBuilder builder(result_size + 1);
     389        3107 :     if (negative) builder.AddCharacter('-');
     390        3107 :     if (decimal_point <= 0) {
     391        1113 :       builder.AddString("0.");
     392        1113 :       builder.AddPadding('0', -decimal_point);
     393        1113 :       builder.AddString(decimal_rep);
     394        1113 :       builder.AddPadding('0', p - decimal_rep_length);
     395             :     } else {
     396        1994 :       const int m = Min(decimal_rep_length, decimal_point);
     397        1994 :       builder.AddSubstring(decimal_rep, m);
     398        1994 :       builder.AddPadding('0', decimal_point - decimal_rep_length);
     399        1994 :       if (decimal_point < p) {
     400             :         builder.AddCharacter('.');
     401        1626 :         const int extra = negative ? 2 : 1;
     402        1626 :         if (decimal_rep_length > decimal_point) {
     403        1318 :           const int len = StrLength(decimal_rep + decimal_point);
     404        1318 :           const int n = Min(len, p - (builder.position() - extra));
     405        1318 :           builder.AddSubstring(decimal_rep + decimal_point, n);
     406             :         }
     407        1626 :         builder.AddPadding('0', extra + (p - builder.position()));
     408             :       }
     409             :     }
     410        3107 :     result = builder.Finalize();
     411             :   }
     412             : 
     413        4683 :   return result;
     414             : }
     415             : 
     416      166882 : char* DoubleToRadixCString(double value, int radix) {
     417             :   DCHECK(radix >= 2 && radix <= 36);
     418             :   DCHECK(std::isfinite(value));
     419             :   DCHECK_NE(0.0, value);
     420             :   // Character array used for conversion.
     421             :   static const char chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
     422             : 
     423             :   // Temporary buffer for the result. We start with the decimal point in the
     424             :   // middle and write to the left for the integer part and to the right for the
     425             :   // fractional part. 1024 characters for the exponent and 52 for the mantissa
     426             :   // either way, with additional space for sign, decimal point and string
     427             :   // termination should be sufficient.
     428             :   static const int kBufferSize = 2200;
     429             :   char buffer[kBufferSize];
     430             :   int integer_cursor = kBufferSize / 2;
     431             :   int fraction_cursor = integer_cursor;
     432             : 
     433      166882 :   bool negative = value < 0;
     434      166882 :   if (negative) value = -value;
     435             : 
     436             :   // Split the value into an integer part and a fractional part.
     437      166882 :   double integer = std::floor(value);
     438      166882 :   double fraction = value - integer;
     439             :   // We only compute fractional digits up to the input double's precision.
     440      166882 :   double delta = 0.5 * (Double(value).NextDouble() - value);
     441      333764 :   delta = std::max(Double(0.0).NextDouble(), delta);
     442             :   DCHECK_GT(delta, 0.0);
     443      166882 :   if (fraction > delta) {
     444             :     // Insert decimal point.
     445        2394 :     buffer[fraction_cursor++] = '.';
     446       55699 :     do {
     447             :       // Shift up by one digit.
     448       56108 :       fraction *= radix;
     449       56108 :       delta *= radix;
     450             :       // Write digit.
     451       56108 :       int digit = static_cast<int>(fraction);
     452       56108 :       buffer[fraction_cursor++] = chars[digit];
     453             :       // Calculate remainder.
     454       56108 :       fraction -= digit;
     455             :       // Round to even.
     456       56108 :       if (fraction > 0.5 || (fraction == 0.5 && (digit & 1))) {
     457       18533 :         if (fraction + delta > 1) {
     458             :           // We need to back trace already written digits in case of carry-over.
     459             :           while (true) {
     460         439 :             fraction_cursor--;
     461         439 :             if (fraction_cursor == kBufferSize / 2) {
     462           0 :               CHECK_EQ('.', buffer[fraction_cursor]);
     463             :               // Carry over to the integer part.
     464           0 :               integer += 1;
     465           0 :               break;
     466             :             }
     467         439 :             char c = buffer[fraction_cursor];
     468             :             // Reconstruct digit.
     469         439 :             int digit = c > '9' ? (c - 'a' + 10) : (c - '0');
     470         439 :             if (digit + 1 < radix) {
     471         409 :               buffer[fraction_cursor++] = chars[digit + 1];
     472         409 :               break;
     473             :             }
     474             :           }
     475             :           break;
     476             :         }
     477             :       }
     478             :     } while (fraction > delta);
     479             :   }
     480             : 
     481             :   // Compute integer digits. Fill unrepresented digits with zero.
     482      364600 :   while (Double(integer / radix).Exponent() > 0) {
     483             :     integer /= radix;
     484       15418 :     buffer[--integer_cursor] = '0';
     485             :   }
     486      631072 :   do {
     487      631072 :     double remainder = modulo(integer, radix);
     488      631072 :     buffer[--integer_cursor] = chars[static_cast<int>(remainder)];
     489      631072 :     integer = (integer - remainder) / radix;
     490             :   } while (integer > 0);
     491             : 
     492             :   // Add sign and terminate string.
     493      166882 :   if (negative) buffer[--integer_cursor] = '-';
     494      166882 :   buffer[fraction_cursor++] = '\0';
     495             :   DCHECK_LT(fraction_cursor, kBufferSize);
     496             :   DCHECK_LE(0, integer_cursor);
     497             :   // Allocate new string as return value.
     498      166882 :   char* result = NewArray<char>(fraction_cursor - integer_cursor);
     499      166882 :   memcpy(result, buffer + integer_cursor, fraction_cursor - integer_cursor);
     500      166882 :   return result;
     501             : }
     502             : 
     503             : 
     504             : // ES6 18.2.4 parseFloat(string)
     505     2720606 : double StringToDouble(UnicodeCache* unicode_cache, Handle<String> string,
     506             :                       int flags, double empty_string_val) {
     507     2720606 :   Handle<String> flattened = String::Flatten(string);
     508             :   {
     509             :     DisallowHeapAllocation no_gc;
     510     2720606 :     String::FlatContent flat = flattened->GetFlatContent();
     511             :     DCHECK(flat.IsFlat());
     512     2720606 :     if (flat.IsOneByte()) {
     513             :       return StringToDouble(unicode_cache, flat.ToOneByteVector(), flags,
     514      244237 :                             empty_string_val);
     515             :     } else {
     516             :       return StringToDouble(unicode_cache, flat.ToUC16Vector(), flags,
     517     2476369 :                             empty_string_val);
     518             :     }
     519             :   }
     520             : }
     521             : 
     522             : 
     523      163752 : bool IsSpecialIndex(UnicodeCache* unicode_cache, String* string) {
     524             :   // Max length of canonical double: -X.XXXXXXXXXXXXXXXXX-eXXX
     525             :   const int kBufferSize = 24;
     526             :   const int length = string->length();
     527      163752 :   if (length == 0 || length > kBufferSize) return false;
     528             :   uint16_t buffer[kBufferSize];
     529      163738 :   String::WriteToFlat(string, buffer, 0, length);
     530             :   // If the first char is not a digit or a '-' or we can't match 'NaN' or
     531             :   // '(-)Infinity', bailout immediately.
     532             :   int offset = 0;
     533      327476 :   if (!IsDecimalDigit(buffer[0])) {
     534      163051 :     if (buffer[0] == '-') {
     535        3307 :       if (length == 1) return false;  // Just '-' is bad.
     536        6600 :       if (!IsDecimalDigit(buffer[1])) {
     537          63 :         if (buffer[1] == 'I' && length == 9) {
     538             :           // Allow matching of '-Infinity' below.
     539             :         } else {
     540             :           return false;
     541             :         }
     542             :       }
     543             :       offset++;
     544      159744 :     } else if (buffer[0] == 'I' && length == 8) {
     545             :       // Allow matching of 'Infinity' below.
     546      159737 :     } else if (buffer[0] == 'N' && length == 3) {
     547             :       // Match NaN.
     548         175 :       return buffer[1] == 'a' && buffer[2] == 'N';
     549             :     } else {
     550             :       return false;
     551             :     }
     552             :   }
     553             :   // Expected fast path: key is an integer.
     554             :   static const int kRepresentableIntegerLength = 15;  // (-)XXXXXXXXXXXXXXX
     555        3994 :   if (length - offset <= kRepresentableIntegerLength) {
     556             :     const int initial_offset = offset;
     557             :     bool matches = true;
     558       11491 :     for (; offset < length; offset++) {
     559       22982 :       matches &= IsDecimalDigit(buffer[offset]);
     560             :     }
     561        3945 :     if (matches) {
     562             :       // Match 0 and -0.
     563        3558 :       if (buffer[initial_offset] == '0') return initial_offset == length - 1;
     564             :       return true;
     565             :     }
     566             :   }
     567             :   // Slow path: test DoubleToString(StringToDouble(string)) == string.
     568             :   Vector<const uint16_t> vector(buffer, length);
     569             :   double d = StringToDouble(unicode_cache, vector, NO_FLAGS);
     570         436 :   if (std::isnan(d)) return false;
     571             :   // Compute reverse string.
     572             :   char reverse_buffer[kBufferSize + 1];  // Result will be /0 terminated.
     573             :   Vector<char> reverse_vector(reverse_buffer, arraysize(reverse_buffer));
     574         429 :   const char* reverse_string = DoubleToCString(d, reverse_vector);
     575        2710 :   for (int i = 0; i < length; ++i) {
     576        2393 :     if (static_cast<uint16_t>(reverse_string[i]) != buffer[i]) return false;
     577             :   }
     578             :   return true;
     579             : }
     580             : }  // namespace internal
     581             : }  // namespace v8

Generated by: LCOV version 1.10