Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / llvm / lib / ExecutionEngine / Orc / MemoryMapper.cpp
blob9cfe547c84c310b75c85c6204500cdd30342eb7a
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 //===----------------------------------------------------------------------===//
9 #include "llvm/ExecutionEngine/Orc/MemoryMapper.h"
11 #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
12 #include "llvm/Support/WindowsError.h"
14 #include <algorithm>
16 #if defined(LLVM_ON_UNIX) && !defined(__ANDROID__)
17 #include <fcntl.h>
18 #include <sys/mman.h>
19 #include <unistd.h>
20 #elif defined(_WIN32)
21 #include <windows.h>
22 #endif
24 namespace llvm {
25 namespace orc {
27 MemoryMapper::~MemoryMapper() {}
29 InProcessMemoryMapper::InProcessMemoryMapper(size_t PageSize)
30 : PageSize(PageSize) {}
32 Expected<std::unique_ptr<InProcessMemoryMapper>>
33 InProcessMemoryMapper::Create() {
34 auto PageSize = sys::Process::getPageSize();
35 if (!PageSize)
36 return PageSize.takeError();
37 return std::make_unique<InProcessMemoryMapper>(*PageSize);
40 void InProcessMemoryMapper::reserve(size_t NumBytes,
41 OnReservedFunction OnReserved) {
42 std::error_code EC;
43 auto MB = sys::Memory::allocateMappedMemory(
44 NumBytes, nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC);
46 if (EC)
47 return OnReserved(errorCodeToError(EC));
50 std::lock_guard<std::mutex> Lock(Mutex);
51 Reservations[MB.base()].Size = MB.allocatedSize();
54 OnReserved(
55 ExecutorAddrRange(ExecutorAddr::fromPtr(MB.base()), MB.allocatedSize()));
58 char *InProcessMemoryMapper::prepare(ExecutorAddr Addr, size_t ContentSize) {
59 return Addr.toPtr<char *>();
62 void InProcessMemoryMapper::initialize(MemoryMapper::AllocInfo &AI,
63 OnInitializedFunction OnInitialized) {
64 ExecutorAddr MinAddr(~0ULL);
65 ExecutorAddr MaxAddr(0);
67 // FIXME: Release finalize lifetime segments.
68 for (auto &Segment : AI.Segments) {
69 auto Base = AI.MappingBase + Segment.Offset;
70 auto Size = Segment.ContentSize + Segment.ZeroFillSize;
72 if (Base < MinAddr)
73 MinAddr = Base;
75 if (Base + Size > MaxAddr)
76 MaxAddr = Base + Size;
78 std::memset((Base + Segment.ContentSize).toPtr<void *>(), 0,
79 Segment.ZeroFillSize);
81 if (auto EC = sys::Memory::protectMappedMemory(
82 {Base.toPtr<void *>(), Size},
83 toSysMemoryProtectionFlags(Segment.AG.getMemProt()))) {
84 return OnInitialized(errorCodeToError(EC));
86 if ((Segment.AG.getMemProt() & MemProt::Exec) == MemProt::Exec)
87 sys::Memory::InvalidateInstructionCache(Base.toPtr<void *>(), Size);
90 auto DeinitializeActions = shared::runFinalizeActions(AI.Actions);
91 if (!DeinitializeActions)
92 return OnInitialized(DeinitializeActions.takeError());
95 std::lock_guard<std::mutex> Lock(Mutex);
97 // This is the maximum range whose permission have been possibly modified
98 Allocations[MinAddr].Size = MaxAddr - MinAddr;
99 Allocations[MinAddr].DeinitializationActions =
100 std::move(*DeinitializeActions);
101 Reservations[AI.MappingBase.toPtr<void *>()].Allocations.push_back(MinAddr);
104 OnInitialized(MinAddr);
107 void InProcessMemoryMapper::deinitialize(
108 ArrayRef<ExecutorAddr> Bases,
109 MemoryMapper::OnDeinitializedFunction OnDeinitialized) {
110 Error AllErr = Error::success();
113 std::lock_guard<std::mutex> Lock(Mutex);
115 for (auto Base : llvm::reverse(Bases)) {
117 if (Error Err = shared::runDeallocActions(
118 Allocations[Base].DeinitializationActions)) {
119 AllErr = joinErrors(std::move(AllErr), std::move(Err));
122 // Reset protections to read/write so the area can be reused
123 if (auto EC = sys::Memory::protectMappedMemory(
124 {Base.toPtr<void *>(), Allocations[Base].Size},
125 sys::Memory::ProtectionFlags::MF_READ |
126 sys::Memory::ProtectionFlags::MF_WRITE)) {
127 AllErr = joinErrors(std::move(AllErr), errorCodeToError(EC));
130 Allocations.erase(Base);
134 OnDeinitialized(std::move(AllErr));
137 void InProcessMemoryMapper::release(ArrayRef<ExecutorAddr> Bases,
138 OnReleasedFunction OnReleased) {
139 Error Err = Error::success();
141 for (auto Base : Bases) {
142 std::vector<ExecutorAddr> AllocAddrs;
143 size_t Size;
145 std::lock_guard<std::mutex> Lock(Mutex);
146 auto &R = Reservations[Base.toPtr<void *>()];
147 Size = R.Size;
148 AllocAddrs.swap(R.Allocations);
151 // deinitialize sub allocations
152 std::promise<MSVCPError> P;
153 auto F = P.get_future();
154 deinitialize(AllocAddrs, [&](Error Err) { P.set_value(std::move(Err)); });
155 if (Error E = F.get()) {
156 Err = joinErrors(std::move(Err), std::move(E));
159 // free the memory
160 auto MB = sys::MemoryBlock(Base.toPtr<void *>(), Size);
162 auto EC = sys::Memory::releaseMappedMemory(MB);
163 if (EC) {
164 Err = joinErrors(std::move(Err), errorCodeToError(EC));
167 std::lock_guard<std::mutex> Lock(Mutex);
168 Reservations.erase(Base.toPtr<void *>());
171 OnReleased(std::move(Err));
174 InProcessMemoryMapper::~InProcessMemoryMapper() {
175 std::vector<ExecutorAddr> ReservationAddrs;
177 std::lock_guard<std::mutex> Lock(Mutex);
179 ReservationAddrs.reserve(Reservations.size());
180 for (const auto &R : Reservations) {
181 ReservationAddrs.push_back(ExecutorAddr::fromPtr(R.getFirst()));
185 std::promise<MSVCPError> P;
186 auto F = P.get_future();
187 release(ReservationAddrs, [&](Error Err) { P.set_value(std::move(Err)); });
188 cantFail(F.get());
191 // SharedMemoryMapper
193 SharedMemoryMapper::SharedMemoryMapper(ExecutorProcessControl &EPC,
194 SymbolAddrs SAs, size_t PageSize)
195 : EPC(EPC), SAs(SAs), PageSize(PageSize) {
196 #if (!defined(LLVM_ON_UNIX) || defined(__ANDROID__)) && !defined(_WIN32)
197 llvm_unreachable("SharedMemoryMapper is not supported on this platform yet");
198 #endif
201 Expected<std::unique_ptr<SharedMemoryMapper>>
202 SharedMemoryMapper::Create(ExecutorProcessControl &EPC, SymbolAddrs SAs) {
203 #if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)
204 auto PageSize = sys::Process::getPageSize();
205 if (!PageSize)
206 return PageSize.takeError();
208 return std::make_unique<SharedMemoryMapper>(EPC, SAs, *PageSize);
209 #else
210 return make_error<StringError>(
211 "SharedMemoryMapper is not supported on this platform yet",
212 inconvertibleErrorCode());
213 #endif
216 void SharedMemoryMapper::reserve(size_t NumBytes,
217 OnReservedFunction OnReserved) {
218 #if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)
220 EPC.callSPSWrapperAsync<
221 rt::SPSExecutorSharedMemoryMapperServiceReserveSignature>(
222 SAs.Reserve,
223 [this, NumBytes, OnReserved = std::move(OnReserved)](
224 Error SerializationErr,
225 Expected<std::pair<ExecutorAddr, std::string>> Result) mutable {
226 if (SerializationErr) {
227 cantFail(Result.takeError());
228 return OnReserved(std::move(SerializationErr));
231 if (!Result)
232 return OnReserved(Result.takeError());
234 ExecutorAddr RemoteAddr;
235 std::string SharedMemoryName;
236 std::tie(RemoteAddr, SharedMemoryName) = std::move(*Result);
238 void *LocalAddr = nullptr;
240 #if defined(LLVM_ON_UNIX)
242 int SharedMemoryFile = shm_open(SharedMemoryName.c_str(), O_RDWR, 0700);
243 if (SharedMemoryFile < 0) {
244 return OnReserved(errorCodeToError(
245 std::error_code(errno, std::generic_category())));
248 // this prevents other processes from accessing it by name
249 shm_unlink(SharedMemoryName.c_str());
251 LocalAddr = mmap(nullptr, NumBytes, PROT_READ | PROT_WRITE, MAP_SHARED,
252 SharedMemoryFile, 0);
253 if (LocalAddr == MAP_FAILED) {
254 return OnReserved(errorCodeToError(
255 std::error_code(errno, std::generic_category())));
258 close(SharedMemoryFile);
260 #elif defined(_WIN32)
262 std::wstring WideSharedMemoryName(SharedMemoryName.begin(),
263 SharedMemoryName.end());
264 HANDLE SharedMemoryFile = OpenFileMappingW(
265 FILE_MAP_ALL_ACCESS, FALSE, WideSharedMemoryName.c_str());
266 if (!SharedMemoryFile)
267 return OnReserved(errorCodeToError(mapWindowsError(GetLastError())));
269 LocalAddr =
270 MapViewOfFile(SharedMemoryFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
271 if (!LocalAddr) {
272 CloseHandle(SharedMemoryFile);
273 return OnReserved(errorCodeToError(mapWindowsError(GetLastError())));
276 CloseHandle(SharedMemoryFile);
278 #endif
280 std::lock_guard<std::mutex> Lock(Mutex);
281 Reservations.insert({RemoteAddr, {LocalAddr, NumBytes}});
284 OnReserved(ExecutorAddrRange(RemoteAddr, NumBytes));
286 SAs.Instance, static_cast<uint64_t>(NumBytes));
288 #else
289 OnReserved(make_error<StringError>(
290 "SharedMemoryMapper is not supported on this platform yet",
291 inconvertibleErrorCode()));
292 #endif
295 char *SharedMemoryMapper::prepare(ExecutorAddr Addr, size_t ContentSize) {
296 auto R = Reservations.upper_bound(Addr);
297 assert(R != Reservations.begin() && "Attempt to prepare unreserved range");
298 R--;
300 ExecutorAddrDiff Offset = Addr - R->first;
302 return static_cast<char *>(R->second.LocalAddr) + Offset;
305 void SharedMemoryMapper::initialize(MemoryMapper::AllocInfo &AI,
306 OnInitializedFunction OnInitialized) {
307 auto Reservation = Reservations.upper_bound(AI.MappingBase);
308 assert(Reservation != Reservations.begin() && "Attempt to initialize unreserved range");
309 Reservation--;
311 auto AllocationOffset = AI.MappingBase - Reservation->first;
313 tpctypes::SharedMemoryFinalizeRequest FR;
315 AI.Actions.swap(FR.Actions);
317 FR.Segments.reserve(AI.Segments.size());
319 for (auto Segment : AI.Segments) {
320 char *Base = static_cast<char *>(Reservation->second.LocalAddr) +
321 AllocationOffset + Segment.Offset;
322 std::memset(Base + Segment.ContentSize, 0, Segment.ZeroFillSize);
324 tpctypes::SharedMemorySegFinalizeRequest SegReq;
325 SegReq.RAG = {Segment.AG.getMemProt(),
326 Segment.AG.getMemLifetime() == MemLifetime::Finalize};
327 SegReq.Addr = AI.MappingBase + Segment.Offset;
328 SegReq.Size = Segment.ContentSize + Segment.ZeroFillSize;
330 FR.Segments.push_back(SegReq);
333 EPC.callSPSWrapperAsync<
334 rt::SPSExecutorSharedMemoryMapperServiceInitializeSignature>(
335 SAs.Initialize,
336 [OnInitialized = std::move(OnInitialized)](
337 Error SerializationErr, Expected<ExecutorAddr> Result) mutable {
338 if (SerializationErr) {
339 cantFail(Result.takeError());
340 return OnInitialized(std::move(SerializationErr));
343 OnInitialized(std::move(Result));
345 SAs.Instance, Reservation->first, std::move(FR));
348 void SharedMemoryMapper::deinitialize(
349 ArrayRef<ExecutorAddr> Allocations,
350 MemoryMapper::OnDeinitializedFunction OnDeinitialized) {
351 EPC.callSPSWrapperAsync<
352 rt::SPSExecutorSharedMemoryMapperServiceDeinitializeSignature>(
353 SAs.Deinitialize,
354 [OnDeinitialized = std::move(OnDeinitialized)](Error SerializationErr,
355 Error Result) mutable {
356 if (SerializationErr) {
357 cantFail(std::move(Result));
358 return OnDeinitialized(std::move(SerializationErr));
361 OnDeinitialized(std::move(Result));
363 SAs.Instance, Allocations);
366 void SharedMemoryMapper::release(ArrayRef<ExecutorAddr> Bases,
367 OnReleasedFunction OnReleased) {
368 #if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)
369 Error Err = Error::success();
372 std::lock_guard<std::mutex> Lock(Mutex);
374 for (auto Base : Bases) {
376 #if defined(LLVM_ON_UNIX)
378 if (munmap(Reservations[Base].LocalAddr, Reservations[Base].Size) != 0)
379 Err = joinErrors(std::move(Err), errorCodeToError(std::error_code(
380 errno, std::generic_category())));
382 #elif defined(_WIN32)
384 if (!UnmapViewOfFile(Reservations[Base].LocalAddr))
385 Err = joinErrors(std::move(Err),
386 errorCodeToError(mapWindowsError(GetLastError())));
388 #endif
390 Reservations.erase(Base);
394 EPC.callSPSWrapperAsync<
395 rt::SPSExecutorSharedMemoryMapperServiceReleaseSignature>(
396 SAs.Release,
397 [OnReleased = std::move(OnReleased),
398 Err = std::move(Err)](Error SerializationErr, Error Result) mutable {
399 if (SerializationErr) {
400 cantFail(std::move(Result));
401 return OnReleased(
402 joinErrors(std::move(Err), std::move(SerializationErr)));
405 return OnReleased(joinErrors(std::move(Err), std::move(Result)));
407 SAs.Instance, Bases);
408 #else
409 OnReleased(make_error<StringError>(
410 "SharedMemoryMapper is not supported on this platform yet",
411 inconvertibleErrorCode()));
412 #endif
415 SharedMemoryMapper::~SharedMemoryMapper() {
416 std::lock_guard<std::mutex> Lock(Mutex);
417 for (const auto &R : Reservations) {
419 #if defined(LLVM_ON_UNIX) && !defined(__ANDROID__)
421 munmap(R.second.LocalAddr, R.second.Size);
423 #elif defined(_WIN32)
425 UnmapViewOfFile(R.second.LocalAddr);
427 #else
429 (void)R;
431 #endif
435 } // namespace orc
437 } // namespace llvm