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