1 //===- MemoryMapper.h - 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 // Cross-process (and in-process) memory mapping and transfer
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_EXECUTIONENGINE_ORC_MEMORYMAPPER_H
14 #define LLVM_EXECUTIONENGINE_ORC_MEMORYMAPPER_H
15 
16 #include "llvm/ExecutionEngine/Orc/Core.h"
17 #include "llvm/Support/Process.h"
18 
19 #include <mutex>
20 
21 namespace llvm {
22 namespace orc {
23 
24 /// Manages mapping, content transfer and protections for JIT memory
25 class MemoryMapper {
26 public:
27   /// Represents a single allocation containing multiple segments and
28   /// initialization and deinitialization actions
29   struct AllocInfo {
30     struct SegInfo {
31       ExecutorAddrDiff Offset;
32       const char *WorkingMem;
33       size_t ContentSize;
34       size_t ZeroFillSize;
35       unsigned Prot;
36     };
37 
38     ExecutorAddr MappingBase;
39     std::vector<SegInfo> Segments;
40     shared::AllocActions Actions;
41   };
42 
43   using OnReservedFunction = unique_function<void(Expected<ExecutorAddrRange>)>;
44 
45   // Page size of the target process
46   virtual unsigned int getPageSize() = 0;
47 
48   /// Reserves address space in executor process
49   virtual void reserve(size_t NumBytes, OnReservedFunction OnReserved) = 0;
50 
51   /// Provides working memory
52   virtual char *prepare(ExecutorAddr Addr, size_t ContentSize) = 0;
53 
54   using OnInitializedFunction = unique_function<void(Expected<ExecutorAddr>)>;
55 
56   /// Ensures executor memory is synchronized with working copy memory, sends
57   /// functions to be called after initilization and before deinitialization and
58   /// applies memory protections
59   /// Returns a unique address identifying the allocation. This address should
60   /// be passed to deinitialize to run deallocation actions (and reset
61   /// permissions where possible).
62   virtual void initialize(AllocInfo &AI,
63                           OnInitializedFunction OnInitialized) = 0;
64 
65   using OnDeinitializedFunction = unique_function<void(Error)>;
66 
67   /// Runs previously specified deinitialization actions
68   /// Executor addresses returned by initialize should be passed
69   virtual void deinitialize(ArrayRef<ExecutorAddr> Allocations,
70                             OnDeinitializedFunction OnDeInitialized) = 0;
71 
72   using OnReleasedFunction = unique_function<void(Error)>;
73 
74   /// Release address space acquired through reserve()
75   virtual void release(ArrayRef<ExecutorAddr> Reservations,
76                        OnReleasedFunction OnRelease) = 0;
77 
78   virtual ~MemoryMapper();
79 };
80 
81 class InProcessMemoryMapper final : public MemoryMapper {
82 public:
83   InProcessMemoryMapper(size_t PageSize);
84 
85   static Expected<std::unique_ptr<InProcessMemoryMapper>> Create();
86 
87   unsigned int getPageSize() override { return PageSize; }
88 
89   void reserve(size_t NumBytes, OnReservedFunction OnReserved) override;
90 
91   void initialize(AllocInfo &AI, OnInitializedFunction OnInitialized) override;
92 
93   char *prepare(ExecutorAddr Addr, size_t ContentSize) override;
94 
95   void deinitialize(ArrayRef<ExecutorAddr> Allocations,
96                     OnDeinitializedFunction OnDeInitialized) override;
97 
98   void release(ArrayRef<ExecutorAddr> Reservations,
99                OnReleasedFunction OnRelease) override;
100 
101   ~InProcessMemoryMapper() override;
102 
103 private:
104   struct Allocation {
105     std::vector<shared::WrapperFunctionCall> DeinitializationActions;
106   };
107   using AllocationMap = DenseMap<ExecutorAddr, Allocation>;
108 
109   struct Reservation {
110     size_t Size;
111     std::vector<ExecutorAddr> Allocations;
112   };
113   using ReservationMap = DenseMap<void *, Reservation>;
114 
115   std::mutex Mutex;
116   ReservationMap Reservations;
117   AllocationMap Allocations;
118 
119   size_t PageSize;
120 };
121 
122 class SharedMemoryMapper final : public MemoryMapper {
123 public:
124   struct SymbolAddrs {
125     ExecutorAddr Instance;
126     ExecutorAddr Reserve;
127     ExecutorAddr Initialize;
128     ExecutorAddr Deinitialize;
129     ExecutorAddr Release;
130   };
131 
132   SharedMemoryMapper(ExecutorProcessControl &EPC, SymbolAddrs SAs,
133                      size_t PageSize);
134 
135   static Expected<std::unique_ptr<SharedMemoryMapper>>
136   Create(ExecutorProcessControl &EPC, SymbolAddrs SAs);
137 
138   unsigned int getPageSize() override { return PageSize; }
139 
140   void reserve(size_t NumBytes, OnReservedFunction OnReserved) override;
141 
142   char *prepare(ExecutorAddr Addr, size_t ContentSize) override;
143 
144   void initialize(AllocInfo &AI, OnInitializedFunction OnInitialized) override;
145 
146   void deinitialize(ArrayRef<ExecutorAddr> Allocations,
147                     OnDeinitializedFunction OnDeInitialized) override;
148 
149   void release(ArrayRef<ExecutorAddr> Reservations,
150                OnReleasedFunction OnRelease) override;
151 
152   ~SharedMemoryMapper() override;
153 
154 private:
155   struct Reservation {
156     void *LocalAddr;
157     size_t Size;
158   };
159 
160   ExecutorProcessControl &EPC;
161   SymbolAddrs SAs;
162 
163   std::mutex Mutex;
164 
165   std::map<ExecutorAddr, Reservation> Reservations;
166 
167   size_t PageSize;
168 };
169 
170 } // namespace orc
171 } // end namespace llvm
172 
173 #endif // LLVM_EXECUTIONENGINE_ORC_MEMORYMAPPER_H
174