11#include "llvm/Config/llvm-config.h"
15#if defined(LLVM_ON_UNIX) && !defined(__ANDROID__)
33 : PageSize(PageSize) {}
39 return PageSize.takeError();
40 return std::make_unique<InProcessMemoryMapper>(*PageSize);
53 std::lock_guard<std::mutex> Lock(Mutex);
54 Reservations[MB.base()].Size = MB.allocatedSize();
63 return Addr.
toPtr<
char *>();
74 auto Size = Segment.ContentSize + Segment.ZeroFillSize;
82 std::memset((
Base + Segment.ContentSize).toPtr<
void *>(), 0,
83 Segment.ZeroFillSize);
94 std::vector<shared::WrapperFunctionCall> DeinitializeActions;
96 std::promise<MSVCPExpected<std::vector<shared::WrapperFunctionCall>>>
P;
97 auto F =
P.get_future();
100 P.set_value(std::move(R));
102 if (
auto DeinitializeActionsOrErr =
F.get())
103 DeinitializeActions = std::move(*DeinitializeActionsOrErr);
105 return OnInitialized(DeinitializeActionsOrErr.takeError());
109 std::lock_guard<std::mutex> Lock(Mutex);
112 auto &
Alloc = Allocations[MinAddr];
113 Alloc.Size = MaxAddr - MinAddr;
114 Alloc.DeinitializationActions = std::move(DeinitializeActions);
115 Reservations[AI.
MappingBase.
toPtr<
void *>()].Allocations.push_back(MinAddr);
118 OnInitialized(MinAddr);
127 std::lock_guard<std::mutex> Lock(Mutex);
132 Allocations[
Base].DeinitializationActions, [&](
Error Err) {
133 AllErr =
joinErrors(std::move(AllErr), std::move(Err));
144 Allocations.erase(
Base);
148 OnDeinitialized(std::move(AllErr));
155 for (
auto Base : Bases) {
156 std::vector<ExecutorAddr> AllocAddrs;
159 std::lock_guard<std::mutex> Lock(Mutex);
160 auto &R = Reservations[
Base.toPtr<
void *>()];
162 AllocAddrs.swap(R.Allocations);
166 std::promise<MSVCPError>
P;
167 auto F =
P.get_future();
181 std::lock_guard<std::mutex> Lock(Mutex);
182 Reservations.erase(
Base.toPtr<
void *>());
185 OnReleased(std::move(Err));
189 std::vector<ExecutorAddr> ReservationAddrs;
191 std::lock_guard<std::mutex> Lock(Mutex);
193 ReservationAddrs.reserve(Reservations.size());
194 for (
const auto &R : Reservations) {
199 std::promise<MSVCPError>
P;
200 auto F =
P.get_future();
201 release(ReservationAddrs, [&](
Error Err) {
P.set_value(std::move(Err)); });
209 : EPC(EPC), SAs(SAs), PageSize(PageSize) {
210#if (!defined(LLVM_ON_UNIX) || defined(__ANDROID__)) && !defined(_WIN32)
211 llvm_unreachable(
"SharedMemoryMapper is not supported on this platform yet");
217#if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)
220 return PageSize.takeError();
222 return std::make_unique<SharedMemoryMapper>(EPC, SAs, *PageSize);
225 "SharedMemoryMapper is not supported on this platform yet",
232#if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)
234 int SharedMemoryId = -1;
235 EPC.callSPSWrapperAsync<
238 [
this, NumBytes, OnReserved = std::move(OnReserved), SharedMemoryId](
239 Error SerializationErr,
241 if (SerializationErr) {
243 return OnReserved(std::move(SerializationErr));
247 return OnReserved(
Result.takeError());
250 std::string SharedMemoryName;
251 std::tie(RemoteAddr, SharedMemoryName) = std::move(*
Result);
253 void *LocalAddr =
nullptr;
255#if defined(LLVM_ON_UNIX)
259 reinterpret_cast<const uint8_t *
>(SharedMemoryName.c_str()),
260 SharedMemoryName.size());
262 key_t
Key = *
reinterpret_cast<key_t *
>(HashedName.data());
264 shmget(
Key, NumBytes, IPC_CREAT | __IPC_SHAREAS | 0700);
265 if (SharedMemoryId < 0) {
267 std::error_code(errno, std::generic_category())));
269 LocalAddr = shmat(SharedMemoryId,
nullptr, 0);
270 if (LocalAddr ==
reinterpret_cast<void *
>(-1)) {
272 std::error_code(errno, std::generic_category())));
275 int SharedMemoryFile = shm_open(SharedMemoryName.c_str(), O_RDWR, 0700);
276 if (SharedMemoryFile < 0) {
281 shm_unlink(SharedMemoryName.c_str());
283 LocalAddr = mmap(
nullptr, NumBytes, PROT_READ | PROT_WRITE, MAP_SHARED,
284 SharedMemoryFile, 0);
285 if (LocalAddr == MAP_FAILED) {
289 close(SharedMemoryFile);
294 std::wstring WideSharedMemoryName(SharedMemoryName.begin(),
295 SharedMemoryName.end());
296 HANDLE SharedMemoryFile = OpenFileMappingW(
297 FILE_MAP_ALL_ACCESS, FALSE, WideSharedMemoryName.c_str());
298 if (!SharedMemoryFile)
302 MapViewOfFile(SharedMemoryFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
304 CloseHandle(SharedMemoryFile);
308 CloseHandle(SharedMemoryFile);
312 std::lock_guard<std::mutex> Lock(Mutex);
314 {RemoteAddr, {LocalAddr, NumBytes, SharedMemoryId}});
319 SAs.Instance,
static_cast<uint64_t>(NumBytes));
323 "SharedMemoryMapper is not supported on this platform yet",
329 size_t ContentSize) {
330 auto R = Reservations.upper_bound(Addr);
331 assert(R != Reservations.begin() &&
"Attempt to prepare unreserved range");
336 return static_cast<char *
>(R->second.LocalAddr) +
Offset;
341 auto Reservation = Reservations.upper_bound(AI.
MappingBase);
342 assert(Reservation != Reservations.begin() &&
"Attempt to initialize unreserved range");
345 auto AllocationOffset = AI.
MappingBase - Reservation->first;
354 char *
Base =
static_cast<char *
>(Reservation->second.LocalAddr) +
355 AllocationOffset + Segment.Offset;
356 std::memset(
Base + Segment.ContentSize, 0, Segment.ZeroFillSize);
359 SegReq.
RAG = {Segment.AG.getMemProt(),
362 SegReq.
Size = Segment.ContentSize + Segment.ZeroFillSize;
367 EPC.callSPSWrapperAsync<
370 [OnInitialized = std::move(OnInitialized)](
372 if (SerializationErr) {
374 return OnInitialized(std::move(SerializationErr));
377 OnInitialized(std::move(
Result));
379 SAs.Instance, Reservation->first, std::move(FR));
385 EPC.callSPSWrapperAsync<
388 [OnDeinitialized = std::move(OnDeinitialized)](
Error SerializationErr,
390 if (SerializationErr) {
392 return OnDeinitialized(std::move(SerializationErr));
395 OnDeinitialized(std::move(
Result));
397 SAs.Instance, Allocations);
402#if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)
406 std::lock_guard<std::mutex> Lock(Mutex);
408 for (
auto Base : Bases) {
410#if defined(LLVM_ON_UNIX)
413 if (shmdt(Reservations[
Base].LocalAddr) < 0 ||
414 shmctl(Reservations[
Base].SharedMemoryId, IPC_RMID, NULL) < 0)
417 if (munmap(Reservations[
Base].LocalAddr, Reservations[
Base].
Size) != 0)
423 if (!UnmapViewOfFile(Reservations[
Base].LocalAddr))
429 Reservations.erase(
Base);
433 EPC.callSPSWrapperAsync<
436 [OnReleased = std::move(OnReleased),
438 if (SerializationErr) {
441 joinErrors(std::move(Err), std::move(SerializationErr)));
446 SAs.Instance, Bases);
449 "SharedMemoryMapper is not supported on this platform yet",
455 std::lock_guard<std::mutex> Lock(Mutex);
456 for (
const auto &R : Reservations) {
458#if defined(LLVM_ON_UNIX) && !defined(__ANDROID__)
461 shmdt(R.second.LocalAddr);
463 munmap(R.second.LocalAddr, R.second.Size);
468 UnmapViewOfFile(R.second.LocalAddr);
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 ...
void reserve(size_t NumBytes, OnReservedFunction OnReserved) override
Reserves address space in executor process.
InProcessMemoryMapper(size_t PageSize)
~InProcessMemoryMapper() override
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...
void deinitialize(ArrayRef< ExecutorAddr > Allocations, OnDeinitializedFunction OnDeInitialized) override
Runs previously specified deinitialization actions Executor addresses returned by initialize should b...
static Expected< std::unique_ptr< InProcessMemoryMapper > > Create()
void release(ArrayRef< ExecutorAddr > Reservations, OnReleasedFunction OnRelease) override
Release address space acquired through reserve()
unique_function< void(Error)> OnReleasedFunction
unique_function< void(Expected< ExecutorAddr >)> OnInitializedFunction
unique_function< void(Expected< ExecutorAddrRange >)> OnReservedFunction
unique_function< void(Error)> OnDeinitializedFunction
static Expected< std::unique_ptr< SharedMemoryMapper > > Create(ExecutorProcessControl &EPC, SymbolAddrs SAs)
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...
void reserve(size_t NumBytes, OnReservedFunction OnReserved) override
Reserves address space in executor process.
void deinitialize(ArrayRef< ExecutorAddr > Allocations, OnDeinitializedFunction OnDeInitialized) override
Runs previously specified deinitialization actions Executor addresses returned by initialize should b...
~SharedMemoryMapper() override
void initialize(AllocInfo &AI, OnInitializedFunction OnInitialized) override
Ensures executor memory is synchronized with working copy memory, sends functions to be called after ...
void release(ArrayRef< ExecutorAddr > Reservations, OnReleasedFunction OnRelease) override
Release address space acquired through reserve()
SharedMemoryMapper(ExecutorProcessControl &EPC, SymbolAddrs SAs, size_t PageSize)
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
LLVM_ABI void runDeallocActions(ArrayRef< WrapperFunctionCall > DAs, OnRunDeallocActionsComeleteFn OnComplete)
Run deallocation actions.
LLVM_ABI void runFinalizeActions(AllocActions &AAs, OnRunFinalizeActionsCompleteFn OnComplete)
Run finalize actions.
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
std::vector< SharedMemorySegFinalizeRequest > Segments
shared::AllocActions Actions