LLVM  14.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;
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<tpctypes::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.Deallocate.Func)
56  DeallocationActions.push_back(ActPair.Deallocate);
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  .Deallocate.runWithSPSRet());
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  memcpy(Mem, Seg.Content.data(), Seg.Content.size());
130  memset(Mem + Seg.Content.size(), 0, Seg.Size - Seg.Content.size());
132  if (auto EC = sys::Memory::protectMappedMemory(
133  {Mem, static_cast<size_t>(Seg.Size)},
135  return BailOut(errorCodeToError(EC));
136  if (Seg.Prot & tpctypes::WPF_Exec)
138  }
139 
140  // Run finalization actions.
141  for (auto &ActPair : FR.Actions) {
142  if (auto Err = ActPair.Finalize.runWithSPSRet())
143  return BailOut(std::move(Err));
144  ++SuccessfulFinalizationActions;
145  }
146 
147  return Error::success();
148 }
149 
151  const std::vector<ExecutorAddr> &Bases) {
152  std::vector<std::pair<void *, Allocation>> AllocPairs;
153  AllocPairs.reserve(Bases.size());
154 
155  // Get allocation to destory.
156  Error Err = Error::success();
157  {
158  std::lock_guard<std::mutex> Lock(M);
159  for (auto &Base : Bases) {
160  auto I = Allocations.find(Base.toPtr<void *>());
161 
162  // Check for missing allocation (effective a double free).
163  if (I != Allocations.end()) {
164  AllocPairs.push_back(std::move(*I));
165  Allocations.erase(I);
166  } else
167  Err = joinErrors(
168  std::move(Err),
169  make_error<StringError>("No allocation entry found "
170  "for " +
171  formatv("{0:x}", Base.getValue()),
173  }
174  }
175 
176  while (!AllocPairs.empty()) {
177  auto &P = AllocPairs.back();
178  Err = joinErrors(std::move(Err), deallocateImpl(P.first, P.second));
179  AllocPairs.pop_back();
180  }
181 
182  return Err;
183 }
184 
186 
187  AllocationsMap AM;
188  {
189  std::lock_guard<std::mutex> Lock(M);
190  AM = std::move(Allocations);
191  }
192 
193  Error Err = Error::success();
194  for (auto &KV : AM)
195  Err = joinErrors(std::move(Err), deallocateImpl(KV.first, KV.second));
196  return Err;
197 }
198 
203  ExecutorAddr::fromPtr(&reserveWrapper);
205  ExecutorAddr::fromPtr(&finalizeWrapper);
207  ExecutorAddr::fromPtr(&deallocateWrapper);
208 }
209 
210 Error SimpleExecutorMemoryManager::deallocateImpl(void *Base, Allocation &A) {
211  Error Err = Error::success();
212 
213  while (!A.DeallocationActions.empty()) {
214  Err = joinErrors(std::move(Err),
215  A.DeallocationActions.back().runWithSPSRet());
216  A.DeallocationActions.pop_back();
217  }
218 
219  sys::MemoryBlock MB(Base, A.Size);
220  if (auto EC = sys::Memory::releaseMappedMemory(MB))
221  Err = joinErrors(std::move(Err), errorCodeToError(EC));
222 
223  return Err;
224 }
225 
227 SimpleExecutorMemoryManager::reserveWrapper(const char *ArgData,
228  size_t ArgSize) {
229  return shared::WrapperFunction<
231  handle(ArgData, ArgSize,
234  .release();
235 }
236 
238 SimpleExecutorMemoryManager::finalizeWrapper(const char *ArgData,
239  size_t ArgSize) {
240  return shared::WrapperFunction<
242  handle(ArgData, ArgSize,
245  .release();
246 }
247 
249 SimpleExecutorMemoryManager::deallocateWrapper(const char *ArgData,
250  size_t ArgSize) {
251  return shared::WrapperFunction<
253  handle(ArgData, ArgSize,
256  .release();
257 }
258 
259 } // namespace rt_bootstrap
260 } // end namespace orc
261 } // end namespace llvm
llvm::Check::Size
@ Size
Definition: FileCheck.h:73
llvm::orc::ExecutorAddr
Represents an address in the executor process.
Definition: ExecutorAddress.h:37
SimpleExecutorMemoryManager.h
llvm::orc::ExecutorAddrDiff
Represents the difference between two addresses in the executor process.
Definition: ExecutorAddress.h:25
llvm::sys::Memory::MF_READ
@ MF_READ
Definition: Memory.h:55
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AllocatorList.h:23
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: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::orc::ExecutorAddr::getValue
uint64_t getValue() const
Definition: ExecutorAddress.h:60
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:57
llvm::Expected
Tagged union holding either a T or a Error.
Definition: APFloat.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:21
llvm::orc::rt_bootstrap::SimpleExecutorMemoryManager::addBootstrapSymbols
void addBootstrapSymbols(StringMap< ExecutorAddr > &M) override
Definition: SimpleExecutorMemoryManager.cpp:199
llvm::orc::rt::SimpleExecutorMemoryManagerFinalizeWrapperName
const char * SimpleExecutorMemoryManagerFinalizeWrapperName
Definition: OrcRTBridge.cpp:25
llvm::Lock
static sys::Mutex Lock
Definition: NVPTXUtilities.cpp:39
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:250
llvm::orc::rt::SimpleExecutorMemoryManagerDeallocateWrapperName
const char * SimpleExecutorMemoryManagerDeallocateWrapperName
Definition: OrcRTBridge.cpp:27
llvm::orc::tpctypes::FinalizeRequest
Definition: TargetProcessControlTypes.h:123
llvm::orc::tpctypes::fromWireProtectionFlags
sys::Memory::ProtectionFlags fromWireProtectionFlags(WireProtectionFlags WPF)
Definition: TargetProcessControlTypes.h:53
llvm::errorCodeToError
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition: Error.cpp:90
llvm::orc::rt::SPSSimpleExecutorMemoryManagerReserveSignature
shared::SPSExpected< shared::SPSExecutorAddr >(shared::SPSExecutorAddr, uint64_t) SPSSimpleExecutorMemoryManagerReserveSignature
Definition: OrcRTBridge.h:55
llvm::orc::rt_bootstrap::SimpleExecutorMemoryManager::~SimpleExecutorMemoryManager
virtual ~SimpleExecutorMemoryManager()
Definition: SimpleExecutorMemoryManager.cpp:20
llvm::orc::ExecutorAddr::fromPtr
static ExecutorAddr fromPtr(T *Value)
Create an ExecutorAddr from the given pointer.
Definition: ExecutorAddress.h:46
FormatVariadic.h
llvm::StringMap
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition: StringMap.h:108
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:59
llvm::joinErrors
Error joinErrors(Error E1, Error E2)
Concatenate errors.
Definition: Error.h:428
llvm::orc::tpctypes::FinalizeRequest::Actions
std::vector< AllocationActionsPair > Actions
Definition: TargetProcessControlTypes.h:125
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:124
llvm::orc::rt_bootstrap::SimpleExecutorMemoryManager::deallocate
Error deallocate(const std::vector< ExecutorAddr > &Bases)
Definition: SimpleExecutorMemoryManager.cpp:150
llvm::min
Expected< ExpressionValue > min(const ExpressionValue &Lhs, const ExpressionValue &Rhs)
Definition: FileCheck.cpp:357
llvm::DenseMapBase::empty
LLVM_NODISCARD bool empty() const
Definition: DenseMap.h:97
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::DenseMapBase::end
iterator end()
Definition: DenseMap.h:83
llvm::Error
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
llvm::orc::tpctypes::WPF_Exec
@ WPF_Exec
Definition: TargetProcessControlTypes.h:35
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::orc::shared::makeMethodWrapperHandler
MethodWrapperHandler< RetT, ClassT, ArgTs... > makeMethodWrapperHandler(RetT(ClassT::*Method)(ArgTs...))
Create a MethodWrapperHandler object from the given method pointer.
Definition: WrapperFunctionUtils.h:608
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:185
llvm::orc::rt::SimpleExecutorMemoryManagerReserveWrapperName
const char * SimpleExecutorMemoryManagerReserveWrapperName
Definition: OrcRTBridge.cpp:23
LLVM_UNLIKELY
#define LLVM_UNLIKELY(EXPR)
Definition: Compiler.h:226
OrcRTBridge.h
llvm::orc::rt::SPSSimpleExecutorMemoryManagerDeallocateSignature
shared::SPSError(shared::SPSExecutorAddr, shared::SPSSequence< shared::SPSExecutorAddr >) SPSSimpleExecutorMemoryManagerDeallocateSignature
Definition: OrcRTBridge.h:59
llvm::sampleprof::Base
@ Base
Definition: Discriminator.h:58