aboutsummaryrefslogtreecommitdiffstats
path: root/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h
blob: 9838991d6f41c7cf0a9b083f060fe311ac25c123 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
//===- ObjectLinkingLayer.h - Add object files to a JIT process -*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Contains the definition for the object layer of the JIT.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H
#define LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H

#include "JITSymbol.h"
#include "LookasideRTDyldMM.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include <list>
#include <memory>

namespace llvm {
namespace orc {

class ObjectLinkingLayerBase {
protected:

  /// @brief Holds a set of objects to be allocated/linked as a unit in the JIT.
  ///
  /// An instance of this class will be created for each set of objects added
  /// via JITObjectLayer::addObjectSet. Deleting the instance (via
  /// removeObjectSet) frees its memory, removing all symbol definitions that
  /// had been provided by this instance. Higher level layers are responsible
  /// for taking any action required to handle the missing symbols.
  class LinkedObjectSet {
    LinkedObjectSet(const LinkedObjectSet&) = delete;
    void operator=(const LinkedObjectSet&) = delete;
  public:
    LinkedObjectSet(std::unique_ptr<RTDyldMemoryManager> MM)
        : MM(std::move(MM)), RTDyld(llvm::make_unique<RuntimeDyld>(&*this->MM)),
          State(Raw) {}

    // MSVC 2012 cannot infer a move constructor, so write it out longhand.
    LinkedObjectSet(LinkedObjectSet &&O)
        : MM(std::move(O.MM)), RTDyld(std::move(O.RTDyld)), State(O.State) {}

    std::unique_ptr<RuntimeDyld::LoadedObjectInfo>
    addObject(const object::ObjectFile &Obj) {
      return RTDyld->loadObject(Obj);
    }

    RuntimeDyld::SymbolInfo getSymbol(StringRef Name) const {
      return RTDyld->getSymbol(Name);
    }

    bool NeedsFinalization() const { return (State == Raw); }

    void Finalize() {
      State = Finalizing;
      RTDyld->resolveRelocations();
      RTDyld->registerEHFrames();
      MM->finalizeMemory();
      OwnedBuffers.clear();
      State = Finalized;
    }

    void mapSectionAddress(const void *LocalAddress, TargetAddress TargetAddr) {
      assert((State != Finalized) &&
             "Attempting to remap sections for finalized objects.");
      RTDyld->mapSectionAddress(LocalAddress, TargetAddr);
    }

    void takeOwnershipOfBuffer(std::unique_ptr<MemoryBuffer> B) {
      OwnedBuffers.push_back(std::move(B));
    }

  private:
    std::unique_ptr<RTDyldMemoryManager> MM;
    std::unique_ptr<RuntimeDyld> RTDyld;
    enum { Raw, Finalizing, Finalized } State;

    // FIXME: This ownership hack only exists because RuntimeDyldELF still
    //        wants to be able to inspect the original object when resolving
    //        relocations. As soon as that can be fixed this should be removed.
    std::vector<std::unique_ptr<MemoryBuffer>> OwnedBuffers;
  };

  typedef std::list<LinkedObjectSet> LinkedObjectSetListT;

public:
  /// @brief Handle to a set of loaded objects.
  typedef LinkedObjectSetListT::iterator ObjSetHandleT;

  // Ownership hack.
  // FIXME: Remove this as soon as RuntimeDyldELF can apply relocations without
  //        referencing the original object.
  template <typename OwningMBSet>
  void takeOwnershipOfBuffers(ObjSetHandleT H, OwningMBSet MBs) {
    for (auto &MB : MBs)
      H->takeOwnershipOfBuffer(std::move(MB));
  }

};

/// @brief Default (no-op) action to perform when loading objects.
class DoNothingOnNotifyLoaded {
public:
  template <typename ObjSetT, typename LoadResult>
  void operator()(ObjectLinkingLayerBase::ObjSetHandleT, const ObjSetT &,
                  const LoadResult &) {}
};

/// @brief Bare bones object linking layer.
///
///   This class is intended to be used as the base layer for a JIT. It allows
/// object files to be loaded into memory, linked, and the addresses of their
/// symbols queried. All objects added to this layer can see each other's
/// symbols.
template <typename NotifyLoadedFtor = DoNothingOnNotifyLoaded>
class ObjectLinkingLayer : public ObjectLinkingLayerBase {
public:

  /// @brief LoadedObjectInfo list. Contains a list of owning pointers to
  ///        RuntimeDyld::LoadedObjectInfo instances.
  typedef std::vector<std::unique_ptr<RuntimeDyld::LoadedObjectInfo>>
      LoadedObjInfoList;

  /// @brief Functor to create RTDyldMemoryManager instances.
  typedef std::function<std::unique_ptr<RTDyldMemoryManager>()> CreateRTDyldMMFtor;

  /// @brief Functor for receiving finalization notifications.
  typedef std::function<void(ObjSetHandleT)> NotifyFinalizedFtor;

  /// @brief Construct an ObjectLinkingLayer with the given NotifyLoaded,
  ///        NotifyFinalized and CreateMemoryManager functors.
  ObjectLinkingLayer(
      CreateRTDyldMMFtor CreateMemoryManager = CreateRTDyldMMFtor(),
      NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(),
      NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor())
      : NotifyLoaded(std::move(NotifyLoaded)),
        NotifyFinalized(std::move(NotifyFinalized)),
        CreateMemoryManager(std::move(CreateMemoryManager)) {}

  /// @brief Add a set of objects (or archives) that will be treated as a unit
  ///        for the purposes of symbol lookup and memory management.
  ///
  /// @return A pair containing (1) A handle that can be used to free the memory
  ///         allocated for the objects, and (2) a LoadedObjInfoList containing
  ///         one LoadedObjInfo instance for each object at the corresponding
  ///         index in the Objects list.
  ///
  ///   This version of this method allows the client to pass in an
  /// RTDyldMemoryManager instance that will be used to allocate memory and look
  /// up external symbol addresses for the given objects.
  template <typename ObjSetT>
  ObjSetHandleT addObjectSet(const ObjSetT &Objects,
                             std::unique_ptr<RTDyldMemoryManager> MM) {

    if (!MM) {
      assert(CreateMemoryManager &&
             "No memory manager or memory manager creator provided.");
      MM = CreateMemoryManager();
    }

    ObjSetHandleT Handle = LinkedObjSetList.insert(
        LinkedObjSetList.end(), LinkedObjectSet(std::move(MM)));
    LinkedObjectSet &LOS = *Handle;
    LoadedObjInfoList LoadedObjInfos;

    for (auto &Obj : Objects)
      LoadedObjInfos.push_back(LOS.addObject(*Obj));

    NotifyLoaded(Handle, Objects, LoadedObjInfos);

    return Handle;
  }

  /// @brief Remove the set of objects associated with handle H.
  ///
  ///   All memory allocated for the objects will be freed, and the sections and
  /// symbols they provided will no longer be available. No attempt is made to
  /// re-emit the missing symbols, and any use of these symbols (directly or
  /// indirectly) will result in undefined behavior. If dependence tracking is
  /// required to detect or resolve such issues it should be added at a higher
  /// layer.
  void removeObjectSet(ObjSetHandleT H) {
    // How do we invalidate the symbols in H?
    LinkedObjSetList.erase(H);
  }

  /// @brief Search for the given named symbol.
  /// @param Name The name of the symbol to search for.
  /// @param ExportedSymbolsOnly If true, search only for exported symbols.
  /// @return A handle for the given named symbol, if it exists.
  JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
    for (auto I = LinkedObjSetList.begin(), E = LinkedObjSetList.end(); I != E;
         ++I)
      if (auto Symbol = findSymbolIn(I, Name, ExportedSymbolsOnly))
        return Symbol;

    return nullptr;
  }

  /// @brief Search for the given named symbol in the context of the set of
  ///        loaded objects represented by the handle H.
  /// @param H The handle for the object set to search in.
  /// @param Name The name of the symbol to search for.
  /// @param ExportedSymbolsOnly If true, search only for exported symbols.
  /// @return A handle for the given named symbol, if it is found in the
  ///         given object set.
  JITSymbol findSymbolIn(ObjSetHandleT H, StringRef Name,
                         bool ExportedSymbolsOnly) {
    if (auto Sym = H->getSymbol(Name)) {
      if (Sym.isExported() || !ExportedSymbolsOnly) {
        auto Addr = Sym.getAddress();
        auto Flags = Sym.getFlags();
        if (!H->NeedsFinalization()) {
          // If this instance has already been finalized then we can just return
          // the address.
          return JITSymbol(Addr, Flags);
        } else {
          // If this instance needs finalization return a functor that will do
          // it. The functor still needs to double-check whether finalization is
          // required, in case someone else finalizes this set before the
          // functor is called.
          auto GetAddress = 
            [this, Addr, H]() {
              if (H->NeedsFinalization()) {
                H->Finalize();
                if (NotifyFinalized)
                  NotifyFinalized(H);
              }
              return Addr;
            };
          return JITSymbol(std::move(GetAddress), Flags);
        }
      }
    }
    return nullptr;
  }

  /// @brief Map section addresses for the objects associated with the handle H.
  void mapSectionAddress(ObjSetHandleT H, const void *LocalAddress,
                         TargetAddress TargetAddr) {
    H->mapSectionAddress(LocalAddress, TargetAddr);
  }

  /// @brief Immediately emit and finalize the object set represented by the
  ///        given handle.
  /// @param H Handle for object set to emit/finalize.
  void emitAndFinalize(ObjSetHandleT H) {
    H->Finalize();
    if (NotifyFinalized)
      NotifyFinalized(H);
  }

private:
  LinkedObjectSetListT LinkedObjSetList;
  NotifyLoadedFtor NotifyLoaded;
  NotifyFinalizedFtor NotifyFinalized;
  CreateRTDyldMMFtor CreateMemoryManager;
};

} // End namespace orc.
} // End namespace llvm

#endif // LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H