1//===- SimpleExecuorMemoryManagare.cpp - Simple executor-side memory mgmt -===// 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 7//===----------------------------------------------------------------------===// 14#define DEBUG_TYPE "orc" 18namespacert_bootstrap {
21assert(Allocations.
empty() &&
"shutdown not called?");
30 std::lock_guard<std::mutex> Lock(M);
31assert(!Allocations.
count(MB.base()) &&
"Duplicate allocation addr");
32 Allocations[MB.base()].Size =
Size;
38 std::vector<shared::WrapperFunctionCall> DeallocationActions;
39size_t SuccessfulFinalizationActions = 0;
42// NOTE: Finalizing nothing is currently a no-op. Should it be an error? 46return make_error<StringError>(
"Finalization actions attached to empty " 47"finalization request",
56 DeallocationActions.push_back(ActPair.Dealloc);
58// Get the Allocation for this finalization. 61 std::lock_guard<std::mutex> Lock(M);
62autoI = Allocations.
find(
Base.toPtr<
void *>());
63if (
I == Allocations.
end())
64return make_error<StringError>(
"Attempt to finalize unrecognized " 68 AllocSize =
I->second.Size;
69I->second.DeallocationActions = std::move(DeallocationActions);
73// Bail-out function: this will run deallocation actions corresponding to any 74// completed finalization actions, then deallocate memory. 75auto BailOut = [&](
Error Err) {
76 std::pair<void *, Allocation> AllocToDestroy;
78// Get allocation to destroy. 80 std::lock_guard<std::mutex> Lock(M);
81autoI = Allocations.
find(
Base.toPtr<
void *>());
83// Check for missing allocation (effective a double free). 84if (
I == Allocations.
end())
87 make_error<StringError>(
"No allocation entry found " 91 AllocToDestroy = std::move(*
I);
95// Run deallocation actions for all completed finalization actions. 96while (SuccessfulFinalizationActions)
99 .Dealloc.runWithSPSRetErrorMerged());
109// Copy content and apply permissions. 112// Check segment ranges. 114return BailOut(make_error<StringError>(
115formatv(
"Segment {0:x} content size ({1:x} bytes) " 116"exceeds segment size ({2:x} bytes)",
117 Seg.Addr.getValue(), Seg.Content.size(), Seg.Size),
121return BailOut(make_error<StringError>(
122formatv(
"Segment {0:x} -- {1:x} crosses boundary of " 123"allocation {2:x} -- {3:x}",
128char *Mem = Seg.Addr.toPtr<
char *>();
129if (!Seg.Content.empty())
130 memcpy(Mem, Seg.Content.data(), Seg.Content.size());
131 memset(Mem + Seg.Content.size(), 0, Seg.Size - Seg.Content.size());
132assert(Seg.Size <= std::numeric_limits<size_t>::max());
134 {Mem,
static_cast<size_t>(Seg.Size)},
141// Run finalization actions. 142for (
auto &ActPair : FR.
Actions) {
143if (
auto Err = ActPair.Finalize.runWithSPSRetErrorMerged())
144return BailOut(std::move(Err));
145 ++SuccessfulFinalizationActions;
152const std::vector<ExecutorAddr> &Bases) {
153 std::vector<std::pair<void *, Allocation>> AllocPairs;
154 AllocPairs.reserve(Bases.size());
156// Get allocation to destroy. 159 std::lock_guard<std::mutex> Lock(M);
160for (
auto &
Base : Bases) {
161autoI = Allocations.
find(
Base.toPtr<
void *>());
163// Check for missing allocation (effective a double free). 164if (
I != Allocations.
end()) {
165 AllocPairs.push_back(std::move(*
I));
170 make_error<StringError>(
"No allocation entry found " 177while (!AllocPairs.empty()) {
178auto &
P = AllocPairs.back();
179 Err =
joinErrors(std::move(Err), deallocateImpl(
P.first,
P.second));
180 AllocPairs.pop_back();
190 std::lock_guard<std::mutex> Lock(M);
191 AM = std::move(Allocations);
196 Err =
joinErrors(std::move(Err), deallocateImpl(KV.first, KV.second));
211Error SimpleExecutorMemoryManager::deallocateImpl(
void *
Base, Allocation &
A) {
214while (!
A.DeallocationActions.empty()) {
216A.DeallocationActions.back().runWithSPSRetErrorMerged());
217A.DeallocationActions.pop_back();
228SimpleExecutorMemoryManager::reserveWrapper(
constchar *ArgData,
230return shared::WrapperFunction<
232 handle(ArgData, ArgSize,
239SimpleExecutorMemoryManager::finalizeWrapper(
constchar *ArgData,
241return shared::WrapperFunction<
243 handle(ArgData, ArgSize,
250SimpleExecutorMemoryManager::deallocateWrapper(
constchar *ArgData,
252return shared::WrapperFunction<
254 handle(ArgData, ArgSize,
260}
// namespace rt_bootstrap 262}
// end namespace llvm static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
#define LLVM_UNLIKELY(EXPR)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
iterator find(const_arg_type_t< KeyT > Val)
bool erase(const KeyT &Val)
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Represents an address in the executor process.
uint64_t getValue() const
static ExecutorAddr fromPtr(T *Ptr, UnwrapFn &&Unwrap=UnwrapFn())
Create an ExecutorAddr from the given pointer.
Error finalize(tpctypes::FinalizeRequest &FR)
Error deallocate(const std::vector< ExecutorAddr > &Bases)
Error shutdown() override
Expected< ExecutorAddr > allocate(uint64_t Size)
virtual ~SimpleExecutorMemoryManager()
void addBootstrapSymbols(StringMap< ExecutorAddr > &M) override
This class encapsulates the notion of a memory block which has an address and a size.
static std::error_code releaseMappedMemory(MemoryBlock &Block)
This method releases a block of memory that was allocated with the allocateMappedMemory method.
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....
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...
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.
shared::SPSExpected< shared::SPSExecutorAddr >(shared::SPSExecutorAddr, uint64_t) SPSSimpleExecutorMemoryManagerReserveSignature
const char * SimpleExecutorMemoryManagerFinalizeWrapperName
const char * SimpleExecutorMemoryManagerDeallocateWrapperName
const char * SimpleExecutorMemoryManagerReserveWrapperName
shared::SPSError(shared::SPSExecutorAddr, shared::SPSFinalizeRequest) SPSSimpleExecutorMemoryManagerFinalizeSignature
const char * SimpleExecutorMemoryManagerInstanceName
shared::SPSError(shared::SPSExecutorAddr, shared::SPSSequence< shared::SPSExecutorAddr >) SPSSimpleExecutorMemoryManagerDeallocateSignature
MethodWrapperHandler< RetT, ClassT, ArgTs... > makeMethodWrapperHandler(RetT(ClassT::*Method)(ArgTs...))
Create a MethodWrapperHandler object from the given method pointer.
uint64_t ExecutorAddrDiff
sys::Memory::ProtectionFlags toSysMemoryProtectionFlags(MemProt MP)
Convert a MemProt value to a corresponding sys::Memory::ProtectionFlags value.
This is an optimization pass for GlobalISel generic memory operations.
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
Error joinErrors(Error E1, Error E2)
Concatenate errors.
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
std::vector< SegFinalizeRequest > Segments
shared::AllocActions Actions