[MCJIT][Orc] Refactor RTDyldMemoryManager, weave RuntimeDyld::SymbolInfo through
[oota-llvm.git] / include / llvm / ExecutionEngine / Orc / ObjectLinkingLayer.h
1 //===- ObjectLinkingLayer.h - Add object files to a JIT process -*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // Contains the definition for the object layer of the JIT.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H
15 #define LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H
16
17 #include "JITSymbol.h"
18 #include "llvm/ExecutionEngine/ExecutionEngine.h"
19 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
20 #include <list>
21 #include <memory>
22
23 namespace llvm {
24 namespace orc {
25
26 class ObjectLinkingLayerBase {
27 protected:
28
29   /// @brief Holds a set of objects to be allocated/linked as a unit in the JIT.
30   ///
31   /// An instance of this class will be created for each set of objects added
32   /// via JITObjectLayer::addObjectSet. Deleting the instance (via
33   /// removeObjectSet) frees its memory, removing all symbol definitions that
34   /// had been provided by this instance. Higher level layers are responsible
35   /// for taking any action required to handle the missing symbols.
36   class LinkedObjectSet {
37     LinkedObjectSet(const LinkedObjectSet&) = delete;
38     void operator=(const LinkedObjectSet&) = delete;
39   public:
40     LinkedObjectSet(RuntimeDyld::MemoryManager &MemMgr,
41                     RuntimeDyld::SymbolResolver &Resolver)
42         : RTDyld(llvm::make_unique<RuntimeDyld>(MemMgr, Resolver)),
43           State(Raw) {}
44
45     virtual ~LinkedObjectSet() {}
46
47     std::unique_ptr<RuntimeDyld::LoadedObjectInfo>
48     addObject(const object::ObjectFile &Obj) {
49       return RTDyld->loadObject(Obj);
50     }
51
52     RuntimeDyld::SymbolInfo getSymbol(StringRef Name) const {
53       return RTDyld->getSymbol(Name);
54     }
55
56     bool NeedsFinalization() const { return (State == Raw); }
57
58     virtual void Finalize() = 0;
59
60     void mapSectionAddress(const void *LocalAddress, TargetAddress TargetAddr) {
61       assert((State != Finalized) &&
62              "Attempting to remap sections for finalized objects.");
63       RTDyld->mapSectionAddress(LocalAddress, TargetAddr);
64     }
65
66     void takeOwnershipOfBuffer(std::unique_ptr<MemoryBuffer> B) {
67       OwnedBuffers.push_back(std::move(B));
68     }
69
70   protected:
71     std::unique_ptr<RuntimeDyld> RTDyld;
72     enum { Raw, Finalizing, Finalized } State;
73
74     // FIXME: This ownership hack only exists because RuntimeDyldELF still
75     //        wants to be able to inspect the original object when resolving
76     //        relocations. As soon as that can be fixed this should be removed.
77     std::vector<std::unique_ptr<MemoryBuffer>> OwnedBuffers;
78   };
79
80   typedef std::list<std::unique_ptr<LinkedObjectSet>> LinkedObjectSetListT;
81
82 public:
83   /// @brief Handle to a set of loaded objects.
84   typedef LinkedObjectSetListT::iterator ObjSetHandleT;
85
86   // Ownership hack.
87   // FIXME: Remove this as soon as RuntimeDyldELF can apply relocations without
88   //        referencing the original object.
89   template <typename OwningMBSet>
90   void takeOwnershipOfBuffers(ObjSetHandleT H, OwningMBSet MBs) {
91     for (auto &MB : MBs)
92       (*H)->takeOwnershipOfBuffer(std::move(MB));
93   }
94
95 };
96
97 /// @brief Default (no-op) action to perform when loading objects.
98 class DoNothingOnNotifyLoaded {
99 public:
100   template <typename ObjSetT, typename LoadResult>
101   void operator()(ObjectLinkingLayerBase::ObjSetHandleT, const ObjSetT &,
102                   const LoadResult &) {}
103 };
104
105 /// @brief Bare bones object linking layer.
106 ///
107 ///   This class is intended to be used as the base layer for a JIT. It allows
108 /// object files to be loaded into memory, linked, and the addresses of their
109 /// symbols queried. All objects added to this layer can see each other's
110 /// symbols.
111 template <typename NotifyLoadedFtor = DoNothingOnNotifyLoaded>
112 class ObjectLinkingLayer : public ObjectLinkingLayerBase {
113 private:
114
115   template <typename MemoryManagerPtrT, typename SymbolResolverPtrT>
116   class ConcreteLinkedObjectSet : public LinkedObjectSet {
117   public:
118     ConcreteLinkedObjectSet(MemoryManagerPtrT MemMgr,
119                             SymbolResolverPtrT Resolver)
120       : LinkedObjectSet(*MemMgr, *Resolver), MemMgr(std::move(MemMgr)),
121         Resolver(std::move(Resolver)) { }
122
123     void Finalize() override {
124       State = Finalizing;
125       RTDyld->resolveRelocations();
126       RTDyld->registerEHFrames();
127       MemMgr->finalizeMemory();
128       OwnedBuffers.clear();
129       State = Finalized;
130     }
131
132   private:
133     MemoryManagerPtrT MemMgr;
134     SymbolResolverPtrT Resolver;
135   };
136
137   template <typename MemoryManagerPtrT, typename SymbolResolverPtrT>
138   std::unique_ptr<LinkedObjectSet>
139   createLinkedObjectSet(MemoryManagerPtrT MemMgr, SymbolResolverPtrT Resolver) {
140     typedef ConcreteLinkedObjectSet<MemoryManagerPtrT, SymbolResolverPtrT> LOS;
141     return llvm::make_unique<LOS>(std::move(MemMgr), std::move(Resolver));
142   }
143
144 public:
145
146   /// @brief LoadedObjectInfo list. Contains a list of owning pointers to
147   ///        RuntimeDyld::LoadedObjectInfo instances.
148   typedef std::vector<std::unique_ptr<RuntimeDyld::LoadedObjectInfo>>
149       LoadedObjInfoList;
150
151   /// @brief Functor for receiving finalization notifications.
152   typedef std::function<void(ObjSetHandleT)> NotifyFinalizedFtor;
153
154   /// @brief Construct an ObjectLinkingLayer with the given NotifyLoaded,
155   ///        and NotifyFinalized functors.
156   ObjectLinkingLayer(
157       NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(),
158       NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor())
159       : NotifyLoaded(std::move(NotifyLoaded)),
160         NotifyFinalized(std::move(NotifyFinalized)) {}
161
162   /// @brief Add a set of objects (or archives) that will be treated as a unit
163   ///        for the purposes of symbol lookup and memory management.
164   ///
165   /// @return A pair containing (1) A handle that can be used to free the memory
166   ///         allocated for the objects, and (2) a LoadedObjInfoList containing
167   ///         one LoadedObjInfo instance for each object at the corresponding
168   ///         index in the Objects list.
169   ///
170   ///   This version of this method allows the client to pass in an
171   /// RTDyldMemoryManager instance that will be used to allocate memory and look
172   /// up external symbol addresses for the given objects.
173   template <typename ObjSetT,
174             typename MemoryManagerPtrT,
175             typename SymbolResolverPtrT>
176   ObjSetHandleT addObjectSet(const ObjSetT &Objects,
177                              MemoryManagerPtrT MemMgr,
178                              SymbolResolverPtrT Resolver) {
179     ObjSetHandleT Handle =
180       LinkedObjSetList.insert(
181         LinkedObjSetList.end(),
182         createLinkedObjectSet(std::move(MemMgr), std::move(Resolver)));
183
184     LinkedObjectSet &LOS = **Handle;
185     LoadedObjInfoList LoadedObjInfos;
186
187     for (auto &Obj : Objects)
188       LoadedObjInfos.push_back(LOS.addObject(*Obj));
189
190     NotifyLoaded(Handle, Objects, LoadedObjInfos);
191
192     return Handle;
193   }
194
195   /// @brief Remove the set of objects associated with handle H.
196   ///
197   ///   All memory allocated for the objects will be freed, and the sections and
198   /// symbols they provided will no longer be available. No attempt is made to
199   /// re-emit the missing symbols, and any use of these symbols (directly or
200   /// indirectly) will result in undefined behavior. If dependence tracking is
201   /// required to detect or resolve such issues it should be added at a higher
202   /// layer.
203   void removeObjectSet(ObjSetHandleT H) {
204     // How do we invalidate the symbols in H?
205     LinkedObjSetList.erase(H);
206   }
207
208   /// @brief Search for the given named symbol.
209   /// @param Name The name of the symbol to search for.
210   /// @param ExportedSymbolsOnly If true, search only for exported symbols.
211   /// @return A handle for the given named symbol, if it exists.
212   JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
213     for (auto I = LinkedObjSetList.begin(), E = LinkedObjSetList.end(); I != E;
214          ++I)
215       if (auto Symbol = findSymbolIn(I, Name, ExportedSymbolsOnly))
216         return Symbol;
217
218     return nullptr;
219   }
220
221   /// @brief Search for the given named symbol in the context of the set of
222   ///        loaded objects represented by the handle H.
223   /// @param H The handle for the object set to search in.
224   /// @param Name The name of the symbol to search for.
225   /// @param ExportedSymbolsOnly If true, search only for exported symbols.
226   /// @return A handle for the given named symbol, if it is found in the
227   ///         given object set.
228   JITSymbol findSymbolIn(ObjSetHandleT H, StringRef Name,
229                          bool ExportedSymbolsOnly) {
230     if (auto Sym = (*H)->getSymbol(Name)) {
231       if (Sym.isExported() || !ExportedSymbolsOnly) {
232         auto Addr = Sym.getAddress();
233         auto Flags = Sym.getFlags();
234         if (!(*H)->NeedsFinalization()) {
235           // If this instance has already been finalized then we can just return
236           // the address.
237           return JITSymbol(Addr, Flags);
238         } else {
239           // If this instance needs finalization return a functor that will do
240           // it. The functor still needs to double-check whether finalization is
241           // required, in case someone else finalizes this set before the
242           // functor is called.
243           auto GetAddress =
244             [this, Addr, H]() {
245               if ((*H)->NeedsFinalization()) {
246                 (*H)->Finalize();
247                 if (NotifyFinalized)
248                   NotifyFinalized(H);
249               }
250               return Addr;
251             };
252           return JITSymbol(std::move(GetAddress), Flags);
253         }
254       }
255     }
256     return nullptr;
257   }
258
259   /// @brief Map section addresses for the objects associated with the handle H.
260   void mapSectionAddress(ObjSetHandleT H, const void *LocalAddress,
261                          TargetAddress TargetAddr) {
262     (*H)->mapSectionAddress(LocalAddress, TargetAddr);
263   }
264
265   /// @brief Immediately emit and finalize the object set represented by the
266   ///        given handle.
267   /// @param H Handle for object set to emit/finalize.
268   void emitAndFinalize(ObjSetHandleT H) {
269     (*H)->Finalize();
270     if (NotifyFinalized)
271       NotifyFinalized(H);
272   }
273
274 private:
275   LinkedObjectSetListT LinkedObjSetList;
276   NotifyLoadedFtor NotifyLoaded;
277   NotifyFinalizedFtor NotifyFinalized;
278 };
279
280 } // End namespace orc.
281 } // End namespace llvm
282
283 #endif // LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H