SimpleExecutorMemoryManager.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  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. #include "llvm/ExecutionEngine/Orc/TargetProcess/SimpleExecutorMemoryManager.h"
  9. #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
  10. #include "llvm/Support/FormatVariadic.h"
  11. #define DEBUG_TYPE "orc"
  12. namespace llvm {
  13. namespace orc {
  14. namespace rt_bootstrap {
  15. SimpleExecutorMemoryManager::~SimpleExecutorMemoryManager() {
  16. assert(Allocations.empty() && "shutdown not called?");
  17. }
  18. Expected<ExecutorAddr> SimpleExecutorMemoryManager::allocate(uint64_t Size) {
  19. std::error_code EC;
  20. auto MB = sys::Memory::allocateMappedMemory(
  21. Size, nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC);
  22. if (EC)
  23. return errorCodeToError(EC);
  24. std::lock_guard<std::mutex> Lock(M);
  25. assert(!Allocations.count(MB.base()) && "Duplicate allocation addr");
  26. Allocations[MB.base()].Size = Size;
  27. return ExecutorAddr::fromPtr(MB.base());
  28. }
  29. Error SimpleExecutorMemoryManager::finalize(tpctypes::FinalizeRequest &FR) {
  30. ExecutorAddr Base(~0ULL);
  31. std::vector<shared::WrapperFunctionCall> DeallocationActions;
  32. size_t SuccessfulFinalizationActions = 0;
  33. if (FR.Segments.empty()) {
  34. // NOTE: Finalizing nothing is currently a no-op. Should it be an error?
  35. if (FR.Actions.empty())
  36. return Error::success();
  37. else
  38. return make_error<StringError>("Finalization actions attached to empty "
  39. "finalization request",
  40. inconvertibleErrorCode());
  41. }
  42. for (auto &Seg : FR.Segments)
  43. Base = std::min(Base, Seg.Addr);
  44. for (auto &ActPair : FR.Actions)
  45. if (ActPair.Dealloc)
  46. DeallocationActions.push_back(ActPair.Dealloc);
  47. // Get the Allocation for this finalization.
  48. size_t AllocSize = 0;
  49. {
  50. std::lock_guard<std::mutex> Lock(M);
  51. auto I = Allocations.find(Base.toPtr<void *>());
  52. if (I == Allocations.end())
  53. return make_error<StringError>("Attempt to finalize unrecognized "
  54. "allocation " +
  55. formatv("{0:x}", Base.getValue()),
  56. inconvertibleErrorCode());
  57. AllocSize = I->second.Size;
  58. I->second.DeallocationActions = std::move(DeallocationActions);
  59. }
  60. ExecutorAddr AllocEnd = Base + ExecutorAddrDiff(AllocSize);
  61. // Bail-out function: this will run deallocation actions corresponding to any
  62. // completed finalization actions, then deallocate memory.
  63. auto BailOut = [&](Error Err) {
  64. std::pair<void *, Allocation> AllocToDestroy;
  65. // Get allocation to destory.
  66. {
  67. std::lock_guard<std::mutex> Lock(M);
  68. auto I = Allocations.find(Base.toPtr<void *>());
  69. // Check for missing allocation (effective a double free).
  70. if (I == Allocations.end())
  71. return joinErrors(
  72. std::move(Err),
  73. make_error<StringError>("No allocation entry found "
  74. "for " +
  75. formatv("{0:x}", Base.getValue()),
  76. inconvertibleErrorCode()));
  77. AllocToDestroy = std::move(*I);
  78. Allocations.erase(I);
  79. }
  80. // Run deallocation actions for all completed finalization actions.
  81. while (SuccessfulFinalizationActions)
  82. Err =
  83. joinErrors(std::move(Err), FR.Actions[--SuccessfulFinalizationActions]
  84. .Dealloc.runWithSPSRetErrorMerged());
  85. // Deallocate memory.
  86. sys::MemoryBlock MB(AllocToDestroy.first, AllocToDestroy.second.Size);
  87. if (auto EC = sys::Memory::releaseMappedMemory(MB))
  88. Err = joinErrors(std::move(Err), errorCodeToError(EC));
  89. return Err;
  90. };
  91. // Copy content and apply permissions.
  92. for (auto &Seg : FR.Segments) {
  93. // Check segment ranges.
  94. if (LLVM_UNLIKELY(Seg.Size < Seg.Content.size()))
  95. return BailOut(make_error<StringError>(
  96. formatv("Segment {0:x} content size ({1:x} bytes) "
  97. "exceeds segment size ({2:x} bytes)",
  98. Seg.Addr.getValue(), Seg.Content.size(), Seg.Size),
  99. inconvertibleErrorCode()));
  100. ExecutorAddr SegEnd = Seg.Addr + ExecutorAddrDiff(Seg.Size);
  101. if (LLVM_UNLIKELY(Seg.Addr < Base || SegEnd > AllocEnd))
  102. return BailOut(make_error<StringError>(
  103. formatv("Segment {0:x} -- {1:x} crosses boundary of "
  104. "allocation {2:x} -- {3:x}",
  105. Seg.Addr.getValue(), SegEnd.getValue(), Base.getValue(),
  106. AllocEnd.getValue()),
  107. inconvertibleErrorCode()));
  108. char *Mem = Seg.Addr.toPtr<char *>();
  109. if (!Seg.Content.empty())
  110. memcpy(Mem, Seg.Content.data(), Seg.Content.size());
  111. memset(Mem + Seg.Content.size(), 0, Seg.Size - Seg.Content.size());
  112. assert(Seg.Size <= std::numeric_limits<size_t>::max());
  113. if (auto EC = sys::Memory::protectMappedMemory(
  114. {Mem, static_cast<size_t>(Seg.Size)},
  115. toSysMemoryProtectionFlags(Seg.AG.getMemProt())))
  116. return BailOut(errorCodeToError(EC));
  117. if ((Seg.AG.getMemProt() & MemProt::Exec) == MemProt::Exec)
  118. sys::Memory::InvalidateInstructionCache(Mem, Seg.Size);
  119. }
  120. // Run finalization actions.
  121. for (auto &ActPair : FR.Actions) {
  122. if (auto Err = ActPair.Finalize.runWithSPSRetErrorMerged())
  123. return BailOut(std::move(Err));
  124. ++SuccessfulFinalizationActions;
  125. }
  126. return Error::success();
  127. }
  128. Error SimpleExecutorMemoryManager::deallocate(
  129. const std::vector<ExecutorAddr> &Bases) {
  130. std::vector<std::pair<void *, Allocation>> AllocPairs;
  131. AllocPairs.reserve(Bases.size());
  132. // Get allocation to destory.
  133. Error Err = Error::success();
  134. {
  135. std::lock_guard<std::mutex> Lock(M);
  136. for (auto &Base : Bases) {
  137. auto I = Allocations.find(Base.toPtr<void *>());
  138. // Check for missing allocation (effective a double free).
  139. if (I != Allocations.end()) {
  140. AllocPairs.push_back(std::move(*I));
  141. Allocations.erase(I);
  142. } else
  143. Err = joinErrors(
  144. std::move(Err),
  145. make_error<StringError>("No allocation entry found "
  146. "for " +
  147. formatv("{0:x}", Base.getValue()),
  148. inconvertibleErrorCode()));
  149. }
  150. }
  151. while (!AllocPairs.empty()) {
  152. auto &P = AllocPairs.back();
  153. Err = joinErrors(std::move(Err), deallocateImpl(P.first, P.second));
  154. AllocPairs.pop_back();
  155. }
  156. return Err;
  157. }
  158. Error SimpleExecutorMemoryManager::shutdown() {
  159. AllocationsMap AM;
  160. {
  161. std::lock_guard<std::mutex> Lock(M);
  162. AM = std::move(Allocations);
  163. }
  164. Error Err = Error::success();
  165. for (auto &KV : AM)
  166. Err = joinErrors(std::move(Err), deallocateImpl(KV.first, KV.second));
  167. return Err;
  168. }
  169. void SimpleExecutorMemoryManager::addBootstrapSymbols(
  170. StringMap<ExecutorAddr> &M) {
  171. M[rt::SimpleExecutorMemoryManagerInstanceName] = ExecutorAddr::fromPtr(this);
  172. M[rt::SimpleExecutorMemoryManagerReserveWrapperName] =
  173. ExecutorAddr::fromPtr(&reserveWrapper);
  174. M[rt::SimpleExecutorMemoryManagerFinalizeWrapperName] =
  175. ExecutorAddr::fromPtr(&finalizeWrapper);
  176. M[rt::SimpleExecutorMemoryManagerDeallocateWrapperName] =
  177. ExecutorAddr::fromPtr(&deallocateWrapper);
  178. }
  179. Error SimpleExecutorMemoryManager::deallocateImpl(void *Base, Allocation &A) {
  180. Error Err = Error::success();
  181. while (!A.DeallocationActions.empty()) {
  182. Err = joinErrors(std::move(Err),
  183. A.DeallocationActions.back().runWithSPSRetErrorMerged());
  184. A.DeallocationActions.pop_back();
  185. }
  186. sys::MemoryBlock MB(Base, A.Size);
  187. if (auto EC = sys::Memory::releaseMappedMemory(MB))
  188. Err = joinErrors(std::move(Err), errorCodeToError(EC));
  189. return Err;
  190. }
  191. llvm::orc::shared::CWrapperFunctionResult
  192. SimpleExecutorMemoryManager::reserveWrapper(const char *ArgData,
  193. size_t ArgSize) {
  194. return shared::WrapperFunction<
  195. rt::SPSSimpleExecutorMemoryManagerReserveSignature>::
  196. handle(ArgData, ArgSize,
  197. shared::makeMethodWrapperHandler(
  198. &SimpleExecutorMemoryManager::allocate))
  199. .release();
  200. }
  201. llvm::orc::shared::CWrapperFunctionResult
  202. SimpleExecutorMemoryManager::finalizeWrapper(const char *ArgData,
  203. size_t ArgSize) {
  204. return shared::WrapperFunction<
  205. rt::SPSSimpleExecutorMemoryManagerFinalizeSignature>::
  206. handle(ArgData, ArgSize,
  207. shared::makeMethodWrapperHandler(
  208. &SimpleExecutorMemoryManager::finalize))
  209. .release();
  210. }
  211. llvm::orc::shared::CWrapperFunctionResult
  212. SimpleExecutorMemoryManager::deallocateWrapper(const char *ArgData,
  213. size_t ArgSize) {
  214. return shared::WrapperFunction<
  215. rt::SPSSimpleExecutorMemoryManagerDeallocateSignature>::
  216. handle(ArgData, ArgSize,
  217. shared::makeMethodWrapperHandler(
  218. &SimpleExecutorMemoryManager::deallocate))
  219. .release();
  220. }
  221. } // namespace rt_bootstrap
  222. } // end namespace orc
  223. } // end namespace llvm