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 }