1 // Copyright 2011 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_CONVERSIONS_INL_H_ 6 #define V8_CONVERSIONS_INL_H_ 7 8 #include <float.h> // Required for DBL_MAX and on Win32 for finite() 9 #include <limits.h> // Required for INT_MAX etc. 10 #include <stdarg.h> 11 #include <cmath> 12 #include "src/globals.h" // Required for V8_INFINITY 13 #include "src/unicode-cache-inl.h" 14 15 // ---------------------------------------------------------------------------- 16 // Extra POSIX/ANSI functions for Win32/MSVC. 17 18 #include "src/base/bits.h" 19 #include "src/base/platform/platform.h" 20 #include "src/conversions.h" 21 #include "src/double.h" 22 #include "src/objects-inl.h" 23 #include "src/strtod.h" 24 25 namespace v8 { 26 namespace internal { 27 28 inline double JunkStringValue() { 29 return bit_cast<double, uint64_t>(kQuietNaNMask); 30 } 31 32 33 inline double SignedZero(bool negative) { 34 return negative ? uint64_to_double(Double::kSignMask) : 0.0; 35 } 36 37 38 // The fast double-to-unsigned-int conversion routine does not guarantee 39 // rounding towards zero, or any reasonable value if the argument is larger 40 // than what fits in an unsigned 32-bit integer. 41 inline unsigned int FastD2UI(double x) { 42 // There is no unsigned version of lrint, so there is no fast path 43 // in this function as there is in FastD2I. Using lrint doesn't work 44 // for values of 2^31 and above. 45 46 // Convert "small enough" doubles to uint32_t by fixing the 32 47 // least significant non-fractional bits in the low 32 bits of the 48 // double, and reading them from there. 49 const double k2Pow52 = 4503599627370496.0; 50 bool negative = x < 0; 51 if (negative) { 52 x = -x; 53 } 54 if (x < k2Pow52) { 55 x += k2Pow52; 56 uint32_t result; 57 #ifndef V8_TARGET_BIG_ENDIAN 58 Address mantissa_ptr = reinterpret_cast<Address>(&x); 59 #else 60 Address mantissa_ptr = reinterpret_cast<Address>(&x) + kIntSize; 61 #endif 62 // Copy least significant 32 bits of mantissa. 63 memcpy(&result, mantissa_ptr, sizeof(result)); 64 return negative ? ~result + 1 : result; 65 } 66 // Large number (outside uint32 range), Infinity or NaN. 67 return 0x80000000u; // Return integer indefinite. 68 } 69 70 71 inline float DoubleToFloat32(double x) { 72 // TODO(yangguo): This static_cast is implementation-defined behaviour in C++, 73 // so we may need to do the conversion manually instead to match the spec. 74 volatile float f = static_cast<float>(x); 75 return f; 76 } 77 78 79 inline double DoubleToInteger(double x) { 80 if (std::isnan(x)) return 0; 81 if (!std::isfinite(x) || x == 0) return x; 82 return (x >= 0) ? std::floor(x) : std::ceil(x); 83 } 84 85 86 int32_t DoubleToInt32(double x) { 87 int32_t i = FastD2I(x); 88 if (FastI2D(i) == x) return i; 89 Double d(x); 90 int exponent = d.Exponent(); 91 if (exponent < 0) { 92 if (exponent <= -Double::kSignificandSize) return 0; 93 return d.Sign() * static_cast<int32_t>(d.Significand() >> -exponent); 94 } else { 95 if (exponent > 31) return 0; 96 return d.Sign() * static_cast<int32_t>(d.Significand() << exponent); 97 } 98 } 99 100 101 bool IsSmiDouble(double value) { 102 return !IsMinusZero(value) && value >= Smi::kMinValue && 103 value <= Smi::kMaxValue && value == FastI2D(FastD2I(value)); 104 } 105 106 107 bool IsInt32Double(double value) { 108 return !IsMinusZero(value) && value >= kMinInt && value <= kMaxInt && 109 value == FastI2D(FastD2I(value)); 110 } 111 112 113 bool IsUint32Double(double value) { 114 return !IsMinusZero(value) && value >= 0 && value <= kMaxUInt32 && 115 value == FastUI2D(FastD2UI(value)); 116 } 117 118 119 int32_t NumberToInt32(Object* number) { 120 if (number->IsSmi()) return Smi::cast(number)->value(); 121 return DoubleToInt32(number->Number()); 122 } 123 124 125 uint32_t NumberToUint32(Object* number) { 126 if (number->IsSmi()) return Smi::cast(number)->value(); 127 return DoubleToUint32(number->Number()); 128 } 129 130 int64_t NumberToInt64(Object* number) { 131 if (number->IsSmi()) return Smi::cast(number)->value(); 132 return static_cast<int64_t>(number->Number()); 133 } 134 135 bool TryNumberToSize(Isolate* isolate, Object* number, size_t* result) { 136 SealHandleScope shs(isolate); 137 if (number->IsSmi()) { 138 int value = Smi::cast(number)->value(); 139 DCHECK(static_cast<unsigned>(Smi::kMaxValue) <= 140 std::numeric_limits<size_t>::max()); 141 if (value >= 0) { 142 *result = static_cast<size_t>(value); 143 return true; 144 } 145 return false; 146 } else { 147 DCHECK(number->IsHeapNumber()); 148 double value = HeapNumber::cast(number)->value(); 149 if (value >= 0 && value <= std::numeric_limits<size_t>::max()) { 150 *result = static_cast<size_t>(value); 151 return true; 152 } else { 153 return false; 154 } 155 } 156 } 157 158 159 size_t NumberToSize(Isolate* isolate, Object* number) { 160 size_t result = 0; 161 bool is_valid = TryNumberToSize(isolate, number, &result); 162 CHECK(is_valid); 163 return result; 164 } 165 166 167 uint32_t DoubleToUint32(double x) { 168 return static_cast<uint32_t>(DoubleToInt32(x)); 169 } 170 171 172 template <class Iterator, class EndMark> 173 bool SubStringEquals(Iterator* current, 174 EndMark end, 175 const char* substring) { 176 DCHECK(**current == *substring); 177 for (substring++; *substring != '\0'; substring++) { 178 ++*current; 179 if (*current == end || **current != *substring) return false; 180 } 181 ++*current; 182 return true; 183 } 184 185 186 // Returns true if a nonspace character has been found and false if the 187 // end was been reached before finding a nonspace character. 188 template <class Iterator, class EndMark> 189 inline bool AdvanceToNonspace(UnicodeCache* unicode_cache, 190 Iterator* current, 191 EndMark end) { 192 while (*current != end) { 193 if (!unicode_cache->IsWhiteSpaceOrLineTerminator(**current)) return true; 194 ++*current; 195 } 196 return false; 197 } 198 199 200 // Parsing integers with radix 2, 4, 8, 16, 32. Assumes current != end. 201 template <int radix_log_2, class Iterator, class EndMark> 202 double InternalStringToIntDouble(UnicodeCache* unicode_cache, 203 Iterator current, 204 EndMark end, 205 bool negative, 206 bool allow_trailing_junk) { 207 DCHECK(current != end); 208 209 // Skip leading 0s. 210 while (*current == '0') { 211 ++current; 212 if (current == end) return SignedZero(negative); 213 } 214 215 int64_t number = 0; 216 int exponent = 0; 217 const int radix = (1 << radix_log_2); 218 219 do { 220 int digit; 221 if (*current >= '0' && *current <= '9' && *current < '0' + radix) { 222 digit = static_cast<char>(*current) - '0'; 223 } else if (radix > 10 && *current >= 'a' && *current < 'a' + radix - 10) { 224 digit = static_cast<char>(*current) - 'a' + 10; 225 } else if (radix > 10 && *current >= 'A' && *current < 'A' + radix - 10) { 226 digit = static_cast<char>(*current) - 'A' + 10; 227 } else { 228 if (allow_trailing_junk || 229 !AdvanceToNonspace(unicode_cache, ¤t, end)) { 230 break; 231 } else { 232 return JunkStringValue(); 233 } 234 } 235 236 number = number * radix + digit; 237 int overflow = static_cast<int>(number >> 53); 238 if (overflow != 0) { 239 // Overflow occurred. Need to determine which direction to round the 240 // result. 241 int overflow_bits_count = 1; 242 while (overflow > 1) { 243 overflow_bits_count++; 244 overflow >>= 1; 245 } 246 247 int dropped_bits_mask = ((1 << overflow_bits_count) - 1); 248 int dropped_bits = static_cast<int>(number) & dropped_bits_mask; 249 number >>= overflow_bits_count; 250 exponent = overflow_bits_count; 251 252 bool zero_tail = true; 253 while (true) { 254 ++current; 255 if (current == end || !isDigit(*current, radix)) break; 256 zero_tail = zero_tail && *current == '0'; 257 exponent += radix_log_2; 258 } 259 260 if (!allow_trailing_junk && 261 AdvanceToNonspace(unicode_cache, ¤t, end)) { 262 return JunkStringValue(); 263 } 264 265 int middle_value = (1 << (overflow_bits_count - 1)); 266 if (dropped_bits > middle_value) { 267 number++; // Rounding up. 268 } else if (dropped_bits == middle_value) { 269 // Rounding to even to consistency with decimals: half-way case rounds 270 // up if significant part is odd and down otherwise. 271 if ((number & 1) != 0 || !zero_tail) { 272 number++; // Rounding up. 273 } 274 } 275 276 // Rounding up may cause overflow. 277 if ((number & (static_cast<int64_t>(1) << 53)) != 0) { 278 exponent++; 279 number >>= 1; 280 } 281 break; 282 } 283 ++current; 284 } while (current != end); 285 286 DCHECK(number < ((int64_t)1 << 53)); 287 DCHECK(static_cast<int64_t>(static_cast<double>(number)) == number); 288 289 if (exponent == 0) { 290 if (negative) { 291 if (number == 0) return -0.0; 292 number = -number; 293 } 294 return static_cast<double>(number); 295 } 296 297 DCHECK(number != 0); 298 return std::ldexp(static_cast<double>(negative ? -number : number), exponent); 299 } 300 301 // ES6 18.2.5 parseInt(string, radix) 302 template <class Iterator, class EndMark> 303 double InternalStringToInt(UnicodeCache* unicode_cache, 304 Iterator current, 305 EndMark end, 306 int radix) { 307 const bool allow_trailing_junk = true; 308 const double empty_string_val = JunkStringValue(); 309 310 if (!AdvanceToNonspace(unicode_cache, ¤t, end)) { 311 return empty_string_val; 312 } 313 314 bool negative = false; 315 bool leading_zero = false; 316 317 if (*current == '+') { 318 // Ignore leading sign; skip following spaces. 319 ++current; 320 if (current == end) { 321 return JunkStringValue(); 322 } 323 } else if (*current == '-') { 324 ++current; 325 if (current == end) { 326 return JunkStringValue(); 327 } 328 negative = true; 329 } 330 331 if (radix == 0) { 332 // Radix detection. 333 radix = 10; 334 if (*current == '0') { 335 ++current; 336 if (current == end) return SignedZero(negative); 337 if (*current == 'x' || *current == 'X') { 338 radix = 16; 339 ++current; 340 if (current == end) return JunkStringValue(); 341 } else { 342 leading_zero = true; 343 } 344 } 345 } else if (radix == 16) { 346 if (*current == '0') { 347 // Allow "0x" prefix. 348 ++current; 349 if (current == end) return SignedZero(negative); 350 if (*current == 'x' || *current == 'X') { 351 ++current; 352 if (current == end) return JunkStringValue(); 353 } else { 354 leading_zero = true; 355 } 356 } 357 } 358 359 if (radix < 2 || radix > 36) return JunkStringValue(); 360 361 // Skip leading zeros. 362 while (*current == '0') { 363 leading_zero = true; 364 ++current; 365 if (current == end) return SignedZero(negative); 366 } 367 368 if (!leading_zero && !isDigit(*current, radix)) { 369 return JunkStringValue(); 370 } 371 372 if (base::bits::IsPowerOfTwo32(radix)) { 373 switch (radix) { 374 case 2: 375 return InternalStringToIntDouble<1>( 376 unicode_cache, current, end, negative, allow_trailing_junk); 377 case 4: 378 return InternalStringToIntDouble<2>( 379 unicode_cache, current, end, negative, allow_trailing_junk); 380 case 8: 381 return InternalStringToIntDouble<3>( 382 unicode_cache, current, end, negative, allow_trailing_junk); 383 384 case 16: 385 return InternalStringToIntDouble<4>( 386 unicode_cache, current, end, negative, allow_trailing_junk); 387 388 case 32: 389 return InternalStringToIntDouble<5>( 390 unicode_cache, current, end, negative, allow_trailing_junk); 391 default: 392 UNREACHABLE(); 393 } 394 } 395 396 if (radix == 10) { 397 // Parsing with strtod. 398 const int kMaxSignificantDigits = 309; // Doubles are less than 1.8e308. 399 // The buffer may contain up to kMaxSignificantDigits + 1 digits and a zero 400 // end. 401 const int kBufferSize = kMaxSignificantDigits + 2; 402 char buffer[kBufferSize]; 403 int buffer_pos = 0; 404 while (*current >= '0' && *current <= '9') { 405 if (buffer_pos <= kMaxSignificantDigits) { 406 // If the number has more than kMaxSignificantDigits it will be parsed 407 // as infinity. 408 DCHECK(buffer_pos < kBufferSize); 409 buffer[buffer_pos++] = static_cast<char>(*current); 410 } 411 ++current; 412 if (current == end) break; 413 } 414 415 if (!allow_trailing_junk && 416 AdvanceToNonspace(unicode_cache, ¤t, end)) { 417 return JunkStringValue(); 418 } 419 420 SLOW_DCHECK(buffer_pos < kBufferSize); 421 buffer[buffer_pos] = '\0'; 422 Vector<const char> buffer_vector(buffer, buffer_pos); 423 return negative ? -Strtod(buffer_vector, 0) : Strtod(buffer_vector, 0); 424 } 425 426 // The following code causes accumulating rounding error for numbers greater 427 // than ~2^56. It's explicitly allowed in the spec: "if R is not 2, 4, 8, 10, 428 // 16, or 32, then mathInt may be an implementation-dependent approximation to 429 // the mathematical integer value" (15.1.2.2). 430 431 int lim_0 = '0' + (radix < 10 ? radix : 10); 432 int lim_a = 'a' + (radix - 10); 433 int lim_A = 'A' + (radix - 10); 434 435 // NOTE: The code for computing the value may seem a bit complex at 436 // first glance. It is structured to use 32-bit multiply-and-add 437 // loops as long as possible to avoid loosing precision. 438 439 double v = 0.0; 440 bool done = false; 441 do { 442 // Parse the longest part of the string starting at index j 443 // possible while keeping the multiplier, and thus the part 444 // itself, within 32 bits. 445 unsigned int part = 0, multiplier = 1; 446 while (true) { 447 int d; 448 if (*current >= '0' && *current < lim_0) { 449 d = *current - '0'; 450 } else if (*current >= 'a' && *current < lim_a) { 451 d = *current - 'a' + 10; 452 } else if (*current >= 'A' && *current < lim_A) { 453 d = *current - 'A' + 10; 454 } else { 455 done = true; 456 break; 457 } 458 459 // Update the value of the part as long as the multiplier fits 460 // in 32 bits. When we can't guarantee that the next iteration 461 // will not overflow the multiplier, we stop parsing the part 462 // by leaving the loop. 463 const unsigned int kMaximumMultiplier = 0xffffffffU / 36; 464 uint32_t m = multiplier * radix; 465 if (m > kMaximumMultiplier) break; 466 part = part * radix + d; 467 multiplier = m; 468 DCHECK(multiplier > part); 469 470 ++current; 471 if (current == end) { 472 done = true; 473 break; 474 } 475 } 476 477 // Update the value and skip the part in the string. 478 v = v * multiplier + part; 479 } while (!done); 480 481 if (!allow_trailing_junk && 482 AdvanceToNonspace(unicode_cache, ¤t, end)) { 483 return JunkStringValue(); 484 } 485 486 return negative ? -v : v; 487 } 488 489 490 // Converts a string to a double value. Assumes the Iterator supports 491 // the following operations: 492 // 1. current == end (other ops are not allowed), current != end. 493 // 2. *current - gets the current character in the sequence. 494 // 3. ++current (advances the position). 495 template <class Iterator, class EndMark> 496 double InternalStringToDouble(UnicodeCache* unicode_cache, 497 Iterator current, 498 EndMark end, 499 int flags, 500 double empty_string_val) { 501 // To make sure that iterator dereferencing is valid the following 502 // convention is used: 503 // 1. Each '++current' statement is followed by check for equality to 'end'. 504 // 2. If AdvanceToNonspace returned false then current == end. 505 // 3. If 'current' becomes be equal to 'end' the function returns or goes to 506 // 'parsing_done'. 507 // 4. 'current' is not dereferenced after the 'parsing_done' label. 508 // 5. Code before 'parsing_done' may rely on 'current != end'. 509 if (!AdvanceToNonspace(unicode_cache, ¤t, end)) { 510 return empty_string_val; 511 } 512 513 const bool allow_trailing_junk = (flags & ALLOW_TRAILING_JUNK) != 0; 514 515 // The longest form of simplified number is: "-<significant digits>'.1eXXX\0". 516 const int kBufferSize = kMaxSignificantDigits + 10; 517 char buffer[kBufferSize]; // NOLINT: size is known at compile time. 518 int buffer_pos = 0; 519 520 // Exponent will be adjusted if insignificant digits of the integer part 521 // or insignificant leading zeros of the fractional part are dropped. 522 int exponent = 0; 523 int significant_digits = 0; 524 int insignificant_digits = 0; 525 bool nonzero_digit_dropped = false; 526 527 enum Sign { 528 NONE, 529 NEGATIVE, 530 POSITIVE 531 }; 532 533 Sign sign = NONE; 534 535 if (*current == '+') { 536 // Ignore leading sign. 537 ++current; 538 if (current == end) return JunkStringValue(); 539 sign = POSITIVE; 540 } else if (*current == '-') { 541 ++current; 542 if (current == end) return JunkStringValue(); 543 sign = NEGATIVE; 544 } 545 546 static const char kInfinityString[] = "Infinity"; 547 if (*current == kInfinityString[0]) { 548 if (!SubStringEquals(¤t, end, kInfinityString)) { 549 return JunkStringValue(); 550 } 551 552 if (!allow_trailing_junk && 553 AdvanceToNonspace(unicode_cache, ¤t, end)) { 554 return JunkStringValue(); 555 } 556 557 DCHECK(buffer_pos == 0); 558 return (sign == NEGATIVE) ? -V8_INFINITY : V8_INFINITY; 559 } 560 561 bool leading_zero = false; 562 if (*current == '0') { 563 ++current; 564 if (current == end) return SignedZero(sign == NEGATIVE); 565 566 leading_zero = true; 567 568 // It could be hexadecimal value. 569 if ((flags & ALLOW_HEX) && (*current == 'x' || *current == 'X')) { 570 ++current; 571 if (current == end || !isDigit(*current, 16) || sign != NONE) { 572 return JunkStringValue(); // "0x". 573 } 574 575 return InternalStringToIntDouble<4>(unicode_cache, 576 current, 577 end, 578 false, 579 allow_trailing_junk); 580 581 // It could be an explicit octal value. 582 } else if ((flags & ALLOW_OCTAL) && (*current == 'o' || *current == 'O')) { 583 ++current; 584 if (current == end || !isDigit(*current, 8) || sign != NONE) { 585 return JunkStringValue(); // "0o". 586 } 587 588 return InternalStringToIntDouble<3>(unicode_cache, 589 current, 590 end, 591 false, 592 allow_trailing_junk); 593 594 // It could be a binary value. 595 } else if ((flags & ALLOW_BINARY) && (*current == 'b' || *current == 'B')) { 596 ++current; 597 if (current == end || !isBinaryDigit(*current) || sign != NONE) { 598 return JunkStringValue(); // "0b". 599 } 600 601 return InternalStringToIntDouble<1>(unicode_cache, 602 current, 603 end, 604 false, 605 allow_trailing_junk); 606 } 607 608 // Ignore leading zeros in the integer part. 609 while (*current == '0') { 610 ++current; 611 if (current == end) return SignedZero(sign == NEGATIVE); 612 } 613 } 614 615 bool octal = leading_zero && (flags & ALLOW_IMPLICIT_OCTAL) != 0; 616 617 // Copy significant digits of the integer part (if any) to the buffer. 618 while (*current >= '0' && *current <= '9') { 619 if (significant_digits < kMaxSignificantDigits) { 620 DCHECK(buffer_pos < kBufferSize); 621 buffer[buffer_pos++] = static_cast<char>(*current); 622 significant_digits++; 623 // Will later check if it's an octal in the buffer. 624 } else { 625 insignificant_digits++; // Move the digit into the exponential part. 626 nonzero_digit_dropped = nonzero_digit_dropped || *current != '0'; 627 } 628 octal = octal && *current < '8'; 629 ++current; 630 if (current == end) goto parsing_done; 631 } 632 633 if (significant_digits == 0) { 634 octal = false; 635 } 636 637 if (*current == '.') { 638 if (octal && !allow_trailing_junk) return JunkStringValue(); 639 if (octal) goto parsing_done; 640 641 ++current; 642 if (current == end) { 643 if (significant_digits == 0 && !leading_zero) { 644 return JunkStringValue(); 645 } else { 646 goto parsing_done; 647 } 648 } 649 650 if (significant_digits == 0) { 651 // octal = false; 652 // Integer part consists of 0 or is absent. Significant digits start after 653 // leading zeros (if any). 654 while (*current == '0') { 655 ++current; 656 if (current == end) return SignedZero(sign == NEGATIVE); 657 exponent--; // Move this 0 into the exponent. 658 } 659 } 660 661 // There is a fractional part. We don't emit a '.', but adjust the exponent 662 // instead. 663 while (*current >= '0' && *current <= '9') { 664 if (significant_digits < kMaxSignificantDigits) { 665 DCHECK(buffer_pos < kBufferSize); 666 buffer[buffer_pos++] = static_cast<char>(*current); 667 significant_digits++; 668 exponent--; 669 } else { 670 // Ignore insignificant digits in the fractional part. 671 nonzero_digit_dropped = nonzero_digit_dropped || *current != '0'; 672 } 673 ++current; 674 if (current == end) goto parsing_done; 675 } 676 } 677 678 if (!leading_zero && exponent == 0 && significant_digits == 0) { 679 // If leading_zeros is true then the string contains zeros. 680 // If exponent < 0 then string was [+-]\.0*... 681 // If significant_digits != 0 the string is not equal to 0. 682 // Otherwise there are no digits in the string. 683 return JunkStringValue(); 684 } 685 686 // Parse exponential part. 687 if (*current == 'e' || *current == 'E') { 688 if (octal) return JunkStringValue(); 689 ++current; 690 if (current == end) { 691 if (allow_trailing_junk) { 692 goto parsing_done; 693 } else { 694 return JunkStringValue(); 695 } 696 } 697 char sign = '+'; 698 if (*current == '+' || *current == '-') { 699 sign = static_cast<char>(*current); 700 ++current; 701 if (current == end) { 702 if (allow_trailing_junk) { 703 goto parsing_done; 704 } else { 705 return JunkStringValue(); 706 } 707 } 708 } 709 710 if (current == end || *current < '0' || *current > '9') { 711 if (allow_trailing_junk) { 712 goto parsing_done; 713 } else { 714 return JunkStringValue(); 715 } 716 } 717 718 const int max_exponent = INT_MAX / 2; 719 DCHECK(-max_exponent / 2 <= exponent && exponent <= max_exponent / 2); 720 int num = 0; 721 do { 722 // Check overflow. 723 int digit = *current - '0'; 724 if (num >= max_exponent / 10 725 && !(num == max_exponent / 10 && digit <= max_exponent % 10)) { 726 num = max_exponent; 727 } else { 728 num = num * 10 + digit; 729 } 730 ++current; 731 } while (current != end && *current >= '0' && *current <= '9'); 732 733 exponent += (sign == '-' ? -num : num); 734 } 735 736 if (!allow_trailing_junk && 737 AdvanceToNonspace(unicode_cache, ¤t, end)) { 738 return JunkStringValue(); 739 } 740 741 parsing_done: 742 exponent += insignificant_digits; 743 744 if (octal) { 745 return InternalStringToIntDouble<3>(unicode_cache, 746 buffer, 747 buffer + buffer_pos, 748 sign == NEGATIVE, 749 allow_trailing_junk); 750 } 751 752 if (nonzero_digit_dropped) { 753 buffer[buffer_pos++] = '1'; 754 exponent--; 755 } 756 757 SLOW_DCHECK(buffer_pos < kBufferSize); 758 buffer[buffer_pos] = '\0'; 759 760 double converted = Strtod(Vector<const char>(buffer, buffer_pos), exponent); 761 return (sign == NEGATIVE) ? -converted : converted; 762 } 763 764 } // namespace internal 765 } // namespace v8 766 767 #endif // V8_CONVERSIONS_INL_H_ 768