1351278Sdim//===-- ObjectLinkingLayer.h - JITLink-based jit linking layer --*- C++ -*-===//
2351278Sdim//
3351278Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4351278Sdim// See https://llvm.org/LICENSE.txt for license information.
5351278Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6351278Sdim//
7351278Sdim//===----------------------------------------------------------------------===//
8351278Sdim//
9351278Sdim// Contains the definition for an JITLink-based, in-process object linking
10351278Sdim// layer.
11351278Sdim//
12351278Sdim//===----------------------------------------------------------------------===//
13351278Sdim
14351278Sdim#ifndef LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H
15351278Sdim#define LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H
16351278Sdim
17351278Sdim#include "llvm/ADT/STLExtras.h"
18351278Sdim#include "llvm/ADT/StringMap.h"
19351278Sdim#include "llvm/ADT/StringRef.h"
20351278Sdim#include "llvm/ExecutionEngine/JITLink/JITLink.h"
21351278Sdim#include "llvm/ExecutionEngine/JITSymbol.h"
22351278Sdim#include "llvm/ExecutionEngine/Orc/Core.h"
23351278Sdim#include "llvm/ExecutionEngine/Orc/Layer.h"
24351278Sdim#include "llvm/Support/Error.h"
25351278Sdim#include <algorithm>
26351278Sdim#include <cassert>
27351278Sdim#include <functional>
28351278Sdim#include <list>
29351278Sdim#include <memory>
30351278Sdim#include <string>
31351278Sdim#include <utility>
32351278Sdim#include <vector>
33351278Sdim
34351278Sdimnamespace llvm {
35351278Sdim
36351278Sdimnamespace jitlink {
37351278Sdimclass EHFrameRegistrar;
38351278Sdim} // namespace jitlink
39351278Sdim
40351278Sdimnamespace object {
41351278Sdimclass ObjectFile;
42351278Sdim} // namespace object
43351278Sdim
44351278Sdimnamespace orc {
45351278Sdim
46351278Sdimclass ObjectLinkingLayerJITLinkContext;
47351278Sdim
48351278Sdim/// An ObjectLayer implementation built on JITLink.
49351278Sdim///
50351278Sdim/// Clients can use this class to add relocatable object files to an
51351278Sdim/// ExecutionSession, and it typically serves as the base layer (underneath
52351278Sdim/// a compiling layer like IRCompileLayer) for the rest of the JIT.
53351278Sdimclass ObjectLinkingLayer : public ObjectLayer {
54351278Sdim  friend class ObjectLinkingLayerJITLinkContext;
55351278Sdim
56351278Sdimpublic:
57351278Sdim  /// Plugin instances can be added to the ObjectLinkingLayer to receive
58351278Sdim  /// callbacks when code is loaded or emitted, and when JITLink is being
59351278Sdim  /// configured.
60351278Sdim  class Plugin {
61351278Sdim  public:
62351278Sdim    virtual ~Plugin();
63351278Sdim    virtual void modifyPassConfig(MaterializationResponsibility &MR,
64351278Sdim                                  const Triple &TT,
65351278Sdim                                  jitlink::PassConfiguration &Config) {}
66351278Sdim    virtual void notifyLoaded(MaterializationResponsibility &MR) {}
67351278Sdim    virtual Error notifyEmitted(MaterializationResponsibility &MR) {
68351278Sdim      return Error::success();
69351278Sdim    }
70351278Sdim    virtual Error notifyRemovingModule(VModuleKey K) {
71351278Sdim      return Error::success();
72351278Sdim    }
73351278Sdim    virtual Error notifyRemovingAllModules() { return Error::success(); }
74351278Sdim  };
75351278Sdim
76360784Sdim  using ReturnObjectBufferFunction =
77360784Sdim      std::function<void(std::unique_ptr<MemoryBuffer>)>;
78360784Sdim
79351278Sdim  /// Construct an ObjectLinkingLayer with the given NotifyLoaded,
80351278Sdim  /// and NotifyEmitted functors.
81351278Sdim  ObjectLinkingLayer(ExecutionSession &ES,
82360784Sdim                     std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr);
83351278Sdim
84351278Sdim  /// Destruct an ObjectLinkingLayer.
85351278Sdim  ~ObjectLinkingLayer();
86351278Sdim
87360784Sdim  /// Set an object buffer return function. By default object buffers are
88360784Sdim  /// deleted once the JIT has linked them. If a return function is set then
89360784Sdim  /// it will be called to transfer ownership of the buffer instead.
90360784Sdim  void setReturnObjectBuffer(ReturnObjectBufferFunction ReturnObjectBuffer) {
91360784Sdim    this->ReturnObjectBuffer = std::move(ReturnObjectBuffer);
92360784Sdim  }
93360784Sdim
94351278Sdim  /// Add a pass-config modifier.
95351278Sdim  ObjectLinkingLayer &addPlugin(std::unique_ptr<Plugin> P) {
96351278Sdim    std::lock_guard<std::mutex> Lock(LayerMutex);
97351278Sdim    Plugins.push_back(std::move(P));
98351278Sdim    return *this;
99351278Sdim  }
100351278Sdim
101351278Sdim  /// Emit the object.
102351278Sdim  void emit(MaterializationResponsibility R,
103351278Sdim            std::unique_ptr<MemoryBuffer> O) override;
104351278Sdim
105351278Sdim  /// Instructs this ObjectLinkingLayer instance to override the symbol flags
106351278Sdim  /// found in the AtomGraph with the flags supplied by the
107351278Sdim  /// MaterializationResponsibility instance. This is a workaround to support
108351278Sdim  /// symbol visibility in COFF, which does not use the libObject's
109351278Sdim  /// SF_Exported flag. Use only when generating / adding COFF object files.
110351278Sdim  ///
111351278Sdim  /// FIXME: We should be able to remove this if/when COFF properly tracks
112351278Sdim  /// exported symbols.
113351278Sdim  ObjectLinkingLayer &
114351278Sdim  setOverrideObjectFlagsWithResponsibilityFlags(bool OverrideObjectFlags) {
115351278Sdim    this->OverrideObjectFlags = OverrideObjectFlags;
116351278Sdim    return *this;
117351278Sdim  }
118351278Sdim
119351278Sdim  /// If set, this ObjectLinkingLayer instance will claim responsibility
120351278Sdim  /// for any symbols provided by a given object file that were not already in
121351278Sdim  /// the MaterializationResponsibility instance. Setting this flag allows
122351278Sdim  /// higher-level program representations (e.g. LLVM IR) to be added based on
123351278Sdim  /// only a subset of the symbols they provide, without having to write
124351278Sdim  /// intervening layers to scan and add the additional symbols. This trades
125351278Sdim  /// diagnostic quality for convenience however: If all symbols are enumerated
126351278Sdim  /// up-front then clashes can be detected and reported early (and usually
127351278Sdim  /// deterministically). If this option is set, clashes for the additional
128351278Sdim  /// symbols may not be detected until late, and detection may depend on
129351278Sdim  /// the flow of control through JIT'd code. Use with care.
130351278Sdim  ObjectLinkingLayer &
131351278Sdim  setAutoClaimResponsibilityForObjectSymbols(bool AutoClaimObjectSymbols) {
132351278Sdim    this->AutoClaimObjectSymbols = AutoClaimObjectSymbols;
133351278Sdim    return *this;
134351278Sdim  }
135351278Sdim
136351278Sdimprivate:
137351278Sdim  using AllocPtr = std::unique_ptr<jitlink::JITLinkMemoryManager::Allocation>;
138351278Sdim
139351278Sdim  void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT,
140351278Sdim                        jitlink::PassConfiguration &PassConfig);
141351278Sdim  void notifyLoaded(MaterializationResponsibility &MR);
142351278Sdim  Error notifyEmitted(MaterializationResponsibility &MR, AllocPtr Alloc);
143351278Sdim
144351278Sdim  Error removeModule(VModuleKey K);
145351278Sdim  Error removeAllModules();
146351278Sdim
147351278Sdim  mutable std::mutex LayerMutex;
148360784Sdim  std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr;
149351278Sdim  bool OverrideObjectFlags = false;
150351278Sdim  bool AutoClaimObjectSymbols = false;
151360784Sdim  ReturnObjectBufferFunction ReturnObjectBuffer;
152351278Sdim  DenseMap<VModuleKey, AllocPtr> TrackedAllocs;
153351278Sdim  std::vector<AllocPtr> UntrackedAllocs;
154351278Sdim  std::vector<std::unique_ptr<Plugin>> Plugins;
155351278Sdim};
156351278Sdim
157351278Sdimclass EHFrameRegistrationPlugin : public ObjectLinkingLayer::Plugin {
158351278Sdimpublic:
159351278Sdim  EHFrameRegistrationPlugin(jitlink::EHFrameRegistrar &Registrar);
160351278Sdim  Error notifyEmitted(MaterializationResponsibility &MR) override;
161351278Sdim  void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT,
162351278Sdim                        jitlink::PassConfiguration &PassConfig) override;
163351278Sdim  Error notifyRemovingModule(VModuleKey K) override;
164351278Sdim  Error notifyRemovingAllModules() override;
165351278Sdim
166351278Sdimprivate:
167360784Sdim
168360784Sdim  struct EHFrameRange {
169360784Sdim    JITTargetAddress Addr = 0;
170360784Sdim    size_t Size;
171360784Sdim  };
172360784Sdim
173351278Sdim  jitlink::EHFrameRegistrar &Registrar;
174360784Sdim  DenseMap<MaterializationResponsibility *, EHFrameRange> InProcessLinks;
175360784Sdim  DenseMap<VModuleKey, EHFrameRange> TrackedEHFrameRanges;
176360784Sdim  std::vector<EHFrameRange> UntrackedEHFrameRanges;
177351278Sdim};
178351278Sdim
179351278Sdim} // end namespace orc
180351278Sdim} // end namespace llvm
181351278Sdim
182351278Sdim#endif // LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H
183