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