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