diff options
Diffstat (limited to 'deps/v8/src/base')
-rw-r--r-- | deps/v8/src/base/OWNERS | 2 | ||||
-rw-r--r-- | deps/v8/src/base/adapters.h | 55 | ||||
-rw-r--r-- | deps/v8/src/base/cpu.cc | 71 | ||||
-rw-r--r-- | deps/v8/src/base/file-utils.cc | 26 | ||||
-rw-r--r-- | deps/v8/src/base/file-utils.h | 6 | ||||
-rw-r--r-- | deps/v8/src/base/free_deleter.h | 1 | ||||
-rw-r--r-- | deps/v8/src/base/iterator.h | 20 | ||||
-rw-r--r-- | deps/v8/src/base/macros.h | 22 | ||||
-rw-r--r-- | deps/v8/src/base/optional.h | 17 | ||||
-rw-r--r-- | deps/v8/src/base/platform/mutex.h | 1 | ||||
-rw-r--r-- | deps/v8/src/base/platform/platform-openbsd.cc | 4 | ||||
-rw-r--r-- | deps/v8/src/base/platform/platform-posix.cc | 1 | ||||
-rw-r--r-- | deps/v8/src/base/platform/semaphore.cc | 49 | ||||
-rw-r--r-- | deps/v8/src/base/platform/semaphore.h | 4 | ||||
-rw-r--r-- | deps/v8/src/base/template-utils.h | 81 | ||||
-rw-r--r-- | deps/v8/src/base/ubsan.cc | 50 |
16 files changed, 157 insertions, 253 deletions
diff --git a/deps/v8/src/base/OWNERS b/deps/v8/src/base/OWNERS index 9c6fd3c859..3654b400ad 100644 --- a/deps/v8/src/base/OWNERS +++ b/deps/v8/src/base/OWNERS @@ -1,4 +1,4 @@ -clemensh@chromium.org +clemensb@chromium.org mlippautz@chromium.org # COMPONENT: Blink>JavaScript diff --git a/deps/v8/src/base/adapters.h b/deps/v8/src/base/adapters.h deleted file mode 100644 index f684b52ccb..0000000000 --- a/deps/v8/src/base/adapters.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Slightly adapted for inclusion in V8. -// Copyright 2014 the V8 project authors. All rights reserved. - -#ifndef V8_BASE_ADAPTERS_H_ -#define V8_BASE_ADAPTERS_H_ - -#include <iterator> - -#include "src/base/macros.h" - -namespace v8 { -namespace base { - -// Internal adapter class for implementing base::Reversed. -template <typename T> -class ReversedAdapter { - public: - using Iterator = - std::reverse_iterator<decltype(std::begin(std::declval<T>()))>; - - explicit ReversedAdapter(T& t) : t_(t) {} - ReversedAdapter(const ReversedAdapter& ra) V8_NOEXCEPT = default; - - // TODO(clemensh): Use std::rbegin/std::rend once we have C++14 support. - Iterator begin() const { return Iterator(std::end(t_)); } - Iterator end() const { return Iterator(std::begin(t_)); } - - private: - T& t_; - - DISALLOW_ASSIGN(ReversedAdapter); -}; - -// Reversed returns a container adapter usable in a range-based "for" statement -// for iterating a reversible container in reverse order. -// -// Example: -// -// std::vector<int> v = ...; -// for (int i : base::Reversed(v)) { -// // iterates through v from back to front -// } -template <typename T> -ReversedAdapter<T> Reversed(T&& t) { - return ReversedAdapter<T>(t); -} - -} // namespace base -} // namespace v8 - -#endif // V8_BASE_ADAPTERS_H_ diff --git a/deps/v8/src/base/cpu.cc b/deps/v8/src/base/cpu.cc index 6ab0ffee29..4f4ac2b328 100644 --- a/deps/v8/src/base/cpu.cc +++ b/deps/v8/src/base/cpu.cc @@ -9,6 +9,7 @@ #endif #if V8_OS_LINUX #include <linux/auxvec.h> // AT_HWCAP +extern "C" char** environ; #endif #if V8_GLIBC_PREREQ(2, 16) #include <sys/auxv.h> // getauxval() @@ -16,7 +17,7 @@ #if V8_OS_QNX #include <sys/syspage.h> // cpuinfo #endif -#if V8_OS_LINUX && V8_HOST_ARCH_PPC +#if (V8_OS_LINUX && V8_HOST_ARCH_PPC) || V8_OS_ANDROID #include <elf.h> #endif #if V8_OS_AIX @@ -109,28 +110,25 @@ static V8_INLINE void __cpuid(int cpu_info[4], int info_type) { #define HWCAP_LPAE (1 << 20) static uint32_t ReadELFHWCaps() { - uint32_t result = 0; #if V8_GLIBC_PREREQ(2, 16) - result = static_cast<uint32_t>(getauxval(AT_HWCAP)); + return static_cast<uint32_t>(getauxval(AT_HWCAP)); #else - // Read the ELF HWCAP flags by parsing /proc/self/auxv. - FILE* fp = fopen("/proc/self/auxv", "r"); - if (fp != nullptr) { - struct { uint32_t tag; uint32_t value; } entry; - for (;;) { - size_t n = fread(&entry, sizeof(entry), 1, fp); - if (n == 0 || (entry.tag == 0 && entry.value == 0)) { - break; - } - if (entry.tag == AT_HWCAP) { - result = entry.value; - break; - } + char** head = environ; + while (*head++ != nullptr) { + } +#ifdef __LP64__ + using elf_auxv_t = Elf64_auxv_t; +#else + using elf_auxv_t = Elf32_auxv_t; +#endif + for (elf_auxv_t* entry = reinterpret_cast<elf_auxv_t*>(head); + entry->a_type != AT_NULL; ++entry) { + if (entry->a_type == AT_HWCAP) { + return entry->a_un.a_val; } - fclose(fp); } + return 0u; #endif - return result; } #endif // V8_HOST_ARCH_ARM @@ -608,33 +606,28 @@ CPU::CPU() #ifndef USE_SIMULATOR #if V8_OS_LINUX - // Read processor info from /proc/self/auxv. char* auxv_cpu_type = nullptr; - FILE* fp = fopen("/proc/self/auxv", "r"); - if (fp != nullptr) { + char** head = environ; + while (*head++ != nullptr) { + } #if V8_TARGET_ARCH_PPC64 - Elf64_auxv_t entry; + using elf_auxv_t = Elf64_auxv_t; #else - Elf32_auxv_t entry; + using elf_auxv_t = Elf32_auxv_t; #endif - for (;;) { - size_t n = fread(&entry, sizeof(entry), 1, fp); - if (n == 0 || entry.a_type == AT_NULL) { + for (elf_auxv_t* entry = reinterpret_cast<elf_auxv_t*>(head); + entry->a_type != AT_NULL; ++entry) { + switch (entry->a_type) { + case AT_PLATFORM: + auxv_cpu_type = reinterpret_cast<char*>(entry->a_un.a_val); + break; + case AT_ICACHEBSIZE: + icache_line_size_ = entry->a_un.a_val; + break; + case AT_DCACHEBSIZE: + dcache_line_size_ = entry->a_un.a_val; break; - } - switch (entry.a_type) { - case AT_PLATFORM: - auxv_cpu_type = reinterpret_cast<char*>(entry.a_un.a_val); - break; - case AT_ICACHEBSIZE: - icache_line_size_ = entry.a_un.a_val; - break; - case AT_DCACHEBSIZE: - dcache_line_size_ = entry.a_un.a_val; - break; - } } - fclose(fp); } part_ = -1; diff --git a/deps/v8/src/base/file-utils.cc b/deps/v8/src/base/file-utils.cc index 31b1b41190..6e1c492144 100644 --- a/deps/v8/src/base/file-utils.cc +++ b/deps/v8/src/base/file-utils.cc @@ -12,24 +12,18 @@ namespace v8 { namespace base { -char* RelativePath(char** buffer, const char* exec_path, const char* name) { +std::unique_ptr<char[]> RelativePath(const char* exec_path, const char* name) { DCHECK(exec_path); - int path_separator = static_cast<int>(strlen(exec_path)) - 1; - while (path_separator >= 0 && - !OS::isDirectorySeparator(exec_path[path_separator])) { - path_separator--; + size_t basename_start = strlen(exec_path); + while (basename_start > 0 && + !OS::isDirectorySeparator(exec_path[basename_start - 1])) { + --basename_start; } - if (path_separator >= 0) { - int name_length = static_cast<int>(strlen(name)); - *buffer = - reinterpret_cast<char*>(calloc(path_separator + name_length + 2, 1)); - *buffer[0] = '\0'; - strncat(*buffer, exec_path, path_separator + 1); - strncat(*buffer, name, name_length); - } else { - *buffer = strdup(name); - } - return *buffer; + size_t name_length = strlen(name); + auto buffer = std::make_unique<char[]>(basename_start + name_length + 1); + if (basename_start > 0) memcpy(buffer.get(), exec_path, basename_start); + memcpy(buffer.get() + basename_start, name, name_length); + return buffer; } } // namespace base diff --git a/deps/v8/src/base/file-utils.h b/deps/v8/src/base/file-utils.h index afd9a1fc25..84b57fb40b 100644 --- a/deps/v8/src/base/file-utils.h +++ b/deps/v8/src/base/file-utils.h @@ -5,6 +5,8 @@ #ifndef V8_BASE_FILE_UTILS_H_ #define V8_BASE_FILE_UTILS_H_ +#include <memory> + #include "src/base/base-export.h" namespace v8 { @@ -12,8 +14,8 @@ namespace base { // Helper functions to manipulate file paths. -V8_BASE_EXPORT char* RelativePath(char** buffer, const char* exec_path, - const char* name); +V8_BASE_EXPORT +std::unique_ptr<char[]> RelativePath(const char* exec_path, const char* name); } // namespace base } // namespace v8 diff --git a/deps/v8/src/base/free_deleter.h b/deps/v8/src/base/free_deleter.h index 77e4f0ed14..a556926685 100644 --- a/deps/v8/src/base/free_deleter.h +++ b/deps/v8/src/base/free_deleter.h @@ -9,6 +9,7 @@ #define V8_BASE_FREE_DELETER_H_ #include <stdlib.h> +#include <memory> namespace v8 { namespace base { diff --git a/deps/v8/src/base/iterator.h b/deps/v8/src/base/iterator.h index b081af62ae..baaf324e21 100644 --- a/deps/v8/src/base/iterator.h +++ b/deps/v8/src/base/iterator.h @@ -59,6 +59,26 @@ class iterator_range { const_iterator const end_; }; +template <typename ForwardIterator> +auto make_iterator_range(ForwardIterator&& begin, ForwardIterator&& end) { + return iterator_range<ForwardIterator>{std::forward<ForwardIterator>(begin), + std::forward<ForwardIterator>(end)}; +} + +// {Reversed} returns a container adapter usable in a range-based "for" +// statement for iterating a reversible container in reverse order. +// +// Example: +// +// std::vector<int> v = ...; +// for (int i : base::Reversed(v)) { +// // iterates through v from back to front +// } +template <typename T> +auto Reversed(T& t) { // NOLINT(runtime/references): match {rbegin} and {rend} + return make_iterator_range(std::rbegin(t), std::rend(t)); +} + } // namespace base } // namespace v8 diff --git a/deps/v8/src/base/macros.h b/deps/v8/src/base/macros.h index ad70e9820d..72ef64cfbe 100644 --- a/deps/v8/src/base/macros.h +++ b/deps/v8/src/base/macros.h @@ -232,35 +232,16 @@ struct is_trivially_copyable { // the standard does not, so let's skip this check.) // Trivial non-deleted destructor. std::is_trivially_destructible<T>::value; - -#elif defined(__GNUC__) && __GNUC__ < 5 - // WARNING: - // On older libstdc++ versions, there is no way to correctly implement - // is_trivially_copyable. The workaround below is an approximation (neither - // over- nor underapproximation). E.g. it wrongly returns true if the move - // constructor is non-trivial, and it wrongly returns false if the copy - // constructor is deleted, but copy assignment is trivial. - // TODO(rongjie) Remove this workaround once we require gcc >= 5.0 - static constexpr bool value = - __has_trivial_copy(T) && __has_trivial_destructor(T); - #else static constexpr bool value = std::is_trivially_copyable<T>::value; #endif }; -#if defined(__GNUC__) && __GNUC__ < 5 -// On older libstdc++ versions, base::is_trivially_copyable<T>::value is only an -// approximation (see above), so make ASSERT_{NOT_,}TRIVIALLY_COPYABLE a noop. -#define ASSERT_TRIVIALLY_COPYABLE(T) static_assert(true, "check disabled") -#define ASSERT_NOT_TRIVIALLY_COPYABLE(T) static_assert(true, "check disabled") -#else #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") -#endif // The USE(x, ...) template is used to silence C++ compiler warnings // issued for (yet) unused variables (typically parameters). @@ -407,6 +388,9 @@ bool is_inbounds(float_t v) { 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)); } diff --git a/deps/v8/src/base/optional.h b/deps/v8/src/base/optional.h index b8df88d844..6610c7ffc3 100644 --- a/deps/v8/src/base/optional.h +++ b/deps/v8/src/base/optional.h @@ -131,21 +131,8 @@ struct OptionalStorageBase<T, true /* trivially destructible */> { // the condition of constexpr-ness is satisfied because the base class also has // compiler generated constexpr {copy,move} constructors). Note that // placement-new is prohibited in constexpr. -#if defined(__GNUC__) && __GNUC__ < 5 -// gcc <5 does not implement std::is_trivially_copy_constructible. -// Conservatively assume false for this configuration. -// TODO(clemensh): Remove this once we drop support for gcc <5. -#define TRIVIALLY_COPY_CONSTRUCTIBLE(T) false -#define TRIVIALLY_MOVE_CONSTRUCTIBLE(T) false -#else -#define TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ - std::is_trivially_copy_constructible<T>::value -#define TRIVIALLY_MOVE_CONSTRUCTIBLE(T) \ - std::is_trivially_move_constructible<T>::value -#endif -template <typename T, bool = TRIVIALLY_COPY_CONSTRUCTIBLE(T), - bool = TRIVIALLY_MOVE_CONSTRUCTIBLE(T)> -#undef TRIVIALLY_COPY_CONSTRUCTIBLE +template <typename T, bool = std::is_trivially_copy_constructible<T>::value, + bool = std::is_trivially_move_constructible<T>::value> struct OptionalStorage : OptionalStorageBase<T> { // This is no trivially {copy,move} constructible case. Other cases are // defined below as specializations. diff --git a/deps/v8/src/base/platform/mutex.h b/deps/v8/src/base/platform/mutex.h index c48cf8d339..5b3b31ec1e 100644 --- a/deps/v8/src/base/platform/mutex.h +++ b/deps/v8/src/base/platform/mutex.h @@ -290,6 +290,7 @@ class LockGuard final { }; using MutexGuard = LockGuard<Mutex>; +using RecursiveMutexGuard = LockGuard<RecursiveMutex>; enum MutexSharedType : bool { kShared = true, kExclusive = false }; diff --git a/deps/v8/src/base/platform/platform-openbsd.cc b/deps/v8/src/base/platform/platform-openbsd.cc index c133ffb68d..e4a3cb6f35 100644 --- a/deps/v8/src/base/platform/platform-openbsd.cc +++ b/deps/v8/src/base/platform/platform-openbsd.cc @@ -107,7 +107,7 @@ void OS::SignalCodeMovingGC() { // it. This injects a GC marker into the stream of events generated // by the kernel and allows us to synchronize V8 code log and the // kernel log. - int size = sysconf(_SC_PAGESIZE); + long size = sysconf(_SC_PAGESIZE); // NOLINT: type more fit than uint64_t FILE* f = fopen(OS::GetGCFakeMMapFile(), "w+"); if (f == nullptr) { OS::PrintError("Failed to open %s\n", OS::GetGCFakeMMapFile()); @@ -116,7 +116,7 @@ void OS::SignalCodeMovingGC() { void* addr = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fileno(f), 0); DCHECK(addr != MAP_FAILED); - OS::Free(addr, size); + CHECK(OS::Free(addr, size)); fclose(f); } diff --git a/deps/v8/src/base/platform/platform-posix.cc b/deps/v8/src/base/platform/platform-posix.cc index c50cdd7a98..99abcd5568 100644 --- a/deps/v8/src/base/platform/platform-posix.cc +++ b/deps/v8/src/base/platform/platform-posix.cc @@ -48,6 +48,7 @@ #if V8_OS_MACOSX #include <dlfcn.h> +#include <mach/mach.h> #endif #if V8_OS_LINUX diff --git a/deps/v8/src/base/platform/semaphore.cc b/deps/v8/src/base/platform/semaphore.cc index a7e50f5880..66464d8258 100644 --- a/deps/v8/src/base/platform/semaphore.cc +++ b/deps/v8/src/base/platform/semaphore.cc @@ -5,8 +5,7 @@ #include "src/base/platform/semaphore.h" #if V8_OS_MACOSX -#include <mach/mach_init.h> -#include <mach/task.h> +#include <dispatch/dispatch.h> #endif #include <errno.h> @@ -21,53 +20,23 @@ namespace base { #if V8_OS_MACOSX Semaphore::Semaphore(int count) { - kern_return_t result = semaphore_create( - mach_task_self(), &native_handle_, SYNC_POLICY_FIFO, count); - DCHECK_EQ(KERN_SUCCESS, result); - USE(result); + native_handle_ = dispatch_semaphore_create(count); + DCHECK(native_handle_); } +Semaphore::~Semaphore() { dispatch_release(native_handle_); } -Semaphore::~Semaphore() { - kern_return_t result = semaphore_destroy(mach_task_self(), native_handle_); - DCHECK_EQ(KERN_SUCCESS, result); - USE(result); -} - -void Semaphore::Signal() { - kern_return_t result = semaphore_signal(native_handle_); - DCHECK_EQ(KERN_SUCCESS, result); - USE(result); -} - +void Semaphore::Signal() { dispatch_semaphore_signal(native_handle_); } void Semaphore::Wait() { - while (true) { - kern_return_t result = semaphore_wait(native_handle_); - if (result == KERN_SUCCESS) return; // Semaphore was signalled. - DCHECK_EQ(KERN_ABORTED, result); - } + dispatch_semaphore_wait(native_handle_, DISPATCH_TIME_FOREVER); } bool Semaphore::WaitFor(const TimeDelta& rel_time) { - TimeTicks now = TimeTicks::Now(); - TimeTicks end = now + rel_time; - while (true) { - mach_timespec_t ts; - if (now >= end) { - // Return immediately if semaphore was not signalled. - ts.tv_sec = 0; - ts.tv_nsec = 0; - } else { - ts = (end - now).ToMachTimespec(); - } - kern_return_t result = semaphore_timedwait(native_handle_, ts); - if (result == KERN_SUCCESS) return true; // Semaphore was signalled. - if (result == KERN_OPERATION_TIMED_OUT) return false; // Timeout. - DCHECK_EQ(KERN_ABORTED, result); - now = TimeTicks::Now(); - } + dispatch_time_t timeout = + dispatch_time(DISPATCH_TIME_NOW, rel_time.InNanoseconds()); + return dispatch_semaphore_wait(native_handle_, timeout) == 0; } #elif V8_OS_POSIX diff --git a/deps/v8/src/base/platform/semaphore.h b/deps/v8/src/base/platform/semaphore.h index 11ff0b9199..c4937acadd 100644 --- a/deps/v8/src/base/platform/semaphore.h +++ b/deps/v8/src/base/platform/semaphore.h @@ -12,7 +12,7 @@ #endif #if V8_OS_MACOSX -#include <mach/semaphore.h> // NOLINT +#include <dispatch/dispatch.h> // NOLINT #elif V8_OS_POSIX #include <semaphore.h> // NOLINT #endif @@ -50,7 +50,7 @@ class V8_BASE_EXPORT Semaphore final { bool WaitFor(const TimeDelta& rel_time) V8_WARN_UNUSED_RESULT; #if V8_OS_MACOSX - using NativeHandle = semaphore_t; + using NativeHandle = dispatch_semaphore_t; #elif V8_OS_POSIX using NativeHandle = sem_t; #elif V8_OS_WIN diff --git a/deps/v8/src/base/template-utils.h b/deps/v8/src/base/template-utils.h index 530114a8e2..146f8d6e6a 100644 --- a/deps/v8/src/base/template-utils.h +++ b/deps/v8/src/base/template-utils.h @@ -6,32 +6,20 @@ #define V8_BASE_TEMPLATE_UTILS_H_ #include <array> -#include <memory> +#include <type_traits> +#include <utility> namespace v8 { namespace base { namespace detail { -// make_array_helper statically iteratively creates the index list 0 .. Size-1. -// A specialization for the base case (first index is 0) finally constructs the -// array. -// TODO(clemensh): Use std::index_sequence once we have C++14 support. -template <class Function, std::size_t... Indexes> -struct make_array_helper; - -template <class Function, std::size_t... Indexes> -struct make_array_helper<Function, 0, Indexes...> { - constexpr static std::array<typename std::result_of<Function(size_t)>::type, - sizeof...(Indexes) + 1> - make_array(Function f) { - return {{f(0), f(Indexes)...}}; - } -}; - -template <class Function, std::size_t FirstIndex, std::size_t... Indexes> -struct make_array_helper<Function, FirstIndex, Indexes...> - : make_array_helper<Function, FirstIndex - 1, FirstIndex, Indexes...> {}; +template <typename Function, std::size_t... Indexes> +constexpr inline auto make_array_helper(Function f, + std::index_sequence<Indexes...>) + -> std::array<decltype(f(0)), sizeof...(Indexes)> { + return {{f(Indexes)...}}; +} } // namespace detail @@ -42,18 +30,8 @@ struct make_array_helper<Function, FirstIndex, Indexes...> // [](std::size_t i) { return static_cast<int>(2 * i); }); // The resulting array will be constexpr if the passed function is constexpr. template <std::size_t Size, class Function> -constexpr std::array<typename std::result_of<Function(size_t)>::type, Size> -make_array(Function f) { - static_assert(Size > 0, "Can only create non-empty arrays"); - return detail::make_array_helper<Function, Size - 1>::make_array(f); -} - -// base::make_unique<T>: Construct an object of type T and wrap it in a -// std::unique_ptr. -// Replacement for C++14's std::make_unique. -template <typename T, typename... Args> -std::unique_ptr<T> make_unique(Args&&... args) { - return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); +constexpr auto make_array(Function f) { + return detail::make_array_helper(f, std::make_index_sequence<Size>{}); } // Helper to determine how to pass values: Pass scalars and arrays by value, @@ -80,38 +58,17 @@ struct has_output_operator<T, decltype(void(std::declval<std::ostream&>() << std::declval<T>()))> : std::true_type {}; -namespace detail { - -template <typename Func, typename T, typename... Ts> -struct fold_helper { - static_assert(sizeof...(Ts) == 0, "this is the base case"); - using result_t = typename std::remove_reference<T>::type; - static constexpr T&& fold(Func func, T&& first) { - return std::forward<T>(first); - } -}; +// Fold all arguments from left to right with a given function. +template <typename Func, typename T> +constexpr auto fold(Func func, T&& t) { + return std::forward<T>(t); +} template <typename Func, typename T1, typename T2, typename... Ts> -struct fold_helper<Func, T1, T2, Ts...> { - using folded_t = typename std::result_of<Func(T1, T2)>::type; - using next_fold_helper = fold_helper<Func, folded_t&&, Ts...>; - using result_t = typename next_fold_helper::result_t; - static constexpr result_t fold(Func func, T1&& first, T2&& second, - Ts&&... more) { - return next_fold_helper::fold( - func, func(std::forward<T1>(first), std::forward<T2>(second)), - std::forward<Ts>(more)...); - } -}; - -} // namespace detail - -// Fold all arguments from left to right with a given function. -template <typename Func, typename... Ts> -constexpr auto fold(Func func, Ts&&... more) -> - typename detail::fold_helper<Func, Ts...>::result_t { - return detail::fold_helper<Func, Ts...>::fold(func, - std::forward<Ts>(more)...); +constexpr auto fold(Func func, T1&& first, T2&& second, Ts&&... more) { + auto&& folded = func(std::forward<T1>(first), std::forward<T2>(second)); + return fold(std::move(func), std::forward<decltype(folded)>(folded), + std::forward<Ts>(more)...); } // {is_same<Ts...>::value} is true if all Ts are the same, false otherwise. diff --git a/deps/v8/src/base/ubsan.cc b/deps/v8/src/base/ubsan.cc new file mode 100644 index 0000000000..fc77156eb1 --- /dev/null +++ b/deps/v8/src/base/ubsan.cc @@ -0,0 +1,50 @@ +// Copyright 2019 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. + +#include <stdint.h> +#include <limits> + +#include "src/base/build_config.h" + +#if !defined(UNDEFINED_SANITIZER) || !defined(V8_TARGET_ARCH_32_BIT) +#error "This file is only needed for 32-bit UBSan builds." +#endif + +// Compiling with -fsanitize=undefined on 32-bit platforms requires __mulodi4 +// to be available. Usually it comes from libcompiler_rt, which our build +// doesn't provide, so here is a custom implementation (inspired by digit_mul +// in src/objects/bigint.cc). +extern "C" int64_t __mulodi4(int64_t a, int64_t b, int* overflow) { + // Multiply in 32-bit chunks. + // For inputs [AH AL]*[BH BL], the result is: + // + // [AL*BL] // r_low + // + [AL*BH] // r_mid1 + // + [AH*BL] // r_mid2 + // + [AH*BH] // r_high + // = [R4 R3 R2 R1] // high = [R4 R3], low = [R2 R1] + // + // Where of course we must be careful with carries between the columns. + uint64_t a_low = a & 0xFFFFFFFFu; + uint64_t a_high = static_cast<uint64_t>(a) >> 32; + uint64_t b_low = b & 0xFFFFFFFFu; + uint64_t b_high = static_cast<uint64_t>(b) >> 32; + + uint64_t r_low = a_low * b_low; + uint64_t r_mid1 = a_low * b_high; + uint64_t r_mid2 = a_high * b_low; + uint64_t r_high = a_high * b_high; + + uint64_t result1 = r_low + (r_mid1 << 32); + if (result1 < r_low) r_high++; + uint64_t result2 = result1 + (r_mid2 << 32); + if (result2 < result1) r_high++; + r_high += (r_mid1 >> 32) + (r_mid2 >> 32); + int64_t result = static_cast<int64_t>(result2); + uint64_t result_sign = (result >> 63); + uint64_t expected_result_sign = (a >> 63) ^ (b >> 63); + + *overflow = (r_high > 0 || result_sign != expected_result_sign) ? 1 : 0; + return result; +} |