Home | History | Annotate | Download | only in Support
      1 //===- llvm/Support/Memory.h - Memory Support -------------------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file declares the llvm::sys::Memory class.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #ifndef LLVM_SUPPORT_MEMORY_H
     15 #define LLVM_SUPPORT_MEMORY_H
     16 
     17 #include "llvm/Support/DataTypes.h"
     18 #include <string>
     19 #include <system_error>
     20 
     21 namespace llvm {
     22 namespace sys {
     23 
     24   /// This class encapsulates the notion of a memory block which has an address
     25   /// and a size. It is used by the Memory class (a friend) as the result of
     26   /// various memory allocation operations.
     27   /// @see Memory
     28   /// @brief Memory block abstraction.
     29   class MemoryBlock {
     30   public:
     31     MemoryBlock() : Address(nullptr), Size(0) { }
     32     MemoryBlock(void *addr, size_t size) : Address(addr), Size(size) { }
     33     void *base() const { return Address; }
     34     size_t size() const { return Size; }
     35 
     36   private:
     37     void *Address;    ///< Address of first byte of memory area
     38     size_t Size;      ///< Size, in bytes of the memory area
     39     friend class Memory;
     40   };
     41 
     42   /// This class provides various memory handling functions that manipulate
     43   /// MemoryBlock instances.
     44   /// @since 1.4
     45   /// @brief An abstraction for memory operations.
     46   class Memory {
     47   public:
     48     enum ProtectionFlags {
     49       MF_READ  = 0x1000000,
     50       MF_WRITE = 0x2000000,
     51       MF_EXEC  = 0x4000000
     52     };
     53 
     54     /// This method allocates a block of memory that is suitable for loading
     55     /// dynamically generated code (e.g. JIT). An attempt to allocate
     56     /// \p NumBytes bytes of virtual memory is made.
     57     /// \p NearBlock may point to an existing allocation in which case
     58     /// an attempt is made to allocate more memory near the existing block.
     59     /// The actual allocated address is not guaranteed to be near the requested
     60     /// address.
     61     /// \p Flags is used to set the initial protection flags for the block
     62     /// of the memory.
     63     /// \p EC [out] returns an object describing any error that occurs.
     64     ///
     65     /// This method may allocate more than the number of bytes requested.  The
     66     /// actual number of bytes allocated is indicated in the returned
     67     /// MemoryBlock.
     68     ///
     69     /// The start of the allocated block must be aligned with the
     70     /// system allocation granularity (64K on Windows, page size on Linux).
     71     /// If the address following \p NearBlock is not so aligned, it will be
     72     /// rounded up to the next allocation granularity boundary.
     73     ///
     74     /// \r a non-null MemoryBlock if the function was successful,
     75     /// otherwise a null MemoryBlock is with \p EC describing the error.
     76     ///
     77     /// @brief Allocate mapped memory.
     78     static MemoryBlock allocateMappedMemory(size_t NumBytes,
     79                                             const MemoryBlock *const NearBlock,
     80                                             unsigned Flags,
     81                                             std::error_code &EC);
     82 
     83     /// This method releases a block of memory that was allocated with the
     84     /// allocateMappedMemory method. It should not be used to release any
     85     /// memory block allocated any other way.
     86     /// \p Block describes the memory to be released.
     87     ///
     88     /// \r error_success if the function was successful, or an error_code
     89     /// describing the failure if an error occurred.
     90     ///
     91     /// @brief Release mapped memory.
     92     static std::error_code releaseMappedMemory(MemoryBlock &Block);
     93 
     94     /// This method sets the protection flags for a block of memory to the
     95     /// state specified by /p Flags.  The behavior is not specified if the
     96     /// memory was not allocated using the allocateMappedMemory method.
     97     /// \p Block describes the memory block to be protected.
     98     /// \p Flags specifies the new protection state to be assigned to the block.
     99     /// \p ErrMsg [out] returns a string describing any error that occurred.
    100     ///
    101     /// If \p Flags is MF_WRITE, the actual behavior varies
    102     /// with the operating system (i.e. MF_READ | MF_WRITE on Windows) and the
    103     /// target architecture (i.e. MF_WRITE -> MF_READ | MF_WRITE on i386).
    104     ///
    105     /// \r error_success if the function was successful, or an error_code
    106     /// describing the failure if an error occurred.
    107     ///
    108     /// @brief Set memory protection state.
    109     static std::error_code protectMappedMemory(const MemoryBlock &Block,
    110                                                unsigned Flags);
    111 
    112     /// This method allocates a block of Read/Write/Execute memory that is
    113     /// suitable for executing dynamically generated code (e.g. JIT). An
    114     /// attempt to allocate \p NumBytes bytes of virtual memory is made.
    115     /// \p NearBlock may point to an existing allocation in which case
    116     /// an attempt is made to allocate more memory near the existing block.
    117     ///
    118     /// On success, this returns a non-null memory block, otherwise it returns
    119     /// a null memory block and fills in *ErrMsg.
    120     ///
    121     /// @brief Allocate Read/Write/Execute memory.
    122     static MemoryBlock AllocateRWX(size_t NumBytes,
    123                                    const MemoryBlock *NearBlock,
    124                                    std::string *ErrMsg = nullptr);
    125 
    126     /// This method releases a block of Read/Write/Execute memory that was
    127     /// allocated with the AllocateRWX method. It should not be used to
    128     /// release any memory block allocated any other way.
    129     ///
    130     /// On success, this returns false, otherwise it returns true and fills
    131     /// in *ErrMsg.
    132     /// @brief Release Read/Write/Execute memory.
    133     static bool ReleaseRWX(MemoryBlock &block, std::string *ErrMsg = nullptr);
    134 
    135     /// InvalidateInstructionCache - Before the JIT can run a block of code
    136     /// that has been emitted it must invalidate the instruction cache on some
    137     /// platforms.
    138     static void InvalidateInstructionCache(const void *Addr, size_t Len);
    139 
    140     /// setExecutable - Before the JIT can run a block of code, it has to be
    141     /// given read and executable privilege. Return true if it is already r-x
    142     /// or the system is able to change its previlege.
    143     static bool setExecutable(MemoryBlock &M, std::string *ErrMsg = nullptr);
    144 
    145     /// setWritable - When adding to a block of code, the JIT may need
    146     /// to mark a block of code as RW since the protections are on page
    147     /// boundaries, and the JIT internal allocations are not page aligned.
    148     static bool setWritable(MemoryBlock &M, std::string *ErrMsg = nullptr);
    149 
    150     /// setRangeExecutable - Mark the page containing a range of addresses
    151     /// as executable.
    152     static bool setRangeExecutable(const void *Addr, size_t Size);
    153 
    154     /// setRangeWritable - Mark the page containing a range of addresses
    155     /// as writable.
    156     static bool setRangeWritable(const void *Addr, size_t Size);
    157   };
    158 
    159   /// Owning version of MemoryBlock.
    160   class OwningMemoryBlock {
    161   public:
    162     OwningMemoryBlock() = default;
    163     explicit OwningMemoryBlock(MemoryBlock M) : M(M) {}
    164     OwningMemoryBlock(OwningMemoryBlock &&Other) {
    165       M = Other.M;
    166       Other.M = MemoryBlock();
    167     }
    168     OwningMemoryBlock& operator=(OwningMemoryBlock &&Other) {
    169       M = Other.M;
    170       Other.M = MemoryBlock();
    171       return *this;
    172     }
    173     ~OwningMemoryBlock() {
    174       Memory::releaseMappedMemory(M);
    175     }
    176     void *base() const { return M.base(); }
    177     size_t size() const { return M.size(); }
    178     MemoryBlock getMemoryBlock() const { return M; }
    179   private:
    180     MemoryBlock M;
    181   };
    182 
    183 }
    184 }
    185 
    186 #endif
    187