1 //===--- JITLinkMemoryManager.cpp - JITLinkMemoryManager implementation ---===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
11 #include "llvm/Support/Process.h"
16 JITLinkMemoryManager::~JITLinkMemoryManager() = default;
17 JITLinkMemoryManager::Allocation::~Allocation() = default;
19 Expected
<std::unique_ptr
<JITLinkMemoryManager::Allocation
>>
20 InProcessMemoryManager::allocate(const SegmentsRequestMap
&Request
) {
22 using AllocationMap
= DenseMap
<unsigned, sys::MemoryBlock
>;
24 // Local class for allocation.
25 class IPMMAlloc
: public Allocation
{
27 IPMMAlloc(AllocationMap SegBlocks
) : SegBlocks(std::move(SegBlocks
)) {}
28 MutableArrayRef
<char> getWorkingMemory(ProtectionFlags Seg
) override
{
29 assert(SegBlocks
.count(Seg
) && "No allocation for segment");
30 return {static_cast<char *>(SegBlocks
[Seg
].base()),
31 SegBlocks
[Seg
].allocatedSize()};
33 JITTargetAddress
getTargetMemory(ProtectionFlags Seg
) override
{
34 assert(SegBlocks
.count(Seg
) && "No allocation for segment");
35 return reinterpret_cast<JITTargetAddress
>(SegBlocks
[Seg
].base());
37 void finalizeAsync(FinalizeContinuation OnFinalize
) override
{
38 OnFinalize(applyProtections());
40 Error
deallocate() override
{
41 if (SegBlocks
.empty())
42 return Error::success();
43 void *SlabStart
= SegBlocks
.begin()->second
.base();
44 char *SlabEnd
= (char *)SlabStart
;
45 for (auto &KV
: SegBlocks
) {
46 SlabStart
= std::min(SlabStart
, KV
.second
.base());
47 SlabEnd
= std::max(SlabEnd
, (char *)(KV
.second
.base()) +
48 KV
.second
.allocatedSize());
50 size_t SlabSize
= SlabEnd
- (char *)SlabStart
;
51 assert((SlabSize
% sys::Process::getPageSizeEstimate()) == 0 &&
52 "Slab size is not a multiple of page size");
53 sys::MemoryBlock
Slab(SlabStart
, SlabSize
);
54 if (auto EC
= sys::Memory::releaseMappedMemory(Slab
))
55 return errorCodeToError(EC
);
56 return Error::success();
60 Error
applyProtections() {
61 for (auto &KV
: SegBlocks
) {
62 auto &Prot
= KV
.first
;
63 auto &Block
= KV
.second
;
64 if (auto EC
= sys::Memory::protectMappedMemory(Block
, Prot
))
65 return errorCodeToError(EC
);
66 if (Prot
& sys::Memory::MF_EXEC
)
67 sys::Memory::InvalidateInstructionCache(Block
.base(),
68 Block
.allocatedSize());
70 return Error::success();
73 AllocationMap SegBlocks
;
76 if (!isPowerOf2_64((uint64_t)sys::Process::getPageSizeEstimate()))
77 return make_error
<StringError
>("Page size is not a power of 2",
78 inconvertibleErrorCode());
81 const sys::Memory::ProtectionFlags ReadWrite
=
82 static_cast<sys::Memory::ProtectionFlags
>(sys::Memory::MF_READ
|
83 sys::Memory::MF_WRITE
);
85 // Compute the total number of pages to allocate.
87 for (auto &KV
: Request
) {
88 const auto &Seg
= KV
.second
;
90 if (Seg
.getAlignment() > sys::Process::getPageSizeEstimate())
91 return make_error
<StringError
>("Cannot request higher than page "
93 inconvertibleErrorCode());
95 TotalSize
= alignTo(TotalSize
, sys::Process::getPageSizeEstimate());
96 TotalSize
+= Seg
.getContentSize();
97 TotalSize
+= Seg
.getZeroFillSize();
100 // Allocate one slab to cover all the segments.
103 sys::Memory::allocateMappedMemory(TotalSize
, nullptr, ReadWrite
, EC
);
106 return errorCodeToError(EC
);
108 // Allocate segment memory from the slab.
109 for (auto &KV
: Request
) {
111 const auto &Seg
= KV
.second
;
113 uint64_t SegmentSize
= alignTo(Seg
.getContentSize() + Seg
.getZeroFillSize(),
114 sys::Process::getPageSizeEstimate());
116 sys::MemoryBlock
SegMem(SlabRemaining
.base(), SegmentSize
);
117 SlabRemaining
= sys::MemoryBlock((char *)SlabRemaining
.base() + SegmentSize
,
120 // Zero out the zero-fill memory.
121 memset(static_cast<char *>(SegMem
.base()) + Seg
.getContentSize(), 0,
122 Seg
.getZeroFillSize());
124 // Record the block for this segment.
125 Blocks
[KV
.first
] = std::move(SegMem
);
127 return std::unique_ptr
<InProcessMemoryManager::Allocation
>(
128 new IPMMAlloc(std::move(Blocks
)));
131 } // end namespace jitlink
132 } // end namespace llvm