54#if !defined(MRBC_ALLOC_LIBC)
58#if defined(MRBC_DEBUG)
80#ifndef MRBC_ALLOC_FLI_BIT_WIDTH
81# define MRBC_ALLOC_FLI_BIT_WIDTH 9
83#ifndef MRBC_ALLOC_SLI_BIT_WIDTH
84# define MRBC_ALLOC_SLI_BIT_WIDTH 3
86#ifndef MRBC_ALLOC_IGNORE_LSBS
87# define MRBC_ALLOC_IGNORE_LSBS 4
90#define SIZE_FREE_BLOCKS \
91 ((MRBC_ALLOC_FLI_BIT_WIDTH + 1) * (1 << MRBC_ALLOC_SLI_BIT_WIDTH))
97#if !defined(MRBC_MIN_MEMORY_BLOCK_SIZE)
98#define MRBC_MIN_MEMORY_BLOCK_SIZE sizeof(FREE_BLOCK)
104#define FLI(x) ((x) >> MRBC_ALLOC_SLI_BIT_WIDTH)
105#define SLI(x) ((x) & ((1 << MRBC_ALLOC_SLI_BIT_WIDTH) - 1))
113# define RETURN_IF_NULL(ptr) (void)0
115# define RETURN_IF_NULL(ptr) if((ptr) == NULL) return (ptr)
129#if defined(MRBC_ALLOC_16BIT)
130#define MRBC_ALLOC_MEMSIZE_T uint16_t
132typedef struct USED_BLOCK {
133 MRBC_ALLOC_MEMSIZE_T size;
134#if defined(MRBC_ALLOC_VMID)
139typedef struct FREE_BLOCK {
140 MRBC_ALLOC_MEMSIZE_T size;
141#if defined(MRBC_ALLOC_VMID)
145 struct FREE_BLOCK *next_free;
146 struct FREE_BLOCK *prev_free;
147 struct FREE_BLOCK *top_adrs;
160#elif defined(MRBC_ALLOC_24BIT)
161#define MRBC_ALLOC_MEMSIZE_T uint32_t
163typedef struct USED_BLOCK {
164#if defined(MRBC_ALLOC_VMID)
165 MRBC_ALLOC_MEMSIZE_T size : 24;
168 MRBC_ALLOC_MEMSIZE_T size;
172typedef struct FREE_BLOCK {
173#if defined(MRBC_ALLOC_VMID)
174 MRBC_ALLOC_MEMSIZE_T size : 24;
177 MRBC_ALLOC_MEMSIZE_T size;
180 struct FREE_BLOCK *next_free;
181 struct FREE_BLOCK *prev_free;
182 struct FREE_BLOCK *top_adrs;
186# error 'define MRBC_ALLOC_*' required.
192#define BLOCK_SIZE(p) (((p)->size) & ~0x03)
193#define PHYS_NEXT(p) ((void *)((uint8_t *)(p) + BLOCK_SIZE(p)))
194#define SET_USED_BLOCK(p) ((p)->size |= 0x01)
195#define SET_FREE_BLOCK(p) ((p)->size &= ~0x01)
196#define IS_USED_BLOCK(p) ((p)->size & 0x01)
197#define IS_FREE_BLOCK(p) (!IS_USED_BLOCK(p))
198#define SET_PREV_USED(p) ((p)->size |= 0x02)
199#define SET_PREV_FREE(p) ((p)->size &= ~0x02)
200#define IS_PREV_USED(p) ((p)->size & 0x02)
201#define IS_PREV_FREE(p) (!IS_PREV_USED(p))
203#if defined(MRBC_ALLOC_VMID)
204#define SET_VM_ID(p,id) (((USED_BLOCK *)(p))->vm_id = (id))
205#define GET_VM_ID(p) (((USED_BLOCK *)(p))->vm_id)
208#define SET_VM_ID(p,id) ((void)0)
209#define GET_VM_ID(p) 0
229#define BPOOL_TOP(memory_pool) ((void *)((uint8_t *)(memory_pool) + sizeof(MEMORY_POOL)))
230#define BPOOL_END(memory_pool) ((void *)((uint8_t *)(memory_pool) + ((MEMORY_POOL *)(memory_pool))->size))
231#define BLOCK_ADRS(p) ((void *)((uint8_t *)(p) - sizeof(USED_BLOCK)))
233#define MSB_BIT1_FLI 0x8000
234#define MSB_BIT1_SLI 0x80
235#define NLZ_FLI(x) nlz16(x)
236#define NLZ_SLI(x) nlz8(x)
244#if defined(MRBC_USE_ALLOC_PROF)
245static int profiling = 0;
260 if( x == 0 )
return 16;
263 if((x >> 8) == 0 ) { n += 8; x <<= 8; }
264 if((x >> 12) == 0 ) { n += 4; x <<= 4; }
265 if((x >> 14) == 0 ) { n += 2; x <<= 2; }
266 return n - (x >> 15);
276static inline int nlz8(uint8_t x)
278 if( x == 0 )
return 8;
281 if((x >> 4) == 0 ) { n += 4; x <<= 4; }
282 if((x >> 6) == 0 ) { n += 2; x <<= 2; }
293static inline unsigned int calc_index(MRBC_ALLOC_MEMSIZE_T alloc_size)
303 unsigned int fli = 16 -
330 FREE_BLOCK **top_adrs = (FREE_BLOCK **)((uint8_t*)target +
BLOCK_SIZE(target) -
sizeof(FREE_BLOCK *));
334 unsigned int fli =
FLI(index);
335 unsigned int sli =
SLI(index);
341 target->prev_free = NULL;
343 if( target->next_free != NULL ) {
344 target->next_free->prev_free = target;
359 if( target->prev_free == NULL ) {
363 if( target->next_free == NULL ) {
364 unsigned int fli =
FLI(index);
365 unsigned int sli =
SLI(index);
371 target->prev_free->next_free = target->next_free;
374 if( target->next_free != NULL ) {
375 target->next_free->prev_free = target->prev_free;
380#if defined(MRBC_USE_ALLOC_PROF)
386 if (!profiling)
return;
390 unsigned int used = 0;
392 while (block < (USED_BLOCK *)
BPOOL_END(pool)) {
399 if (alloc_prof.
max < used) alloc_prof.
max = used;
400 if (used < alloc_prof.
min) alloc_prof.
min = used;
403#define alloc_profile() ((void)0)
414static inline FREE_BLOCK*
split_block(FREE_BLOCK *target, MRBC_ALLOC_MEMSIZE_T size)
420 FREE_BLOCK *split = (FREE_BLOCK *)((uint8_t *)target + size);
423 target->size = size | (target->size & 0x03);
436static inline void merge_block(FREE_BLOCK *target, FREE_BLOCK *next)
438 assert(target < next);
463#if defined(UINTPTR_MAX)
464 assert( ((uintptr_t)ptr & 0x03) == 0 );
466 assert( ((uint32_t)ptr & 0x03) == 0 );
469 assert( size <= (MRBC_ALLOC_MEMSIZE_T)(~0) );
471 size &= ~(
unsigned int)0x03;
478 MRBC_ALLOC_MEMSIZE_T sentinel_size =
sizeof(USED_BLOCK);
479 sentinel_size += (-sentinel_size & 0x03);
480 MRBC_ALLOC_MEMSIZE_T free_size = size -
sizeof(
MEMORY_POOL) - sentinel_size;
482 USED_BLOCK *used_block = (USED_BLOCK *)((uint8_t *)free_block + free_size);
484 free_block->size = free_size | 0x02;
485 used_block->size = sentinel_size | 0x01;
497#if defined(MRBC_DEBUG)
517 MRBC_ALLOC_MEMSIZE_T alloc_size = size +
sizeof(USED_BLOCK);
520 alloc_size += (-alloc_size & 3);
526 unsigned int fli, sli;
533 if( target &&
BLOCK_SIZE(target) >= alloc_size ) {
536 goto FOUND_TARGET_BLOCK;
543 if( target )
goto FOUND_TARGET_BLOCK;
567 target = target->next_free;
571#if defined(MRBC_OUT_OF_MEMORY)
572 MRBC_OUT_OF_MEMORY();
574 static const char msg[] =
"Fatal error: Out of memory.\n";
575 mrbc_hal_write(2, msg,
sizeof(msg)-1);
585 assert( target != NULL );
592 if( target->next_free == NULL ) {
597 target->next_free->prev_free = NULL;
601 FREE_BLOCK *release =
split_block(target, alloc_size);
602 if( release != NULL ) {
614#if defined(MRBC_DEBUG)
615 memset( (uint8_t *)target +
sizeof(USED_BLOCK), 0xaa,
620 return (uint8_t *)target +
sizeof(USED_BLOCK);
634 MRBC_ALLOC_MEMSIZE_T alloc_size = size + (-size & 3);
646 if( (
BLOCK_SIZE(prev) -
sizeof(USED_BLOCK)) < alloc_size )
goto FALLBACK;
649 MRBC_ALLOC_MEMSIZE_T free_size =
BLOCK_SIZE(prev) - alloc_size;
659 MRBC_ALLOC_MEMSIZE_T tail_size = tail->size + alloc_size;
660 tail = (FREE_BLOCK*)((uint8_t *)tail - alloc_size);
661 tail->size = tail_size;
662 prev->size -= alloc_size;
665#if defined(MRBC_DEBUG)
666 memset( (uint8_t *)tail +
sizeof(USED_BLOCK), 0xaa, alloc_size );
671 return (uint8_t *)tail +
sizeof(USED_BLOCK);
688 unsigned int total_size = nmemb * size;
693 volatile unsigned char *vptr = (
volatile unsigned char *)ptr;
694 while (total_size--) {
711#if defined(MRBC_DEBUG)
714 static const char msg[] =
"mrbc_raw_free(): NULL pointer was given.\n";
715 mrbc_hal_write(2, msg,
sizeof(msg)-1);
720 if( target < (FREE_BLOCK *)
BPOOL_TOP(pool) ||
721 target > (FREE_BLOCK *)
BPOOL_END(pool) ) {
722 static const char msg[] =
"mrbc_raw_free(): Outside memory pool address was specified.\n";
723 mrbc_hal_write(2, msg,
sizeof(msg)-1);
729 if( block == target )
break;
734 if( block == target ) {
737 static const char msg[] =
"mrbc_raw_free(): double free detected.\n";
738 mrbc_hal_write(2, msg,
sizeof(msg)-1);
743 static const char msg[] =
"mrbc_raw_free(): no_free address was specified.\n";
744 mrbc_hal_write(2, msg,
sizeof(msg)-1);
750 if( block < target ) {
751 static const char msg[] =
"mrbc_raw_free(): no_free address was specified.\n";
752 mrbc_hal_write(2, msg,
sizeof(msg)-1);
756 static const char msg[] =
"mrbc_raw_free(): Illegal address.\n";
757 mrbc_hal_write(2, msg,
sizeof(msg)-1);
762 memset( ptr, 0xff,
BLOCK_SIZE(target) -
sizeof(USED_BLOCK) );
766 if( ptr == NULL )
return;
783 FREE_BLOCK *prev = *((FREE_BLOCK **)((uint8_t*)target -
sizeof(FREE_BLOCK *)));
817 volatile USED_BLOCK *target =
BLOCK_ADRS(ptr);
818 MRBC_ALLOC_MEMSIZE_T alloc_size = size +
sizeof(USED_BLOCK);
822 alloc_size += (-alloc_size & 3);
840 FREE_BLOCK *release =
split_block((FREE_BLOCK *)target, alloc_size);
841 if( release != NULL ) {
867 memcpy(new_ptr, ptr,
BLOCK_SIZE(target) -
sizeof(USED_BLOCK));
868 mrbc_set_vm_id(new_ptr, target->vm_id);
886 return (
unsigned int)(
BLOCK_SIZE(target) -
sizeof(USED_BLOCK));
890#if defined(MRBC_ALLOC_VMID)
899void * mrbc_alloc(
const struct VM *vm,
unsigned int size)
904 if( vm ) mrbc_set_vm_id(ptr, vm->
vm_id);
919void * mrbc_calloc(
const struct VM *vm,
unsigned int nmemb,
unsigned int size)
924 if( vm ) mrbc_set_vm_id(ptr, vm->
vm_id);
935void mrbc_free_all(
const struct VM *vm)
940 int vm_id = vm->
vm_id;
942 while( target < (USED_BLOCK *)
BPOOL_END(pool) ) {
960void mrbc_set_vm_id(
void *ptr,
int vm_id)
972int mrbc_get_vm_id(
void *ptr)
995 while( block < (USED_BLOCK *)
BPOOL_END(pool) ) {
1010#if defined(MRBC_USE_ALLOC_PROF)
1014void mrbc_alloc_start_profiling(
void)
1016 if (profiling)
return;
1026void mrbc_alloc_stop_profiling(
void)
1028 if (!profiling)
return;
1044#if defined(MRBC_DEBUG)
1051void mrbc_alloc_print_statistics(
void )
1056 mrbc_printf(
" total:%d used:%d free:%d frag:%d\n",
1057 stat.total, stat.used, stat.free, stat.fragmentation );
1067void mrbc_alloc_print_pool_header(
void *pool_header )
1076 mrbc_printf(
" sizeof MEMORY_POOL:%d(%04x), USED_BLOCK:%d(%02x), FREE_BLOCK:%d(%02x)\n",
1078 sizeof(USED_BLOCK),
sizeof(USED_BLOCK),
1079 sizeof(FREE_BLOCK),
sizeof(FREE_BLOCK) );
1081 mrbc_printf(
" FLI/SLI bitmap and free_blocks table.\n");
1082 mrbc_printf(
" FLI :S[0123 4567] -- free_blocks ");
1083 for(
int i = 0; i < 64; i++ ) {
mrbc_printf(
"-"); }
1087 for(
int j = 0; j < 8; j++ ) {
1092 for(
int j = 0; j < 8; j++ ) {
1093 int idx = i * 8 + j;
1094 if( idx >=
sizeof(pool->
free_blocks) /
sizeof(FREE_BLOCK *) )
break;
1101void mrbc_alloc_print_memory_block(
void *pool_header )
1103 const int DUMP_BYTES = 32;
1109 while( block < (FREE_BLOCK *)
BPOOL_END(pool) ) {
1111#if defined(MRBC_ALLOC_VMID)
1115 block->size & ~0x03, block->size & ~0x03,
1116 !!(block->size & 0x01), !!(block->size & 0x02) );
1121 if( n > (
BLOCK_SIZE(block) -
sizeof(USED_BLOCK)) ) {
1124 uint8_t *p = (uint8_t *)block +
sizeof(USED_BLOCK);
1126 for( i = 0; i < n; i++)
mrbc_printf(
" %02x", *p++ );
1130 p = (uint8_t *)block +
sizeof(USED_BLOCK);
1131 for( i = 0; i < n; i++) {
1133 mrbc_printf(
"%c", (
' ' <= ch && ch < 0x7f)? ch :
'.');
1140 FLI(index),
SLI(index), block->prev_free, block->next_free);
1148void mrbc_alloc_print_memory_pool(
void )
1150 mrbc_alloc_print_pool_header(0);
1151 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)
#define RETURN_IF_NULL(ptr)
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.