utils.h 22.6 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5 6
#ifndef V8_UTILS_UTILS_H_
#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"
jfb's avatar
jfb committed
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 28 29 30
#if defined(V8_USE_SIPHASH)
#include "src/third_party/siphash/halfsiphash.h"
#endif

31 32 33 34
#if defined(V8_OS_AIX)
#include <fenv.h>  // NOLINT(build/c++11)
#endif

35 36
namespace v8 {
namespace internal {
37 38 39 40

// ----------------------------------------------------------------------------
// General helper functions

41 42 43 44 45 46 47 48 49 50 51 52
template <typename T>
static T ArithmeticShiftRight(T x, int shift) {
  DCHECK_LE(0, shift);
  if (x < 0) {
    // Right shift of signed values is implementation defined. Simulate a
    // true arithmetic right shift by adding leading sign bits.
    using UnsignedT = typename std::make_unsigned<T>::type;
    UnsignedT mask = ~(static_cast<UnsignedT>(~0) >> shift);
    return (static_cast<UnsignedT>(x) >> shift) | mask;
  } else {
    return x >> shift;
  }
53 54
}

55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
// Returns the maximum of the two parameters according to JavaScript semantics.
template <typename T>
T JSMax(T x, T y) {
  if (std::isnan(x)) return x;
  if (std::isnan(y)) return y;
  if (std::signbit(x) < std::signbit(y)) return x;
  return x > y ? x : y;
}

// Returns the maximum of the two parameters according to JavaScript semantics.
template <typename T>
T JSMin(T x, T y) {
  if (std::isnan(x)) return x;
  if (std::isnan(y)) return y;
  if (std::signbit(x) < std::signbit(y)) return y;
  return x > y ? y : x;
}
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>
76
typename std::make_unsigned<T>::type Abs(T a) {
77 78 79
  // This is a branch-free implementation of the absolute value function and is
  // described in Warren's "Hacker's Delight", chapter 2. It avoids undefined
  // behavior with the arithmetic negation operation on signed values as well.
80
  using unsignedT = typename std::make_unsigned<T>::type;
81 82 83
  unsignedT x = static_cast<unsignedT>(a);
  unsignedT y = static_cast<unsignedT>(a >> (sizeof(T) * 8 - 1));
  return (x ^ y) - y;
84 85
}

86 87 88 89 90 91 92
inline double Modulo(double x, double y) {
#if defined(V8_OS_WIN)
  // Workaround MS fmod bugs. ECMA-262 says:
  // dividend is finite and divisor is an infinity => result equals dividend
  // dividend is a zero and divisor is nonzero finite => result equals dividend
  if (!(std::isfinite(x) && (!std::isfinite(y) && !std::isnan(y))) &&
      !(x == 0 && (y != 0 && std::isfinite(y)))) {
93 94 95 96 97
    double result = fmod(x, y);
    // Workaround MS bug in VS CRT in some OS versions, https://crbug.com/915045
    // fmod(-17, +/-1) should equal -0.0 but now returns 0.0.
    if (x < 0 && result == 0) result = -0.0;
    x = result;
98 99 100 101 102 103 104 105 106 107 108 109 110
  }
  return x;
#elif defined(V8_OS_AIX)
  // AIX raises an underflow exception for (Number.MIN_VALUE % Number.MAX_VALUE)
  feclearexcept(FE_ALL_EXCEPT);
  double result = std::fmod(x, y);
  int exception = fetestexcept(FE_UNDERFLOW);
  return (exception ? x : result);
#else
  return std::fmod(x, y);
#endif
}

111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
template <typename T>
T SaturateAdd(T a, T b) {
  if (std::is_signed<T>::value) {
    if (a > 0 && b > 0) {
      if (a > std::numeric_limits<T>::max() - b) {
        return std::numeric_limits<T>::max();
      }
    } else if (a < 0 && b < 0) {
      if (a < std::numeric_limits<T>::min() - b) {
        return std::numeric_limits<T>::min();
      }
    }
  } else {
    CHECK(std::is_unsigned<T>::value);
    if (a > std::numeric_limits<T>::max() - b) {
      return std::numeric_limits<T>::max();
    }
  }
  return a + b;
}

template <typename T>
T SaturateSub(T a, T b) {
  if (std::is_signed<T>::value) {
135
    if (a >= 0 && b < 0) {
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
      if (a > std::numeric_limits<T>::max() + b) {
        return std::numeric_limits<T>::max();
      }
    } else if (a < 0 && b > 0) {
      if (a < std::numeric_limits<T>::min() + b) {
        return std::numeric_limits<T>::min();
      }
    }
  } else {
    CHECK(std::is_unsigned<T>::value);
    if (a < b) {
      return static_cast<T>(0);
    }
  }
  return a - b;
}
152

153 154 155 156 157 158 159 160 161 162 163 164 165 166
template <typename T>
T SaturateRoundingQMul(T a, T b) {
  // Saturating rounding multiplication for Q-format numbers. See
  // https://en.wikipedia.org/wiki/Q_(number_format) for a description.
  // Specifically this supports Q7, Q15, and Q31. This follows the
  // implementation in simulator-logic-arm64.cc (sqrdmulh) to avoid overflow
  // when a == b == int32 min.
  static_assert(std::is_integral<T>::value, "only integral types");

  constexpr int size_in_bits = sizeof(T) * 8;
  int round_const = 1 << (size_in_bits - 2);
  int64_t product = a * b;
  product += round_const;
  product >>= (size_in_bits - 1);
167
  return base::saturated_cast<T>(product);
168 169
}

170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
// Multiply two numbers, returning a result that is twice as wide, no overflow.
// Put Wide first so we can use function template argument deduction for Narrow,
// and callers can provide only Wide.
template <typename Wide, typename Narrow>
Wide MultiplyLong(Narrow a, Narrow b) {
  static_assert(
      std::is_integral<Narrow>::value && std::is_integral<Wide>::value,
      "only integral types");
  static_assert(std::is_signed<Narrow>::value == std::is_signed<Wide>::value,
                "both must have same signedness");
  static_assert(sizeof(Narrow) * 2 == sizeof(Wide), "only twice as long");

  return static_cast<Wide>(a) * static_cast<Wide>(b);
}

185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
// Add two numbers, returning a result that is twice as wide, no overflow.
// Put Wide first so we can use function template argument deduction for Narrow,
// and callers can provide only Wide.
template <typename Wide, typename Narrow>
Wide AddLong(Narrow a, Narrow b) {
  static_assert(
      std::is_integral<Narrow>::value && std::is_integral<Wide>::value,
      "only integral types");
  static_assert(std::is_signed<Narrow>::value == std::is_signed<Wide>::value,
                "both must have same signedness");
  static_assert(sizeof(Narrow) * 2 == sizeof(Wide), "only twice as long");

  return static_cast<Wide>(a) + static_cast<Wide>(b);
}

200 201 202 203 204 205 206
template <typename T>
inline T RoundingAverageUnsigned(T a, T b) {
  static_assert(std::is_unsigned<T>::value, "Only for unsiged types");
  static_assert(sizeof(T) < sizeof(uint64_t), "Must be smaller than uint64_t");
  return (static_cast<uint64_t>(a) + static_cast<uint64_t>(b) + 1) >> 1;
}

207 208 209 210 211
// Helper macros for defining a contiguous sequence of field offset constants.
// Example: (backslashes at the ends of respective lines of this multi-line
// macro definition are omitted here to please the compiler)
//
// #define MAP_FIELDS(V)
212
//   V(kField1Offset, kTaggedSize)
213 214
//   V(kField2Offset, kIntSize)
//   V(kField3Offset, kIntSize)
215
//   V(kField4Offset, kSystemPointerSize)
216 217 218 219
//   V(kSize, 0)
//
// DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, MAP_FIELDS)
//
220
#define DEFINE_ONE_FIELD_OFFSET(Name, Size) Name, Name##End = Name + (Size)-1,
221 222 223 224 225 226

#define DEFINE_FIELD_OFFSET_CONSTANTS(StartOffset, LIST_MACRO) \
  enum {                                                       \
    LIST_MACRO##_StartOffset = StartOffset - 1,                \
    LIST_MACRO(DEFINE_ONE_FIELD_OFFSET)                        \
  };
227

228 229 230
// Size of the field defined by DEFINE_FIELD_OFFSET_CONSTANTS
#define FIELD_SIZE(Name) (Name##End + 1 - Name)

231 232 233
// Compare two offsets with static cast
#define STATIC_ASSERT_FIELD_OFFSETS_EQUAL(Offset1, Offset2) \
  STATIC_ASSERT(static_cast<int>(Offset1) == Offset2)
234 235 236
// ----------------------------------------------------------------------------
// Hash function.

Yang Guo's avatar
Yang Guo committed
237
static const uint64_t kZeroHashSeed = 0;
238

239
// Thomas Wang, Integer Hash Functions.
240 241
// http://www.concentric.net/~Ttwang/tech/inthash.htm`
inline uint32_t ComputeUnseededHash(uint32_t key) {
242 243 244 245 246 247 248
  uint32_t hash = key;
  hash = ~hash + (hash << 15);  // hash = (hash << 15) - hash - 1;
  hash = hash ^ (hash >> 12);
  hash = hash + (hash << 2);
  hash = hash ^ (hash >> 4);
  hash = hash * 2057;  // hash = (hash + (hash << 3)) + (hash << 11);
  hash = hash ^ (hash >> 16);
249
  return hash & 0x3fffffff;
250
}
251

252
inline uint32_t ComputeLongHash(uint64_t key) {
253 254 255 256 257 258 259
  uint64_t hash = key;
  hash = ~hash + (hash << 18);  // hash = (hash << 18) - hash - 1;
  hash = hash ^ (hash >> 31);
  hash = hash * 21;  // hash = (hash + (hash << 2)) + (hash << 4);
  hash = hash ^ (hash >> 11);
  hash = hash + (hash << 6);
  hash = hash ^ (hash >> 22);
260
  return static_cast<uint32_t>(hash & 0x3fffffff);
261 262
}

263
inline uint32_t ComputeSeededHash(uint32_t key, uint64_t seed) {
264 265 266
#ifdef V8_USE_SIPHASH
  return halfsiphash(key, seed);
#else
267
  return ComputeLongHash(static_cast<uint64_t>(key) ^ seed);
268
#endif  // V8_USE_SIPHASH
269
}
270

271
inline uint32_t ComputePointerHash(void* ptr) {
272
  return ComputeUnseededHash(
273
      static_cast<uint32_t>(reinterpret_cast<intptr_t>(ptr)));
274 275
}

276
inline uint32_t ComputeAddressHash(Address address) {
277
  return ComputeUnseededHash(static_cast<uint32_t>(address & 0xFFFFFFFFul));
278
}
279

280 281 282
// ----------------------------------------------------------------------------
// Miscellaneous

283 284 285 286 287 288 289 290 291
// Memory offset for lower and higher bits in a 64 bit integer.
#if defined(V8_TARGET_LITTLE_ENDIAN)
static const int kInt64LowerHalfMemoryOffset = 0;
static const int kInt64UpperHalfMemoryOffset = 4;
#elif defined(V8_TARGET_BIG_ENDIAN)
static const int kInt64LowerHalfMemoryOffset = 4;
static const int kInt64UpperHalfMemoryOffset = 0;
#endif  // V8_TARGET_LITTLE_ENDIAN

292
// A pointer that can only be set once and doesn't allow NULL values.
293
template <typename T>
294 295
class SetOncePointer {
 public:
296
  SetOncePointer() = default;
297

298
  bool is_set() const { return pointer_ != nullptr; }
299 300

  T* get() const {
301
    DCHECK_NOT_NULL(pointer_);
302 303 304 305
    return pointer_;
  }

  void set(T* value) {
306
    DCHECK(pointer_ == nullptr && value != nullptr);
307 308 309
    pointer_ = value;
  }

310
  SetOncePointer& operator=(T* value) {
311
    set(value);
312
    return *this;
313 314 315 316 317
  }

  bool operator==(std::nullptr_t) const { return pointer_ == nullptr; }
  bool operator!=(std::nullptr_t) const { return pointer_ != nullptr; }

318
 private:
319
  T* pointer_ = nullptr;
320 321
};

322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
// Compare 8bit/16bit chars to 8bit/16bit chars.
template <typename lchar, typename rchar>
inline bool CompareCharsEqualUnsigned(const lchar* lhs, const rchar* rhs,
                                      size_t chars) {
  STATIC_ASSERT(std::is_unsigned<lchar>::value);
  STATIC_ASSERT(std::is_unsigned<rchar>::value);
  if (sizeof(*lhs) == sizeof(*rhs)) {
    // memcmp compares byte-by-byte, but for equality it doesn't matter whether
    // two-byte char comparison is little- or big-endian.
    return memcmp(lhs, rhs, chars * sizeof(*lhs)) == 0;
  }
  for (const lchar* limit = lhs + chars; lhs < limit; ++lhs, ++rhs) {
    if (*lhs != *rhs) return false;
  }
  return true;
}

template <typename lchar, typename rchar>
inline bool CompareCharsEqual(const lchar* lhs, const rchar* rhs,
                              size_t chars) {
  using ulchar = typename std::make_unsigned<lchar>::type;
  using urchar = typename std::make_unsigned<rchar>::type;
  return CompareCharsEqualUnsigned(reinterpret_cast<const ulchar*>(lhs),
                                   reinterpret_cast<const urchar*>(rhs), chars);
}

348
// Compare 8bit/16bit chars to 8bit/16bit chars.
349
template <typename lchar, typename rchar>
350 351
inline int CompareCharsUnsigned(const lchar* lhs, const rchar* rhs,
                                size_t chars) {
352 353
  STATIC_ASSERT(std::is_unsigned<lchar>::value);
  STATIC_ASSERT(std::is_unsigned<rchar>::value);
354 355 356 357
  if (sizeof(*lhs) == sizeof(char) && sizeof(*rhs) == sizeof(char)) {
    // memcmp compares byte-by-byte, yielding wrong results for two-byte
    // strings on little-endian systems.
    return memcmp(lhs, rhs, chars);
358
  }
359
  for (const lchar* limit = lhs + chars; lhs < limit; ++lhs, ++rhs) {
360 361 362 363 364 365
    int r = static_cast<int>(*lhs) - static_cast<int>(*rhs);
    if (r != 0) return r;
  }
  return 0;
}

366 367
template <typename lchar, typename rchar>
inline int CompareChars(const lchar* lhs, const rchar* rhs, size_t chars) {
368 369 370 371
  using ulchar = typename std::make_unsigned<lchar>::type;
  using urchar = typename std::make_unsigned<rchar>::type;
  return CompareCharsUnsigned(reinterpret_cast<const ulchar*>(lhs),
                              reinterpret_cast<const urchar*>(rhs), chars);
372 373
}

374
// Calculate 10^exponent.
375
inline int TenToThe(int exponent) {
376 377
  DCHECK_LE(exponent, 9);
  DCHECK_GE(exponent, 1);
378 379 380 381
  int answer = 10;
  for (int i = 1; i < exponent; i++) answer *= 10;
  return answer;
}
382

383 384 385 386 387 388 389 390 391
// Bit field extraction.
inline uint32_t unsigned_bitextract_32(int msb, int lsb, uint32_t x) {
  return (x >> lsb) & ((1 << (1 + msb - lsb)) - 1);
}

inline uint64_t unsigned_bitextract_64(int msb, int lsb, uint64_t x) {
  return (x >> lsb) & ((static_cast<uint64_t>(1) << (1 + msb - lsb)) - 1);
}

392 393
inline int32_t signed_bitextract_32(int msb, int lsb, uint32_t x) {
  return static_cast<int32_t>(x << (31 - msb)) >> (lsb + 31 - msb);
394 395 396 397
}

// Check number width.
inline bool is_intn(int64_t x, unsigned n) {
398
  DCHECK((0 < n) && (n < 64));
399 400 401 402 403
  int64_t limit = static_cast<int64_t>(1) << (n - 1);
  return (-limit <= x) && (x < limit);
}

inline bool is_uintn(int64_t x, unsigned n) {
404
  DCHECK((0 < n) && (n < (sizeof(x) * kBitsPerByte)));
405 406 407 408 409
  return !(x >> n);
}

template <class T>
inline T truncate_to_intn(T x, unsigned n) {
410
  DCHECK((0 < n) && (n < (sizeof(x) * kBitsPerByte)));
411 412 413
  return (x & ((static_cast<T>(1) << n) - 1));
}

414 415 416 417 418 419 420 421 422 423
// clang-format off
#define INT_1_TO_63_LIST(V)                                   \
  V(1) V(2) V(3) V(4) V(5) V(6) V(7) V(8) V(9) V(10)          \
  V(11) V(12) V(13) V(14) V(15) V(16) V(17) V(18) V(19) V(20) \
  V(21) V(22) V(23) V(24) V(25) V(26) V(27) V(28) V(29) V(30) \
  V(31) V(32) V(33) V(34) V(35) V(36) V(37) V(38) V(39) V(40) \
  V(41) V(42) V(43) V(44) V(45) V(46) V(47) V(48) V(49) V(50) \
  V(51) V(52) V(53) V(54) V(55) V(56) V(57) V(58) V(59) V(60) \
  V(61) V(62) V(63)
// clang-format on
424 425 426 427 428 429 430 431 432 433 434 435 436

#define DECLARE_IS_INT_N(N) \
  inline bool is_int##N(int64_t x) { return is_intn(x, N); }
#define DECLARE_IS_UINT_N(N)    \
  template <class T>            \
  inline bool is_uint##N(T x) { \
    return is_uintn(x, N);      \
  }
#define DECLARE_TRUNCATE_TO_INT_N(N) \
  template <class T>                 \
  inline T truncate_to_int##N(T x) { \
    return truncate_to_intn(x, N);   \
  }
437 438 439 440 441 442
INT_1_TO_63_LIST(DECLARE_IS_INT_N)
INT_1_TO_63_LIST(DECLARE_IS_UINT_N)
INT_1_TO_63_LIST(DECLARE_TRUNCATE_TO_INT_N)
#undef DECLARE_IS_INT_N
#undef DECLARE_IS_UINT_N
#undef DECLARE_TRUNCATE_TO_INT_N
443

444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
// clang-format off
#define INT_0_TO_127_LIST(V)                                          \
V(0)   V(1)   V(2)   V(3)   V(4)   V(5)   V(6)   V(7)   V(8)   V(9)   \
V(10)  V(11)  V(12)  V(13)  V(14)  V(15)  V(16)  V(17)  V(18)  V(19)  \
V(20)  V(21)  V(22)  V(23)  V(24)  V(25)  V(26)  V(27)  V(28)  V(29)  \
V(30)  V(31)  V(32)  V(33)  V(34)  V(35)  V(36)  V(37)  V(38)  V(39)  \
V(40)  V(41)  V(42)  V(43)  V(44)  V(45)  V(46)  V(47)  V(48)  V(49)  \
V(50)  V(51)  V(52)  V(53)  V(54)  V(55)  V(56)  V(57)  V(58)  V(59)  \
V(60)  V(61)  V(62)  V(63)  V(64)  V(65)  V(66)  V(67)  V(68)  V(69)  \
V(70)  V(71)  V(72)  V(73)  V(74)  V(75)  V(76)  V(77)  V(78)  V(79)  \
V(80)  V(81)  V(82)  V(83)  V(84)  V(85)  V(86)  V(87)  V(88)  V(89)  \
V(90)  V(91)  V(92)  V(93)  V(94)  V(95)  V(96)  V(97)  V(98)  V(99)  \
V(100) V(101) V(102) V(103) V(104) V(105) V(106) V(107) V(108) V(109) \
V(110) V(111) V(112) V(113) V(114) V(115) V(116) V(117) V(118) V(119) \
V(120) V(121) V(122) V(123) V(124) V(125) V(126) V(127)
// clang-format on

461
class FeedbackSlot {
462
 public:
463 464
  FeedbackSlot() : id_(kInvalidSlot) {}
  explicit FeedbackSlot(int id) : id_(id) {}
465

466 467
  int ToInt() const { return id_; }

468
  static FeedbackSlot Invalid() { return FeedbackSlot(); }
469 470
  bool IsInvalid() const { return id_ == kInvalidSlot; }

471 472
  bool operator==(FeedbackSlot that) const { return this->id_ == that.id_; }
  bool operator!=(FeedbackSlot that) const { return !(*this == that); }
473

474
  friend size_t hash_value(FeedbackSlot slot) { return slot.ToInt(); }
475 476
  V8_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream& os,
                                                    FeedbackSlot);
477

478 479 480 481
  FeedbackSlot WithOffset(int offset) const {
    return FeedbackSlot(id_ + offset);
  }

482 483 484 485 486 487
 private:
  static const int kInvalidSlot = -1;

  int id_;
};

488
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, FeedbackSlot);
489

490
class BytecodeOffset {
491
 public:
492
  explicit BytecodeOffset(int id) : id_(id) {}
493 494
  int ToInt() const { return id_; }

495
  static BytecodeOffset None() { return BytecodeOffset(kNoneId); }
496

497 498 499 500
  // Special bailout id support for deopting into the {JSConstructStub} stub.
  // The following hard-coded deoptimization points are supported by the stub:
  //  - {ConstructStubCreate} maps to {construct_stub_create_deopt_pc_offset}.
  //  - {ConstructStubInvoke} maps to {construct_stub_invoke_deopt_pc_offset}.
501 502
  static BytecodeOffset ConstructStubCreate() { return BytecodeOffset(1); }
  static BytecodeOffset ConstructStubInvoke() { return BytecodeOffset(2); }
503 504 505 506 507
  bool IsValidForConstructStub() const {
    return id_ == ConstructStubCreate().ToInt() ||
           id_ == ConstructStubInvoke().ToInt();
  }

508
  bool IsNone() const { return id_ == kNoneId; }
509 510 511 512 513 514 515 516 517
  bool operator==(const BytecodeOffset& other) const {
    return id_ == other.id_;
  }
  bool operator!=(const BytecodeOffset& other) const {
    return id_ != other.id_;
  }
  friend size_t hash_value(BytecodeOffset);
  V8_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream&,
                                                    BytecodeOffset);
518 519

 private:
520 521
  friend class Builtins;

522 523 524
  static const int kNoneId = -1;

  // Using 0 could disguise errors.
525
  // Builtin continuations bailout ids start here. If you need to add a
526
  // non-builtin BytecodeOffset, add it before this id so that this Id has the
527
  // highest number.
528
  static const int kFirstBuiltinContinuationId = 1;
529

530 531 532
  int id_;
};

533 534 535 536
// ----------------------------------------------------------------------------
// I/O support.

// Our version of printf().
537
V8_EXPORT_PRIVATE void PRINTF_FORMAT(1, 2) PrintF(const char* format, ...);
538 539
V8_EXPORT_PRIVATE void PRINTF_FORMAT(2, 3)
    PrintF(FILE* out, const char* format, ...);
540 541

// Prepends the current process ID to the output.
jfb's avatar
jfb committed
542
void PRINTF_FORMAT(1, 2) PrintPID(const char* format, ...);
543

544
// Prepends the current process ID and given isolate pointer to the output.
jfb's avatar
jfb committed
545
void PRINTF_FORMAT(2, 3) PrintIsolate(void* isolate, const char* format, ...);
546

547 548 549 550 551 552
// Read a line of characters after printing the prompt to stdout. The resulting
// char* needs to be disposed off with DeleteArray by the caller.
char* ReadLine(const char* prompt);

// Write size chars from str to the file given by filename.
// The file is overwritten. Returns the number of chars written.
553
int WriteChars(const char* filename, const char* str, int size,
554 555 556 557
               bool verbose = true);

// Write size bytes to the file given by filename.
// The file is overwritten. Returns the number of bytes written.
558
int WriteBytes(const char* filename, const byte* bytes, int size,
559 560
               bool verbose = true);

561
// Simple support to read a file into std::string.
562
// On return, *exits tells whether the file existed.
563 564
V8_EXPORT_PRIVATE std::string ReadFile(const char* filename, bool* exists,
                                       bool verbose = true);
565 566
V8_EXPORT_PRIVATE std::string ReadFile(FILE* file, bool* exists,
                                       bool verbose = true);
567

568 569
bool DoubleToBoolean(double d);

570 571 572
template <typename Char>
bool TryAddIndexChar(uint32_t* index, Char c);

573 574
enum ToIndexMode { kToArrayIndex, kToIntegerIndex };

575
// {index_t} is meant to be {uint32_t} or {size_t}.
576 577
template <typename Stream, typename index_t,
          enum ToIndexMode mode = kToArrayIndex>
578
bool StringToIndex(Stream* stream, index_t* index);
579

580 581 582 583 584 585
// Returns the current stack top. Works correctly with ASAN and SafeStack.
// GetCurrentStackPosition() should not be inlined, because it works on stack
// frames if it were inlined into a function with a huge stack frame it would
// return an address significantly above the actual current stack position.
V8_EXPORT_PRIVATE V8_NOINLINE uintptr_t GetCurrentStackPosition();

586
static inline uint16_t ByteReverse16(uint16_t value) {
587
#if V8_HAS_BUILTIN_BSWAP16
588
  return __builtin_bswap16(value);
589
#else
590
  return value << 8 | (value >> 8 & 0x00FF);
591
#endif
592 593 594
}

static inline uint32_t ByteReverse32(uint32_t value) {
595
#if V8_HAS_BUILTIN_BSWAP32
596
  return __builtin_bswap32(value);
597
#else
598 599
  return value << 24 | ((value << 8) & 0x00FF0000) |
         ((value >> 8) & 0x0000FF00) | ((value >> 24) & 0x00000FF);
600
#endif
601 602 603
}

static inline uint64_t ByteReverse64(uint64_t value) {
604
#if V8_HAS_BUILTIN_BSWAP64
605
  return __builtin_bswap64(value);
606
#else
607 608 609 610 611 612 613 614 615
  size_t bits_of_v = sizeof(value) * kBitsPerByte;
  return value << (bits_of_v - 8) |
         ((value << (bits_of_v - 24)) & 0x00FF000000000000) |
         ((value << (bits_of_v - 40)) & 0x0000FF0000000000) |
         ((value << (bits_of_v - 56)) & 0x000000FF00000000) |
         ((value >> (bits_of_v - 56)) & 0x00000000FF000000) |
         ((value >> (bits_of_v - 40)) & 0x0000000000FF0000) |
         ((value >> (bits_of_v - 24)) & 0x000000000000FF00) |
         ((value >> (bits_of_v - 8)) & 0x00000000000000FF);
616
#endif
617 618 619 620 621 622 623 624 625 626 627 628 629 630
}

template <typename V>
static inline V ByteReverse(V value) {
  size_t size_of_v = sizeof(value);
  switch (size_of_v) {
    case 1:
      return value;
    case 2:
      return static_cast<V>(ByteReverse16(static_cast<uint16_t>(value)));
    case 4:
      return static_cast<V>(ByteReverse32(static_cast<uint32_t>(value)));
    case 8:
      return static_cast<V>(ByteReverse64(static_cast<uint64_t>(value)));
631 632 633 634 635
    default:
      UNREACHABLE();
  }
}

636 637 638 639 640 641 642 643 644 645 646 647 648
#if V8_OS_AIX
// glibc on aix has a bug when using ceil, trunc or nearbyint:
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97086
template <typename T>
T FpOpWorkaround(T input, T value) {
  if (/*if -*/ std::signbit(input) && value == 0.0 &&
      /*if +*/ !std::signbit(value)) {
    return -0.0;
  }
  return value;
}
#endif

649 650
V8_EXPORT_PRIVATE bool PassesFilter(base::Vector<const char> name,
                                    base::Vector<const char> filter);
651

652 653 654 655 656 657 658 659 660
// Zap the specified area with a specific byte pattern. This currently defaults
// to int3 on x64 and ia32. On other architectures this will produce unspecified
// instruction sequences.
// TODO(jgruber): Better support for other architectures.
V8_INLINE void ZapCode(Address addr, size_t size_in_bytes) {
  static constexpr int kZapByte = 0xCC;
  std::memset(reinterpret_cast<void*>(addr), kZapByte, size_in_bytes);
}

661 662
}  // namespace internal
}  // namespace v8
663

664
#endif  // V8_UTILS_UTILS_H_