1 //===- ExecutionUtils.h - Utilities for executing code in Orc ---*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // Contains utilities for executing code in Orc.
11 //===----------------------------------------------------------------------===//
13 #ifndef LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H
14 #define LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H
16 #include "llvm/ADT/StringMap.h"
17 #include "llvm/ADT/iterator_range.h"
18 #include "llvm/ExecutionEngine/JITSymbol.h"
19 #include "llvm/ExecutionEngine/Orc/Core.h"
20 #include "llvm/ExecutionEngine/Orc/OrcError.h"
21 #include "llvm/ExecutionEngine/RuntimeDyld.h"
22 #include "llvm/Object/Archive.h"
23 #include "llvm/Support/DynamicLibrary.h"
43 /// This iterator provides a convenient way to iterate over the elements
44 /// of an llvm.global_ctors/llvm.global_dtors instance.
46 /// The easiest way to get hold of instances of this class is to use the
47 /// getConstructors/getDestructors functions.
48 class CtorDtorIterator
{
50 /// Accessor for an element of the global_ctors/global_dtors array.
52 /// This class provides a read-only view of the element with any casts on
53 /// the function stripped away.
55 Element(unsigned Priority
, Function
*Func
, Value
*Data
)
56 : Priority(Priority
), Func(Func
), Data(Data
) {}
63 /// Construct an iterator instance. If End is true then this iterator
64 /// acts as the end of the range, otherwise it is the beginning.
65 CtorDtorIterator(const GlobalVariable
*GV
, bool End
);
67 /// Test iterators for equality.
68 bool operator==(const CtorDtorIterator
&Other
) const;
70 /// Test iterators for inequality.
71 bool operator!=(const CtorDtorIterator
&Other
) const;
73 /// Pre-increment iterator.
74 CtorDtorIterator
& operator++();
76 /// Post-increment iterator.
77 CtorDtorIterator
operator++(int);
79 /// Dereference iterator. The resulting value provides a read-only view
80 /// of this element of the global_ctors/global_dtors list.
81 Element
operator*() const;
84 const ConstantArray
*InitList
;
88 /// Create an iterator range over the entries of the llvm.global_ctors
90 iterator_range
<CtorDtorIterator
> getConstructors(const Module
&M
);
92 /// Create an iterator range over the entries of the llvm.global_ctors
94 iterator_range
<CtorDtorIterator
> getDestructors(const Module
&M
);
96 /// Convenience class for recording constructor/destructor names for
98 template <typename JITLayerT
>
99 class LegacyCtorDtorRunner
{
101 /// Construct a CtorDtorRunner for the given range using the given
102 /// name mangling function.
103 LLVM_ATTRIBUTE_DEPRECATED(
104 LegacyCtorDtorRunner(std::vector
<std::string
> CtorDtorNames
,
106 "ORCv1 utilities (utilities with the 'Legacy' prefix) are deprecated. "
107 "Please use the ORCv2 CtorDtorRunner utility instead");
109 LegacyCtorDtorRunner(ORCv1DeprecationAcknowledgement
,
110 std::vector
<std::string
> CtorDtorNames
, VModuleKey K
)
111 : CtorDtorNames(std::move(CtorDtorNames
)), K(K
) {}
113 /// Run the recorded constructors/destructors through the given JIT
115 Error
runViaLayer(JITLayerT
&JITLayer
) const {
116 using CtorDtorTy
= void (*)();
118 for (const auto &CtorDtorName
: CtorDtorNames
) {
119 if (auto CtorDtorSym
= JITLayer
.findSymbolIn(K
, CtorDtorName
, false)) {
120 if (auto AddrOrErr
= CtorDtorSym
.getAddress()) {
121 CtorDtorTy CtorDtor
=
122 reinterpret_cast<CtorDtorTy
>(static_cast<uintptr_t>(*AddrOrErr
));
125 return AddrOrErr
.takeError();
127 if (auto Err
= CtorDtorSym
.takeError())
130 return make_error
<JITSymbolNotFound
>(CtorDtorName
);
133 return Error::success();
137 std::vector
<std::string
> CtorDtorNames
;
141 template <typename JITLayerT
>
142 LegacyCtorDtorRunner
<JITLayerT
>::LegacyCtorDtorRunner(
143 std::vector
<std::string
> CtorDtorNames
, VModuleKey K
)
144 : CtorDtorNames(std::move(CtorDtorNames
)), K(K
) {}
146 class CtorDtorRunner
{
148 CtorDtorRunner(JITDylib
&JD
) : JD(JD
) {}
149 void add(iterator_range
<CtorDtorIterator
> CtorDtors
);
153 using CtorDtorList
= std::vector
<SymbolStringPtr
>;
154 using CtorDtorPriorityMap
= std::map
<unsigned, CtorDtorList
>;
157 CtorDtorPriorityMap CtorDtorsByPriority
;
160 /// Support class for static dtor execution. For hosted (in-process) JITs
163 /// If a __cxa_atexit function isn't found C++ programs that use static
164 /// destructors will fail to link. However, we don't want to use the host
165 /// process's __cxa_atexit, because it will schedule JIT'd destructors to run
166 /// after the JIT has been torn down, which is no good. This class makes it easy
167 /// to override __cxa_atexit (and the related __dso_handle).
169 /// To use, clients should manually call searchOverrides from their symbol
170 /// resolver. This should generally be done after attempting symbol resolution
171 /// inside the JIT, but before searching the host process's symbol table. When
172 /// the client determines that destructors should be run (generally at JIT
173 /// teardown or after a return from main), the runDestructors method should be
175 class LocalCXXRuntimeOverridesBase
{
177 /// Run any destructors recorded by the overriden __cxa_atexit function
178 /// (CXAAtExitOverride).
179 void runDestructors();
182 template <typename PtrTy
> JITTargetAddress
toTargetAddress(PtrTy
*P
) {
183 return static_cast<JITTargetAddress
>(reinterpret_cast<uintptr_t>(P
));
186 using DestructorPtr
= void (*)(void *);
187 using CXXDestructorDataPair
= std::pair
<DestructorPtr
, void *>;
188 using CXXDestructorDataPairList
= std::vector
<CXXDestructorDataPair
>;
189 CXXDestructorDataPairList DSOHandleOverride
;
190 static int CXAAtExitOverride(DestructorPtr Destructor
, void *Arg
,
194 class LegacyLocalCXXRuntimeOverrides
: public LocalCXXRuntimeOverridesBase
{
196 /// Create a runtime-overrides class.
197 template <typename MangleFtorT
>
198 LLVM_ATTRIBUTE_DEPRECATED(
199 LegacyLocalCXXRuntimeOverrides(const MangleFtorT
&Mangle
),
200 "ORCv1 utilities (utilities with the 'Legacy' prefix) are deprecated. "
201 "Please use the ORCv2 LocalCXXRuntimeOverrides utility instead");
203 template <typename MangleFtorT
>
204 LegacyLocalCXXRuntimeOverrides(ORCv1DeprecationAcknowledgement
,
205 const MangleFtorT
&Mangle
) {
206 addOverride(Mangle("__dso_handle"), toTargetAddress(&DSOHandleOverride
));
207 addOverride(Mangle("__cxa_atexit"), toTargetAddress(&CXAAtExitOverride
));
210 /// Search overrided symbols.
211 JITEvaluatedSymbol
searchOverrides(const std::string
&Name
) {
212 auto I
= CXXRuntimeOverrides
.find(Name
);
213 if (I
!= CXXRuntimeOverrides
.end())
214 return JITEvaluatedSymbol(I
->second
, JITSymbolFlags::Exported
);
219 void addOverride(const std::string
&Name
, JITTargetAddress Addr
) {
220 CXXRuntimeOverrides
.insert(std::make_pair(Name
, Addr
));
223 StringMap
<JITTargetAddress
> CXXRuntimeOverrides
;
226 template <typename MangleFtorT
>
227 LegacyLocalCXXRuntimeOverrides::LegacyLocalCXXRuntimeOverrides(
228 const MangleFtorT
&Mangle
) {
229 addOverride(Mangle("__dso_handle"), toTargetAddress(&DSOHandleOverride
));
230 addOverride(Mangle("__cxa_atexit"), toTargetAddress(&CXAAtExitOverride
));
233 class LocalCXXRuntimeOverrides
: public LocalCXXRuntimeOverridesBase
{
235 Error
enable(JITDylib
&JD
, MangleAndInterner
&Mangler
);
238 /// A utility class to expose symbols found via dlsym to the JIT.
240 /// If an instance of this class is attached to a JITDylib as a fallback
241 /// definition generator, then any symbol found in the given DynamicLibrary that
242 /// passes the 'Allow' predicate will be added to the JITDylib.
243 class DynamicLibrarySearchGenerator
: public JITDylib::DefinitionGenerator
{
245 using SymbolPredicate
= std::function
<bool(SymbolStringPtr
)>;
247 /// Create a DynamicLibrarySearchGenerator that searches for symbols in the
248 /// given sys::DynamicLibrary.
250 /// If the Allow predicate is given then only symbols matching the predicate
251 /// will be searched for. If the predicate is not given then all symbols will
253 DynamicLibrarySearchGenerator(sys::DynamicLibrary Dylib
, char GlobalPrefix
,
254 SymbolPredicate Allow
= SymbolPredicate());
256 /// Permanently loads the library at the given path and, on success, returns
257 /// a DynamicLibrarySearchGenerator that will search it for symbol definitions
258 /// in the library. On failure returns the reason the library failed to load.
259 static Expected
<std::unique_ptr
<DynamicLibrarySearchGenerator
>>
260 Load(const char *FileName
, char GlobalPrefix
,
261 SymbolPredicate Allow
= SymbolPredicate());
263 /// Creates a DynamicLibrarySearchGenerator that searches for symbols in
264 /// the current process.
265 static Expected
<std::unique_ptr
<DynamicLibrarySearchGenerator
>>
266 GetForCurrentProcess(char GlobalPrefix
,
267 SymbolPredicate Allow
= SymbolPredicate()) {
268 return Load(nullptr, GlobalPrefix
, std::move(Allow
));
271 Expected
<SymbolNameSet
> tryToGenerate(JITDylib
&JD
,
272 const SymbolNameSet
&Names
) override
;
275 sys::DynamicLibrary Dylib
;
276 SymbolPredicate Allow
;
280 /// A utility class to expose symbols from a static library.
282 /// If an instance of this class is attached to a JITDylib as a fallback
283 /// definition generator, then any symbol found in the archive will result in
284 /// the containing object being added to the JITDylib.
285 class StaticLibraryDefinitionGenerator
: public JITDylib::DefinitionGenerator
{
287 /// Try to create a StaticLibraryDefinitionGenerator from the given path.
289 /// This call will succeed if the file at the given path is a static library
290 /// is a valid archive, otherwise it will return an error.
291 static Expected
<std::unique_ptr
<StaticLibraryDefinitionGenerator
>>
292 Load(ObjectLayer
&L
, const char *FileName
);
294 /// Try to create a StaticLibrarySearchGenerator from the given memory buffer.
295 /// Thhis call will succeed if the buffer contains a valid archive, otherwise
296 /// it will return an error.
297 static Expected
<std::unique_ptr
<StaticLibraryDefinitionGenerator
>>
298 Create(ObjectLayer
&L
, std::unique_ptr
<MemoryBuffer
> ArchiveBuffer
);
300 Expected
<SymbolNameSet
> tryToGenerate(JITDylib
&JD
,
301 const SymbolNameSet
&Names
) override
;
304 StaticLibraryDefinitionGenerator(ObjectLayer
&L
,
305 std::unique_ptr
<MemoryBuffer
> ArchiveBuffer
,
309 std::unique_ptr
<MemoryBuffer
> ArchiveBuffer
;
310 object::Archive Archive
;
311 size_t UnrealizedObjects
= 0;
314 } // end namespace orc
315 } // end namespace llvm
317 #endif // LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H