1 //===- ExecutionUtils.h - Utilities for executing code in Orc ---*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // Contains utilities for executing code in Orc.
12 //===----------------------------------------------------------------------===//
14 #ifndef LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H
15 #define LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H
17 #include "llvm/ADT/StringMap.h"
18 #include "llvm/ADT/iterator_range.h"
19 #include "llvm/ExecutionEngine/JITSymbol.h"
20 #include "llvm/ExecutionEngine/RuntimeDyld.h"
21 #include "llvm/ExecutionEngine/Orc/OrcError.h"
38 /// @brief This iterator provides a convenient way to iterate over the elements
39 /// of an llvm.global_ctors/llvm.global_dtors instance.
41 /// The easiest way to get hold of instances of this class is to use the
42 /// getConstructors/getDestructors functions.
43 class CtorDtorIterator {
45 /// @brief Accessor for an element of the global_ctors/global_dtors array.
47 /// This class provides a read-only view of the element with any casts on
48 /// the function stripped away.
50 Element(unsigned Priority, Function *Func, Value *Data)
51 : Priority(Priority), Func(Func), Data(Data) {}
58 /// @brief Construct an iterator instance. If End is true then this iterator
59 /// acts as the end of the range, otherwise it is the beginning.
60 CtorDtorIterator(const GlobalVariable *GV, bool End);
62 /// @brief Test iterators for equality.
63 bool operator==(const CtorDtorIterator &Other) const;
65 /// @brief Test iterators for inequality.
66 bool operator!=(const CtorDtorIterator &Other) const;
68 /// @brief Pre-increment iterator.
69 CtorDtorIterator& operator++();
71 /// @brief Post-increment iterator.
72 CtorDtorIterator operator++(int);
74 /// @brief Dereference iterator. The resulting value provides a read-only view
75 /// of this element of the global_ctors/global_dtors list.
76 Element operator*() const;
79 const ConstantArray *InitList;
83 /// @brief Create an iterator range over the entries of the llvm.global_ctors
85 iterator_range<CtorDtorIterator> getConstructors(const Module &M);
87 /// @brief Create an iterator range over the entries of the llvm.global_ctors
89 iterator_range<CtorDtorIterator> getDestructors(const Module &M);
91 /// @brief Convenience class for recording constructor/destructor names for
93 template <typename JITLayerT>
94 class CtorDtorRunner {
96 /// @brief Construct a CtorDtorRunner for the given range using the given
97 /// name mangling function.
98 CtorDtorRunner(std::vector<std::string> CtorDtorNames,
99 typename JITLayerT::ModuleHandleT H)
100 : CtorDtorNames(std::move(CtorDtorNames)), H(H) {}
102 /// @brief Run the recorded constructors/destructors through the given JIT
104 Error runViaLayer(JITLayerT &JITLayer) const {
105 using CtorDtorTy = void (*)();
107 for (const auto &CtorDtorName : CtorDtorNames)
108 if (auto CtorDtorSym = JITLayer.findSymbolIn(H, CtorDtorName, false)) {
109 if (auto AddrOrErr = CtorDtorSym.getAddress()) {
110 CtorDtorTy CtorDtor =
111 reinterpret_cast<CtorDtorTy>(static_cast<uintptr_t>(*AddrOrErr));
114 return AddrOrErr.takeError();
116 if (auto Err = CtorDtorSym.takeError())
119 return make_error<JITSymbolNotFound>(CtorDtorName);
121 return Error::success();
125 std::vector<std::string> CtorDtorNames;
126 typename JITLayerT::ModuleHandleT H;
129 /// @brief Support class for static dtor execution. For hosted (in-process) JITs
132 /// If a __cxa_atexit function isn't found C++ programs that use static
133 /// destructors will fail to link. However, we don't want to use the host
134 /// process's __cxa_atexit, because it will schedule JIT'd destructors to run
135 /// after the JIT has been torn down, which is no good. This class makes it easy
136 /// to override __cxa_atexit (and the related __dso_handle).
138 /// To use, clients should manually call searchOverrides from their symbol
139 /// resolver. This should generally be done after attempting symbol resolution
140 /// inside the JIT, but before searching the host process's symbol table. When
141 /// the client determines that destructors should be run (generally at JIT
142 /// teardown or after a return from main), the runDestructors method should be
144 class LocalCXXRuntimeOverrides {
146 /// Create a runtime-overrides class.
147 template <typename MangleFtorT>
148 LocalCXXRuntimeOverrides(const MangleFtorT &Mangle) {
149 addOverride(Mangle("__dso_handle"), toTargetAddress(&DSOHandleOverride));
150 addOverride(Mangle("__cxa_atexit"), toTargetAddress(&CXAAtExitOverride));
153 /// Search overrided symbols.
154 JITEvaluatedSymbol searchOverrides(const std::string &Name) {
155 auto I = CXXRuntimeOverrides.find(Name);
156 if (I != CXXRuntimeOverrides.end())
157 return JITEvaluatedSymbol(I->second, JITSymbolFlags::Exported);
161 /// Run any destructors recorded by the overriden __cxa_atexit function
162 /// (CXAAtExitOverride).
163 void runDestructors();
166 template <typename PtrTy>
167 JITTargetAddress toTargetAddress(PtrTy* P) {
168 return static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(P));
171 void addOverride(const std::string &Name, JITTargetAddress Addr) {
172 CXXRuntimeOverrides.insert(std::make_pair(Name, Addr));
175 StringMap<JITTargetAddress> CXXRuntimeOverrides;
177 using DestructorPtr = void (*)(void *);
178 using CXXDestructorDataPair = std::pair<DestructorPtr, void *>;
179 using CXXDestructorDataPairList = std::vector<CXXDestructorDataPair>;
180 CXXDestructorDataPairList DSOHandleOverride;
181 static int CXAAtExitOverride(DestructorPtr Destructor, void *Arg,
185 } // end namespace orc
187 } // end namespace llvm
189 #endif // LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H