//===-------------- EPCGenericJITLinkMemoryManagerTest.cpp ----------------===// // // 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 "OrcTestCommon.h" #include "llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h" #include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Memory.h" #include "llvm/Testing/Support/Error.h" #include #include using namespace llvm; using namespace llvm::orc; using namespace llvm::orc::shared; namespace { class SimpleAllocator { public: Expected reserve(uint64_t Size) { std::error_code EC; auto MB = sys::Memory::allocateMappedMemory( Size, 0, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC); if (EC) return errorCodeToError(EC); Blocks[MB.base()] = sys::OwningMemoryBlock(std::move(MB)); return ExecutorAddr::fromPtr(MB.base()); } Error finalize(tpctypes::FinalizeRequest FR) { for (auto &Seg : FR.Segments) { char *Mem = Seg.Addr.toPtr(); memcpy(Mem, Seg.Content.data(), Seg.Content.size()); memset(Mem + Seg.Content.size(), 0, Seg.Size - Seg.Content.size()); assert(Seg.Size <= std::numeric_limits::max()); if (auto EC = sys::Memory::protectMappedMemory( {Mem, static_cast(Seg.Size)}, toSysMemoryProtectionFlags(Seg.RAG.Prot))) return errorCodeToError(EC); if ((Seg.RAG.Prot & MemProt::Exec) != MemProt::Exec) sys::Memory::InvalidateInstructionCache(Mem, Seg.Size); } return Error::success(); } Error deallocate(std::vector &Bases) { Error Err = Error::success(); for (auto &Base : Bases) { auto I = Blocks.find(Base.toPtr()); if (I == Blocks.end()) { Err = joinErrors( std::move(Err), make_error("No allocation for " + formatv("{0:x}", Base.getValue()), inconvertibleErrorCode())); continue; } auto MB = std::move(I->second); Blocks.erase(I); if (auto EC = MB.release()) Err = joinErrors(std::move(Err), errorCodeToError(EC)); } return Err; } private: DenseMap Blocks; }; llvm::orc::shared::CWrapperFunctionResult testReserve(const char *ArgData, size_t ArgSize) { return WrapperFunction:: handle(ArgData, ArgSize, makeMethodWrapperHandler(&SimpleAllocator::reserve)) .release(); } llvm::orc::shared::CWrapperFunctionResult testFinalize(const char *ArgData, size_t ArgSize) { return WrapperFunction:: handle(ArgData, ArgSize, makeMethodWrapperHandler(&SimpleAllocator::finalize)) .release(); } llvm::orc::shared::CWrapperFunctionResult testDeallocate(const char *ArgData, size_t ArgSize) { return WrapperFunction< rt::SPSSimpleExecutorMemoryManagerDeallocateSignature>:: handle(ArgData, ArgSize, makeMethodWrapperHandler(&SimpleAllocator::deallocate)) .release(); } TEST(EPCGenericJITLinkMemoryManagerTest, AllocFinalizeFree) { auto SelfEPC = cantFail(SelfExecutorProcessControl::Create()); SimpleAllocator SA; EPCGenericJITLinkMemoryManager::SymbolAddrs SAs; SAs.Allocator = ExecutorAddr::fromPtr(&SA); SAs.Reserve = ExecutorAddr::fromPtr(&testReserve); SAs.Finalize = ExecutorAddr::fromPtr(&testFinalize); SAs.Deallocate = ExecutorAddr::fromPtr(&testDeallocate); auto MemMgr = std::make_unique(*SelfEPC, SAs); StringRef Hello = "hello"; auto SSA = jitlink::SimpleSegmentAlloc::Create( *MemMgr, std::make_shared(), Triple("x86_64-apple-darwin"), nullptr, {{MemProt::Read, {Hello.size(), Align(1)}}}); EXPECT_THAT_EXPECTED(SSA, Succeeded()); auto SegInfo = SSA->getSegInfo(MemProt::Read); memcpy(SegInfo.WorkingMem.data(), Hello.data(), Hello.size()); auto FA = SSA->finalize(); EXPECT_THAT_EXPECTED(FA, Succeeded()); ExecutorAddr TargetAddr(SegInfo.Addr); const char *TargetMem = TargetAddr.toPtr(); EXPECT_NE(TargetMem, SegInfo.WorkingMem.data()); StringRef TargetHello(TargetMem, Hello.size()); EXPECT_EQ(Hello, TargetHello); auto Err2 = MemMgr->deallocate(std::move(*FA)); EXPECT_THAT_ERROR(std::move(Err2), Succeeded()); cantFail(SelfEPC->disconnect()); } } // namespace