1 //===------- ObjectLinkingLayer.cpp - JITLink backed ORC ObjectLayer ------===// 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 #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" 10 11 #include "llvm/ADT/Optional.h" 12 #include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h" 13 14 #include <vector> 15 16 #define DEBUG_TYPE "orc" 17 18 using namespace llvm; 19 using namespace llvm::jitlink; 20 using namespace llvm::orc; 21 22 namespace llvm { 23 namespace orc { 24 25 class ObjectLinkingLayerJITLinkContext final : public JITLinkContext { 26 public: 27 ObjectLinkingLayerJITLinkContext(ObjectLinkingLayer &Layer, 28 MaterializationResponsibility MR, 29 std::unique_ptr<MemoryBuffer> ObjBuffer) 30 : Layer(Layer), MR(std::move(MR)), ObjBuffer(std::move(ObjBuffer)) {} 31 32 JITLinkMemoryManager &getMemoryManager() override { return Layer.MemMgr; } 33 34 MemoryBufferRef getObjectBuffer() const override { 35 return ObjBuffer->getMemBufferRef(); 36 } 37 38 void notifyFailed(Error Err) override { 39 Layer.getExecutionSession().reportError(std::move(Err)); 40 MR.failMaterialization(); 41 } 42 43 void lookup(const DenseSet<StringRef> &Symbols, 44 JITLinkAsyncLookupContinuation LookupContinuation) override { 45 46 JITDylibSearchList SearchOrder; 47 MR.getTargetJITDylib().withSearchOrderDo( 48 [&](const JITDylibSearchList &JDs) { SearchOrder = JDs; }); 49 50 auto &ES = Layer.getExecutionSession(); 51 52 SymbolNameSet InternedSymbols; 53 for (auto &S : Symbols) 54 InternedSymbols.insert(ES.intern(S)); 55 56 // OnResolve -- De-intern the symbols and pass the result to the linker. 57 // FIXME: Capture LookupContinuation by move once we have c++14. 58 auto SharedLookupContinuation = 59 std::make_shared<JITLinkAsyncLookupContinuation>( 60 std::move(LookupContinuation)); 61 auto OnResolve = [SharedLookupContinuation](Expected<SymbolMap> Result) { 62 if (!Result) 63 (*SharedLookupContinuation)(Result.takeError()); 64 else { 65 AsyncLookupResult LR; 66 for (auto &KV : *Result) 67 LR[*KV.first] = KV.second; 68 (*SharedLookupContinuation)(std::move(LR)); 69 } 70 }; 71 72 ES.lookup( 73 SearchOrder, std::move(InternedSymbols), std::move(OnResolve), 74 // OnReady: 75 [&ES](Error Err) { ES.reportError(std::move(Err)); }, 76 // RegisterDependencies: 77 [this](const SymbolDependenceMap &Deps) { 78 registerDependencies(Deps); 79 }); 80 } 81 82 void notifyResolved(AtomGraph &G) override { 83 auto &ES = Layer.getExecutionSession(); 84 85 SymbolFlagsMap ExtraSymbolsToClaim; 86 bool AutoClaim = Layer.AutoClaimObjectSymbols; 87 88 SymbolMap InternedResult; 89 for (auto *DA : G.defined_atoms()) 90 if (DA->hasName() && DA->isGlobal()) { 91 auto InternedName = ES.intern(DA->getName()); 92 JITSymbolFlags Flags; 93 94 if (DA->isExported()) 95 Flags |= JITSymbolFlags::Exported; 96 if (DA->isWeak()) 97 Flags |= JITSymbolFlags::Weak; 98 if (DA->isCallable()) 99 Flags |= JITSymbolFlags::Callable; 100 if (DA->isCommon()) 101 Flags |= JITSymbolFlags::Common; 102 103 InternedResult[InternedName] = 104 JITEvaluatedSymbol(DA->getAddress(), Flags); 105 if (AutoClaim && !MR.getSymbols().count(InternedName)) { 106 assert(!ExtraSymbolsToClaim.count(InternedName) && 107 "Duplicate symbol to claim?"); 108 ExtraSymbolsToClaim[InternedName] = Flags; 109 } 110 } 111 112 for (auto *A : G.absolute_atoms()) 113 if (A->hasName()) { 114 auto InternedName = ES.intern(A->getName()); 115 JITSymbolFlags Flags; 116 Flags |= JITSymbolFlags::Absolute; 117 if (A->isWeak()) 118 Flags |= JITSymbolFlags::Weak; 119 if (A->isCallable()) 120 Flags |= JITSymbolFlags::Callable; 121 InternedResult[InternedName] = 122 JITEvaluatedSymbol(A->getAddress(), Flags); 123 if (AutoClaim && !MR.getSymbols().count(InternedName)) { 124 assert(!ExtraSymbolsToClaim.count(InternedName) && 125 "Duplicate symbol to claim?"); 126 ExtraSymbolsToClaim[InternedName] = Flags; 127 } 128 } 129 130 if (!ExtraSymbolsToClaim.empty()) 131 if (auto Err = MR.defineMaterializing(ExtraSymbolsToClaim)) 132 return notifyFailed(std::move(Err)); 133 134 MR.resolve(InternedResult); 135 136 Layer.notifyLoaded(MR); 137 } 138 139 void notifyFinalized( 140 std::unique_ptr<JITLinkMemoryManager::Allocation> A) override { 141 142 if (auto Err = Layer.notifyEmitted(MR, std::move(A))) { 143 Layer.getExecutionSession().reportError(std::move(Err)); 144 MR.failMaterialization(); 145 146 return; 147 } 148 MR.emit(); 149 } 150 151 AtomGraphPassFunction getMarkLivePass(const Triple &TT) const override { 152 return [this](AtomGraph &G) { return markResponsibilitySymbolsLive(G); }; 153 } 154 155 Error modifyPassConfig(const Triple &TT, PassConfiguration &Config) override { 156 // Add passes to mark duplicate defs as should-discard, and to walk the 157 // atom graph to build the symbol dependence graph. 158 Config.PrePrunePasses.push_back( 159 [this](AtomGraph &G) { return markSymbolsToDiscard(G); }); 160 Config.PostPrunePasses.push_back( 161 [this](AtomGraph &G) { return computeNamedSymbolDependencies(G); }); 162 163 Layer.modifyPassConfig(MR, TT, Config); 164 165 return Error::success(); 166 } 167 168 private: 169 using AnonAtomNamedDependenciesMap = 170 DenseMap<const DefinedAtom *, SymbolNameSet>; 171 172 Error markSymbolsToDiscard(AtomGraph &G) { 173 auto &ES = Layer.getExecutionSession(); 174 for (auto *DA : G.defined_atoms()) 175 if (DA->isWeak() && DA->hasName()) { 176 auto S = ES.intern(DA->getName()); 177 auto I = MR.getSymbols().find(S); 178 if (I == MR.getSymbols().end()) 179 DA->setShouldDiscard(true); 180 } 181 182 for (auto *A : G.absolute_atoms()) 183 if (A->isWeak() && A->hasName()) { 184 auto S = ES.intern(A->getName()); 185 auto I = MR.getSymbols().find(S); 186 if (I == MR.getSymbols().end()) 187 A->setShouldDiscard(true); 188 } 189 190 return Error::success(); 191 } 192 193 Error markResponsibilitySymbolsLive(AtomGraph &G) const { 194 auto &ES = Layer.getExecutionSession(); 195 for (auto *DA : G.defined_atoms()) 196 if (DA->hasName() && 197 MR.getSymbols().count(ES.intern(DA->getName()))) 198 DA->setLive(true); 199 return Error::success(); 200 } 201 202 Error computeNamedSymbolDependencies(AtomGraph &G) { 203 auto &ES = MR.getTargetJITDylib().getExecutionSession(); 204 auto AnonDeps = computeAnonDeps(G); 205 206 for (auto *DA : G.defined_atoms()) { 207 208 // Skip anonymous and non-global atoms: we do not need dependencies for 209 // these. 210 if (!DA->hasName() || !DA->isGlobal()) 211 continue; 212 213 auto DAName = ES.intern(DA->getName()); 214 SymbolNameSet &DADeps = NamedSymbolDeps[DAName]; 215 216 for (auto &E : DA->edges()) { 217 auto &TA = E.getTarget(); 218 219 if (TA.hasName()) 220 DADeps.insert(ES.intern(TA.getName())); 221 else { 222 assert(TA.isDefined() && "Anonymous atoms must be defined"); 223 auto &DTA = static_cast<DefinedAtom &>(TA); 224 auto I = AnonDeps.find(&DTA); 225 if (I != AnonDeps.end()) 226 for (auto &S : I->second) 227 DADeps.insert(S); 228 } 229 } 230 } 231 232 return Error::success(); 233 } 234 235 AnonAtomNamedDependenciesMap computeAnonDeps(AtomGraph &G) { 236 237 auto &ES = MR.getTargetJITDylib().getExecutionSession(); 238 AnonAtomNamedDependenciesMap DepMap; 239 240 // For all anonymous atoms: 241 // (1) Add their named dependencies. 242 // (2) Add them to the worklist for further iteration if they have any 243 // depend on any other anonymous atoms. 244 struct WorklistEntry { 245 WorklistEntry(DefinedAtom *DA, DenseSet<DefinedAtom *> DAAnonDeps) 246 : DA(DA), DAAnonDeps(std::move(DAAnonDeps)) {} 247 248 DefinedAtom *DA = nullptr; 249 DenseSet<DefinedAtom *> DAAnonDeps; 250 }; 251 std::vector<WorklistEntry> Worklist; 252 for (auto *DA : G.defined_atoms()) 253 if (!DA->hasName()) { 254 auto &DANamedDeps = DepMap[DA]; 255 DenseSet<DefinedAtom *> DAAnonDeps; 256 257 for (auto &E : DA->edges()) { 258 auto &TA = E.getTarget(); 259 if (TA.hasName()) 260 DANamedDeps.insert(ES.intern(TA.getName())); 261 else { 262 assert(TA.isDefined() && "Anonymous atoms must be defined"); 263 DAAnonDeps.insert(static_cast<DefinedAtom *>(&TA)); 264 } 265 } 266 267 if (!DAAnonDeps.empty()) 268 Worklist.push_back(WorklistEntry(DA, std::move(DAAnonDeps))); 269 } 270 271 // Loop over all anonymous atoms with anonymous dependencies, propagating 272 // their respective *named* dependencies. Iterate until we hit a stable 273 // state. 274 bool Changed; 275 do { 276 Changed = false; 277 for (auto &WLEntry : Worklist) { 278 auto *DA = WLEntry.DA; 279 auto &DANamedDeps = DepMap[DA]; 280 auto &DAAnonDeps = WLEntry.DAAnonDeps; 281 282 for (auto *TA : DAAnonDeps) { 283 auto I = DepMap.find(TA); 284 if (I != DepMap.end()) 285 for (const auto &S : I->second) 286 Changed |= DANamedDeps.insert(S).second; 287 } 288 } 289 } while (Changed); 290 291 return DepMap; 292 } 293 294 void registerDependencies(const SymbolDependenceMap &QueryDeps) { 295 for (auto &NamedDepsEntry : NamedSymbolDeps) { 296 auto &Name = NamedDepsEntry.first; 297 auto &NameDeps = NamedDepsEntry.second; 298 SymbolDependenceMap SymbolDeps; 299 300 for (const auto &QueryDepsEntry : QueryDeps) { 301 JITDylib &SourceJD = *QueryDepsEntry.first; 302 const SymbolNameSet &Symbols = QueryDepsEntry.second; 303 auto &DepsForJD = SymbolDeps[&SourceJD]; 304 305 for (const auto &S : Symbols) 306 if (NameDeps.count(S)) 307 DepsForJD.insert(S); 308 309 if (DepsForJD.empty()) 310 SymbolDeps.erase(&SourceJD); 311 } 312 313 MR.addDependencies(Name, SymbolDeps); 314 } 315 } 316 317 ObjectLinkingLayer &Layer; 318 MaterializationResponsibility MR; 319 std::unique_ptr<MemoryBuffer> ObjBuffer; 320 DenseMap<SymbolStringPtr, SymbolNameSet> NamedSymbolDeps; 321 }; 322 323 ObjectLinkingLayer::Plugin::~Plugin() {} 324 325 ObjectLinkingLayer::ObjectLinkingLayer(ExecutionSession &ES, 326 JITLinkMemoryManager &MemMgr) 327 : ObjectLayer(ES), MemMgr(MemMgr) {} 328 329 ObjectLinkingLayer::~ObjectLinkingLayer() { 330 if (auto Err = removeAllModules()) 331 getExecutionSession().reportError(std::move(Err)); 332 } 333 334 void ObjectLinkingLayer::emit(MaterializationResponsibility R, 335 std::unique_ptr<MemoryBuffer> O) { 336 assert(O && "Object must not be null"); 337 jitLink(llvm::make_unique<ObjectLinkingLayerJITLinkContext>( 338 *this, std::move(R), std::move(O))); 339 } 340 341 void ObjectLinkingLayer::modifyPassConfig(MaterializationResponsibility &MR, 342 const Triple &TT, 343 PassConfiguration &PassConfig) { 344 for (auto &P : Plugins) 345 P->modifyPassConfig(MR, TT, PassConfig); 346 } 347 348 void ObjectLinkingLayer::notifyLoaded(MaterializationResponsibility &MR) { 349 for (auto &P : Plugins) 350 P->notifyLoaded(MR); 351 } 352 353 Error ObjectLinkingLayer::notifyEmitted(MaterializationResponsibility &MR, 354 AllocPtr Alloc) { 355 Error Err = Error::success(); 356 for (auto &P : Plugins) 357 Err = joinErrors(std::move(Err), P->notifyEmitted(MR)); 358 359 if (Err) 360 return Err; 361 362 { 363 std::lock_guard<std::mutex> Lock(LayerMutex); 364 UntrackedAllocs.push_back(std::move(Alloc)); 365 } 366 367 return Error::success(); 368 } 369 370 Error ObjectLinkingLayer::removeModule(VModuleKey K) { 371 Error Err = Error::success(); 372 373 for (auto &P : Plugins) 374 Err = joinErrors(std::move(Err), P->notifyRemovingModule(K)); 375 376 AllocPtr Alloc; 377 378 { 379 std::lock_guard<std::mutex> Lock(LayerMutex); 380 auto AllocItr = TrackedAllocs.find(K); 381 Alloc = std::move(AllocItr->second); 382 TrackedAllocs.erase(AllocItr); 383 } 384 385 assert(Alloc && "No allocation for key K"); 386 387 return joinErrors(std::move(Err), Alloc->deallocate()); 388 } 389 390 Error ObjectLinkingLayer::removeAllModules() { 391 392 Error Err = Error::success(); 393 394 for (auto &P : Plugins) 395 Err = joinErrors(std::move(Err), P->notifyRemovingAllModules()); 396 397 std::vector<AllocPtr> Allocs; 398 { 399 std::lock_guard<std::mutex> Lock(LayerMutex); 400 Allocs = std::move(UntrackedAllocs); 401 402 for (auto &KV : TrackedAllocs) 403 Allocs.push_back(std::move(KV.second)); 404 405 TrackedAllocs.clear(); 406 } 407 408 while (!Allocs.empty()) { 409 Err = joinErrors(std::move(Err), Allocs.back()->deallocate()); 410 Allocs.pop_back(); 411 } 412 413 return Err; 414 } 415 416 void LocalEHFrameRegistrationPlugin::modifyPassConfig( 417 MaterializationResponsibility &MR, const Triple &TT, 418 PassConfiguration &PassConfig) { 419 assert(!InProcessLinks.count(&MR) && "Link for MR already being tracked?"); 420 421 PassConfig.PostFixupPasses.push_back( 422 createEHFrameRecorderPass(TT, [this, &MR](JITTargetAddress Addr) { 423 if (Addr) 424 InProcessLinks[&MR] = jitTargetAddressToPointer<void *>(Addr); 425 })); 426 } 427 428 Error LocalEHFrameRegistrationPlugin::notifyEmitted( 429 MaterializationResponsibility &MR) { 430 431 auto EHFrameAddrItr = InProcessLinks.find(&MR); 432 if (EHFrameAddrItr == InProcessLinks.end()) 433 return Error::success(); 434 435 const void *EHFrameAddr = EHFrameAddrItr->second; 436 assert(EHFrameAddr && "eh-frame addr to register can not be null"); 437 438 InProcessLinks.erase(EHFrameAddrItr); 439 if (auto Key = MR.getVModuleKey()) 440 TrackedEHFrameAddrs[Key] = EHFrameAddr; 441 else 442 UntrackedEHFrameAddrs.push_back(EHFrameAddr); 443 444 return registerEHFrameSection(EHFrameAddr); 445 } 446 447 Error LocalEHFrameRegistrationPlugin::notifyRemovingModule(VModuleKey K) { 448 auto EHFrameAddrItr = TrackedEHFrameAddrs.find(K); 449 if (EHFrameAddrItr == TrackedEHFrameAddrs.end()) 450 return Error::success(); 451 452 const void *EHFrameAddr = EHFrameAddrItr->second; 453 assert(EHFrameAddr && "Tracked eh-frame addr must not be null"); 454 455 TrackedEHFrameAddrs.erase(EHFrameAddrItr); 456 457 return deregisterEHFrameSection(EHFrameAddr); 458 } 459 460 Error LocalEHFrameRegistrationPlugin::notifyRemovingAllModules() { 461 462 std::vector<const void *> EHFrameAddrs = std::move(UntrackedEHFrameAddrs); 463 EHFrameAddrs.reserve(EHFrameAddrs.size() + TrackedEHFrameAddrs.size()); 464 465 for (auto &KV : TrackedEHFrameAddrs) 466 EHFrameAddrs.push_back(KV.second); 467 468 TrackedEHFrameAddrs.clear(); 469 470 Error Err = Error::success(); 471 472 while (!EHFrameAddrs.empty()) { 473 const void *EHFrameAddr = EHFrameAddrs.back(); 474 assert(EHFrameAddr && "Untracked eh-frame addr must not be null"); 475 EHFrameAddrs.pop_back(); 476 Err = joinErrors(std::move(Err), deregisterEHFrameSection(EHFrameAddr)); 477 } 478 479 return Err; 480 } 481 482 } // End namespace orc. 483 } // End namespace llvm. 484