1e18e3516Sopenharmony_ci/*
2e18e3516Sopenharmony_ci *    Stack-less Just-In-Time compiler
3e18e3516Sopenharmony_ci *
4e18e3516Sopenharmony_ci *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
5e18e3516Sopenharmony_ci *
6e18e3516Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification, are
7e18e3516Sopenharmony_ci * permitted provided that the following conditions are met:
8e18e3516Sopenharmony_ci *
9e18e3516Sopenharmony_ci *   1. Redistributions of source code must retain the above copyright notice, this list of
10e18e3516Sopenharmony_ci *      conditions and the following disclaimer.
11e18e3516Sopenharmony_ci *
12e18e3516Sopenharmony_ci *   2. Redistributions in binary form must reproduce the above copyright notice, this list
13e18e3516Sopenharmony_ci *      of conditions and the following disclaimer in the documentation and/or other materials
14e18e3516Sopenharmony_ci *      provided with the distribution.
15e18e3516Sopenharmony_ci *
16e18e3516Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
17e18e3516Sopenharmony_ci * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18e18e3516Sopenharmony_ci * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
19e18e3516Sopenharmony_ci * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20e18e3516Sopenharmony_ci * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21e18e3516Sopenharmony_ci * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
22e18e3516Sopenharmony_ci * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23e18e3516Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24e18e3516Sopenharmony_ci * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25e18e3516Sopenharmony_ci */
26e18e3516Sopenharmony_ci
27e18e3516Sopenharmony_ci/*
28e18e3516Sopenharmony_ci   This file contains a simple executable memory allocator
29e18e3516Sopenharmony_ci
30e18e3516Sopenharmony_ci   It is assumed, that executable code blocks are usually medium (or sometimes
31e18e3516Sopenharmony_ci   large) memory blocks, and the allocator is not too frequently called (less
32e18e3516Sopenharmony_ci   optimized than other allocators). Thus, using it as a generic allocator is
33e18e3516Sopenharmony_ci   not suggested.
34e18e3516Sopenharmony_ci
35e18e3516Sopenharmony_ci   How does it work:
36e18e3516Sopenharmony_ci     Memory is allocated in continuous memory areas called chunks by alloc_chunk()
37e18e3516Sopenharmony_ci     Chunk format:
38e18e3516Sopenharmony_ci     [ block ][ block ] ... [ block ][ block terminator ]
39e18e3516Sopenharmony_ci
40e18e3516Sopenharmony_ci   All blocks and the block terminator is started with block_header. The block
41e18e3516Sopenharmony_ci   header contains the size of the previous and the next block. These sizes
42e18e3516Sopenharmony_ci   can also contain special values.
43e18e3516Sopenharmony_ci     Block size:
44e18e3516Sopenharmony_ci       0 - The block is a free_block, with a different size member.
45e18e3516Sopenharmony_ci       1 - The block is a block terminator.
46e18e3516Sopenharmony_ci       n - The block is used at the moment, and the value contains its size.
47e18e3516Sopenharmony_ci     Previous block size:
48e18e3516Sopenharmony_ci       0 - This is the first block of the memory chunk.
49e18e3516Sopenharmony_ci       n - The size of the previous block.
50e18e3516Sopenharmony_ci
51e18e3516Sopenharmony_ci   Using these size values we can go forward or backward on the block chain.
52e18e3516Sopenharmony_ci   The unused blocks are stored in a chain list pointed by free_blocks. This
53e18e3516Sopenharmony_ci   list is useful if we need to find a suitable memory area when the allocator
54e18e3516Sopenharmony_ci   is called.
55e18e3516Sopenharmony_ci
56e18e3516Sopenharmony_ci   When a block is freed, the new free block is connected to its adjacent free
57e18e3516Sopenharmony_ci   blocks if possible.
58e18e3516Sopenharmony_ci
59e18e3516Sopenharmony_ci     [ free block ][ used block ][ free block ]
60e18e3516Sopenharmony_ci   and "used block" is freed, the three blocks are connected together:
61e18e3516Sopenharmony_ci     [           one big free block           ]
62e18e3516Sopenharmony_ci*/
63e18e3516Sopenharmony_ci
64e18e3516Sopenharmony_ci/* --------------------------------------------------------------------- */
65e18e3516Sopenharmony_ci/*  System (OS) functions                                                */
66e18e3516Sopenharmony_ci/* --------------------------------------------------------------------- */
67e18e3516Sopenharmony_ci
68e18e3516Sopenharmony_ci/* 64 KByte. */
69e18e3516Sopenharmony_ci#define CHUNK_SIZE	(sljit_uw)0x10000u
70e18e3516Sopenharmony_ci
71e18e3516Sopenharmony_ci/*
72e18e3516Sopenharmony_ci   alloc_chunk / free_chunk :
73e18e3516Sopenharmony_ci     * allocate executable system memory chunks
74e18e3516Sopenharmony_ci     * the size is always divisible by CHUNK_SIZE
75e18e3516Sopenharmony_ci   SLJIT_ALLOCATOR_LOCK / SLJIT_ALLOCATOR_UNLOCK :
76e18e3516Sopenharmony_ci     * provided as part of sljitUtils
77e18e3516Sopenharmony_ci     * only the allocator requires this lock, sljit is fully thread safe
78e18e3516Sopenharmony_ci       as it only uses local variables
79e18e3516Sopenharmony_ci*/
80e18e3516Sopenharmony_ci
81e18e3516Sopenharmony_ci#ifdef _WIN32
82e18e3516Sopenharmony_ci#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec)
83e18e3516Sopenharmony_ci
84e18e3516Sopenharmony_cistatic SLJIT_INLINE void* alloc_chunk(sljit_uw size)
85e18e3516Sopenharmony_ci{
86e18e3516Sopenharmony_ci	return VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
87e18e3516Sopenharmony_ci}
88e18e3516Sopenharmony_ci
89e18e3516Sopenharmony_cistatic SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
90e18e3516Sopenharmony_ci{
91e18e3516Sopenharmony_ci	SLJIT_UNUSED_ARG(size);
92e18e3516Sopenharmony_ci	VirtualFree(chunk, 0, MEM_RELEASE);
93e18e3516Sopenharmony_ci}
94e18e3516Sopenharmony_ci
95e18e3516Sopenharmony_ci#else /* POSIX */
96e18e3516Sopenharmony_ci
97e18e3516Sopenharmony_ci#if defined(__APPLE__) && defined(MAP_JIT)
98e18e3516Sopenharmony_ci/*
99e18e3516Sopenharmony_ci   On macOS systems, returns MAP_JIT if it is defined _and_ we're running on a
100e18e3516Sopenharmony_ci   version where it's OK to have more than one JIT block or where MAP_JIT is
101e18e3516Sopenharmony_ci   required.
102e18e3516Sopenharmony_ci   On non-macOS systems, returns MAP_JIT if it is defined.
103e18e3516Sopenharmony_ci*/
104e18e3516Sopenharmony_ci#include <TargetConditionals.h>
105e18e3516Sopenharmony_ci#if TARGET_OS_OSX
106e18e3516Sopenharmony_ci#if defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86
107e18e3516Sopenharmony_ci#ifdef MAP_ANON
108e18e3516Sopenharmony_ci#include <sys/utsname.h>
109e18e3516Sopenharmony_ci#include <stdlib.h>
110e18e3516Sopenharmony_ci
111e18e3516Sopenharmony_ci#define SLJIT_MAP_JIT	(get_map_jit_flag())
112e18e3516Sopenharmony_ci
113e18e3516Sopenharmony_cistatic SLJIT_INLINE int get_map_jit_flag()
114e18e3516Sopenharmony_ci{
115e18e3516Sopenharmony_ci	size_t page_size;
116e18e3516Sopenharmony_ci	void *ptr;
117e18e3516Sopenharmony_ci	struct utsname name;
118e18e3516Sopenharmony_ci	static int map_jit_flag = -1;
119e18e3516Sopenharmony_ci
120e18e3516Sopenharmony_ci	if (map_jit_flag < 0) {
121e18e3516Sopenharmony_ci		map_jit_flag = 0;
122e18e3516Sopenharmony_ci		uname(&name);
123e18e3516Sopenharmony_ci
124e18e3516Sopenharmony_ci		/* Kernel version for 10.14.0 (Mojave) or later */
125e18e3516Sopenharmony_ci		if (atoi(name.release) >= 18) {
126e18e3516Sopenharmony_ci			page_size = get_page_alignment() + 1;
127e18e3516Sopenharmony_ci			/* Only use MAP_JIT if a hardened runtime is used */
128e18e3516Sopenharmony_ci			ptr = mmap(NULL, page_size, PROT_WRITE | PROT_EXEC,
129e18e3516Sopenharmony_ci					MAP_PRIVATE | MAP_ANON, -1, 0);
130e18e3516Sopenharmony_ci
131e18e3516Sopenharmony_ci			if (ptr != MAP_FAILED)
132e18e3516Sopenharmony_ci				munmap(ptr, page_size);
133e18e3516Sopenharmony_ci			else
134e18e3516Sopenharmony_ci				map_jit_flag = MAP_JIT;
135e18e3516Sopenharmony_ci		}
136e18e3516Sopenharmony_ci	}
137e18e3516Sopenharmony_ci	return map_jit_flag;
138e18e3516Sopenharmony_ci}
139e18e3516Sopenharmony_ci#endif /* MAP_ANON */
140e18e3516Sopenharmony_ci#else /* !SLJIT_CONFIG_X86 */
141e18e3516Sopenharmony_ci#if !(defined SLJIT_CONFIG_ARM && SLJIT_CONFIG_ARM)
142e18e3516Sopenharmony_ci#error "Unsupported architecture"
143e18e3516Sopenharmony_ci#endif /* SLJIT_CONFIG_ARM */
144e18e3516Sopenharmony_ci#include <AvailabilityMacros.h>
145e18e3516Sopenharmony_ci#include <pthread.h>
146e18e3516Sopenharmony_ci
147e18e3516Sopenharmony_ci#define SLJIT_MAP_JIT	(MAP_JIT)
148e18e3516Sopenharmony_ci#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec) \
149e18e3516Sopenharmony_ci                        apple_update_wx_flags(enable_exec)
150e18e3516Sopenharmony_ci
151e18e3516Sopenharmony_cistatic SLJIT_INLINE void apple_update_wx_flags(sljit_s32 enable_exec)
152e18e3516Sopenharmony_ci{
153e18e3516Sopenharmony_ci#if MAC_OS_X_VERSION_MIN_REQUIRED >= 110000
154e18e3516Sopenharmony_ci	pthread_jit_write_protect_np(enable_exec);
155e18e3516Sopenharmony_ci#else
156e18e3516Sopenharmony_ci#error "Must target Big Sur or newer"
157e18e3516Sopenharmony_ci#endif /* BigSur */
158e18e3516Sopenharmony_ci}
159e18e3516Sopenharmony_ci#endif /* SLJIT_CONFIG_X86 */
160e18e3516Sopenharmony_ci#else /* !TARGET_OS_OSX */
161e18e3516Sopenharmony_ci#define SLJIT_MAP_JIT	(MAP_JIT)
162e18e3516Sopenharmony_ci#endif /* TARGET_OS_OSX */
163e18e3516Sopenharmony_ci#endif /* __APPLE__ && MAP_JIT */
164e18e3516Sopenharmony_ci#ifndef SLJIT_UPDATE_WX_FLAGS
165e18e3516Sopenharmony_ci#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec)
166e18e3516Sopenharmony_ci#endif /* !SLJIT_UPDATE_WX_FLAGS */
167e18e3516Sopenharmony_ci#ifndef SLJIT_MAP_JIT
168e18e3516Sopenharmony_ci#define SLJIT_MAP_JIT	(0)
169e18e3516Sopenharmony_ci#endif /* !SLJIT_MAP_JIT */
170e18e3516Sopenharmony_ci
171e18e3516Sopenharmony_cistatic SLJIT_INLINE void* alloc_chunk(sljit_uw size)
172e18e3516Sopenharmony_ci{
173e18e3516Sopenharmony_ci	void *retval;
174e18e3516Sopenharmony_ci	int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
175e18e3516Sopenharmony_ci	int flags = MAP_PRIVATE;
176e18e3516Sopenharmony_ci	int fd = -1;
177e18e3516Sopenharmony_ci
178e18e3516Sopenharmony_ci#ifdef PROT_MAX
179e18e3516Sopenharmony_ci	prot |= PROT_MAX(prot);
180e18e3516Sopenharmony_ci#endif
181e18e3516Sopenharmony_ci
182e18e3516Sopenharmony_ci#ifdef MAP_ANON
183e18e3516Sopenharmony_ci	flags |= MAP_ANON | SLJIT_MAP_JIT;
184e18e3516Sopenharmony_ci#else /* !MAP_ANON */
185e18e3516Sopenharmony_ci	if (SLJIT_UNLIKELY((dev_zero < 0) && open_dev_zero()))
186e18e3516Sopenharmony_ci		return NULL;
187e18e3516Sopenharmony_ci
188e18e3516Sopenharmony_ci	fd = dev_zero;
189e18e3516Sopenharmony_ci#endif /* MAP_ANON */
190e18e3516Sopenharmony_ci
191e18e3516Sopenharmony_ci	retval = mmap(NULL, size, prot, flags, fd, 0);
192e18e3516Sopenharmony_ci	if (retval == MAP_FAILED)
193e18e3516Sopenharmony_ci		return NULL;
194e18e3516Sopenharmony_ci
195e18e3516Sopenharmony_ci#ifdef __FreeBSD__
196e18e3516Sopenharmony_ci        /* HardenedBSD's mmap lies, so check permissions again */
197e18e3516Sopenharmony_ci	if (mprotect(retval, size, PROT_READ | PROT_WRITE | PROT_EXEC) < 0) {
198e18e3516Sopenharmony_ci		munmap(retval, size);
199e18e3516Sopenharmony_ci		return NULL;
200e18e3516Sopenharmony_ci	}
201e18e3516Sopenharmony_ci#endif /* FreeBSD */
202e18e3516Sopenharmony_ci
203e18e3516Sopenharmony_ci	SLJIT_UPDATE_WX_FLAGS(retval, (uint8_t *)retval + size, 0);
204e18e3516Sopenharmony_ci
205e18e3516Sopenharmony_ci	return retval;
206e18e3516Sopenharmony_ci}
207e18e3516Sopenharmony_ci
208e18e3516Sopenharmony_cistatic SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
209e18e3516Sopenharmony_ci{
210e18e3516Sopenharmony_ci	munmap(chunk, size);
211e18e3516Sopenharmony_ci}
212e18e3516Sopenharmony_ci
213e18e3516Sopenharmony_ci#endif /* windows */
214e18e3516Sopenharmony_ci
215e18e3516Sopenharmony_ci/* --------------------------------------------------------------------- */
216e18e3516Sopenharmony_ci/*  Common functions                                                     */
217e18e3516Sopenharmony_ci/* --------------------------------------------------------------------- */
218e18e3516Sopenharmony_ci
219e18e3516Sopenharmony_ci#define CHUNK_MASK	(~(CHUNK_SIZE - 1))
220e18e3516Sopenharmony_ci
221e18e3516Sopenharmony_cistruct block_header {
222e18e3516Sopenharmony_ci	sljit_uw size;
223e18e3516Sopenharmony_ci	sljit_uw prev_size;
224e18e3516Sopenharmony_ci};
225e18e3516Sopenharmony_ci
226e18e3516Sopenharmony_cistruct free_block {
227e18e3516Sopenharmony_ci	struct block_header header;
228e18e3516Sopenharmony_ci	struct free_block *next;
229e18e3516Sopenharmony_ci	struct free_block *prev;
230e18e3516Sopenharmony_ci	sljit_uw size;
231e18e3516Sopenharmony_ci};
232e18e3516Sopenharmony_ci
233e18e3516Sopenharmony_ci#define AS_BLOCK_HEADER(base, offset) \
234e18e3516Sopenharmony_ci	((struct block_header*)(((sljit_u8*)base) + offset))
235e18e3516Sopenharmony_ci#define AS_FREE_BLOCK(base, offset) \
236e18e3516Sopenharmony_ci	((struct free_block*)(((sljit_u8*)base) + offset))
237e18e3516Sopenharmony_ci#define MEM_START(base)		((void*)(((sljit_u8*)base) + sizeof(struct block_header)))
238e18e3516Sopenharmony_ci#define ALIGN_SIZE(size)	(((size) + sizeof(struct block_header) + 7u) & ~(sljit_uw)7)
239e18e3516Sopenharmony_ci
240e18e3516Sopenharmony_cistatic struct free_block* free_blocks;
241e18e3516Sopenharmony_cistatic sljit_uw allocated_size;
242e18e3516Sopenharmony_cistatic sljit_uw total_size;
243e18e3516Sopenharmony_ci
244e18e3516Sopenharmony_cistatic SLJIT_INLINE void sljit_insert_free_block(struct free_block *free_block, sljit_uw size)
245e18e3516Sopenharmony_ci{
246e18e3516Sopenharmony_ci	free_block->header.size = 0;
247e18e3516Sopenharmony_ci	free_block->size = size;
248e18e3516Sopenharmony_ci
249e18e3516Sopenharmony_ci	free_block->next = free_blocks;
250e18e3516Sopenharmony_ci	free_block->prev = NULL;
251e18e3516Sopenharmony_ci	if (free_blocks)
252e18e3516Sopenharmony_ci		free_blocks->prev = free_block;
253e18e3516Sopenharmony_ci	free_blocks = free_block;
254e18e3516Sopenharmony_ci}
255e18e3516Sopenharmony_ci
256e18e3516Sopenharmony_cistatic SLJIT_INLINE void sljit_remove_free_block(struct free_block *free_block)
257e18e3516Sopenharmony_ci{
258e18e3516Sopenharmony_ci	if (free_block->next)
259e18e3516Sopenharmony_ci		free_block->next->prev = free_block->prev;
260e18e3516Sopenharmony_ci
261e18e3516Sopenharmony_ci	if (free_block->prev)
262e18e3516Sopenharmony_ci		free_block->prev->next = free_block->next;
263e18e3516Sopenharmony_ci	else {
264e18e3516Sopenharmony_ci		SLJIT_ASSERT(free_blocks == free_block);
265e18e3516Sopenharmony_ci		free_blocks = free_block->next;
266e18e3516Sopenharmony_ci	}
267e18e3516Sopenharmony_ci}
268e18e3516Sopenharmony_ci
269e18e3516Sopenharmony_ciSLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
270e18e3516Sopenharmony_ci{
271e18e3516Sopenharmony_ci	struct block_header *header;
272e18e3516Sopenharmony_ci	struct block_header *next_header;
273e18e3516Sopenharmony_ci	struct free_block *free_block;
274e18e3516Sopenharmony_ci	sljit_uw chunk_size;
275e18e3516Sopenharmony_ci
276e18e3516Sopenharmony_ci	SLJIT_ALLOCATOR_LOCK();
277e18e3516Sopenharmony_ci	if (size < (64 - sizeof(struct block_header)))
278e18e3516Sopenharmony_ci		size = (64 - sizeof(struct block_header));
279e18e3516Sopenharmony_ci	size = ALIGN_SIZE(size);
280e18e3516Sopenharmony_ci
281e18e3516Sopenharmony_ci	free_block = free_blocks;
282e18e3516Sopenharmony_ci	while (free_block) {
283e18e3516Sopenharmony_ci		if (free_block->size >= size) {
284e18e3516Sopenharmony_ci			chunk_size = free_block->size;
285e18e3516Sopenharmony_ci			SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 0);
286e18e3516Sopenharmony_ci			if (chunk_size > size + 64) {
287e18e3516Sopenharmony_ci				/* We just cut a block from the end of the free block. */
288e18e3516Sopenharmony_ci				chunk_size -= size;
289e18e3516Sopenharmony_ci				free_block->size = chunk_size;
290e18e3516Sopenharmony_ci				header = AS_BLOCK_HEADER(free_block, chunk_size);
291e18e3516Sopenharmony_ci				header->prev_size = chunk_size;
292e18e3516Sopenharmony_ci				AS_BLOCK_HEADER(header, size)->prev_size = size;
293e18e3516Sopenharmony_ci			}
294e18e3516Sopenharmony_ci			else {
295e18e3516Sopenharmony_ci				sljit_remove_free_block(free_block);
296e18e3516Sopenharmony_ci				header = (struct block_header*)free_block;
297e18e3516Sopenharmony_ci				size = chunk_size;
298e18e3516Sopenharmony_ci			}
299e18e3516Sopenharmony_ci			allocated_size += size;
300e18e3516Sopenharmony_ci			header->size = size;
301e18e3516Sopenharmony_ci			SLJIT_ALLOCATOR_UNLOCK();
302e18e3516Sopenharmony_ci			return MEM_START(header);
303e18e3516Sopenharmony_ci		}
304e18e3516Sopenharmony_ci		free_block = free_block->next;
305e18e3516Sopenharmony_ci	}
306e18e3516Sopenharmony_ci
307e18e3516Sopenharmony_ci	chunk_size = (size + sizeof(struct block_header) + CHUNK_SIZE - 1) & CHUNK_MASK;
308e18e3516Sopenharmony_ci	header = (struct block_header*)alloc_chunk(chunk_size);
309e18e3516Sopenharmony_ci	if (!header) {
310e18e3516Sopenharmony_ci		SLJIT_ALLOCATOR_UNLOCK();
311e18e3516Sopenharmony_ci		return NULL;
312e18e3516Sopenharmony_ci	}
313e18e3516Sopenharmony_ci
314e18e3516Sopenharmony_ci	chunk_size -= sizeof(struct block_header);
315e18e3516Sopenharmony_ci	total_size += chunk_size;
316e18e3516Sopenharmony_ci
317e18e3516Sopenharmony_ci	header->prev_size = 0;
318e18e3516Sopenharmony_ci	if (chunk_size > size + 64) {
319e18e3516Sopenharmony_ci		/* Cut the allocated space into a free and a used block. */
320e18e3516Sopenharmony_ci		allocated_size += size;
321e18e3516Sopenharmony_ci		header->size = size;
322e18e3516Sopenharmony_ci		chunk_size -= size;
323e18e3516Sopenharmony_ci
324e18e3516Sopenharmony_ci		free_block = AS_FREE_BLOCK(header, size);
325e18e3516Sopenharmony_ci		free_block->header.prev_size = size;
326e18e3516Sopenharmony_ci		sljit_insert_free_block(free_block, chunk_size);
327e18e3516Sopenharmony_ci		next_header = AS_BLOCK_HEADER(free_block, chunk_size);
328e18e3516Sopenharmony_ci	}
329e18e3516Sopenharmony_ci	else {
330e18e3516Sopenharmony_ci		/* All space belongs to this allocation. */
331e18e3516Sopenharmony_ci		allocated_size += chunk_size;
332e18e3516Sopenharmony_ci		header->size = chunk_size;
333e18e3516Sopenharmony_ci		next_header = AS_BLOCK_HEADER(header, chunk_size);
334e18e3516Sopenharmony_ci	}
335e18e3516Sopenharmony_ci	next_header->size = 1;
336e18e3516Sopenharmony_ci	next_header->prev_size = chunk_size;
337e18e3516Sopenharmony_ci	SLJIT_ALLOCATOR_UNLOCK();
338e18e3516Sopenharmony_ci	return MEM_START(header);
339e18e3516Sopenharmony_ci}
340e18e3516Sopenharmony_ci
341e18e3516Sopenharmony_ciSLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
342e18e3516Sopenharmony_ci{
343e18e3516Sopenharmony_ci	struct block_header *header;
344e18e3516Sopenharmony_ci	struct free_block* free_block;
345e18e3516Sopenharmony_ci
346e18e3516Sopenharmony_ci	SLJIT_ALLOCATOR_LOCK();
347e18e3516Sopenharmony_ci	header = AS_BLOCK_HEADER(ptr, -(sljit_sw)sizeof(struct block_header));
348e18e3516Sopenharmony_ci	allocated_size -= header->size;
349e18e3516Sopenharmony_ci
350e18e3516Sopenharmony_ci	/* Connecting free blocks together if possible. */
351e18e3516Sopenharmony_ci	SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 0);
352e18e3516Sopenharmony_ci
353e18e3516Sopenharmony_ci	/* If header->prev_size == 0, free_block will equal to header.
354e18e3516Sopenharmony_ci	   In this case, free_block->header.size will be > 0. */
355e18e3516Sopenharmony_ci	free_block = AS_FREE_BLOCK(header, -(sljit_sw)header->prev_size);
356e18e3516Sopenharmony_ci	if (SLJIT_UNLIKELY(!free_block->header.size)) {
357e18e3516Sopenharmony_ci		free_block->size += header->size;
358e18e3516Sopenharmony_ci		header = AS_BLOCK_HEADER(free_block, free_block->size);
359e18e3516Sopenharmony_ci		header->prev_size = free_block->size;
360e18e3516Sopenharmony_ci	}
361e18e3516Sopenharmony_ci	else {
362e18e3516Sopenharmony_ci		free_block = (struct free_block*)header;
363e18e3516Sopenharmony_ci		sljit_insert_free_block(free_block, header->size);
364e18e3516Sopenharmony_ci	}
365e18e3516Sopenharmony_ci
366e18e3516Sopenharmony_ci	header = AS_BLOCK_HEADER(free_block, free_block->size);
367e18e3516Sopenharmony_ci	if (SLJIT_UNLIKELY(!header->size)) {
368e18e3516Sopenharmony_ci		free_block->size += ((struct free_block*)header)->size;
369e18e3516Sopenharmony_ci		sljit_remove_free_block((struct free_block*)header);
370e18e3516Sopenharmony_ci		header = AS_BLOCK_HEADER(free_block, free_block->size);
371e18e3516Sopenharmony_ci		header->prev_size = free_block->size;
372e18e3516Sopenharmony_ci	}
373e18e3516Sopenharmony_ci
374e18e3516Sopenharmony_ci	/* The whole chunk is free. */
375e18e3516Sopenharmony_ci	if (SLJIT_UNLIKELY(!free_block->header.prev_size && header->size == 1)) {
376e18e3516Sopenharmony_ci		/* If this block is freed, we still have (allocated_size / 2) free space. */
377e18e3516Sopenharmony_ci		if (total_size - free_block->size > (allocated_size * 3 / 2)) {
378e18e3516Sopenharmony_ci			total_size -= free_block->size;
379e18e3516Sopenharmony_ci			sljit_remove_free_block(free_block);
380e18e3516Sopenharmony_ci			free_chunk(free_block, free_block->size + sizeof(struct block_header));
381e18e3516Sopenharmony_ci		}
382e18e3516Sopenharmony_ci	}
383e18e3516Sopenharmony_ci
384e18e3516Sopenharmony_ci	SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 1);
385e18e3516Sopenharmony_ci	SLJIT_ALLOCATOR_UNLOCK();
386e18e3516Sopenharmony_ci}
387e18e3516Sopenharmony_ci
388e18e3516Sopenharmony_ciSLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
389e18e3516Sopenharmony_ci{
390e18e3516Sopenharmony_ci	struct free_block* free_block;
391e18e3516Sopenharmony_ci	struct free_block* next_free_block;
392e18e3516Sopenharmony_ci
393e18e3516Sopenharmony_ci	SLJIT_ALLOCATOR_LOCK();
394e18e3516Sopenharmony_ci	SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 0);
395e18e3516Sopenharmony_ci
396e18e3516Sopenharmony_ci	free_block = free_blocks;
397e18e3516Sopenharmony_ci	while (free_block) {
398e18e3516Sopenharmony_ci		next_free_block = free_block->next;
399e18e3516Sopenharmony_ci		if (!free_block->header.prev_size &&
400e18e3516Sopenharmony_ci				AS_BLOCK_HEADER(free_block, free_block->size)->size == 1) {
401e18e3516Sopenharmony_ci			total_size -= free_block->size;
402e18e3516Sopenharmony_ci			sljit_remove_free_block(free_block);
403e18e3516Sopenharmony_ci			free_chunk(free_block, free_block->size + sizeof(struct block_header));
404e18e3516Sopenharmony_ci		}
405e18e3516Sopenharmony_ci		free_block = next_free_block;
406e18e3516Sopenharmony_ci	}
407e18e3516Sopenharmony_ci
408e18e3516Sopenharmony_ci	SLJIT_ASSERT((total_size && free_blocks) || (!total_size && !free_blocks));
409e18e3516Sopenharmony_ci	SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 1);
410e18e3516Sopenharmony_ci	SLJIT_ALLOCATOR_UNLOCK();
411e18e3516Sopenharmony_ci}
412