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 }