blob: ed6d9a4fee1c7e6158ec88fe8d607825cb609c79 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// 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>
Steve Block6ded16b2010-05-10 14:33:55 +010032#include <string.h>
Steve Blocka7e24c12009-10-30 11:49:00 +000033
34namespace v8 {
35namespace internal {
36
37// ----------------------------------------------------------------------------
38// General helper functions
39
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010040#define IS_POWER_OF_TWO(x) (((x) & ((x) - 1)) == 0)
41
Steve Block3ce2e202009-11-05 08:53:23 +000042// 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).
Steve Blocka7e24c12009-10-30 11:49:00 +000044template <typename T>
45static inline bool IsPowerOf2(T x) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010046 return IS_POWER_OF_TWO(x);
Steve Blocka7e24c12009-10-30 11:49:00 +000047}
48
49
50// The C++ standard leaves the semantics of '>>' undefined for
51// negative signed operands. Most implementations do the right thing,
52// though.
53static inline int ArithmeticShiftRight(int x, int s) {
54 return x >> s;
55}
56
57
58// Compute the 0-relative offset of some absolute value x of type T.
59// This allows conversion of Addresses and integral types into
60// 0-relative int offsets.
61template <typename T>
62static inline intptr_t OffsetFrom(T x) {
63 return x - static_cast<T>(0);
64}
65
66
67// Compute the absolute value of type T for some 0-relative offset x.
68// This allows conversion of 0-relative int offsets into Addresses and
69// integral types.
70template <typename T>
71static inline T AddressFrom(intptr_t x) {
Steve Blockd0582a62009-12-15 09:54:21 +000072 return static_cast<T>(static_cast<T>(0) + x);
Steve Blocka7e24c12009-10-30 11:49:00 +000073}
74
75
76// Return the largest multiple of m which is <= x.
77template <typename T>
78static inline T RoundDown(T x, int m) {
79 ASSERT(IsPowerOf2(m));
80 return AddressFrom<T>(OffsetFrom(x) & -m);
81}
82
83
84// Return the smallest multiple of m which is >= x.
85template <typename T>
86static inline T RoundUp(T x, int m) {
87 return RoundDown(x + m - 1, m);
88}
89
90
91template <typename T>
92static int Compare(const T& a, const T& b) {
93 if (a == b)
94 return 0;
95 else if (a < b)
96 return -1;
97 else
98 return 1;
99}
100
101
102template <typename T>
103static int PointerValueCompare(const T* a, const T* b) {
104 return Compare<T>(*a, *b);
105}
106
107
108// Returns the smallest power of two which is >= x. If you pass in a
109// number that is already a power of two, it is returned as is.
110uint32_t RoundUpToPowerOf2(uint32_t x);
111
112
113template <typename T>
114static inline bool IsAligned(T value, T alignment) {
115 ASSERT(IsPowerOf2(alignment));
116 return (value & (alignment - 1)) == 0;
117}
118
119
120// Returns true if (addr + offset) is aligned.
121static inline bool IsAddressAligned(Address addr,
122 intptr_t alignment,
123 int offset) {
124 intptr_t offs = OffsetFrom(addr + offset);
125 return IsAligned(offs, alignment);
126}
127
128
129// Returns the maximum of the two parameters.
130template <typename T>
131static T Max(T a, T b) {
132 return a < b ? b : a;
133}
134
135
136// Returns the minimum of the two parameters.
137template <typename T>
138static T Min(T a, T b) {
139 return a < b ? a : b;
140}
141
142
Steve Blockd0582a62009-12-15 09:54:21 +0000143inline int StrLength(const char* string) {
144 size_t length = strlen(string);
145 ASSERT(length == static_cast<size_t>(static_cast<int>(length)));
146 return static_cast<int>(length);
147}
148
149
Steve Blocka7e24c12009-10-30 11:49:00 +0000150// ----------------------------------------------------------------------------
151// BitField is a help template for encoding and decode bitfield with
152// unsigned content.
153template<class T, int shift, int size>
154class BitField {
155 public:
156 // Tells whether the provided value fits into the bit field.
157 static bool is_valid(T value) {
158 return (static_cast<uint32_t>(value) & ~((1U << (size)) - 1)) == 0;
159 }
160
161 // Returns a uint32_t mask of bit field.
162 static uint32_t mask() {
Andrei Popescu402d9372010-02-26 13:31:12 +0000163 // To use all bits of a uint32 in a bitfield without compiler warnings we
164 // have to compute 2^32 without using a shift count of 32.
165 return ((1U << shift) << size) - (1U << shift);
Steve Blocka7e24c12009-10-30 11:49:00 +0000166 }
167
168 // Returns a uint32_t with the bit field value encoded.
169 static uint32_t encode(T value) {
170 ASSERT(is_valid(value));
171 return static_cast<uint32_t>(value) << shift;
172 }
173
174 // Extracts the bit field from the value.
175 static T decode(uint32_t value) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000176 return static_cast<T>((value & mask()) >> shift);
Steve Blocka7e24c12009-10-30 11:49:00 +0000177 }
178};
179
180
181// ----------------------------------------------------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +0000182// Hash function.
183
184uint32_t ComputeIntegerHash(uint32_t key);
185
186
187// ----------------------------------------------------------------------------
188// I/O support.
189
190// Our version of printf(). Avoids compilation errors that we get
191// with standard printf when attempting to print pointers, etc.
192// (the errors are due to the extra compilation flags, which we
193// want elsewhere).
194void PrintF(const char* format, ...);
195
196// Our version of fflush.
197void Flush();
198
199
200// Read a line of characters after printing the prompt to stdout. The resulting
201// char* needs to be disposed off with DeleteArray by the caller.
202char* ReadLine(const char* prompt);
203
204
205// Read and return the raw bytes in a file. the size of the buffer is returned
206// in size.
207// The returned buffer must be freed by the caller.
208byte* ReadBytes(const char* filename, int* size, bool verbose = true);
209
210
211// Write size chars from str to the file given by filename.
212// The file is overwritten. Returns the number of chars written.
213int WriteChars(const char* filename,
214 const char* str,
215 int size,
216 bool verbose = true);
217
218
219// Write size bytes to the file given by filename.
220// The file is overwritten. Returns the number of bytes written.
221int WriteBytes(const char* filename,
222 const byte* bytes,
223 int size,
224 bool verbose = true);
225
226
227// Write the C code
228// const char* <varname> = "<str>";
229// const int <varname>_len = <len>;
230// to the file given by filename. Only the first len chars are written.
231int WriteAsCFile(const char* filename, const char* varname,
232 const char* str, int size, bool verbose = true);
233
234
235// ----------------------------------------------------------------------------
236// Miscellaneous
237
238// A static resource holds a static instance that can be reserved in
239// a local scope using an instance of Access. Attempts to re-reserve
240// the instance will cause an error.
241template <typename T>
242class StaticResource {
243 public:
244 StaticResource() : is_reserved_(false) {}
245
246 private:
247 template <typename S> friend class Access;
248 T instance_;
249 bool is_reserved_;
250};
251
252
253// Locally scoped access to a static resource.
254template <typename T>
255class Access {
256 public:
257 explicit Access(StaticResource<T>* resource)
258 : resource_(resource)
259 , instance_(&resource->instance_) {
260 ASSERT(!resource->is_reserved_);
261 resource->is_reserved_ = true;
262 }
263
264 ~Access() {
265 resource_->is_reserved_ = false;
266 resource_ = NULL;
267 instance_ = NULL;
268 }
269
270 T* value() { return instance_; }
271 T* operator -> () { return instance_; }
272
273 private:
274 StaticResource<T>* resource_;
275 T* instance_;
276};
277
278
279template <typename T>
280class Vector {
281 public:
282 Vector() : start_(NULL), length_(0) {}
283 Vector(T* data, int length) : start_(data), length_(length) {
284 ASSERT(length == 0 || (length > 0 && data != NULL));
285 }
286
287 static Vector<T> New(int length) {
288 return Vector<T>(NewArray<T>(length), length);
289 }
290
291 // Returns a vector using the same backing storage as this one,
292 // spanning from and including 'from', to but not including 'to'.
293 Vector<T> SubVector(int from, int to) {
294 ASSERT(from < length_);
295 ASSERT(to <= length_);
296 ASSERT(from < to);
297 return Vector<T>(start() + from, to - from);
298 }
299
300 // Returns the length of the vector.
301 int length() const { return length_; }
302
303 // Returns whether or not the vector is empty.
304 bool is_empty() const { return length_ == 0; }
305
306 // Returns the pointer to the start of the data in the vector.
307 T* start() const { return start_; }
308
309 // Access individual vector elements - checks bounds in debug mode.
310 T& operator[](int index) const {
311 ASSERT(0 <= index && index < length_);
312 return start_[index];
313 }
314
315 T& first() { return start_[0]; }
316
317 T& last() { return start_[length_ - 1]; }
318
319 // Returns a clone of this vector with a new backing store.
320 Vector<T> Clone() const {
321 T* result = NewArray<T>(length_);
322 for (int i = 0; i < length_; i++) result[i] = start_[i];
323 return Vector<T>(result, length_);
324 }
325
326 void Sort(int (*cmp)(const T*, const T*)) {
327 typedef int (*RawComparer)(const void*, const void*);
328 qsort(start(),
329 length(),
330 sizeof(T),
331 reinterpret_cast<RawComparer>(cmp));
332 }
333
334 void Sort() {
335 Sort(PointerValueCompare<T>);
336 }
337
338 void Truncate(int length) {
339 ASSERT(length <= length_);
340 length_ = length;
341 }
342
343 // Releases the array underlying this vector. Once disposed the
344 // vector is empty.
345 void Dispose() {
Steve Blocka7e24c12009-10-30 11:49:00 +0000346 DeleteArray(start_);
347 start_ = NULL;
348 length_ = 0;
349 }
350
351 inline Vector<T> operator+(int offset) {
352 ASSERT(offset < length_);
353 return Vector<T>(start_ + offset, length_ - offset);
354 }
355
356 // Factory method for creating empty vectors.
357 static Vector<T> empty() { return Vector<T>(NULL, 0); }
358
359 protected:
360 void set_start(T* start) { start_ = start; }
361
362 private:
363 T* start_;
364 int length_;
365};
366
367
368// A temporary assignment sets a (non-local) variable to a value on
369// construction and resets it the value on destruction.
370template <typename T>
371class TempAssign {
372 public:
373 TempAssign(T* var, T value): var_(var), old_value_(*var) {
374 *var = value;
375 }
376
377 ~TempAssign() { *var_ = old_value_; }
378
379 private:
380 T* var_;
381 T old_value_;
382};
383
384
385template <typename T, int kSize>
386class EmbeddedVector : public Vector<T> {
387 public:
388 EmbeddedVector() : Vector<T>(buffer_, kSize) { }
389
390 // When copying, make underlying Vector to reference our buffer.
391 EmbeddedVector(const EmbeddedVector& rhs)
392 : Vector<T>(rhs) {
393 memcpy(buffer_, rhs.buffer_, sizeof(T) * kSize);
394 set_start(buffer_);
395 }
396
397 EmbeddedVector& operator=(const EmbeddedVector& rhs) {
398 if (this == &rhs) return *this;
399 Vector<T>::operator=(rhs);
400 memcpy(buffer_, rhs.buffer_, sizeof(T) * kSize);
Steve Block6ded16b2010-05-10 14:33:55 +0100401 this->set_start(buffer_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000402 return *this;
403 }
404
405 private:
406 T buffer_[kSize];
407};
408
409
410template <typename T>
411class ScopedVector : public Vector<T> {
412 public:
413 explicit ScopedVector(int length) : Vector<T>(NewArray<T>(length), length) { }
414 ~ScopedVector() {
415 DeleteArray(this->start());
416 }
Kristian Monsen25f61362010-05-21 11:50:48 +0100417
418 private:
419 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedVector);
Steve Blocka7e24c12009-10-30 11:49:00 +0000420};
421
422
423inline Vector<const char> CStrVector(const char* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000424 return Vector<const char>(data, StrLength(data));
Steve Blocka7e24c12009-10-30 11:49:00 +0000425}
426
427inline Vector<char> MutableCStrVector(char* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000428 return Vector<char>(data, StrLength(data));
Steve Blocka7e24c12009-10-30 11:49:00 +0000429}
430
431inline Vector<char> MutableCStrVector(char* data, int max) {
Steve Blockd0582a62009-12-15 09:54:21 +0000432 int length = StrLength(data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000433 return Vector<char>(data, (length < max) ? length : max);
434}
435
436template <typename T>
437inline Vector< Handle<Object> > HandleVector(v8::internal::Handle<T>* elms,
438 int length) {
439 return Vector< Handle<Object> >(
440 reinterpret_cast<v8::internal::Handle<Object>*>(elms), length);
441}
442
443
444// Simple support to read a file into a 0-terminated C-string.
445// The returned buffer must be freed by the caller.
446// On return, *exits tells whether the file existed.
447Vector<const char> ReadFile(const char* filename,
448 bool* exists,
449 bool verbose = true);
450
451
452// Simple wrapper that allows an ExternalString to refer to a
453// Vector<const char>. Doesn't assume ownership of the data.
454class AsciiStringAdapter: public v8::String::ExternalAsciiStringResource {
455 public:
456 explicit AsciiStringAdapter(Vector<const char> data) : data_(data) {}
457
458 virtual const char* data() const { return data_.start(); }
459
460 virtual size_t length() const { return data_.length(); }
461
462 private:
463 Vector<const char> data_;
464};
465
466
467// Helper class for building result strings in a character buffer. The
468// purpose of the class is to use safe operations that checks the
469// buffer bounds on all operations in debug mode.
470class StringBuilder {
471 public:
472 // Create a string builder with a buffer of the given size. The
473 // buffer is allocated through NewArray<char> and must be
474 // deallocated by the caller of Finalize().
475 explicit StringBuilder(int size);
476
477 StringBuilder(char* buffer, int size)
478 : buffer_(buffer, size), position_(0) { }
479
480 ~StringBuilder() { if (!is_finalized()) Finalize(); }
481
482 int size() const { return buffer_.length(); }
483
484 // Get the current position in the builder.
485 int position() const {
486 ASSERT(!is_finalized());
487 return position_;
488 }
489
490 // Reset the position.
491 void Reset() { position_ = 0; }
492
493 // Add a single character to the builder. It is not allowed to add
494 // 0-characters; use the Finalize() method to terminate the string
495 // instead.
496 void AddCharacter(char c) {
497 ASSERT(c != '\0');
498 ASSERT(!is_finalized() && position_ < buffer_.length());
499 buffer_[position_++] = c;
500 }
501
502 // Add an entire string to the builder. Uses strlen() internally to
503 // compute the length of the input string.
504 void AddString(const char* s);
505
506 // Add the first 'n' characters of the given string 's' to the
507 // builder. The input string must have enough characters.
508 void AddSubstring(const char* s, int n);
509
510 // Add formatted contents to the builder just like printf().
511 void AddFormatted(const char* format, ...);
512
513 // Add character padding to the builder. If count is non-positive,
514 // nothing is added to the builder.
515 void AddPadding(char c, int count);
516
517 // Finalize the string by 0-terminating it and returning the buffer.
518 char* Finalize();
519
520 private:
521 Vector<char> buffer_;
522 int position_;
523
524 bool is_finalized() const { return position_ < 0; }
525
526 DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder);
527};
528
529
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100530// Custom memcpy implementation for platforms where the standard version
531// may not be good enough.
532// TODO(lrn): Check whether some IA32 platforms should be excluded.
533#if defined(V8_TARGET_ARCH_IA32)
534
535// TODO(lrn): Extend to other platforms as needed.
536
537typedef void (*MemCopyFunction)(void* dest, const void* src, size_t size);
538
539// Implemented in codegen-<arch>.cc.
540MemCopyFunction CreateMemCopyFunction();
541
542// Copy memory area to disjoint memory area.
543static inline void MemCopy(void* dest, const void* src, size_t size) {
544 static MemCopyFunction memcopy = CreateMemCopyFunction();
545 (*memcopy)(dest, src, size);
546#ifdef DEBUG
547 CHECK_EQ(0, memcmp(dest, src, size));
548#endif
549}
550
551
552// Limit below which the extra overhead of the MemCopy function is likely
553// to outweigh the benefits of faster copying.
554// TODO(lrn): Try to find a more precise value.
555static const int kMinComplexMemCopy = 256;
556
557#else // V8_TARGET_ARCH_IA32
558
559static inline void MemCopy(void* dest, const void* src, size_t size) {
560 memcpy(dest, src, size);
561}
562
563static const int kMinComplexMemCopy = 256;
564
565#endif // V8_TARGET_ARCH_IA32
566
567
Steve Blocka7e24c12009-10-30 11:49:00 +0000568// Copy from ASCII/16bit chars to ASCII/16bit chars.
569template <typename sourcechar, typename sinkchar>
570static inline void CopyChars(sinkchar* dest, const sourcechar* src, int chars) {
571 sinkchar* limit = dest + chars;
572#ifdef V8_HOST_CAN_READ_UNALIGNED
573 if (sizeof(*dest) == sizeof(*src)) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100574 if (chars >= static_cast<int>(kMinComplexMemCopy / sizeof(*dest))) {
575 MemCopy(dest, src, chars * sizeof(*dest));
576 return;
577 }
Steve Block6ded16b2010-05-10 14:33:55 +0100578 // Number of characters in a uintptr_t.
579 static const int kStepSize = sizeof(uintptr_t) / sizeof(*dest); // NOLINT
Steve Blocka7e24c12009-10-30 11:49:00 +0000580 while (dest <= limit - kStepSize) {
Steve Block6ded16b2010-05-10 14:33:55 +0100581 *reinterpret_cast<uintptr_t*>(dest) =
582 *reinterpret_cast<const uintptr_t*>(src);
Steve Blocka7e24c12009-10-30 11:49:00 +0000583 dest += kStepSize;
584 src += kStepSize;
585 }
586 }
587#endif
588 while (dest < limit) {
589 *dest++ = static_cast<sinkchar>(*src++);
590 }
591}
592
593
Steve Block6ded16b2010-05-10 14:33:55 +0100594// Compare ASCII/16bit chars to ASCII/16bit chars.
595template <typename lchar, typename rchar>
596static inline int CompareChars(const lchar* lhs, const rchar* rhs, int chars) {
597 const lchar* limit = lhs + chars;
598#ifdef V8_HOST_CAN_READ_UNALIGNED
599 if (sizeof(*lhs) == sizeof(*rhs)) {
600 // Number of characters in a uintptr_t.
601 static const int kStepSize = sizeof(uintptr_t) / sizeof(*lhs); // NOLINT
602 while (lhs <= limit - kStepSize) {
603 if (*reinterpret_cast<const uintptr_t*>(lhs) !=
604 *reinterpret_cast<const uintptr_t*>(rhs)) {
605 break;
606 }
607 lhs += kStepSize;
608 rhs += kStepSize;
609 }
610 }
611#endif
612 while (lhs < limit) {
613 int r = static_cast<int>(*lhs) - static_cast<int>(*rhs);
614 if (r != 0) return r;
615 ++lhs;
616 ++rhs;
617 }
618 return 0;
619}
620
621
622template <typename T>
623static inline void MemsetPointer(T** dest, T* value, int counter) {
624#if defined(V8_HOST_ARCH_IA32)
625#define STOS "stosl"
626#elif defined(V8_HOST_ARCH_X64)
627#define STOS "stosq"
628#endif
629
630#if defined(__GNUC__) && defined(STOS)
631 asm volatile(
632 "cld;"
633 "rep ; " STOS
634 : "+&c" (counter), "+&D" (dest)
635 : "a" (value)
636 : "memory", "cc");
637#else
638 for (int i = 0; i < counter; i++) {
639 dest[i] = value;
640 }
641#endif
642
643#undef STOS
644}
645
646
647// Copies data from |src| to |dst|. The data spans MUST not overlap.
648inline void CopyWords(Object** dst, Object** src, int num_words) {
649 ASSERT(Min(dst, src) + num_words <= Max(dst, src));
650 ASSERT(num_words > 0);
651
652 // Use block copying memcpy if the segment we're copying is
653 // enough to justify the extra call/setup overhead.
654 static const int kBlockCopyLimit = 16;
655
656 if (num_words >= kBlockCopyLimit) {
657 memcpy(dst, src, num_words * kPointerSize);
658 } else {
659 int remaining = num_words;
660 do {
661 remaining--;
662 *dst++ = *src++;
663 } while (remaining > 0);
664 }
665}
666
667
Steve Blockd0582a62009-12-15 09:54:21 +0000668// Calculate 10^exponent.
669int TenToThe(int exponent);
670
Steve Block6ded16b2010-05-10 14:33:55 +0100671
672// The type-based aliasing rule allows the compiler to assume that pointers of
673// different types (for some definition of different) never alias each other.
674// Thus the following code does not work:
675//
676// float f = foo();
677// int fbits = *(int*)(&f);
678//
679// The compiler 'knows' that the int pointer can't refer to f since the types
680// don't match, so the compiler may cache f in a register, leaving random data
681// in fbits. Using C++ style casts makes no difference, however a pointer to
682// char data is assumed to alias any other pointer. This is the 'memcpy
683// exception'.
684//
685// Bit_cast uses the memcpy exception to move the bits from a variable of one
686// type of a variable of another type. Of course the end result is likely to
687// be implementation dependent. Most compilers (gcc-4.2 and MSVC 2005)
688// will completely optimize BitCast away.
689//
690// There is an additional use for BitCast.
691// Recent gccs will warn when they see casts that may result in breakage due to
692// the type-based aliasing rule. If you have checked that there is no breakage
693// you can use BitCast to cast one pointer type to another. This confuses gcc
694// enough that it can no longer see that you have cast one pointer type to
695// another thus avoiding the warning.
696template <class Dest, class Source>
697inline Dest BitCast(const Source& source) {
698 // Compile time assertion: sizeof(Dest) == sizeof(Source)
699 // A compile error here means your Dest and Source have different sizes.
700 typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1];
701
702 Dest dest;
703 memcpy(&dest, &source, sizeof(dest));
704 return dest;
705}
706
Steve Blocka7e24c12009-10-30 11:49:00 +0000707} } // namespace v8::internal
708
Steve Block6ded16b2010-05-10 14:33:55 +0100709
Steve Blocka7e24c12009-10-30 11:49:00 +0000710#endif // V8_UTILS_H_