xref: /llvm-project/llvm/lib/ExecutionEngine/Orc/MemoryMapper.cpp (revision 4162aefad125e355ce83841bd371c1ca6c52e887)
1 //===- MemoryMapper.cpp - Cross-process memory mapper ------------*- C++ -*-==//
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 
9 #include "llvm/ExecutionEngine/Orc/MemoryMapper.h"
10 
11 namespace llvm {
12 namespace orc {
13 
14 MemoryMapper::~MemoryMapper() {}
15 
16 void InProcessMemoryMapper::reserve(size_t NumBytes,
17                                     OnReservedFunction OnReserved) {
18   std::error_code EC;
19   auto MB = sys::Memory::allocateMappedMemory(
20       NumBytes, nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC);
21 
22   if (EC)
23     return OnReserved(errorCodeToError(EC));
24 
25   {
26     std::lock_guard<std::mutex> Lock(Mutex);
27     Reservations[MB.base()].Size = MB.allocatedSize();
28   }
29 
30   OnReserved(
31       ExecutorAddrRange(ExecutorAddr::fromPtr(MB.base()), MB.allocatedSize()));
32 }
33 
34 char *InProcessMemoryMapper::prepare(ExecutorAddr Addr, size_t ContentSize) {
35   return Addr.toPtr<char *>();
36 }
37 
38 void InProcessMemoryMapper::initialize(MemoryMapper::AllocInfo &AI,
39                                        OnInitializedFunction OnInitialized) {
40   ExecutorAddr MinAddr(~0ULL);
41 
42   for (auto &Segment : AI.Segments) {
43     auto Base = AI.MappingBase + Segment.Offset;
44     auto Size = Segment.ContentSize + Segment.ZeroFillSize;
45 
46     if (Base < MinAddr)
47       MinAddr = Base;
48 
49     std::memset((Base + Segment.ContentSize).toPtr<void *>(), 0,
50                 Segment.ZeroFillSize);
51 
52     if (auto EC = sys::Memory::protectMappedMemory({Base.toPtr<void *>(), Size},
53                                                    Segment.Prot)) {
54       return OnInitialized(errorCodeToError(EC));
55     }
56     if (Segment.Prot & sys::Memory::MF_EXEC)
57       sys::Memory::InvalidateInstructionCache(Base.toPtr<void *>(), Size);
58   }
59 
60   auto DeinitializeActions = shared::runFinalizeActions(AI.Actions);
61   if (!DeinitializeActions)
62     return OnInitialized(DeinitializeActions.takeError());
63 
64   {
65     std::lock_guard<std::mutex> Lock(Mutex);
66     Allocations[MinAddr].DeinitializationActions =
67         std::move(*DeinitializeActions);
68     Reservations[AI.MappingBase.toPtr<void *>()].Allocations.push_back(MinAddr);
69   }
70 
71   OnInitialized(MinAddr);
72 }
73 
74 void InProcessMemoryMapper::deinitialize(
75     ArrayRef<ExecutorAddr> Bases,
76     MemoryMapper::OnDeinitializedFunction OnDeinitialized) {
77   Error AllErr = Error::success();
78 
79   {
80     std::lock_guard<std::mutex> Lock(Mutex);
81 
82     for (auto Base : Bases) {
83 
84       if (Error Err = shared::runDeallocActions(
85               Allocations[Base].DeinitializationActions)) {
86         AllErr = joinErrors(std::move(AllErr), std::move(Err));
87       }
88 
89       Allocations.erase(Base);
90     }
91   }
92 
93   OnDeinitialized(std::move(AllErr));
94 }
95 
96 void InProcessMemoryMapper::release(ArrayRef<ExecutorAddr> Bases,
97                                     OnReleasedFunction OnReleased) {
98   Error Err = Error::success();
99 
100   for (auto Base : Bases) {
101     std::vector<ExecutorAddr> AllocAddrs;
102     size_t Size;
103     {
104       std::lock_guard<std::mutex> Lock(Mutex);
105       auto &R = Reservations[Base.toPtr<void *>()];
106       Size = R.Size;
107       AllocAddrs.swap(R.Allocations);
108     }
109 
110     // deinitialize sub allocations
111     std::promise<MSVCPError> P;
112     auto F = P.get_future();
113     deinitialize(AllocAddrs, [&](Error Err) { P.set_value(std::move(Err)); });
114     if (Error E = F.get()) {
115       Err = joinErrors(std::move(Err), std::move(E));
116     }
117 
118     // free the memory
119     auto MB = sys::MemoryBlock(Base.toPtr<void *>(), Size);
120 
121     auto EC = sys::Memory::releaseMappedMemory(MB);
122     if (EC) {
123       Err = joinErrors(std::move(Err), errorCodeToError(EC));
124     }
125 
126     std::lock_guard<std::mutex> Lock(Mutex);
127     Reservations.erase(Base.toPtr<void *>());
128   }
129 
130   OnReleased(std::move(Err));
131 }
132 
133 InProcessMemoryMapper::~InProcessMemoryMapper() {
134   std::vector<ExecutorAddr> ReservationAddrs;
135   {
136     std::lock_guard<std::mutex> Lock(Mutex);
137 
138     ReservationAddrs.reserve(Reservations.size());
139     for (const auto &R : Reservations) {
140       ReservationAddrs.push_back(ExecutorAddr::fromPtr(R.getFirst()));
141     }
142   }
143 
144   std::promise<MSVCPError> P;
145   auto F = P.get_future();
146   release(ReservationAddrs, [&](Error Err) { P.set_value(std::move(Err)); });
147   cantFail(F.get());
148 }
149 
150 } // namespace orc
151 
152 } // namespace llvm
153