• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_UTILS_H_
6 #define V8_UTILS_UTILS_H_
7 
8 #include <limits.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <cmath>
12 #include <string>
13 #include <type_traits>
14 
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/base/v8-fallthrough.h"
21 #include "src/common/globals.h"
22 #include "src/utils/allocation.h"
23 #include "src/utils/vector.h"
24 
25 #if defined(V8_USE_SIPHASH)
26 #include "src/third_party/siphash/halfsiphash.h"
27 #endif
28 
29 #if defined(V8_OS_AIX)
30 #include <fenv.h>  // NOLINT(build/c++11)
31 #endif
32 
33 namespace v8 {
34 namespace internal {
35 
36 // ----------------------------------------------------------------------------
37 // General helper functions
38 
39 // Returns the value (0 .. 15) of a hexadecimal character c.
40 // If c is not a legal hexadecimal character, returns a value < 0.
HexValue(uc32 c)41 inline int HexValue(uc32 c) {
42   c -= '0';
43   if (static_cast<unsigned>(c) <= 9) return c;
44   c = (c | 0x20) - ('a' - '0');  // detect 0x11..0x16 and 0x31..0x36.
45   if (static_cast<unsigned>(c) <= 5) return c + 10;
46   return -1;
47 }
48 
HexCharOfValue(int value)49 inline char HexCharOfValue(int value) {
50   DCHECK(0 <= value && value <= 16);
51   if (value < 10) return value + '0';
52   return value - 10 + 'A';
53 }
54 
55 template <typename T>
ArithmeticShiftRight(T x,int shift)56 static T ArithmeticShiftRight(T x, int shift) {
57   DCHECK_LE(0, shift);
58   if (x < 0) {
59     // Right shift of signed values is implementation defined. Simulate a
60     // true arithmetic right shift by adding leading sign bits.
61     using UnsignedT = typename std::make_unsigned<T>::type;
62     UnsignedT mask = ~(static_cast<UnsignedT>(~0) >> shift);
63     return (static_cast<UnsignedT>(x) >> shift) | mask;
64   } else {
65     return x >> shift;
66   }
67 }
68 
69 // Returns the maximum of the two parameters.
70 template <typename T>
Max(T a,T b)71 constexpr T Max(T a, T b) {
72   return std::max(a, b);
73 }
74 
75 // Returns the minimum of the two parameters.
76 template <typename T>
Min(T a,T b)77 constexpr T Min(T a, T b) {
78   return std::min(a, b);
79 }
80 
81 // Returns the maximum of the two parameters according to JavaScript semantics.
82 template <typename T>
JSMax(T x,T y)83 T JSMax(T x, T y) {
84   if (std::isnan(x)) return x;
85   if (std::isnan(y)) return y;
86   if (std::signbit(x) < std::signbit(y)) return x;
87   return x > y ? x : y;
88 }
89 
90 // Returns the maximum of the two parameters according to JavaScript semantics.
91 template <typename T>
JSMin(T x,T y)92 T JSMin(T x, T y) {
93   if (std::isnan(x)) return x;
94   if (std::isnan(y)) return y;
95   if (std::signbit(x) < std::signbit(y)) return y;
96   return x > y ? y : x;
97 }
98 
99 // Returns the absolute value of its argument.
100 template <typename T,
101           typename = typename std::enable_if<std::is_signed<T>::value>::type>
Abs(T a)102 typename std::make_unsigned<T>::type Abs(T a) {
103   // This is a branch-free implementation of the absolute value function and is
104   // described in Warren's "Hacker's Delight", chapter 2. It avoids undefined
105   // behavior with the arithmetic negation operation on signed values as well.
106   using unsignedT = typename std::make_unsigned<T>::type;
107   unsignedT x = static_cast<unsignedT>(a);
108   unsignedT y = static_cast<unsignedT>(a >> (sizeof(T) * 8 - 1));
109   return (x ^ y) - y;
110 }
111 
Modulo(double x,double y)112 inline double Modulo(double x, double y) {
113 #if defined(V8_OS_WIN)
114   // Workaround MS fmod bugs. ECMA-262 says:
115   // dividend is finite and divisor is an infinity => result equals dividend
116   // dividend is a zero and divisor is nonzero finite => result equals dividend
117   if (!(std::isfinite(x) && (!std::isfinite(y) && !std::isnan(y))) &&
118       !(x == 0 && (y != 0 && std::isfinite(y)))) {
119     double result = fmod(x, y);
120     // Workaround MS bug in VS CRT in some OS versions, https://crbug.com/915045
121     // fmod(-17, +/-1) should equal -0.0 but now returns 0.0.
122     if (x < 0 && result == 0) result = -0.0;
123     x = result;
124   }
125   return x;
126 #elif defined(V8_OS_AIX)
127   // AIX raises an underflow exception for (Number.MIN_VALUE % Number.MAX_VALUE)
128   feclearexcept(FE_ALL_EXCEPT);
129   double result = std::fmod(x, y);
130   int exception = fetestexcept(FE_UNDERFLOW);
131   return (exception ? x : result);
132 #else
133   return std::fmod(x, y);
134 #endif
135 }
136 
137 template <typename T>
Saturate(int64_t value)138 T Saturate(int64_t value) {
139   static_assert(sizeof(int64_t) > sizeof(T), "T must be int32_t or smaller");
140   int64_t min = static_cast<int64_t>(std::numeric_limits<T>::min());
141   int64_t max = static_cast<int64_t>(std::numeric_limits<T>::max());
142   int64_t clamped = std::max(min, std::min(max, value));
143   return static_cast<T>(clamped);
144 }
145 
146 template <typename T>
SaturateAdd(T a,T b)147 T SaturateAdd(T a, T b) {
148   if (std::is_signed<T>::value) {
149     if (a > 0 && b > 0) {
150       if (a > std::numeric_limits<T>::max() - b) {
151         return std::numeric_limits<T>::max();
152       }
153     } else if (a < 0 && b < 0) {
154       if (a < std::numeric_limits<T>::min() - b) {
155         return std::numeric_limits<T>::min();
156       }
157     }
158   } else {
159     CHECK(std::is_unsigned<T>::value);
160     if (a > std::numeric_limits<T>::max() - b) {
161       return std::numeric_limits<T>::max();
162     }
163   }
164   return a + b;
165 }
166 
167 template <typename T>
SaturateSub(T a,T b)168 T SaturateSub(T a, T b) {
169   if (std::is_signed<T>::value) {
170     if (a >= 0 && b < 0) {
171       if (a > std::numeric_limits<T>::max() + b) {
172         return std::numeric_limits<T>::max();
173       }
174     } else if (a < 0 && b > 0) {
175       if (a < std::numeric_limits<T>::min() + b) {
176         return std::numeric_limits<T>::min();
177       }
178     }
179   } else {
180     CHECK(std::is_unsigned<T>::value);
181     if (a < b) {
182       return static_cast<T>(0);
183     }
184   }
185   return a - b;
186 }
187 
188 template <typename T>
SaturateRoundingQMul(T a,T b)189 T SaturateRoundingQMul(T a, T b) {
190   // Saturating rounding multiplication for Q-format numbers. See
191   // https://en.wikipedia.org/wiki/Q_(number_format) for a description.
192   // Specifically this supports Q7, Q15, and Q31. This follows the
193   // implementation in simulator-logic-arm64.cc (sqrdmulh) to avoid overflow
194   // when a == b == int32 min.
195   static_assert(std::is_integral<T>::value, "only integral types");
196 
197   constexpr int size_in_bits = sizeof(T) * 8;
198   int round_const = 1 << (size_in_bits - 2);
199   int64_t product = a * b;
200   product += round_const;
201   product >>= (size_in_bits - 1);
202   return Saturate<T>(product);
203 }
204 
205 // Multiply two numbers, returning a result that is twice as wide, no overflow.
206 // Put Wide first so we can use function template argument deduction for Narrow,
207 // and callers can provide only Wide.
208 template <typename Wide, typename Narrow>
MultiplyLong(Narrow a,Narrow b)209 Wide MultiplyLong(Narrow a, Narrow b) {
210   static_assert(
211       std::is_integral<Narrow>::value && std::is_integral<Wide>::value,
212       "only integral types");
213   static_assert(std::is_signed<Narrow>::value == std::is_signed<Wide>::value,
214                 "both must have same signedness");
215   static_assert(sizeof(Narrow) * 2 == sizeof(Wide), "only twice as long");
216 
217   return static_cast<Wide>(a) * static_cast<Wide>(b);
218 }
219 
220 // Add two numbers, returning a result that is twice as wide, no overflow.
221 // Put Wide first so we can use function template argument deduction for Narrow,
222 // and callers can provide only Wide.
223 template <typename Wide, typename Narrow>
AddLong(Narrow a,Narrow b)224 Wide AddLong(Narrow a, Narrow b) {
225   static_assert(
226       std::is_integral<Narrow>::value && std::is_integral<Wide>::value,
227       "only integral types");
228   static_assert(std::is_signed<Narrow>::value == std::is_signed<Wide>::value,
229                 "both must have same signedness");
230   static_assert(sizeof(Narrow) * 2 == sizeof(Wide), "only twice as long");
231 
232   return static_cast<Wide>(a) + static_cast<Wide>(b);
233 }
234 
235 // Helper macros for defining a contiguous sequence of field offset constants.
236 // Example: (backslashes at the ends of respective lines of this multi-line
237 // macro definition are omitted here to please the compiler)
238 //
239 // #define MAP_FIELDS(V)
240 //   V(kField1Offset, kTaggedSize)
241 //   V(kField2Offset, kIntSize)
242 //   V(kField3Offset, kIntSize)
243 //   V(kField4Offset, kSystemPointerSize)
244 //   V(kSize, 0)
245 //
246 // DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, MAP_FIELDS)
247 //
248 #define DEFINE_ONE_FIELD_OFFSET(Name, Size) Name, Name##End = Name + (Size)-1,
249 
250 #define DEFINE_FIELD_OFFSET_CONSTANTS(StartOffset, LIST_MACRO) \
251   enum {                                                       \
252     LIST_MACRO##_StartOffset = StartOffset - 1,                \
253     LIST_MACRO(DEFINE_ONE_FIELD_OFFSET)                        \
254   };
255 
256 // Size of the field defined by DEFINE_FIELD_OFFSET_CONSTANTS
257 #define FIELD_SIZE(Name) (Name##End + 1 - Name)
258 
259 // Compare two offsets with static cast
260 #define STATIC_ASSERT_FIELD_OFFSETS_EQUAL(Offset1, Offset2) \
261   STATIC_ASSERT(static_cast<int>(Offset1) == Offset2)
262 // ----------------------------------------------------------------------------
263 // Hash function.
264 
265 static const uint64_t kZeroHashSeed = 0;
266 
267 // Thomas Wang, Integer Hash Functions.
268 // http://www.concentric.net/~Ttwang/tech/inthash.htm`
ComputeUnseededHash(uint32_t key)269 inline uint32_t ComputeUnseededHash(uint32_t key) {
270   uint32_t hash = key;
271   hash = ~hash + (hash << 15);  // hash = (hash << 15) - hash - 1;
272   hash = hash ^ (hash >> 12);
273   hash = hash + (hash << 2);
274   hash = hash ^ (hash >> 4);
275   hash = hash * 2057;  // hash = (hash + (hash << 3)) + (hash << 11);
276   hash = hash ^ (hash >> 16);
277   return hash & 0x3fffffff;
278 }
279 
ComputeLongHash(uint64_t key)280 inline uint32_t ComputeLongHash(uint64_t key) {
281   uint64_t hash = key;
282   hash = ~hash + (hash << 18);  // hash = (hash << 18) - hash - 1;
283   hash = hash ^ (hash >> 31);
284   hash = hash * 21;  // hash = (hash + (hash << 2)) + (hash << 4);
285   hash = hash ^ (hash >> 11);
286   hash = hash + (hash << 6);
287   hash = hash ^ (hash >> 22);
288   return static_cast<uint32_t>(hash & 0x3fffffff);
289 }
290 
ComputeSeededHash(uint32_t key,uint64_t seed)291 inline uint32_t ComputeSeededHash(uint32_t key, uint64_t seed) {
292 #ifdef V8_USE_SIPHASH
293   return halfsiphash(key, seed);
294 #else
295   return ComputeLongHash(static_cast<uint64_t>(key) ^ seed);
296 #endif  // V8_USE_SIPHASH
297 }
298 
ComputePointerHash(void * ptr)299 inline uint32_t ComputePointerHash(void* ptr) {
300   return ComputeUnseededHash(
301       static_cast<uint32_t>(reinterpret_cast<intptr_t>(ptr)));
302 }
303 
ComputeAddressHash(Address address)304 inline uint32_t ComputeAddressHash(Address address) {
305   return ComputeUnseededHash(static_cast<uint32_t>(address & 0xFFFFFFFFul));
306 }
307 
308 // ----------------------------------------------------------------------------
309 // Miscellaneous
310 
311 // Memory offset for lower and higher bits in a 64 bit integer.
312 #if defined(V8_TARGET_LITTLE_ENDIAN)
313 static const int kInt64LowerHalfMemoryOffset = 0;
314 static const int kInt64UpperHalfMemoryOffset = 4;
315 #elif defined(V8_TARGET_BIG_ENDIAN)
316 static const int kInt64LowerHalfMemoryOffset = 4;
317 static const int kInt64UpperHalfMemoryOffset = 0;
318 #endif  // V8_TARGET_LITTLE_ENDIAN
319 
320 // A pointer that can only be set once and doesn't allow NULL values.
321 template <typename T>
322 class SetOncePointer {
323  public:
324   SetOncePointer() = default;
325 
is_set()326   bool is_set() const { return pointer_ != nullptr; }
327 
get()328   T* get() const {
329     DCHECK_NOT_NULL(pointer_);
330     return pointer_;
331   }
332 
set(T * value)333   void set(T* value) {
334     DCHECK(pointer_ == nullptr && value != nullptr);
335     pointer_ = value;
336   }
337 
338   SetOncePointer& operator=(T* value) {
339     set(value);
340     return *this;
341   }
342 
343   bool operator==(std::nullptr_t) const { return pointer_ == nullptr; }
344   bool operator!=(std::nullptr_t) const { return pointer_ != nullptr; }
345 
346  private:
347   T* pointer_ = nullptr;
348 };
349 
350 // Compare 8bit/16bit chars to 8bit/16bit chars.
351 template <typename lchar, typename rchar>
CompareCharsUnsigned(const lchar * lhs,const rchar * rhs,size_t chars)352 inline int CompareCharsUnsigned(const lchar* lhs, const rchar* rhs,
353                                 size_t chars) {
354   const lchar* limit = lhs + chars;
355   if (sizeof(*lhs) == sizeof(char) && sizeof(*rhs) == sizeof(char)) {
356     // memcmp compares byte-by-byte, yielding wrong results for two-byte
357     // strings on little-endian systems.
358     return memcmp(lhs, rhs, chars);
359   }
360   while (lhs < limit) {
361     int r = static_cast<int>(*lhs) - static_cast<int>(*rhs);
362     if (r != 0) return r;
363     ++lhs;
364     ++rhs;
365   }
366   return 0;
367 }
368 
369 template <typename lchar, typename rchar>
CompareChars(const lchar * lhs,const rchar * rhs,size_t chars)370 inline int CompareChars(const lchar* lhs, const rchar* rhs, size_t chars) {
371   DCHECK_LE(sizeof(lchar), 2);
372   DCHECK_LE(sizeof(rchar), 2);
373   if (sizeof(lchar) == 1) {
374     if (sizeof(rchar) == 1) {
375       return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(lhs),
376                                   reinterpret_cast<const uint8_t*>(rhs), chars);
377     } else {
378       return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(lhs),
379                                   reinterpret_cast<const uint16_t*>(rhs),
380                                   chars);
381     }
382   } else {
383     if (sizeof(rchar) == 1) {
384       return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(lhs),
385                                   reinterpret_cast<const uint8_t*>(rhs), chars);
386     } else {
387       return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(lhs),
388                                   reinterpret_cast<const uint16_t*>(rhs),
389                                   chars);
390     }
391   }
392 }
393 
394 // Calculate 10^exponent.
TenToThe(int exponent)395 inline int TenToThe(int exponent) {
396   DCHECK_LE(exponent, 9);
397   DCHECK_GE(exponent, 1);
398   int answer = 10;
399   for (int i = 1; i < exponent; i++) answer *= 10;
400   return answer;
401 }
402 
403 // Helper class for building result strings in a character buffer. The
404 // purpose of the class is to use safe operations that checks the
405 // buffer bounds on all operations in debug mode.
406 // This simple base class does not allow formatted output.
407 class SimpleStringBuilder {
408  public:
409   // Create a string builder with a buffer of the given size. The
410   // buffer is allocated through NewArray<char> and must be
411   // deallocated by the caller of Finalize().
412   explicit SimpleStringBuilder(int size);
413 
SimpleStringBuilder(char * buffer,int size)414   SimpleStringBuilder(char* buffer, int size)
415       : buffer_(buffer, size), position_(0) {}
416 
~SimpleStringBuilder()417   ~SimpleStringBuilder() {
418     if (!is_finalized()) Finalize();
419   }
420 
size()421   int size() const { return buffer_.length(); }
422 
423   // Get the current position in the builder.
position()424   int position() const {
425     DCHECK(!is_finalized());
426     return position_;
427   }
428 
429   // Reset the position.
Reset()430   void Reset() { position_ = 0; }
431 
432   // Add a single character to the builder. It is not allowed to add
433   // 0-characters; use the Finalize() method to terminate the string
434   // instead.
AddCharacter(char c)435   void AddCharacter(char c) {
436     DCHECK_NE(c, '\0');
437     DCHECK(!is_finalized() && position_ < buffer_.length());
438     buffer_[position_++] = c;
439   }
440 
441   // Add an entire string to the builder. Uses strlen() internally to
442   // compute the length of the input string.
443   void AddString(const char* s);
444 
445   // Add the first 'n' characters of the given 0-terminated string 's' to the
446   // builder. The input string must have enough characters.
447   void AddSubstring(const char* s, int n);
448 
449   // Add character padding to the builder. If count is non-positive,
450   // nothing is added to the builder.
451   void AddPadding(char c, int count);
452 
453   // Add the decimal representation of the value.
454   void AddDecimalInteger(int value);
455 
456   // Finalize the string by 0-terminating it and returning the buffer.
457   char* Finalize();
458 
459  protected:
460   Vector<char> buffer_;
461   int position_;
462 
is_finalized()463   bool is_finalized() const { return position_ < 0; }
464 
465  private:
466   DISALLOW_IMPLICIT_CONSTRUCTORS(SimpleStringBuilder);
467 };
468 
469 // Bit field extraction.
unsigned_bitextract_32(int msb,int lsb,uint32_t x)470 inline uint32_t unsigned_bitextract_32(int msb, int lsb, uint32_t x) {
471   return (x >> lsb) & ((1 << (1 + msb - lsb)) - 1);
472 }
473 
unsigned_bitextract_64(int msb,int lsb,uint64_t x)474 inline uint64_t unsigned_bitextract_64(int msb, int lsb, uint64_t x) {
475   return (x >> lsb) & ((static_cast<uint64_t>(1) << (1 + msb - lsb)) - 1);
476 }
477 
signed_bitextract_32(int msb,int lsb,uint32_t x)478 inline int32_t signed_bitextract_32(int msb, int lsb, uint32_t x) {
479   return static_cast<int32_t>(x << (31 - msb)) >> (lsb + 31 - msb);
480 }
481 
482 // Check number width.
is_intn(int64_t x,unsigned n)483 inline bool is_intn(int64_t x, unsigned n) {
484   DCHECK((0 < n) && (n < 64));
485   int64_t limit = static_cast<int64_t>(1) << (n - 1);
486   return (-limit <= x) && (x < limit);
487 }
488 
is_uintn(int64_t x,unsigned n)489 inline bool is_uintn(int64_t x, unsigned n) {
490   DCHECK((0 < n) && (n < (sizeof(x) * kBitsPerByte)));
491   return !(x >> n);
492 }
493 
494 template <class T>
truncate_to_intn(T x,unsigned n)495 inline T truncate_to_intn(T x, unsigned n) {
496   DCHECK((0 < n) && (n < (sizeof(x) * kBitsPerByte)));
497   return (x & ((static_cast<T>(1) << n) - 1));
498 }
499 
500 // clang-format off
501 #define INT_1_TO_63_LIST(V)                                   \
502   V(1) V(2) V(3) V(4) V(5) V(6) V(7) V(8) V(9) V(10)          \
503   V(11) V(12) V(13) V(14) V(15) V(16) V(17) V(18) V(19) V(20) \
504   V(21) V(22) V(23) V(24) V(25) V(26) V(27) V(28) V(29) V(30) \
505   V(31) V(32) V(33) V(34) V(35) V(36) V(37) V(38) V(39) V(40) \
506   V(41) V(42) V(43) V(44) V(45) V(46) V(47) V(48) V(49) V(50) \
507   V(51) V(52) V(53) V(54) V(55) V(56) V(57) V(58) V(59) V(60) \
508   V(61) V(62) V(63)
509 // clang-format on
510 
511 #define DECLARE_IS_INT_N(N) \
512   inline bool is_int##N(int64_t x) { return is_intn(x, N); }
513 #define DECLARE_IS_UINT_N(N)    \
514   template <class T>            \
515   inline bool is_uint##N(T x) { \
516     return is_uintn(x, N);      \
517   }
518 #define DECLARE_TRUNCATE_TO_INT_N(N) \
519   template <class T>                 \
520   inline T truncate_to_int##N(T x) { \
521     return truncate_to_intn(x, N);   \
522   }
523 INT_1_TO_63_LIST(DECLARE_IS_INT_N)
INT_1_TO_63_LIST(DECLARE_IS_UINT_N)524 INT_1_TO_63_LIST(DECLARE_IS_UINT_N)
525 INT_1_TO_63_LIST(DECLARE_TRUNCATE_TO_INT_N)
526 #undef DECLARE_IS_INT_N
527 #undef DECLARE_IS_UINT_N
528 #undef DECLARE_TRUNCATE_TO_INT_N
529 
530 // clang-format off
531 #define INT_0_TO_127_LIST(V)                                          \
532 V(0)   V(1)   V(2)   V(3)   V(4)   V(5)   V(6)   V(7)   V(8)   V(9)   \
533 V(10)  V(11)  V(12)  V(13)  V(14)  V(15)  V(16)  V(17)  V(18)  V(19)  \
534 V(20)  V(21)  V(22)  V(23)  V(24)  V(25)  V(26)  V(27)  V(28)  V(29)  \
535 V(30)  V(31)  V(32)  V(33)  V(34)  V(35)  V(36)  V(37)  V(38)  V(39)  \
536 V(40)  V(41)  V(42)  V(43)  V(44)  V(45)  V(46)  V(47)  V(48)  V(49)  \
537 V(50)  V(51)  V(52)  V(53)  V(54)  V(55)  V(56)  V(57)  V(58)  V(59)  \
538 V(60)  V(61)  V(62)  V(63)  V(64)  V(65)  V(66)  V(67)  V(68)  V(69)  \
539 V(70)  V(71)  V(72)  V(73)  V(74)  V(75)  V(76)  V(77)  V(78)  V(79)  \
540 V(80)  V(81)  V(82)  V(83)  V(84)  V(85)  V(86)  V(87)  V(88)  V(89)  \
541 V(90)  V(91)  V(92)  V(93)  V(94)  V(95)  V(96)  V(97)  V(98)  V(99)  \
542 V(100) V(101) V(102) V(103) V(104) V(105) V(106) V(107) V(108) V(109) \
543 V(110) V(111) V(112) V(113) V(114) V(115) V(116) V(117) V(118) V(119) \
544 V(120) V(121) V(122) V(123) V(124) V(125) V(126) V(127)
545 // clang-format on
546 
547 class FeedbackSlot {
548  public:
549   FeedbackSlot() : id_(kInvalidSlot) {}
550   explicit FeedbackSlot(int id) : id_(id) {}
551 
552   int ToInt() const { return id_; }
553 
554   static FeedbackSlot Invalid() { return FeedbackSlot(); }
555   bool IsInvalid() const { return id_ == kInvalidSlot; }
556 
557   bool operator==(FeedbackSlot that) const { return this->id_ == that.id_; }
558   bool operator!=(FeedbackSlot that) const { return !(*this == that); }
559 
560   friend size_t hash_value(FeedbackSlot slot) { return slot.ToInt(); }
561   V8_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream& os,
562                                                     FeedbackSlot);
563 
564   FeedbackSlot WithOffset(int offset) const {
565     return FeedbackSlot(id_ + offset);
566   }
567 
568  private:
569   static const int kInvalidSlot = -1;
570 
571   int id_;
572 };
573 
574 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, FeedbackSlot);
575 
576 class BailoutId {
577  public:
BailoutId(int id)578   explicit BailoutId(int id) : id_(id) {}
ToInt()579   int ToInt() const { return id_; }
580 
None()581   static BailoutId None() { return BailoutId(kNoneId); }
582 
583   // Special bailout id support for deopting into the {JSConstructStub} stub.
584   // The following hard-coded deoptimization points are supported by the stub:
585   //  - {ConstructStubCreate} maps to {construct_stub_create_deopt_pc_offset}.
586   //  - {ConstructStubInvoke} maps to {construct_stub_invoke_deopt_pc_offset}.
ConstructStubCreate()587   static BailoutId ConstructStubCreate() { return BailoutId(1); }
ConstructStubInvoke()588   static BailoutId ConstructStubInvoke() { return BailoutId(2); }
IsValidForConstructStub()589   bool IsValidForConstructStub() const {
590     return id_ == ConstructStubCreate().ToInt() ||
591            id_ == ConstructStubInvoke().ToInt();
592   }
593 
IsNone()594   bool IsNone() const { return id_ == kNoneId; }
595   bool operator==(const BailoutId& other) const { return id_ == other.id_; }
596   bool operator!=(const BailoutId& other) const { return id_ != other.id_; }
597   friend size_t hash_value(BailoutId);
598   V8_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream&, BailoutId);
599 
600  private:
601   friend class Builtins;
602 
603   static const int kNoneId = -1;
604 
605   // Using 0 could disguise errors.
606   // Builtin continuations bailout ids start here. If you need to add a
607   // non-builtin BailoutId, add it before this id so that this Id has the
608   // highest number.
609   static const int kFirstBuiltinContinuationId = 1;
610 
611   int id_;
612 };
613 
614 // ----------------------------------------------------------------------------
615 // I/O support.
616 
617 // Our version of printf().
618 V8_EXPORT_PRIVATE void PRINTF_FORMAT(1, 2) PrintF(const char* format, ...);
619 V8_EXPORT_PRIVATE void PRINTF_FORMAT(2, 3)
620     PrintF(FILE* out, const char* format, ...);
621 
622 // Prepends the current process ID to the output.
623 void PRINTF_FORMAT(1, 2) PrintPID(const char* format, ...);
624 
625 // Prepends the current process ID and given isolate pointer to the output.
626 void PRINTF_FORMAT(2, 3) PrintIsolate(void* isolate, const char* format, ...);
627 
628 // Safe formatting print. Ensures that str is always null-terminated.
629 // Returns the number of chars written, or -1 if output was truncated.
630 V8_EXPORT_PRIVATE int PRINTF_FORMAT(2, 3)
631     SNPrintF(Vector<char> str, const char* format, ...);
632 V8_EXPORT_PRIVATE int PRINTF_FORMAT(2, 0)
633     VSNPrintF(Vector<char> str, const char* format, va_list args);
634 
635 void StrNCpy(Vector<char> dest, const char* src, size_t n);
636 
637 // Read a line of characters after printing the prompt to stdout. The resulting
638 // char* needs to be disposed off with DeleteArray by the caller.
639 char* ReadLine(const char* prompt);
640 
641 // Write size chars from str to the file given by filename.
642 // The file is overwritten. Returns the number of chars written.
643 int WriteChars(const char* filename, const char* str, int size,
644                bool verbose = true);
645 
646 // Write size bytes to the file given by filename.
647 // The file is overwritten. Returns the number of bytes written.
648 int WriteBytes(const char* filename, const byte* bytes, int size,
649                bool verbose = true);
650 
651 // Simple support to read a file into std::string.
652 // On return, *exits tells whether the file existed.
653 V8_EXPORT_PRIVATE std::string ReadFile(const char* filename, bool* exists,
654                                        bool verbose = true);
655 V8_EXPORT_PRIVATE std::string ReadFile(FILE* file, bool* exists,
656                                        bool verbose = true);
657 
658 class StringBuilder : public SimpleStringBuilder {
659  public:
StringBuilder(int size)660   explicit StringBuilder(int size) : SimpleStringBuilder(size) {}
StringBuilder(char * buffer,int size)661   StringBuilder(char* buffer, int size) : SimpleStringBuilder(buffer, size) {}
662 
663   // Add formatted contents to the builder just like printf().
664   void PRINTF_FORMAT(2, 3) AddFormatted(const char* format, ...);
665 
666   // Add formatted contents like printf based on a va_list.
667   void PRINTF_FORMAT(2, 0) AddFormattedList(const char* format, va_list list);
668 
669  private:
670   DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder);
671 };
672 
673 bool DoubleToBoolean(double d);
674 
675 template <typename Char>
676 bool TryAddIndexChar(uint32_t* index, Char c);
677 
678 enum ToIndexMode { kToArrayIndex, kToIntegerIndex };
679 
680 // {index_t} is meant to be {uint32_t} or {size_t}.
681 template <typename Stream, typename index_t,
682           enum ToIndexMode mode = kToArrayIndex>
683 bool StringToIndex(Stream* stream, index_t* index);
684 
685 // Returns the current stack top. Works correctly with ASAN and SafeStack.
686 // GetCurrentStackPosition() should not be inlined, because it works on stack
687 // frames if it were inlined into a function with a huge stack frame it would
688 // return an address significantly above the actual current stack position.
689 V8_EXPORT_PRIVATE V8_NOINLINE uintptr_t GetCurrentStackPosition();
690 
ByteReverse16(uint16_t value)691 static inline uint16_t ByteReverse16(uint16_t value) {
692 #if V8_HAS_BUILTIN_BSWAP16
693   return __builtin_bswap16(value);
694 #else
695   return value << 8 | (value >> 8 & 0x00FF);
696 #endif
697 }
698 
ByteReverse32(uint32_t value)699 static inline uint32_t ByteReverse32(uint32_t value) {
700 #if V8_HAS_BUILTIN_BSWAP32
701   return __builtin_bswap32(value);
702 #else
703   return value << 24 | ((value << 8) & 0x00FF0000) |
704          ((value >> 8) & 0x0000FF00) | ((value >> 24) & 0x00000FF);
705 #endif
706 }
707 
ByteReverse64(uint64_t value)708 static inline uint64_t ByteReverse64(uint64_t value) {
709 #if V8_HAS_BUILTIN_BSWAP64
710   return __builtin_bswap64(value);
711 #else
712   size_t bits_of_v = sizeof(value) * kBitsPerByte;
713   return value << (bits_of_v - 8) |
714          ((value << (bits_of_v - 24)) & 0x00FF000000000000) |
715          ((value << (bits_of_v - 40)) & 0x0000FF0000000000) |
716          ((value << (bits_of_v - 56)) & 0x000000FF00000000) |
717          ((value >> (bits_of_v - 56)) & 0x00000000FF000000) |
718          ((value >> (bits_of_v - 40)) & 0x0000000000FF0000) |
719          ((value >> (bits_of_v - 24)) & 0x000000000000FF00) |
720          ((value >> (bits_of_v - 8)) & 0x00000000000000FF);
721 #endif
722 }
723 
724 template <typename V>
ByteReverse(V value)725 static inline V ByteReverse(V value) {
726   size_t size_of_v = sizeof(value);
727   switch (size_of_v) {
728     case 1:
729       return value;
730     case 2:
731       return static_cast<V>(ByteReverse16(static_cast<uint16_t>(value)));
732     case 4:
733       return static_cast<V>(ByteReverse32(static_cast<uint32_t>(value)));
734     case 8:
735       return static_cast<V>(ByteReverse64(static_cast<uint64_t>(value)));
736     default:
737       UNREACHABLE();
738   }
739 }
740 
741 #if V8_OS_AIX
742 // glibc on aix has a bug when using ceil, trunc or nearbyint:
743 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97086
744 template <typename T>
FpOpWorkaround(T input,T value)745 T FpOpWorkaround(T input, T value) {
746   if (/*if -*/ std::signbit(input) && value == 0.0 &&
747       /*if +*/ !std::signbit(value)) {
748     return -0.0;
749   }
750   return value;
751 }
752 #endif
753 
754 V8_EXPORT_PRIVATE bool PassesFilter(Vector<const char> name,
755                                     Vector<const char> filter);
756 
757 // Zap the specified area with a specific byte pattern. This currently defaults
758 // to int3 on x64 and ia32. On other architectures this will produce unspecified
759 // instruction sequences.
760 // TODO(jgruber): Better support for other architectures.
ZapCode(Address addr,size_t size_in_bytes)761 V8_INLINE void ZapCode(Address addr, size_t size_in_bytes) {
762   static constexpr int kZapByte = 0xCC;
763   std::memset(reinterpret_cast<void*>(addr), kZapByte, size_in_bytes);
764 }
765 
766 }  // namespace internal
767 }  // namespace v8
768 
769 #endif  // V8_UTILS_UTILS_H_
770