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 (at) 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
39 static SLJIT_INLINE void allocator_grab_lock(void)
40 {
41 /* Always successful. */
42 }
43
44 static 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
53 SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_grab_lock(void)
54 {
55 /* Always successful. */
56 }
57
58 SLJIT_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
71 static HANDLE allocator_mutex = 0;
72
73 static 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
82 static 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
91 static HANDLE global_mutex = 0;
92
93 SLJIT_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
102 SLJIT_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 */
118 extern kmutex_t sljit_allocator_mutex;
119
120 static SLJIT_INLINE void allocator_grab_lock(void)
121 {
122 mutex_enter(&sljit_allocator_mutex);
123 }
124
125 static SLJIT_INLINE void allocator_release_lock(void)
126 {
127 mutex_exit(&sljit_allocator_mutex);
128 }
129 #else
130
131 #include <pthread.h>
132
133 static pthread_mutex_t allocator_mutex = PTHREAD_MUTEX_INITIALIZER;
134
135 static SLJIT_INLINE void allocator_grab_lock(void)
136 {
137 pthread_mutex_lock(&allocator_mutex);
138 }
139
140 static 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 */
155 extern kmutex_t sljit_global_mutex;
156
157 SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_grab_lock(void)
158 {
159 mutex_enter(&sljit_global_mutex);
160 }
161
162 SLJIT_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
170 static pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER;
171
172 SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_grab_lock(void)
173 {
174 pthread_mutex_lock(&global_mutex);
175 }
176
177 SLJIT_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. */
209 static sljit_s32 dev_zero = -1;
210
211 #if (defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED)
212
213 static 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
223 static pthread_mutex_t dev_zero_mutex = PTHREAD_MUTEX_INITIALIZER;
224
225 static 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. */
247 static sljit_sw sljit_page_align = 0;
248
249 SLJIT_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
342 SLJIT_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
356 SLJIT_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