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 22namespace llvm { 23namespace orc { 24 25/// Manages mapping, content transfer and protections for JIT memory 26class MemoryMapper { 27public: 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 82class InProcessMemoryMapper : public MemoryMapper { 83public: 84 InProcessMemoryMapper(size_t PageSize); 85 86 static Expected<std::unique_ptr<InProcessMemoryMapper>> Create(); 87 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 104private: 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 124class SharedMemoryMapper final : public MemoryMapper { 125public: 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 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 156private: 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