[Orc] Make the ObjectLinkingLayer take ownership of object files until
[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 "LookasideRTDyldMM.h"
18 #include "llvm/ExecutionEngine/ExecutionEngine.h"
19 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
20 #include <list>
21 #include <memory>
22
23 namespace llvm {
24
25 class ObjectLinkingLayerBase {
26 protected:
27   /// @brief Holds a set of objects to be allocated/linked as a unit in the JIT.
28   ///
29   /// An instance of this class will be created for each set of objects added
30   /// via JITObjectLayer::addObjectSet. Deleting the instance (via
31   /// removeObjectSet) frees its memory, removing all symbol definitions that
32   /// had been provided by this instance. Higher level layers are responsible
33   /// for taking any action required to handle the missing symbols.
34   class LinkedObjectSet {
35     LinkedObjectSet(const LinkedObjectSet&) LLVM_DELETED_FUNCTION;
36     void operator=(const LinkedObjectSet&) LLVM_DELETED_FUNCTION;
37   public:
38     LinkedObjectSet(std::unique_ptr<RTDyldMemoryManager> MM)
39         : MM(std::move(MM)), RTDyld(llvm::make_unique<RuntimeDyld>(&*this->MM)),
40           State(Raw) {}
41
42     // MSVC 2012 cannot infer a move constructor, so write it out longhand.
43     LinkedObjectSet(LinkedObjectSet &&O)
44         : MM(std::move(O.MM)), RTDyld(std::move(O.RTDyld)), State(O.State) {}
45
46     std::unique_ptr<RuntimeDyld::LoadedObjectInfo>
47     addObject(const object::ObjectFile &Obj) {
48       return RTDyld->loadObject(Obj);
49     }
50
51     uint64_t getSymbolAddress(StringRef Name, bool ExportedSymbolsOnly) {
52       if (ExportedSymbolsOnly)
53         return RTDyld->getExportedSymbolLoadAddress(Name);
54       return RTDyld->getSymbolLoadAddress(Name);
55     }
56
57     bool NeedsFinalization() const { return (State == Raw); }
58
59     void Finalize() {
60       State = Finalizing;
61       RTDyld->resolveRelocations();
62       RTDyld->registerEHFrames();
63       MM->finalizeMemory();
64       OwnedBuffers.clear();
65       State = Finalized;
66     }
67
68     void mapSectionAddress(const void *LocalAddress, uint64_t TargetAddress) {
69       assert((State != Finalized) &&
70              "Attempting to remap sections for finalized objects.");
71       RTDyld->mapSectionAddress(LocalAddress, TargetAddress);
72     }
73
74     void takeOwnershipOfBuffer(std::unique_ptr<MemoryBuffer> B) {
75       OwnedBuffers.push_back(std::move(B));
76     }
77
78   private:
79     std::unique_ptr<RTDyldMemoryManager> MM;
80     std::unique_ptr<RuntimeDyld> RTDyld;
81     enum { Raw, Finalizing, Finalized } State;
82
83     // FIXME: This ownership hack only exists because RuntimeDyldELF still
84     //        wants to be able to inspect the original object when resolving
85     //        relocations. As soon as that can be fixed this should be removed.
86     std::vector<std::unique_ptr<MemoryBuffer>> OwnedBuffers;
87   };
88
89   typedef std::list<LinkedObjectSet> LinkedObjectSetListT;
90
91 public:
92   /// @brief Handle to a set of loaded objects.
93   typedef LinkedObjectSetListT::iterator ObjSetHandleT;
94
95   // Ownership hack.
96   // FIXME: Remove this as soon as RuntimeDyldELF can apply relocations without
97   //        referencing the original object.
98   template <typename OwningMBSet>
99   void takeOwnershipOfBuffers(ObjSetHandleT H, OwningMBSet MBs) {
100     for (auto &MB : MBs)
101       H->takeOwnershipOfBuffer(std::move(MB));
102   }
103
104 };
105
106 /// @brief Default (no-op) action to perform when loading objects.
107 class DoNothingOnNotifyLoaded {
108 public:
109   template <typename ObjSetT, typename LoadResult>
110   void operator()(ObjectLinkingLayerBase::ObjSetHandleT, const ObjSetT &,
111                   const LoadResult &) {}
112 };
113
114 /// @brief Bare bones object linking layer.
115 ///
116 ///   This class is intended to be used as the base layer for a JIT. It allows
117 /// object files to be loaded into memory, linked, and the addresses of their
118 /// symbols queried. All objects added to this layer can see each other's
119 /// symbols.
120 template <typename NotifyLoadedFtor = DoNothingOnNotifyLoaded>
121 class ObjectLinkingLayer : public ObjectLinkingLayerBase {
122 public:
123
124   /// @brief LoadedObjectInfo list. Contains a list of owning pointers to
125   ///        RuntimeDyld::LoadedObjectInfo instances.
126   typedef std::vector<std::unique_ptr<RuntimeDyld::LoadedObjectInfo>>
127       LoadedObjInfoList;
128
129   /// @brief Functor to create RTDyldMemoryManager instances.
130   typedef std::function<std::unique_ptr<RTDyldMemoryManager>()> CreateRTDyldMMFtor;
131
132   /// @brief Functor for receiving finalization notifications.
133   typedef std::function<void(ObjSetHandleT)> NotifyFinalizedFtor;
134
135   /// @brief Construct an ObjectLinkingLayer with the given NotifyLoaded,
136   ///        NotifyFinalized and CreateMemoryManager functors.
137   ObjectLinkingLayer(
138       CreateRTDyldMMFtor CreateMemoryManager = CreateRTDyldMMFtor(),
139       NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(),
140       NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor())
141       : NotifyLoaded(std::move(NotifyLoaded)),
142         NotifyFinalized(std::move(NotifyFinalized)),
143         CreateMemoryManager(std::move(CreateMemoryManager)) {}
144
145   /// @brief Add a set of objects (or archives) that will be treated as a unit
146   ///        for the purposes of symbol lookup and memory management.
147   ///
148   /// @return A pair containing (1) A handle that can be used to free the memory
149   ///         allocated for the objects, and (2) a LoadedObjInfoList containing
150   ///         one LoadedObjInfo instance for each object at the corresponding
151   ///         index in the Objects list.
152   ///
153   ///   This version of this method allows the client to pass in an
154   /// RTDyldMemoryManager instance that will be used to allocate memory and look
155   /// up external symbol addresses for the given objects.
156   template <typename ObjSetT>
157   ObjSetHandleT addObjectSet(const ObjSetT &Objects,
158                              std::unique_ptr<RTDyldMemoryManager> MM) {
159
160     if (!MM) {
161       assert(CreateMemoryManager &&
162              "No memory manager or memory manager creator provided.");
163       MM = CreateMemoryManager();
164     }
165
166     ObjSetHandleT Handle = LinkedObjSetList.insert(
167         LinkedObjSetList.end(), LinkedObjectSet(std::move(MM)));
168     LinkedObjectSet &LOS = *Handle;
169     LoadedObjInfoList LoadedObjInfos;
170
171     for (auto &Obj : Objects)
172       LoadedObjInfos.push_back(LOS.addObject(*Obj));
173
174     NotifyLoaded(Handle, Objects, LoadedObjInfos);
175
176     return Handle;
177   }
178
179   /// @brief Map section addresses for the objects associated with the handle H.
180   void mapSectionAddress(ObjSetHandleT H, const void *LocalAddress,
181                          uint64_t TargetAddress) {
182     H->mapSectionAddress(LocalAddress, TargetAddress);
183   }
184
185   /// @brief Remove the set of objects associated with handle H.
186   ///
187   ///   All memory allocated for the objects will be freed, and the sections and
188   /// symbols they provided will no longer be available. No attempt is made to
189   /// re-emit the missing symbols, and any use of these symbols (directly or
190   /// indirectly) will result in undefined behavior. If dependence tracking is
191   /// required to detect or resolve such issues it should be added at a higher
192   /// layer.
193   void removeObjectSet(ObjSetHandleT H) {
194     // How do we invalidate the symbols in H?
195     LinkedObjSetList.erase(H);
196   }
197
198   /// @brief Get the address of a loaded symbol.
199   ///
200   /// @return The address in the target process's address space of the named
201   ///         symbol. Null if no such symbol is known.
202   ///
203   ///   This method will trigger the finalization of the linked object set
204   /// containing the definition of the given symbol, if it is found.
205   uint64_t getSymbolAddress(StringRef Name, bool ExportedSymbolsOnly) {
206     for (auto I = LinkedObjSetList.begin(), E = LinkedObjSetList.end(); I != E;
207          ++I)
208       if (uint64_t Addr = lookupSymbolAddressIn(I, Name, ExportedSymbolsOnly))
209         return Addr;
210
211     return 0;
212   }
213
214   /// @brief Search for a given symbol in the context of the set of loaded
215   ///        objects represented by the handle H.
216   ///
217   /// @return The address in the target process's address space of the named
218   ///         symbol. Null if the given object set does not contain a definition
219   ///         of this symbol.
220   ///
221   ///   This method will trigger the finalization of the linked object set
222   /// represented by the handle H if that set contains the requested symbol.
223   uint64_t lookupSymbolAddressIn(ObjSetHandleT H, StringRef Name,
224                                  bool ExportedSymbolsOnly) {
225     if (uint64_t Addr = H->getSymbolAddress(Name, ExportedSymbolsOnly)) {
226       if (H->NeedsFinalization()) {
227         H->Finalize();
228         if (NotifyFinalized)
229           NotifyFinalized(H);
230       }
231       return Addr;
232     }
233     return 0;
234   }
235
236 private:
237   LinkedObjectSetListT LinkedObjSetList;
238   NotifyLoadedFtor NotifyLoaded;
239   NotifyFinalizedFtor NotifyFinalized;
240   CreateRTDyldMMFtor CreateMemoryManager;
241 };
242
243 } // end namespace llvm
244
245 #endif // LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H