239 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			239 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			C++
		
	
	
	
//===---------- LazyReexports.cpp - Utilities for lazy reexports ----------===//
 | 
						|
//
 | 
						|
// 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/LazyReexports.h"
 | 
						|
 | 
						|
#include "llvm/ADT/Triple.h"
 | 
						|
#include "llvm/ExecutionEngine/Orc/OrcABISupport.h"
 | 
						|
 | 
						|
#define DEBUG_TYPE "orc"
 | 
						|
 | 
						|
namespace llvm {
 | 
						|
namespace orc {
 | 
						|
 | 
						|
LazyCallThroughManager::LazyCallThroughManager(
 | 
						|
    ExecutionSession &ES, JITTargetAddress ErrorHandlerAddr, TrampolinePool *TP)
 | 
						|
    : ES(ES), ErrorHandlerAddr(ErrorHandlerAddr), TP(TP) {}
 | 
						|
 | 
						|
Expected<JITTargetAddress> LazyCallThroughManager::getCallThroughTrampoline(
 | 
						|
    JITDylib &SourceJD, SymbolStringPtr SymbolName,
 | 
						|
    NotifyResolvedFunction NotifyResolved) {
 | 
						|
  assert(TP && "TrampolinePool not set");
 | 
						|
 | 
						|
  std::lock_guard<std::mutex> Lock(LCTMMutex);
 | 
						|
  auto Trampoline = TP->getTrampoline();
 | 
						|
 | 
						|
  if (!Trampoline)
 | 
						|
    return Trampoline.takeError();
 | 
						|
 | 
						|
  Reexports[*Trampoline] = ReexportsEntry{&SourceJD, std::move(SymbolName)};
 | 
						|
  Notifiers[*Trampoline] = std::move(NotifyResolved);
 | 
						|
  return *Trampoline;
 | 
						|
}
 | 
						|
 | 
						|
JITTargetAddress LazyCallThroughManager::reportCallThroughError(Error Err) {
 | 
						|
  ES.reportError(std::move(Err));
 | 
						|
  return ErrorHandlerAddr;
 | 
						|
}
 | 
						|
 | 
						|
Expected<LazyCallThroughManager::ReexportsEntry>
 | 
						|
LazyCallThroughManager::findReexport(JITTargetAddress TrampolineAddr) {
 | 
						|
  std::lock_guard<std::mutex> Lock(LCTMMutex);
 | 
						|
  auto I = Reexports.find(TrampolineAddr);
 | 
						|
  if (I == Reexports.end())
 | 
						|
    return createStringError(inconvertibleErrorCode(),
 | 
						|
                             "Missing reexport for trampoline address %p",
 | 
						|
                             TrampolineAddr);
 | 
						|
  return I->second;
 | 
						|
}
 | 
						|
 | 
						|
Error LazyCallThroughManager::notifyResolved(JITTargetAddress TrampolineAddr,
 | 
						|
                                             JITTargetAddress ResolvedAddr) {
 | 
						|
  NotifyResolvedFunction NotifyResolved;
 | 
						|
  {
 | 
						|
    std::lock_guard<std::mutex> Lock(LCTMMutex);
 | 
						|
    auto I = Notifiers.find(TrampolineAddr);
 | 
						|
    if (I != Notifiers.end()) {
 | 
						|
      NotifyResolved = std::move(I->second);
 | 
						|
      Notifiers.erase(I);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return NotifyResolved ? NotifyResolved(ResolvedAddr) : Error::success();
 | 
						|
}
 | 
						|
 | 
						|
void LazyCallThroughManager::resolveTrampolineLandingAddress(
 | 
						|
    JITTargetAddress TrampolineAddr,
 | 
						|
    NotifyLandingResolvedFunction NotifyLandingResolved) {
 | 
						|
 | 
						|
  auto Entry = findReexport(TrampolineAddr);
 | 
						|
  if (!Entry)
 | 
						|
    return NotifyLandingResolved(reportCallThroughError(Entry.takeError()));
 | 
						|
 | 
						|
  // Declaring SLS and the callback outside of the call to ES.lookup is a
 | 
						|
  // workaround to fix build failures on AIX and on z/OS platforms.
 | 
						|
  SymbolLookupSet SLS({Entry->SymbolName});
 | 
						|
  auto Callback = [this, TrampolineAddr, SymbolName = Entry->SymbolName,
 | 
						|
                   NotifyLandingResolved = std::move(NotifyLandingResolved)](
 | 
						|
                      Expected<SymbolMap> Result) mutable {
 | 
						|
    if (Result) {
 | 
						|
      assert(Result->size() == 1 && "Unexpected result size");
 | 
						|
      assert(Result->count(SymbolName) && "Unexpected result value");
 | 
						|
      JITTargetAddress LandingAddr = (*Result)[SymbolName].getAddress();
 | 
						|
 | 
						|
      if (auto Err = notifyResolved(TrampolineAddr, LandingAddr))
 | 
						|
        NotifyLandingResolved(reportCallThroughError(std::move(Err)));
 | 
						|
      else
 | 
						|
        NotifyLandingResolved(LandingAddr);
 | 
						|
    } else {
 | 
						|
      NotifyLandingResolved(reportCallThroughError(Result.takeError()));
 | 
						|
    }
 | 
						|
  };
 | 
						|
 | 
						|
  ES.lookup(LookupKind::Static,
 | 
						|
            makeJITDylibSearchOrder(Entry->SourceJD,
 | 
						|
                                    JITDylibLookupFlags::MatchAllSymbols),
 | 
						|
            std::move(SLS), SymbolState::Ready, std::move(Callback),
 | 
						|
            NoDependenciesToRegister);
 | 
						|
}
 | 
						|
 | 
						|
Expected<std::unique_ptr<LazyCallThroughManager>>
 | 
						|
createLocalLazyCallThroughManager(const Triple &T, ExecutionSession &ES,
 | 
						|
                                  JITTargetAddress ErrorHandlerAddr) {
 | 
						|
  switch (T.getArch()) {
 | 
						|
  default:
 | 
						|
    return make_error<StringError>(
 | 
						|
        std::string("No callback manager available for ") + T.str(),
 | 
						|
        inconvertibleErrorCode());
 | 
						|
 | 
						|
  case Triple::aarch64:
 | 
						|
  case Triple::aarch64_32:
 | 
						|
    return LocalLazyCallThroughManager::Create<OrcAArch64>(ES,
 | 
						|
                                                           ErrorHandlerAddr);
 | 
						|
 | 
						|
  case Triple::x86:
 | 
						|
    return LocalLazyCallThroughManager::Create<OrcI386>(ES, ErrorHandlerAddr);
 | 
						|
 | 
						|
  case Triple::mips:
 | 
						|
    return LocalLazyCallThroughManager::Create<OrcMips32Be>(ES,
 | 
						|
                                                            ErrorHandlerAddr);
 | 
						|
 | 
						|
  case Triple::mipsel:
 | 
						|
    return LocalLazyCallThroughManager::Create<OrcMips32Le>(ES,
 | 
						|
                                                            ErrorHandlerAddr);
 | 
						|
 | 
						|
  case Triple::mips64:
 | 
						|
  case Triple::mips64el:
 | 
						|
    return LocalLazyCallThroughManager::Create<OrcMips64>(ES, ErrorHandlerAddr);
 | 
						|
 | 
						|
  case Triple::riscv64:
 | 
						|
    return LocalLazyCallThroughManager::Create<OrcRiscv64>(ES,
 | 
						|
                                                           ErrorHandlerAddr);
 | 
						|
 | 
						|
  case Triple::x86_64:
 | 
						|
    if (T.getOS() == Triple::OSType::Win32)
 | 
						|
      return LocalLazyCallThroughManager::Create<OrcX86_64_Win32>(
 | 
						|
          ES, ErrorHandlerAddr);
 | 
						|
    else
 | 
						|
      return LocalLazyCallThroughManager::Create<OrcX86_64_SysV>(
 | 
						|
          ES, ErrorHandlerAddr);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
LazyReexportsMaterializationUnit::LazyReexportsMaterializationUnit(
 | 
						|
    LazyCallThroughManager &LCTManager, IndirectStubsManager &ISManager,
 | 
						|
    JITDylib &SourceJD, SymbolAliasMap CallableAliases, ImplSymbolMap *SrcJDLoc)
 | 
						|
    : MaterializationUnit(extractFlags(CallableAliases)),
 | 
						|
      LCTManager(LCTManager), ISManager(ISManager), SourceJD(SourceJD),
 | 
						|
      CallableAliases(std::move(CallableAliases)), AliaseeTable(SrcJDLoc) {}
 | 
						|
 | 
						|
StringRef LazyReexportsMaterializationUnit::getName() const {
 | 
						|
  return "<Lazy Reexports>";
 | 
						|
}
 | 
						|
 | 
						|
void LazyReexportsMaterializationUnit::materialize(
 | 
						|
    std::unique_ptr<MaterializationResponsibility> R) {
 | 
						|
  auto RequestedSymbols = R->getRequestedSymbols();
 | 
						|
 | 
						|
  SymbolAliasMap RequestedAliases;
 | 
						|
  for (auto &RequestedSymbol : RequestedSymbols) {
 | 
						|
    auto I = CallableAliases.find(RequestedSymbol);
 | 
						|
    assert(I != CallableAliases.end() && "Symbol not found in alias map?");
 | 
						|
    RequestedAliases[I->first] = std::move(I->second);
 | 
						|
    CallableAliases.erase(I);
 | 
						|
  }
 | 
						|
 | 
						|
  if (!CallableAliases.empty())
 | 
						|
    if (auto Err = R->replace(lazyReexports(LCTManager, ISManager, SourceJD,
 | 
						|
                                            std::move(CallableAliases),
 | 
						|
                                            AliaseeTable))) {
 | 
						|
      R->getExecutionSession().reportError(std::move(Err));
 | 
						|
      R->failMaterialization();
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
  IndirectStubsManager::StubInitsMap StubInits;
 | 
						|
  for (auto &Alias : RequestedAliases) {
 | 
						|
 | 
						|
    auto CallThroughTrampoline = LCTManager.getCallThroughTrampoline(
 | 
						|
        SourceJD, Alias.second.Aliasee,
 | 
						|
        [&ISManager = this->ISManager,
 | 
						|
         StubSym = Alias.first](JITTargetAddress ResolvedAddr) -> Error {
 | 
						|
          return ISManager.updatePointer(*StubSym, ResolvedAddr);
 | 
						|
        });
 | 
						|
 | 
						|
    if (!CallThroughTrampoline) {
 | 
						|
      SourceJD.getExecutionSession().reportError(
 | 
						|
          CallThroughTrampoline.takeError());
 | 
						|
      R->failMaterialization();
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    StubInits[*Alias.first] =
 | 
						|
        std::make_pair(*CallThroughTrampoline, Alias.second.AliasFlags);
 | 
						|
  }
 | 
						|
 | 
						|
  if (AliaseeTable != nullptr && !RequestedAliases.empty())
 | 
						|
    AliaseeTable->trackImpls(RequestedAliases, &SourceJD);
 | 
						|
 | 
						|
  if (auto Err = ISManager.createStubs(StubInits)) {
 | 
						|
    SourceJD.getExecutionSession().reportError(std::move(Err));
 | 
						|
    R->failMaterialization();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  SymbolMap Stubs;
 | 
						|
  for (auto &Alias : RequestedAliases)
 | 
						|
    Stubs[Alias.first] = ISManager.findStub(*Alias.first, false);
 | 
						|
 | 
						|
  // No registered dependencies, so these calls cannot fail.
 | 
						|
  cantFail(R->notifyResolved(Stubs));
 | 
						|
  cantFail(R->notifyEmitted());
 | 
						|
}
 | 
						|
 | 
						|
void LazyReexportsMaterializationUnit::discard(const JITDylib &JD,
 | 
						|
                                               const SymbolStringPtr &Name) {
 | 
						|
  assert(CallableAliases.count(Name) &&
 | 
						|
         "Symbol not covered by this MaterializationUnit");
 | 
						|
  CallableAliases.erase(Name);
 | 
						|
}
 | 
						|
 | 
						|
MaterializationUnit::Interface
 | 
						|
LazyReexportsMaterializationUnit::extractFlags(const SymbolAliasMap &Aliases) {
 | 
						|
  SymbolFlagsMap SymbolFlags;
 | 
						|
  for (auto &KV : Aliases) {
 | 
						|
    assert(KV.second.AliasFlags.isCallable() &&
 | 
						|
           "Lazy re-exports must be callable symbols");
 | 
						|
    SymbolFlags[KV.first] = KV.second.AliasFlags;
 | 
						|
  }
 | 
						|
  return MaterializationUnit::Interface(std::move(SymbolFlags), nullptr);
 | 
						|
}
 | 
						|
 | 
						|
} // End namespace orc.
 | 
						|
} // End namespace llvm.
 |