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@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_s32 dev_zero = -1;
210
211#if (defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED)
212
213static 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
223static pthread_mutex_t dev_zero_mutex = PTHREAD_MUTEX_INITIALIZER;
224
225static 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. */
247static sljit_sw sljit_page_align = 0;
248
249SLJIT_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
342SLJIT_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
356SLJIT_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