blob: a04a08ac9dc2c9ad746e5090deb0252ebee8f899 [file] [log] [blame]
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_BASE_MACROS_H_
#define V8_BASE_MACROS_H_
#include <limits>
#include <type_traits>
#include "include/v8config.h"
#include "src/base/compiler-specific.h"
#include "src/base/logging.h"
// No-op macro which is used to work around MSVC's funky VA_ARGS support.
#define EXPAND(X) X
// This macro does nothing. That's all.
#define NOTHING(...)
#define CONCAT_(a, ...) a##__VA_ARGS__
#define CONCAT(a, ...) CONCAT_(a, __VA_ARGS__)
// Creates an unique identifier. Useful for scopes to avoid shadowing names.
#define UNIQUE_IDENTIFIER(base) CONCAT(base, __COUNTER__)
// COUNT_MACRO_ARGS(...) returns the number of arguments passed. Currently, up
// to 8 arguments are supported.
#define COUNT_MACRO_ARGS(...) \
EXPAND(COUNT_MACRO_ARGS_IMPL(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0))
#define COUNT_MACRO_ARGS_IMPL(_8, _7, _6, _5, _4, _3, _2, _1, N, ...) N
// GET_NTH_ARG(N, ...) returns the Nth argument in the list of arguments
// following. Currently, up to N=8 is supported.
#define GET_NTH_ARG(N, ...) CONCAT(GET_NTH_ARG_IMPL_, N)(__VA_ARGS__)
#define GET_NTH_ARG_IMPL_0(_0, ...) _0
#define GET_NTH_ARG_IMPL_1(_0, _1, ...) _1
#define GET_NTH_ARG_IMPL_2(_0, _1, _2, ...) _2
#define GET_NTH_ARG_IMPL_3(_0, _1, _2, _3, ...) _3
#define GET_NTH_ARG_IMPL_4(_0, _1, _2, _3, _4, ...) _4
#define GET_NTH_ARG_IMPL_5(_0, _1, _2, _3, _4, _5, ...) _5
#define GET_NTH_ARG_IMPL_6(_0, _1, _2, _3, _4, _5, _6, ...) _6
#define GET_NTH_ARG_IMPL_7(_0, _1, _2, _3, _4, _5, _6, _7, ...) _7
// UNPAREN(x) removes a layer of nested parentheses on x, if any. This means
// that both UNPAREN(x) and UNPAREN((x)) expand to x. This is helpful for macros
// that want to support multi argument templates with commas, e.g.
//
// #define FOO(Type, Name) UNPAREN(Type) Name;
//
// will work with both
//
// FOO(int, x);
// FOO((Foo<int, double, float>), x);
#define UNPAREN(X) CONCAT(DROP_, UNPAREN_ X)
#define UNPAREN_(...) UNPAREN_ __VA_ARGS__
#define DROP_UNPAREN_
#define OFFSET_OF(type, field) offsetof(type, field)
// A comma, to be used in macro arguments where it would otherwise be
// interpreted as separator of arguments.
#define LITERAL_COMMA ,
// The arraysize(arr) macro returns the # of elements in an array arr.
// The expression is a compile-time constant, and therefore can be
// used in defining new arrays, for example. If you use arraysize on
// a pointer by mistake, you will get a compile-time error.
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
// This template function declaration is used in defining arraysize.
// Note that the function doesn't need an implementation, as we only
// use its type.
template <typename T, size_t N>
char (&ArraySizeHelper(T (&array)[N]))[N];
#if !V8_CC_MSVC
// That gcc wants both of these prototypes seems mysterious. VC, for
// its part, can't decide which to use (another mystery). Matching of
// template overloads: the final frontier.
template <typename T, size_t N>
char (&ArraySizeHelper(const T (&array)[N]))[N];
#endif
// This is an equivalent to C++20's std::bit_cast<>(), but with additional
// warnings. It morally does what `*reinterpret_cast<Dest*>(&source)` does, but
// the cast/deref pair is undefined behavior, while bit_cast<>() isn't.
//
// This is not a magic "get out of UB free" card. This must only be used on
// values, not on references or pointers. For pointers, use
// reinterpret_cast<>(), or static_cast<>() when casting between void* and other
// pointers, and then look at https://eel.is/c++draft/basic.lval#11 as that's
// probably UB also.
namespace v8::base {
template <class Dest, class Source>
V8_INLINE Dest bit_cast(Source const& source) {
static_assert(!std::is_pointer_v<Source>,
"bit_cast must not be used on pointer types");
static_assert(!std::is_pointer_v<Dest>,
"bit_cast must not be used on pointer types");
static_assert(!std::is_reference_v<Dest>,
"bit_cast must not be used on reference types");
static_assert(
sizeof(Dest) == sizeof(Source),
"bit_cast requires source and destination types to be the same size");
static_assert(std::is_trivially_copyable_v<Source>,
"bit_cast requires the source type to be trivially copyable");
static_assert(
std::is_trivially_copyable_v<Dest>,
"bit_cast requires the destination type to be trivially copyable");
#if V8_HAS_BUILTIN_BIT_CAST
return __builtin_bit_cast(Dest, source);
#else
Dest dest;
memcpy(&dest, &source, sizeof(dest));
return dest;
#endif
}
} // namespace v8::base
// Explicitly declare the assignment operator as deleted.
// Note: This macro is deprecated and will be removed soon. Please explicitly
// delete the assignment operator instead.
#define DISALLOW_ASSIGN(TypeName) TypeName& operator=(const TypeName&) = delete
// Explicitly declare all implicit constructors as deleted, namely the
// default constructor, copy constructor and operator= functions.
// This is especially useful for classes containing only static methods.
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
TypeName() = delete; \
TypeName(const TypeName&) = delete; \
DISALLOW_ASSIGN(TypeName)
// Disallow copying a type, but provide default construction, move construction
// and move assignment. Especially useful for move-only structs.
#define MOVE_ONLY_WITH_DEFAULT_CONSTRUCTORS(TypeName) \
TypeName() = default; \
MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(TypeName)
// Disallow copying a type, and only provide move construction and move
// assignment. Especially useful for move-only structs.
#define MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(TypeName) \
TypeName(TypeName&&) V8_NOEXCEPT = default; \
TypeName& operator=(TypeName&&) V8_NOEXCEPT = default; \
TypeName(const TypeName&) = delete; \
DISALLOW_ASSIGN(TypeName)
// A macro to disallow the dynamic allocation.
// This should be used in the private: declarations for a class
// Declaring operator new and delete as deleted is not spec compliant.
// Extract from 3.2.2 of C++11 spec:
// [...] A non-placement deallocation function for a class is
// odr-used by the definition of the destructor of that class, [...]
#define DISALLOW_NEW_AND_DELETE() \
void* operator new(size_t) { v8::base::OS::Abort(); } \
void* operator new[](size_t) { v8::base::OS::Abort(); } \
void operator delete(void*, size_t) { v8::base::OS::Abort(); } \
void operator delete[](void*, size_t) { v8::base::OS::Abort(); }
// Define V8_USE_ADDRESS_SANITIZER macro.
#if defined(__has_feature)
#if __has_feature(address_sanitizer)
#define V8_USE_ADDRESS_SANITIZER 1
#endif
#endif
// Define V8_USE_HWADDRESS_SANITIZER macro.
#if defined(__has_feature)
#if __has_feature(hwaddress_sanitizer)
#define V8_USE_HWADDRESS_SANITIZER 1
#endif
#endif
// Define V8_USE_MEMORY_SANITIZER macro.
#if defined(__has_feature)
#if __has_feature(memory_sanitizer)
#define V8_USE_MEMORY_SANITIZER 1
#endif
#endif
// Define V8_USE_UNDEFINED_BEHAVIOR_SANITIZER macro.
#if defined(__has_feature)
#if __has_feature(undefined_behavior_sanitizer)
#define V8_USE_UNDEFINED_BEHAVIOR_SANITIZER 1
#endif
#endif
// Define V8_USE_SAFE_STACK macro.
#if defined(__has_feature)
#if __has_feature(safe_stack)
#define V8_USE_SAFE_STACK 1
#endif // __has_feature(safe_stack)
#endif // defined(__has_feature)
// DISABLE_CFI_PERF -- Disable Control Flow Integrity checks for Perf reasons.
#define DISABLE_CFI_PERF V8_CLANG_NO_SANITIZE("cfi")
// DISABLE_CFI_ICALL -- Disable Control Flow Integrity indirect call checks,
// useful because calls into JITed code can not be CFI verified. Same for
// UBSan's function pointer type checks.
#ifdef V8_OS_WIN
// On Windows, also needs __declspec(guard(nocf)) for CFG.
#define DISABLE_CFI_ICALL \
V8_CLANG_NO_SANITIZE("cfi-icall") \
V8_CLANG_NO_SANITIZE("function") \
__declspec(guard(nocf))
#else
#define DISABLE_CFI_ICALL \
V8_CLANG_NO_SANITIZE("cfi-icall") \
V8_CLANG_NO_SANITIZE("function")
#endif
// V8_PRETTY_FUNCTION_VALUE_OR(ELSE) emits a pretty function value, if
// available for this compiler, otherwise it emits ELSE.
#if defined(V8_CC_GNU)
#define V8_PRETTY_FUNCTION_VALUE_OR(ELSE) __PRETTY_FUNCTION__
#elif defined(V8_CC_MSVC)
#define V8_PRETTY_FUNCTION_VALUE_OR(ELSE) __FUNCSIG__
#else
#define V8_PRETTY_FUNCTION_VALUE_OR(ELSE) ELSE
#endif
namespace v8 {
namespace base {
// Note that some implementations of std::is_trivially_copyable mandate that at
// least one of the copy constructor, move constructor, copy assignment or move
// assignment is non-deleted, while others do not. Be aware that also
// base::is_trivially_copyable will differ for these cases.
template <typename T>
struct is_trivially_copyable {
#if V8_CC_MSVC || (__GNUC__ == 12 && __GNUC_MINOR__ <= 2)
// Unfortunately, MSVC 2015 is broken in that std::is_trivially_copyable can
// be false even though it should be true according to the standard.
// (status at 2018-02-26, observed on the msvc waterfall bot).
// Interestingly, the lower-level primitives used below are working as
// intended, so we reimplement this according to the standard.
// See also https://developercommunity.visualstudio.com/content/problem/
// 170883/msvc-type-traits-stdis-trivial-is-bugged.html.
//
// GCC 12.1 and 12.2 are broken too, they are shipped by some stable Linux
// distributions, so the same polyfill is also used.
// See
// https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=aeba3e009b0abfccaf01797556445dbf891cc8dc
static constexpr bool value =
// Copy constructor is trivial or deleted.
(std::is_trivially_copy_constructible<T>::value ||
!std::is_copy_constructible<T>::value) &&
// Copy assignment operator is trivial or deleted.
(std::is_trivially_copy_assignable<T>::value ||
!std::is_copy_assignable<T>::value) &&
// Move constructor is trivial or deleted.
(std::is_trivially_move_constructible<T>::value ||
!std::is_move_constructible<T>::value) &&
// Move assignment operator is trivial or deleted.
(std::is_trivially_move_assignable<T>::value ||
!std::is_move_assignable<T>::value) &&
// (Some implementations mandate that one of the above is non-deleted, but
// the standard does not, so let's skip this check.)
// Trivial non-deleted destructor.
std::is_trivially_destructible<T>::value;
#else
static constexpr bool value = std::is_trivially_copyable<T>::value;
#endif
};
#define ASSERT_TRIVIALLY_COPYABLE(T) \
static_assert(::v8::base::is_trivially_copyable<T>::value, \
#T " should be trivially copyable")
#define ASSERT_NOT_TRIVIALLY_COPYABLE(T) \
static_assert(!::v8::base::is_trivially_copyable<T>::value, \
#T " should not be trivially copyable")
// Be aware that base::is_trivially_destructible will differ from
// std::is_trivially_destructible for cases like DirectHandle<T>.
template <typename T>
struct is_trivially_destructible : public std::is_trivially_destructible<T> {};
#define ASSERT_TRIVIALLY_DESTRUCTIBLE(T) \
static_assert(::v8::base::is_trivially_destructible<T>::value, \
#T " should be trivially destructible")
#define ASSERT_NOT_TRIVIALLY_DESTRUCTIBLE(T) \
static_assert(!::v8::base::is_trivially_destructible<T>::value, \
#T " should not be trivially destructible")
// The USE(x, ...) template is used to silence C++ compiler warnings
// issued for (yet) unused variables (typically parameters).
// The arguments are guaranteed to be evaluated from left to right.
struct Use {
template <typename T>
constexpr Use(T&&) {} // NOLINT(runtime/explicit)
};
#define USE(...) \
do { \
::v8::base::Use unused_tmp_array_for_use_macro[]{__VA_ARGS__}; \
(void)unused_tmp_array_for_use_macro; \
} while (false)
} // namespace base
} // namespace v8
// implicit_cast<A>(x) triggers an implicit cast from {x} to type {A}. This is
// useful in situations where static_cast<A>(x) would do too much.
// Only use this for cheap-to-copy types, or use move semantics explicitly.
template <class A>
V8_INLINE A implicit_cast(A x) {
return x;
}
// Define our own macros for writing 64-bit constants. This is less fragile
// than defining __STDC_CONSTANT_MACROS before including <stdint.h>, and it
// works on compilers that don't have it (like MSVC).
#if V8_CC_MSVC
# if V8_HOST_ARCH_64_BIT
# define V8_PTR_PREFIX "ll"
# else
# define V8_PTR_PREFIX ""
# endif // V8_HOST_ARCH_64_BIT
#elif V8_CC_MINGW64
# define V8_PTR_PREFIX "I64"
#elif V8_HOST_ARCH_64_BIT
# define V8_PTR_PREFIX "l"
#else
#if V8_OS_AIX
#define V8_PTR_PREFIX "l"
#else
# define V8_PTR_PREFIX ""
#endif
#endif
#define V8PRIxPTR V8_PTR_PREFIX "x"
#define V8PRIdPTR V8_PTR_PREFIX "d"
#define V8PRIuPTR V8_PTR_PREFIX "u"
#if V8_TARGET_ARCH_64_BIT
#define V8_PTR_HEX_DIGITS 12
#define V8PRIxPTR_FMT "0x%012" V8PRIxPTR
#else
#define V8_PTR_HEX_DIGITS 8
#define V8PRIxPTR_FMT "0x%08" V8PRIxPTR
#endif
// ptrdiff_t is 't' according to the standard, but MSVC uses 'I'.
#if V8_CC_MSVC
#define V8PRIxPTRDIFF "Ix"
#define V8PRIdPTRDIFF "Id"
#define V8PRIuPTRDIFF "Iu"
#else
#define V8PRIxPTRDIFF "tx"
#define V8PRIdPTRDIFF "td"
#define V8PRIuPTRDIFF "tu"
#endif
// Fix for Mac OS X defining uintptr_t as "unsigned long":
#if V8_OS_DARWIN
#undef V8PRIxPTR
#define V8PRIxPTR "lx"
#undef V8PRIdPTR
#define V8PRIdPTR "ld"
#undef V8PRIuPTR
#define V8PRIuPTR "lxu"
#endif
// Make a uint64 from two uint32_t halves.
inline uint64_t make_uint64(uint32_t high, uint32_t low) {
return (uint64_t{high} << 32) + low;
}
// Return the largest multiple of m which is <= x.
template <typename T>
constexpr T RoundDown(T x, intptr_t m) {
static_assert(std::is_integral<T>::value);
// m must be a power of two.
DCHECK(m != 0 && ((m & (m - 1)) == 0));
return x & static_cast<T>(-m);
}
template <intptr_t m, typename T>
constexpr T RoundDown(T x) {
static_assert(std::is_integral<T>::value);
// m must be a power of two.
static_assert(m != 0 && ((m & (m - 1)) == 0));
return x & static_cast<T>(-m);
}
// Return the smallest multiple of m which is >= x.
template <typename T>
constexpr T RoundUp(T x, intptr_t m) {
static_assert(std::is_integral<T>::value);
DCHECK_GE(x, 0);
DCHECK_GE(std::numeric_limits<T>::max() - x, m - 1); // Overflow check.
return RoundDown<T>(static_cast<T>(x + (m - 1)), m);
}
template <intptr_t m, typename T>
constexpr T RoundUp(T x) {
static_assert(std::is_integral<T>::value);
DCHECK_GE(x, 0);
DCHECK_GE(std::numeric_limits<T>::max() - x, m - 1); // Overflow check.
return RoundDown<m, T>(static_cast<T>(x + (m - 1)));
}
template <typename T, typename U>
constexpr inline bool IsAligned(T value, U alignment) {
return (value & (alignment - 1)) == 0;
}
inline void* AlignedAddress(void* address, size_t alignment) {
return reinterpret_cast<void*>(
RoundDown(reinterpret_cast<uintptr_t>(address), alignment));
}
inline void* RoundUpAddress(void* address, size_t alignment) {
return reinterpret_cast<void*>(
RoundUp(reinterpret_cast<uintptr_t>(address), alignment));
}
// Bounds checks for float to integer conversions, which does truncation. Hence,
// the range of legal values is (min - 1, max + 1).
template <typename int_t, typename float_t, typename biggest_int_t = int64_t>
bool is_inbounds(float_t v) {
static_assert(sizeof(int_t) < sizeof(biggest_int_t),
"int_t can't be bounds checked by the compiler");
constexpr float_t kLowerBound =
static_cast<float_t>(std::numeric_limits<int_t>::min()) - 1;
constexpr float_t kUpperBound =
static_cast<float_t>(std::numeric_limits<int_t>::max()) + 1;
constexpr bool kLowerBoundIsMin =
static_cast<biggest_int_t>(kLowerBound) ==
static_cast<biggest_int_t>(std::numeric_limits<int_t>::min());
constexpr bool kUpperBoundIsMax =
static_cast<biggest_int_t>(kUpperBound) ==
static_cast<biggest_int_t>(std::numeric_limits<int_t>::max());
// Using USE(var) is only a workaround for a GCC 8.1 bug.
USE(kLowerBoundIsMin);
USE(kUpperBoundIsMax);
return (kLowerBoundIsMin ? (kLowerBound <= v) : (kLowerBound < v)) &&
(kUpperBoundIsMax ? (v <= kUpperBound) : (v < kUpperBound));
}
#ifdef V8_OS_WIN
// Setup for Windows shared library export.
#define V8_EXPORT_ENUM
#ifdef BUILDING_V8_SHARED_PRIVATE
#define V8_EXPORT_PRIVATE __declspec(dllexport)
#elif USING_V8_SHARED_PRIVATE
#define V8_EXPORT_PRIVATE __declspec(dllimport)
#else
#define V8_EXPORT_PRIVATE
#endif // BUILDING_V8_SHARED
#else // V8_OS_WIN
// Setup for Linux shared library export.
#if V8_HAS_ATTRIBUTE_VISIBILITY
#ifdef BUILDING_V8_SHARED_PRIVATE
#define V8_EXPORT_PRIVATE __attribute__((visibility("default")))
#define V8_EXPORT_ENUM V8_EXPORT_PRIVATE
#else
#define V8_EXPORT_PRIVATE
#define V8_EXPORT_ENUM
#endif
#else
#define V8_EXPORT_PRIVATE
#define V8_EXPORT_ENUM
#endif
#endif // V8_OS_WIN
// Defines IF_WASM, to be used in macro lists for elements that should only be
// there if WebAssembly is enabled.
#if V8_ENABLE_WEBASSEMBLY
// EXPAND is needed to work around MSVC's broken __VA_ARGS__ expansion.
#define IF_WASM(V, ...) EXPAND(V(__VA_ARGS__))
#else
#define IF_WASM(V, ...)
#endif // V8_ENABLE_WEBASSEMBLY
#ifdef V8_ENABLE_DRUMBRAKE
#define IF_WASM_DRUMBRAKE(V, ...) EXPAND(V(__VA_ARGS__))
#else
#define IF_WASM_DRUMBRAKE(V, ...)
#endif // V8_ENABLE_DRUMBRAKE
#if defined(V8_ENABLE_DRUMBRAKE) && !defined(V8_DRUMBRAKE_BOUNDS_CHECKS)
#define IF_WASM_DRUMBRAKE_INSTR_HANDLER(V, ...) EXPAND(V(__VA_ARGS__))
#else
#define IF_WASM_DRUMBRAKE_INSTR_HANDLER(V, ...)
#endif // V8_ENABLE_DRUMBRAKE && !V8_DRUMBRAKE_BOUNDS_CHECKS
// Defines IF_TSAN, to be used in macro lists for elements that should only be
// there if TSAN is enabled.
#ifdef V8_IS_TSAN
// EXPAND is needed to work around MSVC's broken __VA_ARGS__ expansion.
#define IF_TSAN(V, ...) EXPAND(V(__VA_ARGS__))
#else
#define IF_TSAN(V, ...)
#endif // V8_IS_TSAN
// Defines IF_INTL, to be used in macro lists for elements that should only be
// there if INTL is enabled.
#ifdef V8_INTL_SUPPORT
// EXPAND is needed to work around MSVC's broken __VA_ARGS__ expansion.
#define IF_INTL(V, ...) EXPAND(V(__VA_ARGS__))
#else
#define IF_INTL(V, ...)
#endif // V8_INTL_SUPPORT
// Defines IF_SHADOW_STACK, to be used in macro lists for elements that should
// only be there if CET shadow stack is enabled.
#ifdef V8_ENABLE_CET_SHADOW_STACK
// EXPAND is needed to work around MSVC's broken __VA_ARGS__ expansion.
#define IF_SHADOW_STACK(V, ...) EXPAND(V(__VA_ARGS__))
#else
#define IF_SHADOW_STACK(V, ...)
#endif // V8_ENABLE_CET_SHADOW_STACK
// Defines IF_TARGET_ARCH_64_BIT, to be used in macro lists for elements that
// should only be there if the target architecture is a 64-bit one.
#if V8_TARGET_ARCH_64_BIT
// EXPAND is needed to work around MSVC's broken __VA_ARGS__ expansion.
#define IF_TARGET_ARCH_64_BIT(V, ...) EXPAND(V(__VA_ARGS__))
#else
#define IF_TARGET_ARCH_64_BIT(V, ...)
#endif // V8_TARGET_ARCH_64_BIT
// Defines IF_V8_WASM_RANDOM_FUZZERS and IF_NO_V8_WASM_RANDOM_FUZZERS, to be
// used in macro lists for elements that should only be there/absent when
// building the Wasm fuzzers.
#ifdef V8_WASM_RANDOM_FUZZERS
// EXPAND is needed to work around MSVC's broken __VA_ARGS__ expansion.
#define IF_V8_WASM_RANDOM_FUZZERS(V, ...) EXPAND(V(__VA_ARGS__))
#define IF_NO_V8_WASM_RANDOM_FUZZERS(V, ...)
#else
#define IF_V8_WASM_RANDOM_FUZZERS(V, ...)
#define IF_NO_V8_WASM_RANDOM_FUZZERS(V, ...) EXPAND(V(__VA_ARGS__))
#endif // V8_WASM_RANDOM_FUZZERS
#ifdef GOOGLE3
// Disable FRIEND_TEST macro in Google3.
#define FRIEND_TEST(test_case_name, test_name)
#endif
#endif // V8_BASE_MACROS_H_