142 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			142 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			C++
		
	
	
	
//===-------------- 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 <limits>
 | 
						|
#include <vector>
 | 
						|
 | 
						|
using namespace llvm;
 | 
						|
using namespace llvm::orc;
 | 
						|
using namespace llvm::orc::shared;
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
class SimpleAllocator {
 | 
						|
public:
 | 
						|
  Expected<ExecutorAddr> 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<char *>();
 | 
						|
      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<size_t>::max());
 | 
						|
      if (auto EC = sys::Memory::protectMappedMemory(
 | 
						|
              {Mem, static_cast<size_t>(Seg.Size)},
 | 
						|
              tpctypes::fromWireProtectionFlags(Seg.Prot)))
 | 
						|
        return errorCodeToError(EC);
 | 
						|
      if (Seg.Prot & tpctypes::WPF_Exec)
 | 
						|
        sys::Memory::InvalidateInstructionCache(Mem, Seg.Size);
 | 
						|
    }
 | 
						|
    return Error::success();
 | 
						|
  }
 | 
						|
 | 
						|
  Error deallocate(std::vector<ExecutorAddr> &Bases) {
 | 
						|
    Error Err = Error::success();
 | 
						|
    for (auto &Base : Bases) {
 | 
						|
      auto I = Blocks.find(Base.toPtr<void *>());
 | 
						|
      if (I == Blocks.end()) {
 | 
						|
        Err = joinErrors(
 | 
						|
            std::move(Err),
 | 
						|
            make_error<StringError>("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<void *, sys::OwningMemoryBlock> Blocks;
 | 
						|
};
 | 
						|
 | 
						|
llvm::orc::shared::CWrapperFunctionResult testReserve(const char *ArgData,
 | 
						|
                                                      size_t ArgSize) {
 | 
						|
  return WrapperFunction<rt::SPSSimpleExecutorMemoryManagerReserveSignature>::
 | 
						|
      handle(ArgData, ArgSize,
 | 
						|
             makeMethodWrapperHandler(&SimpleAllocator::reserve))
 | 
						|
          .release();
 | 
						|
}
 | 
						|
 | 
						|
llvm::orc::shared::CWrapperFunctionResult testFinalize(const char *ArgData,
 | 
						|
                                                       size_t ArgSize) {
 | 
						|
  return WrapperFunction<rt::SPSSimpleExecutorMemoryManagerFinalizeSignature>::
 | 
						|
      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<EPCGenericJITLinkMemoryManager>(*SelfEPC, SAs);
 | 
						|
 | 
						|
  StringRef Hello = "hello";
 | 
						|
  auto SSA = jitlink::SimpleSegmentAlloc::Create(
 | 
						|
      *MemMgr, nullptr, {{jitlink::MemProt::Read, {Hello.size(), Align(1)}}});
 | 
						|
  EXPECT_THAT_EXPECTED(SSA, Succeeded());
 | 
						|
  auto SegInfo = SSA->getSegInfo(jitlink::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<const char *>();
 | 
						|
  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
 |