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