//===- llvm/Support/Memory.h - Memory Support -------------------*- 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 // //===----------------------------------------------------------------------===// // // This file declares the llvm::sys::Memory class. // //===----------------------------------------------------------------------===// #ifndef LLVM_SUPPORT_MEMORY_H #define LLVM_SUPPORT_MEMORY_H #include "llvm/Support/DataTypes.h" #include namespace llvm { // Forward declare raw_ostream: it is used for debug dumping below. class raw_ostream; namespace sys { /// This class encapsulates the notion of a memory block which has an address /// and a size. It is used by the Memory class (a friend) as the result of /// various memory allocation operations. /// @see Memory /// Memory block abstraction. class MemoryBlock { public: MemoryBlock() : Address(nullptr), AllocatedSize(0) {} MemoryBlock(void *addr, size_t allocatedSize) : Address(addr), AllocatedSize(allocatedSize) {} void *base() const { return Address; } /// The size as it was allocated. This is always greater or equal to the /// size that was originally requested. size_t allocatedSize() const { return AllocatedSize; } private: void *Address; ///< Address of first byte of memory area size_t AllocatedSize; ///< Size, in bytes of the memory area unsigned Flags = 0; friend class Memory; }; /// This class provides various memory handling functions that manipulate /// MemoryBlock instances. /// @since 1.4 /// An abstraction for memory operations. class Memory { public: enum ProtectionFlags { MF_READ = 0x1000000, MF_WRITE = 0x2000000, MF_EXEC = 0x4000000, MF_RWE_MASK = 0x7000000, /// The \p MF_HUGE_HINT flag is used to indicate that the request for /// a memory block should be satisfied with large pages if possible. /// This is only a hint and small pages will be used as fallback. /// /// The presence or absence of this flag in the returned memory block /// is (at least currently) *not* a reliable indicator that the memory /// block will use or will not use large pages. On some systems a request /// without this flag can be backed by large pages without this flag being /// set, and on some other systems a request with this flag can fallback /// to small pages without this flag being cleared. MF_HUGE_HINT = 0x0000001 }; /// This method allocates a block of memory that is suitable for loading /// dynamically generated code (e.g. JIT). An attempt to allocate /// \p NumBytes bytes of virtual memory is made. /// \p NearBlock may point to an existing allocation in which case /// an attempt is made to allocate more memory near the existing block. /// The actual allocated address is not guaranteed to be near the requested /// address. /// \p Flags is used to set the initial protection flags for the block /// of the memory. /// \p EC [out] returns an object describing any error that occurs. /// /// This method may allocate more than the number of bytes requested. The /// actual number of bytes allocated is indicated in the returned /// MemoryBlock. /// /// The start of the allocated block must be aligned with the /// system allocation granularity (64K on Windows, page size on Linux). /// If the address following \p NearBlock is not so aligned, it will be /// rounded up to the next allocation granularity boundary. /// /// \r a non-null MemoryBlock if the function was successful, /// otherwise a null MemoryBlock is with \p EC describing the error. /// /// Allocate mapped memory. static MemoryBlock allocateMappedMemory(size_t NumBytes, const MemoryBlock *const NearBlock, unsigned Flags, std::error_code &EC); /// This method releases a block of memory that was allocated with the /// allocateMappedMemory method. It should not be used to release any /// memory block allocated any other way. /// \p Block describes the memory to be released. /// /// \r error_success if the function was successful, or an error_code /// describing the failure if an error occurred. /// /// Release mapped memory. static std::error_code releaseMappedMemory(MemoryBlock &Block); /// This method sets the protection flags for a block of memory to the /// state specified by /p Flags. The behavior is not specified if the /// memory was not allocated using the allocateMappedMemory method. /// \p Block describes the memory block to be protected. /// \p Flags specifies the new protection state to be assigned to the block. /// /// If \p Flags is MF_WRITE, the actual behavior varies /// with the operating system (i.e. MF_READ | MF_WRITE on Windows) and the /// target architecture (i.e. MF_WRITE -> MF_READ | MF_WRITE on i386). /// /// \r error_success if the function was successful, or an error_code /// describing the failure if an error occurred. /// /// Set memory protection state. static std::error_code protectMappedMemory(const MemoryBlock &Block, unsigned Flags); /// InvalidateInstructionCache - Before the JIT can run a block of code /// that has been emitted it must invalidate the instruction cache on some /// platforms. static void InvalidateInstructionCache(const void *Addr, size_t Len); }; /// Owning version of MemoryBlock. class OwningMemoryBlock { public: OwningMemoryBlock() = default; explicit OwningMemoryBlock(MemoryBlock M) : M(M) {} OwningMemoryBlock(OwningMemoryBlock &&Other) { M = Other.M; Other.M = MemoryBlock(); } OwningMemoryBlock& operator=(OwningMemoryBlock &&Other) { M = Other.M; Other.M = MemoryBlock(); return *this; } ~OwningMemoryBlock() { if (M.base()) Memory::releaseMappedMemory(M); } void *base() const { return M.base(); } /// The size as it was allocated. This is always greater or equal to the /// size that was originally requested. size_t allocatedSize() const { return M.allocatedSize(); } MemoryBlock getMemoryBlock() const { return M; } std::error_code release() { std::error_code EC; if (M.base()) { EC = Memory::releaseMappedMemory(M); M = MemoryBlock(); } return EC; } private: MemoryBlock M; }; #ifndef NDEBUG /// Debugging output for Memory::ProtectionFlags. raw_ostream &operator<<(raw_ostream &OS, const Memory::ProtectionFlags &PF); /// Debugging output for MemoryBlock. raw_ostream &operator<<(raw_ostream &OS, const MemoryBlock &MB); #endif // ifndef NDEBUG } // end namespace sys } // end namespace llvm #endif