LLVM  16.0.0git
ExecutorSharedMemoryMapperService.cpp
Go to the documentation of this file.
1 //===---------- ExecutorSharedMemoryMapperService.cpp -----------*- 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 
10 
12 #include "llvm/Support/Process.h"
14 
15 #include <sstream>
16 
17 #if defined(LLVM_ON_UNIX)
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <sys/mman.h>
21 #include <unistd.h>
22 #endif
23 
24 namespace llvm {
25 namespace orc {
26 namespace rt_bootstrap {
27 
28 #if defined(_WIN32)
29 static DWORD getWindowsProtectionFlags(MemProt MP) {
30  if (MP == MemProt::Read)
31  return PAGE_READONLY;
32  if (MP == MemProt::Write ||
33  MP == (MemProt::Write | MemProt::Read)) {
34  // Note: PAGE_WRITE is not supported by VirtualProtect
35  return PAGE_READWRITE;
36  }
37  if (MP == (MemProt::Read | MemProt::Exec))
38  return PAGE_EXECUTE_READ;
40  return PAGE_EXECUTE_READWRITE;
41  if (MP == MemProt::Exec)
42  return PAGE_EXECUTE;
43 
44  return PAGE_NOACCESS;
45 }
46 #endif
47 
48 Expected<std::pair<ExecutorAddr, std::string>>
50 #if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)
51 
52 #if defined(LLVM_ON_UNIX)
53 
54  std::string SharedMemoryName;
55  {
56  std::stringstream SharedMemoryNameStream;
57  SharedMemoryNameStream << "/jitlink_" << sys::Process::getProcessId() << '_'
58  << (++SharedMemoryCount);
59  SharedMemoryName = SharedMemoryNameStream.str();
60  }
61 
62  int SharedMemoryFile =
63  shm_open(SharedMemoryName.c_str(), O_RDWR | O_CREAT | O_EXCL, 0700);
64  if (SharedMemoryFile < 0)
65  return errorCodeToError(std::error_code(errno, std::generic_category()));
66 
67  // by default size is 0
68  if (ftruncate(SharedMemoryFile, Size) < 0)
69  return errorCodeToError(std::error_code(errno, std::generic_category()));
70 
71  void *Addr = mmap(nullptr, Size, PROT_NONE, MAP_SHARED, SharedMemoryFile, 0);
72  if (Addr == MAP_FAILED)
73  return errorCodeToError(std::error_code(errno, std::generic_category()));
74 
75  close(SharedMemoryFile);
76 
77 #elif defined(_WIN32)
78 
79  std::string SharedMemoryName;
80  {
81  std::stringstream SharedMemoryNameStream;
82  SharedMemoryNameStream << "jitlink_" << sys::Process::getProcessId() << '_'
83  << (++SharedMemoryCount);
84  SharedMemoryName = SharedMemoryNameStream.str();
85  }
86 
87  std::wstring WideSharedMemoryName(SharedMemoryName.begin(),
88  SharedMemoryName.end());
89  HANDLE SharedMemoryFile = CreateFileMappingW(
90  INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, Size >> 32,
91  Size & 0xffffffff, WideSharedMemoryName.c_str());
92  if (!SharedMemoryFile)
93  return errorCodeToError(mapWindowsError(GetLastError()));
94 
95  void *Addr = MapViewOfFile(SharedMemoryFile,
96  FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE, 0, 0, 0);
97  if (!Addr) {
98  CloseHandle(SharedMemoryFile);
99  return errorCodeToError(mapWindowsError(GetLastError()));
100  }
101 
102 #endif
103 
104  {
105  std::lock_guard<std::mutex> Lock(Mutex);
106  Reservations[Addr].Size = Size;
107 #if defined(_WIN32)
108  Reservations[Addr].SharedMemoryFile = SharedMemoryFile;
109 #endif
110  }
111 
112  return std::make_pair(ExecutorAddr::fromPtr(Addr),
113  std::move(SharedMemoryName));
114 #else
115  return make_error<StringError>(
116  "SharedMemoryMapper is not supported on this platform yet",
118 #endif
119 }
120 
123 #if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)
124 
125  ExecutorAddr MinAddr(~0ULL);
126 
127  // Contents are already in place
128  for (auto &Segment : FR.Segments) {
129  if (Segment.Addr < MinAddr)
130  MinAddr = Segment.Addr;
131 
132 #if defined(LLVM_ON_UNIX)
133 
134  int NativeProt = 0;
135  if ((Segment.AG.getMemProt() & MemProt::Read) == MemProt::Read)
136  NativeProt |= PROT_READ;
137  if ((Segment.AG.getMemProt() & MemProt::Write) == MemProt::Write)
138  NativeProt |= PROT_WRITE;
139  if ((Segment.AG.getMemProt() & MemProt::Exec) == MemProt::Exec)
140  NativeProt |= PROT_EXEC;
141 
142  if (mprotect(Segment.Addr.toPtr<void *>(), Segment.Size, NativeProt))
143  return errorCodeToError(std::error_code(errno, std::generic_category()));
144 
145 #elif defined(_WIN32)
146 
147  DWORD NativeProt =
148  getWindowsProtectionFlags(Segment.AG.getMemProt());
149 
150  if (!VirtualProtect(Segment.Addr.toPtr<void *>(), Segment.Size, NativeProt,
151  &NativeProt))
152  return errorCodeToError(mapWindowsError(GetLastError()));
153 
154 #endif
155 
156  if ((Segment.AG.getMemProt() & MemProt::Exec) == MemProt::Exec)
157  sys::Memory::InvalidateInstructionCache(Segment.Addr.toPtr<void *>(),
158  Segment.Size);
159  }
160 
161  // Run finalization actions and get deinitlization action list.
162  auto DeinitializeActions = shared::runFinalizeActions(FR.Actions);
163  if (!DeinitializeActions) {
164  return DeinitializeActions.takeError();
165  }
166 
167  {
168  std::lock_guard<std::mutex> Lock(Mutex);
169  Allocations[MinAddr].DeinitializationActions =
170  std::move(*DeinitializeActions);
171  Reservations[Reservation.toPtr<void *>()].Allocations.push_back(MinAddr);
172  }
173 
174  return MinAddr;
175 
176 #else
177  return make_error<StringError>(
178  "SharedMemoryMapper is not supported on this platform yet",
180 #endif
181 }
182 
184  const std::vector<ExecutorAddr> &Bases) {
185  Error AllErr = Error::success();
186 
187  {
188  std::lock_guard<std::mutex> Lock(Mutex);
189 
190  for (auto Base : llvm::reverse(Bases)) {
192  Allocations[Base].DeinitializationActions)) {
193  AllErr = joinErrors(std::move(AllErr), std::move(Err));
194  }
195 
196  // Remove the allocation from the allocation list of its reservation
197  for (auto &Reservation : Reservations) {
198  auto AllocationIt =
199  std::find(Reservation.second.Allocations.begin(),
200  Reservation.second.Allocations.end(), Base);
201  if (AllocationIt != Reservation.second.Allocations.end()) {
202  Reservation.second.Allocations.erase(AllocationIt);
203  break;
204  }
205  }
206 
207  Allocations.erase(Base);
208  }
209  }
210 
211  return AllErr;
212 }
213 
215  const std::vector<ExecutorAddr> &Bases) {
216 #if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)
217  Error Err = Error::success();
218 
219  for (auto Base : Bases) {
220  std::vector<ExecutorAddr> AllocAddrs;
221  size_t Size;
222 
223 #if defined(_WIN32)
224  HANDLE SharedMemoryFile;
225 #endif
226 
227  {
228  std::lock_guard<std::mutex> Lock(Mutex);
229  auto &R = Reservations[Base.toPtr<void *>()];
230  Size = R.Size;
231 
232 #if defined(_WIN32)
233  SharedMemoryFile = R.SharedMemoryFile;
234 #endif
235 
236  AllocAddrs.swap(R.Allocations);
237  }
238 
239  // deinitialize sub allocations
240  if (Error E = deinitialize(AllocAddrs))
241  Err = joinErrors(std::move(Err), std::move(E));
242 
243 #if defined(LLVM_ON_UNIX)
244 
245  if (munmap(Base.toPtr<void *>(), Size) != 0)
246  Err = joinErrors(std::move(Err), errorCodeToError(std::error_code(
247  errno, std::generic_category())));
248 
249 #elif defined(_WIN32)
250  (void)Size;
251 
252  if (!UnmapViewOfFile(Base.toPtr<void *>()))
253  Err = joinErrors(std::move(Err),
254  errorCodeToError(mapWindowsError(GetLastError())));
255 
256  CloseHandle(SharedMemoryFile);
257 
258 #endif
259 
260  std::lock_guard<std::mutex> Lock(Mutex);
261  Reservations.erase(Base.toPtr<void *>());
262  }
263 
264  return Err;
265 #else
266  return make_error<StringError>(
267  "SharedMemoryMapper is not supported on this platform yet",
269 #endif
270 }
271 
273  if (Reservations.empty())
274  return Error::success();
275 
276  std::vector<ExecutorAddr> ReservationAddrs;
277  ReservationAddrs.reserve(Reservations.size());
278  for (const auto &R : Reservations)
279  ReservationAddrs.push_back(ExecutorAddr::fromPtr(R.getFirst()));
280 
281  return release(std::move(ReservationAddrs));
282 }
283 
287  ExecutorAddr::fromPtr(this);
289  ExecutorAddr::fromPtr(&reserveWrapper);
291  ExecutorAddr::fromPtr(&initializeWrapper);
293  ExecutorAddr::fromPtr(&deinitializeWrapper);
295  ExecutorAddr::fromPtr(&releaseWrapper);
296 }
297 
299 ExecutorSharedMemoryMapperService::reserveWrapper(const char *ArgData,
300  size_t ArgSize) {
303  handle(ArgData, ArgSize,
306  .release();
307 }
308 
310 ExecutorSharedMemoryMapperService::initializeWrapper(const char *ArgData,
311  size_t ArgSize) {
314  handle(ArgData, ArgSize,
317  .release();
318 }
319 
321 ExecutorSharedMemoryMapperService::deinitializeWrapper(const char *ArgData,
322  size_t ArgSize) {
323  return shared::WrapperFunction<
325  handle(ArgData, ArgSize,
328  .release();
329 }
330 
332 ExecutorSharedMemoryMapperService::releaseWrapper(const char *ArgData,
333  size_t ArgSize) {
334  return shared::WrapperFunction<
336  handle(ArgData, ArgSize,
339  .release();
340 }
341 
342 } // namespace rt_bootstrap
343 } // end namespace orc
344 } // end namespace llvm
llvm::orc::ExecutorAddr
Represents an address in the executor process.
Definition: ExecutorAddress.h:31
llvm::orc::ExecutorAddr::fromPtr
static ExecutorAddr fromPtr(T *Ptr, UnwrapFn &&Unwrap=UnwrapFn())
Create an ExecutorAddr from the given pointer.
Definition: ExecutorAddress.h:80
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
M
We currently emits eax Perhaps this is what we really should generate is Is imull three or four cycles eax eax The current instruction priority is based on pattern complexity The former is more complex because it folds a load so the latter will not be emitted Perhaps we should use AddedComplexity to give LEA32r a higher priority We should always try to match LEA first since the LEA matching code does some estimate to determine whether the match is profitable if we care more about code then imull is better It s two bytes shorter than movl leal On a Pentium M
Definition: README.txt:252
llvm::orc::shared::CWrapperFunctionResult
Definition: WrapperFunctionUtils.h:33
llvm::sys::Memory::InvalidateInstructionCache
static 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...
llvm::orc::tpctypes::SharedMemoryFinalizeRequest
Definition: TargetProcessControlTypes.h:51
llvm::orc::shared::WrapperFunction
Definition: WrapperFunctionUtils.h:434
llvm::Error::success
static ErrorSuccess success()
Create a success value.
Definition: Error.h:329
llvm::DenseMapBase::erase
bool erase(const KeyT &Val)
Definition: DenseMap.h:302
llvm::Expected
Tagged union holding either a T or a Error.
Definition: APFloat.h:41
handle
then ret i32 result Tail recursion elimination should handle
Definition: README.txt:355
Process.h
ExecutorSharedMemoryMapperService.h
llvm::orc::ExecutorAddr::toPtr
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.
Definition: ExecutorAddress.h:89
llvm::orc::shared::runFinalizeActions
Expected< std::vector< WrapperFunctionCall > > runFinalizeActions(AllocActions &AAs)
Run finalize actions.
Definition: AllocationActions.cpp:16
E
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
llvm::orc::rt::SPSExecutorSharedMemoryMapperServiceInitializeSignature
shared::SPSExpected< shared::SPSExecutorAddr >(shared::SPSExecutorAddr, shared::SPSExecutorAddr, shared::SPSSharedMemoryFinalizeRequest) SPSExecutorSharedMemoryMapperServiceInitializeSignature
Definition: OrcRTBridge.h:78
llvm::orc::rt::ExecutorSharedMemoryMapperServiceDeinitializeWrapperName
const char * ExecutorSharedMemoryMapperServiceDeinitializeWrapperName
Definition: OrcRTBridge.cpp:37
llvm::errorCodeToError
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition: Error.cpp:92
llvm::orc::MemProt::Read
@ Read
llvm::orc::rt_bootstrap::ExecutorSharedMemoryMapperService::shutdown
Error shutdown() override
Definition: ExecutorSharedMemoryMapperService.cpp:272
llvm::mapWindowsError
std::error_code mapWindowsError(unsigned EV)
llvm::orc::rt_bootstrap::ExecutorSharedMemoryMapperService::deinitialize
Error deinitialize(const std::vector< ExecutorAddr > &Bases)
Definition: ExecutorSharedMemoryMapperService.cpp:183
llvm::sys::SmartMutex< false >
llvm::orc::rt_bootstrap::ExecutorSharedMemoryMapperService::initialize
Expected< ExecutorAddr > initialize(ExecutorAddr Reservation, tpctypes::SharedMemoryFinalizeRequest &FR)
Definition: ExecutorSharedMemoryMapperService.cpp:121
llvm::StringMap
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition: StringMap.h:110
llvm::orc::rt::ExecutorSharedMemoryMapperServiceInstanceName
const char * ExecutorSharedMemoryMapperServiceInstanceName
Definition: OrcRTBridge.cpp:31
llvm::orc::rt::SPSExecutorSharedMemoryMapperServiceDeinitializeSignature
shared::SPSError(shared::SPSExecutorAddr, shared::SPSSequence< shared::SPSExecutorAddr >) SPSExecutorSharedMemoryMapperServiceDeinitializeSignature
Definition: OrcRTBridge.h:81
llvm::orc::rt::SPSExecutorSharedMemoryMapperServiceReserveSignature
shared::SPSExpected< shared::SPSTuple< shared::SPSExecutorAddr, shared::SPSString > >(shared::SPSExecutorAddr, uint64_t) SPSExecutorSharedMemoryMapperServiceReserveSignature
Definition: OrcRTBridge.h:74
llvm::orc::MemProt
MemProt
Describes Read/Write/Exec permissions for memory.
Definition: MemoryFlags.h:27
uint64_t
llvm::find
auto find(R &&Range, const T &Val)
Provide wrappers to std::find which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1754
Addr
uint64_t Addr
Definition: ELFObjHandler.cpp:79
llvm::orc::tpctypes::SharedMemoryFinalizeRequest::Segments
std::vector< SharedMemorySegFinalizeRequest > Segments
Definition: TargetProcessControlTypes.h:52
move
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
Definition: README.txt:546
llvm::orc::rt::ExecutorSharedMemoryMapperServiceReleaseWrapperName
const char * ExecutorSharedMemoryMapperServiceReleaseWrapperName
Definition: OrcRTBridge.cpp:39
llvm::joinErrors
Error joinErrors(Error E1, Error E2)
Concatenate errors.
Definition: Error.h:426
llvm::orc::shared::runDeallocActions
Error runDeallocActions(ArrayRef< WrapperFunctionCall > DAs)
Run deallocation actions.
Definition: AllocationActions.cpp:33
llvm::AMDGPU::SDWA::DWORD
@ DWORD
Definition: SIDefines.h:766
llvm::DenseMapBase::empty
bool empty() const
Definition: DenseMap.h:98
llvm::orc::rt_bootstrap::ExecutorSharedMemoryMapperService::reserve
Expected< std::pair< ExecutorAddr, std::string > > reserve(uint64_t Size)
Definition: ExecutorSharedMemoryMapperService.cpp:49
llvm::inconvertibleErrorCode
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition: Error.cpp:79
llvm::Error
Lightweight error class with error context and mandatory checking.
Definition: Error.h:155
llvm::DenseMapBase::size
unsigned size() const
Definition: DenseMap.h:99
llvm::sys::Process::getProcessId
static Pid getProcessId()
Get the process's identifier.
llvm::orc::rt_bootstrap::ExecutorSharedMemoryMapperService::release
Error release(const std::vector< ExecutorAddr > &Bases)
Definition: ExecutorSharedMemoryMapperService.cpp:214
llvm::orc::shared::makeMethodWrapperHandler
MethodWrapperHandler< RetT, ClassT, ArgTs... > makeMethodWrapperHandler(RetT(ClassT::*Method)(ArgTs...))
Create a MethodWrapperHandler object from the given method pointer.
Definition: WrapperFunctionUtils.h:617
llvm::orc::rt_bootstrap::ExecutorSharedMemoryMapperService::addBootstrapSymbols
void addBootstrapSymbols(StringMap< ExecutorAddr > &M) override
Definition: ExecutorSharedMemoryMapperService.cpp:284
llvm::reverse
auto reverse(ContainerTy &&C)
Definition: STLExtras.h:485
llvm::orc::MemProt::Exec
@ Exec
llvm::orc::rt::ExecutorSharedMemoryMapperServiceReserveWrapperName
const char * ExecutorSharedMemoryMapperServiceReserveWrapperName
Definition: OrcRTBridge.cpp:33
llvm::orc::tpctypes::SharedMemoryFinalizeRequest::Actions
shared::AllocActions Actions
Definition: TargetProcessControlTypes.h:53
OrcRTBridge.h
llvm::orc::rt::ExecutorSharedMemoryMapperServiceInitializeWrapperName
const char * ExecutorSharedMemoryMapperServiceInitializeWrapperName
Definition: OrcRTBridge.cpp:35
llvm::orc::rt::SPSExecutorSharedMemoryMapperServiceReleaseSignature
shared::SPSError(shared::SPSExecutorAddr, shared::SPSSequence< shared::SPSExecutorAddr >) SPSExecutorSharedMemoryMapperServiceReleaseSignature
Definition: OrcRTBridge.h:83
llvm::sampleprof::Base
@ Base
Definition: Discriminator.h:58
llvm::orc::MemProt::Write
@ Write
WindowsError.h