Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 1 | //===--------- JITLinkGeneric.cpp - Generic JIT linker utilities ----------===// |
| 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 utility class. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #include "JITLinkGeneric.h" |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 14 | |
| 15 | #include "llvm/Support/BinaryStreamReader.h" |
| 16 | #include "llvm/Support/MemoryBuffer.h" |
| 17 | |
| 18 | #define DEBUG_TYPE "jitlink" |
| 19 | |
| 20 | namespace llvm { |
| 21 | namespace jitlink { |
| 22 | |
| 23 | JITLinkerBase::~JITLinkerBase() {} |
| 24 | |
| 25 | void JITLinkerBase::linkPhase1(std::unique_ptr<JITLinkerBase> Self) { |
| 26 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 27 | // Build the link graph. |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 28 | if (auto GraphOrErr = buildGraph(Ctx->getObjectBuffer())) |
| 29 | G = std::move(*GraphOrErr); |
| 30 | else |
| 31 | return Ctx->notifyFailed(GraphOrErr.takeError()); |
| 32 | assert(G && "Graph should have been created by buildGraph above"); |
| 33 | |
| 34 | // Prune and optimize the graph. |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 35 | if (auto Err = runPasses(Passes.PrePrunePasses)) |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 36 | return Ctx->notifyFailed(std::move(Err)); |
| 37 | |
| 38 | LLVM_DEBUG({ |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 39 | dbgs() << "Link graph \"" << G->getName() << "\" pre-pruning:\n"; |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 40 | dumpGraph(dbgs()); |
| 41 | }); |
| 42 | |
| 43 | prune(*G); |
| 44 | |
| 45 | LLVM_DEBUG({ |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 46 | dbgs() << "Link graph \"" << G->getName() << "\" post-pruning:\n"; |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 47 | dumpGraph(dbgs()); |
| 48 | }); |
| 49 | |
| 50 | // Run post-pruning passes. |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 51 | if (auto Err = runPasses(Passes.PostPrunePasses)) |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 52 | return Ctx->notifyFailed(std::move(Err)); |
| 53 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 54 | // Sort blocks into segments. |
| 55 | auto Layout = layOutBlocks(); |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 56 | |
| 57 | // Allocate memory for segments. |
| 58 | if (auto Err = allocateSegments(Layout)) |
| 59 | return Ctx->notifyFailed(std::move(Err)); |
| 60 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 61 | // Notify client that the defined symbols have been assigned addresses. |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 62 | Ctx->notifyResolved(*G); |
| 63 | |
| 64 | auto ExternalSymbols = getExternalSymbolNames(); |
| 65 | |
| 66 | // We're about to hand off ownership of ourself to the continuation. Grab a |
| 67 | // pointer to the context so that we can call it to initiate the lookup. |
| 68 | // |
| 69 | // FIXME: Once callee expressions are defined to be sequenced before argument |
| 70 | // expressions (c++17) we can simplify all this to: |
| 71 | // |
| 72 | // Ctx->lookup(std::move(UnresolvedExternals), |
| 73 | // [Self=std::move(Self)](Expected<AsyncLookupResult> Result) { |
| 74 | // Self->linkPhase2(std::move(Self), std::move(Result)); |
| 75 | // }); |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 76 | auto *TmpCtx = Ctx.get(); |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 77 | TmpCtx->lookup(std::move(ExternalSymbols), |
| 78 | createLookupContinuation( |
| 79 | [S = std::move(Self), L = std::move(Layout)]( |
| 80 | Expected<AsyncLookupResult> LookupResult) mutable { |
| 81 | auto &TmpSelf = *S; |
| 82 | TmpSelf.linkPhase2(std::move(S), std::move(LookupResult), |
| 83 | std::move(L)); |
| 84 | })); |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 85 | } |
| 86 | |
| 87 | void JITLinkerBase::linkPhase2(std::unique_ptr<JITLinkerBase> Self, |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 88 | Expected<AsyncLookupResult> LR, |
| 89 | SegmentLayoutMap Layout) { |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 90 | // If the lookup failed, bail out. |
| 91 | if (!LR) |
Lang Hames | 3181b87 | 2019-05-01 02:43:52 +0000 | [diff] [blame] | 92 | return deallocateAndBailOut(LR.takeError()); |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 93 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 94 | // Assign addresses to external addressables. |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 95 | applyLookupResult(*LR); |
| 96 | |
| 97 | LLVM_DEBUG({ |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 98 | dbgs() << "Link graph \"" << G->getName() << "\" before copy-and-fixup:\n"; |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 99 | dumpGraph(dbgs()); |
| 100 | }); |
| 101 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 102 | // Copy block content to working memory and fix up. |
| 103 | if (auto Err = copyAndFixUpBlocks(Layout, *Alloc)) |
Lang Hames | 3181b87 | 2019-05-01 02:43:52 +0000 | [diff] [blame] | 104 | return deallocateAndBailOut(std::move(Err)); |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 105 | |
| 106 | LLVM_DEBUG({ |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 107 | dbgs() << "Link graph \"" << G->getName() << "\" after copy-and-fixup:\n"; |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 108 | dumpGraph(dbgs()); |
| 109 | }); |
| 110 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 111 | if (auto Err = runPasses(Passes.PostFixupPasses)) |
Lang Hames | 3181b87 | 2019-05-01 02:43:52 +0000 | [diff] [blame] | 112 | return deallocateAndBailOut(std::move(Err)); |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 113 | |
| 114 | // FIXME: Use move capture once we have c++14. |
| 115 | auto *UnownedSelf = Self.release(); |
| 116 | auto Phase3Continuation = [UnownedSelf](Error Err) { |
| 117 | std::unique_ptr<JITLinkerBase> Self(UnownedSelf); |
| 118 | UnownedSelf->linkPhase3(std::move(Self), std::move(Err)); |
| 119 | }; |
| 120 | |
| 121 | Alloc->finalizeAsync(std::move(Phase3Continuation)); |
| 122 | } |
| 123 | |
| 124 | void JITLinkerBase::linkPhase3(std::unique_ptr<JITLinkerBase> Self, Error Err) { |
| 125 | if (Err) |
Lang Hames | 3181b87 | 2019-05-01 02:43:52 +0000 | [diff] [blame] | 126 | return deallocateAndBailOut(std::move(Err)); |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 127 | Ctx->notifyFinalized(std::move(Alloc)); |
| 128 | } |
| 129 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 130 | Error JITLinkerBase::runPasses(LinkGraphPassList &Passes) { |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 131 | for (auto &P : Passes) |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 132 | if (auto Err = P(*G)) |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 133 | return Err; |
| 134 | return Error::success(); |
| 135 | } |
| 136 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 137 | JITLinkerBase::SegmentLayoutMap JITLinkerBase::layOutBlocks() { |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 138 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 139 | SegmentLayoutMap Layout; |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 140 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 141 | /// Partition blocks based on permissions and content vs. zero-fill. |
| 142 | for (auto *B : G->blocks()) { |
| 143 | auto &SegLists = Layout[B->getSection().getProtectionFlags()]; |
| 144 | if (!B->isZeroFill()) |
| 145 | SegLists.ContentBlocks.push_back(B); |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 146 | else |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 147 | SegLists.ZeroFillBlocks.push_back(B); |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 148 | } |
| 149 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 150 | /// Sort blocks within each list. |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 151 | for (auto &KV : Layout) { |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 152 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 153 | auto CompareBlocks = [](const Block *LHS, const Block *RHS) { |
| 154 | if (LHS->getSection().getOrdinal() != RHS->getSection().getOrdinal()) |
| 155 | return LHS->getSection().getOrdinal() < RHS->getSection().getOrdinal(); |
| 156 | return LHS->getOrdinal() < RHS->getOrdinal(); |
| 157 | }; |
Lang Hames | 0d8ae1e | 2019-05-07 22:56:40 +0000 | [diff] [blame] | 158 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 159 | auto &SegLists = KV.second; |
| 160 | llvm::sort(SegLists.ContentBlocks, CompareBlocks); |
| 161 | llvm::sort(SegLists.ZeroFillBlocks, CompareBlocks); |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 162 | } |
| 163 | |
| 164 | LLVM_DEBUG({ |
| 165 | dbgs() << "Segment ordering:\n"; |
| 166 | for (auto &KV : Layout) { |
| 167 | dbgs() << " Segment " |
| 168 | << static_cast<sys::Memory::ProtectionFlags>(KV.first) << ":\n"; |
| 169 | auto &SL = KV.second; |
| 170 | for (auto &SIEntry : |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 171 | {std::make_pair(&SL.ContentBlocks, "content block"), |
| 172 | std::make_pair(&SL.ZeroFillBlocks, "zero-fill block")}) { |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 173 | dbgs() << " " << SIEntry.second << ":\n"; |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 174 | for (auto *B : *SIEntry.first) |
| 175 | dbgs() << " " << *B << "\n"; |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 176 | } |
| 177 | } |
| 178 | }); |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 179 | |
| 180 | return Layout; |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 181 | } |
| 182 | |
| 183 | Error JITLinkerBase::allocateSegments(const SegmentLayoutMap &Layout) { |
| 184 | |
| 185 | // Compute segment sizes and allocate memory. |
| 186 | LLVM_DEBUG(dbgs() << "JIT linker requesting: { "); |
| 187 | JITLinkMemoryManager::SegmentsRequestMap Segments; |
| 188 | for (auto &KV : Layout) { |
| 189 | auto &Prot = KV.first; |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 190 | auto &SegLists = KV.second; |
| 191 | |
| 192 | uint64_t SegAlign = 1; |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 193 | |
| 194 | // Calculate segment content size. |
| 195 | size_t SegContentSize = 0; |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 196 | for (auto *B : SegLists.ContentBlocks) { |
| 197 | SegAlign = std::max(SegAlign, B->getAlignment()); |
| 198 | SegContentSize = alignToBlock(SegContentSize, *B); |
| 199 | SegContentSize += B->getSize(); |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 200 | } |
| 201 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 202 | uint64_t SegZeroFillStart = SegContentSize; |
| 203 | uint64_t SegZeroFillEnd = SegZeroFillStart; |
Lang Hames | 70e158e | 2019-08-27 15:22:23 +0000 | [diff] [blame] | 204 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 205 | for (auto *B : SegLists.ZeroFillBlocks) { |
| 206 | SegAlign = std::max(SegAlign, B->getAlignment()); |
| 207 | SegZeroFillEnd = alignToBlock(SegZeroFillEnd, *B); |
| 208 | SegZeroFillEnd += B->getSize(); |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 209 | } |
| 210 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 211 | Segments[Prot] = {SegAlign, SegContentSize, |
| 212 | SegZeroFillEnd - SegZeroFillStart}; |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 213 | |
| 214 | LLVM_DEBUG({ |
| 215 | dbgs() << (&KV == &*Layout.begin() ? "" : "; ") |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 216 | << static_cast<sys::Memory::ProtectionFlags>(Prot) |
| 217 | << ": alignment = " << SegAlign |
| 218 | << ", content size = " << SegContentSize |
| 219 | << ", zero-fill size = " << (SegZeroFillEnd - SegZeroFillStart); |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 220 | }); |
| 221 | } |
| 222 | LLVM_DEBUG(dbgs() << " }\n"); |
| 223 | |
| 224 | if (auto AllocOrErr = Ctx->getMemoryManager().allocate(Segments)) |
| 225 | Alloc = std::move(*AllocOrErr); |
| 226 | else |
| 227 | return AllocOrErr.takeError(); |
| 228 | |
| 229 | LLVM_DEBUG({ |
| 230 | dbgs() << "JIT linker got working memory:\n"; |
| 231 | for (auto &KV : Layout) { |
| 232 | auto Prot = static_cast<sys::Memory::ProtectionFlags>(KV.first); |
| 233 | dbgs() << " " << Prot << ": " |
| 234 | << (const void *)Alloc->getWorkingMemory(Prot).data() << "\n"; |
| 235 | } |
| 236 | }); |
| 237 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 238 | // Update block target addresses. |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 239 | for (auto &KV : Layout) { |
| 240 | auto &Prot = KV.first; |
| 241 | auto &SL = KV.second; |
| 242 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 243 | JITTargetAddress NextBlockAddr = |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 244 | Alloc->getTargetMemory(static_cast<sys::Memory::ProtectionFlags>(Prot)); |
| 245 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 246 | for (auto *SIList : {&SL.ContentBlocks, &SL.ZeroFillBlocks}) |
| 247 | for (auto *B : *SIList) { |
| 248 | NextBlockAddr = alignToBlock(NextBlockAddr, *B); |
| 249 | B->setAddress(NextBlockAddr); |
| 250 | NextBlockAddr += B->getSize(); |
Lang Hames | 4513929 | 2019-05-13 04:51:31 +0000 | [diff] [blame] | 251 | } |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 252 | } |
| 253 | |
| 254 | return Error::success(); |
| 255 | } |
| 256 | |
| 257 | DenseSet<StringRef> JITLinkerBase::getExternalSymbolNames() const { |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 258 | // Identify unresolved external symbols. |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 259 | DenseSet<StringRef> UnresolvedExternals; |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 260 | for (auto *Sym : G->external_symbols()) { |
| 261 | assert(Sym->getAddress() == 0 && |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 262 | "External has already been assigned an address"); |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 263 | assert(Sym->getName() != StringRef() && Sym->getName() != "" && |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 264 | "Externals must be named"); |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 265 | UnresolvedExternals.insert(Sym->getName()); |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 266 | } |
| 267 | return UnresolvedExternals; |
| 268 | } |
| 269 | |
| 270 | void JITLinkerBase::applyLookupResult(AsyncLookupResult Result) { |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 271 | for (auto *Sym : G->external_symbols()) { |
| 272 | assert(Sym->getAddress() == 0 && "Symbol already resolved"); |
| 273 | assert(!Sym->isDefined() && "Symbol being resolved is already defined"); |
| 274 | assert(Result.count(Sym->getName()) && "Missing resolution for symbol"); |
| 275 | Sym->getAddressable().setAddress(Result[Sym->getName()].getAddress()); |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 276 | } |
| 277 | |
Lang Hames | d407b4b | 2019-04-30 21:28:07 +0000 | [diff] [blame] | 278 | LLVM_DEBUG({ |
| 279 | dbgs() << "Externals after applying lookup result:\n"; |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 280 | for (auto *Sym : G->external_symbols()) |
| 281 | dbgs() << " " << Sym->getName() << ": " |
| 282 | << formatv("{0:x16}", Sym->getAddress()) << "\n"; |
Lang Hames | d407b4b | 2019-04-30 21:28:07 +0000 | [diff] [blame] | 283 | }); |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 284 | assert(llvm::all_of(G->external_symbols(), |
| 285 | [](Symbol *Sym) { return Sym->getAddress() != 0; }) && |
| 286 | "All symbols should have been resolved by this point"); |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 287 | } |
| 288 | |
Lang Hames | 3181b87 | 2019-05-01 02:43:52 +0000 | [diff] [blame] | 289 | void JITLinkerBase::deallocateAndBailOut(Error Err) { |
| 290 | assert(Err && "Should not be bailing out on success value"); |
| 291 | assert(Alloc && "can not call deallocateAndBailOut before allocation"); |
| 292 | Ctx->notifyFailed(joinErrors(std::move(Err), Alloc->deallocate())); |
| 293 | } |
| 294 | |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 295 | void JITLinkerBase::dumpGraph(raw_ostream &OS) { |
| 296 | assert(G && "Graph is not set yet"); |
| 297 | G->dump(dbgs(), [this](Edge::Kind K) { return getEdgeKindName(K); }); |
| 298 | } |
| 299 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 300 | void prune(LinkGraph &G) { |
| 301 | std::vector<Symbol *> Worklist; |
| 302 | DenseSet<Block *> VisitedBlocks; |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 303 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 304 | // Build the initial worklist from all symbols initially live. |
| 305 | for (auto *Sym : G.defined_symbols()) |
| 306 | if (Sym->isLive()) |
| 307 | Worklist.push_back(Sym); |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 308 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 309 | // Propagate live flags to all symbols reachable from the initial live set. |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 310 | while (!Worklist.empty()) { |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 311 | auto *Sym = Worklist.back(); |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 312 | Worklist.pop_back(); |
| 313 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 314 | auto &B = Sym->getBlock(); |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 315 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 316 | // Skip addressables that we've visited before. |
| 317 | if (VisitedBlocks.count(&B)) |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 318 | continue; |
| 319 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 320 | VisitedBlocks.insert(&B); |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 321 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 322 | for (auto &E : Sym->getBlock().edges()) { |
| 323 | if (E.getTarget().isDefined() && !E.getTarget().isLive()) { |
| 324 | E.getTarget().setLive(true); |
| 325 | Worklist.push_back(&E.getTarget()); |
| 326 | } |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 327 | } |
| 328 | } |
| 329 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 330 | // Collect all the symbols to remove, then remove them. |
| 331 | { |
| 332 | LLVM_DEBUG(dbgs() << "Dead-stripping symbols:\n"); |
| 333 | std::vector<Symbol *> SymbolsToRemove; |
| 334 | for (auto *Sym : G.defined_symbols()) |
| 335 | if (!Sym->isLive()) |
| 336 | SymbolsToRemove.push_back(Sym); |
| 337 | for (auto *Sym : SymbolsToRemove) { |
| 338 | LLVM_DEBUG(dbgs() << " " << *Sym << "...\n"); |
| 339 | G.removeDefinedSymbol(*Sym); |
| 340 | } |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 341 | } |
| 342 | |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 343 | // Delete any unused blocks. |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 344 | { |
Lang Hames | 4e920e5 | 2019-10-04 03:55:26 +0000 | [diff] [blame] | 345 | LLVM_DEBUG(dbgs() << "Dead-stripping blocks:\n"); |
| 346 | std::vector<Block *> BlocksToRemove; |
| 347 | for (auto *B : G.blocks()) |
| 348 | if (!VisitedBlocks.count(B)) |
| 349 | BlocksToRemove.push_back(B); |
| 350 | for (auto *B : BlocksToRemove) { |
| 351 | LLVM_DEBUG(dbgs() << " " << *B << "...\n"); |
| 352 | G.removeBlock(*B); |
| 353 | } |
Lang Hames | 11c8dfa5 | 2019-04-20 17:10:34 +0000 | [diff] [blame] | 354 | } |
| 355 | } |
| 356 | |
| 357 | } // end namespace jitlink |
| 358 | } // end namespace llvm |