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