LLVM  16.0.0git
SimpleExecutorMemoryManager.cpp
Go to the documentation of this file.
1 //===- SimpleExecuorMemoryManagare.cpp - Simple executor-side memory mgmt -===//
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 
13 
14 #define DEBUG_TYPE "orc"
15 
16 namespace llvm {
17 namespace orc {
18 namespace rt_bootstrap {
19 
21  assert(Allocations.empty() && "shutdown not called?");
22 }
23 
25  std::error_code EC;
27  Size, nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC);
28  if (EC)
29  return errorCodeToError(EC);
30  std::lock_guard<std::mutex> Lock(M);
31  assert(!Allocations.count(MB.base()) && "Duplicate allocation addr");
32  Allocations[MB.base()].Size = Size;
33  return ExecutorAddr::fromPtr(MB.base());
34 }
35 
37  ExecutorAddr Base(~0ULL);
38  std::vector<shared::WrapperFunctionCall> DeallocationActions;
39  size_t SuccessfulFinalizationActions = 0;
40 
41  if (FR.Segments.empty()) {
42  // NOTE: Finalizing nothing is currently a no-op. Should it be an error?
43  if (FR.Actions.empty())
44  return Error::success();
45  else
46  return make_error<StringError>("Finalization actions attached to empty "
47  "finalization request",
49  }
50 
51  for (auto &Seg : FR.Segments)
52  Base = std::min(Base, Seg.Addr);
53 
54  for (auto &ActPair : FR.Actions)
55  if (ActPair.Dealloc)
56  DeallocationActions.push_back(ActPair.Dealloc);
57 
58  // Get the Allocation for this finalization.
59  size_t AllocSize = 0;
60  {
61  std::lock_guard<std::mutex> Lock(M);
62  auto I = Allocations.find(Base.toPtr<void *>());
63  if (I == Allocations.end())
64  return make_error<StringError>("Attempt to finalize unrecognized "
65  "allocation " +
66  formatv("{0:x}", Base.getValue()),
68  AllocSize = I->second.Size;
69  I->second.DeallocationActions = std::move(DeallocationActions);
70  }
71  ExecutorAddr AllocEnd = Base + ExecutorAddrDiff(AllocSize);
72 
73  // Bail-out function: this will run deallocation actions corresponding to any
74  // completed finalization actions, then deallocate memory.
75  auto BailOut = [&](Error Err) {
76  std::pair<void *, Allocation> AllocToDestroy;
77 
78  // Get allocation to destory.
79  {
80  std::lock_guard<std::mutex> Lock(M);
81  auto I = Allocations.find(Base.toPtr<void *>());
82 
83  // Check for missing allocation (effective a double free).
84  if (I == Allocations.end())
85  return joinErrors(
86  std::move(Err),
87  make_error<StringError>("No allocation entry found "
88  "for " +
89  formatv("{0:x}", Base.getValue()),
91  AllocToDestroy = std::move(*I);
92  Allocations.erase(I);
93  }
94 
95  // Run deallocation actions for all completed finalization actions.
96  while (SuccessfulFinalizationActions)
97  Err =
98  joinErrors(std::move(Err), FR.Actions[--SuccessfulFinalizationActions]
99  .Dealloc.runWithSPSRetErrorMerged());
100 
101  // Deallocate memory.
102  sys::MemoryBlock MB(AllocToDestroy.first, AllocToDestroy.second.Size);
103  if (auto EC = sys::Memory::releaseMappedMemory(MB))
104  Err = joinErrors(std::move(Err), errorCodeToError(EC));
105 
106  return Err;
107  };
108 
109  // Copy content and apply permissions.
110  for (auto &Seg : FR.Segments) {
111 
112  // Check segment ranges.
113  if (LLVM_UNLIKELY(Seg.Size < Seg.Content.size()))
114  return BailOut(make_error<StringError>(
115  formatv("Segment {0:x} content size ({1:x} bytes) "
116  "exceeds segment size ({2:x} bytes)",
117  Seg.Addr.getValue(), Seg.Content.size(), Seg.Size),
119  ExecutorAddr SegEnd = Seg.Addr + ExecutorAddrDiff(Seg.Size);
120  if (LLVM_UNLIKELY(Seg.Addr < Base || SegEnd > AllocEnd))
121  return BailOut(make_error<StringError>(
122  formatv("Segment {0:x} -- {1:x} crosses boundary of "
123  "allocation {2:x} -- {3:x}",
124  Seg.Addr.getValue(), SegEnd.getValue(), Base.getValue(),
125  AllocEnd.getValue()),
127 
128  char *Mem = Seg.Addr.toPtr<char *>();
129  if (!Seg.Content.empty())
130  memcpy(Mem, Seg.Content.data(), Seg.Content.size());
131  memset(Mem + Seg.Content.size(), 0, Seg.Size - Seg.Content.size());
133  if (auto EC = sys::Memory::protectMappedMemory(
134  {Mem, static_cast<size_t>(Seg.Size)},
135  toSysMemoryProtectionFlags(Seg.AG.getMemProt())))
136  return BailOut(errorCodeToError(EC));
137  if ((Seg.AG.getMemProt() & MemProt::Exec) == MemProt::Exec)
139  }
140 
141  // Run finalization actions.
142  for (auto &ActPair : FR.Actions) {
143  if (auto Err = ActPair.Finalize.runWithSPSRetErrorMerged())
144  return BailOut(std::move(Err));
145  ++SuccessfulFinalizationActions;
146  }
147 
148  return Error::success();
149 }
150 
152  const std::vector<ExecutorAddr> &Bases) {
153  std::vector<std::pair<void *, Allocation>> AllocPairs;
154  AllocPairs.reserve(Bases.size());
155 
156  // Get allocation to destory.
157  Error Err = Error::success();
158  {
159  std::lock_guard<std::mutex> Lock(M);
160  for (auto &Base : Bases) {
161  auto I = Allocations.find(Base.toPtr<void *>());
162 
163  // Check for missing allocation (effective a double free).
164  if (I != Allocations.end()) {
165  AllocPairs.push_back(std::move(*I));
166  Allocations.erase(I);
167  } else
168  Err = joinErrors(
169  std::move(Err),
170  make_error<StringError>("No allocation entry found "
171  "for " +
172  formatv("{0:x}", Base.getValue()),
174  }
175  }
176 
177  while (!AllocPairs.empty()) {
178  auto &P = AllocPairs.back();
179  Err = joinErrors(std::move(Err), deallocateImpl(P.first, P.second));
180  AllocPairs.pop_back();
181  }
182 
183  return Err;
184 }
185 
187 
188  AllocationsMap AM;
189  {
190  std::lock_guard<std::mutex> Lock(M);
191  AM = std::move(Allocations);
192  }
193 
194  Error Err = Error::success();
195  for (auto &KV : AM)
196  Err = joinErrors(std::move(Err), deallocateImpl(KV.first, KV.second));
197  return Err;
198 }
199 
204  ExecutorAddr::fromPtr(&reserveWrapper);
206  ExecutorAddr::fromPtr(&finalizeWrapper);
208  ExecutorAddr::fromPtr(&deallocateWrapper);
209 }
210 
211 Error SimpleExecutorMemoryManager::deallocateImpl(void *Base, Allocation &A) {
212  Error Err = Error::success();
213 
214  while (!A.DeallocationActions.empty()) {
215  Err = joinErrors(std::move(Err),
216  A.DeallocationActions.back().runWithSPSRetErrorMerged());
217  A.DeallocationActions.pop_back();
218  }
219 
220  sys::MemoryBlock MB(Base, A.Size);
221  if (auto EC = sys::Memory::releaseMappedMemory(MB))
222  Err = joinErrors(std::move(Err), errorCodeToError(EC));
223 
224  return Err;
225 }
226 
228 SimpleExecutorMemoryManager::reserveWrapper(const char *ArgData,
229  size_t ArgSize) {
230  return shared::WrapperFunction<
232  handle(ArgData, ArgSize,
235  .release();
236 }
237 
239 SimpleExecutorMemoryManager::finalizeWrapper(const char *ArgData,
240  size_t ArgSize) {
241  return shared::WrapperFunction<
243  handle(ArgData, ArgSize,
246  .release();
247 }
248 
250 SimpleExecutorMemoryManager::deallocateWrapper(const char *ArgData,
251  size_t ArgSize) {
252  return shared::WrapperFunction<
254  handle(ArgData, ArgSize,
257  .release();
258 }
259 
260 } // namespace rt_bootstrap
261 } // end namespace orc
262 } // end namespace llvm
llvm::orc::ExecutorAddr
Represents an address in the executor process.
Definition: ExecutorAddress.h:31
llvm::orc::ExecutorAddr::fromPtr
static ExecutorAddr fromPtr(T *Ptr, UnwrapFn &&Unwrap=UnwrapFn())
Create an ExecutorAddr from the given pointer.
Definition: ExecutorAddress.h:80
SimpleExecutorMemoryManager.h
llvm::sys::Memory::MF_READ
@ MF_READ
Definition: Memory.h:55
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
llvm::sys::Memory::MF_WRITE
@ MF_WRITE
Definition: Memory.h:56
M
We currently emits eax Perhaps this is what we really should generate is Is imull three or four cycles eax eax The current instruction priority is based on pattern complexity The former is more complex because it folds a load so the latter will not be emitted Perhaps we should use AddedComplexity to give LEA32r a higher priority We should always try to match LEA first since the LEA matching code does some estimate to determine whether the match is profitable if we care more about code then imull is better It s two bytes shorter than movl leal On a Pentium M
Definition: README.txt:252
llvm::orc::shared::CWrapperFunctionResult
Definition: WrapperFunctionUtils.h:33
P
This currently compiles esp xmm0 movsd esp eax eax esp ret We should use not the dag combiner This is because dagcombine2 needs to be able to see through the X86ISD::Wrapper which DAGCombine can t really do The code for turning x load into a single vector load is target independent and should be moved to the dag combiner The code for turning x load into a vector load can only handle a direct load from a global or a direct load from the stack It should be generalized to handle any load from P
Definition: README-SSE.txt:411
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:329
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::orc::ExecutorAddr::getValue
uint64_t getValue() const
Definition: ExecutorAddress.h:105
llvm::DenseMapBase::erase
bool erase(const KeyT &Val)
Definition: DenseMap.h:302
llvm::sys::MemoryBlock
This class encapsulates the notion of a memory block which has an address and a size.
Definition: Memory.h:31
llvm::DenseMapBase::count
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
Definition: DenseMap.h:145
llvm::orc::rt::SPSSimpleExecutorMemoryManagerFinalizeSignature
shared::SPSError(shared::SPSExecutorAddr, shared::SPSFinalizeRequest) SPSSimpleExecutorMemoryManagerFinalizeSignature
Definition: OrcRTBridge.h:66
llvm::max
Expected< ExpressionValue > max(const ExpressionValue &Lhs, const ExpressionValue &Rhs)
Definition: FileCheck.cpp:337
llvm::Expected
Tagged union holding either a T or a Error.
Definition: APFloat.h:41
llvm::orc::tpctypes::FinalizeRequest::Actions
shared::AllocActions Actions
Definition: TargetProcessControlTypes.h:42
handle
then ret i32 result Tail recursion elimination should handle
Definition: README.txt:355
llvm::orc::rt::SimpleExecutorMemoryManagerInstanceName
const char * SimpleExecutorMemoryManagerInstanceName
Definition: OrcRTBridge.cpp:22
llvm::orc::rt_bootstrap::SimpleExecutorMemoryManager::addBootstrapSymbols
void addBootstrapSymbols(StringMap< ExecutorAddr > &M) override
Definition: SimpleExecutorMemoryManager.cpp:200
llvm::orc::rt::SimpleExecutorMemoryManagerFinalizeWrapperName
const char * SimpleExecutorMemoryManagerFinalizeWrapperName
Definition: OrcRTBridge.cpp:26
llvm::formatv
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
Definition: FormatVariadic.h:251
llvm::orc::rt::SimpleExecutorMemoryManagerDeallocateWrapperName
const char * SimpleExecutorMemoryManagerDeallocateWrapperName
Definition: OrcRTBridge.cpp:28
llvm::orc::tpctypes::FinalizeRequest
Definition: TargetProcessControlTypes.h:40
llvm::errorCodeToError
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition: Error.cpp:92
llvm::orc::rt::SPSSimpleExecutorMemoryManagerReserveSignature
shared::SPSExpected< shared::SPSExecutorAddr >(shared::SPSExecutorAddr, uint64_t) SPSSimpleExecutorMemoryManagerReserveSignature
Definition: OrcRTBridge.h:64
llvm::orc::ExecutorAddrDiff
uint64_t ExecutorAddrDiff
Definition: ExecutorAddress.h:28
llvm::orc::rt_bootstrap::SimpleExecutorMemoryManager::~SimpleExecutorMemoryManager
virtual ~SimpleExecutorMemoryManager()
Definition: SimpleExecutorMemoryManager.cpp:20
FormatVariadic.h
llvm::StringMap
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition: StringMap.h:110
llvm::orc::rt_bootstrap::SimpleExecutorMemoryManager::finalize
Error finalize(tpctypes::FinalizeRequest &FR)
Definition: SimpleExecutorMemoryManager.cpp:36
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< void *, Allocation >
I
#define I(x, y, z)
Definition: MD5.cpp:58
llvm::joinErrors
Error joinErrors(Error E1, Error E2)
Concatenate errors.
Definition: Error.h:426
llvm::DenseMapBase::find
iterator find(const_arg_type_t< KeyT > Val)
Definition: DenseMap.h:150
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
memcpy
<%struct.s * > cast struct s *S to sbyte *< sbyte * > sbyte uint cast struct s *agg result to sbyte *< sbyte * > sbyte uint cast struct s *memtmp to sbyte *< sbyte * > sbyte uint ret void llc ends up issuing two memcpy or custom lower memcpy(of small size) to be ldmia/stmia. I think option 2 is better but the current register allocator cannot allocate a chunk of registers at a time. A feasible temporary solution is to use specific physical registers at the lowering time for small(<
llvm::orc::tpctypes::FinalizeRequest::Segments
std::vector< SegFinalizeRequest > Segments
Definition: TargetProcessControlTypes.h:41
llvm::DenseMapBase::empty
bool empty() const
Definition: DenseMap.h:98
llvm::orc::rt_bootstrap::SimpleExecutorMemoryManager::deallocate
Error deallocate(const std::vector< ExecutorAddr > &Bases)
Definition: SimpleExecutorMemoryManager.cpp:151
llvm::min
Expected< ExpressionValue > min(const ExpressionValue &Lhs, const ExpressionValue &Rhs)
Definition: FileCheck.cpp:357
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:79
llvm::DenseMapBase::end
iterator end()
Definition: DenseMap.h:84
llvm::Error
Lightweight error class with error context and mandatory checking.
Definition: Error.h:155
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::orc::shared::makeMethodWrapperHandler
MethodWrapperHandler< RetT, ClassT, ArgTs... > makeMethodWrapperHandler(RetT(ClassT::*Method)(ArgTs...))
Create a MethodWrapperHandler object from the given method pointer.
Definition: WrapperFunctionUtils.h:617
llvm::orc::toSysMemoryProtectionFlags
sys::Memory::ProtectionFlags toSysMemoryProtectionFlags(MemProt MP)
Convert a MemProt value to a corresponding sys::Memory::ProtectionFlags value.
Definition: MemoryFlags.h:44
llvm::orc::rt_bootstrap::SimpleExecutorMemoryManager::allocate
Expected< ExecutorAddr > allocate(uint64_t Size)
Definition: SimpleExecutorMemoryManager.cpp:24
llvm::orc::rt_bootstrap::SimpleExecutorMemoryManager::shutdown
Error shutdown() override
Definition: SimpleExecutorMemoryManager.cpp:186
llvm::orc::MemProt::Exec
@ Exec
llvm::orc::rt::SimpleExecutorMemoryManagerReserveWrapperName
const char * SimpleExecutorMemoryManagerReserveWrapperName
Definition: OrcRTBridge.cpp:24
LLVM_UNLIKELY
#define LLVM_UNLIKELY(EXPR)
Definition: Compiler.h:210
OrcRTBridge.h
llvm::orc::rt::SPSSimpleExecutorMemoryManagerDeallocateSignature
shared::SPSError(shared::SPSExecutorAddr, shared::SPSSequence< shared::SPSExecutorAddr >) SPSSimpleExecutorMemoryManagerDeallocateSignature
Definition: OrcRTBridge.h:68
llvm::sampleprof::Base
@ Base
Definition: Discriminator.h:58