1 //===-------------- EPCGenericJITLinkMemoryManagerTest.cpp ----------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "OrcTestCommon.h" 10 11 #include "llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h" 12 13 #include "llvm/ADT/DenseMap.h" 14 #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h" 15 #include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h" 16 #include "llvm/Support/FormatVariadic.h" 17 #include "llvm/Support/Memory.h" 18 #include "llvm/Testing/Support/Error.h" 19 20 #include <limits> 21 #include <vector> 22 23 using namespace llvm; 24 using namespace llvm::orc; 25 using namespace llvm::orc::shared; 26 27 namespace { 28 29 class SimpleAllocator { 30 public: 31 Expected<ExecutorAddr> reserve(uint64_t Size) { 32 std::error_code EC; 33 auto MB = sys::Memory::allocateMappedMemory( 34 Size, 0, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC); 35 if (EC) 36 return errorCodeToError(EC); 37 Blocks[MB.base()] = sys::OwningMemoryBlock(std::move(MB)); 38 return ExecutorAddr::fromPtr(MB.base()); 39 } 40 41 Error finalize(tpctypes::FinalizeRequest FR) { 42 for (auto &Seg : FR.Segments) { 43 char *Mem = Seg.Addr.toPtr<char *>(); 44 memcpy(Mem, Seg.Content.data(), Seg.Content.size()); 45 memset(Mem + Seg.Content.size(), 0, Seg.Size - Seg.Content.size()); 46 assert(Seg.Size <= std::numeric_limits<size_t>::max()); 47 if (auto EC = sys::Memory::protectMappedMemory( 48 {Mem, static_cast<size_t>(Seg.Size)}, 49 tpctypes::fromWireProtectionFlags(Seg.Prot))) 50 return errorCodeToError(EC); 51 if (Seg.Prot & tpctypes::WPF_Exec) 52 sys::Memory::InvalidateInstructionCache(Mem, Seg.Size); 53 } 54 return Error::success(); 55 } 56 57 Error deallocate(std::vector<ExecutorAddr> &Bases) { 58 Error Err = Error::success(); 59 for (auto &Base : Bases) { 60 auto I = Blocks.find(Base.toPtr<void *>()); 61 if (I == Blocks.end()) { 62 Err = joinErrors( 63 std::move(Err), 64 make_error<StringError>("No allocation for " + 65 formatv("{0:x}", Base.getValue()), 66 inconvertibleErrorCode())); 67 continue; 68 } 69 auto MB = std::move(I->second); 70 Blocks.erase(I); 71 auto MBToRelease = MB.getMemoryBlock(); 72 if (auto EC = sys::Memory::releaseMappedMemory(MBToRelease)) 73 Err = joinErrors(std::move(Err), errorCodeToError(EC)); 74 } 75 return Err; 76 } 77 78 private: 79 DenseMap<void *, sys::OwningMemoryBlock> Blocks; 80 }; 81 82 llvm::orc::shared::detail::CWrapperFunctionResult 83 testReserve(const char *ArgData, size_t ArgSize) { 84 return WrapperFunction<rt::SPSSimpleExecutorMemoryManagerReserveSignature>:: 85 handle(ArgData, ArgSize, 86 makeMethodWrapperHandler(&SimpleAllocator::reserve)) 87 .release(); 88 } 89 90 llvm::orc::shared::detail::CWrapperFunctionResult 91 testFinalize(const char *ArgData, size_t ArgSize) { 92 return WrapperFunction<rt::SPSSimpleExecutorMemoryManagerFinalizeSignature>:: 93 handle(ArgData, ArgSize, 94 makeMethodWrapperHandler(&SimpleAllocator::finalize)) 95 .release(); 96 } 97 98 llvm::orc::shared::detail::CWrapperFunctionResult 99 testDeallocate(const char *ArgData, size_t ArgSize) { 100 return WrapperFunction< 101 rt::SPSSimpleExecutorMemoryManagerDeallocateSignature>:: 102 handle(ArgData, ArgSize, 103 makeMethodWrapperHandler(&SimpleAllocator::deallocate)) 104 .release(); 105 } 106 107 TEST(EPCGenericJITLinkMemoryManagerTest, AllocFinalizeFree) { 108 auto SelfEPC = cantFail(SelfExecutorProcessControl::Create()); 109 SimpleAllocator SA; 110 111 EPCGenericJITLinkMemoryManager::SymbolAddrs SAs; 112 SAs.Allocator = ExecutorAddr::fromPtr(&SA); 113 SAs.Reserve = ExecutorAddr::fromPtr(&testReserve); 114 SAs.Finalize = ExecutorAddr::fromPtr(&testFinalize); 115 SAs.Deallocate = ExecutorAddr::fromPtr(&testDeallocate); 116 117 auto MemMgr = std::make_unique<EPCGenericJITLinkMemoryManager>(*SelfEPC, SAs); 118 119 StringRef Hello = "hello"; 120 auto SSA = jitlink::SimpleSegmentAlloc::Create( 121 *MemMgr, nullptr, {{jitlink::MemProt::Read, {Hello.size(), Align(1)}}}); 122 EXPECT_THAT_EXPECTED(SSA, Succeeded()); 123 auto SegInfo = SSA->getSegInfo(jitlink::MemProt::Read); 124 memcpy(SegInfo.WorkingMem.data(), Hello.data(), Hello.size()); 125 126 auto FA = SSA->finalize(); 127 EXPECT_THAT_EXPECTED(FA, Succeeded()); 128 129 ExecutorAddr TargetAddr(SegInfo.Addr); 130 131 const char *TargetMem = TargetAddr.toPtr<const char *>(); 132 EXPECT_NE(TargetMem, SegInfo.WorkingMem.data()); 133 StringRef TargetHello(TargetMem, Hello.size()); 134 EXPECT_EQ(Hello, TargetHello); 135 136 auto Err2 = MemMgr->deallocate(std::move(*FA)); 137 EXPECT_THAT_ERROR(std::move(Err2), Succeeded()); 138 } 139 140 } // namespace 141