v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
utils.h
Go to the documentation of this file.
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"
18#include "src/base/logging.h"
19#include "src/base/macros.h"
21#include "src/base/vector.h"
22#include "src/common/globals.h"
23
24#if defined(V8_USE_SIPHASH)
25#include "third_party/siphash/halfsiphash.h"
26#endif
27
28#if defined(V8_OS_AIX)
29#include <fenv.h> // NOLINT(build/c++11)
30
31#include "src/wasm/float16.h"
32#endif
33
34#ifdef _MSC_VER
35// MSVC doesn't define SSE3. However, it does define AVX, and AVX implies SSE3.
36#ifdef __AVX__
37#ifndef __SSE3__
38#define __SSE3__
39#endif
40#endif
41#endif
42
43#ifdef __SSE3__
44#include <pmmintrin.h>
45#endif
46
47#if defined(V8_TARGET_ARCH_ARM64) && \
48 (defined(__ARM_NEON) || defined(__ARM_NEON__))
49#define V8_OPTIMIZE_WITH_NEON
50#include <arm_neon.h>
51#endif
52
53namespace v8 {
54namespace internal {
55
56// ----------------------------------------------------------------------------
57// General helper functions
58
59template <typename T>
60static T ArithmeticShiftRight(T x, int shift) {
61 DCHECK_LE(0, shift);
62 if (x < 0) {
63 // Right shift of signed values is implementation defined. Simulate a
64 // true arithmetic right shift by adding leading sign bits.
65 using UnsignedT = typename std::make_unsigned<T>::type;
66 UnsignedT mask = ~(static_cast<UnsignedT>(~0) >> shift);
67 return (static_cast<UnsignedT>(x) >> shift) | mask;
68 } else {
69 return x >> shift;
70 }
71}
72
73// Returns the maximum of the two parameters according to JavaScript semantics.
74template <typename T>
75T JSMax(T x, T y) {
76 if (std::isnan(x)) return x;
77 if (std::isnan(y)) return y;
78 if (std::signbit(x) < std::signbit(y)) return x;
79 return x > y ? x : y;
80}
81
82// Returns the maximum of the two parameters according to JavaScript semantics.
83template <typename T>
84T JSMin(T x, T y) {
85 if (std::isnan(x)) return x;
86 if (std::isnan(y)) return y;
87 if (std::signbit(x) < std::signbit(y)) return y;
88 return x > y ? y : x;
89}
90
91// Returns the absolute value of its argument.
92template <typename T>
93typename std::make_unsigned<T>::type Abs(T a)
94 requires std::is_signed<T>::value
95{
96 // This is a branch-free implementation of the absolute value function and is
97 // described in Warren's "Hacker's Delight", chapter 2. It avoids undefined
98 // behavior with the arithmetic negation operation on signed values as well.
99 using unsignedT = typename std::make_unsigned<T>::type;
100 unsignedT x = static_cast<unsignedT>(a);
101 unsignedT y = static_cast<unsignedT>(a >> (sizeof(T) * 8 - 1));
102 return (x ^ y) - y;
103}
104
105inline double Modulo(double x, double y) {
106#if defined(V8_OS_WIN)
107 // Workaround MS fmod bugs. ECMA-262 says:
108 // dividend is finite and divisor is an infinity => result equals dividend
109 // dividend is a zero and divisor is nonzero finite => result equals dividend
110 if (!(std::isfinite(x) && (!std::isfinite(y) && !std::isnan(y))) &&
111 !(x == 0 && (y != 0 && std::isfinite(y)))) {
112 double result = fmod(x, y);
113 // Workaround MS bug in VS CRT in some OS versions, https://crbug.com/915045
114 // fmod(-17, +/-1) should equal -0.0 but now returns 0.0.
115 if (x < 0 && result == 0) result = -0.0;
116 x = result;
117 }
118 return x;
119#elif defined(V8_OS_AIX)
120 // AIX raises an underflow exception for (Number.MIN_VALUE % Number.MAX_VALUE)
121 feclearexcept(FE_ALL_EXCEPT);
122 double result = std::fmod(x, y);
123 int exception = fetestexcept(FE_UNDERFLOW);
124 return (exception ? x : result);
125#else
126 return std::fmod(x, y);
127#endif
128}
129
130template <typename T>
131T SaturateAdd(T a, T b) {
132 if (std::is_signed<T>::value) {
133 if (a > 0 && b > 0) {
134 if (a > std::numeric_limits<T>::max() - b) {
135 return std::numeric_limits<T>::max();
136 }
137 } else if (a < 0 && b < 0) {
138 if (a < std::numeric_limits<T>::min() - b) {
139 return std::numeric_limits<T>::min();
140 }
141 }
142 } else {
143 CHECK(std::is_unsigned<T>::value);
144 if (a > std::numeric_limits<T>::max() - b) {
145 return std::numeric_limits<T>::max();
146 }
147 }
148 return a + b;
149}
150
151template <typename T>
152T SaturateSub(T a, T b) {
153 if (std::is_signed<T>::value) {
154 if (a >= 0 && b < 0) {
155 if (a > std::numeric_limits<T>::max() + b) {
156 return std::numeric_limits<T>::max();
157 }
158 } else if (a < 0 && b > 0) {
159 if (a < std::numeric_limits<T>::min() + b) {
160 return std::numeric_limits<T>::min();
161 }
162 }
163 } else {
164 CHECK(std::is_unsigned<T>::value);
165 if (a < b) {
166 return static_cast<T>(0);
167 }
168 }
169 return a - b;
170}
171
172template <typename T>
174 // Saturating rounding multiplication for Q-format numbers. See
175 // https://en.wikipedia.org/wiki/Q_(number_format) for a description.
176 // Specifically this supports Q7, Q15, and Q31. This follows the
177 // implementation in simulator-logic-arm64.cc (sqrdmulh) to avoid overflow
178 // when a == b == int32 min.
179 static_assert(std::is_integral<T>::value, "only integral types");
180
181 constexpr int size_in_bits = sizeof(T) * 8;
182 int round_const = 1 << (size_in_bits - 2);
183 int64_t product = a * b;
184 product += round_const;
185 product >>= (size_in_bits - 1);
186 return base::saturated_cast<T>(product);
187}
188
189// Multiply two numbers, returning a result that is twice as wide, no overflow.
190// Put Wide first so we can use function template argument deduction for Narrow,
191// and callers can provide only Wide.
192template <typename Wide, typename Narrow>
193Wide MultiplyLong(Narrow a, Narrow b) {
194 static_assert(
195 std::is_integral<Narrow>::value && std::is_integral<Wide>::value,
196 "only integral types");
197 static_assert(std::is_signed<Narrow>::value == std::is_signed<Wide>::value,
198 "both must have same signedness");
199 static_assert(sizeof(Narrow) * 2 == sizeof(Wide), "only twice as long");
200
201 return static_cast<Wide>(a) * static_cast<Wide>(b);
202}
203
204// Add two numbers, returning a result that is twice as wide, no overflow.
205// Put Wide first so we can use function template argument deduction for Narrow,
206// and callers can provide only Wide.
207template <typename Wide, typename Narrow>
208Wide AddLong(Narrow a, Narrow b) {
209 static_assert(
210 std::is_integral<Narrow>::value && std::is_integral<Wide>::value,
211 "only integral types");
212 static_assert(std::is_signed<Narrow>::value == std::is_signed<Wide>::value,
213 "both must have same signedness");
214 static_assert(sizeof(Narrow) * 2 == sizeof(Wide), "only twice as long");
215
216 return static_cast<Wide>(a) + static_cast<Wide>(b);
217}
218
219template <typename T>
220inline T RoundingAverageUnsigned(T a, T b) {
221 static_assert(std::is_unsigned<T>::value, "Only for unsiged types");
222 static_assert(sizeof(T) < sizeof(uint64_t), "Must be smaller than uint64_t");
223 return (static_cast<uint64_t>(a) + static_cast<uint64_t>(b) + 1) >> 1;
224}
225
226// Helper macros for defining a contiguous sequence of field offset constants.
227// Example: (backslashes at the ends of respective lines of this multi-line
228// macro definition are omitted here to please the compiler)
229//
230// #define MAP_FIELDS(V)
231// V(kField1Offset, kTaggedSize)
232// V(kField2Offset, kIntSize)
233// V(kField3Offset, kIntSize)
234// V(kField4Offset, kSystemPointerSize)
235// V(kSize, 0)
236//
237// DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, MAP_FIELDS)
238//
239#define DEFINE_ONE_FIELD_OFFSET(Name, Size, ...) \
240 Name, Name##End = Name + (Size)-1,
241
242#define DEFINE_FIELD_OFFSET_CONSTANTS(StartOffset, LIST_MACRO) \
243 enum { \
244 LIST_MACRO##_StartOffset = StartOffset - 1, \
245 LIST_MACRO(DEFINE_ONE_FIELD_OFFSET) \
246 };
247
248#define DEFINE_ONE_FIELD_OFFSET_PURE_NAME(CamelName, Size, ...) \
249 k##CamelName##Offset, \
250 k##CamelName##OffsetEnd = k##CamelName##Offset + (Size)-1,
251
252#define DEFINE_FIELD_OFFSET_CONSTANTS_WITH_PURE_NAME(StartOffset, LIST_MACRO) \
253 enum { \
254 LIST_MACRO##_StartOffset = StartOffset - 1, \
255 LIST_MACRO(DEFINE_ONE_FIELD_OFFSET_PURE_NAME) \
256 };
257
258// Size of the field defined by DEFINE_FIELD_OFFSET_CONSTANTS
259#define FIELD_SIZE(Name) (Name##End + 1 - Name)
260
261// Compare two offsets with static cast
262#define STATIC_ASSERT_FIELD_OFFSETS_EQUAL(Offset1, Offset2) \
263 static_assert(static_cast<int>(Offset1) == Offset2)
264// ----------------------------------------------------------------------------
265// Hash function.
266
267static const uint64_t kZeroHashSeed = 0;
268
269// Thomas Wang, Integer Hash Functions.
270// http://www.concentric.net/~Ttwang/tech/inthash.htm`
271inline uint32_t ComputeUnseededHash(uint32_t key) {
272 uint32_t hash = key;
273 hash = ~hash + (hash << 15); // hash = (hash << 15) - hash - 1;
274 hash = hash ^ (hash >> 12);
275 hash = hash + (hash << 2);
276 hash = hash ^ (hash >> 4);
277 hash = hash * 2057; // hash = (hash + (hash << 3)) + (hash << 11);
278 hash = hash ^ (hash >> 16);
279 return hash & 0x3fffffff;
280}
281
282inline uint32_t ComputeLongHash(uint64_t key) {
283 uint64_t hash = key;
284 hash = ~hash + (hash << 18); // hash = (hash << 18) - hash - 1;
285 hash = hash ^ (hash >> 31);
286 hash = hash * 21; // hash = (hash + (hash << 2)) + (hash << 4);
287 hash = hash ^ (hash >> 11);
288 hash = hash + (hash << 6);
289 hash = hash ^ (hash >> 22);
290 return static_cast<uint32_t>(hash & 0x3fffffff);
291}
292
293inline uint32_t ComputeSeededHash(uint32_t key, uint64_t seed) {
294#ifdef V8_USE_SIPHASH
295 return halfsiphash(key, seed);
296#else
297 return ComputeLongHash(static_cast<uint64_t>(key) ^ seed);
298#endif // V8_USE_SIPHASH
299}
300
301inline uint32_t ComputePointerHash(void* ptr) {
302 return ComputeUnseededHash(
303 static_cast<uint32_t>(reinterpret_cast<intptr_t>(ptr)));
304}
305
306inline uint32_t ComputeAddressHash(Address address) {
307 return ComputeUnseededHash(static_cast<uint32_t>(address & 0xFFFFFFFFul));
308}
309
310// ----------------------------------------------------------------------------
311// Miscellaneous
312
313// Memory offset for lower and higher bits in a 64 bit integer.
314#if defined(V8_TARGET_LITTLE_ENDIAN)
315static const int kInt64LowerHalfMemoryOffset = 0;
316static const int kInt64UpperHalfMemoryOffset = 4;
317#elif defined(V8_TARGET_BIG_ENDIAN)
318static const int kInt64LowerHalfMemoryOffset = 4;
319static const int kInt64UpperHalfMemoryOffset = 0;
320#endif // V8_TARGET_LITTLE_ENDIAN
321
322// A pointer that can only be set once and doesn't allow NULL values.
323template <typename T>
325 public:
326 SetOncePointer() = default;
327
328 bool is_set() const { return pointer_ != nullptr; }
329
330 T* get() const {
332 return pointer_;
333 }
334
335 void set(T* value) {
336 DCHECK(pointer_ == nullptr && value != nullptr);
337 pointer_ = value;
338 }
339
341 set(value);
342 return *this;
343 }
344
345 bool operator==(std::nullptr_t) const { return pointer_ == nullptr; }
346 bool operator!=(std::nullptr_t) const { return pointer_ != nullptr; }
347
348 private:
349 T* pointer_ = nullptr;
350};
351
352#if defined(__SSE3__)
353
354template <typename Char>
355V8_INLINE bool SimdMemEqual(const Char* lhs, const Char* rhs, size_t count,
356 size_t order) {
357 static_assert(sizeof(Char) == 1);
358 DCHECK_GE(order, 5);
359
360 static constexpr uint16_t kSIMDMatched16Mask = UINT16_MAX;
361 static constexpr uint32_t kSIMDMatched32Mask = UINT32_MAX;
362
363 if (order == 5) { // count: [17, 32]
364 // Utilize more simd registers for better pipelining.
365 const __m128i lhs128_start =
366 _mm_lddqu_si128(reinterpret_cast<const __m128i*>(lhs));
367 const __m128i lhs128_end = _mm_lddqu_si128(
368 reinterpret_cast<const __m128i*>(lhs + count - sizeof(__m128i)));
369 const __m128i rhs128_start =
370 _mm_lddqu_si128(reinterpret_cast<const __m128i*>(rhs));
371 const __m128i rhs128_end = _mm_lddqu_si128(
372 reinterpret_cast<const __m128i*>(rhs + count - sizeof(__m128i)));
373 const __m128i res_start = _mm_cmpeq_epi8(lhs128_start, rhs128_start);
374 const __m128i res_end = _mm_cmpeq_epi8(lhs128_end, rhs128_end);
375 const uint32_t res =
376 _mm_movemask_epi8(res_start) << 16 | _mm_movemask_epi8(res_end);
377 return res == kSIMDMatched32Mask;
378 }
379
380 // count: [33, ...]
381 const __m128i lhs128_unrolled =
382 _mm_lddqu_si128(reinterpret_cast<const __m128i*>(lhs));
383 const __m128i rhs128_unrolled =
384 _mm_lddqu_si128(reinterpret_cast<const __m128i*>(rhs));
385 const __m128i res_unrolled = _mm_cmpeq_epi8(lhs128_unrolled, rhs128_unrolled);
386 const uint16_t res_unrolled_mask = _mm_movemask_epi8(res_unrolled);
387 if (res_unrolled_mask != kSIMDMatched16Mask) return false;
388
389 for (size_t i = count % sizeof(__m128i); i < count; i += sizeof(__m128i)) {
390 const __m128i lhs128 =
391 _mm_lddqu_si128(reinterpret_cast<const __m128i*>(lhs + i));
392 const __m128i rhs128 =
393 _mm_lddqu_si128(reinterpret_cast<const __m128i*>(rhs + i));
394 const __m128i res = _mm_cmpeq_epi8(lhs128, rhs128);
395 const uint16_t res_mask = _mm_movemask_epi8(res);
396 if (res_mask != kSIMDMatched16Mask) return false;
397 }
398 return true;
399}
400
401#elif defined(V8_OPTIMIZE_WITH_NEON)
402
403// We intentionally use misaligned read/writes for NEON intrinsics, disable
404// alignment sanitization explicitly.
405template <typename Char>
406V8_INLINE V8_CLANG_NO_SANITIZE("alignment") bool SimdMemEqual(const Char* lhs,
407 const Char* rhs,
408 size_t count,
409 size_t order) {
410 static_assert(sizeof(Char) == 1);
411 DCHECK_GE(order, 5);
412
413 if (order == 5) { // count: [17, 32]
414 // Utilize more simd registers for better pipelining.
415 const auto lhs0 = vld1q_u8(lhs);
416 const auto lhs1 = vld1q_u8(lhs + count - sizeof(uint8x16_t));
417 const auto rhs0 = vld1q_u8(rhs);
418 const auto rhs1 = vld1q_u8(rhs + count - sizeof(uint8x16_t));
419 const auto xored0 = veorq_u8(lhs0, rhs0);
420 const auto xored1 = veorq_u8(lhs1, rhs1);
421 const auto ored = vorrq_u8(xored0, xored1);
422 return !static_cast<bool>(
423 vgetq_lane_u64(vreinterpretq_u64_u8(vpmaxq_u8(ored, ored)), 0));
424 }
425
426 // count: [33, ...]
427 const auto first_lhs0 = vld1q_u8(lhs);
428 const auto first_rhs0 = vld1q_u8(rhs);
429 const auto first_xored = veorq_u8(first_lhs0, first_rhs0);
430 if (static_cast<bool>(vgetq_lane_u64(
431 vreinterpretq_u64_u8(vpmaxq_u8(first_xored, first_xored)), 0))) {
432 return false;
433 }
434 for (size_t i = count % sizeof(uint8x16_t); i < count;
435 i += sizeof(uint8x16_t)) {
436 const auto lhs0 = vld1q_u8(lhs + i);
437 const auto rhs0 = vld1q_u8(rhs + i);
438 const auto xored = veorq_u8(lhs0, rhs0);
439 if (static_cast<bool>(
440 vgetq_lane_u64(vreinterpretq_u64_u8(vpmaxq_u8(xored, xored)), 0)))
441 return false;
442 }
443 return true;
444}
445
446#endif
447
448template <typename IntType, typename Char>
449V8_CLANG_NO_SANITIZE("alignment")
450V8_INLINE bool OverlappingCompare(const Char* lhs, const Char* rhs,
451 size_t count) {
452 static_assert(sizeof(Char) == 1);
453 return *reinterpret_cast<const IntType*>(lhs) ==
454 *reinterpret_cast<const IntType*>(rhs) &&
455 *reinterpret_cast<const IntType*>(lhs + count - sizeof(IntType)) ==
456 *reinterpret_cast<const IntType*>(rhs + count - sizeof(IntType));
457}
458
459template <typename Char>
460V8_CLANG_NO_SANITIZE("alignment")
461V8_INLINE bool SimdMemEqual(const Char* lhs, const Char* rhs, size_t count) {
462 static_assert(sizeof(Char) == 1);
463 if (count == 0) {
464 return true;
465 }
466 if (count == 1) {
467 return *lhs == *rhs;
468 }
469 const size_t order =
470 sizeof(count) * CHAR_BIT - base::bits::CountLeadingZeros(count - 1);
471 switch (order) {
472 case 1: // count: [2, 2]
473 return *reinterpret_cast<const uint16_t*>(lhs) ==
474 *reinterpret_cast<const uint16_t*>(rhs);
475 case 2: // count: [3, 4]
476 return OverlappingCompare<uint16_t>(lhs, rhs, count);
477 case 3: // count: [5, 8]
478 return OverlappingCompare<uint32_t>(lhs, rhs, count);
479 case 4: // count: [9, 16]
480 return OverlappingCompare<uint64_t>(lhs, rhs, count);
481 default:
482 return SimdMemEqual(lhs, rhs, count, order);
483 }
484}
485
486// Compare 8bit/16bit chars to 8bit/16bit chars.
487template <typename lchar, typename rchar>
488inline bool CompareCharsEqualUnsigned(const lchar* lhs, const rchar* rhs,
489 size_t chars) {
490 static_assert(std::is_unsigned<lchar>::value);
491 static_assert(std::is_unsigned<rchar>::value);
492 if constexpr (sizeof(*lhs) == sizeof(*rhs)) {
493#if defined(__SSE3__) || defined(V8_OPTIMIZE_WITH_NEON)
494 if constexpr (sizeof(*lhs) == 1) {
495 return SimdMemEqual(lhs, rhs, chars);
496 }
497#endif
498 // memcmp compares byte-by-byte, but for equality it doesn't matter whether
499 // two-byte char comparison is little- or big-endian.
500 return memcmp(lhs, rhs, chars * sizeof(*lhs)) == 0;
501 }
502 for (const lchar* limit = lhs + chars; lhs < limit; ++lhs, ++rhs) {
503 if (*lhs != *rhs) return false;
504 }
505 return true;
506}
507
508template <typename lchar, typename rchar>
509inline bool CompareCharsEqual(const lchar* lhs, const rchar* rhs,
510 size_t chars) {
511 using ulchar = typename std::make_unsigned<lchar>::type;
512 using urchar = typename std::make_unsigned<rchar>::type;
513 return CompareCharsEqualUnsigned(reinterpret_cast<const ulchar*>(lhs),
514 reinterpret_cast<const urchar*>(rhs), chars);
515}
516
517// Compare 8bit/16bit chars to 8bit/16bit chars.
518template <typename lchar, typename rchar>
519inline int CompareCharsUnsigned(const lchar* lhs, const rchar* rhs,
520 size_t chars) {
521 static_assert(std::is_unsigned<lchar>::value);
522 static_assert(std::is_unsigned<rchar>::value);
523 if (sizeof(*lhs) == sizeof(char) && sizeof(*rhs) == sizeof(char)) {
524 // memcmp compares byte-by-byte, yielding wrong results for two-byte
525 // strings on little-endian systems.
526 return memcmp(lhs, rhs, chars);
527 }
528 for (const lchar* limit = lhs + chars; lhs < limit; ++lhs, ++rhs) {
529 int r = static_cast<int>(*lhs) - static_cast<int>(*rhs);
530 if (r != 0) return r;
531 }
532 return 0;
533}
534
535template <typename lchar, typename rchar>
536inline int CompareChars(const lchar* lhs, const rchar* rhs, size_t chars) {
537 using ulchar = typename std::make_unsigned<lchar>::type;
538 using urchar = typename std::make_unsigned<rchar>::type;
539 return CompareCharsUnsigned(reinterpret_cast<const ulchar*>(lhs),
540 reinterpret_cast<const urchar*>(rhs), chars);
541}
542
543// Calculate 10^exponent.
544inline constexpr uint64_t TenToThe(uint32_t exponent) {
545 DCHECK_LE(exponent, 19);
546 DCHECK_GE(exponent, 0);
547 uint64_t answer = 1;
548 for (uint32_t i = 0; i < exponent; i++) answer *= 10;
549 return answer;
550}
551static_assert(TenToThe(19) < kMaxUInt64);
552static_assert(TenToThe(19) > kMaxUInt64 / 10);
553
554// Bit field extraction.
555inline uint32_t unsigned_bitextract_32(int msb, int lsb, uint32_t x) {
556 return (x >> lsb) & ((1 << (1 + msb - lsb)) - 1);
557}
558
559inline uint64_t unsigned_bitextract_64(int msb, int lsb, uint64_t x) {
560 return (x >> lsb) & ((static_cast<uint64_t>(1) << (1 + msb - lsb)) - 1);
561}
562
563inline int32_t signed_bitextract_32(int msb, int lsb, uint32_t x) {
564 return static_cast<int32_t>(x << (31 - msb)) >> (lsb + 31 - msb);
565}
566
567// Check number width.
568inline constexpr bool is_intn(int64_t x, unsigned n) {
569 DCHECK((0 < n) && (n < 64));
570 int64_t limit = static_cast<int64_t>(1) << (n - 1);
571 return (-limit <= x) && (x < limit);
572}
573
574inline constexpr bool is_uintn(int64_t x, unsigned n) {
575 DCHECK((0 < n) && (n < (sizeof(x) * kBitsPerByte)));
576 return !(x >> n);
577}
578
579template <class T>
580inline constexpr T truncate_to_intn(T x, unsigned n) {
581 DCHECK((0 < n) && (n < (sizeof(x) * kBitsPerByte)));
582 return (x & ((static_cast<T>(1) << n) - 1));
583}
584
585// clang-format off
586#define INT_1_TO_63_LIST(V) \
587 V(1) V(2) V(3) V(4) V(5) V(6) V(7) V(8) V(9) V(10) \
588 V(11) V(12) V(13) V(14) V(15) V(16) V(17) V(18) V(19) V(20) \
589 V(21) V(22) V(23) V(24) V(25) V(26) V(27) V(28) V(29) V(30) \
590 V(31) V(32) V(33) V(34) V(35) V(36) V(37) V(38) V(39) V(40) \
591 V(41) V(42) V(43) V(44) V(45) V(46) V(47) V(48) V(49) V(50) \
592 V(51) V(52) V(53) V(54) V(55) V(56) V(57) V(58) V(59) V(60) \
593 V(61) V(62) V(63)
594// clang-format on
595
596#define DECLARE_IS_INT_N(N) \
597 inline constexpr bool is_int##N(int64_t x) { return is_intn(x, N); }
598#define DECLARE_IS_UINT_N(N) \
599 template <class T> \
600 inline constexpr bool is_uint##N(T x) { \
601 return is_uintn(x, N); \
602 }
603#define DECLARE_TRUNCATE_TO_INT_N(N) \
604 template <class T> \
605 inline constexpr T truncate_to_int##N(T x) { \
606 return truncate_to_intn(x, N); \
607 }
608
609#define DECLARE_CHECKED_TRUNCATE_TO_INT_N(N) \
610 template <class T> \
611 inline constexpr T checked_truncate_to_int##N(T x) { \
612 CHECK(is_int##N(x)); \
613 return truncate_to_intn(x, N); \
614 }
619#undef DECLARE_IS_INT_N
620#undef DECLARE_IS_UINT_N
621#undef DECLARE_TRUNCATE_TO_INT_N
622#undef DECLARE_CHECKED_TRUNCATE_TO_INT_N
623
624// clang-format off
625#define INT_0_TO_127_LIST(V) \
626V(0) V(1) V(2) V(3) V(4) V(5) V(6) V(7) V(8) V(9) \
627V(10) V(11) V(12) V(13) V(14) V(15) V(16) V(17) V(18) V(19) \
628V(20) V(21) V(22) V(23) V(24) V(25) V(26) V(27) V(28) V(29) \
629V(30) V(31) V(32) V(33) V(34) V(35) V(36) V(37) V(38) V(39) \
630V(40) V(41) V(42) V(43) V(44) V(45) V(46) V(47) V(48) V(49) \
631V(50) V(51) V(52) V(53) V(54) V(55) V(56) V(57) V(58) V(59) \
632V(60) V(61) V(62) V(63) V(64) V(65) V(66) V(67) V(68) V(69) \
633V(70) V(71) V(72) V(73) V(74) V(75) V(76) V(77) V(78) V(79) \
634V(80) V(81) V(82) V(83) V(84) V(85) V(86) V(87) V(88) V(89) \
635V(90) V(91) V(92) V(93) V(94) V(95) V(96) V(97) V(98) V(99) \
636V(100) V(101) V(102) V(103) V(104) V(105) V(106) V(107) V(108) V(109) \
637V(110) V(111) V(112) V(113) V(114) V(115) V(116) V(117) V(118) V(119) \
638V(120) V(121) V(122) V(123) V(124) V(125) V(126) V(127)
639// clang-format on
640
642 public:
644 explicit FeedbackSlot(int id) : id_(id) {}
645
646 int ToInt() const { return id_; }
647
648 static FeedbackSlot Invalid() { return FeedbackSlot(); }
649 bool IsInvalid() const { return id_ == kInvalidSlot; }
650
651 bool operator==(FeedbackSlot that) const { return this->id_ == that.id_; }
652 bool operator!=(FeedbackSlot that) const { return !(*this == that); }
653
654 friend size_t hash_value(FeedbackSlot slot) { return slot.ToInt(); }
655 V8_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream& os,
657
659 return FeedbackSlot(id_ + offset);
660 }
661
662 private:
663 static const int kInvalidSlot = -1;
664
665 int id_;
666};
667
668V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, FeedbackSlot);
669
671 public:
672 explicit constexpr BytecodeOffset(int id) : id_(id) {}
673 constexpr int ToInt() const { return id_; }
674
675 static constexpr BytecodeOffset None() { return BytecodeOffset(kNoneId); }
676
677 // Special bailout id support for deopting into the {JSConstructStub} stub.
678 // The following hard-coded deoptimization points are supported by the stub:
679 // - {ConstructStubCreate} maps to {construct_stub_create_deopt_pc_offset}.
680 // - {ConstructStubInvoke} maps to {construct_stub_invoke_deopt_pc_offset}.
683
684 constexpr bool IsNone() const { return id_ == kNoneId; }
685 bool operator==(const BytecodeOffset& other) const {
686 return id_ == other.id_;
687 }
688 bool operator!=(const BytecodeOffset& other) const {
689 return id_ != other.id_;
690 }
691 friend size_t hash_value(BytecodeOffset);
692 V8_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream&,
694
695 private:
696 friend class Builtins;
697
698 static const int kNoneId = -1;
699
700 // Using 0 could disguise errors.
701 // Builtin continuations bailout ids start here. If you need to add a
702 // non-builtin BytecodeOffset, add it before this id so that this Id has the
703 // highest number.
704 static const int kFirstBuiltinContinuationId = 1;
705
706 int id_;
707};
708
709// ----------------------------------------------------------------------------
710// I/O support.
711
712// Our version of printf().
713V8_EXPORT_PRIVATE void PRINTF_FORMAT(1, 2) PrintF(const char* format, ...);
715 PrintF(FILE* out, const char* format, ...);
716
717// Prepends the current process ID to the output.
718void PRINTF_FORMAT(1, 2) PrintPID(const char* format, ...);
719
720// Prepends the current process ID and given isolate pointer to the output.
721void PRINTF_FORMAT(2, 3) PrintIsolate(void* isolate, const char* format, ...);
722
723// Read a line of characters after printing the prompt to stdout. The resulting
724// char* needs to be disposed off with DeleteArray by the caller.
725char* ReadLine(const char* prompt);
726
727// Write size chars from str to the file given by filename.
728// The file is overwritten. Returns the number of chars written.
729int WriteChars(const char* filename, const char* str, int size,
730 bool verbose = true);
731
732// Write size bytes to the file given by filename.
733// The file is overwritten. Returns the number of bytes written.
734int WriteBytes(const char* filename, const uint8_t* bytes, int size,
735 bool verbose = true);
736
737// Simple support to read a file into std::string.
738// On return, *exits tells whether the file existed.
739V8_EXPORT_PRIVATE std::string ReadFile(const char* filename, bool* exists,
740 bool verbose = true);
741V8_EXPORT_PRIVATE std::string ReadFile(FILE* file, bool* exists,
742 bool verbose = true);
743
744bool DoubleToBoolean(double d);
745
746template <typename Char>
747bool TryAddIndexChar(uint32_t* index, Char c);
748
750
751// {index_t} is meant to be {uint32_t} or {size_t}.
752template <typename Stream, typename index_t,
753 enum ToIndexMode mode = kToArrayIndex>
754bool StringToIndex(Stream* stream, index_t* index);
755
756// Returns the current stack top. Works correctly with ASAN and SafeStack.
757// GetCurrentStackPosition() should not be inlined, because it works on stack
758// frames if it were inlined into a function with a huge stack frame it would
759// return an address significantly above the actual current stack position.
761
762static inline uint16_t ByteReverse16(uint16_t value) {
763#if V8_HAS_BUILTIN_BSWAP16
764 return __builtin_bswap16(value);
765#else
766 return value << 8 | (value >> 8 & 0x00FF);
767#endif
768}
769
770static inline uint32_t ByteReverse32(uint32_t value) {
771#if V8_HAS_BUILTIN_BSWAP32
772 return __builtin_bswap32(value);
773#else
774 return value << 24 | ((value << 8) & 0x00FF0000) |
775 ((value >> 8) & 0x0000FF00) | ((value >> 24) & 0x00000FF);
776#endif
777}
778
779static inline uint64_t ByteReverse64(uint64_t value) {
780#if V8_HAS_BUILTIN_BSWAP64
781 return __builtin_bswap64(value);
782#else
783 size_t bits_of_v = sizeof(value) * kBitsPerByte;
784 return value << (bits_of_v - 8) |
785 ((value << (bits_of_v - 24)) & 0x00FF000000000000) |
786 ((value << (bits_of_v - 40)) & 0x0000FF0000000000) |
787 ((value << (bits_of_v - 56)) & 0x000000FF00000000) |
788 ((value >> (bits_of_v - 56)) & 0x00000000FF000000) |
789 ((value >> (bits_of_v - 40)) & 0x0000000000FF0000) |
790 ((value >> (bits_of_v - 24)) & 0x000000000000FF00) |
791 ((value >> (bits_of_v - 8)) & 0x00000000000000FF);
792#endif
793}
794
795template <typename V>
796static inline V ByteReverse(V value) {
797 size_t size_of_v = sizeof(value);
798 switch (size_of_v) {
799 case 1:
800 return value;
801 case 2:
802 return static_cast<V>(ByteReverse16(static_cast<uint16_t>(value)));
803 case 4:
804 return static_cast<V>(ByteReverse32(static_cast<uint32_t>(value)));
805 case 8:
806 return static_cast<V>(ByteReverse64(static_cast<uint64_t>(value)));
807 default:
808 UNREACHABLE();
809 }
810}
811
812#if V8_OS_AIX
813// glibc on aix has a bug when using ceil, trunc or nearbyint:
814// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97086
815template <typename T>
816T FpOpWorkaround(T input, T value) {
817 if (/*if -*/ std::signbit(input) && value == 0.0 &&
818 /*if +*/ !std::signbit(value)) {
819 return -0.0;
820 }
821 return value;
822}
823
824template <>
825inline Float16 FpOpWorkaround(Float16 input, Float16 value) {
826 float result = FpOpWorkaround(input.ToFloat32(), value.ToFloat32());
828}
829
830#endif
831
832V8_EXPORT_PRIVATE bool PassesFilter(base::Vector<const char> name,
833 base::Vector<const char> filter);
834
835// Zap the specified area with a specific byte pattern. This currently defaults
836// to int3 on x64 and ia32. On other architectures this will produce unspecified
837// instruction sequences.
838// TODO(jgruber): Better support for other architectures.
839V8_INLINE void ZapCode(Address addr, size_t size_in_bytes) {
840 static constexpr int kZapByte = 0xCC;
841 std::memset(reinterpret_cast<void*>(addr), kZapByte, size_in_bytes);
842}
843
844inline bool RoundUpToPageSize(size_t byte_length, size_t page_size,
845 size_t max_allowed_byte_length, size_t* pages) {
846 // This check is needed, since the arithmetic in RoundUp only works when
847 // byte_length is not too close to the size_t limit.
848 if (byte_length > max_allowed_byte_length) {
849 return false;
850 }
851 size_t bytes_wanted = RoundUp(byte_length, page_size);
852 if (bytes_wanted > max_allowed_byte_length) {
853 return false;
854 }
855 *pages = bytes_wanted / page_size;
856 return true;
857}
858
859} // namespace internal
860} // namespace v8
861
862#endif // V8_UTILS_UTILS_H_
#define T
bool operator==(const BytecodeOffset &other) const
Definition utils.h:685
static const int kFirstBuiltinContinuationId
Definition utils.h:704
static constexpr BytecodeOffset None()
Definition utils.h:675
static BytecodeOffset ConstructStubCreate()
Definition utils.h:681
friend size_t hash_value(BytecodeOffset)
Definition utils.cc:30
static const int kNoneId
Definition utils.h:698
bool operator!=(const BytecodeOffset &other) const
Definition utils.h:688
constexpr bool IsNone() const
Definition utils.h:684
V8_EXPORT_PRIVATE friend std::ostream & operator<<(std::ostream &, BytecodeOffset)
Definition utils.cc:35
static BytecodeOffset ConstructStubInvoke()
Definition utils.h:682
constexpr int ToInt() const
Definition utils.h:673
constexpr BytecodeOffset(int id)
Definition utils.h:672
bool IsInvalid() const
Definition utils.h:649
bool operator!=(FeedbackSlot that) const
Definition utils.h:652
static const int kInvalidSlot
Definition utils.h:663
FeedbackSlot WithOffset(int offset) const
Definition utils.h:658
bool operator==(FeedbackSlot that) const
Definition utils.h:651
static FeedbackSlot Invalid()
Definition utils.h:648
V8_EXPORT_PRIVATE friend std::ostream & operator<<(std::ostream &os, FeedbackSlot)
Definition utils.cc:26
friend size_t hash_value(FeedbackSlot slot)
Definition utils.h:654
static Float16 FromFloat32(float f32)
Definition float16.h:26
SetOncePointer & operator=(T *value)
Definition utils.h:340
bool operator!=(std::nullptr_t) const
Definition utils.h:346
bool operator==(std::nullptr_t) const
Definition utils.h:345
uint32_t count
std::string filename
int32_t offset
std::optional< TNode< JSArray > > a
ZoneVector< RpoNumber > & result
int x
uint32_t const mask
int n
Definition mul-fft.cc:296
int r
Definition mul-fft.cc:298
STL namespace.
constexpr unsigned CountLeadingZeros(T value)
Definition bits.h:100
V8_INLINE bool SimdMemEqual(const Char *lhs, const Char *rhs, size_t count)
Definition utils.h:461
int WriteBytes(const char *filename, const uint8_t *bytes, int size, bool verbose)
Definition utils.cc:201
Wide MultiplyLong(Narrow a, Narrow b)
Definition utils.h:193
void PrintPID(const char *format,...)
Definition utils.cc:53
std::make_unsigned< T >::type Abs(T a)
Definition utils.h:93
constexpr int kBitsPerByte
Definition globals.h:682
uint32_t ComputeLongHash(uint64_t key)
Definition utils.h:282
static uint16_t ByteReverse16(uint16_t value)
Definition utils.h:762
V8_INLINE void ZapCode(Address addr, size_t size_in_bytes)
Definition utils.h:839
double Modulo(double x, double y)
Definition utils.h:105
void PrintF(const char *format,...)
Definition utils.cc:39
char * ReadLine(const char *prompt)
Definition utils.cc:69
bool DoubleToBoolean(double d)
Definition utils.cc:208
int32_t signed_bitextract_32(int msb, int lsb, uint32_t x)
Definition utils.h:563
T JSMax(T x, T y)
Definition utils.h:75
static uint32_t ByteReverse32(uint32_t value)
Definition utils.h:770
uint32_t ComputeUnseededHash(uint32_t key)
Definition utils.h:271
bool CompareCharsEqualUnsigned(const lchar *lhs, const rchar *rhs, size_t chars)
Definition utils.h:488
std::ostream & operator<<(std::ostream &os, AtomicMemoryOrder order)
bool RoundUpToPageSize(size_t byte_length, size_t page_size, size_t max_allowed_byte_length, size_t *pages)
Definition utils.h:844
T SaturateRoundingQMul(T a, T b)
Definition utils.h:173
@ kToArrayIndex
Definition utils.h:749
@ kToIntegerIndex
Definition utils.h:749
uint32_t ComputePointerHash(void *ptr)
Definition utils.h:301
bool CompareCharsEqual(const lchar *lhs, const rchar *rhs, size_t chars)
Definition utils.h:509
int WriteChars(const char *filename, const char *str, int size, bool verbose)
Definition utils.cc:188
constexpr uint64_t kMaxUInt64
Definition globals.h:390
uintptr_t GetCurrentStackPosition()
Definition utils.cc:222
constexpr uint64_t TenToThe(uint32_t exponent)
Definition utils.h:544
constexpr bool is_intn(int64_t x, unsigned n)
Definition utils.h:568
bool PassesFilter(base::Vector< const char > name, base::Vector< const char > filter)
Definition utils.cc:238
static T ArithmeticShiftRight(T x, int shift)
Definition utils.h:60
constexpr T truncate_to_intn(T x, unsigned n)
Definition utils.h:580
Wide AddLong(Narrow a, Narrow b)
Definition utils.h:208
return ComputeSeededHash(static_cast< uint32_t >(key), HashSeed(isolate))
bool StringToIndex(Stream *stream, index_t *index)
Definition utils-inl.h:59
static const uint64_t kZeroHashSeed
Definition utils.h:267
int CompareChars(const lchar *lhs, const rchar *rhs, size_t chars)
Definition utils.h:536
V8_INLINE bool OverlappingCompare(const Char *lhs, const Char *rhs, size_t count)
Definition utils.h:450
T SaturateAdd(T a, T b)
Definition utils.h:131
return value
Definition map-inl.h:893
uint64_t unsigned_bitextract_64(int msb, int lsb, uint64_t x)
Definition utils.h:559
void PrintIsolate(void *isolate, const char *format,...)
Definition utils.cc:61
constexpr bool is_uintn(int64_t x, unsigned n)
Definition utils.h:574
T RoundingAverageUnsigned(T a, T b)
Definition utils.h:220
T SaturateSub(T a, T b)
Definition utils.h:152
static uint64_t ByteReverse64(uint64_t value)
Definition utils.h:779
int CompareCharsUnsigned(const lchar *lhs, const rchar *rhs, size_t chars)
Definition utils.h:519
uint32_t unsigned_bitextract_32(int msb, int lsb, uint32_t x)
Definition utils.h:555
std::string ReadFile(const char *filename, bool *exists, bool verbose)
Definition utils.cc:178
T JSMin(T x, T y)
Definition utils.h:84
static V ByteReverse(V value)
Definition utils.h:796
bool TryAddIndexChar(uint32_t *index, Char c)
uint32_t ComputeAddressHash(Address address)
Definition utils.h:306
#define PRINTF_FORMAT(format_param, dots_param)
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define DCHECK(condition)
Definition logging.h:482
constexpr T RoundUp(T x, intptr_t m)
Definition macros.h:387
#define V8_EXPORT_PRIVATE
Definition macros.h:460
#define DECLARE_IS_UINT_N(N)
Definition utils.h:598
#define INT_1_TO_63_LIST(V)
Definition utils.h:586
#define DECLARE_TRUNCATE_TO_INT_N(N)
Definition utils.h:603
#define DECLARE_IS_INT_N(N)
Definition utils.h:596
#define DECLARE_CHECKED_TRUNCATE_TO_INT_N(N)
Definition utils.h:609
#define V8_INLINE
Definition v8config.h:500
#define V8_CLANG_NO_SANITIZE(what)
defined(V8_TRIVIAL_ABI)
Definition v8config.h:765
#define V8_NOINLINE
Definition v8config.h:586