github.com/goccy/go-jit@v0.0.0-20200514131505-ff78d45cf6af/internal/ccall/jit-vmem.c (about)

     1  /*
     2   * jit-vmem.c - Virtual memory routines.
     3   *
     4   * Copyright (C) 2011  Aleksey Demakov
     5   *
     6   * The libjit library is free software: you can redistribute it and/or
     7   * modify it under the terms of the GNU Lesser General Public License
     8   * as published by the Free Software Foundation, either version 2.1 of
     9   * the License, or (at your option) any later version.
    10   *
    11   * The libjit library is distributed in the hope that it will be useful,
    12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    14   * Lesser General Public License for more details.
    15   *
    16   * You should have received a copy of the GNU Lesser General Public
    17   * License along with the libjit library.  If not, see
    18   * <http://www.gnu.org/licenses/>.
    19   */
    20  
    21  #include <jit/jit-vmem.h>
    22  #include "jit-config.h"
    23  
    24  #if defined(JIT_VMEM_WIN32)
    25  # include <windows.h>
    26  #elif defined(JIT_VMEM_MMAP)
    27  # include <sys/mman.h>
    28  #endif
    29  
    30  #if !defined(JIT_WIN32_PLATFORM) && defined(HAVE_UNISTD_H)
    31  # include <unistd.h>
    32  #endif
    33  
    34  /*
    35   * Define getpagesize() if not provided
    36   */
    37  #if !defined(JIT_WIN32_PLATFORM) && !defined(HAVE_GETPAGESIZE)
    38  # if defined(NBPG)
    39  #  define getpagesize() (NBPG)
    40  # elif defined(PAGE_SIZE)
    41  #  define getpagesize() (PAGE_SIZE)
    42  # else
    43  #  define getpagesize() (4096)
    44  # endif
    45  #endif
    46  
    47  /*
    48   * Make sure that "MAP_ANONYMOUS" is correctly defined, because it
    49   * may not exist on some variants of Unix.
    50   */
    51  #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
    52  # define MAP_ANONYMOUS        MAP_ANON
    53  #endif
    54  
    55  static jit_uint page_size;
    56  
    57  #if defined(JIT_VMEM_WIN32)
    58  static DWORD
    59  convert_prot(jit_prot_t prot)
    60  {
    61  	switch(prot)
    62  	{
    63  	case JIT_PROT_NONE:
    64  		return PAGE_NOACCESS;
    65  	case JIT_PROT_READ:
    66  		return PAGE_READONLY;
    67  	case JIT_PROT_READ_WRITE:
    68  		return PAGE_READWRITE;
    69  	case JIT_PROT_EXEC_READ:
    70  		return PAGE_EXECUTE_READ;
    71  	case JIT_PROT_EXEC_READ_WRITE:
    72  		return PAGE_EXECUTE_READWRITE;
    73  	}
    74  	return PAGE_NOACCESS;
    75  }
    76  #elif defined(JIT_VMEM_MMAP)
    77  static int
    78  convert_prot(jit_prot_t prot)
    79  {
    80  	switch(prot)
    81  	{
    82  	case JIT_PROT_NONE:
    83  		return PROT_NONE;
    84  	case JIT_PROT_READ:
    85  		return PROT_READ;
    86  	case JIT_PROT_READ_WRITE:
    87  		return PROT_READ | PROT_WRITE;
    88  	case JIT_PROT_EXEC_READ:
    89  		return PROT_EXEC | PROT_READ;
    90  	case JIT_PROT_EXEC_READ_WRITE:
    91  		return PROT_EXEC | PROT_READ | PROT_WRITE;
    92  	}
    93  	return PROT_NONE;
    94  }
    95  #endif
    96  
    97  void
    98  jit_vmem_init(void)
    99  {
   100  #if defined(JIT_VMEM_WIN32)
   101  	/* Get the page size from a Windows-specific API */
   102  	SYSTEM_INFO sysInfo;
   103  	GetSystemInfo(&sysInfo);
   104  	page_size = (jit_uint) (sysInfo.dwPageSize);
   105  #else
   106  	/* Get the page size using a Unix-like sequence */
   107  	page_size = (jit_uint) getpagesize();
   108  #endif
   109  }
   110  
   111  /*@
   112   * @deftypefun {unsigned int} jit_vmem_page_size (void)
   113   * Get the page allocation size for the system.  This is the preferred
   114   * unit when making calls to @code{_jit_malloc_exec}.  It is not
   115   * required that you supply a multiple of this size when allocating,
   116   * but it can lead to better performance on some systems.
   117   * @end deftypefun
   118  @*/
   119  jit_uint
   120  jit_vmem_page_size(void)
   121  {
   122  	return page_size;
   123  }
   124  
   125  jit_nuint
   126  jit_vmem_round_up(jit_nuint value)
   127  {
   128  	return (value + page_size - 1) & ~(page_size - 1);
   129  }
   130  
   131  jit_nuint
   132  jit_vmem_round_down(jit_nuint value)
   133  {
   134  	return ((jit_nuint) value) & ~(page_size - 1);
   135  }
   136  
   137  void *
   138  jit_vmem_reserve(jit_uint size)
   139  {
   140  #if defined(JIT_VMEM_WIN32)
   141  
   142  	return VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS);
   143  
   144  #elif defined(JIT_VMEM_MMAP)
   145  
   146  	void *addr;
   147  
   148  	addr = mmap(0, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
   149  	if(addr == MAP_FAILED)
   150  	{
   151  		return (void *) 0;
   152  	}
   153  	return addr;
   154  
   155  #else
   156  	return (void *) 0;
   157  #endif
   158  }
   159  
   160  void *
   161  jit_vmem_reserve_committed(jit_uint size, jit_prot_t prot)
   162  {
   163  #if defined(JIT_VMEM_WIN32)
   164  
   165  	DWORD nprot;
   166  
   167  	nprot = convert_prot(prot);
   168  	return VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, nprot);
   169  
   170  #elif defined(JIT_VMEM_MMAP)
   171  
   172  	void *addr;
   173  	int nprot;
   174  
   175  	nprot = convert_prot(prot);
   176  	addr = mmap(0, size, nprot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
   177  	if(addr == MAP_FAILED)
   178  	{
   179  		return (void *) 0;
   180  	}
   181  	return addr;
   182  
   183  #else
   184  	return (void *) 0;
   185  #endif
   186  }
   187  
   188  int
   189  jit_vmem_release(void *addr, jit_uint size)
   190  {
   191  #if defined(JIT_VMEM_WIN32)
   192  
   193  	return VirtualFree(addr, 0, MEM_RELEASE) != 0;
   194  
   195  #elif defined(JIT_VMEM_MMAP)
   196  
   197  	return munmap(addr, size) == 0;
   198  
   199  #else
   200  	return 0;
   201  #endif
   202  }
   203  
   204  int
   205  jit_vmem_commit(void *addr, jit_uint size, jit_prot_t prot)
   206  {
   207  #if defined(JIT_VMEM_WIN32)
   208  
   209  	DWORD nprot;
   210  
   211  	nprot = convert_prot(prot);
   212  	return VirtualAlloc(addr, size, MEM_COMMIT, nprot) != 0;
   213  
   214  #elif defined(JIT_VMEM_MMAP)
   215  
   216  	int nprot;
   217  	void *raddr;
   218  
   219  	nprot = convert_prot(prot);
   220  	raddr = mmap(addr, size, nprot, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
   221  	if(raddr != addr)
   222  	{
   223  		if(raddr != MAP_FAILED)
   224  		{
   225  			munmap(raddr, size);
   226  		}
   227  		return 0;
   228  	}
   229  	return 1;
   230  
   231  #else
   232  	return 0;
   233  #endif
   234  }
   235  
   236  int
   237  jit_vmem_decommit(void *addr, jit_uint size)
   238  {
   239  #if defined(JIT_VMEM_WIN32)
   240  
   241  	return VirtualFree(addr, size, MEM_DECOMMIT) != 0;
   242  
   243  #elif defined(JIT_VMEM_MMAP)
   244  # if defined(MADV_FREE)
   245  
   246  	int result = madvise(addr, size, MADV_FREE);
   247  	if(result < 0)
   248  	{
   249  		return 0;
   250  	}
   251  
   252  # elif defined(MADV_DONTNEED) && defined(JIT_LINUX_PLATFORM)
   253  
   254  	int result = madvise(addr, size, MADV_DONTNEED);
   255  	if(result < 0)
   256  	{
   257  		return 0;
   258  	}
   259  
   260  # endif
   261  
   262  	addr = mmap(addr, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
   263  	if(addr == MAP_FAILED)
   264  	{
   265  		return 0;
   266  	}
   267  	return 1;
   268  
   269  #else
   270  	return 0;
   271  #endif
   272  }
   273  
   274  int
   275  jit_vmem_protect(void *addr, jit_uint size, jit_prot_t prot)
   276  {
   277  #if defined(JIT_VMEM_WIN32)
   278  
   279  	DWORD nprot, oprot;
   280  
   281  	nprot = convert_prot(prot);
   282  	if(VirtualProtect(addr, size, nprot, &oprot) == 0)
   283  	{
   284  		return 0;
   285  	}
   286  	return 1;
   287  
   288  #elif defined(JIT_VMEM_MMAP)
   289  
   290  	int nprot;
   291  
   292  	nprot = convert_prot(prot);
   293  	if(mprotect(addr, size, nprot) < 0)
   294  	{
   295  		return 0;
   296  	}
   297  	return 1;
   298  
   299  #else
   300  	return 0;
   301  #endif
   302  }