xref: /llvm-project/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp (revision 8904ee8ac7ebcc50a60de0914abc6862e28b6664)
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