//===- MemoryMapper.cpp - Cross-process memory mapper ------------*- C++ -*-==// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/Orc/MemoryMapper.h" namespace llvm { namespace orc { MemoryMapper::~MemoryMapper() {} void InProcessMemoryMapper::reserve(size_t NumBytes, OnReservedFunction OnReserved) { std::error_code EC; auto MB = sys::Memory::allocateMappedMemory( NumBytes, nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC); if (EC) return OnReserved(errorCodeToError(EC)); { std::lock_guard Lock(Mutex); Reservations[MB.base()].Size = MB.allocatedSize(); } OnReserved( ExecutorAddrRange(ExecutorAddr::fromPtr(MB.base()), MB.allocatedSize())); } char *InProcessMemoryMapper::prepare(ExecutorAddr Addr, size_t ContentSize) { return Addr.toPtr(); } void InProcessMemoryMapper::initialize(MemoryMapper::AllocInfo &AI, OnInitializedFunction OnInitialized) { ExecutorAddr MinAddr(~0ULL); for (auto &Segment : AI.Segments) { auto Base = AI.MappingBase + Segment.Offset; auto Size = Segment.ContentSize + Segment.ZeroFillSize; if (Base < MinAddr) MinAddr = Base; std::memset((Base + Segment.ContentSize).toPtr(), 0, Segment.ZeroFillSize); if (auto EC = sys::Memory::protectMappedMemory({Base.toPtr(), Size}, Segment.Prot)) { return OnInitialized(errorCodeToError(EC)); } if (Segment.Prot & sys::Memory::MF_EXEC) sys::Memory::InvalidateInstructionCache(Base.toPtr(), Size); } auto DeinitializeActions = shared::runFinalizeActions(AI.Actions); if (!DeinitializeActions) return OnInitialized(DeinitializeActions.takeError()); { std::lock_guard Lock(Mutex); Allocations[MinAddr].DeinitializationActions = std::move(*DeinitializeActions); Reservations[AI.MappingBase.toPtr()].Allocations.push_back(MinAddr); } OnInitialized(MinAddr); } void InProcessMemoryMapper::deinitialize( ArrayRef Bases, MemoryMapper::OnDeinitializedFunction OnDeinitialized) { Error AllErr = Error::success(); { std::lock_guard Lock(Mutex); for (auto Base : Bases) { if (Error Err = shared::runDeallocActions( Allocations[Base].DeinitializationActions)) { AllErr = joinErrors(std::move(AllErr), std::move(Err)); } Allocations.erase(Base); } } OnDeinitialized(std::move(AllErr)); } void InProcessMemoryMapper::release(ArrayRef Bases, OnReleasedFunction OnReleased) { Error Err = Error::success(); for (auto Base : Bases) { std::vector AllocAddrs; size_t Size; { std::lock_guard Lock(Mutex); auto &R = Reservations[Base.toPtr()]; Size = R.Size; AllocAddrs.swap(R.Allocations); } // deinitialize sub allocations std::promise P; auto F = P.get_future(); deinitialize(AllocAddrs, [&](Error Err) { P.set_value(std::move(Err)); }); if (Error E = F.get()) { Err = joinErrors(std::move(Err), std::move(E)); } // free the memory auto MB = sys::MemoryBlock(Base.toPtr(), Size); auto EC = sys::Memory::releaseMappedMemory(MB); if (EC) { Err = joinErrors(std::move(Err), errorCodeToError(EC)); } std::lock_guard Lock(Mutex); Reservations.erase(Base.toPtr()); } OnReleased(std::move(Err)); } InProcessMemoryMapper::~InProcessMemoryMapper() { std::vector ReservationAddrs; { std::lock_guard Lock(Mutex); ReservationAddrs.reserve(Reservations.size()); for (const auto &R : Reservations) { ReservationAddrs.push_back(ExecutorAddr::fromPtr(R.getFirst())); } } std::promise P; auto F = P.get_future(); release(ReservationAddrs, [&](Error Err) { P.set_value(std::move(Err)); }); cantFail(F.get()); } } // namespace orc } // namespace llvm