//===----- memorymanager.h - Memory manager for MCJIT/RtDyld -*- C++ -*----===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file contains the declaration of a section-based memory manager used by9// the MCJIT execution engine and RuntimeDyld.10//11//===----------------------------------------------------------------------===//1213#pragma once1415// Force default visibility of the llvm::ErrorInfoBase class. The conda16// compilers use the -fvisibility-inlines-hidden flag, which seems to17// erroneously result in ErrorInfoBase::isA() being hidden (and not exported) on18// PowerPC. The reason for this is not conclusively known, but the circumstances19// appear similar to those reported in GCC Bug 4506520// (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=45066) - ErrorInfoBase has21// both a template and non-template version, and the non-template version is22// overridden by the derived class ErrorInfo; the template vs. non-template23// versions may have different inlining decisions applied, and this could create24// a similar circumstance to that described in the bug.25//26// The workaround here adds the default visiblity attribute to ErrorInfoBase27// before its definition, which precludes it from being inferred to be hidden28// later on.29#if not defined(_MSC_VER)30namespace llvm {31class __attribute__((visibility("default"))) ErrorInfoBase;32}33#endif3435#include "core.h"36#include "llvm/ADT/SmallVector.h"37#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"38#include "llvm/Support/Alignment.h"39#include "llvm/Support/Memory.h"40#include <cstdint>41#include <string>42#include <system_error>4344namespace llvm {4546/// This is a simple memory manager which implements the methods called by47/// the RuntimeDyld class to allocate memory for section-based loading of48/// objects, usually those generated by the MCJIT execution engine.49///50/// This memory manager allocates all section memory as read-write. The51/// RuntimeDyld will copy JITed section memory into these allocated blocks52/// and perform any necessary linking and relocations.53///54/// Any client using this memory manager MUST ensure that section-specific55/// page permissions have been applied before attempting to execute functions56/// in the JITed object. Permissions can be applied either by calling57/// MCJIT::finalizeObject or by calling LlvmliteMemoryManager::finalizeMemory58/// directly. Clients of MCJIT should call MCJIT::finalizeObject.59class API_EXPORT(LlvmliteMemoryManager : public RTDyldMemoryManager) {60public:61/// This enum describes the various reasons to allocate pages from62/// allocateMappedMemory.63enum class AllocationPurpose {64Code,65ROData,66RWData,67};6869/// Implementations of this interface are used by LlvmliteMemoryManager to70/// request pages from the operating system.71class MemoryMapper {72public:73/// This method attempts to allocate \p NumBytes bytes of virtual memory74/// for \p Purpose. \p NearBlock may point to an existing allocation,75/// in which case an attempt is made to allocate more memory near the76/// existing block. The actual allocated address is not guaranteed to be77/// near the requested address. \p Flags is used to set the initial78/// protection flags for the block of the memory. \p EC [out] returns79/// an object describing any error that occurs.80///81/// This method may allocate more than the number of bytes requested.82/// The actual number of bytes allocated is indicated in the returned83/// MemoryBlock.84///85/// The start of the allocated block must be aligned with the system86/// allocation granularity (64K on Windows, page size on Linux). If the87/// address following \p NearBlock is not so aligned, it will be rounded88/// up to the next allocation granularity boundary.89///90/// \r a non-null MemoryBlock if the function was successful, otherwise91/// a null MemoryBlock with \p EC describing the error.92virtual sys::MemoryBlock93allocateMappedMemory(AllocationPurpose Purpose, size_t NumBytes,94const sys::MemoryBlock *const NearBlock,95unsigned Flags, std::error_code &EC) = 0;9697/// This method sets the protection flags for a block of memory to the98/// state specified by \p Flags. The behavior is not specified if the99/// memory was not allocated using the allocateMappedMemory method. \p100/// Block describes the memory block to be protected. \p Flags specifies101/// the new protection state to be assigned to the block.102///103/// If \p Flags is MF_WRITE, the actual behavior varies with the104/// operating system (i.e. MF_READ | MF_WRITE on Windows) and the target105/// architecture (i.e. MF_WRITE -> MF_READ | MF_WRITE on i386).106///107/// \r error_success if the function was successful, or an error_code108/// describing the failure if an error occurred.109virtual std::error_code110protectMappedMemory(const sys::MemoryBlock &Block, unsigned Flags) = 0;111112/// This method releases a block of memory that was allocated with the113/// allocateMappedMemory method. It should not be used to release any114/// memory block allocated any other way. \p Block describes the memory115/// to be released.116///117/// \r error_success if the function was successful, or an error_code118/// describing the failure if an error occurred.119virtual std::error_code releaseMappedMemory(sys::MemoryBlock &M) = 0;120121virtual ~MemoryMapper();122};123124/// Creates a LlvmliteMemoryManager instance with \p MM as the associated125/// memory mapper. If \p MM is nullptr then a default memory mapper is used126/// that directly calls into the operating system.127LlvmliteMemoryManager(MemoryMapper *MM = nullptr);128LlvmliteMemoryManager(const LlvmliteMemoryManager &) = delete;129void operator=(const LlvmliteMemoryManager &) = delete;130~LlvmliteMemoryManager() override;131132/// Allocates a memory block of (at least) the given size suitable for133/// executable code.134///135/// The value of \p Alignment must be a power of two. If \p Alignment is136/// zero a default alignment of 16 will be used.137uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,138unsigned SectionID,139StringRef SectionName) override;140141/// Allocates a memory block of (at least) the given size suitable for142/// executable code.143///144/// The value of \p Alignment must be a power of two. If \p Alignment is145/// zero a default alignment of 16 will be used.146uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,147unsigned SectionID, StringRef SectionName,148bool isReadOnly) override;149150/// Update section-specific memory permissions and other attributes.151///152/// This method is called when object loading is complete and section page153/// permissions can be applied. It is up to the memory manager154/// implementation to decide whether or not to act on this method. The155/// memory manager will typically allocate all sections as read-write and156/// then apply specific permissions when this method is called. Code157/// sections cannot be executed until this function has been called. In158/// addition, any cache coherency operations needed to reliably use the159/// memory are also performed.160///161/// \returns true if an error occurred, false otherwise.162bool finalizeMemory(std::string *ErrMsg = nullptr) override;163164/// Invalidate instruction cache for code sections.165///166/// Some platforms with separate data cache and instruction cache require167/// explicit cache flush, otherwise JIT code manipulations (like resolved168/// relocations) will get to the data cache but not to the instruction169/// cache.170///171/// This method is called from finalizeMemory.172virtual void invalidateInstructionCache();173174virtual bool needsToReserveAllocationSpace() override { return true; }175176virtual void reserveAllocationSpace(uintptr_t CodeSize, Align CodeAlign,177uintptr_t RODataSize, Align RODataAlign,178uintptr_t RWDataSize,179Align RWDataAlign) override;180181private:182struct FreeMemBlock {183// The actual block of free memory184sys::MemoryBlock Free;185// If there is a pending allocation from the same reservation right186// before this block, store it's index in PendingMem, to be able to187// update the pending region if part of this block is allocated, rather188// than having to create a new one189unsigned PendingPrefixIndex;190};191192struct MemoryGroup {193// PendingMem contains all blocks of memory (subblocks of AllocatedMem)194// which have not yet had their permissions applied, but have been given195// out to the user. FreeMem contains all block of memory, which have196// neither had their permissions applied, nor been given out to the197// user.198SmallVector<sys::MemoryBlock, 16> PendingMem;199SmallVector<FreeMemBlock, 16> FreeMem;200201// All memory blocks that have been requested from the system202SmallVector<sys::MemoryBlock, 16> AllocatedMem;203204sys::MemoryBlock Near;205};206207uint8_t *allocateSection(AllocationPurpose Purpose, uintptr_t Size,208unsigned Alignment);209210std::error_code applyMemoryGroupPermissions(MemoryGroup &MemGroup,211unsigned Permissions);212213bool hasSpace(const MemoryGroup &MemGroup, uintptr_t Size) const;214215void anchor() override;216217MemoryGroup CodeMem;218MemoryGroup RWDataMem;219MemoryGroup RODataMem;220MemoryMapper &MMapper;221};222223} // end namespace llvm224225226