Annotation of embedaddon/pcre/sljit/sljitExecAllocator.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Stack-less Just-In-Time compiler
! 3: *
! 4: * Copyright 2009-2010 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
! 5: *
! 6: * Redistribution and use in source and binary forms, with or without modification, are
! 7: * permitted provided that the following conditions are met:
! 8: *
! 9: * 1. Redistributions of source code must retain the above copyright notice, this list of
! 10: * conditions and the following disclaimer.
! 11: *
! 12: * 2. Redistributions in binary form must reproduce the above copyright notice, this list
! 13: * of conditions and the following disclaimer in the documentation and/or other materials
! 14: * provided with the distribution.
! 15: *
! 16: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
! 17: * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 18: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
! 19: * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
! 20: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
! 21: * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
! 22: * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 23: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
! 24: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 25: */
! 26:
! 27: /*
! 28: This file contains a simple executable memory allocator
! 29:
! 30: It is assumed, that executable code blocks are usually medium (or sometimes
! 31: large) memory blocks, and the allocator is not too frequently called (less
! 32: optimized than other allocators). Thus, using it as a generic allocator is
! 33: not suggested.
! 34:
! 35: How does it work:
! 36: Memory is allocated in continuous memory areas called chunks by alloc_chunk()
! 37: Chunk format:
! 38: [ block ][ block ] ... [ block ][ block terminator ]
! 39:
! 40: All blocks and the block terminator is started with block_header. The block
! 41: header contains the size of the previous and the next block. These sizes
! 42: can also contain special values.
! 43: Block size:
! 44: 0 - The block is a free_block, with a different size member.
! 45: 1 - The block is a block terminator.
! 46: n - The block is used at the moment, and the value contains its size.
! 47: Previous block size:
! 48: 0 - This is the first block of the memory chunk.
! 49: n - The size of the previous block.
! 50:
! 51: Using these size values we can go forward or backward on the block chain.
! 52: The unused blocks are stored in a chain list pointed by free_blocks. This
! 53: list is useful if we need to find a suitable memory area when the allocator
! 54: is called.
! 55:
! 56: When a block is freed, the new free block is connected to its adjacent free
! 57: blocks if possible.
! 58:
! 59: [ free block ][ used block ][ free block ]
! 60: and "used block" is freed, the three blocks are connected together:
! 61: [ one big free block ]
! 62: */
! 63:
! 64: /* --------------------------------------------------------------------- */
! 65: /* System (OS) functions */
! 66: /* --------------------------------------------------------------------- */
! 67:
! 68: /* 64 KByte. */
! 69: #define CHUNK_SIZE 0x10000
! 70:
! 71: /*
! 72: alloc_chunk / free_chunk :
! 73: * allocate executable system memory chunks
! 74: * the size is always divisible by CHUNK_SIZE
! 75: allocator_grab_lock / allocator_release_lock :
! 76: * make the allocator thread safe
! 77: * can be empty if the OS (or the application) does not support threading
! 78: * only the allocator requires this lock, sljit is fully thread safe
! 79: as it only uses local variables
! 80: */
! 81:
! 82: #ifdef _WIN32
! 83:
! 84: static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
! 85: {
! 86: return VirtualAlloc(0, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
! 87: }
! 88:
! 89: static SLJIT_INLINE void free_chunk(void* chunk, sljit_uw size)
! 90: {
! 91: SLJIT_UNUSED_ARG(size);
! 92: VirtualFree(chunk, 0, MEM_RELEASE);
! 93: }
! 94:
! 95: #else
! 96:
! 97: #include <sys/mman.h>
! 98:
! 99: static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
! 100: {
! 101: void* retval = mmap(0, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0);
! 102: return (retval != MAP_FAILED) ? retval : NULL;
! 103: }
! 104:
! 105: static SLJIT_INLINE void free_chunk(void* chunk, sljit_uw size)
! 106: {
! 107: munmap(chunk, size);
! 108: }
! 109:
! 110: #endif
! 111:
! 112: /* --------------------------------------------------------------------- */
! 113: /* Common functions */
! 114: /* --------------------------------------------------------------------- */
! 115:
! 116: #define CHUNK_MASK (~(CHUNK_SIZE - 1))
! 117:
! 118: struct block_header {
! 119: sljit_uw size;
! 120: sljit_uw prev_size;
! 121: };
! 122:
! 123: struct free_block {
! 124: struct block_header header;
! 125: struct free_block *next;
! 126: struct free_block *prev;
! 127: sljit_uw size;
! 128: };
! 129:
! 130: #define AS_BLOCK_HEADER(base, offset) \
! 131: ((struct block_header*)(((sljit_ub*)base) + offset))
! 132: #define AS_FREE_BLOCK(base, offset) \
! 133: ((struct free_block*)(((sljit_ub*)base) + offset))
! 134: #define MEM_START(base) ((void*)(((sljit_ub*)base) + sizeof(struct block_header)))
! 135: #define ALIGN_SIZE(size) (((size) + sizeof(struct block_header) + 7) & ~7)
! 136:
! 137: static struct free_block* free_blocks;
! 138: static sljit_uw allocated_size;
! 139: static sljit_uw total_size;
! 140:
! 141: static SLJIT_INLINE void sljit_insert_free_block(struct free_block *free_block, sljit_uw size)
! 142: {
! 143: free_block->header.size = 0;
! 144: free_block->size = size;
! 145:
! 146: free_block->next = free_blocks;
! 147: free_block->prev = 0;
! 148: if (free_blocks)
! 149: free_blocks->prev = free_block;
! 150: free_blocks = free_block;
! 151: }
! 152:
! 153: static SLJIT_INLINE void sljit_remove_free_block(struct free_block *free_block)
! 154: {
! 155: if (free_block->next)
! 156: free_block->next->prev = free_block->prev;
! 157:
! 158: if (free_block->prev)
! 159: free_block->prev->next = free_block->next;
! 160: else {
! 161: SLJIT_ASSERT(free_blocks == free_block);
! 162: free_blocks = free_block->next;
! 163: }
! 164: }
! 165:
! 166: SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
! 167: {
! 168: struct block_header *header;
! 169: struct block_header *next_header;
! 170: struct free_block *free_block;
! 171: sljit_uw chunk_size;
! 172:
! 173: allocator_grab_lock();
! 174: if (size < sizeof(struct free_block))
! 175: size = sizeof(struct free_block);
! 176: size = ALIGN_SIZE(size);
! 177:
! 178: free_block = free_blocks;
! 179: while (free_block) {
! 180: if (free_block->size >= size) {
! 181: chunk_size = free_block->size;
! 182: if (chunk_size > size + 64) {
! 183: /* We just cut a block from the end of the free block. */
! 184: chunk_size -= size;
! 185: free_block->size = chunk_size;
! 186: header = AS_BLOCK_HEADER(free_block, chunk_size);
! 187: header->prev_size = chunk_size;
! 188: AS_BLOCK_HEADER(header, size)->prev_size = size;
! 189: }
! 190: else {
! 191: sljit_remove_free_block(free_block);
! 192: header = (struct block_header*)free_block;
! 193: size = chunk_size;
! 194: }
! 195: allocated_size += size;
! 196: header->size = size;
! 197: allocator_release_lock();
! 198: return MEM_START(header);
! 199: }
! 200: free_block = free_block->next;
! 201: }
! 202:
! 203: chunk_size = (size + sizeof(struct block_header) + CHUNK_SIZE - 1) & CHUNK_MASK;
! 204: header = (struct block_header*)alloc_chunk(chunk_size);
! 205: PTR_FAIL_IF(!header);
! 206:
! 207: chunk_size -= sizeof(struct block_header);
! 208: total_size += chunk_size;
! 209:
! 210: header->prev_size = 0;
! 211: if (chunk_size > size + 64) {
! 212: /* Cut the allocated space into a free and a used block. */
! 213: allocated_size += size;
! 214: header->size = size;
! 215: chunk_size -= size;
! 216:
! 217: free_block = AS_FREE_BLOCK(header, size);
! 218: free_block->header.prev_size = size;
! 219: sljit_insert_free_block(free_block, chunk_size);
! 220: next_header = AS_BLOCK_HEADER(free_block, chunk_size);
! 221: }
! 222: else {
! 223: /* All space belongs to this allocation. */
! 224: allocated_size += chunk_size;
! 225: header->size = chunk_size;
! 226: next_header = AS_BLOCK_HEADER(header, chunk_size);
! 227: }
! 228: next_header->size = 1;
! 229: next_header->prev_size = chunk_size;
! 230: allocator_release_lock();
! 231: return MEM_START(header);
! 232: }
! 233:
! 234: SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
! 235: {
! 236: struct block_header *header;
! 237: struct free_block* free_block;
! 238:
! 239: allocator_grab_lock();
! 240: header = AS_BLOCK_HEADER(ptr, -(sljit_w)sizeof(struct block_header));
! 241: allocated_size -= header->size;
! 242:
! 243: /* Connecting free blocks together if possible. */
! 244:
! 245: /* If header->prev_size == 0, free_block will equal to header.
! 246: In this case, free_block->header.size will be > 0. */
! 247: free_block = AS_FREE_BLOCK(header, -(sljit_w)header->prev_size);
! 248: if (SLJIT_UNLIKELY(!free_block->header.size)) {
! 249: free_block->size += header->size;
! 250: header = AS_BLOCK_HEADER(free_block, free_block->size);
! 251: header->prev_size = free_block->size;
! 252: }
! 253: else {
! 254: free_block = (struct free_block*)header;
! 255: sljit_insert_free_block(free_block, header->size);
! 256: }
! 257:
! 258: header = AS_BLOCK_HEADER(free_block, free_block->size);
! 259: if (SLJIT_UNLIKELY(!header->size)) {
! 260: free_block->size += ((struct free_block*)header)->size;
! 261: sljit_remove_free_block((struct free_block*)header);
! 262: header = AS_BLOCK_HEADER(free_block, free_block->size);
! 263: header->prev_size = free_block->size;
! 264: }
! 265:
! 266: if (SLJIT_UNLIKELY(!free_block->header.prev_size && header->size == 1)) {
! 267: if (total_size - free_block->size > (allocated_size * 3 / 2)) {
! 268: sljit_remove_free_block(free_block);
! 269: free_chunk(free_block, free_block->size + sizeof(struct block_header));
! 270: }
! 271: }
! 272:
! 273: allocator_release_lock();
! 274: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>