LLVM 17.0.0git
JITLinkGeneric.h
Go to the documentation of this file.
1//===------ JITLinkGeneric.h - Generic JIT linker utilities -----*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Generic JITLinker utilities. E.g. graph pruning, eh-frame parsing.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LIB_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H
14#define LIB_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H
15
16#include "llvm/ADT/DenseSet.h"
18
19#define DEBUG_TYPE "jitlink"
20
21namespace llvm {
22namespace jitlink {
23
24/// Base class for a JIT linker.
25///
26/// A JITLinkerBase instance links one object file into an ongoing JIT
27/// session. Symbol resolution and finalization operations are pluggable,
28/// and called using continuation passing (passing a continuation for the
29/// remaining linker work) to allow them to be performed asynchronously.
31public:
32 JITLinkerBase(std::unique_ptr<JITLinkContext> Ctx,
33 std::unique_ptr<LinkGraph> G, PassConfiguration Passes)
34 : Ctx(std::move(Ctx)), G(std::move(G)), Passes(std::move(Passes)) {
35 assert(this->Ctx && "Ctx can not be null");
36 assert(this->G && "G can not be null");
37 }
38
39 virtual ~JITLinkerBase();
40
41protected:
45
46 // Returns the PassConfiguration for this instance. This can be used by
47 // JITLinkerBase implementations to add late passes that reference their
48 // own data structures (e.g. for ELF implementations to locate / construct
49 // a GOT start symbol prior to fixup).
50 PassConfiguration &getPassConfig() { return Passes; }
51
52 // Phase 1:
53 // 1.1: Run pre-prune passes
54 // 1.2: Prune graph
55 // 1.3: Run post-prune passes
56 // 1.4: Allocate memory.
57 void linkPhase1(std::unique_ptr<JITLinkerBase> Self);
58
59 // Phase 2:
60 // 2.2: Run post-allocation passes
61 // 2.3: Notify context of final assigned symbol addresses
62 // 2.4: Identify external symbols and make an async call to resolve
63 void linkPhase2(std::unique_ptr<JITLinkerBase> Self, AllocResult AR);
64
65 // Phase 3:
66 // 3.1: Apply resolution results
67 // 3.2: Run pre-fixup passes
68 // 3.3: Fix up block contents
69 // 3.4: Run post-fixup passes
70 // 3.5: Make an async call to transfer and finalize memory.
71 void linkPhase3(std::unique_ptr<JITLinkerBase> Self,
72 Expected<AsyncLookupResult> LookupResult);
73
74 // Phase 4:
75 // 4.1: Call OnFinalized callback, handing off allocation.
76 void linkPhase4(std::unique_ptr<JITLinkerBase> Self, FinalizeResult FR);
77
78private:
79 // Run all passes in the given pass list, bailing out immediately if any pass
80 // returns an error.
81 Error runPasses(LinkGraphPassList &Passes);
82
83 // Copy block contents and apply relocations.
84 // Implemented in JITLinker.
85 virtual Error fixUpBlocks(LinkGraph &G) const = 0;
86
87 JITLinkContext::LookupMap getExternalSymbolNames() const;
88 void applyLookupResult(AsyncLookupResult LR);
89 void abandonAllocAndBailOut(std::unique_ptr<JITLinkerBase> Self, Error Err);
90
91 std::unique_ptr<JITLinkContext> Ctx;
92 std::unique_ptr<LinkGraph> G;
93 PassConfiguration Passes;
94 std::unique_ptr<InFlightAlloc> Alloc;
95};
96
97template <typename LinkerImpl> class JITLinker : public JITLinkerBase {
98public:
100
101 /// Link constructs a LinkerImpl instance and calls linkPhase1.
102 /// Link should be called with the constructor arguments for LinkerImpl, which
103 /// will be forwarded to the constructor.
104 template <typename... ArgTs> static void link(ArgTs &&... Args) {
105 auto L = std::make_unique<LinkerImpl>(std::forward<ArgTs>(Args)...);
106
107 // Ownership of the linker is passed into the linker's doLink function to
108 // allow it to be passed on to async continuations.
109 //
110 // FIXME: Remove LTmp once we have c++17.
111 // C++17 sequencing rules guarantee that function name expressions are
112 // sequenced before arguments, so L->linkPhase1(std::move(L), ...) will be
113 // well formed.
114 auto &LTmp = *L;
115 LTmp.linkPhase1(std::move(L));
116 }
117
118private:
119 const LinkerImpl &impl() const {
120 return static_cast<const LinkerImpl &>(*this);
121 }
122
123 Error fixUpBlocks(LinkGraph &G) const override {
124 LLVM_DEBUG(dbgs() << "Fixing up blocks:\n");
125
126 for (auto &Sec : G.sections()) {
127 bool NoAllocSection =
128 Sec.getMemLifetimePolicy() == orc::MemLifetimePolicy::NoAlloc;
129
130 for (auto *B : Sec.blocks()) {
131 LLVM_DEBUG(dbgs() << " " << *B << ":\n");
132
133 // Copy Block data and apply fixups.
134 LLVM_DEBUG(dbgs() << " Applying fixups.\n");
135 assert((!B->isZeroFill() || all_of(B->edges(),
136 [](const Edge &E) {
137 return E.getKind() ==
138 Edge::KeepAlive;
139 })) &&
140 "Non-KeepAlive edges in zero-fill block?");
141
142 // If this is a no-alloc section then copy the block content into
143 // memory allocated on the Graph's allocator (if it hasn't been
144 // already).
145 if (NoAllocSection)
146 (void)B->getMutableContent(G);
147
148 for (auto &E : B->edges()) {
149
150 // Skip non-relocation edges.
151 if (!E.isRelocation())
152 continue;
153
154 // If B is a block in a Standard or Finalize section then make sure
155 // that no edges point to symbols in NoAlloc sections.
156 assert(
157 (NoAllocSection || !E.getTarget().isDefined() ||
158 E.getTarget().getBlock().getSection().getMemLifetimePolicy() !=
160 "Block in allocated section has edge pointing to no-alloc "
161 "section");
162
163 // Dispatch to LinkerImpl for fixup.
164 if (auto Err = impl().applyFixup(G, *B, E))
165 return Err;
166 }
167 }
168 }
169
170 return Error::success();
171 }
172};
173
174/// Removes dead symbols/blocks/addressables.
175///
176/// Finds the set of symbols and addressables reachable from any symbol
177/// initially marked live. All symbols/addressables not marked live at the end
178/// of this process are removed.
179void prune(LinkGraph &G);
180
181} // end namespace jitlink
182} // end namespace llvm
183
184#undef DEBUG_TYPE // "jitlink"
185
186#endif // LIB_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_DEBUG(X)
Definition: Debug.h:101
This file defines the DenseSet and SmallDenseSet classes.
#define G(x, y, z)
Definition: MD5.cpp:56
const char * Passes
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Lightweight error class with error context and mandatory checking.
Definition: Error.h:156
static ErrorSuccess success()
Create a success value.
Definition: Error.h:330
Tagged union holding either a T or a Error.
Definition: Error.h:470
@ NoAlloc
NoAlloc memory should not be allocated by the JITLinkMemoryManager at all.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1782
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1909
Definition: BitVector.h:851