1 // Copyright 2012 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_UTILS_H_ 6 #define V8_UTILS_H_ 7 8 #include <limits.h> 9 #include <stdlib.h> 10 #include <string.h> 11 #include <cmath> 12 13 #include "include/v8.h" 14 #include "src/allocation.h" 15 #include "src/base/bits.h" 16 #include "src/base/compiler-specific.h" 17 #include "src/base/logging.h" 18 #include "src/base/macros.h" 19 #include "src/base/platform/platform.h" 20 #include "src/globals.h" 21 #include "src/list.h" 22 #include "src/vector.h" 23 #include "src/zone/zone.h" 24 25 namespace v8 { 26 namespace internal { 27 28 // ---------------------------------------------------------------------------- 29 // General helper functions 30 31 // Returns the value (0 .. 15) of a hexadecimal character c. 32 // If c is not a legal hexadecimal character, returns a value < 0. 33 inline int HexValue(uc32 c) { 34 c -= '0'; 35 if (static_cast<unsigned>(c) <= 9) return c; 36 c = (c | 0x20) - ('a' - '0'); // detect 0x11..0x16 and 0x31..0x36. 37 if (static_cast<unsigned>(c) <= 5) return c + 10; 38 return -1; 39 } 40 41 inline char HexCharOfValue(int value) { 42 DCHECK(0 <= value && value <= 16); 43 if (value < 10) return value + '0'; 44 return value - 10 + 'A'; 45 } 46 47 inline int BoolToInt(bool b) { return b ? 1 : 0; } 48 49 50 // Same as strcmp, but can handle NULL arguments. 51 inline bool CStringEquals(const char* s1, const char* s2) { 52 return (s1 == s2) || (s1 != NULL && s2 != NULL && strcmp(s1, s2) == 0); 53 } 54 55 56 // X must be a power of 2. Returns the number of trailing zeros. 57 inline int WhichPowerOf2(uint32_t x) { 58 DCHECK(base::bits::IsPowerOfTwo32(x)); 59 int bits = 0; 60 #ifdef DEBUG 61 uint32_t original_x = x; 62 #endif 63 if (x >= 0x10000) { 64 bits += 16; 65 x >>= 16; 66 } 67 if (x >= 0x100) { 68 bits += 8; 69 x >>= 8; 70 } 71 if (x >= 0x10) { 72 bits += 4; 73 x >>= 4; 74 } 75 switch (x) { 76 default: UNREACHABLE(); 77 case 8: bits++; // Fall through. 78 case 4: bits++; // Fall through. 79 case 2: bits++; // Fall through. 80 case 1: break; 81 } 82 DCHECK_EQ(static_cast<uint32_t>(1) << bits, original_x); 83 return bits; 84 } 85 86 87 // X must be a power of 2. Returns the number of trailing zeros. 88 inline int WhichPowerOf2_64(uint64_t x) { 89 DCHECK(base::bits::IsPowerOfTwo64(x)); 90 int bits = 0; 91 #ifdef DEBUG 92 uint64_t original_x = x; 93 #endif 94 if (x >= 0x100000000L) { 95 bits += 32; 96 x >>= 32; 97 } 98 if (x >= 0x10000) { 99 bits += 16; 100 x >>= 16; 101 } 102 if (x >= 0x100) { 103 bits += 8; 104 x >>= 8; 105 } 106 if (x >= 0x10) { 107 bits += 4; 108 x >>= 4; 109 } 110 switch (x) { 111 default: UNREACHABLE(); 112 case 8: bits++; // Fall through. 113 case 4: bits++; // Fall through. 114 case 2: bits++; // Fall through. 115 case 1: break; 116 } 117 DCHECK_EQ(static_cast<uint64_t>(1) << bits, original_x); 118 return bits; 119 } 120 121 122 inline int MostSignificantBit(uint32_t x) { 123 static const int msb4[] = {0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4}; 124 int nibble = 0; 125 if (x & 0xffff0000) { 126 nibble += 16; 127 x >>= 16; 128 } 129 if (x & 0xff00) { 130 nibble += 8; 131 x >>= 8; 132 } 133 if (x & 0xf0) { 134 nibble += 4; 135 x >>= 4; 136 } 137 return nibble + msb4[x]; 138 } 139 140 template <typename T> 141 static T ArithmeticShiftRight(T x, int shift) { 142 DCHECK_LE(0, shift); 143 if (x < 0) { 144 // Right shift of signed values is implementation defined. Simulate a 145 // true arithmetic right shift by adding leading sign bits. 146 using UnsignedT = typename std::make_unsigned<T>::type; 147 UnsignedT mask = ~(static_cast<UnsignedT>(~0) >> shift); 148 return (static_cast<UnsignedT>(x) >> shift) | mask; 149 } else { 150 return x >> shift; 151 } 152 } 153 154 template <typename T> 155 int Compare(const T& a, const T& b) { 156 if (a == b) 157 return 0; 158 else if (a < b) 159 return -1; 160 else 161 return 1; 162 } 163 164 165 template <typename T> 166 int PointerValueCompare(const T* a, const T* b) { 167 return Compare<T>(*a, *b); 168 } 169 170 171 // Compare function to compare the object pointer value of two 172 // handlified objects. The handles are passed as pointers to the 173 // handles. 174 template<typename T> class Handle; // Forward declaration. 175 template <typename T> 176 int HandleObjectPointerCompare(const Handle<T>* a, const Handle<T>* b) { 177 return Compare<T*>(*(*a), *(*b)); 178 } 179 180 181 template <typename T, typename U> 182 inline bool IsAligned(T value, U alignment) { 183 return (value & (alignment - 1)) == 0; 184 } 185 186 187 // Returns true if (addr + offset) is aligned. 188 inline bool IsAddressAligned(Address addr, 189 intptr_t alignment, 190 int offset = 0) { 191 intptr_t offs = OffsetFrom(addr + offset); 192 return IsAligned(offs, alignment); 193 } 194 195 template <typename T, typename U> 196 inline T RoundUpToMultipleOfPowOf2(T value, U multiple) { 197 DCHECK(multiple && ((multiple & (multiple - 1)) == 0)); 198 return (value + multiple - 1) & ~(multiple - 1); 199 } 200 201 // Returns the maximum of the two parameters. 202 template <typename T> 203 T Max(T a, T b) { 204 return a < b ? b : a; 205 } 206 207 208 // Returns the minimum of the two parameters. 209 template <typename T> 210 T Min(T a, T b) { 211 return a < b ? a : b; 212 } 213 214 // Returns the maximum of the two parameters according to JavaScript semantics. 215 template <typename T> 216 T JSMax(T x, T y) { 217 if (std::isnan(x)) return x; 218 if (std::isnan(y)) return y; 219 if (std::signbit(x) < std::signbit(y)) return x; 220 return x > y ? x : y; 221 } 222 223 // Returns the maximum of the two parameters according to JavaScript semantics. 224 template <typename T> 225 T JSMin(T x, T y) { 226 if (std::isnan(x)) return x; 227 if (std::isnan(y)) return y; 228 if (std::signbit(x) < std::signbit(y)) return y; 229 return x > y ? y : x; 230 } 231 232 // Returns the absolute value of its argument. 233 template <typename T> 234 T Abs(T a) { 235 return a < 0 ? -a : a; 236 } 237 238 239 // Floor(-0.0) == 0.0 240 inline double Floor(double x) { 241 #if V8_CC_MSVC 242 if (x == 0) return x; // Fix for issue 3477. 243 #endif 244 return std::floor(x); 245 } 246 247 inline double Pow(double x, double y) { 248 if (y == 0.0) return 1.0; 249 if (std::isnan(y) || ((x == 1 || x == -1) && std::isinf(y))) { 250 return std::numeric_limits<double>::quiet_NaN(); 251 } 252 #if (defined(__MINGW64_VERSION_MAJOR) && \ 253 (!defined(__MINGW64_VERSION_RC) || __MINGW64_VERSION_RC < 1)) || \ 254 defined(V8_OS_AIX) 255 // MinGW64 and AIX have a custom implementation for pow. This handles certain 256 // special cases that are different. 257 if ((x == 0.0 || std::isinf(x)) && y != 0.0 && std::isfinite(y)) { 258 double f; 259 double result = ((x == 0.0) ^ (y > 0)) ? V8_INFINITY : 0; 260 /* retain sign if odd integer exponent */ 261 return ((std::modf(y, &f) == 0.0) && (static_cast<int64_t>(y) & 1)) 262 ? copysign(result, x) 263 : result; 264 } 265 266 if (x == 2.0) { 267 int y_int = static_cast<int>(y); 268 if (y == y_int) { 269 return std::ldexp(1.0, y_int); 270 } 271 } 272 #endif 273 return std::pow(x, y); 274 } 275 276 // TODO(svenpanne) Clean up the whole power-of-2 mess. 277 inline int32_t WhichPowerOf2Abs(int32_t x) { 278 return (x == kMinInt) ? 31 : WhichPowerOf2(Abs(x)); 279 } 280 281 282 // Obtains the unsigned type corresponding to T 283 // available in C++11 as std::make_unsigned 284 template<typename T> 285 struct make_unsigned { 286 typedef T type; 287 }; 288 289 290 // Template specializations necessary to have make_unsigned work 291 template<> struct make_unsigned<int32_t> { 292 typedef uint32_t type; 293 }; 294 295 296 template<> struct make_unsigned<int64_t> { 297 typedef uint64_t type; 298 }; 299 300 301 // ---------------------------------------------------------------------------- 302 // BitField is a help template for encoding and decode bitfield with 303 // unsigned content. 304 305 template<class T, int shift, int size, class U> 306 class BitFieldBase { 307 public: 308 // A type U mask of bit field. To use all bits of a type U of x bits 309 // in a bitfield without compiler warnings we have to compute 2^x 310 // without using a shift count of x in the computation. 311 static const U kOne = static_cast<U>(1U); 312 static const U kMask = ((kOne << shift) << size) - (kOne << shift); 313 static const U kShift = shift; 314 static const U kSize = size; 315 static const U kNext = kShift + kSize; 316 317 // Value for the field with all bits set. 318 static const T kMax = static_cast<T>((kOne << size) - 1); 319 320 // Tells whether the provided value fits into the bit field. 321 static bool is_valid(T value) { 322 return (static_cast<U>(value) & ~static_cast<U>(kMax)) == 0; 323 } 324 325 // Returns a type U with the bit field value encoded. 326 static U encode(T value) { 327 DCHECK(is_valid(value)); 328 return static_cast<U>(value) << shift; 329 } 330 331 // Returns a type U with the bit field value updated. 332 static U update(U previous, T value) { 333 return (previous & ~kMask) | encode(value); 334 } 335 336 // Extracts the bit field from the value. 337 static T decode(U value) { 338 return static_cast<T>((value & kMask) >> shift); 339 } 340 341 STATIC_ASSERT((kNext - 1) / 8 < sizeof(U)); 342 }; 343 344 template <class T, int shift, int size> 345 class BitField8 : public BitFieldBase<T, shift, size, uint8_t> {}; 346 347 348 template <class T, int shift, int size> 349 class BitField16 : public BitFieldBase<T, shift, size, uint16_t> {}; 350 351 352 template<class T, int shift, int size> 353 class BitField : public BitFieldBase<T, shift, size, uint32_t> { }; 354 355 356 template<class T, int shift, int size> 357 class BitField64 : public BitFieldBase<T, shift, size, uint64_t> { }; 358 359 360 // ---------------------------------------------------------------------------- 361 // BitSetComputer is a help template for encoding and decoding information for 362 // a variable number of items in an array. 363 // 364 // To encode boolean data in a smi array you would use: 365 // typedef BitSetComputer<bool, 1, kSmiValueSize, uint32_t> BoolComputer; 366 // 367 template <class T, int kBitsPerItem, int kBitsPerWord, class U> 368 class BitSetComputer { 369 public: 370 static const int kItemsPerWord = kBitsPerWord / kBitsPerItem; 371 static const int kMask = (1 << kBitsPerItem) - 1; 372 373 // The number of array elements required to embed T information for each item. 374 static int word_count(int items) { 375 if (items == 0) return 0; 376 return (items - 1) / kItemsPerWord + 1; 377 } 378 379 // The array index to look at for item. 380 static int index(int base_index, int item) { 381 return base_index + item / kItemsPerWord; 382 } 383 384 // Extract T data for a given item from data. 385 static T decode(U data, int item) { 386 return static_cast<T>((data >> shift(item)) & kMask); 387 } 388 389 // Return the encoding for a store of value for item in previous. 390 static U encode(U previous, int item, T value) { 391 int shift_value = shift(item); 392 int set_bits = (static_cast<int>(value) << shift_value); 393 return (previous & ~(kMask << shift_value)) | set_bits; 394 } 395 396 static int shift(int item) { return (item % kItemsPerWord) * kBitsPerItem; } 397 }; 398 399 400 // ---------------------------------------------------------------------------- 401 // Hash function. 402 403 static const uint32_t kZeroHashSeed = 0; 404 405 // Thomas Wang, Integer Hash Functions. 406 // http://www.concentric.net/~Ttwang/tech/inthash.htm 407 inline uint32_t ComputeIntegerHash(uint32_t key, uint32_t seed) { 408 uint32_t hash = key; 409 hash = hash ^ seed; 410 hash = ~hash + (hash << 15); // hash = (hash << 15) - hash - 1; 411 hash = hash ^ (hash >> 12); 412 hash = hash + (hash << 2); 413 hash = hash ^ (hash >> 4); 414 hash = hash * 2057; // hash = (hash + (hash << 3)) + (hash << 11); 415 hash = hash ^ (hash >> 16); 416 return hash & 0x3fffffff; 417 } 418 419 420 inline uint32_t ComputeLongHash(uint64_t key) { 421 uint64_t hash = key; 422 hash = ~hash + (hash << 18); // hash = (hash << 18) - hash - 1; 423 hash = hash ^ (hash >> 31); 424 hash = hash * 21; // hash = (hash + (hash << 2)) + (hash << 4); 425 hash = hash ^ (hash >> 11); 426 hash = hash + (hash << 6); 427 hash = hash ^ (hash >> 22); 428 return static_cast<uint32_t>(hash); 429 } 430 431 432 inline uint32_t ComputePointerHash(void* ptr) { 433 return ComputeIntegerHash( 434 static_cast<uint32_t>(reinterpret_cast<intptr_t>(ptr)), 435 v8::internal::kZeroHashSeed); 436 } 437 438 439 // ---------------------------------------------------------------------------- 440 // Generated memcpy/memmove 441 442 // Initializes the codegen support that depends on CPU features. 443 void init_memcopy_functions(Isolate* isolate); 444 445 #if defined(V8_TARGET_ARCH_IA32) || defined(V8_TARGET_ARCH_X87) 446 // Limit below which the extra overhead of the MemCopy function is likely 447 // to outweigh the benefits of faster copying. 448 const int kMinComplexMemCopy = 64; 449 450 // Copy memory area. No restrictions. 451 V8_EXPORT_PRIVATE void MemMove(void* dest, const void* src, size_t size); 452 typedef void (*MemMoveFunction)(void* dest, const void* src, size_t size); 453 454 // Keep the distinction of "move" vs. "copy" for the benefit of other 455 // architectures. 456 V8_INLINE void MemCopy(void* dest, const void* src, size_t size) { 457 MemMove(dest, src, size); 458 } 459 #elif defined(V8_HOST_ARCH_ARM) 460 typedef void (*MemCopyUint8Function)(uint8_t* dest, const uint8_t* src, 461 size_t size); 462 V8_EXPORT_PRIVATE extern MemCopyUint8Function memcopy_uint8_function; 463 V8_INLINE void MemCopyUint8Wrapper(uint8_t* dest, const uint8_t* src, 464 size_t chars) { 465 memcpy(dest, src, chars); 466 } 467 // For values < 16, the assembler function is slower than the inlined C code. 468 const int kMinComplexMemCopy = 16; 469 V8_INLINE void MemCopy(void* dest, const void* src, size_t size) { 470 (*memcopy_uint8_function)(reinterpret_cast<uint8_t*>(dest), 471 reinterpret_cast<const uint8_t*>(src), size); 472 } 473 V8_EXPORT_PRIVATE V8_INLINE void MemMove(void* dest, const void* src, 474 size_t size) { 475 memmove(dest, src, size); 476 } 477 478 typedef void (*MemCopyUint16Uint8Function)(uint16_t* dest, const uint8_t* src, 479 size_t size); 480 extern MemCopyUint16Uint8Function memcopy_uint16_uint8_function; 481 void MemCopyUint16Uint8Wrapper(uint16_t* dest, const uint8_t* src, 482 size_t chars); 483 // For values < 12, the assembler function is slower than the inlined C code. 484 const int kMinComplexConvertMemCopy = 12; 485 V8_INLINE void MemCopyUint16Uint8(uint16_t* dest, const uint8_t* src, 486 size_t size) { 487 (*memcopy_uint16_uint8_function)(dest, src, size); 488 } 489 #elif defined(V8_HOST_ARCH_MIPS) 490 typedef void (*MemCopyUint8Function)(uint8_t* dest, const uint8_t* src, 491 size_t size); 492 V8_EXPORT_PRIVATE extern MemCopyUint8Function memcopy_uint8_function; 493 V8_INLINE void MemCopyUint8Wrapper(uint8_t* dest, const uint8_t* src, 494 size_t chars) { 495 memcpy(dest, src, chars); 496 } 497 // For values < 16, the assembler function is slower than the inlined C code. 498 const int kMinComplexMemCopy = 16; 499 V8_INLINE void MemCopy(void* dest, const void* src, size_t size) { 500 (*memcopy_uint8_function)(reinterpret_cast<uint8_t*>(dest), 501 reinterpret_cast<const uint8_t*>(src), size); 502 } 503 V8_EXPORT_PRIVATE V8_INLINE void MemMove(void* dest, const void* src, 504 size_t size) { 505 memmove(dest, src, size); 506 } 507 #else 508 // Copy memory area to disjoint memory area. 509 V8_INLINE void MemCopy(void* dest, const void* src, size_t size) { 510 memcpy(dest, src, size); 511 } 512 V8_EXPORT_PRIVATE V8_INLINE void MemMove(void* dest, const void* src, 513 size_t size) { 514 memmove(dest, src, size); 515 } 516 const int kMinComplexMemCopy = 8; 517 #endif // V8_TARGET_ARCH_IA32 518 519 520 // ---------------------------------------------------------------------------- 521 // Miscellaneous 522 523 // Memory offset for lower and higher bits in a 64 bit integer. 524 #if defined(V8_TARGET_LITTLE_ENDIAN) 525 static const int kInt64LowerHalfMemoryOffset = 0; 526 static const int kInt64UpperHalfMemoryOffset = 4; 527 #elif defined(V8_TARGET_BIG_ENDIAN) 528 static const int kInt64LowerHalfMemoryOffset = 4; 529 static const int kInt64UpperHalfMemoryOffset = 0; 530 #endif // V8_TARGET_LITTLE_ENDIAN 531 532 // A static resource holds a static instance that can be reserved in 533 // a local scope using an instance of Access. Attempts to re-reserve 534 // the instance will cause an error. 535 template <typename T> 536 class StaticResource { 537 public: 538 StaticResource() : is_reserved_(false) {} 539 540 private: 541 template <typename S> friend class Access; 542 T instance_; 543 bool is_reserved_; 544 }; 545 546 547 // Locally scoped access to a static resource. 548 template <typename T> 549 class Access { 550 public: 551 explicit Access(StaticResource<T>* resource) 552 : resource_(resource) 553 , instance_(&resource->instance_) { 554 DCHECK(!resource->is_reserved_); 555 resource->is_reserved_ = true; 556 } 557 558 ~Access() { 559 resource_->is_reserved_ = false; 560 resource_ = NULL; 561 instance_ = NULL; 562 } 563 564 T* value() { return instance_; } 565 T* operator -> () { return instance_; } 566 567 private: 568 StaticResource<T>* resource_; 569 T* instance_; 570 }; 571 572 573 // A pointer that can only be set once and doesn't allow NULL values. 574 template<typename T> 575 class SetOncePointer { 576 public: 577 SetOncePointer() : pointer_(NULL) { } 578 579 bool is_set() const { return pointer_ != NULL; } 580 581 T* get() const { 582 DCHECK(pointer_ != NULL); 583 return pointer_; 584 } 585 586 void set(T* value) { 587 DCHECK(pointer_ == NULL && value != NULL); 588 pointer_ = value; 589 } 590 591 private: 592 T* pointer_; 593 }; 594 595 596 template <typename T, int kSize> 597 class EmbeddedVector : public Vector<T> { 598 public: 599 EmbeddedVector() : Vector<T>(buffer_, kSize) { } 600 601 explicit EmbeddedVector(T initial_value) : Vector<T>(buffer_, kSize) { 602 for (int i = 0; i < kSize; ++i) { 603 buffer_[i] = initial_value; 604 } 605 } 606 607 // When copying, make underlying Vector to reference our buffer. 608 EmbeddedVector(const EmbeddedVector& rhs) 609 : Vector<T>(rhs) { 610 MemCopy(buffer_, rhs.buffer_, sizeof(T) * kSize); 611 this->set_start(buffer_); 612 } 613 614 EmbeddedVector& operator=(const EmbeddedVector& rhs) { 615 if (this == &rhs) return *this; 616 Vector<T>::operator=(rhs); 617 MemCopy(buffer_, rhs.buffer_, sizeof(T) * kSize); 618 this->set_start(buffer_); 619 return *this; 620 } 621 622 private: 623 T buffer_[kSize]; 624 }; 625 626 // Compare 8bit/16bit chars to 8bit/16bit chars. 627 template <typename lchar, typename rchar> 628 inline int CompareCharsUnsigned(const lchar* lhs, const rchar* rhs, 629 size_t chars) { 630 const lchar* limit = lhs + chars; 631 if (sizeof(*lhs) == sizeof(char) && sizeof(*rhs) == sizeof(char)) { 632 // memcmp compares byte-by-byte, yielding wrong results for two-byte 633 // strings on little-endian systems. 634 return memcmp(lhs, rhs, chars); 635 } 636 while (lhs < limit) { 637 int r = static_cast<int>(*lhs) - static_cast<int>(*rhs); 638 if (r != 0) return r; 639 ++lhs; 640 ++rhs; 641 } 642 return 0; 643 } 644 645 template <typename lchar, typename rchar> 646 inline int CompareChars(const lchar* lhs, const rchar* rhs, size_t chars) { 647 DCHECK(sizeof(lchar) <= 2); 648 DCHECK(sizeof(rchar) <= 2); 649 if (sizeof(lchar) == 1) { 650 if (sizeof(rchar) == 1) { 651 return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(lhs), 652 reinterpret_cast<const uint8_t*>(rhs), 653 chars); 654 } else { 655 return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(lhs), 656 reinterpret_cast<const uint16_t*>(rhs), 657 chars); 658 } 659 } else { 660 if (sizeof(rchar) == 1) { 661 return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(lhs), 662 reinterpret_cast<const uint8_t*>(rhs), 663 chars); 664 } else { 665 return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(lhs), 666 reinterpret_cast<const uint16_t*>(rhs), 667 chars); 668 } 669 } 670 } 671 672 673 // Calculate 10^exponent. 674 inline int TenToThe(int exponent) { 675 DCHECK(exponent <= 9); 676 DCHECK(exponent >= 1); 677 int answer = 10; 678 for (int i = 1; i < exponent; i++) answer *= 10; 679 return answer; 680 } 681 682 683 template<typename ElementType, int NumElements> 684 class EmbeddedContainer { 685 public: 686 EmbeddedContainer() : elems_() { } 687 688 int length() const { return NumElements; } 689 const ElementType& operator[](int i) const { 690 DCHECK(i < length()); 691 return elems_[i]; 692 } 693 ElementType& operator[](int i) { 694 DCHECK(i < length()); 695 return elems_[i]; 696 } 697 698 private: 699 ElementType elems_[NumElements]; 700 }; 701 702 703 template<typename ElementType> 704 class EmbeddedContainer<ElementType, 0> { 705 public: 706 int length() const { return 0; } 707 const ElementType& operator[](int i) const { 708 UNREACHABLE(); 709 static ElementType t = 0; 710 return t; 711 } 712 ElementType& operator[](int i) { 713 UNREACHABLE(); 714 static ElementType t = 0; 715 return t; 716 } 717 }; 718 719 720 // Helper class for building result strings in a character buffer. The 721 // purpose of the class is to use safe operations that checks the 722 // buffer bounds on all operations in debug mode. 723 // This simple base class does not allow formatted output. 724 class SimpleStringBuilder { 725 public: 726 // Create a string builder with a buffer of the given size. The 727 // buffer is allocated through NewArray<char> and must be 728 // deallocated by the caller of Finalize(). 729 explicit SimpleStringBuilder(int size); 730 731 SimpleStringBuilder(char* buffer, int size) 732 : buffer_(buffer, size), position_(0) { } 733 734 ~SimpleStringBuilder() { if (!is_finalized()) Finalize(); } 735 736 int size() const { return buffer_.length(); } 737 738 // Get the current position in the builder. 739 int position() const { 740 DCHECK(!is_finalized()); 741 return position_; 742 } 743 744 // Reset the position. 745 void Reset() { position_ = 0; } 746 747 // Add a single character to the builder. It is not allowed to add 748 // 0-characters; use the Finalize() method to terminate the string 749 // instead. 750 void AddCharacter(char c) { 751 DCHECK(c != '\0'); 752 DCHECK(!is_finalized() && position_ < buffer_.length()); 753 buffer_[position_++] = c; 754 } 755 756 // Add an entire string to the builder. Uses strlen() internally to 757 // compute the length of the input string. 758 void AddString(const char* s); 759 760 // Add the first 'n' characters of the given 0-terminated string 's' to the 761 // builder. The input string must have enough characters. 762 void AddSubstring(const char* s, int n); 763 764 // Add character padding to the builder. If count is non-positive, 765 // nothing is added to the builder. 766 void AddPadding(char c, int count); 767 768 // Add the decimal representation of the value. 769 void AddDecimalInteger(int value); 770 771 // Finalize the string by 0-terminating it and returning the buffer. 772 char* Finalize(); 773 774 protected: 775 Vector<char> buffer_; 776 int position_; 777 778 bool is_finalized() const { return position_ < 0; } 779 780 private: 781 DISALLOW_IMPLICIT_CONSTRUCTORS(SimpleStringBuilder); 782 }; 783 784 785 // A poor man's version of STL's bitset: A bit set of enums E (without explicit 786 // values), fitting into an integral type T. 787 template <class E, class T = int> 788 class EnumSet { 789 public: 790 explicit EnumSet(T bits = 0) : bits_(bits) {} 791 bool IsEmpty() const { return bits_ == 0; } 792 bool Contains(E element) const { return (bits_ & Mask(element)) != 0; } 793 bool ContainsAnyOf(const EnumSet& set) const { 794 return (bits_ & set.bits_) != 0; 795 } 796 void Add(E element) { bits_ |= Mask(element); } 797 void Add(const EnumSet& set) { bits_ |= set.bits_; } 798 void Remove(E element) { bits_ &= ~Mask(element); } 799 void Remove(const EnumSet& set) { bits_ &= ~set.bits_; } 800 void RemoveAll() { bits_ = 0; } 801 void Intersect(const EnumSet& set) { bits_ &= set.bits_; } 802 T ToIntegral() const { return bits_; } 803 bool operator==(const EnumSet& set) { return bits_ == set.bits_; } 804 bool operator!=(const EnumSet& set) { return bits_ != set.bits_; } 805 EnumSet<E, T> operator|(const EnumSet& set) const { 806 return EnumSet<E, T>(bits_ | set.bits_); 807 } 808 809 private: 810 T Mask(E element) const { 811 // The strange typing in DCHECK is necessary to avoid stupid warnings, see: 812 // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43680 813 DCHECK(static_cast<int>(element) < static_cast<int>(sizeof(T) * CHAR_BIT)); 814 return static_cast<T>(1) << element; 815 } 816 817 T bits_; 818 }; 819 820 // Bit field extraction. 821 inline uint32_t unsigned_bitextract_32(int msb, int lsb, uint32_t x) { 822 return (x >> lsb) & ((1 << (1 + msb - lsb)) - 1); 823 } 824 825 inline uint64_t unsigned_bitextract_64(int msb, int lsb, uint64_t x) { 826 return (x >> lsb) & ((static_cast<uint64_t>(1) << (1 + msb - lsb)) - 1); 827 } 828 829 inline int32_t signed_bitextract_32(int msb, int lsb, int32_t x) { 830 return (x << (31 - msb)) >> (lsb + 31 - msb); 831 } 832 833 inline int signed_bitextract_64(int msb, int lsb, int x) { 834 // TODO(jbramley): This is broken for big bitfields. 835 return (x << (63 - msb)) >> (lsb + 63 - msb); 836 } 837 838 // Check number width. 839 inline bool is_intn(int64_t x, unsigned n) { 840 DCHECK((0 < n) && (n < 64)); 841 int64_t limit = static_cast<int64_t>(1) << (n - 1); 842 return (-limit <= x) && (x < limit); 843 } 844 845 inline bool is_uintn(int64_t x, unsigned n) { 846 DCHECK((0 < n) && (n < (sizeof(x) * kBitsPerByte))); 847 return !(x >> n); 848 } 849 850 template <class T> 851 inline T truncate_to_intn(T x, unsigned n) { 852 DCHECK((0 < n) && (n < (sizeof(x) * kBitsPerByte))); 853 return (x & ((static_cast<T>(1) << n) - 1)); 854 } 855 856 #define INT_1_TO_63_LIST(V) \ 857 V(1) V(2) V(3) V(4) V(5) V(6) V(7) V(8) \ 858 V(9) V(10) V(11) V(12) V(13) V(14) V(15) V(16) \ 859 V(17) V(18) V(19) V(20) V(21) V(22) V(23) V(24) \ 860 V(25) V(26) V(27) V(28) V(29) V(30) V(31) V(32) \ 861 V(33) V(34) V(35) V(36) V(37) V(38) V(39) V(40) \ 862 V(41) V(42) V(43) V(44) V(45) V(46) V(47) V(48) \ 863 V(49) V(50) V(51) V(52) V(53) V(54) V(55) V(56) \ 864 V(57) V(58) V(59) V(60) V(61) V(62) V(63) 865 866 #define DECLARE_IS_INT_N(N) \ 867 inline bool is_int##N(int64_t x) { return is_intn(x, N); } 868 #define DECLARE_IS_UINT_N(N) \ 869 template <class T> \ 870 inline bool is_uint##N(T x) { return is_uintn(x, N); } 871 #define DECLARE_TRUNCATE_TO_INT_N(N) \ 872 template <class T> \ 873 inline T truncate_to_int##N(T x) { return truncate_to_intn(x, N); } 874 INT_1_TO_63_LIST(DECLARE_IS_INT_N) 875 INT_1_TO_63_LIST(DECLARE_IS_UINT_N) 876 INT_1_TO_63_LIST(DECLARE_TRUNCATE_TO_INT_N) 877 #undef DECLARE_IS_INT_N 878 #undef DECLARE_IS_UINT_N 879 #undef DECLARE_TRUNCATE_TO_INT_N 880 881 class TypeFeedbackId { 882 public: 883 explicit TypeFeedbackId(int id) : id_(id) { } 884 int ToInt() const { return id_; } 885 886 static TypeFeedbackId None() { return TypeFeedbackId(kNoneId); } 887 bool IsNone() const { return id_ == kNoneId; } 888 889 private: 890 static const int kNoneId = -1; 891 892 int id_; 893 }; 894 895 inline bool operator<(TypeFeedbackId lhs, TypeFeedbackId rhs) { 896 return lhs.ToInt() < rhs.ToInt(); 897 } 898 inline bool operator>(TypeFeedbackId lhs, TypeFeedbackId rhs) { 899 return lhs.ToInt() > rhs.ToInt(); 900 } 901 902 class FeedbackSlot { 903 public: 904 FeedbackSlot() : id_(kInvalidSlot) {} 905 explicit FeedbackSlot(int id) : id_(id) {} 906 907 int ToInt() const { return id_; } 908 909 static FeedbackSlot Invalid() { return FeedbackSlot(); } 910 bool IsInvalid() const { return id_ == kInvalidSlot; } 911 912 bool operator==(FeedbackSlot that) const { return this->id_ == that.id_; } 913 bool operator!=(FeedbackSlot that) const { return !(*this == that); } 914 915 friend size_t hash_value(FeedbackSlot slot) { return slot.ToInt(); } 916 friend std::ostream& operator<<(std::ostream& os, FeedbackSlot); 917 918 private: 919 static const int kInvalidSlot = -1; 920 921 int id_; 922 }; 923 924 925 class BailoutId { 926 public: 927 explicit BailoutId(int id) : id_(id) { } 928 int ToInt() const { return id_; } 929 930 static BailoutId None() { return BailoutId(kNoneId); } 931 static BailoutId ScriptContext() { return BailoutId(kScriptContextId); } 932 static BailoutId FunctionContext() { return BailoutId(kFunctionContextId); } 933 static BailoutId FunctionEntry() { return BailoutId(kFunctionEntryId); } 934 static BailoutId Declarations() { return BailoutId(kDeclarationsId); } 935 static BailoutId FirstUsable() { return BailoutId(kFirstUsableId); } 936 static BailoutId StubEntry() { return BailoutId(kStubEntryId); } 937 938 // Special bailout id support for deopting into the {JSConstructStub} stub. 939 // The following hard-coded deoptimization points are supported by the stub: 940 // - {ConstructStubCreate} maps to {construct_stub_create_deopt_pc_offset}. 941 // - {ConstructStubInvoke} maps to {construct_stub_invoke_deopt_pc_offset}. 942 static BailoutId ConstructStubCreate() { return BailoutId(1); } 943 static BailoutId ConstructStubInvoke() { return BailoutId(2); } 944 bool IsValidForConstructStub() const { 945 return id_ == ConstructStubCreate().ToInt() || 946 id_ == ConstructStubInvoke().ToInt(); 947 } 948 949 bool IsNone() const { return id_ == kNoneId; } 950 bool operator==(const BailoutId& other) const { return id_ == other.id_; } 951 bool operator!=(const BailoutId& other) const { return id_ != other.id_; } 952 friend size_t hash_value(BailoutId); 953 V8_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream&, BailoutId); 954 955 private: 956 static const int kNoneId = -1; 957 958 // Using 0 could disguise errors. 959 static const int kScriptContextId = 1; 960 static const int kFunctionContextId = 2; 961 static const int kFunctionEntryId = 3; 962 963 // This AST id identifies the point after the declarations have been visited. 964 // We need it to capture the environment effects of declarations that emit 965 // code (function declarations). 966 static const int kDeclarationsId = 4; 967 968 // Every FunctionState starts with this id. 969 static const int kFirstUsableId = 5; 970 971 // Every compiled stub starts with this id. 972 static const int kStubEntryId = 6; 973 974 int id_; 975 }; 976 977 978 // ---------------------------------------------------------------------------- 979 // I/O support. 980 981 // Our version of printf(). 982 V8_EXPORT_PRIVATE void PRINTF_FORMAT(1, 2) PrintF(const char* format, ...); 983 void PRINTF_FORMAT(2, 3) PrintF(FILE* out, const char* format, ...); 984 985 // Prepends the current process ID to the output. 986 void PRINTF_FORMAT(1, 2) PrintPID(const char* format, ...); 987 988 // Prepends the current process ID and given isolate pointer to the output. 989 void PRINTF_FORMAT(2, 3) PrintIsolate(void* isolate, const char* format, ...); 990 991 // Safe formatting print. Ensures that str is always null-terminated. 992 // Returns the number of chars written, or -1 if output was truncated. 993 int PRINTF_FORMAT(2, 3) SNPrintF(Vector<char> str, const char* format, ...); 994 int PRINTF_FORMAT(2, 0) 995 VSNPrintF(Vector<char> str, const char* format, va_list args); 996 997 void StrNCpy(Vector<char> dest, const char* src, size_t n); 998 999 // Our version of fflush. 1000 void Flush(FILE* out); 1001 1002 inline void Flush() { 1003 Flush(stdout); 1004 } 1005 1006 1007 // Read a line of characters after printing the prompt to stdout. The resulting 1008 // char* needs to be disposed off with DeleteArray by the caller. 1009 char* ReadLine(const char* prompt); 1010 1011 1012 // Read and return the raw bytes in a file. the size of the buffer is returned 1013 // in size. 1014 // The returned buffer must be freed by the caller. 1015 byte* ReadBytes(const char* filename, int* size, bool verbose = true); 1016 1017 1018 // Append size chars from str to the file given by filename. 1019 // The file is overwritten. Returns the number of chars written. 1020 int AppendChars(const char* filename, 1021 const char* str, 1022 int size, 1023 bool verbose = true); 1024 1025 1026 // Write size chars from str to the file given by filename. 1027 // The file is overwritten. Returns the number of chars written. 1028 int WriteChars(const char* filename, 1029 const char* str, 1030 int size, 1031 bool verbose = true); 1032 1033 1034 // Write size bytes to the file given by filename. 1035 // The file is overwritten. Returns the number of bytes written. 1036 int WriteBytes(const char* filename, 1037 const byte* bytes, 1038 int size, 1039 bool verbose = true); 1040 1041 1042 // Write the C code 1043 // const char* <varname> = "<str>"; 1044 // const int <varname>_len = <len>; 1045 // to the file given by filename. Only the first len chars are written. 1046 int WriteAsCFile(const char* filename, const char* varname, 1047 const char* str, int size, bool verbose = true); 1048 1049 1050 // ---------------------------------------------------------------------------- 1051 // Memory 1052 1053 // Copies words from |src| to |dst|. The data spans must not overlap. 1054 template <typename T> 1055 inline void CopyWords(T* dst, const T* src, size_t num_words) { 1056 STATIC_ASSERT(sizeof(T) == kPointerSize); 1057 // TODO(mvstanton): disabled because mac builds are bogus failing on this 1058 // assert. They are doing a signed comparison. Investigate in 1059 // the morning. 1060 // DCHECK(Min(dst, const_cast<T*>(src)) + num_words <= 1061 // Max(dst, const_cast<T*>(src))); 1062 DCHECK(num_words > 0); 1063 1064 // Use block copying MemCopy if the segment we're copying is 1065 // enough to justify the extra call/setup overhead. 1066 static const size_t kBlockCopyLimit = 16; 1067 1068 if (num_words < kBlockCopyLimit) { 1069 do { 1070 num_words--; 1071 *dst++ = *src++; 1072 } while (num_words > 0); 1073 } else { 1074 MemCopy(dst, src, num_words * kPointerSize); 1075 } 1076 } 1077 1078 1079 // Copies words from |src| to |dst|. No restrictions. 1080 template <typename T> 1081 inline void MoveWords(T* dst, const T* src, size_t num_words) { 1082 STATIC_ASSERT(sizeof(T) == kPointerSize); 1083 DCHECK(num_words > 0); 1084 1085 // Use block copying MemCopy if the segment we're copying is 1086 // enough to justify the extra call/setup overhead. 1087 static const size_t kBlockCopyLimit = 16; 1088 1089 if (num_words < kBlockCopyLimit && 1090 ((dst < src) || (dst >= (src + num_words * kPointerSize)))) { 1091 T* end = dst + num_words; 1092 do { 1093 num_words--; 1094 *dst++ = *src++; 1095 } while (num_words > 0); 1096 } else { 1097 MemMove(dst, src, num_words * kPointerSize); 1098 } 1099 } 1100 1101 1102 // Copies data from |src| to |dst|. The data spans must not overlap. 1103 template <typename T> 1104 inline void CopyBytes(T* dst, const T* src, size_t num_bytes) { 1105 STATIC_ASSERT(sizeof(T) == 1); 1106 DCHECK(Min(dst, const_cast<T*>(src)) + num_bytes <= 1107 Max(dst, const_cast<T*>(src))); 1108 if (num_bytes == 0) return; 1109 1110 // Use block copying MemCopy if the segment we're copying is 1111 // enough to justify the extra call/setup overhead. 1112 static const int kBlockCopyLimit = kMinComplexMemCopy; 1113 1114 if (num_bytes < static_cast<size_t>(kBlockCopyLimit)) { 1115 do { 1116 num_bytes--; 1117 *dst++ = *src++; 1118 } while (num_bytes > 0); 1119 } else { 1120 MemCopy(dst, src, num_bytes); 1121 } 1122 } 1123 1124 1125 template <typename T, typename U> 1126 inline void MemsetPointer(T** dest, U* value, int counter) { 1127 #ifdef DEBUG 1128 T* a = NULL; 1129 U* b = NULL; 1130 a = b; // Fake assignment to check assignability. 1131 USE(a); 1132 #endif // DEBUG 1133 #if V8_HOST_ARCH_IA32 1134 #define STOS "stosl" 1135 #elif V8_HOST_ARCH_X64 1136 #if V8_HOST_ARCH_32_BIT 1137 #define STOS "addr32 stosl" 1138 #else 1139 #define STOS "stosq" 1140 #endif 1141 #endif 1142 1143 #if defined(MEMORY_SANITIZER) 1144 // MemorySanitizer does not understand inline assembly. 1145 #undef STOS 1146 #endif 1147 1148 #if defined(__GNUC__) && defined(STOS) 1149 asm volatile( 1150 "cld;" 1151 "rep ; " STOS 1152 : "+&c" (counter), "+&D" (dest) 1153 : "a" (value) 1154 : "memory", "cc"); 1155 #else 1156 for (int i = 0; i < counter; i++) { 1157 dest[i] = value; 1158 } 1159 #endif 1160 1161 #undef STOS 1162 } 1163 1164 1165 // Simple support to read a file into a 0-terminated C-string. 1166 // The returned buffer must be freed by the caller. 1167 // On return, *exits tells whether the file existed. 1168 V8_EXPORT_PRIVATE Vector<const char> ReadFile(const char* filename, 1169 bool* exists, 1170 bool verbose = true); 1171 Vector<const char> ReadFile(FILE* file, 1172 bool* exists, 1173 bool verbose = true); 1174 1175 1176 template <typename sourcechar, typename sinkchar> 1177 INLINE(static void CopyCharsUnsigned(sinkchar* dest, const sourcechar* src, 1178 size_t chars)); 1179 #if defined(V8_HOST_ARCH_ARM) 1180 INLINE(void CopyCharsUnsigned(uint8_t* dest, const uint8_t* src, size_t chars)); 1181 INLINE(void CopyCharsUnsigned(uint16_t* dest, const uint8_t* src, 1182 size_t chars)); 1183 INLINE(void CopyCharsUnsigned(uint16_t* dest, const uint16_t* src, 1184 size_t chars)); 1185 #elif defined(V8_HOST_ARCH_MIPS) 1186 INLINE(void CopyCharsUnsigned(uint8_t* dest, const uint8_t* src, size_t chars)); 1187 INLINE(void CopyCharsUnsigned(uint16_t* dest, const uint16_t* src, 1188 size_t chars)); 1189 #elif defined(V8_HOST_ARCH_PPC) || defined(V8_HOST_ARCH_S390) 1190 INLINE(void CopyCharsUnsigned(uint8_t* dest, const uint8_t* src, size_t chars)); 1191 INLINE(void CopyCharsUnsigned(uint16_t* dest, const uint16_t* src, 1192 size_t chars)); 1193 #endif 1194 1195 // Copy from 8bit/16bit chars to 8bit/16bit chars. 1196 template <typename sourcechar, typename sinkchar> 1197 INLINE(void CopyChars(sinkchar* dest, const sourcechar* src, size_t chars)); 1198 1199 template <typename sourcechar, typename sinkchar> 1200 void CopyChars(sinkchar* dest, const sourcechar* src, size_t chars) { 1201 DCHECK(sizeof(sourcechar) <= 2); 1202 DCHECK(sizeof(sinkchar) <= 2); 1203 if (sizeof(sinkchar) == 1) { 1204 if (sizeof(sourcechar) == 1) { 1205 CopyCharsUnsigned(reinterpret_cast<uint8_t*>(dest), 1206 reinterpret_cast<const uint8_t*>(src), 1207 chars); 1208 } else { 1209 CopyCharsUnsigned(reinterpret_cast<uint8_t*>(dest), 1210 reinterpret_cast<const uint16_t*>(src), 1211 chars); 1212 } 1213 } else { 1214 if (sizeof(sourcechar) == 1) { 1215 CopyCharsUnsigned(reinterpret_cast<uint16_t*>(dest), 1216 reinterpret_cast<const uint8_t*>(src), 1217 chars); 1218 } else { 1219 CopyCharsUnsigned(reinterpret_cast<uint16_t*>(dest), 1220 reinterpret_cast<const uint16_t*>(src), 1221 chars); 1222 } 1223 } 1224 } 1225 1226 template <typename sourcechar, typename sinkchar> 1227 void CopyCharsUnsigned(sinkchar* dest, const sourcechar* src, size_t chars) { 1228 sinkchar* limit = dest + chars; 1229 if ((sizeof(*dest) == sizeof(*src)) && 1230 (chars >= static_cast<int>(kMinComplexMemCopy / sizeof(*dest)))) { 1231 MemCopy(dest, src, chars * sizeof(*dest)); 1232 } else { 1233 while (dest < limit) *dest++ = static_cast<sinkchar>(*src++); 1234 } 1235 } 1236 1237 1238 #if defined(V8_HOST_ARCH_ARM) 1239 void CopyCharsUnsigned(uint8_t* dest, const uint8_t* src, size_t chars) { 1240 switch (static_cast<unsigned>(chars)) { 1241 case 0: 1242 break; 1243 case 1: 1244 *dest = *src; 1245 break; 1246 case 2: 1247 memcpy(dest, src, 2); 1248 break; 1249 case 3: 1250 memcpy(dest, src, 3); 1251 break; 1252 case 4: 1253 memcpy(dest, src, 4); 1254 break; 1255 case 5: 1256 memcpy(dest, src, 5); 1257 break; 1258 case 6: 1259 memcpy(dest, src, 6); 1260 break; 1261 case 7: 1262 memcpy(dest, src, 7); 1263 break; 1264 case 8: 1265 memcpy(dest, src, 8); 1266 break; 1267 case 9: 1268 memcpy(dest, src, 9); 1269 break; 1270 case 10: 1271 memcpy(dest, src, 10); 1272 break; 1273 case 11: 1274 memcpy(dest, src, 11); 1275 break; 1276 case 12: 1277 memcpy(dest, src, 12); 1278 break; 1279 case 13: 1280 memcpy(dest, src, 13); 1281 break; 1282 case 14: 1283 memcpy(dest, src, 14); 1284 break; 1285 case 15: 1286 memcpy(dest, src, 15); 1287 break; 1288 default: 1289 MemCopy(dest, src, chars); 1290 break; 1291 } 1292 } 1293 1294 1295 void CopyCharsUnsigned(uint16_t* dest, const uint8_t* src, size_t chars) { 1296 if (chars >= static_cast<size_t>(kMinComplexConvertMemCopy)) { 1297 MemCopyUint16Uint8(dest, src, chars); 1298 } else { 1299 MemCopyUint16Uint8Wrapper(dest, src, chars); 1300 } 1301 } 1302 1303 1304 void CopyCharsUnsigned(uint16_t* dest, const uint16_t* src, size_t chars) { 1305 switch (static_cast<unsigned>(chars)) { 1306 case 0: 1307 break; 1308 case 1: 1309 *dest = *src; 1310 break; 1311 case 2: 1312 memcpy(dest, src, 4); 1313 break; 1314 case 3: 1315 memcpy(dest, src, 6); 1316 break; 1317 case 4: 1318 memcpy(dest, src, 8); 1319 break; 1320 case 5: 1321 memcpy(dest, src, 10); 1322 break; 1323 case 6: 1324 memcpy(dest, src, 12); 1325 break; 1326 case 7: 1327 memcpy(dest, src, 14); 1328 break; 1329 default: 1330 MemCopy(dest, src, chars * sizeof(*dest)); 1331 break; 1332 } 1333 } 1334 1335 1336 #elif defined(V8_HOST_ARCH_MIPS) 1337 void CopyCharsUnsigned(uint8_t* dest, const uint8_t* src, size_t chars) { 1338 if (chars < kMinComplexMemCopy) { 1339 memcpy(dest, src, chars); 1340 } else { 1341 MemCopy(dest, src, chars); 1342 } 1343 } 1344 1345 void CopyCharsUnsigned(uint16_t* dest, const uint16_t* src, size_t chars) { 1346 if (chars < kMinComplexMemCopy) { 1347 memcpy(dest, src, chars * sizeof(*dest)); 1348 } else { 1349 MemCopy(dest, src, chars * sizeof(*dest)); 1350 } 1351 } 1352 #elif defined(V8_HOST_ARCH_PPC) || defined(V8_HOST_ARCH_S390) 1353 #define CASE(n) \ 1354 case n: \ 1355 memcpy(dest, src, n); \ 1356 break 1357 void CopyCharsUnsigned(uint8_t* dest, const uint8_t* src, size_t chars) { 1358 switch (static_cast<unsigned>(chars)) { 1359 case 0: 1360 break; 1361 case 1: 1362 *dest = *src; 1363 break; 1364 CASE(2); 1365 CASE(3); 1366 CASE(4); 1367 CASE(5); 1368 CASE(6); 1369 CASE(7); 1370 CASE(8); 1371 CASE(9); 1372 CASE(10); 1373 CASE(11); 1374 CASE(12); 1375 CASE(13); 1376 CASE(14); 1377 CASE(15); 1378 CASE(16); 1379 CASE(17); 1380 CASE(18); 1381 CASE(19); 1382 CASE(20); 1383 CASE(21); 1384 CASE(22); 1385 CASE(23); 1386 CASE(24); 1387 CASE(25); 1388 CASE(26); 1389 CASE(27); 1390 CASE(28); 1391 CASE(29); 1392 CASE(30); 1393 CASE(31); 1394 CASE(32); 1395 CASE(33); 1396 CASE(34); 1397 CASE(35); 1398 CASE(36); 1399 CASE(37); 1400 CASE(38); 1401 CASE(39); 1402 CASE(40); 1403 CASE(41); 1404 CASE(42); 1405 CASE(43); 1406 CASE(44); 1407 CASE(45); 1408 CASE(46); 1409 CASE(47); 1410 CASE(48); 1411 CASE(49); 1412 CASE(50); 1413 CASE(51); 1414 CASE(52); 1415 CASE(53); 1416 CASE(54); 1417 CASE(55); 1418 CASE(56); 1419 CASE(57); 1420 CASE(58); 1421 CASE(59); 1422 CASE(60); 1423 CASE(61); 1424 CASE(62); 1425 CASE(63); 1426 CASE(64); 1427 default: 1428 memcpy(dest, src, chars); 1429 break; 1430 } 1431 } 1432 #undef CASE 1433 1434 #define CASE(n) \ 1435 case n: \ 1436 memcpy(dest, src, n * 2); \ 1437 break 1438 void CopyCharsUnsigned(uint16_t* dest, const uint16_t* src, size_t chars) { 1439 switch (static_cast<unsigned>(chars)) { 1440 case 0: 1441 break; 1442 case 1: 1443 *dest = *src; 1444 break; 1445 CASE(2); 1446 CASE(3); 1447 CASE(4); 1448 CASE(5); 1449 CASE(6); 1450 CASE(7); 1451 CASE(8); 1452 CASE(9); 1453 CASE(10); 1454 CASE(11); 1455 CASE(12); 1456 CASE(13); 1457 CASE(14); 1458 CASE(15); 1459 CASE(16); 1460 CASE(17); 1461 CASE(18); 1462 CASE(19); 1463 CASE(20); 1464 CASE(21); 1465 CASE(22); 1466 CASE(23); 1467 CASE(24); 1468 CASE(25); 1469 CASE(26); 1470 CASE(27); 1471 CASE(28); 1472 CASE(29); 1473 CASE(30); 1474 CASE(31); 1475 CASE(32); 1476 default: 1477 memcpy(dest, src, chars * 2); 1478 break; 1479 } 1480 } 1481 #undef CASE 1482 #endif 1483 1484 1485 class StringBuilder : public SimpleStringBuilder { 1486 public: 1487 explicit StringBuilder(int size) : SimpleStringBuilder(size) { } 1488 StringBuilder(char* buffer, int size) : SimpleStringBuilder(buffer, size) { } 1489 1490 // Add formatted contents to the builder just like printf(). 1491 void PRINTF_FORMAT(2, 3) AddFormatted(const char* format, ...); 1492 1493 // Add formatted contents like printf based on a va_list. 1494 void PRINTF_FORMAT(2, 0) AddFormattedList(const char* format, va_list list); 1495 1496 private: 1497 DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder); 1498 }; 1499 1500 1501 bool DoubleToBoolean(double d); 1502 1503 template <typename Stream> 1504 bool StringToArrayIndex(Stream* stream, uint32_t* index) { 1505 uint16_t ch = stream->GetNext(); 1506 1507 // If the string begins with a '0' character, it must only consist 1508 // of it to be a legal array index. 1509 if (ch == '0') { 1510 *index = 0; 1511 return !stream->HasMore(); 1512 } 1513 1514 // Convert string to uint32 array index; character by character. 1515 int d = ch - '0'; 1516 if (d < 0 || d > 9) return false; 1517 uint32_t result = d; 1518 while (stream->HasMore()) { 1519 d = stream->GetNext() - '0'; 1520 if (d < 0 || d > 9) return false; 1521 // Check that the new result is below the 32 bit limit. 1522 if (result > 429496729U - ((d + 3) >> 3)) return false; 1523 result = (result * 10) + d; 1524 } 1525 1526 *index = result; 1527 return true; 1528 } 1529 1530 1531 // Returns current value of top of the stack. Works correctly with ASAN. 1532 DISABLE_ASAN 1533 inline uintptr_t GetCurrentStackPosition() { 1534 // Takes the address of the limit variable in order to find out where 1535 // the top of stack is right now. 1536 uintptr_t limit = reinterpret_cast<uintptr_t>(&limit); 1537 return limit; 1538 } 1539 1540 template <typename V> 1541 static inline V ReadUnalignedValue(const void* p) { 1542 #if !(V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM) 1543 return *reinterpret_cast<const V*>(p); 1544 #else // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM 1545 V r; 1546 memmove(&r, p, sizeof(V)); 1547 return r; 1548 #endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM 1549 } 1550 1551 template <typename V> 1552 static inline void WriteUnalignedValue(void* p, V value) { 1553 #if !(V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM) 1554 *(reinterpret_cast<V*>(p)) = value; 1555 #else // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM 1556 memmove(p, &value, sizeof(V)); 1557 #endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM 1558 } 1559 1560 static inline double ReadFloatValue(const void* p) { 1561 return ReadUnalignedValue<float>(p); 1562 } 1563 1564 static inline double ReadDoubleValue(const void* p) { 1565 return ReadUnalignedValue<double>(p); 1566 } 1567 1568 static inline void WriteDoubleValue(void* p, double value) { 1569 WriteUnalignedValue(p, value); 1570 } 1571 1572 static inline uint16_t ReadUnalignedUInt16(const void* p) { 1573 return ReadUnalignedValue<uint16_t>(p); 1574 } 1575 1576 static inline void WriteUnalignedUInt16(void* p, uint16_t value) { 1577 WriteUnalignedValue(p, value); 1578 } 1579 1580 static inline uint32_t ReadUnalignedUInt32(const void* p) { 1581 return ReadUnalignedValue<uint32_t>(p); 1582 } 1583 1584 static inline void WriteUnalignedUInt32(void* p, uint32_t value) { 1585 WriteUnalignedValue(p, value); 1586 } 1587 1588 template <typename V> 1589 static inline V ReadLittleEndianValue(const void* p) { 1590 #if defined(V8_TARGET_LITTLE_ENDIAN) 1591 return ReadUnalignedValue<V>(p); 1592 #elif defined(V8_TARGET_BIG_ENDIAN) 1593 V ret = 0; 1594 const byte* src = reinterpret_cast<const byte*>(p); 1595 byte* dst = reinterpret_cast<byte*>(&ret); 1596 for (size_t i = 0; i < sizeof(V); i++) { 1597 dst[i] = src[sizeof(V) - i - 1]; 1598 } 1599 return ret; 1600 #endif // V8_TARGET_LITTLE_ENDIAN 1601 } 1602 1603 template <typename V> 1604 static inline void WriteLittleEndianValue(void* p, V value) { 1605 #if defined(V8_TARGET_LITTLE_ENDIAN) 1606 WriteUnalignedValue<V>(p, value); 1607 #elif defined(V8_TARGET_BIG_ENDIAN) 1608 byte* src = reinterpret_cast<byte*>(&value); 1609 byte* dst = reinterpret_cast<byte*>(p); 1610 for (size_t i = 0; i < sizeof(V); i++) { 1611 dst[i] = src[sizeof(V) - i - 1]; 1612 } 1613 #endif // V8_TARGET_LITTLE_ENDIAN 1614 } 1615 1616 // Represents a linked list that threads through the nodes in the linked list. 1617 // Entries in the list are pointers to nodes. The nodes need to have a T** 1618 // next() method that returns the location where the next value is stored. 1619 template <typename T> 1620 class ThreadedList final { 1621 public: 1622 ThreadedList() : head_(nullptr), tail_(&head_) {} 1623 void Add(T* v) { 1624 DCHECK_NULL(*tail_); 1625 DCHECK_NULL(*v->next()); 1626 *tail_ = v; 1627 tail_ = v->next(); 1628 } 1629 1630 void Clear() { 1631 head_ = nullptr; 1632 tail_ = &head_; 1633 } 1634 1635 class Iterator final { 1636 public: 1637 Iterator& operator++() { 1638 entry_ = (*entry_)->next(); 1639 return *this; 1640 } 1641 bool operator!=(const Iterator& other) { return entry_ != other.entry_; } 1642 T* operator*() { return *entry_; } 1643 Iterator& operator=(T* entry) { 1644 T* next = *(*entry_)->next(); 1645 *entry->next() = next; 1646 *entry_ = entry; 1647 return *this; 1648 } 1649 1650 private: 1651 explicit Iterator(T** entry) : entry_(entry) {} 1652 1653 T** entry_; 1654 1655 friend class ThreadedList; 1656 }; 1657 1658 class ConstIterator final { 1659 public: 1660 ConstIterator& operator++() { 1661 entry_ = (*entry_)->next(); 1662 return *this; 1663 } 1664 bool operator!=(const ConstIterator& other) { 1665 return entry_ != other.entry_; 1666 } 1667 const T* operator*() const { return *entry_; } 1668 1669 private: 1670 explicit ConstIterator(T* const* entry) : entry_(entry) {} 1671 1672 T* const* entry_; 1673 1674 friend class ThreadedList; 1675 }; 1676 1677 Iterator begin() { return Iterator(&head_); } 1678 Iterator end() { return Iterator(tail_); } 1679 1680 ConstIterator begin() const { return ConstIterator(&head_); } 1681 ConstIterator end() const { return ConstIterator(tail_); } 1682 1683 void Rewind(Iterator reset_point) { 1684 tail_ = reset_point.entry_; 1685 *tail_ = nullptr; 1686 } 1687 1688 void MoveTail(ThreadedList<T>* parent, Iterator location) { 1689 if (parent->end() != location) { 1690 DCHECK_NULL(*tail_); 1691 *tail_ = *location; 1692 tail_ = parent->tail_; 1693 parent->Rewind(location); 1694 } 1695 } 1696 1697 bool is_empty() const { return head_ == nullptr; } 1698 1699 // Slow. For testing purposes. 1700 int LengthForTest() { 1701 int result = 0; 1702 for (Iterator t = begin(); t != end(); ++t) ++result; 1703 return result; 1704 } 1705 T* AtForTest(int i) { 1706 Iterator t = begin(); 1707 while (i-- > 0) ++t; 1708 return *t; 1709 } 1710 1711 private: 1712 T* head_; 1713 T** tail_; 1714 DISALLOW_COPY_AND_ASSIGN(ThreadedList); 1715 }; 1716 1717 // Can be used to create a threaded list of |T|. 1718 template <typename T> 1719 class ThreadedListZoneEntry final : public ZoneObject { 1720 public: 1721 explicit ThreadedListZoneEntry(T value) : value_(value), next_(nullptr) {} 1722 1723 T value() { return value_; } 1724 ThreadedListZoneEntry<T>** next() { return &next_; } 1725 1726 private: 1727 T value_; 1728 ThreadedListZoneEntry<T>* next_; 1729 DISALLOW_COPY_AND_ASSIGN(ThreadedListZoneEntry); 1730 }; 1731 1732 } // namespace internal 1733 } // namespace v8 1734 1735 #endif // V8_UTILS_H_ 1736