sljitUtils.c revision 1.8
1/* $NetBSD: sljitUtils.c,v 1.8 2016/05/29 17:09:33 alnsn Exp $ */ 2 3/* 4 * Stack-less Just-In-Time compiler 5 * 6 * Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without modification, are 9 * permitted provided that the following conditions are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright notice, this list of 12 * conditions and the following disclaimer. 13 * 14 * 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 * of conditions and the following disclaimer in the documentation and/or other materials 16 * provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 21 * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 23 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 26 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29/* ------------------------------------------------------------------------ */ 30/* Locks */ 31/* ------------------------------------------------------------------------ */ 32 33#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) || (defined SLJIT_UTIL_GLOBAL_LOCK && SLJIT_UTIL_GLOBAL_LOCK) 34 35#if (defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED) 36 37#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) 38 39static SLJIT_INLINE void allocator_grab_lock(void) 40{ 41 /* Always successful. */ 42} 43 44static SLJIT_INLINE void allocator_release_lock(void) 45{ 46 /* Always successful. */ 47} 48 49#endif /* SLJIT_EXECUTABLE_ALLOCATOR */ 50 51#if (defined SLJIT_UTIL_GLOBAL_LOCK && SLJIT_UTIL_GLOBAL_LOCK) 52 53SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_grab_lock(void) 54{ 55 /* Always successful. */ 56} 57 58SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_release_lock(void) 59{ 60 /* Always successful. */ 61} 62 63#endif /* SLJIT_UTIL_GLOBAL_LOCK */ 64 65#elif defined(_WIN32) /* SLJIT_SINGLE_THREADED */ 66 67#include "windows.h" 68 69#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) 70 71static HANDLE allocator_mutex = 0; 72 73static SLJIT_INLINE void allocator_grab_lock(void) 74{ 75 /* No idea what to do if an error occures. Static mutexes should never fail... */ 76 if (!allocator_mutex) 77 allocator_mutex = CreateMutex(NULL, TRUE, NULL); 78 else 79 WaitForSingleObject(allocator_mutex, INFINITE); 80} 81 82static SLJIT_INLINE void allocator_release_lock(void) 83{ 84 ReleaseMutex(allocator_mutex); 85} 86 87#endif /* SLJIT_EXECUTABLE_ALLOCATOR */ 88 89#if (defined SLJIT_UTIL_GLOBAL_LOCK && SLJIT_UTIL_GLOBAL_LOCK) 90 91static HANDLE global_mutex = 0; 92 93SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_grab_lock(void) 94{ 95 /* No idea what to do if an error occures. Static mutexes should never fail... */ 96 if (!global_mutex) 97 global_mutex = CreateMutex(NULL, TRUE, NULL); 98 else 99 WaitForSingleObject(global_mutex, INFINITE); 100} 101 102SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_release_lock(void) 103{ 104 ReleaseMutex(global_mutex); 105} 106 107#endif /* SLJIT_UTIL_GLOBAL_LOCK */ 108 109#else /* _WIN32 */ 110 111#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) 112 113#ifdef _KERNEL 114 115#include <sys/mutex.h> 116 117/* Defined in sljit_mod.c */ 118extern kmutex_t sljit_allocator_mutex; 119 120static SLJIT_INLINE void allocator_grab_lock(void) 121{ 122 mutex_enter(&sljit_allocator_mutex); 123} 124 125static SLJIT_INLINE void allocator_release_lock(void) 126{ 127 mutex_exit(&sljit_allocator_mutex); 128} 129#else 130 131#include <pthread.h> 132 133static pthread_mutex_t allocator_mutex = PTHREAD_MUTEX_INITIALIZER; 134 135static SLJIT_INLINE void allocator_grab_lock(void) 136{ 137 pthread_mutex_lock(&allocator_mutex); 138} 139 140static SLJIT_INLINE void allocator_release_lock(void) 141{ 142 pthread_mutex_unlock(&allocator_mutex); 143} 144#endif 145 146#endif /* SLJIT_EXECUTABLE_ALLOCATOR */ 147 148#if (defined SLJIT_UTIL_GLOBAL_LOCK && SLJIT_UTIL_GLOBAL_LOCK) 149 150#ifdef _KERNEL 151 152#include <sys/mutex.h> 153 154/* Defined in sljit_mod.c */ 155extern kmutex_t sljit_global_mutex; 156 157SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_grab_lock(void) 158{ 159 mutex_enter(&sljit_global_mutex); 160} 161 162SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_release_lock(void) 163{ 164 mutex_exit(&sljit_global_mutex); 165} 166#else 167 168#include <pthread.h> 169 170static pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER; 171 172SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_grab_lock(void) 173{ 174 pthread_mutex_lock(&global_mutex); 175} 176 177SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_release_lock(void) 178{ 179 pthread_mutex_unlock(&global_mutex); 180} 181#endif 182 183#endif /* SLJIT_UTIL_GLOBAL_LOCK */ 184 185#endif /* _WIN32 */ 186 187/* ------------------------------------------------------------------------ */ 188/* Stack */ 189/* ------------------------------------------------------------------------ */ 190 191#if (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK) || (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) 192 193#ifdef _KERNEL 194#include <sys/param.h> 195#include <uvm/uvm.h> 196#elif defined(_WIN32) 197#include "windows.h" 198#else 199/* Provides mmap function. */ 200#include <sys/mman.h> 201/* For detecting the page size. */ 202#include <unistd.h> 203 204#ifndef MAP_ANON 205 206#include <fcntl.h> 207 208/* Some old systems does not have MAP_ANON. */ 209static sljit_s32 dev_zero = -1; 210 211#if (defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED) 212 213static SLJIT_INLINE sljit_s32 open_dev_zero(void) 214{ 215 dev_zero = open("/dev/zero", O_RDWR); 216 return dev_zero < 0; 217} 218 219#else /* SLJIT_SINGLE_THREADED */ 220 221#include <pthread.h> 222 223static pthread_mutex_t dev_zero_mutex = PTHREAD_MUTEX_INITIALIZER; 224 225static SLJIT_INLINE sljit_s32 open_dev_zero(void) 226{ 227 pthread_mutex_lock(&dev_zero_mutex); 228 /* The dev_zero might be initialized by another thread during the waiting. */ 229 if (dev_zero < 0) { 230 dev_zero = open("/dev/zero", O_RDWR); 231 } 232 pthread_mutex_unlock(&dev_zero_mutex); 233 return dev_zero < 0; 234} 235 236#endif /* SLJIT_SINGLE_THREADED */ 237 238#endif 239 240#endif 241 242#endif /* SLJIT_UTIL_STACK || SLJIT_EXECUTABLE_ALLOCATOR */ 243 244#if (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK) 245 246/* Planning to make it even more clever in the future. */ 247static sljit_sw sljit_page_align = 0; 248 249SLJIT_API_FUNC_ATTRIBUTE struct sljit_stack* SLJIT_CALL sljit_allocate_stack(sljit_uw limit, sljit_uw max_limit, void *allocator_data) 250{ 251 struct sljit_stack *stack; 252 union { 253 void *ptr; 254 sljit_uw uw; 255 } base; 256#ifdef _WIN32 257 SYSTEM_INFO si; 258#endif 259#ifdef _KERNEL 260 vaddr_t v; 261#endif 262 263 SLJIT_UNUSED_ARG(allocator_data); 264 if (limit > max_limit || limit < 1) 265 return NULL; 266 267#ifdef _WIN32 268 if (!sljit_page_align) { 269 GetSystemInfo(&si); 270 sljit_page_align = si.dwPageSize - 1; 271 } 272#else 273 if (!sljit_page_align) { 274#ifdef _KERNEL 275 sljit_page_align = PAGE_SIZE; 276#else 277 sljit_page_align = sysconf(_SC_PAGESIZE); 278#endif 279 /* Should never happen. */ 280 if (sljit_page_align < 0) 281 sljit_page_align = 4096; 282 sljit_page_align--; 283 } 284#endif 285 286 /* Align limit and max_limit. */ 287 max_limit = (max_limit + sljit_page_align) & ~sljit_page_align; 288 289 stack = (struct sljit_stack*)SLJIT_MALLOC(sizeof(struct sljit_stack), allocator_data); 290 if (!stack) 291 return NULL; 292 293#ifdef _KERNEL 294 v = uvm_km_alloc(kernel_map, max_limit, PAGE_SIZE, UVM_KMF_WIRED|UVM_KMF_ZERO); 295 base.ptr = (void *)v; 296 if (base.ptr == NULL) { 297 SLJIT_FREE(stack); 298 return NULL; 299 } 300 stack->base = base.uw; 301 stack->limit = stack->base + limit; 302 stack->max_limit = stack->base + max_limit; 303#elif defined(_WIN32) 304 base.ptr = VirtualAlloc(NULL, max_limit, MEM_RESERVE, PAGE_READWRITE); 305 if (!base.ptr) { 306 SLJIT_FREE(stack, allocator_data); 307 return NULL; 308 } 309 stack->base = base.uw; 310 stack->limit = stack->base; 311 stack->max_limit = stack->base + max_limit; 312 if (sljit_stack_resize(stack, stack->base + limit)) { 313 sljit_free_stack(stack, allocator_data); 314 return NULL; 315 } 316#else 317#ifdef MAP_ANON 318 base.ptr = mmap(NULL, max_limit, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 319#else 320 if (dev_zero < 0) { 321 if (open_dev_zero()) { 322 SLJIT_FREE(stack, allocator_data); 323 return NULL; 324 } 325 } 326 base.ptr = mmap(NULL, max_limit, PROT_READ | PROT_WRITE, MAP_PRIVATE, dev_zero, 0); 327#endif 328 if (base.ptr == MAP_FAILED) { 329 SLJIT_FREE(stack, allocator_data); 330 return NULL; 331 } 332 stack->base = base.uw; 333 stack->limit = stack->base + limit; 334 stack->max_limit = stack->base + max_limit; 335#endif 336 stack->top = stack->base; 337 return stack; 338} 339 340#undef PAGE_ALIGN 341 342SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_free_stack(struct sljit_stack* stack, void *allocator_data) 343{ 344 SLJIT_UNUSED_ARG(allocator_data); 345#ifdef _KERNEL 346 uvm_km_free(kernel_map, (vaddr_t)stack->base, 347 stack->max_limit - stack->base, UVM_KMF_WIRED); 348#elif defined(_WIN32) 349 VirtualFree((void*)stack->base, 0, MEM_RELEASE); 350#else 351 munmap((void*)stack->base, stack->max_limit - stack->base); 352#endif 353 SLJIT_FREE(stack, allocator_data); 354} 355 356SLJIT_API_FUNC_ATTRIBUTE sljit_sw SLJIT_CALL sljit_stack_resize(struct sljit_stack* stack, sljit_uw new_limit) 357{ 358 if ((new_limit > stack->max_limit) || (new_limit < stack->base)) 359 return -1; 360#ifdef _WIN32 361 sljit_uw aligned_new_limit = 362 (new_limit + sljit_page_align) & ~sljit_page_align; 363 sljit_uw aligned_old_limit = 364 (stack->limit + sljit_page_align) & ~sljit_page_align; 365 if (aligned_new_limit != aligned_old_limit) { 366 if (aligned_new_limit > aligned_old_limit) { 367 if (!VirtualAlloc((void*)aligned_old_limit, aligned_new_limit - aligned_old_limit, MEM_COMMIT, PAGE_READWRITE)) 368 return -1; 369 } 370 else { 371 if (!VirtualFree((void*)aligned_new_limit, aligned_old_limit - aligned_new_limit, MEM_DECOMMIT)) 372 return -1; 373 } 374 } 375 stack->limit = new_limit; 376 return 0; 377#else 378 if (new_limit >= stack->limit) { 379 stack->limit = new_limit; 380 return 0; 381 } 382#if defined(POSIX_MADV_DONTNEED) 383# define MADVISE(new, old) posix_madvise((new), (old), POSIX_MADV_DONTNEED) 384#elif defined(MADV_DONTNEED) 385# define MADVISE(new, old) madvise((new), (old), MADV_DONTNEED) 386#endif 387#ifdef MADVISE 388 sljit_uw aligned_new_limit = 389 (new_limit + sljit_page_align) & ~sljit_page_align; 390 sljit_uw aligned_old_limit = 391 (stack->limit + sljit_page_align) & ~sljit_page_align; 392 /* If madvise is available, we release the unnecessary space. */ 393 if (aligned_new_limit < aligned_old_limit) 394 MADVISE((void*)aligned_new_limit, 395 aligned_old_limit - aligned_new_limit); 396#endif 397 stack->limit = new_limit; 398 return 0; 399#endif 400} 401 402#endif /* SLJIT_UTIL_STACK */ 403 404#endif 405