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