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