diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2023-04-14 21:41:27 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2023-06-22 18:20:56 +0000 |
commit | bdd1243df58e60e85101c09001d9812a789b6bc4 (patch) | |
tree | a1ce621c7301dd47ba2ddc3b8eaa63b441389481 /contrib/llvm-project/llvm/lib/ExecutionEngine/Orc | |
parent | 781624ca2d054430052c828ba8d2c2eaf2d733e7 (diff) | |
parent | e3b557809604d036af6e00c60f012c2025b59a5e (diff) |
Diffstat (limited to 'contrib/llvm-project/llvm/lib/ExecutionEngine/Orc')
39 files changed, 2560 insertions, 498 deletions
diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/COFFPlatform.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/COFFPlatform.cpp new file mode 100644 index 000000000000..40716a7f9b61 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/COFFPlatform.cpp @@ -0,0 +1,902 @@ +//===------- COFFPlatform.cpp - Utilities for executing COFF 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/COFFPlatform.h" +#include "llvm/ExecutionEngine/Orc/DebugUtils.h" +#include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.h" +#include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h" + +#include "llvm/Object/COFF.h" + +#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h" + +#include "llvm/ExecutionEngine/JITLink/x86_64.h" + +#define DEBUG_TYPE "orc" + +using namespace llvm; +using namespace llvm::orc; +using namespace llvm::orc::shared; + +namespace llvm { +namespace orc { +namespace shared { + +using SPSCOFFJITDylibDepInfo = SPSSequence<SPSExecutorAddr>; +using SPSCOFFJITDylibDepInfoMap = + SPSSequence<SPSTuple<SPSExecutorAddr, SPSCOFFJITDylibDepInfo>>; +using SPSCOFFObjectSectionsMap = + SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRange>>; +using SPSCOFFRegisterObjectSectionsArgs = + SPSArgList<SPSExecutorAddr, SPSCOFFObjectSectionsMap, bool>; +using SPSCOFFDeregisterObjectSectionsArgs = + SPSArgList<SPSExecutorAddr, SPSCOFFObjectSectionsMap>; + +} // namespace shared +} // namespace orc +} // namespace llvm +namespace { + +class COFFHeaderMaterializationUnit : public MaterializationUnit { +public: + COFFHeaderMaterializationUnit(COFFPlatform &CP, + const SymbolStringPtr &HeaderStartSymbol) + : MaterializationUnit(createHeaderInterface(CP, HeaderStartSymbol)), + CP(CP) {} + + StringRef getName() const override { return "COFFHeaderMU"; } + + void materialize(std::unique_ptr<MaterializationResponsibility> R) override { + unsigned PointerSize; + support::endianness Endianness; + const auto &TT = + CP.getExecutionSession().getExecutorProcessControl().getTargetTriple(); + + switch (TT.getArch()) { + case Triple::x86_64: + PointerSize = 8; + Endianness = support::endianness::little; + break; + default: + llvm_unreachable("Unrecognized architecture"); + } + + auto G = std::make_unique<jitlink::LinkGraph>( + "<COFFHeaderMU>", TT, PointerSize, Endianness, + jitlink::getGenericEdgeKindName); + auto &HeaderSection = G->createSection("__header", MemProt::Read); + auto &HeaderBlock = createHeaderBlock(*G, HeaderSection); + + // Init symbol is __ImageBase symbol. + auto &ImageBaseSymbol = G->addDefinedSymbol( + HeaderBlock, 0, *R->getInitializerSymbol(), HeaderBlock.getSize(), + jitlink::Linkage::Strong, jitlink::Scope::Default, false, true); + + addImageBaseRelocationEdge(HeaderBlock, ImageBaseSymbol); + + CP.getObjectLinkingLayer().emit(std::move(R), std::move(G)); + } + + void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {} + +private: + struct HeaderSymbol { + const char *Name; + uint64_t Offset; + }; + + struct NTHeader { + support::ulittle32_t PEMagic; + object::coff_file_header FileHeader; + struct PEHeader { + object::pe32plus_header Header; + object::data_directory DataDirectory[COFF::NUM_DATA_DIRECTORIES + 1]; + } OptionalHeader; + }; + + struct HeaderBlockContent { + object::dos_header DOSHeader; + COFFHeaderMaterializationUnit::NTHeader NTHeader; + }; + + static jitlink::Block &createHeaderBlock(jitlink::LinkGraph &G, + jitlink::Section &HeaderSection) { + HeaderBlockContent Hdr = {}; + + // Set up magic + Hdr.DOSHeader.Magic[0] = 'M'; + Hdr.DOSHeader.Magic[1] = 'Z'; + Hdr.DOSHeader.AddressOfNewExeHeader = + offsetof(HeaderBlockContent, NTHeader); + uint32_t PEMagic = *reinterpret_cast<const uint32_t *>(COFF::PEMagic); + Hdr.NTHeader.PEMagic = PEMagic; + Hdr.NTHeader.OptionalHeader.Header.Magic = COFF::PE32Header::PE32_PLUS; + + switch (G.getTargetTriple().getArch()) { + case Triple::x86_64: + Hdr.NTHeader.FileHeader.Machine = COFF::IMAGE_FILE_MACHINE_AMD64; + break; + default: + llvm_unreachable("Unrecognized architecture"); + } + + auto HeaderContent = G.allocateString( + StringRef(reinterpret_cast<const char *>(&Hdr), sizeof(Hdr))); + + return G.createContentBlock(HeaderSection, HeaderContent, ExecutorAddr(), 8, + 0); + } + + static void addImageBaseRelocationEdge(jitlink::Block &B, + jitlink::Symbol &ImageBase) { + auto ImageBaseOffset = offsetof(HeaderBlockContent, NTHeader) + + offsetof(NTHeader, OptionalHeader) + + offsetof(object::pe32plus_header, ImageBase); + B.addEdge(jitlink::x86_64::Pointer64, ImageBaseOffset, ImageBase, 0); + } + + static MaterializationUnit::Interface + createHeaderInterface(COFFPlatform &MOP, + const SymbolStringPtr &HeaderStartSymbol) { + SymbolFlagsMap HeaderSymbolFlags; + + HeaderSymbolFlags[HeaderStartSymbol] = JITSymbolFlags::Exported; + + return MaterializationUnit::Interface(std::move(HeaderSymbolFlags), + HeaderStartSymbol); + } + + COFFPlatform &CP; +}; + +} // end anonymous namespace + +namespace llvm { +namespace orc { + +Expected<std::unique_ptr<COFFPlatform>> +COFFPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, + JITDylib &PlatformJD, const char *OrcRuntimePath, + LoadDynamicLibrary LoadDynLibrary, bool StaticVCRuntime, + const char *VCRuntimePath, + std::optional<SymbolAliasMap> RuntimeAliases) { + auto &EPC = ES.getExecutorProcessControl(); + + // If the target is not supported then bail out immediately. + if (!supportedTarget(EPC.getTargetTriple())) + return make_error<StringError>("Unsupported COFFPlatform triple: " + + EPC.getTargetTriple().str(), + inconvertibleErrorCode()); + + // Create default aliases if the caller didn't supply any. + if (!RuntimeAliases) + RuntimeAliases = standardPlatformAliases(ES); + + // Define the aliases. + if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases)))) + return std::move(Err); + + auto &HostFuncJD = ES.createBareJITDylib("$<PlatformRuntimeHostFuncJD>"); + + // Add JIT-dispatch function support symbols. + if (auto Err = HostFuncJD.define(absoluteSymbols( + {{ES.intern("__orc_rt_jit_dispatch"), + {EPC.getJITDispatchInfo().JITDispatchFunction.getValue(), + JITSymbolFlags::Exported}}, + {ES.intern("__orc_rt_jit_dispatch_ctx"), + {EPC.getJITDispatchInfo().JITDispatchContext.getValue(), + JITSymbolFlags::Exported}}}))) + return std::move(Err); + + PlatformJD.addToLinkOrder(HostFuncJD); + + // Create the instance. + Error Err = Error::success(); + auto P = std::unique_ptr<COFFPlatform>(new COFFPlatform( + ES, ObjLinkingLayer, PlatformJD, OrcRuntimePath, + std::move(LoadDynLibrary), StaticVCRuntime, VCRuntimePath, Err)); + if (Err) + return std::move(Err); + return std::move(P); +} + +Expected<MemoryBufferRef> COFFPlatform::getPerJDObjectFile() { + auto PerJDObj = OrcRuntimeArchive->findSym("__orc_rt_coff_per_jd_marker"); + if (!PerJDObj) + return PerJDObj.takeError(); + + if (!*PerJDObj) + return make_error<StringError>("Could not find per jd object file", + inconvertibleErrorCode()); + + auto Buffer = (*PerJDObj)->getAsBinary(); + if (!Buffer) + return Buffer.takeError(); + + return (*Buffer)->getMemoryBufferRef(); +} + +static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases, + ArrayRef<std::pair<const char *, const char *>> AL) { + for (auto &KV : AL) { + auto AliasName = ES.intern(KV.first); + assert(!Aliases.count(AliasName) && "Duplicate symbol name in alias map"); + Aliases[std::move(AliasName)] = {ES.intern(KV.second), + JITSymbolFlags::Exported}; + } +} + +Error COFFPlatform::setupJITDylib(JITDylib &JD) { + if (auto Err = JD.define(std::make_unique<COFFHeaderMaterializationUnit>( + *this, COFFHeaderStartSymbol))) + return Err; + + if (auto Err = ES.lookup({&JD}, COFFHeaderStartSymbol).takeError()) + return Err; + + // Define the CXX aliases. + SymbolAliasMap CXXAliases; + addAliases(ES, CXXAliases, requiredCXXAliases()); + if (auto Err = JD.define(symbolAliases(std::move(CXXAliases)))) + return Err; + + auto PerJDObj = getPerJDObjectFile(); + if (!PerJDObj) + return PerJDObj.takeError(); + + auto I = getObjectFileInterface(ES, *PerJDObj); + if (!I) + return I.takeError(); + + if (auto Err = ObjLinkingLayer.add( + JD, MemoryBuffer::getMemBuffer(*PerJDObj, false), std::move(*I))) + return Err; + + if (!Bootstrapping) { + auto ImportedLibs = StaticVCRuntime + ? VCRuntimeBootstrap->loadStaticVCRuntime(JD) + : VCRuntimeBootstrap->loadDynamicVCRuntime(JD); + if (!ImportedLibs) + return ImportedLibs.takeError(); + for (auto &Lib : *ImportedLibs) + if (auto Err = LoadDynLibrary(JD, Lib)) + return Err; + if (StaticVCRuntime) + if (auto Err = VCRuntimeBootstrap->initializeStaticVCRuntime(JD)) + return Err; + } + + JD.addGenerator(DLLImportDefinitionGenerator::Create(ES, ObjLinkingLayer)); + return Error::success(); +} + +Error COFFPlatform::teardownJITDylib(JITDylib &JD) { + std::lock_guard<std::mutex> Lock(PlatformMutex); + auto I = JITDylibToHeaderAddr.find(&JD); + if (I != JITDylibToHeaderAddr.end()) { + assert(HeaderAddrToJITDylib.count(I->second) && + "HeaderAddrToJITDylib missing entry"); + HeaderAddrToJITDylib.erase(I->second); + JITDylibToHeaderAddr.erase(I); + } + return Error::success(); +} + +Error COFFPlatform::notifyAdding(ResourceTracker &RT, + const MaterializationUnit &MU) { + auto &JD = RT.getJITDylib(); + const auto &InitSym = MU.getInitializerSymbol(); + if (!InitSym) + return Error::success(); + + RegisteredInitSymbols[&JD].add(InitSym, + SymbolLookupFlags::WeaklyReferencedSymbol); + + LLVM_DEBUG({ + dbgs() << "COFFPlatform: Registered init symbol " << *InitSym << " for MU " + << MU.getName() << "\n"; + }); + return Error::success(); +} + +Error COFFPlatform::notifyRemoving(ResourceTracker &RT) { + llvm_unreachable("Not supported yet"); +} + +SymbolAliasMap COFFPlatform::standardPlatformAliases(ExecutionSession &ES) { + SymbolAliasMap Aliases; + addAliases(ES, Aliases, standardRuntimeUtilityAliases()); + return Aliases; +} + +ArrayRef<std::pair<const char *, const char *>> +COFFPlatform::requiredCXXAliases() { + static const std::pair<const char *, const char *> RequiredCXXAliases[] = { + {"_CxxThrowException", "__orc_rt_coff_cxx_throw_exception"}, + {"_onexit", "__orc_rt_coff_onexit_per_jd"}, + {"atexit", "__orc_rt_coff_atexit_per_jd"}}; + + return ArrayRef<std::pair<const char *, const char *>>(RequiredCXXAliases); +} + +ArrayRef<std::pair<const char *, const char *>> +COFFPlatform::standardRuntimeUtilityAliases() { + static const std::pair<const char *, const char *> + StandardRuntimeUtilityAliases[] = { + {"__orc_rt_run_program", "__orc_rt_coff_run_program"}, + {"__orc_rt_jit_dlerror", "__orc_rt_coff_jit_dlerror"}, + {"__orc_rt_jit_dlopen", "__orc_rt_coff_jit_dlopen"}, + {"__orc_rt_jit_dlclose", "__orc_rt_coff_jit_dlclose"}, + {"__orc_rt_jit_dlsym", "__orc_rt_coff_jit_dlsym"}, + {"__orc_rt_log_error", "__orc_rt_log_error_to_stderr"}}; + + return ArrayRef<std::pair<const char *, const char *>>( + StandardRuntimeUtilityAliases); +} + +bool COFFPlatform::supportedTarget(const Triple &TT) { + switch (TT.getArch()) { + case Triple::x86_64: + return true; + default: + return false; + } +} + +COFFPlatform::COFFPlatform(ExecutionSession &ES, + ObjectLinkingLayer &ObjLinkingLayer, + JITDylib &PlatformJD, const char *OrcRuntimePath, + LoadDynamicLibrary LoadDynLibrary, + bool StaticVCRuntime, const char *VCRuntimePath, + Error &Err) + : ES(ES), ObjLinkingLayer(ObjLinkingLayer), + LoadDynLibrary(std::move(LoadDynLibrary)), + StaticVCRuntime(StaticVCRuntime), + COFFHeaderStartSymbol(ES.intern("__ImageBase")) { + ErrorAsOutParameter _(&Err); + + // Create a generator for the ORC runtime archive. + auto OrcRuntimeArchiveGenerator = + StaticLibraryDefinitionGenerator::Load(ObjLinkingLayer, OrcRuntimePath); + if (!OrcRuntimeArchiveGenerator) { + Err = OrcRuntimeArchiveGenerator.takeError(); + return; + } + + auto ArchiveBuffer = MemoryBuffer::getFile(OrcRuntimePath); + if (!ArchiveBuffer) { + Err = createFileError(OrcRuntimePath, ArchiveBuffer.getError()); + return; + } + OrcRuntimeArchiveBuffer = std::move(*ArchiveBuffer); + OrcRuntimeArchive = + std::make_unique<object::Archive>(*OrcRuntimeArchiveBuffer, Err); + if (Err) + return; + + Bootstrapping.store(true); + ObjLinkingLayer.addPlugin(std::make_unique<COFFPlatformPlugin>(*this)); + + // Load vc runtime + auto VCRT = + COFFVCRuntimeBootstrapper::Create(ES, ObjLinkingLayer, VCRuntimePath); + if (!VCRT) { + Err = VCRT.takeError(); + return; + } + VCRuntimeBootstrap = std::move(*VCRT); + + for (auto &Lib : (*OrcRuntimeArchiveGenerator)->getImportedDynamicLibraries()) + DylibsToPreload.insert(Lib); + + auto ImportedLibs = + StaticVCRuntime ? VCRuntimeBootstrap->loadStaticVCRuntime(PlatformJD) + : VCRuntimeBootstrap->loadDynamicVCRuntime(PlatformJD); + if (!ImportedLibs) { + Err = ImportedLibs.takeError(); + return; + } + + for (auto &Lib : *ImportedLibs) + DylibsToPreload.insert(Lib); + + PlatformJD.addGenerator(std::move(*OrcRuntimeArchiveGenerator)); + + // PlatformJD hasn't been set up by the platform yet (since we're creating + // the platform now), so set it up. + if (auto E2 = setupJITDylib(PlatformJD)) { + Err = std::move(E2); + return; + } + + for (auto& Lib : DylibsToPreload) + if (auto E2 = LoadDynLibrary(PlatformJD, Lib)) { + Err = std::move(E2); + return; + } + + if (StaticVCRuntime) + if (auto E2 = VCRuntimeBootstrap->initializeStaticVCRuntime(PlatformJD)) { + Err = std::move(E2); + return; + } + + // Associate wrapper function tags with JIT-side function implementations. + if (auto E2 = associateRuntimeSupportFunctions(PlatformJD)) { + Err = std::move(E2); + return; + } + + // Lookup addresses of runtime functions callable by the platform, + // call the platform bootstrap function to initialize the platform-state + // object in the executor. + if (auto E2 = bootstrapCOFFRuntime(PlatformJD)) { + Err = std::move(E2); + return; + } + + Bootstrapping.store(false); + JDBootstrapStates.clear(); +} + +Expected<COFFPlatform::JITDylibDepMap> +COFFPlatform::buildJDDepMap(JITDylib &JD) { + return ES.runSessionLocked([&]() -> Expected<JITDylibDepMap> { + JITDylibDepMap JDDepMap; + + SmallVector<JITDylib *, 16> Worklist({&JD}); + while (!Worklist.empty()) { + auto CurJD = Worklist.back(); + Worklist.pop_back(); + + auto &DM = JDDepMap[CurJD]; + CurJD->withLinkOrderDo([&](const JITDylibSearchOrder &O) { + DM.reserve(O.size()); + for (auto &KV : O) { + if (KV.first == CurJD) + continue; + { + // Bare jitdylibs not known to the platform + std::lock_guard<std::mutex> Lock(PlatformMutex); + if (!JITDylibToHeaderAddr.count(KV.first)) { + LLVM_DEBUG({ + dbgs() << "JITDylib unregistered to COFFPlatform detected in " + "LinkOrder: " + << CurJD->getName() << "\n"; + }); + continue; + } + } + DM.push_back(KV.first); + // Push unvisited entry. + if (!JDDepMap.count(KV.first)) { + Worklist.push_back(KV.first); + JDDepMap[KV.first] = {}; + } + } + }); + } + return std::move(JDDepMap); + }); +} + +void COFFPlatform::pushInitializersLoop(PushInitializersSendResultFn SendResult, + JITDylibSP JD, + JITDylibDepMap &JDDepMap) { + SmallVector<JITDylib *, 16> Worklist({JD.get()}); + DenseSet<JITDylib *> Visited({JD.get()}); + DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols; + ES.runSessionLocked([&]() { + while (!Worklist.empty()) { + auto CurJD = Worklist.back(); + Worklist.pop_back(); + + auto RISItr = RegisteredInitSymbols.find(CurJD); + if (RISItr != RegisteredInitSymbols.end()) { + NewInitSymbols[CurJD] = std::move(RISItr->second); + RegisteredInitSymbols.erase(RISItr); + } + + for (auto *DepJD : JDDepMap[CurJD]) + if (!Visited.count(DepJD)) { + Worklist.push_back(DepJD); + Visited.insert(DepJD); + } + } + }); + + // If there are no further init symbols to look up then send the link order + // (as a list of header addresses) to the caller. + if (NewInitSymbols.empty()) { + // Build the dep info map to return. + COFFJITDylibDepInfoMap DIM; + DIM.reserve(JDDepMap.size()); + for (auto &KV : JDDepMap) { + std::lock_guard<std::mutex> Lock(PlatformMutex); + COFFJITDylibDepInfo DepInfo; + DepInfo.reserve(KV.second.size()); + for (auto &Dep : KV.second) { + DepInfo.push_back(JITDylibToHeaderAddr[Dep]); + } + auto H = JITDylibToHeaderAddr[KV.first]; + DIM.push_back(std::make_pair(H, std::move(DepInfo))); + } + SendResult(DIM); + return; + } + + // Otherwise issue a lookup and re-run this phase when it completes. + lookupInitSymbolsAsync( + [this, SendResult = std::move(SendResult), &JD, + JDDepMap = std::move(JDDepMap)](Error Err) mutable { + if (Err) + SendResult(std::move(Err)); + else + pushInitializersLoop(std::move(SendResult), JD, JDDepMap); + }, + ES, std::move(NewInitSymbols)); +} + +void COFFPlatform::rt_pushInitializers(PushInitializersSendResultFn SendResult, + ExecutorAddr JDHeaderAddr) { + JITDylibSP JD; + { + std::lock_guard<std::mutex> Lock(PlatformMutex); + auto I = HeaderAddrToJITDylib.find(JDHeaderAddr); + if (I != HeaderAddrToJITDylib.end()) + JD = I->second; + } + + LLVM_DEBUG({ + dbgs() << "COFFPlatform::rt_pushInitializers(" << JDHeaderAddr << ") "; + if (JD) + dbgs() << "pushing initializers for " << JD->getName() << "\n"; + else + dbgs() << "No JITDylib for header address.\n"; + }); + + if (!JD) { + SendResult( + make_error<StringError>("No JITDylib with header addr " + + formatv("{0:x}", JDHeaderAddr.getValue()), + inconvertibleErrorCode())); + return; + } + + auto JDDepMap = buildJDDepMap(*JD); + if (!JDDepMap) { + SendResult(JDDepMap.takeError()); + return; + } + + pushInitializersLoop(std::move(SendResult), JD, *JDDepMap); +} + +void COFFPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult, + ExecutorAddr Handle, StringRef SymbolName) { + LLVM_DEBUG({ + dbgs() << "COFFPlatform::rt_lookupSymbol(\"" + << formatv("{0:x}", Handle.getValue()) << "\")\n"; + }); + + JITDylib *JD = nullptr; + + { + std::lock_guard<std::mutex> Lock(PlatformMutex); + auto I = HeaderAddrToJITDylib.find(Handle); + if (I != HeaderAddrToJITDylib.end()) + JD = I->second; + } + + if (!JD) { + LLVM_DEBUG({ + dbgs() << " No JITDylib for handle " + << formatv("{0:x}", Handle.getValue()) << "\n"; + }); + SendResult(make_error<StringError>("No JITDylib associated with handle " + + formatv("{0:x}", Handle.getValue()), + inconvertibleErrorCode())); + return; + } + + // Use functor class to work around XL build compiler issue on AIX. + class RtLookupNotifyComplete { + public: + RtLookupNotifyComplete(SendSymbolAddressFn &&SendResult) + : SendResult(std::move(SendResult)) {} + void operator()(Expected<SymbolMap> Result) { + if (Result) { + assert(Result->size() == 1 && "Unexpected result map count"); + SendResult(ExecutorAddr(Result->begin()->second.getAddress())); + } else { + SendResult(Result.takeError()); + } + } + + private: + SendSymbolAddressFn SendResult; + }; + + ES.lookup( + LookupKind::DLSym, {{JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}}, + SymbolLookupSet(ES.intern(SymbolName)), SymbolState::Ready, + RtLookupNotifyComplete(std::move(SendResult)), NoDependenciesToRegister); +} + +Error COFFPlatform::associateRuntimeSupportFunctions(JITDylib &PlatformJD) { + ExecutionSession::JITDispatchHandlerAssociationMap WFs; + + using LookupSymbolSPSSig = + SPSExpected<SPSExecutorAddr>(SPSExecutorAddr, SPSString); + WFs[ES.intern("__orc_rt_coff_symbol_lookup_tag")] = + ES.wrapAsyncWithSPS<LookupSymbolSPSSig>(this, + &COFFPlatform::rt_lookupSymbol); + using PushInitializersSPSSig = + SPSExpected<SPSCOFFJITDylibDepInfoMap>(SPSExecutorAddr); + WFs[ES.intern("__orc_rt_coff_push_initializers_tag")] = + ES.wrapAsyncWithSPS<PushInitializersSPSSig>( + this, &COFFPlatform::rt_pushInitializers); + + return ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs)); +} + +Error COFFPlatform::runBootstrapInitializers(JDBootstrapState &BState) { + llvm::sort(BState.Initializers); + if (auto Err = + runBootstrapSubsectionInitializers(BState, ".CRT$XIA", ".CRT$XIZ")) + return Err; + + if (auto Err = runSymbolIfExists(*BState.JD, "__run_after_c_init")) + return Err; + + if (auto Err = + runBootstrapSubsectionInitializers(BState, ".CRT$XCA", ".CRT$XCZ")) + return Err; + return Error::success(); +} + +Error COFFPlatform::runBootstrapSubsectionInitializers(JDBootstrapState &BState, + StringRef Start, + StringRef End) { + for (auto &Initializer : BState.Initializers) + if (Initializer.first >= Start && Initializer.first <= End && + Initializer.second) { + auto Res = + ES.getExecutorProcessControl().runAsVoidFunction(Initializer.second); + if (!Res) + return Res.takeError(); + } + return Error::success(); +} + +Error COFFPlatform::bootstrapCOFFRuntime(JITDylib &PlatformJD) { + // Lookup of runtime symbols causes the collection of initializers if + // it's static linking setting. + if (auto Err = lookupAndRecordAddrs( + ES, LookupKind::Static, makeJITDylibSearchOrder(&PlatformJD), + { + {ES.intern("__orc_rt_coff_platform_bootstrap"), + &orc_rt_coff_platform_bootstrap}, + {ES.intern("__orc_rt_coff_platform_shutdown"), + &orc_rt_coff_platform_shutdown}, + {ES.intern("__orc_rt_coff_register_jitdylib"), + &orc_rt_coff_register_jitdylib}, + {ES.intern("__orc_rt_coff_deregister_jitdylib"), + &orc_rt_coff_deregister_jitdylib}, + {ES.intern("__orc_rt_coff_register_object_sections"), + &orc_rt_coff_register_object_sections}, + {ES.intern("__orc_rt_coff_deregister_object_sections"), + &orc_rt_coff_deregister_object_sections}, + })) + return Err; + + // Call bootstrap functions + if (auto Err = ES.callSPSWrapper<void()>(orc_rt_coff_platform_bootstrap)) + return Err; + + // Do the pending jitdylib registration actions that we couldn't do + // because orc runtime was not linked fully. + for (auto KV : JDBootstrapStates) { + auto &JDBState = KV.second; + if (auto Err = ES.callSPSWrapper<void(SPSString, SPSExecutorAddr)>( + orc_rt_coff_register_jitdylib, JDBState.JDName, + JDBState.HeaderAddr)) + return Err; + + for (auto &ObjSectionMap : JDBState.ObjectSectionsMaps) + if (auto Err = ES.callSPSWrapper<void(SPSExecutorAddr, + SPSCOFFObjectSectionsMap, bool)>( + orc_rt_coff_register_object_sections, JDBState.HeaderAddr, + ObjSectionMap, false)) + return Err; + } + + // Run static initializers collected in bootstrap stage. + for (auto KV : JDBootstrapStates) { + auto &JDBState = KV.second; + if (auto Err = runBootstrapInitializers(JDBState)) + return Err; + } + + return Error::success(); +} + +Error COFFPlatform::runSymbolIfExists(JITDylib &PlatformJD, + StringRef SymbolName) { + ExecutorAddr jit_function; + auto AfterCLookupErr = lookupAndRecordAddrs( + ES, LookupKind::Static, makeJITDylibSearchOrder(&PlatformJD), + {{ES.intern(SymbolName), &jit_function}}); + if (!AfterCLookupErr) { + auto Res = ES.getExecutorProcessControl().runAsVoidFunction(jit_function); + if (!Res) + return Res.takeError(); + return Error::success(); + } + if (!AfterCLookupErr.isA<SymbolsNotFound>()) + return AfterCLookupErr; + consumeError(std::move(AfterCLookupErr)); + return Error::success(); +} + +void COFFPlatform::COFFPlatformPlugin::modifyPassConfig( + MaterializationResponsibility &MR, jitlink::LinkGraph &LG, + jitlink::PassConfiguration &Config) { + + bool IsBootstrapping = CP.Bootstrapping.load(); + + if (auto InitSymbol = MR.getInitializerSymbol()) { + if (InitSymbol == CP.COFFHeaderStartSymbol) { + Config.PostAllocationPasses.push_back( + [this, &MR, IsBootstrapping](jitlink::LinkGraph &G) { + return associateJITDylibHeaderSymbol(G, MR, IsBootstrapping); + }); + return; + } + Config.PrePrunePasses.push_back([this, &MR](jitlink::LinkGraph &G) { + return preserveInitializerSections(G, MR); + }); + } + + if (!IsBootstrapping) + Config.PostFixupPasses.push_back( + [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) { + return registerObjectPlatformSections(G, JD); + }); + else + Config.PostFixupPasses.push_back( + [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) { + return registerObjectPlatformSectionsInBootstrap(G, JD); + }); +} + +ObjectLinkingLayer::Plugin::SyntheticSymbolDependenciesMap +COFFPlatform::COFFPlatformPlugin::getSyntheticSymbolDependencies( + MaterializationResponsibility &MR) { + std::lock_guard<std::mutex> Lock(PluginMutex); + auto I = InitSymbolDeps.find(&MR); + if (I != InitSymbolDeps.end()) { + SyntheticSymbolDependenciesMap Result; + Result[MR.getInitializerSymbol()] = std::move(I->second); + InitSymbolDeps.erase(&MR); + return Result; + } + return SyntheticSymbolDependenciesMap(); +} + +Error COFFPlatform::COFFPlatformPlugin::associateJITDylibHeaderSymbol( + jitlink::LinkGraph &G, MaterializationResponsibility &MR, + bool IsBootstraping) { + auto I = llvm::find_if(G.defined_symbols(), [this](jitlink::Symbol *Sym) { + return Sym->getName() == *CP.COFFHeaderStartSymbol; + }); + assert(I != G.defined_symbols().end() && "Missing COFF header start symbol"); + + auto &JD = MR.getTargetJITDylib(); + std::lock_guard<std::mutex> Lock(CP.PlatformMutex); + auto HeaderAddr = (*I)->getAddress(); + CP.JITDylibToHeaderAddr[&JD] = HeaderAddr; + CP.HeaderAddrToJITDylib[HeaderAddr] = &JD; + if (!IsBootstraping) { + G.allocActions().push_back( + {cantFail(WrapperFunctionCall::Create< + SPSArgList<SPSString, SPSExecutorAddr>>( + CP.orc_rt_coff_register_jitdylib, JD.getName(), HeaderAddr)), + cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>( + CP.orc_rt_coff_deregister_jitdylib, HeaderAddr))}); + } else { + G.allocActions().push_back( + {{}, + cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>( + CP.orc_rt_coff_deregister_jitdylib, HeaderAddr))}); + JDBootstrapState BState; + BState.JD = &JD; + BState.JDName = JD.getName(); + BState.HeaderAddr = HeaderAddr; + CP.JDBootstrapStates.emplace(&JD, BState); + } + + return Error::success(); +} + +Error COFFPlatform::COFFPlatformPlugin::registerObjectPlatformSections( + jitlink::LinkGraph &G, JITDylib &JD) { + COFFObjectSectionsMap ObjSecs; + auto HeaderAddr = CP.JITDylibToHeaderAddr[&JD]; + assert(HeaderAddr && "Must be registered jitdylib"); + for (auto &S : G.sections()) { + jitlink::SectionRange Range(S); + if (Range.getSize()) + ObjSecs.push_back(std::make_pair(S.getName().str(), Range.getRange())); + } + + G.allocActions().push_back( + {cantFail(WrapperFunctionCall::Create<SPSCOFFRegisterObjectSectionsArgs>( + CP.orc_rt_coff_register_object_sections, HeaderAddr, ObjSecs, true)), + cantFail( + WrapperFunctionCall::Create<SPSCOFFDeregisterObjectSectionsArgs>( + CP.orc_rt_coff_deregister_object_sections, HeaderAddr, + ObjSecs))}); + + return Error::success(); +} + +Error COFFPlatform::COFFPlatformPlugin::preserveInitializerSections( + jitlink::LinkGraph &G, MaterializationResponsibility &MR) { + JITLinkSymbolSet InitSectionSymbols; + for (auto &Sec : G.sections()) + if (COFFPlatform::isInitializerSection(Sec.getName())) + for (auto *B : Sec.blocks()) + if (!B->edges_empty()) + InitSectionSymbols.insert( + &G.addAnonymousSymbol(*B, 0, 0, false, true)); + + std::lock_guard<std::mutex> Lock(PluginMutex); + InitSymbolDeps[&MR] = InitSectionSymbols; + return Error::success(); +} + +Error COFFPlatform::COFFPlatformPlugin:: + registerObjectPlatformSectionsInBootstrap(jitlink::LinkGraph &G, + JITDylib &JD) { + std::lock_guard<std::mutex> Lock(CP.PlatformMutex); + auto HeaderAddr = CP.JITDylibToHeaderAddr[&JD]; + COFFObjectSectionsMap ObjSecs; + for (auto &S : G.sections()) { + jitlink::SectionRange Range(S); + if (Range.getSize()) + ObjSecs.push_back(std::make_pair(S.getName().str(), Range.getRange())); + } + + G.allocActions().push_back( + {{}, + cantFail( + WrapperFunctionCall::Create<SPSCOFFDeregisterObjectSectionsArgs>( + CP.orc_rt_coff_deregister_object_sections, HeaderAddr, + ObjSecs))}); + + auto &BState = CP.JDBootstrapStates[&JD]; + BState.ObjectSectionsMaps.push_back(std::move(ObjSecs)); + + // Collect static initializers + for (auto &S : G.sections()) + if (COFFPlatform::isInitializerSection(S.getName())) + for (auto *B : S.blocks()) { + if (B->edges_empty()) + continue; + for (auto &E : B->edges()) + BState.Initializers.push_back(std::make_pair( + S.getName().str(), + ExecutorAddr(E.getTarget().getAddress() + E.getAddend()))); + } + + return Error::success(); +} + +} // End namespace orc. +} // End namespace llvm. diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/COFFVCRuntimeSupport.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/COFFVCRuntimeSupport.cpp new file mode 100644 index 000000000000..d9316fab2de3 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/COFFVCRuntimeSupport.cpp @@ -0,0 +1,184 @@ +//===------- COFFVCRuntimeSupport.cpp - VC runtime support 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/COFFVCRuntimeSupport.h" + +#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" +#include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.h" +#include "llvm/Support/VirtualFileSystem.h" +#include "llvm/WindowsDriver/MSVCPaths.h" + +#define DEBUG_TYPE "orc" + +using namespace llvm; +using namespace llvm::orc; +using namespace llvm::orc::shared; + +Expected<std::unique_ptr<COFFVCRuntimeBootstrapper>> +COFFVCRuntimeBootstrapper::Create(ExecutionSession &ES, + ObjectLinkingLayer &ObjLinkingLayer, + const char *RuntimePath) { + return std::unique_ptr<COFFVCRuntimeBootstrapper>( + new COFFVCRuntimeBootstrapper(ES, ObjLinkingLayer, RuntimePath)); +} + +COFFVCRuntimeBootstrapper::COFFVCRuntimeBootstrapper( + ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, + const char *RuntimePath) + : ES(ES), ObjLinkingLayer(ObjLinkingLayer) { + if (RuntimePath) + this->RuntimePath = RuntimePath; +} + +Expected<std::vector<std::string>> +COFFVCRuntimeBootstrapper::loadStaticVCRuntime(JITDylib &JD, + bool DebugVersion) { + StringRef VCLibs[] = {"libvcruntime.lib", "libcmt.lib", "libcpmt.lib"}; + StringRef UCRTLibs[] = {"libucrt.lib"}; + std::vector<std::string> ImportedLibraries; + if (auto Err = loadVCRuntime(JD, ImportedLibraries, ArrayRef(VCLibs), + ArrayRef(UCRTLibs))) + return std::move(Err); + return ImportedLibraries; +} + +Expected<std::vector<std::string>> +COFFVCRuntimeBootstrapper::loadDynamicVCRuntime(JITDylib &JD, + bool DebugVersion) { + StringRef VCLibs[] = {"vcruntime.lib", "msvcrt.lib", "msvcprt.lib"}; + StringRef UCRTLibs[] = {"ucrt.lib"}; + std::vector<std::string> ImportedLibraries; + if (auto Err = loadVCRuntime(JD, ImportedLibraries, ArrayRef(VCLibs), + ArrayRef(UCRTLibs))) + return std::move(Err); + return ImportedLibraries; +} + +Error COFFVCRuntimeBootstrapper::loadVCRuntime( + JITDylib &JD, std::vector<std::string> &ImportedLibraries, + ArrayRef<StringRef> VCLibs, ArrayRef<StringRef> UCRTLibs) { + MSVCToolchainPath Path; + if (!RuntimePath.empty()) { + Path.UCRTSdkLib = RuntimePath; + Path.VCToolchainLib = RuntimePath; + } else { + auto ToolchainPath = getMSVCToolchainPath(); + if (!ToolchainPath) + return ToolchainPath.takeError(); + Path = *ToolchainPath; + } + LLVM_DEBUG({ + dbgs() << "Using VC toolchain pathes\n"; + dbgs() << " VC toolchain path: " << Path.VCToolchainLib << "\n"; + dbgs() << " UCRT path: " << Path.UCRTSdkLib << "\n"; + }); + + auto LoadLibrary = [&](SmallString<256> LibPath, StringRef LibName) -> Error { + sys::path::append(LibPath, LibName); + + auto G = StaticLibraryDefinitionGenerator::Load(ObjLinkingLayer, + LibPath.c_str()); + if (!G) + return G.takeError(); + + for (auto &Lib : (*G)->getImportedDynamicLibraries()) + ImportedLibraries.push_back(Lib); + + JD.addGenerator(std::move(*G)); + + return Error::success(); + }; + for (auto &Lib : UCRTLibs) + if (auto Err = LoadLibrary(Path.UCRTSdkLib, Lib)) + return Err; + + for (auto &Lib : VCLibs) + if (auto Err = LoadLibrary(Path.VCToolchainLib, Lib)) + return Err; + ImportedLibraries.push_back("ntdll.dll"); + ImportedLibraries.push_back("Kernel32.dll"); + + return Error::success(); +} + +Error COFFVCRuntimeBootstrapper::initializeStaticVCRuntime(JITDylib &JD) { + ExecutorAddr jit_scrt_initialize, jit_scrt_dllmain_before_initialize_c, + jit_scrt_initialize_type_info, + jit_scrt_initialize_default_local_stdio_options; + if (auto Err = lookupAndRecordAddrs( + ES, LookupKind::Static, makeJITDylibSearchOrder(&JD), + {{ES.intern("__scrt_initialize_crt"), &jit_scrt_initialize}, + {ES.intern("__scrt_dllmain_before_initialize_c"), + &jit_scrt_dllmain_before_initialize_c}, + {ES.intern("?__scrt_initialize_type_info@@YAXXZ"), + &jit_scrt_initialize_type_info}, + {ES.intern("__scrt_initialize_default_local_stdio_options"), + &jit_scrt_initialize_default_local_stdio_options}})) + return Err; + + auto RunVoidInitFunc = [&](ExecutorAddr Addr) -> Error { + if (auto Res = ES.getExecutorProcessControl().runAsVoidFunction(Addr)) + return Error::success(); + else + return Res.takeError(); + }; + + auto R = + ES.getExecutorProcessControl().runAsIntFunction(jit_scrt_initialize, 0); + if (!R) + return R.takeError(); + + if (auto Err = RunVoidInitFunc(jit_scrt_dllmain_before_initialize_c)) + return Err; + + if (auto Err = RunVoidInitFunc(jit_scrt_initialize_type_info)) + return Err; + + if (auto Err = + RunVoidInitFunc(jit_scrt_initialize_default_local_stdio_options)) + return Err; + + SymbolAliasMap Alias; + Alias[ES.intern("__run_after_c_init")] = { + ES.intern("__scrt_dllmain_after_initialize_c"), JITSymbolFlags::Exported}; + if (auto Err = JD.define(symbolAliases(Alias))) + return Err; + + return Error::success(); +} + +Expected<COFFVCRuntimeBootstrapper::MSVCToolchainPath> +COFFVCRuntimeBootstrapper::getMSVCToolchainPath() { + std::string VCToolChainPath; + ToolsetLayout VSLayout; + IntrusiveRefCntPtr<vfs::FileSystem> VFS = vfs::getRealFileSystem(); + if (!findVCToolChainViaCommandLine(*VFS, std::nullopt, std::nullopt, + std::nullopt, VCToolChainPath, VSLayout) && + !findVCToolChainViaEnvironment(*VFS, VCToolChainPath, VSLayout) && + !findVCToolChainViaSetupConfig(*VFS, VCToolChainPath, VSLayout) && + !findVCToolChainViaRegistry(VCToolChainPath, VSLayout)) + return make_error<StringError>("Couldn't find msvc toolchain.", + inconvertibleErrorCode()); + + std::string UniversalCRTSdkPath; + std::string UCRTVersion; + if (!getUniversalCRTSdkDir(*VFS, std::nullopt, std::nullopt, std::nullopt, + UniversalCRTSdkPath, UCRTVersion)) + return make_error<StringError>("Couldn't find universal sdk.", + inconvertibleErrorCode()); + + MSVCToolchainPath ToolchainPath; + SmallString<256> VCToolchainLib(VCToolChainPath); + sys::path::append(VCToolchainLib, "lib", "x64"); + ToolchainPath.VCToolchainLib = VCToolchainLib; + + SmallString<256> UCRTSdkLib(UniversalCRTSdkPath); + sys::path::append(UCRTSdkLib, "Lib", UCRTVersion, "ucrt", "x64"); + ToolchainPath.UCRTSdkLib = UCRTSdkLib; + return ToolchainPath; +} diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/CompileOnDemandLayer.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/CompileOnDemandLayer.cpp index e2a0cadb6348..6448adaa0ceb 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/CompileOnDemandLayer.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/CompileOnDemandLayer.cpp @@ -102,14 +102,14 @@ private: CompileOnDemandLayer &Parent; }; -Optional<CompileOnDemandLayer::GlobalValueSet> +std::optional<CompileOnDemandLayer::GlobalValueSet> CompileOnDemandLayer::compileRequested(GlobalValueSet Requested) { return std::move(Requested); } -Optional<CompileOnDemandLayer::GlobalValueSet> +std::optional<CompileOnDemandLayer::GlobalValueSet> CompileOnDemandLayer::compileWholeModule(GlobalValueSet Requested) { - return None; + return std::nullopt; } CompileOnDemandLayer::CompileOnDemandLayer( @@ -237,7 +237,7 @@ void CompileOnDemandLayer::expandPartition(GlobalValueSet &Partition) { bool ContainsGlobalVariables = false; std::vector<const GlobalValue *> GVsToAdd; - for (auto *GV : Partition) + for (const auto *GV : Partition) if (isa<GlobalAlias>(GV)) GVsToAdd.push_back( cast<GlobalValue>(cast<GlobalAlias>(GV)->getAliasee())); @@ -252,7 +252,7 @@ void CompileOnDemandLayer::expandPartition(GlobalValueSet &Partition) { for (auto &G : M.globals()) GVsToAdd.push_back(&G); - for (auto *GV : GVsToAdd) + for (const auto *GV : GVsToAdd) Partition.insert(GV); } @@ -287,7 +287,7 @@ void CompileOnDemandLayer::emitPartition( // Take a 'None' partition to mean the whole module (as opposed to an empty // partition, which means "materialize nothing"). Emit the whole module // unmodified to the base layer. - if (GVsToExtract == None) { + if (GVsToExtract == std::nullopt) { Defs.clear(); BaseLayer.emit(std::move(R), std::move(TSM)); return; @@ -336,13 +336,13 @@ void CompileOnDemandLayer::emitPartition( { std::vector<const GlobalValue*> HashGVs; HashGVs.reserve(GVsToExtract->size()); - for (auto *GV : *GVsToExtract) + for (const auto *GV : *GVsToExtract) HashGVs.push_back(GV); llvm::sort(HashGVs, [](const GlobalValue *LHS, const GlobalValue *RHS) { return LHS->getName() < RHS->getName(); }); hash_code HC(0); - for (auto *GV : HashGVs) { + for (const auto *GV : HashGVs) { assert(GV->hasName() && "All GVs to extract should be named by now"); auto GVName = GV->getName(); HC = hash_combine(HC, hash_combine_range(GVName.begin(), GVName.end())); diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/Core.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/Core.cpp index dd80630a33c1..4a9d0d470a8e 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/Core.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/Core.cpp @@ -17,6 +17,7 @@ #include <condition_variable> #include <future> +#include <optional> #define DEBUG_TYPE "orc" @@ -970,10 +971,9 @@ Error JITDylib::resolve(MaterializationResponsibility &MR, SymbolsInErrorState.insert(KV.first); else { auto Flags = KV.second.getFlags(); - Flags &= ~(JITSymbolFlags::Weak | JITSymbolFlags::Common); + Flags &= ~JITSymbolFlags::Common; assert(Flags == - (SymI->second.getFlags() & - ~(JITSymbolFlags::Weak | JITSymbolFlags::Common)) && + (SymI->second.getFlags() & ~JITSymbolFlags::Common) && "Resolved flags should match the declared flags"); Worklist.push_back( @@ -1482,8 +1482,8 @@ void JITDylib::dump(raw_ostream &OS) { void JITDylib::MaterializingInfo::addQuery( std::shared_ptr<AsynchronousSymbolQuery> Q) { - auto I = std::lower_bound( - PendingQueries.rbegin(), PendingQueries.rend(), Q->getRequiredState(), + auto I = llvm::lower_bound( + llvm::reverse(PendingQueries), Q->getRequiredState(), [](const std::shared_ptr<AsynchronousSymbolQuery> &V, SymbolState S) { return V->getRequiredState() <= S; }); @@ -2244,8 +2244,8 @@ void ExecutionSession::dump(raw_ostream &OS) { void ExecutionSession::dispatchOutstandingMUs() { LLVM_DEBUG(dbgs() << "Dispatching MaterializationUnits...\n"); while (true) { - Optional<std::pair<std::unique_ptr<MaterializationUnit>, - std::unique_ptr<MaterializationResponsibility>>> + std::optional<std::pair<std::unique_ptr<MaterializationUnit>, + std::unique_ptr<MaterializationResponsibility>>> JMU; { @@ -2285,9 +2285,10 @@ Error ExecutionSession::removeResourceTracker(ResourceTracker &RT) { Error Err = Error::success(); + auto &JD = RT.getJITDylib(); for (auto *L : reverse(CurrentResourceManagers)) - Err = - joinErrors(std::move(Err), L->handleRemoveResources(RT.getKeyUnsafe())); + Err = joinErrors(std::move(Err), + L->handleRemoveResources(JD, RT.getKeyUnsafe())); for (auto &Q : QueriesToFail) Q->handleFailed( @@ -2316,7 +2317,8 @@ void ExecutionSession::transferResourceTracker(ResourceTracker &DstRT, auto &JD = DstRT.getJITDylib(); JD.transferTracker(DstRT, SrcRT); for (auto *L : reverse(ResourceManagers)) - L->handleTransferResources(DstRT.getKeyUnsafe(), SrcRT.getKeyUnsafe()); + L->handleTransferResources(JD, DstRT.getKeyUnsafe(), + SrcRT.getKeyUnsafe()); }); } @@ -2427,7 +2429,7 @@ void ExecutionSession::OL_applyQueryPhase1( // Add any non-candidates from the last JITDylib (if any) back on to the // list of definition candidates for this JITDylib, reset definition - // non-candiates to the empty set. + // non-candidates to the empty set. SymbolLookupSet Tmp; std::swap(IPLS->DefGeneratorNonCandidates, Tmp); IPLS->DefGeneratorCandidates.append(std::move(Tmp)); @@ -2909,13 +2911,13 @@ Error ExecutionSession::OL_notifyResolved(MaterializationResponsibility &MR, }); #ifndef NDEBUG for (auto &KV : Symbols) { - auto WeakFlags = JITSymbolFlags::Weak | JITSymbolFlags::Common; auto I = MR.SymbolFlags.find(KV.first); assert(I != MR.SymbolFlags.end() && "Resolving symbol outside this responsibility set"); assert(!I->second.hasMaterializationSideEffectsOnly() && "Can't resolve materialization-side-effects-only symbol"); - assert((KV.second.getFlags() & ~WeakFlags) == (I->second & ~WeakFlags) && + assert((KV.second.getFlags() & ~JITSymbolFlags::Common) == + (I->second & ~JITSymbolFlags::Common) && "Resolving symbol with incorrect flags"); } #endif diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/DebugObjectManagerPlugin.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/DebugObjectManagerPlugin.cpp index 1e68ea1225e6..02c3e617df68 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/DebugObjectManagerPlugin.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/DebugObjectManagerPlugin.cpp @@ -289,6 +289,9 @@ ELFDebugObject::CreateArchType(MemoryBufferRef Buffer, continue; HasDwarfSection |= isDwarfSection(*Name); + if (!(Header.sh_flags & ELF::SHF_ALLOC)) + continue; + auto Wrapped = std::make_unique<ELFDebugObjectSection<ELFT>>(&Header); if (Error Err = DebugObj->recordSection(*Name, std::move(Wrapped))) return std::move(Err); @@ -370,7 +373,9 @@ Error ELFDebugObject::recordSection( return Err; auto ItInserted = Sections.try_emplace(Name, std::move(Section)); if (!ItInserted.second) - return make_error<StringError>("Duplicate section", + return make_error<StringError>("In " + Buffer->getBufferIdentifier() + + ", encountered duplicate section \"" + + Name + "\" while building debug object", inconvertibleErrorCode()); return Error::success(); } @@ -487,7 +492,8 @@ Error DebugObjectManagerPlugin::notifyFailed( return Error::success(); } -void DebugObjectManagerPlugin::notifyTransferringResources(ResourceKey DstKey, +void DebugObjectManagerPlugin::notifyTransferringResources(JITDylib &JD, + ResourceKey DstKey, ResourceKey SrcKey) { // Debug objects are stored by ResourceKey only after registration. // Thus, pending objects don't need to be updated here. @@ -502,7 +508,8 @@ void DebugObjectManagerPlugin::notifyTransferringResources(ResourceKey DstKey, } } -Error DebugObjectManagerPlugin::notifyRemovingResources(ResourceKey Key) { +Error DebugObjectManagerPlugin::notifyRemovingResources(JITDylib &JD, + ResourceKey Key) { // Removing the resource for a pending object fails materialization, so they // get cleaned up in the notifyFailed() handler. std::lock_guard<std::mutex> Lock(RegisteredObjsLock); diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/DebuggerSupportPlugin.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/DebuggerSupportPlugin.cpp index 3c44fe81b4a9..15e7ffb2f75a 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/DebuggerSupportPlugin.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/DebuggerSupportPlugin.cpp @@ -137,7 +137,7 @@ public: SmallVector<DebugSectionInfo, 12> DebugSecInfos; size_t NumSections = 0; for (auto &Sec : G.sections()) { - if (llvm::empty(Sec.blocks())) + if (Sec.blocks().empty()) continue; ++NumSections; @@ -189,7 +189,7 @@ public: // Copy debug section blocks and symbols. orc::ExecutorAddr NextBlockAddr(MachOContainerBlock->getSize()); for (auto &SI : DebugSecInfos) { - assert(!llvm::empty(SI.Sec->blocks()) && "Empty debug info section?"); + assert(!SI.Sec->blocks().empty() && "Empty debug info section?"); // Update addresses in debug section. LLVM_DEBUG({ @@ -390,12 +390,12 @@ Error GDBJITDebugInfoRegistrationPlugin::notifyFailed( } Error GDBJITDebugInfoRegistrationPlugin::notifyRemovingResources( - ResourceKey K) { + JITDylib &JD, ResourceKey K) { return Error::success(); } void GDBJITDebugInfoRegistrationPlugin::notifyTransferringResources( - ResourceKey DstKey, ResourceKey SrcKey) {} + JITDylib &JD, ResourceKey DstKey, ResourceKey SrcKey) {} void GDBJITDebugInfoRegistrationPlugin::modifyPassConfig( MaterializationResponsibility &MR, LinkGraph &LG, diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp index e7ca636c83e9..00032e4dca3f 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp @@ -16,6 +16,7 @@ #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" #include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/Debug.h" +#include <optional> #define DEBUG_TYPE "orc" @@ -62,7 +63,7 @@ public: "<DSOHandleMU>", TT, PointerSize, Endianness, jitlink::getGenericEdgeKindName); auto &DSOHandleSection = - G->createSection(".data.__dso_handle", jitlink::MemProt::Read); + G->createSection(".data.__dso_handle", MemProt::Read); auto &DSOHandleBlock = G->createContentBlock( DSOHandleSection, getDSOHandleContent(PointerSize), orc::ExecutorAddr(), 8, 0); @@ -110,7 +111,7 @@ Expected<std::unique_ptr<ELFNixPlatform>> ELFNixPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD, const char *OrcRuntimePath, - Optional<SymbolAliasMap> RuntimeAliases) { + std::optional<SymbolAliasMap> RuntimeAliases) { auto &EPC = ES.getExecutorProcessControl(); @@ -850,7 +851,7 @@ Error ELFNixPlatform::ELFNixPlatformPlugin::fixTLVSectionsAndEdges( auto *TLSInfoEntrySection = G.findSectionByName("$__TLSINFO"); if (TLSInfoEntrySection) { - Optional<uint64_t> Key; + std::optional<uint64_t> Key; { std::lock_guard<std::mutex> Lock(MP.PlatformMutex); auto I = MP.JITDylibToPThreadKey.find(&JD); diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCDebugObjectRegistrar.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCDebugObjectRegistrar.cpp index c591acdd646b..30d641ee00cf 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCDebugObjectRegistrar.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCDebugObjectRegistrar.cpp @@ -16,12 +16,17 @@ namespace llvm { namespace orc { -Expected<std::unique_ptr<EPCDebugObjectRegistrar>> -createJITLoaderGDBRegistrar(ExecutionSession &ES) { +Expected<std::unique_ptr<EPCDebugObjectRegistrar>> createJITLoaderGDBRegistrar( + ExecutionSession &ES, + std::optional<ExecutorAddr> RegistrationFunctionDylib) { auto &EPC = ES.getExecutorProcessControl(); - auto ProcessHandle = EPC.loadDylib(nullptr); - if (!ProcessHandle) - return ProcessHandle.takeError(); + + if (!RegistrationFunctionDylib) { + if (auto D = EPC.loadDylib(nullptr)) + RegistrationFunctionDylib = *D; + else + return D.takeError(); + } SymbolStringPtr RegisterFn = EPC.getTargetTriple().isOSBinFormatMachO() @@ -31,7 +36,8 @@ createJITLoaderGDBRegistrar(ExecutionSession &ES) { SymbolLookupSet RegistrationSymbols; RegistrationSymbols.add(RegisterFn); - auto Result = EPC.lookupSymbols({{*ProcessHandle, RegistrationSymbols}}); + auto Result = + EPC.lookupSymbols({{*RegistrationFunctionDylib, RegistrationSymbols}}); if (!Result) return Result.takeError(); diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp index ba154aaecd1a..1adcc9156957 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp @@ -54,7 +54,7 @@ Error EPCDynamicLibrarySearchGenerator::tryToGenerate( for (auto &KV : LookupSymbols) { if (*ResultI) NewSymbols[KV.first] = - JITEvaluatedSymbol(*ResultI, JITSymbolFlags::Exported); + JITEvaluatedSymbol(ResultI->getValue(), JITSymbolFlags::Exported); ++ResultI; } diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCEHFrameRegistrar.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCEHFrameRegistrar.cpp index 256ce94690f0..3aa94a7f43e2 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCEHFrameRegistrar.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCEHFrameRegistrar.cpp @@ -16,17 +16,22 @@ using namespace llvm::orc::shared; namespace llvm { namespace orc { -Expected<std::unique_ptr<EPCEHFrameRegistrar>> -EPCEHFrameRegistrar::Create(ExecutionSession &ES) { +Expected<std::unique_ptr<EPCEHFrameRegistrar>> EPCEHFrameRegistrar::Create( + ExecutionSession &ES, + std::optional<ExecutorAddr> RegistrationFunctionsDylib) { // FIXME: Proper mangling here -- we really need to decouple linker mangling // from DataLayout. // Find the addresses of the registration/deregistration functions in the // executor process. auto &EPC = ES.getExecutorProcessControl(); - auto ProcessHandle = EPC.loadDylib(nullptr); - if (!ProcessHandle) - return ProcessHandle.takeError(); + + if (!RegistrationFunctionsDylib) { + if (auto D = EPC.loadDylib(nullptr)) + RegistrationFunctionsDylib = *D; + else + return D.takeError(); + } std::string RegisterWrapperName, DeregisterWrapperName; if (EPC.getTargetTriple().isOSBinFormatMachO()) { @@ -40,7 +45,8 @@ EPCEHFrameRegistrar::Create(ExecutionSession &ES) { RegistrationSymbols.add(EPC.intern(RegisterWrapperName)); RegistrationSymbols.add(EPC.intern(DeregisterWrapperName)); - auto Result = EPC.lookupSymbols({{*ProcessHandle, RegistrationSymbols}}); + auto Result = + EPC.lookupSymbols({{*RegistrationFunctionsDylib, RegistrationSymbols}}); if (!Result) return Result.takeError(); diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCGenericDylibManager.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCGenericDylibManager.cpp index 6c47c5c5f7bb..e70749cdfab2 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCGenericDylibManager.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCGenericDylibManager.cpp @@ -73,7 +73,7 @@ EPCGenericDylibManager::CreateWithDefaultBootstrapSymbols( Expected<tpctypes::DylibHandle> EPCGenericDylibManager::open(StringRef Path, uint64_t Mode) { - Expected<tpctypes::DylibHandle> H(0); + Expected<tpctypes::DylibHandle> H((ExecutorAddr())); if (auto Err = EPC.callSPSWrapper<rt::SPSSimpleExecutorDylibManagerOpenSignature>( SAs.Open, H, SAs.Instance, Path, Mode)) diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.cpp index 75cc30753f41..a3d857c3bfc4 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.cpp @@ -47,8 +47,7 @@ public: for (auto &KV : Segs) { assert(KV.second.ContentSize <= std::numeric_limits<size_t>::max()); FR.Segments.push_back(tpctypes::SegFinalizeRequest{ - tpctypes::toWireProtectionFlags( - toSysMemoryProtectionFlags(KV.first.getMemProt())), + KV.first, KV.second.Addr, alignTo(KV.second.ContentSize + KV.second.ZeroFillSize, Parent.EPC.getPageSize()), diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCGenericRTDyldMemoryManager.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCGenericRTDyldMemoryManager.cpp index cdac367e11a3..ec82081937e2 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCGenericRTDyldMemoryManager.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCGenericRTDyldMemoryManager.cpp @@ -94,8 +94,8 @@ uint8_t *EPCGenericRTDyldMemoryManager::allocateDataSection( } void EPCGenericRTDyldMemoryManager::reserveAllocationSpace( - uintptr_t CodeSize, uint32_t CodeAlign, uintptr_t RODataSize, - uint32_t RODataAlign, uintptr_t RWDataSize, uint32_t RWDataAlign) { + uintptr_t CodeSize, Align CodeAlign, uintptr_t RODataSize, + Align RODataAlign, uintptr_t RWDataSize, Align RWDataAlign) { { std::lock_guard<std::mutex> Lock(M); @@ -103,15 +103,15 @@ void EPCGenericRTDyldMemoryManager::reserveAllocationSpace( if (!ErrMsg.empty()) return; - if (!isPowerOf2_32(CodeAlign) || CodeAlign > EPC.getPageSize()) { + if (CodeAlign > EPC.getPageSize()) { ErrMsg = "Invalid code alignment in reserveAllocationSpace"; return; } - if (!isPowerOf2_32(RODataAlign) || RODataAlign > EPC.getPageSize()) { + if (RODataAlign > EPC.getPageSize()) { ErrMsg = "Invalid ro-data alignment in reserveAllocationSpace"; return; } - if (!isPowerOf2_32(RWDataAlign) || RWDataAlign > EPC.getPageSize()) { + if (RWDataAlign > EPC.getPageSize()) { ErrMsg = "Invalid rw-data alignment in reserveAllocationSpace"; return; } @@ -142,7 +142,7 @@ void EPCGenericRTDyldMemoryManager::reserveAllocationSpace( } std::lock_guard<std::mutex> Lock(M); - Unmapped.push_back(AllocGroup()); + Unmapped.push_back(SectionAllocGroup()); Unmapped.back().RemoteCode = { *TargetAllocAddr, ExecutorAddrDiff(alignTo(CodeSize, EPC.getPageSize()))}; Unmapped.back().RemoteROData = { @@ -170,10 +170,11 @@ void EPCGenericRTDyldMemoryManager::registerEHFrames(uint8_t *Addr, return; ExecutorAddr LA(LoadAddr); - for (auto &Alloc : llvm::reverse(Unfinalized)) { - if (Alloc.RemoteCode.contains(LA) || Alloc.RemoteROData.contains(LA) || - Alloc.RemoteRWData.contains(LA)) { - Alloc.UnfinalizedEHFrames.push_back({LA, Size}); + for (auto &SecAllocGroup : llvm::reverse(Unfinalized)) { + if (SecAllocGroup.RemoteCode.contains(LA) || + SecAllocGroup.RemoteROData.contains(LA) || + SecAllocGroup.RemoteRWData.contains(LA)) { + SecAllocGroup.UnfinalizedEHFrames.push_back({LA, Size}); return; } } @@ -204,35 +205,29 @@ bool EPCGenericRTDyldMemoryManager::finalizeMemory(std::string *ErrMsg) { LLVM_DEBUG(dbgs() << "Allocator " << (void *)this << " finalizing:\n"); // If there's an error then bail out here. - std::vector<AllocGroup> Allocs; + std::vector<SectionAllocGroup> SecAllocGroups; { std::lock_guard<std::mutex> Lock(M); if (ErrMsg && !this->ErrMsg.empty()) { *ErrMsg = std::move(this->ErrMsg); return true; } - std::swap(Allocs, Unfinalized); + std::swap(SecAllocGroups, Unfinalized); } // Loop over unfinalized objects to make finalization requests. - for (auto &ObjAllocs : Allocs) { + for (auto &SecAllocGroup : SecAllocGroups) { - tpctypes::WireProtectionFlags SegProts[3] = { - tpctypes::toWireProtectionFlags( - static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ | - sys::Memory::MF_EXEC)), - tpctypes::toWireProtectionFlags(sys::Memory::MF_READ), - tpctypes::toWireProtectionFlags( - static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ | - sys::Memory::MF_WRITE))}; + MemProt SegMemProts[3] = {MemProt::Read | MemProt::Exec, MemProt::Read, + MemProt::Read | MemProt::Write}; - ExecutorAddrRange *RemoteAddrs[3] = {&ObjAllocs.RemoteCode, - &ObjAllocs.RemoteROData, - &ObjAllocs.RemoteRWData}; + ExecutorAddrRange *RemoteAddrs[3] = {&SecAllocGroup.RemoteCode, + &SecAllocGroup.RemoteROData, + &SecAllocGroup.RemoteRWData}; - std::vector<Alloc> *SegSections[3] = {&ObjAllocs.CodeAllocs, - &ObjAllocs.RODataAllocs, - &ObjAllocs.RWDataAllocs}; + std::vector<SectionAlloc> *SegSections[3] = {&SecAllocGroup.CodeAllocs, + &SecAllocGroup.RODataAllocs, + &SecAllocGroup.RWDataAllocs}; tpctypes::FinalizeRequest FR; std::unique_ptr<char[]> AggregateContents[3]; @@ -240,7 +235,7 @@ bool EPCGenericRTDyldMemoryManager::finalizeMemory(std::string *ErrMsg) { for (unsigned I = 0; I != 3; ++I) { FR.Segments.push_back({}); auto &Seg = FR.Segments.back(); - Seg.Prot = SegProts[I]; + Seg.AG = SegMemProts[I]; Seg.Addr = RemoteAddrs[I]->Start; for (auto &SecAlloc : *SegSections[I]) { Seg.Size = alignTo(Seg.Size, SecAlloc.Align); @@ -261,7 +256,7 @@ bool EPCGenericRTDyldMemoryManager::finalizeMemory(std::string *ErrMsg) { Seg.Content = {AggregateContents[I].get(), SecOffset}; } - for (auto &Frame : ObjAllocs.UnfinalizedEHFrames) + for (auto &Frame : SecAllocGroup.UnfinalizedEHFrames) FR.Actions.push_back( {cantFail( WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>( @@ -297,7 +292,8 @@ bool EPCGenericRTDyldMemoryManager::finalizeMemory(std::string *ErrMsg) { } void EPCGenericRTDyldMemoryManager::mapAllocsToRemoteAddrs( - RuntimeDyld &Dyld, std::vector<Alloc> &Allocs, ExecutorAddr NextAddr) { + RuntimeDyld &Dyld, std::vector<SectionAlloc> &Allocs, + ExecutorAddr NextAddr) { for (auto &Alloc : Allocs) { NextAddr.setValue(alignTo(NextAddr.getValue(), Alloc.Align)); LLVM_DEBUG({ diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCIndirectionUtils.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCIndirectionUtils.cpp index 48aaab96e71f..ddfb30500c7b 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCIndirectionUtils.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/EPCIndirectionUtils.cpp @@ -250,6 +250,9 @@ EPCIndirectionUtils::Create(ExecutorProcessControl &EPC) { case Triple::x86: return CreateWithABI<OrcI386>(EPC); + case Triple::loongarch64: + return CreateWithABI<OrcLoongArch64>(EPC); + case Triple::mips: return CreateWithABI<OrcMips32Be>(EPC); diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp index 95cf89ec3f8b..377a59993eb0 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" +#include "llvm/ExecutionEngine/JITLink/x86_64.h" #include "llvm/ExecutionEngine/Orc/Layer.h" #include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h" #include "llvm/IR/Constants.h" @@ -350,7 +351,6 @@ StaticLibraryDefinitionGenerator::Create( Error StaticLibraryDefinitionGenerator::tryToGenerate( LookupState &LS, LookupKind K, JITDylib &JD, JITDylibLookupFlags JDLookupFlags, const SymbolLookupSet &Symbols) { - // Don't materialize symbols from static archives unless this is a static // lookup. if (K != LookupKind::Static) @@ -364,16 +364,11 @@ Error StaticLibraryDefinitionGenerator::tryToGenerate( for (const auto &KV : Symbols) { const auto &Name = KV.first; - auto Child = Archive->findSym(*Name); - if (!Child) - return Child.takeError(); - if (*Child == None) + if (!ObjectFilesMap.count(Name)) continue; - auto ChildBuffer = (*Child)->getMemoryBufferRef(); - if (!ChildBuffer) - return ChildBuffer.takeError(); + auto ChildBuffer = ObjectFilesMap[Name]; ChildBufferInfos.insert( - {ChildBuffer->getBuffer(), ChildBuffer->getBufferIdentifier()}); + {ChildBuffer.getBuffer(), ChildBuffer.getBufferIdentifier()}); } for (auto ChildBufferInfo : ChildBufferInfos) { @@ -392,15 +387,163 @@ Error StaticLibraryDefinitionGenerator::tryToGenerate( return Error::success(); } +Error StaticLibraryDefinitionGenerator::buildObjectFilesMap() { + DenseMap<uint64_t, MemoryBufferRef> MemoryBuffers; + DenseSet<uint64_t> Visited; + DenseSet<uint64_t> Excluded; + for (auto &S : Archive->symbols()) { + StringRef SymName = S.getName(); + auto Member = S.getMember(); + if (!Member) + return Member.takeError(); + auto DataOffset = Member->getDataOffset(); + if (!Visited.count(DataOffset)) { + Visited.insert(DataOffset); + auto Child = Member->getAsBinary(); + if (!Child) + return Child.takeError(); + if ((*Child)->isCOFFImportFile()) { + ImportedDynamicLibraries.insert((*Child)->getFileName().str()); + Excluded.insert(DataOffset); + continue; + } + MemoryBuffers[DataOffset] = (*Child)->getMemoryBufferRef(); + } + if (!Excluded.count(DataOffset)) + ObjectFilesMap[L.getExecutionSession().intern(SymName)] = + MemoryBuffers[DataOffset]; + } + + return Error::success(); +} + StaticLibraryDefinitionGenerator::StaticLibraryDefinitionGenerator( ObjectLayer &L, std::unique_ptr<MemoryBuffer> ArchiveBuffer, GetObjectFileInterface GetObjFileInterface, Error &Err) : L(L), GetObjFileInterface(std::move(GetObjFileInterface)), ArchiveBuffer(std::move(ArchiveBuffer)), Archive(std::make_unique<object::Archive>(*this->ArchiveBuffer, Err)) { - + ErrorAsOutParameter _(&Err); if (!this->GetObjFileInterface) this->GetObjFileInterface = getObjectFileInterface; + if (!Err) + Err = buildObjectFilesMap(); +} + +std::unique_ptr<DLLImportDefinitionGenerator> +DLLImportDefinitionGenerator::Create(ExecutionSession &ES, + ObjectLinkingLayer &L) { + return std::unique_ptr<DLLImportDefinitionGenerator>( + new DLLImportDefinitionGenerator(ES, L)); +} + +Error DLLImportDefinitionGenerator::tryToGenerate( + LookupState &LS, LookupKind K, JITDylib &JD, + JITDylibLookupFlags JDLookupFlags, const SymbolLookupSet &Symbols) { + JITDylibSearchOrder LinkOrder; + JD.withLinkOrderDo([&](const JITDylibSearchOrder &LO) { + LinkOrder.reserve(LO.size()); + for (auto &KV : LO) { + if (KV.first == &JD) + continue; + LinkOrder.push_back(KV); + } + }); + + // FIXME: if regular symbol name start with __imp_ we have to issue lookup of + // both __imp_ and stripped name and use the lookup information to resolve the + // real symbol name. + SymbolLookupSet LookupSet; + DenseMap<StringRef, SymbolLookupFlags> ToLookUpSymbols; + for (auto &KV : Symbols) { + StringRef Deinterned = *KV.first; + if (Deinterned.startswith(getImpPrefix())) + Deinterned = Deinterned.drop_front(StringRef(getImpPrefix()).size()); + // Don't degrade the required state + if (ToLookUpSymbols.count(Deinterned) && + ToLookUpSymbols[Deinterned] == SymbolLookupFlags::RequiredSymbol) + continue; + ToLookUpSymbols[Deinterned] = KV.second; + } + + for (auto &KV : ToLookUpSymbols) + LookupSet.add(ES.intern(KV.first), KV.second); + + auto Resolved = + ES.lookup(LinkOrder, LookupSet, LookupKind::DLSym, SymbolState::Resolved); + if (!Resolved) + return Resolved.takeError(); + + auto G = createStubsGraph(*Resolved); + if (!G) + return G.takeError(); + return L.add(JD, std::move(*G)); +} + +Expected<unsigned> +DLLImportDefinitionGenerator::getTargetPointerSize(const Triple &TT) { + switch (TT.getArch()) { + case Triple::x86_64: + return 8; + default: + return make_error<StringError>( + "architecture unsupported by DLLImportDefinitionGenerator", + inconvertibleErrorCode()); + } +} + +Expected<support::endianness> +DLLImportDefinitionGenerator::getTargetEndianness(const Triple &TT) { + switch (TT.getArch()) { + case Triple::x86_64: + return support::endianness::little; + default: + return make_error<StringError>( + "architecture unsupported by DLLImportDefinitionGenerator", + inconvertibleErrorCode()); + } +} + +Expected<std::unique_ptr<jitlink::LinkGraph>> +DLLImportDefinitionGenerator::createStubsGraph(const SymbolMap &Resolved) { + Triple TT = ES.getExecutorProcessControl().getTargetTriple(); + auto PointerSize = getTargetEndianness(TT); + if (!PointerSize) + return PointerSize.takeError(); + auto Endianness = getTargetEndianness(TT); + if (!Endianness) + return Endianness.takeError(); + + auto G = std::make_unique<jitlink::LinkGraph>( + "<DLLIMPORT_STUBS>", TT, *PointerSize, *Endianness, + jitlink::getGenericEdgeKindName); + jitlink::Section &Sec = + G->createSection(getSectionName(), MemProt::Read | MemProt::Exec); + + for (auto &KV : Resolved) { + jitlink::Symbol &Target = G->addAbsoluteSymbol( + *KV.first, ExecutorAddr(KV.second.getAddress()), *PointerSize, + jitlink::Linkage::Strong, jitlink::Scope::Local, false); + + // Create __imp_ symbol + jitlink::Symbol &Ptr = + jitlink::x86_64::createAnonymousPointer(*G, Sec, &Target); + auto NameCopy = G->allocateString(Twine(getImpPrefix()) + *KV.first); + StringRef NameCopyRef = StringRef(NameCopy.data(), NameCopy.size()); + Ptr.setName(NameCopyRef); + Ptr.setLinkage(jitlink::Linkage::Strong); + Ptr.setScope(jitlink::Scope::Default); + + // Create PLT stub + // FIXME: check PLT stub of data symbol is not accessed + jitlink::Block &StubBlock = + jitlink::x86_64::createPointerJumpStubBlock(*G, Sec, Ptr); + G->addDefinedSymbol(StubBlock, 0, *KV.first, StubBlock.getSize(), + jitlink::Linkage::Strong, jitlink::Scope::Default, true, + false); + } + + return std::move(G); } } // End namespace orc. diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp index 412b9f95ea62..361fcd4a2e9c 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp @@ -75,12 +75,10 @@ SelfExecutorProcessControl::Create( Expected<tpctypes::DylibHandle> SelfExecutorProcessControl::loadDylib(const char *DylibPath) { std::string ErrMsg; - auto Dylib = std::make_unique<sys::DynamicLibrary>( - sys::DynamicLibrary::getPermanentLibrary(DylibPath, &ErrMsg)); - if (!Dylib->isValid()) + auto Dylib = sys::DynamicLibrary::getPermanentLibrary(DylibPath, &ErrMsg); + if (!Dylib.isValid()) return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode()); - DynamicLibraries.push_back(std::move(Dylib)); - return pointerToJITTargetAddress(DynamicLibraries.back().get()); + return ExecutorAddr::fromPtr(Dylib.getOSSpecificHandle()); } Expected<std::vector<tpctypes::LookupResult>> @@ -88,26 +86,20 @@ SelfExecutorProcessControl::lookupSymbols(ArrayRef<LookupRequest> Request) { std::vector<tpctypes::LookupResult> R; for (auto &Elem : Request) { - auto *Dylib = jitTargetAddressToPointer<sys::DynamicLibrary *>(Elem.Handle); - assert(llvm::any_of(DynamicLibraries, - [=](const std::unique_ptr<sys::DynamicLibrary> &DL) { - return DL.get() == Dylib; - }) && - "Invalid handle"); - - R.push_back(std::vector<JITTargetAddress>()); + sys::DynamicLibrary Dylib(Elem.Handle.toPtr<void *>()); + R.push_back(std::vector<ExecutorAddr>()); for (auto &KV : Elem.Symbols) { auto &Sym = KV.first; std::string Tmp((*Sym).data() + !!GlobalManglingPrefix, (*Sym).size() - !!GlobalManglingPrefix); - void *Addr = Dylib->getAddressOfSymbol(Tmp.c_str()); + void *Addr = Dylib.getAddressOfSymbol(Tmp.c_str()); if (!Addr && KV.second == SymbolLookupFlags::RequiredSymbol) { // FIXME: Collect all failing symbols before erroring out. SymbolNameVector MissingSymbols; MissingSymbols.push_back(Sym); return make_error<SymbolsNotFound>(SSP, std::move(MissingSymbols)); } - R.back().push_back(pointerToJITTargetAddress(Addr)); + R.back().push_back(ExecutorAddr::fromPtr(Addr)); } } @@ -121,6 +113,18 @@ SelfExecutorProcessControl::runAsMain(ExecutorAddr MainFnAddr, return orc::runAsMain(MainFnAddr.toPtr<MainTy>(), Args); } +Expected<int32_t> +SelfExecutorProcessControl::runAsVoidFunction(ExecutorAddr VoidFnAddr) { + using VoidTy = int (*)(); + return orc::runAsVoidFunction(VoidFnAddr.toPtr<VoidTy>()); +} + +Expected<int32_t> +SelfExecutorProcessControl::runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) { + using IntTy = int (*)(int); + return orc::runAsIntFunction(IntFnAddr.toPtr<IntTy>(), Arg); +} + void SelfExecutorProcessControl::callWrapperAsync(ExecutorAddr WrapperFnAddr, IncomingWFRHandler SendResult, ArrayRef<char> ArgBuffer) { diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp index 38cab526704f..989bb094cc25 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp @@ -137,6 +137,11 @@ createLocalCompileCallbackManager(const Triple &T, ExecutionSession &ES, return CCMgrT::Create(ES, ErrorHandlerAddress); } + case Triple::loongarch64: { + typedef orc::LocalJITCompileCallbackManager<orc::OrcLoongArch64> CCMgrT; + return CCMgrT::Create(ES, ErrorHandlerAddress); + } + case Triple::mips: { typedef orc::LocalJITCompileCallbackManager<orc::OrcMips32Be> CCMgrT; return CCMgrT::Create(ES, ErrorHandlerAddress); @@ -192,6 +197,12 @@ createLocalIndirectStubsManagerBuilder(const Triple &T) { orc::LocalIndirectStubsManager<orc::OrcI386>>(); }; + case Triple::loongarch64: + return []() { + return std::make_unique< + orc::LocalIndirectStubsManager<orc::OrcLoongArch64>>(); + }; + case Triple::mips: return [](){ return std::make_unique< @@ -407,7 +418,7 @@ Error addFunctionPointerRelocationsToCurrentSymbol(jitlink::Symbol &Sym, auto SymStartInBlock = (const uint8_t *)B.getContent().data() + Sym.getOffset(); auto SymSize = Sym.getSize() ? Sym.getSize() : B.getSize() - Sym.getOffset(); - auto Content = makeArrayRef(SymStartInBlock, SymSize); + auto Content = ArrayRef(SymStartInBlock, SymSize); LLVM_DEBUG(dbgs() << "Adding self-relocations to " << Sym.getName() << "\n"); diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp index 1926ef1ecc72..bc84988e3254 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp @@ -9,12 +9,14 @@ #include "llvm/ExecutionEngine/Orc/LLJIT.h" #include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h" #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h" +#include "llvm/ExecutionEngine/Orc/EPCEHFrameRegistrar.h" #include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" #include "llvm/ExecutionEngine/Orc/MachOPlatform.h" #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" #include "llvm/ExecutionEngine/Orc/ObjectTransformLayer.h" #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" #include "llvm/ExecutionEngine/Orc/Shared/OrcError.h" +#include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/IRBuilder.h" @@ -81,6 +83,53 @@ Function *addHelperAndWrapper(Module &M, StringRef WrapperName, return WrapperFn; } +class ORCPlatformSupport : public LLJIT::PlatformSupport { +public: + ORCPlatformSupport(orc::LLJIT &J) : J(J) {} + + Error initialize(orc::JITDylib &JD) override { + using llvm::orc::shared::SPSExecutorAddr; + using llvm::orc::shared::SPSString; + using SPSDLOpenSig = SPSExecutorAddr(SPSString, int32_t); + enum dlopen_mode : int32_t { + ORC_RT_RTLD_LAZY = 0x1, + ORC_RT_RTLD_NOW = 0x2, + ORC_RT_RTLD_LOCAL = 0x4, + ORC_RT_RTLD_GLOBAL = 0x8 + }; + + if (auto WrapperAddr = J.lookup("__orc_rt_jit_dlopen_wrapper")) { + return J.getExecutionSession().callSPSWrapper<SPSDLOpenSig>( + *WrapperAddr, DSOHandles[&JD], JD.getName(), + int32_t(ORC_RT_RTLD_LAZY)); + } else + return WrapperAddr.takeError(); + } + + Error deinitialize(orc::JITDylib &JD) override { + using llvm::orc::shared::SPSExecutorAddr; + using SPSDLCloseSig = int32_t(SPSExecutorAddr); + + if (auto WrapperAddr = J.lookup("__orc_rt_jit_dlclose_wrapper")) { + int32_t result; + auto E = J.getExecutionSession().callSPSWrapper<SPSDLCloseSig>( + *WrapperAddr, result, DSOHandles[&JD]); + if (E) + return E; + else if (result) + return make_error<StringError>("dlclose failed", + inconvertibleErrorCode()); + DSOHandles.erase(&JD); + } else + return WrapperAddr.takeError(); + return Error::success(); + } + +private: + orc::LLJIT &J; + DenseMap<orc::JITDylib *, orc::ExecutorAddr> DSOHandles; +}; + class GenericLLVMIRPlatformSupport; /// orc::Platform component of Generic LLVM IR Platform support. @@ -667,6 +716,7 @@ Error LLJITBuilderState::prepareForConstruction() { if (!CreateObjectLinkingLayer) { auto &TT = JTMB->getTargetTriple(); if (TT.getArch() == Triple::riscv64 || + TT.getArch() == Triple::loongarch64 || (TT.isOSBinFormatMachO() && (TT.getArch() == Triple::aarch64 || TT.getArch() == Triple::x86_64))) { @@ -676,8 +726,12 @@ Error LLJITBuilderState::prepareForConstruction() { [](ExecutionSession &ES, const Triple &) -> Expected<std::unique_ptr<ObjectLayer>> { auto ObjLinkingLayer = std::make_unique<ObjectLinkingLayer>(ES); - ObjLinkingLayer->addPlugin(std::make_unique<EHFrameRegistrationPlugin>( - ES, std::make_unique<jitlink::InProcessEHFrameRegistrar>())); + if (auto EHFrameRegistrar = EPCEHFrameRegistrar::Create(ES)) + ObjLinkingLayer->addPlugin( + std::make_unique<EHFrameRegistrationPlugin>( + ES, std::move(*EHFrameRegistrar))); + else + return EHFrameRegistrar.takeError(); return std::move(ObjLinkingLayer); }; } @@ -746,6 +800,11 @@ LLJIT::createObjectLinkingLayer(LLJITBuilderState &S, ExecutionSession &ES) { Layer->setAutoClaimResponsibilityForObjectSymbols(true); } + if (S.JTMB->getTargetTriple().isOSBinFormatELF() && + (S.JTMB->getTargetTriple().getArch() == Triple::ArchType::ppc64 || + S.JTMB->getTargetTriple().getArch() == Triple::ArchType::ppc64le)) + Layer->setAutoClaimResponsibilityForObjectSymbols(true); + // FIXME: Explicit conversion to std::unique_ptr<ObjectLayer> added to silence // errors from some GCC / libstdc++ bots. Remove this conversion (i.e. // just return ObjLinkingLayer) once those bots are upgraded. @@ -875,6 +934,13 @@ Error LLJIT::applyDataLayout(Module &M) { return Error::success(); } +Error setUpOrcPlatform(LLJIT& J) { + LLVM_DEBUG( + { dbgs() << "Setting up orc platform support for LLJIT\n"; }); + J.setPlatformSupport(std::make_unique<ORCPlatformSupport>(J)); + return Error::success(); +} + void setUpGenericLLVMIRPlatform(LLJIT &J) { LLVM_DEBUG( { dbgs() << "Setting up GenericLLVMIRPlatform support for LLJIT\n"; }); @@ -950,5 +1016,12 @@ LLLazyJIT::LLLazyJIT(LLLazyJITBuilderState &S, Error &Err) : LLJIT(S, Err) { CODLayer->setCloneToNewContextOnEmit(true); } +// In-process LLJIT uses eh-frame section wrappers via EPC, so we need to force +// them to be linked in. +LLVM_ATTRIBUTE_USED void linkComponents() { + errs() << (void *)&llvm_orc_registerEHFrameSectionWrapper + << (void *)&llvm_orc_deregisterEHFrameSectionWrapper; +} + } // End namespace orc. } // End namespace llvm. diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/Layer.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/Layer.cpp index 4a50f2d7a153..95380d912392 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/Layer.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/Layer.cpp @@ -77,11 +77,14 @@ IRMaterializationUnit::IRMaterializationUnit( // Otherwise we just need a normal linker mangling. auto MangledName = Mangle(G.getName()); SymbolFlags[MangledName] = JITSymbolFlags::fromGlobalValue(G); + if (G.getComdat() && + G.getComdat()->getSelectionKind() != Comdat::NoDeduplicate) + SymbolFlags[MangledName] |= JITSymbolFlags::Weak; SymbolToDefinition[MangledName] = &G; } // If we need an init symbol for this module then create one. - if (!llvm::empty(getStaticInitGVs(M))) { + if (!getStaticInitGVs(M).empty()) { size_t Counter = 0; do { diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp index 20b655bdf4b1..c0a740d42dbd 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp @@ -119,6 +119,10 @@ createLocalLazyCallThroughManager(const Triple &T, ExecutionSession &ES, case Triple::x86: return LocalLazyCallThroughManager::Create<OrcI386>(ES, ErrorHandlerAddr); + case Triple::loongarch64: + return LocalLazyCallThroughManager::Create<OrcLoongArch64>( + ES, ErrorHandlerAddr); + case Triple::mips: return LocalLazyCallThroughManager::Create<OrcMips32Be>(ES, ErrorHandlerAddr); diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/LookupAndRecordAddrs.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/LookupAndRecordAddrs.cpp index 3452267e4df4..59c63d38458b 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/LookupAndRecordAddrs.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/LookupAndRecordAddrs.cpp @@ -73,7 +73,7 @@ Error lookupAndRecordAddrs( inconvertibleErrorCode()); for (unsigned I = 0; I != Pairs.size(); ++I) - Pairs[I].second->setValue(Result->front()[I]); + *Pairs[I].second = Result->front()[I]; return Error::success(); } diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp index d5274b06a76f..914a1b5afc71 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp @@ -15,6 +15,7 @@ #include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.h" #include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/Debug.h" +#include <optional> #define DEBUG_TYPE "orc" @@ -57,6 +58,29 @@ public: namespace { +std::unique_ptr<jitlink::LinkGraph> createPlatformGraph(MachOPlatform &MOP, + std::string Name) { + unsigned PointerSize; + support::endianness Endianness; + const auto &TT = + MOP.getExecutionSession().getExecutorProcessControl().getTargetTriple(); + + switch (TT.getArch()) { + case Triple::aarch64: + case Triple::x86_64: + PointerSize = 8; + Endianness = support::endianness::little; + break; + default: + llvm_unreachable("Unrecognized architecture"); + } + + return std::make_unique<jitlink::LinkGraph>(std::move(Name), TT, PointerSize, + Endianness, + jitlink::getGenericEdgeKindName); +} + +// Generates a MachO header. class MachOHeaderMaterializationUnit : public MaterializationUnit { public: MachOHeaderMaterializationUnit(MachOPlatform &MOP, @@ -67,41 +91,28 @@ public: StringRef getName() const override { return "MachOHeaderMU"; } void materialize(std::unique_ptr<MaterializationResponsibility> R) override { - unsigned PointerSize; - support::endianness Endianness; - const auto &TT = - MOP.getExecutionSession().getExecutorProcessControl().getTargetTriple(); + auto G = createPlatformGraph(MOP, "<MachOHeaderMU>"); + addMachOHeader(*G, MOP, R->getInitializerSymbol()); + MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G)); + } - switch (TT.getArch()) { - case Triple::aarch64: - case Triple::x86_64: - PointerSize = 8; - Endianness = support::endianness::little; - break; - default: - llvm_unreachable("Unrecognized architecture"); - } + void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {} - auto G = std::make_unique<jitlink::LinkGraph>( - "<MachOHeaderMU>", TT, PointerSize, Endianness, - jitlink::getGenericEdgeKindName); - auto &HeaderSection = G->createSection("__header", jitlink::MemProt::Read); - auto &HeaderBlock = createHeaderBlock(*G, HeaderSection); + static void addMachOHeader(jitlink::LinkGraph &G, MachOPlatform &MOP, + const SymbolStringPtr &InitializerSymbol) { + auto &HeaderSection = G.createSection("__header", MemProt::Read); + auto &HeaderBlock = createHeaderBlock(G, HeaderSection); // Init symbol is header-start symbol. - G->addDefinedSymbol(HeaderBlock, 0, *R->getInitializerSymbol(), - HeaderBlock.getSize(), jitlink::Linkage::Strong, - jitlink::Scope::Default, false, true); + G.addDefinedSymbol(HeaderBlock, 0, *InitializerSymbol, + HeaderBlock.getSize(), jitlink::Linkage::Strong, + jitlink::Scope::Default, false, true); for (auto &HS : AdditionalHeaderSymbols) - G->addDefinedSymbol(HeaderBlock, HS.Offset, HS.Name, - HeaderBlock.getSize(), jitlink::Linkage::Strong, - jitlink::Scope::Default, false, true); - - MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G)); + G.addDefinedSymbol(HeaderBlock, HS.Offset, HS.Name, HeaderBlock.getSize(), + jitlink::Linkage::Strong, jitlink::Scope::Default, + false, true); } - void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {} - private: struct HeaderSymbol { const char *Name; @@ -163,7 +174,82 @@ private: constexpr MachOHeaderMaterializationUnit::HeaderSymbol MachOHeaderMaterializationUnit::AdditionalHeaderSymbols[]; +// Creates a Bootstrap-Complete LinkGraph to run deferred actions. +class MachOPlatformCompleteBootstrapMaterializationUnit + : public MaterializationUnit { +public: + MachOPlatformCompleteBootstrapMaterializationUnit( + MachOPlatform &MOP, StringRef PlatformJDName, + SymbolStringPtr CompleteBootstrapSymbol, shared::AllocActions DeferredAAs, + ExecutorAddr PlatformBootstrap, ExecutorAddr PlatformShutdown, + ExecutorAddr RegisterJITDylib, ExecutorAddr DeregisterJITDylib, + ExecutorAddr MachOHeaderAddr) + : MaterializationUnit( + {{{CompleteBootstrapSymbol, JITSymbolFlags::None}}, nullptr}), + MOP(MOP), PlatformJDName(PlatformJDName), + CompleteBootstrapSymbol(std::move(CompleteBootstrapSymbol)), + DeferredAAs(std::move(DeferredAAs)), + PlatformBootstrap(PlatformBootstrap), + PlatformShutdown(PlatformShutdown), RegisterJITDylib(RegisterJITDylib), + DeregisterJITDylib(DeregisterJITDylib), + MachOHeaderAddr(MachOHeaderAddr) {} + + StringRef getName() const override { + return "MachOPlatformCompleteBootstrap"; + } + + void materialize(std::unique_ptr<MaterializationResponsibility> R) override { + using namespace jitlink; + auto G = createPlatformGraph(MOP, "<OrcRTCompleteBootstrap>"); + auto &PlaceholderSection = + G->createSection("__orc_rt_cplt_bs", MemProt::Read); + auto &PlaceholderBlock = + G->createZeroFillBlock(PlaceholderSection, 1, ExecutorAddr(), 1, 0); + G->addDefinedSymbol(PlaceholderBlock, 0, *CompleteBootstrapSymbol, 1, + Linkage::Strong, Scope::Hidden, false, true); + + // Reserve space for the stolen actions, plus two extras. + G->allocActions().reserve(DeferredAAs.size() + 2); + + // 1. Bootstrap the platform support code. + G->allocActions().push_back( + {cantFail(WrapperFunctionCall::Create<SPSArgList<>>(PlatformBootstrap)), + cantFail( + WrapperFunctionCall::Create<SPSArgList<>>(PlatformShutdown))}); + + // 2. Register the platform JITDylib. + G->allocActions().push_back( + {cantFail(WrapperFunctionCall::Create< + SPSArgList<SPSString, SPSExecutorAddr>>( + RegisterJITDylib, PlatformJDName, MachOHeaderAddr)), + cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>( + DeregisterJITDylib, MachOHeaderAddr))}); + + // 3. Add the deferred actions to the graph. + std::move(DeferredAAs.begin(), DeferredAAs.end(), + std::back_inserter(G->allocActions())); + + MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G)); + } + + void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {} + +private: + MachOPlatform &MOP; + StringRef PlatformJDName; + SymbolStringPtr CompleteBootstrapSymbol; + shared::AllocActions DeferredAAs; + ExecutorAddr PlatformBootstrap; + ExecutorAddr PlatformShutdown; + ExecutorAddr RegisterJITDylib; + ExecutorAddr DeregisterJITDylib; + ExecutorAddr MachOHeaderAddr; +}; + +StringRef DataCommonSectionName = "__DATA,__common"; +StringRef DataDataSectionName = "__DATA,__data"; StringRef EHFrameSectionName = "__TEXT,__eh_frame"; +StringRef CompactUnwindInfoSectionName = "__TEXT,__unwind_info"; StringRef ModInitFuncSectionName = "__DATA,__mod_init_func"; StringRef ObjCClassListSectionName = "__DATA,__objc_classlist"; StringRef ObjCImageInfoSectionName = "__DATA,__objc_image_info"; @@ -187,7 +273,7 @@ namespace orc { Expected<std::unique_ptr<MachOPlatform>> MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD, const char *OrcRuntimePath, - Optional<SymbolAliasMap> RuntimeAliases) { + std::optional<SymbolAliasMap> RuntimeAliases) { auto &EPC = ES.getExecutorProcessControl(); @@ -335,52 +421,115 @@ MachOPlatform::MachOPlatform( ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD, std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, Error &Err) - : ES(ES), ObjLinkingLayer(ObjLinkingLayer), - MachOHeaderStartSymbol(ES.intern("___dso_handle")) { + : ES(ES), PlatformJD(PlatformJD), ObjLinkingLayer(ObjLinkingLayer) { ErrorAsOutParameter _(&Err); - ObjLinkingLayer.addPlugin(std::make_unique<MachOPlatformPlugin>(*this)); - PlatformJD.addGenerator(std::move(OrcRuntimeGenerator)); - // Force linking of eh-frame registration functions. - if (auto Err2 = lookupAndRecordAddrs( - ES, LookupKind::Static, makeJITDylibSearchOrder(&PlatformJD), - {{ES.intern("___orc_rt_macho_register_ehframe_section"), - &orc_rt_macho_register_ehframe_section}, - {ES.intern("___orc_rt_macho_deregister_ehframe_section"), - &orc_rt_macho_deregister_ehframe_section}})) { - Err = std::move(Err2); + BootstrapInfo BI; + Bootstrap = &BI; + + // Bootstrap process -- here be phase-ordering dragons. + // + // The MachOPlatform class uses allocation actions to register metadata + // sections with the ORC runtime, however the runtime contains metadata + // registration functions that have their own metadata that they need to + // register (e.g. the frame-info registration functions have frame-info). + // We can't use an ordinary lookup to find these registration functions + // because their address is needed during the link of the containing graph + // itself (to build the allocation actions that will call the registration + // functions). Further complicating the situation (a) the graph containing + // the registration functions is allowed to depend on other graphs (e.g. the + // graph containing the ORC runtime RTTI support) so we need to handle with + // an unknown set of dependencies during bootstrap, and (b) these graphs may + // be linked concurrently if the user has installed a concurrent dispatcher. + // + // We satisfy these constraint by implementing a bootstrap phase during which + // allocation actions generated by MachOPlatform are appended to a list of + // deferred allocation actions, rather than to the graphs themselves. At the + // end of the bootstrap process the deferred actions are attached to a final + // "complete-bootstrap" graph that causes them to be run. + // + // The bootstrap steps are as follows: + // + // 1. Request the graph containing the mach header. This graph is guaranteed + // not to have any metadata so the fact that the registration functions + // are not available yet is not a problem. + // + // 2. Look up the registration functions and discard the results. This will + // trigger linking of the graph containing these functions, and + // consequently any graphs that it depends on. We do not use the lookup + // result to find the addresses of the functions requested (as described + // above the lookup will return too late for that), instead we capture the + // addresses in a post-allocation pass injected by the platform runtime + // during bootstrap only. + // + // 3. During bootstrap the MachOPlatformPlugin keeps a count of the number of + // graphs being linked (potentially concurrently), and we block until all + // of these graphs have completed linking. This is to avoid a race on the + // deferred-actions vector: the lookup for the runtime registration + // functions may return while some functions (those that are being + // incidentally linked in, but aren't reachable via the runtime functions) + // are still being linked, and we need to capture any allocation actions + // for this incidental code before we proceed. + // + // 4. Once all active links are complete we transfer the deferred actions to + // a newly added CompleteBootstrap graph and then request a symbol from + // the CompleteBootstrap graph to trigger materialization. This will cause + // all deferred actions to be run, and once this lookup returns we can + // proceed. + // + // 5. Finally, we associate runtime support methods in MachOPlatform with + // the corresponding jit-dispatch tag variables in the ORC runtime to make + // the support methods callable. The bootstrap is now complete. + + // Step (1) Add header materialization unit and request. + if ((Err = PlatformJD.define(std::make_unique<MachOHeaderMaterializationUnit>( + *this, MachOHeaderStartSymbol)))) return; - } - - State = BootstrapPhase2; - - // Associate wrapper function tags with JIT-side function implementations. - if (auto E2 = associateRuntimeSupportFunctions(PlatformJD)) { - Err = std::move(E2); + if ((Err = ES.lookup(&PlatformJD, MachOHeaderStartSymbol).takeError())) return; - } - // Lookup addresses of runtime functions callable by the platform, - // call the platform bootstrap function to initialize the platform-state - // object in the executor. - if (auto E2 = bootstrapMachORuntime(PlatformJD)) { - Err = std::move(E2); + // Step (2) Request runtime registration functions to trigger + // materialization.. + if ((Err = ES.lookup(makeJITDylibSearchOrder(&PlatformJD), + SymbolLookupSet( + {PlatformBootstrap.Name, PlatformShutdown.Name, + RegisterJITDylib.Name, DeregisterJITDylib.Name, + RegisterObjectPlatformSections.Name, + DeregisterObjectPlatformSections.Name, + CreatePThreadKey.Name})) + .takeError())) return; + + // Step (3) Wait for any incidental linker work to complete. + { + std::unique_lock<std::mutex> Lock(BI.Mutex); + BI.CV.wait(Lock, [&]() { return BI.ActiveGraphs == 0; }); + Bootstrap = nullptr; } - // PlatformJD hasn't been set up by the platform yet (since we're creating - // the platform now), so set it up. - if (auto E2 = setupJITDylib(PlatformJD)) { - Err = std::move(E2); + // Step (4) Add complete-bootstrap materialization unit and request. + auto BootstrapCompleteSymbol = ES.intern("__orc_rt_macho_complete_bootstrap"); + if ((Err = PlatformJD.define( + std::make_unique<MachOPlatformCompleteBootstrapMaterializationUnit>( + *this, PlatformJD.getName(), BootstrapCompleteSymbol, + std::move(BI.DeferredAAs), PlatformBootstrap.Addr, + PlatformShutdown.Addr, RegisterJITDylib.Addr, + DeregisterJITDylib.Addr, BI.MachOHeaderAddr)))) + return; + if ((Err = ES.lookup(makeJITDylibSearchOrder( + &PlatformJD, JITDylibLookupFlags::MatchAllSymbols), + std::move(BootstrapCompleteSymbol)) + .takeError())) return; - } - State = Initialized; + // (5) Associate runtime support functions. + if ((Err = associateRuntimeSupportFunctions())) + return; } -Error MachOPlatform::associateRuntimeSupportFunctions(JITDylib &PlatformJD) { +Error MachOPlatform::associateRuntimeSupportFunctions() { ExecutionSession::JITDispatchHandlerAssociationMap WFs; using PushInitializersSPSSig = @@ -440,24 +589,17 @@ void MachOPlatform::pushInitializersLoop( if (NewInitSymbols.empty()) { // To make the list intelligible to the runtime we need to convert all - // JITDylib pointers to their header addresses. + // JITDylib pointers to their header addresses. Only include JITDylibs + // that appear in the JITDylibToHeaderAddr map (i.e. those that have been + // through setupJITDylib) -- bare JITDylibs aren't managed by the platform. DenseMap<JITDylib *, ExecutorAddr> HeaderAddrs; HeaderAddrs.reserve(JDDepMap.size()); { std::lock_guard<std::mutex> Lock(PlatformMutex); for (auto &KV : JDDepMap) { auto I = JITDylibToHeaderAddr.find(KV.first); - if (I == JITDylibToHeaderAddr.end()) { - // The header address should have been materialized by the previous - // round, but we need to handle the pathalogical case where someone - // removes the symbol on another thread while we're running. - SendResult( - make_error<StringError>("JITDylib " + KV.first->getName() + - " has no registered header address", - inconvertibleErrorCode())); - return; - } - HeaderAddrs[KV.first] = I->second; + if (I != JITDylibToHeaderAddr.end()) + HeaderAddrs[KV.first] = I->second; } } @@ -465,12 +607,16 @@ void MachOPlatform::pushInitializersLoop( MachOJITDylibDepInfoMap DIM; DIM.reserve(JDDepMap.size()); for (auto &KV : JDDepMap) { - assert(HeaderAddrs.count(KV.first) && "Missing header addr"); - auto H = HeaderAddrs[KV.first]; + auto HI = HeaderAddrs.find(KV.first); + // Skip unmanaged JITDylibs. + if (HI == HeaderAddrs.end()) + continue; + auto H = HI->second; MachOJITDylibDepInfo DepInfo; for (auto &Dep : KV.second) { - assert(HeaderAddrs.count(Dep) && "Missing header addr"); - DepInfo.DepHeaders.push_back(HeaderAddrs[Dep]); + auto HJ = HeaderAddrs.find(Dep); + if (HJ != HeaderAddrs.end()) + DepInfo.DepHeaders.push_back(HJ->second); } DIM.push_back(std::make_pair(H, std::move(DepInfo))); } @@ -480,7 +626,7 @@ void MachOPlatform::pushInitializersLoop( // Otherwise issue a lookup and re-run this phase when it completes. lookupInitSymbolsAsync( - [this, SendResult = std::move(SendResult), &JD](Error Err) mutable { + [this, SendResult = std::move(SendResult), JD](Error Err) mutable { if (Err) SendResult(std::move(Err)); else @@ -571,30 +717,8 @@ void MachOPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult, RtLookupNotifyComplete(std::move(SendResult)), NoDependenciesToRegister); } -Error MachOPlatform::bootstrapMachORuntime(JITDylib &PlatformJD) { - if (auto Err = lookupAndRecordAddrs( - ES, LookupKind::Static, makeJITDylibSearchOrder(&PlatformJD), - {{ES.intern("___orc_rt_macho_platform_bootstrap"), - &orc_rt_macho_platform_bootstrap}, - {ES.intern("___orc_rt_macho_platform_shutdown"), - &orc_rt_macho_platform_shutdown}, - {ES.intern("___orc_rt_macho_register_jitdylib"), - &orc_rt_macho_register_jitdylib}, - {ES.intern("___orc_rt_macho_deregister_jitdylib"), - &orc_rt_macho_deregister_jitdylib}, - {ES.intern("___orc_rt_macho_register_object_platform_sections"), - &orc_rt_macho_register_object_platform_sections}, - {ES.intern("___orc_rt_macho_deregister_object_platform_sections"), - &orc_rt_macho_deregister_object_platform_sections}, - {ES.intern("___orc_rt_macho_create_pthread_key"), - &orc_rt_macho_create_pthread_key}})) - return Err; - - return ES.callSPSWrapper<void()>(orc_rt_macho_platform_bootstrap); -} - Expected<uint64_t> MachOPlatform::createPThreadKey() { - if (!orc_rt_macho_create_pthread_key) + if (!CreatePThreadKey.Addr) return make_error<StringError>( "Attempting to create pthread key in target, but runtime support has " "not been loaded yet", @@ -602,7 +726,7 @@ Expected<uint64_t> MachOPlatform::createPThreadKey() { Expected<uint64_t> Result(0); if (auto Err = ES.callSPSWrapper<SPSExpected<uint64_t>(void)>( - orc_rt_macho_create_pthread_key, Result)) + CreatePThreadKey.Addr, Result)) return std::move(Err); return Result; } @@ -611,7 +735,19 @@ void MachOPlatform::MachOPlatformPlugin::modifyPassConfig( MaterializationResponsibility &MR, jitlink::LinkGraph &LG, jitlink::PassConfiguration &Config) { - auto PS = MP.State.load(); + using namespace jitlink; + + bool InBootstrapPhase = + &MR.getTargetJITDylib() == &MP.PlatformJD && MP.Bootstrap; + + // If we're in the bootstrap phase then increment the active graphs. + if (InBootstrapPhase) { + Config.PrePrunePasses.push_back( + [this](LinkGraph &G) { return bootstrapPipelineStart(G); }); + Config.PostAllocationPasses.push_back([this](LinkGraph &G) { + return bootstrapPipelineRecordRuntimeFunctions(G); + }); + } // --- Handle Initializers --- if (auto InitSymbol = MR.getInitializerSymbol()) { @@ -619,8 +755,8 @@ void MachOPlatform::MachOPlatformPlugin::modifyPassConfig( // If the initializer symbol is the MachOHeader start symbol then just // register it and then bail out -- the header materialization unit // definitely doesn't need any other passes. - if (InitSymbol == MP.MachOHeaderStartSymbol) { - Config.PostAllocationPasses.push_back([this, &MR](jitlink::LinkGraph &G) { + if (InitSymbol == MP.MachOHeaderStartSymbol && !InBootstrapPhase) { + Config.PostAllocationPasses.push_back([this, &MR](LinkGraph &G) { return associateJITDylibHeaderSymbol(G, MR); }); return; @@ -629,34 +765,33 @@ void MachOPlatform::MachOPlatformPlugin::modifyPassConfig( // If the object contains an init symbol other than the header start symbol // then add passes to preserve, process and register the init // sections/symbols. - Config.PrePrunePasses.push_back([this, &MR](jitlink::LinkGraph &G) { + Config.PrePrunePasses.push_back([this, &MR](LinkGraph &G) { if (auto Err = preserveInitSections(G, MR)) return Err; return processObjCImageInfo(G, MR); }); } - // --- Add passes for eh-frame and TLV support --- - if (PS == MachOPlatform::BootstrapPhase1) { - Config.PostFixupPasses.push_back( - [this](jitlink::LinkGraph &G) { return registerEHSectionsPhase1(G); }); - return; - } - // Insert TLV lowering at the start of the PostPrunePasses, since we want // it to run before GOT/PLT lowering. Config.PostPrunePasses.insert( Config.PostPrunePasses.begin(), - [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) { + [this, &JD = MR.getTargetJITDylib()](LinkGraph &G) { return fixTLVSectionsAndEdges(G, JD); }); // Add a pass to register the final addresses of any special sections in the // object with the runtime. Config.PostAllocationPasses.push_back( - [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) { - return registerObjectPlatformSections(G, JD); + [this, &JD = MR.getTargetJITDylib(), InBootstrapPhase](LinkGraph &G) { + return registerObjectPlatformSections(G, JD, InBootstrapPhase); }); + + // If we're in the bootstrap phase then steal allocation actions and then + // decrement the active graphs. + if (InBootstrapPhase) + Config.PostFixupPasses.push_back( + [this](LinkGraph &G) { return bootstrapPipelineEnd(G); }); } ObjectLinkingLayer::Plugin::SyntheticSymbolDependenciesMap @@ -673,6 +808,73 @@ MachOPlatform::MachOPlatformPlugin::getSyntheticSymbolDependencies( return SyntheticSymbolDependenciesMap(); } +Error MachOPlatform::MachOPlatformPlugin::bootstrapPipelineStart( + jitlink::LinkGraph &G) { + // Increment the active graphs count in BootstrapInfo. + std::lock_guard<std::mutex> Lock(MP.Bootstrap.load()->Mutex); + ++MP.Bootstrap.load()->ActiveGraphs; + return Error::success(); +} + +Error MachOPlatform::MachOPlatformPlugin:: + bootstrapPipelineRecordRuntimeFunctions(jitlink::LinkGraph &G) { + // Record bootstrap function names. + std::pair<StringRef, ExecutorAddr *> RuntimeSymbols[] = { + {*MP.MachOHeaderStartSymbol, &MP.Bootstrap.load()->MachOHeaderAddr}, + {*MP.PlatformBootstrap.Name, &MP.PlatformBootstrap.Addr}, + {*MP.PlatformShutdown.Name, &MP.PlatformShutdown.Addr}, + {*MP.RegisterJITDylib.Name, &MP.RegisterJITDylib.Addr}, + {*MP.DeregisterJITDylib.Name, &MP.DeregisterJITDylib.Addr}, + {*MP.RegisterObjectPlatformSections.Name, + &MP.RegisterObjectPlatformSections.Addr}, + {*MP.DeregisterObjectPlatformSections.Name, + &MP.DeregisterObjectPlatformSections.Addr}, + {*MP.CreatePThreadKey.Name, &MP.CreatePThreadKey.Addr}}; + + bool RegisterMachOHeader = false; + + for (auto *Sym : G.defined_symbols()) { + for (auto &RTSym : RuntimeSymbols) { + if (Sym->hasName() && Sym->getName() == RTSym.first) { + if (*RTSym.second) + return make_error<StringError>( + "Duplicate " + RTSym.first + + " detected during MachOPlatform bootstrap", + inconvertibleErrorCode()); + + if (Sym->getName() == *MP.MachOHeaderStartSymbol) + RegisterMachOHeader = true; + + *RTSym.second = Sym->getAddress(); + } + } + } + + if (RegisterMachOHeader) { + // If this graph defines the macho header symbol then create the internal + // mapping between it and PlatformJD. + std::lock_guard<std::mutex> Lock(MP.PlatformMutex); + MP.JITDylibToHeaderAddr[&MP.PlatformJD] = + MP.Bootstrap.load()->MachOHeaderAddr; + MP.HeaderAddrToJITDylib[MP.Bootstrap.load()->MachOHeaderAddr] = + &MP.PlatformJD; + } + + return Error::success(); +} + +Error MachOPlatform::MachOPlatformPlugin::bootstrapPipelineEnd( + jitlink::LinkGraph &G) { + std::lock_guard<std::mutex> Lock(MP.Bootstrap.load()->Mutex); + assert(MP.Bootstrap && "DeferredAAs reset before bootstrap completed"); + --MP.Bootstrap.load()->ActiveGraphs; + // Notify Bootstrap->CV while holding the mutex because the mutex is + // also keeping Bootstrap->CV alive. + if (MP.Bootstrap.load()->ActiveGraphs == 0) + MP.Bootstrap.load()->CV.notify_all(); + return Error::success(); +} + Error MachOPlatform::MachOPlatformPlugin::associateJITDylibHeaderSymbol( jitlink::LinkGraph &G, MaterializationResponsibility &MR) { auto I = llvm::find_if(G.defined_symbols(), [this](jitlink::Symbol *Sym) { @@ -685,12 +887,14 @@ Error MachOPlatform::MachOPlatformPlugin::associateJITDylibHeaderSymbol( auto HeaderAddr = (*I)->getAddress(); MP.JITDylibToHeaderAddr[&JD] = HeaderAddr; MP.HeaderAddrToJITDylib[HeaderAddr] = &JD; + // We can unconditionally add these actions to the Graph because this pass + // isn't used during bootstrap. G.allocActions().push_back( {cantFail( WrapperFunctionCall::Create<SPSArgList<SPSString, SPSExecutorAddr>>( - MP.orc_rt_macho_register_jitdylib, JD.getName(), HeaderAddr)), + MP.RegisterJITDylib.Addr, JD.getName(), HeaderAddr)), cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>( - MP.orc_rt_macho_deregister_jitdylib, HeaderAddr))}); + MP.DeregisterJITDylib.Addr, HeaderAddr))}); return Error::success(); } @@ -747,7 +951,7 @@ Error MachOPlatform::MachOPlatformPlugin::processObjCImageInfo( auto ObjCImageInfoBlocks = ObjCImageInfo->blocks(); // Check that the section is not empty if present. - if (llvm::empty(ObjCImageInfoBlocks)) + if (ObjCImageInfoBlocks.empty()) return make_error<StringError>("Empty " + ObjCImageInfoSectionName + " section in " + G.getName(), inconvertibleErrorCode()); @@ -821,7 +1025,7 @@ Error MachOPlatform::MachOPlatformPlugin::fixTLVSectionsAndEdges( // Store key in __thread_vars struct fields. if (auto *ThreadDataSec = G.findSectionByName(ThreadVarsSectionName)) { - Optional<uint64_t> Key; + std::optional<uint64_t> Key; { std::lock_guard<std::mutex> Lock(MP.PlatformMutex); auto I = MP.JITDylibToPThreadKey.find(&JD); @@ -865,22 +1069,84 @@ Error MachOPlatform::MachOPlatformPlugin::fixTLVSectionsAndEdges( return Error::success(); } -Error MachOPlatform::MachOPlatformPlugin::registerObjectPlatformSections( - jitlink::LinkGraph &G, JITDylib &JD) { +std::optional<MachOPlatform::MachOPlatformPlugin::UnwindSections> +MachOPlatform::MachOPlatformPlugin::findUnwindSectionInfo( + jitlink::LinkGraph &G) { + using namespace jitlink; - // Add an action to register the eh-frame. - if (auto *EHFrameSection = G.findSectionByName(EHFrameSectionName)) { - jitlink::SectionRange R(*EHFrameSection); - if (!R.empty()) - G.allocActions().push_back( - {cantFail( - WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>( - MP.orc_rt_macho_register_ehframe_section, R.getRange())), - cantFail( - WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>( - MP.orc_rt_macho_deregister_ehframe_section, R.getRange()))}); + UnwindSections US; + + // ScanSection records a section range and adds any executable blocks that + // that section points to to the CodeBlocks vector. + SmallVector<Block *> CodeBlocks; + auto ScanUnwindInfoSection = [&](Section &Sec, ExecutorAddrRange &SecRange) { + if (Sec.blocks().empty()) + return; + SecRange = (*Sec.blocks().begin())->getRange(); + for (auto *B : Sec.blocks()) { + auto R = B->getRange(); + SecRange.Start = std::min(SecRange.Start, R.Start); + SecRange.End = std::max(SecRange.End, R.End); + for (auto &E : B->edges()) { + if (!E.getTarget().isDefined()) + continue; + auto &TargetBlock = E.getTarget().getBlock(); + auto &TargetSection = TargetBlock.getSection(); + if ((TargetSection.getMemProt() & MemProt::Exec) == MemProt::Exec) + CodeBlocks.push_back(&TargetBlock); + } + } + }; + + if (Section *EHFrameSec = G.findSectionByName(EHFrameSectionName)) + ScanUnwindInfoSection(*EHFrameSec, US.DwarfSection); + + if (Section *CUInfoSec = G.findSectionByName(CompactUnwindInfoSectionName)) + ScanUnwindInfoSection(*CUInfoSec, US.CompactUnwindSection); + + // If we didn't find any pointed-to code-blocks then there's no need to + // register any info. + if (CodeBlocks.empty()) + return std::nullopt; + + // We have info to register. Sort the code blocks into address order and + // build a list of contiguous address ranges covering them all. + llvm::sort(CodeBlocks, [](const Block *LHS, const Block *RHS) { + return LHS->getAddress() < RHS->getAddress(); + }); + for (auto *B : CodeBlocks) { + if (US.CodeRanges.empty() || US.CodeRanges.back().End != B->getAddress()) + US.CodeRanges.push_back(B->getRange()); + else + US.CodeRanges.back().End = B->getRange().End; } + LLVM_DEBUG({ + dbgs() << "MachOPlatform identified unwind info in " << G.getName() << ":\n" + << " DWARF: "; + if (US.DwarfSection.Start) + dbgs() << US.DwarfSection << "\n"; + else + dbgs() << "none\n"; + dbgs() << " Compact-unwind: "; + if (US.CompactUnwindSection.Start) + dbgs() << US.CompactUnwindSection << "\n"; + else + dbgs() << "none\n" + << "for code ranges:\n"; + for (auto &CR : US.CodeRanges) + dbgs() << " " << CR << "\n"; + if (US.CodeRanges.size() >= G.sections_size()) + dbgs() << "WARNING: High number of discontiguous code ranges! " + "Padding may be interfering with coalescing.\n"; + }); + + return US; +} + +Error MachOPlatform::MachOPlatformPlugin::registerObjectPlatformSections( + jitlink::LinkGraph &G, JITDylib &JD, bool InBootstrapPhase) { + // Get a pointer to the thread data section if there is one. It will be used // below. jitlink::Section *ThreadDataSection = @@ -899,18 +1165,23 @@ Error MachOPlatform::MachOPlatformPlugin::registerObjectPlatformSections( SmallVector<std::pair<StringRef, ExecutorAddrRange>, 8> MachOPlatformSecs; + // Collect data sections to register. + StringRef DataSections[] = {DataDataSectionName, DataCommonSectionName, + EHFrameSectionName}; + for (auto &SecName : DataSections) { + if (auto *Sec = G.findSectionByName(SecName)) { + jitlink::SectionRange R(*Sec); + if (!R.empty()) + MachOPlatformSecs.push_back({SecName, R.getRange()}); + } + } + // Having merged thread BSS (if present) and thread data (if present), // record the resulting section range. if (ThreadDataSection) { jitlink::SectionRange R(*ThreadDataSection); - if (!R.empty()) { - if (MP.State != MachOPlatform::Initialized) - return make_error<StringError>("__thread_data section encountered, but " - "MachOPlatform has not finished booting", - inconvertibleErrorCode()); - + if (!R.empty()) MachOPlatformSecs.push_back({ThreadDataSectionName, R.getRange()}); - } } // If any platform sections were found then add an allocation action to call @@ -933,19 +1204,23 @@ Error MachOPlatform::MachOPlatformPlugin::registerObjectPlatformSections( MachOPlatformSecs.push_back({SecName, R.getRange()}); } - if (!MachOPlatformSecs.empty()) { - Optional<ExecutorAddr> HeaderAddr; + std::optional<std::tuple<SmallVector<ExecutorAddrRange>, ExecutorAddrRange, + ExecutorAddrRange>> + UnwindInfo; + if (auto UI = findUnwindSectionInfo(G)) + UnwindInfo = std::make_tuple(std::move(UI->CodeRanges), UI->DwarfSection, + UI->CompactUnwindSection); + + if (!MachOPlatformSecs.empty() || UnwindInfo) { + ExecutorAddr HeaderAddr; { std::lock_guard<std::mutex> Lock(MP.PlatformMutex); auto I = MP.JITDylibToHeaderAddr.find(&JD); - if (I != MP.JITDylibToHeaderAddr.end()) - HeaderAddr = I->second; + assert(I != MP.JITDylibToHeaderAddr.end() && + "Missing header for JITDylib"); + HeaderAddr = I->second; } - if (!HeaderAddr) - return make_error<StringError>("Missing header for " + JD.getName(), - inconvertibleErrorCode()); - // Dump the scraped inits. LLVM_DEBUG({ dbgs() << "MachOPlatform: Scraped " << G.getName() << " init sections:\n"; @@ -953,71 +1228,29 @@ Error MachOPlatform::MachOPlatformPlugin::registerObjectPlatformSections( dbgs() << " " << KV.first << ": " << KV.second << "\n"; }); - using SPSRegisterObjectPlatformSectionsArgs = - SPSArgList<SPSExecutorAddr, - SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRange>>>; - G.allocActions().push_back( + using SPSRegisterObjectPlatformSectionsArgs = SPSArgList< + SPSExecutorAddr, + SPSOptional<SPSTuple<SPSSequence<SPSExecutorAddrRange>, + SPSExecutorAddrRange, SPSExecutorAddrRange>>, + SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRange>>>; + + shared::AllocActions &allocActions = LLVM_LIKELY(!InBootstrapPhase) + ? G.allocActions() + : MP.Bootstrap.load()->DeferredAAs; + + allocActions.push_back( {cantFail( WrapperFunctionCall::Create<SPSRegisterObjectPlatformSectionsArgs>( - MP.orc_rt_macho_register_object_platform_sections, *HeaderAddr, + MP.RegisterObjectPlatformSections.Addr, HeaderAddr, UnwindInfo, MachOPlatformSecs)), cantFail( WrapperFunctionCall::Create<SPSRegisterObjectPlatformSectionsArgs>( - MP.orc_rt_macho_deregister_object_platform_sections, - *HeaderAddr, MachOPlatformSecs))}); + MP.DeregisterObjectPlatformSections.Addr, HeaderAddr, + UnwindInfo, MachOPlatformSecs))}); } return Error::success(); } -Error MachOPlatform::MachOPlatformPlugin::registerEHSectionsPhase1( - jitlink::LinkGraph &G) { - - // If there's no eh-frame there's nothing to do. - auto *EHFrameSection = G.findSectionByName(EHFrameSectionName); - if (!EHFrameSection) - return Error::success(); - - // If the eh-frame section is empty there's nothing to do. - jitlink::SectionRange R(*EHFrameSection); - if (R.empty()) - return Error::success(); - - // Since we're linking the object containing the registration code now the - // addresses won't be ready in the platform. We'll have to find them in this - // graph instead. - ExecutorAddr orc_rt_macho_register_ehframe_section; - ExecutorAddr orc_rt_macho_deregister_ehframe_section; - for (auto *Sym : G.defined_symbols()) { - if (!Sym->hasName()) - continue; - if (Sym->getName() == "___orc_rt_macho_register_ehframe_section") - orc_rt_macho_register_ehframe_section = ExecutorAddr(Sym->getAddress()); - else if (Sym->getName() == "___orc_rt_macho_deregister_ehframe_section") - orc_rt_macho_deregister_ehframe_section = ExecutorAddr(Sym->getAddress()); - - if (orc_rt_macho_register_ehframe_section && - orc_rt_macho_deregister_ehframe_section) - break; - } - - // If we failed to find the required functions then bail out. - if (!orc_rt_macho_register_ehframe_section || - !orc_rt_macho_deregister_ehframe_section) - return make_error<StringError>("Could not find eh-frame registration " - "functions during platform bootstrap", - inconvertibleErrorCode()); - - // Otherwise, add allocation actions to the graph to register eh-frames for - // this object. - G.allocActions().push_back( - {cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>( - orc_rt_macho_register_ehframe_section, R.getRange())), - cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>( - orc_rt_macho_deregister_ehframe_section, R.getRange()))}); - - return Error::success(); -} - } // End namespace orc. } // End namespace llvm. diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/MapperJITLinkMemoryManager.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/MapperJITLinkMemoryManager.cpp index c2e7baabb994..d099a251232e 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/MapperJITLinkMemoryManager.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/MapperJITLinkMemoryManager.cpp @@ -8,11 +8,10 @@ #include "llvm/ExecutionEngine/Orc/MapperJITLinkMemoryManager.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ExecutionEngine/JITLink/JITLink.h" #include "llvm/Support/Process.h" -#include <limits> - using namespace llvm::jitlink; namespace llvm { @@ -33,7 +32,8 @@ public: std::swap(AI.Segments, Segs); std::swap(AI.Actions, G.allocActions()); - Parent.Mapper->initialize(AI, [&](Expected<ExecutorAddr> Result) { + Parent.Mapper->initialize(AI, [OnFinalize = std::move(OnFinalize)]( + Expected<ExecutorAddr> Result) mutable { if (!Result) { OnFinalize(Result.takeError()); return; @@ -55,8 +55,9 @@ private: }; MapperJITLinkMemoryManager::MapperJITLinkMemoryManager( - std::unique_ptr<MemoryMapper> Mapper) - : Mapper(std::move(Mapper)) {} + size_t ReservationGranularity, std::unique_ptr<MemoryMapper> Mapper) + : ReservationUnits(ReservationGranularity), AvailableMemory(AMAllocator), + Mapper(std::move(Mapper)) {} void MapperJITLinkMemoryManager::allocate(const JITLinkDylib *JD, LinkGraph &G, OnAllocatedFunction OnAllocated) { @@ -69,55 +70,78 @@ void MapperJITLinkMemoryManager::allocate(const JITLinkDylib *JD, LinkGraph &G, return; } - // Check if total size fits in address space - if (SegsSizes->total() > std::numeric_limits<size_t>::max()) { - OnAllocated(make_error<JITLinkError>( - formatv("Total requested size {:x} for graph {} exceeds address space", - SegsSizes->total(), G.getName()))); - return; - } + auto TotalSize = SegsSizes->total(); + + auto CompleteAllocation = [this, &G, BL = std::move(BL), + OnAllocated = std::move(OnAllocated)]( + Expected<ExecutorAddrRange> Result) mutable { + if (!Result) { + Mutex.unlock(); + return OnAllocated(Result.takeError()); + } + + auto NextSegAddr = Result->Start; + + std::vector<MemoryMapper::AllocInfo::SegInfo> SegInfos; + + for (auto &KV : BL.segments()) { + auto &AG = KV.first; + auto &Seg = KV.second; - Mapper->reserve( - SegsSizes->total(), - [this, &G, BL = std::move(BL), OnAllocated = std::move(OnAllocated)]( - Expected<ExecutorAddrRange> Result) mutable { - if (!Result) { - return OnAllocated(Result.takeError()); - } + auto TotalSize = Seg.ContentSize + Seg.ZeroFillSize; - auto NextSegAddr = Result->Start; + Seg.Addr = NextSegAddr; + Seg.WorkingMem = Mapper->prepare(NextSegAddr, TotalSize); - std::vector<MemoryMapper::AllocInfo::SegInfo> SegInfos; + NextSegAddr += alignTo(TotalSize, Mapper->getPageSize()); - for (auto &KV : BL.segments()) { - auto &AG = KV.first; - auto &Seg = KV.second; + MemoryMapper::AllocInfo::SegInfo SI; + SI.Offset = Seg.Addr - Result->Start; + SI.ContentSize = Seg.ContentSize; + SI.ZeroFillSize = Seg.ZeroFillSize; + SI.AG = AG; + SI.WorkingMem = Seg.WorkingMem; - auto TotalSize = Seg.ContentSize + Seg.ZeroFillSize; + SegInfos.push_back(SI); + } - Seg.Addr = NextSegAddr; - Seg.WorkingMem = Mapper->prepare(NextSegAddr, TotalSize); + UsedMemory.insert({Result->Start, NextSegAddr - Result->Start}); - NextSegAddr += alignTo(TotalSize, Mapper->getPageSize()); + if (NextSegAddr < Result->End) { + // Save the remaining memory for reuse in next allocation(s) + AvailableMemory.insert(NextSegAddr, Result->End - 1, true); + } + Mutex.unlock(); - MemoryMapper::AllocInfo::SegInfo SI; - SI.Offset = Seg.Addr - Result->Start; - SI.ContentSize = Seg.ContentSize; - SI.ZeroFillSize = Seg.ZeroFillSize; - SI.Prot = (toSysMemoryProtectionFlags(AG.getMemProt())); - SI.WorkingMem = Seg.WorkingMem; + if (auto Err = BL.apply()) { + OnAllocated(std::move(Err)); + return; + } - SegInfos.push_back(SI); - } + OnAllocated(std::make_unique<InFlightAlloc>(*this, G, Result->Start, + std::move(SegInfos))); + }; - if (auto Err = BL.apply()) { - OnAllocated(std::move(Err)); - return; - } + Mutex.lock(); - OnAllocated(std::make_unique<InFlightAlloc>(*this, G, Result->Start, - std::move(SegInfos))); - }); + // find an already reserved range that is large enough + ExecutorAddrRange SelectedRange{}; + + for (AvailableMemoryMap::iterator It = AvailableMemory.begin(); + It != AvailableMemory.end(); It++) { + if (It.stop() - It.start() + 1 >= TotalSize) { + SelectedRange = ExecutorAddrRange(It.start(), It.stop() + 1); + It.erase(); + break; + } + } + + if (SelectedRange.empty()) { // no already reserved range was found + auto TotalAllocation = alignTo(TotalSize, ReservationUnits); + Mapper->reserve(TotalAllocation, std::move(CompleteAllocation)); + } else { + CompleteAllocation(SelectedRange); + } } void MapperJITLinkMemoryManager::deallocate( @@ -125,10 +149,40 @@ void MapperJITLinkMemoryManager::deallocate( std::vector<ExecutorAddr> Bases; Bases.reserve(Allocs.size()); for (auto &FA : Allocs) { - Bases.push_back(FA.getAddress()); - FA.release(); + ExecutorAddr Addr = FA.getAddress(); + Bases.push_back(Addr); } - Mapper->release(Bases, std::move(OnDeallocated)); + + Mapper->deinitialize(Bases, [this, Allocs = std::move(Allocs), + OnDeallocated = std::move(OnDeallocated)]( + llvm::Error Err) mutable { + // TODO: How should we treat memory that we fail to deinitialize? + // We're currently bailing out and treating it as "burned" -- should we + // require that a failure to deinitialize still reset the memory so that + // we can reclaim it? + if (Err) { + for (auto &FA : Allocs) + FA.release(); + OnDeallocated(std::move(Err)); + return; + } + + { + std::lock_guard<std::mutex> Lock(Mutex); + + for (auto &FA : Allocs) { + ExecutorAddr Addr = FA.getAddress(); + ExecutorAddrDiff Size = UsedMemory[Addr]; + + UsedMemory.erase(Addr); + AvailableMemory.insert(Addr, Addr + Size - 1, true); + + FA.release(); + } + } + + OnDeallocated(Error::success()); + }); } } // end namespace orc diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/MemoryMapper.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/MemoryMapper.cpp index ee92e5191b50..b457c7297bed 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/MemoryMapper.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/MemoryMapper.cpp @@ -11,6 +11,8 @@ #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h" #include "llvm/Support/WindowsError.h" +#include <algorithm> + #if defined(LLVM_ON_UNIX) && !defined(__ANDROID__) #include <fcntl.h> #include <sys/mman.h> @@ -60,7 +62,9 @@ char *InProcessMemoryMapper::prepare(ExecutorAddr Addr, size_t ContentSize) { void InProcessMemoryMapper::initialize(MemoryMapper::AllocInfo &AI, OnInitializedFunction OnInitialized) { ExecutorAddr MinAddr(~0ULL); + ExecutorAddr MaxAddr(0); + // FIXME: Release finalize lifetime segments. for (auto &Segment : AI.Segments) { auto Base = AI.MappingBase + Segment.Offset; auto Size = Segment.ContentSize + Segment.ZeroFillSize; @@ -68,14 +72,18 @@ void InProcessMemoryMapper::initialize(MemoryMapper::AllocInfo &AI, if (Base < MinAddr) MinAddr = Base; + if (Base + Size > MaxAddr) + MaxAddr = Base + Size; + std::memset((Base + Segment.ContentSize).toPtr<void *>(), 0, Segment.ZeroFillSize); - if (auto EC = sys::Memory::protectMappedMemory({Base.toPtr<void *>(), Size}, - Segment.Prot)) { + if (auto EC = sys::Memory::protectMappedMemory( + {Base.toPtr<void *>(), Size}, + toSysMemoryProtectionFlags(Segment.AG.getMemProt()))) { return OnInitialized(errorCodeToError(EC)); } - if (Segment.Prot & sys::Memory::MF_EXEC) + if ((Segment.AG.getMemProt() & MemProt::Exec) == MemProt::Exec) sys::Memory::InvalidateInstructionCache(Base.toPtr<void *>(), Size); } @@ -85,6 +93,9 @@ void InProcessMemoryMapper::initialize(MemoryMapper::AllocInfo &AI, { std::lock_guard<std::mutex> Lock(Mutex); + + // This is the maximum range whose permission have been possibly modified + Allocations[MinAddr].Size = MaxAddr - MinAddr; Allocations[MinAddr].DeinitializationActions = std::move(*DeinitializeActions); Reservations[AI.MappingBase.toPtr<void *>()].Allocations.push_back(MinAddr); @@ -101,13 +112,21 @@ void InProcessMemoryMapper::deinitialize( { std::lock_guard<std::mutex> Lock(Mutex); - for (auto Base : Bases) { + for (auto Base : llvm::reverse(Bases)) { if (Error Err = shared::runDeallocActions( Allocations[Base].DeinitializationActions)) { AllErr = joinErrors(std::move(AllErr), std::move(Err)); } + // Reset protections to read/write so the area can be reused + if (auto EC = sys::Memory::protectMappedMemory( + {Base.toPtr<void *>(), Allocations[Base].Size}, + sys::Memory::ProtectionFlags::MF_READ | + sys::Memory::ProtectionFlags::MF_WRITE)) { + AllErr = joinErrors(std::move(AllErr), errorCodeToError(EC)); + } + Allocations.erase(Base); } } @@ -275,7 +294,7 @@ void SharedMemoryMapper::reserve(size_t NumBytes, char *SharedMemoryMapper::prepare(ExecutorAddr Addr, size_t ContentSize) { auto R = Reservations.upper_bound(Addr); - assert(R != Reservations.begin() && "Attempt to prepare unknown range"); + assert(R != Reservations.begin() && "Attempt to prepare unreserved range"); R--; ExecutorAddrDiff Offset = Addr - R->first; @@ -285,9 +304,11 @@ char *SharedMemoryMapper::prepare(ExecutorAddr Addr, size_t ContentSize) { void SharedMemoryMapper::initialize(MemoryMapper::AllocInfo &AI, OnInitializedFunction OnInitialized) { - auto Reservation = Reservations.find(AI.MappingBase); - assert(Reservation != Reservations.end() && - "Attempt to initialize unreserved range"); + auto Reservation = Reservations.upper_bound(AI.MappingBase); + assert(Reservation != Reservations.begin() && "Attempt to initialize unreserved range"); + Reservation--; + + auto AllocationOffset = AI.MappingBase - Reservation->first; tpctypes::SharedMemoryFinalizeRequest FR; @@ -296,13 +317,12 @@ void SharedMemoryMapper::initialize(MemoryMapper::AllocInfo &AI, FR.Segments.reserve(AI.Segments.size()); for (auto Segment : AI.Segments) { - char *Base = - static_cast<char *>(Reservation->second.LocalAddr) + Segment.Offset; + char *Base = static_cast<char *>(Reservation->second.LocalAddr) + + AllocationOffset + Segment.Offset; std::memset(Base + Segment.ContentSize, 0, Segment.ZeroFillSize); tpctypes::SharedMemorySegFinalizeRequest SegReq; - SegReq.Prot = tpctypes::toWireProtectionFlags( - static_cast<sys::Memory::ProtectionFlags>(Segment.Prot)); + SegReq.AG = Segment.AG; SegReq.Addr = AI.MappingBase + Segment.Offset; SegReq.Size = Segment.ContentSize + Segment.ZeroFillSize; @@ -321,7 +341,7 @@ void SharedMemoryMapper::initialize(MemoryMapper::AllocInfo &AI, OnInitialized(std::move(Result)); }, - SAs.Instance, AI.MappingBase, std::move(FR)); + SAs.Instance, Reservation->first, std::move(FR)); } void SharedMemoryMapper::deinitialize( @@ -392,23 +412,23 @@ void SharedMemoryMapper::release(ArrayRef<ExecutorAddr> Bases, } SharedMemoryMapper::~SharedMemoryMapper() { - std::vector<ExecutorAddr> ReservationAddrs; - if (!Reservations.empty()) { - std::lock_guard<std::mutex> Lock(Mutex); - { - ReservationAddrs.reserve(Reservations.size()); - for (const auto &R : Reservations) { - ReservationAddrs.push_back(R.first); - } - } - } + std::lock_guard<std::mutex> Lock(Mutex); + for (const auto &R : Reservations) { - std::promise<MSVCPError> P; - auto F = P.get_future(); - release(ReservationAddrs, [&](Error Err) { P.set_value(std::move(Err)); }); - // FIXME: Release can actually fail. The error should be propagated. - // Meanwhile, a better option is to explicitly call release(). - cantFail(F.get()); +#if defined(LLVM_ON_UNIX) && !defined(__ANDROID__) + + munmap(R.second.LocalAddr, R.second.Size); + +#elif defined(_WIN32) + + UnmapViewOfFile(R.second.LocalAddr); + +#else + + (void)R; + +#endif + } } } // namespace orc diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp index 3de15db3f1c6..0c3beba43a35 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h" +#include "llvm/ExecutionEngine/Orc/COFFPlatform.h" #include "llvm/ExecutionEngine/Orc/ELFNixPlatform.h" #include "llvm/ExecutionEngine/Orc/MachOPlatform.h" #include "llvm/Object/COFF.h" @@ -14,6 +15,7 @@ #include "llvm/Object/MachO.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Debug.h" +#include <optional> #define DEBUG_TYPE "orc" @@ -150,7 +152,7 @@ static Expected<MaterializationUnit::Interface> getCOFFObjectFileSymbolInfo(ExecutionSession &ES, const object::COFFObjectFile &Obj) { MaterializationUnit::Interface I; - std::vector<Optional<object::coff_aux_section_definition>> ComdatDefs( + std::vector<std::optional<object::coff_aux_section_definition>> ComdatDefs( Obj.getNumberOfSections() + 1); for (auto &Sym : Obj.symbols()) { Expected<uint32_t> SymFlagsOrErr = Sym.getFlags(); @@ -177,7 +179,7 @@ getCOFFObjectFileSymbolInfo(ExecutionSession &ES, if (Def->Selection != COFF::IMAGE_COMDAT_SELECT_NODUPLICATES) { IsWeak = true; } - ComdatDefs[COFFSym.getSectionNumber()] = None; + ComdatDefs[COFFSym.getSectionNumber()] = std::nullopt; } else { // Skip symbols not defined in this object file. if (*SymFlagsOrErr & object::BasicSymbolRef::SF_Undefined) @@ -214,7 +216,16 @@ getCOFFObjectFileSymbolInfo(ExecutionSession &ES, I.SymbolFlags[ES.intern(*Name)] = std::move(*SymFlags); } - // FIXME: handle init symbols + SymbolStringPtr InitSymbol; + for (auto &Sec : Obj.sections()) { + if (auto SecName = Sec.getName()) { + if (COFFPlatform::isInitializerSection(*SecName)) { + addInitSymbol(I, ES, Obj.getFileName()); + break; + } + } else + return SecName.takeError(); + } return I; } @@ -276,5 +287,22 @@ getObjectFileInterface(ExecutionSession &ES, MemoryBufferRef ObjBuffer) { return getGenericObjectFileSymbolInfo(ES, **Obj); } +bool hasInitializerSection(jitlink::LinkGraph &G) { + bool IsMachO = G.getTargetTriple().isOSBinFormatMachO(); + bool IsElf = G.getTargetTriple().isOSBinFormatELF(); + if (!IsMachO && !IsElf) + return false; + + for (auto &Sec : G.sections()) { + if (IsMachO && std::apply(MachOPlatform::isInitializerSection, + Sec.getName().split(","))) + return true; + if (IsElf && ELFNixPlatform::isInitializerSection(Sec.getName())) + return true; + } + + return false; +} + } // End namespace orc. } // End namespace llvm. diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp index 5ddb35cbafd5..2b11c472e812 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp @@ -7,9 +7,9 @@ //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" -#include "llvm/ADT/Optional.h" #include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h" #include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h" +#include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h" #include "llvm/Support/MemoryBuffer.h" #include <string> #include <vector> @@ -58,35 +58,12 @@ private: LGI.SymbolFlags[ES.intern(Sym->getName())] = Flags; } - if ((G.getTargetTriple().isOSBinFormatMachO() && hasMachOInitSection(G)) || - (G.getTargetTriple().isOSBinFormatELF() && hasELFInitSection(G))) + if (hasInitializerSection(G)) LGI.InitSymbol = makeInitSymbol(ES, G); return LGI; } - static bool hasMachOInitSection(LinkGraph &G) { - for (auto &Sec : G.sections()) - if (Sec.getName() == "__DATA,__obj_selrefs" || - Sec.getName() == "__DATA,__objc_classlist" || - Sec.getName() == "__TEXT,__swift5_protos" || - Sec.getName() == "__TEXT,__swift5_proto" || - Sec.getName() == "__TEXT,__swift5_types" || - Sec.getName() == "__DATA,__mod_init_func") - return true; - return false; - } - - static bool hasELFInitSection(LinkGraph &G) { - for (auto &Sec : G.sections()) { - auto SecName = Sec.getName(); - if (SecName.consume_front(".init_array") && - (SecName.empty() || SecName[0] == '.')) - return true; - } - return false; - } - static SymbolStringPtr makeInitSymbol(ExecutionSession &ES, LinkGraph &G) { std::string InitSymString; raw_string_ostream(InitSymString) @@ -218,6 +195,8 @@ public: Flags |= JITSymbolFlags::Callable; if (Sym->getScope() == Scope::Default) Flags |= JITSymbolFlags::Exported; + if (Sym->getLinkage() == Linkage::Weak) + Flags |= JITSymbolFlags::Weak; InternedResult[InternedName] = JITEvaluatedSymbol(Sym->getAddress().getValue(), Flags); @@ -447,9 +426,15 @@ private: // claim, at which point we'll externalize that symbol. cantFail(MR->defineMaterializing(std::move(NewSymbolsToClaim))); - for (auto &KV : NameToSym) - if (!MR->getSymbols().count(KV.first)) + // Walk the list of symbols that we just tried to claim. Symbols that we're + // responsible for are marked live. Symbols that we're not responsible for + // are turned into external references. + for (auto &KV : NameToSym) { + if (MR->getSymbols().count(KV.first)) + KV.second->setLive(true); + else G.makeExternal(*KV.second); + } return Error::success(); } @@ -537,7 +522,8 @@ private: for (auto *B : G.blocks()) { auto &BI = BlockInfos[B]; for (auto &E : B->edges()) { - if (E.getTarget().getScope() == Scope::Local) { + if (E.getTarget().getScope() == Scope::Local && + !E.getTarget().isAbsolute()) { auto &TgtB = E.getTarget().getBlock(); if (&TgtB != B) { BI.Dependencies.insert(&TgtB); @@ -694,12 +680,12 @@ Error ObjectLinkingLayer::notifyEmitted(MaterializationResponsibility &MR, [&](ResourceKey K) { Allocs[K].push_back(std::move(FA)); }); } -Error ObjectLinkingLayer::handleRemoveResources(ResourceKey K) { +Error ObjectLinkingLayer::handleRemoveResources(JITDylib &JD, ResourceKey K) { { Error Err = Error::success(); for (auto &P : Plugins) - Err = joinErrors(std::move(Err), P->notifyRemovingResources(K)); + Err = joinErrors(std::move(Err), P->notifyRemovingResources(JD, K)); if (Err) return Err; } @@ -719,7 +705,8 @@ Error ObjectLinkingLayer::handleRemoveResources(ResourceKey K) { return MemMgr.deallocate(std::move(AllocsToRemove)); } -void ObjectLinkingLayer::handleTransferResources(ResourceKey DstKey, +void ObjectLinkingLayer::handleTransferResources(JITDylib &JD, + ResourceKey DstKey, ResourceKey SrcKey) { auto I = Allocs.find(SrcKey); if (I != Allocs.end()) { @@ -735,7 +722,7 @@ void ObjectLinkingLayer::handleTransferResources(ResourceKey DstKey, } for (auto &P : Plugins) - P->notifyTransferringResources(DstKey, SrcKey); + P->notifyTransferringResources(JD, DstKey, SrcKey); } EHFrameRegistrationPlugin::EHFrameRegistrationPlugin( @@ -787,7 +774,8 @@ Error EHFrameRegistrationPlugin::notifyFailed( return Error::success(); } -Error EHFrameRegistrationPlugin::notifyRemovingResources(ResourceKey K) { +Error EHFrameRegistrationPlugin::notifyRemovingResources(JITDylib &JD, + ResourceKey K) { std::vector<ExecutorAddrRange> RangesToRemove; ES.runSessionLocked([&] { @@ -811,7 +799,7 @@ Error EHFrameRegistrationPlugin::notifyRemovingResources(ResourceKey K) { } void EHFrameRegistrationPlugin::notifyTransferringResources( - ResourceKey DstKey, ResourceKey SrcKey) { + JITDylib &JD, ResourceKey DstKey, ResourceKey SrcKey) { auto SI = EHFrameRanges.find(SrcKey); if (SI == EHFrameRanges.end()) return; diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/OrcABISupport.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/OrcABISupport.cpp index da8aaad08cad..48dd0df80415 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/OrcABISupport.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/OrcABISupport.cpp @@ -1077,5 +1077,158 @@ void OrcRiscv64::writeIndirectStubsBlock( } } +void OrcLoongArch64::writeResolverCode(char *ResolverWorkingMem, + JITTargetAddress ResolverTargetAddress, + JITTargetAddress ReentryFnAddr, + JITTargetAddress ReentryCtxAddr) { + + LLVM_DEBUG({ + dbgs() << "Writing resolver code to " + << formatv("{0:x16}", ResolverTargetAddress) << "\n"; + }); + + const uint32_t ResolverCode[] = { + 0x02fde063, // 0x0: addi.d $sp, $sp, -136(0xf78) + 0x29c00061, // 0x4: st.d $ra, $sp, 0 + 0x29c02064, // 0x8: st.d $a0, $sp, 8(0x8) + 0x29c04065, // 0xc: st.d $a1, $sp, 16(0x10) + 0x29c06066, // 0x10: st.d $a2, $sp, 24(0x18) + 0x29c08067, // 0x14: st.d $a3, $sp, 32(0x20) + 0x29c0a068, // 0x18: st.d $a4, $sp, 40(0x28) + 0x29c0c069, // 0x1c: st.d $a5, $sp, 48(0x30) + 0x29c0e06a, // 0x20: st.d $a6, $sp, 56(0x38) + 0x29c1006b, // 0x24: st.d $a7, $sp, 64(0x40) + 0x2bc12060, // 0x28: fst.d $fa0, $sp, 72(0x48) + 0x2bc14061, // 0x2c: fst.d $fa1, $sp, 80(0x50) + 0x2bc16062, // 0x30: fst.d $fa2, $sp, 88(0x58) + 0x2bc18063, // 0x34: fst.d $fa3, $sp, 96(0x60) + 0x2bc1a064, // 0x38: fst.d $fa4, $sp, 104(0x68) + 0x2bc1c065, // 0x3c: fst.d $fa5, $sp, 112(0x70) + 0x2bc1e066, // 0x40: fst.d $fa6, $sp, 120(0x78) + 0x2bc20067, // 0x44: fst.d $fa7, $sp, 128(0x80) + 0x1c000004, // 0x48: pcaddu12i $a0, 0 + 0x28c1c084, // 0x4c: ld.d $a0, $a0, 112(0x70) + 0x001501a5, // 0x50: move $a1, $t1 + 0x02ffd0a5, // 0x54: addi.d $a1, $a1, -12(0xff4) + 0x1c000006, // 0x58: pcaddu12i $a2, 0 + 0x28c1a0c6, // 0x5c: ld.d $a2, $a2, 104(0x68) + 0x4c0000c1, // 0x60: jirl $ra, $a2, 0 + 0x0015008c, // 0x64: move $t0, $a0 + 0x2b820067, // 0x68: fld.d $fa7, $sp, 128(0x80) + 0x2b81e066, // 0x6c: fld.d $fa6, $sp, 120(0x78) + 0x2b81c065, // 0x70: fld.d $fa5, $sp, 112(0x70) + 0x2b81a064, // 0x74: fld.d $fa4, $sp, 104(0x68) + 0x2b818063, // 0x78: fld.d $fa3, $sp, 96(0x60) + 0x2b816062, // 0x7c: fld.d $fa2, $sp, 88(0x58) + 0x2b814061, // 0x80: fld.d $fa1, $sp, 80(0x50) + 0x2b812060, // 0x84: fld.d $fa0, $sp, 72(0x48) + 0x28c1006b, // 0x88: ld.d $a7, $sp, 64(0x40) + 0x28c0e06a, // 0x8c: ld.d $a6, $sp, 56(0x38) + 0x28c0c069, // 0x90: ld.d $a5, $sp, 48(0x30) + 0x28c0a068, // 0x94: ld.d $a4, $sp, 40(0x28) + 0x28c08067, // 0x98: ld.d $a3, $sp, 32(0x20) + 0x28c06066, // 0x9c: ld.d $a2, $sp, 24(0x18) + 0x28c04065, // 0xa0: ld.d $a1, $sp, 16(0x10) + 0x28c02064, // 0xa4: ld.d $a0, $sp, 8(0x8) + 0x28c00061, // 0xa8: ld.d $ra, $sp, 0 + 0x02c22063, // 0xac: addi.d $sp, $sp, 136(0x88) + 0x4c000180, // 0xb0: jr $t0 + 0x00000000, // 0xb4: padding to align at 8 bytes + 0x01234567, // 0xb8: Lreentry_ctx_ptr: + 0xdeedbeef, // 0xbc: .dword 0 + 0x98765432, // 0xc0: Lreentry_fn_ptr: + 0xcafef00d, // 0xc4: .dword 0 + }; + + const unsigned ReentryCtxAddrOffset = 0xb8; + const unsigned ReentryFnAddrOffset = 0xc0; + + memcpy(ResolverWorkingMem, ResolverCode, sizeof(ResolverCode)); + memcpy(ResolverWorkingMem + ReentryFnAddrOffset, &ReentryFnAddr, + sizeof(uint64_t)); + memcpy(ResolverWorkingMem + ReentryCtxAddrOffset, &ReentryCtxAddr, + sizeof(uint64_t)); +} + +void OrcLoongArch64::writeTrampolines( + char *TrampolineBlockWorkingMem, + JITTargetAddress TrampolineBlockTargetAddress, + JITTargetAddress ResolverAddr, unsigned NumTrampolines) { + + LLVM_DEBUG({ + dbgs() << "Writing trampoline code to " + << formatv("{0:x16}", TrampolineBlockTargetAddress) << "\n"; + }); + + unsigned OffsetToPtr = alignTo(NumTrampolines * TrampolineSize, 8); + + memcpy(TrampolineBlockWorkingMem + OffsetToPtr, &ResolverAddr, + sizeof(uint64_t)); + + uint32_t *Trampolines = + reinterpret_cast<uint32_t *>(TrampolineBlockWorkingMem); + for (unsigned I = 0; I < NumTrampolines; ++I, OffsetToPtr -= TrampolineSize) { + uint32_t Hi20 = (OffsetToPtr + 0x800) & 0xfffff000; + uint32_t Lo12 = OffsetToPtr - Hi20; + Trampolines[4 * I + 0] = + 0x1c00000c | + (((Hi20 >> 12) & 0xfffff) << 5); // pcaddu12i $t0, %pc_hi20(Lptr) + Trampolines[4 * I + 1] = + 0x28c0018c | ((Lo12 & 0xfff) << 10); // ld.d $t0, $t0, %pc_lo12(Lptr) + Trampolines[4 * I + 2] = 0x4c00018d; // jirl $t1, $t0, 0 + Trampolines[4 * I + 3] = 0x0; // padding + } +} + +void OrcLoongArch64::writeIndirectStubsBlock( + char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress, + JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs) { + // Stub format is: + // + // .section __orc_stubs + // stub1: + // pcaddu12i $t0, %pc_hi20(ptr1) ; PC-rel load of ptr1 + // ld.d $t0, $t0, %pc_lo12(ptr1) + // jr $t0 ; Jump to resolver + // .dword 0 ; Pad to 16 bytes + // stub2: + // pcaddu12i $t0, %pc_hi20(ptr2) ; PC-rel load of ptr2 + // ld.d $t0, $t0, %pc_lo12(ptr2) + // jr $t0 ; Jump to resolver + // .dword 0 ; Pad to 16 bytes + // ... + // + // .section __orc_ptrs + // ptr1: + // .dword 0x0 + // ptr2: + // .dword 0x0 + // ... + LLVM_DEBUG({ + dbgs() << "Writing stubs code to " + << formatv("{0:x16}", StubsBlockTargetAddress) << "\n"; + }); + assert(stubAndPointerRangesOk<OrcLoongArch64>( + StubsBlockTargetAddress, PointersBlockTargetAddress, NumStubs) && + "PointersBlock is out of range"); + + uint32_t *Stub = reinterpret_cast<uint32_t *>(StubsBlockWorkingMem); + + for (unsigned I = 0; I < NumStubs; ++I) { + uint64_t PtrDisplacement = + PointersBlockTargetAddress - StubsBlockTargetAddress; + uint32_t Hi20 = (PtrDisplacement + 0x800) & 0xfffff000; + uint32_t Lo12 = PtrDisplacement - Hi20; + Stub[4 * I + 0] = 0x1c00000c | (((Hi20 >> 12) & 0xfffff) + << 5); // pcaddu12i $t0, %pc_hi20(Lptr) + Stub[4 * I + 1] = + 0x28c0018c | ((Lo12 & 0xfff) << 10); // ld.d $t0, $t0, %pc_lo12(Lptr) + Stub[4 * I + 2] = 0x4c000180; // jr $t0 + Stub[4 * I + 3] = 0x0; // padding + PointersBlockTargetAddress += PointerSize; + StubsBlockTargetAddress += StubSize; + } +} + } // End namespace orc. } // End namespace llvm. diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp index b7eab6b85ecf..b823197b404f 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp @@ -892,7 +892,10 @@ void LLVMOrcIRTransformLayerSetTransform( assert(!TSMRef && "TSMRef was not reset to null on error"); return unwrap(Err); } - return std::move(*unwrap(TSMRef)); + assert(TSMRef && "Transform succeeded, but TSMRef was set to null"); + ThreadSafeModule Result = std::move(*unwrap(TSMRef)); + LLVMOrcDisposeThreadSafeModule(TSMRef); + return std::move(Result); }); } @@ -1066,6 +1069,116 @@ LLVMOrcCreateRTDyldObjectLinkingLayerWithSectionMemoryManager( *unwrap(ES), [] { return std::make_unique<SectionMemoryManager>(); })); } +LLVMOrcObjectLayerRef +LLVMOrcCreateRTDyldObjectLinkingLayerWithMCJITMemoryManagerLikeCallbacks( + LLVMOrcExecutionSessionRef ES, void *CreateContextCtx, + LLVMMemoryManagerCreateContextCallback CreateContext, + LLVMMemoryManagerNotifyTerminatingCallback NotifyTerminating, + LLVMMemoryManagerAllocateCodeSectionCallback AllocateCodeSection, + LLVMMemoryManagerAllocateDataSectionCallback AllocateDataSection, + LLVMMemoryManagerFinalizeMemoryCallback FinalizeMemory, + LLVMMemoryManagerDestroyCallback Destroy) { + + struct MCJITMemoryManagerLikeCallbacks { + MCJITMemoryManagerLikeCallbacks() = default; + MCJITMemoryManagerLikeCallbacks( + void *CreateContextCtx, + LLVMMemoryManagerCreateContextCallback CreateContext, + LLVMMemoryManagerNotifyTerminatingCallback NotifyTerminating, + LLVMMemoryManagerAllocateCodeSectionCallback AllocateCodeSection, + LLVMMemoryManagerAllocateDataSectionCallback AllocateDataSection, + LLVMMemoryManagerFinalizeMemoryCallback FinalizeMemory, + LLVMMemoryManagerDestroyCallback Destroy) + : CreateContextCtx(CreateContextCtx), CreateContext(CreateContext), + NotifyTerminating(NotifyTerminating), + AllocateCodeSection(AllocateCodeSection), + AllocateDataSection(AllocateDataSection), + FinalizeMemory(FinalizeMemory), Destroy(Destroy) {} + + MCJITMemoryManagerLikeCallbacks(MCJITMemoryManagerLikeCallbacks &&Other) { + std::swap(CreateContextCtx, Other.CreateContextCtx); + std::swap(CreateContext, Other.CreateContext); + std::swap(NotifyTerminating, Other.NotifyTerminating); + std::swap(AllocateCodeSection, Other.AllocateCodeSection); + std::swap(AllocateDataSection, Other.AllocateDataSection); + std::swap(FinalizeMemory, Other.FinalizeMemory); + std::swap(Destroy, Other.Destroy); + } + + ~MCJITMemoryManagerLikeCallbacks() { + if (NotifyTerminating) + NotifyTerminating(CreateContextCtx); + } + + void *CreateContextCtx = nullptr; + LLVMMemoryManagerCreateContextCallback CreateContext = nullptr; + LLVMMemoryManagerNotifyTerminatingCallback NotifyTerminating = nullptr; + LLVMMemoryManagerAllocateCodeSectionCallback AllocateCodeSection = nullptr; + LLVMMemoryManagerAllocateDataSectionCallback AllocateDataSection = nullptr; + LLVMMemoryManagerFinalizeMemoryCallback FinalizeMemory = nullptr; + LLVMMemoryManagerDestroyCallback Destroy = nullptr; + }; + + class MCJITMemoryManagerLikeCallbacksMemMgr : public RTDyldMemoryManager { + public: + MCJITMemoryManagerLikeCallbacksMemMgr( + const MCJITMemoryManagerLikeCallbacks &CBs) + : CBs(CBs) { + Opaque = CBs.CreateContext(CBs.CreateContextCtx); + } + ~MCJITMemoryManagerLikeCallbacksMemMgr() override { CBs.Destroy(Opaque); } + + uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, + StringRef SectionName) override { + return CBs.AllocateCodeSection(Opaque, Size, Alignment, SectionID, + SectionName.str().c_str()); + } + + uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, StringRef SectionName, + bool isReadOnly) override { + return CBs.AllocateDataSection(Opaque, Size, Alignment, SectionID, + SectionName.str().c_str(), isReadOnly); + } + + bool finalizeMemory(std::string *ErrMsg) override { + char *ErrMsgCString = nullptr; + bool Result = CBs.FinalizeMemory(Opaque, &ErrMsgCString); + assert((Result || !ErrMsgCString) && + "Did not expect an error message if FinalizeMemory succeeded"); + if (ErrMsgCString) { + if (ErrMsg) + *ErrMsg = ErrMsgCString; + free(ErrMsgCString); + } + return Result; + } + + private: + const MCJITMemoryManagerLikeCallbacks &CBs; + void *Opaque = nullptr; + }; + + assert(ES && "ES must not be null"); + assert(CreateContext && "CreateContext must not be null"); + assert(NotifyTerminating && "NotifyTerminating must not be null"); + assert(AllocateCodeSection && "AllocateCodeSection must not be null"); + assert(AllocateDataSection && "AllocateDataSection must not be null"); + assert(FinalizeMemory && "FinalizeMemory must not be null"); + assert(Destroy && "Destroy must not be null"); + + MCJITMemoryManagerLikeCallbacks CBs( + CreateContextCtx, CreateContext, NotifyTerminating, AllocateCodeSection, + AllocateDataSection, FinalizeMemory, Destroy); + + return wrap(new RTDyldObjectLinkingLayer(*unwrap(ES), [CBs = std::move(CBs)] { + return std::make_unique<MCJITMemoryManagerLikeCallbacksMemMgr>(CBs); + })); + + return nullptr; +} + void LLVMOrcRTDyldObjectLinkingLayerRegisterJITEventListener( LLVMOrcObjectLayerRef RTDyldObjLinkingLayer, LLVMJITEventListenerRef Listener) { diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp index 27044f66a55d..07b19b2e54f1 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp @@ -81,7 +81,7 @@ using BaseT = RTTIExtends<RTDyldObjectLinkingLayer, ObjectLayer>; RTDyldObjectLinkingLayer::RTDyldObjectLinkingLayer( ExecutionSession &ES, GetMemoryManagerFunction GetMemoryManager) - : BaseT(ES), GetMemoryManager(GetMemoryManager) { + : BaseT(ES), GetMemoryManager(std::move(GetMemoryManager)) { ES.registerResourceManager(*this); } @@ -108,6 +108,7 @@ void RTDyldObjectLinkingLayer::emit( // filter these later. auto InternalSymbols = std::make_shared<std::set<StringRef>>(); { + SymbolFlagsMap ExtraSymbolsToClaim; for (auto &Sym : (*Obj)->symbols()) { // Skip file symbols. @@ -128,6 +129,33 @@ void RTDyldObjectLinkingLayer::emit( return; } + // Try to claim responsibility of weak symbols + // if AutoClaimObjectSymbols flag is set. + if (AutoClaimObjectSymbols && + (*SymFlagsOrErr & object::BasicSymbolRef::SF_Weak)) { + auto SymName = Sym.getName(); + if (!SymName) { + ES.reportError(SymName.takeError()); + R->failMaterialization(); + return; + } + + // Already included in responsibility set, skip it + SymbolStringPtr SymbolName = ES.intern(*SymName); + if (R->getSymbols().count(SymbolName)) + continue; + + auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym); + if (!SymFlags) { + ES.reportError(SymFlags.takeError()); + R->failMaterialization(); + return; + } + + ExtraSymbolsToClaim[SymbolName] = *SymFlags; + continue; + } + // Don't include symbols that aren't global. if (!(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global)) { if (auto SymName = Sym.getName()) @@ -139,6 +167,13 @@ void RTDyldObjectLinkingLayer::emit( } } } + + if (!ExtraSymbolsToClaim.empty()) { + if (auto Err = R->defineMaterializing(ExtraSymbolsToClaim)) { + ES.reportError(std::move(Err)); + R->failMaterialization(); + } + } } auto MemMgr = GetMemoryManager(); @@ -224,6 +259,46 @@ Error RTDyldObjectLinkingLayer::onObjLoad( if (COFFSec.Characteristics & COFF::IMAGE_SCN_LNK_COMDAT) I->second.setFlags(I->second.getFlags() | JITSymbolFlags::Weak); } + + // Handle any aliases. + for (auto &Sym : COFFObj->symbols()) { + uint32_t SymFlags = cantFail(Sym.getFlags()); + if (SymFlags & object::BasicSymbolRef::SF_Undefined) + continue; + auto Name = Sym.getName(); + if (!Name) + return Name.takeError(); + auto I = Resolved.find(*Name); + + // Skip already-resolved symbols, and symbols that we're not responsible + // for. + if (I != Resolved.end() || !R.getSymbols().count(ES.intern(*Name))) + continue; + + // Skip anything other than weak externals. + auto COFFSym = COFFObj->getCOFFSymbol(Sym); + if (!COFFSym.isWeakExternal()) + continue; + auto *WeakExternal = COFFSym.getAux<object::coff_aux_weak_external>(); + if (WeakExternal->Characteristics != COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS) + continue; + + // We found an alias. Reuse the resolution of the alias target for the + // alias itself. + Expected<object::COFFSymbolRef> TargetSymbol = + COFFObj->getSymbol(WeakExternal->TagIndex); + if (!TargetSymbol) + return TargetSymbol.takeError(); + Expected<StringRef> TargetName = COFFObj->getSymbolName(*TargetSymbol); + if (!TargetName) + return TargetName.takeError(); + auto J = Resolved.find(*TargetName); + if (J == Resolved.end()) + return make_error<StringError>("Could alias target " + *TargetName + + " not resolved", + inconvertibleErrorCode()); + Resolved[*Name] = J->second; + } } for (auto &KV : Resolved) { @@ -235,17 +310,21 @@ Error RTDyldObjectLinkingLayer::onObjLoad( auto InternedName = getExecutionSession().intern(KV.first); auto Flags = KV.second.getFlags(); - - // Override object flags and claim responsibility for symbols if - // requested. - if (OverrideObjectFlags || AutoClaimObjectSymbols) { - auto I = R.getSymbols().find(InternedName); - - if (OverrideObjectFlags && I != R.getSymbols().end()) + auto I = R.getSymbols().find(InternedName); + if (I != R.getSymbols().end()) { + // Override object flags and claim responsibility for symbols if + // requested. + if (OverrideObjectFlags) Flags = I->second; - else if (AutoClaimObjectSymbols && I == R.getSymbols().end()) - ExtraSymbolsToClaim[InternedName] = Flags; - } + else { + // RuntimeDyld/MCJIT's weak tracking isn't compatible with ORC's. Even + // if we're not overriding flags in general we should set the weak flag + // according to the MaterializationResponsibility object symbol table. + if (I->second.isWeak()) + Flags |= JITSymbolFlags::Weak; + } + } else if (AutoClaimObjectSymbols) + ExtraSymbolsToClaim[InternedName] = Flags; Symbols[InternedName] = JITEvaluatedSymbol(KV.second.getAddress(), Flags); } @@ -311,7 +390,8 @@ void RTDyldObjectLinkingLayer::onObjEmit( } } -Error RTDyldObjectLinkingLayer::handleRemoveResources(ResourceKey K) { +Error RTDyldObjectLinkingLayer::handleRemoveResources(JITDylib &JD, + ResourceKey K) { std::vector<MemoryManagerUP> MemMgrsToRemove; @@ -335,7 +415,8 @@ Error RTDyldObjectLinkingLayer::handleRemoveResources(ResourceKey K) { return Error::success(); } -void RTDyldObjectLinkingLayer::handleTransferResources(ResourceKey DstKey, +void RTDyldObjectLinkingLayer::handleTransferResources(JITDylib &JD, + ResourceKey DstKey, ResourceKey SrcKey) { auto I = MemMgrs.find(SrcKey); if (I != MemMgrs.end()) { diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/Shared/OrcError.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/Shared/OrcError.cpp index 2cc2bddeb21a..ec53338570db 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/Shared/OrcError.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/Shared/OrcError.cpp @@ -82,7 +82,7 @@ char DuplicateDefinition::ID = 0; char JITSymbolNotFound::ID = 0; std::error_code orcError(OrcErrorCode ErrCode) { - typedef std::underlying_type<OrcErrorCode>::type UT; + typedef std::underlying_type_t<OrcErrorCode> UT; return std::error_code(static_cast<UT>(ErrCode), getOrcErrCat()); } @@ -105,7 +105,7 @@ JITSymbolNotFound::JITSymbolNotFound(std::string SymbolName) : SymbolName(std::move(SymbolName)) {} std::error_code JITSymbolNotFound::convertToErrorCode() const { - typedef std::underlying_type<OrcErrorCode>::type UT; + typedef std::underlying_type_t<OrcErrorCode> UT; return std::error_code(static_cast<UT>(OrcErrorCode::JITSymbolNotFound), getOrcErrCat()); } diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp index dfdd846c46a7..86e31c52100e 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp @@ -56,6 +56,10 @@ const char *DeregisterEHFrameSectionWrapperName = "__llvm_orc_bootstrap_deregister_ehframe_section_wrapper"; const char *RunAsMainWrapperName = "__llvm_orc_bootstrap_run_as_main_wrapper"; +const char *RunAsVoidFunctionWrapperName = + "__llvm_orc_bootstrap_run_as_void_function_wrapper"; +const char *RunAsIntFunctionWrapperName = + "__llvm_orc_bootstrap_run_as_int_function_wrapper"; } // end namespace rt } // end namespace orc diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.cpp index 2bb204e688fc..921ac47d421d 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.cpp @@ -137,7 +137,7 @@ static Error makeUnexpectedEOFError() { Error FDSimpleRemoteEPCTransport::readBytes(char *Dst, size_t Size, bool *IsEOF) { - assert(Dst && "Attempt to read into null."); + assert((Size == 0 || Dst) && "Attempt to read into null."); ssize_t Completed = 0; while (Completed < static_cast<ssize_t>(Size)) { ssize_t Read = ::read(InFD, Dst + Completed, Size - Completed); @@ -167,7 +167,7 @@ Error FDSimpleRemoteEPCTransport::readBytes(char *Dst, size_t Size, } int FDSimpleRemoteEPCTransport::writeBytes(const char *Src, size_t Size) { - assert(Src && "Attempt to append from null."); + assert((Size == 0 || Src) && "Attempt to append from null."); ssize_t Completed = 0; while (Completed < static_cast<ssize_t>(Size)) { ssize_t Written = ::write(OutFD, Src + Completed, Size - Completed); diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp index 47364a92a451..1bd10c9c6c0e 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp @@ -38,7 +38,7 @@ SimpleRemoteEPC::lookupSymbols(ArrayRef<LookupRequest> Request) { Result.push_back({}); Result.back().reserve(R->size()); for (auto Addr : *R) - Result.back().push_back(Addr.getValue()); + Result.back().push_back(Addr); } else return R.takeError(); } @@ -54,6 +54,23 @@ Expected<int32_t> SimpleRemoteEPC::runAsMain(ExecutorAddr MainFnAddr, return Result; } +Expected<int32_t> SimpleRemoteEPC::runAsVoidFunction(ExecutorAddr VoidFnAddr) { + int32_t Result = 0; + if (auto Err = callSPSWrapper<rt::SPSRunAsVoidFunctionSignature>( + RunAsVoidFunctionAddr, Result, ExecutorAddr(VoidFnAddr))) + return std::move(Err); + return Result; +} + +Expected<int32_t> SimpleRemoteEPC::runAsIntFunction(ExecutorAddr IntFnAddr, + int Arg) { + int32_t Result = 0; + if (auto Err = callSPSWrapper<rt::SPSRunAsIntFunctionSignature>( + RunAsIntFunctionAddr, Result, ExecutorAddr(IntFnAddr), Arg)) + return std::move(Err); + return Result; +} + void SimpleRemoteEPC::callWrapperAsync(ExecutorAddr WrapperFnAddr, IncomingWFRHandler OnComplete, ArrayRef<char> ArgBuffer) { @@ -312,7 +329,9 @@ Error SimpleRemoteEPC::setup(Setup S) { if (auto Err = getBootstrapSymbols( {{JDI.JITDispatchContext, ExecutorSessionObjectName}, {JDI.JITDispatchFunction, DispatchFnName}, - {RunAsMainAddr, rt::RunAsMainWrapperName}})) + {RunAsMainAddr, rt::RunAsMainWrapperName}, + {RunAsVoidFunctionAddr, rt::RunAsVoidFunctionWrapperName}, + {RunAsIntFunctionAddr, rt::RunAsIntFunctionWrapperName}})) return Err; if (auto DM = diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/SpeculateAnalyses.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/SpeculateAnalyses.cpp index c2fa4466eab6..0388725dfb63 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/SpeculateAnalyses.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/SpeculateAnalyses.cpp @@ -67,7 +67,7 @@ void SpeculateQuery::findCalles(const BasicBlock *BB, } bool SpeculateQuery::isStraightLine(const Function &F) { - return llvm::all_of(F.getBasicBlockList(), [](const BasicBlock &BB) { + return llvm::all_of(F, [](const BasicBlock &BB) { return BB.getSingleSuccessor() != nullptr; }); } @@ -97,7 +97,7 @@ BlockFreqQuery::ResultTy BlockFreqQuery::operator()(Function &F) { auto IBBs = findBBwithCalls(F); if (IBBs.empty()) - return None; + return std::nullopt; auto &BFI = FAM.getResult<BlockFrequencyAnalysis>(F); @@ -136,7 +136,7 @@ SequenceBBQuery::BlockListTy SequenceBBQuery::rearrangeBB(const Function &F, const BlockListTy &BBList) { BlockListTy RearrangedBBSet; - for (auto &Block : F.getBasicBlockList()) + for (auto &Block : F) if (llvm::is_contained(BBList, &Block)) RearrangedBBSet.push_back(&Block); @@ -288,14 +288,14 @@ SpeculateQuery::ResultTy SequenceBBQuery::operator()(Function &F) { CallerBlocks = findBBwithCalls(F); if (CallerBlocks.empty()) - return None; + return std::nullopt; if (isStraightLine(F)) SequencedBlocks = rearrangeBB(F, CallerBlocks); else SequencedBlocks = queryCFG(F, CallerBlocks); - for (auto BB : SequencedBlocks) + for (const auto *BB : SequencedBlocks) findCalles(BB, Calles); CallerAndCalles.insert({F.getName(), std::move(Calles)}); diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/TargetProcess/ExecutorSharedMemoryMapperService.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/TargetProcess/ExecutorSharedMemoryMapperService.cpp index caa191cea899..147f915f61d6 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/TargetProcess/ExecutorSharedMemoryMapperService.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/TargetProcess/ExecutorSharedMemoryMapperService.cpp @@ -21,35 +21,30 @@ #include <unistd.h> #endif +namespace llvm { +namespace orc { +namespace rt_bootstrap { + #if defined(_WIN32) -static DWORD getWindowsProtectionFlags(unsigned Flags) { - switch (Flags & llvm::sys::Memory::MF_RWE_MASK) { - case llvm::sys::Memory::MF_READ: +static DWORD getWindowsProtectionFlags(MemProt MP) { + if (MP == MemProt::Read) return PAGE_READONLY; - case llvm::sys::Memory::MF_WRITE: + if (MP == MemProt::Write || + MP == (MemProt::Write | MemProt::Read)) { // Note: PAGE_WRITE is not supported by VirtualProtect return PAGE_READWRITE; - case llvm::sys::Memory::MF_READ | llvm::sys::Memory::MF_WRITE: - return PAGE_READWRITE; - case llvm::sys::Memory::MF_READ | llvm::sys::Memory::MF_EXEC: + } + if (MP == (MemProt::Read | MemProt::Exec)) return PAGE_EXECUTE_READ; - case llvm::sys::Memory::MF_READ | llvm::sys::Memory::MF_WRITE | - llvm::sys::Memory::MF_EXEC: + if (MP == (MemProt::Read | MemProt::Write | MemProt::Exec)) return PAGE_EXECUTE_READWRITE; - case llvm::sys::Memory::MF_EXEC: + if (MP == MemProt::Exec) return PAGE_EXECUTE; - default: - llvm_unreachable("Illegal memory protection flag specified!"); - } - // Provide a default return value as required by some compilers. + return PAGE_NOACCESS; } #endif -namespace llvm { -namespace orc { -namespace rt_bootstrap { - Expected<std::pair<ExecutorAddr, std::string>> ExecutorSharedMemoryMapperService::reserve(uint64_t Size) { #if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32) @@ -137,11 +132,11 @@ Expected<ExecutorAddr> ExecutorSharedMemoryMapperService::initialize( #if defined(LLVM_ON_UNIX) int NativeProt = 0; - if (Segment.Prot & tpctypes::WPF_Read) + if ((Segment.AG.getMemProt() & MemProt::Read) == MemProt::Read) NativeProt |= PROT_READ; - if (Segment.Prot & tpctypes::WPF_Write) + if ((Segment.AG.getMemProt() & MemProt::Write) == MemProt::Write) NativeProt |= PROT_WRITE; - if (Segment.Prot & tpctypes::WPF_Exec) + if ((Segment.AG.getMemProt() & MemProt::Exec) == MemProt::Exec) NativeProt |= PROT_EXEC; if (mprotect(Segment.Addr.toPtr<void *>(), Segment.Size, NativeProt)) @@ -150,7 +145,7 @@ Expected<ExecutorAddr> ExecutorSharedMemoryMapperService::initialize( #elif defined(_WIN32) DWORD NativeProt = - getWindowsProtectionFlags(fromWireProtectionFlags(Segment.Prot)); + getWindowsProtectionFlags(Segment.AG.getMemProt()); if (!VirtualProtect(Segment.Addr.toPtr<void *>(), Segment.Size, NativeProt, &NativeProt)) @@ -158,7 +153,7 @@ Expected<ExecutorAddr> ExecutorSharedMemoryMapperService::initialize( #endif - if (Segment.Prot & tpctypes::WPF_Exec) + if ((Segment.AG.getMemProt() & MemProt::Exec) == MemProt::Exec) sys::Memory::InvalidateInstructionCache(Segment.Addr.toPtr<void *>(), Segment.Size); } @@ -192,12 +187,23 @@ Error ExecutorSharedMemoryMapperService::deinitialize( { std::lock_guard<std::mutex> Lock(Mutex); - for (auto Base : Bases) { + for (auto Base : llvm::reverse(Bases)) { if (Error Err = shared::runDeallocActions( Allocations[Base].DeinitializationActions)) { AllErr = joinErrors(std::move(AllErr), std::move(Err)); } + // Remove the allocation from the allocation list of its reservation + for (auto &Reservation : Reservations) { + auto AllocationIt = + std::find(Reservation.second.Allocations.begin(), + Reservation.second.Allocations.end(), Base); + if (AllocationIt != Reservation.second.Allocations.end()) { + Reservation.second.Allocations.erase(AllocationIt); + break; + } + } + Allocations.erase(Base); } } @@ -264,19 +270,15 @@ Error ExecutorSharedMemoryMapperService::release( } Error ExecutorSharedMemoryMapperService::shutdown() { + if (Reservations.empty()) + return Error::success(); + std::vector<ExecutorAddr> ReservationAddrs; - if (!Reservations.empty()) { - std::lock_guard<std::mutex> Lock(Mutex); - { - ReservationAddrs.reserve(Reservations.size()); - for (const auto &R : Reservations) { - ReservationAddrs.push_back(ExecutorAddr::fromPtr(R.getFirst())); - } - } - } - return release(ReservationAddrs); + ReservationAddrs.reserve(Reservations.size()); + for (const auto &R : Reservations) + ReservationAddrs.push_back(ExecutorAddr::fromPtr(R.getFirst())); - return Error::success(); + return release(std::move(ReservationAddrs)); } void ExecutorSharedMemoryMapperService::addBootstrapSymbols( diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/TargetProcess/OrcRTBootstrap.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/TargetProcess/OrcRTBootstrap.cpp index 909d47deef59..b38877955282 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/TargetProcess/OrcRTBootstrap.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/TargetProcess/OrcRTBootstrap.cpp @@ -56,6 +56,27 @@ runAsMainWrapper(const char *ArgData, size_t ArgSize) { .release(); } +static llvm::orc::shared::CWrapperFunctionResult +runAsVoidFunctionWrapper(const char *ArgData, size_t ArgSize) { + return WrapperFunction<rt::SPSRunAsVoidFunctionSignature>::handle( + ArgData, ArgSize, + [](ExecutorAddr MainAddr) -> int32_t { + return runAsVoidFunction(MainAddr.toPtr<int32_t (*)(void)>()); + }) + .release(); +} + +static llvm::orc::shared::CWrapperFunctionResult +runAsIntFunctionWrapper(const char *ArgData, size_t ArgSize) { + return WrapperFunction<rt::SPSRunAsIntFunctionSignature>::handle( + ArgData, ArgSize, + [](ExecutorAddr MainAddr, int32_t Arg) -> int32_t { + return runAsIntFunction(MainAddr.toPtr<int32_t (*)(int32_t)>(), + Arg); + }) + .release(); +} + void addTo(StringMap<ExecutorAddr> &M) { M[rt::MemoryWriteUInt8sWrapperName] = ExecutorAddr::fromPtr( &writeUIntsWrapper<tpctypes::UInt8Write, @@ -76,6 +97,10 @@ void addTo(StringMap<ExecutorAddr> &M) { M[rt::DeregisterEHFrameSectionWrapperName] = ExecutorAddr::fromPtr(&llvm_orc_deregisterEHFrameSectionWrapper); M[rt::RunAsMainWrapperName] = ExecutorAddr::fromPtr(&runAsMainWrapper); + M[rt::RunAsVoidFunctionWrapperName] = + ExecutorAddr::fromPtr(&runAsVoidFunctionWrapper); + M[rt::RunAsIntFunctionWrapperName] = + ExecutorAddr::fromPtr(&runAsIntFunctionWrapper); } } // end namespace rt_bootstrap diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp index 3c9dd21b0832..cb11b68e2719 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp @@ -35,24 +35,18 @@ SimpleExecutorDylibManager::open(const std::string &Path, uint64_t Mode) { return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode()); std::lock_guard<std::mutex> Lock(M); - Dylibs[NextId] = std::move(DL); - return NextId++; + auto H = ExecutorAddr::fromPtr(DL.getOSSpecificHandle()); + Dylibs.insert(DL.getOSSpecificHandle()); + return H; } Expected<std::vector<ExecutorAddr>> SimpleExecutorDylibManager::lookup(tpctypes::DylibHandle H, const RemoteSymbolLookupSet &L) { std::vector<ExecutorAddr> Result; - - std::lock_guard<std::mutex> Lock(M); - auto I = Dylibs.find(H); - if (I == Dylibs.end()) - return make_error<StringError>("No dylib for handle " + formatv("{0:x}", H), - inconvertibleErrorCode()); - auto &DL = I->second; + auto DL = sys::DynamicLibrary(H.toPtr<void *>()); for (const auto &E : L) { - if (E.Name.empty()) { if (E.Required) return make_error<StringError>("Required address for empty symbol \"\"", @@ -85,10 +79,10 @@ SimpleExecutorDylibManager::lookup(tpctypes::DylibHandle H, Error SimpleExecutorDylibManager::shutdown() { - DylibsMap DM; + DylibSet DS; { std::lock_guard<std::mutex> Lock(M); - std::swap(DM, Dylibs); + std::swap(DS, Dylibs); } // There is no removal of dylibs at the moment, so nothing to do here. diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorMemoryManager.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorMemoryManager.cpp index c848dd65fa7e..ce94bf1e039a 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorMemoryManager.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorMemoryManager.cpp @@ -132,9 +132,9 @@ Error SimpleExecutorMemoryManager::finalize(tpctypes::FinalizeRequest &FR) { assert(Seg.Size <= std::numeric_limits<size_t>::max()); if (auto EC = sys::Memory::protectMappedMemory( {Mem, static_cast<size_t>(Seg.Size)}, - tpctypes::fromWireProtectionFlags(Seg.Prot))) + toSysMemoryProtectionFlags(Seg.AG.getMemProt()))) return BailOut(errorCodeToError(EC)); - if (Seg.Prot & tpctypes::WPF_Exec) + if ((Seg.AG.getMemProt() & MemProt::Exec) == MemProt::Exec) sys::Memory::InvalidateInstructionCache(Mem, Seg.Size); } diff --git a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.cpp b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.cpp index a8e6c049cf4b..7546b3f8d0fa 100644 --- a/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.cpp +++ b/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.cpp @@ -14,7 +14,7 @@ namespace llvm { namespace orc { int runAsMain(int (*Main)(int, char *[]), ArrayRef<std::string> Args, - Optional<StringRef> ProgramName) { + std::optional<StringRef> ProgramName) { std::vector<std::unique_ptr<char[]>> ArgVStorage; std::vector<char *> ArgV; @@ -39,5 +39,9 @@ int runAsMain(int (*Main)(int, char *[]), ArrayRef<std::string> Args, return Main(Args.size() + !!ProgramName, ArgV.data()); } +int runAsVoidFunction(int (*Func)(void)) { return Func(); } + +int runAsIntFunction(int (*Func)(int), int Arg) { return Func(Arg); } + } // End namespace orc. } // End namespace llvm. |