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