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