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

     1  /*
     2   * jit-alloc.c - Memory allocation routines.
     3   *
     4   * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
     5   *
     6   * This file is part of the libjit library.
     7   *
     8   * The libjit library is free software: you can redistribute it and/or
     9   * modify it under the terms of the GNU Lesser General Public License
    10   * as published by the Free Software Foundation, either version 2.1 of
    11   * the License, or (at your option) any later version.
    12   *
    13   * The libjit library is distributed in the hope that it will be useful,
    14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    16   * Lesser General Public License for more details.
    17   *
    18   * You should have received a copy of the GNU Lesser General Public
    19   * License along with the libjit library.  If not, see
    20   * <http://www.gnu.org/licenses/>.
    21   */
    22  
    23  #include "jit-config.h"
    24  
    25  #ifdef HAVE_STDLIB_H
    26  	#include <stdlib.h>
    27  #endif
    28  #ifndef JIT_WIN32_PLATFORM
    29  #ifdef HAVE_SYS_TYPES_H
    30  	#include <sys/types.h>
    31  #endif
    32  #ifdef HAVE_UNISTD_H
    33  	#include <unistd.h>
    34  #endif
    35  #ifdef HAVE_SYS_MMAN_H
    36  	#include <sys/mman.h>
    37  #endif
    38  #ifdef HAVE_FCNTL_H
    39  	#include <fcntl.h>
    40  #endif
    41  #else /* JIT_WIN32_PLATFORM */
    42  	#include <windows.h>
    43  	#include <io.h>
    44  #endif
    45  #if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MMAP) && defined(HAVE_MUNMAP)
    46  /*
    47   * Make sure that "MAP_ANONYMOUS" is correctly defined, because it
    48   * may not exist on some variants of Unix.
    49   */
    50  #ifndef MAP_ANONYMOUS
    51      #ifdef MAP_ANON
    52          #define MAP_ANONYMOUS        MAP_ANON
    53      #endif
    54  #endif
    55  #ifdef MAP_ANONYMOUS
    56  #define JIT_USE_MMAP
    57  #endif
    58  #endif
    59  
    60  /*@
    61   * @deftypefun {void *} _jit_malloc_exec (unsigned int @var{size})
    62   * Allocate a block of memory that is read/write/executable.  Such blocks
    63   * are used to store JIT'ed code, function closures, and other trampolines.
    64   * The size should be a multiple of @code{jit_vmem_page_size()}.
    65   *
    66   * This will usually be identical to @code{jit_malloc}.  However,
    67   * some systems may need special handling to create executable code
    68   * segments, so this function must be used instead.
    69   *
    70   * You must never mix regular and executable segment allocation.  That is,
    71   * do not use @code{jit_free} to free the result of @code{_jit_malloc_exec}.
    72   * @end deftypefun
    73  @*/
    74  void *
    75  _jit_malloc_exec(unsigned int size)
    76  {
    77  #if defined(JIT_WIN32_PLATFORM)
    78  	return VirtualAlloc(NULL, size,
    79  			    MEM_COMMIT | MEM_RESERVE,
    80  			    PAGE_EXECUTE_READWRITE);
    81  #elif defined(JIT_USE_MMAP)
    82  	void *ptr = mmap(0, size,
    83  			 PROT_READ | PROT_WRITE | PROT_EXEC,
    84  			 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    85  	if(ptr == (void *)-1)
    86  	{
    87  		return (void *)0;
    88  	}
    89  	return ptr;
    90  #else
    91  	return malloc(size);
    92  #endif
    93  }
    94  
    95  /*@
    96   * @deftypefun void _jit_free_exec (void *@var{ptr}, unsigned int @var{size})
    97   * Free a block of memory that was previously allocated by
    98   * @code{_jit_malloc_exec}.  The @var{size} must be identical to the
    99   * original allocated size, as some systems need to know this information
   100   * to be able to free the block.
   101   * @end deftypefun
   102  @*/
   103  void
   104  _jit_free_exec(void *ptr, unsigned int size)
   105  {
   106  	if(ptr)
   107  	{
   108  #if defined(JIT_WIN32_PLATFORM)
   109  		VirtualFree(ptr, 0, MEM_RELEASE);
   110  #elif defined(JIT_USE_MMAP)
   111  		munmap(ptr, size);
   112  #else
   113  		free(ptr);
   114  #endif
   115  	}
   116  }
   117  
   118  /*@
   119   * @deftypefun void _jit_flush_exec (void *@var{ptr}, unsigned int @var{size})
   120   * Flush the contents of the block at @var{ptr} from the CPU's
   121   * data and instruction caches.  This must be used after the code is
   122   * written to an executable code segment, but before the code is
   123   * executed, to prepare it for execution.
   124   * @end deftypefun
   125  @*/
   126  void
   127  _jit_flush_exec(void *ptr, unsigned int size)
   128  {
   129  
   130  #define ROUND_BEG_PTR(p) \
   131  	((void *)((((jit_nuint)(p)) / CLSIZE) * CLSIZE))
   132  #define ROUND_END_PTR(p,s) \
   133  	((void *)(((((jit_nuint)(p)) + (s) + CLSIZE - 1)/CLSIZE)*CLSIZE))
   134  
   135  #if defined(__GNUC__)
   136  #if defined(PPC)
   137  
   138  #define CLSIZE 4
   139  	/* Flush the CPU cache on PPC platforms */
   140  	register unsigned char *p;
   141  	register unsigned char *end;
   142  
   143  	/* Flush the data out of the data cache */
   144  	p   = ROUND_BEG_PTR (ptr);
   145  	end = ROUND_END_PTR (p, size);
   146  	while (p < end)
   147  	{
   148  		__asm__ __volatile__ ("dcbst 0,%0" :: "r"(p));
   149  		p += CLSIZE;
   150  	}
   151  	__asm__ __volatile__ ("sync");
   152  
   153  	/* Invalidate the cache lines in the instruction cache */
   154  	p = ROUND_BEG_PTR (ptr);
   155  	while (p < end)
   156  	{
   157  		__asm__ __volatile__ ("icbi 0,%0; isync" :: "r"(p));
   158  		p += CLSIZE;
   159  	}
   160  	__asm__ __volatile__ ("isync");
   161  
   162  #elif defined(__sparc)
   163  
   164  #define CLSIZE 4
   165  
   166  	/* Flush the CPU cache on sparc platforms */
   167  	register unsigned char *p   = ROUND_BEG_PTR (ptr);
   168  	register unsigned char *end = ROUND_END_PTR (p, size);
   169  	__asm__ __volatile__ ("stbar");
   170  	while (p < end)
   171  	{
   172  		__asm__ __volatile__ ("flush %0" :: "r"(p));
   173  		p += CLSIZE;
   174  	}
   175  	__asm__ __volatile__ ("nop; nop; nop; nop; nop");
   176  
   177  #elif (defined(__arm__) || defined(__arm)) && defined(linux)
   178  
   179  	/* ARM Linux has a "cacheflush" system call */
   180  	/* R0 = start of range, R1 = end of range, R3 = flags */
   181  	/* flags = 0 indicates data cache, flags = 1 indicates both caches */
   182  	__asm __volatile ("mov r0, %0\n"
   183  	                  "mov r1, %1\n"
   184  					  "mov r2, %2\n"
   185  					  "swi 0x9f0002       @ sys_cacheflush"
   186  					  : /* no outputs */
   187  					  : "r" (ptr),
   188  					    "r" (((int)ptr) + (int)size),
   189  						"r" (0)
   190  					  : "r0", "r1", "r3" );
   191  
   192  #elif (defined(__ia64) || defined(__ia64__)) && defined(linux)
   193  #define CLSIZE 32
   194  	register unsigned char *p   = ROUND_BEG_PTR (ptr);
   195  	register unsigned char *end = ROUND_END_PTR (p, size);
   196  	while(p < end)
   197  	{
   198  		asm volatile("fc %0" :: "r"(p));
   199  		p += CLSIZE;
   200  	}
   201  	asm volatile(";;sync.i;;srlz.i;;");
   202  #endif
   203  #endif	/* __GNUC__ */
   204  }