LLVM: lib/ExecutionEngine/Orc/MemoryMapper.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
10
11#include "llvm/Config/llvm-config.h"
14
15#if defined(LLVM_ON_UNIX) && !defined(__ANDROID__)
16#include <fcntl.h>
17#include <sys/mman.h>
18#if defined(__MVS__)
20#include <sys/shm.h>
21#endif
22#include <unistd.h>
23#elif defined(_WIN32)
24#include <windows.h>
25#endif
26
27namespace llvm {
28namespace orc {
29
31
33 : PageSize(PageSize) {}
34
38 if (!PageSize)
39 return PageSize.takeError();
40 return std::make_unique(*PageSize);
41}
42
45 std::error_code EC;
48
49 if (EC)
51
52 {
53 std::lock_guardstd::mutex Lock(Mutex);
54 Reservations[MB.base()].Size = MB.allocatedSize();
55 }
56
57 OnReserved(
59}
60
62 size_t ContentSize) {
63 return Addr.toPtr<char *>();
64}
65
70
71
72 for (auto &Segment : AI.Segments) {
74 auto Size = Segment.ContentSize + Segment.ZeroFillSize;
75
76 if (Base < MinAddr)
77 MinAddr = Base;
78
81
82 std::memset((Base + Segment.ContentSize).toPtr<void *>(), 0,
83 Segment.ZeroFillSize);
84
89 }
92 }
93
95 if (!DeinitializeActions)
96 return OnInitialized(DeinitializeActions.takeError());
97
98 {
99 std::lock_guardstd::mutex Lock(Mutex);
100
101
102 auto &Alloc = Allocations[MinAddr];
103 Alloc.Size = MaxAddr - MinAddr;
104 Alloc.DeinitializationActions = std::move(*DeinitializeActions);
105 Reservations[AI.MappingBase.toPtr<void *>()].Allocations.push_back(MinAddr);
106 }
107
108 OnInitialized(MinAddr);
109}
110
115
116 {
117 std::lock_guardstd::mutex Lock(Mutex);
118
120
122 Allocations[Base].DeinitializationActions)) {
123 AllErr = joinErrors(std::move(AllErr), std::move(Err));
124 }
125
126
128 {Base.toPtr<void *>(), Allocations[Base].Size},
132 }
133
134 Allocations.erase(Base);
135 }
136 }
137
138 OnDeinitialized(std::move(AllErr));
139}
140
144
145 for (auto Base : Bases) {
146 std::vector AllocAddrs;
148 {
149 std::lock_guardstd::mutex Lock(Mutex);
150 auto &R = Reservations[Base.toPtr<void *>()];
151 Size = R.Size;
152 AllocAddrs.swap(R.Allocations);
153 }
154
155
156 std::promise P;
158 deinitialize(AllocAddrs, [&](Error Err) { P.set_value(std::move(Err)); });
160 Err = joinErrors(std::move(Err), std::move(E));
161 }
162
163
165
167 if (EC) {
169 }
170
171 std::lock_guardstd::mutex Lock(Mutex);
172 Reservations.erase(Base.toPtr<void *>());
173 }
174
175 OnReleased(std::move(Err));
176}
177
179 std::vector ReservationAddrs;
180 {
181 std::lock_guardstd::mutex Lock(Mutex);
182
183 ReservationAddrs.reserve(Reservations.size());
184 for (const auto &R : Reservations) {
186 }
187 }
188
189 std::promise P;
191 release(ReservationAddrs, [&](Error Err) { P.set_value(std::move(Err)); });
193}
194
195
196
199 : EPC(EPC), SAs(SAs), PageSize(PageSize) {
200#if (!defined(LLVM_ON_UNIX) || defined(__ANDROID__)) && !defined(_WIN32)
201 llvm_unreachable("SharedMemoryMapper is not supported on this platform yet");
202#endif
203}
204
207#if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)
209 if (!PageSize)
210 return PageSize.takeError();
211
212 return std::make_unique(EPC, SAs, *PageSize);
213#else
215 "SharedMemoryMapper is not supported on this platform yet",
217#endif
218}
219
222#if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)
223
224 int SharedMemoryId = -1;
225 EPC.callSPSWrapperAsync<
227 SAs.Reserve,
228 [this, NumBytes, OnReserved = std::move(OnReserved), SharedMemoryId](
229 Error SerializationErr,
231 if (SerializationErr) {
233 return OnReserved(std::move(SerializationErr));
234 }
235
237 return OnReserved(Result.takeError());
238
240 std::string SharedMemoryName;
241 std::tie(RemoteAddr, SharedMemoryName) = std::move(*Result);
242
243 void *LocalAddr = nullptr;
244
245#if defined(LLVM_ON_UNIX)
246
247#if defined(__MVS__)
249 reinterpret_cast<const uint8_t *>(SharedMemoryName.c_str()),
250 SharedMemoryName.size());
252 key_t Key = *reinterpret_cast<key_t *>(HashedName.data());
253 SharedMemoryId =
254 shmget(Key, NumBytes, IPC_CREAT | __IPC_SHAREAS | 0700);
255 if (SharedMemoryId < 0) {
257 std::error_code(errno, std::generic_category())));
258 }
259 LocalAddr = shmat(SharedMemoryId, nullptr, 0);
260 if (LocalAddr == reinterpret_cast<void *>(-1)) {
262 std::error_code(errno, std::generic_category())));
263 }
264#else
265 int SharedMemoryFile = shm_open(SharedMemoryName.c_str(), O_RDWR, 0700);
266 if (SharedMemoryFile < 0) {
268 }
269
270
271 shm_unlink(SharedMemoryName.c_str());
272
273 LocalAddr = mmap(nullptr, NumBytes, PROT_READ | PROT_WRITE, MAP_SHARED,
274 SharedMemoryFile, 0);
275 if (LocalAddr == MAP_FAILED) {
277 }
278
279 close(SharedMemoryFile);
280#endif
281
282#elif defined(_WIN32)
283
284 std::wstring WideSharedMemoryName(SharedMemoryName.begin(),
285 SharedMemoryName.end());
286 HANDLE SharedMemoryFile = OpenFileMappingW(
287 FILE_MAP_ALL_ACCESS, FALSE, WideSharedMemoryName.c_str());
288 if (!SharedMemoryFile)
290
291 LocalAddr =
292 MapViewOfFile(SharedMemoryFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
293 if (!LocalAddr) {
294 CloseHandle(SharedMemoryFile);
296 }
297
298 CloseHandle(SharedMemoryFile);
299
300#endif
301 {
302 std::lock_guardstd::mutex Lock(Mutex);
303 Reservations.insert(
304 {RemoteAddr, {LocalAddr, NumBytes, SharedMemoryId}});
305 }
306
308 },
309 SAs.Instance, static_cast<uint64_t>(NumBytes));
310
311#else
313 "SharedMemoryMapper is not supported on this platform yet",
315#endif
316}
317
319 size_t ContentSize) {
320 auto R = Reservations.upper_bound(Addr);
321 assert(R != Reservations.begin() && "Attempt to prepare unreserved range");
322 R--;
323
325
326 return static_cast<char *>(R->second.LocalAddr) + Offset;
327}
328
331 auto Reservation = Reservations.upper_bound(AI.MappingBase);
332 assert(Reservation != Reservations.begin() && "Attempt to initialize unreserved range");
333 Reservation--;
334
335 auto AllocationOffset = AI.MappingBase - Reservation->first;
336
338
340
342
343 for (auto Segment : AI.Segments) {
344 char *Base = static_cast<char *>(Reservation->second.LocalAddr) +
345 AllocationOffset + Segment.Offset;
346 std::memset(Base + Segment.ContentSize, 0, Segment.ZeroFillSize);
347
349 SegReq.RAG = {Segment.AG.getMemProt(),
352 SegReq.Size = Segment.ContentSize + Segment.ZeroFillSize;
353
354 FR.Segments.push_back(SegReq);
355 }
356
357 EPC.callSPSWrapperAsync<
359 SAs.Initialize,
360 [OnInitialized = std::move(OnInitialized)](
362 if (SerializationErr) {
364 return OnInitialized(std::move(SerializationErr));
365 }
366
367 OnInitialized(std::move(Result));
368 },
369 SAs.Instance, Reservation->first, std::move(FR));
370}
371
375 EPC.callSPSWrapperAsync<
377 SAs.Deinitialize,
378 [OnDeinitialized = std::move(OnDeinitialized)](Error SerializationErr,
380 if (SerializationErr) {
382 return OnDeinitialized(std::move(SerializationErr));
383 }
384
385 OnDeinitialized(std::move(Result));
386 },
387 SAs.Instance, Allocations);
388}
389
392#if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)
394
395 {
396 std::lock_guardstd::mutex Lock(Mutex);
397
398 for (auto Base : Bases) {
399
400#if defined(LLVM_ON_UNIX)
401
402#if defined(__MVS__)
403 if (shmdt(Reservations[Base].LocalAddr) < 0 ||
404 shmctl(Reservations[Base].SharedMemoryId, IPC_RMID, NULL) < 0)
406#else
407 if (munmap(Reservations[Base].LocalAddr, Reservations[Base].Size) != 0)
409#endif
410
411#elif defined(_WIN32)
412
413 if (!UnmapViewOfFile(Reservations[Base].LocalAddr))
416
417#endif
418
419 Reservations.erase(Base);
420 }
421 }
422
423 EPC.callSPSWrapperAsync<
425 SAs.Release,
426 [OnReleased = std::move(OnReleased),
427 Err = std::move(Err)](Error SerializationErr, Error Result) mutable {
428 if (SerializationErr) {
430 return OnReleased(
431 joinErrors(std::move(Err), std::move(SerializationErr)));
432 }
433
434 return OnReleased(joinErrors(std::move(Err), std::move(Result)));
435 },
436 SAs.Instance, Bases);
437#else
439 "SharedMemoryMapper is not supported on this platform yet",
441#endif
442}
443
445 std::lock_guardstd::mutex Lock(Mutex);
446 for (const auto &R : Reservations) {
447
448#if defined(LLVM_ON_UNIX) && !defined(__ANDROID__)
449
450#if defined(__MVS__)
451 shmdt(R.second.LocalAddr);
452#else
453 munmap(R.second.LocalAddr, R.second.Size);
454#endif
455
456#elif defined(_WIN32)
457
458 UnmapViewOfFile(R.second.LocalAddr);
459
460#else
461
462 (void)R;
463
464#endif
465 }
466}
467
468}
469
470}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
static BLAKE3Result< NumBytes > hash(ArrayRef< uint8_t > Data)
Returns a BLAKE3 hash for the given data.
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.
Represents an address in the executor process.
static ExecutorAddr fromPtr(T *Ptr, UnwrapFn &&Unwrap=UnwrapFn())
Create an ExecutorAddr from the given pointer.
std::enable_if_t< std::is_pointer< T >::value, T > toPtr(WrapFn &&Wrap=WrapFn()) const
Cast this ExecutorAddr to a pointer of the given type.
ExecutorProcessControl supports interaction with a JIT target process.
void initialize(AllocInfo &AI, OnInitializedFunction OnInitialized) override
Ensures executor memory is synchronized with working copy memory, sends functions to be called after ...
Definition MemoryMapper.cpp:66
void reserve(size_t NumBytes, OnReservedFunction OnReserved) override
Reserves address space in executor process.
Definition MemoryMapper.cpp:43
InProcessMemoryMapper(size_t PageSize)
Definition MemoryMapper.cpp:32
~InProcessMemoryMapper() override
Definition MemoryMapper.cpp:178
char * prepare(jitlink::LinkGraph &G, ExecutorAddr Addr, size_t ContentSize) override
Provides working memory The LinkGraph parameter is included to allow implementations to allocate work...
Definition MemoryMapper.cpp:61
void deinitialize(ArrayRef< ExecutorAddr > Allocations, OnDeinitializedFunction OnDeInitialized) override
Runs previously specified deinitialization actions Executor addresses returned by initialize should b...
Definition MemoryMapper.cpp:111
static Expected< std::unique_ptr< InProcessMemoryMapper > > Create()
Definition MemoryMapper.cpp:36
void release(ArrayRef< ExecutorAddr > Reservations, OnReleasedFunction OnRelease) override
Release address space acquired through reserve()
Definition MemoryMapper.cpp:141
unique_function< void(Error)> OnReleasedFunction
unique_function< void(Expected< ExecutorAddr >)> OnInitializedFunction
unique_function< void(Expected< ExecutorAddrRange >)> OnReservedFunction
unique_function< void(Error)> OnDeinitializedFunction
This class encapsulates the notion of a memory block which has an address and a size.
static LLVM_ABI 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.
static LLVM_ABI std::error_code releaseMappedMemory(MemoryBlock &Block)
This method releases a block of memory that was allocated with the allocateMappedMemory method.
static LLVM_ABI 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 LLVM_ABI 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 LLVM_ABI Expected< unsigned > getPageSize()
Get the process's page size.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
shared::SPSExpected< shared::SPSTuple< shared::SPSExecutorAddr, shared::SPSString > >( shared::SPSExecutorAddr, uint64_t) SPSExecutorSharedMemoryMapperServiceReserveSignature
shared::SPSExpected< shared::SPSExecutorAddr >( shared::SPSExecutorAddr, shared::SPSExecutorAddr, shared::SPSSharedMemoryFinalizeRequest) SPSExecutorSharedMemoryMapperServiceInitializeSignature
shared::SPSError(shared::SPSExecutorAddr, shared::SPSSequence< shared::SPSExecutorAddr >) SPSExecutorSharedMemoryMapperServiceDeinitializeSignature
shared::SPSError( shared::SPSExecutorAddr, shared::SPSSequence< shared::SPSExecutorAddr >) SPSExecutorSharedMemoryMapperServiceReleaseSignature
uint64_t ExecutorAddrDiff
@ Finalize
Finalize memory should be allocated by the allocator, and then be overwritten and deallocated after a...
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.
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
auto reverse(ContainerTy &&C)
Error joinErrors(Error E1, Error E2)
Concatenate errors.
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
FunctionAddr VTableAddr uintptr_t uintptr_t Data
LLVM_ABI Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
LLVM_ABI std::error_code mapWindowsError(unsigned EV)
std::error_code errnoAsErrorCode()
Helper to get errno as an std::error_code.
Represents an address range in the exceutor process.
Represents a single allocation containing multiple segments and initialization and deinitialization a...
std::vector< SegInfo > Segments
shared::AllocActions Actions