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( 28 ObjectLinkingLayer &Layer, 29 std::unique_ptr<MaterializationResponsibility> MR, 30 std::unique_ptr<MemoryBuffer> ObjBuffer) 31 : JITLinkContext(&MR->getTargetJITDylib()), Layer(Layer), 32 MR(std::move(MR)), ObjBuffer(std::move(ObjBuffer)) {} 33 34 ~ObjectLinkingLayerJITLinkContext() { 35 // If there is an object buffer return function then use it to 36 // return ownership of the buffer. 37 if (Layer.ReturnObjectBuffer) 38 Layer.ReturnObjectBuffer(std::move(ObjBuffer)); 39 } 40 41 JITLinkMemoryManager &getMemoryManager() override { return Layer.MemMgr; } 42 43 MemoryBufferRef getObjectBuffer() const override { 44 return ObjBuffer->getMemBufferRef(); 45 } 46 47 void notifyFailed(Error Err) override { 48 for (auto &P : Layer.Plugins) 49 Err = joinErrors(std::move(Err), P->notifyFailed(*MR)); 50 Layer.getExecutionSession().reportError(std::move(Err)); 51 MR->failMaterialization(); 52 } 53 54 void lookup(const LookupMap &Symbols, 55 std::unique_ptr<JITLinkAsyncLookupContinuation> LC) override { 56 57 JITDylibSearchOrder LinkOrder; 58 MR->getTargetJITDylib().withLinkOrderDo( 59 [&](const JITDylibSearchOrder &LO) { LinkOrder = LO; }); 60 61 auto &ES = Layer.getExecutionSession(); 62 63 SymbolLookupSet LookupSet; 64 for (auto &KV : Symbols) { 65 orc::SymbolLookupFlags LookupFlags; 66 switch (KV.second) { 67 case jitlink::SymbolLookupFlags::RequiredSymbol: 68 LookupFlags = orc::SymbolLookupFlags::RequiredSymbol; 69 break; 70 case jitlink::SymbolLookupFlags::WeaklyReferencedSymbol: 71 LookupFlags = orc::SymbolLookupFlags::WeaklyReferencedSymbol; 72 break; 73 } 74 LookupSet.add(ES.intern(KV.first), LookupFlags); 75 } 76 77 // OnResolve -- De-intern the symbols and pass the result to the linker. 78 auto OnResolve = [LookupContinuation = 79 std::move(LC)](Expected<SymbolMap> Result) mutable { 80 if (!Result) 81 LookupContinuation->run(Result.takeError()); 82 else { 83 AsyncLookupResult LR; 84 for (auto &KV : *Result) 85 LR[*KV.first] = KV.second; 86 LookupContinuation->run(std::move(LR)); 87 } 88 }; 89 90 for (auto &KV : InternalNamedSymbolDeps) { 91 SymbolDependenceMap InternalDeps; 92 InternalDeps[&MR->getTargetJITDylib()] = std::move(KV.second); 93 MR->addDependencies(KV.first, InternalDeps); 94 } 95 96 ES.lookup(LookupKind::Static, LinkOrder, std::move(LookupSet), 97 SymbolState::Resolved, std::move(OnResolve), 98 [this](const SymbolDependenceMap &Deps) { 99 registerDependencies(Deps); 100 }); 101 } 102 103 Error notifyResolved(LinkGraph &G) override { 104 auto &ES = Layer.getExecutionSession(); 105 106 SymbolFlagsMap ExtraSymbolsToClaim; 107 bool AutoClaim = Layer.AutoClaimObjectSymbols; 108 109 SymbolMap InternedResult; 110 for (auto *Sym : G.defined_symbols()) 111 if (Sym->hasName() && Sym->getScope() != Scope::Local) { 112 auto InternedName = ES.intern(Sym->getName()); 113 JITSymbolFlags Flags; 114 115 if (Sym->isCallable()) 116 Flags |= JITSymbolFlags::Callable; 117 if (Sym->getScope() == Scope::Default) 118 Flags |= JITSymbolFlags::Exported; 119 120 InternedResult[InternedName] = 121 JITEvaluatedSymbol(Sym->getAddress(), Flags); 122 if (AutoClaim && !MR->getSymbols().count(InternedName)) { 123 assert(!ExtraSymbolsToClaim.count(InternedName) && 124 "Duplicate symbol to claim?"); 125 ExtraSymbolsToClaim[InternedName] = Flags; 126 } 127 } 128 129 for (auto *Sym : G.absolute_symbols()) 130 if (Sym->hasName()) { 131 auto InternedName = ES.intern(Sym->getName()); 132 JITSymbolFlags Flags; 133 Flags |= JITSymbolFlags::Absolute; 134 if (Sym->isCallable()) 135 Flags |= JITSymbolFlags::Callable; 136 if (Sym->getLinkage() == Linkage::Weak) 137 Flags |= JITSymbolFlags::Weak; 138 InternedResult[InternedName] = 139 JITEvaluatedSymbol(Sym->getAddress(), Flags); 140 if (AutoClaim && !MR->getSymbols().count(InternedName)) { 141 assert(!ExtraSymbolsToClaim.count(InternedName) && 142 "Duplicate symbol to claim?"); 143 ExtraSymbolsToClaim[InternedName] = Flags; 144 } 145 } 146 147 if (!ExtraSymbolsToClaim.empty()) 148 if (auto Err = MR->defineMaterializing(ExtraSymbolsToClaim)) 149 return Err; 150 151 { 152 153 // Check that InternedResult matches up with MR->getSymbols(). 154 // This guards against faulty transformations / compilers / object caches. 155 156 // First check that there aren't any missing symbols. 157 size_t NumMaterializationSideEffectsOnlySymbols = 0; 158 SymbolNameVector ExtraSymbols; 159 SymbolNameVector MissingSymbols; 160 for (auto &KV : MR->getSymbols()) { 161 162 // If this is a materialization-side-effects only symbol then bump 163 // the counter and make sure it's *not* defined, otherwise make 164 // sure that it is defined. 165 if (KV.second.hasMaterializationSideEffectsOnly()) { 166 ++NumMaterializationSideEffectsOnlySymbols; 167 if (InternedResult.count(KV.first)) 168 ExtraSymbols.push_back(KV.first); 169 continue; 170 } else if (!InternedResult.count(KV.first)) 171 MissingSymbols.push_back(KV.first); 172 } 173 174 // If there were missing symbols then report the error. 175 if (!MissingSymbols.empty()) 176 return make_error<MissingSymbolDefinitions>(G.getName(), 177 std::move(MissingSymbols)); 178 179 // If there are more definitions than expected, add them to the 180 // ExtraSymbols vector. 181 if (InternedResult.size() > 182 MR->getSymbols().size() - NumMaterializationSideEffectsOnlySymbols) { 183 for (auto &KV : InternedResult) 184 if (!MR->getSymbols().count(KV.first)) 185 ExtraSymbols.push_back(KV.first); 186 } 187 188 // If there were extra definitions then report the error. 189 if (!ExtraSymbols.empty()) 190 return make_error<UnexpectedSymbolDefinitions>(G.getName(), 191 std::move(ExtraSymbols)); 192 } 193 194 if (auto Err = MR->notifyResolved(InternedResult)) 195 return Err; 196 197 Layer.notifyLoaded(*MR); 198 return Error::success(); 199 } 200 201 void notifyFinalized( 202 std::unique_ptr<JITLinkMemoryManager::Allocation> A) override { 203 if (auto Err = Layer.notifyEmitted(*MR, std::move(A))) { 204 Layer.getExecutionSession().reportError(std::move(Err)); 205 MR->failMaterialization(); 206 return; 207 } 208 if (auto Err = MR->notifyEmitted()) { 209 Layer.getExecutionSession().reportError(std::move(Err)); 210 MR->failMaterialization(); 211 } 212 } 213 214 LinkGraphPassFunction getMarkLivePass(const Triple &TT) const override { 215 return [this](LinkGraph &G) { return markResponsibilitySymbolsLive(G); }; 216 } 217 218 Error modifyPassConfig(const Triple &TT, PassConfiguration &Config) override { 219 // Add passes to mark duplicate defs as should-discard, and to walk the 220 // link graph to build the symbol dependence graph. 221 Config.PrePrunePasses.push_back( 222 [this](LinkGraph &G) { return externalizeWeakAndCommonSymbols(G); }); 223 224 Layer.modifyPassConfig(*MR, TT, Config); 225 226 Config.PostPrunePasses.push_back( 227 [this](LinkGraph &G) { return computeNamedSymbolDependencies(G); }); 228 229 return Error::success(); 230 } 231 232 private: 233 struct LocalSymbolNamedDependencies { 234 SymbolNameSet Internal, External; 235 }; 236 237 using LocalSymbolNamedDependenciesMap = 238 DenseMap<const Symbol *, LocalSymbolNamedDependencies>; 239 240 Error externalizeWeakAndCommonSymbols(LinkGraph &G) { 241 auto &ES = Layer.getExecutionSession(); 242 for (auto *Sym : G.defined_symbols()) 243 if (Sym->hasName() && Sym->getLinkage() == Linkage::Weak) { 244 if (!MR->getSymbols().count(ES.intern(Sym->getName()))) 245 G.makeExternal(*Sym); 246 } 247 248 for (auto *Sym : G.absolute_symbols()) 249 if (Sym->hasName() && Sym->getLinkage() == Linkage::Weak) { 250 if (!MR->getSymbols().count(ES.intern(Sym->getName()))) 251 G.makeExternal(*Sym); 252 } 253 254 return Error::success(); 255 } 256 257 Error markResponsibilitySymbolsLive(LinkGraph &G) const { 258 auto &ES = Layer.getExecutionSession(); 259 for (auto *Sym : G.defined_symbols()) 260 if (Sym->hasName() && MR->getSymbols().count(ES.intern(Sym->getName()))) 261 Sym->setLive(true); 262 return Error::success(); 263 } 264 265 Error computeNamedSymbolDependencies(LinkGraph &G) { 266 auto &ES = MR->getTargetJITDylib().getExecutionSession(); 267 auto LocalDeps = computeLocalDeps(G); 268 269 // Compute dependencies for symbols defined in the JITLink graph. 270 for (auto *Sym : G.defined_symbols()) { 271 272 // Skip local symbols: we do not track dependencies for these. 273 if (Sym->getScope() == Scope::Local) 274 continue; 275 assert(Sym->hasName() && 276 "Defined non-local jitlink::Symbol should have a name"); 277 278 SymbolNameSet ExternalSymDeps, InternalSymDeps; 279 280 // Find internal and external named symbol dependencies. 281 for (auto &E : Sym->getBlock().edges()) { 282 auto &TargetSym = E.getTarget(); 283 284 if (TargetSym.getScope() != Scope::Local) { 285 if (TargetSym.isExternal()) 286 ExternalSymDeps.insert(ES.intern(TargetSym.getName())); 287 else if (&TargetSym != Sym) 288 InternalSymDeps.insert(ES.intern(TargetSym.getName())); 289 } else { 290 assert(TargetSym.isDefined() && 291 "local symbols must be defined"); 292 auto I = LocalDeps.find(&TargetSym); 293 if (I != LocalDeps.end()) { 294 for (auto &S : I->second.External) 295 ExternalSymDeps.insert(S); 296 for (auto &S : I->second.Internal) 297 InternalSymDeps.insert(S); 298 } 299 } 300 } 301 302 if (ExternalSymDeps.empty() && InternalSymDeps.empty()) 303 continue; 304 305 auto SymName = ES.intern(Sym->getName()); 306 if (!ExternalSymDeps.empty()) 307 ExternalNamedSymbolDeps[SymName] = std::move(ExternalSymDeps); 308 if (!InternalSymDeps.empty()) 309 InternalNamedSymbolDeps[SymName] = std::move(InternalSymDeps); 310 } 311 312 for (auto &P : Layer.Plugins) { 313 auto SyntheticLocalDeps = P->getSyntheticSymbolLocalDependencies(*MR); 314 if (SyntheticLocalDeps.empty()) 315 continue; 316 317 for (auto &KV : SyntheticLocalDeps) { 318 auto &Name = KV.first; 319 auto &LocalDepsForName = KV.second; 320 for (auto *Local : LocalDepsForName) { 321 assert(Local->getScope() == Scope::Local && 322 "Dependence on non-local symbol"); 323 auto LocalNamedDepsItr = LocalDeps.find(Local); 324 if (LocalNamedDepsItr == LocalDeps.end()) 325 continue; 326 for (auto &S : LocalNamedDepsItr->second.Internal) 327 InternalNamedSymbolDeps[Name].insert(S); 328 for (auto &S : LocalNamedDepsItr->second.External) 329 ExternalNamedSymbolDeps[Name].insert(S); 330 } 331 } 332 } 333 334 return Error::success(); 335 } 336 337 LocalSymbolNamedDependenciesMap computeLocalDeps(LinkGraph &G) { 338 DenseMap<jitlink::Symbol *, DenseSet<jitlink::Symbol *>> DepMap; 339 340 // For all local symbols: 341 // (1) Add their named dependencies. 342 // (2) Add them to the worklist for further iteration if they have any 343 // depend on any other local symbols. 344 struct WorklistEntry { 345 WorklistEntry(Symbol *Sym, DenseSet<Symbol *> LocalDeps) 346 : Sym(Sym), LocalDeps(std::move(LocalDeps)) {} 347 348 Symbol *Sym = nullptr; 349 DenseSet<Symbol *> LocalDeps; 350 }; 351 std::vector<WorklistEntry> Worklist; 352 for (auto *Sym : G.defined_symbols()) 353 if (Sym->getScope() == Scope::Local) { 354 auto &SymNamedDeps = DepMap[Sym]; 355 DenseSet<Symbol *> LocalDeps; 356 357 for (auto &E : Sym->getBlock().edges()) { 358 auto &TargetSym = E.getTarget(); 359 if (TargetSym.getScope() != Scope::Local) 360 SymNamedDeps.insert(&TargetSym); 361 else { 362 assert(TargetSym.isDefined() && 363 "local symbols must be defined"); 364 LocalDeps.insert(&TargetSym); 365 } 366 } 367 368 if (!LocalDeps.empty()) 369 Worklist.push_back(WorklistEntry(Sym, std::move(LocalDeps))); 370 } 371 372 // Loop over all local symbols with local dependencies, propagating 373 // their respective non-local dependencies. Iterate until we hit a stable 374 // state. 375 bool Changed; 376 do { 377 Changed = false; 378 for (auto &WLEntry : Worklist) { 379 auto *Sym = WLEntry.Sym; 380 auto &NamedDeps = DepMap[Sym]; 381 auto &LocalDeps = WLEntry.LocalDeps; 382 383 for (auto *TargetSym : LocalDeps) { 384 auto I = DepMap.find(TargetSym); 385 if (I != DepMap.end()) 386 for (const auto &S : I->second) 387 Changed |= NamedDeps.insert(S).second; 388 } 389 } 390 } while (Changed); 391 392 // Intern the results to produce a mapping of jitlink::Symbol* to internal 393 // and external symbol names. 394 auto &ES = Layer.getExecutionSession(); 395 LocalSymbolNamedDependenciesMap Result; 396 for (auto &KV : DepMap) { 397 auto *Local = KV.first; 398 assert(Local->getScope() == Scope::Local && 399 "DepMap keys should all be local symbols"); 400 auto &LocalNamedDeps = Result[Local]; 401 for (auto *Named : KV.second) { 402 assert(Named->getScope() != Scope::Local && 403 "DepMap values should all be non-local symbol sets"); 404 if (Named->isExternal()) 405 LocalNamedDeps.External.insert(ES.intern(Named->getName())); 406 else 407 LocalNamedDeps.Internal.insert(ES.intern(Named->getName())); 408 } 409 } 410 411 return Result; 412 } 413 414 void registerDependencies(const SymbolDependenceMap &QueryDeps) { 415 for (auto &NamedDepsEntry : ExternalNamedSymbolDeps) { 416 auto &Name = NamedDepsEntry.first; 417 auto &NameDeps = NamedDepsEntry.second; 418 SymbolDependenceMap SymbolDeps; 419 420 for (const auto &QueryDepsEntry : QueryDeps) { 421 JITDylib &SourceJD = *QueryDepsEntry.first; 422 const SymbolNameSet &Symbols = QueryDepsEntry.second; 423 auto &DepsForJD = SymbolDeps[&SourceJD]; 424 425 for (const auto &S : Symbols) 426 if (NameDeps.count(S)) 427 DepsForJD.insert(S); 428 429 if (DepsForJD.empty()) 430 SymbolDeps.erase(&SourceJD); 431 } 432 433 MR->addDependencies(Name, SymbolDeps); 434 } 435 } 436 437 ObjectLinkingLayer &Layer; 438 std::unique_ptr<MaterializationResponsibility> MR; 439 std::unique_ptr<MemoryBuffer> ObjBuffer; 440 DenseMap<SymbolStringPtr, SymbolNameSet> ExternalNamedSymbolDeps; 441 DenseMap<SymbolStringPtr, SymbolNameSet> InternalNamedSymbolDeps; 442 }; 443 444 ObjectLinkingLayer::Plugin::~Plugin() {} 445 446 ObjectLinkingLayer::ObjectLinkingLayer(ExecutionSession &ES, 447 JITLinkMemoryManager &MemMgr) 448 : ObjectLayer(ES), MemMgr(MemMgr) { 449 ES.registerResourceManager(*this); 450 } 451 452 ObjectLinkingLayer::ObjectLinkingLayer( 453 ExecutionSession &ES, std::unique_ptr<JITLinkMemoryManager> MemMgr) 454 : ObjectLayer(ES), MemMgr(*MemMgr), MemMgrOwnership(std::move(MemMgr)) { 455 ES.registerResourceManager(*this); 456 } 457 458 ObjectLinkingLayer::~ObjectLinkingLayer() { 459 assert(Allocs.empty() && "Layer destroyed with resources still attached"); 460 getExecutionSession().deregisterResourceManager(*this); 461 } 462 463 void ObjectLinkingLayer::emit(std::unique_ptr<MaterializationResponsibility> R, 464 std::unique_ptr<MemoryBuffer> O) { 465 assert(O && "Object must not be null"); 466 jitLink(std::make_unique<ObjectLinkingLayerJITLinkContext>( 467 *this, std::move(R), std::move(O))); 468 } 469 470 void ObjectLinkingLayer::modifyPassConfig(MaterializationResponsibility &MR, 471 const Triple &TT, 472 PassConfiguration &PassConfig) { 473 for (auto &P : Plugins) 474 P->modifyPassConfig(MR, TT, PassConfig); 475 } 476 477 void ObjectLinkingLayer::notifyLoaded(MaterializationResponsibility &MR) { 478 for (auto &P : Plugins) 479 P->notifyLoaded(MR); 480 } 481 482 Error ObjectLinkingLayer::notifyEmitted(MaterializationResponsibility &MR, 483 AllocPtr Alloc) { 484 Error Err = Error::success(); 485 for (auto &P : Plugins) 486 Err = joinErrors(std::move(Err), P->notifyEmitted(MR)); 487 488 if (Err) 489 return Err; 490 491 return MR.withResourceKeyDo( 492 [&](ResourceKey K) { Allocs[K].push_back(std::move(Alloc)); }); 493 } 494 495 Error ObjectLinkingLayer::handleRemoveResources(ResourceKey K) { 496 497 Error Err = Error::success(); 498 499 for (auto &P : Plugins) 500 Err = joinErrors(std::move(Err), P->notifyRemovingResources(K)); 501 502 std::vector<AllocPtr> AllocsToRemove; 503 getExecutionSession().runSessionLocked([&] { 504 auto I = Allocs.find(K); 505 if (I != Allocs.end()) { 506 std::swap(AllocsToRemove, I->second); 507 Allocs.erase(I); 508 } 509 }); 510 511 while (!AllocsToRemove.empty()) { 512 Err = joinErrors(std::move(Err), AllocsToRemove.back()->deallocate()); 513 AllocsToRemove.pop_back(); 514 } 515 516 return Err; 517 } 518 519 void ObjectLinkingLayer::handleTransferResources(ResourceKey DstKey, 520 ResourceKey SrcKey) { 521 auto I = Allocs.find(SrcKey); 522 if (I != Allocs.end()) { 523 auto &SrcAllocs = I->second; 524 auto &DstAllocs = Allocs[DstKey]; 525 DstAllocs.reserve(DstAllocs.size() + SrcAllocs.size()); 526 for (auto &Alloc : SrcAllocs) 527 DstAllocs.push_back(std::move(Alloc)); 528 529 // Erase SrcKey entry using value rather than iterator I: I may have been 530 // invalidated when we looked up DstKey. 531 Allocs.erase(SrcKey); 532 } 533 534 for (auto &P : Plugins) 535 P->notifyTransferringResources(DstKey, SrcKey); 536 } 537 538 EHFrameRegistrationPlugin::EHFrameRegistrationPlugin( 539 ExecutionSession &ES, std::unique_ptr<EHFrameRegistrar> Registrar) 540 : ES(ES), Registrar(std::move(Registrar)) {} 541 542 void EHFrameRegistrationPlugin::modifyPassConfig( 543 MaterializationResponsibility &MR, const Triple &TT, 544 PassConfiguration &PassConfig) { 545 546 PassConfig.PostFixupPasses.push_back(createEHFrameRecorderPass( 547 TT, [this, &MR](JITTargetAddress Addr, size_t Size) { 548 if (Addr) { 549 std::lock_guard<std::mutex> Lock(EHFramePluginMutex); 550 assert(!InProcessLinks.count(&MR) && 551 "Link for MR already being tracked?"); 552 InProcessLinks[&MR] = {Addr, Size}; 553 } 554 })); 555 } 556 557 Error EHFrameRegistrationPlugin::notifyEmitted( 558 MaterializationResponsibility &MR) { 559 560 EHFrameRange EmittedRange; 561 { 562 std::lock_guard<std::mutex> Lock(EHFramePluginMutex); 563 564 auto EHFrameRangeItr = InProcessLinks.find(&MR); 565 if (EHFrameRangeItr == InProcessLinks.end()) 566 return Error::success(); 567 568 EmittedRange = EHFrameRangeItr->second; 569 assert(EmittedRange.Addr && "eh-frame addr to register can not be null"); 570 InProcessLinks.erase(EHFrameRangeItr); 571 } 572 573 if (auto Err = MR.withResourceKeyDo( 574 [&](ResourceKey K) { EHFrameRanges[K].push_back(EmittedRange); })) 575 return Err; 576 577 return Registrar->registerEHFrames(EmittedRange.Addr, EmittedRange.Size); 578 } 579 580 Error EHFrameRegistrationPlugin::notifyFailed( 581 MaterializationResponsibility &MR) { 582 std::lock_guard<std::mutex> Lock(EHFramePluginMutex); 583 InProcessLinks.erase(&MR); 584 return Error::success(); 585 } 586 587 Error EHFrameRegistrationPlugin::notifyRemovingResources(ResourceKey K) { 588 std::vector<EHFrameRange> RangesToRemove; 589 590 ES.runSessionLocked([&] { 591 auto I = EHFrameRanges.find(K); 592 if (I != EHFrameRanges.end()) { 593 RangesToRemove = std::move(I->second); 594 EHFrameRanges.erase(I); 595 } 596 }); 597 598 Error Err = Error::success(); 599 while (!RangesToRemove.empty()) { 600 auto RangeToRemove = RangesToRemove.back(); 601 RangesToRemove.pop_back(); 602 assert(RangeToRemove.Addr && "Untracked eh-frame range must not be null"); 603 Err = joinErrors( 604 std::move(Err), 605 Registrar->deregisterEHFrames(RangeToRemove.Addr, RangeToRemove.Size)); 606 } 607 608 return Err; 609 } 610 611 void EHFrameRegistrationPlugin::notifyTransferringResources( 612 ResourceKey DstKey, ResourceKey SrcKey) { 613 auto SI = EHFrameRanges.find(SrcKey); 614 if (SI != EHFrameRanges.end()) { 615 auto &SrcRanges = SI->second; 616 auto &DstRanges = EHFrameRanges[DstKey]; 617 DstRanges.reserve(DstRanges.size() + SrcRanges.size()); 618 for (auto &SrcRange : SrcRanges) 619 DstRanges.push_back(std::move(SrcRange)); 620 EHFrameRanges.erase(SI); 621 } 622 } 623 624 } // End namespace orc. 625 } // End namespace llvm. 626