aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/compiler-rt/lib/orc
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/compiler-rt/lib/orc')
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/adt.h63
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/bitmask_enum.h151
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/coff_platform.cpp775
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/coff_platform.h39
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/coff_platform.per_jd.cpp31
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/common.h48
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/compiler.h74
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/debug.cpp83
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/debug.h56
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/dlfcn_wrapper.cpp52
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/elfnix_platform.cpp624
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/elfnix_platform.h131
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/elfnix_tls.aarch64.S94
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/elfnix_tls.ppc64.S33
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/elfnix_tls.x86-64.S64
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/endianness.h143
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/error.h426
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/executor_address.h263
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/executor_symbol_def.h151
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/extensible_rtti.cpp24
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/extensible_rtti.h145
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/interval_map.h168
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/interval_set.h87
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/log_error_to_stderr.cpp19
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/macho_platform.cpp1550
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/macho_platform.h44
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/macho_tlv.arm64.S92
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/macho_tlv.x86-64.S73
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/run_program_wrapper.cpp51
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/simple_packed_serialization.h689
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/stl_extras.h45
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/string_pool.h172
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/tests/tools/orc-rt-executor.cpp49
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/tests/unit/adt_test.cpp50
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/tests/unit/bitmask_enum_test.cpp143
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/tests/unit/c_api_test.cpp200
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/tests/unit/endian_test.cpp174
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/tests/unit/error_test.cpp295
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/tests/unit/executor_address_test.cpp115
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/tests/unit/executor_symbol_def_test.cpp19
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/tests/unit/extensible_rtti_test.cpp54
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/tests/unit/interval_map_test.cpp204
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/tests/unit/interval_set_test.cpp121
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/tests/unit/orc_unit_test_main.cpp18
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/tests/unit/simple_packed_serialization_test.cpp184
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/tests/unit/simple_packed_serialization_utils.h34
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/tests/unit/string_pool_test.cpp66
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/tests/unit/wrapper_function_utils_test.cpp184
-rw-r--r--contrib/llvm-project/compiler-rt/lib/orc/wrapper_function_utils.h509
49 files changed, 8879 insertions, 0 deletions
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/adt.h b/contrib/llvm-project/compiler-rt/lib/orc/adt.h
new file mode 100644
index 000000000000..8884cc8812be
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/adt.h
@@ -0,0 +1,63 @@
+//===----------------------- adt.h - Handy ADTs -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime support library.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_ADT_H
+#define ORC_RT_ADT_H
+
+#include <cstring>
+#include <limits>
+#include <ostream>
+#include <string>
+
+namespace __orc_rt {
+
+constexpr std::size_t dynamic_extent = std::numeric_limits<std::size_t>::max();
+
+/// A substitute for std::span (and llvm::ArrayRef).
+/// FIXME: Remove in favor of std::span once we can use c++20.
+template <typename T, std::size_t Extent = dynamic_extent> class span {
+public:
+ typedef T element_type;
+ typedef std::remove_cv<T> value_type;
+ typedef std::size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+ typedef T *pointer;
+ typedef const T *const_pointer;
+ typedef T &reference;
+ typedef const T &const_reference;
+
+ typedef pointer iterator;
+
+ static constexpr std::size_t extent = Extent;
+
+ constexpr span() noexcept = default;
+ constexpr span(T *first, size_type count) noexcept
+ : Data(first), Size(count) {}
+
+ template <std::size_t N>
+ constexpr span(T (&arr)[N]) noexcept : Data(&arr[0]), Size(N) {}
+
+ constexpr iterator begin() const noexcept { return Data; }
+ constexpr iterator end() const noexcept { return Data + Size; }
+ constexpr pointer data() const noexcept { return Data; }
+ constexpr reference operator[](size_type idx) const { return Data[idx]; }
+ constexpr size_type size() const noexcept { return Size; }
+ constexpr bool empty() const noexcept { return Size == 0; }
+
+private:
+ T *Data = nullptr;
+ size_type Size = 0;
+};
+
+} // end namespace __orc_rt
+
+#endif // ORC_RT_ADT_H
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/bitmask_enum.h b/contrib/llvm-project/compiler-rt/lib/orc/bitmask_enum.h
new file mode 100644
index 000000000000..b9fb776bdf23
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/bitmask_enum.h
@@ -0,0 +1,151 @@
+//===---- bitmask_enum.h - Enable bitmask operations on enums ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime support library.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_BITMASK_ENUM_H
+#define ORC_RT_BITMASK_ENUM_H
+
+#include "stl_extras.h"
+
+#include <cassert>
+#include <type_traits>
+
+namespace __orc_rt {
+
+/// ORC_RT_MARK_AS_BITMASK_ENUM lets you opt in an individual enum type so you
+/// can perform bitwise operations on it without putting static_cast everywhere.
+///
+/// \code
+/// enum MyEnum {
+/// E1 = 1, E2 = 2, E3 = 4, E4 = 8,
+/// ORC_RT_MARK_AS_BITMASK_ENUM(/* LargestValue = */ E4)
+/// };
+///
+/// void Foo() {
+/// MyEnum A = (E1 | E2) & E3 ^ ~E4; // Look, ma: No static_cast!
+/// }
+/// \endcode
+///
+/// Normally when you do a bitwise operation on an enum value, you get back an
+/// instance of the underlying type (e.g. int). But using this macro, bitwise
+/// ops on your enum will return you back instances of the enum. This is
+/// particularly useful for enums which represent a combination of flags.
+///
+/// The parameter to ORC_RT_MARK_AS_BITMASK_ENUM should be the largest
+/// individual value in your enum.
+///
+/// All of the enum's values must be non-negative.
+#define ORC_RT_MARK_AS_BITMASK_ENUM(LargestValue) \
+ ORC_RT_BITMASK_LARGEST_ENUMERATOR = LargestValue
+
+/// ORC_RT_DECLARE_ENUM_AS_BITMASK can be used to declare an enum type as a bit
+/// set, so that bitwise operation on such enum does not require static_cast.
+///
+/// \code
+/// enum MyEnum { E1 = 1, E2 = 2, E3 = 4, E4 = 8 };
+/// ORC_RT_DECLARE_ENUM_AS_BITMASK(MyEnum, E4);
+///
+/// void Foo() {
+/// MyEnum A = (E1 | E2) & E3 ^ ~E4; // No static_cast
+/// }
+/// \endcode
+///
+/// The second parameter to ORC_RT_DECLARE_ENUM_AS_BITMASK specifies the largest
+/// bit value of the enum type.
+///
+/// ORC_RT_DECLARE_ENUM_AS_BITMASK should be used in __orc_rt namespace.
+///
+/// This a non-intrusive alternative for ORC_RT_MARK_AS_BITMASK_ENUM. It allows
+/// declaring more than one non-scoped enumerations as bitmask types in the same
+/// scope. Otherwise it provides the same functionality as
+/// ORC_RT_MARK_AS_BITMASK_ENUM.
+#define ORC_RT_DECLARE_ENUM_AS_BITMASK(Enum, LargestValue) \
+ template <> struct is_bitmask_enum<Enum> : std::true_type {}; \
+ template <> struct largest_bitmask_enum_bit<Enum> { \
+ static constexpr std::underlying_type_t<Enum> value = LargestValue; \
+ }
+
+/// Traits class to determine whether an enum has been declared as a bitwise
+/// enum via ORC_RT_DECLARE_ENUM_AS_BITMASK.
+template <typename E, typename Enable = void>
+struct is_bitmask_enum : std::false_type {};
+
+template <typename E>
+struct is_bitmask_enum<
+ E, std::enable_if_t<sizeof(E::ORC_RT_BITMASK_LARGEST_ENUMERATOR) >= 0>>
+ : std::true_type {};
+
+template <typename E>
+inline constexpr bool is_bitmask_enum_v = is_bitmask_enum<E>::value;
+
+/// Traits class to deermine bitmask enum largest bit.
+template <typename E, typename Enable = void> struct largest_bitmask_enum_bit;
+
+template <typename E>
+struct largest_bitmask_enum_bit<
+ E, std::enable_if_t<sizeof(E::ORC_RT_BITMASK_LARGEST_ENUMERATOR) >= 0>> {
+ using UnderlyingTy = std::underlying_type_t<E>;
+ static constexpr UnderlyingTy value =
+ static_cast<UnderlyingTy>(E::ORC_RT_BITMASK_LARGEST_ENUMERATOR);
+};
+
+template <typename E> constexpr std::underlying_type_t<E> Mask() {
+ return bit_ceil(largest_bitmask_enum_bit<E>::value) - 1;
+}
+
+template <typename E> constexpr std::underlying_type_t<E> Underlying(E Val) {
+ auto U = static_cast<std::underlying_type_t<E>>(Val);
+ assert(U >= 0 && "Negative enum values are not allowed");
+ assert(U <= Mask<E>() && "Enum value too large (or langest val too small");
+ return U;
+}
+
+template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
+constexpr E operator~(E Val) {
+ return static_cast<E>(~Underlying(Val) & Mask<E>());
+}
+
+template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
+constexpr E operator|(E LHS, E RHS) {
+ return static_cast<E>(Underlying(LHS) | Underlying(RHS));
+}
+
+template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
+constexpr E operator&(E LHS, E RHS) {
+ return static_cast<E>(Underlying(LHS) & Underlying(RHS));
+}
+
+template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
+constexpr E operator^(E LHS, E RHS) {
+ return static_cast<E>(Underlying(LHS) ^ Underlying(RHS));
+}
+
+template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
+E &operator|=(E &LHS, E RHS) {
+ LHS = LHS | RHS;
+ return LHS;
+}
+
+template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
+E &operator&=(E &LHS, E RHS) {
+ LHS = LHS & RHS;
+ return LHS;
+}
+
+template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
+E &operator^=(E &LHS, E RHS) {
+ LHS = LHS ^ RHS;
+ return LHS;
+}
+
+} // end namespace __orc_rt
+
+#endif // ORC_RT_BITMASK_ENUM_H
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/coff_platform.cpp b/contrib/llvm-project/compiler-rt/lib/orc/coff_platform.cpp
new file mode 100644
index 000000000000..9fe5c0b06289
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/coff_platform.cpp
@@ -0,0 +1,775 @@
+//===- coff_platform.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains code required to load the rest of the COFF runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#define NOMINMAX
+#include <windows.h>
+
+#include "coff_platform.h"
+
+#include "debug.h"
+#include "error.h"
+#include "wrapper_function_utils.h"
+
+#include <array>
+#include <list>
+#include <map>
+#include <mutex>
+#include <sstream>
+#include <string_view>
+#include <vector>
+
+#define DEBUG_TYPE "coff_platform"
+
+using namespace __orc_rt;
+
+namespace __orc_rt {
+
+using COFFJITDylibDepInfo = std::vector<ExecutorAddr>;
+using COFFJITDylibDepInfoMap =
+ std::unordered_map<ExecutorAddr, COFFJITDylibDepInfo>;
+
+using SPSCOFFObjectSectionsMap =
+ SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRange>>;
+
+using SPSCOFFJITDylibDepInfo = SPSSequence<SPSExecutorAddr>;
+
+using SPSCOFFJITDylibDepInfoMap =
+ SPSSequence<SPSTuple<SPSExecutorAddr, SPSCOFFJITDylibDepInfo>>;
+
+} // namespace __orc_rt
+
+ORC_RT_JIT_DISPATCH_TAG(__orc_rt_coff_symbol_lookup_tag)
+ORC_RT_JIT_DISPATCH_TAG(__orc_rt_coff_push_initializers_tag)
+
+namespace {
+class COFFPlatformRuntimeState {
+private:
+ // Ctor/dtor section.
+ // Manage lists of *tor functions sorted by the last character of subsection
+ // name.
+ struct XtorSection {
+ void Register(char SubsectionChar, span<void (*)(void)> Xtors) {
+ Subsections[SubsectionChar - 'A'].push_back(Xtors);
+ SubsectionsNew[SubsectionChar - 'A'].push_back(Xtors);
+ }
+
+ void RegisterNoRun(char SubsectionChar, span<void (*)(void)> Xtors) {
+ Subsections[SubsectionChar - 'A'].push_back(Xtors);
+ }
+
+ void Reset() { SubsectionsNew = Subsections; }
+
+ void RunAllNewAndFlush();
+
+ private:
+ std::array<std::vector<span<void (*)(void)>>, 26> Subsections;
+ std::array<std::vector<span<void (*)(void)>>, 26> SubsectionsNew;
+ };
+
+ struct JITDylibState {
+ std::string Name;
+ void *Header = nullptr;
+ size_t LinkedAgainstRefCount = 0;
+ size_t DlRefCount = 0;
+ std::vector<JITDylibState *> Deps;
+ std::vector<void (*)(void)> AtExits;
+ XtorSection CInitSection; // XIA~XIZ
+ XtorSection CXXInitSection; // XCA~XCZ
+ XtorSection CPreTermSection; // XPA~XPZ
+ XtorSection CTermSection; // XTA~XTZ
+
+ bool referenced() const {
+ return LinkedAgainstRefCount != 0 || DlRefCount != 0;
+ }
+ };
+
+public:
+ static void initialize();
+ static COFFPlatformRuntimeState &get();
+ static bool isInitialized() { return CPS; }
+ static void destroy();
+
+ COFFPlatformRuntimeState() = default;
+
+ // Delete copy and move constructors.
+ COFFPlatformRuntimeState(const COFFPlatformRuntimeState &) = delete;
+ COFFPlatformRuntimeState &
+ operator=(const COFFPlatformRuntimeState &) = delete;
+ COFFPlatformRuntimeState(COFFPlatformRuntimeState &&) = delete;
+ COFFPlatformRuntimeState &operator=(COFFPlatformRuntimeState &&) = delete;
+
+ const char *dlerror();
+ void *dlopen(std::string_view Name, int Mode);
+ int dlclose(void *Header);
+ void *dlsym(void *Header, std::string_view Symbol);
+
+ Error registerJITDylib(std::string Name, void *Header);
+ Error deregisterJITDylib(void *Header);
+
+ Error registerAtExit(ExecutorAddr HeaderAddr, void (*AtExit)(void));
+
+ Error registerObjectSections(
+ ExecutorAddr HeaderAddr,
+ std::vector<std::pair<std::string_view, ExecutorAddrRange>> Secs,
+ bool RunInitializers);
+ Error deregisterObjectSections(
+ ExecutorAddr HeaderAddr,
+ std::vector<std::pair<std::string_view, ExecutorAddrRange>> Secs);
+
+ void *findJITDylibBaseByPC(uint64_t PC);
+
+private:
+ Error registerBlockRange(ExecutorAddr HeaderAddr, ExecutorAddrRange Range);
+ Error deregisterBlockRange(ExecutorAddr HeaderAddr, ExecutorAddrRange Range);
+
+ Error registerSEHFrames(ExecutorAddr HeaderAddr,
+ ExecutorAddrRange SEHFrameRange);
+ Error deregisterSEHFrames(ExecutorAddr HeaderAddr,
+ ExecutorAddrRange SEHFrameRange);
+
+ Expected<void *> dlopenImpl(std::string_view Path, int Mode);
+ Error dlopenFull(JITDylibState &JDS);
+ Error dlopenInitialize(JITDylibState &JDS, COFFJITDylibDepInfoMap &DepInfo);
+
+ Error dlcloseImpl(void *DSOHandle);
+ Error dlcloseDeinitialize(JITDylibState &JDS);
+
+ JITDylibState *getJITDylibStateByHeader(void *DSOHandle);
+ JITDylibState *getJITDylibStateByName(std::string_view Path);
+ Expected<ExecutorAddr> lookupSymbolInJITDylib(void *DSOHandle,
+ std::string_view Symbol);
+
+ static COFFPlatformRuntimeState *CPS;
+
+ std::recursive_mutex JDStatesMutex;
+ std::map<void *, JITDylibState> JDStates;
+ struct BlockRange {
+ void *Header;
+ size_t Size;
+ };
+ std::map<void *, BlockRange> BlockRanges;
+ std::unordered_map<std::string_view, void *> JDNameToHeader;
+ std::string DLFcnError;
+};
+
+} // namespace
+
+COFFPlatformRuntimeState *COFFPlatformRuntimeState::CPS = nullptr;
+
+COFFPlatformRuntimeState::JITDylibState *
+COFFPlatformRuntimeState::getJITDylibStateByHeader(void *Header) {
+ auto I = JDStates.find(Header);
+ if (I == JDStates.end())
+ return nullptr;
+ return &I->second;
+}
+
+COFFPlatformRuntimeState::JITDylibState *
+COFFPlatformRuntimeState::getJITDylibStateByName(std::string_view Name) {
+ // FIXME: Avoid creating string copy here.
+ auto I = JDNameToHeader.find(std::string(Name.data(), Name.size()));
+ if (I == JDNameToHeader.end())
+ return nullptr;
+ void *H = I->second;
+ auto J = JDStates.find(H);
+ assert(J != JDStates.end() &&
+ "JITDylib has name map entry but no header map entry");
+ return &J->second;
+}
+
+Error COFFPlatformRuntimeState::registerJITDylib(std::string Name,
+ void *Header) {
+ ORC_RT_DEBUG({
+ printdbg("Registering JITDylib %s: Header = %p\n", Name.c_str(), Header);
+ });
+ std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex);
+ if (JDStates.count(Header)) {
+ std::ostringstream ErrStream;
+ ErrStream << "Duplicate JITDylib registration for header " << Header
+ << " (name = " << Name << ")";
+ return make_error<StringError>(ErrStream.str());
+ }
+ if (JDNameToHeader.count(Name)) {
+ std::ostringstream ErrStream;
+ ErrStream << "Duplicate JITDylib registration for header " << Header
+ << " (header = " << Header << ")";
+ return make_error<StringError>(ErrStream.str());
+ }
+
+ auto &JDS = JDStates[Header];
+ JDS.Name = std::move(Name);
+ JDS.Header = Header;
+ JDNameToHeader[JDS.Name] = Header;
+ return Error::success();
+}
+
+Error COFFPlatformRuntimeState::deregisterJITDylib(void *Header) {
+ std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex);
+ auto I = JDStates.find(Header);
+ if (I == JDStates.end()) {
+ std::ostringstream ErrStream;
+ ErrStream << "Attempted to deregister unrecognized header " << Header;
+ return make_error<StringError>(ErrStream.str());
+ }
+
+ // Remove std::string construction once we can use C++20.
+ auto J = JDNameToHeader.find(
+ std::string(I->second.Name.data(), I->second.Name.size()));
+ assert(J != JDNameToHeader.end() &&
+ "Missing JDNameToHeader entry for JITDylib");
+
+ ORC_RT_DEBUG({
+ printdbg("Deregistering JITDylib %s: Header = %p\n", I->second.Name.c_str(),
+ Header);
+ });
+
+ JDNameToHeader.erase(J);
+ JDStates.erase(I);
+ return Error::success();
+}
+
+void COFFPlatformRuntimeState::XtorSection::RunAllNewAndFlush() {
+ for (auto &Subsection : SubsectionsNew) {
+ for (auto &XtorGroup : Subsection)
+ for (auto &Xtor : XtorGroup)
+ if (Xtor)
+ Xtor();
+ Subsection.clear();
+ }
+}
+
+const char *COFFPlatformRuntimeState::dlerror() { return DLFcnError.c_str(); }
+
+void *COFFPlatformRuntimeState::dlopen(std::string_view Path, int Mode) {
+ ORC_RT_DEBUG({
+ std::string S(Path.data(), Path.size());
+ printdbg("COFFPlatform::dlopen(\"%s\")\n", S.c_str());
+ });
+ std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex);
+ if (auto H = dlopenImpl(Path, Mode))
+ return *H;
+ else {
+ // FIXME: Make dlerror thread safe.
+ DLFcnError = toString(H.takeError());
+ return nullptr;
+ }
+}
+
+int COFFPlatformRuntimeState::dlclose(void *DSOHandle) {
+ ORC_RT_DEBUG({
+ auto *JDS = getJITDylibStateByHeader(DSOHandle);
+ std::string DylibName;
+ if (JDS) {
+ std::string S;
+ printdbg("COFFPlatform::dlclose(%p) (%s)\n", DSOHandle, S.c_str());
+ } else
+ printdbg("COFFPlatform::dlclose(%p) (%s)\n", DSOHandle, "invalid handle");
+ });
+ std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex);
+ if (auto Err = dlcloseImpl(DSOHandle)) {
+ // FIXME: Make dlerror thread safe.
+ DLFcnError = toString(std::move(Err));
+ return -1;
+ }
+ return 0;
+}
+
+void *COFFPlatformRuntimeState::dlsym(void *Header, std::string_view Symbol) {
+ auto Addr = lookupSymbolInJITDylib(Header, Symbol);
+ if (!Addr) {
+ return 0;
+ }
+
+ return Addr->toPtr<void *>();
+}
+
+Expected<void *> COFFPlatformRuntimeState::dlopenImpl(std::string_view Path,
+ int Mode) {
+ // Try to find JITDylib state by name.
+ auto *JDS = getJITDylibStateByName(Path);
+
+ if (!JDS)
+ return make_error<StringError>("No registered JTIDylib for path " +
+ std::string(Path.data(), Path.size()));
+
+ if (auto Err = dlopenFull(*JDS))
+ return std::move(Err);
+
+ // Bump the ref-count on this dylib.
+ ++JDS->DlRefCount;
+
+ // Return the header address.
+ return JDS->Header;
+}
+
+Error COFFPlatformRuntimeState::dlopenFull(JITDylibState &JDS) {
+ // Call back to the JIT to push the initializers.
+ Expected<COFFJITDylibDepInfoMap> DepInfoMap((COFFJITDylibDepInfoMap()));
+ if (auto Err = WrapperFunction<SPSExpected<SPSCOFFJITDylibDepInfoMap>(
+ SPSExecutorAddr)>::call(&__orc_rt_coff_push_initializers_tag,
+ DepInfoMap,
+ ExecutorAddr::fromPtr(JDS.Header)))
+ return Err;
+ if (!DepInfoMap)
+ return DepInfoMap.takeError();
+
+ if (auto Err = dlopenInitialize(JDS, *DepInfoMap))
+ return Err;
+
+ if (!DepInfoMap->empty()) {
+ ORC_RT_DEBUG({
+ printdbg("Unrecognized dep-info key headers in dlopen of %s\n",
+ JDS.Name.c_str());
+ });
+ std::ostringstream ErrStream;
+ ErrStream << "Encountered unrecognized dep-info key headers "
+ "while processing dlopen of "
+ << JDS.Name;
+ return make_error<StringError>(ErrStream.str());
+ }
+
+ return Error::success();
+}
+
+Error COFFPlatformRuntimeState::dlopenInitialize(
+ JITDylibState &JDS, COFFJITDylibDepInfoMap &DepInfo) {
+ ORC_RT_DEBUG({
+ printdbg("COFFPlatformRuntimeState::dlopenInitialize(\"%s\")\n",
+ JDS.Name.c_str());
+ });
+
+ // Skip visited dependency.
+ auto I = DepInfo.find(ExecutorAddr::fromPtr(JDS.Header));
+ if (I == DepInfo.end())
+ return Error::success();
+
+ auto DI = std::move(I->second);
+ DepInfo.erase(I);
+
+ // Run initializers of dependencies in proper order by depth-first traversal
+ // of dependency graph.
+ std::vector<JITDylibState *> OldDeps;
+ std::swap(JDS.Deps, OldDeps);
+ JDS.Deps.reserve(DI.size());
+ for (auto DepHeaderAddr : DI) {
+ auto *DepJDS = getJITDylibStateByHeader(DepHeaderAddr.toPtr<void *>());
+ if (!DepJDS) {
+ std::ostringstream ErrStream;
+ ErrStream << "Encountered unrecognized dep header "
+ << DepHeaderAddr.toPtr<void *>() << " while initializing "
+ << JDS.Name;
+ return make_error<StringError>(ErrStream.str());
+ }
+ ++DepJDS->LinkedAgainstRefCount;
+ if (auto Err = dlopenInitialize(*DepJDS, DepInfo))
+ return Err;
+ }
+
+ // Run static initializers.
+ JDS.CInitSection.RunAllNewAndFlush();
+ JDS.CXXInitSection.RunAllNewAndFlush();
+
+ // Decrement old deps.
+ for (auto *DepJDS : OldDeps) {
+ --DepJDS->LinkedAgainstRefCount;
+ if (!DepJDS->referenced())
+ if (auto Err = dlcloseDeinitialize(*DepJDS))
+ return Err;
+ }
+
+ return Error::success();
+}
+
+Error COFFPlatformRuntimeState::dlcloseImpl(void *DSOHandle) {
+ // Try to find JITDylib state by header.
+ auto *JDS = getJITDylibStateByHeader(DSOHandle);
+
+ if (!JDS) {
+ std::ostringstream ErrStream;
+ ErrStream << "No registered JITDylib for " << DSOHandle;
+ return make_error<StringError>(ErrStream.str());
+ }
+
+ // Bump the ref-count.
+ --JDS->DlRefCount;
+
+ if (!JDS->referenced())
+ return dlcloseDeinitialize(*JDS);
+
+ return Error::success();
+}
+
+Error COFFPlatformRuntimeState::dlcloseDeinitialize(JITDylibState &JDS) {
+ ORC_RT_DEBUG({
+ printdbg("COFFPlatformRuntimeState::dlcloseDeinitialize(\"%s\")\n",
+ JDS.Name.c_str());
+ });
+
+ // Run atexits
+ for (auto AtExit : JDS.AtExits)
+ AtExit();
+ JDS.AtExits.clear();
+
+ // Run static terminators.
+ JDS.CPreTermSection.RunAllNewAndFlush();
+ JDS.CTermSection.RunAllNewAndFlush();
+
+ // Queue all xtors as new again.
+ JDS.CInitSection.Reset();
+ JDS.CXXInitSection.Reset();
+ JDS.CPreTermSection.Reset();
+ JDS.CTermSection.Reset();
+
+ // Deinitialize any dependencies.
+ for (auto *DepJDS : JDS.Deps) {
+ --DepJDS->LinkedAgainstRefCount;
+ if (!DepJDS->referenced())
+ if (auto Err = dlcloseDeinitialize(*DepJDS))
+ return Err;
+ }
+
+ return Error::success();
+}
+
+Expected<ExecutorAddr>
+COFFPlatformRuntimeState::lookupSymbolInJITDylib(void *header,
+ std::string_view Sym) {
+ Expected<ExecutorAddr> Result((ExecutorAddr()));
+ if (auto Err = WrapperFunction<SPSExpected<SPSExecutorAddr>(
+ SPSExecutorAddr, SPSString)>::call(&__orc_rt_coff_symbol_lookup_tag,
+ Result,
+ ExecutorAddr::fromPtr(header),
+ Sym))
+ return std::move(Err);
+ return Result;
+}
+
+Error COFFPlatformRuntimeState::registerObjectSections(
+ ExecutorAddr HeaderAddr,
+ std::vector<std::pair<std::string_view, ExecutorAddrRange>> Secs,
+ bool RunInitializers) {
+ std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex);
+ auto I = JDStates.find(HeaderAddr.toPtr<void *>());
+ if (I == JDStates.end()) {
+ std::ostringstream ErrStream;
+ ErrStream << "Unrecognized header " << HeaderAddr.getValue();
+ return make_error<StringError>(ErrStream.str());
+ }
+ auto &JDState = I->second;
+ for (auto &KV : Secs) {
+ if (auto Err = registerBlockRange(HeaderAddr, KV.second))
+ return Err;
+ if (KV.first.empty())
+ continue;
+ char LastChar = KV.first.data()[KV.first.size() - 1];
+ if (KV.first == ".pdata") {
+ if (auto Err = registerSEHFrames(HeaderAddr, KV.second))
+ return Err;
+ } else if (KV.first >= ".CRT$XIA" && KV.first <= ".CRT$XIZ") {
+ if (RunInitializers)
+ JDState.CInitSection.Register(LastChar,
+ KV.second.toSpan<void (*)(void)>());
+ else
+ JDState.CInitSection.RegisterNoRun(LastChar,
+ KV.second.toSpan<void (*)(void)>());
+ } else if (KV.first >= ".CRT$XCA" && KV.first <= ".CRT$XCZ") {
+ if (RunInitializers)
+ JDState.CXXInitSection.Register(LastChar,
+ KV.second.toSpan<void (*)(void)>());
+ else
+ JDState.CXXInitSection.RegisterNoRun(
+ LastChar, KV.second.toSpan<void (*)(void)>());
+ } else if (KV.first >= ".CRT$XPA" && KV.first <= ".CRT$XPZ")
+ JDState.CPreTermSection.Register(LastChar,
+ KV.second.toSpan<void (*)(void)>());
+ else if (KV.first >= ".CRT$XTA" && KV.first <= ".CRT$XTZ")
+ JDState.CTermSection.Register(LastChar,
+ KV.second.toSpan<void (*)(void)>());
+ }
+ return Error::success();
+}
+
+Error COFFPlatformRuntimeState::deregisterObjectSections(
+ ExecutorAddr HeaderAddr,
+ std::vector<std::pair<std::string_view, ExecutorAddrRange>> Secs) {
+ std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex);
+ auto I = JDStates.find(HeaderAddr.toPtr<void *>());
+ if (I == JDStates.end()) {
+ std::ostringstream ErrStream;
+ ErrStream << "Attempted to deregister unrecognized header "
+ << HeaderAddr.getValue();
+ return make_error<StringError>(ErrStream.str());
+ }
+ for (auto &KV : Secs) {
+ if (auto Err = deregisterBlockRange(HeaderAddr, KV.second))
+ return Err;
+ if (KV.first == ".pdata")
+ if (auto Err = deregisterSEHFrames(HeaderAddr, KV.second))
+ return Err;
+ }
+ return Error::success();
+}
+
+Error COFFPlatformRuntimeState::registerSEHFrames(
+ ExecutorAddr HeaderAddr, ExecutorAddrRange SEHFrameRange) {
+ int N = (SEHFrameRange.End.getValue() - SEHFrameRange.Start.getValue()) /
+ sizeof(RUNTIME_FUNCTION);
+ auto Func = SEHFrameRange.Start.toPtr<PRUNTIME_FUNCTION>();
+ if (!RtlAddFunctionTable(Func, N,
+ static_cast<DWORD64>(HeaderAddr.getValue())))
+ return make_error<StringError>("Failed to register SEH frames");
+ return Error::success();
+}
+
+Error COFFPlatformRuntimeState::deregisterSEHFrames(
+ ExecutorAddr HeaderAddr, ExecutorAddrRange SEHFrameRange) {
+ if (!RtlDeleteFunctionTable(SEHFrameRange.Start.toPtr<PRUNTIME_FUNCTION>()))
+ return make_error<StringError>("Failed to deregister SEH frames");
+ return Error::success();
+}
+
+Error COFFPlatformRuntimeState::registerBlockRange(ExecutorAddr HeaderAddr,
+ ExecutorAddrRange Range) {
+ assert(!BlockRanges.count(Range.Start.toPtr<void *>()) &&
+ "Block range address already registered");
+ BlockRange B = {HeaderAddr.toPtr<void *>(), Range.size()};
+ BlockRanges.emplace(Range.Start.toPtr<void *>(), B);
+ return Error::success();
+}
+
+Error COFFPlatformRuntimeState::deregisterBlockRange(ExecutorAddr HeaderAddr,
+ ExecutorAddrRange Range) {
+ assert(BlockRanges.count(Range.Start.toPtr<void *>()) &&
+ "Block range address not registered");
+ BlockRanges.erase(Range.Start.toPtr<void *>());
+ return Error::success();
+}
+
+Error COFFPlatformRuntimeState::registerAtExit(ExecutorAddr HeaderAddr,
+ void (*AtExit)(void)) {
+ std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex);
+ auto I = JDStates.find(HeaderAddr.toPtr<void *>());
+ if (I == JDStates.end()) {
+ std::ostringstream ErrStream;
+ ErrStream << "Unrecognized header " << HeaderAddr.getValue();
+ return make_error<StringError>(ErrStream.str());
+ }
+ I->second.AtExits.push_back(AtExit);
+ return Error::success();
+}
+
+void COFFPlatformRuntimeState::initialize() {
+ assert(!CPS && "COFFPlatformRuntimeState should be null");
+ CPS = new COFFPlatformRuntimeState();
+}
+
+COFFPlatformRuntimeState &COFFPlatformRuntimeState::get() {
+ assert(CPS && "COFFPlatformRuntimeState not initialized");
+ return *CPS;
+}
+
+void COFFPlatformRuntimeState::destroy() {
+ assert(CPS && "COFFPlatformRuntimeState not initialized");
+ delete CPS;
+}
+
+void *COFFPlatformRuntimeState::findJITDylibBaseByPC(uint64_t PC) {
+ std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex);
+ auto It = BlockRanges.upper_bound(reinterpret_cast<void *>(PC));
+ if (It == BlockRanges.begin())
+ return nullptr;
+ --It;
+ auto &Range = It->second;
+ if (PC >= reinterpret_cast<uint64_t>(It->first) + Range.Size)
+ return nullptr;
+ return Range.Header;
+}
+
+ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
+__orc_rt_coff_platform_bootstrap(char *ArgData, size_t ArgSize) {
+ COFFPlatformRuntimeState::initialize();
+ return WrapperFunctionResult().release();
+}
+
+ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
+__orc_rt_coff_platform_shutdown(char *ArgData, size_t ArgSize) {
+ COFFPlatformRuntimeState::destroy();
+ return WrapperFunctionResult().release();
+}
+
+ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
+__orc_rt_coff_register_jitdylib(char *ArgData, size_t ArgSize) {
+ return WrapperFunction<SPSError(SPSString, SPSExecutorAddr)>::handle(
+ ArgData, ArgSize,
+ [](std::string &Name, ExecutorAddr HeaderAddr) {
+ return COFFPlatformRuntimeState::get().registerJITDylib(
+ std::move(Name), HeaderAddr.toPtr<void *>());
+ })
+ .release();
+}
+
+ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
+__orc_rt_coff_deregister_jitdylib(char *ArgData, size_t ArgSize) {
+ return WrapperFunction<SPSError(SPSExecutorAddr)>::handle(
+ ArgData, ArgSize,
+ [](ExecutorAddr HeaderAddr) {
+ return COFFPlatformRuntimeState::get().deregisterJITDylib(
+ HeaderAddr.toPtr<void *>());
+ })
+ .release();
+}
+
+ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
+__orc_rt_coff_register_object_sections(char *ArgData, size_t ArgSize) {
+ return WrapperFunction<SPSError(SPSExecutorAddr, SPSCOFFObjectSectionsMap,
+ bool)>::
+ handle(ArgData, ArgSize,
+ [](ExecutorAddr HeaderAddr,
+ std::vector<std::pair<std::string_view, ExecutorAddrRange>>
+ &Secs,
+ bool RunInitializers) {
+ return COFFPlatformRuntimeState::get().registerObjectSections(
+ HeaderAddr, std::move(Secs), RunInitializers);
+ })
+ .release();
+}
+
+ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
+__orc_rt_coff_deregister_object_sections(char *ArgData, size_t ArgSize) {
+ return WrapperFunction<SPSError(SPSExecutorAddr, SPSCOFFObjectSectionsMap)>::
+ handle(ArgData, ArgSize,
+ [](ExecutorAddr HeaderAddr,
+ std::vector<std::pair<std::string_view, ExecutorAddrRange>>
+ &Secs) {
+ return COFFPlatformRuntimeState::get().deregisterObjectSections(
+ HeaderAddr, std::move(Secs));
+ })
+ .release();
+}
+//------------------------------------------------------------------------------
+// JIT'd dlfcn alternatives.
+//------------------------------------------------------------------------------
+
+const char *__orc_rt_coff_jit_dlerror() {
+ return COFFPlatformRuntimeState::get().dlerror();
+}
+
+void *__orc_rt_coff_jit_dlopen(const char *path, int mode) {
+ return COFFPlatformRuntimeState::get().dlopen(path, mode);
+}
+
+int __orc_rt_coff_jit_dlclose(void *header) {
+ return COFFPlatformRuntimeState::get().dlclose(header);
+}
+
+void *__orc_rt_coff_jit_dlsym(void *header, const char *symbol) {
+ return COFFPlatformRuntimeState::get().dlsym(header, symbol);
+}
+
+//------------------------------------------------------------------------------
+// COFF SEH exception support
+//------------------------------------------------------------------------------
+
+struct ThrowInfo {
+ uint32_t attributes;
+ void *data;
+};
+
+ORC_RT_INTERFACE void __stdcall __orc_rt_coff_cxx_throw_exception(
+ void *pExceptionObject, ThrowInfo *pThrowInfo) {
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmultichar"
+#endif
+ constexpr uint32_t EH_EXCEPTION_NUMBER = 'msc' | 0xE0000000;
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+ constexpr uint32_t EH_MAGIC_NUMBER1 = 0x19930520;
+ auto BaseAddr = COFFPlatformRuntimeState::get().findJITDylibBaseByPC(
+ reinterpret_cast<uint64_t>(pThrowInfo));
+ if (!BaseAddr) {
+ // This is not from JIT'd region.
+ // FIXME: Use the default implementation like below when alias api is
+ // capable. _CxxThrowException(pExceptionObject, pThrowInfo);
+ fprintf(stderr, "Throwing exception from compiled callback into JIT'd "
+ "exception handler not supported yet.\n");
+ abort();
+ return;
+ }
+ const ULONG_PTR parameters[] = {
+ EH_MAGIC_NUMBER1,
+ reinterpret_cast<ULONG_PTR>(pExceptionObject),
+ reinterpret_cast<ULONG_PTR>(pThrowInfo),
+ reinterpret_cast<ULONG_PTR>(BaseAddr),
+ };
+ RaiseException(EH_EXCEPTION_NUMBER, EXCEPTION_NONCONTINUABLE,
+ _countof(parameters), parameters);
+}
+
+//------------------------------------------------------------------------------
+// COFF atexits
+//------------------------------------------------------------------------------
+
+typedef int (*OnExitFunction)(void);
+typedef void (*AtExitFunction)(void);
+
+ORC_RT_INTERFACE OnExitFunction __orc_rt_coff_onexit(void *Header,
+ OnExitFunction Func) {
+ if (auto Err = COFFPlatformRuntimeState::get().registerAtExit(
+ ExecutorAddr::fromPtr(Header), (void (*)(void))Func)) {
+ consumeError(std::move(Err));
+ return nullptr;
+ }
+ return Func;
+}
+
+ORC_RT_INTERFACE int __orc_rt_coff_atexit(void *Header, AtExitFunction Func) {
+ if (auto Err = COFFPlatformRuntimeState::get().registerAtExit(
+ ExecutorAddr::fromPtr(Header), (void (*)(void))Func)) {
+ consumeError(std::move(Err));
+ return -1;
+ }
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+// COFF Run Program
+//------------------------------------------------------------------------------
+
+ORC_RT_INTERFACE int64_t __orc_rt_coff_run_program(const char *JITDylibName,
+ const char *EntrySymbolName,
+ int argc, char *argv[]) {
+ using MainTy = int (*)(int, char *[]);
+
+ void *H =
+ __orc_rt_coff_jit_dlopen(JITDylibName, __orc_rt::coff::ORC_RT_RTLD_LAZY);
+ if (!H) {
+ __orc_rt_log_error(__orc_rt_coff_jit_dlerror());
+ return -1;
+ }
+
+ auto *Main =
+ reinterpret_cast<MainTy>(__orc_rt_coff_jit_dlsym(H, EntrySymbolName));
+
+ if (!Main) {
+ __orc_rt_log_error(__orc_rt_coff_jit_dlerror());
+ return -1;
+ }
+
+ int Result = Main(argc, argv);
+
+ if (__orc_rt_coff_jit_dlclose(H) == -1)
+ __orc_rt_log_error(__orc_rt_coff_jit_dlerror());
+
+ return Result;
+}
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/coff_platform.h b/contrib/llvm-project/compiler-rt/lib/orc/coff_platform.h
new file mode 100644
index 000000000000..c84185d40b60
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/coff_platform.h
@@ -0,0 +1,39 @@
+//===- coff_platform.h -------------------------------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// ORC Runtime support for dynamic loading features on COFF-based platforms.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_COFF_PLATFORM_H
+#define ORC_RT_COFF_PLATFORM_H
+
+#include "common.h"
+#include "executor_address.h"
+
+// dlfcn functions.
+ORC_RT_INTERFACE const char *__orc_rt_coff_jit_dlerror();
+ORC_RT_INTERFACE void *__orc_rt_coff_jit_dlopen(const char *path, int mode);
+ORC_RT_INTERFACE int __orc_rt_coff_jit_dlclose(void *header);
+ORC_RT_INTERFACE void *__orc_rt_coff_jit_dlsym(void *header,
+ const char *symbol);
+
+namespace __orc_rt {
+namespace coff {
+
+enum dlopen_mode : int {
+ ORC_RT_RTLD_LAZY = 0x1,
+ ORC_RT_RTLD_NOW = 0x2,
+ ORC_RT_RTLD_LOCAL = 0x4,
+ ORC_RT_RTLD_GLOBAL = 0x8
+};
+
+} // end namespace coff
+} // end namespace __orc_rt
+
+#endif
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/coff_platform.per_jd.cpp b/contrib/llvm-project/compiler-rt/lib/orc/coff_platform.per_jd.cpp
new file mode 100644
index 000000000000..6c208cb31858
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/coff_platform.per_jd.cpp
@@ -0,0 +1,31 @@
+//===- coff_platform.per_jd.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains code that will be loaded per each JITDylib.
+//
+//===----------------------------------------------------------------------===//
+#include "compiler.h"
+
+ORC_RT_INTERFACE void __orc_rt_coff_per_jd_marker() {}
+
+typedef int (*OnExitFunction)(void);
+typedef void (*AtExitFunction)(void);
+
+extern "C" void *__ImageBase;
+ORC_RT_INTERFACE OnExitFunction __orc_rt_coff_onexit(void *Header,
+ OnExitFunction Func);
+ORC_RT_INTERFACE int __orc_rt_coff_atexit(void *Header, AtExitFunction Func);
+
+ORC_RT_INTERFACE OnExitFunction
+__orc_rt_coff_onexit_per_jd(OnExitFunction Func) {
+ return __orc_rt_coff_onexit(&__ImageBase, Func);
+}
+
+ORC_RT_INTERFACE int __orc_rt_coff_atexit_per_jd(AtExitFunction Func) {
+ return __orc_rt_coff_atexit(&__ImageBase, Func);
+}
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/common.h b/contrib/llvm-project/compiler-rt/lib/orc/common.h
new file mode 100644
index 000000000000..73c5c4a2bd8d
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/common.h
@@ -0,0 +1,48 @@
+//===- common.h - Common utilities for the ORC runtime ----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime support library.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_COMMON_H
+#define ORC_RT_COMMON_H
+
+#include "compiler.h"
+#include "orc_rt/c_api.h"
+#include <type_traits>
+
+/// This macro should be used to define tags that will be associated with
+/// handlers in the JIT process, and call can be used to define tags f
+#define ORC_RT_JIT_DISPATCH_TAG(X) \
+extern "C" char X; \
+char X = 0;
+
+/// Opaque struct for external symbols.
+struct __orc_rt_Opaque {};
+
+/// Error reporting function.
+extern "C" void __orc_rt_log_error(const char *ErrMsg);
+
+/// Context object for dispatching calls to the JIT object.
+///
+/// This is declared for use by the runtime, but should be implemented in the
+/// executor or provided by a definition added to the JIT before the runtime
+/// is loaded.
+ORC_RT_IMPORT __orc_rt_Opaque __orc_rt_jit_dispatch_ctx ORC_RT_WEAK_IMPORT;
+
+/// For dispatching calls to the JIT object.
+///
+/// This is declared for use by the runtime, but should be implemented in the
+/// executor or provided by a definition added to the JIT before the runtime
+/// is loaded.
+ORC_RT_IMPORT orc_rt_CWrapperFunctionResult
+__orc_rt_jit_dispatch(__orc_rt_Opaque *DispatchCtx, const void *FnTag,
+ const char *Data, size_t Size) ORC_RT_WEAK_IMPORT;
+
+#endif // ORC_RT_COMMON_H
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/compiler.h b/contrib/llvm-project/compiler-rt/lib/orc/compiler.h
new file mode 100644
index 000000000000..88cb3d92b03b
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/compiler.h
@@ -0,0 +1,74 @@
+//===--------- compiler.h - Compiler abstraction support --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime support library.
+//
+// Most functionality in this file was swiped from llvm/Support/Compiler.h.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_COMPILER_H
+#define ORC_RT_COMPILER_H
+
+#if defined(_WIN32)
+#define ORC_RT_INTERFACE extern "C"
+#define ORC_RT_HIDDEN
+#define ORC_RT_IMPORT extern "C" __declspec(dllimport)
+#else
+#define ORC_RT_INTERFACE extern "C" __attribute__((visibility("default")))
+#define ORC_RT_HIDDEN __attribute__((visibility("hidden")))
+#define ORC_RT_IMPORT extern "C"
+#endif
+
+#ifndef __has_builtin
+# define __has_builtin(x) 0
+#endif
+
+// Only use __has_cpp_attribute in C++ mode. GCC defines __has_cpp_attribute in
+// C mode, but the :: in __has_cpp_attribute(scoped::attribute) is invalid.
+#ifndef ORC_RT_HAS_CPP_ATTRIBUTE
+#if defined(__cplusplus) && defined(__has_cpp_attribute)
+#define ORC_RT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
+#else
+#define ORC_RT_HAS_CPP_ATTRIBUTE(x) 0
+#endif
+#endif
+
+// Use the 'nodiscard' attribute in C++17 or newer mode.
+#if defined(__cplusplus) && __cplusplus > 201402L && \
+ ORC_RT_HAS_CPP_ATTRIBUTE(nodiscard)
+#define ORC_RT_NODISCARD [[nodiscard]]
+#elif ORC_RT_HAS_CPP_ATTRIBUTE(clang::warn_unused_result)
+#define ORC_RT_NODISCARD [[clang::warn_unused_result]]
+// Clang in C++14 mode claims that it has the 'nodiscard' attribute, but also
+// warns in the pedantic mode that 'nodiscard' is a C++17 extension (PR33518).
+// Use the 'nodiscard' attribute in C++14 mode only with GCC.
+// TODO: remove this workaround when PR33518 is resolved.
+#elif defined(__GNUC__) && ORC_RT_HAS_CPP_ATTRIBUTE(nodiscard)
+#define ORC_RT_NODISCARD [[nodiscard]]
+#else
+#define ORC_RT_NODISCARD
+#endif
+
+#if __has_builtin(__builtin_expect)
+#define ORC_RT_LIKELY(EXPR) __builtin_expect((bool)(EXPR), true)
+#define ORC_RT_UNLIKELY(EXPR) __builtin_expect((bool)(EXPR), false)
+#else
+#define ORC_RT_LIKELY(EXPR) (EXPR)
+#define ORC_RT_UNLIKELY(EXPR) (EXPR)
+#endif
+
+#if defined(__APPLE__)
+#define ORC_RT_WEAK_IMPORT __attribute__((weak_import))
+#elif defined(_WIN32)
+#define ORC_RT_WEAK_IMPORT
+#else
+#define ORC_RT_WEAK_IMPORT __attribute__((weak))
+#endif
+
+#endif // ORC_RT_COMPILER_H
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/debug.cpp b/contrib/llvm-project/compiler-rt/lib/orc/debug.cpp
new file mode 100644
index 000000000000..af20fa4e6f4e
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/debug.cpp
@@ -0,0 +1,83 @@
+//===- debug.cpp ----------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime support library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "debug.h"
+
+#include <cassert>
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+
+namespace __orc_rt {
+
+#ifndef NDEBUG
+
+std::atomic<const char *> DebugTypes;
+char DebugTypesAll;
+char DebugTypesNone;
+
+/// Sets the DebugState and DebugTypes values -- this function may be called
+/// concurrently on multiple threads, but will always assign the same values so
+/// this should be safe.
+const char *initializeDebug() {
+ if (const char *DT = getenv("ORC_RT_DEBUG")) {
+ // If ORC_RT_DEBUG=1 then log everything.
+ if (strcmp(DT, "1") == 0) {
+ DebugTypes.store(&DebugTypesAll, std::memory_order_relaxed);
+ return &DebugTypesAll;
+ }
+
+ // If ORC_RT_DEBUG is non-empty then record the string for use in
+ // debugTypeEnabled.
+ if (strcmp(DT, "") != 0) {
+ DebugTypes.store(DT, std::memory_order_relaxed);
+ return DT;
+ }
+ }
+
+ // If ORT_RT_DEBUG is undefined or defined as empty then log nothing.
+ DebugTypes.store(&DebugTypesNone, std::memory_order_relaxed);
+ return &DebugTypesNone;
+}
+
+bool debugTypeEnabled(const char *Type, const char *Types) {
+ assert(Types && Types != &DebugTypesAll && Types != &DebugTypesNone &&
+ "Invalid Types value");
+ size_t TypeLen = strlen(Type);
+ const char *Start = Types;
+ const char *End = Start;
+
+ do {
+ if (*End == '\0' || *End == ',') {
+ size_t ItemLen = End - Start;
+ if (ItemLen == TypeLen && memcmp(Type, Start, TypeLen) == 0)
+ return true;
+ if (*End == '\0')
+ return false;
+ Start = End + 1;
+ }
+ ++End;
+ } while (true);
+}
+
+void printdbg(const char *format, ...) {
+ va_list Args;
+ va_start(Args, format);
+ vfprintf(stderr, format, Args);
+ va_end(Args);
+}
+
+#endif // !NDEBUG
+
+} // end namespace __orc_rt
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/debug.h b/contrib/llvm-project/compiler-rt/lib/orc/debug.h
new file mode 100644
index 000000000000..a0bc653d032e
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/debug.h
@@ -0,0 +1,56 @@
+//===- debug.h - Debugging output utilities ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime support library.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_DEBUG_H
+#define ORC_RT_DEBUG_H
+
+#include <atomic>
+
+#ifndef NDEBUG
+
+namespace __orc_rt {
+
+extern std::atomic<const char *> DebugTypes;
+extern char DebugTypesAll;
+extern char DebugTypesNone;
+
+const char *initializeDebug();
+bool debugTypeEnabled(const char *Type, const char *Types);
+void printdbg(const char *format, ...);
+
+} // namespace __orc_rt
+
+#define ORC_RT_DEBUG_WITH_TYPE(TYPE, X) \
+ do { \
+ const char *Types = \
+ ::__orc_rt::DebugTypes.load(std::memory_order_relaxed); \
+ if (!Types) \
+ Types = initializeDebug(); \
+ if (Types == &DebugTypesNone) \
+ break; \
+ if (Types == &DebugTypesAll || \
+ ::__orc_rt::debugTypeEnabled(TYPE, Types)) { \
+ X; \
+ } \
+ } while (false)
+
+#else
+
+#define ORC_RT_DEBUG_WITH_TYPE(TYPE, X) \
+ do { \
+ } while (false)
+
+#endif // !NDEBUG
+
+#define ORC_RT_DEBUG(X) ORC_RT_DEBUG_WITH_TYPE(DEBUG_TYPE, X)
+
+#endif // ORC_RT_DEBUG_H
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/dlfcn_wrapper.cpp b/contrib/llvm-project/compiler-rt/lib/orc/dlfcn_wrapper.cpp
new file mode 100644
index 000000000000..ece63da2cb48
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/dlfcn_wrapper.cpp
@@ -0,0 +1,52 @@
+//===- dlfcn_wrapper.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime support library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "adt.h"
+#include "common.h"
+#include "wrapper_function_utils.h"
+
+#include <vector>
+
+using namespace __orc_rt;
+
+extern "C" const char *__orc_rt_jit_dlerror();
+extern "C" void *__orc_rt_jit_dlopen(const char *path, int mode);
+extern "C" int __orc_rt_jit_dlclose(void *dso_handle);
+
+ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
+__orc_rt_jit_dlerror_wrapper(const char *ArgData, size_t ArgSize) {
+ return WrapperFunction<SPSString()>::handle(
+ ArgData, ArgSize,
+ []() { return std::string(__orc_rt_jit_dlerror()); })
+ .release();
+}
+
+ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
+__orc_rt_jit_dlopen_wrapper(const char *ArgData, size_t ArgSize) {
+ return WrapperFunction<SPSExecutorAddr(SPSString, int32_t)>::handle(
+ ArgData, ArgSize,
+ [](const std::string &Path, int32_t mode) {
+ return ExecutorAddr::fromPtr(
+ __orc_rt_jit_dlopen(Path.c_str(), mode));
+ })
+ .release();
+}
+
+ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
+__orc_rt_jit_dlclose_wrapper(const char *ArgData, size_t ArgSize) {
+ return WrapperFunction<int32_t(SPSExecutorAddr)>::handle(
+ ArgData, ArgSize,
+ [](ExecutorAddr &DSOHandle) {
+ return __orc_rt_jit_dlclose(DSOHandle.toPtr<void *>());
+ })
+ .release();
+}
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/elfnix_platform.cpp b/contrib/llvm-project/compiler-rt/lib/orc/elfnix_platform.cpp
new file mode 100644
index 000000000000..c087e71038f9
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/elfnix_platform.cpp
@@ -0,0 +1,624 @@
+//===- elfnix_platform.cpp ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains code required to load the rest of the ELF-on-*IX runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#include "elfnix_platform.h"
+#include "common.h"
+#include "compiler.h"
+#include "error.h"
+#include "wrapper_function_utils.h"
+
+#include <algorithm>
+#include <map>
+#include <mutex>
+#include <sstream>
+#include <string_view>
+#include <unordered_map>
+#include <vector>
+
+using namespace __orc_rt;
+using namespace __orc_rt::elfnix;
+
+// Declare function tags for functions in the JIT process.
+ORC_RT_JIT_DISPATCH_TAG(__orc_rt_elfnix_get_initializers_tag)
+ORC_RT_JIT_DISPATCH_TAG(__orc_rt_elfnix_get_deinitializers_tag)
+ORC_RT_JIT_DISPATCH_TAG(__orc_rt_elfnix_symbol_lookup_tag)
+
+// eh-frame registration functions, made available via aliases
+// installed by the Platform
+extern "C" void __register_frame(const void *);
+extern "C" void __deregister_frame(const void *);
+
+extern "C" void
+__unw_add_dynamic_eh_frame_section(const void *) ORC_RT_WEAK_IMPORT;
+extern "C" void
+__unw_remove_dynamic_eh_frame_section(const void *) ORC_RT_WEAK_IMPORT;
+
+namespace {
+
+Error validatePointerSectionExtent(const char *SectionName,
+ const ExecutorAddrRange &SE) {
+ if (SE.size() % sizeof(uintptr_t)) {
+ std::ostringstream ErrMsg;
+ ErrMsg << std::hex << "Size of " << SectionName << " 0x"
+ << SE.Start.getValue() << " -- 0x" << SE.End.getValue()
+ << " is not a pointer multiple";
+ return make_error<StringError>(ErrMsg.str());
+ }
+ return Error::success();
+}
+
+Error runInitArray(const std::vector<ExecutorAddrRange> &InitArraySections,
+ const ELFNixJITDylibInitializers &MOJDIs) {
+
+ for (const auto &ModInits : InitArraySections) {
+ if (auto Err = validatePointerSectionExtent(".init_array", ModInits))
+ return Err;
+
+ using InitFunc = void (*)();
+ for (auto *Init : ModInits.toSpan<InitFunc>())
+ (*Init)();
+ }
+
+ return Error::success();
+}
+
+struct TLSInfoEntry {
+ unsigned long Key = 0;
+ unsigned long DataAddress = 0;
+};
+
+struct TLSDescriptor {
+ void (*Resolver)(void *);
+ TLSInfoEntry *InfoEntry;
+};
+
+class ELFNixPlatformRuntimeState {
+private:
+ struct AtExitEntry {
+ void (*Func)(void *);
+ void *Arg;
+ };
+
+ using AtExitsVector = std::vector<AtExitEntry>;
+
+ struct PerJITDylibState {
+ void *Header = nullptr;
+ size_t RefCount = 0;
+ bool AllowReinitialization = false;
+ AtExitsVector AtExits;
+ };
+
+public:
+ static void initialize(void *DSOHandle);
+ static ELFNixPlatformRuntimeState &get();
+ static void destroy();
+
+ ELFNixPlatformRuntimeState(void *DSOHandle);
+
+ // Delete copy and move constructors.
+ ELFNixPlatformRuntimeState(const ELFNixPlatformRuntimeState &) = delete;
+ ELFNixPlatformRuntimeState &
+ operator=(const ELFNixPlatformRuntimeState &) = delete;
+ ELFNixPlatformRuntimeState(ELFNixPlatformRuntimeState &&) = delete;
+ ELFNixPlatformRuntimeState &operator=(ELFNixPlatformRuntimeState &&) = delete;
+
+ Error registerObjectSections(ELFNixPerObjectSectionsToRegister POSR);
+ Error deregisterObjectSections(ELFNixPerObjectSectionsToRegister POSR);
+
+ const char *dlerror();
+ void *dlopen(std::string_view Name, int Mode);
+ int dlclose(void *DSOHandle);
+ void *dlsym(void *DSOHandle, std::string_view Symbol);
+
+ int registerAtExit(void (*F)(void *), void *Arg, void *DSOHandle);
+ void runAtExits(void *DSOHandle);
+
+ /// Returns the base address of the section containing ThreadData.
+ Expected<std::pair<const char *, size_t>>
+ getThreadDataSectionFor(const char *ThreadData);
+
+ void *getPlatformJDDSOHandle() { return PlatformJDDSOHandle; }
+
+private:
+ PerJITDylibState *getJITDylibStateByHeaderAddr(void *DSOHandle);
+ PerJITDylibState *getJITDylibStateByName(std::string_view Path);
+ PerJITDylibState &
+ getOrCreateJITDylibState(ELFNixJITDylibInitializers &MOJDIs);
+
+ Error registerThreadDataSection(span<const char> ThreadDataSection);
+
+ Expected<ExecutorAddr> lookupSymbolInJITDylib(void *DSOHandle,
+ std::string_view Symbol);
+
+ Expected<ELFNixJITDylibInitializerSequence>
+ getJITDylibInitializersByName(std::string_view Path);
+ Expected<void *> dlopenInitialize(std::string_view Path, int Mode);
+ Error initializeJITDylib(ELFNixJITDylibInitializers &MOJDIs);
+
+ static ELFNixPlatformRuntimeState *MOPS;
+
+ void *PlatformJDDSOHandle;
+
+ // Frame registration functions:
+ void (*registerEHFrameSection)(const void *) = nullptr;
+ void (*deregisterEHFrameSection)(const void *) = nullptr;
+
+ // FIXME: Move to thread-state.
+ std::string DLFcnError;
+
+ std::recursive_mutex JDStatesMutex;
+ std::unordered_map<void *, PerJITDylibState> JDStates;
+ std::unordered_map<std::string, void *> JDNameToHeader;
+
+ std::mutex ThreadDataSectionsMutex;
+ std::map<const char *, size_t> ThreadDataSections;
+};
+
+ELFNixPlatformRuntimeState *ELFNixPlatformRuntimeState::MOPS = nullptr;
+
+void ELFNixPlatformRuntimeState::initialize(void *DSOHandle) {
+ assert(!MOPS && "ELFNixPlatformRuntimeState should be null");
+ MOPS = new ELFNixPlatformRuntimeState(DSOHandle);
+}
+
+ELFNixPlatformRuntimeState &ELFNixPlatformRuntimeState::get() {
+ assert(MOPS && "ELFNixPlatformRuntimeState not initialized");
+ return *MOPS;
+}
+
+void ELFNixPlatformRuntimeState::destroy() {
+ assert(MOPS && "ELFNixPlatformRuntimeState not initialized");
+ delete MOPS;
+}
+
+ELFNixPlatformRuntimeState::ELFNixPlatformRuntimeState(void *DSOHandle)
+ : PlatformJDDSOHandle(DSOHandle) {
+ if (__unw_add_dynamic_eh_frame_section &&
+ __unw_remove_dynamic_eh_frame_section) {
+ registerEHFrameSection = __unw_add_dynamic_eh_frame_section;
+ deregisterEHFrameSection = __unw_remove_dynamic_eh_frame_section;
+ } else {
+ registerEHFrameSection = __register_frame;
+ deregisterEHFrameSection = __deregister_frame;
+ }
+}
+
+Error ELFNixPlatformRuntimeState::registerObjectSections(
+ ELFNixPerObjectSectionsToRegister POSR) {
+ if (POSR.EHFrameSection.Start)
+ registerEHFrameSection(POSR.EHFrameSection.Start.toPtr<const char *>());
+
+ if (POSR.ThreadDataSection.Start) {
+ if (auto Err = registerThreadDataSection(
+ POSR.ThreadDataSection.toSpan<const char>()))
+ return Err;
+ }
+
+ return Error::success();
+}
+
+Error ELFNixPlatformRuntimeState::deregisterObjectSections(
+ ELFNixPerObjectSectionsToRegister POSR) {
+ if (POSR.EHFrameSection.Start)
+ deregisterEHFrameSection(POSR.EHFrameSection.Start.toPtr<const char *>());
+
+ return Error::success();
+}
+
+const char *ELFNixPlatformRuntimeState::dlerror() { return DLFcnError.c_str(); }
+
+void *ELFNixPlatformRuntimeState::dlopen(std::string_view Path, int Mode) {
+ std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex);
+
+ // Use fast path if all JITDylibs are already loaded and don't require
+ // re-running initializers.
+ if (auto *JDS = getJITDylibStateByName(Path)) {
+ if (!JDS->AllowReinitialization) {
+ ++JDS->RefCount;
+ return JDS->Header;
+ }
+ }
+
+ auto H = dlopenInitialize(Path, Mode);
+ if (!H) {
+ DLFcnError = toString(H.takeError());
+ return nullptr;
+ }
+
+ return *H;
+}
+
+int ELFNixPlatformRuntimeState::dlclose(void *DSOHandle) {
+ runAtExits(DSOHandle);
+ return 0;
+}
+
+void *ELFNixPlatformRuntimeState::dlsym(void *DSOHandle,
+ std::string_view Symbol) {
+ auto Addr = lookupSymbolInJITDylib(DSOHandle, Symbol);
+ if (!Addr) {
+ DLFcnError = toString(Addr.takeError());
+ return 0;
+ }
+
+ return Addr->toPtr<void *>();
+}
+
+int ELFNixPlatformRuntimeState::registerAtExit(void (*F)(void *), void *Arg,
+ void *DSOHandle) {
+ // FIXME: Handle out-of-memory errors, returning -1 if OOM.
+ std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex);
+ auto *JDS = getJITDylibStateByHeaderAddr(DSOHandle);
+ assert(JDS && "JITDylib state not initialized");
+ JDS->AtExits.push_back({F, Arg});
+ return 0;
+}
+
+void ELFNixPlatformRuntimeState::runAtExits(void *DSOHandle) {
+ // FIXME: Should atexits be allowed to run concurrently with access to
+ // JDState?
+ AtExitsVector V;
+ {
+ std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex);
+ auto *JDS = getJITDylibStateByHeaderAddr(DSOHandle);
+ assert(JDS && "JITDlybi state not initialized");
+ std::swap(V, JDS->AtExits);
+ }
+
+ while (!V.empty()) {
+ auto &AE = V.back();
+ AE.Func(AE.Arg);
+ V.pop_back();
+ }
+}
+
+Expected<std::pair<const char *, size_t>>
+ELFNixPlatformRuntimeState::getThreadDataSectionFor(const char *ThreadData) {
+ std::lock_guard<std::mutex> Lock(ThreadDataSectionsMutex);
+ auto I = ThreadDataSections.upper_bound(ThreadData);
+ // Check that we have a valid entry conovering this address.
+ if (I == ThreadDataSections.begin())
+ return make_error<StringError>("No thread local data section for key");
+ I = std::prev(I);
+ if (ThreadData >= I->first + I->second)
+ return make_error<StringError>("No thread local data section for key");
+ return *I;
+}
+
+ELFNixPlatformRuntimeState::PerJITDylibState *
+ELFNixPlatformRuntimeState::getJITDylibStateByHeaderAddr(void *DSOHandle) {
+ auto I = JDStates.find(DSOHandle);
+ if (I == JDStates.end())
+ return nullptr;
+ return &I->second;
+}
+
+ELFNixPlatformRuntimeState::PerJITDylibState *
+ELFNixPlatformRuntimeState::getJITDylibStateByName(std::string_view Name) {
+ // FIXME: Avoid creating string copy here.
+ auto I = JDNameToHeader.find(std::string(Name.data(), Name.size()));
+ if (I == JDNameToHeader.end())
+ return nullptr;
+ void *H = I->second;
+ auto J = JDStates.find(H);
+ assert(J != JDStates.end() &&
+ "JITDylib has name map entry but no header map entry");
+ return &J->second;
+}
+
+ELFNixPlatformRuntimeState::PerJITDylibState &
+ELFNixPlatformRuntimeState::getOrCreateJITDylibState(
+ ELFNixJITDylibInitializers &MOJDIs) {
+ void *Header = MOJDIs.DSOHandleAddress.toPtr<void *>();
+
+ auto &JDS = JDStates[Header];
+
+ // If this entry hasn't been created yet.
+ if (!JDS.Header) {
+ assert(!JDNameToHeader.count(MOJDIs.Name) &&
+ "JITDylib has header map entry but no name map entry");
+ JDNameToHeader[MOJDIs.Name] = Header;
+ JDS.Header = Header;
+ }
+
+ return JDS;
+}
+
+Error ELFNixPlatformRuntimeState::registerThreadDataSection(
+ span<const char> ThreadDataSection) {
+ std::lock_guard<std::mutex> Lock(ThreadDataSectionsMutex);
+ auto I = ThreadDataSections.upper_bound(ThreadDataSection.data());
+ if (I != ThreadDataSections.begin()) {
+ auto J = std::prev(I);
+ if (J->first + J->second > ThreadDataSection.data())
+ return make_error<StringError>("Overlapping .tdata sections");
+ }
+ ThreadDataSections.insert(
+ I, std::make_pair(ThreadDataSection.data(), ThreadDataSection.size()));
+ return Error::success();
+}
+
+Expected<ExecutorAddr>
+ELFNixPlatformRuntimeState::lookupSymbolInJITDylib(void *DSOHandle,
+ std::string_view Sym) {
+ Expected<ExecutorAddr> Result((ExecutorAddr()));
+ if (auto Err = WrapperFunction<SPSExpected<SPSExecutorAddr>(
+ SPSExecutorAddr, SPSString)>::call(&__orc_rt_elfnix_symbol_lookup_tag,
+ Result,
+ ExecutorAddr::fromPtr(DSOHandle),
+ Sym))
+ return std::move(Err);
+ return Result;
+}
+
+Expected<ELFNixJITDylibInitializerSequence>
+ELFNixPlatformRuntimeState::getJITDylibInitializersByName(
+ std::string_view Path) {
+ Expected<ELFNixJITDylibInitializerSequence> Result(
+ (ELFNixJITDylibInitializerSequence()));
+ std::string PathStr(Path.data(), Path.size());
+ if (auto Err =
+ WrapperFunction<SPSExpected<SPSELFNixJITDylibInitializerSequence>(
+ SPSString)>::call(&__orc_rt_elfnix_get_initializers_tag, Result,
+ Path))
+ return std::move(Err);
+ return Result;
+}
+
+Expected<void *>
+ELFNixPlatformRuntimeState::dlopenInitialize(std::string_view Path, int Mode) {
+ // Either our JITDylib wasn't loaded, or it or one of its dependencies allows
+ // reinitialization. We need to call in to the JIT to see if there's any new
+ // work pending.
+ auto InitSeq = getJITDylibInitializersByName(Path);
+ if (!InitSeq)
+ return InitSeq.takeError();
+
+ // Init sequences should be non-empty.
+ if (InitSeq->empty())
+ return make_error<StringError>(
+ "__orc_rt_elfnix_get_initializers returned an "
+ "empty init sequence");
+
+ // Otherwise register and run initializers for each JITDylib.
+ for (auto &MOJDIs : *InitSeq)
+ if (auto Err = initializeJITDylib(MOJDIs))
+ return std::move(Err);
+
+ // Return the header for the last item in the list.
+ auto *JDS = getJITDylibStateByHeaderAddr(
+ InitSeq->back().DSOHandleAddress.toPtr<void *>());
+ assert(JDS && "Missing state entry for JD");
+ return JDS->Header;
+}
+
+long getPriority(const std::string &name) {
+ auto pos = name.find_last_not_of("0123456789");
+ if (pos == name.size() - 1)
+ return 65535;
+ else
+ return std::strtol(name.c_str() + pos + 1, nullptr, 10);
+}
+
+Error ELFNixPlatformRuntimeState::initializeJITDylib(
+ ELFNixJITDylibInitializers &MOJDIs) {
+
+ auto &JDS = getOrCreateJITDylibState(MOJDIs);
+ ++JDS.RefCount;
+
+ using SectionList = std::vector<ExecutorAddrRange>;
+ std::sort(MOJDIs.InitSections.begin(), MOJDIs.InitSections.end(),
+ [](const std::pair<std::string, SectionList> &LHS,
+ const std::pair<std::string, SectionList> &RHS) -> bool {
+ return getPriority(LHS.first) < getPriority(RHS.first);
+ });
+ for (auto &Entry : MOJDIs.InitSections)
+ if (auto Err = runInitArray(Entry.second, MOJDIs))
+ return Err;
+
+ return Error::success();
+}
+class ELFNixPlatformRuntimeTLVManager {
+public:
+ void *getInstance(const char *ThreadData);
+
+private:
+ std::unordered_map<const char *, char *> Instances;
+ std::unordered_map<const char *, std::unique_ptr<char[]>> AllocatedSections;
+};
+
+void *ELFNixPlatformRuntimeTLVManager::getInstance(const char *ThreadData) {
+ auto I = Instances.find(ThreadData);
+ if (I != Instances.end())
+ return I->second;
+ auto TDS =
+ ELFNixPlatformRuntimeState::get().getThreadDataSectionFor(ThreadData);
+ if (!TDS) {
+ __orc_rt_log_error(toString(TDS.takeError()).c_str());
+ return nullptr;
+ }
+
+ auto &Allocated = AllocatedSections[TDS->first];
+ if (!Allocated) {
+ Allocated = std::make_unique<char[]>(TDS->second);
+ memcpy(Allocated.get(), TDS->first, TDS->second);
+ }
+ size_t ThreadDataDelta = ThreadData - TDS->first;
+ assert(ThreadDataDelta <= TDS->second && "ThreadData outside section bounds");
+
+ char *Instance = Allocated.get() + ThreadDataDelta;
+ Instances[ThreadData] = Instance;
+ return Instance;
+}
+
+void destroyELFNixTLVMgr(void *ELFNixTLVMgr) {
+ delete static_cast<ELFNixPlatformRuntimeTLVManager *>(ELFNixTLVMgr);
+}
+
+} // end anonymous namespace
+
+//------------------------------------------------------------------------------
+// JIT entry points
+//------------------------------------------------------------------------------
+
+ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
+__orc_rt_elfnix_platform_bootstrap(char *ArgData, size_t ArgSize) {
+ return WrapperFunction<void(uint64_t)>::handle(
+ ArgData, ArgSize,
+ [](uint64_t &DSOHandle) {
+ ELFNixPlatformRuntimeState::initialize(
+ reinterpret_cast<void *>(DSOHandle));
+ })
+ .release();
+}
+
+ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
+__orc_rt_elfnix_platform_shutdown(char *ArgData, size_t ArgSize) {
+ ELFNixPlatformRuntimeState::destroy();
+ return WrapperFunctionResult().release();
+}
+
+/// Wrapper function for registering metadata on a per-object basis.
+ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
+__orc_rt_elfnix_register_object_sections(char *ArgData, size_t ArgSize) {
+ return WrapperFunction<SPSError(SPSELFNixPerObjectSectionsToRegister)>::
+ handle(ArgData, ArgSize,
+ [](ELFNixPerObjectSectionsToRegister &POSR) {
+ return ELFNixPlatformRuntimeState::get().registerObjectSections(
+ std::move(POSR));
+ })
+ .release();
+}
+
+/// Wrapper for releasing per-object metadat.
+ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
+__orc_rt_elfnix_deregister_object_sections(char *ArgData, size_t ArgSize) {
+ return WrapperFunction<SPSError(SPSELFNixPerObjectSectionsToRegister)>::
+ handle(ArgData, ArgSize,
+ [](ELFNixPerObjectSectionsToRegister &POSR) {
+ return ELFNixPlatformRuntimeState::get()
+ .deregisterObjectSections(std::move(POSR));
+ })
+ .release();
+}
+
+//------------------------------------------------------------------------------
+// TLV support
+//------------------------------------------------------------------------------
+
+ORC_RT_INTERFACE void *__orc_rt_elfnix_tls_get_addr_impl(TLSInfoEntry *D) {
+ auto *TLVMgr = static_cast<ELFNixPlatformRuntimeTLVManager *>(
+ pthread_getspecific(D->Key));
+ if (!TLVMgr)
+ TLVMgr = new ELFNixPlatformRuntimeTLVManager();
+ if (pthread_setspecific(D->Key, TLVMgr)) {
+ __orc_rt_log_error("Call to pthread_setspecific failed");
+ return nullptr;
+ }
+
+ return TLVMgr->getInstance(
+ reinterpret_cast<char *>(static_cast<uintptr_t>(D->DataAddress)));
+}
+
+ORC_RT_INTERFACE ptrdiff_t ___orc_rt_elfnix_tlsdesc_resolver_impl(
+ TLSDescriptor *D, const char *ThreadPointer) {
+ const char *TLVPtr = reinterpret_cast<const char *>(
+ __orc_rt_elfnix_tls_get_addr_impl(D->InfoEntry));
+ return TLVPtr - ThreadPointer;
+}
+
+ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
+__orc_rt_elfnix_create_pthread_key(char *ArgData, size_t ArgSize) {
+ return WrapperFunction<SPSExpected<uint64_t>(void)>::handle(
+ ArgData, ArgSize,
+ []() -> Expected<uint64_t> {
+ pthread_key_t Key;
+ if (int Err = pthread_key_create(&Key, destroyELFNixTLVMgr)) {
+ __orc_rt_log_error("Call to pthread_key_create failed");
+ return make_error<StringError>(strerror(Err));
+ }
+ return static_cast<uint64_t>(Key);
+ })
+ .release();
+}
+
+//------------------------------------------------------------------------------
+// cxa_atexit support
+//------------------------------------------------------------------------------
+
+int __orc_rt_elfnix_cxa_atexit(void (*func)(void *), void *arg,
+ void *dso_handle) {
+ return ELFNixPlatformRuntimeState::get().registerAtExit(func, arg,
+ dso_handle);
+}
+
+int __orc_rt_elfnix_atexit(void (*func)(void *)) {
+ auto &PlatformRTState = ELFNixPlatformRuntimeState::get();
+ return ELFNixPlatformRuntimeState::get().registerAtExit(
+ func, NULL, PlatformRTState.getPlatformJDDSOHandle());
+}
+
+void __orc_rt_elfnix_cxa_finalize(void *dso_handle) {
+ ELFNixPlatformRuntimeState::get().runAtExits(dso_handle);
+}
+
+//------------------------------------------------------------------------------
+// JIT'd dlfcn alternatives.
+//------------------------------------------------------------------------------
+
+const char *__orc_rt_elfnix_jit_dlerror() {
+ return ELFNixPlatformRuntimeState::get().dlerror();
+}
+
+void *__orc_rt_elfnix_jit_dlopen(const char *path, int mode) {
+ return ELFNixPlatformRuntimeState::get().dlopen(path, mode);
+}
+
+int __orc_rt_elfnix_jit_dlclose(void *dso_handle) {
+ return ELFNixPlatformRuntimeState::get().dlclose(dso_handle);
+}
+
+void *__orc_rt_elfnix_jit_dlsym(void *dso_handle, const char *symbol) {
+ return ELFNixPlatformRuntimeState::get().dlsym(dso_handle, symbol);
+}
+
+//------------------------------------------------------------------------------
+// ELFNix Run Program
+//------------------------------------------------------------------------------
+
+ORC_RT_INTERFACE int64_t __orc_rt_elfnix_run_program(
+ const char *JITDylibName, const char *EntrySymbolName, int argc,
+ char *argv[]) {
+ using MainTy = int (*)(int, char *[]);
+
+ void *H = __orc_rt_elfnix_jit_dlopen(JITDylibName,
+ __orc_rt::elfnix::ORC_RT_RTLD_LAZY);
+ if (!H) {
+ __orc_rt_log_error(__orc_rt_elfnix_jit_dlerror());
+ return -1;
+ }
+
+ auto *Main =
+ reinterpret_cast<MainTy>(__orc_rt_elfnix_jit_dlsym(H, EntrySymbolName));
+
+ if (!Main) {
+ __orc_rt_log_error(__orc_rt_elfnix_jit_dlerror());
+ return -1;
+ }
+
+ int Result = Main(argc, argv);
+
+ if (__orc_rt_elfnix_jit_dlclose(H) == -1)
+ __orc_rt_log_error(__orc_rt_elfnix_jit_dlerror());
+
+ return Result;
+}
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/elfnix_platform.h b/contrib/llvm-project/compiler-rt/lib/orc/elfnix_platform.h
new file mode 100644
index 000000000000..e0ee9591dfc6
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/elfnix_platform.h
@@ -0,0 +1,131 @@
+//===- elfnix_platform.h ----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// ORC Runtime support for dynamic loading features on ELF-based platforms.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_ELFNIX_PLATFORM_H
+#define ORC_RT_ELFNIX_PLATFORM_H
+
+#include "common.h"
+#include "executor_address.h"
+
+// Atexit functions.
+ORC_RT_INTERFACE int __orc_rt_elfnix_cxa_atexit(void (*func)(void *), void *arg,
+ void *dso_handle);
+ORC_RT_INTERFACE int __orc_rt_elfnix_atexit(void (*func)(void *));
+ORC_RT_INTERFACE void __orc_rt_elfnix_cxa_finalize(void *dso_handle);
+
+// dlfcn functions.
+ORC_RT_INTERFACE const char *__orc_rt_elfnix_jit_dlerror();
+ORC_RT_INTERFACE void *__orc_rt_elfnix_jit_dlopen(const char *path, int mode);
+ORC_RT_INTERFACE int __orc_rt_elfnix_jit_dlclose(void *dso_handle);
+ORC_RT_INTERFACE void *__orc_rt_elfnix_jit_dlsym(void *dso_handle,
+ const char *symbol);
+
+namespace __orc_rt {
+namespace elfnix {
+
+struct ELFNixPerObjectSectionsToRegister {
+ ExecutorAddrRange EHFrameSection;
+ ExecutorAddrRange ThreadDataSection;
+};
+
+struct ELFNixJITDylibInitializers {
+ using SectionList = std::vector<ExecutorAddrRange>;
+
+ ELFNixJITDylibInitializers() = default;
+ ELFNixJITDylibInitializers(std::string Name, ExecutorAddr DSOHandleAddress)
+ : Name(std::move(Name)), DSOHandleAddress(std::move(DSOHandleAddress)) {}
+
+ std::string Name;
+ ExecutorAddr DSOHandleAddress;
+
+ std::vector<std::pair<std::string, SectionList>> InitSections;
+};
+
+class ELFNixJITDylibDeinitializers {};
+
+using ELFNixJITDylibInitializerSequence =
+ std::vector<ELFNixJITDylibInitializers>;
+
+using ELFNixJITDylibDeinitializerSequence =
+ std::vector<ELFNixJITDylibDeinitializers>;
+
+enum dlopen_mode : int {
+ ORC_RT_RTLD_LAZY = 0x1,
+ ORC_RT_RTLD_NOW = 0x2,
+ ORC_RT_RTLD_LOCAL = 0x4,
+ ORC_RT_RTLD_GLOBAL = 0x8
+};
+
+} // end namespace elfnix
+
+using SPSELFNixPerObjectSectionsToRegister =
+ SPSTuple<SPSExecutorAddrRange, SPSExecutorAddrRange>;
+
+template <>
+class SPSSerializationTraits<SPSELFNixPerObjectSectionsToRegister,
+ elfnix::ELFNixPerObjectSectionsToRegister> {
+
+public:
+ static size_t size(const elfnix::ELFNixPerObjectSectionsToRegister &MOPOSR) {
+ return SPSELFNixPerObjectSectionsToRegister::AsArgList::size(
+ MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
+ }
+
+ static bool
+ serialize(SPSOutputBuffer &OB,
+ const elfnix::ELFNixPerObjectSectionsToRegister &MOPOSR) {
+ return SPSELFNixPerObjectSectionsToRegister::AsArgList::serialize(
+ OB, MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
+ }
+
+ static bool deserialize(SPSInputBuffer &IB,
+ elfnix::ELFNixPerObjectSectionsToRegister &MOPOSR) {
+ return SPSELFNixPerObjectSectionsToRegister::AsArgList::deserialize(
+ IB, MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
+ }
+};
+
+using SPSNamedExecutorAddrRangeSequenceMap =
+ SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRangeSequence>>;
+
+using SPSELFNixJITDylibInitializers =
+ SPSTuple<SPSString, SPSExecutorAddr, SPSNamedExecutorAddrRangeSequenceMap>;
+
+using SPSELFNixJITDylibInitializerSequence =
+ SPSSequence<SPSELFNixJITDylibInitializers>;
+
+/// Serialization traits for ELFNixJITDylibInitializers.
+template <>
+class SPSSerializationTraits<SPSELFNixJITDylibInitializers,
+ elfnix::ELFNixJITDylibInitializers> {
+public:
+ static size_t size(const elfnix::ELFNixJITDylibInitializers &MOJDIs) {
+ return SPSELFNixJITDylibInitializers::AsArgList::size(
+ MOJDIs.Name, MOJDIs.DSOHandleAddress, MOJDIs.InitSections);
+ }
+
+ static bool serialize(SPSOutputBuffer &OB,
+ const elfnix::ELFNixJITDylibInitializers &MOJDIs) {
+ return SPSELFNixJITDylibInitializers::AsArgList::serialize(
+ OB, MOJDIs.Name, MOJDIs.DSOHandleAddress, MOJDIs.InitSections);
+ }
+
+ static bool deserialize(SPSInputBuffer &IB,
+ elfnix::ELFNixJITDylibInitializers &MOJDIs) {
+ return SPSELFNixJITDylibInitializers::AsArgList::deserialize(
+ IB, MOJDIs.Name, MOJDIs.DSOHandleAddress, MOJDIs.InitSections);
+ }
+};
+
+} // end namespace __orc_rt
+
+#endif // ORC_RT_ELFNIX_PLATFORM_H
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/elfnix_tls.aarch64.S b/contrib/llvm-project/compiler-rt/lib/orc/elfnix_tls.aarch64.S
new file mode 100644
index 000000000000..8dcdd535be8a
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/elfnix_tls.aarch64.S
@@ -0,0 +1,94 @@
+//===-- elfnix_tlv.aarch64.s ---------------------------------------*- ASM -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime support library.
+//
+//===----------------------------------------------------------------------===//
+
+// The content of this file is aarch64-only
+#if defined(__arm64__) || defined(__aarch64__)
+
+#define REGISTER_SAVE_SPACE_SIZE 32 * 24
+
+ .text
+
+ // returns address of TLV in x0, all other registers preserved
+ // TODO: add fast-path for repeat access
+ .globl ___orc_rt_elfnix_tlsdesc_resolver
+___orc_rt_elfnix_tlsdesc_resolver:
+ sub sp, sp, #REGISTER_SAVE_SPACE_SIZE
+ stp x29, x30, [sp, #16 * 1]
+ stp x27, x28, [sp, #16 * 2]
+ stp x25, x26, [sp, #16 * 3]
+ stp x23, x24, [sp, #16 * 4]
+ stp x21, x22, [sp, #16 * 5]
+ stp x19, x20, [sp, #16 * 6]
+ stp x17, x18, [sp, #16 * 7]
+ stp x15, x16, [sp, #16 * 8]
+ stp x13, x14, [sp, #16 * 9]
+ stp x11, x12, [sp, #16 * 10]
+ stp x9, x10, [sp, #16 * 11]
+ stp x7, x8, [sp, #16 * 12]
+ stp x5, x6, [sp, #16 * 13]
+ stp x3, x4, [sp, #16 * 14]
+ stp x1, x2, [sp, #16 * 15]
+ stp q30, q31, [sp, #32 * 8]
+ stp q28, q29, [sp, #32 * 9]
+ stp q26, q27, [sp, #32 * 10]
+ stp q24, q25, [sp, #32 * 11]
+ stp q22, q23, [sp, #32 * 12]
+ stp q20, q21, [sp, #32 * 13]
+ stp q18, q19, [sp, #32 * 14]
+ stp q16, q17, [sp, #32 * 15]
+ stp q14, q15, [sp, #32 * 16]
+ stp q12, q13, [sp, #32 * 17]
+ stp q10, q11, [sp, #32 * 18]
+ stp q8, q9, [sp, #32 * 19]
+ stp q6, q7, [sp, #32 * 20]
+ stp q4, q5, [sp, #32 * 21]
+ stp q2, q3, [sp, #32 * 22]
+ stp q0, q1, [sp, #32 * 23]
+
+ mrs x1, TPIDR_EL0 // get thread pointer
+ bl ___orc_rt_elfnix_tlsdesc_resolver_impl
+
+ ldp q0, q1, [sp, #32 * 23]
+ ldp q2, q3, [sp, #32 * 22]
+ ldp q4, q5, [sp, #32 * 21]
+ ldp q6, q7, [sp, #32 * 20]
+ ldp q8, q9, [sp, #32 * 19]
+ ldp q10, q11, [sp, #32 * 18]
+ ldp q12, q13, [sp, #32 * 17]
+ ldp q14, q15, [sp, #32 * 16]
+ ldp q16, q17, [sp, #32 * 15]
+ ldp q18, q19, [sp, #32 * 14]
+ ldp q20, q21, [sp, #32 * 13]
+ ldp q22, q23, [sp, #32 * 12]
+ ldp q24, q25, [sp, #32 * 11]
+ ldp q26, q27, [sp, #32 * 10]
+ ldp q28, q29, [sp, #32 * 9]
+ ldp q30, q31, [sp, #32 * 8]
+ ldp x1, x2, [sp, #16 * 15]
+ ldp x3, x4, [sp, #16 * 14]
+ ldp x5, x6, [sp, #16 * 13]
+ ldp x7, x8, [sp, #16 * 12]
+ ldp x9, x10, [sp, #16 * 11]
+ ldp x11, x12, [sp, #16 * 10]
+ ldp x13, x14, [sp, #16 * 9]
+ ldp x15, x16, [sp, #16 * 8]
+ ldp x17, x18, [sp, #16 * 7]
+ ldp x19, x20, [sp, #16 * 6]
+ ldp x21, x22, [sp, #16 * 5]
+ ldp x23, x24, [sp, #16 * 4]
+ ldp x25, x26, [sp, #16 * 3]
+ ldp x27, x28, [sp, #16 * 2]
+ ldp x29, x30, [sp, #16 * 1]
+ add sp, sp, #REGISTER_SAVE_SPACE_SIZE
+ ret
+
+#endif // defined(__arm64__) || defined(__aarch64__)
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/elfnix_tls.ppc64.S b/contrib/llvm-project/compiler-rt/lib/orc/elfnix_tls.ppc64.S
new file mode 100644
index 000000000000..84854795dba1
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/elfnix_tls.ppc64.S
@@ -0,0 +1,33 @@
+//===-- orc_rt_elfnix_tls.ppc64.s -------------------------------*- ASM -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime support library.
+//
+//===----------------------------------------------------------------------===//
+
+// The content of this file is PowerPC64 only.
+#if defined(__powerpc64__)
+
+ .text
+ // TODO: add fast-path for repeat access.
+ // See https://github.com/llvm/llvm-project/issues/51162.
+ .global ___orc_rt_elfnix_tls_get_addr
+___orc_rt_elfnix_tls_get_addr:
+ addis 2, 12, .TOC.-___orc_rt_elfnix_tls_get_addr@ha
+ addi 2, 2, .TOC.-___orc_rt_elfnix_tls_get_addr@l
+ mflr 0
+ std 0, 16(1)
+ stdu 1, -32(1)
+ bl __orc_rt_elfnix_tls_get_addr_impl
+ nop
+ addi 1, 1, 32
+ ld 0, 16(1)
+ mtlr 0
+ blr
+
+#endif
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/elfnix_tls.x86-64.S b/contrib/llvm-project/compiler-rt/lib/orc/elfnix_tls.x86-64.S
new file mode 100644
index 000000000000..b3e0bef00867
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/elfnix_tls.x86-64.S
@@ -0,0 +1,64 @@
+
+//===-- orc_rt_elfnix_tls_x86-64.s -------------------------------*- ASM -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime support library.
+//
+//===----------------------------------------------------------------------===//
+
+// The content of this file is x86_64-only
+#if defined(__x86_64__)
+
+#define REGISTER_SAVE_SPACE_SIZE 512
+
+ .text
+
+ // returns address of TLV in %rax, all other registers preserved
+ .globl ___orc_rt_elfnix_tls_get_addr
+___orc_rt_elfnix_tls_get_addr:
+ pushq %rbp
+ movq %rsp, %rbp
+ subq $REGISTER_SAVE_SPACE_SIZE, %rsp
+ movq %rcx, -16(%rbp)
+ movq %rdx, -24(%rbp)
+ movq %rsi, -32(%rbp)
+ movq %rdi, -40(%rbp)
+ movq %r8, -48(%rbp)
+ movq %r9, -56(%rbp)
+ movq %r10, -64(%rbp)
+ movq %r11, -72(%rbp)
+ movdqa %xmm0, -128(%rbp)
+ movdqa %xmm1, -144(%rbp)
+ movdqa %xmm2, -160(%rbp)
+ movdqa %xmm3, -176(%rbp)
+ movdqa %xmm4, -192(%rbp)
+ movdqa %xmm5, -208(%rbp)
+ movdqa %xmm6, -224(%rbp)
+ movdqa %xmm7, -240(%rbp)
+ call __orc_rt_elfnix_tls_get_addr_impl
+ movq -16(%rbp), %rcx
+ movq -24(%rbp), %rdx
+ movq -32(%rbp), %rsi
+ movq -40(%rbp), %rdi
+ movq -48(%rbp), %r8
+ movq -56(%rbp), %r9
+ movq -64(%rbp), %r10
+ movq -72(%rbp), %r11
+ movdqa -128(%rbp), %xmm0
+ movdqa -144(%rbp), %xmm1
+ movdqa -160(%rbp), %xmm2
+ movdqa -176(%rbp), %xmm3
+ movdqa -192(%rbp), %xmm4
+ movdqa -208(%rbp), %xmm5
+ movdqa -224(%rbp), %xmm6
+ movdqa -240(%rbp), %xmm7
+ addq $REGISTER_SAVE_SPACE_SIZE, %rsp
+ popq %rbp
+ ret
+
+#endif // defined(__x86_64__)
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/endianness.h b/contrib/llvm-project/compiler-rt/lib/orc/endianness.h
new file mode 100644
index 000000000000..4ee5505ce6dd
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/endianness.h
@@ -0,0 +1,143 @@
+//===- endian.h - Endianness support ----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares generic and optimized functions to swap the byte order of
+// an integral type.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_ENDIAN_H
+#define ORC_RT_ENDIAN_H
+
+#include <cstddef>
+#include <cstdint>
+#include <type_traits>
+#if defined(_MSC_VER) && !defined(_DEBUG)
+#include <stdlib.h>
+#endif
+
+#if defined(__linux__) || defined(__GNU__) || defined(__HAIKU__) || \
+ defined(__Fuchsia__) || defined(__EMSCRIPTEN__)
+#include <endian.h>
+#elif defined(_AIX)
+#include <sys/machine.h>
+#elif defined(__sun)
+/* Solaris provides _BIG_ENDIAN/_LITTLE_ENDIAN selector in sys/types.h */
+#include <sys/types.h>
+#define BIG_ENDIAN 4321
+#define LITTLE_ENDIAN 1234
+#if defined(_BIG_ENDIAN)
+#define BYTE_ORDER BIG_ENDIAN
+#else
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif
+#elif defined(__MVS__)
+#define BIG_ENDIAN 4321
+#define LITTLE_ENDIAN 1234
+#define BYTE_ORDER BIG_ENDIAN
+#else
+#if !defined(BYTE_ORDER) && !defined(_WIN32)
+#include <machine/endian.h>
+#endif
+#endif
+
+namespace __orc_rt {
+
+/// ByteSwap_16 - This function returns a byte-swapped representation of
+/// the 16-bit argument.
+inline uint16_t ByteSwap_16(uint16_t value) {
+#if defined(_MSC_VER) && !defined(_DEBUG)
+ // The DLL version of the runtime lacks these functions (bug!?), but in a
+ // release build they're replaced with BSWAP instructions anyway.
+ return _byteswap_ushort(value);
+#else
+ uint16_t Hi = value << 8;
+ uint16_t Lo = value >> 8;
+ return Hi | Lo;
+#endif
+}
+
+/// This function returns a byte-swapped representation of the 32-bit argument.
+inline uint32_t ByteSwap_32(uint32_t value) {
+#if defined(__llvm__) || (defined(__GNUC__) && !defined(__ICC))
+ return __builtin_bswap32(value);
+#elif defined(_MSC_VER) && !defined(_DEBUG)
+ return _byteswap_ulong(value);
+#else
+ uint32_t Byte0 = value & 0x000000FF;
+ uint32_t Byte1 = value & 0x0000FF00;
+ uint32_t Byte2 = value & 0x00FF0000;
+ uint32_t Byte3 = value & 0xFF000000;
+ return (Byte0 << 24) | (Byte1 << 8) | (Byte2 >> 8) | (Byte3 >> 24);
+#endif
+}
+
+/// This function returns a byte-swapped representation of the 64-bit argument.
+inline uint64_t ByteSwap_64(uint64_t value) {
+#if defined(__llvm__) || (defined(__GNUC__) && !defined(__ICC))
+ return __builtin_bswap64(value);
+#elif defined(_MSC_VER) && !defined(_DEBUG)
+ return _byteswap_uint64(value);
+#else
+ uint64_t Hi = ByteSwap_32(uint32_t(value));
+ uint32_t Lo = ByteSwap_32(uint32_t(value >> 32));
+ return (Hi << 32) | Lo;
+#endif
+}
+
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN
+constexpr bool IsBigEndianHost = true;
+#else
+constexpr bool IsBigEndianHost = false;
+#endif
+
+static const bool IsLittleEndianHost = !IsBigEndianHost;
+
+inline unsigned char getSwappedBytes(unsigned char C) { return C; }
+inline signed char getSwappedBytes(signed char C) { return C; }
+inline char getSwappedBytes(char C) { return C; }
+
+inline unsigned short getSwappedBytes(unsigned short C) {
+ return ByteSwap_16(C);
+}
+inline signed short getSwappedBytes(signed short C) { return ByteSwap_16(C); }
+
+inline unsigned int getSwappedBytes(unsigned int C) { return ByteSwap_32(C); }
+inline signed int getSwappedBytes(signed int C) { return ByteSwap_32(C); }
+
+inline unsigned long getSwappedBytes(unsigned long C) {
+ // Handle LLP64 and LP64 platforms.
+ return sizeof(long) == sizeof(int) ? ByteSwap_32((uint32_t)C)
+ : ByteSwap_64((uint64_t)C);
+}
+inline signed long getSwappedBytes(signed long C) {
+ // Handle LLP64 and LP64 platforms.
+ return sizeof(long) == sizeof(int) ? ByteSwap_32((uint32_t)C)
+ : ByteSwap_64((uint64_t)C);
+}
+
+inline unsigned long long getSwappedBytes(unsigned long long C) {
+ return ByteSwap_64(C);
+}
+inline signed long long getSwappedBytes(signed long long C) {
+ return ByteSwap_64(C);
+}
+
+template <typename T>
+inline std::enable_if_t<std::is_enum<T>::value, T> getSwappedBytes(T C) {
+ return static_cast<T>(
+ getSwappedBytes(static_cast<std::underlying_type_t<T>>(C)));
+}
+
+template <typename T> inline void swapByteOrder(T &Value) {
+ Value = getSwappedBytes(Value);
+}
+
+} // end namespace __orc_rt
+
+#endif // ORC_RT_ENDIAN_H
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/error.h b/contrib/llvm-project/compiler-rt/lib/orc/error.h
new file mode 100644
index 000000000000..b5da0769c637
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/error.h
@@ -0,0 +1,426 @@
+//===-------- error.h - Enforced error checking for ORC RT ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_ERROR_H
+#define ORC_RT_ERROR_H
+
+#include "compiler.h"
+#include "extensible_rtti.h"
+#include "stl_extras.h"
+
+#include <cassert>
+#include <memory>
+#include <string>
+#include <type_traits>
+
+namespace __orc_rt {
+
+/// Base class for all errors.
+class ErrorInfoBase : public RTTIExtends<ErrorInfoBase, RTTIRoot> {
+public:
+ virtual std::string toString() const = 0;
+};
+
+/// Represents an environmental error.
+class ORC_RT_NODISCARD Error {
+
+ template <typename ErrT, typename... ArgTs>
+ friend Error make_error(ArgTs &&...Args);
+
+ friend Error repackage_error(std::unique_ptr<ErrorInfoBase>);
+
+ template <typename ErrT> friend std::unique_ptr<ErrT> error_cast(Error &);
+
+ template <typename T> friend class Expected;
+
+public:
+ /// Destroy this error. Aborts if error was not checked, or was checked but
+ /// not handled.
+ ~Error() { assertIsChecked(); }
+
+ Error(const Error &) = delete;
+ Error &operator=(const Error &) = delete;
+
+ /// Move-construct an error. The newly constructed error is considered
+ /// unchecked, even if the source error had been checked. The original error
+ /// becomes a checked success value.
+ Error(Error &&Other) {
+ setChecked(true);
+ *this = std::move(Other);
+ }
+
+ /// Move-assign an error value. The current error must represent success, you
+ /// you cannot overwrite an unhandled error. The current error is then
+ /// considered unchecked. The source error becomes a checked success value,
+ /// regardless of its original state.
+ Error &operator=(Error &&Other) {
+ // Don't allow overwriting of unchecked values.
+ assertIsChecked();
+ setPtr(Other.getPtr());
+
+ // This Error is unchecked, even if the source error was checked.
+ setChecked(false);
+
+ // Null out Other's payload and set its checked bit.
+ Other.setPtr(nullptr);
+ Other.setChecked(true);
+
+ return *this;
+ }
+
+ /// Create a success value.
+ static Error success() { return Error(); }
+
+ /// Error values convert to true for failure values, false otherwise.
+ explicit operator bool() {
+ setChecked(getPtr() == nullptr);
+ return getPtr() != nullptr;
+ }
+
+ /// Return true if this Error contains a failure value of the given type.
+ template <typename ErrT> bool isA() const {
+ return getPtr() && getPtr()->isA<ErrT>();
+ }
+
+private:
+ Error() = default;
+
+ Error(std::unique_ptr<ErrorInfoBase> ErrInfo) {
+ auto RawErrPtr = reinterpret_cast<uintptr_t>(ErrInfo.release());
+ assert((RawErrPtr & 0x1) == 0 && "ErrorInfo is insufficiently aligned");
+ ErrPtr = RawErrPtr | 0x1;
+ }
+
+ void assertIsChecked() {
+ if (ORC_RT_UNLIKELY(!isChecked() || getPtr())) {
+ fprintf(stderr, "Error must be checked prior to destruction.\n");
+ abort(); // Some sort of JIT program abort?
+ }
+ }
+
+ template <typename ErrT = ErrorInfoBase> ErrT *getPtr() const {
+ return reinterpret_cast<ErrT *>(ErrPtr & ~uintptr_t(1));
+ }
+
+ void setPtr(ErrorInfoBase *Ptr) {
+ ErrPtr = (reinterpret_cast<uintptr_t>(Ptr) & ~uintptr_t(1)) | (ErrPtr & 1);
+ }
+
+ bool isChecked() const { return ErrPtr & 0x1; }
+
+ void setChecked(bool Checked) { ErrPtr = (ErrPtr & ~uintptr_t(1)) | Checked; }
+
+ template <typename ErrT = ErrorInfoBase> std::unique_ptr<ErrT> takePayload() {
+ static_assert(std::is_base_of<ErrorInfoBase, ErrT>::value,
+ "ErrT is not an ErrorInfoBase subclass");
+ std::unique_ptr<ErrT> Tmp(getPtr<ErrT>());
+ setPtr(nullptr);
+ setChecked(true);
+ return Tmp;
+ }
+
+ uintptr_t ErrPtr = 0;
+};
+
+/// Construct an error of ErrT with the given arguments.
+template <typename ErrT, typename... ArgTs> Error make_error(ArgTs &&...Args) {
+ static_assert(std::is_base_of<ErrorInfoBase, ErrT>::value,
+ "ErrT is not an ErrorInfoBase subclass");
+ return Error(std::make_unique<ErrT>(std::forward<ArgTs>(Args)...));
+}
+
+/// Construct an error of ErrT using a std::unique_ptr<ErrorInfoBase>. The
+/// primary use-case for this is 're-packaging' errors after inspecting them
+/// using error_cast, hence the name.
+inline Error repackage_error(std::unique_ptr<ErrorInfoBase> EIB) {
+ return Error(std::move(EIB));
+}
+
+/// If the argument is an error of type ErrT then this function unpacks it
+/// and returns a std::unique_ptr<ErrT>. Otherwise returns a nullptr and
+/// leaves the error untouched. Common usage looks like:
+///
+/// \code{.cpp}
+/// if (Error E = foo()) {
+/// if (auto EV1 = error_cast<ErrorType1>(E)) {
+/// // use unwrapped EV1 value.
+/// } else if (EV2 = error_cast<ErrorType2>(E)) {
+/// // use unwrapped EV2 value.
+/// } ...
+/// }
+/// \endcode
+template <typename ErrT> std::unique_ptr<ErrT> error_cast(Error &Err) {
+ static_assert(std::is_base_of<ErrorInfoBase, ErrT>::value,
+ "ErrT is not an ErrorInfoBase subclass");
+ if (Err.isA<ErrT>())
+ return Err.takePayload<ErrT>();
+ return nullptr;
+}
+
+/// Helper for Errors used as out-parameters.
+/// Sets the 'checked' flag on construction, resets it on destruction.
+class ErrorAsOutParameter {
+public:
+ ErrorAsOutParameter(Error *Err) : Err(Err) {
+ // Raise the checked bit if Err is success.
+ if (Err)
+ (void)!!*Err;
+ }
+
+ ~ErrorAsOutParameter() {
+ // Clear the checked bit.
+ if (Err && !*Err)
+ *Err = Error::success();
+ }
+
+private:
+ Error *Err;
+};
+
+template <typename T> class ORC_RT_NODISCARD Expected {
+
+ template <class OtherT> friend class Expected;
+
+ static constexpr bool IsRef = std::is_reference<T>::value;
+ using wrap = std::reference_wrapper<std::remove_reference_t<T>>;
+ using error_type = std::unique_ptr<ErrorInfoBase>;
+ using storage_type = std::conditional_t<IsRef, wrap, T>;
+ using value_type = T;
+
+ using reference = std::remove_reference_t<T> &;
+ using const_reference = const std::remove_reference_t<T> &;
+ using pointer = std::remove_reference_t<T> *;
+ using const_pointer = const std::remove_reference_t<T> *;
+
+public:
+ /// Create an Expected from a failure value.
+ Expected(Error Err) : HasError(true), Unchecked(true) {
+ assert(Err && "Cannot create Expected<T> from Error success value");
+ new (getErrorStorage()) error_type(Err.takePayload());
+ }
+
+ /// Create an Expected from a T value.
+ template <typename OtherT>
+ Expected(OtherT &&Val,
+ std::enable_if_t<std::is_convertible<OtherT, T>::value> * = nullptr)
+ : HasError(false), Unchecked(true) {
+ new (getStorage()) storage_type(std::forward<OtherT>(Val));
+ }
+
+ /// Move-construct an Expected<T> from an Expected<OtherT>.
+ Expected(Expected &&Other) { moveConstruct(std::move(Other)); }
+
+ /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT
+ /// must be convertible to T.
+ template <class OtherT>
+ Expected(
+ Expected<OtherT> &&Other,
+ std::enable_if_t<std::is_convertible<OtherT, T>::value> * = nullptr) {
+ moveConstruct(std::move(Other));
+ }
+
+ /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT
+ /// isn't convertible to T.
+ template <class OtherT>
+ explicit Expected(
+ Expected<OtherT> &&Other,
+ std::enable_if_t<!std::is_convertible<OtherT, T>::value> * = nullptr) {
+ moveConstruct(std::move(Other));
+ }
+
+ /// Move-assign from another Expected<T>.
+ Expected &operator=(Expected &&Other) {
+ moveAssign(std::move(Other));
+ return *this;
+ }
+
+ /// Destroy an Expected<T>.
+ ~Expected() {
+ assertIsChecked();
+ if (!HasError)
+ getStorage()->~storage_type();
+ else
+ getErrorStorage()->~error_type();
+ }
+
+ /// Returns true if this Expected value is in a success state (holding a T),
+ /// and false if this Expected value is in a failure state.
+ explicit operator bool() {
+ Unchecked = HasError;
+ return !HasError;
+ }
+
+ /// Returns true if this Expected value holds an Error of type error_type.
+ template <typename ErrT> bool isFailureOfType() const {
+ return HasError && (*getErrorStorage())->template isFailureOfType<ErrT>();
+ }
+
+ /// Take ownership of the stored error.
+ ///
+ /// If this Expected value is in a success state (holding a T) then this
+ /// method is a no-op and returns Error::success.
+ ///
+ /// If thsi Expected value is in a failure state (holding an Error) then this
+ /// method returns the contained error and leaves this Expected in an
+ /// 'empty' state from which it may be safely destructed but not otherwise
+ /// accessed.
+ Error takeError() {
+ Unchecked = false;
+ return HasError ? Error(std::move(*getErrorStorage())) : Error::success();
+ }
+
+ /// Returns a pointer to the stored T value.
+ pointer operator->() {
+ assertIsChecked();
+ return toPointer(getStorage());
+ }
+
+ /// Returns a pointer to the stored T value.
+ const_pointer operator->() const {
+ assertIsChecked();
+ return toPointer(getStorage());
+ }
+
+ /// Returns a reference to the stored T value.
+ reference operator*() {
+ assertIsChecked();
+ return *getStorage();
+ }
+
+ /// Returns a reference to the stored T value.
+ const_reference operator*() const {
+ assertIsChecked();
+ return *getStorage();
+ }
+
+private:
+ template <class T1>
+ static bool compareThisIfSameType(const T1 &a, const T1 &b) {
+ return &a == &b;
+ }
+
+ template <class T1, class T2>
+ static bool compareThisIfSameType(const T1 &a, const T2 &b) {
+ return false;
+ }
+
+ template <class OtherT> void moveConstruct(Expected<OtherT> &&Other) {
+ HasError = Other.HasError;
+ Unchecked = true;
+ Other.Unchecked = false;
+
+ if (!HasError)
+ new (getStorage()) storage_type(std::move(*Other.getStorage()));
+ else
+ new (getErrorStorage()) error_type(std::move(*Other.getErrorStorage()));
+ }
+
+ template <class OtherT> void moveAssign(Expected<OtherT> &&Other) {
+ assertIsChecked();
+
+ if (compareThisIfSameType(*this, Other))
+ return;
+
+ this->~Expected();
+ new (this) Expected(std::move(Other));
+ }
+
+ pointer toPointer(pointer Val) { return Val; }
+
+ const_pointer toPointer(const_pointer Val) const { return Val; }
+
+ pointer toPointer(wrap *Val) { return &Val->get(); }
+
+ const_pointer toPointer(const wrap *Val) const { return &Val->get(); }
+
+ storage_type *getStorage() {
+ assert(!HasError && "Cannot get value when an error exists!");
+ return reinterpret_cast<storage_type *>(&TStorage);
+ }
+
+ const storage_type *getStorage() const {
+ assert(!HasError && "Cannot get value when an error exists!");
+ return reinterpret_cast<const storage_type *>(&TStorage);
+ }
+
+ error_type *getErrorStorage() {
+ assert(HasError && "Cannot get error when a value exists!");
+ return reinterpret_cast<error_type *>(&ErrorStorage);
+ }
+
+ const error_type *getErrorStorage() const {
+ assert(HasError && "Cannot get error when a value exists!");
+ return reinterpret_cast<const error_type *>(&ErrorStorage);
+ }
+
+ void assertIsChecked() {
+ if (ORC_RT_UNLIKELY(Unchecked)) {
+ fprintf(stderr,
+ "Expected<T> must be checked before access or destruction.\n");
+ abort();
+ }
+ }
+
+ union {
+ std::aligned_union_t<1, storage_type> TStorage;
+ std::aligned_union_t<1, error_type> ErrorStorage;
+ };
+
+ bool HasError : 1;
+ bool Unchecked : 1;
+};
+
+/// Consume an error without doing anything.
+inline void consumeError(Error Err) {
+ if (Err)
+ (void)error_cast<ErrorInfoBase>(Err);
+}
+
+/// Consumes success values. It is a programmatic error to call this function
+/// on a failure value.
+inline void cantFail(Error Err) {
+ assert(!Err && "cantFail called on failure value");
+ consumeError(std::move(Err));
+}
+
+/// Auto-unwrap an Expected<T> value in the success state. It is a programmatic
+/// error to call this function on a failure value.
+template <typename T> T cantFail(Expected<T> E) {
+ assert(E && "cantFail called on failure value");
+ consumeError(E.takeError());
+ return std::move(*E);
+}
+
+/// Auto-unwrap an Expected<T> value in the success state. It is a programmatic
+/// error to call this function on a failure value.
+template <typename T> T &cantFail(Expected<T &> E) {
+ assert(E && "cantFail called on failure value");
+ consumeError(E.takeError());
+ return *E;
+}
+
+/// Convert the given error to a string. The error value is consumed in the
+/// process.
+inline std::string toString(Error Err) {
+ if (auto EIB = error_cast<ErrorInfoBase>(Err))
+ return EIB->toString();
+ return {};
+}
+
+class StringError : public RTTIExtends<StringError, ErrorInfoBase> {
+public:
+ StringError(std::string ErrMsg) : ErrMsg(std::move(ErrMsg)) {}
+ std::string toString() const override { return ErrMsg; }
+
+private:
+ std::string ErrMsg;
+};
+
+} // end namespace __orc_rt
+
+#endif // ORC_RT_ERROR_H
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/executor_address.h b/contrib/llvm-project/compiler-rt/lib/orc/executor_address.h
new file mode 100644
index 000000000000..1542ee96bd92
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/executor_address.h
@@ -0,0 +1,263 @@
+//===------ ExecutorAddress.h - Executing process address -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Represents an address in the executing program.
+//
+// This file was derived from
+// llvm/include/llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_EXECUTOR_ADDRESS_H
+#define ORC_RT_EXECUTOR_ADDRESS_H
+
+#include "adt.h"
+#include "simple_packed_serialization.h"
+
+#include <cassert>
+#include <type_traits>
+
+namespace __orc_rt {
+
+using ExecutorAddrDiff = uint64_t;
+
+/// Represents an address in the executor process.
+class ExecutorAddr {
+public:
+ /// A wrap/unwrap function that leaves pointers unmodified.
+ template <typename T> using rawPtr = __orc_rt::identity<T *>;
+
+ /// Default wrap function to use on this host.
+ template <typename T> using defaultWrap = rawPtr<T>;
+
+ /// Default unwrap function to use on this host.
+ template <typename T> using defaultUnwrap = rawPtr<T>;
+
+ /// Merges a tag into the raw address value:
+ /// P' = P | (TagValue << TagOffset).
+ class Tag {
+ public:
+ constexpr Tag(uintptr_t TagValue, uintptr_t TagOffset)
+ : TagMask(TagValue << TagOffset) {}
+
+ template <typename T> constexpr T *operator()(T *P) {
+ return reinterpret_cast<T *>(reinterpret_cast<uintptr_t>(P) | TagMask);
+ }
+
+ private:
+ uintptr_t TagMask;
+ };
+
+ /// Strips a tag of the given length from the given offset within the pointer:
+ /// P' = P & ~(((1 << TagLen) -1) << TagOffset)
+ class Untag {
+ public:
+ constexpr Untag(uintptr_t TagLen, uintptr_t TagOffset)
+ : UntagMask(~(((uintptr_t(1) << TagLen) - 1) << TagOffset)) {}
+
+ template <typename T> constexpr T *operator()(T *P) {
+ return reinterpret_cast<T *>(reinterpret_cast<uintptr_t>(P) & UntagMask);
+ }
+
+ private:
+ uintptr_t UntagMask;
+ };
+
+ ExecutorAddr() = default;
+ explicit ExecutorAddr(uint64_t Addr) : Addr(Addr) {}
+
+ /// Create an ExecutorAddr from the given pointer.
+ template <typename T, typename UnwrapFn = defaultUnwrap<T>>
+ static ExecutorAddr fromPtr(T *Ptr, UnwrapFn &&Unwrap = UnwrapFn()) {
+ return ExecutorAddr(
+ static_cast<uint64_t>(reinterpret_cast<uintptr_t>(Unwrap(Ptr))));
+ }
+
+ /// Cast this ExecutorAddr to a pointer of the given type.
+ template <typename T, typename WrapFn = defaultWrap<std::remove_pointer_t<T>>>
+ std::enable_if_t<std::is_pointer<T>::value, T>
+ toPtr(WrapFn &&Wrap = WrapFn()) const {
+ uintptr_t IntPtr = static_cast<uintptr_t>(Addr);
+ assert(IntPtr == Addr && "ExecutorAddr value out of range for uintptr_t");
+ return Wrap(reinterpret_cast<T>(IntPtr));
+ }
+
+ /// Cast this ExecutorAddr to a pointer of the given function type.
+ template <typename T, typename WrapFn = defaultWrap<T>>
+ std::enable_if_t<std::is_function<T>::value, T *>
+ toPtr(WrapFn &&Wrap = WrapFn()) const {
+ uintptr_t IntPtr = static_cast<uintptr_t>(Addr);
+ assert(IntPtr == Addr && "ExecutorAddr value out of range for uintptr_t");
+ return Wrap(reinterpret_cast<T *>(IntPtr));
+ }
+
+ uint64_t getValue() const { return Addr; }
+ void setValue(uint64_t Addr) { this->Addr = Addr; }
+ bool isNull() const { return Addr == 0; }
+
+ explicit operator bool() const { return Addr != 0; }
+
+ friend bool operator==(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
+ return LHS.Addr == RHS.Addr;
+ }
+
+ friend bool operator!=(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
+ return LHS.Addr != RHS.Addr;
+ }
+
+ friend bool operator<(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
+ return LHS.Addr < RHS.Addr;
+ }
+
+ friend bool operator<=(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
+ return LHS.Addr <= RHS.Addr;
+ }
+
+ friend bool operator>(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
+ return LHS.Addr > RHS.Addr;
+ }
+
+ friend bool operator>=(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
+ return LHS.Addr >= RHS.Addr;
+ }
+
+ ExecutorAddr &operator++() {
+ ++Addr;
+ return *this;
+ }
+ ExecutorAddr &operator--() {
+ --Addr;
+ return *this;
+ }
+ ExecutorAddr operator++(int) { return ExecutorAddr(Addr++); }
+ ExecutorAddr operator--(int) { return ExecutorAddr(Addr++); }
+
+ ExecutorAddr &operator+=(const ExecutorAddrDiff Delta) {
+ Addr += Delta;
+ return *this;
+ }
+
+ ExecutorAddr &operator-=(const ExecutorAddrDiff Delta) {
+ Addr -= Delta;
+ return *this;
+ }
+
+private:
+ uint64_t Addr = 0;
+};
+
+/// Subtracting two addresses yields an offset.
+inline ExecutorAddrDiff operator-(const ExecutorAddr &LHS,
+ const ExecutorAddr &RHS) {
+ return ExecutorAddrDiff(LHS.getValue() - RHS.getValue());
+}
+
+/// Adding an offset and an address yields an address.
+inline ExecutorAddr operator+(const ExecutorAddr &LHS,
+ const ExecutorAddrDiff &RHS) {
+ return ExecutorAddr(LHS.getValue() + RHS);
+}
+
+/// Adding an address and an offset yields an address.
+inline ExecutorAddr operator+(const ExecutorAddrDiff &LHS,
+ const ExecutorAddr &RHS) {
+ return ExecutorAddr(LHS + RHS.getValue());
+}
+
+/// Represents an address range in the exceutor process.
+struct ExecutorAddrRange {
+ ExecutorAddrRange() = default;
+ ExecutorAddrRange(ExecutorAddr Start, ExecutorAddr End)
+ : Start(Start), End(End) {}
+ ExecutorAddrRange(ExecutorAddr Start, ExecutorAddrDiff Size)
+ : Start(Start), End(Start + Size) {}
+
+ bool empty() const { return Start == End; }
+ ExecutorAddrDiff size() const { return End - Start; }
+
+ friend bool operator==(const ExecutorAddrRange &LHS,
+ const ExecutorAddrRange &RHS) {
+ return LHS.Start == RHS.Start && LHS.End == RHS.End;
+ }
+ friend bool operator!=(const ExecutorAddrRange &LHS,
+ const ExecutorAddrRange &RHS) {
+ return !(LHS == RHS);
+ }
+ bool contains(ExecutorAddr Addr) const { return Start <= Addr && Addr < End; }
+ bool overlaps(const ExecutorAddrRange &Other) {
+ return !(Other.End <= Start || End <= Other.Start);
+ }
+
+ template <typename T> span<T> toSpan() const {
+ assert(size() % sizeof(T) == 0 &&
+ "AddressRange is not a multiple of sizeof(T)");
+ return span<T>(Start.toPtr<T *>(), size() / sizeof(T));
+ }
+
+ ExecutorAddr Start;
+ ExecutorAddr End;
+};
+
+/// SPS serializatior for ExecutorAddr.
+template <> class SPSSerializationTraits<SPSExecutorAddr, ExecutorAddr> {
+public:
+ static size_t size(const ExecutorAddr &EA) {
+ return SPSArgList<uint64_t>::size(EA.getValue());
+ }
+
+ static bool serialize(SPSOutputBuffer &BOB, const ExecutorAddr &EA) {
+ return SPSArgList<uint64_t>::serialize(BOB, EA.getValue());
+ }
+
+ static bool deserialize(SPSInputBuffer &BIB, ExecutorAddr &EA) {
+ uint64_t Tmp;
+ if (!SPSArgList<uint64_t>::deserialize(BIB, Tmp))
+ return false;
+ EA = ExecutorAddr(Tmp);
+ return true;
+ }
+};
+
+using SPSExecutorAddrRange = SPSTuple<SPSExecutorAddr, SPSExecutorAddr>;
+
+/// Serialization traits for address ranges.
+template <>
+class SPSSerializationTraits<SPSExecutorAddrRange, ExecutorAddrRange> {
+public:
+ static size_t size(const ExecutorAddrRange &Value) {
+ return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::size(Value.Start,
+ Value.End);
+ }
+
+ static bool serialize(SPSOutputBuffer &BOB, const ExecutorAddrRange &Value) {
+ return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::serialize(
+ BOB, Value.Start, Value.End);
+ }
+
+ static bool deserialize(SPSInputBuffer &BIB, ExecutorAddrRange &Value) {
+ return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::deserialize(
+ BIB, Value.Start, Value.End);
+ }
+};
+
+using SPSExecutorAddrRangeSequence = SPSSequence<SPSExecutorAddrRange>;
+
+} // End namespace __orc_rt
+
+namespace std {
+
+// Make ExecutorAddr hashable.
+template <> struct hash<__orc_rt::ExecutorAddr> {
+ size_t operator()(const __orc_rt::ExecutorAddr &A) const {
+ return hash<uint64_t>()(A.getValue());
+ }
+};
+
+} // namespace std
+
+#endif // ORC_RT_EXECUTOR_ADDRESS_H
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/executor_symbol_def.h b/contrib/llvm-project/compiler-rt/lib/orc/executor_symbol_def.h
new file mode 100644
index 000000000000..454cefe525cf
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/executor_symbol_def.h
@@ -0,0 +1,151 @@
+//===--------- ExecutorSymbolDef.h - (Addr, Flags) pair ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Represents a defining location for a symbol in the executing program.
+//
+// This file was derived from
+// llvm/include/llvm/ExecutionEngine/Orc/Shared/ExecutorSymbolDef.h.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_EXECUTOR_SYMBOL_DEF_H
+#define ORC_RT_EXECUTOR_SYMBOL_DEF_H
+
+#include "bitmask_enum.h"
+#include "executor_address.h"
+#include "simple_packed_serialization.h"
+
+namespace __orc_rt {
+
+/// Flags for symbols in the JIT.
+class JITSymbolFlags {
+public:
+ using UnderlyingType = uint8_t;
+ using TargetFlagsType = uint8_t;
+
+ /// These values must be kept in sync with \c JITSymbolFlags in the JIT.
+ enum FlagNames : UnderlyingType {
+ None = 0,
+ HasError = 1U << 0,
+ Weak = 1U << 1,
+ Common = 1U << 2,
+ Absolute = 1U << 3,
+ Exported = 1U << 4,
+ Callable = 1U << 5,
+ MaterializationSideEffectsOnly = 1U << 6,
+ ORC_RT_MARK_AS_BITMASK_ENUM( // LargestValue =
+ MaterializationSideEffectsOnly)
+ };
+
+ /// Default-construct a JITSymbolFlags instance.
+ JITSymbolFlags() = default;
+
+ /// Construct a JITSymbolFlags instance from the given flags and target
+ /// flags.
+ JITSymbolFlags(FlagNames Flags, TargetFlagsType TargetFlags)
+ : TargetFlags(TargetFlags), Flags(Flags) {}
+
+ bool operator==(const JITSymbolFlags &RHS) const {
+ return Flags == RHS.Flags && TargetFlags == RHS.TargetFlags;
+ }
+
+ /// Get the underlying flags value as an integer.
+ UnderlyingType getRawFlagsValue() const {
+ return static_cast<UnderlyingType>(Flags);
+ }
+
+ /// Return a reference to the target-specific flags.
+ TargetFlagsType &getTargetFlags() { return TargetFlags; }
+
+ /// Return a reference to the target-specific flags.
+ const TargetFlagsType &getTargetFlags() const { return TargetFlags; }
+
+private:
+ TargetFlagsType TargetFlags = 0;
+ FlagNames Flags = None;
+};
+
+/// Represents a defining location for a JIT symbol.
+class ExecutorSymbolDef {
+public:
+ ExecutorSymbolDef() = default;
+ ExecutorSymbolDef(ExecutorAddr Addr, JITSymbolFlags Flags)
+ : Addr(Addr), Flags(Flags) {}
+
+ const ExecutorAddr &getAddress() const { return Addr; }
+
+ const JITSymbolFlags &getFlags() const { return Flags; }
+
+ friend bool operator==(const ExecutorSymbolDef &LHS,
+ const ExecutorSymbolDef &RHS) {
+ return LHS.getAddress() == RHS.getAddress() &&
+ LHS.getFlags() == RHS.getFlags();
+ }
+
+private:
+ ExecutorAddr Addr;
+ JITSymbolFlags Flags;
+};
+
+using SPSJITSymbolFlags =
+ SPSTuple<JITSymbolFlags::UnderlyingType, JITSymbolFlags::TargetFlagsType>;
+
+/// SPS serializatior for JITSymbolFlags.
+template <> class SPSSerializationTraits<SPSJITSymbolFlags, JITSymbolFlags> {
+ using FlagsArgList = SPSJITSymbolFlags::AsArgList;
+
+public:
+ static size_t size(const JITSymbolFlags &F) {
+ return FlagsArgList::size(F.getRawFlagsValue(), F.getTargetFlags());
+ }
+
+ static bool serialize(SPSOutputBuffer &BOB, const JITSymbolFlags &F) {
+ return FlagsArgList::serialize(BOB, F.getRawFlagsValue(),
+ F.getTargetFlags());
+ }
+
+ static bool deserialize(SPSInputBuffer &BIB, JITSymbolFlags &F) {
+ JITSymbolFlags::UnderlyingType RawFlags;
+ JITSymbolFlags::TargetFlagsType TargetFlags;
+ if (!FlagsArgList::deserialize(BIB, RawFlags, TargetFlags))
+ return false;
+ F = JITSymbolFlags{static_cast<JITSymbolFlags::FlagNames>(RawFlags),
+ TargetFlags};
+ return true;
+ }
+};
+
+using SPSExecutorSymbolDef = SPSTuple<SPSExecutorAddr, SPSJITSymbolFlags>;
+
+/// SPS serializatior for ExecutorSymbolDef.
+template <>
+class SPSSerializationTraits<SPSExecutorSymbolDef, ExecutorSymbolDef> {
+ using DefArgList = SPSExecutorSymbolDef::AsArgList;
+
+public:
+ static size_t size(const ExecutorSymbolDef &ESD) {
+ return DefArgList::size(ESD.getAddress(), ESD.getFlags());
+ }
+
+ static bool serialize(SPSOutputBuffer &BOB, const ExecutorSymbolDef &ESD) {
+ return DefArgList::serialize(BOB, ESD.getAddress(), ESD.getFlags());
+ }
+
+ static bool deserialize(SPSInputBuffer &BIB, ExecutorSymbolDef &ESD) {
+ ExecutorAddr Addr;
+ JITSymbolFlags Flags;
+ if (!DefArgList::deserialize(BIB, Addr, Flags))
+ return false;
+ ESD = ExecutorSymbolDef{Addr, Flags};
+ return true;
+ }
+};
+
+} // End namespace __orc_rt
+
+#endif // ORC_RT_EXECUTOR_SYMBOL_DEF_H
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/extensible_rtti.cpp b/contrib/llvm-project/compiler-rt/lib/orc/extensible_rtti.cpp
new file mode 100644
index 000000000000..c6951a449a3d
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/extensible_rtti.cpp
@@ -0,0 +1,24 @@
+//===- extensible_rtti.cpp ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime support library.
+//
+// Note:
+// This source file was adapted from lib/Support/ExtensibleRTTI.cpp, however
+// the data structures are not shared and the code need not be kept in sync.
+//
+//===----------------------------------------------------------------------===//
+
+#include "extensible_rtti.h"
+
+namespace __orc_rt {
+
+char RTTIRoot::ID = 0;
+void RTTIRoot::anchor() {}
+
+} // end namespace __orc_rt
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/extensible_rtti.h b/contrib/llvm-project/compiler-rt/lib/orc/extensible_rtti.h
new file mode 100644
index 000000000000..72f68242e7c4
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/extensible_rtti.h
@@ -0,0 +1,145 @@
+//===------ extensible_rtti.h - Extensible RTTI for ORC RT ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// \file
+//
+// Provides an extensible RTTI mechanism, that can be used regardless of whether
+// the runtime is built with -frtti or not. This is predominantly used to
+// support error handling.
+//
+// The RTTIRoot class defines methods for comparing type ids. Implementations
+// of these methods can be injected into new classes using the RTTIExtends
+// class template.
+//
+// E.g.
+//
+// @code{.cpp}
+// class MyBaseClass : public RTTIExtends<MyBaseClass, RTTIRoot> {
+// public:
+// static char ID;
+// virtual void foo() = 0;
+// };
+//
+// class MyDerivedClass1 : public RTTIExtends<MyDerivedClass1, MyBaseClass> {
+// public:
+// static char ID;
+// void foo() override {}
+// };
+//
+// class MyDerivedClass2 : public RTTIExtends<MyDerivedClass2, MyBaseClass> {
+// public:
+// static char ID;
+// void foo() override {}
+// };
+//
+// char MyBaseClass::ID = 0;
+// char MyDerivedClass1::ID = 0;
+// char MyDerivedClass2:: ID = 0;
+//
+// void fn() {
+// std::unique_ptr<MyBaseClass> B = std::make_unique<MyDerivedClass1>();
+// outs() << isa<MyBaseClass>(B) << "\n"; // Outputs "1".
+// outs() << isa<MyDerivedClass1>(B) << "\n"; // Outputs "1".
+// outs() << isa<MyDerivedClass2>(B) << "\n"; // Outputs "0'.
+// }
+//
+// @endcode
+//
+// Note:
+// This header was adapted from llvm/Support/ExtensibleRTTI.h, however the
+// data structures are not shared and the code need not be kept in sync.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_EXTENSIBLE_RTTI_H
+#define ORC_RT_EXTENSIBLE_RTTI_H
+
+namespace __orc_rt {
+
+template <typename ThisT, typename ParentT> class RTTIExtends;
+
+/// Base class for the extensible RTTI hierarchy.
+///
+/// This class defines virtual methods, dynamicClassID and isA, that enable
+/// type comparisons.
+class RTTIRoot {
+public:
+ virtual ~RTTIRoot() = default;
+
+ /// Returns the class ID for this type.
+ static const void *classID() { return &ID; }
+
+ /// Returns the class ID for the dynamic type of this RTTIRoot instance.
+ virtual const void *dynamicClassID() const = 0;
+
+ /// Returns true if this class's ID matches the given class ID.
+ virtual bool isA(const void *const ClassID) const {
+ return ClassID == classID();
+ }
+
+ /// Check whether this instance is a subclass of QueryT.
+ template <typename QueryT> bool isA() const { return isA(QueryT::classID()); }
+
+ static bool classof(const RTTIRoot *R) { return R->isA<RTTIRoot>(); }
+
+private:
+ virtual void anchor();
+
+ static char ID;
+};
+
+/// Inheritance utility for extensible RTTI.
+///
+/// Supports single inheritance only: A class can only have one
+/// ExtensibleRTTI-parent (i.e. a parent for which the isa<> test will work),
+/// though it can have many non-ExtensibleRTTI parents.
+///
+/// RTTIExtents uses CRTP so the first template argument to RTTIExtends is the
+/// newly introduced type, and the *second* argument is the parent class.
+///
+/// class MyType : public RTTIExtends<MyType, RTTIRoot> {
+/// public:
+/// static char ID;
+/// };
+///
+/// class MyDerivedType : public RTTIExtends<MyDerivedType, MyType> {
+/// public:
+/// static char ID;
+/// };
+///
+template <typename ThisT, typename ParentT> class RTTIExtends : public ParentT {
+public:
+ // Inherit constructors and isA methods from ParentT.
+ using ParentT::isA;
+ using ParentT::ParentT;
+
+ static char ID;
+
+ static const void *classID() { return &ThisT::ID; }
+
+ const void *dynamicClassID() const override { return &ThisT::ID; }
+
+ bool isA(const void *const ClassID) const override {
+ return ClassID == classID() || ParentT::isA(ClassID);
+ }
+
+ static bool classof(const RTTIRoot *R) { return R->isA<ThisT>(); }
+};
+
+template <typename ThisT, typename ParentT>
+char RTTIExtends<ThisT, ParentT>::ID = 0;
+
+/// Returns true if the given value is an instance of the template type
+/// parameter.
+template <typename To, typename From> bool isa(const From &Value) {
+ return To::classof(&Value);
+}
+
+} // end namespace __orc_rt
+
+#endif // ORC_RT_EXTENSIBLE_RTTI_H
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/interval_map.h b/contrib/llvm-project/compiler-rt/lib/orc/interval_map.h
new file mode 100644
index 000000000000..8c1609d72f57
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/interval_map.h
@@ -0,0 +1,168 @@
+//===--------- interval_map.h - A sorted interval map -----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements a coalescing interval map.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_INTERVAL_MAP_H
+#define ORC_RT_INTERVAL_MAP_H
+
+#include "adt.h"
+#include <cassert>
+#include <map>
+
+namespace __orc_rt {
+
+enum class IntervalCoalescing { Enabled, Disabled };
+
+/// Maps intervals to keys with optional coalescing.
+///
+/// NOTE: The interface is kept mostly compatible with LLVM's IntervalMap
+/// collection to make it easy to swap over in the future if we choose
+/// to.
+template <typename KeyT, typename ValT> class IntervalMapBase {
+private:
+ using KeyPairT = std::pair<KeyT, KeyT>;
+
+ struct Compare {
+ using is_transparent = std::true_type;
+ bool operator()(const KeyPairT &LHS, const KeyPairT &RHS) const {
+ return LHS < RHS;
+ }
+ bool operator()(const KeyPairT &LHS, const KeyT &RHS) const {
+ return LHS.first < RHS;
+ }
+ bool operator()(const KeyT &LHS, const KeyPairT &RHS) const {
+ return LHS < RHS.first;
+ }
+ };
+
+ using ImplMap = std::map<KeyPairT, ValT, Compare>;
+
+public:
+ using iterator = typename ImplMap::iterator;
+ using const_iterator = typename ImplMap::const_iterator;
+ using size_type = typename ImplMap::size_type;
+
+ bool empty() const { return Impl.empty(); }
+
+ void clear() { Impl.clear(); }
+
+ iterator begin() { return Impl.begin(); }
+ iterator end() { return Impl.end(); }
+
+ const_iterator begin() const { return Impl.begin(); }
+ const_iterator end() const { return Impl.end(); }
+
+ iterator find(KeyT K) {
+ // Early out if the key is clearly outside the range.
+ if (empty() || K < begin()->first.first ||
+ K >= std::prev(end())->first.second)
+ return end();
+
+ auto I = Impl.upper_bound(K);
+ assert(I != begin() && "Should have hit early out above");
+ I = std::prev(I);
+ if (K < I->first.second)
+ return I;
+ return end();
+ }
+
+ const_iterator find(KeyT K) const {
+ return const_cast<IntervalMapBase<KeyT, ValT> *>(this)->find(K);
+ }
+
+ ValT lookup(KeyT K, ValT NotFound = ValT()) const {
+ auto I = find(K);
+ if (I == end())
+ return NotFound;
+ return I->second;
+ }
+
+ // Erase [KS, KE), which must be entirely containing within one existing
+ // range in the map. Removal is allowed to split the range.
+ void erase(KeyT KS, KeyT KE) {
+ if (empty())
+ return;
+
+ auto J = Impl.upper_bound(KS);
+
+ // Check previous range. Bail out if range to remove is entirely after
+ // it.
+ auto I = std::prev(J);
+ if (KS >= I->first.second)
+ return;
+
+ // Assert that range is wholly contained.
+ assert(KE <= I->first.second);
+
+ auto Tmp = std::move(*I);
+ Impl.erase(I);
+
+ // Split-right -- introduce right-split range.
+ if (KE < Tmp.first.second) {
+ Impl.insert(
+ J, std::make_pair(std::make_pair(KE, Tmp.first.second), Tmp.second));
+ J = std::prev(J);
+ }
+
+ // Split-left -- introduce left-split range.
+ if (KS > Tmp.first.first)
+ Impl.insert(
+ J, std::make_pair(std::make_pair(Tmp.first.first, KS), Tmp.second));
+ }
+
+protected:
+ ImplMap Impl;
+};
+
+template <typename KeyT, typename ValT, IntervalCoalescing Coalescing>
+class IntervalMap;
+
+template <typename KeyT, typename ValT>
+class IntervalMap<KeyT, ValT, IntervalCoalescing::Enabled>
+ : public IntervalMapBase<KeyT, ValT> {
+public:
+ // Coalescing insert. Requires that ValTs be equality-comparable.
+ void insert(KeyT KS, KeyT KE, ValT V) {
+ auto J = this->Impl.upper_bound(KS);
+
+ // Coalesce-right if possible. Either way, J points at our insertion
+ // point.
+ if (J != this->end() && KE == J->first.first && J->second == V) {
+ KE = J->first.second;
+ auto Tmp = J++;
+ this->Impl.erase(Tmp);
+ }
+
+ // Coalesce-left if possible.
+ if (J != this->begin()) {
+ auto I = std::prev(J);
+ if (I->first.second == KS && I->second == V) {
+ KS = I->first.first;
+ this->Impl.erase(I);
+ }
+ }
+ this->Impl.insert(J, std::make_pair(std::make_pair(KS, KE), std::move(V)));
+ }
+};
+
+template <typename KeyT, typename ValT>
+class IntervalMap<KeyT, ValT, IntervalCoalescing::Disabled>
+ : public IntervalMapBase<KeyT, ValT> {
+public:
+ // Non-coalescing insert. Does not require ValT to be equality-comparable.
+ void insert(KeyT KS, KeyT KE, ValT V) {
+ this->Impl.insert(std::make_pair(std::make_pair(KS, KE), std::move(V)));
+ }
+};
+
+} // End namespace __orc_rt
+
+#endif // ORC_RT_INTERVAL_MAP_H
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/interval_set.h b/contrib/llvm-project/compiler-rt/lib/orc/interval_set.h
new file mode 100644
index 000000000000..20f40f9c7d37
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/interval_set.h
@@ -0,0 +1,87 @@
+//===--------- interval_set.h - A sorted interval set -----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements a coalescing interval set.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_INTERVAL_SET_H
+#define ORC_RT_INTERVAL_SET_H
+
+#include "interval_map.h"
+
+namespace __orc_rt {
+
+/// Implements a coalescing interval set.
+///
+/// Adjacent intervals are coalesced.
+///
+/// NOTE: The interface is kept mostly compatible with LLVM's IntervalMap
+/// collection to make it easy to swap over in the future if we choose
+/// to.
+template <typename KeyT, IntervalCoalescing Coalescing>
+class IntervalSet {
+private:
+ using ImplMap = IntervalMap<KeyT, std::monostate, Coalescing>;
+public:
+
+ using value_type = std::pair<KeyT, KeyT>;
+
+ class const_iterator {
+ friend class IntervalSet;
+ public:
+ using difference_type = typename ImplMap::iterator::difference_type;
+ using value_type = IntervalSet::value_type;
+ using pointer = const value_type *;
+ using reference = const value_type &;
+ using iterator_category = std::input_iterator_tag;
+
+ const_iterator() = default;
+ const value_type &operator*() const { return I->first; }
+ const value_type *operator->() const { return &I->first; }
+ const_iterator &operator++() { ++I; return *this; }
+ const_iterator operator++(int) { auto Tmp = I; ++I; return Tmp; }
+ friend bool operator==(const const_iterator &LHS,
+ const const_iterator &RHS) {
+ return LHS.I == RHS.I;
+ }
+ friend bool operator!=(const const_iterator &LHS,
+ const const_iterator &RHS) {
+ return LHS.I != RHS.I;
+ }
+ private:
+ const_iterator(typename ImplMap::const_iterator I) : I(std::move(I)) {}
+ typename ImplMap::const_iterator I;
+ };
+
+ bool empty() const { return Map.empty(); }
+
+ void clear() { Map.clear(); }
+
+ const_iterator begin() const { return const_iterator(Map.begin()); }
+ const_iterator end() const { return const_iterator(Map.end()); }
+
+ const_iterator find(KeyT K) const {
+ return const_iterator(Map.find(K));
+ }
+
+ void insert(KeyT KS, KeyT KE) {
+ Map.insert(std::move(KS), std::move(KE), std::monostate());
+ }
+
+ void erase(KeyT KS, KeyT KE) {
+ Map.erase(KS, KE);
+ }
+
+private:
+ ImplMap Map;
+};
+
+} // End namespace __orc_rt
+
+#endif // ORC_RT_INTERVAL_SET_H
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/log_error_to_stderr.cpp b/contrib/llvm-project/compiler-rt/lib/orc/log_error_to_stderr.cpp
new file mode 100644
index 000000000000..4fabbc0d212a
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/log_error_to_stderr.cpp
@@ -0,0 +1,19 @@
+//===-- log_error_to_stderr.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime support library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "compiler.h"
+
+#include <stdio.h>
+
+ORC_RT_INTERFACE void __orc_rt_log_error_to_stderr(const char *ErrMsg) {
+ fprintf(stderr, "orc runtime error: %s\n", ErrMsg);
+}
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/macho_platform.cpp b/contrib/llvm-project/compiler-rt/lib/orc/macho_platform.cpp
new file mode 100644
index 000000000000..340846f5f900
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/macho_platform.cpp
@@ -0,0 +1,1550 @@
+//===- macho_platform.cpp -------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains code required to load the rest of the MachO runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#include "macho_platform.h"
+#include "bitmask_enum.h"
+#include "common.h"
+#include "debug.h"
+#include "error.h"
+#include "interval_map.h"
+#include "wrapper_function_utils.h"
+
+#include <algorithm>
+#include <ios>
+#include <map>
+#include <mutex>
+#include <sstream>
+#include <string_view>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#define DEBUG_TYPE "macho_platform"
+
+using namespace __orc_rt;
+using namespace __orc_rt::macho;
+
+// Declare function tags for functions in the JIT process.
+ORC_RT_JIT_DISPATCH_TAG(__orc_rt_macho_push_initializers_tag)
+ORC_RT_JIT_DISPATCH_TAG(__orc_rt_macho_push_symbols_tag)
+
+struct objc_image_info;
+struct mach_header;
+
+// Objective-C registration functions.
+// These are weakly imported. If the Objective-C runtime has not been loaded
+// then code containing Objective-C sections will generate an error.
+extern "C" void
+_objc_map_images(unsigned count, const char *const paths[],
+ const mach_header *const mhdrs[]) ORC_RT_WEAK_IMPORT;
+
+extern "C" void _objc_load_image(const char *path,
+ const mach_header *mh) ORC_RT_WEAK_IMPORT;
+
+// Libunwind prototypes.
+struct unw_dynamic_unwind_sections {
+ uintptr_t dso_base;
+ uintptr_t dwarf_section;
+ size_t dwarf_section_length;
+ uintptr_t compact_unwind_section;
+ size_t compact_unwind_section_length;
+};
+
+typedef int (*unw_find_dynamic_unwind_sections)(
+ uintptr_t addr, struct unw_dynamic_unwind_sections *info);
+
+extern "C" int __unw_add_find_dynamic_unwind_sections(
+ unw_find_dynamic_unwind_sections find_dynamic_unwind_sections)
+ ORC_RT_WEAK_IMPORT;
+
+extern "C" int __unw_remove_find_dynamic_unwind_sections(
+ unw_find_dynamic_unwind_sections find_dynamic_unwind_sections)
+ ORC_RT_WEAK_IMPORT;
+
+namespace {
+
+struct MachOJITDylibDepInfo {
+ bool Sealed = false;
+ std::vector<ExecutorAddr> DepHeaders;
+};
+
+using MachOJITDylibDepInfoMap =
+ std::unordered_map<ExecutorAddr, MachOJITDylibDepInfo>;
+
+} // anonymous namespace
+
+namespace __orc_rt {
+
+using SPSMachOObjectPlatformSectionsMap =
+ SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRange>>;
+
+using SPSMachOJITDylibDepInfo = SPSTuple<bool, SPSSequence<SPSExecutorAddr>>;
+
+using SPSMachOJITDylibDepInfoMap =
+ SPSSequence<SPSTuple<SPSExecutorAddr, SPSMachOJITDylibDepInfo>>;
+
+template <>
+class SPSSerializationTraits<SPSMachOJITDylibDepInfo, MachOJITDylibDepInfo> {
+public:
+ static size_t size(const MachOJITDylibDepInfo &JDI) {
+ return SPSMachOJITDylibDepInfo::AsArgList::size(JDI.Sealed, JDI.DepHeaders);
+ }
+
+ static bool serialize(SPSOutputBuffer &OB, const MachOJITDylibDepInfo &JDI) {
+ return SPSMachOJITDylibDepInfo::AsArgList::serialize(OB, JDI.Sealed,
+ JDI.DepHeaders);
+ }
+
+ static bool deserialize(SPSInputBuffer &IB, MachOJITDylibDepInfo &JDI) {
+ return SPSMachOJITDylibDepInfo::AsArgList::deserialize(IB, JDI.Sealed,
+ JDI.DepHeaders);
+ }
+};
+
+struct UnwindSectionInfo {
+ std::vector<ExecutorAddrRange> CodeRanges;
+ ExecutorAddrRange DwarfSection;
+ ExecutorAddrRange CompactUnwindSection;
+};
+
+using SPSUnwindSectionInfo =
+ SPSTuple<SPSSequence<SPSExecutorAddrRange>, SPSExecutorAddrRange,
+ SPSExecutorAddrRange>;
+
+template <>
+class SPSSerializationTraits<SPSUnwindSectionInfo, UnwindSectionInfo> {
+public:
+ static size_t size(const UnwindSectionInfo &USI) {
+ return SPSUnwindSectionInfo::AsArgList::size(
+ USI.CodeRanges, USI.DwarfSection, USI.CompactUnwindSection);
+ }
+
+ static bool serialize(SPSOutputBuffer &OB, const UnwindSectionInfo &USI) {
+ return SPSUnwindSectionInfo::AsArgList::serialize(
+ OB, USI.CodeRanges, USI.DwarfSection, USI.CompactUnwindSection);
+ }
+
+ static bool deserialize(SPSInputBuffer &IB, UnwindSectionInfo &USI) {
+ return SPSUnwindSectionInfo::AsArgList::deserialize(
+ IB, USI.CodeRanges, USI.DwarfSection, USI.CompactUnwindSection);
+ }
+};
+
+} // namespace __orc_rt
+
+namespace {
+struct TLVDescriptor {
+ void *(*Thunk)(TLVDescriptor *) = nullptr;
+ unsigned long Key = 0;
+ unsigned long DataAddress = 0;
+};
+
+class MachOPlatformRuntimeState {
+public:
+ // Used internally by MachOPlatformRuntimeState, but made public to enable
+ // serialization.
+ enum class MachOExecutorSymbolFlags : uint8_t {
+ None = 0,
+ Weak = 1U << 0,
+ Callable = 1U << 1,
+ ORC_RT_MARK_AS_BITMASK_ENUM(/* LargestValue = */ Callable)
+ };
+
+private:
+ struct AtExitEntry {
+ void (*Func)(void *);
+ void *Arg;
+ };
+
+ using AtExitsVector = std::vector<AtExitEntry>;
+
+ /// Used to manage sections of fixed-sized metadata records (e.g. pointer
+ /// sections, selector refs, etc.)
+ template <typename RecordElement> class RecordSectionsTracker {
+ public:
+ /// Add a section to the "new" list.
+ void add(span<RecordElement> Sec) { New.push_back(std::move(Sec)); }
+
+ /// Returns true if there are new sections to process.
+ bool hasNewSections() const { return !New.empty(); }
+
+ /// Returns the number of new sections to process.
+ size_t numNewSections() const { return New.size(); }
+
+ /// Process all new sections.
+ template <typename ProcessSectionFunc>
+ std::enable_if_t<std::is_void_v<
+ std::invoke_result_t<ProcessSectionFunc, span<RecordElement>>>>
+ processNewSections(ProcessSectionFunc &&ProcessSection) {
+ for (auto &Sec : New)
+ ProcessSection(Sec);
+ moveNewToProcessed();
+ }
+
+ /// Proces all new sections with a fallible handler.
+ ///
+ /// Successfully handled sections will be moved to the Processed
+ /// list.
+ template <typename ProcessSectionFunc>
+ std::enable_if_t<
+ std::is_same_v<Error, std::invoke_result_t<ProcessSectionFunc,
+ span<RecordElement>>>,
+ Error>
+ processNewSections(ProcessSectionFunc &&ProcessSection) {
+ for (size_t I = 0; I != New.size(); ++I) {
+ if (auto Err = ProcessSection(New[I])) {
+ for (size_t J = 0; J != I; ++J)
+ Processed.push_back(New[J]);
+ New.erase(New.begin(), New.begin() + I);
+ return Err;
+ }
+ }
+ moveNewToProcessed();
+ return Error::success();
+ }
+
+ /// Move all sections back to New for reprocessing.
+ void reset() {
+ moveNewToProcessed();
+ New = std::move(Processed);
+ }
+
+ /// Remove the section with the given range.
+ bool removeIfPresent(ExecutorAddrRange R) {
+ if (removeIfPresent(New, R))
+ return true;
+ return removeIfPresent(Processed, R);
+ }
+
+ private:
+ void moveNewToProcessed() {
+ if (Processed.empty())
+ Processed = std::move(New);
+ else {
+ Processed.reserve(Processed.size() + New.size());
+ std::copy(New.begin(), New.end(), std::back_inserter(Processed));
+ New.clear();
+ }
+ }
+
+ bool removeIfPresent(std::vector<span<RecordElement>> &V,
+ ExecutorAddrRange R) {
+ auto RI = std::find_if(
+ V.rbegin(), V.rend(),
+ [RS = R.toSpan<RecordElement>()](const span<RecordElement> &E) {
+ return E.data() == RS.data();
+ });
+ if (RI != V.rend()) {
+ V.erase(std::next(RI).base());
+ return true;
+ }
+ return false;
+ }
+
+ std::vector<span<RecordElement>> Processed;
+ std::vector<span<RecordElement>> New;
+ };
+
+ struct UnwindSections {
+ UnwindSections(const UnwindSectionInfo &USI)
+ : DwarfSection(USI.DwarfSection.toSpan<char>()),
+ CompactUnwindSection(USI.CompactUnwindSection.toSpan<char>()) {}
+
+ span<char> DwarfSection;
+ span<char> CompactUnwindSection;
+ };
+
+ using UnwindSectionsMap =
+ IntervalMap<char *, UnwindSections, IntervalCoalescing::Disabled>;
+
+ struct JITDylibState {
+
+ using SymbolTableMap =
+ std::unordered_map<std::string_view,
+ std::pair<ExecutorAddr, MachOExecutorSymbolFlags>>;
+
+ std::string Name;
+ void *Header = nullptr;
+ bool Sealed = false;
+ size_t LinkedAgainstRefCount = 0;
+ size_t DlRefCount = 0;
+ SymbolTableMap SymbolTable;
+ std::vector<JITDylibState *> Deps;
+ AtExitsVector AtExits;
+ const objc_image_info *ObjCImageInfo = nullptr;
+ std::unordered_map<void *, std::vector<char>> DataSectionContent;
+ std::unordered_map<void *, size_t> ZeroInitRanges;
+ UnwindSectionsMap UnwindSections;
+ RecordSectionsTracker<void (*)()> ModInitsSections;
+ RecordSectionsTracker<char> ObjCRuntimeRegistrationObjects;
+
+ bool referenced() const {
+ return LinkedAgainstRefCount != 0 || DlRefCount != 0;
+ }
+ };
+
+public:
+ static Error create();
+ static MachOPlatformRuntimeState &get();
+ static Error destroy();
+
+ MachOPlatformRuntimeState() = default;
+
+ // Delete copy and move constructors.
+ MachOPlatformRuntimeState(const MachOPlatformRuntimeState &) = delete;
+ MachOPlatformRuntimeState &
+ operator=(const MachOPlatformRuntimeState &) = delete;
+ MachOPlatformRuntimeState(MachOPlatformRuntimeState &&) = delete;
+ MachOPlatformRuntimeState &operator=(MachOPlatformRuntimeState &&) = delete;
+
+ Error initialize();
+ Error shutdown();
+
+ Error registerJITDylib(std::string Name, void *Header);
+ Error deregisterJITDylib(void *Header);
+ Error registerThreadDataSection(span<const char> ThreadDataSection);
+ Error deregisterThreadDataSection(span<const char> ThreadDataSection);
+ Error registerObjectSymbolTable(
+ ExecutorAddr HeaderAddr,
+ const std::vector<std::tuple<ExecutorAddr, ExecutorAddr,
+ MachOExecutorSymbolFlags>> &Entries);
+ Error deregisterObjectSymbolTable(
+ ExecutorAddr HeaderAddr,
+ const std::vector<std::tuple<ExecutorAddr, ExecutorAddr,
+ MachOExecutorSymbolFlags>> &Entries);
+ Error registerObjectPlatformSections(
+ ExecutorAddr HeaderAddr, std::optional<UnwindSectionInfo> UnwindSections,
+ std::vector<std::pair<std::string_view, ExecutorAddrRange>> Secs);
+ Error deregisterObjectPlatformSections(
+ ExecutorAddr HeaderAddr, std::optional<UnwindSectionInfo> UnwindSections,
+ std::vector<std::pair<std::string_view, ExecutorAddrRange>> Secs);
+
+ const char *dlerror();
+ void *dlopen(std::string_view Name, int Mode);
+ int dlclose(void *DSOHandle);
+ void *dlsym(void *DSOHandle, const char *Symbol);
+
+ int registerAtExit(void (*F)(void *), void *Arg, void *DSOHandle);
+ void runAtExits(std::unique_lock<std::mutex> &JDStatesLock,
+ JITDylibState &JDS);
+ void runAtExits(void *DSOHandle);
+
+ /// Returns the base address of the section containing ThreadData.
+ Expected<std::pair<const char *, size_t>>
+ getThreadDataSectionFor(const char *ThreadData);
+
+private:
+ JITDylibState *getJITDylibStateByHeader(void *DSOHandle);
+ JITDylibState *getJITDylibStateByName(std::string_view Path);
+
+ /// Requests materialization of the given symbols. For each pair, the bool
+ /// element indicates whether the symbol is required (true) or weakly
+ /// referenced (false).
+ Error requestPushSymbols(JITDylibState &JDS,
+ span<std::pair<std::string_view, bool>> Symbols);
+
+ /// Attempts to look up the given symbols locally, requesting a push from the
+ /// remote if they're not found. Results are written to the Result span, which
+ /// must have the same size as the Symbols span.
+ Error
+ lookupSymbols(JITDylibState &JDS, std::unique_lock<std::mutex> &JDStatesLock,
+ span<std::pair<ExecutorAddr, MachOExecutorSymbolFlags>> Result,
+ span<std::pair<std::string_view, bool>> Symbols);
+
+ bool lookupUnwindSections(void *Addr, unw_dynamic_unwind_sections &Info);
+
+ static int findDynamicUnwindSections(uintptr_t addr,
+ unw_dynamic_unwind_sections *info);
+ static Error registerEHFrames(span<const char> EHFrameSection);
+ static Error deregisterEHFrames(span<const char> EHFrameSection);
+
+ static Error registerObjCRegistrationObjects(JITDylibState &JDS);
+ static Error runModInits(std::unique_lock<std::mutex> &JDStatesLock,
+ JITDylibState &JDS);
+
+ Expected<void *> dlopenImpl(std::string_view Path, int Mode);
+ Error dlopenFull(std::unique_lock<std::mutex> &JDStatesLock,
+ JITDylibState &JDS);
+ Error dlopenInitialize(std::unique_lock<std::mutex> &JDStatesLock,
+ JITDylibState &JDS, MachOJITDylibDepInfoMap &DepInfo);
+
+ Error dlcloseImpl(void *DSOHandle);
+ Error dlcloseDeinitialize(std::unique_lock<std::mutex> &JDStatesLock,
+ JITDylibState &JDS);
+
+ static MachOPlatformRuntimeState *MOPS;
+
+ bool UseCallbackStyleUnwindInfo = false;
+
+ // FIXME: Move to thread-state.
+ std::string DLFcnError;
+
+ // APIMutex guards against concurrent entry into key "dyld" API functions
+ // (e.g. dlopen, dlclose).
+ std::recursive_mutex DyldAPIMutex;
+
+ // JDStatesMutex guards the data structures that hold JITDylib state.
+ std::mutex JDStatesMutex;
+ std::unordered_map<void *, JITDylibState> JDStates;
+ std::unordered_map<std::string_view, void *> JDNameToHeader;
+
+ // ThreadDataSectionsMutex guards thread local data section state.
+ std::mutex ThreadDataSectionsMutex;
+ std::map<const char *, size_t> ThreadDataSections;
+};
+
+} // anonymous namespace
+
+namespace __orc_rt {
+
+class SPSMachOExecutorSymbolFlags;
+
+template <>
+class SPSSerializationTraits<
+ SPSMachOExecutorSymbolFlags,
+ MachOPlatformRuntimeState::MachOExecutorSymbolFlags> {
+private:
+ using UT = std::underlying_type_t<
+ MachOPlatformRuntimeState::MachOExecutorSymbolFlags>;
+
+public:
+ static size_t
+ size(const MachOPlatformRuntimeState::MachOExecutorSymbolFlags &SF) {
+ return sizeof(UT);
+ }
+
+ static bool
+ serialize(SPSOutputBuffer &OB,
+ const MachOPlatformRuntimeState::MachOExecutorSymbolFlags &SF) {
+ return SPSArgList<UT>::serialize(OB, static_cast<UT>(SF));
+ }
+
+ static bool
+ deserialize(SPSInputBuffer &IB,
+ MachOPlatformRuntimeState::MachOExecutorSymbolFlags &SF) {
+ UT Tmp;
+ if (!SPSArgList<UT>::deserialize(IB, Tmp))
+ return false;
+ SF = static_cast<MachOPlatformRuntimeState::MachOExecutorSymbolFlags>(Tmp);
+ return true;
+ }
+};
+
+} // namespace __orc_rt
+
+namespace {
+
+MachOPlatformRuntimeState *MachOPlatformRuntimeState::MOPS = nullptr;
+
+Error MachOPlatformRuntimeState::create() {
+ assert(!MOPS && "MachOPlatformRuntimeState should be null");
+ MOPS = new MachOPlatformRuntimeState();
+ return MOPS->initialize();
+}
+
+MachOPlatformRuntimeState &MachOPlatformRuntimeState::get() {
+ assert(MOPS && "MachOPlatformRuntimeState not initialized");
+ return *MOPS;
+}
+
+Error MachOPlatformRuntimeState::destroy() {
+ assert(MOPS && "MachOPlatformRuntimeState not initialized");
+ auto Err = MOPS->shutdown();
+ delete MOPS;
+ return Err;
+}
+
+Error MachOPlatformRuntimeState::initialize() {
+ UseCallbackStyleUnwindInfo = __unw_add_find_dynamic_unwind_sections &&
+ __unw_remove_find_dynamic_unwind_sections;
+ if (UseCallbackStyleUnwindInfo) {
+ ORC_RT_DEBUG({
+ printdbg("__unw_add/remove_find_dynamic_unwind_sections available."
+ " Using callback-based frame info lookup.\n");
+ });
+ if (__unw_add_find_dynamic_unwind_sections(&findDynamicUnwindSections))
+ return make_error<StringError>(
+ "Could not register findDynamicUnwindSections");
+ } else {
+ ORC_RT_DEBUG({
+ printdbg("__unw_add/remove_find_dynamic_unwind_sections not available."
+ " Using classic frame info registration.\n");
+ });
+ }
+ return Error::success();
+}
+
+Error MachOPlatformRuntimeState::shutdown() {
+ if (UseCallbackStyleUnwindInfo) {
+ if (__unw_remove_find_dynamic_unwind_sections(&findDynamicUnwindSections)) {
+ ORC_RT_DEBUG(
+ { printdbg("__unw_remove_find_dynamic_unwind_sections failed.\n"); });
+ }
+ }
+ return Error::success();
+}
+
+Error MachOPlatformRuntimeState::registerJITDylib(std::string Name,
+ void *Header) {
+ ORC_RT_DEBUG({
+ printdbg("Registering JITDylib %s: Header = %p\n", Name.c_str(), Header);
+ });
+ std::lock_guard<std::mutex> Lock(JDStatesMutex);
+ if (JDStates.count(Header)) {
+ std::ostringstream ErrStream;
+ ErrStream << "Duplicate JITDylib registration for header " << Header
+ << " (name = " << Name << ")";
+ return make_error<StringError>(ErrStream.str());
+ }
+ if (JDNameToHeader.count(Name)) {
+ std::ostringstream ErrStream;
+ ErrStream << "Duplicate JITDylib registration for header " << Header
+ << " (header = " << Header << ")";
+ return make_error<StringError>(ErrStream.str());
+ }
+
+ auto &JDS = JDStates[Header];
+ JDS.Name = std::move(Name);
+ JDS.Header = Header;
+ JDNameToHeader[JDS.Name] = Header;
+ return Error::success();
+}
+
+Error MachOPlatformRuntimeState::deregisterJITDylib(void *Header) {
+ std::lock_guard<std::mutex> Lock(JDStatesMutex);
+ auto I = JDStates.find(Header);
+ if (I == JDStates.end()) {
+ std::ostringstream ErrStream;
+ ErrStream << "Attempted to deregister unrecognized header " << Header;
+ return make_error<StringError>(ErrStream.str());
+ }
+
+ // Remove std::string construction once we can use C++20.
+ auto J = JDNameToHeader.find(
+ std::string(I->second.Name.data(), I->second.Name.size()));
+ assert(J != JDNameToHeader.end() &&
+ "Missing JDNameToHeader entry for JITDylib");
+
+ ORC_RT_DEBUG({
+ printdbg("Deregistering JITDylib %s: Header = %p\n", I->second.Name.c_str(),
+ Header);
+ });
+
+ JDNameToHeader.erase(J);
+ JDStates.erase(I);
+ return Error::success();
+}
+
+Error MachOPlatformRuntimeState::registerThreadDataSection(
+ span<const char> ThreadDataSection) {
+ std::lock_guard<std::mutex> Lock(ThreadDataSectionsMutex);
+ auto I = ThreadDataSections.upper_bound(ThreadDataSection.data());
+ if (I != ThreadDataSections.begin()) {
+ auto J = std::prev(I);
+ if (J->first + J->second > ThreadDataSection.data())
+ return make_error<StringError>("Overlapping __thread_data sections");
+ }
+ ThreadDataSections.insert(
+ I, std::make_pair(ThreadDataSection.data(), ThreadDataSection.size()));
+ return Error::success();
+}
+
+Error MachOPlatformRuntimeState::deregisterThreadDataSection(
+ span<const char> ThreadDataSection) {
+ std::lock_guard<std::mutex> Lock(ThreadDataSectionsMutex);
+ auto I = ThreadDataSections.find(ThreadDataSection.data());
+ if (I == ThreadDataSections.end())
+ return make_error<StringError>("Attempt to deregister unknown thread data "
+ "section");
+ ThreadDataSections.erase(I);
+ return Error::success();
+}
+
+Error MachOPlatformRuntimeState::registerObjectSymbolTable(
+ ExecutorAddr HeaderAddr,
+ const std::vector<std::tuple<ExecutorAddr, ExecutorAddr,
+ MachOExecutorSymbolFlags>> &Entries) {
+
+ std::lock_guard<std::mutex> Lock(JDStatesMutex);
+ auto *JDS = getJITDylibStateByHeader(HeaderAddr.toPtr<void *>());
+ if (!JDS) {
+ std::ostringstream ErrStream;
+ ErrStream << "Could not register object platform sections for "
+ "unrecognized header "
+ << HeaderAddr.toPtr<void *>();
+ return make_error<StringError>(ErrStream.str());
+ }
+
+ for (auto &[NameAddr, SymAddr, Flags] : Entries)
+ JDS->SymbolTable[NameAddr.toPtr<const char *>()] = {SymAddr, Flags};
+
+ return Error::success();
+}
+
+Error MachOPlatformRuntimeState::deregisterObjectSymbolTable(
+ ExecutorAddr HeaderAddr,
+ const std::vector<std::tuple<ExecutorAddr, ExecutorAddr,
+ MachOExecutorSymbolFlags>> &Entries) {
+
+ std::lock_guard<std::mutex> Lock(JDStatesMutex);
+ auto *JDS = getJITDylibStateByHeader(HeaderAddr.toPtr<void *>());
+ if (!JDS) {
+ std::ostringstream ErrStream;
+ ErrStream << "Could not register object platform sections for "
+ "unrecognized header "
+ << HeaderAddr.toPtr<void *>();
+ return make_error<StringError>(ErrStream.str());
+ }
+
+ for (auto &[NameAddr, SymAddr, Flags] : Entries)
+ JDS->SymbolTable.erase(NameAddr.toPtr<const char *>());
+
+ return Error::success();
+}
+
+Error MachOPlatformRuntimeState::registerObjectPlatformSections(
+ ExecutorAddr HeaderAddr, std::optional<UnwindSectionInfo> UnwindInfo,
+ std::vector<std::pair<std::string_view, ExecutorAddrRange>> Secs) {
+
+ // FIXME: Reject platform section registration after the JITDylib is
+ // sealed?
+
+ ORC_RT_DEBUG({
+ printdbg("MachOPlatform: Registering object sections for %p.\n",
+ HeaderAddr.toPtr<void *>());
+ });
+
+ std::lock_guard<std::mutex> Lock(JDStatesMutex);
+ auto *JDS = getJITDylibStateByHeader(HeaderAddr.toPtr<void *>());
+ if (!JDS) {
+ std::ostringstream ErrStream;
+ ErrStream << "Could not register object platform sections for "
+ "unrecognized header "
+ << HeaderAddr.toPtr<void *>();
+ return make_error<StringError>(ErrStream.str());
+ }
+
+ if (UnwindInfo && UseCallbackStyleUnwindInfo) {
+ ORC_RT_DEBUG({
+ printdbg(" Registering new-style unwind info for:\n"
+ " DWARF: %p -- %p\n"
+ " Compact-unwind: %p -- %p\n"
+ " for:\n",
+ UnwindInfo->DwarfSection.Start.toPtr<void *>(),
+ UnwindInfo->DwarfSection.End.toPtr<void *>(),
+ UnwindInfo->CompactUnwindSection.Start.toPtr<void *>(),
+ UnwindInfo->CompactUnwindSection.End.toPtr<void *>());
+ });
+ for (auto &CodeRange : UnwindInfo->CodeRanges) {
+ JDS->UnwindSections.insert(CodeRange.Start.toPtr<char *>(),
+ CodeRange.End.toPtr<char *>(), *UnwindInfo);
+ ORC_RT_DEBUG({
+ printdbg(" [ %p -- %p ]\n", CodeRange.Start.toPtr<void *>(),
+ CodeRange.End.toPtr<void *>());
+ });
+ }
+ }
+
+ for (auto &KV : Secs) {
+ // FIXME: Validate section ranges?
+ if (KV.first == "__TEXT,__eh_frame") {
+ if (!UseCallbackStyleUnwindInfo) {
+ // Use classic libunwind registration.
+ if (auto Err = registerEHFrames(KV.second.toSpan<const char>()))
+ return Err;
+ }
+ } else if (KV.first == "__DATA,__data") {
+ assert(!JDS->DataSectionContent.count(KV.second.Start.toPtr<char *>()) &&
+ "Address already registered.");
+ auto S = KV.second.toSpan<char>();
+ JDS->DataSectionContent[KV.second.Start.toPtr<char *>()] =
+ std::vector<char>(S.begin(), S.end());
+ } else if (KV.first == "__DATA,__common") {
+ JDS->ZeroInitRanges[KV.second.Start.toPtr<char *>()] = KV.second.size();
+ } else if (KV.first == "__DATA,__thread_data") {
+ if (auto Err = registerThreadDataSection(KV.second.toSpan<const char>()))
+ return Err;
+ } else if (KV.first == "__llvm_jitlink_ObjCRuntimeRegistrationObject")
+ JDS->ObjCRuntimeRegistrationObjects.add(KV.second.toSpan<char>());
+ else if (KV.first == "__DATA,__mod_init_func")
+ JDS->ModInitsSections.add(KV.second.toSpan<void (*)()>());
+ else {
+ // Should this be a warning instead?
+ return make_error<StringError>(
+ "Encountered unexpected section " +
+ std::string(KV.first.data(), KV.first.size()) +
+ " while registering object platform sections");
+ }
+ }
+
+ return Error::success();
+}
+
+Error MachOPlatformRuntimeState::deregisterObjectPlatformSections(
+ ExecutorAddr HeaderAddr, std::optional<UnwindSectionInfo> UnwindInfo,
+ std::vector<std::pair<std::string_view, ExecutorAddrRange>> Secs) {
+ // TODO: Make this more efficient? (maybe unnecessary if removal is rare?)
+ // TODO: Add a JITDylib prepare-for-teardown operation that clears all
+ // registered sections, causing this function to take the fast-path.
+ ORC_RT_DEBUG({
+ printdbg("MachOPlatform: Deregistering object sections for %p.\n",
+ HeaderAddr.toPtr<void *>());
+ });
+
+ std::lock_guard<std::mutex> Lock(JDStatesMutex);
+ auto *JDS = getJITDylibStateByHeader(HeaderAddr.toPtr<void *>());
+ if (!JDS) {
+ std::ostringstream ErrStream;
+ ErrStream << "Could not register object platform sections for unrecognized "
+ "header "
+ << HeaderAddr.toPtr<void *>();
+ return make_error<StringError>(ErrStream.str());
+ }
+
+ // FIXME: Implement faster-path by returning immediately if JDS is being
+ // torn down entirely?
+
+ // TODO: Make library permanent (i.e. not able to be dlclosed) if it contains
+ // any Swift or ObjC. Once this happens we can clear (and no longer record)
+ // data section content, as the library could never be re-initialized.
+
+ if (UnwindInfo && UseCallbackStyleUnwindInfo) {
+ ORC_RT_DEBUG({
+ printdbg(" Deregistering new-style unwind info for:\n"
+ " DWARF: %p -- %p\n"
+ " Compact-unwind: %p -- %p\n"
+ " for:\n",
+ UnwindInfo->DwarfSection.Start.toPtr<void *>(),
+ UnwindInfo->DwarfSection.End.toPtr<void *>(),
+ UnwindInfo->CompactUnwindSection.Start.toPtr<void *>(),
+ UnwindInfo->CompactUnwindSection.End.toPtr<void *>());
+ });
+ for (auto &CodeRange : UnwindInfo->CodeRanges) {
+ JDS->UnwindSections.erase(CodeRange.Start.toPtr<char *>(),
+ CodeRange.End.toPtr<char *>());
+ ORC_RT_DEBUG({
+ printdbg(" [ %p -- %p ]\n", CodeRange.Start.toPtr<void *>(),
+ CodeRange.End.toPtr<void *>());
+ });
+ }
+ }
+
+ for (auto &KV : Secs) {
+ // FIXME: Validate section ranges?
+ if (KV.first == "__TEXT,__eh_frame") {
+ if (!UseCallbackStyleUnwindInfo) {
+ // Use classic libunwind registration.
+ if (auto Err = deregisterEHFrames(KV.second.toSpan<const char>()))
+ return Err;
+ }
+ } else if (KV.first == "__DATA,__data") {
+ JDS->DataSectionContent.erase(KV.second.Start.toPtr<char *>());
+ } else if (KV.first == "__DATA,__common") {
+ JDS->ZeroInitRanges.erase(KV.second.Start.toPtr<char *>());
+ } else if (KV.first == "__DATA,__thread_data") {
+ if (auto Err =
+ deregisterThreadDataSection(KV.second.toSpan<const char>()))
+ return Err;
+ } else if (KV.first == "__llvm_jitlink_ObjCRuntimeRegistrationObject")
+ JDS->ObjCRuntimeRegistrationObjects.removeIfPresent(KV.second);
+ else if (KV.first == "__DATA,__mod_init_func")
+ JDS->ModInitsSections.removeIfPresent(KV.second);
+ else {
+ // Should this be a warning instead?
+ return make_error<StringError>(
+ "Encountered unexpected section " +
+ std::string(KV.first.data(), KV.first.size()) +
+ " while deregistering object platform sections");
+ }
+ }
+ return Error::success();
+}
+
+const char *MachOPlatformRuntimeState::dlerror() { return DLFcnError.c_str(); }
+
+void *MachOPlatformRuntimeState::dlopen(std::string_view Path, int Mode) {
+ ORC_RT_DEBUG({
+ std::string S(Path.data(), Path.size());
+ printdbg("MachOPlatform::dlopen(\"%s\")\n", S.c_str());
+ });
+ std::lock_guard<std::recursive_mutex> Lock(DyldAPIMutex);
+ if (auto H = dlopenImpl(Path, Mode))
+ return *H;
+ else {
+ // FIXME: Make dlerror thread safe.
+ DLFcnError = toString(H.takeError());
+ return nullptr;
+ }
+}
+
+int MachOPlatformRuntimeState::dlclose(void *DSOHandle) {
+ ORC_RT_DEBUG({
+ auto *JDS = getJITDylibStateByHeader(DSOHandle);
+ std::string DylibName;
+ if (JDS) {
+ std::string S;
+ printdbg("MachOPlatform::dlclose(%p) (%s)\n", DSOHandle, S.c_str());
+ } else
+ printdbg("MachOPlatform::dlclose(%p) (%s)\n", DSOHandle,
+ "invalid handle");
+ });
+ std::lock_guard<std::recursive_mutex> Lock(DyldAPIMutex);
+ if (auto Err = dlcloseImpl(DSOHandle)) {
+ // FIXME: Make dlerror thread safe.
+ DLFcnError = toString(std::move(Err));
+ return -1;
+ }
+ return 0;
+}
+
+void *MachOPlatformRuntimeState::dlsym(void *DSOHandle, const char *Symbol) {
+ std::unique_lock<std::mutex> Lock(JDStatesMutex);
+ auto *JDS = getJITDylibStateByHeader(DSOHandle);
+ if (!JDS) {
+ std::ostringstream ErrStream;
+ ErrStream << "In call to dlsym, unrecognized header address " << DSOHandle;
+ DLFcnError = ErrStream.str();
+ return nullptr;
+ }
+
+ std::string MangledName = std::string("_") + Symbol;
+ std::pair<std::string_view, bool> Lookup(MangledName, false);
+ std::pair<ExecutorAddr, MachOExecutorSymbolFlags> Result;
+
+ if (auto Err = lookupSymbols(*JDS, Lock, {&Result, 1}, {&Lookup, 1})) {
+ DLFcnError = toString(std::move(Err));
+ return nullptr;
+ }
+
+ // Sign callable symbols as functions, to match dyld.
+ if ((Result.second & MachOExecutorSymbolFlags::Callable) ==
+ MachOExecutorSymbolFlags::Callable)
+ return reinterpret_cast<void *>(Result.first.toPtr<void(void)>());
+ return Result.first.toPtr<void *>();
+}
+
+int MachOPlatformRuntimeState::registerAtExit(void (*F)(void *), void *Arg,
+ void *DSOHandle) {
+ // FIXME: Handle out-of-memory errors, returning -1 if OOM.
+ std::lock_guard<std::mutex> Lock(JDStatesMutex);
+ auto *JDS = getJITDylibStateByHeader(DSOHandle);
+ if (!JDS) {
+ ORC_RT_DEBUG({
+ printdbg("MachOPlatformRuntimeState::registerAtExit called with "
+ "unrecognized dso handle %p\n",
+ DSOHandle);
+ });
+ return -1;
+ }
+ JDS->AtExits.push_back({F, Arg});
+ return 0;
+}
+
+void MachOPlatformRuntimeState::runAtExits(
+ std::unique_lock<std::mutex> &JDStatesLock, JITDylibState &JDS) {
+ auto AtExits = std::move(JDS.AtExits);
+
+ // Unlock while running atexits, as they may trigger operations that modify
+ // JDStates.
+ JDStatesLock.unlock();
+ while (!AtExits.empty()) {
+ auto &AE = AtExits.back();
+ AE.Func(AE.Arg);
+ AtExits.pop_back();
+ }
+ JDStatesLock.lock();
+}
+
+void MachOPlatformRuntimeState::runAtExits(void *DSOHandle) {
+ std::unique_lock<std::mutex> Lock(JDStatesMutex);
+ auto *JDS = getJITDylibStateByHeader(DSOHandle);
+ ORC_RT_DEBUG({
+ printdbg("MachOPlatformRuntimeState::runAtExits called on unrecognized "
+ "dso_handle %p\n",
+ DSOHandle);
+ });
+ if (JDS)
+ runAtExits(Lock, *JDS);
+}
+
+Expected<std::pair<const char *, size_t>>
+MachOPlatformRuntimeState::getThreadDataSectionFor(const char *ThreadData) {
+ std::lock_guard<std::mutex> Lock(ThreadDataSectionsMutex);
+ auto I = ThreadDataSections.upper_bound(ThreadData);
+ // Check that we have a valid entry covering this address.
+ if (I == ThreadDataSections.begin())
+ return make_error<StringError>("No thread local data section for key");
+ I = std::prev(I);
+ if (ThreadData >= I->first + I->second)
+ return make_error<StringError>("No thread local data section for key");
+ return *I;
+}
+
+MachOPlatformRuntimeState::JITDylibState *
+MachOPlatformRuntimeState::getJITDylibStateByHeader(void *DSOHandle) {
+ auto I = JDStates.find(DSOHandle);
+ if (I == JDStates.end()) {
+ I = JDStates.insert(std::make_pair(DSOHandle, JITDylibState())).first;
+ I->second.Header = DSOHandle;
+ }
+ return &I->second;
+}
+
+MachOPlatformRuntimeState::JITDylibState *
+MachOPlatformRuntimeState::getJITDylibStateByName(std::string_view Name) {
+ // FIXME: Avoid creating string once we have C++20.
+ auto I = JDNameToHeader.find(std::string(Name.data(), Name.size()));
+ if (I != JDNameToHeader.end())
+ return getJITDylibStateByHeader(I->second);
+ return nullptr;
+}
+
+Error MachOPlatformRuntimeState::requestPushSymbols(
+ JITDylibState &JDS, span<std::pair<std::string_view, bool>> Symbols) {
+ Error OpErr = Error::success();
+ if (auto Err = WrapperFunction<SPSError(
+ SPSExecutorAddr, SPSSequence<SPSTuple<SPSString, bool>>)>::
+ call(&__orc_rt_macho_push_symbols_tag, OpErr,
+ ExecutorAddr::fromPtr(JDS.Header), Symbols)) {
+ cantFail(std::move(OpErr));
+ return std::move(Err);
+ }
+ return OpErr;
+}
+
+Error MachOPlatformRuntimeState::lookupSymbols(
+ JITDylibState &JDS, std::unique_lock<std::mutex> &JDStatesLock,
+ span<std::pair<ExecutorAddr, MachOExecutorSymbolFlags>> Result,
+ span<std::pair<std::string_view, bool>> Symbols) {
+ assert(JDStatesLock.owns_lock() &&
+ "JDStatesLock should be locked at call-site");
+ assert(Result.size() == Symbols.size() &&
+ "Results and Symbols span sizes should match");
+
+ // Make an initial pass over the local symbol table.
+ std::vector<size_t> MissingSymbolIndexes;
+ for (size_t Idx = 0; Idx != Symbols.size(); ++Idx) {
+ auto I = JDS.SymbolTable.find(Symbols[Idx].first);
+ if (I != JDS.SymbolTable.end())
+ Result[Idx] = I->second;
+ else
+ MissingSymbolIndexes.push_back(Idx);
+ }
+
+ // If everything has been resolved already then bail out early.
+ if (MissingSymbolIndexes.empty())
+ return Error::success();
+
+ // Otherwise call back to the controller to try to request that the symbol
+ // be materialized.
+ std::vector<std::pair<std::string_view, bool>> MissingSymbols;
+ MissingSymbols.reserve(MissingSymbolIndexes.size());
+ ORC_RT_DEBUG({
+ printdbg("requesting push of %i missing symbols...\n",
+ MissingSymbolIndexes.size());
+ });
+ for (auto MissingIdx : MissingSymbolIndexes)
+ MissingSymbols.push_back(Symbols[MissingIdx]);
+
+ JDStatesLock.unlock();
+ if (auto Err = requestPushSymbols(
+ JDS, {MissingSymbols.data(), MissingSymbols.size()}))
+ return Err;
+ JDStatesLock.lock();
+
+ // Try to resolve the previously missing symbols locally.
+ std::vector<size_t> MissingRequiredSymbols;
+ for (auto MissingIdx : MissingSymbolIndexes) {
+ auto I = JDS.SymbolTable.find(Symbols[MissingIdx].first);
+ if (I != JDS.SymbolTable.end())
+ Result[MissingIdx] = I->second;
+ else {
+ if (Symbols[MissingIdx].second)
+ MissingRequiredSymbols.push_back(MissingIdx);
+ else
+ Result[MissingIdx] = {ExecutorAddr(), {}};
+ }
+ }
+
+ // Error out if any missing symbols could not be resolved.
+ if (!MissingRequiredSymbols.empty()) {
+ std::ostringstream ErrStream;
+ ErrStream << "Lookup could not find required symbols: [ ";
+ for (auto MissingIdx : MissingRequiredSymbols)
+ ErrStream << "\"" << Symbols[MissingIdx].first << "\" ";
+ ErrStream << "]";
+ return make_error<StringError>(ErrStream.str());
+ }
+
+ return Error::success();
+}
+
+// eh-frame registration functions.
+// We expect these to be available for all processes.
+extern "C" void __register_frame(const void *);
+extern "C" void __deregister_frame(const void *);
+
+template <typename HandleFDEFn>
+void walkEHFrameSection(span<const char> EHFrameSection,
+ HandleFDEFn HandleFDE) {
+ const char *CurCFIRecord = EHFrameSection.data();
+ uint64_t Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
+
+ while (CurCFIRecord != EHFrameSection.end() && Size != 0) {
+ const char *OffsetField = CurCFIRecord + (Size == 0xffffffff ? 12 : 4);
+ if (Size == 0xffffffff)
+ Size = *reinterpret_cast<const uint64_t *>(CurCFIRecord + 4) + 12;
+ else
+ Size += 4;
+ uint32_t Offset = *reinterpret_cast<const uint32_t *>(OffsetField);
+
+ if (Offset != 0)
+ HandleFDE(CurCFIRecord);
+
+ CurCFIRecord += Size;
+ Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
+ }
+}
+
+bool MachOPlatformRuntimeState::lookupUnwindSections(
+ void *Addr, unw_dynamic_unwind_sections &Info) {
+ ORC_RT_DEBUG(
+ { printdbg("Tried to lookup unwind-info via new lookup call.\n"); });
+ std::lock_guard<std::mutex> Lock(JDStatesMutex);
+ for (auto &KV : JDStates) {
+ auto &JD = KV.second;
+ auto I = JD.UnwindSections.find(reinterpret_cast<char *>(Addr));
+ if (I != JD.UnwindSections.end()) {
+ Info.dso_base = reinterpret_cast<uintptr_t>(JD.Header);
+ Info.dwarf_section =
+ reinterpret_cast<uintptr_t>(I->second.DwarfSection.data());
+ Info.dwarf_section_length = I->second.DwarfSection.size();
+ Info.compact_unwind_section =
+ reinterpret_cast<uintptr_t>(I->second.CompactUnwindSection.data());
+ Info.compact_unwind_section_length =
+ I->second.CompactUnwindSection.size();
+ return true;
+ }
+ }
+ return false;
+}
+
+int MachOPlatformRuntimeState::findDynamicUnwindSections(
+ uintptr_t addr, unw_dynamic_unwind_sections *info) {
+ if (!info)
+ return 0;
+ return MachOPlatformRuntimeState::get().lookupUnwindSections((void *)addr,
+ *info);
+}
+
+Error MachOPlatformRuntimeState::registerEHFrames(
+ span<const char> EHFrameSection) {
+ walkEHFrameSection(EHFrameSection, __register_frame);
+ return Error::success();
+}
+
+Error MachOPlatformRuntimeState::deregisterEHFrames(
+ span<const char> EHFrameSection) {
+ walkEHFrameSection(EHFrameSection, __deregister_frame);
+ return Error::success();
+}
+
+Error MachOPlatformRuntimeState::registerObjCRegistrationObjects(
+ JITDylibState &JDS) {
+ ORC_RT_DEBUG(printdbg("Registering Objective-C / Swift metadata.\n"));
+
+ std::vector<char *> RegObjBases;
+ JDS.ObjCRuntimeRegistrationObjects.processNewSections(
+ [&](span<char> RegObj) { RegObjBases.push_back(RegObj.data()); });
+
+ if (RegObjBases.empty())
+ return Error::success();
+
+ if (!_objc_map_images || !_objc_load_image)
+ return make_error<StringError>(
+ "Could not register Objective-C / Swift metadata: _objc_map_images / "
+ "_objc_load_image not found");
+
+ std::vector<char *> Paths;
+ Paths.resize(RegObjBases.size());
+ _objc_map_images(RegObjBases.size(), Paths.data(),
+ reinterpret_cast<mach_header **>(RegObjBases.data()));
+
+ for (void *RegObjBase : RegObjBases)
+ _objc_load_image(nullptr, reinterpret_cast<mach_header *>(RegObjBase));
+
+ return Error::success();
+}
+
+Error MachOPlatformRuntimeState::runModInits(
+ std::unique_lock<std::mutex> &JDStatesLock, JITDylibState &JDS) {
+ std::vector<span<void (*)()>> InitSections;
+ InitSections.reserve(JDS.ModInitsSections.numNewSections());
+
+ // Copy initializer sections: If the JITDylib is unsealed then the
+ // initializers could reach back into the JIT and cause more initializers to
+ // be added.
+ // FIXME: Skip unlock and run in-place on sealed JITDylibs?
+ JDS.ModInitsSections.processNewSections(
+ [&](span<void (*)()> Inits) { InitSections.push_back(Inits); });
+
+ JDStatesLock.unlock();
+ for (auto InitSec : InitSections)
+ for (auto *Init : InitSec)
+ Init();
+ JDStatesLock.lock();
+
+ return Error::success();
+}
+
+Expected<void *> MachOPlatformRuntimeState::dlopenImpl(std::string_view Path,
+ int Mode) {
+ std::unique_lock<std::mutex> Lock(JDStatesMutex);
+
+ // Try to find JITDylib state by name.
+ auto *JDS = getJITDylibStateByName(Path);
+
+ if (!JDS)
+ return make_error<StringError>("No registered JTIDylib for path " +
+ std::string(Path.data(), Path.size()));
+
+ // If this JITDylib is unsealed, or this is the first dlopen then run
+ // full dlopen path (update deps, push and run initializers, update ref
+ // counts on all JITDylibs in the dep tree).
+ if (!JDS->referenced() || !JDS->Sealed) {
+ if (auto Err = dlopenFull(Lock, *JDS))
+ return std::move(Err);
+ }
+
+ // Bump the ref-count on this dylib.
+ ++JDS->DlRefCount;
+
+ // Return the header address.
+ return JDS->Header;
+}
+
+Error MachOPlatformRuntimeState::dlopenFull(
+ std::unique_lock<std::mutex> &JDStatesLock, JITDylibState &JDS) {
+ // Call back to the JIT to push the initializers.
+ Expected<MachOJITDylibDepInfoMap> DepInfo((MachOJITDylibDepInfoMap()));
+ // Unlock so that we can accept the initializer update.
+ JDStatesLock.unlock();
+ if (auto Err = WrapperFunction<SPSExpected<SPSMachOJITDylibDepInfoMap>(
+ SPSExecutorAddr)>::call(&__orc_rt_macho_push_initializers_tag,
+ DepInfo, ExecutorAddr::fromPtr(JDS.Header)))
+ return Err;
+ JDStatesLock.lock();
+
+ if (!DepInfo)
+ return DepInfo.takeError();
+
+ if (auto Err = dlopenInitialize(JDStatesLock, JDS, *DepInfo))
+ return Err;
+
+ if (!DepInfo->empty()) {
+ ORC_RT_DEBUG({
+ printdbg("Unrecognized dep-info key headers in dlopen of %s\n",
+ JDS.Name.c_str());
+ });
+ std::ostringstream ErrStream;
+ ErrStream << "Encountered unrecognized dep-info key headers "
+ "while processing dlopen of "
+ << JDS.Name;
+ return make_error<StringError>(ErrStream.str());
+ }
+
+ return Error::success();
+}
+
+Error MachOPlatformRuntimeState::dlopenInitialize(
+ std::unique_lock<std::mutex> &JDStatesLock, JITDylibState &JDS,
+ MachOJITDylibDepInfoMap &DepInfo) {
+ ORC_RT_DEBUG({
+ printdbg("MachOPlatformRuntimeState::dlopenInitialize(\"%s\")\n",
+ JDS.Name.c_str());
+ });
+
+ // If the header is not present in the dep map then assume that we
+ // already processed it earlier in the dlopenInitialize traversal and
+ // return.
+ // TODO: Keep a visited set instead so that we can error out on missing
+ // entries?
+ auto I = DepInfo.find(ExecutorAddr::fromPtr(JDS.Header));
+ if (I == DepInfo.end())
+ return Error::success();
+
+ auto DI = std::move(I->second);
+ DepInfo.erase(I);
+
+ // We don't need to re-initialize sealed JITDylibs that have already been
+ // initialized. Just check that their dep-map entry is empty as expected.
+ if (JDS.Sealed) {
+ if (!DI.DepHeaders.empty()) {
+ std::ostringstream ErrStream;
+ ErrStream << "Sealed JITDylib " << JDS.Header
+ << " already has registered dependencies";
+ return make_error<StringError>(ErrStream.str());
+ }
+ if (JDS.referenced())
+ return Error::success();
+ } else
+ JDS.Sealed = DI.Sealed;
+
+ // This is an unsealed or newly sealed JITDylib. Run initializers.
+ std::vector<JITDylibState *> OldDeps;
+ std::swap(JDS.Deps, OldDeps);
+ JDS.Deps.reserve(DI.DepHeaders.size());
+ for (auto DepHeaderAddr : DI.DepHeaders) {
+ auto *DepJDS = getJITDylibStateByHeader(DepHeaderAddr.toPtr<void *>());
+ if (!DepJDS) {
+ std::ostringstream ErrStream;
+ ErrStream << "Encountered unrecognized dep header "
+ << DepHeaderAddr.toPtr<void *>() << " while initializing "
+ << JDS.Name;
+ return make_error<StringError>(ErrStream.str());
+ }
+ ++DepJDS->LinkedAgainstRefCount;
+ if (auto Err = dlopenInitialize(JDStatesLock, *DepJDS, DepInfo))
+ return Err;
+ }
+
+ // Initialize this JITDylib.
+ if (auto Err = registerObjCRegistrationObjects(JDS))
+ return Err;
+ if (auto Err = runModInits(JDStatesLock, JDS))
+ return Err;
+
+ // Decrement old deps.
+ // FIXME: We should probably continue and just report deinitialize errors
+ // here.
+ for (auto *DepJDS : OldDeps) {
+ --DepJDS->LinkedAgainstRefCount;
+ if (!DepJDS->referenced())
+ if (auto Err = dlcloseDeinitialize(JDStatesLock, *DepJDS))
+ return Err;
+ }
+
+ return Error::success();
+}
+
+Error MachOPlatformRuntimeState::dlcloseImpl(void *DSOHandle) {
+ std::unique_lock<std::mutex> Lock(JDStatesMutex);
+
+ // Try to find JITDylib state by header.
+ auto *JDS = getJITDylibStateByHeader(DSOHandle);
+
+ if (!JDS) {
+ std::ostringstream ErrStream;
+ ErrStream << "No registered JITDylib for " << DSOHandle;
+ return make_error<StringError>(ErrStream.str());
+ }
+
+ // Bump the ref-count.
+ --JDS->DlRefCount;
+
+ if (!JDS->referenced())
+ return dlcloseDeinitialize(Lock, *JDS);
+
+ return Error::success();
+}
+
+Error MachOPlatformRuntimeState::dlcloseDeinitialize(
+ std::unique_lock<std::mutex> &JDStatesLock, JITDylibState &JDS) {
+
+ ORC_RT_DEBUG({
+ printdbg("MachOPlatformRuntimeState::dlcloseDeinitialize(\"%s\")\n",
+ JDS.Name.c_str());
+ });
+
+ runAtExits(JDStatesLock, JDS);
+
+ // Reset mod-inits
+ JDS.ModInitsSections.reset();
+
+ // Reset data section contents.
+ for (auto &KV : JDS.DataSectionContent)
+ memcpy(KV.first, KV.second.data(), KV.second.size());
+ for (auto &KV : JDS.ZeroInitRanges)
+ memset(KV.first, 0, KV.second);
+
+ // Deinitialize any dependencies.
+ for (auto *DepJDS : JDS.Deps) {
+ --DepJDS->LinkedAgainstRefCount;
+ if (!DepJDS->referenced())
+ if (auto Err = dlcloseDeinitialize(JDStatesLock, *DepJDS))
+ return Err;
+ }
+
+ return Error::success();
+}
+
+class MachOPlatformRuntimeTLVManager {
+public:
+ void *getInstance(const char *ThreadData);
+
+private:
+ std::unordered_map<const char *, char *> Instances;
+ std::unordered_map<const char *, std::unique_ptr<char[]>> AllocatedSections;
+};
+
+void *MachOPlatformRuntimeTLVManager::getInstance(const char *ThreadData) {
+ auto I = Instances.find(ThreadData);
+ if (I != Instances.end())
+ return I->second;
+
+ auto TDS =
+ MachOPlatformRuntimeState::get().getThreadDataSectionFor(ThreadData);
+ if (!TDS) {
+ __orc_rt_log_error(toString(TDS.takeError()).c_str());
+ return nullptr;
+ }
+
+ auto &Allocated = AllocatedSections[TDS->first];
+ if (!Allocated) {
+ Allocated = std::make_unique<char[]>(TDS->second);
+ memcpy(Allocated.get(), TDS->first, TDS->second);
+ }
+
+ size_t ThreadDataDelta = ThreadData - TDS->first;
+ assert(ThreadDataDelta <= TDS->second && "ThreadData outside section bounds");
+
+ char *Instance = Allocated.get() + ThreadDataDelta;
+ Instances[ThreadData] = Instance;
+ return Instance;
+}
+
+void destroyMachOTLVMgr(void *MachOTLVMgr) {
+ delete static_cast<MachOPlatformRuntimeTLVManager *>(MachOTLVMgr);
+}
+
+Error runWrapperFunctionCalls(std::vector<WrapperFunctionCall> WFCs) {
+ for (auto &WFC : WFCs)
+ if (auto Err = WFC.runWithSPSRet<void>())
+ return Err;
+ return Error::success();
+}
+
+} // end anonymous namespace
+
+//------------------------------------------------------------------------------
+// JIT entry points
+//------------------------------------------------------------------------------
+
+ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
+__orc_rt_macho_platform_bootstrap(char *ArgData, size_t ArgSize) {
+ return WrapperFunction<SPSError()>::handle(
+ ArgData, ArgSize,
+ []() { return MachOPlatformRuntimeState::create(); })
+ .release();
+}
+
+ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
+__orc_rt_macho_platform_shutdown(char *ArgData, size_t ArgSize) {
+ return WrapperFunction<SPSError()>::handle(
+ ArgData, ArgSize,
+ []() { return MachOPlatformRuntimeState::destroy(); })
+ .release();
+}
+
+ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
+__orc_rt_macho_register_jitdylib(char *ArgData, size_t ArgSize) {
+ return WrapperFunction<SPSError(SPSString, SPSExecutorAddr)>::handle(
+ ArgData, ArgSize,
+ [](std::string &Name, ExecutorAddr HeaderAddr) {
+ return MachOPlatformRuntimeState::get().registerJITDylib(
+ std::move(Name), HeaderAddr.toPtr<void *>());
+ })
+ .release();
+}
+
+ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
+__orc_rt_macho_deregister_jitdylib(char *ArgData, size_t ArgSize) {
+ return WrapperFunction<SPSError(SPSExecutorAddr)>::handle(
+ ArgData, ArgSize,
+ [](ExecutorAddr HeaderAddr) {
+ return MachOPlatformRuntimeState::get().deregisterJITDylib(
+ HeaderAddr.toPtr<void *>());
+ })
+ .release();
+}
+
+ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
+__orc_rt_macho_register_object_platform_sections(char *ArgData,
+ size_t ArgSize) {
+ return WrapperFunction<SPSError(SPSExecutorAddr,
+ SPSOptional<SPSUnwindSectionInfo>,
+ SPSMachOObjectPlatformSectionsMap)>::
+ handle(ArgData, ArgSize,
+ [](ExecutorAddr HeaderAddr, std::optional<UnwindSectionInfo> USI,
+ std::vector<std::pair<std::string_view, ExecutorAddrRange>>
+ &Secs) {
+ return MachOPlatformRuntimeState::get()
+ .registerObjectPlatformSections(HeaderAddr, std::move(USI),
+ std::move(Secs));
+ })
+ .release();
+}
+
+ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
+__orc_rt_macho_register_object_symbol_table(char *ArgData, size_t ArgSize) {
+ using SymtabContainer = std::vector<
+ std::tuple<ExecutorAddr, ExecutorAddr,
+ MachOPlatformRuntimeState::MachOExecutorSymbolFlags>>;
+ return WrapperFunction<SPSError(
+ SPSExecutorAddr, SPSSequence<SPSTuple<SPSExecutorAddr, SPSExecutorAddr,
+ SPSMachOExecutorSymbolFlags>>)>::
+ handle(ArgData, ArgSize,
+ [](ExecutorAddr HeaderAddr, SymtabContainer &Symbols) {
+ return MachOPlatformRuntimeState::get()
+ .registerObjectSymbolTable(HeaderAddr, Symbols);
+ })
+ .release();
+}
+
+ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
+__orc_rt_macho_deregister_object_symbol_table(char *ArgData, size_t ArgSize) {
+ using SymtabContainer = std::vector<
+ std::tuple<ExecutorAddr, ExecutorAddr,
+ MachOPlatformRuntimeState::MachOExecutorSymbolFlags>>;
+ return WrapperFunction<SPSError(
+ SPSExecutorAddr, SPSSequence<SPSTuple<SPSExecutorAddr, SPSExecutorAddr,
+ SPSMachOExecutorSymbolFlags>>)>::
+ handle(ArgData, ArgSize,
+ [](ExecutorAddr HeaderAddr, SymtabContainer &Symbols) {
+ return MachOPlatformRuntimeState::get()
+ .deregisterObjectSymbolTable(HeaderAddr, Symbols);
+ })
+ .release();
+}
+
+ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
+__orc_rt_macho_deregister_object_platform_sections(char *ArgData,
+ size_t ArgSize) {
+ return WrapperFunction<SPSError(SPSExecutorAddr,
+ SPSOptional<SPSUnwindSectionInfo>,
+ SPSMachOObjectPlatformSectionsMap)>::
+ handle(ArgData, ArgSize,
+ [](ExecutorAddr HeaderAddr, std::optional<UnwindSectionInfo> USI,
+ std::vector<std::pair<std::string_view, ExecutorAddrRange>>
+ &Secs) {
+ return MachOPlatformRuntimeState::get()
+ .deregisterObjectPlatformSections(HeaderAddr, std::move(USI),
+ std::move(Secs));
+ })
+ .release();
+}
+
+ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
+__orc_rt_macho_run_wrapper_function_calls(char *ArgData, size_t ArgSize) {
+ return WrapperFunction<SPSError(SPSSequence<SPSWrapperFunctionCall>)>::handle(
+ ArgData, ArgSize, runWrapperFunctionCalls)
+ .release();
+}
+
+//------------------------------------------------------------------------------
+// TLV support
+//------------------------------------------------------------------------------
+
+ORC_RT_INTERFACE void *__orc_rt_macho_tlv_get_addr_impl(TLVDescriptor *D) {
+ auto *TLVMgr = static_cast<MachOPlatformRuntimeTLVManager *>(
+ pthread_getspecific(D->Key));
+ if (!TLVMgr) {
+ TLVMgr = new MachOPlatformRuntimeTLVManager();
+ if (pthread_setspecific(D->Key, TLVMgr)) {
+ __orc_rt_log_error("Call to pthread_setspecific failed");
+ return nullptr;
+ }
+ }
+
+ return TLVMgr->getInstance(
+ reinterpret_cast<char *>(static_cast<uintptr_t>(D->DataAddress)));
+}
+
+ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
+__orc_rt_macho_create_pthread_key(char *ArgData, size_t ArgSize) {
+ return WrapperFunction<SPSExpected<uint64_t>(void)>::handle(
+ ArgData, ArgSize,
+ []() -> Expected<uint64_t> {
+ pthread_key_t Key;
+ if (int Err = pthread_key_create(&Key, destroyMachOTLVMgr)) {
+ __orc_rt_log_error("Call to pthread_key_create failed");
+ return make_error<StringError>(strerror(Err));
+ }
+ return static_cast<uint64_t>(Key);
+ })
+ .release();
+}
+
+//------------------------------------------------------------------------------
+// cxa_atexit support
+//------------------------------------------------------------------------------
+
+int __orc_rt_macho_cxa_atexit(void (*func)(void *), void *arg,
+ void *dso_handle) {
+ return MachOPlatformRuntimeState::get().registerAtExit(func, arg, dso_handle);
+}
+
+void __orc_rt_macho_cxa_finalize(void *dso_handle) {
+ MachOPlatformRuntimeState::get().runAtExits(dso_handle);
+}
+
+//------------------------------------------------------------------------------
+// JIT'd dlfcn alternatives.
+//------------------------------------------------------------------------------
+
+const char *__orc_rt_macho_jit_dlerror() {
+ return MachOPlatformRuntimeState::get().dlerror();
+}
+
+void *__orc_rt_macho_jit_dlopen(const char *path, int mode) {
+ return MachOPlatformRuntimeState::get().dlopen(path, mode);
+}
+
+int __orc_rt_macho_jit_dlclose(void *dso_handle) {
+ return MachOPlatformRuntimeState::get().dlclose(dso_handle);
+}
+
+void *__orc_rt_macho_jit_dlsym(void *dso_handle, const char *symbol) {
+ return MachOPlatformRuntimeState::get().dlsym(dso_handle, symbol);
+}
+
+//------------------------------------------------------------------------------
+// MachO Run Program
+//------------------------------------------------------------------------------
+
+ORC_RT_INTERFACE int64_t __orc_rt_macho_run_program(const char *JITDylibName,
+ const char *EntrySymbolName,
+ int argc, char *argv[]) {
+ using MainTy = int (*)(int, char *[]);
+
+ void *H = __orc_rt_macho_jit_dlopen(JITDylibName,
+ __orc_rt::macho::ORC_RT_RTLD_LAZY);
+ if (!H) {
+ __orc_rt_log_error(__orc_rt_macho_jit_dlerror());
+ return -1;
+ }
+
+ auto *Main =
+ reinterpret_cast<MainTy>(__orc_rt_macho_jit_dlsym(H, EntrySymbolName));
+
+ if (!Main) {
+ __orc_rt_log_error(__orc_rt_macho_jit_dlerror());
+ return -1;
+ }
+
+ int Result = Main(argc, argv);
+
+ if (__orc_rt_macho_jit_dlclose(H) == -1)
+ __orc_rt_log_error(__orc_rt_macho_jit_dlerror());
+
+ return Result;
+}
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/macho_platform.h b/contrib/llvm-project/compiler-rt/lib/orc/macho_platform.h
new file mode 100644
index 000000000000..3b2242ab27ce
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/macho_platform.h
@@ -0,0 +1,44 @@
+//===- macho_platform.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// ORC Runtime support for Darwin dynamic loading features.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_MACHO_PLATFORM_H
+#define ORC_RT_MACHO_PLATFORM_H
+
+#include "common.h"
+#include "executor_address.h"
+
+// Atexit functions.
+ORC_RT_INTERFACE int __orc_rt_macho_cxa_atexit(void (*func)(void *), void *arg,
+ void *dso_handle);
+ORC_RT_INTERFACE void __orc_rt_macho_cxa_finalize(void *dso_handle);
+
+// dlfcn functions.
+ORC_RT_INTERFACE const char *__orc_rt_macho_jit_dlerror();
+ORC_RT_INTERFACE void *__orc_rt_macho_jit_dlopen(const char *path, int mode);
+ORC_RT_INTERFACE int __orc_rt_macho_jit_dlclose(void *dso_handle);
+ORC_RT_INTERFACE void *__orc_rt_macho_jit_dlsym(void *dso_handle,
+ const char *symbol);
+
+namespace __orc_rt {
+namespace macho {
+
+enum dlopen_mode : int {
+ ORC_RT_RTLD_LAZY = 0x1,
+ ORC_RT_RTLD_NOW = 0x2,
+ ORC_RT_RTLD_LOCAL = 0x4,
+ ORC_RT_RTLD_GLOBAL = 0x8
+};
+
+} // end namespace macho
+} // end namespace __orc_rt
+
+#endif // ORC_RT_MACHO_PLATFORM_H
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/macho_tlv.arm64.S b/contrib/llvm-project/compiler-rt/lib/orc/macho_tlv.arm64.S
new file mode 100644
index 000000000000..f6eb9fc4da39
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/macho_tlv.arm64.S
@@ -0,0 +1,92 @@
+//===-- macho_tlv.arm64.s ---------------------------------------*- ASM -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime support library.
+//
+//===----------------------------------------------------------------------===//
+
+// The content of this file is arm64-only
+#if defined(__arm64__) || defined(__aarch64__)
+
+#define REGISTER_SAVE_SPACE_SIZE 32 * 24
+
+ .text
+
+ // returns address of TLV in x0, all other registers preserved
+ .globl ___orc_rt_macho_tlv_get_addr
+___orc_rt_macho_tlv_get_addr:
+ sub sp, sp, #REGISTER_SAVE_SPACE_SIZE
+ stp x29, x30, [sp, #16 * 1]
+ stp x27, x28, [sp, #16 * 2]
+ stp x25, x26, [sp, #16 * 3]
+ stp x23, x24, [sp, #16 * 4]
+ stp x21, x22, [sp, #16 * 5]
+ stp x19, x20, [sp, #16 * 6]
+ stp x17, x18, [sp, #16 * 7]
+ stp x15, x16, [sp, #16 * 8]
+ stp x13, x14, [sp, #16 * 9]
+ stp x11, x12, [sp, #16 * 10]
+ stp x9, x10, [sp, #16 * 11]
+ stp x7, x8, [sp, #16 * 12]
+ stp x5, x6, [sp, #16 * 13]
+ stp x3, x4, [sp, #16 * 14]
+ stp x1, x2, [sp, #16 * 15]
+ stp q30, q31, [sp, #32 * 8]
+ stp q28, q29, [sp, #32 * 9]
+ stp q26, q27, [sp, #32 * 10]
+ stp q24, q25, [sp, #32 * 11]
+ stp q22, q23, [sp, #32 * 12]
+ stp q20, q21, [sp, #32 * 13]
+ stp q18, q19, [sp, #32 * 14]
+ stp q16, q17, [sp, #32 * 15]
+ stp q14, q15, [sp, #32 * 16]
+ stp q12, q13, [sp, #32 * 17]
+ stp q10, q11, [sp, #32 * 18]
+ stp q8, q9, [sp, #32 * 19]
+ stp q6, q7, [sp, #32 * 20]
+ stp q4, q5, [sp, #32 * 21]
+ stp q2, q3, [sp, #32 * 22]
+ stp q0, q1, [sp, #32 * 23]
+
+ bl ___orc_rt_macho_tlv_get_addr_impl
+
+ ldp q0, q1, [sp, #32 * 23]
+ ldp q2, q3, [sp, #32 * 22]
+ ldp q4, q5, [sp, #32 * 21]
+ ldp q6, q7, [sp, #32 * 20]
+ ldp q8, q9, [sp, #32 * 19]
+ ldp q10, q11, [sp, #32 * 18]
+ ldp q12, q13, [sp, #32 * 17]
+ ldp q14, q15, [sp, #32 * 16]
+ ldp q16, q17, [sp, #32 * 15]
+ ldp q18, q19, [sp, #32 * 14]
+ ldp q20, q21, [sp, #32 * 13]
+ ldp q22, q23, [sp, #32 * 12]
+ ldp q24, q25, [sp, #32 * 11]
+ ldp q26, q27, [sp, #32 * 10]
+ ldp q28, q29, [sp, #32 * 9]
+ ldp q30, q31, [sp, #32 * 8]
+ ldp x1, x2, [sp, #16 * 15]
+ ldp x3, x4, [sp, #16 * 14]
+ ldp x5, x6, [sp, #16 * 13]
+ ldp x7, x8, [sp, #16 * 12]
+ ldp x9, x10, [sp, #16 * 11]
+ ldp x11, x12, [sp, #16 * 10]
+ ldp x13, x14, [sp, #16 * 9]
+ ldp x15, x16, [sp, #16 * 8]
+ ldp x17, x18, [sp, #16 * 7]
+ ldp x19, x20, [sp, #16 * 6]
+ ldp x21, x22, [sp, #16 * 5]
+ ldp x23, x24, [sp, #16 * 4]
+ ldp x25, x26, [sp, #16 * 3]
+ ldp x27, x28, [sp, #16 * 2]
+ ldp x29, x30, [sp, #16 * 1]
+ add sp, sp, #REGISTER_SAVE_SPACE_SIZE
+ ret
+
+#endif // defined(__arm64__) || defined(__aarch64__)
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/macho_tlv.x86-64.S b/contrib/llvm-project/compiler-rt/lib/orc/macho_tlv.x86-64.S
new file mode 100644
index 000000000000..e3daf23e3029
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/macho_tlv.x86-64.S
@@ -0,0 +1,73 @@
+//===-- orc_rt_macho_tlv.x86-64.s -------------------------------*- ASM -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime support library.
+//
+//===----------------------------------------------------------------------===//
+
+// The content of this file is x86_64-only
+#if defined(__x86_64__)
+
+#define REGISTER_SAVE_SPACE_SIZE 512
+
+ .text
+
+ // returns address of TLV in %rax, all other registers preserved
+ .globl ___orc_rt_macho_tlv_get_addr
+___orc_rt_macho_tlv_get_addr:
+ pushq %rbp
+ movq %rsp, %rbp
+ subq $REGISTER_SAVE_SPACE_SIZE, %rsp
+ movq %rbx, -8(%rbp)
+ movq %rcx, -16(%rbp)
+ movq %rdx, -24(%rbp)
+ movq %rsi, -32(%rbp)
+ movq %rdi, -40(%rbp)
+ movq %r8, -48(%rbp)
+ movq %r9, -56(%rbp)
+ movq %r10, -64(%rbp)
+ movq %r11, -72(%rbp)
+ movq %r12, -80(%rbp)
+ movq %r13, -88(%rbp)
+ movq %r14, -96(%rbp)
+ movq %r15, -104(%rbp)
+ movdqa %xmm0, -128(%rbp)
+ movdqa %xmm1, -144(%rbp)
+ movdqa %xmm2, -160(%rbp)
+ movdqa %xmm3, -176(%rbp)
+ movdqa %xmm4, -192(%rbp)
+ movdqa %xmm5, -208(%rbp)
+ movdqa %xmm6, -224(%rbp)
+ movdqa %xmm7, -240(%rbp)
+ call ___orc_rt_macho_tlv_get_addr_impl
+ movq -8(%rbp), %rbx
+ movq -16(%rbp), %rcx
+ movq -24(%rbp), %rdx
+ movq -32(%rbp), %rsi
+ movq -40(%rbp), %rdi
+ movq -48(%rbp), %r8
+ movq -56(%rbp), %r9
+ movq -64(%rbp), %r10
+ movq -72(%rbp), %r11
+ movq -80(%rbp), %r12
+ movq -88(%rbp), %r13
+ movq -96(%rbp), %r14
+ movq -104(%rbp), %r15
+ movdqa -128(%rbp), %xmm0
+ movdqa -144(%rbp), %xmm1
+ movdqa -160(%rbp), %xmm2
+ movdqa -176(%rbp), %xmm3
+ movdqa -192(%rbp), %xmm4
+ movdqa -208(%rbp), %xmm5
+ movdqa -224(%rbp), %xmm6
+ movdqa -240(%rbp), %xmm7
+ addq $REGISTER_SAVE_SPACE_SIZE, %rsp
+ popq %rbp
+ ret
+
+#endif // defined(__x86_64__)
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/run_program_wrapper.cpp b/contrib/llvm-project/compiler-rt/lib/orc/run_program_wrapper.cpp
new file mode 100644
index 000000000000..24a7b4fc3cbe
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/run_program_wrapper.cpp
@@ -0,0 +1,51 @@
+//===- run_program_wrapper.cpp --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime support library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "adt.h"
+#include "common.h"
+#include "wrapper_function_utils.h"
+
+#include <vector>
+
+using namespace __orc_rt;
+
+extern "C" int64_t __orc_rt_run_program(const char *JITDylibName,
+ const char *EntrySymbolName, int argc,
+ char *argv[]);
+
+ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
+__orc_rt_run_program_wrapper(const char *ArgData, size_t ArgSize) {
+ return WrapperFunction<int64_t(SPSString, SPSString,
+ SPSSequence<SPSString>)>::
+ handle(ArgData, ArgSize,
+ [](const std::string &JITDylibName,
+ const std::string &EntrySymbolName,
+ const std::vector<std::string_view> &Args) {
+ std::vector<std::unique_ptr<char[]>> ArgVStorage;
+ ArgVStorage.reserve(Args.size());
+ for (auto &Arg : Args) {
+ ArgVStorage.push_back(
+ std::make_unique<char[]>(Arg.size() + 1));
+ memcpy(ArgVStorage.back().get(), Arg.data(), Arg.size());
+ ArgVStorage.back()[Arg.size()] = '\0';
+ }
+ std::vector<char *> ArgV;
+ ArgV.reserve(ArgVStorage.size() + 1);
+ for (auto &ArgStorage : ArgVStorage)
+ ArgV.push_back(ArgStorage.get());
+ ArgV.push_back(nullptr);
+ return __orc_rt_run_program(JITDylibName.c_str(),
+ EntrySymbolName.c_str(),
+ ArgV.size() - 1, ArgV.data());
+ })
+ .release();
+}
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/simple_packed_serialization.h b/contrib/llvm-project/compiler-rt/lib/orc/simple_packed_serialization.h
new file mode 100644
index 000000000000..488d2407ddd4
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/simple_packed_serialization.h
@@ -0,0 +1,689 @@
+//===--- simple_packed_serialization.h - simple serialization ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime support library.
+//
+// The behavior of the utilities in this header must be synchronized with the
+// behavior of the utilities in
+// llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h.
+//
+// The Simple Packed Serialization (SPS) utilities are used to generate
+// argument and return buffers for wrapper functions using the following
+// serialization scheme:
+//
+// Primitives:
+// bool, char, int8_t, uint8_t -- Two's complement 8-bit (0=false, 1=true)
+// int16_t, uint16_t -- Two's complement 16-bit little endian
+// int32_t, uint32_t -- Two's complement 32-bit little endian
+// int64_t, int64_t -- Two's complement 64-bit little endian
+//
+// Sequence<T>:
+// Serialized as the sequence length (as a uint64_t) followed by the
+// serialization of each of the elements without padding.
+//
+// Tuple<T1, ..., TN>:
+// Serialized as each of the element types from T1 to TN without padding.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_SIMPLE_PACKED_SERIALIZATION_H
+#define ORC_RT_SIMPLE_PACKED_SERIALIZATION_H
+
+#include "adt.h"
+#include "endianness.h"
+#include "error.h"
+#include "stl_extras.h"
+
+#include <optional>
+#include <string>
+#include <string_view>
+#include <tuple>
+#include <type_traits>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+namespace __orc_rt {
+
+/// Output char buffer with overflow check.
+class SPSOutputBuffer {
+public:
+ SPSOutputBuffer(char *Buffer, size_t Remaining)
+ : Buffer(Buffer), Remaining(Remaining) {}
+ bool write(const char *Data, size_t Size) {
+ if (Size > Remaining)
+ return false;
+ memcpy(Buffer, Data, Size);
+ Buffer += Size;
+ Remaining -= Size;
+ return true;
+ }
+
+private:
+ char *Buffer = nullptr;
+ size_t Remaining = 0;
+};
+
+/// Input char buffer with underflow check.
+class SPSInputBuffer {
+public:
+ SPSInputBuffer() = default;
+ SPSInputBuffer(const char *Buffer, size_t Remaining)
+ : Buffer(Buffer), Remaining(Remaining) {}
+ bool read(char *Data, size_t Size) {
+ if (Size > Remaining)
+ return false;
+ memcpy(Data, Buffer, Size);
+ Buffer += Size;
+ Remaining -= Size;
+ return true;
+ }
+
+ const char *data() const { return Buffer; }
+ bool skip(size_t Size) {
+ if (Size > Remaining)
+ return false;
+ Buffer += Size;
+ Remaining -= Size;
+ return true;
+ }
+
+private:
+ const char *Buffer = nullptr;
+ size_t Remaining = 0;
+};
+
+/// Specialize to describe how to serialize/deserialize to/from the given
+/// concrete type.
+template <typename SPSTagT, typename ConcreteT, typename _ = void>
+class SPSSerializationTraits;
+
+/// A utility class for serializing to a blob from a variadic list.
+template <typename... ArgTs> class SPSArgList;
+
+// Empty list specialization for SPSArgList.
+template <> class SPSArgList<> {
+public:
+ static size_t size() { return 0; }
+
+ static bool serialize(SPSOutputBuffer &OB) { return true; }
+ static bool deserialize(SPSInputBuffer &IB) { return true; }
+};
+
+// Non-empty list specialization for SPSArgList.
+template <typename SPSTagT, typename... SPSTagTs>
+class SPSArgList<SPSTagT, SPSTagTs...> {
+public:
+ template <typename ArgT, typename... ArgTs>
+ static size_t size(const ArgT &Arg, const ArgTs &...Args) {
+ return SPSSerializationTraits<SPSTagT, ArgT>::size(Arg) +
+ SPSArgList<SPSTagTs...>::size(Args...);
+ }
+
+ template <typename ArgT, typename... ArgTs>
+ static bool serialize(SPSOutputBuffer &OB, const ArgT &Arg,
+ const ArgTs &...Args) {
+ return SPSSerializationTraits<SPSTagT, ArgT>::serialize(OB, Arg) &&
+ SPSArgList<SPSTagTs...>::serialize(OB, Args...);
+ }
+
+ template <typename ArgT, typename... ArgTs>
+ static bool deserialize(SPSInputBuffer &IB, ArgT &Arg, ArgTs &...Args) {
+ return SPSSerializationTraits<SPSTagT, ArgT>::deserialize(IB, Arg) &&
+ SPSArgList<SPSTagTs...>::deserialize(IB, Args...);
+ }
+};
+
+/// SPS serialization for integral types, bool, and char.
+template <typename SPSTagT>
+class SPSSerializationTraits<
+ SPSTagT, SPSTagT,
+ std::enable_if_t<std::is_same<SPSTagT, bool>::value ||
+ std::is_same<SPSTagT, char>::value ||
+ std::is_same<SPSTagT, int8_t>::value ||
+ std::is_same<SPSTagT, int16_t>::value ||
+ std::is_same<SPSTagT, int32_t>::value ||
+ std::is_same<SPSTagT, int64_t>::value ||
+ std::is_same<SPSTagT, uint8_t>::value ||
+ std::is_same<SPSTagT, uint16_t>::value ||
+ std::is_same<SPSTagT, uint32_t>::value ||
+ std::is_same<SPSTagT, uint64_t>::value>> {
+public:
+ static size_t size(const SPSTagT &Value) { return sizeof(SPSTagT); }
+
+ static bool serialize(SPSOutputBuffer &OB, const SPSTagT &Value) {
+ SPSTagT Tmp = Value;
+ if (IsBigEndianHost)
+ swapByteOrder(Tmp);
+ return OB.write(reinterpret_cast<const char *>(&Tmp), sizeof(Tmp));
+ }
+
+ static bool deserialize(SPSInputBuffer &IB, SPSTagT &Value) {
+ SPSTagT Tmp;
+ if (!IB.read(reinterpret_cast<char *>(&Tmp), sizeof(Tmp)))
+ return false;
+ if (IsBigEndianHost)
+ swapByteOrder(Tmp);
+ Value = Tmp;
+ return true;
+ }
+};
+
+/// Any empty placeholder suitable as a substitute for void when deserializing
+class SPSEmpty {};
+
+/// Represents an address in the executor.
+class SPSExecutorAddr {};
+
+/// SPS tag type for tuples.
+///
+/// A blob tuple should be serialized by serializing each of the elements in
+/// sequence.
+template <typename... SPSTagTs> class SPSTuple {
+public:
+ /// Convenience typedef of the corresponding arg list.
+ typedef SPSArgList<SPSTagTs...> AsArgList;
+};
+
+/// SPS tag type for optionals.
+///
+/// SPSOptionals should be serialized as a bool with true indicating that an
+/// SPSTagT value is present, and false indicating that there is no value.
+/// If the boolean is true then the serialized SPSTagT will follow immediately
+/// after it.
+template <typename SPSTagT> class SPSOptional {};
+
+/// SPS tag type for sequences.
+///
+/// SPSSequences should be serialized as a uint64_t sequence length,
+/// followed by the serialization of each of the elements.
+template <typename SPSElementTagT> class SPSSequence;
+
+/// SPS tag type for strings, which are equivalent to sequences of chars.
+using SPSString = SPSSequence<char>;
+
+/// SPS tag type for maps.
+///
+/// SPS maps are just sequences of (Key, Value) tuples.
+template <typename SPSTagT1, typename SPSTagT2>
+using SPSMap = SPSSequence<SPSTuple<SPSTagT1, SPSTagT2>>;
+
+/// Serialization for SPSEmpty type.
+template <> class SPSSerializationTraits<SPSEmpty, SPSEmpty> {
+public:
+ static size_t size(const SPSEmpty &EP) { return 0; }
+ static bool serialize(SPSOutputBuffer &OB, const SPSEmpty &BE) {
+ return true;
+ }
+ static bool deserialize(SPSInputBuffer &IB, SPSEmpty &BE) { return true; }
+};
+
+/// Specialize this to implement 'trivial' sequence serialization for
+/// a concrete sequence type.
+///
+/// Trivial sequence serialization uses the sequence's 'size' member to get the
+/// length of the sequence, and uses a range-based for loop to iterate over the
+/// elements.
+///
+/// Specializing this template class means that you do not need to provide a
+/// specialization of SPSSerializationTraits for your type.
+template <typename SPSElementTagT, typename ConcreteSequenceT>
+class TrivialSPSSequenceSerialization {
+public:
+ static constexpr bool available = false;
+};
+
+/// Specialize this to implement 'trivial' sequence deserialization for
+/// a concrete sequence type.
+///
+/// Trivial deserialization calls a static 'reserve(SequenceT&)' method on your
+/// specialization (you must implement this) to reserve space, and then calls
+/// a static 'append(SequenceT&, ElementT&) method to append each of the
+/// deserialized elements.
+///
+/// Specializing this template class means that you do not need to provide a
+/// specialization of SPSSerializationTraits for your type.
+template <typename SPSElementTagT, typename ConcreteSequenceT>
+class TrivialSPSSequenceDeserialization {
+public:
+ static constexpr bool available = false;
+};
+
+/// Trivial std::string -> SPSSequence<char> serialization.
+template <> class TrivialSPSSequenceSerialization<char, std::string> {
+public:
+ static constexpr bool available = true;
+};
+
+/// Trivial SPSSequence<char> -> std::string deserialization.
+template <> class TrivialSPSSequenceDeserialization<char, std::string> {
+public:
+ static constexpr bool available = true;
+
+ using element_type = char;
+
+ static void reserve(std::string &S, uint64_t Size) { S.reserve(Size); }
+ static bool append(std::string &S, char C) {
+ S.push_back(C);
+ return true;
+ }
+};
+
+/// Trivial std::vector<T> -> SPSSequence<SPSElementTagT> serialization.
+template <typename SPSElementTagT, typename T>
+class TrivialSPSSequenceSerialization<SPSElementTagT, std::vector<T>> {
+public:
+ static constexpr bool available = true;
+};
+
+/// Trivial span<T> -> SPSSequence<SPSElementTagT> serialization.
+template <typename SPSElementTagT, typename T>
+class TrivialSPSSequenceSerialization<SPSElementTagT, span<T>> {
+public:
+ static constexpr bool available = true;
+};
+
+/// Trivial SPSSequence<SPSElementTagT> -> std::vector<T> deserialization.
+template <typename SPSElementTagT, typename T>
+class TrivialSPSSequenceDeserialization<SPSElementTagT, std::vector<T>> {
+public:
+ static constexpr bool available = true;
+
+ using element_type = typename std::vector<T>::value_type;
+
+ static void reserve(std::vector<T> &V, uint64_t Size) { V.reserve(Size); }
+ static bool append(std::vector<T> &V, T E) {
+ V.push_back(std::move(E));
+ return true;
+ }
+};
+
+/// Trivial std::unordered_map<K, V> -> SPSSequence<SPSTuple<SPSKey, SPSValue>>
+/// serialization.
+template <typename SPSKeyTagT, typename SPSValueTagT, typename K, typename V>
+class TrivialSPSSequenceSerialization<SPSTuple<SPSKeyTagT, SPSValueTagT>,
+ std::unordered_map<K, V>> {
+public:
+ static constexpr bool available = true;
+};
+
+/// Trivial SPSSequence<SPSTuple<SPSKey, SPSValue>> -> std::unordered_map<K, V>
+/// deserialization.
+template <typename SPSKeyTagT, typename SPSValueTagT, typename K, typename V>
+class TrivialSPSSequenceDeserialization<SPSTuple<SPSKeyTagT, SPSValueTagT>,
+ std::unordered_map<K, V>> {
+public:
+ static constexpr bool available = true;
+
+ using element_type = std::pair<K, V>;
+
+ static void reserve(std::unordered_map<K, V> &M, uint64_t Size) {
+ M.reserve(Size);
+ }
+ static bool append(std::unordered_map<K, V> &M, element_type E) {
+ return M.insert(std::move(E)).second;
+ }
+};
+
+/// 'Trivial' sequence serialization: Sequence is serialized as a uint64_t size
+/// followed by a for-earch loop over the elements of the sequence to serialize
+/// each of them.
+template <typename SPSElementTagT, typename SequenceT>
+class SPSSerializationTraits<SPSSequence<SPSElementTagT>, SequenceT,
+ std::enable_if_t<TrivialSPSSequenceSerialization<
+ SPSElementTagT, SequenceT>::available>> {
+public:
+ static size_t size(const SequenceT &S) {
+ size_t Size = SPSArgList<uint64_t>::size(static_cast<uint64_t>(S.size()));
+ for (const auto &E : S)
+ Size += SPSArgList<SPSElementTagT>::size(E);
+ return Size;
+ }
+
+ static bool serialize(SPSOutputBuffer &OB, const SequenceT &S) {
+ if (!SPSArgList<uint64_t>::serialize(OB, static_cast<uint64_t>(S.size())))
+ return false;
+ for (const auto &E : S)
+ if (!SPSArgList<SPSElementTagT>::serialize(OB, E))
+ return false;
+ return true;
+ }
+
+ static bool deserialize(SPSInputBuffer &IB, SequenceT &S) {
+ using TBSD = TrivialSPSSequenceDeserialization<SPSElementTagT, SequenceT>;
+ uint64_t Size;
+ if (!SPSArgList<uint64_t>::deserialize(IB, Size))
+ return false;
+ TBSD::reserve(S, Size);
+ for (size_t I = 0; I != Size; ++I) {
+ typename TBSD::element_type E;
+ if (!SPSArgList<SPSElementTagT>::deserialize(IB, E))
+ return false;
+ if (!TBSD::append(S, std::move(E)))
+ return false;
+ }
+ return true;
+ }
+};
+
+/// Trivial serialization / deserialization for span<char>
+template <> class SPSSerializationTraits<SPSSequence<char>, span<const char>> {
+public:
+ static size_t size(const span<const char> &S) {
+ return SPSArgList<uint64_t>::size(static_cast<uint64_t>(S.size())) +
+ S.size();
+ }
+ static bool serialize(SPSOutputBuffer &OB, const span<const char> &S) {
+ if (!SPSArgList<uint64_t>::serialize(OB, static_cast<uint64_t>(S.size())))
+ return false;
+ return OB.write(S.data(), S.size());
+ }
+ static bool deserialize(SPSInputBuffer &IB, span<const char> &S) {
+ uint64_t Size;
+ if (!SPSArgList<uint64_t>::deserialize(IB, Size))
+ return false;
+ S = span<const char>(IB.data(), Size);
+ return IB.skip(Size);
+ }
+};
+
+/// SPSTuple serialization for std::tuple.
+template <typename... SPSTagTs, typename... Ts>
+class SPSSerializationTraits<SPSTuple<SPSTagTs...>, std::tuple<Ts...>> {
+private:
+ using TupleArgList = typename SPSTuple<SPSTagTs...>::AsArgList;
+ using ArgIndices = std::make_index_sequence<sizeof...(Ts)>;
+
+ template <std::size_t... I>
+ static size_t size(const std::tuple<Ts...> &T, std::index_sequence<I...>) {
+ return TupleArgList::size(std::get<I>(T)...);
+ }
+
+ template <std::size_t... I>
+ static bool serialize(SPSOutputBuffer &OB, const std::tuple<Ts...> &T,
+ std::index_sequence<I...>) {
+ return TupleArgList::serialize(OB, std::get<I>(T)...);
+ }
+
+ template <std::size_t... I>
+ static bool deserialize(SPSInputBuffer &IB, std::tuple<Ts...> &T,
+ std::index_sequence<I...>) {
+ return TupleArgList::deserialize(IB, std::get<I>(T)...);
+ }
+
+public:
+ static size_t size(const std::tuple<Ts...> &T) {
+ return size(T, ArgIndices{});
+ }
+
+ static bool serialize(SPSOutputBuffer &OB, const std::tuple<Ts...> &T) {
+ return serialize(OB, T, ArgIndices{});
+ }
+
+ static bool deserialize(SPSInputBuffer &IB, std::tuple<Ts...> &T) {
+ return deserialize(IB, T, ArgIndices{});
+ }
+};
+
+/// SPSTuple serialization for std::pair.
+template <typename SPSTagT1, typename SPSTagT2, typename T1, typename T2>
+class SPSSerializationTraits<SPSTuple<SPSTagT1, SPSTagT2>, std::pair<T1, T2>> {
+public:
+ static size_t size(const std::pair<T1, T2> &P) {
+ return SPSArgList<SPSTagT1>::size(P.first) +
+ SPSArgList<SPSTagT2>::size(P.second);
+ }
+
+ static bool serialize(SPSOutputBuffer &OB, const std::pair<T1, T2> &P) {
+ return SPSArgList<SPSTagT1>::serialize(OB, P.first) &&
+ SPSArgList<SPSTagT2>::serialize(OB, P.second);
+ }
+
+ static bool deserialize(SPSInputBuffer &IB, std::pair<T1, T2> &P) {
+ return SPSArgList<SPSTagT1>::deserialize(IB, P.first) &&
+ SPSArgList<SPSTagT2>::deserialize(IB, P.second);
+ }
+};
+
+/// SPSOptional serialization for std::optional.
+template <typename SPSTagT, typename T>
+class SPSSerializationTraits<SPSOptional<SPSTagT>, std::optional<T>> {
+public:
+ static size_t size(const std::optional<T> &Value) {
+ size_t Size = SPSArgList<bool>::size(!!Value);
+ if (Value)
+ Size += SPSArgList<SPSTagT>::size(*Value);
+ return Size;
+ }
+
+ static bool serialize(SPSOutputBuffer &OB, const std::optional<T> &Value) {
+ if (!SPSArgList<bool>::serialize(OB, !!Value))
+ return false;
+ if (Value)
+ return SPSArgList<SPSTagT>::serialize(OB, *Value);
+ return true;
+ }
+
+ static bool deserialize(SPSInputBuffer &IB, std::optional<T> &Value) {
+ bool HasValue;
+ if (!SPSArgList<bool>::deserialize(IB, HasValue))
+ return false;
+ if (HasValue) {
+ Value = T();
+ return SPSArgList<SPSTagT>::deserialize(IB, *Value);
+ } else
+ Value = std::optional<T>();
+ return true;
+ }
+};
+
+/// Serialization for string_views.
+///
+/// Serialization is as for regular strings. Deserialization points directly
+/// into the blob.
+template <> class SPSSerializationTraits<SPSString, std::string_view> {
+public:
+ static size_t size(const std::string_view &S) {
+ return SPSArgList<uint64_t>::size(static_cast<uint64_t>(S.size())) +
+ S.size();
+ }
+
+ static bool serialize(SPSOutputBuffer &OB, const std::string_view &S) {
+ if (!SPSArgList<uint64_t>::serialize(OB, static_cast<uint64_t>(S.size())))
+ return false;
+ return OB.write(S.data(), S.size());
+ }
+
+ static bool deserialize(SPSInputBuffer &IB, std::string_view &S) {
+ const char *Data = nullptr;
+ uint64_t Size;
+ if (!SPSArgList<uint64_t>::deserialize(IB, Size))
+ return false;
+ if (Size > std::numeric_limits<size_t>::max())
+ return false;
+ Data = IB.data();
+ if (!IB.skip(Size))
+ return false;
+ S = {Data, static_cast<size_t>(Size)};
+ return true;
+ }
+};
+
+/// SPS tag type for errors.
+class SPSError;
+
+/// SPS tag type for expecteds, which are either a T or a string representing
+/// an error.
+template <typename SPSTagT> class SPSExpected;
+
+namespace detail {
+
+/// Helper type for serializing Errors.
+///
+/// llvm::Errors are move-only, and not inspectable except by consuming them.
+/// This makes them unsuitable for direct serialization via
+/// SPSSerializationTraits, which needs to inspect values twice (once to
+/// determine the amount of space to reserve, and then again to serialize).
+///
+/// The SPSSerializableError type is a helper that can be
+/// constructed from an llvm::Error, but inspected more than once.
+struct SPSSerializableError {
+ bool HasError = false;
+ std::string ErrMsg;
+};
+
+/// Helper type for serializing Expected<T>s.
+///
+/// See SPSSerializableError for more details.
+///
+// FIXME: Use std::variant for storage once we have c++17.
+template <typename T> struct SPSSerializableExpected {
+ bool HasValue = false;
+ T Value{};
+ std::string ErrMsg;
+};
+
+inline SPSSerializableError toSPSSerializable(Error Err) {
+ if (Err)
+ return {true, toString(std::move(Err))};
+ return {false, {}};
+}
+
+inline Error fromSPSSerializable(SPSSerializableError BSE) {
+ if (BSE.HasError)
+ return make_error<StringError>(BSE.ErrMsg);
+ return Error::success();
+}
+
+template <typename T>
+SPSSerializableExpected<T> toSPSSerializable(Expected<T> E) {
+ if (E)
+ return {true, std::move(*E), {}};
+ else
+ return {false, {}, toString(E.takeError())};
+}
+
+template <typename T>
+Expected<T> fromSPSSerializable(SPSSerializableExpected<T> BSE) {
+ if (BSE.HasValue)
+ return std::move(BSE.Value);
+ else
+ return make_error<StringError>(BSE.ErrMsg);
+}
+
+} // end namespace detail
+
+/// Serialize to a SPSError from a detail::SPSSerializableError.
+template <>
+class SPSSerializationTraits<SPSError, detail::SPSSerializableError> {
+public:
+ static size_t size(const detail::SPSSerializableError &BSE) {
+ size_t Size = SPSArgList<bool>::size(BSE.HasError);
+ if (BSE.HasError)
+ Size += SPSArgList<SPSString>::size(BSE.ErrMsg);
+ return Size;
+ }
+
+ static bool serialize(SPSOutputBuffer &OB,
+ const detail::SPSSerializableError &BSE) {
+ if (!SPSArgList<bool>::serialize(OB, BSE.HasError))
+ return false;
+ if (BSE.HasError)
+ if (!SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg))
+ return false;
+ return true;
+ }
+
+ static bool deserialize(SPSInputBuffer &IB,
+ detail::SPSSerializableError &BSE) {
+ if (!SPSArgList<bool>::deserialize(IB, BSE.HasError))
+ return false;
+
+ if (!BSE.HasError)
+ return true;
+
+ return SPSArgList<SPSString>::deserialize(IB, BSE.ErrMsg);
+ }
+};
+
+/// Serialize to a SPSExpected<SPSTagT> from a
+/// detail::SPSSerializableExpected<T>.
+template <typename SPSTagT, typename T>
+class SPSSerializationTraits<SPSExpected<SPSTagT>,
+ detail::SPSSerializableExpected<T>> {
+public:
+ static size_t size(const detail::SPSSerializableExpected<T> &BSE) {
+ size_t Size = SPSArgList<bool>::size(BSE.HasValue);
+ if (BSE.HasValue)
+ Size += SPSArgList<SPSTagT>::size(BSE.Value);
+ else
+ Size += SPSArgList<SPSString>::size(BSE.ErrMsg);
+ return Size;
+ }
+
+ static bool serialize(SPSOutputBuffer &OB,
+ const detail::SPSSerializableExpected<T> &BSE) {
+ if (!SPSArgList<bool>::serialize(OB, BSE.HasValue))
+ return false;
+
+ if (BSE.HasValue)
+ return SPSArgList<SPSTagT>::serialize(OB, BSE.Value);
+
+ return SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg);
+ }
+
+ static bool deserialize(SPSInputBuffer &IB,
+ detail::SPSSerializableExpected<T> &BSE) {
+ if (!SPSArgList<bool>::deserialize(IB, BSE.HasValue))
+ return false;
+
+ if (BSE.HasValue)
+ return SPSArgList<SPSTagT>::deserialize(IB, BSE.Value);
+
+ return SPSArgList<SPSString>::deserialize(IB, BSE.ErrMsg);
+ }
+};
+
+/// Serialize to a SPSExpected<SPSTagT> from a detail::SPSSerializableError.
+template <typename SPSTagT>
+class SPSSerializationTraits<SPSExpected<SPSTagT>,
+ detail::SPSSerializableError> {
+public:
+ static size_t size(const detail::SPSSerializableError &BSE) {
+ assert(BSE.HasError && "Cannot serialize expected from a success value");
+ return SPSArgList<bool>::size(false) +
+ SPSArgList<SPSString>::size(BSE.ErrMsg);
+ }
+
+ static bool serialize(SPSOutputBuffer &OB,
+ const detail::SPSSerializableError &BSE) {
+ assert(BSE.HasError && "Cannot serialize expected from a success value");
+ if (!SPSArgList<bool>::serialize(OB, false))
+ return false;
+ return SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg);
+ }
+};
+
+/// Serialize to a SPSExpected<SPSTagT> from a T.
+template <typename SPSTagT, typename T>
+class SPSSerializationTraits<SPSExpected<SPSTagT>, T> {
+public:
+ static size_t size(const T &Value) {
+ return SPSArgList<bool>::size(true) + SPSArgList<SPSTagT>::size(Value);
+ }
+
+ static bool serialize(SPSOutputBuffer &OB, const T &Value) {
+ if (!SPSArgList<bool>::serialize(OB, true))
+ return false;
+ return SPSArgList<SPSTagT>::serialize(Value);
+ }
+};
+
+} // end namespace __orc_rt
+
+#endif // ORC_RT_SIMPLE_PACKED_SERIALIZATION_H
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/stl_extras.h b/contrib/llvm-project/compiler-rt/lib/orc/stl_extras.h
new file mode 100644
index 000000000000..80a6cd13ac28
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/stl_extras.h
@@ -0,0 +1,45 @@
+//===-------- stl_extras.h - Useful STL related functions-------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime support library.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_STL_EXTRAS_H
+#define ORC_RT_STL_EXTRAS_H
+
+#include <cstdint>
+#include <utility>
+#include <tuple>
+
+namespace __orc_rt {
+
+/// Substitute for std::identity.
+/// Switch to std::identity once we can use c++20.
+template <class Ty> struct identity {
+ using is_transparent = void;
+ using argument_type = Ty;
+
+ Ty &operator()(Ty &self) const { return self; }
+ const Ty &operator()(const Ty &self) const { return self; }
+};
+
+/// Substitute for std::bit_ceil.
+constexpr uint64_t bit_ceil(uint64_t Val) noexcept {
+ Val |= (Val >> 1);
+ Val |= (Val >> 2);
+ Val |= (Val >> 4);
+ Val |= (Val >> 8);
+ Val |= (Val >> 16);
+ Val |= (Val >> 32);
+ return Val + 1;
+}
+
+} // namespace __orc_rt
+
+#endif // ORC_RT_STL_EXTRAS
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/string_pool.h b/contrib/llvm-project/compiler-rt/lib/orc/string_pool.h
new file mode 100644
index 000000000000..c0ba4ea8980e
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/string_pool.h
@@ -0,0 +1,172 @@
+//===------- string_pool.h - Thread-safe pool for strings -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Contains a thread-safe string pool. Strings are ref-counted, but not
+// automatically deallocated. Unused entries can be cleared by calling
+// StringPool::clearDeadEntries.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_STRING_POOL_H
+#define ORC_RT_STRING_POOL_H
+
+#include <atomic>
+#include <cassert>
+#include <functional>
+#include <mutex>
+#include <string>
+#include <unordered_map>
+
+namespace __orc_rt {
+
+class PooledStringPtr;
+
+/// String pool for strings names used by the ORC runtime.
+class StringPool {
+ friend class PooledStringPtr;
+
+public:
+ /// Destroy a StringPool.
+ ~StringPool();
+
+ /// Create a string pointer from the given string.
+ PooledStringPtr intern(std::string S);
+
+ /// Remove from the pool any entries that are no longer referenced.
+ void clearDeadEntries();
+
+ /// Returns true if the pool is empty.
+ bool empty() const;
+
+private:
+ using RefCountType = std::atomic<size_t>;
+ using PoolMap = std::unordered_map<std::string, RefCountType>;
+ using PoolMapEntry = PoolMap::value_type;
+ mutable std::mutex PoolMutex;
+ PoolMap Pool;
+};
+
+/// Pointer to a pooled string.
+class PooledStringPtr {
+ friend class StringPool;
+ friend struct std::hash<PooledStringPtr>;
+
+public:
+ PooledStringPtr() = default;
+ PooledStringPtr(std::nullptr_t) {}
+ PooledStringPtr(const PooledStringPtr &Other) : S(Other.S) {
+ if (S)
+ ++S->second;
+ }
+
+ PooledStringPtr &operator=(const PooledStringPtr &Other) {
+ if (S) {
+ assert(S->second && "Releasing PooledStringPtr with zero ref count");
+ --S->second;
+ }
+ S = Other.S;
+ if (S)
+ ++S->second;
+ return *this;
+ }
+
+ PooledStringPtr(PooledStringPtr &&Other) : S(nullptr) {
+ std::swap(S, Other.S);
+ }
+
+ PooledStringPtr &operator=(PooledStringPtr &&Other) {
+ if (S) {
+ assert(S->second && "Releasing PooledStringPtr with zero ref count");
+ --S->second;
+ }
+ S = nullptr;
+ std::swap(S, Other.S);
+ return *this;
+ }
+
+ ~PooledStringPtr() {
+ if (S) {
+ assert(S->second && "Releasing PooledStringPtr with zero ref count");
+ --S->second;
+ }
+ }
+
+ explicit operator bool() const { return S; }
+
+ const std::string &operator*() const { return S->first; }
+
+ friend bool operator==(const PooledStringPtr &LHS,
+ const PooledStringPtr &RHS) {
+ return LHS.S == RHS.S;
+ }
+
+ friend bool operator!=(const PooledStringPtr &LHS,
+ const PooledStringPtr &RHS) {
+ return !(LHS == RHS);
+ }
+
+ friend bool operator<(const PooledStringPtr &LHS,
+ const PooledStringPtr &RHS) {
+ return LHS.S < RHS.S;
+ }
+
+private:
+ using PoolEntry = StringPool::PoolMapEntry;
+ using PoolEntryPtr = PoolEntry *;
+
+ PooledStringPtr(StringPool::PoolMapEntry *S) : S(S) {
+ if (S)
+ ++S->second;
+ }
+
+ PoolEntryPtr S = nullptr;
+};
+
+inline StringPool::~StringPool() {
+#ifndef NDEBUG
+ clearDeadEntries();
+ assert(Pool.empty() && "Dangling references at pool destruction time");
+#endif // NDEBUG
+}
+
+inline PooledStringPtr StringPool::intern(std::string S) {
+ std::lock_guard<std::mutex> Lock(PoolMutex);
+ PoolMap::iterator I;
+ bool Added;
+ std::tie(I, Added) = Pool.try_emplace(std::move(S), 0);
+ return PooledStringPtr(&*I);
+}
+
+inline void StringPool::clearDeadEntries() {
+ std::lock_guard<std::mutex> Lock(PoolMutex);
+ for (auto I = Pool.begin(), E = Pool.end(); I != E;) {
+ auto Tmp = I++;
+ if (Tmp->second == 0)
+ Pool.erase(Tmp);
+ }
+}
+
+inline bool StringPool::empty() const {
+ std::lock_guard<std::mutex> Lock(PoolMutex);
+ return Pool.empty();
+}
+
+} // end namespace __orc_rt
+
+namespace std {
+
+// Make PooledStringPtrs hashable.
+template <> struct hash<__orc_rt::PooledStringPtr> {
+ size_t operator()(const __orc_rt::PooledStringPtr &A) const {
+ return hash<__orc_rt::PooledStringPtr::PoolEntryPtr>()(A.S);
+ }
+};
+
+} // namespace std
+
+#endif // ORC_RT_REF_COUNTED_STRING_POOL_H
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/tools/orc-rt-executor.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/tools/orc-rt-executor.cpp
new file mode 100644
index 000000000000..da45a2d64d68
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/tools/orc-rt-executor.cpp
@@ -0,0 +1,49 @@
+//===- orc-rt-executor.cpp ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Contains the orc-rt-executor test tool. This is a "blank executable" that
+// links the ORC runtime and can accept code from a JIT controller like lii or
+// llvm-jitlink.
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstring>
+#include <iostream>
+#include <optional>
+#include <string_view>
+
+void printHelp(std::string_view ProgName, std::ostream &OS) {
+ OS << "usage: " << ProgName << " [help] [<mode>] <program arguments>...\n"
+ << " <mode> -- specify how to listen for JIT'd program\n"
+ << " filedesc=<in>,<out> -- read from <in> filedesc, write to out\n"
+ << " tcp=<host>:<port> -- listen on the given host/port\n"
+ << " help -- print help and exit\n"
+ << "\n"
+ << " Notes:\n"
+ << " Program arguments will be made available to the JIT controller.\n"
+ << " When running a JIT'd program containing a main function the\n"
+ << " controller may choose to pass these on to main, however\n"
+ << " orc-rt-executor does not enforce this.\n";
+}
+
+int main(int argc, char *argv[]) {
+ if (argc < 2) {
+ printHelp("orc-rt-executor", std::cerr);
+ std::cerr << "error: insufficient arguments.\n";
+ exit(1);
+ }
+
+ if (!strcmp(argv[1], "help")) {
+ printHelp(argv[0], std::cerr);
+ exit(0);
+ }
+
+ std::cerr << "error: One day I will be a real program, but I am not yet.\n";
+
+ return 0;
+}
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/adt_test.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/adt_test.cpp
new file mode 100644
index 000000000000..6625a590e363
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/adt_test.cpp
@@ -0,0 +1,50 @@
+//===-- adt_test.cpp ------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#include "adt.h"
+#include "gtest/gtest.h"
+
+#include <sstream>
+#include <string>
+
+using namespace __orc_rt;
+
+TEST(ADTTest, SpanDefaultConstruction) {
+ span<int> S;
+ EXPECT_TRUE(S.empty()) << "Default constructed span not empty";
+ EXPECT_EQ(S.size(), 0U) << "Default constructed span size not zero";
+ EXPECT_EQ(S.begin(), S.end()) << "Default constructed span begin != end";
+}
+
+TEST(ADTTest, SpanConstructFromFixedArray) {
+ int A[] = {1, 2, 3, 4, 5};
+ span<int> S(A);
+ EXPECT_FALSE(S.empty()) << "Span should be non-empty";
+ EXPECT_EQ(S.size(), 5U) << "Span has unexpected size";
+ EXPECT_EQ(std::distance(S.begin(), S.end()), 5U)
+ << "Unexpected iterator range size";
+ EXPECT_EQ(S.data(), &A[0]) << "Span data has unexpected value";
+ for (unsigned I = 0; I != S.size(); ++I)
+ EXPECT_EQ(S[I], A[I]) << "Unexpected span element value";
+}
+
+TEST(ADTTest, SpanConstructFromIteratorAndSize) {
+ int A[] = {1, 2, 3, 4, 5};
+ span<int> S(&A[0], 5);
+ EXPECT_FALSE(S.empty()) << "Span should be non-empty";
+ EXPECT_EQ(S.size(), 5U) << "Span has unexpected size";
+ EXPECT_EQ(std::distance(S.begin(), S.end()), 5U)
+ << "Unexpected iterator range size";
+ EXPECT_EQ(S.data(), &A[0]) << "Span data has unexpected value";
+ for (unsigned I = 0; I != S.size(); ++I)
+ EXPECT_EQ(S[I], A[I]) << "Unexpected span element value";
+}
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/bitmask_enum_test.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/bitmask_enum_test.cpp
new file mode 100644
index 000000000000..4c27d54fb4a9
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/bitmask_enum_test.cpp
@@ -0,0 +1,143 @@
+//===-- adt_test.cpp ------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#include "bitmask_enum.h"
+#include "gtest/gtest.h"
+
+#include <sstream>
+#include <string>
+
+using namespace __orc_rt;
+
+namespace {
+
+enum Flags { F0 = 0, F1 = 1, F2 = 2, F3 = 4, F4 = 8 };
+
+} // namespace
+
+namespace __orc_rt {
+ORC_RT_DECLARE_ENUM_AS_BITMASK(Flags, F4);
+} // namespace __orc_rt
+
+static_assert(is_bitmask_enum<Flags>::value != 0);
+static_assert(largest_bitmask_enum_bit<Flags>::value == Flags::F4);
+
+namespace {
+
+static_assert(is_bitmask_enum<Flags>::value != 0);
+static_assert(largest_bitmask_enum_bit<Flags>::value == Flags::F4);
+
+TEST(BitmaskEnumTest, BitwiseOr) {
+ Flags f = F1 | F2;
+ EXPECT_EQ(3, f);
+
+ f = f | F3;
+ EXPECT_EQ(7, f);
+}
+
+TEST(BitmaskEnumTest, BitwiseOrEquals) {
+ Flags f = F1;
+ f |= F3;
+ EXPECT_EQ(5, f);
+
+ // |= should return a reference to the LHS.
+ f = F2;
+ (f |= F3) = F1;
+ EXPECT_EQ(F1, f);
+}
+
+TEST(BitmaskEnumTest, BitwiseAnd) {
+ Flags f = static_cast<Flags>(3) & F2;
+ EXPECT_EQ(F2, f);
+
+ f = (f | F3) & (F1 | F2 | F3);
+ EXPECT_EQ(6, f);
+}
+
+TEST(BitmaskEnumTest, BitwiseAndEquals) {
+ Flags f = F1 | F2 | F3;
+ f &= F1 | F2;
+ EXPECT_EQ(3, f);
+
+ // &= should return a reference to the LHS.
+ (f &= F1) = F3;
+ EXPECT_EQ(F3, f);
+}
+
+TEST(BitmaskEnumTest, BitwiseXor) {
+ Flags f = (F1 | F2) ^ (F2 | F3);
+ EXPECT_EQ(5, f);
+
+ f = f ^ F1;
+ EXPECT_EQ(4, f);
+}
+
+TEST(BitmaskEnumTest, BitwiseXorEquals) {
+ Flags f = (F1 | F2);
+ f ^= (F2 | F4);
+ EXPECT_EQ(9, f);
+
+ // ^= should return a reference to the LHS.
+ (f ^= F4) = F3;
+ EXPECT_EQ(F3, f);
+}
+
+TEST(BitmaskEnumTest, ConstantExpression) {
+ constexpr Flags f1 = ~F1;
+ constexpr Flags f2 = F1 | F2;
+ constexpr Flags f3 = F1 & F2;
+ constexpr Flags f4 = F1 ^ F2;
+ EXPECT_EQ(f1, ~F1);
+ EXPECT_EQ(f2, F1 | F2);
+ EXPECT_EQ(f3, F1 & F2);
+ EXPECT_EQ(f4, F1 ^ F2);
+}
+
+TEST(BitmaskEnumTest, BitwiseNot) {
+ Flags f = ~F1;
+ EXPECT_EQ(14, f); // Largest value for f is 15.
+ EXPECT_EQ(15, ~F0);
+}
+
+enum class FlagsClass {
+ F0 = 0,
+ F1 = 1,
+ F2 = 2,
+ F3 = 4,
+ ORC_RT_MARK_AS_BITMASK_ENUM(F3)
+};
+
+TEST(BitmaskEnumTest, ScopedEnum) {
+ FlagsClass f = (FlagsClass::F1 & ~FlagsClass::F0) | FlagsClass::F2;
+ f |= FlagsClass::F3;
+ EXPECT_EQ(7, static_cast<int>(f));
+}
+
+struct Container {
+ enum Flags {
+ F0 = 0,
+ F1 = 1,
+ F2 = 2,
+ F3 = 4,
+ ORC_RT_MARK_AS_BITMASK_ENUM(F3)
+ };
+
+ static Flags getFlags() {
+ Flags f = F0 | F1;
+ f |= F2;
+ return f;
+ }
+};
+
+TEST(BitmaskEnumTest, EnumInStruct) { EXPECT_EQ(3, Container::getFlags()); }
+
+} // namespace
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/c_api_test.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/c_api_test.cpp
new file mode 100644
index 000000000000..497cb937e2af
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/c_api_test.cpp
@@ -0,0 +1,200 @@
+//===-- c_api_test.cpp ----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#include "orc_rt/c_api.h"
+#include "gtest/gtest.h"
+
+TEST(CAPITest, CWrapperFunctionResultInit) {
+ orc_rt_CWrapperFunctionResult R;
+ orc_rt_CWrapperFunctionResultInit(&R);
+
+ EXPECT_EQ(R.Size, 0U);
+ EXPECT_EQ(R.Data.ValuePtr, nullptr);
+
+ // Check that this value isn't treated as an out-of-band error.
+ EXPECT_EQ(orc_rt_CWrapperFunctionResultGetOutOfBandError(&R), nullptr);
+
+ // Check that we can dispose of the value.
+ orc_rt_DisposeCWrapperFunctionResult(&R);
+}
+
+TEST(CAPITest, CWrapperFunctionResultAllocSmall) {
+ constexpr size_t SmallAllocSize = sizeof(const char *);
+
+ auto R = orc_rt_CWrapperFunctionResultAllocate(SmallAllocSize);
+ char *DataPtr = orc_rt_CWrapperFunctionResultData(&R);
+
+ for (size_t I = 0; I != SmallAllocSize; ++I)
+ DataPtr[I] = 0x55 + I;
+
+ // Check that the inline storage in R.Data.Value contains the expected
+ // sequence.
+ EXPECT_EQ(R.Size, SmallAllocSize);
+ for (size_t I = 0; I != SmallAllocSize; ++I)
+ EXPECT_EQ(R.Data.Value[I], (char)(0x55 + I))
+ << "Unexpected value at index " << I;
+
+ // Check that this value isn't treated as an out-of-band error.
+ EXPECT_EQ(orc_rt_CWrapperFunctionResultGetOutOfBandError(&R), nullptr);
+
+ // Check that orc_rt_CWrapperFunctionResult(Data|Result|Size) and
+ // orc_rt_CWrapperFunctionResultGetOutOfBandError behave as expected.
+ EXPECT_EQ(orc_rt_CWrapperFunctionResultData(&R), R.Data.Value);
+ EXPECT_EQ(orc_rt_CWrapperFunctionResultSize(&R), SmallAllocSize);
+ EXPECT_FALSE(orc_rt_CWrapperFunctionResultEmpty(&R));
+ EXPECT_EQ(orc_rt_CWrapperFunctionResultGetOutOfBandError(&R), nullptr);
+
+ // Check that we can dispose of the value.
+ orc_rt_DisposeCWrapperFunctionResult(&R);
+}
+
+TEST(CAPITest, CWrapperFunctionResultAllocLarge) {
+ constexpr size_t LargeAllocSize = sizeof(const char *) + 1;
+
+ auto R = orc_rt_CWrapperFunctionResultAllocate(LargeAllocSize);
+ char *DataPtr = orc_rt_CWrapperFunctionResultData(&R);
+
+ for (size_t I = 0; I != LargeAllocSize; ++I)
+ DataPtr[I] = 0x55 + I;
+
+ // Check that the inline storage in R.Data.Value contains the expected
+ // sequence.
+ EXPECT_EQ(R.Size, LargeAllocSize);
+ EXPECT_EQ(R.Data.ValuePtr, DataPtr);
+ for (size_t I = 0; I != LargeAllocSize; ++I)
+ EXPECT_EQ(R.Data.ValuePtr[I], (char)(0x55 + I))
+ << "Unexpected value at index " << I;
+
+ // Check that this value isn't treated as an out-of-band error.
+ EXPECT_EQ(orc_rt_CWrapperFunctionResultGetOutOfBandError(&R), nullptr);
+
+ // Check that orc_rt_CWrapperFunctionResult(Data|Result|Size) and
+ // orc_rt_CWrapperFunctionResultGetOutOfBandError behave as expected.
+ EXPECT_EQ(orc_rt_CWrapperFunctionResultData(&R), R.Data.ValuePtr);
+ EXPECT_EQ(orc_rt_CWrapperFunctionResultSize(&R), LargeAllocSize);
+ EXPECT_FALSE(orc_rt_CWrapperFunctionResultEmpty(&R));
+ EXPECT_EQ(orc_rt_CWrapperFunctionResultGetOutOfBandError(&R), nullptr);
+
+ // Check that we can dispose of the value.
+ orc_rt_DisposeCWrapperFunctionResult(&R);
+}
+
+TEST(CAPITest, CWrapperFunctionResultFromRangeSmall) {
+ constexpr size_t SmallAllocSize = sizeof(const char *);
+
+ char Source[SmallAllocSize];
+ for (size_t I = 0; I != SmallAllocSize; ++I)
+ Source[I] = 0x55 + I;
+
+ orc_rt_CWrapperFunctionResult R =
+ orc_rt_CreateCWrapperFunctionResultFromRange(Source, SmallAllocSize);
+
+ // Check that the inline storage in R.Data.Value contains the expected
+ // sequence.
+ EXPECT_EQ(R.Size, SmallAllocSize);
+ for (size_t I = 0; I != SmallAllocSize; ++I)
+ EXPECT_EQ(R.Data.Value[I], (char)(0x55 + I))
+ << "Unexpected value at index " << I;
+
+ // Check that we can dispose of the value.
+ orc_rt_DisposeCWrapperFunctionResult(&R);
+}
+
+TEST(CAPITest, CWrapperFunctionResultFromRangeLarge) {
+ constexpr size_t LargeAllocSize = sizeof(const char *) + 1;
+
+ char Source[LargeAllocSize];
+ for (size_t I = 0; I != LargeAllocSize; ++I)
+ Source[I] = 0x55 + I;
+
+ orc_rt_CWrapperFunctionResult R =
+ orc_rt_CreateCWrapperFunctionResultFromRange(Source, LargeAllocSize);
+
+ // Check that the inline storage in R.Data.Value contains the expected
+ // sequence.
+ EXPECT_EQ(R.Size, LargeAllocSize);
+ for (size_t I = 0; I != LargeAllocSize; ++I)
+ EXPECT_EQ(R.Data.ValuePtr[I], (char)(0x55 + I))
+ << "Unexpected value at index " << I;
+
+ // Check that we can dispose of the value.
+ orc_rt_DisposeCWrapperFunctionResult(&R);
+}
+
+TEST(CAPITest, CWrapperFunctionResultFromStringSmall) {
+ constexpr size_t SmallAllocSize = sizeof(const char *);
+
+ char Source[SmallAllocSize];
+ for (size_t I = 0; I != SmallAllocSize - 1; ++I)
+ Source[I] = 'a' + I;
+ Source[SmallAllocSize - 1] = '\0';
+
+ orc_rt_CWrapperFunctionResult R =
+ orc_rt_CreateCWrapperFunctionResultFromString(Source);
+
+ // Check that the inline storage in R.Data.Value contains the expected
+ // sequence.
+ EXPECT_EQ(R.Size, SmallAllocSize);
+ for (size_t I = 0; I != SmallAllocSize - 1; ++I)
+ EXPECT_EQ(R.Data.Value[I], (char)('a' + I))
+ << "Unexpected value at index " << I;
+ EXPECT_EQ(R.Data.Value[SmallAllocSize - 1], '\0')
+ << "Unexpected value at index " << (SmallAllocSize - 1);
+
+ // Check that we can dispose of the value.
+ orc_rt_DisposeCWrapperFunctionResult(&R);
+}
+
+TEST(CAPITest, CWrapperFunctionResultFromStringLarge) {
+ constexpr size_t LargeAllocSize = sizeof(const char *) + 1;
+
+ char Source[LargeAllocSize];
+ for (size_t I = 0; I != LargeAllocSize - 1; ++I)
+ Source[I] = 'a' + I;
+ Source[LargeAllocSize - 1] = '\0';
+
+ orc_rt_CWrapperFunctionResult R =
+ orc_rt_CreateCWrapperFunctionResultFromString(Source);
+
+ // Check that the inline storage in R.Data.Value contains the expected
+ // sequence.
+ EXPECT_EQ(R.Size, LargeAllocSize);
+ for (size_t I = 0; I != LargeAllocSize - 1; ++I)
+ EXPECT_EQ(R.Data.ValuePtr[I], (char)('a' + I))
+ << "Unexpected value at index " << I;
+ EXPECT_EQ(R.Data.ValuePtr[LargeAllocSize - 1], '\0')
+ << "Unexpected value at index " << (LargeAllocSize - 1);
+
+ // Check that we can dispose of the value.
+ orc_rt_DisposeCWrapperFunctionResult(&R);
+}
+
+TEST(CAPITest, CWrapperFunctionResultFromOutOfBandError) {
+ constexpr const char *ErrMsg = "test error message";
+ orc_rt_CWrapperFunctionResult R =
+ orc_rt_CreateCWrapperFunctionResultFromOutOfBandError(ErrMsg);
+
+#ifndef NDEBUG
+ EXPECT_DEATH({ orc_rt_CWrapperFunctionResultData(&R); },
+ "Cannot get data for out-of-band error value");
+ EXPECT_DEATH({ orc_rt_CWrapperFunctionResultSize(&R); },
+ "Cannot get size for out-of-band error value");
+#endif
+
+ EXPECT_FALSE(orc_rt_CWrapperFunctionResultEmpty(&R));
+ const char *OOBErrMsg = orc_rt_CWrapperFunctionResultGetOutOfBandError(&R);
+ EXPECT_NE(OOBErrMsg, nullptr);
+ EXPECT_NE(OOBErrMsg, ErrMsg);
+ EXPECT_TRUE(strcmp(OOBErrMsg, ErrMsg) == 0);
+
+ orc_rt_DisposeCWrapperFunctionResult(&R);
+}
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/endian_test.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/endian_test.cpp
new file mode 100644
index 000000000000..71b677af694c
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/endian_test.cpp
@@ -0,0 +1,174 @@
+//===- endian_test.cpp ------------------------- swap byte order test -----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime.
+//
+// Adapted from the llvm/unittests/Support/SwapByteOrderTest.cpp LLVM unit test.
+//
+//===----------------------------------------------------------------------===//
+
+#include "endianness.h"
+#include "gtest/gtest.h"
+
+using namespace __orc_rt;
+
+TEST(Endian, ByteSwap_32) {
+ EXPECT_EQ(0x44332211u, ByteSwap_32(0x11223344));
+ EXPECT_EQ(0xDDCCBBAAu, ByteSwap_32(0xAABBCCDD));
+}
+
+TEST(Endian, ByteSwap_64) {
+ EXPECT_EQ(0x8877665544332211ULL, ByteSwap_64(0x1122334455667788LL));
+ EXPECT_EQ(0x1100FFEEDDCCBBAAULL, ByteSwap_64(0xAABBCCDDEEFF0011LL));
+}
+
+// In these first two tests all of the original_uintx values are truncated
+// except for 64. We could avoid this, but there's really no point.
+TEST(Endian, getSwappedBytes_UnsignedRoundTrip) {
+ // The point of the bit twiddling of magic is to test with and without bits
+ // in every byte.
+ uint64_t value = 1;
+ for (std::size_t i = 0; i <= sizeof(value); ++i) {
+ uint8_t original_uint8 = static_cast<uint8_t>(value);
+ EXPECT_EQ(original_uint8, getSwappedBytes(getSwappedBytes(original_uint8)));
+
+ uint16_t original_uint16 = static_cast<uint16_t>(value);
+ EXPECT_EQ(original_uint16,
+ getSwappedBytes(getSwappedBytes(original_uint16)));
+
+ uint32_t original_uint32 = static_cast<uint32_t>(value);
+ EXPECT_EQ(original_uint32,
+ getSwappedBytes(getSwappedBytes(original_uint32)));
+
+ uint64_t original_uint64 = static_cast<uint64_t>(value);
+ EXPECT_EQ(original_uint64,
+ getSwappedBytes(getSwappedBytes(original_uint64)));
+
+ value = (value << 8) | 0x55; // binary 0101 0101.
+ }
+}
+
+TEST(Endian, getSwappedBytes_SignedRoundTrip) {
+ // The point of the bit twiddling of magic is to test with and without bits
+ // in every byte.
+ uint64_t value = 1;
+ for (std::size_t i = 0; i <= sizeof(value); ++i) {
+ int8_t original_int8 = static_cast<int8_t>(value);
+ EXPECT_EQ(original_int8, getSwappedBytes(getSwappedBytes(original_int8)));
+
+ int16_t original_int16 = static_cast<int16_t>(value);
+ EXPECT_EQ(original_int16, getSwappedBytes(getSwappedBytes(original_int16)));
+
+ int32_t original_int32 = static_cast<int32_t>(value);
+ EXPECT_EQ(original_int32, getSwappedBytes(getSwappedBytes(original_int32)));
+
+ int64_t original_int64 = static_cast<int64_t>(value);
+ EXPECT_EQ(original_int64, getSwappedBytes(getSwappedBytes(original_int64)));
+
+ // Test other sign.
+ value *= -1;
+
+ original_int8 = static_cast<int8_t>(value);
+ EXPECT_EQ(original_int8, getSwappedBytes(getSwappedBytes(original_int8)));
+
+ original_int16 = static_cast<int16_t>(value);
+ EXPECT_EQ(original_int16, getSwappedBytes(getSwappedBytes(original_int16)));
+
+ original_int32 = static_cast<int32_t>(value);
+ EXPECT_EQ(original_int32, getSwappedBytes(getSwappedBytes(original_int32)));
+
+ original_int64 = static_cast<int64_t>(value);
+ EXPECT_EQ(original_int64, getSwappedBytes(getSwappedBytes(original_int64)));
+
+ // Return to normal sign and twiddle.
+ value *= -1;
+ value = (value << 8) | 0x55; // binary 0101 0101.
+ }
+}
+
+TEST(Endian, getSwappedBytes_uint8_t) {
+ EXPECT_EQ(uint8_t(0x11), getSwappedBytes(uint8_t(0x11)));
+}
+
+TEST(Endian, getSwappedBytes_uint16_t) {
+ EXPECT_EQ(uint16_t(0x1122), getSwappedBytes(uint16_t(0x2211)));
+}
+
+TEST(Endian, getSwappedBytes_uint32_t) {
+ EXPECT_EQ(uint32_t(0x11223344), getSwappedBytes(uint32_t(0x44332211)));
+}
+
+TEST(Endian, getSwappedBytes_uint64_t) {
+ EXPECT_EQ(uint64_t(0x1122334455667788ULL),
+ getSwappedBytes(uint64_t(0x8877665544332211ULL)));
+}
+
+TEST(Endian, getSwappedBytes_int8_t) {
+ EXPECT_EQ(int8_t(0x11), getSwappedBytes(int8_t(0x11)));
+}
+
+TEST(Endian, getSwappedBytes_int16_t) {
+ EXPECT_EQ(int16_t(0x1122), getSwappedBytes(int16_t(0x2211)));
+}
+
+TEST(Endian, getSwappedBytes_int32_t) {
+ EXPECT_EQ(int32_t(0x11223344), getSwappedBytes(int32_t(0x44332211)));
+}
+
+TEST(Endian, getSwappedBytes_int64_t) {
+ EXPECT_EQ(int64_t(0x1122334455667788LL),
+ getSwappedBytes(int64_t(0x8877665544332211LL)));
+}
+
+TEST(Endian, swapByteOrder_uint8_t) {
+ uint8_t value = 0x11;
+ swapByteOrder(value);
+ EXPECT_EQ(uint8_t(0x11), value);
+}
+
+TEST(Endian, swapByteOrder_uint16_t) {
+ uint16_t value = 0x2211;
+ swapByteOrder(value);
+ EXPECT_EQ(uint16_t(0x1122), value);
+}
+
+TEST(Endian, swapByteOrder_uint32_t) {
+ uint32_t value = 0x44332211;
+ swapByteOrder(value);
+ EXPECT_EQ(uint32_t(0x11223344), value);
+}
+
+TEST(Endian, swapByteOrder_uint64_t) {
+ uint64_t value = 0x8877665544332211ULL;
+ swapByteOrder(value);
+ EXPECT_EQ(uint64_t(0x1122334455667788ULL), value);
+}
+
+TEST(Endian, swapByteOrder_int8_t) {
+ int8_t value = 0x11;
+ swapByteOrder(value);
+ EXPECT_EQ(int8_t(0x11), value);
+}
+
+TEST(Endian, swapByteOrder_int16_t) {
+ int16_t value = 0x2211;
+ swapByteOrder(value);
+ EXPECT_EQ(int16_t(0x1122), value);
+}
+
+TEST(Endian, swapByteOrder_int32_t) {
+ int32_t value = 0x44332211;
+ swapByteOrder(value);
+ EXPECT_EQ(int32_t(0x11223344), value);
+}
+
+TEST(Endian, swapByteOrder_int64_t) {
+ int64_t value = 0x8877665544332211LL;
+ swapByteOrder(value);
+ EXPECT_EQ(int64_t(0x1122334455667788LL), value);
+}
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/error_test.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/error_test.cpp
new file mode 100644
index 000000000000..5251d788e01b
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/error_test.cpp
@@ -0,0 +1,295 @@
+//===-- error_test.cpp --sssssssss-----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime.
+//
+// Note:
+// This unit test was adapted from
+// llvm/unittests/Support/ExtensibleRTTITest.cpp
+//
+//===----------------------------------------------------------------------===//
+
+#include "error.h"
+#include "gtest/gtest.h"
+
+using namespace __orc_rt;
+
+namespace {
+
+class CustomError : public RTTIExtends<CustomError, ErrorInfoBase> {
+public:
+ CustomError(int V1) : V1(V1) {}
+ std::string toString() const override {
+ return "CustomError V1 = " + std::to_string(V1);
+ }
+ int getV1() const { return V1; }
+
+protected:
+ int V1;
+};
+
+class CustomSubError : public RTTIExtends<CustomSubError, CustomError> {
+public:
+ CustomSubError(int V1, std::string V2)
+ : RTTIExtends<CustomSubError, CustomError>(V1), V2(std::move(V2)) {}
+ std::string toString() const override {
+ return "CustomSubError V1 = " + std::to_string(V1) + ", " + V2;
+ }
+ const std::string &getV2() const { return V2; }
+
+protected:
+ std::string V2;
+};
+
+} // end anonymous namespace
+
+// Test that a checked success value doesn't cause any issues.
+TEST(Error, CheckedSuccess) {
+ Error E = Error::success();
+ EXPECT_FALSE(E) << "Unexpected error while testing Error 'Success'";
+}
+
+// Check that a consumed success value doesn't cause any issues.
+TEST(Error, ConsumeSuccess) { consumeError(Error::success()); }
+
+TEST(Error, ConsumeError) {
+ Error E = make_error<CustomError>(42);
+ if (E) {
+ consumeError(std::move(E));
+ } else
+ ADD_FAILURE() << "Error failure value should convert to true";
+}
+
+// Test that unchecked success values cause an abort.
+TEST(Error, UncheckedSuccess) {
+ EXPECT_DEATH({ Error E = Error::success(); },
+ "Error must be checked prior to destruction")
+ << "Unchecked Error Succes value did not cause abort()";
+}
+
+// Test that a checked but unhandled error causes an abort.
+TEST(Error, CheckedButUnhandledError) {
+ auto DropUnhandledError = []() {
+ Error E = make_error<CustomError>(42);
+ (void)!E;
+ };
+ EXPECT_DEATH(DropUnhandledError(),
+ "Error must be checked prior to destruction")
+ << "Unhandled Error failure value did not cause an abort()";
+}
+
+// Test that error_cast works as expected.
+TEST(Error, BasicErrorCast) {
+ {
+ // Check casting base error value to base error type.
+ auto E = make_error<CustomError>(42);
+ if (auto CSE = error_cast<CustomSubError>(E)) {
+ ADD_FAILURE() << "Derived cast incorrectly matched base error";
+ } else if (auto CE = error_cast<CustomError>(E)) {
+ EXPECT_EQ(CE->getV1(), 42) << "Unexpected wrapped value";
+ } else
+ ADD_FAILURE() << "Unexpected error value";
+ }
+
+ {
+ // Check casting derived error value to base error type.
+ auto E = make_error<CustomSubError>(42, "foo");
+ if (auto CE = error_cast<CustomError>(E)) {
+ EXPECT_EQ(CE->getV1(), 42) << "Unexpected wrapped value";
+ } else
+ ADD_FAILURE() << "Unexpected error value";
+ }
+
+ {
+ // Check casting derived error value to derived error type.
+ auto E = make_error<CustomSubError>(42, "foo");
+ if (auto CSE = error_cast<CustomSubError>(E)) {
+ EXPECT_EQ(CSE->getV1(), 42) << "Unexpected wrapped value";
+ EXPECT_EQ(CSE->getV2(), "foo") << "Unexpected wrapped value";
+ } else
+ ADD_FAILURE() << "Unexpected error value";
+ }
+}
+
+// ErrorAsOutParameter tester.
+static void errAsOutParamHelper(Error &Err) {
+ ErrorAsOutParameter ErrAsOutParam(&Err);
+ // Verify that checked flag is raised - assignment should not crash.
+ Err = Error::success();
+ // Raise the checked bit manually - caller should still have to test the
+ // error.
+ (void)!!Err;
+}
+
+// Test that ErrorAsOutParameter sets the checked flag on construction.
+TEST(Error, ErrorAsOutParameterChecked) {
+ Error E = Error::success();
+ errAsOutParamHelper(E);
+ (void)!!E;
+}
+
+// Test that ErrorAsOutParameter clears the checked flag on destruction.
+TEST(Error, ErrorAsOutParameterUnchecked) {
+ EXPECT_DEATH(
+ {
+ Error E = Error::success();
+ errAsOutParamHelper(E);
+ },
+ "Error must be checked prior to destruction")
+ << "ErrorAsOutParameter did not clear the checked flag on destruction.";
+}
+
+// Check 'Error::isA<T>' method handling.
+TEST(Error, IsAHandling) {
+ // Check 'isA' handling.
+ Error E = make_error<CustomError>(42);
+ Error F = make_error<CustomSubError>(42, "foo");
+ Error G = Error::success();
+
+ EXPECT_TRUE(E.isA<CustomError>());
+ EXPECT_FALSE(E.isA<CustomSubError>());
+ EXPECT_TRUE(F.isA<CustomError>());
+ EXPECT_TRUE(F.isA<CustomSubError>());
+ EXPECT_FALSE(G.isA<CustomError>());
+
+ consumeError(std::move(E));
+ consumeError(std::move(F));
+ consumeError(std::move(G));
+}
+
+TEST(Error, StringError) {
+ auto E = make_error<StringError>("foo");
+ if (auto SE = error_cast<StringError>(E)) {
+ EXPECT_EQ(SE->toString(), "foo") << "Unexpected StringError value";
+ } else
+ ADD_FAILURE() << "Expected StringError value";
+}
+
+// Test Checked Expected<T> in success mode.
+TEST(Error, CheckedExpectedInSuccessMode) {
+ Expected<int> A = 7;
+ EXPECT_TRUE(!!A) << "Expected with non-error value doesn't convert to 'true'";
+ // Access is safe in second test, since we checked the error in the first.
+ EXPECT_EQ(*A, 7) << "Incorrect Expected non-error value";
+}
+
+// Test Expected with reference type.
+TEST(Error, ExpectedWithReferenceType) {
+ int A = 7;
+ Expected<int &> B = A;
+ // 'Check' B.
+ (void)!!B;
+ int &C = *B;
+ EXPECT_EQ(&A, &C) << "Expected failed to propagate reference";
+}
+
+// Test Unchecked Expected<T> in success mode.
+// We expect this to blow up the same way Error would.
+// Test runs in debug mode only.
+TEST(Error, UncheckedExpectedInSuccessModeDestruction) {
+ EXPECT_DEATH({ Expected<int> A = 7; },
+ "Expected<T> must be checked before access or destruction.")
+ << "Unchecekd Expected<T> success value did not cause an abort().";
+}
+
+// Test Unchecked Expected<T> in success mode.
+// We expect this to blow up the same way Error would.
+// Test runs in debug mode only.
+TEST(Error, UncheckedExpectedInSuccessModeAccess) {
+ EXPECT_DEATH(
+ {
+ Expected<int> A = 7;
+ *A;
+ },
+ "Expected<T> must be checked before access or destruction.")
+ << "Unchecekd Expected<T> success value did not cause an abort().";
+}
+
+// Test Unchecked Expected<T> in success mode.
+// We expect this to blow up the same way Error would.
+// Test runs in debug mode only.
+TEST(Error, UncheckedExpectedInSuccessModeAssignment) {
+ EXPECT_DEATH(
+ {
+ Expected<int> A = 7;
+ A = 7;
+ },
+ "Expected<T> must be checked before access or destruction.")
+ << "Unchecekd Expected<T> success value did not cause an abort().";
+}
+
+// Test Expected<T> in failure mode.
+TEST(Error, ExpectedInFailureMode) {
+ Expected<int> A = make_error<CustomError>(42);
+ EXPECT_FALSE(!!A) << "Expected with error value doesn't convert to 'false'";
+ Error E = A.takeError();
+ EXPECT_TRUE(E.isA<CustomError>()) << "Incorrect Expected error value";
+ consumeError(std::move(E));
+}
+
+// Check that an Expected instance with an error value doesn't allow access to
+// operator*.
+// Test runs in debug mode only.
+TEST(Error, AccessExpectedInFailureMode) {
+ Expected<int> A = make_error<CustomError>(42);
+ EXPECT_DEATH(*A, "Expected<T> must be checked before access or destruction.")
+ << "Incorrect Expected error value";
+ consumeError(A.takeError());
+}
+
+// Check that an Expected instance with an error triggers an abort if
+// unhandled.
+// Test runs in debug mode only.
+TEST(Error, UnhandledExpectedInFailureMode) {
+ EXPECT_DEATH({ Expected<int> A = make_error<CustomError>(42); },
+ "Expected<T> must be checked before access or destruction.")
+ << "Unchecked Expected<T> failure value did not cause an abort()";
+}
+
+// Test covariance of Expected.
+TEST(Error, ExpectedCovariance) {
+ class B {};
+ class D : public B {};
+
+ Expected<B *> A1(Expected<D *>(nullptr));
+ // Check A1 by converting to bool before assigning to it.
+ (void)!!A1;
+ A1 = Expected<D *>(nullptr);
+ // Check A1 again before destruction.
+ (void)!!A1;
+
+ Expected<std::unique_ptr<B>> A2(Expected<std::unique_ptr<D>>(nullptr));
+ // Check A2 by converting to bool before assigning to it.
+ (void)!!A2;
+ A2 = Expected<std::unique_ptr<D>>(nullptr);
+ // Check A2 again before destruction.
+ (void)!!A2;
+}
+
+// Test that the ExitOnError utility works as expected.
+TEST(Error, CantFailSuccess) {
+ cantFail(Error::success());
+
+ int X = cantFail(Expected<int>(42));
+ EXPECT_EQ(X, 42) << "Expected value modified by cantFail";
+
+ int Dummy = 42;
+ int &Y = cantFail(Expected<int &>(Dummy));
+ EXPECT_EQ(&Dummy, &Y) << "Reference mangled by cantFail";
+}
+
+// Test that cantFail results in a crash if you pass it a failure value.
+TEST(Error, CantFailDeath) {
+ EXPECT_DEATH(cantFail(make_error<StringError>("foo")),
+ "cantFail called on failure value")
+ << "cantFail(Error) did not cause an abort for failure value";
+
+ EXPECT_DEATH(cantFail(Expected<int>(make_error<StringError>("foo"))),
+ "cantFail called on failure value")
+ << "cantFail(Expected<int>) did not cause an abort for failure value";
+}
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/executor_address_test.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/executor_address_test.cpp
new file mode 100644
index 000000000000..05b91f3f8609
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/executor_address_test.cpp
@@ -0,0 +1,115 @@
+//===-- executor_address_test.cpp -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime.
+//
+// Note:
+// This unit test was adapted from
+// llvm/unittests/Support/ExecutorAddressTest.cpp
+//
+//===----------------------------------------------------------------------===//
+
+#include "executor_address.h"
+#include "gtest/gtest.h"
+
+using namespace __orc_rt;
+
+TEST(ExecutorAddrTest, DefaultAndNull) {
+ // Check that default constructed values and isNull behave as expected.
+
+ ExecutorAddr Default;
+ ExecutorAddr Null(0);
+ ExecutorAddr NonNull(1);
+
+ EXPECT_TRUE(Null.isNull());
+ EXPECT_EQ(Default, Null);
+
+ EXPECT_FALSE(NonNull.isNull());
+ EXPECT_NE(Default, NonNull);
+}
+
+TEST(ExecutorAddrTest, Ordering) {
+ // Check that ordering operations.
+ ExecutorAddr A1(1), A2(2);
+
+ EXPECT_LE(A1, A1);
+ EXPECT_LT(A1, A2);
+ EXPECT_GT(A2, A1);
+ EXPECT_GE(A2, A2);
+}
+
+TEST(ExecutorAddrTest, PtrConversion) {
+ // Test toPtr / fromPtr round-tripping.
+ int X = 0;
+ auto XAddr = ExecutorAddr::fromPtr(&X);
+ int *XPtr = XAddr.toPtr<int *>();
+
+ EXPECT_EQ(XPtr, &X);
+}
+
+static void F() {}
+
+TEST(ExecutorAddrTest, PtrConversionWithFunctionType) {
+ // Test that function types (as opposed to function pointer types) can be
+ // used with toPtr.
+ auto FAddr = ExecutorAddr::fromPtr(F);
+ void (*FPtr)() = FAddr.toPtr<void()>();
+
+ EXPECT_EQ(FPtr, &F);
+}
+
+TEST(ExecutorAddrTest, WrappingAndUnwrapping) {
+ constexpr uintptr_t RawAddr = 0x123456;
+ int *RawPtr = (int *)RawAddr;
+
+ constexpr uintptr_t TagOffset = 8 * (sizeof(uintptr_t) - 1);
+ uintptr_t TagVal = 0xA5;
+ uintptr_t TagBits = TagVal << TagOffset;
+ void *TaggedPtr = (void *)((uintptr_t)RawPtr | TagBits);
+
+ ExecutorAddr EA =
+ ExecutorAddr::fromPtr(TaggedPtr, ExecutorAddr::Untag(8, TagOffset));
+
+ EXPECT_EQ(EA.getValue(), RawAddr);
+
+ void *ReconstitutedTaggedPtr =
+ EA.toPtr<void *>(ExecutorAddr::Tag(TagVal, TagOffset));
+
+ EXPECT_EQ(TaggedPtr, ReconstitutedTaggedPtr);
+}
+
+TEST(ExecutorAddrTest, AddrRanges) {
+ ExecutorAddr A0(0), A1(1), A2(2), A3(3);
+ ExecutorAddrRange R0(A0, A1), R1(A1, A2), R2(A2, A3), R3(A0, A2), R4(A1, A3);
+ // 012
+ // R0: # -- Before R1
+ // R1: # --
+ // R2: # -- After R1
+ // R3: ## -- Overlaps R1 start
+ // R4: ## -- Overlaps R1 end
+
+ EXPECT_EQ(R1, ExecutorAddrRange(A1, A2));
+ EXPECT_EQ(R1, ExecutorAddrRange(A1, ExecutorAddrDiff(1)));
+ EXPECT_NE(R1, R2);
+
+ EXPECT_TRUE(R1.contains(A1));
+ EXPECT_FALSE(R1.contains(A0));
+ EXPECT_FALSE(R1.contains(A2));
+
+ EXPECT_FALSE(R1.overlaps(R0));
+ EXPECT_FALSE(R1.overlaps(R2));
+ EXPECT_TRUE(R1.overlaps(R3));
+ EXPECT_TRUE(R1.overlaps(R4));
+}
+
+TEST(ExecutorAddrTest, Hashable) {
+ uint64_t RawAddr = 0x1234567890ABCDEF;
+ ExecutorAddr Addr(RawAddr);
+
+ EXPECT_EQ(std::hash<uint64_t>()(RawAddr), std::hash<ExecutorAddr>()(Addr));
+}
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/executor_symbol_def_test.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/executor_symbol_def_test.cpp
new file mode 100644
index 000000000000..181091ca1e60
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/executor_symbol_def_test.cpp
@@ -0,0 +1,19 @@
+//===-- executor_symbol_def_test.cpp --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "executor_symbol_def.h"
+#include "simple_packed_serialization_utils.h"
+#include "gtest/gtest.h"
+
+using namespace __orc_rt;
+
+TEST(ExecutorSymbolDefTest, Serialization) {
+ blobSerializationRoundTrip<SPSExecutorSymbolDef>(ExecutorSymbolDef{});
+ blobSerializationRoundTrip<SPSExecutorSymbolDef>(
+ ExecutorSymbolDef{ExecutorAddr{0x70}, {JITSymbolFlags::Callable, 9}});
+} \ No newline at end of file
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/extensible_rtti_test.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/extensible_rtti_test.cpp
new file mode 100644
index 000000000000..feca1ec1d18c
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/extensible_rtti_test.cpp
@@ -0,0 +1,54 @@
+//===-- extensible_rtti_test.cpp ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime.
+//
+// Note:
+// This unit test was adapted from
+// llvm/unittests/Support/ExtensibleRTTITest.cpp
+//
+//===----------------------------------------------------------------------===//
+
+#include "extensible_rtti.h"
+#include "gtest/gtest.h"
+
+using namespace __orc_rt;
+
+namespace {
+
+class MyBase : public RTTIExtends<MyBase, RTTIRoot> {};
+
+class MyDerivedA : public RTTIExtends<MyDerivedA, MyBase> {};
+
+class MyDerivedB : public RTTIExtends<MyDerivedB, MyBase> {};
+
+} // end anonymous namespace
+
+TEST(ExtensibleRTTITest, BaseCheck) {
+ MyBase MB;
+ MyDerivedA MDA;
+ MyDerivedB MDB;
+
+ // Check MB properties.
+ EXPECT_TRUE(isa<RTTIRoot>(MB));
+ EXPECT_TRUE(isa<MyBase>(MB));
+ EXPECT_FALSE(isa<MyDerivedA>(MB));
+ EXPECT_FALSE(isa<MyDerivedB>(MB));
+
+ // Check MDA properties.
+ EXPECT_TRUE(isa<RTTIRoot>(MDA));
+ EXPECT_TRUE(isa<MyBase>(MDA));
+ EXPECT_TRUE(isa<MyDerivedA>(MDA));
+ EXPECT_FALSE(isa<MyDerivedB>(MDA));
+
+ // Check MDB properties.
+ EXPECT_TRUE(isa<RTTIRoot>(MDB));
+ EXPECT_TRUE(isa<MyBase>(MDB));
+ EXPECT_FALSE(isa<MyDerivedA>(MDB));
+ EXPECT_TRUE(isa<MyDerivedB>(MDB));
+}
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/interval_map_test.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/interval_map_test.cpp
new file mode 100644
index 000000000000..a1c6958fcd52
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/interval_map_test.cpp
@@ -0,0 +1,204 @@
+//===-- interval_map_test.cpp ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#include "interval_map.h"
+#include "gtest/gtest.h"
+
+using namespace __orc_rt;
+
+TEST(IntervalMapTest, DefaultConstructed) {
+ // Check that a default-constructed IntervalMap behaves as expected.
+ IntervalMap<unsigned, unsigned, IntervalCoalescing::Enabled> M;
+
+ EXPECT_TRUE(M.empty());
+ EXPECT_TRUE(M.begin() == M.end());
+ EXPECT_TRUE(M.find(0) == M.end());
+}
+
+TEST(IntervalMapTest, InsertSingleElement) {
+ // Check that a map with a single element inserted behaves as expected.
+ IntervalMap<unsigned, unsigned, IntervalCoalescing::Enabled> M;
+
+ M.insert(7, 8, 42);
+
+ EXPECT_FALSE(M.empty());
+ EXPECT_EQ(std::next(M.begin()), M.end());
+ EXPECT_EQ(M.find(7), M.begin());
+ EXPECT_EQ(M.find(8), M.end());
+ EXPECT_EQ(M.lookup(7), 42U);
+ EXPECT_EQ(M.lookup(8), 0U); // 8 not present, so should return unsigned().
+}
+
+TEST(IntervalMapTest, InsertCoalesceWithPrevious) {
+ // Check that insertions coalesce with previous ranges that share the same
+ // value. Also check that they _don't_ coalesce if the values are different.
+
+ // Check that insertion coalesces with previous range when values are equal.
+ IntervalMap<unsigned, unsigned, IntervalCoalescing::Enabled> M1;
+
+ M1.insert(7, 8, 42);
+ M1.insert(8, 9, 42);
+
+ EXPECT_FALSE(M1.empty());
+ EXPECT_EQ(std::next(M1.begin()), M1.end()); // Should see just one range.
+ EXPECT_EQ(M1.find(7), M1.find(8)); // 7 and 8 should point to same range.
+ EXPECT_EQ(M1.lookup(7), 42U); // Value should be preserved.
+
+ // Check that insertion does not coalesce with previous range when values are
+ // not equal.
+ IntervalMap<unsigned, unsigned, IntervalCoalescing::Enabled> M2;
+
+ M2.insert(7, 8, 42);
+ M2.insert(8, 9, 7);
+
+ EXPECT_FALSE(M2.empty());
+ EXPECT_EQ(std::next(std::next(M2.begin())), M2.end()); // Expect two ranges.
+ EXPECT_NE(M2.find(7), M2.find(8)); // 7 and 8 should be different ranges.
+ EXPECT_EQ(M2.lookup(7), 42U); // Keys 7 and 8 should map to different values.
+ EXPECT_EQ(M2.lookup(8), 7U);
+}
+
+TEST(IntervalMapTest, InsertCoalesceWithFollowing) {
+ // Check that insertions coalesce with following ranges that share the same
+ // value. Also check that they _don't_ coalesce if the values are different.
+
+ // Check that insertion coalesces with following range when values are equal.
+ IntervalMap<unsigned, unsigned, IntervalCoalescing::Enabled> M1;
+
+ M1.insert(8, 9, 42);
+ M1.insert(7, 8, 42);
+
+ EXPECT_FALSE(M1.empty());
+ EXPECT_EQ(std::next(M1.begin()), M1.end()); // Should see just one range.
+ EXPECT_EQ(M1.find(7), M1.find(8)); // 7 and 8 should point to same range.
+ EXPECT_EQ(M1.lookup(7), 42U); // Value should be preserved.
+
+ // Check that insertion does not coalesce with previous range when values are
+ // not equal.
+ IntervalMap<unsigned, unsigned, IntervalCoalescing::Enabled> M2;
+
+ M2.insert(8, 9, 42);
+ M2.insert(7, 8, 7);
+
+ EXPECT_FALSE(M2.empty());
+ EXPECT_EQ(std::next(std::next(M2.begin())), M2.end()); // Expect two ranges.
+ EXPECT_EQ(M2.lookup(7), 7U); // Keys 7 and 8 should map to different values.
+ EXPECT_EQ(M2.lookup(8), 42U);
+}
+
+TEST(IntervalMapTest, InsertCoalesceBoth) {
+ // Check that insertions coalesce with ranges on both sides where posssible.
+ // Also check that they _don't_ coalesce if the values are different.
+
+ // Check that insertion coalesces with both previous and following ranges
+ // when values are equal.
+ IntervalMap<unsigned, unsigned, IntervalCoalescing::Enabled> M1;
+
+ M1.insert(7, 8, 42);
+ M1.insert(9, 10, 42);
+
+ // Check no coalescing yet.
+ EXPECT_NE(M1.find(7), M1.find(9));
+
+ // Insert a 3rd range to trigger coalescing on both sides.
+ M1.insert(8, 9, 42);
+
+ EXPECT_FALSE(M1.empty());
+ EXPECT_EQ(std::next(M1.begin()), M1.end()); // Should see just one range.
+ EXPECT_EQ(M1.find(7), M1.find(8)); // 7, 8, and 9 should point to same range.
+ EXPECT_EQ(M1.find(8), M1.find(9));
+ EXPECT_EQ(M1.lookup(7), 42U); // Value should be preserved.
+
+ // Check that insertion does not coalesce with previous range when values are
+ // not equal.
+ IntervalMap<unsigned, unsigned, IntervalCoalescing::Enabled> M2;
+
+ M2.insert(7, 8, 42);
+ M2.insert(8, 9, 7);
+ M2.insert(9, 10, 42);
+
+ EXPECT_FALSE(M2.empty());
+ // Expect three ranges.
+ EXPECT_EQ(std::next(std::next(std::next(M2.begin()))), M2.end());
+ EXPECT_NE(M2.find(7), M2.find(8)); // All keys should map to different ranges.
+ EXPECT_NE(M2.find(8), M2.find(9));
+ EXPECT_EQ(M2.lookup(7), 42U); // Key 7, 8, and 9 should map to different vals.
+ EXPECT_EQ(M2.lookup(8), 7U);
+ EXPECT_EQ(M2.lookup(9), 42U);
+}
+
+TEST(IntervalMapTest, EraseSingleElement) {
+ // Check that we can insert and then remove a single range.
+ IntervalMap<unsigned, unsigned, IntervalCoalescing::Enabled> M;
+
+ M.insert(7, 10, 42);
+ EXPECT_FALSE(M.empty());
+ M.erase(7, 10);
+ EXPECT_TRUE(M.empty());
+}
+
+TEST(IntervalMapTest, EraseSplittingLeft) {
+ // Check that removal of a trailing subrange succeeds, but leaves the
+ // residual range in-place.
+ IntervalMap<unsigned, unsigned, IntervalCoalescing::Enabled> M;
+
+ M.insert(7, 10, 42);
+ EXPECT_FALSE(M.empty());
+ M.erase(9, 10);
+ EXPECT_EQ(std::next(M.begin()), M.end());
+ EXPECT_EQ(M.begin()->first.first, 7U);
+ EXPECT_EQ(M.begin()->first.second, 9U);
+}
+
+TEST(IntervalMapTest, EraseSplittingRight) {
+ // Check that removal of a leading subrange succeeds, but leaves the
+ // residual range in-place.
+ IntervalMap<unsigned, unsigned, IntervalCoalescing::Enabled> M;
+
+ M.insert(7, 10, 42);
+ EXPECT_FALSE(M.empty());
+ M.erase(7, 8);
+ EXPECT_EQ(std::next(M.begin()), M.end());
+ EXPECT_EQ(M.begin()->first.first, 8U);
+ EXPECT_EQ(M.begin()->first.second, 10U);
+}
+
+TEST(IntervalMapTest, EraseSplittingBoth) {
+ // Check that removal of an interior subrange leaves both the leading and
+ // trailing residual subranges in-place.
+ IntervalMap<unsigned, unsigned, IntervalCoalescing::Enabled> M;
+
+ M.insert(7, 10, 42);
+ EXPECT_FALSE(M.empty());
+ M.erase(8, 9);
+ EXPECT_EQ(std::next(std::next(M.begin())), M.end());
+ EXPECT_EQ(M.begin()->first.first, 7U);
+ EXPECT_EQ(M.begin()->first.second, 8U);
+ EXPECT_EQ(std::next(M.begin())->first.first, 9U);
+ EXPECT_EQ(std::next(M.begin())->first.second, 10U);
+}
+
+TEST(IntervalMapTest, NonCoalescingMapPermitsNonComparableKeys) {
+ // Test that values that can't be equality-compared are still usable when
+ // coalescing is disabled and behave as expected.
+
+ struct S {}; // Struct with no equality comparison.
+
+ IntervalMap<unsigned, S, IntervalCoalescing::Disabled> M;
+
+ M.insert(7, 8, S());
+
+ EXPECT_FALSE(M.empty());
+ EXPECT_EQ(std::next(M.begin()), M.end());
+ EXPECT_EQ(M.find(7), M.begin());
+ EXPECT_EQ(M.find(8), M.end());
+}
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/interval_set_test.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/interval_set_test.cpp
new file mode 100644
index 000000000000..7971a55f271f
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/interval_set_test.cpp
@@ -0,0 +1,121 @@
+//===-- interval_set_test.cpp ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#include "interval_set.h"
+#include "gtest/gtest.h"
+
+using namespace __orc_rt;
+
+TEST(IntervalSetTest, DefaultConstructed) {
+ // Check that a default-constructed IntervalSet behaves as expected.
+ IntervalSet<unsigned, IntervalCoalescing::Enabled> S;
+
+ EXPECT_TRUE(S.empty());
+ EXPECT_TRUE(S.begin() == S.end());
+ EXPECT_TRUE(S.find(0) == S.end());
+}
+
+TEST(IntervalSetTest, InsertSingleElement) {
+ // Check that a set with a single element inserted behaves as expected.
+ IntervalSet<unsigned, IntervalCoalescing::Enabled> S;
+
+ S.insert(7, 8);
+
+ EXPECT_FALSE(S.empty());
+ EXPECT_EQ(std::next(S.begin()), S.end());
+ EXPECT_EQ(S.find(7), S.begin());
+ EXPECT_EQ(S.find(8), S.end());
+}
+
+TEST(IntervalSetTest, InsertCoalesceWithPrevious) {
+ // Check that insertions coalesce with previous ranges.
+ IntervalSet<unsigned, IntervalCoalescing::Enabled> S;
+
+ S.insert(7, 8);
+ S.insert(8, 9);
+
+ EXPECT_FALSE(S.empty());
+ EXPECT_EQ(std::next(S.begin()), S.end()); // Should see just one range.
+ EXPECT_EQ(S.find(7), S.find(8)); // 7 and 8 should point to same range.
+}
+
+TEST(IntervalSetTest, InsertCoalesceWithFollowing) {
+ // Check that insertions coalesce with following ranges.
+ IntervalSet<unsigned, IntervalCoalescing::Enabled> S;
+
+ S.insert(8, 9);
+ S.insert(7, 8);
+
+ EXPECT_FALSE(S.empty());
+ EXPECT_EQ(std::next(S.begin()), S.end()); // Should see just one range.
+ EXPECT_EQ(S.find(7), S.find(8)); // 7 and 8 should point to same range.
+}
+
+TEST(IntervalSetTest, InsertCoalesceBoth) {
+ // Check that insertions coalesce with ranges on both sides.
+ IntervalSet<unsigned, IntervalCoalescing::Enabled> S;
+
+ S.insert(7, 8);
+ S.insert(9, 10);
+
+ // Check no coalescing yet.
+ EXPECT_NE(S.find(7), S.find(9));
+
+ // Insert a 3rd range to trigger coalescing on both sides.
+ S.insert(8, 9);
+
+ EXPECT_FALSE(S.empty());
+ EXPECT_EQ(std::next(S.begin()), S.end()); // Should see just one range.
+ EXPECT_EQ(S.find(7), S.find(8)); // 7, 8, and 9 should point to same range.
+ EXPECT_EQ(S.find(8), S.find(9));
+}
+
+TEST(IntervalSetTest, EraseSplittingLeft) {
+ // Check that removal of a trailing subrange succeeds, but leaves the
+ // residual range in-place.
+ IntervalSet<unsigned, IntervalCoalescing::Enabled> S;
+
+ S.insert(7, 10);
+ EXPECT_FALSE(S.empty());
+ S.erase(9, 10);
+ EXPECT_EQ(std::next(S.begin()), S.end());
+ EXPECT_EQ(S.begin()->first, 7U);
+ EXPECT_EQ(S.begin()->second, 9U);
+}
+
+TEST(IntervalSetTest, EraseSplittingRight) {
+ // Check that removal of a leading subrange succeeds, but leaves the
+ // residual range in-place.
+ IntervalSet<unsigned, IntervalCoalescing::Enabled> S;
+
+ S.insert(7, 10);
+ EXPECT_FALSE(S.empty());
+ S.erase(7, 8);
+ EXPECT_EQ(std::next(S.begin()), S.end());
+ EXPECT_EQ(S.begin()->first, 8U);
+ EXPECT_EQ(S.begin()->second, 10U);
+}
+
+TEST(IntervalSetTest, EraseSplittingBoth) {
+ // Check that removal of an interior subrange leaves both the leading and
+ // trailing residual subranges in-place.
+ IntervalSet<unsigned, IntervalCoalescing::Enabled> S;
+
+ S.insert(7, 10);
+ EXPECT_FALSE(S.empty());
+ S.erase(8, 9);
+ EXPECT_EQ(std::next(std::next(S.begin())), S.end());
+ EXPECT_EQ(S.begin()->first, 7U);
+ EXPECT_EQ(S.begin()->second, 8U);
+ EXPECT_EQ(std::next(S.begin())->first, 9U);
+ EXPECT_EQ(std::next(S.begin())->second, 10U);
+}
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/orc_unit_test_main.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/orc_unit_test_main.cpp
new file mode 100644
index 000000000000..d02101704d65
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/orc_unit_test_main.cpp
@@ -0,0 +1,18 @@
+//===-- orc_unit_test_main.cpp --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime.
+//
+//===----------------------------------------------------------------------===//
+#include "gtest/gtest.h"
+
+int main(int argc, char **argv) {
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/simple_packed_serialization_test.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/simple_packed_serialization_test.cpp
new file mode 100644
index 000000000000..397114b4017e
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/simple_packed_serialization_test.cpp
@@ -0,0 +1,184 @@
+//===-- simple_packed_serialization_test.cpp ------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#include "simple_packed_serialization.h"
+#include "simple_packed_serialization_utils.h"
+#include "gtest/gtest.h"
+
+using namespace __orc_rt;
+
+TEST(SimplePackedSerializationTest, SPSOutputBuffer) {
+ constexpr unsigned NumBytes = 8;
+ char Buffer[NumBytes];
+ char Zero = 0;
+ SPSOutputBuffer OB(Buffer, NumBytes);
+
+ // Expect that we can write NumBytes of content.
+ for (unsigned I = 0; I != NumBytes; ++I) {
+ char C = I;
+ EXPECT_TRUE(OB.write(&C, 1));
+ }
+
+ // Expect an error when we attempt to write an extra byte.
+ EXPECT_FALSE(OB.write(&Zero, 1));
+
+ // Check that the buffer contains the expected content.
+ for (unsigned I = 0; I != NumBytes; ++I)
+ EXPECT_EQ(Buffer[I], (char)I);
+}
+
+TEST(SimplePackedSerializationTest, SPSInputBuffer) {
+ char Buffer[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
+ SPSInputBuffer IB(Buffer, sizeof(Buffer));
+
+ char C;
+ for (unsigned I = 0; I != sizeof(Buffer); ++I) {
+ EXPECT_TRUE(IB.read(&C, 1));
+ EXPECT_EQ(C, (char)I);
+ }
+
+ EXPECT_FALSE(IB.read(&C, 1));
+}
+
+template <typename T> static void testFixedIntegralTypeSerialization() {
+ blobSerializationRoundTrip<T, T>(0);
+ blobSerializationRoundTrip<T, T>(static_cast<T>(1));
+ if (std::is_signed<T>::value) {
+ blobSerializationRoundTrip<T, T>(static_cast<T>(-1));
+ blobSerializationRoundTrip<T, T>(std::numeric_limits<T>::min());
+ }
+ blobSerializationRoundTrip<T, T>(std::numeric_limits<T>::max());
+}
+
+TEST(SimplePackedSerializationTest, BoolSerialization) {
+ blobSerializationRoundTrip<bool, bool>(true);
+ blobSerializationRoundTrip<bool, bool>(false);
+}
+
+TEST(SimplePackedSerializationTest, CharSerialization) {
+ blobSerializationRoundTrip<char, char>((char)0x00);
+ blobSerializationRoundTrip<char, char>((char)0xAA);
+ blobSerializationRoundTrip<char, char>((char)0xFF);
+}
+
+TEST(SimplePackedSerializationTest, Int8Serialization) {
+ testFixedIntegralTypeSerialization<int8_t>();
+}
+
+TEST(SimplePackedSerializationTest, UInt8Serialization) {
+ testFixedIntegralTypeSerialization<uint8_t>();
+}
+
+TEST(SimplePackedSerializationTest, Int16Serialization) {
+ testFixedIntegralTypeSerialization<int16_t>();
+}
+
+TEST(SimplePackedSerializationTest, UInt16Serialization) {
+ testFixedIntegralTypeSerialization<uint16_t>();
+}
+
+TEST(SimplePackedSerializationTest, Int32Serialization) {
+ testFixedIntegralTypeSerialization<int32_t>();
+}
+
+TEST(SimplePackedSerializationTest, UInt32Serialization) {
+ testFixedIntegralTypeSerialization<uint32_t>();
+}
+
+TEST(SimplePackedSerializationTest, Int64Serialization) {
+ testFixedIntegralTypeSerialization<int64_t>();
+}
+
+TEST(SimplePackedSerializationTest, UInt64Serialization) {
+ testFixedIntegralTypeSerialization<uint64_t>();
+}
+
+TEST(SimplePackedSerializationTest, SequenceSerialization) {
+ std::vector<int32_t> V({1, 2, -47, 139});
+ blobSerializationRoundTrip<SPSSequence<int32_t>, std::vector<int32_t>>(V);
+}
+
+TEST(SimplePackedSerializationTest, StringViewCharSequenceSerialization) {
+ const char *HW = "Hello, world!";
+ blobSerializationRoundTrip<SPSString, std::string_view>(std::string_view(HW));
+}
+
+TEST(SimplePackedSerializationTest, SpanSerialization) {
+ const char Data[] = {3, 2, 1, 0, 1, 2, 3}; // Span should handle nulls.
+ span<const char> OutS(Data, sizeof(Data));
+
+ size_t Size = SPSArgList<SPSSequence<char>>::size(OutS);
+ auto Buffer = std::make_unique<char[]>(Size);
+ SPSOutputBuffer OB(Buffer.get(), Size);
+
+ EXPECT_TRUE(SPSArgList<SPSSequence<char>>::serialize(OB, OutS));
+
+ SPSInputBuffer IB(Buffer.get(), Size);
+
+ span<const char> InS;
+
+ EXPECT_TRUE(SPSArgList<SPSSequence<char>>::deserialize(IB, InS));
+
+ // Check that the serialized and deserialized values match.
+ EXPECT_EQ(InS.size(), OutS.size());
+ EXPECT_EQ(memcmp(OutS.data(), InS.data(), InS.size()), 0);
+
+ // Check that the span points directly to the input buffer.
+ EXPECT_EQ(InS.data(), Buffer.get() + sizeof(uint64_t));
+}
+
+TEST(SimplePackedSerializationTest, StdTupleSerialization) {
+ std::tuple<int32_t, std::string, bool> P(42, "foo", true);
+ blobSerializationRoundTrip<SPSTuple<int32_t, SPSString, bool>>(P);
+}
+
+TEST(SimplePackedSerializationTest, StdPairSerialization) {
+ std::pair<int32_t, std::string> P(42, "foo");
+ blobSerializationRoundTrip<SPSTuple<int32_t, SPSString>,
+ std::pair<int32_t, std::string>>(P);
+}
+
+TEST(SimplePackedSerializationTest, StdOptionalNoValueSerialization) {
+ std::optional<int64_t> NoValue;
+ blobSerializationRoundTrip<SPSOptional<int64_t>>(NoValue);
+}
+
+TEST(SimplePackedSerializationTest, StdOptionalValueSerialization) {
+ std::optional<int64_t> Value(42);
+ blobSerializationRoundTrip<SPSOptional<int64_t>>(Value);
+}
+
+TEST(SimplePackedSerializationTest, ArgListSerialization) {
+ using BAL = SPSArgList<bool, int32_t, SPSString>;
+
+ bool Arg1 = true;
+ int32_t Arg2 = 42;
+ std::string Arg3 = "foo";
+
+ size_t Size = BAL::size(Arg1, Arg2, Arg3);
+ auto Buffer = std::make_unique<char[]>(Size);
+ SPSOutputBuffer OB(Buffer.get(), Size);
+
+ EXPECT_TRUE(BAL::serialize(OB, Arg1, Arg2, Arg3));
+
+ SPSInputBuffer IB(Buffer.get(), Size);
+
+ bool ArgOut1;
+ int32_t ArgOut2;
+ std::string ArgOut3;
+
+ EXPECT_TRUE(BAL::deserialize(IB, ArgOut1, ArgOut2, ArgOut3));
+
+ EXPECT_EQ(Arg1, ArgOut1);
+ EXPECT_EQ(Arg2, ArgOut2);
+ EXPECT_EQ(Arg3, ArgOut3);
+}
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/simple_packed_serialization_utils.h b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/simple_packed_serialization_utils.h
new file mode 100644
index 000000000000..746be43d250b
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/simple_packed_serialization_utils.h
@@ -0,0 +1,34 @@
+//===-- simple_packed_serialization_utils.h -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_TEST_SIMPLE_PACKED_SERIALIZATION_UTILS_H
+#define ORC_RT_TEST_SIMPLE_PACKED_SERIALIZATION_UTILS_H
+
+#include "simple_packed_serialization.h"
+#include "gtest/gtest.h"
+
+template <typename SPSTagT, typename T>
+static void blobSerializationRoundTrip(const T &Value) {
+ using BST = __orc_rt::SPSSerializationTraits<SPSTagT, T>;
+
+ size_t Size = BST::size(Value);
+ auto Buffer = std::make_unique<char[]>(Size);
+ __orc_rt::SPSOutputBuffer OB(Buffer.get(), Size);
+
+ EXPECT_TRUE(BST::serialize(OB, Value));
+
+ __orc_rt::SPSInputBuffer IB(Buffer.get(), Size);
+
+ T DSValue;
+ EXPECT_TRUE(BST::deserialize(IB, DSValue));
+
+ EXPECT_EQ(Value, DSValue)
+ << "Incorrect value after serialization/deserialization round-trip";
+}
+
+#endif // ORC_RT_TEST_SIMPLE_PACKED_SERIALIZATION_UTILS_H \ No newline at end of file
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/string_pool_test.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/string_pool_test.cpp
new file mode 100644
index 000000000000..15ee2ce7d24d
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/string_pool_test.cpp
@@ -0,0 +1,66 @@
+//===---------- string_pool_test.cpp - Unit tests for StringPool ----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "string_pool.h"
+#include "gtest/gtest.h"
+
+using namespace __orc_rt;
+
+namespace {
+
+TEST(StringPool, UniquingAndComparisons) {
+ StringPool SP;
+ auto P1 = SP.intern("hello");
+
+ std::string S("hel");
+ S += "lo";
+ auto P2 = SP.intern(S);
+
+ auto P3 = SP.intern("goodbye");
+
+ EXPECT_EQ(P1, P2) << "Failed to unique entries";
+ EXPECT_NE(P1, P3) << "Unequal pooled strings comparing equal";
+
+ // We want to test that less-than comparison of PooledStringPtrs compiles,
+ // however we can't test the actual result as this is a pointer comparison and
+ // PooledStringPtr doesn't expose the underlying address of the string.
+ (void)(P1 < P3);
+}
+
+TEST(StringPool, Dereference) {
+ StringPool SP;
+ auto Foo = SP.intern("foo");
+ EXPECT_EQ(*Foo, "foo") << "Equality on dereferenced string failed";
+}
+
+TEST(StringPool, ClearDeadEntries) {
+ StringPool SP;
+ {
+ auto P1 = SP.intern("s1");
+ SP.clearDeadEntries();
+ EXPECT_FALSE(SP.empty()) << "\"s1\" entry in pool should still be retained";
+ }
+ SP.clearDeadEntries();
+ EXPECT_TRUE(SP.empty()) << "pool should be empty";
+}
+
+TEST(StringPool, NullPtr) {
+ // Make sure that we can default construct and then destroy a null
+ // PooledStringPtr.
+ PooledStringPtr Null;
+}
+
+TEST(StringPool, Hashable) {
+ StringPool SP;
+ PooledStringPtr P1 = SP.intern("s1");
+ PooledStringPtr Null;
+ EXPECT_NE(std::hash<PooledStringPtr>()(P1),
+ std::hash<PooledStringPtr>()(Null));
+}
+
+} // end anonymous namespace
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/wrapper_function_utils_test.cpp b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/wrapper_function_utils_test.cpp
new file mode 100644
index 000000000000..f10c5093046d
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/tests/unit/wrapper_function_utils_test.cpp
@@ -0,0 +1,184 @@
+//===-- wrapper_function_utils_test.cpp -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#include "wrapper_function_utils.h"
+#include "gtest/gtest.h"
+
+using namespace __orc_rt;
+
+namespace {
+constexpr const char *TestString = "test string";
+} // end anonymous namespace
+
+TEST(WrapperFunctionUtilsTest, DefaultWrapperFunctionResult) {
+ WrapperFunctionResult R;
+ EXPECT_TRUE(R.empty());
+ EXPECT_EQ(R.size(), 0U);
+ EXPECT_EQ(R.getOutOfBandError(), nullptr);
+}
+
+TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromCStruct) {
+ orc_rt_CWrapperFunctionResult CR =
+ orc_rt_CreateCWrapperFunctionResultFromString(TestString);
+ WrapperFunctionResult R(CR);
+ EXPECT_EQ(R.size(), strlen(TestString) + 1);
+ EXPECT_TRUE(strcmp(R.data(), TestString) == 0);
+ EXPECT_FALSE(R.empty());
+ EXPECT_EQ(R.getOutOfBandError(), nullptr);
+}
+
+TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromRange) {
+ auto R = WrapperFunctionResult::copyFrom(TestString, strlen(TestString) + 1);
+ EXPECT_EQ(R.size(), strlen(TestString) + 1);
+ EXPECT_TRUE(strcmp(R.data(), TestString) == 0);
+ EXPECT_FALSE(R.empty());
+ EXPECT_EQ(R.getOutOfBandError(), nullptr);
+}
+
+TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromCString) {
+ auto R = WrapperFunctionResult::copyFrom(TestString);
+ EXPECT_EQ(R.size(), strlen(TestString) + 1);
+ EXPECT_TRUE(strcmp(R.data(), TestString) == 0);
+ EXPECT_FALSE(R.empty());
+ EXPECT_EQ(R.getOutOfBandError(), nullptr);
+}
+
+TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromStdString) {
+ auto R = WrapperFunctionResult::copyFrom(std::string(TestString));
+ EXPECT_EQ(R.size(), strlen(TestString) + 1);
+ EXPECT_TRUE(strcmp(R.data(), TestString) == 0);
+ EXPECT_FALSE(R.empty());
+ EXPECT_EQ(R.getOutOfBandError(), nullptr);
+}
+
+TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromOutOfBandError) {
+ auto R = WrapperFunctionResult::createOutOfBandError(TestString);
+ EXPECT_FALSE(R.empty());
+ EXPECT_TRUE(strcmp(R.getOutOfBandError(), TestString) == 0);
+}
+
+TEST(WrapperFunctionUtilsTest, WrapperFunctionCCallCreateEmpty) {
+ EXPECT_TRUE(!!WrapperFunctionCall::Create<SPSArgList<>>(ExecutorAddr()));
+}
+
+static void voidNoop() {}
+
+static orc_rt_CWrapperFunctionResult voidNoopWrapper(const char *ArgData,
+ size_t ArgSize) {
+ return WrapperFunction<void()>::handle(ArgData, ArgSize, voidNoop).release();
+}
+
+static orc_rt_CWrapperFunctionResult addWrapper(const char *ArgData,
+ size_t ArgSize) {
+ return WrapperFunction<int32_t(int32_t, int32_t)>::handle(
+ ArgData, ArgSize,
+ [](int32_t X, int32_t Y) -> int32_t { return X + Y; })
+ .release();
+}
+
+extern "C" __orc_rt_Opaque __orc_rt_jit_dispatch_ctx{};
+
+extern "C" orc_rt_CWrapperFunctionResult
+__orc_rt_jit_dispatch(__orc_rt_Opaque *Ctx, const void *FnTag,
+ const char *ArgData, size_t ArgSize) {
+ using WrapperFunctionType =
+ orc_rt_CWrapperFunctionResult (*)(const char *, size_t);
+
+ return reinterpret_cast<WrapperFunctionType>(const_cast<void *>(FnTag))(
+ ArgData, ArgSize);
+}
+
+TEST(WrapperFunctionUtilsTest, WrapperFunctionCallVoidNoopAndHandle) {
+ EXPECT_FALSE(!!WrapperFunction<void()>::call((void *)&voidNoopWrapper));
+}
+
+TEST(WrapperFunctionUtilsTest, WrapperFunctionCallAddWrapperAndHandle) {
+ int32_t Result;
+ EXPECT_FALSE(!!WrapperFunction<int32_t(int32_t, int32_t)>::call(
+ (void *)&addWrapper, Result, 1, 2));
+ EXPECT_EQ(Result, (int32_t)3);
+}
+
+class AddClass {
+public:
+ AddClass(int32_t X) : X(X) {}
+ int32_t addMethod(int32_t Y) { return X + Y; }
+
+private:
+ int32_t X;
+};
+
+static orc_rt_CWrapperFunctionResult addMethodWrapper(const char *ArgData,
+ size_t ArgSize) {
+ return WrapperFunction<int32_t(SPSExecutorAddr, int32_t)>::handle(
+ ArgData, ArgSize, makeMethodWrapperHandler(&AddClass::addMethod))
+ .release();
+}
+
+TEST(WrapperFunctionUtilsTest, WrapperFunctionMethodCallAndHandleRet) {
+ int32_t Result;
+ AddClass AddObj(1);
+ EXPECT_FALSE(!!WrapperFunction<int32_t(SPSExecutorAddr, int32_t)>::call(
+ (void *)&addMethodWrapper, Result, ExecutorAddr::fromPtr(&AddObj), 2));
+ EXPECT_EQ(Result, (int32_t)3);
+}
+
+static orc_rt_CWrapperFunctionResult sumArrayWrapper(const char *ArgData,
+ size_t ArgSize) {
+ return WrapperFunction<int8_t(SPSExecutorAddrRange)>::handle(
+ ArgData, ArgSize,
+ [](ExecutorAddrRange R) {
+ int8_t Sum = 0;
+ for (char C : R.toSpan<char>())
+ Sum += C;
+ return Sum;
+ })
+ .release();
+}
+
+TEST(WrapperFunctionUtilsTest, SerializedWrapperFunctionCallTest) {
+ {
+ // Check wrapper function calls.
+ char A[] = {1, 2, 3, 4};
+
+ auto WFC =
+ cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>(
+ ExecutorAddr::fromPtr(sumArrayWrapper),
+ ExecutorAddrRange(ExecutorAddr::fromPtr(A),
+ ExecutorAddrDiff(sizeof(A)))));
+
+ WrapperFunctionResult WFR(WFC.run());
+ EXPECT_EQ(WFR.size(), 1U);
+ EXPECT_EQ(WFR.data()[0], 10);
+ }
+
+ {
+ // Check calls to void functions.
+ auto WFC =
+ cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>(
+ ExecutorAddr::fromPtr(voidNoopWrapper), ExecutorAddrRange()));
+ auto Err = WFC.runWithSPSRet<void>();
+ EXPECT_FALSE(!!Err);
+ }
+
+ {
+ // Check calls with arguments and return values.
+ auto WFC =
+ cantFail(WrapperFunctionCall::Create<SPSArgList<int32_t, int32_t>>(
+ ExecutorAddr::fromPtr(addWrapper), 2, 4));
+
+ int32_t Result = 0;
+ auto Err = WFC.runWithSPSRet<int32_t>(Result);
+ EXPECT_FALSE(!!Err);
+ EXPECT_EQ(Result, 6);
+ }
+}
diff --git a/contrib/llvm-project/compiler-rt/lib/orc/wrapper_function_utils.h b/contrib/llvm-project/compiler-rt/lib/orc/wrapper_function_utils.h
new file mode 100644
index 000000000000..8009438547a3
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/orc/wrapper_function_utils.h
@@ -0,0 +1,509 @@
+//===-- wrapper_function_utils.h - Utilities for wrapper funcs --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime support library.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_WRAPPER_FUNCTION_UTILS_H
+#define ORC_RT_WRAPPER_FUNCTION_UTILS_H
+
+#include "orc_rt/c_api.h"
+#include "common.h"
+#include "error.h"
+#include "executor_address.h"
+#include "simple_packed_serialization.h"
+#include <type_traits>
+
+namespace __orc_rt {
+
+/// C++ wrapper function result: Same as CWrapperFunctionResult but
+/// auto-releases memory.
+class WrapperFunctionResult {
+public:
+ /// Create a default WrapperFunctionResult.
+ WrapperFunctionResult() { orc_rt_CWrapperFunctionResultInit(&R); }
+
+ /// Create a WrapperFunctionResult from a CWrapperFunctionResult. This
+ /// instance takes ownership of the result object and will automatically
+ /// call dispose on the result upon destruction.
+ WrapperFunctionResult(orc_rt_CWrapperFunctionResult R) : R(R) {}
+
+ WrapperFunctionResult(const WrapperFunctionResult &) = delete;
+ WrapperFunctionResult &operator=(const WrapperFunctionResult &) = delete;
+
+ WrapperFunctionResult(WrapperFunctionResult &&Other) {
+ orc_rt_CWrapperFunctionResultInit(&R);
+ std::swap(R, Other.R);
+ }
+
+ WrapperFunctionResult &operator=(WrapperFunctionResult &&Other) {
+ orc_rt_CWrapperFunctionResult Tmp;
+ orc_rt_CWrapperFunctionResultInit(&Tmp);
+ std::swap(Tmp, Other.R);
+ std::swap(R, Tmp);
+ return *this;
+ }
+
+ ~WrapperFunctionResult() { orc_rt_DisposeCWrapperFunctionResult(&R); }
+
+ /// Relinquish ownership of and return the
+ /// orc_rt_CWrapperFunctionResult.
+ orc_rt_CWrapperFunctionResult release() {
+ orc_rt_CWrapperFunctionResult Tmp;
+ orc_rt_CWrapperFunctionResultInit(&Tmp);
+ std::swap(R, Tmp);
+ return Tmp;
+ }
+
+ /// Get a pointer to the data contained in this instance.
+ char *data() { return orc_rt_CWrapperFunctionResultData(&R); }
+
+ /// Returns the size of the data contained in this instance.
+ size_t size() const { return orc_rt_CWrapperFunctionResultSize(&R); }
+
+ /// Returns true if this value is equivalent to a default-constructed
+ /// WrapperFunctionResult.
+ bool empty() const { return orc_rt_CWrapperFunctionResultEmpty(&R); }
+
+ /// Create a WrapperFunctionResult with the given size and return a pointer
+ /// to the underlying memory.
+ static WrapperFunctionResult allocate(size_t Size) {
+ WrapperFunctionResult R;
+ R.R = orc_rt_CWrapperFunctionResultAllocate(Size);
+ return R;
+ }
+
+ /// Copy from the given char range.
+ static WrapperFunctionResult copyFrom(const char *Source, size_t Size) {
+ return orc_rt_CreateCWrapperFunctionResultFromRange(Source, Size);
+ }
+
+ /// Copy from the given null-terminated string (includes the null-terminator).
+ static WrapperFunctionResult copyFrom(const char *Source) {
+ return orc_rt_CreateCWrapperFunctionResultFromString(Source);
+ }
+
+ /// Copy from the given std::string (includes the null terminator).
+ static WrapperFunctionResult copyFrom(const std::string &Source) {
+ return copyFrom(Source.c_str());
+ }
+
+ /// Create an out-of-band error by copying the given string.
+ static WrapperFunctionResult createOutOfBandError(const char *Msg) {
+ return orc_rt_CreateCWrapperFunctionResultFromOutOfBandError(Msg);
+ }
+
+ /// Create an out-of-band error by copying the given string.
+ static WrapperFunctionResult createOutOfBandError(const std::string &Msg) {
+ return createOutOfBandError(Msg.c_str());
+ }
+
+ template <typename SPSArgListT, typename... ArgTs>
+ static WrapperFunctionResult fromSPSArgs(const ArgTs &...Args) {
+ auto Result = allocate(SPSArgListT::size(Args...));
+ SPSOutputBuffer OB(Result.data(), Result.size());
+ if (!SPSArgListT::serialize(OB, Args...))
+ return createOutOfBandError(
+ "Error serializing arguments to blob in call");
+ return Result;
+ }
+
+ /// If this value is an out-of-band error then this returns the error message,
+ /// otherwise returns nullptr.
+ const char *getOutOfBandError() const {
+ return orc_rt_CWrapperFunctionResultGetOutOfBandError(&R);
+ }
+
+private:
+ orc_rt_CWrapperFunctionResult R;
+};
+
+namespace detail {
+
+template <typename RetT> class WrapperFunctionHandlerCaller {
+public:
+ template <typename HandlerT, typename ArgTupleT, std::size_t... I>
+ static decltype(auto) call(HandlerT &&H, ArgTupleT &Args,
+ std::index_sequence<I...>) {
+ return std::forward<HandlerT>(H)(std::get<I>(Args)...);
+ }
+};
+
+template <> class WrapperFunctionHandlerCaller<void> {
+public:
+ template <typename HandlerT, typename ArgTupleT, std::size_t... I>
+ static SPSEmpty call(HandlerT &&H, ArgTupleT &Args,
+ std::index_sequence<I...>) {
+ std::forward<HandlerT>(H)(std::get<I>(Args)...);
+ return SPSEmpty();
+ }
+};
+
+template <typename WrapperFunctionImplT,
+ template <typename> class ResultSerializer, typename... SPSTagTs>
+class WrapperFunctionHandlerHelper
+ : public WrapperFunctionHandlerHelper<
+ decltype(&std::remove_reference_t<WrapperFunctionImplT>::operator()),
+ ResultSerializer, SPSTagTs...> {};
+
+template <typename RetT, typename... ArgTs,
+ template <typename> class ResultSerializer, typename... SPSTagTs>
+class WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
+ SPSTagTs...> {
+public:
+ using ArgTuple = std::tuple<std::decay_t<ArgTs>...>;
+ using ArgIndices = std::make_index_sequence<std::tuple_size<ArgTuple>::value>;
+
+ template <typename HandlerT>
+ static WrapperFunctionResult apply(HandlerT &&H, const char *ArgData,
+ size_t ArgSize) {
+ ArgTuple Args;
+ if (!deserialize(ArgData, ArgSize, Args, ArgIndices{}))
+ return WrapperFunctionResult::createOutOfBandError(
+ "Could not deserialize arguments for wrapper function call");
+
+ auto HandlerResult = WrapperFunctionHandlerCaller<RetT>::call(
+ std::forward<HandlerT>(H), Args, ArgIndices{});
+
+ return ResultSerializer<decltype(HandlerResult)>::serialize(
+ std::move(HandlerResult));
+ }
+
+private:
+ template <std::size_t... I>
+ static bool deserialize(const char *ArgData, size_t ArgSize, ArgTuple &Args,
+ std::index_sequence<I...>) {
+ SPSInputBuffer IB(ArgData, ArgSize);
+ return SPSArgList<SPSTagTs...>::deserialize(IB, std::get<I>(Args)...);
+ }
+};
+
+// Map function pointers to function types.
+template <typename RetT, typename... ArgTs,
+ template <typename> class ResultSerializer, typename... SPSTagTs>
+class WrapperFunctionHandlerHelper<RetT (*)(ArgTs...), ResultSerializer,
+ SPSTagTs...>
+ : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
+ SPSTagTs...> {};
+
+// Map non-const member function types to function types.
+template <typename ClassT, typename RetT, typename... ArgTs,
+ template <typename> class ResultSerializer, typename... SPSTagTs>
+class WrapperFunctionHandlerHelper<RetT (ClassT::*)(ArgTs...), ResultSerializer,
+ SPSTagTs...>
+ : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
+ SPSTagTs...> {};
+
+// Map const member function types to function types.
+template <typename ClassT, typename RetT, typename... ArgTs,
+ template <typename> class ResultSerializer, typename... SPSTagTs>
+class WrapperFunctionHandlerHelper<RetT (ClassT::*)(ArgTs...) const,
+ ResultSerializer, SPSTagTs...>
+ : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
+ SPSTagTs...> {};
+
+template <typename SPSRetTagT, typename RetT> class ResultSerializer {
+public:
+ static WrapperFunctionResult serialize(RetT Result) {
+ return WrapperFunctionResult::fromSPSArgs<SPSArgList<SPSRetTagT>>(Result);
+ }
+};
+
+template <typename SPSRetTagT> class ResultSerializer<SPSRetTagT, Error> {
+public:
+ static WrapperFunctionResult serialize(Error Err) {
+ return WrapperFunctionResult::fromSPSArgs<SPSArgList<SPSRetTagT>>(
+ toSPSSerializable(std::move(Err)));
+ }
+};
+
+template <typename SPSRetTagT, typename T>
+class ResultSerializer<SPSRetTagT, Expected<T>> {
+public:
+ static WrapperFunctionResult serialize(Expected<T> E) {
+ return WrapperFunctionResult::fromSPSArgs<SPSArgList<SPSRetTagT>>(
+ toSPSSerializable(std::move(E)));
+ }
+};
+
+template <typename SPSRetTagT, typename RetT> class ResultDeserializer {
+public:
+ static void makeSafe(RetT &Result) {}
+
+ static Error deserialize(RetT &Result, const char *ArgData, size_t ArgSize) {
+ SPSInputBuffer IB(ArgData, ArgSize);
+ if (!SPSArgList<SPSRetTagT>::deserialize(IB, Result))
+ return make_error<StringError>(
+ "Error deserializing return value from blob in call");
+ return Error::success();
+ }
+};
+
+template <> class ResultDeserializer<SPSError, Error> {
+public:
+ static void makeSafe(Error &Err) { cantFail(std::move(Err)); }
+
+ static Error deserialize(Error &Err, const char *ArgData, size_t ArgSize) {
+ SPSInputBuffer IB(ArgData, ArgSize);
+ SPSSerializableError BSE;
+ if (!SPSArgList<SPSError>::deserialize(IB, BSE))
+ return make_error<StringError>(
+ "Error deserializing return value from blob in call");
+ Err = fromSPSSerializable(std::move(BSE));
+ return Error::success();
+ }
+};
+
+template <typename SPSTagT, typename T>
+class ResultDeserializer<SPSExpected<SPSTagT>, Expected<T>> {
+public:
+ static void makeSafe(Expected<T> &E) { cantFail(E.takeError()); }
+
+ static Error deserialize(Expected<T> &E, const char *ArgData,
+ size_t ArgSize) {
+ SPSInputBuffer IB(ArgData, ArgSize);
+ SPSSerializableExpected<T> BSE;
+ if (!SPSArgList<SPSExpected<SPSTagT>>::deserialize(IB, BSE))
+ return make_error<StringError>(
+ "Error deserializing return value from blob in call");
+ E = fromSPSSerializable(std::move(BSE));
+ return Error::success();
+ }
+};
+
+} // end namespace detail
+
+template <typename SPSSignature> class WrapperFunction;
+
+template <typename SPSRetTagT, typename... SPSTagTs>
+class WrapperFunction<SPSRetTagT(SPSTagTs...)> {
+private:
+ template <typename RetT>
+ using ResultSerializer = detail::ResultSerializer<SPSRetTagT, RetT>;
+
+public:
+ template <typename RetT, typename... ArgTs>
+ static Error call(const void *FnTag, RetT &Result, const ArgTs &...Args) {
+
+ // RetT might be an Error or Expected value. Set the checked flag now:
+ // we don't want the user to have to check the unused result if this
+ // operation fails.
+ detail::ResultDeserializer<SPSRetTagT, RetT>::makeSafe(Result);
+
+ // Since the functions cannot be zero/unresolved on Windows, the following
+ // reference taking would always be non-zero, thus generating a compiler
+ // warning otherwise.
+#if !defined(_WIN32)
+ if (ORC_RT_UNLIKELY(!&__orc_rt_jit_dispatch_ctx))
+ return make_error<StringError>("__orc_rt_jit_dispatch_ctx not set");
+ if (ORC_RT_UNLIKELY(!&__orc_rt_jit_dispatch))
+ return make_error<StringError>("__orc_rt_jit_dispatch not set");
+#endif
+ auto ArgBuffer =
+ WrapperFunctionResult::fromSPSArgs<SPSArgList<SPSTagTs...>>(Args...);
+ if (const char *ErrMsg = ArgBuffer.getOutOfBandError())
+ return make_error<StringError>(ErrMsg);
+
+ WrapperFunctionResult ResultBuffer = __orc_rt_jit_dispatch(
+ &__orc_rt_jit_dispatch_ctx, FnTag, ArgBuffer.data(), ArgBuffer.size());
+ if (auto ErrMsg = ResultBuffer.getOutOfBandError())
+ return make_error<StringError>(ErrMsg);
+
+ return detail::ResultDeserializer<SPSRetTagT, RetT>::deserialize(
+ Result, ResultBuffer.data(), ResultBuffer.size());
+ }
+
+ template <typename HandlerT>
+ static WrapperFunctionResult handle(const char *ArgData, size_t ArgSize,
+ HandlerT &&Handler) {
+ using WFHH =
+ detail::WrapperFunctionHandlerHelper<std::remove_reference_t<HandlerT>,
+ ResultSerializer, SPSTagTs...>;
+ return WFHH::apply(std::forward<HandlerT>(Handler), ArgData, ArgSize);
+ }
+
+private:
+ template <typename T> static const T &makeSerializable(const T &Value) {
+ return Value;
+ }
+
+ static detail::SPSSerializableError makeSerializable(Error Err) {
+ return detail::toSPSSerializable(std::move(Err));
+ }
+
+ template <typename T>
+ static detail::SPSSerializableExpected<T> makeSerializable(Expected<T> E) {
+ return detail::toSPSSerializable(std::move(E));
+ }
+};
+
+template <typename... SPSTagTs>
+class WrapperFunction<void(SPSTagTs...)>
+ : private WrapperFunction<SPSEmpty(SPSTagTs...)> {
+public:
+ template <typename... ArgTs>
+ static Error call(const void *FnTag, const ArgTs &...Args) {
+ SPSEmpty BE;
+ return WrapperFunction<SPSEmpty(SPSTagTs...)>::call(FnTag, BE, Args...);
+ }
+
+ using WrapperFunction<SPSEmpty(SPSTagTs...)>::handle;
+};
+
+/// A function object that takes an ExecutorAddr as its first argument,
+/// casts that address to a ClassT*, then calls the given method on that
+/// pointer passing in the remaining function arguments. This utility
+/// removes some of the boilerplate from writing wrappers for method calls.
+///
+/// @code{.cpp}
+/// class MyClass {
+/// public:
+/// void myMethod(uint32_t, bool) { ... }
+/// };
+///
+/// // SPS Method signature -- note MyClass object address as first argument.
+/// using SPSMyMethodWrapperSignature =
+/// SPSTuple<SPSExecutorAddr, uint32_t, bool>;
+///
+/// WrapperFunctionResult
+/// myMethodCallWrapper(const char *ArgData, size_t ArgSize) {
+/// return WrapperFunction<SPSMyMethodWrapperSignature>::handle(
+/// ArgData, ArgSize, makeMethodWrapperHandler(&MyClass::myMethod));
+/// }
+/// @endcode
+///
+template <typename RetT, typename ClassT, typename... ArgTs>
+class MethodWrapperHandler {
+public:
+ using MethodT = RetT (ClassT::*)(ArgTs...);
+ MethodWrapperHandler(MethodT M) : M(M) {}
+ RetT operator()(ExecutorAddr ObjAddr, ArgTs &...Args) {
+ return (ObjAddr.toPtr<ClassT *>()->*M)(std::forward<ArgTs>(Args)...);
+ }
+
+private:
+ MethodT M;
+};
+
+/// Create a MethodWrapperHandler object from the given method pointer.
+template <typename RetT, typename ClassT, typename... ArgTs>
+MethodWrapperHandler<RetT, ClassT, ArgTs...>
+makeMethodWrapperHandler(RetT (ClassT::*Method)(ArgTs...)) {
+ return MethodWrapperHandler<RetT, ClassT, ArgTs...>(Method);
+}
+
+/// Represents a call to a wrapper function.
+class WrapperFunctionCall {
+public:
+ // FIXME: Switch to a SmallVector<char, 24> once ORC runtime has a
+ // smallvector.
+ using ArgDataBufferType = std::vector<char>;
+
+ /// Create a WrapperFunctionCall using the given SPS serializer to serialize
+ /// the arguments.
+ template <typename SPSSerializer, typename... ArgTs>
+ static Expected<WrapperFunctionCall> Create(ExecutorAddr FnAddr,
+ const ArgTs &...Args) {
+ ArgDataBufferType ArgData;
+ ArgData.resize(SPSSerializer::size(Args...));
+ SPSOutputBuffer OB(ArgData.empty() ? nullptr : ArgData.data(),
+ ArgData.size());
+ if (SPSSerializer::serialize(OB, Args...))
+ return WrapperFunctionCall(FnAddr, std::move(ArgData));
+ return make_error<StringError>("Cannot serialize arguments for "
+ "AllocActionCall");
+ }
+
+ WrapperFunctionCall() = default;
+
+ /// Create a WrapperFunctionCall from a target function and arg buffer.
+ WrapperFunctionCall(ExecutorAddr FnAddr, ArgDataBufferType ArgData)
+ : FnAddr(FnAddr), ArgData(std::move(ArgData)) {}
+
+ /// Returns the address to be called.
+ const ExecutorAddr &getCallee() const { return FnAddr; }
+
+ /// Returns the argument data.
+ const ArgDataBufferType &getArgData() const { return ArgData; }
+
+ /// WrapperFunctionCalls convert to true if the callee is non-null.
+ explicit operator bool() const { return !!FnAddr; }
+
+ /// Run call returning raw WrapperFunctionResult.
+ WrapperFunctionResult run() const {
+ using FnTy =
+ orc_rt_CWrapperFunctionResult(const char *ArgData, size_t ArgSize);
+ return WrapperFunctionResult(
+ FnAddr.toPtr<FnTy *>()(ArgData.data(), ArgData.size()));
+ }
+
+ /// Run call and deserialize result using SPS.
+ template <typename SPSRetT, typename RetT>
+ std::enable_if_t<!std::is_same<SPSRetT, void>::value, Error>
+ runWithSPSRet(RetT &RetVal) const {
+ auto WFR = run();
+ if (const char *ErrMsg = WFR.getOutOfBandError())
+ return make_error<StringError>(ErrMsg);
+ SPSInputBuffer IB(WFR.data(), WFR.size());
+ if (!SPSSerializationTraits<SPSRetT, RetT>::deserialize(IB, RetVal))
+ return make_error<StringError>("Could not deserialize result from "
+ "serialized wrapper function call");
+ return Error::success();
+ }
+
+ /// Overload for SPS functions returning void.
+ template <typename SPSRetT>
+ std::enable_if_t<std::is_same<SPSRetT, void>::value, Error>
+ runWithSPSRet() const {
+ SPSEmpty E;
+ return runWithSPSRet<SPSEmpty>(E);
+ }
+
+ /// Run call and deserialize an SPSError result. SPSError returns and
+ /// deserialization failures are merged into the returned error.
+ Error runWithSPSRetErrorMerged() const {
+ detail::SPSSerializableError RetErr;
+ if (auto Err = runWithSPSRet<SPSError>(RetErr))
+ return Err;
+ return detail::fromSPSSerializable(std::move(RetErr));
+ }
+
+private:
+ ExecutorAddr FnAddr;
+ std::vector<char> ArgData;
+};
+
+using SPSWrapperFunctionCall = SPSTuple<SPSExecutorAddr, SPSSequence<char>>;
+
+template <>
+class SPSSerializationTraits<SPSWrapperFunctionCall, WrapperFunctionCall> {
+public:
+ static size_t size(const WrapperFunctionCall &WFC) {
+ return SPSArgList<SPSExecutorAddr, SPSSequence<char>>::size(
+ WFC.getCallee(), WFC.getArgData());
+ }
+
+ static bool serialize(SPSOutputBuffer &OB, const WrapperFunctionCall &WFC) {
+ return SPSArgList<SPSExecutorAddr, SPSSequence<char>>::serialize(
+ OB, WFC.getCallee(), WFC.getArgData());
+ }
+
+ static bool deserialize(SPSInputBuffer &IB, WrapperFunctionCall &WFC) {
+ ExecutorAddr FnAddr;
+ WrapperFunctionCall::ArgDataBufferType ArgData;
+ if (!SPSWrapperFunctionCall::AsArgList::deserialize(IB, FnAddr, ArgData))
+ return false;
+ WFC = WrapperFunctionCall(FnAddr, std::move(ArgData));
+ return true;
+ }
+};
+
+} // end namespace __orc_rt
+
+#endif // ORC_RT_WRAPPER_FUNCTION_UTILS_H