1/* 2 * Stack-less Just-In-Time compiler 3 * 4 * Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without modification, are 7 * permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright notice, this list of 10 * conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright notice, this list 13 * of conditions and the following disclaimer in the documentation and/or other materials 14 * provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 19 * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 22 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27/* ------------------------------------------------------------------------ */ 28/* Locks */ 29/* ------------------------------------------------------------------------ */ 30 31#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) || (defined SLJIT_UTIL_GLOBAL_LOCK && SLJIT_UTIL_GLOBAL_LOCK) 32 33#if (defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED) 34 35#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) 36 37static SLJIT_INLINE void allocator_grab_lock(void) 38{ 39 /* Always successful. */ 40} 41 42static SLJIT_INLINE void allocator_release_lock(void) 43{ 44 /* Always successful. */ 45} 46 47#endif /* SLJIT_EXECUTABLE_ALLOCATOR */ 48 49#if (defined SLJIT_UTIL_GLOBAL_LOCK && SLJIT_UTIL_GLOBAL_LOCK) 50 51SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_grab_lock(void) 52{ 53 /* Always successful. */ 54} 55 56SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_release_lock(void) 57{ 58 /* Always successful. */ 59} 60 61#endif /* SLJIT_UTIL_GLOBAL_LOCK */ 62 63#elif defined(_WIN32) /* SLJIT_SINGLE_THREADED */ 64 65#include "windows.h" 66 67#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) 68 69static HANDLE allocator_mutex = 0; 70 71static SLJIT_INLINE void allocator_grab_lock(void) 72{ 73 /* No idea what to do if an error occures. Static mutexes should never fail... */ 74 if (!allocator_mutex) 75 allocator_mutex = CreateMutex(NULL, TRUE, NULL); 76 else 77 WaitForSingleObject(allocator_mutex, INFINITE); 78} 79 80static SLJIT_INLINE void allocator_release_lock(void) 81{ 82 ReleaseMutex(allocator_mutex); 83} 84 85#endif /* SLJIT_EXECUTABLE_ALLOCATOR */ 86 87#if (defined SLJIT_UTIL_GLOBAL_LOCK && SLJIT_UTIL_GLOBAL_LOCK) 88 89static HANDLE global_mutex = 0; 90 91SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_grab_lock(void) 92{ 93 /* No idea what to do if an error occures. Static mutexes should never fail... */ 94 if (!global_mutex) 95 global_mutex = CreateMutex(NULL, TRUE, NULL); 96 else 97 WaitForSingleObject(global_mutex, INFINITE); 98} 99 100SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_release_lock(void) 101{ 102 ReleaseMutex(global_mutex); 103} 104 105#endif /* SLJIT_UTIL_GLOBAL_LOCK */ 106 107#else /* _WIN32 */ 108 109#include "pthread.h" 110 111#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) 112 113static pthread_mutex_t allocator_mutex = PTHREAD_MUTEX_INITIALIZER; 114 115static SLJIT_INLINE void allocator_grab_lock(void) 116{ 117 pthread_mutex_lock(&allocator_mutex); 118} 119 120static SLJIT_INLINE void allocator_release_lock(void) 121{ 122 pthread_mutex_unlock(&allocator_mutex); 123} 124 125#endif /* SLJIT_EXECUTABLE_ALLOCATOR */ 126 127#if (defined SLJIT_UTIL_GLOBAL_LOCK && SLJIT_UTIL_GLOBAL_LOCK) 128 129static pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER; 130 131SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_grab_lock(void) 132{ 133 pthread_mutex_lock(&global_mutex); 134} 135 136SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_release_lock(void) 137{ 138 pthread_mutex_unlock(&global_mutex); 139} 140 141#endif /* SLJIT_UTIL_GLOBAL_LOCK */ 142 143#endif /* _WIN32 */ 144 145/* ------------------------------------------------------------------------ */ 146/* Stack */ 147/* ------------------------------------------------------------------------ */ 148 149#if (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK) 150 151#ifdef _WIN32 152#include "windows.h" 153#else 154#include <sys/mman.h> 155#include <unistd.h> 156#endif 157 158/* Planning to make it even more clever in the future. */ 159static sljit_w sljit_page_align = 0; 160 161SLJIT_API_FUNC_ATTRIBUTE struct sljit_stack* SLJIT_CALL sljit_allocate_stack(sljit_uw limit, sljit_uw max_limit) 162{ 163 struct sljit_stack *stack; 164 union { 165 void *ptr; 166 sljit_uw uw; 167 } base; 168#ifdef _WIN32 169 SYSTEM_INFO si; 170#endif 171 172 if (limit > max_limit || limit < 1) 173 return NULL; 174 175#ifdef _WIN32 176 if (!sljit_page_align) { 177 GetSystemInfo(&si); 178 sljit_page_align = si.dwPageSize - 1; 179 } 180#else 181 if (!sljit_page_align) { 182 sljit_page_align = sysconf(_SC_PAGESIZE); 183 /* Should never happen. */ 184 if (sljit_page_align < 0) 185 sljit_page_align = 4096; 186 sljit_page_align--; 187 } 188#endif 189 190 /* Align limit and max_limit. */ 191 max_limit = (max_limit + sljit_page_align) & ~sljit_page_align; 192 193 stack = (struct sljit_stack*)SLJIT_MALLOC(sizeof(struct sljit_stack)); 194 if (!stack) 195 return NULL; 196 197#ifdef _WIN32 198 base.ptr = VirtualAlloc(0, max_limit, MEM_RESERVE, PAGE_READWRITE); 199 if (!base.ptr) { 200 SLJIT_FREE(stack); 201 return NULL; 202 } 203 stack->base = base.uw; 204 stack->limit = stack->base; 205 stack->max_limit = stack->base + max_limit; 206 if (sljit_stack_resize(stack, stack->base + limit)) { 207 sljit_free_stack(stack); 208 return NULL; 209 } 210#else 211 base.ptr = mmap(0, max_limit, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 212 if (base.ptr == MAP_FAILED) { 213 SLJIT_FREE(stack); 214 return NULL; 215 } 216 stack->base = base.uw; 217 stack->limit = stack->base + limit; 218 stack->max_limit = stack->base + max_limit; 219#endif 220 stack->top = stack->base; 221 return stack; 222} 223 224#undef PAGE_ALIGN 225 226SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_free_stack(struct sljit_stack* stack) 227{ 228#ifdef _WIN32 229 VirtualFree((void*)stack->base, 0, MEM_RELEASE); 230#else 231 munmap((void*)stack->base, stack->max_limit - stack->base); 232#endif 233 SLJIT_FREE(stack); 234} 235 236SLJIT_API_FUNC_ATTRIBUTE sljit_w SLJIT_CALL sljit_stack_resize(struct sljit_stack* stack, sljit_uw new_limit) 237{ 238 sljit_uw aligned_old_limit; 239 sljit_uw aligned_new_limit; 240 241 if ((new_limit > stack->max_limit) || (new_limit < stack->base)) 242 return -1; 243#ifdef _WIN32 244 aligned_new_limit = (new_limit + sljit_page_align) & ~sljit_page_align; 245 aligned_old_limit = (stack->limit + sljit_page_align) & ~sljit_page_align; 246 if (aligned_new_limit != aligned_old_limit) { 247 if (aligned_new_limit > aligned_old_limit) { 248 if (!VirtualAlloc((void*)aligned_old_limit, aligned_new_limit - aligned_old_limit, MEM_COMMIT, PAGE_READWRITE)) 249 return -1; 250 } 251 else { 252 if (!VirtualFree((void*)aligned_new_limit, aligned_old_limit - aligned_new_limit, MEM_DECOMMIT)) 253 return -1; 254 } 255 } 256 stack->limit = new_limit; 257 return 0; 258#else 259 if (new_limit >= stack->limit) { 260 stack->limit = new_limit; 261 return 0; 262 } 263 aligned_new_limit = (new_limit + sljit_page_align) & ~sljit_page_align; 264 aligned_old_limit = (stack->limit + sljit_page_align) & ~sljit_page_align; 265 if (aligned_new_limit < aligned_old_limit) 266 posix_madvise((void*)aligned_new_limit, aligned_old_limit - aligned_new_limit, POSIX_MADV_DONTNEED); 267 stack->limit = new_limit; 268 return 0; 269#endif 270} 271 272#endif /* SLJIT_UTIL_STACK */ 273 274#endif 275