LLVM  14.0.0git
JITLinkMemoryManager.cpp
Go to the documentation of this file.
1 //===--- JITLinkMemoryManager.cpp - JITLinkMemoryManager implementation ---===//
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 
10 #include "llvm/Support/Process.h"
11 
12 namespace llvm {
13 namespace jitlink {
14 
17 
18 Expected<std::unique_ptr<JITLinkMemoryManager::Allocation>>
20  const SegmentsRequestMap &Request) {
21 
22  using AllocationMap = DenseMap<unsigned, sys::MemoryBlock>;
23 
24  // Local class for allocation.
25  class IPMMAlloc : public Allocation {
26  public:
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()};
32  }
33  JITTargetAddress getTargetMemory(ProtectionFlags Seg) override {
34  assert(SegBlocks.count(Seg) && "No allocation for segment");
35  return pointerToJITTargetAddress(SegBlocks[Seg].base());
36  }
37  void finalizeAsync(FinalizeContinuation OnFinalize) override {
38  OnFinalize(applyProtections());
39  }
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());
49  }
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();
57  }
58 
59  private:
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)
68  Block.allocatedSize());
69  }
70  return Error::success();
71  }
72 
73  AllocationMap SegBlocks;
74  };
75 
77  return make_error<StringError>("Page size is not a power of 2",
79 
80  AllocationMap Blocks;
81  const sys::Memory::ProtectionFlags ReadWrite =
84 
85  // Compute the total number of pages to allocate.
86  size_t TotalSize = 0;
87  for (auto &KV : Request) {
88  const auto &Seg = KV.second;
89 
90  if (Seg.getAlignment() > sys::Process::getPageSizeEstimate())
91  return make_error<StringError>("Cannot request higher than page "
92  "alignment",
94 
95  TotalSize = alignTo(TotalSize, sys::Process::getPageSizeEstimate());
96  TotalSize += Seg.getContentSize();
97  TotalSize += Seg.getZeroFillSize();
98  }
99 
100  // Allocate one slab to cover all the segments.
101  std::error_code EC;
102  auto SlabRemaining =
103  sys::Memory::allocateMappedMemory(TotalSize, nullptr, ReadWrite, EC);
104 
105  if (EC)
106  return errorCodeToError(EC);
107 
108  // Allocate segment memory from the slab.
109  for (auto &KV : Request) {
110 
111  const auto &Seg = KV.second;
112 
113  uint64_t SegmentSize = alignTo(Seg.getContentSize() + Seg.getZeroFillSize(),
115  assert(SlabRemaining.allocatedSize() >= SegmentSize &&
116  "Mapping exceeds allocation");
117 
118  sys::MemoryBlock SegMem(SlabRemaining.base(), SegmentSize);
119  SlabRemaining = sys::MemoryBlock((char *)SlabRemaining.base() + SegmentSize,
120  SlabRemaining.allocatedSize() - SegmentSize);
121 
122  // Zero out the zero-fill memory.
123  memset(static_cast<char *>(SegMem.base()) + Seg.getContentSize(), 0,
124  Seg.getZeroFillSize());
125 
126  // Record the block for this segment.
127  Blocks[KV.first] = std::move(SegMem);
128  }
129 
130  return std::unique_ptr<InProcessMemoryManager::Allocation>(
131  new IPMMAlloc(std::move(Blocks)));
132 }
133 
134 } // end namespace jitlink
135 } // end namespace llvm
llvm::alignTo
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition: Alignment.h:148
llvm::sys::Memory::MF_READ
@ MF_READ
Definition: Memory.h:55
llvm
---------------------— PointerInfo ------------------------------------—
Definition: AllocatorList.h:23
llvm::sys::Memory::MF_WRITE
@ MF_WRITE
Definition: Memory.h:56
llvm::sys::Memory::InvalidateInstructionCache
static void InvalidateInstructionCache(const void *Addr, size_t Len)
InvalidateInstructionCache - Before the JIT can run a block of code that has been emitted it must inv...
llvm::Error::success
static ErrorSuccess success()
Create a success value.
Definition: Error.h:331
llvm::sys::Memory::allocateMappedMemory
static MemoryBlock allocateMappedMemory(size_t NumBytes, const MemoryBlock *const NearBlock, unsigned Flags, std::error_code &EC)
This method allocates a block of memory that is suitable for loading dynamically generated code (e....
llvm::sys::Memory::releaseMappedMemory
static std::error_code releaseMappedMemory(MemoryBlock &Block)
This method releases a block of memory that was allocated with the allocateMappedMemory method.
llvm::sys::MemoryBlock
This class encapsulates the notion of a memory block which has an address and a size.
Definition: Memory.h:31
Process.h
llvm::MutableArrayRef
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
Definition: ArrayRef.h:307
llvm::errorCodeToError
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition: Error.cpp:87
llvm::sys::Memory::ProtectionFlags
ProtectionFlags
Definition: Memory.h:54
llvm::sys::MemoryBlock::base
void * base() const
Definition: Memory.h:36
llvm::sys::Memory::MF_EXEC
@ MF_EXEC
Definition: Memory.h:57
uint64_t
move
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
Definition: README.txt:546
llvm::DenseMap
Definition: DenseMap.h:714
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
base
therefore end up llgh r3 lr r0 br r14 but truncating the load would lh r3 br r14 Functions ret i64 and ought to be implemented ngr r0 br r14 but two address optimizations reverse the order of the AND and ngr r2 lgr r0 br r14 CodeGen SystemZ and ll has several examples of this Out of range displacements are usually handled by loading the full address into a register In many cases it would be better to create an anchor point instead E g i64 base
Definition: README.txt:125
llvm::min
Expected< ExpressionValue > min(const ExpressionValue &Lhs, const ExpressionValue &Rhs)
Definition: FileCheck.cpp:357
JITLinkMemoryManager.h
llvm::pointerToJITTargetAddress
JITTargetAddress pointerToJITTargetAddress(T *Ptr)
Convert a pointer to a JITTargetAddress.
Definition: JITSymbol.h:69
llvm::inconvertibleErrorCode
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition: Error.cpp:77
llvm::Error
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
llvm::sys::Memory::protectMappedMemory
static std::error_code protectMappedMemory(const MemoryBlock &Block, unsigned Flags)
This method sets the protection flags for a block of memory to the state specified by /p Flags.
llvm::max
Align max(MaybeAlign Lhs, Align Rhs)
Definition: Alignment.h:340
llvm::sys::Process::getPageSizeEstimate
static unsigned getPageSizeEstimate()
Get the process's estimated page size.
Definition: Process.h:62
llvm::isPowerOf2_64
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
Definition: MathExtras.h:496