12ce73f13SLang Hames //===- SimpleExecuorMemoryManagare.cpp - Simple executor-side memory mgmt -===//
278b083dbSLang Hames //
378b083dbSLang Hames // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
478b083dbSLang Hames // See https://llvm.org/LICENSE.txt for license information.
578b083dbSLang Hames // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
678b083dbSLang Hames //
778b083dbSLang Hames //===----------------------------------------------------------------------===//
878b083dbSLang Hames 
978b083dbSLang Hames #include "llvm/ExecutionEngine/Orc/TargetProcess/SimpleExecutorMemoryManager.h"
1078b083dbSLang Hames 
1178b083dbSLang Hames #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
1278b083dbSLang Hames #include "llvm/Support/FormatVariadic.h"
1378b083dbSLang Hames 
1478b083dbSLang Hames #define DEBUG_TYPE "orc"
1578b083dbSLang Hames 
1678b083dbSLang Hames namespace llvm {
1778b083dbSLang Hames namespace orc {
1878b083dbSLang Hames namespace rt_bootstrap {
1978b083dbSLang Hames 
2078b083dbSLang Hames SimpleExecutorMemoryManager::~SimpleExecutorMemoryManager() {
2178b083dbSLang Hames   assert(Allocations.empty() && "shutdown not called?");
2278b083dbSLang Hames }
2378b083dbSLang Hames 
24*ef391df2SLang Hames Expected<ExecutorAddr> SimpleExecutorMemoryManager::allocate(uint64_t Size) {
2578b083dbSLang Hames   std::error_code EC;
2678b083dbSLang Hames   auto MB = sys::Memory::allocateMappedMemory(
2778b083dbSLang Hames       Size, 0, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC);
2878b083dbSLang Hames   if (EC)
2978b083dbSLang Hames     return errorCodeToError(EC);
3078b083dbSLang Hames   std::lock_guard<std::mutex> Lock(M);
3178b083dbSLang Hames   assert(!Allocations.count(MB.base()) && "Duplicate allocation addr");
3278b083dbSLang Hames   Allocations[MB.base()].Size = Size;
33*ef391df2SLang Hames   return ExecutorAddr::fromPtr(MB.base());
3478b083dbSLang Hames }
3578b083dbSLang Hames 
3678b083dbSLang Hames Error SimpleExecutorMemoryManager::finalize(tpctypes::FinalizeRequest &FR) {
37*ef391df2SLang Hames   ExecutorAddr Base(~0ULL);
3878b083dbSLang Hames   std::vector<tpctypes::SupportFunctionCall> DeallocationActions;
3978b083dbSLang Hames   size_t SuccessfulFinalizationActions = 0;
4078b083dbSLang Hames 
4178b083dbSLang Hames   for (auto &Seg : FR.Segments)
4278b083dbSLang Hames     Base = std::min(Base, Seg.Addr);
4378b083dbSLang Hames 
4478b083dbSLang Hames   for (auto &ActPair : FR.Actions)
4578b083dbSLang Hames     if (ActPair.Deallocate.Func)
4678b083dbSLang Hames       DeallocationActions.push_back(ActPair.Deallocate);
4778b083dbSLang Hames 
4878b083dbSLang Hames   // Get the Allocation for this finalization.
4978b083dbSLang Hames   size_t AllocSize = 0;
5078b083dbSLang Hames   {
5178b083dbSLang Hames     std::lock_guard<std::mutex> Lock(M);
5278b083dbSLang Hames     auto I = Allocations.find(Base.toPtr<void *>());
5378b083dbSLang Hames     if (I == Allocations.end())
5478b083dbSLang Hames       return make_error<StringError>("Attempt to finalize unrecognized "
5578b083dbSLang Hames                                      "allocation " +
5678b083dbSLang Hames                                          formatv("{0:x}", Base.getValue()),
5778b083dbSLang Hames                                      inconvertibleErrorCode());
5878b083dbSLang Hames     AllocSize = I->second.Size;
5978b083dbSLang Hames     I->second.DeallocationActions = std::move(DeallocationActions);
6078b083dbSLang Hames   }
61*ef391df2SLang Hames   ExecutorAddr AllocEnd = Base + ExecutorAddrDiff(AllocSize);
6278b083dbSLang Hames 
6378b083dbSLang Hames   // Bail-out function: this will run deallocation actions corresponding to any
6478b083dbSLang Hames   // completed finalization actions, then deallocate memory.
6578b083dbSLang Hames   auto BailOut = [&](Error Err) {
6678b083dbSLang Hames     std::pair<void *, Allocation> AllocToDestroy;
6778b083dbSLang Hames 
6878b083dbSLang Hames     // Get allocation to destory.
6978b083dbSLang Hames     {
7078b083dbSLang Hames       std::lock_guard<std::mutex> Lock(M);
7178b083dbSLang Hames       auto I = Allocations.find(Base.toPtr<void *>());
7278b083dbSLang Hames 
7378b083dbSLang Hames       // Check for missing allocation (effective a double free).
7478b083dbSLang Hames       if (I == Allocations.end())
7578b083dbSLang Hames         return joinErrors(
7678b083dbSLang Hames             std::move(Err),
7778b083dbSLang Hames             make_error<StringError>("No allocation entry found "
7878b083dbSLang Hames                                     "for " +
7978b083dbSLang Hames                                         formatv("{0:x}", Base.getValue()),
8078b083dbSLang Hames                                     inconvertibleErrorCode()));
8178b083dbSLang Hames       AllocToDestroy = std::move(*I);
8278b083dbSLang Hames       Allocations.erase(I);
8378b083dbSLang Hames     }
8478b083dbSLang Hames 
8578b083dbSLang Hames     // Run deallocation actions for all completed finalization actions.
8678b083dbSLang Hames     while (SuccessfulFinalizationActions)
8778b083dbSLang Hames       Err = joinErrors(
8878b083dbSLang Hames           std::move(Err),
8978b083dbSLang Hames           FR.Actions[--SuccessfulFinalizationActions].Deallocate.run());
9078b083dbSLang Hames 
9178b083dbSLang Hames     // Deallocate memory.
9278b083dbSLang Hames     sys::MemoryBlock MB(AllocToDestroy.first, AllocToDestroy.second.Size);
9378b083dbSLang Hames     if (auto EC = sys::Memory::releaseMappedMemory(MB))
9478b083dbSLang Hames       Err = joinErrors(std::move(Err), errorCodeToError(EC));
9578b083dbSLang Hames 
9678b083dbSLang Hames     return Err;
9778b083dbSLang Hames   };
9878b083dbSLang Hames 
9978b083dbSLang Hames   // Copy content and apply permissions.
10078b083dbSLang Hames   for (auto &Seg : FR.Segments) {
10178b083dbSLang Hames 
10278b083dbSLang Hames     // Check segment ranges.
10378b083dbSLang Hames     if (LLVM_UNLIKELY(Seg.Size < Seg.Content.size()))
10478b083dbSLang Hames       return BailOut(make_error<StringError>(
10578b083dbSLang Hames           formatv("Segment {0:x} content size ({1:x} bytes) "
10678b083dbSLang Hames                   "exceeds segment size ({2:x} bytes)",
10778b083dbSLang Hames                   Seg.Addr.getValue(), Seg.Content.size(), Seg.Size),
10878b083dbSLang Hames           inconvertibleErrorCode()));
109*ef391df2SLang Hames     ExecutorAddr SegEnd = Seg.Addr + ExecutorAddrDiff(Seg.Size);
11078b083dbSLang Hames     if (LLVM_UNLIKELY(Seg.Addr < Base || SegEnd > AllocEnd))
11178b083dbSLang Hames       return BailOut(make_error<StringError>(
11278b083dbSLang Hames           formatv("Segment {0:x} -- {1:x} crosses boundary of "
11378b083dbSLang Hames                   "allocation {2:x} -- {3:x}",
11478b083dbSLang Hames                   Seg.Addr.getValue(), SegEnd.getValue(), Base.getValue(),
11578b083dbSLang Hames                   AllocEnd.getValue()),
11678b083dbSLang Hames           inconvertibleErrorCode()));
11778b083dbSLang Hames 
11878b083dbSLang Hames     char *Mem = Seg.Addr.toPtr<char *>();
11978b083dbSLang Hames     memcpy(Mem, Seg.Content.data(), Seg.Content.size());
12078b083dbSLang Hames     memset(Mem + Seg.Content.size(), 0, Seg.Size - Seg.Content.size());
12178b083dbSLang Hames     assert(Seg.Size <= std::numeric_limits<size_t>::max());
12278b083dbSLang Hames     if (auto EC = sys::Memory::protectMappedMemory(
12378b083dbSLang Hames             {Mem, static_cast<size_t>(Seg.Size)},
12478b083dbSLang Hames             tpctypes::fromWireProtectionFlags(Seg.Prot)))
12578b083dbSLang Hames       return BailOut(errorCodeToError(EC));
12678b083dbSLang Hames     if (Seg.Prot & tpctypes::WPF_Exec)
12778b083dbSLang Hames       sys::Memory::InvalidateInstructionCache(Mem, Seg.Size);
12878b083dbSLang Hames   }
12978b083dbSLang Hames 
13078b083dbSLang Hames   // Run finalization actions.
13178b083dbSLang Hames   for (auto &ActPair : FR.Actions) {
13278b083dbSLang Hames     if (auto Err = ActPair.Finalize.run())
13378b083dbSLang Hames       return BailOut(std::move(Err));
13478b083dbSLang Hames     ++SuccessfulFinalizationActions;
13578b083dbSLang Hames   }
13678b083dbSLang Hames 
13778b083dbSLang Hames   return Error::success();
13878b083dbSLang Hames }
13978b083dbSLang Hames 
14078b083dbSLang Hames Error SimpleExecutorMemoryManager::deallocate(
141*ef391df2SLang Hames     const std::vector<ExecutorAddr> &Bases) {
14278b083dbSLang Hames   std::vector<std::pair<void *, Allocation>> AllocPairs;
14378b083dbSLang Hames   AllocPairs.reserve(Bases.size());
14478b083dbSLang Hames 
14578b083dbSLang Hames   // Get allocation to destory.
14678b083dbSLang Hames   Error Err = Error::success();
14778b083dbSLang Hames   {
14878b083dbSLang Hames     std::lock_guard<std::mutex> Lock(M);
14978b083dbSLang Hames     for (auto &Base : Bases) {
15078b083dbSLang Hames       auto I = Allocations.find(Base.toPtr<void *>());
15178b083dbSLang Hames 
15278b083dbSLang Hames       // Check for missing allocation (effective a double free).
15378b083dbSLang Hames       if (I != Allocations.end()) {
15478b083dbSLang Hames         AllocPairs.push_back(std::move(*I));
15578b083dbSLang Hames         Allocations.erase(I);
15678b083dbSLang Hames       } else
15778b083dbSLang Hames         Err = joinErrors(
15878b083dbSLang Hames             std::move(Err),
15978b083dbSLang Hames             make_error<StringError>("No allocation entry found "
16078b083dbSLang Hames                                     "for " +
16178b083dbSLang Hames                                         formatv("{0:x}", Base.getValue()),
16278b083dbSLang Hames                                     inconvertibleErrorCode()));
16378b083dbSLang Hames     }
16478b083dbSLang Hames   }
16578b083dbSLang Hames 
16678b083dbSLang Hames   while (!AllocPairs.empty()) {
16778b083dbSLang Hames     auto &P = AllocPairs.back();
16878b083dbSLang Hames     Err = joinErrors(std::move(Err), deallocateImpl(P.first, P.second));
16978b083dbSLang Hames     AllocPairs.pop_back();
17078b083dbSLang Hames   }
17178b083dbSLang Hames 
17278b083dbSLang Hames   return Err;
17378b083dbSLang Hames }
17478b083dbSLang Hames 
17578b083dbSLang Hames Error SimpleExecutorMemoryManager::shutdown() {
17678b083dbSLang Hames 
17778b083dbSLang Hames   AllocationsMap AM;
17878b083dbSLang Hames   {
17978b083dbSLang Hames     std::lock_guard<std::mutex> Lock(M);
18078b083dbSLang Hames     AM = std::move(Allocations);
18178b083dbSLang Hames   }
18278b083dbSLang Hames 
18378b083dbSLang Hames   Error Err = Error::success();
18478b083dbSLang Hames   for (auto &KV : AM)
18578b083dbSLang Hames     Err = joinErrors(std::move(Err), deallocateImpl(KV.first, KV.second));
18678b083dbSLang Hames   return Err;
18778b083dbSLang Hames }
18878b083dbSLang Hames 
18978b083dbSLang Hames void SimpleExecutorMemoryManager::addBootstrapSymbols(
190*ef391df2SLang Hames     StringMap<ExecutorAddr> &M) {
191*ef391df2SLang Hames   M[rt::SimpleExecutorMemoryManagerInstanceName] = ExecutorAddr::fromPtr(this);
19278b083dbSLang Hames   M[rt::SimpleExecutorMemoryManagerReserveWrapperName] =
193*ef391df2SLang Hames       ExecutorAddr::fromPtr(&reserveWrapper);
19478b083dbSLang Hames   M[rt::SimpleExecutorMemoryManagerFinalizeWrapperName] =
195*ef391df2SLang Hames       ExecutorAddr::fromPtr(&finalizeWrapper);
19678b083dbSLang Hames   M[rt::SimpleExecutorMemoryManagerDeallocateWrapperName] =
197*ef391df2SLang Hames       ExecutorAddr::fromPtr(&deallocateWrapper);
19878b083dbSLang Hames }
19978b083dbSLang Hames 
20078b083dbSLang Hames Error SimpleExecutorMemoryManager::deallocateImpl(void *Base, Allocation &A) {
20178b083dbSLang Hames   Error Err = Error::success();
20278b083dbSLang Hames 
20378b083dbSLang Hames   while (!A.DeallocationActions.empty()) {
20478b083dbSLang Hames     Err = joinErrors(std::move(Err), A.DeallocationActions.back().run());
20578b083dbSLang Hames     A.DeallocationActions.pop_back();
20678b083dbSLang Hames   }
20778b083dbSLang Hames 
20878b083dbSLang Hames   sys::MemoryBlock MB(Base, A.Size);
20978b083dbSLang Hames   if (auto EC = sys::Memory::releaseMappedMemory(MB))
21078b083dbSLang Hames     Err = joinErrors(std::move(Err), errorCodeToError(EC));
21178b083dbSLang Hames 
21278b083dbSLang Hames   return Err;
21378b083dbSLang Hames }
21478b083dbSLang Hames 
21578b083dbSLang Hames llvm::orc::shared::detail::CWrapperFunctionResult
21678b083dbSLang Hames SimpleExecutorMemoryManager::reserveWrapper(const char *ArgData,
21778b083dbSLang Hames                                             size_t ArgSize) {
21878b083dbSLang Hames   return shared::WrapperFunction<
21978b083dbSLang Hames              rt::SPSSimpleExecutorMemoryManagerReserveSignature>::
22078b083dbSLang Hames       handle(ArgData, ArgSize,
22178b083dbSLang Hames              shared::makeMethodWrapperHandler(
22278b083dbSLang Hames                  &SimpleExecutorMemoryManager::allocate))
22378b083dbSLang Hames           .release();
22478b083dbSLang Hames }
22578b083dbSLang Hames 
22678b083dbSLang Hames llvm::orc::shared::detail::CWrapperFunctionResult
22778b083dbSLang Hames SimpleExecutorMemoryManager::finalizeWrapper(const char *ArgData,
22878b083dbSLang Hames                                              size_t ArgSize) {
22978b083dbSLang Hames   return shared::WrapperFunction<
23078b083dbSLang Hames              rt::SPSSimpleExecutorMemoryManagerFinalizeSignature>::
23178b083dbSLang Hames       handle(ArgData, ArgSize,
23278b083dbSLang Hames              shared::makeMethodWrapperHandler(
23378b083dbSLang Hames                  &SimpleExecutorMemoryManager::finalize))
23478b083dbSLang Hames           .release();
23578b083dbSLang Hames }
23678b083dbSLang Hames 
23778b083dbSLang Hames llvm::orc::shared::detail::CWrapperFunctionResult
23878b083dbSLang Hames SimpleExecutorMemoryManager::deallocateWrapper(const char *ArgData,
23978b083dbSLang Hames                                                size_t ArgSize) {
24078b083dbSLang Hames   return shared::WrapperFunction<
24178b083dbSLang Hames              rt::SPSSimpleExecutorMemoryManagerDeallocateSignature>::
24278b083dbSLang Hames       handle(ArgData, ArgSize,
24378b083dbSLang Hames              shared::makeMethodWrapperHandler(
24478b083dbSLang Hames                  &SimpleExecutorMemoryManager::deallocate))
24578b083dbSLang Hames           .release();
24678b083dbSLang Hames }
24778b083dbSLang Hames 
24878b083dbSLang Hames } // namespace rt_bootstrap
24978b083dbSLang Hames } // end namespace orc
25078b083dbSLang Hames } // end namespace llvm
251