/* * Copyright (C) 2008-2019 Apple Inc. All Rights Reserved. * Copyright (C) 2013 Patrick Gansterer * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #pragma once #include #include #include #include #include #include // Use this macro to declare and define a debug-only global variable that may have a // non-trivial constructor and destructor. When building with clang, this will suppress // warnings about global constructors and exit-time destructors. #define DEFINE_GLOBAL_FOR_LOGGING(type, name, arguments) \ _Pragma("clang diagnostic push") \ _Pragma("clang diagnostic ignored \"-Wglobal-constructors\"") \ _Pragma("clang diagnostic ignored \"-Wexit-time-destructors\"") \ static type name arguments; \ _Pragma("clang diagnostic pop") #ifndef NDEBUG #if COMPILER(CLANG) #define DEFINE_DEBUG_ONLY_GLOBAL(type, name, arguments) DEFINE_GLOBAL_FOR_LOGGING(type, name, arguments) #else #define DEFINE_DEBUG_ONLY_GLOBAL(type, name, arguments) \ static type name arguments; #endif // COMPILER(CLANG) #else #define DEFINE_DEBUG_ONLY_GLOBAL(type, name, arguments) #endif // NDEBUG // OBJECT_OFFSETOF: Like the C++ offsetof macro, but you can use it with classes. // The magic number 0x4000 is insignificant. We use it to avoid using NULL, since // NULL can cause compiler problems, especially in cases of multiple inheritance. #define OBJECT_OFFSETOF(class, field) (reinterpret_cast(&(reinterpret_cast(0x4000)->field)) - 0x4000) #define CAST_OFFSET(from, to) (reinterpret_cast(static_cast((reinterpret_cast(0x4000)))) - 0x4000) // STRINGIZE: Can convert any value to quoted string, even expandable macros #define STRINGIZE(exp) #exp #define STRINGIZE_VALUE_OF(exp) STRINGIZE(exp) // WTF_CONCAT: concatenate two symbols into one, even expandable macros #define WTF_CONCAT_INTERNAL_DONT_USE(a, b) a ## b #define WTF_CONCAT(a, b) WTF_CONCAT_INTERNAL_DONT_USE(a, b) /* * The reinterpret_cast([pointer to Type2]) expressions - where * sizeof(Type1) > sizeof(Type2) - cause the following warning on ARM with GCC: * increases required alignment of target type. * * An implicit or an extra static_cast bypasses the warning. * For more info see the following bugzilla entries: * - https://bugs.webkit.org/show_bug.cgi?id=38045 * - http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43976 */ #if (CPU(ARM) || CPU(MIPS) || CPU(RISCV64)) && COMPILER(GCC_COMPATIBLE) template inline bool isPointerTypeAlignmentOkay(Type* ptr) { return !(reinterpret_cast(ptr) % __alignof__(Type)); } template inline TypePtr reinterpret_cast_ptr(void* ptr) { ASSERT(isPointerTypeAlignmentOkay(reinterpret_cast(ptr))); return reinterpret_cast(ptr); } template inline TypePtr reinterpret_cast_ptr(const void* ptr) { ASSERT(isPointerTypeAlignmentOkay(reinterpret_cast(ptr))); return reinterpret_cast(ptr); } #else template inline bool isPointerTypeAlignmentOkay(Type*) { return true; } #define reinterpret_cast_ptr reinterpret_cast #endif namespace WTF { enum CheckMoveParameterTag { CheckMoveParameter }; static constexpr size_t KB = 1024; static constexpr size_t MB = 1024 * 1024; static constexpr size_t GB = 1024 * 1024 * 1024; inline bool isPointerAligned(void* p) { return !((intptr_t)(p) & (sizeof(char*) - 1)); } inline bool is8ByteAligned(void* p) { return !((uintptr_t)(p) & (sizeof(double) - 1)); } template inline ToType bitwise_cast(FromType from) { static_assert(sizeof(FromType) == sizeof(ToType), "bitwise_cast size of FromType and ToType must be equal!"); #if COMPILER_SUPPORTS(BUILTIN_IS_TRIVIALLY_COPYABLE) // Not all recent STL implementations support the std::is_trivially_copyable type trait. Work around this by only checking on toolchains which have the equivalent compiler intrinsic. static_assert(__is_trivially_copyable(ToType), "bitwise_cast of non-trivially-copyable type!"); static_assert(__is_trivially_copyable(FromType), "bitwise_cast of non-trivially-copyable type!"); #endif typename std::remove_const::type to { }; std::memcpy(static_cast(&to), static_cast(&from), sizeof(to)); return to; } template inline ToType safeCast(FromType value) { RELEASE_ASSERT(isInBounds(value)); return static_cast(value); } // Returns a count of the number of bits set in 'bits'. inline size_t bitCount(unsigned bits) { bits = bits - ((bits >> 1) & 0x55555555); bits = (bits & 0x33333333) + ((bits >> 2) & 0x33333333); return (((bits + (bits >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; } inline size_t bitCount(uint64_t bits) { return bitCount(static_cast(bits)) + bitCount(static_cast(bits >> 32)); } // Macro that returns a compile time constant with the length of an array, but gives an error if passed a non-array. template char (&ArrayLengthHelperFunction(T (&)[Size]))[Size]; // GCC needs some help to deduce a 0 length array. #if COMPILER(GCC_COMPATIBLE) template char (&ArrayLengthHelperFunction(T (&)[0]))[0]; #endif #define WTF_ARRAY_LENGTH(array) sizeof(::WTF::ArrayLengthHelperFunction(array)) ALWAYS_INLINE constexpr size_t roundUpToMultipleOfImpl(size_t divisor, size_t x) { size_t remainderMask = divisor - 1; return (x + remainderMask) & ~remainderMask; } // Efficient implementation that takes advantage of powers of two. inline size_t roundUpToMultipleOf(size_t divisor, size_t x) { ASSERT(divisor && !(divisor & (divisor - 1))); return roundUpToMultipleOfImpl(divisor, x); } template constexpr size_t roundUpToMultipleOf(size_t x) { static_assert(divisor && !(divisor & (divisor - 1)), "divisor must be a power of two!"); return roundUpToMultipleOfImpl(divisor, x); } template inline T* roundUpToMultipleOf(T* x) { static_assert(sizeof(T*) == sizeof(size_t), ""); return reinterpret_cast(roundUpToMultipleOf(reinterpret_cast(x))); } enum BinarySearchMode { KeyMustBePresentInArray, KeyMightNotBePresentInArray, ReturnAdjacentElementIfKeyIsNotPresent }; template inline ArrayElementType* binarySearchImpl(ArrayType& array, size_t size, KeyType key, const ExtractKey& extractKey = ExtractKey()) { size_t offset = 0; while (size > 1) { size_t pos = (size - 1) >> 1; auto val = extractKey(&array[offset + pos]); if (val == key) return &array[offset + pos]; // The item we are looking for is smaller than the item being check; reduce the value of 'size', // chopping off the right hand half of the array. if (key < val) size = pos; // Discard all values in the left hand half of the array, up to and including the item at pos. else { size -= (pos + 1); offset += (pos + 1); } ASSERT(mode != KeyMustBePresentInArray || size); } if (mode == KeyMightNotBePresentInArray && !size) return 0; ArrayElementType* result = &array[offset]; if (mode == KeyMightNotBePresentInArray && key != extractKey(result)) return 0; if (mode == KeyMustBePresentInArray) { ASSERT(size == 1); ASSERT(key == extractKey(result)); } return result; } // If the element is not found, crash if asserts are enabled, and behave like approximateBinarySearch in release builds. template inline ArrayElementType* binarySearch(ArrayType& array, size_t size, KeyType key, ExtractKey extractKey = ExtractKey()) { return binarySearchImpl(array, size, key, extractKey); } // Return zero if the element is not found. template inline ArrayElementType* tryBinarySearch(ArrayType& array, size_t size, KeyType key, ExtractKey extractKey = ExtractKey()) { return binarySearchImpl(array, size, key, extractKey); } // Return the element that is either to the left, or the right, of where the element would have been found. template inline ArrayElementType* approximateBinarySearch(ArrayType& array, size_t size, KeyType key, ExtractKey extractKey = ExtractKey()) { return binarySearchImpl(array, size, key, extractKey); } // Variants of the above that use const. template inline ArrayElementType* binarySearch(const ArrayType& array, size_t size, KeyType key, ExtractKey extractKey = ExtractKey()) { return binarySearchImpl(const_cast(array), size, key, extractKey); } template inline ArrayElementType* tryBinarySearch(const ArrayType& array, size_t size, KeyType key, ExtractKey extractKey = ExtractKey()) { return binarySearchImpl(const_cast(array), size, key, extractKey); } template inline ArrayElementType* approximateBinarySearch(const ArrayType& array, size_t size, KeyType key, ExtractKey extractKey = ExtractKey()) { return binarySearchImpl(const_cast(array), size, key, extractKey); } template inline void insertIntoBoundedVector(VectorType& vector, size_t size, const ElementType& element, size_t index) { for (size_t i = size; i-- > index + 1;) vector[i] = vector[i - 1]; vector[index] = element; } // This is here instead of CompilationThread.h to prevent that header from being included // everywhere. The fact that this method, and that header, exist outside of JSC is a bug. // https://bugs.webkit.org/show_bug.cgi?id=131815 WTF_EXPORT_PRIVATE bool isCompilationThread(); template bool isStatelessLambda() { return std::is_empty::value; } template ResultType callStatelessLambda(ArgumentTypes&&... arguments) { uint64_t data[(sizeof(Func) + sizeof(uint64_t) - 1) / sizeof(uint64_t)]; memset(data, 0, sizeof(data)); return (*bitwise_cast(data))(std::forward(arguments)...); } template bool checkAndSet(T& left, U right) { if (left == right) return false; left = right; return true; } template inline unsigned ctz(T value); // Clients will also need to #include MathExtras.h template bool findBitInWord(T word, size_t& startOrResultIndex, size_t endIndex, bool value) { static_assert(std::is_unsigned::value, "Type used in findBitInWord must be unsigned"); constexpr size_t bitsInWord = sizeof(word) * 8; ASSERT_UNUSED(bitsInWord, startOrResultIndex <= bitsInWord && endIndex <= bitsInWord); size_t index = startOrResultIndex; word >>= index; #if COMPILER(GCC_COMPATIBLE) && (CPU(X86_64) || CPU(ARM64)) // We should only use ctz() when we know that ctz() is implementated using // a fast hardware instruction. Otherwise, this will actually result in // worse performance. word ^= (static_cast(value) - 1); index += ctz(word); if (index < endIndex) { startOrResultIndex = index; return true; } #else while (index < endIndex) { if ((word & 1) == static_cast(value)) { startOrResultIndex = index; return true; } index++; word >>= 1; } #endif startOrResultIndex = endIndex; return false; } // Visitor adapted from http://stackoverflow.com/questions/25338795/is-there-a-name-for-this-tuple-creation-idiom template struct Visitor : Visitor, Visitor { Visitor(A a, B... b) : Visitor(a) , Visitor(b...) { } using Visitor::operator (); using Visitor::operator (); }; template struct Visitor : A { Visitor(A a) : A(a) { } using A::operator(); }; template Visitor makeVisitor(F... f) { return Visitor(f...); } namespace Detail { template class> struct IsTemplate_ : std::false_type { }; template class C> struct IsTemplate_, C> : std::true_type { }; } template class Template> struct IsTemplate : public std::integral_constant::value> {}; namespace Detail { template