utils.h revision 80d68eab642096c1a48b6474d6ec33064b0ad1f5
1// Copyright 2006-2008 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28#ifndef V8_UTILS_H_ 29#define V8_UTILS_H_ 30 31#include <stdlib.h> 32#include <string.h> 33 34namespace v8 { 35namespace internal { 36 37// ---------------------------------------------------------------------------- 38// General helper functions 39 40#define IS_POWER_OF_TWO(x) (((x) & ((x) - 1)) == 0) 41 42// Returns true iff x is a power of 2 (or zero). Cannot be used with the 43// maximally negative value of the type T (the -1 overflows). 44template <typename T> 45static inline bool IsPowerOf2(T x) { 46 return IS_POWER_OF_TWO(x); 47} 48 49 50// X must be a power of 2. Returns the number of trailing zeros. 51template <typename T> 52static inline int WhichPowerOf2(T x) { 53 ASSERT(IsPowerOf2(x)); 54 ASSERT(x != 0); 55 if (x < 0) return 31; 56 int bits = 0; 57#ifdef DEBUG 58 int original_x = x; 59#endif 60 if (x >= 0x10000) { 61 bits += 16; 62 x >>= 16; 63 } 64 if (x >= 0x100) { 65 bits += 8; 66 x >>= 8; 67 } 68 if (x >= 0x10) { 69 bits += 4; 70 x >>= 4; 71 } 72 switch (x) { 73 default: UNREACHABLE(); 74 case 8: bits++; // Fall through. 75 case 4: bits++; // Fall through. 76 case 2: bits++; // Fall through. 77 case 1: break; 78 } 79 ASSERT_EQ(1 << bits, original_x); 80 return bits; 81 return 0; 82} 83 84 85// The C++ standard leaves the semantics of '>>' undefined for 86// negative signed operands. Most implementations do the right thing, 87// though. 88static inline int ArithmeticShiftRight(int x, int s) { 89 return x >> s; 90} 91 92 93// Compute the 0-relative offset of some absolute value x of type T. 94// This allows conversion of Addresses and integral types into 95// 0-relative int offsets. 96template <typename T> 97static inline intptr_t OffsetFrom(T x) { 98 return x - static_cast<T>(0); 99} 100 101 102// Compute the absolute value of type T for some 0-relative offset x. 103// This allows conversion of 0-relative int offsets into Addresses and 104// integral types. 105template <typename T> 106static inline T AddressFrom(intptr_t x) { 107 return static_cast<T>(static_cast<T>(0) + x); 108} 109 110 111// Return the largest multiple of m which is <= x. 112template <typename T> 113static inline T RoundDown(T x, int m) { 114 ASSERT(IsPowerOf2(m)); 115 return AddressFrom<T>(OffsetFrom(x) & -m); 116} 117 118 119// Return the smallest multiple of m which is >= x. 120template <typename T> 121static inline T RoundUp(T x, int m) { 122 return RoundDown(x + m - 1, m); 123} 124 125 126template <typename T> 127static int Compare(const T& a, const T& b) { 128 if (a == b) 129 return 0; 130 else if (a < b) 131 return -1; 132 else 133 return 1; 134} 135 136 137template <typename T> 138static int PointerValueCompare(const T* a, const T* b) { 139 return Compare<T>(*a, *b); 140} 141 142 143// Returns the smallest power of two which is >= x. If you pass in a 144// number that is already a power of two, it is returned as is. 145uint32_t RoundUpToPowerOf2(uint32_t x); 146 147 148template <typename T> 149static inline bool IsAligned(T value, T alignment) { 150 ASSERT(IsPowerOf2(alignment)); 151 return (value & (alignment - 1)) == 0; 152} 153 154 155// Returns true if (addr + offset) is aligned. 156static inline bool IsAddressAligned(Address addr, 157 intptr_t alignment, 158 int offset) { 159 intptr_t offs = OffsetFrom(addr + offset); 160 return IsAligned(offs, alignment); 161} 162 163 164// Returns the maximum of the two parameters. 165template <typename T> 166static T Max(T a, T b) { 167 return a < b ? b : a; 168} 169 170 171// Returns the minimum of the two parameters. 172template <typename T> 173static T Min(T a, T b) { 174 return a < b ? a : b; 175} 176 177 178inline int StrLength(const char* string) { 179 size_t length = strlen(string); 180 ASSERT(length == static_cast<size_t>(static_cast<int>(length))); 181 return static_cast<int>(length); 182} 183 184 185// ---------------------------------------------------------------------------- 186// BitField is a help template for encoding and decode bitfield with 187// unsigned content. 188template<class T, int shift, int size> 189class BitField { 190 public: 191 // Tells whether the provided value fits into the bit field. 192 static bool is_valid(T value) { 193 return (static_cast<uint32_t>(value) & ~((1U << (size)) - 1)) == 0; 194 } 195 196 // Returns a uint32_t mask of bit field. 197 static uint32_t mask() { 198 // To use all bits of a uint32 in a bitfield without compiler warnings we 199 // have to compute 2^32 without using a shift count of 32. 200 return ((1U << shift) << size) - (1U << shift); 201 } 202 203 // Returns a uint32_t with the bit field value encoded. 204 static uint32_t encode(T value) { 205 ASSERT(is_valid(value)); 206 return static_cast<uint32_t>(value) << shift; 207 } 208 209 // Extracts the bit field from the value. 210 static T decode(uint32_t value) { 211 return static_cast<T>((value & mask()) >> shift); 212 } 213}; 214 215 216// ---------------------------------------------------------------------------- 217// Hash function. 218 219uint32_t ComputeIntegerHash(uint32_t key); 220 221 222// ---------------------------------------------------------------------------- 223// I/O support. 224 225// Our version of printf(). Avoids compilation errors that we get 226// with standard printf when attempting to print pointers, etc. 227// (the errors are due to the extra compilation flags, which we 228// want elsewhere). 229void PrintF(const char* format, ...); 230 231// Our version of fflush. 232void Flush(); 233 234 235// Read a line of characters after printing the prompt to stdout. The resulting 236// char* needs to be disposed off with DeleteArray by the caller. 237char* ReadLine(const char* prompt); 238 239 240// Read and return the raw bytes in a file. the size of the buffer is returned 241// in size. 242// The returned buffer must be freed by the caller. 243byte* ReadBytes(const char* filename, int* size, bool verbose = true); 244 245 246// Write size chars from str to the file given by filename. 247// The file is overwritten. Returns the number of chars written. 248int WriteChars(const char* filename, 249 const char* str, 250 int size, 251 bool verbose = true); 252 253 254// Write size bytes to the file given by filename. 255// The file is overwritten. Returns the number of bytes written. 256int WriteBytes(const char* filename, 257 const byte* bytes, 258 int size, 259 bool verbose = true); 260 261 262// Write the C code 263// const char* <varname> = "<str>"; 264// const int <varname>_len = <len>; 265// to the file given by filename. Only the first len chars are written. 266int WriteAsCFile(const char* filename, const char* varname, 267 const char* str, int size, bool verbose = true); 268 269 270// ---------------------------------------------------------------------------- 271// Miscellaneous 272 273// A static resource holds a static instance that can be reserved in 274// a local scope using an instance of Access. Attempts to re-reserve 275// the instance will cause an error. 276template <typename T> 277class StaticResource { 278 public: 279 StaticResource() : is_reserved_(false) {} 280 281 private: 282 template <typename S> friend class Access; 283 T instance_; 284 bool is_reserved_; 285}; 286 287 288// Locally scoped access to a static resource. 289template <typename T> 290class Access { 291 public: 292 explicit Access(StaticResource<T>* resource) 293 : resource_(resource) 294 , instance_(&resource->instance_) { 295 ASSERT(!resource->is_reserved_); 296 resource->is_reserved_ = true; 297 } 298 299 ~Access() { 300 resource_->is_reserved_ = false; 301 resource_ = NULL; 302 instance_ = NULL; 303 } 304 305 T* value() { return instance_; } 306 T* operator -> () { return instance_; } 307 308 private: 309 StaticResource<T>* resource_; 310 T* instance_; 311}; 312 313 314template <typename T> 315class Vector { 316 public: 317 Vector() : start_(NULL), length_(0) {} 318 Vector(T* data, int length) : start_(data), length_(length) { 319 ASSERT(length == 0 || (length > 0 && data != NULL)); 320 } 321 322 static Vector<T> New(int length) { 323 return Vector<T>(NewArray<T>(length), length); 324 } 325 326 // Returns a vector using the same backing storage as this one, 327 // spanning from and including 'from', to but not including 'to'. 328 Vector<T> SubVector(int from, int to) { 329 ASSERT(to <= length_); 330 ASSERT(from < to); 331 ASSERT(0 <= from); 332 return Vector<T>(start() + from, to - from); 333 } 334 335 // Returns the length of the vector. 336 int length() const { return length_; } 337 338 // Returns whether or not the vector is empty. 339 bool is_empty() const { return length_ == 0; } 340 341 // Returns the pointer to the start of the data in the vector. 342 T* start() const { return start_; } 343 344 // Access individual vector elements - checks bounds in debug mode. 345 T& operator[](int index) const { 346 ASSERT(0 <= index && index < length_); 347 return start_[index]; 348 } 349 350 T& first() { return start_[0]; } 351 352 T& last() { return start_[length_ - 1]; } 353 354 // Returns a clone of this vector with a new backing store. 355 Vector<T> Clone() const { 356 T* result = NewArray<T>(length_); 357 for (int i = 0; i < length_; i++) result[i] = start_[i]; 358 return Vector<T>(result, length_); 359 } 360 361 void Sort(int (*cmp)(const T*, const T*)) { 362 typedef int (*RawComparer)(const void*, const void*); 363 qsort(start(), 364 length(), 365 sizeof(T), 366 reinterpret_cast<RawComparer>(cmp)); 367 } 368 369 void Sort() { 370 Sort(PointerValueCompare<T>); 371 } 372 373 void Truncate(int length) { 374 ASSERT(length <= length_); 375 length_ = length; 376 } 377 378 // Releases the array underlying this vector. Once disposed the 379 // vector is empty. 380 void Dispose() { 381 DeleteArray(start_); 382 start_ = NULL; 383 length_ = 0; 384 } 385 386 inline Vector<T> operator+(int offset) { 387 ASSERT(offset < length_); 388 return Vector<T>(start_ + offset, length_ - offset); 389 } 390 391 // Factory method for creating empty vectors. 392 static Vector<T> empty() { return Vector<T>(NULL, 0); } 393 394 protected: 395 void set_start(T* start) { start_ = start; } 396 397 private: 398 T* start_; 399 int length_; 400}; 401 402 403// A temporary assignment sets a (non-local) variable to a value on 404// construction and resets it the value on destruction. 405template <typename T> 406class TempAssign { 407 public: 408 TempAssign(T* var, T value): var_(var), old_value_(*var) { 409 *var = value; 410 } 411 412 ~TempAssign() { *var_ = old_value_; } 413 414 private: 415 T* var_; 416 T old_value_; 417}; 418 419 420template <typename T, int kSize> 421class EmbeddedVector : public Vector<T> { 422 public: 423 EmbeddedVector() : Vector<T>(buffer_, kSize) { } 424 425 // When copying, make underlying Vector to reference our buffer. 426 EmbeddedVector(const EmbeddedVector& rhs) 427 : Vector<T>(rhs) { 428 memcpy(buffer_, rhs.buffer_, sizeof(T) * kSize); 429 set_start(buffer_); 430 } 431 432 EmbeddedVector& operator=(const EmbeddedVector& rhs) { 433 if (this == &rhs) return *this; 434 Vector<T>::operator=(rhs); 435 memcpy(buffer_, rhs.buffer_, sizeof(T) * kSize); 436 this->set_start(buffer_); 437 return *this; 438 } 439 440 private: 441 T buffer_[kSize]; 442}; 443 444 445template <typename T> 446class ScopedVector : public Vector<T> { 447 public: 448 explicit ScopedVector(int length) : Vector<T>(NewArray<T>(length), length) { } 449 ~ScopedVector() { 450 DeleteArray(this->start()); 451 } 452 453 private: 454 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedVector); 455}; 456 457 458inline Vector<const char> CStrVector(const char* data) { 459 return Vector<const char>(data, StrLength(data)); 460} 461 462inline Vector<char> MutableCStrVector(char* data) { 463 return Vector<char>(data, StrLength(data)); 464} 465 466inline Vector<char> MutableCStrVector(char* data, int max) { 467 int length = StrLength(data); 468 return Vector<char>(data, (length < max) ? length : max); 469} 470 471template <typename T> 472inline Vector< Handle<Object> > HandleVector(v8::internal::Handle<T>* elms, 473 int length) { 474 return Vector< Handle<Object> >( 475 reinterpret_cast<v8::internal::Handle<Object>*>(elms), length); 476} 477 478 479/* 480 * A class that collects values into a backing store. 481 * Specialized versions of the class can allow access to the backing store 482 * in different ways. 483 * There is no guarantee that the backing store is contiguous (and, as a 484 * consequence, no guarantees that consecutively added elements are adjacent 485 * in memory). The collector may move elements unless it has guaranteed not 486 * to. 487 */ 488template <typename T, int growth_factor = 2, int max_growth = 1 * MB> 489class Collector { 490 public: 491 explicit Collector(int initial_capacity = kMinCapacity) 492 : index_(0), size_(0) { 493 if (initial_capacity < kMinCapacity) { 494 initial_capacity = kMinCapacity; 495 } 496 current_chunk_ = Vector<T>::New(initial_capacity); 497 } 498 499 virtual ~Collector() { 500 // Free backing store (in reverse allocation order). 501 current_chunk_.Dispose(); 502 for (int i = chunks_.length() - 1; i >= 0; i--) { 503 chunks_.at(i).Dispose(); 504 } 505 } 506 507 // Add a single element. 508 inline void Add(T value) { 509 if (index_ >= current_chunk_.length()) { 510 Grow(1); 511 } 512 current_chunk_[index_] = value; 513 index_++; 514 size_++; 515 } 516 517 // Add a block of contiguous elements and return a Vector backed by the 518 // memory area. 519 // A basic Collector will keep this vector valid as long as the Collector 520 // is alive. 521 inline Vector<T> AddBlock(int size, T initial_value) { 522 ASSERT(size > 0); 523 if (size > current_chunk_.length() - index_) { 524 Grow(size); 525 } 526 T* position = current_chunk_.start() + index_; 527 index_ += size; 528 size_ += size; 529 for (int i = 0; i < size; i++) { 530 position[i] = initial_value; 531 } 532 return Vector<T>(position, size); 533 } 534 535 536 // Write the contents of the collector into the provided vector. 537 void WriteTo(Vector<T> destination) { 538 ASSERT(size_ <= destination.length()); 539 int position = 0; 540 for (int i = 0; i < chunks_.length(); i++) { 541 Vector<T> chunk = chunks_.at(i); 542 for (int j = 0; j < chunk.length(); j++) { 543 destination[position] = chunk[j]; 544 position++; 545 } 546 } 547 for (int i = 0; i < index_; i++) { 548 destination[position] = current_chunk_[i]; 549 position++; 550 } 551 } 552 553 // Allocate a single contiguous vector, copy all the collected 554 // elements to the vector, and return it. 555 // The caller is responsible for freeing the memory of the returned 556 // vector (e.g., using Vector::Dispose). 557 Vector<T> ToVector() { 558 Vector<T> new_store = Vector<T>::New(size_); 559 WriteTo(new_store); 560 return new_store; 561 } 562 563 // Resets the collector to be empty. 564 virtual void Reset() { 565 for (int i = chunks_.length() - 1; i >= 0; i--) { 566 chunks_.at(i).Dispose(); 567 } 568 chunks_.Rewind(0); 569 index_ = 0; 570 size_ = 0; 571 } 572 573 // Total number of elements added to collector so far. 574 inline int size() { return size_; } 575 576 protected: 577 static const int kMinCapacity = 16; 578 List<Vector<T> > chunks_; 579 Vector<T> current_chunk_; // Block of memory currently being written into. 580 int index_; // Current index in current chunk. 581 int size_; // Total number of elements in collector. 582 583 // Creates a new current chunk, and stores the old chunk in the chunks_ list. 584 void Grow(int min_capacity) { 585 ASSERT(growth_factor > 1); 586 int growth = current_chunk_.length() * (growth_factor - 1); 587 if (growth > max_growth) { 588 growth = max_growth; 589 } 590 int new_capacity = current_chunk_.length() + growth; 591 if (new_capacity < min_capacity) { 592 new_capacity = min_capacity + growth; 593 } 594 Vector<T> new_chunk = Vector<T>::New(new_capacity); 595 int new_index = PrepareGrow(new_chunk); 596 if (index_ > 0) { 597 chunks_.Add(current_chunk_.SubVector(0, index_)); 598 } else { 599 // Can happen if the call to PrepareGrow moves everything into 600 // the new chunk. 601 current_chunk_.Dispose(); 602 } 603 current_chunk_ = new_chunk; 604 index_ = new_index; 605 ASSERT(index_ + min_capacity <= current_chunk_.length()); 606 } 607 608 // Before replacing the current chunk, give a subclass the option to move 609 // some of the current data into the new chunk. The function may update 610 // the current index_ value to represent data no longer in the current chunk. 611 // Returns the initial index of the new chunk (after copied data). 612 virtual int PrepareGrow(Vector<T> new_chunk) { 613 return 0; 614 } 615}; 616 617 618/* 619 * A collector that allows sequences of values to be guaranteed to 620 * stay consecutive. 621 * If the backing store grows while a sequence is active, the current 622 * sequence might be moved, but after the sequence is ended, it will 623 * not move again. 624 * NOTICE: Blocks allocated using Collector::AddBlock(int) can move 625 * as well, if inside an active sequence where another element is added. 626 */ 627template <typename T, int growth_factor = 2, int max_growth = 1 * MB> 628class SequenceCollector : public Collector<T, growth_factor, max_growth> { 629 public: 630 explicit SequenceCollector(int initial_capacity) 631 : Collector<T, growth_factor, max_growth>(initial_capacity), 632 sequence_start_(kNoSequence) { } 633 634 virtual ~SequenceCollector() {} 635 636 void StartSequence() { 637 ASSERT(sequence_start_ == kNoSequence); 638 sequence_start_ = this->index_; 639 } 640 641 Vector<T> EndSequence() { 642 ASSERT(sequence_start_ != kNoSequence); 643 int sequence_start = sequence_start_; 644 sequence_start_ = kNoSequence; 645 if (sequence_start == this->index_) return Vector<T>(); 646 return this->current_chunk_.SubVector(sequence_start, this->index_); 647 } 648 649 // Drops the currently added sequence, and all collected elements in it. 650 void DropSequence() { 651 ASSERT(sequence_start_ != kNoSequence); 652 int sequence_length = this->index_ - sequence_start_; 653 this->index_ = sequence_start_; 654 this->size_ -= sequence_length; 655 sequence_start_ = kNoSequence; 656 } 657 658 virtual void Reset() { 659 sequence_start_ = kNoSequence; 660 this->Collector<T, growth_factor, max_growth>::Reset(); 661 } 662 663 private: 664 static const int kNoSequence = -1; 665 int sequence_start_; 666 667 // Move the currently active sequence to the new chunk. 668 virtual int PrepareGrow(Vector<T> new_chunk) { 669 if (sequence_start_ != kNoSequence) { 670 int sequence_length = this->index_ - sequence_start_; 671 // The new chunk is always larger than the current chunk, so there 672 // is room for the copy. 673 ASSERT(sequence_length < new_chunk.length()); 674 for (int i = 0; i < sequence_length; i++) { 675 new_chunk[i] = this->current_chunk_[sequence_start_ + i]; 676 } 677 this->index_ = sequence_start_; 678 sequence_start_ = 0; 679 return sequence_length; 680 } 681 return 0; 682 } 683}; 684 685 686// Simple support to read a file into a 0-terminated C-string. 687// The returned buffer must be freed by the caller. 688// On return, *exits tells whether the file existed. 689Vector<const char> ReadFile(const char* filename, 690 bool* exists, 691 bool verbose = true); 692 693 694// Simple wrapper that allows an ExternalString to refer to a 695// Vector<const char>. Doesn't assume ownership of the data. 696class AsciiStringAdapter: public v8::String::ExternalAsciiStringResource { 697 public: 698 explicit AsciiStringAdapter(Vector<const char> data) : data_(data) {} 699 700 virtual const char* data() const { return data_.start(); } 701 702 virtual size_t length() const { return data_.length(); } 703 704 private: 705 Vector<const char> data_; 706}; 707 708 709// Helper class for building result strings in a character buffer. The 710// purpose of the class is to use safe operations that checks the 711// buffer bounds on all operations in debug mode. 712class StringBuilder { 713 public: 714 // Create a string builder with a buffer of the given size. The 715 // buffer is allocated through NewArray<char> and must be 716 // deallocated by the caller of Finalize(). 717 explicit StringBuilder(int size); 718 719 StringBuilder(char* buffer, int size) 720 : buffer_(buffer, size), position_(0) { } 721 722 ~StringBuilder() { if (!is_finalized()) Finalize(); } 723 724 int size() const { return buffer_.length(); } 725 726 // Get the current position in the builder. 727 int position() const { 728 ASSERT(!is_finalized()); 729 return position_; 730 } 731 732 // Reset the position. 733 void Reset() { position_ = 0; } 734 735 // Add a single character to the builder. It is not allowed to add 736 // 0-characters; use the Finalize() method to terminate the string 737 // instead. 738 void AddCharacter(char c) { 739 ASSERT(c != '\0'); 740 ASSERT(!is_finalized() && position_ < buffer_.length()); 741 buffer_[position_++] = c; 742 } 743 744 // Add an entire string to the builder. Uses strlen() internally to 745 // compute the length of the input string. 746 void AddString(const char* s); 747 748 // Add the first 'n' characters of the given string 's' to the 749 // builder. The input string must have enough characters. 750 void AddSubstring(const char* s, int n); 751 752 // Add formatted contents to the builder just like printf(). 753 void AddFormatted(const char* format, ...); 754 755 // Add character padding to the builder. If count is non-positive, 756 // nothing is added to the builder. 757 void AddPadding(char c, int count); 758 759 // Finalize the string by 0-terminating it and returning the buffer. 760 char* Finalize(); 761 762 private: 763 Vector<char> buffer_; 764 int position_; 765 766 bool is_finalized() const { return position_ < 0; } 767 768 DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder); 769}; 770 771 772// Custom memcpy implementation for platforms where the standard version 773// may not be good enough. 774// TODO(lrn): Check whether some IA32 platforms should be excluded. 775#if defined(V8_TARGET_ARCH_IA32) 776 777// TODO(lrn): Extend to other platforms as needed. 778 779typedef void (*MemCopyFunction)(void* dest, const void* src, size_t size); 780 781// Implemented in codegen-<arch>.cc. 782MemCopyFunction CreateMemCopyFunction(); 783 784// Copy memory area to disjoint memory area. 785static inline void MemCopy(void* dest, const void* src, size_t size) { 786 static MemCopyFunction memcopy = CreateMemCopyFunction(); 787 (*memcopy)(dest, src, size); 788#ifdef DEBUG 789 CHECK_EQ(0, memcmp(dest, src, size)); 790#endif 791} 792 793 794// Limit below which the extra overhead of the MemCopy function is likely 795// to outweigh the benefits of faster copying. 796// TODO(lrn): Try to find a more precise value. 797static const int kMinComplexMemCopy = 64; 798 799#else // V8_TARGET_ARCH_IA32 800 801static inline void MemCopy(void* dest, const void* src, size_t size) { 802 memcpy(dest, src, size); 803} 804 805static const int kMinComplexMemCopy = 256; 806 807#endif // V8_TARGET_ARCH_IA32 808 809 810// Copy from ASCII/16bit chars to ASCII/16bit chars. 811template <typename sourcechar, typename sinkchar> 812static inline void CopyChars(sinkchar* dest, const sourcechar* src, int chars) { 813 sinkchar* limit = dest + chars; 814#ifdef V8_HOST_CAN_READ_UNALIGNED 815 if (sizeof(*dest) == sizeof(*src)) { 816 if (chars >= static_cast<int>(kMinComplexMemCopy / sizeof(*dest))) { 817 MemCopy(dest, src, chars * sizeof(*dest)); 818 return; 819 } 820 // Number of characters in a uintptr_t. 821 static const int kStepSize = sizeof(uintptr_t) / sizeof(*dest); // NOLINT 822 while (dest <= limit - kStepSize) { 823 *reinterpret_cast<uintptr_t*>(dest) = 824 *reinterpret_cast<const uintptr_t*>(src); 825 dest += kStepSize; 826 src += kStepSize; 827 } 828 } 829#endif 830 while (dest < limit) { 831 *dest++ = static_cast<sinkchar>(*src++); 832 } 833} 834 835 836// Compare ASCII/16bit chars to ASCII/16bit chars. 837template <typename lchar, typename rchar> 838static inline int CompareChars(const lchar* lhs, const rchar* rhs, int chars) { 839 const lchar* limit = lhs + chars; 840#ifdef V8_HOST_CAN_READ_UNALIGNED 841 if (sizeof(*lhs) == sizeof(*rhs)) { 842 // Number of characters in a uintptr_t. 843 static const int kStepSize = sizeof(uintptr_t) / sizeof(*lhs); // NOLINT 844 while (lhs <= limit - kStepSize) { 845 if (*reinterpret_cast<const uintptr_t*>(lhs) != 846 *reinterpret_cast<const uintptr_t*>(rhs)) { 847 break; 848 } 849 lhs += kStepSize; 850 rhs += kStepSize; 851 } 852 } 853#endif 854 while (lhs < limit) { 855 int r = static_cast<int>(*lhs) - static_cast<int>(*rhs); 856 if (r != 0) return r; 857 ++lhs; 858 ++rhs; 859 } 860 return 0; 861} 862 863 864template <typename T> 865static inline void MemsetPointer(T** dest, T* value, int counter) { 866#if defined(V8_HOST_ARCH_IA32) 867#define STOS "stosl" 868#elif defined(V8_HOST_ARCH_X64) 869#define STOS "stosq" 870#endif 871 872#if defined(__GNUC__) && defined(STOS) 873 asm volatile( 874 "cld;" 875 "rep ; " STOS 876 : "+&c" (counter), "+&D" (dest) 877 : "a" (value) 878 : "memory", "cc"); 879#else 880 for (int i = 0; i < counter; i++) { 881 dest[i] = value; 882 } 883#endif 884 885#undef STOS 886} 887 888 889// Copies data from |src| to |dst|. The data spans MUST not overlap. 890inline void CopyWords(Object** dst, Object** src, int num_words) { 891 ASSERT(Min(dst, src) + num_words <= Max(dst, src)); 892 ASSERT(num_words > 0); 893 894 // Use block copying memcpy if the segment we're copying is 895 // enough to justify the extra call/setup overhead. 896 static const int kBlockCopyLimit = 16; 897 898 if (num_words >= kBlockCopyLimit) { 899 memcpy(dst, src, num_words * kPointerSize); 900 } else { 901 int remaining = num_words; 902 do { 903 remaining--; 904 *dst++ = *src++; 905 } while (remaining > 0); 906 } 907} 908 909 910// Calculate 10^exponent. 911int TenToThe(int exponent); 912 913 914// The type-based aliasing rule allows the compiler to assume that pointers of 915// different types (for some definition of different) never alias each other. 916// Thus the following code does not work: 917// 918// float f = foo(); 919// int fbits = *(int*)(&f); 920// 921// The compiler 'knows' that the int pointer can't refer to f since the types 922// don't match, so the compiler may cache f in a register, leaving random data 923// in fbits. Using C++ style casts makes no difference, however a pointer to 924// char data is assumed to alias any other pointer. This is the 'memcpy 925// exception'. 926// 927// Bit_cast uses the memcpy exception to move the bits from a variable of one 928// type of a variable of another type. Of course the end result is likely to 929// be implementation dependent. Most compilers (gcc-4.2 and MSVC 2005) 930// will completely optimize BitCast away. 931// 932// There is an additional use for BitCast. 933// Recent gccs will warn when they see casts that may result in breakage due to 934// the type-based aliasing rule. If you have checked that there is no breakage 935// you can use BitCast to cast one pointer type to another. This confuses gcc 936// enough that it can no longer see that you have cast one pointer type to 937// another thus avoiding the warning. 938template <class Dest, class Source> 939inline Dest BitCast(const Source& source) { 940 // Compile time assertion: sizeof(Dest) == sizeof(Source) 941 // A compile error here means your Dest and Source have different sizes. 942 typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1]; 943 944 Dest dest; 945 memcpy(&dest, &source, sizeof(dest)); 946 return dest; 947} 948 949template <class Dest, class Source> 950inline Dest BitCast(Source* source) { 951 return BitCast<Dest>(reinterpret_cast<uintptr_t>(source)); 952} 953 954} } // namespace v8::internal 955 956#endif // V8_UTILS_H_ 957