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