53#if !defined(MRBC_ALLOC_LIBC)
57#if defined(MRBC_DEBUG)
79#ifndef MRBC_ALLOC_FLI_BIT_WIDTH
80# define MRBC_ALLOC_FLI_BIT_WIDTH 9
82#ifndef MRBC_ALLOC_SLI_BIT_WIDTH
83# define MRBC_ALLOC_SLI_BIT_WIDTH 3
85#ifndef MRBC_ALLOC_IGNORE_LSBS
86# define MRBC_ALLOC_IGNORE_LSBS 4
89#define SIZE_FREE_BLOCKS \
90 ((MRBC_ALLOC_FLI_BIT_WIDTH + 1) * (1 << MRBC_ALLOC_SLI_BIT_WIDTH))
96#if !defined(MRBC_MIN_MEMORY_BLOCK_SIZE)
97#define MRBC_MIN_MEMORY_BLOCK_SIZE sizeof(FREE_BLOCK)
103#define FLI(x) ((x) >> MRBC_ALLOC_SLI_BIT_WIDTH)
104#define SLI(x) ((x) & ((1 << MRBC_ALLOC_SLI_BIT_WIDTH) - 1))
117#if defined(MRBC_ALLOC_16BIT)
118#define MRBC_ALLOC_MEMSIZE_T uint16_t
120typedef struct USED_BLOCK {
121 MRBC_ALLOC_MEMSIZE_T size;
122#if defined(MRBC_ALLOC_VMID)
127typedef struct FREE_BLOCK {
128 MRBC_ALLOC_MEMSIZE_T size;
129#if defined(MRBC_ALLOC_VMID)
133 struct FREE_BLOCK *next_free;
134 struct FREE_BLOCK *prev_free;
135 struct FREE_BLOCK *top_adrs;
148#elif defined(MRBC_ALLOC_24BIT)
149#define MRBC_ALLOC_MEMSIZE_T uint32_t
151typedef struct USED_BLOCK {
152#if defined(MRBC_ALLOC_VMID)
153 MRBC_ALLOC_MEMSIZE_T size : 24;
156 MRBC_ALLOC_MEMSIZE_T size;
160typedef struct FREE_BLOCK {
161#if defined(MRBC_ALLOC_VMID)
162 MRBC_ALLOC_MEMSIZE_T size : 24;
165 MRBC_ALLOC_MEMSIZE_T size;
168 struct FREE_BLOCK *next_free;
169 struct FREE_BLOCK *prev_free;
170 struct FREE_BLOCK *top_adrs;
174# error 'define MRBC_ALLOC_*' required.
180#define BLOCK_SIZE(p) (((p)->size) & ~0x03)
181#define PHYS_NEXT(p) ((void *)((uint8_t *)(p) + BLOCK_SIZE(p)))
182#define SET_USED_BLOCK(p) ((p)->size |= 0x01)
183#define SET_FREE_BLOCK(p) ((p)->size &= ~0x01)
184#define IS_USED_BLOCK(p) ((p)->size & 0x01)
185#define IS_FREE_BLOCK(p) (!IS_USED_BLOCK(p))
186#define SET_PREV_USED(p) ((p)->size |= 0x02)
187#define SET_PREV_FREE(p) ((p)->size &= ~0x02)
188#define IS_PREV_USED(p) ((p)->size & 0x02)
189#define IS_PREV_FREE(p) (!IS_PREV_USED(p))
191#if defined(MRBC_ALLOC_VMID)
192#define SET_VM_ID(p,id) (((USED_BLOCK *)(p))->vm_id = (id))
193#define GET_VM_ID(p) (((USED_BLOCK *)(p))->vm_id)
196#define SET_VM_ID(p,id) ((void)0)
197#define GET_VM_ID(p) 0
217#define BPOOL_TOP(memory_pool) ((void *)((uint8_t *)(memory_pool) + sizeof(MEMORY_POOL)))
218#define BPOOL_END(memory_pool) ((void *)((uint8_t *)(memory_pool) + ((MEMORY_POOL *)(memory_pool))->size))
219#define BLOCK_ADRS(p) ((void *)((uint8_t *)(p) - sizeof(USED_BLOCK)))
221#define MSB_BIT1_FLI 0x8000
222#define MSB_BIT1_SLI 0x80
223#define NLZ_FLI(x) nlz16(x)
224#define NLZ_SLI(x) nlz8(x)
232#if defined(MRBC_USE_ALLOC_PROF)
233static int profiling = 0;
248 if( x == 0 )
return 16;
251 if((x >> 8) == 0 ) { n += 8; x <<= 8; }
252 if((x >> 12) == 0 ) { n += 4; x <<= 4; }
253 if((x >> 14) == 0 ) { n += 2; x <<= 2; }
254 return n - (x >> 15);
264static inline int nlz8(uint8_t x)
266 if( x == 0 )
return 8;
269 if((x >> 4) == 0 ) { n += 4; x <<= 4; }
270 if((x >> 6) == 0 ) { n += 2; x <<= 2; }
281static inline unsigned int calc_index(MRBC_ALLOC_MEMSIZE_T alloc_size)
291 unsigned int fli = 16 -
318 FREE_BLOCK **top_adrs = (FREE_BLOCK **)((uint8_t*)target +
BLOCK_SIZE(target) -
sizeof(FREE_BLOCK *));
322 unsigned int fli =
FLI(index);
323 unsigned int sli =
SLI(index);
329 target->prev_free = NULL;
331 if( target->next_free != NULL ) {
332 target->next_free->prev_free = target;
347 if( target->prev_free == NULL ) {
351 if( target->next_free == NULL ) {
352 unsigned int fli =
FLI(index);
353 unsigned int sli =
SLI(index);
359 target->prev_free->next_free = target->next_free;
362 if( target->next_free != NULL ) {
363 target->next_free->prev_free = target->prev_free;
368#if defined(MRBC_USE_ALLOC_PROF)
372static void alloc_profile(
void)
374 if (!profiling)
return;
378 unsigned int used = 0;
380 while (block < (USED_BLOCK *)
BPOOL_END(pool)) {
387 if (alloc_prof.
max < used) alloc_prof.
max = used;
388 if (used < alloc_prof.
min) alloc_prof.
min = used;
400static inline FREE_BLOCK*
split_block(FREE_BLOCK *target, MRBC_ALLOC_MEMSIZE_T size)
406 FREE_BLOCK *split = (FREE_BLOCK *)((uint8_t *)target + size);
409 target->size = size | (target->size & 0x03);
422static inline void merge_block(FREE_BLOCK *target, FREE_BLOCK *next)
424 assert(target < next);
449#if defined(UINTPTR_MAX)
450 assert( ((uintptr_t)ptr & 0x03) == 0 );
452 assert( ((uint32_t)ptr & 0x03) == 0 );
455 assert( size <= (MRBC_ALLOC_MEMSIZE_T)(~0) );
457 size &= ~(
unsigned int)0x03;
464 MRBC_ALLOC_MEMSIZE_T sentinel_size =
sizeof(USED_BLOCK);
465 sentinel_size += (-sentinel_size & 0x03);
466 MRBC_ALLOC_MEMSIZE_T free_size = size -
sizeof(
MEMORY_POOL) - sentinel_size;
468 USED_BLOCK *used_block = (USED_BLOCK *)((uint8_t *)free_block + free_size);
470 free_block->size = free_size | 0x02;
471 used_block->size = sentinel_size | 0x01;
483#if defined(MRBC_DEBUG)
503 MRBC_ALLOC_MEMSIZE_T alloc_size = size +
sizeof(USED_BLOCK);
506 alloc_size += (-alloc_size & 3);
512 unsigned int fli, sli;
519 if( target &&
BLOCK_SIZE(target) >= alloc_size ) {
522 goto FOUND_TARGET_BLOCK;
529 if( target )
goto FOUND_TARGET_BLOCK;
553 target = target->next_free;
557#if defined(MRBC_OUT_OF_MEMORY)
558 MRBC_OUT_OF_MEMORY();
560 static const char msg[] =
"Fatal error: Out of memory.\n";
561 hal_write(2, msg,
sizeof(msg)-1);
570 assert( target != NULL );
577 if( target->next_free == NULL ) {
582 target->next_free->prev_free = NULL;
586 FREE_BLOCK *release =
split_block(target, alloc_size);
587 if( release != NULL ) {
599#if defined(MRBC_DEBUG)
600 memset( (uint8_t *)target +
sizeof(USED_BLOCK), 0xaa,
604#if defined(MRBC_USE_ALLOC_PROF)
608 return (uint8_t *)target +
sizeof(USED_BLOCK);
622 MRBC_ALLOC_MEMSIZE_T alloc_size = size + (-size & 3);
634 if( (
BLOCK_SIZE(prev) -
sizeof(USED_BLOCK)) < alloc_size )
goto FALLBACK;
637 MRBC_ALLOC_MEMSIZE_T free_size =
BLOCK_SIZE(prev) - alloc_size;
647 MRBC_ALLOC_MEMSIZE_T tail_size = tail->size + alloc_size;
648 tail = (FREE_BLOCK*)((uint8_t *)tail - alloc_size);
649 tail->size = tail_size;
650 prev->size -= alloc_size;
653#if defined(MRBC_DEBUG)
654 memset( (uint8_t *)tail +
sizeof(USED_BLOCK), 0xaa, alloc_size );
659 return (uint8_t *)tail +
sizeof(USED_BLOCK);
676 unsigned int total_size = nmemb * size;
681 volatile unsigned char *vptr = (
volatile unsigned char *)ptr;
682 while (total_size--) {
699#if defined(MRBC_DEBUG)
702 static const char msg[] =
"mrbc_raw_free(): NULL pointer was given.\n";
703 hal_write(2, msg,
sizeof(msg)-1);
708 if( target < (FREE_BLOCK *)
BPOOL_TOP(pool) ||
709 target > (FREE_BLOCK *)
BPOOL_END(pool) ) {
710 static const char msg[] =
"mrbc_raw_free(): Outside memory pool address was specified.\n";
711 hal_write(2, msg,
sizeof(msg)-1);
717 if( block == target )
break;
722 if( block == target ) {
725 static const char msg[] =
"mrbc_raw_free(): double free detected.\n";
726 hal_write(2, msg,
sizeof(msg)-1);
731 static const char msg[] =
"mrbc_raw_free(): no_free address was specified.\n";
732 hal_write(2, msg,
sizeof(msg)-1);
738 if( block < target ) {
739 static const char msg[] =
"mrbc_raw_free(): no_free address was specified.\n";
740 hal_write(2, msg,
sizeof(msg)-1);
744 static const char msg[] =
"mrbc_raw_free(): Illegal address.\n";
745 hal_write(2, msg,
sizeof(msg)-1);
750 memset( ptr, 0xff,
BLOCK_SIZE(target) -
sizeof(USED_BLOCK) );
754 if( ptr == NULL )
return;
771 FREE_BLOCK *prev = *((FREE_BLOCK **)((uint8_t*)target -
sizeof(FREE_BLOCK *)));
782#if defined(MRBC_USE_ALLOC_PROF)
798 if (ptr != NULL && size == 0) {
804 volatile USED_BLOCK *target =
BLOCK_ADRS(ptr);
805 MRBC_ALLOC_MEMSIZE_T alloc_size = size +
sizeof(USED_BLOCK);
809 alloc_size += (-alloc_size & 3);
827 FREE_BLOCK *release =
split_block((FREE_BLOCK *)target, alloc_size);
828 if( release != NULL ) {
832#if defined(MRBC_USE_ALLOC_PROF)
846#if defined(MRBC_USE_ALLOC_PROF)
856 if( new_ptr == NULL )
return NULL;
858 memcpy(new_ptr, ptr,
BLOCK_SIZE(target) -
sizeof(USED_BLOCK));
859 mrbc_set_vm_id(new_ptr, target->vm_id);
877 return (
unsigned int)(
BLOCK_SIZE(target) -
sizeof(USED_BLOCK));
881#if defined(MRBC_ALLOC_VMID)
890void * mrbc_alloc(
const struct VM *vm,
unsigned int size)
893 if( ptr == NULL )
return NULL;
895 if( vm ) mrbc_set_vm_id(ptr, vm->
vm_id);
910void * mrbc_calloc(
const struct VM *vm,
unsigned int nmemb,
unsigned int size)
913 if( ptr == NULL )
return NULL;
915 if( vm ) mrbc_set_vm_id(ptr, vm->
vm_id);
926void mrbc_free_all(
const struct VM *vm)
931 int vm_id = vm->
vm_id;
933 while( target < (USED_BLOCK *)
BPOOL_END(pool) ) {
951void mrbc_set_vm_id(
void *ptr,
int vm_id)
963int mrbc_get_vm_id(
void *ptr)
986 while( block < (USED_BLOCK *)
BPOOL_END(pool) ) {
1001#if defined(MRBC_USE_ALLOC_PROF)
1005void mrbc_alloc_start_profiling(
void)
1007 if (profiling)
return;
1017void mrbc_alloc_stop_profiling(
void)
1019 if (!profiling)
return;
1035#if defined(MRBC_DEBUG)
1042void mrbc_alloc_print_statistics(
void )
1047 mrbc_printf(
" total:%d used:%d free:%d frag:%d\n",
1048 stat.total, stat.used, stat.free, stat.fragmentation );
1058void mrbc_alloc_print_pool_header(
void *pool_header )
1067 mrbc_printf(
" sizeof MEMORY_POOL:%d(%04x), USED_BLOCK:%d(%02x), FREE_BLOCK:%d(%02x)\n",
1069 sizeof(USED_BLOCK),
sizeof(USED_BLOCK),
1070 sizeof(FREE_BLOCK),
sizeof(FREE_BLOCK) );
1072 mrbc_printf(
" FLI/SLI bitmap and free_blocks table.\n");
1073 mrbc_printf(
" FLI :S[0123 4567] -- free_blocks ");
1074 for(
int i = 0; i < 64; i++ ) {
mrbc_printf(
"-"); }
1078 for(
int j = 0; j < 8; j++ ) {
1083 for(
int j = 0; j < 8; j++ ) {
1084 int idx = i * 8 + j;
1085 if( idx >=
sizeof(pool->
free_blocks) /
sizeof(FREE_BLOCK *) )
break;
1092void mrbc_alloc_print_memory_block(
void *pool_header )
1094 const int DUMP_BYTES = 32;
1100 while( block < (FREE_BLOCK *)
BPOOL_END(pool) ) {
1102#if defined(MRBC_ALLOC_VMID)
1106 block->size & ~0x03, block->size & ~0x03,
1107 !!(block->size & 0x01), !!(block->size & 0x02) );
1112 if( n > (
BLOCK_SIZE(block) -
sizeof(USED_BLOCK)) ) {
1115 uint8_t *p = (uint8_t *)block +
sizeof(USED_BLOCK);
1117 for( i = 0; i < n; i++)
mrbc_printf(
" %02x", *p++ );
1121 p = (uint8_t *)block +
sizeof(USED_BLOCK);
1122 for( i = 0; i < n; i++) {
1124 mrbc_printf(
"%c", (
' ' <= ch && ch < 0x7f)? ch :
'.');
1131 FLI(index),
SLI(index), block->prev_free, block->next_free);
1139void mrbc_alloc_print_memory_pool(
void )
1141 mrbc_alloc_print_pool_header(0);
1142 mrbc_alloc_print_memory_block(0);
static unsigned int calc_index(MRBC_ALLOC_MEMSIZE_T alloc_size)
void * mrbc_raw_alloc(unsigned int size)
static FREE_BLOCK * split_block(FREE_BLOCK *target, MRBC_ALLOC_MEMSIZE_T size)
void mrbc_alloc_statistics(struct MRBC_ALLOC_STATISTICS *ret)
#define MRBC_ALLOC_FLI_BIT_WIDTH
#define BPOOL_TOP(memory_pool)
static int nlz8(uint8_t x)
static void merge_block(FREE_BLOCK *target, FREE_BLOCK *next)
void * mrbc_raw_alloc_no_free(unsigned int size)
static void remove_free_block(MEMORY_POOL *pool, FREE_BLOCK *target)
#define SET_FREE_BLOCK(p)
#define MRBC_MIN_MEMORY_BLOCK_SIZE
#define MRBC_ALLOC_IGNORE_LSBS
void * mrbc_raw_realloc(void *ptr, unsigned int size)
#define BPOOL_END(memory_pool)
void mrbc_init_alloc(void *ptr, unsigned int size)
static int nlz16(uint16_t x)
#define SET_USED_BLOCK(p)
unsigned int mrbc_alloc_usable_size(void *ptr)
#define MRBC_ALLOC_SLI_BIT_WIDTH
static void add_free_block(MEMORY_POOL *pool, FREE_BLOCK *target)
void * mrbc_raw_calloc(unsigned int nmemb, unsigned int size)
static MEMORY_POOL * memory_pool
void mrbc_raw_free(void *ptr)
void mrbc_cleanup_alloc(void)
mruby/c memory management.
static mrbc_int_t shift(mrbc_int_t x, mrbc_int_t y)
void mrbc_printf(const char *fstr,...)
console output module. (not yet input)
FREE_BLOCK * free_blocks[SIZE_FREE_BLOCKS+1]
MRBC_ALLOC_MEMSIZE_T size
uint8_t free_sli_bitmap[MRBC_ALLOC_FLI_BIT_WIDTH+1+1]
for memory allocation profiling functions. if you use this, define MRBC_USE_ALLOC_PROF pre-processor ...
Return value structure for mrbc_alloc_statistics function.
unsigned int total
returns total memory.
unsigned int used
returns used memory.
unsigned int fragmentation
returns memory fragmentation count.
unsigned int free
returns free memory.
uint8_t vm_id
vm_id : 1..MAX_VM_COUNT
Global configuration of mruby/c VM's.