diff options
Diffstat (limited to 'llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp')
| -rw-r--r-- | llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp | 308 | 
1 files changed, 308 insertions, 0 deletions
| diff --git a/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp b/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp new file mode 100644 index 0000000000000..4a886ac0597c1 --- /dev/null +++ b/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp @@ -0,0 +1,308 @@ +//===---- ExecutionUtils.cpp - Utilities for executing functions in Orc ---===// +// +// 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/ExecutionUtils.h" + +#include "llvm/ExecutionEngine/Orc/Layer.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { +namespace orc { + +CtorDtorIterator::CtorDtorIterator(const GlobalVariable *GV, bool End) +  : InitList( +      GV ? dyn_cast_or_null<ConstantArray>(GV->getInitializer()) : nullptr), +    I((InitList && End) ? InitList->getNumOperands() : 0) { +} + +bool CtorDtorIterator::operator==(const CtorDtorIterator &Other) const { +  assert(InitList == Other.InitList && "Incomparable iterators."); +  return I == Other.I; +} + +bool CtorDtorIterator::operator!=(const CtorDtorIterator &Other) const { +  return !(*this == Other); +} + +CtorDtorIterator& CtorDtorIterator::operator++() { +  ++I; +  return *this; +} + +CtorDtorIterator CtorDtorIterator::operator++(int) { +  CtorDtorIterator Temp = *this; +  ++I; +  return Temp; +} + +CtorDtorIterator::Element CtorDtorIterator::operator*() const { +  ConstantStruct *CS = dyn_cast<ConstantStruct>(InitList->getOperand(I)); +  assert(CS && "Unrecognized type in llvm.global_ctors/llvm.global_dtors"); + +  Constant *FuncC = CS->getOperand(1); +  Function *Func = nullptr; + +  // Extract function pointer, pulling off any casts. +  while (FuncC) { +    if (Function *F = dyn_cast_or_null<Function>(FuncC)) { +      Func = F; +      break; +    } else if (ConstantExpr *CE = dyn_cast_or_null<ConstantExpr>(FuncC)) { +      if (CE->isCast()) +        FuncC = dyn_cast_or_null<ConstantExpr>(CE->getOperand(0)); +      else +        break; +    } else { +      // This isn't anything we recognize. Bail out with Func left set to null. +      break; +    } +  } + +  auto *Priority = cast<ConstantInt>(CS->getOperand(0)); +  Value *Data = CS->getNumOperands() == 3 ? CS->getOperand(2) : nullptr; +  if (Data && !isa<GlobalValue>(Data)) +    Data = nullptr; +  return Element(Priority->getZExtValue(), Func, Data); +} + +iterator_range<CtorDtorIterator> getConstructors(const Module &M) { +  const GlobalVariable *CtorsList = M.getNamedGlobal("llvm.global_ctors"); +  return make_range(CtorDtorIterator(CtorsList, false), +                    CtorDtorIterator(CtorsList, true)); +} + +iterator_range<CtorDtorIterator> getDestructors(const Module &M) { +  const GlobalVariable *DtorsList = M.getNamedGlobal("llvm.global_dtors"); +  return make_range(CtorDtorIterator(DtorsList, false), +                    CtorDtorIterator(DtorsList, true)); +} + +void CtorDtorRunner::add(iterator_range<CtorDtorIterator> CtorDtors) { +  if (CtorDtors.empty()) +    return; + +  MangleAndInterner Mangle( +      JD.getExecutionSession(), +      (*CtorDtors.begin()).Func->getParent()->getDataLayout()); + +  for (const auto &CtorDtor : CtorDtors) { +    assert(CtorDtor.Func && CtorDtor.Func->hasName() && +           "Ctor/Dtor function must be named to be runnable under the JIT"); + +    // FIXME: Maybe use a symbol promoter here instead. +    if (CtorDtor.Func->hasLocalLinkage()) { +      CtorDtor.Func->setLinkage(GlobalValue::ExternalLinkage); +      CtorDtor.Func->setVisibility(GlobalValue::HiddenVisibility); +    } + +    if (CtorDtor.Data && cast<GlobalValue>(CtorDtor.Data)->isDeclaration()) { +      dbgs() << "  Skipping because why now?\n"; +      continue; +    } + +    CtorDtorsByPriority[CtorDtor.Priority].push_back( +        Mangle(CtorDtor.Func->getName())); +  } +} + +Error CtorDtorRunner::run() { +  using CtorDtorTy = void (*)(); + +  SymbolNameSet Names; + +  for (auto &KV : CtorDtorsByPriority) { +    for (auto &Name : KV.second) { +      auto Added = Names.insert(Name).second; +      (void)Added; +      assert(Added && "Ctor/Dtor names clashed"); +    } +  } + +  auto &ES = JD.getExecutionSession(); +  if (auto CtorDtorMap = +          ES.lookup(JITDylibSearchList({{&JD, true}}), std::move(Names))) { +    for (auto &KV : CtorDtorsByPriority) { +      for (auto &Name : KV.second) { +        assert(CtorDtorMap->count(Name) && "No entry for Name"); +        auto CtorDtor = reinterpret_cast<CtorDtorTy>( +            static_cast<uintptr_t>((*CtorDtorMap)[Name].getAddress())); +        CtorDtor(); +      } +    } +    CtorDtorsByPriority.clear(); +    return Error::success(); +  } else +    return CtorDtorMap.takeError(); +} + +void LocalCXXRuntimeOverridesBase::runDestructors() { +  auto& CXXDestructorDataPairs = DSOHandleOverride; +  for (auto &P : CXXDestructorDataPairs) +    P.first(P.second); +  CXXDestructorDataPairs.clear(); +} + +int LocalCXXRuntimeOverridesBase::CXAAtExitOverride(DestructorPtr Destructor, +                                                    void *Arg, +                                                    void *DSOHandle) { +  auto& CXXDestructorDataPairs = +    *reinterpret_cast<CXXDestructorDataPairList*>(DSOHandle); +  CXXDestructorDataPairs.push_back(std::make_pair(Destructor, Arg)); +  return 0; +} + +Error LocalCXXRuntimeOverrides::enable(JITDylib &JD, +                                        MangleAndInterner &Mangle) { +  SymbolMap RuntimeInterposes; +  RuntimeInterposes[Mangle("__dso_handle")] = +    JITEvaluatedSymbol(toTargetAddress(&DSOHandleOverride), +                       JITSymbolFlags::Exported); +  RuntimeInterposes[Mangle("__cxa_atexit")] = +    JITEvaluatedSymbol(toTargetAddress(&CXAAtExitOverride), +                       JITSymbolFlags::Exported); + +  return JD.define(absoluteSymbols(std::move(RuntimeInterposes))); +} + +DynamicLibrarySearchGenerator::DynamicLibrarySearchGenerator( +    sys::DynamicLibrary Dylib, char GlobalPrefix, SymbolPredicate Allow) +    : Dylib(std::move(Dylib)), Allow(std::move(Allow)), +      GlobalPrefix(GlobalPrefix) {} + +Expected<std::unique_ptr<DynamicLibrarySearchGenerator>> +DynamicLibrarySearchGenerator::Load(const char *FileName, char GlobalPrefix, +                                    SymbolPredicate Allow) { +  std::string ErrMsg; +  auto Lib = sys::DynamicLibrary::getPermanentLibrary(FileName, &ErrMsg); +  if (!Lib.isValid()) +    return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode()); +  return std::make_unique<DynamicLibrarySearchGenerator>( +      std::move(Lib), GlobalPrefix, std::move(Allow)); +} + +Expected<SymbolNameSet> +DynamicLibrarySearchGenerator::tryToGenerate(JITDylib &JD, +                                             const SymbolNameSet &Names) { +  orc::SymbolNameSet Added; +  orc::SymbolMap NewSymbols; + +  bool HasGlobalPrefix = (GlobalPrefix != '\0'); + +  for (auto &Name : Names) { +    if ((*Name).empty()) +      continue; + +    if (Allow && !Allow(Name)) +      continue; + +    if (HasGlobalPrefix && (*Name).front() != GlobalPrefix) +      continue; + +    std::string Tmp((*Name).data() + HasGlobalPrefix, +                    (*Name).size() - HasGlobalPrefix); +    if (void *Addr = Dylib.getAddressOfSymbol(Tmp.c_str())) { +      Added.insert(Name); +      NewSymbols[Name] = JITEvaluatedSymbol( +          static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(Addr)), +          JITSymbolFlags::Exported); +    } +  } + +  // Add any new symbols to JD. Since the generator is only called for symbols +  // that are not already defined, this will never trigger a duplicate +  // definition error, so we can wrap this call in a 'cantFail'. +  if (!NewSymbols.empty()) +    cantFail(JD.define(absoluteSymbols(std::move(NewSymbols)))); + +  return Added; +} + +Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> +StaticLibraryDefinitionGenerator::Load(ObjectLayer &L, const char *FileName) { +  auto ArchiveBuffer = errorOrToExpected(MemoryBuffer::getFile(FileName)); + +  if (!ArchiveBuffer) +    return ArchiveBuffer.takeError(); + +  return Create(L, std::move(*ArchiveBuffer)); +} + +Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> +StaticLibraryDefinitionGenerator::Create( +    ObjectLayer &L, std::unique_ptr<MemoryBuffer> ArchiveBuffer) { +  Error Err = Error::success(); + +  std::unique_ptr<StaticLibraryDefinitionGenerator> ADG( +      new StaticLibraryDefinitionGenerator(L, std::move(ArchiveBuffer), Err)); + +  if (Err) +    return std::move(Err); + +  return std::move(ADG); +} + +Expected<SymbolNameSet> +StaticLibraryDefinitionGenerator::tryToGenerate(JITDylib &JD, +                                                const SymbolNameSet &Names) { + +  DenseSet<std::pair<StringRef, StringRef>> ChildBufferInfos; +  SymbolNameSet NewDefs; + +  for (const auto &Name : Names) { +    auto Child = Archive.findSym(*Name); +    if (!Child) +      return Child.takeError(); +    if (*Child == None) +      continue; +    auto ChildBuffer = (*Child)->getMemoryBufferRef(); +    if (!ChildBuffer) +      return ChildBuffer.takeError(); +    ChildBufferInfos.insert( +        {ChildBuffer->getBuffer(), ChildBuffer->getBufferIdentifier()}); +    NewDefs.insert(Name); +  } + +  for (auto ChildBufferInfo : ChildBufferInfos) { +    MemoryBufferRef ChildBufferRef(ChildBufferInfo.first, +                                   ChildBufferInfo.second); + +    if (auto Err = +            L.add(JD, MemoryBuffer::getMemBuffer(ChildBufferRef), VModuleKey())) +      return std::move(Err); + +    --UnrealizedObjects; +  } + +  return NewDefs; +} + +StaticLibraryDefinitionGenerator::StaticLibraryDefinitionGenerator( +    ObjectLayer &L, std::unique_ptr<MemoryBuffer> ArchiveBuffer, Error &Err) +    : L(L), ArchiveBuffer(std::move(ArchiveBuffer)), +      Archive(*this->ArchiveBuffer, Err) { + +  if (Err) +    return; + +  Error Err2 = Error::success(); +  for (auto _ : Archive.children(Err2)) { +    (void)_; +    ++UnrealizedObjects; +  } + +  // No need to check this: We will leave it to the caller. +  Err = std::move(Err2); +} + +} // End namespace orc. +} // End namespace llvm. | 
