19#define DEBUG_TYPE "orc"
28 bool IsMachO =
G.getTargetTriple().isOSBinFormatMachO();
29 bool IsElf =
G.getTargetTriple().isOSBinFormatELF();
30 if (!IsMachO && !IsElf)
33 for (
auto &Sec :
G.sections()) {
44 switch (TT.getArch()) {
78 static std::unique_ptr<LinkGraphMaterializationUnit>
80 auto LGI = scanLinkGraph(ObjLinkingLayer.getExecutionSession(), *
G);
81 return std::unique_ptr<LinkGraphMaterializationUnit>(
82 new LinkGraphMaterializationUnit(ObjLinkingLayer, std::move(
G),
87 void materialize(std::unique_ptr<MaterializationResponsibility> MR)
override {
88 ObjLinkingLayer.
emit(std::move(MR), std::move(
G));
96 for (
auto *
Sym :
G.defined_symbols()) {
103 getJITSymbolFlagsForSymbol(*
Sym);
106 if (hasInitializerSection(
G))
107 LGI.InitSymbol = makeInitSymbol(ES,
G);
113 std::string InitSymString;
115 <<
"$." <<
G.getName() <<
".__inits" << Counter++;
116 return ES.
intern(InitSymString);
120 std::unique_ptr<LinkGraph>
G, Interface LGI)
125 for (
auto *
Sym :
G->defined_symbols())
128 "Discarding non-weak definition");
129 G->makeExternal(*
Sym);
135 std::unique_ptr<LinkGraph>
G;
136 static std::atomic<uint64_t> Counter;
139std::atomic<uint64_t> LinkGraphMaterializationUnit::Counter{0};
150 std::unique_ptr<MaterializationResponsibility> MR,
151 std::unique_ptr<MemoryBuffer> ObjBuffer)
158 if (Layer.ReturnObjectBuffer && ObjBuffer)
159 Layer.ReturnObjectBuffer(std::move(ObjBuffer));
165 for (
auto &
P : Layer.Plugins)
166 P->notifyMaterializing(*MR,
G, *
this,
167 ObjBuffer ? ObjBuffer->getMemBufferRef()
172 for (
auto &
P : Layer.Plugins)
173 Err =
joinErrors(std::move(Err),
P->notifyFailed(*MR));
174 Layer.getExecutionSession().reportError(std::move(Err));
175 MR->failMaterialization();
179 std::unique_ptr<JITLinkAsyncLookupContinuation> LC)
override {
182 MR->getTargetJITDylib().withLinkOrderDo(
185 auto &ES = Layer.getExecutionSession();
188 for (
auto &KV : Symbols) {
198 LookupSet.
add(ES.intern(KV.first), LookupFlags);
202 auto OnResolve = [LookupContinuation =
205 LookupContinuation->run(
Result.takeError());
209 LR[*KV.first] = KV.second;
210 LookupContinuation->run(std::move(LR));
214 for (
auto &KV : InternalNamedSymbolDeps) {
216 InternalDeps[&MR->getTargetJITDylib()] = std::move(KV.second);
217 MR->addDependencies(KV.first, InternalDeps);
223 registerDependencies(Deps);
228 auto &ES = Layer.getExecutionSession();
231 bool AutoClaim = Layer.AutoClaimObjectSymbols;
234 for (
auto *
Sym :
G.defined_symbols())
236 auto InternedName = ES.intern(
Sym->
getName());
237 auto Ptr = getJITSymbolPtrForSymbol(*
Sym,
G.getTargetTriple());
238 auto Flags = getJITSymbolFlagsForSymbol(*
Sym);
239 InternedResult[InternedName] = {
Ptr, Flags};
240 if (AutoClaim && !MR->getSymbols().count(InternedName)) {
242 "Duplicate symbol to claim?");
243 ExtraSymbolsToClaim[InternedName] = Flags;
247 for (
auto *
Sym :
G.absolute_symbols())
249 auto InternedName = ES.intern(
Sym->
getName());
250 auto Ptr = getJITSymbolPtrForSymbol(*
Sym,
G.getTargetTriple());
251 auto Flags = getJITSymbolFlagsForSymbol(*
Sym);
252 InternedResult[InternedName] = {
Ptr, Flags};
253 if (AutoClaim && !MR->getSymbols().count(InternedName)) {
255 "Duplicate symbol to claim?");
256 ExtraSymbolsToClaim[InternedName] = Flags;
260 if (!ExtraSymbolsToClaim.
empty())
261 if (
auto Err = MR->defineMaterializing(ExtraSymbolsToClaim))
271 size_t NumMaterializationSideEffectsOnlySymbols = 0;
274 for (
auto &KV : MR->getSymbols()) {
276 auto I = InternedResult.
find(KV.first);
281 if (KV.second.hasMaterializationSideEffectsOnly()) {
282 ++NumMaterializationSideEffectsOnlySymbols;
283 if (
I != InternedResult.
end())
284 ExtraSymbols.push_back(KV.first);
286 }
else if (
I == InternedResult.
end())
287 MissingSymbols.push_back(KV.first);
288 else if (Layer.OverrideObjectFlags)
289 I->second.setFlags(KV.second);
293 if (!MissingSymbols.empty())
294 return make_error<MissingSymbolDefinitions>(
295 Layer.getExecutionSession().getSymbolStringPool(),
G.getName(),
296 std::move(MissingSymbols));
300 if (InternedResult.
size() >
301 MR->getSymbols().size() - NumMaterializationSideEffectsOnlySymbols) {
302 for (
auto &KV : InternedResult)
303 if (!MR->getSymbols().count(KV.first))
304 ExtraSymbols.push_back(KV.first);
308 if (!ExtraSymbols.empty())
309 return make_error<UnexpectedSymbolDefinitions>(
310 Layer.getExecutionSession().getSymbolStringPool(),
G.getName(),
311 std::move(ExtraSymbols));
314 if (
auto Err = MR->notifyResolved(InternedResult))
317 Layer.notifyLoaded(*MR);
322 if (
auto Err = Layer.notifyEmitted(*MR, std::move(
A))) {
323 Layer.getExecutionSession().reportError(std::move(Err));
324 MR->failMaterialization();
327 if (
auto Err = MR->notifyEmitted()) {
328 Layer.getExecutionSession().reportError(std::move(Err));
329 MR->failMaterialization();
334 return [
this](
LinkGraph &
G) {
return markResponsibilitySymbolsLive(
G); };
341 return claimOrExternalizeWeakAndCommonSymbols(
G);
344 Layer.modifyPassConfig(*MR, LG,
Config);
346 Config.PostPrunePasses.push_back(
347 [
this](
LinkGraph &
G) {
return computeNamedSymbolDependencies(
G); });
356 struct BlockSymbolDependencies {
361 class BlockDependenciesMap {
365 : ES(ES), BlockDeps(
std::
move(BlockDeps)) {}
367 const BlockSymbolDependencies &operator[](
const Block &
B) {
369 auto I = BlockTransitiveDepsCache.find(&
B);
370 if (
I != BlockTransitiveDepsCache.end())
374 BlockSymbolDependencies BTDCacheVal;
375 auto BDI = BlockDeps.find(&
B);
376 assert(BDI != BlockDeps.end() &&
"No block dependencies");
378 for (
auto *BDep : BDI->second) {
379 auto &BID = getBlockImmediateDeps(*BDep);
380 for (
auto &ExternalDep : BID.External)
381 BTDCacheVal.External.insert(ExternalDep);
382 for (
auto &InternalDep : BID.Internal)
383 BTDCacheVal.Internal.insert(InternalDep);
386 return BlockTransitiveDepsCache
387 .insert(std::make_pair(&
B, std::move(BTDCacheVal)))
392 auto I = NameCache.find(&
Sym);
393 if (
I != NameCache.end())
396 return NameCache.insert(std::make_pair(&
Sym, ES.intern(
Sym.
getName())))
401 BlockSymbolDependencies &getBlockImmediateDeps(
Block &
B) {
403 auto I = BlockImmediateDepsCache.find(&
B);
404 if (
I != BlockImmediateDepsCache.end())
407 BlockSymbolDependencies BIDCacheVal;
408 for (
auto &
E :
B.edges()) {
409 auto &Tgt =
E.getTarget();
410 if (Tgt.getScope() != Scope::Local) {
411 if (Tgt.isExternal())
412 BIDCacheVal.External.insert(getInternedName(Tgt));
414 BIDCacheVal.Internal.insert(getInternedName(Tgt));
418 return BlockImmediateDepsCache
419 .insert(std::make_pair(&
B, std::move(BIDCacheVal)))
431 auto &ES = Layer.getExecutionSession();
434 std::vector<std::pair<SymbolStringPtr, Symbol *>> NameToSym;
440 if (!MR->getSymbols().count(ES.intern(
Sym->
getName()))) {
441 NewSymbolsToClaim[
Name] =
443 NameToSym.push_back(std::make_pair(std::move(
Name),
Sym));
448 for (
auto *
Sym :
G.defined_symbols())
450 for (
auto *
Sym :
G.absolute_symbols())
456 cantFail(MR->defineMaterializing(std::move(NewSymbolsToClaim)));
461 for (
auto &KV : NameToSym) {
462 if (MR->getSymbols().count(KV.first))
463 KV.second->setLive(
true);
465 G.makeExternal(*KV.second);
472 auto &ES = Layer.getExecutionSession();
473 for (
auto *
Sym :
G.defined_symbols())
480 auto &ES = MR->getTargetJITDylib().getExecutionSession();
481 auto BlockDeps = computeBlockNonLocalDeps(
G);
484 for (
auto *
Sym :
G.defined_symbols()) {
490 "Defined non-local jitlink::Symbol should have a name");
493 if (SymDeps.External.empty() && SymDeps.Internal.empty())
497 if (!SymDeps.External.empty())
498 ExternalNamedSymbolDeps[SymName] = SymDeps.External;
499 if (!SymDeps.Internal.empty())
500 InternalNamedSymbolDeps[SymName] = SymDeps.Internal;
503 for (
auto &
P : Layer.Plugins) {
504 auto SynthDeps =
P->getSyntheticSymbolDependencies(*MR);
505 if (SynthDeps.empty())
509 for (
auto &KV : SynthDeps) {
510 auto &
Name = KV.first;
511 auto &DepsForName = KV.second;
512 for (
auto *
Sym : DepsForName) {
515 for (
auto &S : BDeps.Internal)
516 InternalNamedSymbolDeps[
Name].insert(S);
517 for (
auto &S : BDeps.External)
518 ExternalNamedSymbolDeps[
Name].insert(S);
521 ExternalNamedSymbolDeps[
Name].insert(
522 BlockDeps.getInternedName(*
Sym));
524 InternalNamedSymbolDeps[
Name].insert(
525 BlockDeps.getInternedName(*
Sym));
534 BlockDependenciesMap computeBlockNonLocalDeps(
LinkGraph &
G) {
539 bool DependenciesChanged =
true;
546 for (
auto *
B :
G.blocks())
551 for (
auto *
B :
G.blocks()) {
552 auto &BI = BlockInfos[
B];
553 for (
auto &
E :
B->edges()) {
554 if (
E.getTarget().getScope() == Scope::Local &&
555 !
E.getTarget().isAbsolute()) {
556 auto &TgtB =
E.getTarget().getBlock();
558 BI.Dependencies.insert(&TgtB);
559 BlockInfos[&TgtB].Dependants.
insert(
B);
566 if (!BI.Dependants.empty() && !BI.Dependencies.empty())
571 while (!WorkList.
empty()) {
574 auto &BI = BlockInfos[
B];
575 assert(BI.DependenciesChanged &&
576 "Block in worklist has unchanged dependencies");
577 BI.DependenciesChanged =
false;
578 for (
auto *Dependant : BI.Dependants) {
579 auto &DependantBI = BlockInfos[Dependant];
580 for (
auto *Dependency : BI.Dependencies) {
581 if (Dependant != Dependency &&
582 DependantBI.Dependencies.insert(Dependency).second)
583 if (!DependantBI.DependenciesChanged) {
584 DependantBI.DependenciesChanged =
true;
592 for (
auto &KV : BlockInfos)
593 BlockDeps[KV.first] = std::move(KV.second.Dependencies);
595 return BlockDependenciesMap(Layer.getExecutionSession(),
596 std::move(BlockDeps));
600 for (
auto &NamedDepsEntry : ExternalNamedSymbolDeps) {
601 auto &
Name = NamedDepsEntry.first;
602 auto &NameDeps = NamedDepsEntry.second;
605 for (
const auto &QueryDepsEntry : QueryDeps) {
606 JITDylib &SourceJD = *QueryDepsEntry.first;
608 auto &DepsForJD = SymbolDeps[&SourceJD];
610 for (
const auto &S : Symbols)
611 if (NameDeps.count(S))
614 if (DepsForJD.empty())
615 SymbolDeps.
erase(&SourceJD);
618 MR->addDependencies(
Name, SymbolDeps);
623 std::unique_ptr<MaterializationResponsibility> MR;
624 std::unique_ptr<MemoryBuffer> ObjBuffer;
636 :
BaseT(ES), MemMgr(ES.getExecutorProcessControl().getMemMgr()) {
642 :
BaseT(ES), MemMgr(MemMgr) {
648 :
BaseT(ES), MemMgr(*MemMgr), MemMgrOwnership(
std::
move(MemMgr)) {
653 assert(Allocs.empty() &&
"Layer destroyed with resources still attached");
654 getExecutionSession().deregisterResourceManager(*
this);
658 std::unique_ptr<LinkGraph>
G) {
660 return JD.
define(LinkGraphMaterializationUnit::Create(*
this, std::move(
G)),
665 std::unique_ptr<MemoryBuffer> O) {
666 assert(O &&
"Object must not be null");
669 auto Ctx = std::make_unique<ObjectLinkingLayerJITLinkContext>(
670 *
this, std::move(R), std::move(O));
672 Ctx->notifyMaterializing(**
G);
673 link(std::move(*
G), std::move(Ctx));
675 Ctx->notifyFailed(
G.takeError());
680 std::unique_ptr<LinkGraph>
G) {
681 auto Ctx = std::make_unique<ObjectLinkingLayerJITLinkContext>(
682 *
this, std::move(R),
nullptr);
683 Ctx->notifyMaterializing(*
G);
684 link(std::move(
G), std::move(Ctx));
690 for (
auto &
P : Plugins)
691 P->modifyPassConfig(MR,
G, PassConfig);
695 for (
auto &
P : Plugins)
702 for (
auto &
P : Plugins)
703 Err =
joinErrors(std::move(Err),
P->notifyEmitted(MR));
709 [&](
ResourceKey K) { Allocs[
K].push_back(std::move(FA)); });
716 for (
auto &
P : Plugins)
717 Err =
joinErrors(std::move(Err),
P->notifyRemovingResources(JD, K));
722 std::vector<FinalizedAlloc> AllocsToRemove;
723 getExecutionSession().runSessionLocked([&] {
724 auto I = Allocs.find(K);
725 if (
I != Allocs.end()) {
726 std::swap(AllocsToRemove, I->second);
731 if (AllocsToRemove.empty())
734 return MemMgr.deallocate(std::move(AllocsToRemove));
737void ObjectLinkingLayer::handleTransferResources(
JITDylib &JD,
740 auto I = Allocs.find(SrcKey);
741 if (
I != Allocs.end()) {
742 auto &SrcAllocs =
I->second;
743 auto &DstAllocs = Allocs[DstKey];
744 DstAllocs.reserve(DstAllocs.size() + SrcAllocs.size());
745 for (
auto &
Alloc : SrcAllocs)
746 DstAllocs.push_back(std::move(
Alloc));
750 Allocs.erase(SrcKey);
753 for (
auto &
P : Plugins)
754 P->notifyTransferringResources(JD, DstKey, SrcKey);
759 : ES(ES), Registrar(
std::
move(Registrar)) {}
768 std::lock_guard<std::mutex> Lock(EHFramePluginMutex);
769 assert(!InProcessLinks.count(&MR) &&
770 "Link for MR already being tracked?");
771 InProcessLinks[&MR] = {Addr, Size};
781 std::lock_guard<std::mutex> Lock(EHFramePluginMutex);
783 auto EHFrameRangeItr = InProcessLinks.find(&MR);
784 if (EHFrameRangeItr == InProcessLinks.end())
787 EmittedRange = EHFrameRangeItr->second;
788 assert(EmittedRange.
Start &&
"eh-frame addr to register can not be null");
789 InProcessLinks.erase(EHFrameRangeItr);
793 [&](
ResourceKey K) { EHFrameRanges[K].push_back(EmittedRange); }))
796 return Registrar->registerEHFrames(EmittedRange);
801 std::lock_guard<std::mutex> Lock(EHFramePluginMutex);
802 InProcessLinks.erase(&MR);
808 std::vector<ExecutorAddrRange> RangesToRemove;
811 auto I = EHFrameRanges.find(K);
812 if (
I != EHFrameRanges.end()) {
813 RangesToRemove = std::move(I->second);
814 EHFrameRanges.erase(I);
819 while (!RangesToRemove.empty()) {
820 auto RangeToRemove = RangesToRemove.back();
821 RangesToRemove.pop_back();
822 assert(RangeToRemove.Start &&
"Untracked eh-frame range must not be null");
824 Registrar->deregisterEHFrames(RangeToRemove));
832 auto SI = EHFrameRanges.find(SrcKey);
833 if (SI == EHFrameRanges.end())
836 auto DI = EHFrameRanges.find(DstKey);
837 if (DI != EHFrameRanges.end()) {
838 auto &SrcRanges = SI->second;
839 auto &DstRanges = DI->second;
840 DstRanges.reserve(DstRanges.size() + SrcRanges.size());
841 for (
auto &SrcRange : SrcRanges)
842 DstRanges.push_back(std::move(SrcRange));
843 EHFrameRanges.erase(SI);
847 auto Tmp = std::move(SI->second);
848 EHFrameRanges.erase(SI);
849 EHFrameRanges[DstKey] = std::move(Tmp);
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
iterator find(const_arg_type_t< KeyT > Val)
bool erase(const KeyT &Val)
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
Flags for symbols in the JIT.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
Triple - Helper class for working with autoconf configuration names.
An Addressable with content and edges.
Holds context for a single jitLink invocation.
Represents a finalized allocation.
Manages allocations of JIT memory.
bool isExternal() const
Returns true if the underlying addressable is an unresolved external.
bool isCallable() const
Returns true is this symbol is callable.
StringRef getName() const
Returns the name of this symbol (empty if the symbol is anonymous).
Scope getScope() const
Get the visibility for this Symbol.
Linkage getLinkage() const
Get the linkage for this Symbol.
orc::ExecutorAddr getAddress() const
Returns the address of this symbol.
void setLive(bool IsLive)
Set this symbol's live bit.
Block & getBlock()
Return the Block for this Symbol (Symbol must be defined).
bool hasName() const
Returns true if this symbol has a name.
void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey, ResourceKey SrcKey) override
Error notifyEmitted(MaterializationResponsibility &MR) override
Error notifyFailed(MaterializationResponsibility &MR) override
EHFrameRegistrationPlugin(ExecutionSession &ES, std::unique_ptr< jitlink::EHFrameRegistrar > Registrar)
Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override
void modifyPassConfig(MaterializationResponsibility &MR, jitlink::LinkGraph &G, jitlink::PassConfiguration &PassConfig) override
An ExecutionSession represents a running JIT program.
SymbolStringPtr intern(StringRef SymName)
Add a symbol name to the SymbolStringPool and return a pointer to it.
void registerResourceManager(ResourceManager &RM)
Register the given ResourceManager with this ExecutionSession.
decltype(auto) runSessionLocked(Func &&F)
Run the given lambda with the session mutex locked.
Represents an address in the executor process.
uint64_t getValue() const
Represents a JIT'd dynamic library.
Error define(std::unique_ptr< MaterializationUnitType > &&MU, ResourceTrackerSP RT=nullptr)
Define all symbols provided by the materialization unit to be part of this JITDylib.
Tracks responsibility for materialization, and mediates interactions between MaterializationUnits and...
Error withResourceKeyDo(Func &&F) const
Runs the given callback under the session lock, passing in the associated ResourceKey.
A MaterializationUnit represents a set of symbol definitions that can be materialized as a group,...
virtual StringRef getName() const =0
Return the name of this materialization unit.
virtual void materialize(std::unique_ptr< MaterializationResponsibility > R)=0
Implementations of this method should materialize all symbols in the materialzation unit,...
ObjectLinkingLayerJITLinkContext(ObjectLinkingLayer &Layer, std::unique_ptr< MaterializationResponsibility > MR, std::unique_ptr< MemoryBuffer > ObjBuffer)
void notifyFinalized(JITLinkMemoryManager::FinalizedAlloc A) override
Called by JITLink to notify the context that the object has been finalized (i.e.
void notifyFailed(Error Err) override
Notify this context that linking failed.
void lookup(const LookupMap &Symbols, std::unique_ptr< JITLinkAsyncLookupContinuation > LC) override
Called by JITLink to resolve external symbols.
Error notifyResolved(LinkGraph &G) override
Called by JITLink once all defined symbols in the graph have been assigned their final memory locatio...
~ObjectLinkingLayerJITLinkContext()
void notifyMaterializing(LinkGraph &G)
JITLinkMemoryManager & getMemoryManager() override
Return the MemoryManager to be used for this link.
LinkGraphPassFunction getMarkLivePass(const Triple &TT) const override
Returns the mark-live pass to be used for this link.
Error modifyPassConfig(LinkGraph &LG, PassConfiguration &Config) override
Called by JITLink to modify the pass pipeline prior to linking.
An ObjectLayer implementation built on JITLink.
ObjectLinkingLayer(ExecutionSession &ES)
Construct an ObjectLinkingLayer using the ExecutorProcessControl instance's memory manager.
Error add(ResourceTrackerSP, std::unique_ptr< jitlink::LinkGraph > G)
Add a LinkGraph to the JITDylib targeted by the given tracker.
void emit(std::unique_ptr< MaterializationResponsibility > R, std::unique_ptr< MemoryBuffer > O) override
Emit an object file.
~ObjectLinkingLayer()
Destruct an ObjectLinkingLayer.
JITDylib & getJITDylib() const
Return the JITDylib targeted by this tracker.
A set of symbols to look up, each associated with a SymbolLookupFlags value.
SymbolLookupSet & add(SymbolStringPtr Name, SymbolLookupFlags Flags=SymbolLookupFlags::RequiredSymbol)
Add an element to the set.
Pointer to a pooled string representing a symbol name.
A raw_ostream that writes to an std::string.
unique_function is a type-erasing functor similar to std::function.
LinkGraphPassFunction createEHFrameRecorderPass(const Triple &TT, StoreFrameRangeFunction StoreFrameRange)
Creates a pass that records the address and size of the EH frame section.
Expected< std::unique_ptr< LinkGraph > > createLinkGraphFromObject(MemoryBufferRef ObjectBuffer)
Create a LinkGraph from the given object buffer.
void link(std::unique_ptr< LinkGraph > G, std::unique_ptr< JITLinkContext > Ctx)
Link the given graph.
std::vector< std::pair< JITDylib *, JITDylibLookupFlags > > JITDylibSearchOrder
A list of (JITDylib*, JITDylibLookupFlags) pairs to be used as a search order during symbol lookup.
SymbolLookupFlags
Lookup flags that apply to each symbol in a lookup.
bool isMachOInitializerSection(StringRef SegName, StringRef SecName)
std::vector< SymbolStringPtr > SymbolNameVector
A vector of symbol names.
@ Resolved
Queried, materialization begun.
bool isELFInitializerSection(StringRef SecName)
This is an optimization pass for GlobalISel generic memory operations.
Error joinErrors(Error E1, Error E2)
Concatenate errors.
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Implement std::hash so that hash_code can be used in STL containers.
An LinkGraph pass configuration, consisting of a list of pre-prune, post-prune, and post-fixup passes...
LinkGraphPassList PostFixupPasses
Post-fixup passes.
Represents an address range in the exceutor process.