1 //===- MemoryMapper.cpp - 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 #include "llvm/ExecutionEngine/Orc/MemoryMapper.h" 10 11 namespace llvm { 12 namespace orc { 13 14 MemoryMapper::~MemoryMapper() {} 15 16 void InProcessMemoryMapper::reserve(size_t NumBytes, 17 OnReservedFunction OnReserved) { 18 std::error_code EC; 19 auto MB = sys::Memory::allocateMappedMemory( 20 NumBytes, nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC); 21 22 if (EC) 23 return OnReserved(errorCodeToError(EC)); 24 25 { 26 std::lock_guard<std::mutex> Lock(Mutex); 27 Reservations[MB.base()].Size = MB.allocatedSize(); 28 } 29 30 OnReserved( 31 ExecutorAddrRange(ExecutorAddr::fromPtr(MB.base()), MB.allocatedSize())); 32 } 33 34 char *InProcessMemoryMapper::prepare(ExecutorAddr Addr, size_t ContentSize) { 35 return Addr.toPtr<char *>(); 36 } 37 38 void InProcessMemoryMapper::initialize(MemoryMapper::AllocInfo &AI, 39 OnInitializedFunction OnInitialized) { 40 ExecutorAddr MinAddr(~0ULL); 41 42 for (auto &Segment : AI.Segments) { 43 auto Base = AI.MappingBase + Segment.Offset; 44 auto Size = Segment.ContentSize + Segment.ZeroFillSize; 45 46 if (Base < MinAddr) 47 MinAddr = Base; 48 49 std::memset((Base + Segment.ContentSize).toPtr<void *>(), 0, 50 Segment.ZeroFillSize); 51 52 if (auto EC = sys::Memory::protectMappedMemory({Base.toPtr<void *>(), Size}, 53 Segment.Prot)) { 54 return OnInitialized(errorCodeToError(EC)); 55 } 56 if (Segment.Prot & sys::Memory::MF_EXEC) 57 sys::Memory::InvalidateInstructionCache(Base.toPtr<void *>(), Size); 58 } 59 60 auto DeinitializeActions = shared::runFinalizeActions(AI.Actions); 61 if (!DeinitializeActions) 62 return OnInitialized(DeinitializeActions.takeError()); 63 64 { 65 std::lock_guard<std::mutex> Lock(Mutex); 66 Allocations[MinAddr].DeinitializationActions = 67 std::move(*DeinitializeActions); 68 Reservations[AI.MappingBase.toPtr<void *>()].Allocations.push_back(MinAddr); 69 } 70 71 OnInitialized(MinAddr); 72 } 73 74 void InProcessMemoryMapper::deinitialize( 75 ArrayRef<ExecutorAddr> Bases, 76 MemoryMapper::OnDeinitializedFunction OnDeinitialized) { 77 Error AllErr = Error::success(); 78 79 { 80 std::lock_guard<std::mutex> Lock(Mutex); 81 82 for (auto Base : Bases) { 83 84 if (Error Err = shared::runDeallocActions( 85 Allocations[Base].DeinitializationActions)) { 86 AllErr = joinErrors(std::move(AllErr), std::move(Err)); 87 } 88 89 Allocations.erase(Base); 90 } 91 } 92 93 OnDeinitialized(std::move(AllErr)); 94 } 95 96 void InProcessMemoryMapper::release(ArrayRef<ExecutorAddr> Bases, 97 OnReleasedFunction OnReleased) { 98 Error Err = Error::success(); 99 100 for (auto Base : Bases) { 101 std::vector<ExecutorAddr> AllocAddrs; 102 size_t Size; 103 { 104 std::lock_guard<std::mutex> Lock(Mutex); 105 auto &R = Reservations[Base.toPtr<void *>()]; 106 Size = R.Size; 107 AllocAddrs.swap(R.Allocations); 108 } 109 110 // deinitialize sub allocations 111 std::promise<MSVCPError> P; 112 auto F = P.get_future(); 113 deinitialize(AllocAddrs, [&](Error Err) { P.set_value(std::move(Err)); }); 114 if (Error E = F.get()) { 115 Err = joinErrors(std::move(Err), std::move(E)); 116 } 117 118 // free the memory 119 auto MB = sys::MemoryBlock(Base.toPtr<void *>(), Size); 120 121 auto EC = sys::Memory::releaseMappedMemory(MB); 122 if (EC) { 123 Err = joinErrors(std::move(Err), errorCodeToError(EC)); 124 } 125 126 std::lock_guard<std::mutex> Lock(Mutex); 127 Reservations.erase(Base.toPtr<void *>()); 128 } 129 130 OnReleased(std::move(Err)); 131 } 132 133 InProcessMemoryMapper::~InProcessMemoryMapper() { 134 std::vector<ExecutorAddr> ReservationAddrs; 135 { 136 std::lock_guard<std::mutex> Lock(Mutex); 137 138 ReservationAddrs.reserve(Reservations.size()); 139 for (const auto &R : Reservations) { 140 ReservationAddrs.push_back(ExecutorAddr::fromPtr(R.getFirst())); 141 } 142 } 143 144 std::promise<MSVCPError> P; 145 auto F = P.get_future(); 146 release(ReservationAddrs, [&](Error Err) { P.set_value(std::move(Err)); }); 147 cantFail(F.get()); 148 } 149 150 } // namespace orc 151 152 } // namespace llvm 153