diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2019-12-20 19:53:05 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2019-12-20 19:53:05 +0000 | 
| commit | 0b57cec536236d46e3dba9bd041533462f33dbb7 (patch) | |
| tree | 56229dbdbbf76d18580f72f789003db17246c8d9 /contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp | |
| parent | 718ef55ec7785aae63f98f8ca05dc07ed399c16d (diff) | |
Notes
Diffstat (limited to 'contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp')
| -rw-r--r-- | contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp | 483 | 
1 files changed, 483 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp new file mode 100644 index 000000000000..def0b300eca1 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp @@ -0,0 +1,483 @@ +//===------- ObjectLinkingLayer.cpp - JITLink backed ORC ObjectLayer ------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" + +#include "llvm/ADT/Optional.h" +#include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h" + +#include <vector> + +#define DEBUG_TYPE "orc" + +using namespace llvm; +using namespace llvm::jitlink; +using namespace llvm::orc; + +namespace llvm { +namespace orc { + +class ObjectLinkingLayerJITLinkContext final : public JITLinkContext { +public: +  ObjectLinkingLayerJITLinkContext(ObjectLinkingLayer &Layer, +                                   MaterializationResponsibility MR, +                                   std::unique_ptr<MemoryBuffer> ObjBuffer) +      : Layer(Layer), MR(std::move(MR)), ObjBuffer(std::move(ObjBuffer)) {} + +  JITLinkMemoryManager &getMemoryManager() override { return Layer.MemMgr; } + +  MemoryBufferRef getObjectBuffer() const override { +    return ObjBuffer->getMemBufferRef(); +  } + +  void notifyFailed(Error Err) override { +    Layer.getExecutionSession().reportError(std::move(Err)); +    MR.failMaterialization(); +  } + +  void lookup(const DenseSet<StringRef> &Symbols, +              JITLinkAsyncLookupContinuation LookupContinuation) override { + +    JITDylibSearchList SearchOrder; +    MR.getTargetJITDylib().withSearchOrderDo( +        [&](const JITDylibSearchList &JDs) { SearchOrder = JDs; }); + +    auto &ES = Layer.getExecutionSession(); + +    SymbolNameSet InternedSymbols; +    for (auto &S : Symbols) +      InternedSymbols.insert(ES.intern(S)); + +    // OnResolve -- De-intern the symbols and pass the result to the linker. +    // FIXME: Capture LookupContinuation by move once we have c++14. +    auto SharedLookupContinuation = +        std::make_shared<JITLinkAsyncLookupContinuation>( +            std::move(LookupContinuation)); +    auto OnResolve = [SharedLookupContinuation](Expected<SymbolMap> Result) { +      if (!Result) +        (*SharedLookupContinuation)(Result.takeError()); +      else { +        AsyncLookupResult LR; +        for (auto &KV : *Result) +          LR[*KV.first] = KV.second; +        (*SharedLookupContinuation)(std::move(LR)); +      } +    }; + +    ES.lookup(SearchOrder, std::move(InternedSymbols), SymbolState::Resolved, +              std::move(OnResolve), [this](const SymbolDependenceMap &Deps) { +                registerDependencies(Deps); +              }); +  } + +  void notifyResolved(AtomGraph &G) override { +    auto &ES = Layer.getExecutionSession(); + +    SymbolFlagsMap ExtraSymbolsToClaim; +    bool AutoClaim = Layer.AutoClaimObjectSymbols; + +    SymbolMap InternedResult; +    for (auto *DA : G.defined_atoms()) +      if (DA->hasName() && DA->isGlobal()) { +        auto InternedName = ES.intern(DA->getName()); +        JITSymbolFlags Flags; + +        if (DA->isExported()) +          Flags |= JITSymbolFlags::Exported; +        if (DA->isWeak()) +          Flags |= JITSymbolFlags::Weak; +        if (DA->isCallable()) +          Flags |= JITSymbolFlags::Callable; +        if (DA->isCommon()) +          Flags |= JITSymbolFlags::Common; + +        InternedResult[InternedName] = +            JITEvaluatedSymbol(DA->getAddress(), Flags); +        if (AutoClaim && !MR.getSymbols().count(InternedName)) { +          assert(!ExtraSymbolsToClaim.count(InternedName) && +                 "Duplicate symbol to claim?"); +          ExtraSymbolsToClaim[InternedName] = Flags; +        } +      } + +    for (auto *A : G.absolute_atoms()) +      if (A->hasName()) { +        auto InternedName = ES.intern(A->getName()); +        JITSymbolFlags Flags; +        Flags |= JITSymbolFlags::Absolute; +        if (A->isWeak()) +          Flags |= JITSymbolFlags::Weak; +        if (A->isCallable()) +          Flags |= JITSymbolFlags::Callable; +        InternedResult[InternedName] = +            JITEvaluatedSymbol(A->getAddress(), Flags); +        if (AutoClaim && !MR.getSymbols().count(InternedName)) { +          assert(!ExtraSymbolsToClaim.count(InternedName) && +                 "Duplicate symbol to claim?"); +          ExtraSymbolsToClaim[InternedName] = Flags; +        } +      } + +    if (!ExtraSymbolsToClaim.empty()) +      if (auto Err = MR.defineMaterializing(ExtraSymbolsToClaim)) +        return notifyFailed(std::move(Err)); + +    MR.notifyResolved(InternedResult); + +    Layer.notifyLoaded(MR); +  } + +  void notifyFinalized( +      std::unique_ptr<JITLinkMemoryManager::Allocation> A) override { + +    if (auto Err = Layer.notifyEmitted(MR, std::move(A))) { +      Layer.getExecutionSession().reportError(std::move(Err)); +      MR.failMaterialization(); + +      return; +    } +    MR.notifyEmitted(); +  } + +  AtomGraphPassFunction getMarkLivePass(const Triple &TT) const override { +    return [this](AtomGraph &G) { return markResponsibilitySymbolsLive(G); }; +  } + +  Error modifyPassConfig(const Triple &TT, PassConfiguration &Config) override { +    // Add passes to mark duplicate defs as should-discard, and to walk the +    // atom graph to build the symbol dependence graph. +    Config.PrePrunePasses.push_back( +        [this](AtomGraph &G) { return markSymbolsToDiscard(G); }); +    Config.PostPrunePasses.push_back( +        [this](AtomGraph &G) { return computeNamedSymbolDependencies(G); }); + +    Layer.modifyPassConfig(MR, TT, Config); + +    return Error::success(); +  } + +private: +  using AnonAtomNamedDependenciesMap = +      DenseMap<const DefinedAtom *, SymbolNameSet>; + +  Error markSymbolsToDiscard(AtomGraph &G) { +    auto &ES = Layer.getExecutionSession(); +    for (auto *DA : G.defined_atoms()) +      if (DA->isWeak() && DA->hasName()) { +        auto S = ES.intern(DA->getName()); +        auto I = MR.getSymbols().find(S); +        if (I == MR.getSymbols().end()) +          DA->setShouldDiscard(true); +      } + +    for (auto *A : G.absolute_atoms()) +      if (A->isWeak() && A->hasName()) { +        auto S = ES.intern(A->getName()); +        auto I = MR.getSymbols().find(S); +        if (I == MR.getSymbols().end()) +          A->setShouldDiscard(true); +      } + +    return Error::success(); +  } + +  Error markResponsibilitySymbolsLive(AtomGraph &G) const { +    auto &ES = Layer.getExecutionSession(); +    for (auto *DA : G.defined_atoms()) +      if (DA->hasName() && +          MR.getSymbols().count(ES.intern(DA->getName()))) +        DA->setLive(true); +    return Error::success(); +  } + +  Error computeNamedSymbolDependencies(AtomGraph &G) { +    auto &ES = MR.getTargetJITDylib().getExecutionSession(); +    auto AnonDeps = computeAnonDeps(G); + +    for (auto *DA : G.defined_atoms()) { + +      // Skip anonymous and non-global atoms: we do not need dependencies for +      // these. +      if (!DA->hasName() || !DA->isGlobal()) +        continue; + +      auto DAName = ES.intern(DA->getName()); +      SymbolNameSet &DADeps = NamedSymbolDeps[DAName]; + +      for (auto &E : DA->edges()) { +        auto &TA = E.getTarget(); + +        if (TA.hasName()) +          DADeps.insert(ES.intern(TA.getName())); +        else { +          assert(TA.isDefined() && "Anonymous atoms must be defined"); +          auto &DTA = static_cast<DefinedAtom &>(TA); +          auto I = AnonDeps.find(&DTA); +          if (I != AnonDeps.end()) +            for (auto &S : I->second) +              DADeps.insert(S); +        } +      } +    } + +    return Error::success(); +  } + +  AnonAtomNamedDependenciesMap computeAnonDeps(AtomGraph &G) { + +    auto &ES = MR.getTargetJITDylib().getExecutionSession(); +    AnonAtomNamedDependenciesMap DepMap; + +    // For all anonymous atoms: +    // (1) Add their named dependencies. +    // (2) Add them to the worklist for further iteration if they have any +    //     depend on any other anonymous atoms. +    struct WorklistEntry { +      WorklistEntry(DefinedAtom *DA, DenseSet<DefinedAtom *> DAAnonDeps) +          : DA(DA), DAAnonDeps(std::move(DAAnonDeps)) {} + +      DefinedAtom *DA = nullptr; +      DenseSet<DefinedAtom *> DAAnonDeps; +    }; +    std::vector<WorklistEntry> Worklist; +    for (auto *DA : G.defined_atoms()) +      if (!DA->hasName()) { +        auto &DANamedDeps = DepMap[DA]; +        DenseSet<DefinedAtom *> DAAnonDeps; + +        for (auto &E : DA->edges()) { +          auto &TA = E.getTarget(); +          if (TA.hasName()) +            DANamedDeps.insert(ES.intern(TA.getName())); +          else { +            assert(TA.isDefined() && "Anonymous atoms must be defined"); +            DAAnonDeps.insert(static_cast<DefinedAtom *>(&TA)); +          } +        } + +        if (!DAAnonDeps.empty()) +          Worklist.push_back(WorklistEntry(DA, std::move(DAAnonDeps))); +      } + +    // Loop over all anonymous atoms with anonymous dependencies, propagating +    // their respective *named* dependencies. Iterate until we hit a stable +    // state. +    bool Changed; +    do { +      Changed = false; +      for (auto &WLEntry : Worklist) { +        auto *DA = WLEntry.DA; +        auto &DANamedDeps = DepMap[DA]; +        auto &DAAnonDeps = WLEntry.DAAnonDeps; + +        for (auto *TA : DAAnonDeps) { +          auto I = DepMap.find(TA); +          if (I != DepMap.end()) +            for (const auto &S : I->second) +              Changed |= DANamedDeps.insert(S).second; +        } +      } +    } while (Changed); + +    return DepMap; +  } + +  void registerDependencies(const SymbolDependenceMap &QueryDeps) { +    for (auto &NamedDepsEntry : NamedSymbolDeps) { +      auto &Name = NamedDepsEntry.first; +      auto &NameDeps = NamedDepsEntry.second; +      SymbolDependenceMap SymbolDeps; + +      for (const auto &QueryDepsEntry : QueryDeps) { +        JITDylib &SourceJD = *QueryDepsEntry.first; +        const SymbolNameSet &Symbols = QueryDepsEntry.second; +        auto &DepsForJD = SymbolDeps[&SourceJD]; + +        for (const auto &S : Symbols) +          if (NameDeps.count(S)) +            DepsForJD.insert(S); + +        if (DepsForJD.empty()) +          SymbolDeps.erase(&SourceJD); +      } + +      MR.addDependencies(Name, SymbolDeps); +    } +  } + +  ObjectLinkingLayer &Layer; +  MaterializationResponsibility MR; +  std::unique_ptr<MemoryBuffer> ObjBuffer; +  DenseMap<SymbolStringPtr, SymbolNameSet> NamedSymbolDeps; +}; + +ObjectLinkingLayer::Plugin::~Plugin() {} + +ObjectLinkingLayer::ObjectLinkingLayer(ExecutionSession &ES, +                                       JITLinkMemoryManager &MemMgr) +    : ObjectLayer(ES), MemMgr(MemMgr) {} + +ObjectLinkingLayer::~ObjectLinkingLayer() { +  if (auto Err = removeAllModules()) +    getExecutionSession().reportError(std::move(Err)); +} + +void ObjectLinkingLayer::emit(MaterializationResponsibility R, +                              std::unique_ptr<MemoryBuffer> O) { +  assert(O && "Object must not be null"); +  jitLink(llvm::make_unique<ObjectLinkingLayerJITLinkContext>( +      *this, std::move(R), std::move(O))); +} + +void ObjectLinkingLayer::modifyPassConfig(MaterializationResponsibility &MR, +                                          const Triple &TT, +                                          PassConfiguration &PassConfig) { +  for (auto &P : Plugins) +    P->modifyPassConfig(MR, TT, PassConfig); +} + +void ObjectLinkingLayer::notifyLoaded(MaterializationResponsibility &MR) { +  for (auto &P : Plugins) +    P->notifyLoaded(MR); +} + +Error ObjectLinkingLayer::notifyEmitted(MaterializationResponsibility &MR, +                                        AllocPtr Alloc) { +  Error Err = Error::success(); +  for (auto &P : Plugins) +    Err = joinErrors(std::move(Err), P->notifyEmitted(MR)); + +  if (Err) +    return Err; + +  { +    std::lock_guard<std::mutex> Lock(LayerMutex); +    UntrackedAllocs.push_back(std::move(Alloc)); +  } + +  return Error::success(); +} + +Error ObjectLinkingLayer::removeModule(VModuleKey K) { +  Error Err = Error::success(); + +  for (auto &P : Plugins) +    Err = joinErrors(std::move(Err), P->notifyRemovingModule(K)); + +  AllocPtr Alloc; + +  { +    std::lock_guard<std::mutex> Lock(LayerMutex); +    auto AllocItr = TrackedAllocs.find(K); +    Alloc = std::move(AllocItr->second); +    TrackedAllocs.erase(AllocItr); +  } + +  assert(Alloc && "No allocation for key K"); + +  return joinErrors(std::move(Err), Alloc->deallocate()); +} + +Error ObjectLinkingLayer::removeAllModules() { + +  Error Err = Error::success(); + +  for (auto &P : Plugins) +    Err = joinErrors(std::move(Err), P->notifyRemovingAllModules()); + +  std::vector<AllocPtr> Allocs; +  { +    std::lock_guard<std::mutex> Lock(LayerMutex); +    Allocs = std::move(UntrackedAllocs); + +    for (auto &KV : TrackedAllocs) +      Allocs.push_back(std::move(KV.second)); + +    TrackedAllocs.clear(); +  } + +  while (!Allocs.empty()) { +    Err = joinErrors(std::move(Err), Allocs.back()->deallocate()); +    Allocs.pop_back(); +  } + +  return Err; +} + +EHFrameRegistrationPlugin::EHFrameRegistrationPlugin( +    jitlink::EHFrameRegistrar &Registrar) +    : Registrar(Registrar) {} + +void EHFrameRegistrationPlugin::modifyPassConfig( +    MaterializationResponsibility &MR, const Triple &TT, +    PassConfiguration &PassConfig) { +  assert(!InProcessLinks.count(&MR) && "Link for MR already being tracked?"); + +  PassConfig.PostFixupPasses.push_back( +      createEHFrameRecorderPass(TT, [this, &MR](JITTargetAddress Addr) { +        if (Addr) +          InProcessLinks[&MR] = Addr; +      })); +} + +Error EHFrameRegistrationPlugin::notifyEmitted( +    MaterializationResponsibility &MR) { + +  auto EHFrameAddrItr = InProcessLinks.find(&MR); +  if (EHFrameAddrItr == InProcessLinks.end()) +    return Error::success(); + +  auto EHFrameAddr = EHFrameAddrItr->second; +  assert(EHFrameAddr && "eh-frame addr to register can not be null"); + +  InProcessLinks.erase(EHFrameAddrItr); +  if (auto Key = MR.getVModuleKey()) +    TrackedEHFrameAddrs[Key] = EHFrameAddr; +  else +    UntrackedEHFrameAddrs.push_back(EHFrameAddr); + +  return Registrar.registerEHFrames(EHFrameAddr); +} + +Error EHFrameRegistrationPlugin::notifyRemovingModule(VModuleKey K) { +  auto EHFrameAddrItr = TrackedEHFrameAddrs.find(K); +  if (EHFrameAddrItr == TrackedEHFrameAddrs.end()) +    return Error::success(); + +  auto EHFrameAddr = EHFrameAddrItr->second; +  assert(EHFrameAddr && "Tracked eh-frame addr must not be null"); + +  TrackedEHFrameAddrs.erase(EHFrameAddrItr); + +  return Registrar.deregisterEHFrames(EHFrameAddr); +} + +Error EHFrameRegistrationPlugin::notifyRemovingAllModules() { + +  std::vector<JITTargetAddress> EHFrameAddrs = std::move(UntrackedEHFrameAddrs); +  EHFrameAddrs.reserve(EHFrameAddrs.size() + TrackedEHFrameAddrs.size()); + +  for (auto &KV : TrackedEHFrameAddrs) +    EHFrameAddrs.push_back(KV.second); + +  TrackedEHFrameAddrs.clear(); + +  Error Err = Error::success(); + +  while (!EHFrameAddrs.empty()) { +    auto EHFrameAddr = EHFrameAddrs.back(); +    assert(EHFrameAddr && "Untracked eh-frame addr must not be null"); +    EHFrameAddrs.pop_back(); +    Err = joinErrors(std::move(Err), Registrar.deregisterEHFrames(EHFrameAddr)); +  } + +  return Err; +} + +} // End namespace orc. +} // End namespace llvm.  | 
