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