• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/ADT/STLExtras.h"
19 #include "llvm/ExecutionEngine/ExecutionEngine.h"
20 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
21 #include <list>
22 #include <memory>
23 
24 namespace llvm {
25 namespace orc {
26 
27 class ObjectLinkingLayerBase {
28 protected:
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() = default;
~LinkedObjectSet()41     virtual ~LinkedObjectSet() {}
42 
43     virtual void finalize() = 0;
44 
45     virtual JITSymbol::GetAddressFtor
46     getSymbolMaterializer(std::string Name) = 0;
47 
48     virtual void mapSectionAddress(const void *LocalAddress,
49                                    TargetAddress TargetAddr) const = 0;
50 
getSymbol(StringRef Name,bool ExportedSymbolsOnly)51     JITSymbol getSymbol(StringRef Name, bool ExportedSymbolsOnly) {
52       auto SymEntry = SymbolTable.find(Name);
53       if (SymEntry == SymbolTable.end())
54         return nullptr;
55       if (!SymEntry->second.isExported() && ExportedSymbolsOnly)
56         return nullptr;
57       if (!Finalized)
58         return JITSymbol(getSymbolMaterializer(Name),
59                          SymEntry->second.getFlags());
60       return JITSymbol(SymEntry->second);
61     }
62   protected:
63     StringMap<RuntimeDyld::SymbolInfo> SymbolTable;
64     bool Finalized = false;
65   };
66 
67   typedef std::list<std::unique_ptr<LinkedObjectSet>> LinkedObjectSetListT;
68 
69 public:
70   /// @brief Handle to a set of loaded objects.
71   typedef LinkedObjectSetListT::iterator ObjSetHandleT;
72 };
73 
74 
75 /// @brief Default (no-op) action to perform when loading objects.
76 class DoNothingOnNotifyLoaded {
77 public:
78   template <typename ObjSetT, typename LoadResult>
operator()79   void operator()(ObjectLinkingLayerBase::ObjSetHandleT, const ObjSetT &,
80                   const LoadResult &) {}
81 };
82 
83 /// @brief Bare bones object linking layer.
84 ///
85 ///   This class is intended to be used as the base layer for a JIT. It allows
86 /// object files to be loaded into memory, linked, and the addresses of their
87 /// symbols queried. All objects added to this layer can see each other's
88 /// symbols.
89 template <typename NotifyLoadedFtor = DoNothingOnNotifyLoaded>
90 class ObjectLinkingLayer : public ObjectLinkingLayerBase {
91 public:
92 
93   /// @brief Functor for receiving finalization notifications.
94   typedef std::function<void(ObjSetHandleT)> NotifyFinalizedFtor;
95 
96 private:
97 
98   template <typename ObjSetT, typename MemoryManagerPtrT,
99             typename SymbolResolverPtrT, typename FinalizerFtor>
100   class ConcreteLinkedObjectSet : public LinkedObjectSet {
101   public:
ConcreteLinkedObjectSet(ObjSetT Objects,MemoryManagerPtrT MemMgr,SymbolResolverPtrT Resolver,FinalizerFtor Finalizer,bool ProcessAllSections)102     ConcreteLinkedObjectSet(ObjSetT Objects, MemoryManagerPtrT MemMgr,
103                             SymbolResolverPtrT Resolver,
104                             FinalizerFtor Finalizer,
105                             bool ProcessAllSections)
106       : MemMgr(std::move(MemMgr)),
107         PFC(llvm::make_unique<PreFinalizeContents>(std::move(Objects),
108                                                    std::move(Resolver),
109                                                    std::move(Finalizer),
110                                                    ProcessAllSections)) {
111       buildInitialSymbolTable(PFC->Objects);
112     }
113 
setHandle(ObjSetHandleT H)114     void setHandle(ObjSetHandleT H) {
115       PFC->Handle = H;
116     }
117 
finalize()118     void finalize() override {
119       assert(PFC && "mapSectionAddress called on finalized LinkedObjectSet");
120 
121       RuntimeDyld RTDyld(*MemMgr, *PFC->Resolver);
122       RTDyld.setProcessAllSections(PFC->ProcessAllSections);
123       PFC->RTDyld = &RTDyld;
124 
125       PFC->Finalizer(PFC->Handle, RTDyld, std::move(PFC->Objects),
126                      [&]() {
127                        this->updateSymbolTable(RTDyld);
128                        this->Finalized = true;
129                      });
130 
131       // Release resources.
132       PFC = nullptr;
133     }
134 
getSymbolMaterializer(std::string Name)135     JITSymbol::GetAddressFtor getSymbolMaterializer(std::string Name) override {
136       return
137         [this, Name]() {
138           // The symbol may be materialized between the creation of this lambda
139           // and its execution, so we need to double check.
140           if (!this->Finalized)
141             this->finalize();
142           return this->getSymbol(Name, false).getAddress();
143         };
144     }
145 
mapSectionAddress(const void * LocalAddress,TargetAddress TargetAddr)146     void mapSectionAddress(const void *LocalAddress,
147                            TargetAddress TargetAddr) const override {
148       assert(PFC && "mapSectionAddress called on finalized LinkedObjectSet");
149       assert(PFC->RTDyld && "mapSectionAddress called on raw LinkedObjectSet");
150       PFC->RTDyld->mapSectionAddress(LocalAddress, TargetAddr);
151     }
152 
153   private:
154 
buildInitialSymbolTable(const ObjSetT & Objects)155     void buildInitialSymbolTable(const ObjSetT &Objects) {
156       for (const auto &Obj : Objects)
157         for (auto &Symbol : getObject(*Obj).symbols()) {
158           if (Symbol.getFlags() & object::SymbolRef::SF_Undefined)
159             continue;
160           Expected<StringRef> SymbolName = Symbol.getName();
161           // FIXME: Raise an error for bad symbols.
162           if (!SymbolName) {
163             consumeError(SymbolName.takeError());
164             continue;
165           }
166           auto Flags = JITSymbol::flagsFromObjectSymbol(Symbol);
167           SymbolTable.insert(
168             std::make_pair(*SymbolName, RuntimeDyld::SymbolInfo(0, Flags)));
169         }
170     }
171 
updateSymbolTable(const RuntimeDyld & RTDyld)172     void updateSymbolTable(const RuntimeDyld &RTDyld) {
173       for (auto &SymEntry : SymbolTable)
174         SymEntry.second = RTDyld.getSymbol(SymEntry.first());
175     }
176 
177     // Contains the information needed prior to finalization: the object files,
178     // memory manager, resolver, and flags needed for RuntimeDyld.
179     struct PreFinalizeContents {
PreFinalizeContentsPreFinalizeContents180       PreFinalizeContents(ObjSetT Objects, SymbolResolverPtrT Resolver,
181                           FinalizerFtor Finalizer, bool ProcessAllSections)
182         : Objects(std::move(Objects)), Resolver(std::move(Resolver)),
183           Finalizer(std::move(Finalizer)),
184           ProcessAllSections(ProcessAllSections) {}
185 
186       ObjSetT Objects;
187       SymbolResolverPtrT Resolver;
188       FinalizerFtor Finalizer;
189       bool ProcessAllSections;
190       ObjSetHandleT Handle;
191       RuntimeDyld *RTDyld;
192     };
193 
194     MemoryManagerPtrT MemMgr;
195     std::unique_ptr<PreFinalizeContents> PFC;
196   };
197 
198   template <typename ObjSetT, typename MemoryManagerPtrT,
199             typename SymbolResolverPtrT, typename FinalizerFtor>
200   std::unique_ptr<
201     ConcreteLinkedObjectSet<ObjSetT, MemoryManagerPtrT,
202                             SymbolResolverPtrT, FinalizerFtor>>
createLinkedObjectSet(ObjSetT Objects,MemoryManagerPtrT MemMgr,SymbolResolverPtrT Resolver,FinalizerFtor Finalizer,bool ProcessAllSections)203   createLinkedObjectSet(ObjSetT Objects, MemoryManagerPtrT MemMgr,
204                         SymbolResolverPtrT Resolver,
205                         FinalizerFtor Finalizer,
206                         bool ProcessAllSections) {
207     typedef ConcreteLinkedObjectSet<ObjSetT, MemoryManagerPtrT,
208                                     SymbolResolverPtrT, FinalizerFtor> LOS;
209     return llvm::make_unique<LOS>(std::move(Objects), std::move(MemMgr),
210                                   std::move(Resolver), std::move(Finalizer),
211                                   ProcessAllSections);
212   }
213 
214 public:
215 
216   /// @brief LoadedObjectInfo list. Contains a list of owning pointers to
217   ///        RuntimeDyld::LoadedObjectInfo instances.
218   typedef std::vector<std::unique_ptr<RuntimeDyld::LoadedObjectInfo>>
219       LoadedObjInfoList;
220 
221   /// @brief Construct an ObjectLinkingLayer with the given NotifyLoaded,
222   ///        and NotifyFinalized functors.
223   ObjectLinkingLayer(
224       NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(),
225       NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor())
NotifyLoaded(std::move (NotifyLoaded))226       : NotifyLoaded(std::move(NotifyLoaded)),
227         NotifyFinalized(std::move(NotifyFinalized)),
228         ProcessAllSections(false) {}
229 
230   /// @brief Set the 'ProcessAllSections' flag.
231   ///
232   /// If set to true, all sections in each object file will be allocated using
233   /// the memory manager, rather than just the sections required for execution.
234   ///
235   /// This is kludgy, and may be removed in the future.
setProcessAllSections(bool ProcessAllSections)236   void setProcessAllSections(bool ProcessAllSections) {
237     this->ProcessAllSections = ProcessAllSections;
238   }
239 
240   /// @brief Add a set of objects (or archives) that will be treated as a unit
241   ///        for the purposes of symbol lookup and memory management.
242   ///
243   /// @return A handle that can be used to refer to the loaded objects (for
244   ///         symbol searching, finalization, freeing memory, etc.).
245   template <typename ObjSetT,
246             typename MemoryManagerPtrT,
247             typename SymbolResolverPtrT>
addObjectSet(ObjSetT Objects,MemoryManagerPtrT MemMgr,SymbolResolverPtrT Resolver)248   ObjSetHandleT addObjectSet(ObjSetT Objects,
249                              MemoryManagerPtrT MemMgr,
250                              SymbolResolverPtrT Resolver) {
251 
252     auto Finalizer = [&](ObjSetHandleT H, RuntimeDyld &RTDyld,
253                          const ObjSetT &Objs,
254                          std::function<void()> LOSHandleLoad) {
255       LoadedObjInfoList LoadedObjInfos;
256 
257       for (auto &Obj : Objs)
258         LoadedObjInfos.push_back(RTDyld.loadObject(this->getObject(*Obj)));
259 
260       LOSHandleLoad();
261 
262       this->NotifyLoaded(H, Objs, LoadedObjInfos);
263 
264       RTDyld.finalizeWithMemoryManagerLocking();
265 
266       if (this->NotifyFinalized)
267         this->NotifyFinalized(H);
268     };
269 
270     auto LOS =
271       createLinkedObjectSet(std::move(Objects), std::move(MemMgr),
272                             std::move(Resolver), std::move(Finalizer),
273                             ProcessAllSections);
274     // LOS is an owning-ptr. Keep a non-owning one so that we can set the handle
275     // below.
276     auto *LOSPtr = LOS.get();
277 
278     ObjSetHandleT Handle = LinkedObjSetList.insert(LinkedObjSetList.end(),
279                                                    std::move(LOS));
280     LOSPtr->setHandle(Handle);
281 
282     return Handle;
283   }
284 
285   /// @brief Remove the set of objects associated with handle H.
286   ///
287   ///   All memory allocated for the objects will be freed, and the sections and
288   /// symbols they provided will no longer be available. No attempt is made to
289   /// re-emit the missing symbols, and any use of these symbols (directly or
290   /// indirectly) will result in undefined behavior. If dependence tracking is
291   /// required to detect or resolve such issues it should be added at a higher
292   /// layer.
removeObjectSet(ObjSetHandleT H)293   void removeObjectSet(ObjSetHandleT H) {
294     // How do we invalidate the symbols in H?
295     LinkedObjSetList.erase(H);
296   }
297 
298   /// @brief Search for the given named symbol.
299   /// @param Name The name of the symbol to search for.
300   /// @param ExportedSymbolsOnly If true, search only for exported symbols.
301   /// @return A handle for the given named symbol, if it exists.
findSymbol(StringRef Name,bool ExportedSymbolsOnly)302   JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
303     for (auto I = LinkedObjSetList.begin(), E = LinkedObjSetList.end(); I != E;
304          ++I)
305       if (auto Symbol = findSymbolIn(I, Name, ExportedSymbolsOnly))
306         return Symbol;
307 
308     return nullptr;
309   }
310 
311   /// @brief Search for the given named symbol in the context of the set of
312   ///        loaded objects represented by the handle H.
313   /// @param H The handle for the object set to search in.
314   /// @param Name The name of the symbol to search for.
315   /// @param ExportedSymbolsOnly If true, search only for exported symbols.
316   /// @return A handle for the given named symbol, if it is found in the
317   ///         given object set.
findSymbolIn(ObjSetHandleT H,StringRef Name,bool ExportedSymbolsOnly)318   JITSymbol findSymbolIn(ObjSetHandleT H, StringRef Name,
319                          bool ExportedSymbolsOnly) {
320     return (*H)->getSymbol(Name, ExportedSymbolsOnly);
321   }
322 
323   /// @brief Map section addresses for the objects associated with the handle H.
mapSectionAddress(ObjSetHandleT H,const void * LocalAddress,TargetAddress TargetAddr)324   void mapSectionAddress(ObjSetHandleT H, const void *LocalAddress,
325                          TargetAddress TargetAddr) {
326     (*H)->mapSectionAddress(LocalAddress, TargetAddr);
327   }
328 
329   /// @brief Immediately emit and finalize the object set represented by the
330   ///        given handle.
331   /// @param H Handle for object set to emit/finalize.
emitAndFinalize(ObjSetHandleT H)332   void emitAndFinalize(ObjSetHandleT H) {
333     (*H)->finalize();
334   }
335 
336 private:
337 
getObject(const object::ObjectFile & Obj)338   static const object::ObjectFile& getObject(const object::ObjectFile &Obj) {
339     return Obj;
340   }
341 
342   template <typename ObjT>
343   static const object::ObjectFile&
getObject(const object::OwningBinary<ObjT> & Obj)344   getObject(const object::OwningBinary<ObjT> &Obj) {
345     return *Obj.getBinary();
346   }
347 
348   LinkedObjectSetListT LinkedObjSetList;
349   NotifyLoadedFtor NotifyLoaded;
350   NotifyFinalizedFtor NotifyFinalized;
351   bool ProcessAllSections;
352 };
353 
354 } // End namespace orc.
355 } // End namespace llvm
356 
357 #endif // LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H
358