sljitUtils.c revision 1.7
1/* $NetBSD: sljitUtils.c,v 1.7 2014/06/17 19:33:20 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_si dev_zero = -1; 210 211#if (defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED) 212 213static SLJIT_INLINE sljit_si 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_si open_dev_zero(void) 226{ 227 pthread_mutex_lock(&dev_zero_mutex); 228 dev_zero = open("/dev/zero", O_RDWR); 229 pthread_mutex_unlock(&dev_zero_mutex); 230 return dev_zero < 0; 231} 232 233#endif /* SLJIT_SINGLE_THREADED */ 234 235#endif 236 237#endif 238 239#endif /* SLJIT_UTIL_STACK || SLJIT_EXECUTABLE_ALLOCATOR */ 240 241#if (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK) 242 243/* Planning to make it even more clever in the future. */ 244static sljit_sw sljit_page_align = 0; 245 246SLJIT_API_FUNC_ATTRIBUTE struct sljit_stack* SLJIT_CALL sljit_allocate_stack(sljit_uw limit, sljit_uw max_limit) 247{ 248 struct sljit_stack *stack; 249 union { 250 void *ptr; 251 sljit_uw uw; 252 } base; 253#ifdef _WIN32 254 SYSTEM_INFO si; 255#endif 256#ifdef _KERNEL 257 vaddr_t v; 258#endif 259 260 if (limit > max_limit || limit < 1) 261 return NULL; 262 263#ifdef _WIN32 264 if (!sljit_page_align) { 265 GetSystemInfo(&si); 266 sljit_page_align = si.dwPageSize - 1; 267 } 268#else 269 if (!sljit_page_align) { 270#ifdef _KERNEL 271 sljit_page_align = PAGE_SIZE; 272#else 273 sljit_page_align = sysconf(_SC_PAGESIZE); 274#endif 275 /* Should never happen. */ 276 if (sljit_page_align < 0) 277 sljit_page_align = 4096; 278 sljit_page_align--; 279 } 280#endif 281 282 /* Align limit and max_limit. */ 283 max_limit = (max_limit + sljit_page_align) & ~sljit_page_align; 284 285 stack = (struct sljit_stack*)SLJIT_MALLOC(sizeof(struct sljit_stack)); 286 if (!stack) 287 return NULL; 288 289#ifdef _KERNEL 290 v = uvm_km_alloc(kernel_map, max_limit, PAGE_SIZE, UVM_KMF_WIRED|UVM_KMF_ZERO); 291 base.ptr = (void *)v; 292 if (base.ptr == NULL) { 293 SLJIT_FREE(stack); 294 return NULL; 295 } 296 stack->base = base.uw; 297 stack->limit = stack->base + limit; 298 stack->max_limit = stack->base + max_limit; 299#elif defined(_WIN32) 300 base.ptr = VirtualAlloc(NULL, max_limit, MEM_RESERVE, PAGE_READWRITE); 301 if (!base.ptr) { 302 SLJIT_FREE(stack); 303 return NULL; 304 } 305 stack->base = base.uw; 306 stack->limit = stack->base; 307 stack->max_limit = stack->base + max_limit; 308 if (sljit_stack_resize(stack, stack->base + limit)) { 309 sljit_free_stack(stack); 310 return NULL; 311 } 312#else 313#ifdef MAP_ANON 314 base.ptr = mmap(NULL, max_limit, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 315#else 316 if (dev_zero < 0) { 317 if (open_dev_zero()) { 318 SLJIT_FREE(stack); 319 return NULL; 320 } 321 } 322 base.ptr = mmap(NULL, max_limit, PROT_READ | PROT_WRITE, MAP_PRIVATE, dev_zero, 0); 323#endif 324 if (base.ptr == MAP_FAILED) { 325 SLJIT_FREE(stack); 326 return NULL; 327 } 328 stack->base = base.uw; 329 stack->limit = stack->base + limit; 330 stack->max_limit = stack->base + max_limit; 331#endif 332 stack->top = stack->base; 333 return stack; 334} 335 336#undef PAGE_ALIGN 337 338SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_free_stack(struct sljit_stack* stack) 339{ 340#ifdef _KERNEL 341 uvm_km_free(kernel_map, (vaddr_t)stack->base, 342 stack->max_limit - stack->base, UVM_KMF_WIRED); 343#elif defined(_WIN32) 344 VirtualFree((void*)stack->base, 0, MEM_RELEASE); 345#else 346 munmap((void*)stack->base, stack->max_limit - stack->base); 347#endif 348 SLJIT_FREE(stack); 349} 350 351SLJIT_API_FUNC_ATTRIBUTE sljit_sw SLJIT_CALL sljit_stack_resize(struct sljit_stack* stack, sljit_uw new_limit) 352{ 353 if ((new_limit > stack->max_limit) || (new_limit < stack->base)) 354 return -1; 355#ifdef _WIN32 356 sljit_uw aligned_new_limit = 357 (new_limit + sljit_page_align) & ~sljit_page_align; 358 sljit_uw aligned_old_limit = 359 (stack->limit + sljit_page_align) & ~sljit_page_align; 360 if (aligned_new_limit != aligned_old_limit) { 361 if (aligned_new_limit > aligned_old_limit) { 362 if (!VirtualAlloc((void*)aligned_old_limit, aligned_new_limit - aligned_old_limit, MEM_COMMIT, PAGE_READWRITE)) 363 return -1; 364 } 365 else { 366 if (!VirtualFree((void*)aligned_new_limit, aligned_old_limit - aligned_new_limit, MEM_DECOMMIT)) 367 return -1; 368 } 369 } 370 stack->limit = new_limit; 371 return 0; 372#else 373 if (new_limit >= stack->limit) { 374 stack->limit = new_limit; 375 return 0; 376 } 377#if defined(POSIX_MADV_DONTNEED) 378# define MADVISE(new, old) posix_madvise((new), (old), POSIX_MADV_DONTNEED) 379#elif defined(MADV_DONTNEED) 380# define MADVISE(new, old) madvise((new), (old), MADV_DONTNEED) 381#endif 382#ifdef MADVISE 383 sljit_uw aligned_new_limit = 384 (new_limit + sljit_page_align) & ~sljit_page_align; 385 sljit_uw aligned_old_limit = 386 (stack->limit + sljit_page_align) & ~sljit_page_align; 387 /* If madvise is available, we release the unnecessary space. */ 388 if (aligned_new_limit < aligned_old_limit) 389 MADVISE((void*)aligned_new_limit, 390 aligned_old_limit - aligned_new_limit); 391#endif 392 stack->limit = new_limit; 393 return 0; 394#endif 395} 396 397#endif /* SLJIT_UTIL_STACK */ 398 399#endif 400