1 /* 2 * Stack-less Just-In-Time compiler 3 * 4 * Copyright 2009-2012 Zoltan Herczeg (hzmester (at) 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 37 static SLJIT_INLINE void allocator_grab_lock(void) 38 { 39 /* Always successful. */ 40 } 41 42 static 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 51 SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_grab_lock(void) 52 { 53 /* Always successful. */ 54 } 55 56 SLJIT_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 69 static HANDLE allocator_mutex = 0; 70 71 static 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 80 static 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 89 static HANDLE global_mutex = 0; 90 91 SLJIT_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 100 SLJIT_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 #if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) 110 111 #include <pthread.h> 112 113 static pthread_mutex_t allocator_mutex = PTHREAD_MUTEX_INITIALIZER; 114 115 static SLJIT_INLINE void allocator_grab_lock(void) 116 { 117 pthread_mutex_lock(&allocator_mutex); 118 } 119 120 static 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 129 #include <pthread.h> 130 131 static pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER; 132 133 SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_grab_lock(void) 134 { 135 pthread_mutex_lock(&global_mutex); 136 } 137 138 SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_release_lock(void) 139 { 140 pthread_mutex_unlock(&global_mutex); 141 } 142 143 #endif /* SLJIT_UTIL_GLOBAL_LOCK */ 144 145 #endif /* _WIN32 */ 146 147 /* ------------------------------------------------------------------------ */ 148 /* Stack */ 149 /* ------------------------------------------------------------------------ */ 150 151 #if (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK) || (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) 152 153 #ifdef _WIN32 154 #include "windows.h" 155 #else 156 /* Provides mmap function. */ 157 #include <sys/mman.h> 158 /* For detecting the page size. */ 159 #include <unistd.h> 160 161 #ifndef MAP_ANON 162 163 #include <fcntl.h> 164 165 /* Some old systems does not have MAP_ANON. */ 166 static sljit_si dev_zero = -1; 167 168 #if (defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED) 169 170 static SLJIT_INLINE sljit_si open_dev_zero(void) 171 { 172 dev_zero = open("/dev/zero", O_RDWR); 173 return dev_zero < 0; 174 } 175 176 #else /* SLJIT_SINGLE_THREADED */ 177 178 #include <pthread.h> 179 180 static pthread_mutex_t dev_zero_mutex = PTHREAD_MUTEX_INITIALIZER; 181 182 static SLJIT_INLINE sljit_si open_dev_zero(void) 183 { 184 pthread_mutex_lock(&dev_zero_mutex); 185 dev_zero = open("/dev/zero", O_RDWR); 186 pthread_mutex_unlock(&dev_zero_mutex); 187 return dev_zero < 0; 188 } 189 190 #endif /* SLJIT_SINGLE_THREADED */ 191 192 #endif 193 194 #endif 195 196 #endif /* SLJIT_UTIL_STACK || SLJIT_EXECUTABLE_ALLOCATOR */ 197 198 #if (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK) 199 200 /* Planning to make it even more clever in the future. */ 201 static sljit_sw sljit_page_align = 0; 202 203 SLJIT_API_FUNC_ATTRIBUTE struct sljit_stack* SLJIT_CALL sljit_allocate_stack(sljit_uw limit, sljit_uw max_limit, void *allocator_data) 204 { 205 struct sljit_stack *stack; 206 union { 207 void *ptr; 208 sljit_uw uw; 209 } base; 210 #ifdef _WIN32 211 SYSTEM_INFO si; 212 #endif 213 214 SLJIT_UNUSED_ARG(allocator_data); 215 if (limit > max_limit || limit < 1) 216 return NULL; 217 218 #ifdef _WIN32 219 if (!sljit_page_align) { 220 GetSystemInfo(&si); 221 sljit_page_align = si.dwPageSize - 1; 222 } 223 #else 224 if (!sljit_page_align) { 225 sljit_page_align = sysconf(_SC_PAGESIZE); 226 /* Should never happen. */ 227 if (sljit_page_align < 0) 228 sljit_page_align = 4096; 229 sljit_page_align--; 230 } 231 #endif 232 233 /* Align limit and max_limit. */ 234 max_limit = (max_limit + sljit_page_align) & ~sljit_page_align; 235 236 stack = (struct sljit_stack*)SLJIT_MALLOC(sizeof(struct sljit_stack), allocator_data); 237 if (!stack) 238 return NULL; 239 240 #ifdef _WIN32 241 base.ptr = VirtualAlloc(NULL, max_limit, MEM_RESERVE, PAGE_READWRITE); 242 if (!base.ptr) { 243 SLJIT_FREE(stack, allocator_data); 244 return NULL; 245 } 246 stack->base = base.uw; 247 stack->limit = stack->base; 248 stack->max_limit = stack->base + max_limit; 249 if (sljit_stack_resize(stack, stack->base + limit)) { 250 sljit_free_stack(stack, allocator_data); 251 return NULL; 252 } 253 #else 254 #ifdef MAP_ANON 255 base.ptr = mmap(NULL, max_limit, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 256 #else 257 if (dev_zero < 0) { 258 if (open_dev_zero()) { 259 SLJIT_FREE(stack, allocator_data); 260 return NULL; 261 } 262 } 263 base.ptr = mmap(NULL, max_limit, PROT_READ | PROT_WRITE, MAP_PRIVATE, dev_zero, 0); 264 #endif 265 if (base.ptr == MAP_FAILED) { 266 SLJIT_FREE(stack, allocator_data); 267 return NULL; 268 } 269 stack->base = base.uw; 270 stack->limit = stack->base + limit; 271 stack->max_limit = stack->base + max_limit; 272 #endif 273 stack->top = stack->base; 274 return stack; 275 } 276 277 #undef PAGE_ALIGN 278 279 SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_free_stack(struct sljit_stack* stack, void *allocator_data) 280 { 281 SLJIT_UNUSED_ARG(allocator_data); 282 #ifdef _WIN32 283 VirtualFree((void*)stack->base, 0, MEM_RELEASE); 284 #else 285 munmap((void*)stack->base, stack->max_limit - stack->base); 286 #endif 287 SLJIT_FREE(stack, allocator_data); 288 } 289 290 SLJIT_API_FUNC_ATTRIBUTE sljit_sw SLJIT_CALL sljit_stack_resize(struct sljit_stack* stack, sljit_uw new_limit) 291 { 292 sljit_uw aligned_old_limit; 293 sljit_uw aligned_new_limit; 294 295 if ((new_limit > stack->max_limit) || (new_limit < stack->base)) 296 return -1; 297 #ifdef _WIN32 298 aligned_new_limit = (new_limit + sljit_page_align) & ~sljit_page_align; 299 aligned_old_limit = (stack->limit + sljit_page_align) & ~sljit_page_align; 300 if (aligned_new_limit != aligned_old_limit) { 301 if (aligned_new_limit > aligned_old_limit) { 302 if (!VirtualAlloc((void*)aligned_old_limit, aligned_new_limit - aligned_old_limit, MEM_COMMIT, PAGE_READWRITE)) 303 return -1; 304 } 305 else { 306 if (!VirtualFree((void*)aligned_new_limit, aligned_old_limit - aligned_new_limit, MEM_DECOMMIT)) 307 return -1; 308 } 309 } 310 stack->limit = new_limit; 311 return 0; 312 #else 313 if (new_limit >= stack->limit) { 314 stack->limit = new_limit; 315 return 0; 316 } 317 aligned_new_limit = (new_limit + sljit_page_align) & ~sljit_page_align; 318 aligned_old_limit = (stack->limit + sljit_page_align) & ~sljit_page_align; 319 /* If madvise is available, we release the unnecessary space. */ 320 #if defined(MADV_DONTNEED) 321 if (aligned_new_limit < aligned_old_limit) 322 madvise((void*)aligned_new_limit, aligned_old_limit - aligned_new_limit, MADV_DONTNEED); 323 #elif defined(POSIX_MADV_DONTNEED) 324 if (aligned_new_limit < aligned_old_limit) 325 posix_madvise((void*)aligned_new_limit, aligned_old_limit - aligned_new_limit, POSIX_MADV_DONTNEED); 326 #endif 327 stack->limit = new_limit; 328 return 0; 329 #endif 330 } 331 332 #endif /* SLJIT_UTIL_STACK */ 333 334 #endif 335