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